@contractspec/module.workspace 0.0.0-canary-20260113162409
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/LICENSE +21 -0
- package/README.md +50 -0
- package/dist/ai/prompts/code-generation.d.ts +24 -0
- package/dist/ai/prompts/code-generation.d.ts.map +1 -0
- package/dist/ai/prompts/code-generation.js +134 -0
- package/dist/ai/prompts/code-generation.js.map +1 -0
- package/dist/ai/prompts/spec-creation.d.ts +28 -0
- package/dist/ai/prompts/spec-creation.d.ts.map +1 -0
- package/dist/ai/prompts/spec-creation.js +102 -0
- package/dist/ai/prompts/spec-creation.js.map +1 -0
- package/dist/analysis/deps/graph.d.ts +34 -0
- package/dist/analysis/deps/graph.d.ts.map +1 -0
- package/dist/analysis/deps/graph.js +85 -0
- package/dist/analysis/deps/graph.js.map +1 -0
- package/dist/analysis/deps/parse-imports.d.ts +17 -0
- package/dist/analysis/deps/parse-imports.d.ts.map +1 -0
- package/dist/analysis/deps/parse-imports.js +31 -0
- package/dist/analysis/deps/parse-imports.js.map +1 -0
- package/dist/analysis/diff/deep-diff.d.ts +33 -0
- package/dist/analysis/diff/deep-diff.d.ts.map +1 -0
- package/dist/analysis/diff/deep-diff.js +114 -0
- package/dist/analysis/diff/deep-diff.js.map +1 -0
- package/dist/analysis/diff/semantic.d.ts +11 -0
- package/dist/analysis/diff/semantic.d.ts.map +1 -0
- package/dist/analysis/diff/semantic.js +97 -0
- package/dist/analysis/diff/semantic.js.map +1 -0
- package/dist/analysis/example-scan.d.ts +15 -0
- package/dist/analysis/example-scan.d.ts.map +1 -0
- package/dist/analysis/example-scan.js +116 -0
- package/dist/analysis/example-scan.js.map +1 -0
- package/dist/analysis/feature-extractor.js +203 -0
- package/dist/analysis/feature-extractor.js.map +1 -0
- package/dist/analysis/feature-scan.d.ts +15 -0
- package/dist/analysis/feature-scan.d.ts.map +1 -0
- package/dist/analysis/feature-scan.js +56 -0
- package/dist/analysis/feature-scan.js.map +1 -0
- package/dist/analysis/grouping.d.ts +79 -0
- package/dist/analysis/grouping.d.ts.map +1 -0
- package/dist/analysis/grouping.js +115 -0
- package/dist/analysis/grouping.js.map +1 -0
- package/dist/analysis/impact/classifier.d.ts +19 -0
- package/dist/analysis/impact/classifier.d.ts.map +1 -0
- package/dist/analysis/impact/classifier.js +135 -0
- package/dist/analysis/impact/classifier.js.map +1 -0
- package/dist/analysis/impact/index.js +2 -0
- package/dist/analysis/impact/rules.d.ts +35 -0
- package/dist/analysis/impact/rules.d.ts.map +1 -0
- package/dist/analysis/impact/rules.js +154 -0
- package/dist/analysis/impact/rules.js.map +1 -0
- package/dist/analysis/impact/types.d.ts +95 -0
- package/dist/analysis/impact/types.d.ts.map +1 -0
- package/dist/analysis/index.js +18 -0
- package/dist/analysis/snapshot/index.js +2 -0
- package/dist/analysis/snapshot/normalizer.d.ts +36 -0
- package/dist/analysis/snapshot/normalizer.d.ts.map +1 -0
- package/dist/analysis/snapshot/normalizer.js +67 -0
- package/dist/analysis/snapshot/normalizer.js.map +1 -0
- package/dist/analysis/snapshot/snapshot.d.ts +18 -0
- package/dist/analysis/snapshot/snapshot.d.ts.map +1 -0
- package/dist/analysis/snapshot/snapshot.js +163 -0
- package/dist/analysis/snapshot/snapshot.js.map +1 -0
- package/dist/analysis/snapshot/types.d.ts +74 -0
- package/dist/analysis/snapshot/types.d.ts.map +1 -0
- package/dist/analysis/spec-parser.d.ts +11 -0
- package/dist/analysis/spec-parser.d.ts.map +1 -0
- package/dist/analysis/spec-parser.js +89 -0
- package/dist/analysis/spec-parser.js.map +1 -0
- package/dist/analysis/spec-parsing-utils.d.ts +26 -0
- package/dist/analysis/spec-parsing-utils.d.ts.map +1 -0
- package/dist/analysis/spec-parsing-utils.js +98 -0
- package/dist/analysis/spec-parsing-utils.js.map +1 -0
- package/dist/analysis/spec-scan.d.ts +20 -0
- package/dist/analysis/spec-scan.d.ts.map +1 -0
- package/dist/analysis/spec-scan.js +141 -0
- package/dist/analysis/spec-scan.js.map +1 -0
- package/dist/analysis/utils/matchers.js +77 -0
- package/dist/analysis/utils/matchers.js.map +1 -0
- package/dist/analysis/utils/variables.js +45 -0
- package/dist/analysis/utils/variables.js.map +1 -0
- package/dist/analysis/validate/index.js +1 -0
- package/dist/analysis/validate/spec-structure.d.ts +29 -0
- package/dist/analysis/validate/spec-structure.d.ts.map +1 -0
- package/dist/analysis/validate/spec-structure.js +455 -0
- package/dist/analysis/validate/spec-structure.js.map +1 -0
- package/dist/formatter.d.ts +42 -0
- package/dist/formatter.d.ts.map +1 -0
- package/dist/formatter.js +163 -0
- package/dist/formatter.js.map +1 -0
- package/dist/formatters/index.js +2 -0
- package/dist/formatters/spec-markdown.d.ts +31 -0
- package/dist/formatters/spec-markdown.d.ts.map +1 -0
- package/dist/formatters/spec-markdown.js +263 -0
- package/dist/formatters/spec-markdown.js.map +1 -0
- package/dist/formatters/spec-to-docblock.d.ts +14 -0
- package/dist/formatters/spec-to-docblock.d.ts.map +1 -0
- package/dist/formatters/spec-to-docblock.js +48 -0
- package/dist/formatters/spec-to-docblock.js.map +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +39 -0
- package/dist/templates/app-config.d.ts +7 -0
- package/dist/templates/app-config.d.ts.map +1 -0
- package/dist/templates/app-config.js +107 -0
- package/dist/templates/app-config.js.map +1 -0
- package/dist/templates/data-view.d.ts +7 -0
- package/dist/templates/data-view.d.ts.map +1 -0
- package/dist/templates/data-view.js +69 -0
- package/dist/templates/data-view.js.map +1 -0
- package/dist/templates/event.d.ts +11 -0
- package/dist/templates/event.d.ts.map +1 -0
- package/dist/templates/event.js +41 -0
- package/dist/templates/event.js.map +1 -0
- package/dist/templates/experiment.d.ts +7 -0
- package/dist/templates/experiment.d.ts.map +1 -0
- package/dist/templates/experiment.js +88 -0
- package/dist/templates/experiment.js.map +1 -0
- package/dist/templates/handler.d.ts +20 -0
- package/dist/templates/handler.d.ts.map +1 -0
- package/dist/templates/handler.js +96 -0
- package/dist/templates/handler.js.map +1 -0
- package/dist/templates/integration-utils.js +105 -0
- package/dist/templates/integration-utils.js.map +1 -0
- package/dist/templates/integration.d.ts +7 -0
- package/dist/templates/integration.d.ts.map +1 -0
- package/dist/templates/integration.js +62 -0
- package/dist/templates/integration.js.map +1 -0
- package/dist/templates/knowledge.d.ts +7 -0
- package/dist/templates/knowledge.d.ts.map +1 -0
- package/dist/templates/knowledge.js +69 -0
- package/dist/templates/knowledge.js.map +1 -0
- package/dist/templates/migration.d.ts +7 -0
- package/dist/templates/migration.d.ts.map +1 -0
- package/dist/templates/migration.js +61 -0
- package/dist/templates/migration.js.map +1 -0
- package/dist/templates/operation.d.ts +11 -0
- package/dist/templates/operation.d.ts.map +1 -0
- package/dist/templates/operation.js +101 -0
- package/dist/templates/operation.js.map +1 -0
- package/dist/templates/presentation.d.ts +11 -0
- package/dist/templates/presentation.d.ts.map +1 -0
- package/dist/templates/presentation.js +79 -0
- package/dist/templates/presentation.js.map +1 -0
- package/dist/templates/telemetry.d.ts +7 -0
- package/dist/templates/telemetry.d.ts.map +1 -0
- package/dist/templates/telemetry.js +90 -0
- package/dist/templates/telemetry.js.map +1 -0
- package/dist/templates/utils.d.ts +27 -0
- package/dist/templates/utils.d.ts.map +1 -0
- package/dist/templates/utils.js +39 -0
- package/dist/templates/utils.js.map +1 -0
- package/dist/templates/workflow-runner.d.ts +16 -0
- package/dist/templates/workflow-runner.d.ts.map +1 -0
- package/dist/templates/workflow-runner.js +49 -0
- package/dist/templates/workflow-runner.js.map +1 -0
- package/dist/templates/workflow.d.ts +11 -0
- package/dist/templates/workflow.d.ts.map +1 -0
- package/dist/templates/workflow.js +68 -0
- package/dist/templates/workflow.js.map +1 -0
- package/dist/types/analysis-types.d.ts +199 -0
- package/dist/types/analysis-types.d.ts.map +1 -0
- package/dist/types/generation-types.d.ts +87 -0
- package/dist/types/generation-types.d.ts.map +1 -0
- package/dist/types/generation-types.js +21 -0
- package/dist/types/generation-types.js.map +1 -0
- package/dist/types/llm-types.d.ts +138 -0
- package/dist/types/llm-types.d.ts.map +1 -0
- package/dist/types/rulesync-types.d.ts +24 -0
- package/dist/types/rulesync-types.d.ts.map +1 -0
- package/dist/types/spec-types.d.ts +343 -0
- package/dist/types/spec-types.d.ts.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { toPascalCase } from "./utils.js";
|
|
2
|
+
|
|
3
|
+
//#region src/templates/presentation.ts
|
|
4
|
+
/**
|
|
5
|
+
* Generate presentation spec TypeScript code.
|
|
6
|
+
*/
|
|
7
|
+
function generatePresentationSpec(data) {
|
|
8
|
+
const { name, version, description, stability, owners, tags, presentationKind } = data;
|
|
9
|
+
const varName = toPascalCase(name.replace(/\./g, "_")) + "Presentation";
|
|
10
|
+
let contentBlock = "";
|
|
11
|
+
switch (presentationKind) {
|
|
12
|
+
case "web_component":
|
|
13
|
+
contentBlock = ` content: {
|
|
14
|
+
kind: 'web_component',
|
|
15
|
+
framework: 'react',
|
|
16
|
+
componentKey: '${name.replace(/\./g, "_")}',
|
|
17
|
+
props: new SchemaModel({
|
|
18
|
+
name: '${varName}Props',
|
|
19
|
+
description: 'Props for ${name}',
|
|
20
|
+
fields: {
|
|
21
|
+
// TODO: Define component props
|
|
22
|
+
},
|
|
23
|
+
}),
|
|
24
|
+
analytics: [
|
|
25
|
+
// TODO: Define analytics events
|
|
26
|
+
],
|
|
27
|
+
},`;
|
|
28
|
+
break;
|
|
29
|
+
case "markdown":
|
|
30
|
+
contentBlock = ` content: {
|
|
31
|
+
kind: 'markdown',
|
|
32
|
+
content: \`
|
|
33
|
+
# ${description}
|
|
34
|
+
|
|
35
|
+
TODO: Add markdown content here
|
|
36
|
+
\`,
|
|
37
|
+
// Or use resourceUri: 'feature://${name}/guide.md'
|
|
38
|
+
},`;
|
|
39
|
+
break;
|
|
40
|
+
case "data":
|
|
41
|
+
contentBlock = ` content: {
|
|
42
|
+
kind: 'data',
|
|
43
|
+
mimeType: 'application/json',
|
|
44
|
+
model: new SchemaModel({
|
|
45
|
+
name: '${varName}Data',
|
|
46
|
+
description: 'Data structure for ${name}',
|
|
47
|
+
fields: {
|
|
48
|
+
// TODO: Define data structure
|
|
49
|
+
},
|
|
50
|
+
}),
|
|
51
|
+
},`;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
return `import type { PresentationSpec } from '@contractspec/lib.contracts/presentations';
|
|
55
|
+
import { SchemaModel, ScalarTypeEnum } from '@contractspec/lib.schema';
|
|
56
|
+
|
|
57
|
+
export const ${varName}: PresentationSpec = {
|
|
58
|
+
meta: {
|
|
59
|
+
key: '${name}',
|
|
60
|
+
version: ${version},
|
|
61
|
+
stability: '${stability}',
|
|
62
|
+
owners: [${owners.map((o) => `'${o}'`).join(", ")}],
|
|
63
|
+
tags: [${tags.map((t) => `'${t}'`).join(", ")}],
|
|
64
|
+
description: '${description}',
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
policy: {
|
|
68
|
+
// flags: [],
|
|
69
|
+
// pii: [],
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
${contentBlock}
|
|
73
|
+
};
|
|
74
|
+
`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
//#endregion
|
|
78
|
+
export { generatePresentationSpec };
|
|
79
|
+
//# sourceMappingURL=presentation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentation.js","names":[],"sources":["../../src/templates/presentation.ts"],"sourcesContent":["/**\n * Presentation spec template generation.\n * Extracted from cli-contractspec/src/templates/presentation.template.ts\n */\n\nimport type { PresentationSpecData } from '../types/spec-types';\nimport { toPascalCase } from './utils';\n\n/**\n * Generate presentation spec TypeScript code.\n */\nexport function generatePresentationSpec(data: PresentationSpecData): string {\n const {\n name,\n version,\n description,\n stability,\n owners,\n tags,\n presentationKind,\n } = data;\n\n const varName = toPascalCase(name.replace(/\\./g, '_')) + 'Presentation';\n\n let contentBlock = '';\n\n switch (presentationKind) {\n case 'web_component':\n contentBlock = ` content: {\n kind: 'web_component',\n framework: 'react',\n componentKey: '${name.replace(/\\./g, '_')}',\n props: new SchemaModel({\n name: '${varName}Props',\n description: 'Props for ${name}',\n fields: {\n // TODO: Define component props\n },\n }),\n analytics: [\n // TODO: Define analytics events\n ],\n },`;\n break;\n\n case 'markdown':\n contentBlock = ` content: {\n kind: 'markdown',\n content: \\`\n# ${description}\n\nTODO: Add markdown content here\n \\`,\n // Or use resourceUri: 'feature://${name}/guide.md'\n },`;\n break;\n\n case 'data':\n contentBlock = ` content: {\n kind: 'data',\n mimeType: 'application/json',\n model: new SchemaModel({\n name: '${varName}Data',\n description: 'Data structure for ${name}',\n fields: {\n // TODO: Define data structure\n },\n }),\n },`;\n break;\n }\n\n return `import type { PresentationSpec } from '@contractspec/lib.contracts/presentations';\nimport { SchemaModel, ScalarTypeEnum } from '@contractspec/lib.schema';\n\nexport const ${varName}: PresentationSpec = {\n meta: {\n key: '${name}',\n version: ${version},\n stability: '${stability}',\n owners: [${owners.map((o) => `'${o}'`).join(', ')}],\n tags: [${tags.map((t) => `'${t}'`).join(', ')}],\n description: '${description}',\n },\n \n policy: {\n // flags: [],\n // pii: [],\n },\n \n${contentBlock}\n};\n`;\n}\n"],"mappings":";;;;;;AAWA,SAAgB,yBAAyB,MAAoC;CAC3E,MAAM,EACJ,MACA,SACA,aACA,WACA,QACA,MACA,qBACE;CAEJ,MAAM,UAAU,aAAa,KAAK,QAAQ,OAAO,IAAI,CAAC,GAAG;CAEzD,IAAI,eAAe;AAEnB,SAAQ,kBAAR;EACE,KAAK;AACH,kBAAe;;;qBAGA,KAAK,QAAQ,OAAO,IAAI,CAAC;;eAE/B,QAAQ;gCACS,KAAK;;;;;;;;;AAS/B;EAEF,KAAK;AACH,kBAAe;;;IAGjB,YAAY;;;;wCAIwB,KAAK;;AAEvC;EAEF,KAAK;AACH,kBAAe;;;;eAIN,QAAQ;yCACkB,KAAK;;;;;;AAMxC;;AAGJ,QAAO;;;eAGM,QAAQ;;YAEX,KAAK;eACF,QAAQ;kBACL,UAAU;eACb,OAAO,KAAK,MAAM,IAAI,EAAE,GAAG,CAAC,KAAK,KAAK,CAAC;aACzC,KAAK,KAAK,MAAM,IAAI,EAAE,GAAG,CAAC,KAAK,KAAK,CAAC;oBAC9B,YAAY;;;;;;;;EAQ9B,aAAa"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { TelemetrySpecData } from "../types/spec-types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/templates/telemetry.d.ts
|
|
4
|
+
declare function generateTelemetrySpec(data: TelemetrySpecData): string;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { generateTelemetrySpec };
|
|
7
|
+
//# sourceMappingURL=telemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.d.ts","names":[],"sources":["../../src/templates/telemetry.ts"],"sourcesContent":[],"mappings":";;;iBAGgB,qBAAA,OAA4B"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { toPascalCase } from "./utils.js";
|
|
2
|
+
|
|
3
|
+
//#region src/templates/telemetry.ts
|
|
4
|
+
function generateTelemetrySpec(data) {
|
|
5
|
+
const specVar = toPascalCase(data.name.split(".").pop() ?? "Telemetry") + "Telemetry";
|
|
6
|
+
const providers = data.providers?.length ? `providers: [
|
|
7
|
+
${data.providers.map((provider) => ` {
|
|
8
|
+
type: '${provider.type}',
|
|
9
|
+
config: ${formatConfigValue(provider.config)},
|
|
10
|
+
}`).join(",\n")}
|
|
11
|
+
],` : "";
|
|
12
|
+
const events = data.events.map((event) => {
|
|
13
|
+
const properties = event.properties.map((prop) => ` '${prop.name}': {
|
|
14
|
+
type: '${prop.type}',
|
|
15
|
+
${prop.required ? "required: true," : ""}
|
|
16
|
+
${prop.pii ? "pii: true," : ""}
|
|
17
|
+
${prop.redact ? "redact: true," : ""}
|
|
18
|
+
${prop.description ? `description: '${escapeString(prop.description)}',` : ""}
|
|
19
|
+
}`).join(",\n");
|
|
20
|
+
const anomalyRules = event.anomalyRules?.length ? ` anomalyDetection: {
|
|
21
|
+
enabled: true,
|
|
22
|
+
${typeof event.anomalyMinimumSample === "number" ? `minimumSample: ${event.anomalyMinimumSample},` : ""}
|
|
23
|
+
thresholds: [
|
|
24
|
+
${event.anomalyRules.map((rule) => ` {
|
|
25
|
+
metric: '${escapeString(rule.metric)}',
|
|
26
|
+
${typeof rule.min === "number" ? `min: ${rule.min},` : ""}
|
|
27
|
+
${typeof rule.max === "number" ? `max: ${rule.max},` : ""}
|
|
28
|
+
}`).join(",\n")}
|
|
29
|
+
],
|
|
30
|
+
actions: [${(event.anomalyActions ?? []).map((action) => `'${action}'`).join(", ")}],
|
|
31
|
+
},` : event.anomalyEnabled ? ` anomalyDetection: {
|
|
32
|
+
enabled: true,
|
|
33
|
+
${typeof event.anomalyMinimumSample === "number" ? `minimumSample: ${event.anomalyMinimumSample},` : ""}
|
|
34
|
+
},` : "";
|
|
35
|
+
return ` {
|
|
36
|
+
name: '${escapeString(event.name)}',
|
|
37
|
+
version: ${event.version},
|
|
38
|
+
semantics: {
|
|
39
|
+
what: '${escapeString(event.what)}',
|
|
40
|
+
${event.who ? `who: '${escapeString(event.who)}',` : ""}
|
|
41
|
+
${event.why ? `why: '${escapeString(event.why)}',` : ""}
|
|
42
|
+
},
|
|
43
|
+
privacy: '${event.privacy}',
|
|
44
|
+
properties: {
|
|
45
|
+
${properties}
|
|
46
|
+
},
|
|
47
|
+
${typeof event.retentionDays === "number" ? `retention: { days: ${event.retentionDays}, ${event.retentionPolicy ? `policy: '${event.retentionPolicy}'` : ""} },` : ""}
|
|
48
|
+
${typeof event.samplingRate === "number" ? `sampling: { rate: ${event.samplingRate}${event.samplingConditions ? `, conditions: ['${escapeString(event.samplingConditions)}']` : ""} },` : ""}
|
|
49
|
+
${anomalyRules}
|
|
50
|
+
${event.tags?.length ? `tags: [${event.tags.map((tag) => `'${escapeString(tag)}'`).join(", ")}],` : ""}
|
|
51
|
+
}`;
|
|
52
|
+
}).join(",\n");
|
|
53
|
+
return `import type { TelemetrySpec } from '@contractspec/lib.contracts/telemetry';
|
|
54
|
+
|
|
55
|
+
export const ${specVar}: TelemetrySpec = {
|
|
56
|
+
meta: {
|
|
57
|
+
key: '${escapeString(data.name)}',
|
|
58
|
+
version: ${data.version},
|
|
59
|
+
title: '${escapeString(data.name)} telemetry',
|
|
60
|
+
description: '${escapeString(data.description || "Describe the purpose of this telemetry spec.")}',
|
|
61
|
+
domain: '${escapeString(data.domain)}',
|
|
62
|
+
owners: [${data.owners.map((owner) => `'${escapeString(owner)}'`).join(", ")}],
|
|
63
|
+
tags: [${data.tags.map((tag) => `'${escapeString(tag)}'`).join(", ")}],
|
|
64
|
+
stability: '${data.stability}',
|
|
65
|
+
},
|
|
66
|
+
config: {
|
|
67
|
+
${typeof data.defaultRetentionDays === "number" ? `defaultRetentionDays: ${data.defaultRetentionDays},` : ""}
|
|
68
|
+
${typeof data.defaultSamplingRate === "number" ? `defaultSamplingRate: ${data.defaultSamplingRate},` : ""}
|
|
69
|
+
${data.anomalyEnabled ? `anomalyDetection: { enabled: true${typeof data.anomalyCheckIntervalMs === "number" ? `, checkIntervalMs: ${data.anomalyCheckIntervalMs}` : ""} },` : ""}
|
|
70
|
+
${providers}
|
|
71
|
+
},
|
|
72
|
+
events: [
|
|
73
|
+
${events}
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
`;
|
|
77
|
+
}
|
|
78
|
+
function escapeString(value) {
|
|
79
|
+
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
80
|
+
}
|
|
81
|
+
function formatConfigValue(value) {
|
|
82
|
+
const trimmed = value.trim();
|
|
83
|
+
if (!trimmed) return "{}";
|
|
84
|
+
if (trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]")) return trimmed;
|
|
85
|
+
return `'${escapeString(trimmed)}'`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
//#endregion
|
|
89
|
+
export { generateTelemetrySpec };
|
|
90
|
+
//# sourceMappingURL=telemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.js","names":[],"sources":["../../src/templates/telemetry.ts"],"sourcesContent":["import type { TelemetrySpecData } from '../types/spec-types';\nimport { toPascalCase } from './utils';\n\nexport function generateTelemetrySpec(data: TelemetrySpecData): string {\n const specVar =\n toPascalCase(data.name.split('.').pop() ?? 'Telemetry') + 'Telemetry';\n\n const providers = data.providers?.length\n ? `providers: [\n${data.providers\n .map(\n (provider) => ` {\n type: '${provider.type}',\n config: ${formatConfigValue(provider.config)},\n }`\n )\n .join(',\\n')}\n ],`\n : '';\n\n const events = data.events\n .map((event) => {\n const properties = event.properties\n .map(\n (prop) => ` '${prop.name}': {\n type: '${prop.type}',\n ${prop.required ? 'required: true,' : ''}\n ${prop.pii ? 'pii: true,' : ''}\n ${prop.redact ? 'redact: true,' : ''}\n ${\n prop.description\n ? `description: '${escapeString(prop.description)}',`\n : ''\n }\n }`\n )\n .join(',\\n');\n\n const anomalyRules = event.anomalyRules?.length\n ? ` anomalyDetection: {\n enabled: true,\n ${typeof event.anomalyMinimumSample === 'number' ? `minimumSample: ${event.anomalyMinimumSample},` : ''}\n thresholds: [\n${event.anomalyRules\n .map(\n (rule) => ` {\n metric: '${escapeString(rule.metric)}',\n ${typeof rule.min === 'number' ? `min: ${rule.min},` : ''}\n ${typeof rule.max === 'number' ? `max: ${rule.max},` : ''}\n }`\n )\n .join(',\\n')}\n ],\n actions: [${(event.anomalyActions ?? [])\n .map((action) => `'${action}'`)\n .join(', ')}],\n },`\n : event.anomalyEnabled\n ? ` anomalyDetection: {\n enabled: true,\n ${typeof event.anomalyMinimumSample === 'number' ? `minimumSample: ${event.anomalyMinimumSample},` : ''}\n },`\n : '';\n\n return ` {\n name: '${escapeString(event.name)}',\n version: ${event.version},\n semantics: {\n what: '${escapeString(event.what)}',\n ${event.who ? `who: '${escapeString(event.who)}',` : ''}\n ${event.why ? `why: '${escapeString(event.why)}',` : ''}\n },\n privacy: '${event.privacy}',\n properties: {\n${properties}\n },\n ${\n typeof event.retentionDays === 'number'\n ? `retention: { days: ${event.retentionDays}, ${\n event.retentionPolicy ? `policy: '${event.retentionPolicy}'` : ''\n } },`\n : ''\n }\n ${\n typeof event.samplingRate === 'number'\n ? `sampling: { rate: ${event.samplingRate}${\n event.samplingConditions\n ? `, conditions: ['${escapeString(event.samplingConditions)}']`\n : ''\n } },`\n : ''\n }\n${anomalyRules}\n ${event.tags?.length ? `tags: [${event.tags.map((tag) => `'${escapeString(tag)}'`).join(', ')}],` : ''}\n }`;\n })\n .join(',\\n');\n\n return `import type { TelemetrySpec } from '@contractspec/lib.contracts/telemetry';\n\nexport const ${specVar}: TelemetrySpec = {\n meta: {\n key: '${escapeString(data.name)}',\n version: ${data.version},\n title: '${escapeString(data.name)} telemetry',\n description: '${escapeString(\n data.description || 'Describe the purpose of this telemetry spec.'\n )}',\n domain: '${escapeString(data.domain)}',\n owners: [${data.owners.map((owner) => `'${escapeString(owner)}'`).join(', ')}],\n tags: [${data.tags.map((tag) => `'${escapeString(tag)}'`).join(', ')}],\n stability: '${data.stability}',\n },\n config: {\n ${typeof data.defaultRetentionDays === 'number' ? `defaultRetentionDays: ${data.defaultRetentionDays},` : ''}\n ${typeof data.defaultSamplingRate === 'number' ? `defaultSamplingRate: ${data.defaultSamplingRate},` : ''}\n ${data.anomalyEnabled ? `anomalyDetection: { enabled: true${typeof data.anomalyCheckIntervalMs === 'number' ? `, checkIntervalMs: ${data.anomalyCheckIntervalMs}` : ''} },` : ''}\n${providers}\n },\n events: [\n${events}\n ],\n};\n`;\n}\n\nfunction escapeString(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\nfunction formatConfigValue(value: string): string {\n const trimmed = value.trim();\n if (!trimmed) return '{}';\n if (\n (trimmed.startsWith('{') && trimmed.endsWith('}')) ||\n (trimmed.startsWith('[') && trimmed.endsWith(']'))\n ) {\n return trimmed;\n }\n return `'${escapeString(trimmed)}'`;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/templates/utils.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Utility functions for template generation.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Convert string to camelCase.
|
|
7
|
+
*/
|
|
8
|
+
declare function toCamelCase(str: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Convert string to PascalCase.
|
|
11
|
+
*/
|
|
12
|
+
declare function toPascalCase(str: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Convert string to kebab-case.
|
|
15
|
+
*/
|
|
16
|
+
declare function toKebabCase(str: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Capitalize first letter.
|
|
19
|
+
*/
|
|
20
|
+
declare function capitalize(str: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Escape single quotes in string.
|
|
23
|
+
*/
|
|
24
|
+
declare function escapeString(value: string): string;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { capitalize, escapeString, toCamelCase, toKebabCase, toPascalCase };
|
|
27
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","names":[],"sources":["../../src/templates/utils.ts"],"sourcesContent":[],"mappings":";;AAOA;AAQA;AAUA;AAUA;AAOA;iBAnCgB,WAAA;;;;iBAQA,YAAA;;;;iBAUA,WAAA;;;;iBAUA,UAAA;;;;iBAOA,YAAA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//#region src/templates/utils.ts
|
|
2
|
+
/**
|
|
3
|
+
* Utility functions for template generation.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Convert string to camelCase.
|
|
7
|
+
*/
|
|
8
|
+
function toCamelCase(str) {
|
|
9
|
+
const pascal = toPascalCase(str);
|
|
10
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Convert string to PascalCase.
|
|
14
|
+
*/
|
|
15
|
+
function toPascalCase(str) {
|
|
16
|
+
return str.split(/[-_.]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Convert string to kebab-case.
|
|
20
|
+
*/
|
|
21
|
+
function toKebabCase(str) {
|
|
22
|
+
return str.replace(/\./g, "-").replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Capitalize first letter.
|
|
26
|
+
*/
|
|
27
|
+
function capitalize(str) {
|
|
28
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Escape single quotes in string.
|
|
32
|
+
*/
|
|
33
|
+
function escapeString(value) {
|
|
34
|
+
return value.replace(/'/g, "\\'");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
export { capitalize, escapeString, toCamelCase, toKebabCase, toPascalCase };
|
|
39
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","names":[],"sources":["../../src/templates/utils.ts"],"sourcesContent":["/**\n * Utility functions for template generation.\n */\n\n/**\n * Convert string to camelCase.\n */\nexport function toCamelCase(str: string): string {\n const pascal = toPascalCase(str);\n return pascal.charAt(0).toLowerCase() + pascal.slice(1);\n}\n\n/**\n * Convert string to PascalCase.\n */\nexport function toPascalCase(str: string): string {\n return str\n .split(/[-_.]/)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join('');\n}\n\n/**\n * Convert string to kebab-case.\n */\nexport function toKebabCase(str: string): string {\n return str\n .replace(/\\./g, '-')\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .toLowerCase();\n}\n\n/**\n * Capitalize first letter.\n */\nexport function capitalize(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\n/**\n * Escape single quotes in string.\n */\nexport function escapeString(value: string): string {\n return value.replace(/'/g, \"\\\\'\");\n}\n"],"mappings":";;;;;;;AAOA,SAAgB,YAAY,KAAqB;CAC/C,MAAM,SAAS,aAAa,IAAI;AAChC,QAAO,OAAO,OAAO,EAAE,CAAC,aAAa,GAAG,OAAO,MAAM,EAAE;;;;;AAMzD,SAAgB,aAAa,KAAqB;AAChD,QAAO,IACJ,MAAM,QAAQ,CACd,KAAK,SAAS,KAAK,OAAO,EAAE,CAAC,aAAa,GAAG,KAAK,MAAM,EAAE,CAAC,CAC3D,KAAK,GAAG;;;;;AAMb,SAAgB,YAAY,KAAqB;AAC/C,QAAO,IACJ,QAAQ,OAAO,IAAI,CACnB,QAAQ,mBAAmB,QAAQ,CACnC,aAAa;;;;;AAMlB,SAAgB,WAAW,KAAqB;AAC9C,QAAO,IAAI,OAAO,EAAE,CAAC,aAAa,GAAG,IAAI,MAAM,EAAE;;;;;AAMnD,SAAgB,aAAa,OAAuB;AAClD,QAAO,MAAM,QAAQ,MAAM,MAAM"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/templates/workflow-runner.d.ts
|
|
2
|
+
interface RunnerTemplateOptions {
|
|
3
|
+
exportName: string;
|
|
4
|
+
specImportPath: string;
|
|
5
|
+
runnerName: string;
|
|
6
|
+
workflowName: string;
|
|
7
|
+
}
|
|
8
|
+
declare function generateWorkflowRunnerTemplate({
|
|
9
|
+
exportName,
|
|
10
|
+
specImportPath,
|
|
11
|
+
runnerName,
|
|
12
|
+
workflowName
|
|
13
|
+
}: RunnerTemplateOptions): string;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { generateWorkflowRunnerTemplate };
|
|
16
|
+
//# sourceMappingURL=workflow-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-runner.d.ts","names":[],"sources":["../../src/templates/workflow-runner.ts"],"sourcesContent":[],"mappings":";UAAU,qBAAA;EAAA,UAAA,EAAA,MAAA;EAOM,cAAA,EAAA,MAAA;EACd,UAAA,EAAA,MAAA;EACA,YAAA,EAAA,MAAA;;AAEA,iBAJc,8BAAA,CAId;EAAA,UAAA;EAAA,cAAA;EAAA,UAAA;EAAA;AAAA,CAAA,EACC,qBADD,CAAA,EAAA,MAAA"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
//#region src/templates/workflow-runner.ts
|
|
2
|
+
function generateWorkflowRunnerTemplate({ exportName, specImportPath, runnerName, workflowName }) {
|
|
3
|
+
return `import {
|
|
4
|
+
InMemoryStateStore,
|
|
5
|
+
WorkflowRegistry,
|
|
6
|
+
WorkflowRunner,
|
|
7
|
+
} from '@contractspec/lib.contracts/workflow';
|
|
8
|
+
import { ${exportName} } from '${specImportPath}';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Runner wiring for ${workflowName}.
|
|
12
|
+
*
|
|
13
|
+
* TODO:
|
|
14
|
+
* - Replace the in-memory state store with a persistent adapter if needed.
|
|
15
|
+
* - Implement opExecutor to invoke the correct contract handlers.
|
|
16
|
+
* - Wire eventEmitter to telemetry sinks.
|
|
17
|
+
*/
|
|
18
|
+
const registry = new WorkflowRegistry();
|
|
19
|
+
registry.register(${exportName});
|
|
20
|
+
|
|
21
|
+
const stateStore = new InMemoryStateStore();
|
|
22
|
+
|
|
23
|
+
export const ${runnerName} = new WorkflowRunner({
|
|
24
|
+
registry,
|
|
25
|
+
stateStore,
|
|
26
|
+
opExecutor: async (operation, input, ctx) => {
|
|
27
|
+
// TODO: route to the appropriate contract handler
|
|
28
|
+
// Example: return contractRegistry.execute(operation.name, operation.version, input, ctx);
|
|
29
|
+
throw new Error(
|
|
30
|
+
\`opExecutor for \${operation.name}.v\${operation.version} is not implemented\`
|
|
31
|
+
);
|
|
32
|
+
},
|
|
33
|
+
// appConfigProvider: async (state) => {
|
|
34
|
+
// // TODO: return the ResolvedAppConfig for this workflow run (tenant/environment)
|
|
35
|
+
// return undefined;
|
|
36
|
+
// },
|
|
37
|
+
// enforceCapabilities: async (operation, context) => {
|
|
38
|
+
// // TODO: ensure required capabilities are satisfied using context.integrations/context.resolvedAppConfig
|
|
39
|
+
// },
|
|
40
|
+
eventEmitter: (_event, _payload) => {
|
|
41
|
+
// TODO: forward workflow events to telemetry or logging sinks
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//#endregion
|
|
48
|
+
export { generateWorkflowRunnerTemplate };
|
|
49
|
+
//# sourceMappingURL=workflow-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-runner.js","names":[],"sources":["../../src/templates/workflow-runner.ts"],"sourcesContent":["interface RunnerTemplateOptions {\n exportName: string;\n specImportPath: string;\n runnerName: string;\n workflowName: string;\n}\n\nexport function generateWorkflowRunnerTemplate({\n exportName,\n specImportPath,\n runnerName,\n workflowName,\n}: RunnerTemplateOptions): string {\n return `import {\n InMemoryStateStore,\n WorkflowRegistry,\n WorkflowRunner,\n} from '@contractspec/lib.contracts/workflow';\nimport { ${exportName} } from '${specImportPath}';\n\n/**\n * Runner wiring for ${workflowName}.\n *\n * TODO:\n * - Replace the in-memory state store with a persistent adapter if needed.\n * - Implement opExecutor to invoke the correct contract handlers.\n * - Wire eventEmitter to telemetry sinks.\n */\nconst registry = new WorkflowRegistry();\nregistry.register(${exportName});\n\nconst stateStore = new InMemoryStateStore();\n\nexport const ${runnerName} = new WorkflowRunner({\n registry,\n stateStore,\n opExecutor: async (operation, input, ctx) => {\n // TODO: route to the appropriate contract handler\n // Example: return contractRegistry.execute(operation.name, operation.version, input, ctx);\n throw new Error(\n \\`opExecutor for \\${operation.name}.v\\${operation.version} is not implemented\\`\n );\n },\n // appConfigProvider: async (state) => {\n // // TODO: return the ResolvedAppConfig for this workflow run (tenant/environment)\n // return undefined;\n // },\n // enforceCapabilities: async (operation, context) => {\n // // TODO: ensure required capabilities are satisfied using context.integrations/context.resolvedAppConfig\n // },\n eventEmitter: (_event, _payload) => {\n // TODO: forward workflow events to telemetry or logging sinks\n },\n});\n`;\n}\n"],"mappings":";AAOA,SAAgB,+BAA+B,EAC7C,YACA,gBACA,YACA,gBACgC;AAChC,QAAO;;;;;WAKE,WAAW,WAAW,eAAe;;;uBAGzB,aAAa;;;;;;;;oBAQhB,WAAW;;;;eAIhB,WAAW"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { WorkflowSpecData } from "../types/spec-types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/templates/workflow.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Generate workflow spec TypeScript code.
|
|
7
|
+
*/
|
|
8
|
+
declare function generateWorkflowSpec(data: WorkflowSpecData): string;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { generateWorkflowSpec };
|
|
11
|
+
//# sourceMappingURL=workflow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.d.ts","names":[],"sources":["../../src/templates/workflow.ts"],"sourcesContent":[],"mappings":";;;;;;;iBAWgB,oBAAA,OAA2B"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { escapeString, toPascalCase } from "./utils.js";
|
|
2
|
+
|
|
3
|
+
//#region src/templates/workflow.ts
|
|
4
|
+
/**
|
|
5
|
+
* Generate workflow spec TypeScript code.
|
|
6
|
+
*/
|
|
7
|
+
function generateWorkflowSpec(data) {
|
|
8
|
+
const specVarName = toPascalCase(data.name.split(".").pop() ?? "Workflow") + "Workflow";
|
|
9
|
+
const stepsCode = data.steps.map((step) => formatStep(step)).join(",\n");
|
|
10
|
+
const transitionsCode = data.transitions.map((transition) => ` {
|
|
11
|
+
from: '${transition.from}',
|
|
12
|
+
to: '${transition.to}',
|
|
13
|
+
${transition.condition ? ` condition: '${escapeString(transition.condition)}',` : ""}
|
|
14
|
+
}`).join(",\n");
|
|
15
|
+
return `import type { WorkflowSpec } from '@contractspec/lib.contracts/workflow';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Workflow generated via contractspec CLI.
|
|
19
|
+
* TODO:
|
|
20
|
+
* - Review step definitions and descriptions.
|
|
21
|
+
* - Wire automation steps to actual operations.
|
|
22
|
+
* - Provide form renderers for human steps.
|
|
23
|
+
* - Add guards/conditions as needed.
|
|
24
|
+
*/
|
|
25
|
+
export const ${specVarName}: WorkflowSpec = {
|
|
26
|
+
meta: {
|
|
27
|
+
key: '${data.name}',
|
|
28
|
+
version: ${data.version},
|
|
29
|
+
title: '${escapeString(data.title)}',
|
|
30
|
+
description: '${escapeString(data.description)}',
|
|
31
|
+
domain: '${escapeString(data.domain)}',
|
|
32
|
+
stability: '${data.stability}',
|
|
33
|
+
owners: [${data.owners.map((owner) => `'${owner}'`).join(", ")}],
|
|
34
|
+
tags: [${data.tags.map((tag) => `'${tag}'`).join(", ")}],
|
|
35
|
+
},
|
|
36
|
+
definition: {
|
|
37
|
+
${data.entryStepId ? ` entryStepId: '${data.entryStepId}',\n` : ""} steps: [
|
|
38
|
+
${stepsCode}
|
|
39
|
+
],
|
|
40
|
+
transitions: [
|
|
41
|
+
${transitionsCode}
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
${data.policyFlags.length > 0 ? `policy: {
|
|
45
|
+
flags: [${data.policyFlags.map((flag) => `'${flag}'`).join(", ")}],
|
|
46
|
+
},` : "// policy: { flags: [] },"}
|
|
47
|
+
};
|
|
48
|
+
`;
|
|
49
|
+
}
|
|
50
|
+
function formatStep(step) {
|
|
51
|
+
const lines = [
|
|
52
|
+
` {`,
|
|
53
|
+
` id: '${step.id}',`,
|
|
54
|
+
` type: '${step.type}',`,
|
|
55
|
+
` label: '${escapeString(step.label)}',`
|
|
56
|
+
];
|
|
57
|
+
if (step.description) lines.push(` description: '${escapeString(step.description)}',`);
|
|
58
|
+
const actionLines = [];
|
|
59
|
+
if (step.operation) actionLines.push(`operation: { name: '${step.operation.name}', version: ${step.operation.version} }`);
|
|
60
|
+
if (step.form) actionLines.push(`form: { key: '${step.form.key}', version: ${step.form.version} }`);
|
|
61
|
+
if (actionLines.length) lines.push(` action: { ${actionLines.join(", ")} },`);
|
|
62
|
+
lines.push(` }`);
|
|
63
|
+
return lines.join("\n");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
//#endregion
|
|
67
|
+
export { generateWorkflowSpec };
|
|
68
|
+
//# sourceMappingURL=workflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.js","names":[],"sources":["../../src/templates/workflow.ts"],"sourcesContent":["/**\n * Workflow spec template generation.\n * Extracted from cli-contractspec/src/templates/workflow.template.ts\n */\n\nimport type { WorkflowSpecData } from '../types/spec-types';\nimport { toPascalCase, escapeString } from './utils';\n\n/**\n * Generate workflow spec TypeScript code.\n */\nexport function generateWorkflowSpec(data: WorkflowSpecData): string {\n const specVarName =\n toPascalCase(data.name.split('.').pop() ?? 'Workflow') + 'Workflow';\n\n const stepsCode = data.steps.map((step) => formatStep(step)).join(',\\n');\n\n const transitionsCode = data.transitions\n .map(\n (transition) => ` {\n from: '${transition.from}',\n to: '${transition.to}',\n${transition.condition ? ` condition: '${escapeString(transition.condition)}',` : ''}\n }`\n )\n .join(',\\n');\n\n return `import type { WorkflowSpec } from '@contractspec/lib.contracts/workflow';\n\n/**\n * Workflow generated via contractspec CLI.\n * TODO:\n * - Review step definitions and descriptions.\n * - Wire automation steps to actual operations.\n * - Provide form renderers for human steps.\n * - Add guards/conditions as needed.\n */\nexport const ${specVarName}: WorkflowSpec = {\n meta: {\n key: '${data.name}',\n version: ${data.version},\n title: '${escapeString(data.title)}',\n description: '${escapeString(data.description)}',\n domain: '${escapeString(data.domain)}',\n stability: '${data.stability}',\n owners: [${data.owners.map((owner) => `'${owner}'`).join(', ')}],\n tags: [${data.tags.map((tag) => `'${tag}'`).join(', ')}],\n },\n definition: {\n${data.entryStepId ? ` entryStepId: '${data.entryStepId}',\\n` : ''} steps: [\n${stepsCode}\n ],\n transitions: [\n${transitionsCode}\n ],\n },\n ${\n data.policyFlags.length > 0\n ? `policy: {\n flags: [${data.policyFlags.map((flag) => `'${flag}'`).join(', ')}],\n },`\n : '// policy: { flags: [] },'\n }\n};\n`;\n}\n\nfunction formatStep(step: WorkflowSpecData['steps'][number]): string {\n const lines: string[] = [\n ` {`,\n ` id: '${step.id}',`,\n ` type: '${step.type}',`,\n ` label: '${escapeString(step.label)}',`,\n ];\n if (step.description) {\n lines.push(` description: '${escapeString(step.description)}',`);\n }\n\n const actionLines: string[] = [];\n if (step.operation) {\n actionLines.push(\n `operation: { name: '${step.operation.name}', version: ${step.operation.version} }`\n );\n }\n if (step.form) {\n actionLines.push(\n `form: { key: '${step.form.key}', version: ${step.form.version} }`\n );\n }\n if (actionLines.length) {\n lines.push(` action: { ${actionLines.join(', ')} },`);\n }\n\n lines.push(` }`);\n return lines.join('\\n');\n}\n"],"mappings":";;;;;;AAWA,SAAgB,qBAAqB,MAAgC;CACnE,MAAM,cACJ,aAAa,KAAK,KAAK,MAAM,IAAI,CAAC,KAAK,IAAI,WAAW,GAAG;CAE3D,MAAM,YAAY,KAAK,MAAM,KAAK,SAAS,WAAW,KAAK,CAAC,CAAC,KAAK,MAAM;CAExE,MAAM,kBAAkB,KAAK,YAC1B,KACE,eAAe;eACP,WAAW,KAAK;aAClB,WAAW,GAAG;EACzB,WAAW,YAAY,qBAAqB,aAAa,WAAW,UAAU,CAAC,MAAM,GAAG;OAErF,CACA,KAAK,MAAM;AAEd,QAAO;;;;;;;;;;eAUM,YAAY;;YAEf,KAAK,KAAK;eACP,KAAK,QAAQ;cACd,aAAa,KAAK,MAAM,CAAC;oBACnB,aAAa,KAAK,YAAY,CAAC;eACpC,aAAa,KAAK,OAAO,CAAC;kBACvB,KAAK,UAAU;eAClB,KAAK,OAAO,KAAK,UAAU,IAAI,MAAM,GAAG,CAAC,KAAK,KAAK,CAAC;aACtD,KAAK,KAAK,KAAK,QAAQ,IAAI,IAAI,GAAG,CAAC,KAAK,KAAK,CAAC;;;EAGzD,KAAK,cAAc,qBAAqB,KAAK,YAAY,QAAQ,GAAG;EACpE,UAAU;;;EAGV,gBAAgB;;;IAId,KAAK,YAAY,SAAS,IACtB;cACM,KAAK,YAAY,KAAK,SAAS,IAAI,KAAK,GAAG,CAAC,KAAK,KAAK,CAAC;QAE7D,4BACL;;;;AAKH,SAAS,WAAW,MAAiD;CACnE,MAAM,QAAkB;EACtB;EACA,cAAc,KAAK,GAAG;EACtB,gBAAgB,KAAK,KAAK;EAC1B,iBAAiB,aAAa,KAAK,MAAM,CAAC;EAC3C;AACD,KAAI,KAAK,YACP,OAAM,KAAK,uBAAuB,aAAa,KAAK,YAAY,CAAC,IAAI;CAGvE,MAAM,cAAwB,EAAE;AAChC,KAAI,KAAK,UACP,aAAY,KACV,uBAAuB,KAAK,UAAU,KAAK,cAAc,KAAK,UAAU,QAAQ,IACjF;AAEH,KAAI,KAAK,KACP,aAAY,KACV,iBAAiB,KAAK,KAAK,IAAI,cAAc,KAAK,KAAK,QAAQ,IAChE;AAEH,KAAI,YAAY,OACd,OAAM,KAAK,mBAAmB,YAAY,KAAK,KAAK,CAAC,KAAK;AAG5D,OAAM,KAAK,QAAQ;AACnB,QAAO,MAAM,KAAK,KAAK"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { Stability } from "./spec-types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/types/analysis-types.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Spec type detected from file analysis.
|
|
7
|
+
* Covers all contract types from @contractspec/lib.contracts.
|
|
8
|
+
*/
|
|
9
|
+
type AnalyzedSpecType = 'operation' | 'event' | 'presentation' | 'feature' | 'capability' | 'data-view' | 'form' | 'migration' | 'workflow' | 'experiment' | 'integration' | 'knowledge' | 'knowledge' | 'telemetry' | 'example' | 'app-config' | 'policy' | 'test-spec' | 'type' | 'unknown';
|
|
10
|
+
/**
|
|
11
|
+
* Types that can be referenced by features.
|
|
12
|
+
*/
|
|
13
|
+
type RefType = 'operation' | 'event' | 'presentation' | 'capability' | 'experiment' | 'policy' | 'test';
|
|
14
|
+
/**
|
|
15
|
+
/**
|
|
16
|
+
* Operation kind detected from file analysis.
|
|
17
|
+
*/
|
|
18
|
+
type AnalyzedOperationKind = 'command' | 'query' | 'event' | 'presentation' | 'capability' | 'policy' | 'type' | 'example' | 'app-config' | 'integration' | 'workflow' | 'unknown';
|
|
19
|
+
/**
|
|
20
|
+
* Reference information (name + version).
|
|
21
|
+
*/
|
|
22
|
+
interface RefInfo {
|
|
23
|
+
key: string;
|
|
24
|
+
version: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Test target extracted from a TestSpec.
|
|
28
|
+
* Matches the TestTarget type from @contractspec/lib.contracts.
|
|
29
|
+
*/
|
|
30
|
+
interface ExtractedTestTarget {
|
|
31
|
+
type: 'operation' | 'workflow';
|
|
32
|
+
key: string;
|
|
33
|
+
version?: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A reference extracted from source code with location context.
|
|
37
|
+
*/
|
|
38
|
+
interface ExtractedRef {
|
|
39
|
+
type: RefType;
|
|
40
|
+
key: string;
|
|
41
|
+
version: string;
|
|
42
|
+
sourceFile: string;
|
|
43
|
+
sourceLine?: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Result of scanning a spec source file.
|
|
47
|
+
*/
|
|
48
|
+
interface SpecScanResult {
|
|
49
|
+
filePath: string;
|
|
50
|
+
specType: AnalyzedSpecType;
|
|
51
|
+
key?: string;
|
|
52
|
+
version?: string;
|
|
53
|
+
kind?: AnalyzedOperationKind;
|
|
54
|
+
stability?: Stability;
|
|
55
|
+
description?: string;
|
|
56
|
+
goal?: string;
|
|
57
|
+
context?: string;
|
|
58
|
+
owners?: string[];
|
|
59
|
+
tags?: string[];
|
|
60
|
+
hasMeta: boolean;
|
|
61
|
+
hasIo: boolean;
|
|
62
|
+
hasPolicy: boolean;
|
|
63
|
+
hasPayload: boolean;
|
|
64
|
+
hasContent: boolean;
|
|
65
|
+
hasDefinition: boolean;
|
|
66
|
+
emittedEvents?: RefInfo[];
|
|
67
|
+
policyRefs?: RefInfo[];
|
|
68
|
+
testRefs?: RefInfo[];
|
|
69
|
+
testTarget?: ExtractedTestTarget;
|
|
70
|
+
testCoverage?: {
|
|
71
|
+
hasSuccess: boolean;
|
|
72
|
+
hasError: boolean;
|
|
73
|
+
};
|
|
74
|
+
sourceBlock?: string;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Result of scanning a feature file.
|
|
78
|
+
*/
|
|
79
|
+
interface FeatureScanResult {
|
|
80
|
+
filePath: string;
|
|
81
|
+
key: string;
|
|
82
|
+
version?: string;
|
|
83
|
+
title?: string;
|
|
84
|
+
description?: string;
|
|
85
|
+
goal?: string;
|
|
86
|
+
context?: string;
|
|
87
|
+
domain?: string;
|
|
88
|
+
stability?: Stability;
|
|
89
|
+
owners?: string[];
|
|
90
|
+
tags?: string[];
|
|
91
|
+
operations: RefInfo[];
|
|
92
|
+
events: RefInfo[];
|
|
93
|
+
presentations: RefInfo[];
|
|
94
|
+
experiments: RefInfo[];
|
|
95
|
+
capabilities: {
|
|
96
|
+
provides: RefInfo[];
|
|
97
|
+
requires: RefInfo[];
|
|
98
|
+
};
|
|
99
|
+
opToPresentationLinks: {
|
|
100
|
+
op: RefInfo;
|
|
101
|
+
pres: RefInfo;
|
|
102
|
+
}[];
|
|
103
|
+
presentationsTargets?: {
|
|
104
|
+
key: string;
|
|
105
|
+
version: string;
|
|
106
|
+
targets: Record<string, unknown>[];
|
|
107
|
+
}[];
|
|
108
|
+
sourceBlock?: string;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Result of scanning an example file.
|
|
112
|
+
*/
|
|
113
|
+
interface ExampleScanResult {
|
|
114
|
+
filePath: string;
|
|
115
|
+
key: string;
|
|
116
|
+
version?: string;
|
|
117
|
+
title?: string;
|
|
118
|
+
description?: string;
|
|
119
|
+
summary?: string;
|
|
120
|
+
kind?: string;
|
|
121
|
+
visibility?: string;
|
|
122
|
+
stability?: Stability;
|
|
123
|
+
owners?: string[];
|
|
124
|
+
tags?: string[];
|
|
125
|
+
domain?: string;
|
|
126
|
+
docs?: {
|
|
127
|
+
rootDocId?: string;
|
|
128
|
+
goalDocId?: string;
|
|
129
|
+
usageDocId?: string;
|
|
130
|
+
};
|
|
131
|
+
surfaces: {
|
|
132
|
+
templates: boolean;
|
|
133
|
+
sandbox: {
|
|
134
|
+
enabled: boolean;
|
|
135
|
+
modes: string[];
|
|
136
|
+
};
|
|
137
|
+
studio: {
|
|
138
|
+
enabled: boolean;
|
|
139
|
+
installable: boolean;
|
|
140
|
+
};
|
|
141
|
+
mcp: {
|
|
142
|
+
enabled: boolean;
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
entrypoints: {
|
|
146
|
+
packageName: string;
|
|
147
|
+
feature?: string;
|
|
148
|
+
blueprint?: string;
|
|
149
|
+
contracts?: string;
|
|
150
|
+
presentations?: string;
|
|
151
|
+
handlers?: string;
|
|
152
|
+
ui?: string;
|
|
153
|
+
docs?: string;
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Semantic diff item types.
|
|
158
|
+
*/
|
|
159
|
+
type SemanticDiffType = 'breaking' | 'changed' | 'added' | 'removed';
|
|
160
|
+
/**
|
|
161
|
+
* A single semantic difference between two specs.
|
|
162
|
+
*/
|
|
163
|
+
interface SemanticDiffItem {
|
|
164
|
+
type: SemanticDiffType;
|
|
165
|
+
path: string;
|
|
166
|
+
oldValue?: unknown;
|
|
167
|
+
newValue?: unknown;
|
|
168
|
+
description: string;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Options for semantic diff computation.
|
|
172
|
+
*/
|
|
173
|
+
interface SemanticDiffOptions {
|
|
174
|
+
breakingOnly?: boolean;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* A node in the contract dependency graph.
|
|
178
|
+
*/
|
|
179
|
+
interface ContractNode {
|
|
180
|
+
key: string;
|
|
181
|
+
file: string;
|
|
182
|
+
dependencies: string[];
|
|
183
|
+
dependents: string[];
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* The contract dependency graph.
|
|
187
|
+
*/
|
|
188
|
+
type ContractGraph = Map<string, ContractNode>;
|
|
189
|
+
/**
|
|
190
|
+
* Result of spec structure validation.
|
|
191
|
+
*/
|
|
192
|
+
interface ValidationResult {
|
|
193
|
+
valid: boolean;
|
|
194
|
+
errors: string[];
|
|
195
|
+
warnings: string[];
|
|
196
|
+
}
|
|
197
|
+
//#endregion
|
|
198
|
+
export { AnalyzedOperationKind, AnalyzedSpecType, ContractGraph, ContractNode, ExampleScanResult, ExtractedRef, ExtractedTestTarget, FeatureScanResult, RefInfo, RefType, SemanticDiffItem, SemanticDiffOptions, SemanticDiffType, SpecScanResult, ValidationResult };
|
|
199
|
+
//# sourceMappingURL=analysis-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analysis-types.d.ts","names":[],"sources":["../../src/types/analysis-types.ts"],"sourcesContent":[],"mappings":";;;;AAmCA;AAaA;AAiBA;AASA;AASiB,KAzEL,gBAAA,GA0EJ,WAAO,GAAA,OAAA,GAAA,cAAA,GAAA,SAAA,GAAA,YAAA,GAAA,WAAA,GAAA,MAAA,GAAA,WAAA,GAAA,UAAA,GAAA,YAAA,GAAA,aAAA,GAAA,WAAA,GAAA,WAAA,GAAA,WAAA,GAAA,SAAA,GAAA,YAAA,GAAA,QAAA,GAAA,WAAA,GAAA,MAAA,GAAA,SAAA;AAUf;;;AAMc,KAjEF,OAAA,GAiEE,WAAA,GAAA,OAAA,GAAA,cAAA,GAAA,YAAA,GAAA,YAAA,GAAA,QAAA,GAAA,MAAA;;;;;AAqBoB,KAzEtB,qBAAA,GAyEsB,SAAA,GAAA,OAAA,GAAA,OAAA,GAAA,cAAA,GAAA,YAAA,GAAA,QAAA,GAAA,MAAA,GAAA,SAAA,GAAA,YAAA,GAAA,aAAA,GAAA,UAAA,GAAA,SAAA;AAalC;;;AAeU,UApFO,OAAA,CAoFP;EACO,GAAA,EAAA,MAAA;EACF,OAAA,EAAA,MAAA;;;;;;AAeI,UA5FF,mBAAA,CA4FE;EAUF,IAAA,EAAA,WAAA,GAAiB,UAAA;EA6CtB,GAAA,EAAA,MAAA;EAKK,OAAA,CAAA,EAAA,MAAA;AAWjB;AAOA;AAUA;AAKA;UAhLiB,YAAA;QACT;;;;;;;;;UAUS,cAAA;;YAEL;;;SAGH;cACK;;;;;;;;;;;;kBAgBI;eACH;aACF;eAGE;;;;;;;;;;UAaE,iBAAA;;;;;;;;;cASH;;;cAKA;UACJ;iBACO;eACF;;cAID;cACA;;;QAIiB;UAAe;;;;;aAMjC;;;;;;;UAUI,iBAAA;;;;;;;;;cASH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAoCF,gBAAA;;;;UAKK,gBAAA;QACT;;;;;;;;;UAUS,mBAAA;;;;;;UAOA,YAAA;;;;;;;;;KAUL,aAAA,GAAgB,YAAY;;;;UAKvB,gBAAA"}
|