diff --git a/server/typescript/packages/docs-site/src/builders/object-data.ts b/server/typescript/packages/docs-site/src/builders/object-data.ts index 09001aec4..9beef38c6 100644 --- a/server/typescript/packages/docs-site/src/builders/object-data.ts +++ b/server/typescript/packages/docs-site/src/builders/object-data.ts @@ -35,7 +35,7 @@ export interface FieldRow { name: string; type: string; isArray: boolean; requir /** Render an attr value for display: an object (e.g. view.badge @variantMap) as * ordered `k: v` pairs, an array as a comma list, else the scalar. */ -function fmtAttrValue(v: unknown): string { +export function fmtAttrValue(v: unknown): string { if (v !== null && typeof v === "object" && !Array.isArray(v)) { return Object.entries(v as Record) .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) @@ -45,15 +45,45 @@ function fmtAttrValue(v: unknown): string { if (Array.isArray(v)) return v.map(String).join(", "); return String(v); } + +/** A node's authored attrs not already rendered by a specific renderer, as + * escaped key/value pairs — consumed so they don't surface as "not rendered by + * any page" in coverage. `skip` names the attrs a specific renderer handles. + * Deterministic (sorted by name). This is the generic catch-all that documents + * a consumer's own attrs (e.g. object.@dataflow) + the structural ones a + * bespoke renderer doesn't (e.g. relationship.@onDelete). */ +function otherAttrs(node: MetaData, cov: CoverageTracker, skip: Set): ViewAttr[] { + return [...node.ownAttrs()] + .filter(([n]) => !skip.has(n)) + .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) + .map(([n, v]) => { cov.consumeAttr(node, n); return { name: esc(n), value: esc(fmtAttrValue(v)) }; }); +} + +/** Consume a node + its whole subtree (nodes + attrs) so a section that renders + * only a summary (e.g. a grid layout's top-level attrs) doesn't leave its nested + * config flagged as un-rendered. */ +function consumeSubtree(node: MetaData, cov: CoverageTracker): void { + cov.consumeNode(node); + for (const [n] of node.ownAttrs()) cov.consumeAttr(node, n); + for (const c of node.ownChildren()) consumeSubtree(c, cov); +} + export interface IndexRow { name: string; kind: string; fields: string; extra: string; unique: boolean; } export interface ValidatorRow { scope: "field" | "object"; subject: string; rule: string; // human-readable, HTML-escaped } -export interface RelationRow { name: string; toName: string; toHref: string; cardinality: string; } -export interface OriginRow { field: string; from: string; via: string; } +export interface RelationRow { name: string; toName: string; toHref: string; cardinality: string; attrs: ViewAttr[]; } +export interface OriginRow { field: string; from: string; via: string; attrs: ViewAttr[]; } +export interface LayoutRow { kind: string; attrs: ViewAttr[]; } + +// Field attrs fieldRow renders specifically (as their own badges / enum / ref); +// everything else authored on a field (e.g. @column, @storage) is rendered +// generically as a badge so it isn't flagged "not rendered" in coverage. +const FIELD_KNOWN_ATTRS = new Set(["required", "deprecated", "maxLength", "dbColumnType", "default", "xmlText", "values", "objectRef", "description"]); export interface HierRow { name: string; href: string; level: number; self: boolean; } export interface ObjectPageData { name: string; kindBadge: string; isAbstract: boolean; isView: boolean; generation: string; pkg: string; href: string; breadcrumbHtml: string; desc: string; tableName?: string | undefined; pkHtml?: string | undefined; + objectAttrs: ViewAttr[]; storageAttrs: ViewAttr[]; layouts: LayoutRow[]; ownFields: FieldRow[]; inheritedFields: FieldRow[]; indexes: IndexRow[]; validators: ValidatorRow[]; relations: RelationRow[]; origins: OriginRow[]; hierarchy: HierRow[]; inheritanceMermaid?: string | undefined; neighborhoodMermaid?: string | undefined; neighborhoodLegend?: { pkg: string; fill: string; stroke: string }[] | undefined; neighborhoodMore?: number | undefined; @@ -115,6 +145,12 @@ function fieldRow(f: MetaData, ownerHref: string, g: LinkGraph, cov: CoverageTra .map(([an, av]) => { cov.consumeAttr(v, an); return { name: esc(an), value: esc(fmtAttrValue(av)) }; }); views.push({ subType: esc(v.subType), attrs: vAttrs }); } + // any other authored field attrs (e.g. @column DB name, @storage) as badges + for (const [n, val] of [...f.ownAttrs()].sort(([x], [y]) => (x < y ? -1 : x > y ? 1 : 0))) { + if (FIELD_KNOWN_ATTRS.has(n)) continue; + cov.consumeAttr(f, n); + bits.push(badge({ text: `@${n}=${fmtAttrValue(val)}`, cls: "badge-soft badge-ghost" })); + } const desc = esc(a("description") ?? ""); return { name: f.name, type: f.subType, isArray: f.resolvedIsArray(), required, badgesHtml: bits.join(" "), desc, enumValues, views, refHref, refName, inheritedFrom: undefined, anchor: `f-${f.name}` }; } @@ -136,6 +172,8 @@ export function buildObjectPage(fqn: string, g: LinkGraph, cov: CoverageTracker) const o = dn.node; cov.consumeNode(o); cov.consumeAttr(o, "description"); + // consumer/structural attrs authored on the object itself (e.g. @dataflow, @neo4j) + const objectAttrs = otherAttrs(o, cov, new Set(["description"])); // inheritance hierarchy rows (ancestors nearest-last so level increases downward) + self + direct children const anc = g.ancestors(fqn); // nearest-first @@ -150,10 +188,13 @@ export function buildObjectPage(fqn: string, g: LinkGraph, cov: CoverageTracker) // storage: table vs view, generation, pk let tableName: string | undefined, isView = false, pkHtml: string | undefined, generation = ""; + const storageAttrs: ViewAttr[] = []; for (const s of o.childrenOfType("source")) { cov.consumeNode(s); const t = s.attr("table"); if (t !== undefined) { cov.consumeAttr(s, "table"); tableName = String(t); } const kind = s.attr("kind"); if (kind !== undefined) { cov.consumeAttr(s, "kind"); if (String(kind) === "view") isView = true; } + // extra source attrs — e.g. a view source's @view (view name) — rendered in the storage section + storageAttrs.push(...otherAttrs(s, cov, new Set(["table", "kind"]))); } // indexes: identity (pk/secondary) + index.lookup with tuning detail const indexes: IndexRow[] = []; @@ -161,16 +202,18 @@ export function buildObjectPage(fqn: string, g: LinkGraph, cov: CoverageTracker) cov.consumeNode(id); const flds = id.attr("fields"); if (flds !== undefined) cov.consumeAttr(id, "fields"); const fields = Array.isArray(flds) ? flds.join(", ") : String(flds ?? ""); + // other authored identity attrs (e.g. @constraintName) rendered into the detail cell + const idExtra = otherAttrs(id, cov, new Set(["fields", "references", "enforce", "generation"])).map((x) => `@${x.name}=${x.value}`).join(" · "); if (id.subType === "primary") { pkHtml = `${esc(fields)}`; const gen = id.attr("generation"); if (gen !== undefined) { cov.consumeAttr(id, "generation"); generation = String(gen); } - indexes.push({ name: id.name, kind: "primary", fields, extra: "", unique: true }); + indexes.push({ name: id.name, kind: "primary", fields, extra: idExtra, unique: true }); } else if (id.subType === "secondary") { - indexes.push({ name: id.name, kind: "unique", fields, extra: "", unique: true }); + indexes.push({ name: id.name, kind: "unique", fields, extra: idExtra, unique: true }); } else if (id.subType === "reference") { const ref = id.attr("references"); if (ref !== undefined) cov.consumeAttr(id, "references"); const enf = id.attr("enforce"); if (enf !== undefined) cov.consumeAttr(id, "enforce"); - indexes.push({ name: id.name, kind: "fk", fields, extra: [ref ? `→ ${esc(String(ref))}` : "", enf === false || enf === "false" ? "logical" : ""].filter(Boolean).join(" · "), unique: false }); + indexes.push({ name: id.name, kind: "fk", fields, extra: [ref ? `→ ${esc(String(ref))}` : "", enf === false || enf === "false" ? "logical" : "", idExtra].filter(Boolean).join(" · "), unique: false }); } } for (const ix of o.childrenOfType("index")) { @@ -201,17 +244,38 @@ export function buildObjectPage(fqn: string, g: LinkGraph, cov: CoverageTracker) } validators.sort((a, b) => a.subject.localeCompare(b.subject)); - // relationships + // relationships — bespoke name/target/cardinality + generic extras (@onDelete/@onUpdate/…) + const relAttrs = new Map(); + for (const rel of o.childrenOfType("relationship")) { + cov.consumeNode(rel); cov.consumeAttr(rel, "objectRef"); cov.consumeAttr(rel, "cardinality"); + relAttrs.set(rel.name, otherAttrs(rel, cov, new Set(["objectRef", "cardinality", "through", "sourceRefField", "symmetric"]))); + } const relations: RelationRow[] = g.relationshipsOf(fqn).map((r) => { const t = g.byFqn(r.toFqn); - return { name: r.name, toName: t?.name ?? r.toFqn, toHref: t ? g.relHref(dn.href, t.href) : "", cardinality: r.cardinality }; + return { name: r.name, toName: t?.name ?? r.toFqn, toHref: t ? g.relHref(dn.href, t.href) : "", cardinality: r.cardinality, attrs: relAttrs.get(r.name) ?? [] }; }); - for (const rel of o.childrenOfType("relationship")) { cov.consumeNode(rel); cov.consumeAttr(rel, "objectRef"); cov.consumeAttr(rel, "cardinality"); } - // origin provenance - const origins: OriginRow[] = g.originsOf(fqn).map((r) => ({ field: r.field, from: esc(r.from), via: esc(r.via) })) + // origin provenance — bespoke field/from/via + generic extras (@of/@agg/@filter/…) + const originAttrs = new Map(); + for (const f of o.childrenOfType("field")) for (const org of f.childrenOfType("origin")) { + cov.consumeNode(org); cov.consumeAttr(org, "from"); cov.consumeAttr(org, "via"); + const cur = originAttrs.get(f.name) ?? []; + cur.push(...otherAttrs(org, cov, new Set(["from", "via"]))); + originAttrs.set(f.name, cur); + } + const origins: OriginRow[] = g.originsOf(fqn).map((r) => ({ field: r.field, from: esc(r.from), via: esc(r.via), attrs: originAttrs.get(r.field) ?? [] })) .sort((a, b) => a.field.localeCompare(b.field)); - for (const f of o.childrenOfType("field")) for (const org of f.childrenOfType("origin")) { cov.consumeNode(org); cov.consumeAttr(org, "from"); cov.consumeAttr(org, "via"); } + + // grid/form layout (admin-ui presentation on projections): render the layout node's + // own attrs (@pageSize/@defaultSortOrder/…); consume nested column config so it + // isn't flagged un-rendered. + const layouts: LayoutRow[] = []; + for (const l of o.childrenOfType("layout")) { + cov.consumeNode(l); + const attrs = otherAttrs(l, cov, new Set()); + for (const c of l.ownChildren()) consumeSubtree(c, cov); + layouts.push({ kind: esc(l.subType), attrs }); + } // fields own vs inherited const ownNames = new Set(o.ownChildren().filter((c) => c.type === "field").map((c) => c.name)); @@ -282,7 +346,7 @@ export function buildObjectPage(fqn: string, g: LinkGraph, cov: CoverageTracker) return { name: dn.name, kindBadge: o.subType, isAbstract: o.isAbstract, isView, generation, pkg: dn.pkg, href: dn.href, breadcrumbHtml: crumbs.join(" / "), desc: esc(o.attr("description") ?? ""), - tableName, pkHtml, ownFields, inheritedFields, indexes, validators, relations, origins, + tableName, pkHtml, objectAttrs, storageAttrs, layouts, ownFields, inheritedFields, indexes, validators, relations, origins, hierarchy, inheritanceMermaid, neighborhoodMermaid, neighborhoodLegend, neighborhoodMore, referencedBy, references, usedByTemplates, sourceFile: src, }; } diff --git a/server/typescript/packages/docs-site/src/builders/output-data.ts b/server/typescript/packages/docs-site/src/builders/output-data.ts index ea4196864..ad233150f 100644 --- a/server/typescript/packages/docs-site/src/builders/output-data.ts +++ b/server/typescript/packages/docs-site/src/builders/output-data.ts @@ -4,14 +4,25 @@ import { LinkGraph } from "../link-graph.js"; import type { CoverageTracker } from "../coverage.js"; import type { CommentDocs } from "../yaml-comments.js"; import { esc } from "../badges.js"; +import { fmtAttrValue } from "./object-data.js"; -export interface OutputPageData { name: string; pkg: string; href: string; breadcrumbHtml: string; format: string; kind: string; textRef: string; textRefResolves: boolean; payloadName: string; payloadHref: string; desc: string; fields: { name: string; type: string; isArray: boolean; wire: string; note: string; refHtml: string }[]; } +// Rendered specifically (own fields/badges); everything else a template authors +// (e.g. a consumer's @dataflow) is rendered generically as extraAttrsHtml. +const OUTPUT_KNOWN_ATTRS = new Set(["payloadRef", "textRef", "format", "kind", "description"]); + +export interface OutputPageData { name: string; pkg: string; href: string; breadcrumbHtml: string; format: string; kind: string; textRef: string; textRefResolves: boolean; payloadName: string; payloadHref: string; desc: string; extraAttrsHtml: string; fields: { name: string; type: string; isArray: boolean; wire: string; note: string; refHtml: string }[]; } export function buildOutputPage(fqn: string, g: LinkGraph, cov: CoverageTracker, docs: CommentDocs, sourceDirs: string[] = []): OutputPageData { const dn = g.byFqn(fqn)!; const t = dn.node; - cov.consumeNode(t); cov.consumeAttr(t, "payloadRef"); cov.consumeAttr(t, "textRef"); cov.consumeAttr(t, "format"); + cov.consumeNode(t); cov.consumeAttr(t, "payloadRef"); cov.consumeAttr(t, "textRef"); cov.consumeAttr(t, "format"); cov.consumeAttr(t, "kind"); const format = String(t.attr("format") ?? "text"); + // any other authored template attrs (e.g. @maxChars, @requiredTags, a consumer's @dataflow) + const extraAttrsHtml = [...t.ownAttrs()] + .filter(([n]) => !OUTPUT_KNOWN_ATTRS.has(n)) + .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) + .map(([n, v]) => { cov.consumeAttr(t, n); return `@${esc(n)}=${esc(fmtAttrValue(v))}`; }) + .join(" "); const pRef = g.refsFrom(fqn).find((r) => r.kind === "payload"); const payload = pRef ? g.byFqn(pRef.to) : undefined; const fields = (payload?.node.childrenOfType("field") ?? []).map((f) => { @@ -29,7 +40,7 @@ export function buildOutputPage(fqn: string, g: LinkGraph, cov: CoverageTracker, const textRefResolves = sourceDirs.some((d) => existsSync(join(d, ...textRef.split("/")) + ".mustache")); return { name: dn.name, pkg: dn.pkg, href: dn.href, breadcrumbHtml: `index / ${esc(dn.pkg)} / ${esc(dn.name)}`, - format, kind: String(t.attr("kind") ?? "document"), textRef, textRefResolves, + format, kind: String(t.attr("kind") ?? "document"), textRef, textRefResolves, extraAttrsHtml, payloadName: payload?.name ?? "", payloadHref: payload ? esc(g.relHref(dn.href, payload.href)) : "", desc: payload ? esc(payload.node.attr("description") ?? docs.objectDesc.get(payload.name) ?? "") : "", fields }; } diff --git a/server/typescript/packages/docs-site/src/builders/prompt-data.ts b/server/typescript/packages/docs-site/src/builders/prompt-data.ts index f38ecf6df..cdb8b95be 100644 --- a/server/typescript/packages/docs-site/src/builders/prompt-data.ts +++ b/server/typescript/packages/docs-site/src/builders/prompt-data.ts @@ -4,6 +4,11 @@ import { LinkGraph } from "../link-graph.js"; import type { CoverageTracker } from "../coverage.js"; import { highlightMustache } from "../mustache-highlight.js"; import { esc } from "../badges.js"; +import { fmtAttrValue } from "./object-data.js"; + +// Template attrs rendered specifically (as their own badges) — everything else a +// template authors (e.g. a consumer's @dataflow) is rendered generically below. +const PROMPT_KNOWN_ATTRS = new Set(["format", "maxTokens", "requiredSlots", "model", "responseRef", "maxChars", "promptStyle", "payloadRef", "textRef", "description"]); export interface PayloadTreeRow { indent: number; name: string; type: string; isArray: boolean; anchor: string; desc: string; refHtml: string; } export interface PromptPageData { name: string; pkg: string; href: string; breadcrumbHtml: string; attrsHtml: string; desc: string; payloadName: string; payloadHref: string; payloadTree: PayloadTreeRow[]; sourceHtml?: string | undefined; sourceMissingNote?: string | undefined; tocHtml?: string | undefined; packageFiles: { file: string; html: string }[]; } @@ -17,6 +22,12 @@ export function buildPromptPage(fqn: string, g: LinkGraph, cov: CoverageTracker, const v = t.attr(a); if (v !== undefined) { cov.consumeAttr(t, a); attrs.push(`@${esc(a)} ${esc(v)}`); } } cov.consumeAttr(t, "payloadRef"); cov.consumeAttr(t, "textRef"); + // any other authored attrs (e.g. a consumer's @dataflow) rendered generically + for (const [n, v] of [...t.ownAttrs()].sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))) { + if (PROMPT_KNOWN_ATTRS.has(n)) continue; + cov.consumeAttr(t, n); + attrs.push(`@${esc(n)}=${esc(fmtAttrValue(v))}`); + } // payload tree (root + one nested level) const pRef = g.refsFrom(fqn).find((r) => r.kind === "payload"); const payload = pRef ? g.byFqn(pRef.to) : undefined; diff --git a/server/typescript/packages/docs-site/templates/object.html.mustache b/server/typescript/packages/docs-site/templates/object.html.mustache index 36b10a786..0978feefc 100644 --- a/server/typescript/packages/docs-site/templates/object.html.mustache +++ b/server/typescript/packages/docs-site/templates/object.html.mustache @@ -5,8 +5,9 @@ {{#isAbstract}}abstract{{/isAbstract}}
{{#tableName}}{{#isView}}view{{/isView}}{{^isView}}table{{/isView}} {{tableName}}{{/tableName}} - {{#pkHtml}} · pk {{{pkHtml}}}{{/pkHtml}}{{#generation}} · gen {{generation}}{{/generation}}
+ {{#pkHtml}} · pk {{{pkHtml}}}{{/pkHtml}}{{#generation}} · gen {{generation}}{{/generation}}{{#storageAttrs}} · {{name}} {{value}}{{/storageAttrs}} {{#desc}}

{{desc}}

{{/desc}} +{{#objectAttrs.length}}
attributes{{#objectAttrs}}@{{name}}={{value}}{{/objectAttrs}}
{{/objectAttrs.length}}

Fields

@@ -28,10 +29,13 @@
FieldTypeDescription
{{#validators}}{{/validators}}
{{subject}}{{rule}}
{{/validators.length}} {{#relations.length}}

Relationships

-{{#relations}}{{/relations}}
{{name}}{{cardinality}}{{toName}}
{{/relations.length}} +{{#relations}}{{/relations}}
{{name}}{{cardinality}}{{toName}}{{#attrs}}@{{name}}={{value}}{{/attrs}}
{{/relations.length}} {{#origins.length}}

Field provenance

-{{#origins}}{{/origins}}
FieldFromVia
{{field}}{{from}}{{via}}
{{/origins.length}} +{{#origins}}{{/origins}}
FieldFromVia
{{field}}{{from}}{{via}}{{#attrs}}@{{name}}={{value}}{{/attrs}}
{{/origins.length}} + +{{#layouts.length}}

Layout

+{{#layouts}}{{/layouts}}
{{kind}}{{#attrs}}@{{name}}={{value}}{{/attrs}}
{{/layouts.length}} {{#inheritanceMermaid}}

Inheritance

{{inheritanceMermaid}}
{{/inheritanceMermaid}} diff --git a/server/typescript/packages/docs-site/templates/output.html.mustache b/server/typescript/packages/docs-site/templates/output.html.mustache index 801653b4c..b6d5734c1 100644 --- a/server/typescript/packages/docs-site/templates/output.html.mustache +++ b/server/typescript/packages/docs-site/templates/output.html.mustache @@ -1,5 +1,6 @@

{{name}} {{format}} output

+{{#extraAttrsHtml}}
{{{extraAttrsHtml}}}
{{/extraAttrsHtml}} {{#payloadName}}{{/payloadName}}
textRef: {{textRef}} diff --git a/server/typescript/packages/docs-site/test/fixture/golden/acme/ai/ItemView.html b/server/typescript/packages/docs-site/test/fixture/golden/acme/ai/ItemView.html index 506cf36be..9a2676297 100644 --- a/server/typescript/packages/docs-site/test/fixture/golden/acme/ai/ItemView.html +++ b/server/typescript/packages/docs-site/test/fixture/golden/acme/ai/ItemView.html @@ -55,6 +55,7 @@

ItemView

+

Fields

@@ -73,6 +74,8 @@

ItemView + +

Neighborhood

%%{init: {'theme':'base','themeVariables':{'darkMode':true,'background':'#0b1220','primaryColor':'#1e2a3a','primaryTextColor':'#cbd5e1','primaryBorderColor':'#4a7fa5','lineColor':'#64748b','secondaryColor':'#1a2535','tertiaryColor':'#0f1826','fontSize':'13px'}}}%%
 erDiagram
diff --git a/server/typescript/packages/docs-site/test/fixture/golden/acme/ai/NpcPayload.html b/server/typescript/packages/docs-site/test/fixture/golden/acme/ai/NpcPayload.html
index d9280911c..fe46b3e32 100644
--- a/server/typescript/packages/docs-site/test/fixture/golden/acme/ai/NpcPayload.html
+++ b/server/typescript/packages/docs-site/test/fixture/golden/acme/ai/NpcPayload.html
@@ -55,12 +55,13 @@ 

NpcPayload

+

Fields

FieldTypeDescription
labelstring
- +
FieldTypeDescription
npcNamestringrequired
items[]object⊃ ItemView
items[]object⊃ ItemView @storage=jsonb
@@ -76,6 +77,8 @@

NpcPayload + +

Neighborhood

%%{init: {'theme':'base','themeVariables':{'darkMode':true,'background':'#0b1220','primaryColor':'#1e2a3a','primaryTextColor':'#cbd5e1','primaryBorderColor':'#4a7fa5','lineColor':'#64748b','secondaryColor':'#1a2535','tertiaryColor':'#0f1826','fontSize':'13px'}}}%%
 erDiagram
diff --git a/server/typescript/packages/docs-site/test/fixture/golden/acme/ai/NpcResponse.html b/server/typescript/packages/docs-site/test/fixture/golden/acme/ai/NpcResponse.html
index f6c549300..27d75dc62 100644
--- a/server/typescript/packages/docs-site/test/fixture/golden/acme/ai/NpcResponse.html
+++ b/server/typescript/packages/docs-site/test/fixture/golden/acme/ai/NpcResponse.html
@@ -55,6 +55,7 @@ 

NpcResponse

+

Fields

@@ -78,6 +79,8 @@

NpcResponse + +
referenced by npcReviewOutput
used by templates npcReviewOutput
meta.ai.yaml
diff --git a/server/typescript/packages/docs-site/test/fixture/golden/acme/ai/OrderLine.html b/server/typescript/packages/docs-site/test/fixture/golden/acme/ai/OrderLine.html index f9235356f..29c418f22 100644 --- a/server/typescript/packages/docs-site/test/fixture/golden/acme/ai/OrderLine.html +++ b/server/typescript/packages/docs-site/test/fixture/golden/acme/ai/OrderLine.html @@ -55,6 +55,7 @@

OrderLine +

Fields

FieldTypeDescription
verdictstringverdict <b>tag</b> & "quote"
@@ -79,6 +80,8 @@

OrderLine + +

Neighborhood

%%{init: {'theme':'base','themeVariables':{'darkMode':true,'background':'#0b1220','primaryColor':'#1e2a3a','primaryTextColor':'#cbd5e1','primaryBorderColor':'#4a7fa5','lineColor':'#64748b','secondaryColor':'#1a2535','tertiaryColor':'#0f1826','fontSize':'13px'}}}%%
 erDiagram
diff --git a/server/typescript/packages/docs-site/test/fixture/golden/acme/ai/OrphanVO.html b/server/typescript/packages/docs-site/test/fixture/golden/acme/ai/OrphanVO.html
index 8bb09d857..b3cff6581 100644
--- a/server/typescript/packages/docs-site/test/fixture/golden/acme/ai/OrphanVO.html
+++ b/server/typescript/packages/docs-site/test/fixture/golden/acme/ai/OrphanVO.html
@@ -55,6 +55,7 @@ 

OrphanVO

+

Fields

FieldTypeDescription
orderIduuid
FieldTypeDescription
@@ -74,6 +75,8 @@

OrphanVO + +
meta.ai.yaml

+ + diff --git a/server/typescript/packages/docs-site/test/fixture/golden/acme/shop/Order.html b/server/typescript/packages/docs-site/test/fixture/golden/acme/shop/Order.html index 8a4cc1aa9..544c8cc98 100644 --- a/server/typescript/packages/docs-site/test/fixture/golden/acme/shop/Order.html +++ b/server/typescript/packages/docs-site/test/fixture/golden/acme/shop/Order.html @@ -54,6 +54,7 @@

Order table orders · pk id · gen uuid

A customer <order> with "items" & totals.

+
attributes@team=platform

Fields

@@ -63,7 +64,7 @@

Order

- +
FieldTypeDescription
qtyintdefault 1 min=1 max=99
customerIdstring≤36
customerIdstring≤36 @column=customer_id
@@ -73,14 +74,16 @@

Order

Indexes & keys

- +
NameKindFieldsDetail
fkCustomerfkcustomerId→ acme::shop::Customer
idx_order_qtyindexqtyorders desc · where (qty > 0)
idprimaryid
fkCustomerfkcustomerId→ acme::shop::Customer · @constraintName=fk_order_customer
idx_order_qtyindexqtyorders desc · where (qty > 0)
idprimaryid

Validators

comparisonqty lte 99

Relationships

-
customeroneCustomer
productsmanyProduct
+
customeroneCustomer@onDelete=cascade@onUpdate=restrict
productsmanyProduct

+ + diff --git a/server/typescript/packages/docs-site/test/fixture/golden/acme/shop/OrderProduct.html b/server/typescript/packages/docs-site/test/fixture/golden/acme/shop/OrderProduct.html index e5ab4d0bd..239aaa972 100644 --- a/server/typescript/packages/docs-site/test/fixture/golden/acme/shop/OrderProduct.html +++ b/server/typescript/packages/docs-site/test/fixture/golden/acme/shop/OrderProduct.html @@ -55,6 +55,7 @@

OrderProduct · pk id · gen uuid +

Fields

@@ -79,6 +80,8 @@

OrderProduct + +

Inheritance

%%{init: {'theme':'base','themeVariables':{'darkMode':true,'background':'#0b1220','primaryColor':'#1e2a3a','primaryTextColor':'#cbd5e1','primaryBorderColor':'#4a7fa5','lineColor':'#64748b','secondaryColor':'#1a2535','tertiaryColor':'#0f1826','fontSize':'13px'}}}%%
 flowchart TD
diff --git a/server/typescript/packages/docs-site/test/fixture/golden/acme/shop/OrphanLog.html b/server/typescript/packages/docs-site/test/fixture/golden/acme/shop/OrphanLog.html
index 4fea0130e..0d1742200 100644
--- a/server/typescript/packages/docs-site/test/fixture/golden/acme/shop/OrphanLog.html
+++ b/server/typescript/packages/docs-site/test/fixture/golden/acme/shop/OrphanLog.html
@@ -55,6 +55,7 @@ 

OrphanLog

+

Fields

FieldTypeDescription
orderIdstring≤36
@@ -77,6 +78,8 @@

OrphanLog + +
meta.shop.yaml

FieldTypeDescription
linestring
@@ -79,6 +80,8 @@

Product + +

Inheritance

%%{init: {'theme':'base','themeVariables':{'darkMode':true,'background':'#0b1220','primaryColor':'#1e2a3a','primaryTextColor':'#cbd5e1','primaryBorderColor':'#4a7fa5','lineColor':'#64748b','secondaryColor':'#1a2535','tertiaryColor':'#0f1826','fontSize':'13px'}}}%%
 flowchart TD
diff --git a/server/typescript/packages/docs-site/test/fixture/golden/acme/shop/index.html b/server/typescript/packages/docs-site/test/fixture/golden/acme/shop/index.html
index 221fb1203..b4c3a7ba1 100644
--- a/server/typescript/packages/docs-site/test/fixture/golden/acme/shop/index.html
+++ b/server/typescript/packages/docs-site/test/fixture/golden/acme/shop/index.html
@@ -82,7 +82,7 @@ 

Fixture

Objects

FieldTypeDescription
skustringrequired ≤40
- +
NameKindTableFieldsExtends
Customerentitycustomers3BaseEntity
CustomerFriendentitycustomer_friends4BaseEntity
CustomerReferralentitycustomer_referrals4BaseEntity
LineItemViewprojectionv_line_item2
Orderentityorders5BaseEntity
OrderProductentityorder_products4BaseEntity
OrphanLogentity1
Productentityproducts4BaseEntity
Customerentitycustomers3BaseEntity
CustomerFriendentitycustomer_friends4BaseEntity
CustomerReferralentitycustomer_referrals4BaseEntity
LineItemViewprojection2
Orderentityorders5BaseEntity
OrderProductentityorder_products4BaseEntity
OrphanLogentity1
Productentityproducts4BaseEntity

Referenced by

diff --git a/server/typescript/packages/docs-site/test/fixture/golden/coverage.html b/server/typescript/packages/docs-site/test/fixture/golden/coverage.html index 87a5e1143..56a6df13a 100644 --- a/server/typescript/packages/docs-site/test/fixture/golden/coverage.html +++ b/server/typescript/packages/docs-site/test/fixture/golden/coverage.html @@ -55,7 +55,7 @@

Node kinds

Attributes

- +
AttributeCountRendered
field:@dbColumnType1
field:@default2
field:@description1
field:@maxLength10
field:@objectRef2
field:@required4
field:@storage1
field:@values1
field:@xmlText1
identity:@fields9
identity:@generation1
identity:@references8
index:@fields1
index:@orders1
index:@where1
object:@description1
origin:@from1
origin:@via1
relationship:@cardinality4
relationship:@objectRef4
relationship:@onDelete1
relationship:@sourceRefField1
relationship:@symmetric1
relationship:@through3
source:@kind1
source:@table8
template:@format2
template:@payloadRef2
template:@textRef2
validator:@left1
validator:@max1
validator:@min1
validator:@op1
validator:@right1
view:@decimals1
view:@locale1
field:@column1
field:@dbColumnType1
field:@default2
field:@description1
field:@maxLength10
field:@objectRef2
field:@required4
field:@storage1
field:@values1
field:@xmlText1
identity:@constraintName1
identity:@fields9
identity:@generation1
identity:@references8
index:@fields1
index:@orders1
index:@where1
object:@description1
object:@team1
origin:@agg1
origin:@from1
origin:@via1
relationship:@cardinality4
relationship:@objectRef4
relationship:@onDelete1
relationship:@onUpdate1
relationship:@sourceRefField1
relationship:@symmetric1
relationship:@through3
source:@kind1
source:@table7
source:@view1
template:@dataflow2
template:@format2
template:@payloadRef2
template:@textRef2
validator:@left1
validator:@max1
validator:@min1
validator:@op1
validator:@right1
view:@decimals1
view:@locale1

Anomalies

diff --git a/server/typescript/packages/docs-site/test/fixture/input/acme/ai/meta.ai.yaml b/server/typescript/packages/docs-site/test/fixture/input/acme/ai/meta.ai.yaml index 7a8531fe8..bcbd3632d 100644 --- a/server/typescript/packages/docs-site/test/fixture/input/acme/ai/meta.ai.yaml +++ b/server/typescript/packages/docs-site/test/fixture/input/acme/ai/meta.ai.yaml @@ -20,11 +20,13 @@ metadata: "@payloadRef": NpcPayload "@textRef": ai/npc-review "@format": text + "@dataflow": ingest - template.output: name: npcReviewOutput "@payloadRef": NpcResponse "@textRef": ai/npc-response-format "@format": xml + "@dataflow": emit - object.entity: name: OrderLine children: diff --git a/server/typescript/packages/docs-site/test/fixture/input/acme/shop/meta.shop.yaml b/server/typescript/packages/docs-site/test/fixture/input/acme/shop/meta.shop.yaml index 46f4db385..328844aa9 100644 --- a/server/typescript/packages/docs-site/test/fixture/input/acme/shop/meta.shop.yaml +++ b/server/typescript/packages/docs-site/test/fixture/input/acme/shop/meta.shop.yaml @@ -4,6 +4,7 @@ metadata: - object.entity: name: Order "@description": "A customer with \"items\" & totals." + "@team": platform extends: acme::common::BaseEntity children: - field.enum: { name: status, extends: acme::common::statusEnum, default: OPEN } @@ -12,9 +13,9 @@ metadata: default: "1" children: - validator.numeric: { min: 1, max: 99 } - - field.string: { name: customerId, maxLength: 36 } - - identity.reference: { name: fkCustomer, fields: customerId, references: acme::shop::Customer } - - relationship.association: { name: customer, "@objectRef": "acme::shop::Customer", cardinality: one, "@onDelete": cascade } + - field.string: { name: customerId, maxLength: 36, "@column": customer_id } + - identity.reference: { name: fkCustomer, fields: customerId, references: acme::shop::Customer, "@constraintName": fk_order_customer } + - relationship.association: { name: customer, "@objectRef": "acme::shop::Customer", cardinality: one, "@onDelete": cascade, "@onUpdate": restrict } - relationship.association: { name: products, "@objectRef": "acme::shop::Product", cardinality: many, "@through": "acme::shop::OrderProduct" } - index.lookup: { name: idx_order_qty, fields: qty, orders: [desc], where: "(qty > 0)" } - validator.comparison: { left: qty, op: lte, right: "99" } @@ -75,5 +76,5 @@ metadata: - field.string: name: customerName children: - - origin.passthrough: { "@from": "acme::shop::Customer.email", "@via": "Order.customer" } - - source.rdb: { kind: view, table: v_line_item } + - origin.passthrough: { "@from": "acme::shop::Customer.email", "@via": "Order.customer", "@agg": max } + - source.rdb: { kind: view, view: v_line_item }