@sdd-method/sdd-cli 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/catalogue/aggregate.d.ts +39 -0
- package/dist/lib/catalogue/aggregate.d.ts.map +1 -0
- package/dist/lib/catalogue/aggregate.js +344 -0
- package/dist/lib/catalogue/aggregate.js.map +1 -0
- package/dist/lib/catalogue/aggregation-manifest-loader.d.ts +25 -0
- package/dist/lib/catalogue/aggregation-manifest-loader.d.ts.map +1 -0
- package/dist/lib/catalogue/aggregation-manifest-loader.js +111 -0
- package/dist/lib/catalogue/aggregation-manifest-loader.js.map +1 -0
- package/dist/lib/catalogue/build.d.ts +42 -0
- package/dist/lib/catalogue/build.d.ts.map +1 -0
- package/dist/lib/catalogue/build.js +373 -0
- package/dist/lib/catalogue/build.js.map +1 -0
- package/dist/lib/catalogue/builders/adr-supersedes.d.ts +14 -0
- package/dist/lib/catalogue/builders/adr-supersedes.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/adr-supersedes.js +62 -0
- package/dist/lib/catalogue/builders/adr-supersedes.js.map +1 -0
- package/dist/lib/catalogue/builders/adrs.d.ts +27 -0
- package/dist/lib/catalogue/builders/adrs.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/adrs.js +191 -0
- package/dist/lib/catalogue/builders/adrs.js.map +1 -0
- package/dist/lib/catalogue/builders/c4-containers.d.ts +16 -0
- package/dist/lib/catalogue/builders/c4-containers.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/c4-containers.js +169 -0
- package/dist/lib/catalogue/builders/c4-containers.js.map +1 -0
- package/dist/lib/catalogue/builders/c4-systems.d.ts +10 -0
- package/dist/lib/catalogue/builders/c4-systems.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/c4-systems.js +99 -0
- package/dist/lib/catalogue/builders/c4-systems.js.map +1 -0
- package/dist/lib/catalogue/builders/capabilities.d.ts +11 -0
- package/dist/lib/catalogue/builders/capabilities.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/capabilities.js +173 -0
- package/dist/lib/catalogue/builders/capabilities.js.map +1 -0
- package/dist/lib/catalogue/builders/capability-edges.d.ts +27 -0
- package/dist/lib/catalogue/builders/capability-edges.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/capability-edges.js +166 -0
- package/dist/lib/catalogue/builders/capability-edges.js.map +1 -0
- package/dist/lib/catalogue/builders/contracts.d.ts +15 -0
- package/dist/lib/catalogue/builders/contracts.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/contracts.js +153 -0
- package/dist/lib/catalogue/builders/contracts.js.map +1 -0
- package/dist/lib/catalogue/builders/domains.d.ts +10 -0
- package/dist/lib/catalogue/builders/domains.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/domains.js +93 -0
- package/dist/lib/catalogue/builders/domains.js.map +1 -0
- package/dist/lib/catalogue/builders/event-edges.d.ts +20 -0
- package/dist/lib/catalogue/builders/event-edges.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/event-edges.js +112 -0
- package/dist/lib/catalogue/builders/event-edges.js.map +1 -0
- package/dist/lib/catalogue/builders/events.d.ts +26 -0
- package/dist/lib/catalogue/builders/events.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/events.js +99 -0
- package/dist/lib/catalogue/builders/events.js.map +1 -0
- package/dist/lib/catalogue/builders/feature-groups.d.ts +10 -0
- package/dist/lib/catalogue/builders/feature-groups.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/feature-groups.js +118 -0
- package/dist/lib/catalogue/builders/feature-groups.js.map +1 -0
- package/dist/lib/catalogue/builders/features.d.ts +35 -0
- package/dist/lib/catalogue/builders/features.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/features.js +206 -0
- package/dist/lib/catalogue/builders/features.js.map +1 -0
- package/dist/lib/catalogue/builders/glossary-xref.d.ts +11 -0
- package/dist/lib/catalogue/builders/glossary-xref.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/glossary-xref.js +107 -0
- package/dist/lib/catalogue/builders/glossary-xref.js.map +1 -0
- package/dist/lib/catalogue/builders/glossary.d.ts +14 -0
- package/dist/lib/catalogue/builders/glossary.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/glossary.js +150 -0
- package/dist/lib/catalogue/builders/glossary.js.map +1 -0
- package/dist/lib/catalogue/builders/index.d.ts +57 -0
- package/dist/lib/catalogue/builders/index.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/index.js +33 -0
- package/dist/lib/catalogue/builders/index.js.map +1 -0
- package/dist/lib/catalogue/builders/integrations.d.ts +12 -0
- package/dist/lib/catalogue/builders/integrations.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/integrations.js +85 -0
- package/dist/lib/catalogue/builders/integrations.js.map +1 -0
- package/dist/lib/catalogue/builders/persona-journey-edges.d.ts +26 -0
- package/dist/lib/catalogue/builders/persona-journey-edges.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/persona-journey-edges.js +133 -0
- package/dist/lib/catalogue/builders/persona-journey-edges.js.map +1 -0
- package/dist/lib/catalogue/builders/personas.d.ts +22 -0
- package/dist/lib/catalogue/builders/personas.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/personas.js +150 -0
- package/dist/lib/catalogue/builders/personas.js.map +1 -0
- package/dist/lib/catalogue/builders/product-edges.d.ts +15 -0
- package/dist/lib/catalogue/builders/product-edges.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/product-edges.js +97 -0
- package/dist/lib/catalogue/builders/product-edges.js.map +1 -0
- package/dist/lib/catalogue/builders/products.d.ts +26 -0
- package/dist/lib/catalogue/builders/products.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/products.js +57 -0
- package/dist/lib/catalogue/builders/products.js.map +1 -0
- package/dist/lib/catalogue/builders/repo-edges.d.ts +18 -0
- package/dist/lib/catalogue/builders/repo-edges.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/repo-edges.js +113 -0
- package/dist/lib/catalogue/builders/repo-edges.js.map +1 -0
- package/dist/lib/catalogue/builders/repositories.d.ts +78 -0
- package/dist/lib/catalogue/builders/repositories.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/repositories.js +204 -0
- package/dist/lib/catalogue/builders/repositories.js.map +1 -0
- package/dist/lib/catalogue/builders/service-contract.d.ts +11 -0
- package/dist/lib/catalogue/builders/service-contract.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/service-contract.js +53 -0
- package/dist/lib/catalogue/builders/service-contract.js.map +1 -0
- package/dist/lib/catalogue/builders/services.d.ts +15 -0
- package/dist/lib/catalogue/builders/services.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/services.js +40 -0
- package/dist/lib/catalogue/builders/services.js.map +1 -0
- package/dist/lib/catalogue/builders/user-journeys.d.ts +24 -0
- package/dist/lib/catalogue/builders/user-journeys.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/user-journeys.js +253 -0
- package/dist/lib/catalogue/builders/user-journeys.js.map +1 -0
- package/dist/lib/catalogue/canonical-schema.yaml +624 -0
- package/dist/lib/catalogue/cli-version.d.ts +10 -0
- package/dist/lib/catalogue/cli-version.d.ts.map +1 -0
- package/dist/lib/catalogue/cli-version.js +10 -0
- package/dist/lib/catalogue/cli-version.js.map +1 -0
- package/dist/lib/catalogue/csv-reader.d.ts +7 -0
- package/dist/lib/catalogue/csv-reader.d.ts.map +1 -0
- package/dist/lib/catalogue/csv-reader.js +97 -0
- package/dist/lib/catalogue/csv-reader.js.map +1 -0
- package/dist/lib/catalogue/csv-writer.d.ts +29 -0
- package/dist/lib/catalogue/csv-writer.d.ts.map +1 -0
- package/dist/lib/catalogue/csv-writer.js +55 -0
- package/dist/lib/catalogue/csv-writer.js.map +1 -0
- package/dist/lib/catalogue/findings.d.ts +27 -0
- package/dist/lib/catalogue/findings.d.ts.map +1 -0
- package/dist/lib/catalogue/findings.js +34 -0
- package/dist/lib/catalogue/findings.js.map +1 -0
- package/dist/lib/catalogue/fk-validator.d.ts +44 -0
- package/dist/lib/catalogue/fk-validator.d.ts.map +1 -0
- package/dist/lib/catalogue/fk-validator.js +90 -0
- package/dist/lib/catalogue/fk-validator.js.map +1 -0
- package/dist/lib/catalogue/index.d.ts +27 -0
- package/dist/lib/catalogue/index.d.ts.map +1 -0
- package/dist/lib/catalogue/index.js +18 -0
- package/dist/lib/catalogue/index.js.map +1 -0
- package/dist/lib/catalogue/manifest-loader.d.ts +47 -0
- package/dist/lib/catalogue/manifest-loader.d.ts.map +1 -0
- package/dist/lib/catalogue/manifest-loader.js +161 -0
- package/dist/lib/catalogue/manifest-loader.js.map +1 -0
- package/dist/lib/catalogue/schema-compat.d.ts +47 -0
- package/dist/lib/catalogue/schema-compat.d.ts.map +1 -0
- package/dist/lib/catalogue/schema-compat.js +52 -0
- package/dist/lib/catalogue/schema-compat.js.map +1 -0
- package/dist/lib/catalogue/schema-loader.d.ts +58 -0
- package/dist/lib/catalogue/schema-loader.d.ts.map +1 -0
- package/dist/lib/catalogue/schema-loader.js +86 -0
- package/dist/lib/catalogue/schema-loader.js.map +1 -0
- package/dist/lib/catalogue/traceability-loader.d.ts +56 -0
- package/dist/lib/catalogue/traceability-loader.d.ts.map +1 -0
- package/dist/lib/catalogue/traceability-loader.js +217 -0
- package/dist/lib/catalogue/traceability-loader.js.map +1 -0
- package/dist/lib/catalogue/validate.d.ts +16 -0
- package/dist/lib/catalogue/validate.d.ts.map +1 -0
- package/dist/lib/catalogue/validate.js +137 -0
- package/dist/lib/catalogue/validate.js.map +1 -0
- package/dist/lib/catalogue/version.d.ts +3 -0
- package/dist/lib/catalogue/version.d.ts.map +1 -0
- package/dist/lib/catalogue/version.js +18 -0
- package/dist/lib/catalogue/version.js.map +1 -0
- package/dist/lib/init/index.d.ts.map +1 -1
- package/dist/lib/init/index.js +6 -0
- package/dist/lib/init/index.js.map +1 -1
- package/dist/lib/mcp/build-info.d.ts +1 -1
- package/dist/lib/mcp/build-info.d.ts.map +1 -1
- package/dist/lib/mcp/build-info.js +1 -1
- package/dist/lib/mcp/build-info.js.map +1 -1
- package/dist/lib/repo-kind.d.ts +3 -3
- package/dist/lib/repo-kind.d.ts.map +1 -1
- package/dist/lib/repo-kind.js +4 -0
- package/dist/lib/repo-kind.js.map +1 -1
- package/dist/verbs/catalogue.d.ts +3 -0
- package/dist/verbs/catalogue.d.ts.map +1 -0
- package/dist/verbs/catalogue.js +60 -0
- package/dist/verbs/catalogue.js.map +1 -0
- package/package.json +3 -3
- package/scripts/copy-yaml-assets.mjs +38 -0
- package/scripts/sync-canonical-schema.sh +39 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integrations.d.ts","sourceRoot":"","sources":["../../../../src/lib/catalogue/builders/integrations.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAWD,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,YAAY,EAAE,CAAC,CA4DzB"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Integrations discoverer — emits a single `integrations.csv` row per
|
|
2
|
+
// integration-product SDD, sourced from `integration-manifest.yaml` at
|
|
3
|
+
// the SDD root.
|
|
4
|
+
//
|
|
5
|
+
// Per ADR 0134 federation: each integration-provider SDD owns one row
|
|
6
|
+
// in the granular integrations.csv. The aggregator merges siblings.
|
|
7
|
+
//
|
|
8
|
+
// Profile gating: only integration-product profile SDDs emit. Other
|
|
9
|
+
// profiles are no-ops.
|
|
10
|
+
//
|
|
11
|
+
// id = integrationId from the manifest (or sdd_id as fallback).
|
|
12
|
+
// name = providerName (or title-cased id).
|
|
13
|
+
// category = profileType (open enum per schema description; ecosystems
|
|
14
|
+
// extend with values like saas-platform, oem, device, ...).
|
|
15
|
+
// parent_product_id = empty (umbrella integration-products are not yet
|
|
16
|
+
// modelled in the federation; this is a hook for future use).
|
|
17
|
+
// domain_id = empty (integration providers are federation nodes, not
|
|
18
|
+
// capability-domain members — per ADR 0136).
|
|
19
|
+
// doc_path = "." (SDD root).
|
|
20
|
+
// repo_count = supplied by the orchestrator from discovered repos.
|
|
21
|
+
import { readFile } from "node:fs/promises";
|
|
22
|
+
import { join } from "node:path";
|
|
23
|
+
import { parse as parseYaml } from "yaml";
|
|
24
|
+
import { z } from "zod";
|
|
25
|
+
const REL_PATH = "integration-manifest.yaml";
|
|
26
|
+
const ManifestSchema = z.object({
|
|
27
|
+
integrationId: z.string().optional(),
|
|
28
|
+
providerName: z.string().optional(),
|
|
29
|
+
profileType: z.string().optional(),
|
|
30
|
+
parentIntegrationProductId: z.string().optional(),
|
|
31
|
+
});
|
|
32
|
+
export async function buildIntegrations(inputs) {
|
|
33
|
+
if (inputs.profile !== "integration-product")
|
|
34
|
+
return [];
|
|
35
|
+
const path = join(inputs.sddPath, REL_PATH);
|
|
36
|
+
let text;
|
|
37
|
+
try {
|
|
38
|
+
text = await readFile(path, "utf-8");
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
if (err.code !== "ENOENT")
|
|
42
|
+
throw err;
|
|
43
|
+
inputs.findings.add("coverage", `${REL_PATH} not found — emitting empty integrations.csv (integration-product SDD without a manifest)`);
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
let raw;
|
|
47
|
+
try {
|
|
48
|
+
raw = parseYaml(text);
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
inputs.findings.add("convention", `${REL_PATH}: failed to parse YAML — ${err.message}`);
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
const parsed = ManifestSchema.safeParse(raw);
|
|
55
|
+
if (!parsed.success) {
|
|
56
|
+
inputs.findings.add("convention", `${REL_PATH}: shape violation — ${parsed.error.issues.map((i) => i.path.join(".") + ": " + i.message).join("; ")}`);
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
const id = (parsed.data.integrationId ?? "").trim() || inputs.sddId;
|
|
60
|
+
const name = (parsed.data.providerName ?? "").trim() || titleCase(id);
|
|
61
|
+
const category = (parsed.data.profileType ?? "").trim();
|
|
62
|
+
const parentProductId = (parsed.data.parentIntegrationProductId ?? "").trim();
|
|
63
|
+
if (category === "") {
|
|
64
|
+
inputs.findings.add("convention", `${REL_PATH}: missing required \`profileType\` (used as integrations.category)`);
|
|
65
|
+
}
|
|
66
|
+
return [
|
|
67
|
+
{
|
|
68
|
+
id,
|
|
69
|
+
name,
|
|
70
|
+
domain_id: "",
|
|
71
|
+
parent_product_id: parentProductId,
|
|
72
|
+
category,
|
|
73
|
+
doc_path: ".",
|
|
74
|
+
repo_count: inputs.repoCount,
|
|
75
|
+
source_sdd_id: "",
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
}
|
|
79
|
+
function titleCase(slug) {
|
|
80
|
+
return slug
|
|
81
|
+
.split("-")
|
|
82
|
+
.map((p) => (p.length === 0 ? p : p[0].toUpperCase() + p.slice(1)))
|
|
83
|
+
.join(" ");
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=integrations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integrations.js","sourceRoot":"","sources":["../../../../src/lib/catalogue/builders/integrations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { CatalogueRow } from "../csv-writer.js";
|
|
2
|
+
import type { FindingsLog } from "../findings.js";
|
|
3
|
+
export interface PersonaJourneyEdgeInputs {
|
|
4
|
+
readonly findings: FindingsLog;
|
|
5
|
+
readonly personaIdByName: ReadonlyMap<string, string>;
|
|
6
|
+
readonly personaIdBySlug: ReadonlyMap<string, string>;
|
|
7
|
+
readonly journeyPrimaryPersonaById: ReadonlyMap<string, string>;
|
|
8
|
+
readonly journeySupportingPersonasById: ReadonlyMap<string, readonly string[]>;
|
|
9
|
+
}
|
|
10
|
+
export interface PersonaFeatureEdgeInputs {
|
|
11
|
+
readonly findings: FindingsLog;
|
|
12
|
+
readonly relatedFeaturesById: ReadonlyMap<string, readonly string[]>;
|
|
13
|
+
readonly featureIdByPath: ReadonlyMap<string, string>;
|
|
14
|
+
readonly featureIdBySlug: ReadonlyMap<string, string>;
|
|
15
|
+
}
|
|
16
|
+
export interface JourneyFeatureEdgeInputs {
|
|
17
|
+
readonly findings: FindingsLog;
|
|
18
|
+
readonly journeyFeaturePathsById: ReadonlyMap<string, readonly string[]>;
|
|
19
|
+
readonly journeyRelatedFeatureSlugsById: ReadonlyMap<string, readonly string[]>;
|
|
20
|
+
readonly featureIdByPath: ReadonlyMap<string, string>;
|
|
21
|
+
readonly featureIdBySlug: ReadonlyMap<string, string>;
|
|
22
|
+
}
|
|
23
|
+
export declare function buildPersonaJourney(inputs: PersonaJourneyEdgeInputs): CatalogueRow[];
|
|
24
|
+
export declare function buildPersonaFeature(inputs: PersonaFeatureEdgeInputs): CatalogueRow[];
|
|
25
|
+
export declare function buildJourneyFeature(inputs: JourneyFeatureEdgeInputs): CatalogueRow[];
|
|
26
|
+
//# sourceMappingURL=persona-journey-edges.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persona-journey-edges.d.ts","sourceRoot":"","sources":["../../../../src/lib/catalogue/builders/persona-journey-edges.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtD,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtD,QAAQ,CAAC,yBAAyB,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChE,QAAQ,CAAC,6BAA6B,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;CAChF;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,mBAAmB,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;IACrE,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtD,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvD;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,uBAAuB,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;IACzE,QAAQ,CAAC,8BAA8B,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;IAChF,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtD,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvD;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,wBAAwB,GAC/B,YAAY,EAAE,CAgChB;AAyDD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,wBAAwB,GAC/B,YAAY,EAAE,CAUhB;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,wBAAwB,GAC/B,YAAY,EAAE,CAUhB"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// Persona/journey edge builders — emit:
|
|
2
|
+
// - persona_journey (persona ↔ journey, role: primary | handoff | supporting)
|
|
3
|
+
// - persona_feature (persona ↔ feature, from `## Related Features` in persona files)
|
|
4
|
+
// - journey_feature (journey ↔ feature, from `**Feature:**` link or
|
|
5
|
+
// `## Related Features` in journey files)
|
|
6
|
+
//
|
|
7
|
+
// Resolution rules:
|
|
8
|
+
// - Persona references in journeys are free-text (e.g. "Fleet Manager")
|
|
9
|
+
// because the persona convention doesn't enforce slug references. We
|
|
10
|
+
// resolve by name match (case-insensitive) against the personas index;
|
|
11
|
+
// unresolved entries log `[finding] orphan` and are skipped.
|
|
12
|
+
// - Feature references resolve via the path index from the features
|
|
13
|
+
// builder when the journey/persona uses a markdown link, OR via slug
|
|
14
|
+
// match against the feature id namespace ({capability_id}-{slug}).
|
|
15
|
+
// - "X → Y (handoff)" in primary_persona triggers a handoff role for Y
|
|
16
|
+
// against the same journey. The "primary" role goes to X.
|
|
17
|
+
export function buildPersonaJourney(inputs) {
|
|
18
|
+
const rows = [];
|
|
19
|
+
const seen = new Set();
|
|
20
|
+
for (const [journeyId, primaryRaw] of inputs.journeyPrimaryPersonaById) {
|
|
21
|
+
const { primary, handoff } = splitHandoff(primaryRaw);
|
|
22
|
+
if (primary !== "") {
|
|
23
|
+
addEdge(inputs, rows, seen, journeyId, primary, "primary");
|
|
24
|
+
}
|
|
25
|
+
if (handoff !== "") {
|
|
26
|
+
addEdge(inputs, rows, seen, journeyId, handoff, "handoff");
|
|
27
|
+
}
|
|
28
|
+
const supporting = inputs.journeySupportingPersonasById.get(journeyId) ?? [];
|
|
29
|
+
for (const name of supporting) {
|
|
30
|
+
addEdge(inputs, rows, seen, journeyId, name, "supporting");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return rows;
|
|
34
|
+
}
|
|
35
|
+
function addEdge(inputs, rows, seen, journeyId, personaName, role) {
|
|
36
|
+
const personaId = resolvePersona(inputs.personaIdByName, inputs.personaIdBySlug, personaName);
|
|
37
|
+
if (personaId === undefined) {
|
|
38
|
+
inputs.findings.add("orphan", `persona_journey: journey ${journeyId} references persona "${personaName}" — no matching personas/<slug>.md`);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const id = `${personaId}__${journeyId}__${role}`;
|
|
42
|
+
if (seen.has(id))
|
|
43
|
+
return;
|
|
44
|
+
seen.add(id);
|
|
45
|
+
rows.push({
|
|
46
|
+
id,
|
|
47
|
+
persona_id: personaId,
|
|
48
|
+
journey_id: journeyId,
|
|
49
|
+
role,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function resolvePersona(byName, bySlug, raw) {
|
|
53
|
+
const trimmed = raw.trim();
|
|
54
|
+
if (trimmed === "")
|
|
55
|
+
return undefined;
|
|
56
|
+
const byNameHit = byName.get(trimmed.toLowerCase());
|
|
57
|
+
if (byNameHit !== undefined)
|
|
58
|
+
return byNameHit;
|
|
59
|
+
// Try slugified form: "Fleet Manager" → "fleet-manager".
|
|
60
|
+
const slug = trimmed
|
|
61
|
+
.toLowerCase()
|
|
62
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
63
|
+
.replace(/^-+|-+$/g, "");
|
|
64
|
+
return bySlug.get(slug);
|
|
65
|
+
}
|
|
66
|
+
function splitHandoff(raw) {
|
|
67
|
+
// Pattern: `X → Y (handoff)` or `X -> Y (handoff)`.
|
|
68
|
+
const m = /^(.+?)\s*(?:→|->)\s*(.+?)\s*\(handoff\)\s*$/i.exec(raw.trim());
|
|
69
|
+
if (m)
|
|
70
|
+
return { primary: (m[1] ?? "").trim(), handoff: (m[2] ?? "").trim() };
|
|
71
|
+
return { primary: raw.trim(), handoff: "" };
|
|
72
|
+
}
|
|
73
|
+
export function buildPersonaFeature(inputs) {
|
|
74
|
+
return buildEdgesByFeatureRef({
|
|
75
|
+
findings: inputs.findings,
|
|
76
|
+
leftKey: "persona_id",
|
|
77
|
+
leftIdToRefs: inputs.relatedFeaturesById,
|
|
78
|
+
leftIdToPaths: new Map(),
|
|
79
|
+
featureIdByPath: inputs.featureIdByPath,
|
|
80
|
+
featureIdBySlug: inputs.featureIdBySlug,
|
|
81
|
+
edgeName: "persona_feature",
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
export function buildJourneyFeature(inputs) {
|
|
85
|
+
return buildEdgesByFeatureRef({
|
|
86
|
+
findings: inputs.findings,
|
|
87
|
+
leftKey: "journey_id",
|
|
88
|
+
leftIdToRefs: inputs.journeyRelatedFeatureSlugsById,
|
|
89
|
+
leftIdToPaths: inputs.journeyFeaturePathsById,
|
|
90
|
+
featureIdByPath: inputs.featureIdByPath,
|
|
91
|
+
featureIdBySlug: inputs.featureIdBySlug,
|
|
92
|
+
edgeName: "journey_feature",
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function buildEdgesByFeatureRef(inputs) {
|
|
96
|
+
const rows = [];
|
|
97
|
+
const seen = new Set();
|
|
98
|
+
const addRow = (leftId, featureId) => {
|
|
99
|
+
const id = `${leftId}__${featureId}`;
|
|
100
|
+
if (seen.has(id))
|
|
101
|
+
return;
|
|
102
|
+
seen.add(id);
|
|
103
|
+
rows.push({
|
|
104
|
+
id,
|
|
105
|
+
[inputs.leftKey]: leftId,
|
|
106
|
+
feature_id: featureId,
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
// Path-based references (markdown links to feature spec files).
|
|
110
|
+
for (const [leftId, paths] of inputs.leftIdToPaths) {
|
|
111
|
+
for (const path of paths) {
|
|
112
|
+
const featureId = inputs.featureIdByPath.get(path);
|
|
113
|
+
if (featureId === undefined) {
|
|
114
|
+
inputs.findings.add("orphan", `${inputs.edgeName}: ${leftId} links to "${path}" — no matching features.csv row`);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
addRow(leftId, featureId);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Slug-based references (bare bullets in `## Related Features`).
|
|
121
|
+
for (const [leftId, slugs] of inputs.leftIdToRefs) {
|
|
122
|
+
for (const slug of slugs) {
|
|
123
|
+
const featureId = inputs.featureIdBySlug.get(slug);
|
|
124
|
+
if (featureId === undefined) {
|
|
125
|
+
inputs.findings.add("orphan", `${inputs.edgeName}: ${leftId} references feature slug "${slug}" — no feature with this slug in features.csv`);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
addRow(leftId, featureId);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return rows;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=persona-journey-edges.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persona-journey-edges.js","sourceRoot":"","sources":["../../../../src/lib/catalogue/builders/persona-journey-edges.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { CatalogueRow } from "../csv-writer.js";
|
|
2
|
+
import type { FindingsLog } from "../findings.js";
|
|
3
|
+
import type { Profile } from "../manifest-loader.js";
|
|
4
|
+
export interface PersonasBuildInputs {
|
|
5
|
+
readonly sddPath: string;
|
|
6
|
+
readonly findings: FindingsLog;
|
|
7
|
+
readonly profile: Profile;
|
|
8
|
+
readonly productId: string;
|
|
9
|
+
}
|
|
10
|
+
export interface PersonasBuildResult {
|
|
11
|
+
readonly rows: CatalogueRow[];
|
|
12
|
+
/** Map of `relPath` → persona id, for downstream edge builders. */
|
|
13
|
+
readonly idByPath: ReadonlyMap<string, string>;
|
|
14
|
+
/** Map of slug (filename stem) → persona id, for in-content reference resolution. */
|
|
15
|
+
readonly idBySlug: ReadonlyMap<string, string>;
|
|
16
|
+
/** Map of normalised persona name → persona id, for in-content reference resolution. */
|
|
17
|
+
readonly idByName: ReadonlyMap<string, string>;
|
|
18
|
+
/** Map of persona id → list of feature slugs declared in `## Related Features`. */
|
|
19
|
+
readonly relatedFeaturesById: ReadonlyMap<string, readonly string[]>;
|
|
20
|
+
}
|
|
21
|
+
export declare function buildPersonas(inputs: PersonasBuildInputs): Promise<PersonasBuildResult>;
|
|
22
|
+
//# sourceMappingURL=personas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"personas.d.ts","sourceRoot":"","sources":["../../../../src/lib/catalogue/builders/personas.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,CAAC;IAC9B,mEAAmE;IACnE,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/C,qFAAqF;IACrF,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/C,wFAAwF;IACxF,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/C,mFAAmF;IACnF,QAAQ,CAAC,mBAAmB,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;CACtE;AAID,wBAAsB,aAAa,CACjC,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,mBAAmB,CAAC,CAwD9B"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// Personas discoverer — emits `personas.csv` rows from `personas/*.md`
|
|
2
|
+
// at the SDD root.
|
|
3
|
+
//
|
|
4
|
+
// Source convention (per docs/method/methods/persona-template.md):
|
|
5
|
+
// personas/<slug>.md
|
|
6
|
+
// ---
|
|
7
|
+
// # Persona: {Name}
|
|
8
|
+
// **App:** {app-name}
|
|
9
|
+
// ## Summary
|
|
10
|
+
// {1-2 sentences}
|
|
11
|
+
//
|
|
12
|
+
// Profile gating: personas are an application-product profile concept.
|
|
13
|
+
// Other profiles emit zero rows and skip the directory walk silently.
|
|
14
|
+
//
|
|
15
|
+
// id = `{product_id}-{slug}`, slug from filename stem.
|
|
16
|
+
// name = H1 (with the optional `Persona:` prefix stripped).
|
|
17
|
+
// description = first non-empty paragraph under `## Summary`.
|
|
18
|
+
// role = empty (template doesn't carry a single-token role today; the
|
|
19
|
+
// column stays available for ecosystems that want to populate it).
|
|
20
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
21
|
+
import { basename, join, relative } from "node:path";
|
|
22
|
+
const PERSONAS_DIR_REL = "personas";
|
|
23
|
+
export async function buildPersonas(inputs) {
|
|
24
|
+
const idByPath = new Map();
|
|
25
|
+
const idBySlug = new Map();
|
|
26
|
+
const idByName = new Map();
|
|
27
|
+
const relatedFeaturesById = new Map();
|
|
28
|
+
if (inputs.profile !== "application-product") {
|
|
29
|
+
return { rows: [], idByPath, idBySlug, idByName, relatedFeaturesById };
|
|
30
|
+
}
|
|
31
|
+
const dir = join(inputs.sddPath, PERSONAS_DIR_REL);
|
|
32
|
+
let entries;
|
|
33
|
+
try {
|
|
34
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
if (err.code !== "ENOENT")
|
|
38
|
+
throw err;
|
|
39
|
+
inputs.findings.add("coverage", `${PERSONAS_DIR_REL}/ not found — emitting empty personas.csv`);
|
|
40
|
+
return { rows: [], idByPath, idBySlug, idByName, relatedFeaturesById };
|
|
41
|
+
}
|
|
42
|
+
const files = entries
|
|
43
|
+
.filter((e) => e.isFile() && e.name.endsWith(".md") && !isTemplate(e.name))
|
|
44
|
+
.map((e) => e.name)
|
|
45
|
+
.sort();
|
|
46
|
+
const rows = [];
|
|
47
|
+
for (const filename of files) {
|
|
48
|
+
const slug = basename(filename).replace(/\.md$/i, "");
|
|
49
|
+
const id = `${inputs.productId}-${slug}`;
|
|
50
|
+
const absPath = join(dir, filename);
|
|
51
|
+
const relPath = relative(inputs.sddPath, absPath);
|
|
52
|
+
const text = await readFile(absPath, "utf-8");
|
|
53
|
+
const name = extractName(text) || titleCase(slug);
|
|
54
|
+
const description = extractSummary(text);
|
|
55
|
+
const relatedFeatures = extractRelatedFeatures(text);
|
|
56
|
+
rows.push({
|
|
57
|
+
id,
|
|
58
|
+
name,
|
|
59
|
+
product_id: inputs.productId,
|
|
60
|
+
role: "",
|
|
61
|
+
description,
|
|
62
|
+
source_sdd_id: "",
|
|
63
|
+
});
|
|
64
|
+
idByPath.set(relPath, id);
|
|
65
|
+
idBySlug.set(slug, id);
|
|
66
|
+
idByName.set(normaliseName(name), id);
|
|
67
|
+
relatedFeaturesById.set(id, relatedFeatures);
|
|
68
|
+
}
|
|
69
|
+
return { rows, idByPath, idBySlug, idByName, relatedFeaturesById };
|
|
70
|
+
}
|
|
71
|
+
function isTemplate(name) {
|
|
72
|
+
return /[{}]/.test(name) || name.toLowerCase().endsWith("-template.md");
|
|
73
|
+
}
|
|
74
|
+
function extractName(text) {
|
|
75
|
+
for (const raw of text.split(/\r?\n/)) {
|
|
76
|
+
const line = raw.trim();
|
|
77
|
+
if (line === "")
|
|
78
|
+
continue;
|
|
79
|
+
// Only the top-level H1 counts as a name. Skip non-heading lines and
|
|
80
|
+
// sub-headings (## ...).
|
|
81
|
+
const m = /^#\s+(.+)$/.exec(line);
|
|
82
|
+
if (!m)
|
|
83
|
+
return "";
|
|
84
|
+
const stripped = (m[1] ?? "").trim();
|
|
85
|
+
const personaPrefix = /^Persona:\s*(.+)$/i.exec(stripped);
|
|
86
|
+
return personaPrefix ? (personaPrefix[1] ?? "").trim() : stripped;
|
|
87
|
+
}
|
|
88
|
+
return "";
|
|
89
|
+
}
|
|
90
|
+
function extractSummary(text) {
|
|
91
|
+
const lines = text.split(/\r?\n/);
|
|
92
|
+
let i = 0;
|
|
93
|
+
// Find `## Summary` heading.
|
|
94
|
+
while (i < lines.length) {
|
|
95
|
+
if (/^##\s+summary\b/i.test(lines[i] ?? ""))
|
|
96
|
+
break;
|
|
97
|
+
i++;
|
|
98
|
+
}
|
|
99
|
+
if (i === lines.length)
|
|
100
|
+
return "";
|
|
101
|
+
i++;
|
|
102
|
+
// Skip blank lines.
|
|
103
|
+
while (i < lines.length && (lines[i] ?? "").trim() === "")
|
|
104
|
+
i++;
|
|
105
|
+
// Capture first non-empty paragraph until blank line.
|
|
106
|
+
const para = [];
|
|
107
|
+
while (i < lines.length) {
|
|
108
|
+
const line = lines[i] ?? "";
|
|
109
|
+
if (line.trim() === "")
|
|
110
|
+
break;
|
|
111
|
+
if (line.startsWith("#") || line.startsWith("---"))
|
|
112
|
+
break;
|
|
113
|
+
para.push(line.trim());
|
|
114
|
+
i++;
|
|
115
|
+
}
|
|
116
|
+
return para.join(" ").trim().slice(0, 500);
|
|
117
|
+
}
|
|
118
|
+
function extractRelatedFeatures(text) {
|
|
119
|
+
const lines = text.split(/\r?\n/);
|
|
120
|
+
let i = 0;
|
|
121
|
+
while (i < lines.length) {
|
|
122
|
+
if (/^##\s+related\s+features\b/i.test(lines[i] ?? ""))
|
|
123
|
+
break;
|
|
124
|
+
i++;
|
|
125
|
+
}
|
|
126
|
+
if (i === lines.length)
|
|
127
|
+
return [];
|
|
128
|
+
i++;
|
|
129
|
+
const out = [];
|
|
130
|
+
while (i < lines.length) {
|
|
131
|
+
const line = lines[i] ?? "";
|
|
132
|
+
if (line.startsWith("#") || line.startsWith("---"))
|
|
133
|
+
break;
|
|
134
|
+
const m = /^[-*]\s+`?([a-z0-9][a-z0-9-]*)`?(?:\s|$)/i.exec(line.trim());
|
|
135
|
+
if (m && m[1])
|
|
136
|
+
out.push(m[1].toLowerCase());
|
|
137
|
+
i++;
|
|
138
|
+
}
|
|
139
|
+
return out;
|
|
140
|
+
}
|
|
141
|
+
function normaliseName(name) {
|
|
142
|
+
return name.toLowerCase().replace(/\s+/g, " ").trim();
|
|
143
|
+
}
|
|
144
|
+
function titleCase(slug) {
|
|
145
|
+
return slug
|
|
146
|
+
.split("-")
|
|
147
|
+
.map((p) => (p.length === 0 ? p : p[0].toUpperCase() + p.slice(1)))
|
|
148
|
+
.join(" ");
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=personas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"personas.js","sourceRoot":"","sources":["../../../../src/lib/catalogue/builders/personas.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CatalogueRow } from "../csv-writer.js";
|
|
2
|
+
import type { FindingsLog } from "../findings.js";
|
|
3
|
+
import type { Profile } from "../manifest-loader.js";
|
|
4
|
+
export interface ProductEdgesInputs {
|
|
5
|
+
readonly sddPath: string;
|
|
6
|
+
readonly findings: FindingsLog;
|
|
7
|
+
readonly profile: Profile;
|
|
8
|
+
readonly productId: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ProductEdgesResult {
|
|
11
|
+
readonly productCapability: CatalogueRow[];
|
|
12
|
+
readonly productService: CatalogueRow[];
|
|
13
|
+
}
|
|
14
|
+
export declare function buildProductEdges(inputs: ProductEdgesInputs): Promise<ProductEdgesResult>;
|
|
15
|
+
//# sourceMappingURL=product-edges.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product-edges.d.ts","sourceRoot":"","sources":["../../../../src/lib/catalogue/builders/product-edges.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,iBAAiB,EAAE,YAAY,EAAE,CAAC;IAC3C,QAAQ,CAAC,cAAc,EAAE,YAAY,EAAE,CAAC;CACzC;AAgBD,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,kBAAkB,CAAC,CAuF7B"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Product-edge builders — emit:
|
|
2
|
+
// - product_capability (product depends on / consumes capability)
|
|
3
|
+
// - product_service (product depends on / consumes service)
|
|
4
|
+
//
|
|
5
|
+
// Source: `app-platform-dependencies.yaml` at the SDD root for
|
|
6
|
+
// application-product profile SDDs. Per the schema, both edges'
|
|
7
|
+
// referenced columns are external FKs (capability_id and service_id
|
|
8
|
+
// are owned by the platform-root SDD, not by the consuming app SDD).
|
|
9
|
+
// The per-SDD builder logs `[finding] external` for each unresolved
|
|
10
|
+
// reference; the aggregator validates after merge per ADR 0134 §4.3.
|
|
11
|
+
//
|
|
12
|
+
// Profile gating: only application-product SDDs read this file. Other
|
|
13
|
+
// profiles emit zero rows (no convention defined).
|
|
14
|
+
import { readFile } from "node:fs/promises";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
import { parse as parseYaml } from "yaml";
|
|
17
|
+
import { z } from "zod";
|
|
18
|
+
const REL_PATH = "app-platform-dependencies.yaml";
|
|
19
|
+
const DependencyEntrySchema = z.object({
|
|
20
|
+
capability_id: z.string().optional(),
|
|
21
|
+
service_id: z.string().optional(),
|
|
22
|
+
required_stability: z.string().optional(),
|
|
23
|
+
notes: z.string().optional(),
|
|
24
|
+
});
|
|
25
|
+
const FileSchema = z.object({
|
|
26
|
+
app_id: z.string().optional(),
|
|
27
|
+
platform_dependencies: z.array(DependencyEntrySchema).optional(),
|
|
28
|
+
});
|
|
29
|
+
export async function buildProductEdges(inputs) {
|
|
30
|
+
if (inputs.profile !== "application-product") {
|
|
31
|
+
return { productCapability: [], productService: [] };
|
|
32
|
+
}
|
|
33
|
+
const path = join(inputs.sddPath, REL_PATH);
|
|
34
|
+
let text;
|
|
35
|
+
try {
|
|
36
|
+
text = await readFile(path, "utf-8");
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
if (err.code !== "ENOENT")
|
|
40
|
+
throw err;
|
|
41
|
+
inputs.findings.add("coverage", `${REL_PATH} not found — emitting empty product_capability + product_service`);
|
|
42
|
+
return { productCapability: [], productService: [] };
|
|
43
|
+
}
|
|
44
|
+
let raw;
|
|
45
|
+
try {
|
|
46
|
+
raw = parseYaml(text);
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
inputs.findings.add("convention", `${REL_PATH}: failed to parse YAML — ${err.message}`);
|
|
50
|
+
return { productCapability: [], productService: [] };
|
|
51
|
+
}
|
|
52
|
+
const parsed = FileSchema.safeParse(raw);
|
|
53
|
+
if (!parsed.success) {
|
|
54
|
+
inputs.findings.add("convention", `${REL_PATH}: shape violation — ${parsed.error.issues.map((i) => i.path.join(".") + ": " + i.message).join("; ")}`);
|
|
55
|
+
return { productCapability: [], productService: [] };
|
|
56
|
+
}
|
|
57
|
+
const productCapability = [];
|
|
58
|
+
const productService = [];
|
|
59
|
+
const seenCap = new Set();
|
|
60
|
+
const seenSvc = new Set();
|
|
61
|
+
for (const dep of parsed.data.platform_dependencies ?? []) {
|
|
62
|
+
const capabilityId = (dep.capability_id ?? "").trim();
|
|
63
|
+
const serviceId = (dep.service_id ?? "").trim();
|
|
64
|
+
const requiredStability = (dep.required_stability ?? "").trim();
|
|
65
|
+
const notes = (dep.notes ?? "").trim();
|
|
66
|
+
if (capabilityId !== "") {
|
|
67
|
+
const id = `${inputs.productId}__${capabilityId}`;
|
|
68
|
+
if (!seenCap.has(id)) {
|
|
69
|
+
seenCap.add(id);
|
|
70
|
+
productCapability.push({
|
|
71
|
+
id,
|
|
72
|
+
product_id: inputs.productId,
|
|
73
|
+
capability_id: capabilityId,
|
|
74
|
+
role: "consumes",
|
|
75
|
+
notes,
|
|
76
|
+
});
|
|
77
|
+
inputs.findings.add("external", `product_capability: ${id} → capability_id="${capabilityId}" (external FK; aggregator validates)`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (serviceId !== "") {
|
|
81
|
+
const id = `${inputs.productId}__${serviceId}`;
|
|
82
|
+
if (!seenSvc.has(id)) {
|
|
83
|
+
seenSvc.add(id);
|
|
84
|
+
productService.push({
|
|
85
|
+
id,
|
|
86
|
+
product_id: inputs.productId,
|
|
87
|
+
service_id: serviceId,
|
|
88
|
+
role: "consumes",
|
|
89
|
+
required_stability: requiredStability,
|
|
90
|
+
});
|
|
91
|
+
inputs.findings.add("external", `product_service: ${id} → service_id="${serviceId}" (external FK; aggregator validates)`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return { productCapability, productService };
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=product-edges.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product-edges.js","sourceRoot":"","sources":["../../../../src/lib/catalogue/builders/product-edges.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Products discoverer — emits the SDD-as-Product row from the manifest.
|
|
3
|
+
*
|
|
4
|
+
* Per ADR 0134 + catalogue-metamodel.md: every SDD is one Product. The
|
|
5
|
+
* canonical builder emits ONE products.csv row per SDD — the SDD itself.
|
|
6
|
+
* Sibling SDDs (apps, integrations) get their own products.csv rows in
|
|
7
|
+
* their own builds; the aggregator merges by primary key.
|
|
8
|
+
*
|
|
9
|
+
* domain_id selection (per ADR 0136):
|
|
10
|
+
* - manifest.domainId when declared,
|
|
11
|
+
* - else a sensible default for platform-profile categories (where a
|
|
12
|
+
* real `platform` domain exists locally),
|
|
13
|
+
* - else empty (app and integration products do not have a primary
|
|
14
|
+
* domain — they are federation nodes that consume capabilities
|
|
15
|
+
* across multiple domains via product_capability).
|
|
16
|
+
*/
|
|
17
|
+
import type { CatalogueRow } from "../csv-writer.js";
|
|
18
|
+
import type { FindingsLog } from "../findings.js";
|
|
19
|
+
import type { SddManifest } from "../manifest-loader.js";
|
|
20
|
+
export interface ProductsBuildInputs {
|
|
21
|
+
readonly manifest: SddManifest;
|
|
22
|
+
readonly repoCount: number;
|
|
23
|
+
readonly findings: FindingsLog;
|
|
24
|
+
}
|
|
25
|
+
export declare function buildProducts(inputs: ProductsBuildInputs): CatalogueRow[];
|
|
26
|
+
//# sourceMappingURL=products.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"products.d.ts","sourceRoot":"","sources":["../../../../src/lib/catalogue/builders/products.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAY,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEnE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;CAChC;AAYD,wBAAgB,aAAa,CAC3B,MAAM,EAAE,mBAAmB,GAC1B,YAAY,EAAE,CA6BhB"}
|