You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/web/routes/active/_components/ArtifactDoc.svelte

281 lines
6.3 KiB

<script lang="ts">
import ModuleHeader from './ModuleHeader.svelte';
import CodeBlock from './CodeBlock.svelte';
import Callout from './Callout.svelte';
import AiAgentsBox from './AiAgentsBox.svelte';
import PageNav from './PageNav.svelte';
export interface DocCode {
readonly title?: string;
readonly lang?: string;
readonly code: string;
}
export interface DocRow {
readonly name: string;
readonly purpose: string;
readonly notes?: string;
}
export interface DocSection {
readonly title: string;
readonly body?: readonly string[];
readonly bullets?: readonly string[];
readonly table?: readonly DocRow[];
readonly code?: DocCode;
}
export interface ArtifactDocModel {
readonly section: string;
readonly title: string;
readonly alias: string;
readonly summary: string;
readonly factories: readonly string[];
readonly dependsOn?: readonly string[];
readonly layer: string;
readonly overview: readonly string[];
readonly dynamics?: readonly string[];
readonly commonMistakes?: readonly DocRow[];
readonly quickStart: DocCode;
readonly factoryRows: readonly DocRow[];
readonly api?: readonly DocSection[];
readonly sections: readonly DocSection[];
readonly tests: readonly DocRow[];
readonly status?: {
readonly variant: 'info' | 'warn' | 'success' | 'tip';
readonly title: string;
readonly body: string;
};
}
let { doc }: { doc: ArtifactDocModel } = $props();
const moduleName = $derived(doc.alias.startsWith('$') ? doc.alias.slice(1) : doc.alias);
const hasServerLayer = $derived(
doc.layer.toLowerCase().includes('server') ||
(doc.dependsOn ?? []).some((dependency) => dependency.includes('$svrs'))
);
const testTargets = $derived(doc.tests.map((test) => test.name).join(', '));
const aiAgentRows = $derived.by(() => {
const rows = [
{
step: 'Public API',
where: `src/arts/${moduleName}/index.ts and src/arts/${moduleName}/types.ts`,
rule: 'Docs and examples must match exported symbols, not planned APIs.'
},
{
step: 'Runtime shape',
where: doc.layer,
rule: 'Preserve the documented Engine/Active boundary and the ActiveEngine contract when reactive state exists.'
}
];
if (hasServerLayer) {
rows.push({
step: 'Server authority',
where: `src/svrs/${moduleName}`,
rule: 'Identity, authorization and private cache decisions stay server-side; active clients are UX reflectors.'
});
}
rows.push(
{
step: 'Logging',
where: '$libs/logger.Logger plus module consts.ts',
rule: 'Use the shared Logger contract. Do not create local logger interfaces or hard-code categories/messages.'
},
{
step: 'Tests',
where: testTargets,
rule: 'Update or add tests when behavior, public contracts or integration points change.'
}
);
return rows;
});
</script>
<svelte:head>
<title>{doc.title} ({doc.alias}) — Active</title>
</svelte:head>
<article class="article">
<ModuleHeader
section={doc.section}
title={doc.title}
alias={doc.alias}
summary={doc.summary}
factories={doc.factories}
dependsOn={doc.dependsOn}
layer={doc.layer}
/>
{#if doc.status}
<Callout variant={doc.status.variant} title={doc.status.title}>
<p>{doc.status.body}</p>
</Callout>
{/if}
<h2>Overview</h2>
{#each doc.overview as paragraph}
<p>{paragraph}</p>
{/each}
{#if doc.dynamics?.length}
<h2>How it works in practice</h2>
{#each doc.dynamics as paragraph}
<p>{paragraph}</p>
{/each}
{/if}
<h2>Quick start</h2>
<CodeBlock code={doc.quickStart.code} lang={doc.quickStart.lang ?? 'ts'} title={doc.quickStart.title} />
<h2>Factories</h2>
<table>
<thead>
<tr>
<th>Factory</th>
<th>Purpose</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
{#each doc.factoryRows as row (row.name)}
<tr>
<td><code>{row.name}</code></td>
<td>{row.purpose}</td>
<td>{row.notes ?? ''}</td>
</tr>
{/each}
</tbody>
</table>
{#if doc.api?.length}
<h2>API reference</h2>
{#each doc.api as section (section.title)}
<h3>{section.title}</h3>
{#each section.body ?? [] as paragraph}
<p>{paragraph}</p>
{/each}
{#if section.table}
<table>
<thead>
<tr>
<th>Member</th>
<th>Purpose</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
{#each section.table as row (row.name)}
<tr>
<td><code>{row.name}</code></td>
<td>{row.purpose}</td>
<td>{row.notes ?? ''}</td>
</tr>
{/each}
</tbody>
</table>
{/if}
{#if section.code}
<CodeBlock
code={section.code.code}
lang={section.code.lang ?? 'ts'}
title={section.code.title}
/>
{/if}
{/each}
{/if}
{#each doc.sections as section (section.title)}
<h2>{section.title}</h2>
{#each section.body ?? [] as paragraph}
<p>{paragraph}</p>
{/each}
{#if section.bullets}
<ul>
{#each section.bullets as item}
<li>{item}</li>
{/each}
</ul>
{/if}
{#if section.table}
<table>
<thead>
<tr>
<th>Name</th>
<th>Purpose</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
{#each section.table as row (row.name)}
<tr>
<td><code>{row.name}</code></td>
<td>{row.purpose}</td>
<td>{row.notes ?? ''}</td>
</tr>
{/each}
</tbody>
</table>
{/if}
{#if section.code}
<CodeBlock
code={section.code.code}
lang={section.code.lang ?? 'ts'}
title={section.code.title}
/>
{/if}
{/each}
{#if doc.commonMistakes?.length}
<h2>Common mistakes</h2>
<table>
<thead>
<tr>
<th>Mistake</th>
<th>Why it hurts</th>
<th>Correct pattern</th>
</tr>
</thead>
<tbody>
{#each doc.commonMistakes as row (row.name)}
<tr>
<td><code>{row.name}</code></td>
<td>{row.purpose}</td>
<td>{row.notes ?? ''}</td>
</tr>
{/each}
</tbody>
</table>
{/if}
<h2>Testing</h2>
<table>
<thead>
<tr>
<th>Target</th>
<th>Purpose</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
{#each doc.tests as test (test.name)}
<tr>
<td><code>{test.name}</code></td>
<td>{test.purpose}</td>
<td>{test.notes ?? ''}</td>
</tr>
{/each}
</tbody>
</table>
<AiAgentsBox
intro={`Before editing ${doc.alias}, inspect the real exports and types. Do not invent factories, methods, logger shapes or undocumented behavior from examples alone.`}
rows={aiAgentRows}
/>
<PageNav />
</article>

Powered by TurnKey Linux.