@lssm/module.contractspec-workspace 0.0.0-canary-20251217083314 → 0.0.0-canary-20251219202229
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/dist/ai/code-generation.d.ts +2 -1
- package/dist/ai/code-generation.d.ts.map +1 -0
- package/dist/ai/code-generation.js +2 -1
- package/dist/ai/code-generation.js.map +1 -0
- package/dist/ai/spec-creation.d.ts +2 -1
- package/dist/ai/spec-creation.d.ts.map +1 -0
- package/dist/ai/spec-creation.js +2 -1
- package/dist/ai/spec-creation.js.map +1 -0
- package/dist/analysis/deps/graph.d.ts +2 -1
- package/dist/analysis/deps/graph.d.ts.map +1 -0
- package/dist/analysis/deps/graph.js +2 -1
- package/dist/analysis/deps/graph.js.map +1 -0
- package/dist/analysis/deps/parse-imports.d.ts +2 -1
- package/dist/analysis/deps/parse-imports.d.ts.map +1 -0
- package/dist/analysis/deps/parse-imports.js +2 -1
- package/dist/analysis/deps/parse-imports.js.map +1 -0
- package/dist/analysis/diff/semantic.d.ts +2 -1
- package/dist/analysis/diff/semantic.d.ts.map +1 -0
- package/dist/analysis/diff/semantic.js +2 -1
- package/dist/analysis/diff/semantic.js.map +1 -0
- package/dist/analysis/feature-scan.d.ts +2 -1
- package/dist/analysis/feature-scan.d.ts.map +1 -0
- package/dist/analysis/feature-scan.js +2 -1
- package/dist/analysis/feature-scan.js.map +1 -0
- package/dist/analysis/spec-scan.d.ts +2 -1
- package/dist/analysis/spec-scan.d.ts.map +1 -0
- package/dist/analysis/spec-scan.js +2 -1
- package/dist/analysis/spec-scan.js.map +1 -0
- package/dist/analysis/validate/spec-structure.d.ts +2 -1
- package/dist/analysis/validate/spec-structure.d.ts.map +1 -0
- package/dist/analysis/validate/spec-structure.js +2 -1
- package/dist/analysis/validate/spec-structure.js.map +1 -0
- package/dist/templates/app-config.d.ts +2 -1
- package/dist/templates/app-config.d.ts.map +1 -0
- package/dist/templates/app-config.js +2 -1
- package/dist/templates/app-config.js.map +1 -0
- package/dist/templates/data-view.d.ts +2 -1
- package/dist/templates/data-view.d.ts.map +1 -0
- package/dist/templates/data-view.js +2 -1
- package/dist/templates/data-view.js.map +1 -0
- package/dist/templates/event.d.ts +2 -1
- package/dist/templates/event.d.ts.map +1 -0
- package/dist/templates/event.js +2 -1
- package/dist/templates/event.js.map +1 -0
- package/dist/templates/experiment.d.ts +2 -1
- package/dist/templates/experiment.d.ts.map +1 -0
- package/dist/templates/experiment.js +2 -1
- package/dist/templates/experiment.js.map +1 -0
- package/dist/templates/handler.d.ts +2 -1
- package/dist/templates/handler.d.ts.map +1 -0
- package/dist/templates/handler.js +2 -1
- package/dist/templates/handler.js.map +1 -0
- package/dist/templates/integration-utils.js +2 -1
- package/dist/templates/integration-utils.js.map +1 -0
- package/dist/templates/integration.d.ts +2 -1
- package/dist/templates/integration.d.ts.map +1 -0
- package/dist/templates/integration.js +2 -1
- package/dist/templates/integration.js.map +1 -0
- package/dist/templates/knowledge.d.ts +2 -1
- package/dist/templates/knowledge.d.ts.map +1 -0
- package/dist/templates/knowledge.js +2 -1
- package/dist/templates/knowledge.js.map +1 -0
- package/dist/templates/migration.d.ts +2 -1
- package/dist/templates/migration.d.ts.map +1 -0
- package/dist/templates/migration.js +2 -1
- package/dist/templates/migration.js.map +1 -0
- package/dist/templates/operation.d.ts +2 -1
- package/dist/templates/operation.d.ts.map +1 -0
- package/dist/templates/operation.js +2 -1
- package/dist/templates/operation.js.map +1 -0
- package/dist/templates/presentation.d.ts +2 -1
- package/dist/templates/presentation.d.ts.map +1 -0
- package/dist/templates/presentation.js +2 -1
- package/dist/templates/presentation.js.map +1 -0
- package/dist/templates/telemetry.d.ts +2 -1
- package/dist/templates/telemetry.d.ts.map +1 -0
- package/dist/templates/telemetry.js +2 -1
- package/dist/templates/telemetry.js.map +1 -0
- package/dist/templates/utils.d.ts +2 -1
- package/dist/templates/utils.d.ts.map +1 -0
- package/dist/templates/utils.js +2 -1
- package/dist/templates/utils.js.map +1 -0
- package/dist/templates/workflow-runner.d.ts +2 -1
- package/dist/templates/workflow-runner.d.ts.map +1 -0
- package/dist/templates/workflow-runner.js +2 -1
- package/dist/templates/workflow-runner.js.map +1 -0
- package/dist/templates/workflow.d.ts +2 -1
- package/dist/templates/workflow.d.ts.map +1 -0
- package/dist/templates/workflow.js +2 -1
- package/dist/templates/workflow.js.map +1 -0
- package/dist/types/analysis-types.d.ts +2 -1
- package/dist/types/analysis-types.d.ts.map +1 -0
- package/dist/types/generation-types.d.ts +2 -1
- package/dist/types/generation-types.d.ts.map +1 -0
- package/dist/types/generation-types.js +2 -1
- package/dist/types/generation-types.js.map +1 -0
- package/dist/types/spec-types.d.ts +2 -1
- package/dist/types/spec-types.d.ts.map +1 -0
- package/package.json +8 -7
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Chaman Ventures, SASU
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -24,4 +24,5 @@ declare function buildTestPrompt(specCode: string, implementationCode: string, t
|
|
|
24
24
|
*/
|
|
25
25
|
declare function getCodeGenSystemPrompt(): string;
|
|
26
26
|
//#endregion
|
|
27
|
-
export { buildComponentPrompt, buildFormPrompt, buildHandlerPrompt, buildTestPrompt, getCodeGenSystemPrompt };
|
|
27
|
+
export { buildComponentPrompt, buildFormPrompt, buildHandlerPrompt, buildTestPrompt, getCodeGenSystemPrompt };
|
|
28
|
+
//# sourceMappingURL=code-generation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-generation.d.ts","names":[],"sources":["../../src/ai/code-generation.ts"],"sourcesContent":[],"mappings":";;AAQA;AA0BA;AA0BA;AA2BA;AA2CA;;iBA1HgB,kBAAA;;;;iBA0BA,oBAAA;;;;iBA0BA,eAAA;;;;iBA2BA,eAAA;;;;iBA2CA,sBAAA,CAAA"}
|
|
@@ -134,4 +134,5 @@ Always prioritize code quality, safety, and user experience.`;
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
//#endregion
|
|
137
|
-
export { buildComponentPrompt, buildFormPrompt, buildHandlerPrompt, buildTestPrompt, getCodeGenSystemPrompt };
|
|
137
|
+
export { buildComponentPrompt, buildFormPrompt, buildHandlerPrompt, buildTestPrompt, getCodeGenSystemPrompt };
|
|
138
|
+
//# sourceMappingURL=code-generation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-generation.js","names":[],"sources":["../../src/ai/code-generation.ts"],"sourcesContent":["/**\n * AI prompts for code generation.\n * Extracted from cli-contracts/src/ai/prompts/code-generation.ts\n */\n\n/**\n * Build prompt for generating handler implementation.\n */\nexport function buildHandlerPrompt(specCode: string): string {\n return `You are a senior TypeScript developer implementing a handler for a contract specification.\n\nHere is the contract spec:\n\n\\`\\`\\`typescript\n${specCode}\n\\`\\`\\`\n\nGenerate a complete handler implementation that:\n\n1. **Matches the spec signature**: Input/output types from the spec\n2. **Handles errors**: Implement error cases defined in spec.io.errors\n3. **Emits events**: Use the events declared in spec.sideEffects.emits\n4. **Validates input**: Use zod validation from the schema\n5. **Follows best practices**: Clean, type-safe TypeScript\n6. **Includes comments**: Explain business logic\n\nThe handler should be production-ready with proper error handling, logging points, and clear structure.\n\nReturn only the TypeScript code for the handler function.`;\n}\n\n/**\n * Build prompt for generating React component from presentation spec.\n */\nexport function buildComponentPrompt(specCode: string): string {\n return `You are a senior React developer creating a component for a presentation specification.\n\nHere is the presentation spec:\n\n\\`\\`\\`typescript\n${specCode}\n\\`\\`\\`\n\nGenerate a complete React component that:\n\n1. **Props interface**: Typed props from the spec\n2. **Accessibility**: Proper ARIA labels, roles, keyboard navigation\n3. **Mobile-first**: Optimized for small screens and touch\n4. **Clean UI**: Simple, intuitive interface\n5. **Type-safe**: Full TypeScript with no 'any' types\n6. **Best practices**: React hooks, proper state management\n\nThe component should follow Atomic Design principles and be reusable.\n\nReturn only the TypeScript/TSX code for the component.`;\n}\n\n/**\n * Build prompt for generating form component.\n */\nexport function buildFormPrompt(specCode: string): string {\n return `You are a senior React developer creating a form component from a form specification.\n\nHere is the form spec:\n\n\\`\\`\\`typescript\n${specCode}\n\\`\\`\\`\n\nGenerate a complete form component using react-hook-form that:\n\n1. **Form validation**: Use zod schema for validation\n2. **Field types**: Proper inputs for each field type\n3. **Conditional logic**: Support visibleWhen, enabledWhen, requiredWhen predicates\n4. **Error handling**: Clear, user-friendly error messages\n5. **Accessibility**: Labels, hints, ARIA attributes\n6. **Mobile-optimized**: Touch-friendly, appropriate input types\n7. **Type-safe**: Full TypeScript\n\nThe form should provide excellent UX with real-time validation and helpful feedback.\n\nReturn only the TypeScript/TSX code for the form component.`;\n}\n\n/**\n * Build prompt for generating tests.\n */\nexport function buildTestPrompt(\n specCode: string,\n implementationCode: string,\n testType: 'handler' | 'component'\n): string {\n const testFocus =\n testType === 'handler'\n ? `\n - Test all acceptance scenarios from the spec\n - Test error cases defined in spec.io.errors\n - Verify events are emitted correctly\n - Test input validation\n - Test happy path and edge cases`\n : `\n - Test rendering with various props\n - Test user interactions\n - Test accessibility (a11y)\n - Test responsive behavior\n - Test error states`;\n\n return `You are a senior developer writing comprehensive tests.\n\nSpec:\n\\`\\`\\`typescript\n${specCode}\n\\`\\`\\`\n\nImplementation:\n\\`\\`\\`typescript\n${implementationCode}\n\\`\\`\\`\n\nGenerate complete test suite using Vitest that:\n${testFocus}\n\nUse clear test descriptions and follow AAA pattern (Arrange, Act, Assert).\n\nReturn only the TypeScript test code.`;\n}\n\n/**\n * System prompt for code generation.\n */\nexport function getCodeGenSystemPrompt(): string {\n return `You are an expert TypeScript developer with deep knowledge of:\n- Type-safe API design\n- React and modern hooks\n- Test-driven development\n- Accessibility best practices\n- Clean code principles\n\nGenerate production-ready code that is:\n- Fully typed (no 'any' or type assertions unless absolutely necessary)\n- Well-documented with TSDoc comments\n- Following project conventions\n- Defensive and error-safe\n- Easy to maintain and extend\n\nAlways prioritize code quality, safety, and user experience.`;\n}\n"],"mappings":";;;;;;;;AAQA,SAAgB,mBAAmB,UAA0B;AAC3D,QAAO;;;;;EAKP,SAAS;;;;;;;;;;;;;;;;;;;AAoBX,SAAgB,qBAAqB,UAA0B;AAC7D,QAAO;;;;;EAKP,SAAS;;;;;;;;;;;;;;;;;;;AAoBX,SAAgB,gBAAgB,UAA0B;AACxD,QAAO;;;;;EAKP,SAAS;;;;;;;;;;;;;;;;;;;;AAqBX,SAAgB,gBACd,UACA,oBACA,UACQ;AAgBR,QAAO;;;;EAIP,SAAS;;;;;EAKT,mBAAmB;;;;EAvBjB,aAAa,YACT;;;;;sCAMA;;;;;uBAoBI;;;;;;;;;AAUZ,SAAgB,yBAAiC;AAC/C,QAAO"}
|
|
@@ -23,4 +23,5 @@ declare function getSystemPrompt(): string;
|
|
|
23
23
|
*/
|
|
24
24
|
declare function addExampleContext(basePrompt: string, examples: string[]): string;
|
|
25
25
|
//#endregion
|
|
26
|
-
export { addExampleContext, buildEventSpecPrompt, buildOperationSpecPrompt, buildPresentationSpecPrompt, getSystemPrompt };
|
|
26
|
+
export { addExampleContext, buildEventSpecPrompt, buildOperationSpecPrompt, buildPresentationSpecPrompt, getSystemPrompt };
|
|
27
|
+
//# sourceMappingURL=spec-creation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-creation.d.ts","names":[],"sources":["../../src/ai/spec-creation.ts"],"sourcesContent":[],"mappings":";;;;AA2DA;AAoCA;AAiBA;iBAtGgB,wBAAA,4BAER;;;;iBA0BQ,oBAAA;;;;iBAqBA,2BAAA,4BAER;;;;iBAkCQ,eAAA,CAAA;;;;iBAiBA,iBAAA"}
|
package/dist/ai/spec-creation.js
CHANGED
|
@@ -98,4 +98,5 @@ Follow this structure and quality level.`;
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
//#endregion
|
|
101
|
-
export { addExampleContext, buildEventSpecPrompt, buildOperationSpecPrompt, buildPresentationSpecPrompt, getSystemPrompt };
|
|
101
|
+
export { addExampleContext, buildEventSpecPrompt, buildOperationSpecPrompt, buildPresentationSpecPrompt, getSystemPrompt };
|
|
102
|
+
//# sourceMappingURL=spec-creation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-creation.js","names":[],"sources":["../../src/ai/spec-creation.ts"],"sourcesContent":["/**\n * AI prompts for spec creation.\n * Extracted from cli-contracts/src/ai/prompts/spec-creation.ts\n */\n\nimport type { OpKind, PresentationKind } from '../types/spec-types';\n\n/**\n * Build prompt for creating operation spec from description.\n */\nexport function buildOperationSpecPrompt(\n description: string,\n kind: OpKind\n): string {\n return `You are a senior software architect creating a contract specification for an operation.\n\nThe operation is a ${kind} (${kind === 'command' ? 'changes state, has side effects' : 'read-only, idempotent'}).\n\nUser description: ${description}\n\nCreate a complete contract specification following these guidelines:\n\n1. **Name**: Use dot notation like \"domain.operationName\" (e.g., \"user.signup\", \"payment.charge\")\n2. **Version**: Start at 1\n3. **Description**: Clear, concise summary (1-2 sentences)\n4. **Goal**: Business purpose - why this operation exists\n5. **Context**: Background, constraints, scope (what it does and doesn't do)\n6. **Input/Output**: Describe the shape (we'll create schemas separately)\n7. **Auth**: Who can call this - anonymous, user, or admin\n8. **Feature Flags**: Any flags that gate this operation\n9. **Side Effects**: What events might be emitted, analytics to track\n\nRespond with a structured spec.`;\n}\n\n/**\n * Build prompt for creating event spec from description.\n */\nexport function buildEventSpecPrompt(description: string): string {\n return `You are a senior software architect creating an event specification.\n\nUser description: ${description}\n\nCreate a complete event specification following these guidelines:\n\n1. **Name**: Use dot notation like \"domain.event_name\" (e.g., \"user.signup_completed\", \"payment.charged\")\n2. **Version**: Start at 1\n3. **Description**: Clear description of when this event is emitted\n4. **Payload**: Describe what data the event carries\n5. **PII Fields**: List any personally identifiable information fields (e.g., [\"email\", \"name\"])\n\nEvents represent things that have already happened and should use past tense.\n\nRespond with a structured spec.`;\n}\n\n/**\n * Build prompt for creating presentation spec from description.\n */\nexport function buildPresentationSpecPrompt(\n description: string,\n kind: PresentationKind\n): string {\n const kindDescriptions = {\n web_component: 'a React component with props schema',\n markdown: 'markdown/MDX documentation or guide',\n data: 'structured data export (JSON/XML)',\n };\n\n return `You are a senior software architect creating a presentation specification.\n\nThis is a ${kind} presentation - ${kindDescriptions[kind]}.\n\nUser description: ${description}\n\nCreate a complete presentation specification following these guidelines:\n\n1. **Name**: Use dot notation like \"domain.presentation_name\" (e.g., \"user.profile_card\", \"docs.api_guide\")\n2. **Version**: Start at 1\n3. **Description**: What this presentation shows/provides\n4. **Kind-specific details**:\n ${\n kind === 'web_component'\n ? '- Component key (symbolic, resolved by host app)\\n - Props structure\\n - Analytics events to track'\n : kind === 'markdown'\n ? '- Content or resource URI\\n - Target audience'\n : '- MIME type (e.g., application/json)\\n - Data structure description'\n }\n\nRespond with a structured spec.`;\n}\n\n/**\n * Build system prompt for all spec generation.\n */\nexport function getSystemPrompt(): string {\n return `You are an expert software architect specializing in API design and contract-driven development.\n\nYou create clear, well-documented specifications that serve as the single source of truth for operations, events, and presentations.\n\nYour specs are:\n- Precise and unambiguous\n- Following TypeScript conventions\n- Business-oriented (capturing the \"why\" not just \"what\")\n- Designed for both humans and AI agents to understand\n\nAlways use proper dot notation for names and ensure all metadata is meaningful and accurate.`;\n}\n\n/**\n * Create example-based prompt for better results.\n */\nexport function addExampleContext(\n basePrompt: string,\n examples: string[]\n): string {\n if (examples.length === 0) return basePrompt;\n\n return `${basePrompt}\n\nHere are some good examples for reference:\n\n${examples.join('\\n\\n')}\n\nFollow this structure and quality level.`;\n}\n"],"mappings":";;;;AAUA,SAAgB,yBACd,aACA,MACQ;AACR,QAAO;;qBAEY,KAAK,IAAI,SAAS,YAAY,oCAAoC,wBAAwB;;oBAE3F,YAAY;;;;;;;;;;;;;;;;;;;AAoBhC,SAAgB,qBAAqB,aAA6B;AAChE,QAAO;;oBAEW,YAAY;;;;;;;;;;;;;;;;;AAkBhC,SAAgB,4BACd,aACA,MACQ;AAOR,QAAO;;YAEG,KAAK,kBARU;EACvB,eAAe;EACf,UAAU;EACV,MAAM;EACP,CAIiD,MAAM;;oBAEtC,YAAY;;;;;;;;KAS3B,SAAS,kBACL,2GACA,SAAS,aACP,oDACA,wEACP;;;;;;;AAQJ,SAAgB,kBAA0B;AACxC,QAAO;;;;;;;;;;;;;;;AAgBT,SAAgB,kBACd,YACA,UACQ;AACR,KAAI,SAAS,WAAW,EAAG,QAAO;AAElC,QAAO,GAAG,WAAW;;;;EAIrB,SAAS,KAAK,OAAO,CAAC"}
|
|
@@ -30,4 +30,5 @@ declare function createContractGraph(): ContractGraph;
|
|
|
30
30
|
*/
|
|
31
31
|
declare function addContractNode(graph: ContractGraph, name: string, file: string, dependencies: string[]): void;
|
|
32
32
|
//#endregion
|
|
33
|
-
export { addContractNode, buildReverseEdges, createContractGraph, detectCycles, findMissingDependencies, toDot };
|
|
33
|
+
export { addContractNode, buildReverseEdges, createContractGraph, detectCycles, findMissingDependencies, toDot };
|
|
34
|
+
//# sourceMappingURL=graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.d.ts","names":[],"sources":["../../../src/analysis/deps/graph.ts"],"sourcesContent":[],"mappings":";;;;AAwFA;AAsBA;AAOA;iBAzGgB,iBAAA,QAAyB;;;;iBAsBzB,YAAA,QAAoB;;;;iBAoCpB,uBAAA,QACP;;;;;;;iBAiBO,KAAA,QAAa;;;;iBAsBb,mBAAA,CAAA,GAAuB;;;;iBAOvB,eAAA,QACP"}
|
|
@@ -81,4 +81,5 @@ function addContractNode(graph, name, file, dependencies) {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
//#endregion
|
|
84
|
-
export { addContractNode, buildReverseEdges, createContractGraph, detectCycles, findMissingDependencies, toDot };
|
|
84
|
+
export { addContractNode, buildReverseEdges, createContractGraph, detectCycles, findMissingDependencies, toDot };
|
|
85
|
+
//# sourceMappingURL=graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.js","names":["cycles: string[][]","missing: { contract: string; missing: string[] }[]","lines: string[]"],"sources":["../../../src/analysis/deps/graph.ts"],"sourcesContent":["/**\n * Contract dependency graph utilities.\n * Extracted from cli-contracts/src/commands/deps/graph.ts\n */\n\nimport type { ContractNode, ContractGraph } from '../../types/analysis-types';\n\nexport type { ContractNode, ContractGraph };\n\n/**\n * Build reverse edges (dependents) for all nodes in the graph.\n */\nexport function buildReverseEdges(graph: ContractGraph): void {\n for (const node of graph.values()) {\n node.dependents = [];\n }\n\n for (const [name, node] of graph) {\n for (const dep of node.dependencies) {\n const depNode = graph.get(dep);\n if (depNode) {\n depNode.dependents.push(name);\n }\n }\n }\n\n for (const node of graph.values()) {\n node.dependents.sort((a, b) => a.localeCompare(b));\n }\n}\n\n/**\n * Detect circular dependencies in the graph.\n */\nexport function detectCycles(graph: ContractGraph): string[][] {\n const visited = new Set<string>();\n const stack = new Set<string>();\n const cycles: string[][] = [];\n\n function dfs(name: string, path: string[]) {\n if (stack.has(name)) {\n const start = path.indexOf(name);\n if (start >= 0) cycles.push([...path.slice(start), name]);\n return;\n }\n if (visited.has(name)) return;\n\n visited.add(name);\n stack.add(name);\n\n const node = graph.get(name);\n if (node) {\n for (const dep of node.dependencies) {\n dfs(dep, [...path, name]);\n }\n }\n\n stack.delete(name);\n }\n\n for (const name of graph.keys()) {\n if (!visited.has(name)) dfs(name, []);\n }\n\n return cycles;\n}\n\n/**\n * Find missing dependencies (referenced but not defined).\n */\nexport function findMissingDependencies(\n graph: ContractGraph\n): { contract: string; missing: string[] }[] {\n const missing: { contract: string; missing: string[] }[] = [];\n\n for (const [name, node] of graph) {\n const absent = node.dependencies.filter((dep) => !graph.has(dep));\n if (absent.length > 0) {\n missing.push({ contract: name, missing: absent });\n }\n }\n\n return missing;\n}\n\n/**\n * Generate DOT format output for visualization.\n */\nexport function toDot(graph: ContractGraph): string {\n const lines: string[] = [];\n lines.push('digraph ContractDependencies {');\n lines.push(' rankdir=LR;');\n lines.push(' node [shape=box];');\n\n for (const [name, node] of graph) {\n for (const dep of node.dependencies) {\n lines.push(` \"${name}\" -> \"${dep}\";`);\n }\n if (node.dependencies.length === 0) {\n lines.push(` \"${name}\";`);\n }\n }\n\n lines.push('}');\n return lines.join('\\n');\n}\n\n/**\n * Create an empty contract graph.\n */\nexport function createContractGraph(): ContractGraph {\n return new Map();\n}\n\n/**\n * Add a node to the contract graph.\n */\nexport function addContractNode(\n graph: ContractGraph,\n name: string,\n file: string,\n dependencies: string[]\n): void {\n graph.set(name, {\n name,\n file,\n dependencies,\n dependents: [],\n });\n}\n"],"mappings":";;;;AAYA,SAAgB,kBAAkB,OAA4B;AAC5D,MAAK,MAAM,QAAQ,MAAM,QAAQ,CAC/B,MAAK,aAAa,EAAE;AAGtB,MAAK,MAAM,CAAC,MAAM,SAAS,MACzB,MAAK,MAAM,OAAO,KAAK,cAAc;EACnC,MAAM,UAAU,MAAM,IAAI,IAAI;AAC9B,MAAI,QACF,SAAQ,WAAW,KAAK,KAAK;;AAKnC,MAAK,MAAM,QAAQ,MAAM,QAAQ,CAC/B,MAAK,WAAW,MAAM,GAAG,MAAM,EAAE,cAAc,EAAE,CAAC;;;;;AAOtD,SAAgB,aAAa,OAAkC;CAC7D,MAAM,0BAAU,IAAI,KAAa;CACjC,MAAM,wBAAQ,IAAI,KAAa;CAC/B,MAAMA,SAAqB,EAAE;CAE7B,SAAS,IAAI,MAAc,MAAgB;AACzC,MAAI,MAAM,IAAI,KAAK,EAAE;GACnB,MAAM,QAAQ,KAAK,QAAQ,KAAK;AAChC,OAAI,SAAS,EAAG,QAAO,KAAK,CAAC,GAAG,KAAK,MAAM,MAAM,EAAE,KAAK,CAAC;AACzD;;AAEF,MAAI,QAAQ,IAAI,KAAK,CAAE;AAEvB,UAAQ,IAAI,KAAK;AACjB,QAAM,IAAI,KAAK;EAEf,MAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,MAAI,KACF,MAAK,MAAM,OAAO,KAAK,aACrB,KAAI,KAAK,CAAC,GAAG,MAAM,KAAK,CAAC;AAI7B,QAAM,OAAO,KAAK;;AAGpB,MAAK,MAAM,QAAQ,MAAM,MAAM,CAC7B,KAAI,CAAC,QAAQ,IAAI,KAAK,CAAE,KAAI,MAAM,EAAE,CAAC;AAGvC,QAAO;;;;;AAMT,SAAgB,wBACd,OAC2C;CAC3C,MAAMC,UAAqD,EAAE;AAE7D,MAAK,MAAM,CAAC,MAAM,SAAS,OAAO;EAChC,MAAM,SAAS,KAAK,aAAa,QAAQ,QAAQ,CAAC,MAAM,IAAI,IAAI,CAAC;AACjE,MAAI,OAAO,SAAS,EAClB,SAAQ,KAAK;GAAE,UAAU;GAAM,SAAS;GAAQ,CAAC;;AAIrD,QAAO;;;;;AAMT,SAAgB,MAAM,OAA8B;CAClD,MAAMC,QAAkB,EAAE;AAC1B,OAAM,KAAK,iCAAiC;AAC5C,OAAM,KAAK,gBAAgB;AAC3B,OAAM,KAAK,sBAAsB;AAEjC,MAAK,MAAM,CAAC,MAAM,SAAS,OAAO;AAChC,OAAK,MAAM,OAAO,KAAK,aACrB,OAAM,KAAK,MAAM,KAAK,QAAQ,IAAI,IAAI;AAExC,MAAI,KAAK,aAAa,WAAW,EAC/B,OAAM,KAAK,MAAM,KAAK,IAAI;;AAI9B,OAAM,KAAK,IAAI;AACf,QAAO,MAAM,KAAK,KAAK;;;;;AAMzB,SAAgB,sBAAqC;AACnD,wBAAO,IAAI,KAAK;;;;;AAMlB,SAAgB,gBACd,OACA,MACA,MACA,cACM;AACN,OAAM,IAAI,MAAM;EACd;EACA;EACA;EACA,YAAY,EAAE;EACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-imports.d.ts","names":[],"sources":["../../../src/analysis/deps/parse-imports.ts"],"sourcesContent":[],"mappings":";;AAaA;;;;;;;;;;;iBAAgB,sBAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-imports.js","names":["imports: string[]","match: RegExpExecArray | null"],"sources":["../../../src/analysis/deps/parse-imports.ts"],"sourcesContent":["/**\n * Import parsing utilities for dependency analysis.\n * Extracted from cli-contracts/src/commands/deps/parse-imports.ts\n */\n\n/**\n * Parse spec imports from source code.\n * Returns the names of imported specs based on file naming conventions.\n *\n * @param sourceCode - The source code to parse\n * @param fromFilePath - The path of the file being parsed (for relative resolution)\n * @returns Array of imported spec names\n */\nexport function parseImportedSpecNames(\n sourceCode: string,\n _fromFilePath: string\n): string[] {\n const imports: string[] = [];\n\n // Capture relative imports that reference spec-ish files.\n // Examples:\n // import x from './foo.contracts'\n // import { y } from '../bar.event.ts'\n const importRegex =\n /import\\s+.*?\\s+from\\s+['\"]([^'\"]+\\.(?:contracts|event|presentation|workflow|data-view|migration|telemetry|experiment|app-config|integration|knowledge)(?:\\.[jt]s)?)['\"]/g;\n\n let match: RegExpExecArray | null;\n while ((match = importRegex.exec(sourceCode)) !== null) {\n const importPath = match[1];\n if (!importPath) continue;\n if (!importPath.startsWith('.') && !importPath.startsWith('/')) continue;\n\n // Extract base name from the import path\n const pathParts = importPath.split('/');\n const base = pathParts[pathParts.length - 1] ?? '';\n\n const name = base\n .replace(/\\.(ts|js)$/, '')\n .replace(\n /\\.(contracts|event|presentation|workflow|data-view|migration|telemetry|experiment|app-config|integration|knowledge)$/,\n ''\n );\n\n if (name.length > 0) {\n imports.push(name);\n }\n }\n\n return Array.from(new Set(imports)).sort((a, b) => a.localeCompare(b));\n}\n"],"mappings":";;;;;;;;;;;;;AAaA,SAAgB,uBACd,YACA,eACU;CACV,MAAMA,UAAoB,EAAE;CAM5B,MAAM,cACJ;CAEF,IAAIC;AACJ,SAAQ,QAAQ,YAAY,KAAK,WAAW,MAAM,MAAM;EACtD,MAAM,aAAa,MAAM;AACzB,MAAI,CAAC,WAAY;AACjB,MAAI,CAAC,WAAW,WAAW,IAAI,IAAI,CAAC,WAAW,WAAW,IAAI,CAAE;EAGhE,MAAM,YAAY,WAAW,MAAM,IAAI;EAGvC,MAAM,QAFO,UAAU,UAAU,SAAS,MAAM,IAG7C,QAAQ,cAAc,GAAG,CACzB,QACC,wHACA,GACD;AAEH,MAAI,KAAK,SAAS,EAChB,SAAQ,KAAK,KAAK;;AAItB,QAAO,MAAM,KAAK,IAAI,IAAI,QAAQ,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -7,4 +7,5 @@ import { SemanticDiffItem, SemanticDiffOptions } from "../../types/analysis-type
|
|
|
7
7
|
*/
|
|
8
8
|
declare function computeSemanticDiff(aCode: string, aPath: string, bCode: string, bPath: string, options?: SemanticDiffOptions): SemanticDiffItem[];
|
|
9
9
|
//#endregion
|
|
10
|
-
export { computeSemanticDiff };
|
|
10
|
+
export { computeSemanticDiff };
|
|
11
|
+
//# sourceMappingURL=semantic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic.d.ts","names":[],"sources":["../../../src/analysis/diff/semantic.ts"],"sourcesContent":[],"mappings":";;;;;;;iBAegB,mBAAA,uEAKL,sBACR"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic.js","names":["diffs: SemanticDiffItem[]","order: Record<string, number>"],"sources":["../../../src/analysis/diff/semantic.ts"],"sourcesContent":["/**\n * Semantic diff computation for contract specs.\n * Extracted from cli-contracts/src/commands/diff/semantic.ts\n */\n\nimport type {\n SemanticDiffItem,\n SemanticDiffOptions,\n SpecScanResult,\n} from '../../types/analysis-types';\nimport { scanSpecSource } from '../spec-scan';\n\n/**\n * Compute semantic differences between two spec sources.\n */\nexport function computeSemanticDiff(\n aCode: string,\n aPath: string,\n bCode: string,\n bPath: string,\n options: SemanticDiffOptions = {}\n): SemanticDiffItem[] {\n const a = scanSpecSource(aCode, aPath);\n const b = scanSpecSource(bCode, bPath);\n\n const diffs: SemanticDiffItem[] = [];\n\n compareScalar(diffs, 'specType', a.specType, b.specType, {\n breaking: true,\n label: 'Spec type',\n });\n\n compareScalar(diffs, 'name', a.name, b.name, {\n breaking: true,\n label: 'Name',\n });\n compareScalar(diffs, 'version', a.version, b.version, {\n breaking: true,\n label: 'Version',\n });\n compareScalar(diffs, 'kind', a.kind, b.kind, {\n breaking: true,\n label: 'Kind',\n });\n\n compareScalar(diffs, 'stability', a.stability, b.stability, {\n breaking: isStabilityDowngrade(a, b),\n label: 'Stability',\n });\n\n compareArray(diffs, 'owners', a.owners ?? [], b.owners ?? [], {\n label: 'Owners',\n });\n compareArray(diffs, 'tags', a.tags ?? [], b.tags ?? [], { label: 'Tags' });\n\n compareStructuralHints(diffs, a, b);\n\n const filtered = options.breakingOnly\n ? diffs.filter((d) => d.type === 'breaking')\n : diffs;\n\n return filtered;\n}\n\nfunction compareScalar(\n diffs: SemanticDiffItem[],\n path: string,\n a: unknown,\n b: unknown,\n config: { breaking: boolean; label: string }\n) {\n if (a === b) return;\n diffs.push({\n type: config.breaking ? 'breaking' : 'changed',\n path,\n oldValue: a,\n newValue: b,\n description: `${config.label} changed`,\n });\n}\n\nfunction compareArray(\n diffs: SemanticDiffItem[],\n path: string,\n a: string[],\n b: string[],\n config: { label: string }\n) {\n const aSorted = [...a].sort();\n const bSorted = [...b].sort();\n if (JSON.stringify(aSorted) === JSON.stringify(bSorted)) return;\n\n diffs.push({\n type: 'changed',\n path,\n oldValue: aSorted,\n newValue: bSorted,\n description: `${config.label} changed`,\n });\n}\n\nfunction isStabilityDowngrade(a: SpecScanResult, b: SpecScanResult): boolean {\n const order: Record<string, number> = {\n experimental: 0,\n beta: 1,\n stable: 2,\n deprecated: 3,\n };\n const aValue = a.stability ? (order[a.stability] ?? 0) : 0;\n const bValue = b.stability ? (order[b.stability] ?? 0) : 0;\n // Moving toward deprecated is effectively a breaking signal for consumers.\n return bValue > aValue;\n}\n\nfunction compareStructuralHints(\n diffs: SemanticDiffItem[],\n a: SpecScanResult,\n b: SpecScanResult\n) {\n // For operations these sections are usually required; missing them is breaking.\n compareScalar(diffs, 'hasMeta', a.hasMeta, b.hasMeta, {\n breaking: a.specType === 'operation' || b.specType === 'operation',\n label: 'meta section presence',\n });\n compareScalar(diffs, 'hasIo', a.hasIo, b.hasIo, {\n breaking: a.specType === 'operation' || b.specType === 'operation',\n label: 'io section presence',\n });\n compareScalar(diffs, 'hasPolicy', a.hasPolicy, b.hasPolicy, {\n breaking: a.specType === 'operation' || b.specType === 'operation',\n label: 'policy section presence',\n });\n compareScalar(diffs, 'hasPayload', a.hasPayload, b.hasPayload, {\n breaking: a.specType === 'event' || b.specType === 'event',\n label: 'payload section presence',\n });\n compareScalar(diffs, 'hasContent', a.hasContent, b.hasContent, {\n breaking: a.specType === 'presentation' || b.specType === 'presentation',\n label: 'content section presence',\n });\n compareScalar(diffs, 'hasDefinition', a.hasDefinition, b.hasDefinition, {\n breaking: a.specType === 'workflow' || b.specType === 'workflow',\n label: 'definition section presence',\n });\n}\n"],"mappings":";;;;;;AAeA,SAAgB,oBACd,OACA,OACA,OACA,OACA,UAA+B,EAAE,EACb;CACpB,MAAM,IAAI,eAAe,OAAO,MAAM;CACtC,MAAM,IAAI,eAAe,OAAO,MAAM;CAEtC,MAAMA,QAA4B,EAAE;AAEpC,eAAc,OAAO,YAAY,EAAE,UAAU,EAAE,UAAU;EACvD,UAAU;EACV,OAAO;EACR,CAAC;AAEF,eAAc,OAAO,QAAQ,EAAE,MAAM,EAAE,MAAM;EAC3C,UAAU;EACV,OAAO;EACR,CAAC;AACF,eAAc,OAAO,WAAW,EAAE,SAAS,EAAE,SAAS;EACpD,UAAU;EACV,OAAO;EACR,CAAC;AACF,eAAc,OAAO,QAAQ,EAAE,MAAM,EAAE,MAAM;EAC3C,UAAU;EACV,OAAO;EACR,CAAC;AAEF,eAAc,OAAO,aAAa,EAAE,WAAW,EAAE,WAAW;EAC1D,UAAU,qBAAqB,GAAG,EAAE;EACpC,OAAO;EACR,CAAC;AAEF,cAAa,OAAO,UAAU,EAAE,UAAU,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAC5D,OAAO,UACR,CAAC;AACF,cAAa,OAAO,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,QAAQ,CAAC;AAE1E,wBAAuB,OAAO,GAAG,EAAE;AAMnC,QAJiB,QAAQ,eACrB,MAAM,QAAQ,MAAM,EAAE,SAAS,WAAW,GAC1C;;AAKN,SAAS,cACP,OACA,MACA,GACA,GACA,QACA;AACA,KAAI,MAAM,EAAG;AACb,OAAM,KAAK;EACT,MAAM,OAAO,WAAW,aAAa;EACrC;EACA,UAAU;EACV,UAAU;EACV,aAAa,GAAG,OAAO,MAAM;EAC9B,CAAC;;AAGJ,SAAS,aACP,OACA,MACA,GACA,GACA,QACA;CACA,MAAM,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM;CAC7B,MAAM,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM;AAC7B,KAAI,KAAK,UAAU,QAAQ,KAAK,KAAK,UAAU,QAAQ,CAAE;AAEzD,OAAM,KAAK;EACT,MAAM;EACN;EACA,UAAU;EACV,UAAU;EACV,aAAa,GAAG,OAAO,MAAM;EAC9B,CAAC;;AAGJ,SAAS,qBAAqB,GAAmB,GAA4B;CAC3E,MAAMC,QAAgC;EACpC,cAAc;EACd,MAAM;EACN,QAAQ;EACR,YAAY;EACb;CACD,MAAM,SAAS,EAAE,YAAa,MAAM,EAAE,cAAc,IAAK;AAGzD,SAFe,EAAE,YAAa,MAAM,EAAE,cAAc,IAAK,KAEzC;;AAGlB,SAAS,uBACP,OACA,GACA,GACA;AAEA,eAAc,OAAO,WAAW,EAAE,SAAS,EAAE,SAAS;EACpD,UAAU,EAAE,aAAa,eAAe,EAAE,aAAa;EACvD,OAAO;EACR,CAAC;AACF,eAAc,OAAO,SAAS,EAAE,OAAO,EAAE,OAAO;EAC9C,UAAU,EAAE,aAAa,eAAe,EAAE,aAAa;EACvD,OAAO;EACR,CAAC;AACF,eAAc,OAAO,aAAa,EAAE,WAAW,EAAE,WAAW;EAC1D,UAAU,EAAE,aAAa,eAAe,EAAE,aAAa;EACvD,OAAO;EACR,CAAC;AACF,eAAc,OAAO,cAAc,EAAE,YAAY,EAAE,YAAY;EAC7D,UAAU,EAAE,aAAa,WAAW,EAAE,aAAa;EACnD,OAAO;EACR,CAAC;AACF,eAAc,OAAO,cAAc,EAAE,YAAY,EAAE,YAAY;EAC7D,UAAU,EAAE,aAAa,kBAAkB,EAAE,aAAa;EAC1D,OAAO;EACR,CAAC;AACF,eAAc,OAAO,iBAAiB,EAAE,eAAe,EAAE,eAAe;EACtE,UAAU,EAAE,aAAa,cAAc,EAAE,aAAa;EACtD,OAAO;EACR,CAAC"}
|
|
@@ -11,4 +11,5 @@ declare function isFeatureFile(filePath: string): boolean;
|
|
|
11
11
|
*/
|
|
12
12
|
declare function scanFeatureSource(code: string, filePath: string): FeatureScanResult;
|
|
13
13
|
//#endregion
|
|
14
|
-
export { isFeatureFile, scanFeatureSource };
|
|
14
|
+
export { isFeatureFile, scanFeatureSource };
|
|
15
|
+
//# sourceMappingURL=feature-scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-scan.d.ts","names":[],"sources":["../../src/analysis/feature-scan.ts"],"sourcesContent":[],"mappings":";;;;;;;iBAYgB,aAAA;;;;iBAOA,iBAAA,kCAGb"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-scan.js","names":["refs: RefInfo[]","provides: RefInfo[]","requires: RefInfo[]","match: RegExpExecArray | null","links: { op: RefInfo; pres: RefInfo }[]"],"sources":["../../src/analysis/feature-scan.ts"],"sourcesContent":["/**\n * Feature file scanning utilities.\n *\n * Extracts FeatureModuleSpec metadata from source code without execution.\n */\n\nimport type { FeatureScanResult, RefInfo } from '../types/analysis-types';\nimport type { Stability } from '../types/spec-types';\n\n/**\n * Check if a file is a feature file based on naming conventions.\n */\nexport function isFeatureFile(filePath: string): boolean {\n return filePath.includes('.feature.');\n}\n\n/**\n * Scan a feature source file to extract metadata.\n */\nexport function scanFeatureSource(\n code: string,\n filePath: string\n): FeatureScanResult {\n const key = matchStringField(code, 'key') ?? extractKeyFromFilePath(filePath);\n const title = matchStringField(code, 'title') ?? undefined;\n const description = matchStringField(code, 'description') ?? undefined;\n const domain = matchStringField(code, 'domain') ?? undefined;\n const stabilityRaw = matchStringField(code, 'stability');\n const stability = isStability(stabilityRaw) ? stabilityRaw : undefined;\n const owners = matchStringArrayField(code, 'owners');\n const tags = matchStringArrayField(code, 'tags');\n\n // Extract operations\n const operations = extractRefsFromArray(code, 'operations');\n\n // Extract events\n const events = extractRefsFromArray(code, 'events');\n\n // Extract presentations\n const presentations = extractRefsFromArray(code, 'presentations');\n\n // Extract experiments\n const experiments = extractRefsFromArray(code, 'experiments');\n\n // Extract capabilities\n const capabilities = extractCapabilities(code);\n\n // Extract op to presentation links\n const opToPresentationLinks = extractOpToPresentationLinks(code);\n\n return {\n filePath,\n key,\n title,\n description,\n domain,\n stability,\n owners,\n tags,\n operations,\n events,\n presentations,\n experiments,\n capabilities,\n opToPresentationLinks,\n };\n}\n\n/**\n * Extract refs from a named array (e.g., operations, events, presentations).\n */\nfunction extractRefsFromArray(code: string, fieldName: string): RefInfo[] {\n const refs: RefInfo[] = [];\n\n // Match the array section\n const arrayPattern = new RegExp(\n `${escapeRegex(fieldName)}\\\\s*:\\\\s*\\\\[([\\\\s\\\\S]*?)\\\\]`,\n 'm'\n );\n const arrayMatch = code.match(arrayPattern);\n\n if (!arrayMatch?.[1]) return refs;\n\n // Extract each { name: 'x', version: N } entry\n const refPattern = /\\{\\s*name:\\s*['\"]([^'\"]+)['\"]\\s*,\\s*version:\\s*(\\d+)/g;\n let match;\n while ((match = refPattern.exec(arrayMatch[1])) !== null) {\n if (match[1] && match[2]) {\n refs.push({\n name: match[1],\n version: Number(match[2]),\n });\n }\n }\n\n return refs;\n}\n\n/**\n * Extract capability bindings (provides and requires).\n */\nfunction extractCapabilities(code: string): {\n provides: RefInfo[];\n requires: RefInfo[];\n} {\n const provides: RefInfo[] = [];\n const requires: RefInfo[] = [];\n\n // Match the capabilities section\n const capabilitiesMatch = code.match(/capabilities\\s*:\\s*\\{([\\s\\S]*?)\\}/);\n if (!capabilitiesMatch?.[1]) {\n return { provides, requires };\n }\n\n const capabilitiesContent = capabilitiesMatch[1];\n\n // Extract provides\n const providesMatch = capabilitiesContent.match(\n /provides\\s*:\\s*\\[([\\s\\S]*?)\\]/\n );\n if (providesMatch?.[1]) {\n const refPattern = /\\{\\s*key:\\s*['\"]([^'\"]+)['\"]\\s*,\\s*version:\\s*(\\d+)/g;\n let match;\n while ((match = refPattern.exec(providesMatch[1])) !== null) {\n if (match[1] && match[2]) {\n provides.push({\n name: match[1],\n version: Number(match[2]),\n });\n }\n }\n }\n\n // Extract requires\n const requiresMatch = capabilitiesContent.match(\n /requires\\s*:\\s*\\[([\\s\\S]*?)\\]/\n );\n if (requiresMatch?.[1]) {\n // Requires can have key+version or just key\n const refPatternWithVersion =\n /\\{\\s*key:\\s*['\"]([^'\"]+)['\"]\\s*,\\s*version:\\s*(\\d+)/g;\n const refPatternKeyOnly = /\\{\\s*key:\\s*['\"]([^'\"]+)['\"]\\s*\\}/g;\n\n let match: RegExpExecArray | null = null;\n while ((match = refPatternWithVersion.exec(requiresMatch[1])) !== null) {\n if (match[1] && match[2]) {\n requires.push({\n name: match[1],\n version: Number(match[2]),\n });\n }\n }\n\n // Also match key-only requires (version defaults to 1)\n while ((match = refPatternKeyOnly.exec(requiresMatch[1])) !== null) {\n if (match && match[1]) {\n // Check if we already added this with a version\n const alreadyExists = requires.some((r) => r.name === match![1]!);\n if (!alreadyExists) {\n requires.push({\n name: match[1],\n version: 1, // Default version\n });\n }\n }\n }\n }\n\n return { provides, requires };\n}\n\n/**\n * Extract opToPresentation links.\n */\nfunction extractOpToPresentationLinks(\n code: string\n): { op: RefInfo; pres: RefInfo }[] {\n const links: { op: RefInfo; pres: RefInfo }[] = [];\n\n // Match the opToPresentation array\n const arrayMatch = code.match(/opToPresentation\\s*:\\s*\\[([\\s\\S]*?)\\]/);\n if (!arrayMatch?.[1]) return links;\n\n // Match each link entry\n // Pattern: { op: { name: 'x', version: N }, pres: { name: 'y', version: M } }\n const linkPattern =\n /\\{\\s*op:\\s*\\{\\s*name:\\s*['\"]([^'\"]+)['\"]\\s*,\\s*version:\\s*(\\d+)\\s*\\}\\s*,\\s*pres:\\s*\\{\\s*name:\\s*['\"]([^'\"]+)['\"]\\s*,\\s*version:\\s*(\\d+)\\s*\\}/g;\n\n let match;\n while ((match = linkPattern.exec(arrayMatch[1])) !== null) {\n if (match[1] && match[2] && match[3] && match[4]) {\n links.push({\n op: { name: match[1], version: Number(match[2]) },\n pres: { name: match[3], version: Number(match[4]) },\n });\n }\n }\n\n return links;\n}\n\n/**\n * Extract key from file path as fallback.\n */\nfunction extractKeyFromFilePath(filePath: string): string {\n const fileName = filePath.split('/').pop() ?? filePath;\n return fileName\n .replace(/\\.feature\\.[jt]s$/, '')\n .replace(/[^a-zA-Z0-9-]/g, '-');\n}\n\n/**\n * Match a string field in source code.\n */\nfunction matchStringField(code: string, field: string): string | null {\n const regex = new RegExp(`${escapeRegex(field)}\\\\s*:\\\\s*['\"]([^'\"]+)['\"]`);\n const match = code.match(regex);\n return match?.[1] ?? null;\n}\n\n/**\n * Match a string array field in source code.\n */\nfunction matchStringArrayField(\n code: string,\n field: string\n): string[] | undefined {\n const regex = new RegExp(`${escapeRegex(field)}\\\\s*:\\\\s*\\\\[([\\\\s\\\\S]*?)\\\\]`);\n const match = code.match(regex);\n if (!match?.[1]) return undefined;\n\n const inner = match[1];\n const items = Array.from(inner.matchAll(/['\"]([^'\"]+)['\"]/g))\n .map((m) => m[1])\n .filter(\n (value): value is string => typeof value === 'string' && value.length > 0\n );\n\n return items.length > 0 ? items : undefined;\n}\n\n/**\n * Check if a value is a valid stability.\n */\nfunction isStability(value: string | null): value is Stability {\n return (\n value === 'experimental' ||\n value === 'beta' ||\n value === 'stable' ||\n value === 'deprecated'\n );\n}\n\n/**\n * Escape regex special characters.\n */\nfunction escapeRegex(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n"],"mappings":"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"}
|
|
@@ -30,4 +30,5 @@ declare function extractTestRefs(code: string): RefInfo[] | undefined;
|
|
|
30
30
|
*/
|
|
31
31
|
declare function scanAllSpecsFromSource(code: string, filePath: string): SpecScanResult[];
|
|
32
32
|
//#endregion
|
|
33
|
-
export { extractEmittedEvents, extractPolicyRefs, extractTestRefs, inferSpecTypeFromFilePath, scanAllSpecsFromSource, scanSpecSource };
|
|
33
|
+
export { extractEmittedEvents, extractPolicyRefs, extractTestRefs, inferSpecTypeFromFilePath, scanAllSpecsFromSource, scanSpecSource };
|
|
34
|
+
//# sourceMappingURL=spec-scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-scan.d.ts","names":[],"sources":["../../src/analysis/spec-scan.ts"],"sourcesContent":[],"mappings":";;;;AA+GA;AAgCA;AA0BA;AAgMA;iBAxVgB,yBAAA,oBAA6C;;;;iBAyC7C,cAAA,kCAAgD;;;;;iBAqDhD,oBAAA,gBAAoC;;;;iBAgCpC,iBAAA,gBAAiC;;;;iBA0BjC,eAAA,gBAA+B;;;;;iBAgM/B,sBAAA,kCAGb"}
|
|
@@ -341,4 +341,5 @@ function scanAllSpecsFromSource(code, filePath) {
|
|
|
341
341
|
}
|
|
342
342
|
|
|
343
343
|
//#endregion
|
|
344
|
-
export { extractEmittedEvents, extractPolicyRefs, extractTestRefs, inferSpecTypeFromFilePath, scanAllSpecsFromSource, scanSpecSource };
|
|
344
|
+
export { extractEmittedEvents, extractPolicyRefs, extractTestRefs, inferSpecTypeFromFilePath, scanAllSpecsFromSource, scanSpecSource };
|
|
345
|
+
//# sourceMappingURL=spec-scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-scan.js","names":["events: RefInfo[]","policies: RefInfo[]","tests: RefInfo[]","results: SpecScanResult[]"],"sources":["../../src/analysis/spec-scan.ts"],"sourcesContent":["/**\n * Spec source scanning utilities.\n * Extracted from cli-contracts/src/utils/spec-scan.ts\n */\n\nimport type {\n AnalyzedSpecType,\n AnalyzedOperationKind,\n SpecScanResult,\n RefInfo,\n} from '../types/analysis-types';\nimport type { Stability } from '../types/spec-types';\n\n/**\n * Infer spec type from file path based on naming conventions.\n * Supports all contract types from @lssm/lib.contracts.\n */\nexport function inferSpecTypeFromFilePath(filePath: string): AnalyzedSpecType {\n // Check more specific patterns first\n // Operation patterns: .contracts. OR /contracts/ directory\n if (filePath.includes('.contracts.') || filePath.includes('/contracts/'))\n return 'operation';\n\n // Event patterns: .event. OR /events/ OR /events.ts\n if (\n filePath.includes('.event.') ||\n filePath.includes('/events/') ||\n filePath.endsWith('/events.ts')\n )\n return 'event';\n\n // Presentation patterns: .presentation. OR /presentations/ OR /presentations.ts\n if (\n filePath.includes('.presentation.') ||\n filePath.includes('/presentations/') ||\n filePath.endsWith('/presentations.ts')\n )\n return 'presentation';\n\n if (filePath.includes('.feature.')) return 'feature';\n if (filePath.includes('.capability.')) return 'capability';\n if (filePath.includes('.data-view.')) return 'data-view';\n if (filePath.includes('.form.')) return 'form';\n if (filePath.includes('.migration.')) return 'migration';\n if (filePath.includes('.workflow.')) return 'workflow';\n if (filePath.includes('.experiment.')) return 'experiment';\n if (filePath.includes('.integration.')) return 'integration';\n if (filePath.includes('.knowledge.')) return 'knowledge';\n if (filePath.includes('.telemetry.')) return 'telemetry';\n if (filePath.includes('.app-config.')) return 'app-config';\n if (filePath.includes('.policy.')) return 'policy';\n if (filePath.includes('.test-spec.')) return 'test-spec';\n return 'unknown';\n}\n\n/**\n * Scan spec source code to extract metadata without executing it.\n */\nexport function scanSpecSource(code: string, filePath: string): SpecScanResult {\n const specType = inferSpecTypeFromFilePath(filePath);\n\n const name = matchStringField(code, 'name');\n const description = matchStringField(code, 'description');\n const stabilityRaw = matchStringField(code, 'stability');\n const stability = isStability(stabilityRaw) ? stabilityRaw : undefined;\n const owners = matchStringArrayField(code, 'owners');\n const tags = matchStringArrayField(code, 'tags');\n\n const version = matchNumberField(code, 'version');\n const kind = inferOperationKind(code);\n\n const hasMeta = /meta\\s*:\\s*{/.test(code);\n const hasIo = /\\bio\\s*:\\s*{/.test(code);\n const hasPolicy = /\\bpolicy\\s*:\\s*{/.test(code);\n const hasPayload = /\\bpayload\\s*:\\s*{/.test(code);\n const hasContent = /\\bcontent\\s*:\\s*{/.test(code);\n const hasDefinition = /\\bdefinition\\s*:\\s*{/.test(code);\n\n // Extract references from operations\n const emittedEvents =\n specType === 'operation' ? extractEmittedEvents(code) : undefined;\n const policyRefs =\n specType === 'operation' ? extractPolicyRefs(code) : undefined;\n const testRefs = extractTestRefs(code);\n\n return {\n filePath,\n specType,\n name: name ?? undefined,\n description: description ?? undefined,\n stability,\n owners,\n tags,\n version: version ?? undefined,\n kind,\n hasMeta,\n hasIo,\n hasPolicy,\n hasPayload,\n hasContent,\n hasDefinition,\n emittedEvents,\n policyRefs,\n testRefs,\n };\n}\n\n/**\n * Extract emitted event refs from operation spec source.\n * Looks for sideEffects.emits array entries.\n */\nexport function extractEmittedEvents(code: string): RefInfo[] | undefined {\n const events: RefInfo[] = [];\n\n // Match inline emit declarations: { name: 'x', version: N, ... }\n const inlinePattern = /\\{\\s*name:\\s*['\"]([^'\"]+)['\"]\\s*,\\s*version:\\s*(\\d+)/g;\n let match;\n while ((match = inlinePattern.exec(code)) !== null) {\n if (match[1] && match[2]) {\n events.push({\n name: match[1],\n version: Number(match[2]),\n });\n }\n }\n\n // Match ref pattern: { ref: SomeEventSpec, ... }\n // We can't fully resolve these without execution, but we can note they exist\n const refPattern = /\\{\\s*ref:\\s*(\\w+)/g;\n while ((match = refPattern.exec(code)) !== null) {\n // Store a placeholder - actual resolution needs runtime\n if (match[1] && !match[1].startsWith('when')) {\n // We can't extract name/version from a variable ref statically\n // This is noted for completeness but won't be fully resolvable\n }\n }\n\n return events.length > 0 ? events : undefined;\n}\n\n/**\n * Extract policy refs from operation spec source.\n */\nexport function extractPolicyRefs(code: string): RefInfo[] | undefined {\n const policies: RefInfo[] = [];\n\n // Match policy ref pattern in policies array\n const policyPattern = /\\{\\s*name:\\s*['\"]([^'\"]+)['\"]\\s*,\\s*version:\\s*(\\d+)/g;\n\n // Only look within policy section\n const policySectionMatch = code.match(/policies\\s*:\\s*\\[([\\s\\S]*?)\\]/);\n if (policySectionMatch?.[1]) {\n let match;\n while ((match = policyPattern.exec(policySectionMatch[1])) !== null) {\n if (match[1] && match[2]) {\n policies.push({\n name: match[1],\n version: Number(match[2]),\n });\n }\n }\n }\n\n return policies.length > 0 ? policies : undefined;\n}\n\n/**\n * Extract test spec refs.\n */\nexport function extractTestRefs(code: string): RefInfo[] | undefined {\n const tests: RefInfo[] = [];\n\n // Look for tests array\n const testsSectionMatch = code.match(/tests\\s*:\\s*\\[([\\s\\S]*?)\\]/);\n if (testsSectionMatch?.[1]) {\n const refPattern = /\\{\\s*name:\\s*['\"]([^'\"]+)['\"]\\s*,\\s*version:\\s*(\\d+)/g;\n let match;\n while ((match = refPattern.exec(testsSectionMatch[1])) !== null) {\n if (match[1] && match[2]) {\n tests.push({\n name: match[1],\n version: Number(match[2]),\n });\n }\n }\n }\n\n return tests.length > 0 ? tests : undefined;\n}\n\nfunction matchStringField(code: string, field: string): string | null {\n const regex = new RegExp(`${escapeRegex(field)}\\\\s*:\\\\s*['\"]([^'\"]+)['\"]`);\n const match = code.match(regex);\n return match?.[1] ?? null;\n}\n\nfunction matchNumberField(code: string, field: string): number | null {\n const regex = new RegExp(`${escapeRegex(field)}\\\\s*:\\\\s*(\\\\d+)`);\n const match = code.match(regex);\n if (!match?.[1]) return null;\n const parsed = Number(match[1]);\n return Number.isFinite(parsed) ? parsed : null;\n}\n\nfunction matchStringArrayField(\n code: string,\n field: string\n): string[] | undefined {\n const regex = new RegExp(`${escapeRegex(field)}\\\\s*:\\\\s*\\\\[([\\\\s\\\\S]*?)\\\\]`);\n const match = code.match(regex);\n if (!match?.[1]) return undefined;\n\n const inner = match[1];\n const items = Array.from(inner.matchAll(/['\"]([^'\"]+)['\"]/g))\n .map((m) => m[1])\n .filter(\n (value): value is string => typeof value === 'string' && value.length > 0\n );\n\n return items.length > 0 ? items : undefined;\n}\n\nfunction isStability(value: string | null): value is Stability {\n return (\n value === 'experimental' ||\n value === 'beta' ||\n value === 'stable' ||\n value === 'deprecated'\n );\n}\n\nfunction escapeRegex(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Infer operation kind from source code.\n * First checks for defineCommand/defineQuery usage (which set kind automatically),\n * then falls back to explicit kind field.\n */\nfunction inferOperationKind(code: string): AnalyzedOperationKind {\n // Check for defineCommand/defineQuery usage first (they set kind automatically)\n if (/defineCommand\\s*\\(/.test(code)) return 'command';\n if (/defineQuery\\s*\\(/.test(code)) return 'query';\n // Fall back to explicit kind field\n const kindRaw = matchStringField(code, 'kind');\n return kindRaw === 'command' || kindRaw === 'query' ? kindRaw : 'unknown';\n}\n\n/**\n * Infer operation kind from a specific code block.\n */\nfunction inferOperationKindFromBlock(block: string): AnalyzedOperationKind {\n if (/defineCommand\\s*\\(/.test(block)) return 'command';\n if (/defineQuery\\s*\\(/.test(block)) return 'query';\n const kindRaw = matchStringField(block, 'kind');\n return kindRaw === 'command' || kindRaw === 'query' ? kindRaw : 'unknown';\n}\n\n/**\n * Extract name and version from a meta block.\n */\nfunction extractMetaFromBlock(\n block: string\n): { name: string; version: number } | null {\n const name = matchStringField(block, 'name');\n const version = matchNumberField(block, 'version');\n if (name && version !== null) {\n return { name, version };\n }\n return null;\n}\n\n/**\n * Define function patterns for all spec types.\n */\nconst DEFINE_FUNCTION_PATTERNS = [\n // Operations\n { pattern: /defineCommand\\s*\\(\\s*\\{/g, type: 'operation' as const },\n { pattern: /defineQuery\\s*\\(\\s*\\{/g, type: 'operation' as const },\n // Events\n { pattern: /defineEvent\\s*\\(\\s*\\{/g, type: 'event' as const },\n // Presentations (both v1 and v2 patterns)\n {\n pattern: /:\\s*PresentationDescriptorV2\\s*=\\s*\\{/g,\n type: 'presentation' as const,\n },\n {\n pattern: /:\\s*PresentationDescriptor\\s*=\\s*\\{/g,\n type: 'presentation' as const,\n },\n { pattern: /definePresentation\\s*\\(\\s*\\{/g, type: 'presentation' as const },\n // Capabilities\n { pattern: /defineCapability\\s*\\(\\s*\\{/g, type: 'capability' as const },\n // Workflows\n { pattern: /defineWorkflow\\s*\\(\\s*\\{/g, type: 'workflow' as const },\n // Experiments\n { pattern: /defineExperiment\\s*\\(\\s*\\{/g, type: 'experiment' as const },\n // Integrations\n { pattern: /defineIntegration\\s*\\(\\s*\\{/g, type: 'integration' as const },\n // Knowledge\n { pattern: /defineKnowledge\\s*\\(\\s*\\{/g, type: 'knowledge' as const },\n // Telemetry\n { pattern: /defineTelemetry\\s*\\(\\s*\\{/g, type: 'telemetry' as const },\n // App config\n { pattern: /defineAppConfig\\s*\\(\\s*\\{/g, type: 'app-config' as const },\n // Policy\n { pattern: /definePolicy\\s*\\(\\s*\\{/g, type: 'policy' as const },\n // Test spec\n { pattern: /defineTestSpec\\s*\\(\\s*\\{/g, type: 'test-spec' as const },\n // Data view\n { pattern: /defineDataView\\s*\\(\\s*\\{/g, type: 'data-view' as const },\n // Form\n { pattern: /defineForm\\s*\\(\\s*\\{/g, type: 'form' as const },\n // Migration\n { pattern: /defineMigration\\s*\\(\\s*\\{/g, type: 'migration' as const },\n];\n\n/**\n * Find matching closing brace for an opening brace.\n * Returns the index of the closing brace or -1 if not found.\n */\nfunction findMatchingBrace(code: string, startIndex: number): number {\n let depth = 0;\n let inString = false;\n let stringChar = '';\n\n for (let i = startIndex; i < code.length; i++) {\n const char = code[i];\n const prevChar = i > 0 ? code[i - 1] : '';\n\n // Handle string literals\n if ((char === '\"' || char === \"'\" || char === '`') && prevChar !== '\\\\') {\n if (!inString) {\n inString = true;\n stringChar = char;\n } else if (char === stringChar) {\n inString = false;\n }\n continue;\n }\n\n if (inString) continue;\n\n if (char === '{') {\n depth++;\n } else if (char === '}') {\n depth--;\n if (depth === 0) {\n return i;\n }\n }\n }\n\n return -1;\n}\n\n/**\n * Scan spec source code to extract ALL specs from a file.\n * This function finds multiple spec definitions in a single file.\n */\nexport function scanAllSpecsFromSource(\n code: string,\n filePath: string\n): SpecScanResult[] {\n const results: SpecScanResult[] = [];\n const baseSpecType = inferSpecTypeFromFilePath(filePath);\n\n // Track positions we've already processed to avoid duplicates\n const processedPositions = new Set<number>();\n\n for (const { pattern, type } of DEFINE_FUNCTION_PATTERNS) {\n // Reset the regex lastIndex\n pattern.lastIndex = 0;\n\n let match;\n while ((match = pattern.exec(code)) !== null) {\n const startPos = match.index;\n\n // Skip if we've already processed this position\n if (processedPositions.has(startPos)) continue;\n processedPositions.add(startPos);\n\n // Find the opening brace position\n const openBracePos = code.indexOf('{', startPos);\n if (openBracePos === -1) continue;\n\n // Find the matching closing brace\n const closeBracePos = findMatchingBrace(code, openBracePos);\n if (closeBracePos === -1) continue;\n\n // Extract the block content\n const block = code.slice(openBracePos, closeBracePos + 1);\n\n // Extract meta information\n const meta = extractMetaFromBlock(block);\n if (!meta) continue;\n\n // Extract additional metadata\n const description = matchStringField(block, 'description');\n const stabilityRaw = matchStringField(block, 'stability');\n const stability = isStability(stabilityRaw) ? stabilityRaw : undefined;\n const owners = matchStringArrayField(block, 'owners');\n const tags = matchStringArrayField(block, 'tags');\n\n const hasMeta = /meta\\s*:\\s*{/.test(block);\n const hasIo = /\\bio\\s*:\\s*{/.test(block);\n const hasPolicy = /\\bpolicy\\s*:\\s*{/.test(block);\n const hasPayload = /\\bpayload\\s*:\\s*{/.test(block);\n const hasContent = /\\bcontent\\s*:\\s*{/.test(block);\n const hasDefinition = /\\bdefinition\\s*:\\s*{/.test(block);\n\n // Infer kind for operations\n const kind =\n type === 'operation' ? inferOperationKindFromBlock(block) : 'unknown';\n\n // Extract references from operations\n const emittedEvents =\n type === 'operation' ? extractEmittedEvents(block) : undefined;\n const policyRefs =\n type === 'operation' ? extractPolicyRefs(block) : undefined;\n const testRefs = extractTestRefs(block);\n\n results.push({\n filePath,\n specType: type,\n name: meta.name,\n version: meta.version,\n description: description ?? undefined,\n stability,\n owners,\n tags,\n kind,\n hasMeta,\n hasIo,\n hasPolicy,\n hasPayload,\n hasContent,\n hasDefinition,\n emittedEvents,\n policyRefs,\n testRefs,\n });\n }\n }\n\n // If no specs found via patterns, fall back to file-type based scanning\n // This handles cases where the file uses non-standard patterns\n if (results.length === 0 && baseSpecType !== 'unknown') {\n const fallback = scanSpecSource(code, filePath);\n if (fallback.name && fallback.version !== undefined) {\n results.push(fallback);\n }\n }\n\n return results;\n}\n"],"mappings":"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"}
|
|
@@ -7,4 +7,5 @@ import { ValidationResult } from "../../types/analysis-types.js";
|
|
|
7
7
|
*/
|
|
8
8
|
declare function validateSpecStructure(code: string, fileName: string): ValidationResult;
|
|
9
9
|
//#endregion
|
|
10
|
-
export { validateSpecStructure };
|
|
10
|
+
export { validateSpecStructure };
|
|
11
|
+
//# sourceMappingURL=spec-structure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-structure.d.ts","names":[],"sources":["../../../src/analysis/validate/spec-structure.ts"],"sourcesContent":[],"mappings":";;;;;;;iBAYgB,qBAAA,kCAGb"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-structure.js","names":["errors: string[]","warnings: string[]"],"sources":["../../../src/analysis/validate/spec-structure.ts"],"sourcesContent":["/**\n * Spec structure validation utilities.\n * Extracted from cli-contracts/src/commands/validate/spec-checker.ts\n */\n\nimport type { ValidationResult } from '../../types/analysis-types';\n\nexport type { ValidationResult };\n\n/**\n * Validate spec structure based on source code and filename.\n */\nexport function validateSpecStructure(\n code: string,\n fileName: string\n): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // Check for required exports\n const hasExport = /export\\s+(const|let)\\s+\\w+/.test(code);\n if (!hasExport) {\n errors.push('No exported spec found');\n }\n\n // Validate operation specs\n if (fileName.includes('.contracts.')) {\n validateOperationSpec(code, errors, warnings);\n }\n\n // Validate event specs\n if (fileName.includes('.event.')) {\n validateEventSpec(code, errors, warnings);\n }\n\n // Validate presentation specs\n if (fileName.includes('.presentation.')) {\n validatePresentationSpec(code, errors, warnings);\n }\n\n if (fileName.includes('.workflow.')) {\n validateWorkflowSpec(code, errors, warnings);\n }\n\n if (fileName.includes('.data-view.')) {\n validateDataViewSpec(code, errors, warnings);\n }\n\n if (fileName.includes('.migration.')) {\n validateMigrationSpec(code, errors, warnings);\n }\n\n if (fileName.includes('.telemetry.')) {\n validateTelemetrySpec(code, errors, warnings);\n }\n\n if (fileName.includes('.experiment.')) {\n validateExperimentSpec(code, errors, warnings);\n }\n\n if (fileName.includes('.app-config.')) {\n validateAppConfigSpec(code, errors, warnings);\n }\n\n // Common validations\n validateCommonFields(code, errors, warnings);\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\n/**\n * Validate operation spec\n */\nfunction validateOperationSpec(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n // Check for defineCommand or defineQuery\n const hasDefine = /define(Command|Query)/.test(code);\n if (!hasDefine) {\n errors.push('Missing defineCommand or defineQuery call');\n }\n\n // Check for required meta fields\n if (!code.includes('meta:')) {\n errors.push('Missing meta section');\n }\n\n if (!code.includes('io:')) {\n errors.push('Missing io section');\n }\n\n if (!code.includes('policy:')) {\n errors.push('Missing policy section');\n }\n\n // Check for name\n if (!code.match(/name:\\s*['\"][^'\"]+['\"]/)) {\n errors.push('Missing or invalid name field');\n }\n\n // Check for version\n if (!code.match(/version:\\s*\\d+/)) {\n errors.push('Missing or invalid version field');\n }\n\n // Check for kind (defineCommand/defineQuery set it automatically, or explicit kind field)\n const hasDefineCommand = /defineCommand\\s*\\(/.test(code);\n const hasDefineQuery = /defineQuery\\s*\\(/.test(code);\n const hasExplicitKind = /kind:\\s*['\"](?:command|query)['\"]/.test(code);\n if (!hasDefineCommand && !hasDefineQuery && !hasExplicitKind) {\n errors.push(\n 'Missing kind: use defineCommand(), defineQuery(), or explicit kind field'\n );\n }\n\n // Warnings\n if (!code.includes('acceptance:')) {\n warnings.push('No acceptance scenarios defined');\n }\n\n if (!code.includes('examples:')) {\n warnings.push('No examples provided');\n }\n\n if (code.includes('TODO')) {\n warnings.push('Contains TODO items that need completion');\n }\n}\n\nfunction validateTelemetrySpec(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n if (!code.match(/:\\s*TelemetrySpec\\s*=/)) {\n errors.push('Missing TelemetrySpec type annotation');\n }\n\n if (!code.match(/meta:\\s*{[\\s\\S]*name:/)) {\n errors.push('TelemetrySpec.meta is required');\n }\n\n if (!code.includes('events:')) {\n errors.push('TelemetrySpec must declare events');\n }\n\n if (!code.match(/privacy:\\s*'(public|internal|pii|sensitive)'/)) {\n warnings.push('No explicit privacy classification found');\n }\n}\n\nfunction validateExperimentSpec(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n if (!code.match(/:\\s*ExperimentSpec\\s*=/)) {\n errors.push('Missing ExperimentSpec type annotation');\n }\n if (!code.includes('controlVariant')) {\n errors.push('ExperimentSpec must declare controlVariant');\n }\n if (!code.includes('variants:')) {\n errors.push('ExperimentSpec must declare variants');\n }\n if (!code.match(/allocation:\\s*{/)) {\n warnings.push('ExperimentSpec missing allocation configuration');\n }\n}\n\nfunction validateAppConfigSpec(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n if (!code.match(/:\\s*AppBlueprintSpec\\s*=/)) {\n errors.push('Missing AppBlueprintSpec type annotation');\n }\n if (!code.includes('meta:')) {\n errors.push('AppBlueprintSpec must define meta');\n }\n if (!code.includes('appId')) {\n warnings.push('AppBlueprint meta missing appId assignment');\n }\n if (!code.includes('capabilities')) {\n warnings.push('App blueprint spec does not declare capabilities');\n }\n}\n\n/**\n * Validate event spec\n */\nfunction validateEventSpec(code: string, errors: string[], warnings: string[]) {\n if (!code.includes('defineEvent')) {\n errors.push('Missing defineEvent call');\n }\n\n if (!code.match(/name:\\s*['\"][^'\"]+['\"]/)) {\n errors.push('Missing or invalid name field');\n }\n\n if (!code.match(/version:\\s*\\d+/)) {\n errors.push('Missing or invalid version field');\n }\n\n if (!code.includes('payload:')) {\n errors.push('Missing payload field');\n }\n\n // Check for past tense naming convention\n const nameMatch = code.match(/name:\\s*['\"]([^'\"]+)['\"]/);\n if (nameMatch?.[1]) {\n const eventName = nameMatch[1].split('.').pop() ?? '';\n if (!eventName.match(/(ed|created|updated|deleted|completed)$/i)) {\n warnings.push(\n 'Event name should use past tense (e.g., \"created\", \"updated\")'\n );\n }\n }\n}\n\n/**\n * Validate presentation spec\n */\nfunction validatePresentationSpec(\n code: string,\n errors: string[],\n _warnings: string[]\n) {\n if (!code.match(/:\\s*PresentationSpec\\s*=/)) {\n errors.push('Missing PresentationSpec type annotation');\n }\n\n if (!code.includes('meta:')) {\n errors.push('Missing meta section');\n }\n\n if (!code.includes('content:')) {\n errors.push('Missing content section');\n }\n\n if (!code.match(/kind:\\s*['\"](?:web_component|markdown|data)['\"]/)) {\n errors.push('Missing or invalid kind field');\n }\n}\n\nfunction validateWorkflowSpec(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n if (!code.match(/:\\s*WorkflowSpec\\s*=/)) {\n errors.push('Missing WorkflowSpec type annotation');\n }\n\n if (!code.includes('definition:')) {\n errors.push('Missing definition section');\n }\n\n if (!code.includes('steps:')) {\n errors.push('Workflow must declare steps');\n }\n\n if (!code.includes('transitions:')) {\n warnings.push(\n 'No transitions declared; workflow will complete after first step.'\n );\n }\n\n if (!code.match(/title:\\s*['\"][^'\"]+['\"]/)) {\n warnings.push('Missing workflow title');\n }\n\n if (!code.match(/domain:\\s*['\"][^'\"]+['\"]/)) {\n warnings.push('Missing domain field');\n }\n\n if (code.includes('TODO')) {\n warnings.push('Contains TODO items that need completion');\n }\n}\n\nfunction validateMigrationSpec(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n if (!code.match(/:\\s*MigrationSpec\\s*=/)) {\n errors.push('Missing MigrationSpec type annotation');\n }\n\n if (!code.includes('plan:')) {\n errors.push('Missing plan section');\n } else {\n if (!code.includes('up:')) {\n errors.push('Migration must define at least one up step');\n }\n }\n\n if (!code.match(/name:\\s*['\"][^'\"]+['\"]/)) {\n errors.push('Missing or invalid migration name');\n }\n\n if (!code.match(/version:\\s*\\d+/)) {\n errors.push('Missing or invalid migration version');\n }\n\n if (code.includes('TODO')) {\n warnings.push('Contains TODO items that need completion');\n }\n}\n\n/**\n * Validate common fields across all spec types\n */\nfunction validateCommonFields(\n code: string,\n errors: string[],\n warnings: string[]\n) {\n // Check for SchemaModel import\n if (\n code.includes('SchemaModel') &&\n !code.includes(\"from '@lssm/lib.schema'\")\n ) {\n errors.push('Missing import for SchemaModel from @lssm/lib.schema');\n }\n\n // Check for contracts import\n if (!code.includes(\"from '@lssm/lib.contracts'\")) {\n errors.push('Missing import from @lssm/lib.contracts');\n }\n\n // Check owners format\n const ownersMatch = code.match(/owners:\\s*\\[(.*?)\\]/s);\n if (ownersMatch?.[1]) {\n const ownersContent = ownersMatch[1];\n if (!ownersContent.includes('@')) {\n warnings.push('Owners should start with @ (e.g., \"@team\")');\n }\n }\n\n // Check for stability\n if (\n !code.match(/stability:\\s*['\"](?:experimental|beta|stable|deprecated)['\"]/)\n ) {\n warnings.push('Missing or invalid stability field');\n }\n}\n\nfunction validateDataViewSpec(\n code: string,\n errors: string[],\n _warnings: string[]\n) {\n if (!code.match(/:\\s*DataViewSpec\\s*=/)) {\n errors.push('Missing DataViewSpec type annotation');\n }\n if (!code.includes('meta:')) {\n errors.push('Missing meta section');\n }\n if (!code.includes('source:')) {\n errors.push('Missing source section');\n }\n if (!code.includes('view:')) {\n errors.push('Missing view section');\n }\n if (!code.match(/kind:\\s*['\"](list|table|detail|grid)['\"]/)) {\n errors.push('Missing or invalid view.kind (list/table/detail/grid)');\n }\n if (!code.match(/fields:\\s*\\[/)) {\n // Note: _warnings unused in this case, but kept for consistency with other validators\n errors.push('No fields defined for data view');\n }\n}\n"],"mappings":";;;;AAYA,SAAgB,sBACd,MACA,UACkB;CAClB,MAAMA,SAAmB,EAAE;CAC3B,MAAMC,WAAqB,EAAE;AAI7B,KAAI,CADc,6BAA6B,KAAK,KAAK,CAEvD,QAAO,KAAK,yBAAyB;AAIvC,KAAI,SAAS,SAAS,cAAc,CAClC,uBAAsB,MAAM,QAAQ,SAAS;AAI/C,KAAI,SAAS,SAAS,UAAU,CAC9B,mBAAkB,MAAM,QAAQ,SAAS;AAI3C,KAAI,SAAS,SAAS,iBAAiB,CACrC,0BAAyB,MAAM,QAAQ,SAAS;AAGlD,KAAI,SAAS,SAAS,aAAa,CACjC,sBAAqB,MAAM,QAAQ,SAAS;AAG9C,KAAI,SAAS,SAAS,cAAc,CAClC,sBAAqB,MAAM,QAAQ,SAAS;AAG9C,KAAI,SAAS,SAAS,cAAc,CAClC,uBAAsB,MAAM,QAAQ,SAAS;AAG/C,KAAI,SAAS,SAAS,cAAc,CAClC,uBAAsB,MAAM,QAAQ,SAAS;AAG/C,KAAI,SAAS,SAAS,eAAe,CACnC,wBAAuB,MAAM,QAAQ,SAAS;AAGhD,KAAI,SAAS,SAAS,eAAe,CACnC,uBAAsB,MAAM,QAAQ,SAAS;AAI/C,sBAAqB,MAAM,QAAQ,SAAS;AAE5C,QAAO;EACL,OAAO,OAAO,WAAW;EACzB;EACA;EACD;;;;;AAMH,SAAS,sBACP,MACA,QACA,UACA;AAGA,KAAI,CADc,wBAAwB,KAAK,KAAK,CAElD,QAAO,KAAK,4CAA4C;AAI1D,KAAI,CAAC,KAAK,SAAS,QAAQ,CACzB,QAAO,KAAK,uBAAuB;AAGrC,KAAI,CAAC,KAAK,SAAS,MAAM,CACvB,QAAO,KAAK,qBAAqB;AAGnC,KAAI,CAAC,KAAK,SAAS,UAAU,CAC3B,QAAO,KAAK,yBAAyB;AAIvC,KAAI,CAAC,KAAK,MAAM,yBAAyB,CACvC,QAAO,KAAK,gCAAgC;AAI9C,KAAI,CAAC,KAAK,MAAM,iBAAiB,CAC/B,QAAO,KAAK,mCAAmC;CAIjD,MAAM,mBAAmB,qBAAqB,KAAK,KAAK;CACxD,MAAM,iBAAiB,mBAAmB,KAAK,KAAK;CACpD,MAAM,kBAAkB,oCAAoC,KAAK,KAAK;AACtE,KAAI,CAAC,oBAAoB,CAAC,kBAAkB,CAAC,gBAC3C,QAAO,KACL,2EACD;AAIH,KAAI,CAAC,KAAK,SAAS,cAAc,CAC/B,UAAS,KAAK,kCAAkC;AAGlD,KAAI,CAAC,KAAK,SAAS,YAAY,CAC7B,UAAS,KAAK,uBAAuB;AAGvC,KAAI,KAAK,SAAS,OAAO,CACvB,UAAS,KAAK,2CAA2C;;AAI7D,SAAS,sBACP,MACA,QACA,UACA;AACA,KAAI,CAAC,KAAK,MAAM,wBAAwB,CACtC,QAAO,KAAK,wCAAwC;AAGtD,KAAI,CAAC,KAAK,MAAM,wBAAwB,CACtC,QAAO,KAAK,iCAAiC;AAG/C,KAAI,CAAC,KAAK,SAAS,UAAU,CAC3B,QAAO,KAAK,oCAAoC;AAGlD,KAAI,CAAC,KAAK,MAAM,+CAA+C,CAC7D,UAAS,KAAK,2CAA2C;;AAI7D,SAAS,uBACP,MACA,QACA,UACA;AACA,KAAI,CAAC,KAAK,MAAM,yBAAyB,CACvC,QAAO,KAAK,yCAAyC;AAEvD,KAAI,CAAC,KAAK,SAAS,iBAAiB,CAClC,QAAO,KAAK,6CAA6C;AAE3D,KAAI,CAAC,KAAK,SAAS,YAAY,CAC7B,QAAO,KAAK,uCAAuC;AAErD,KAAI,CAAC,KAAK,MAAM,kBAAkB,CAChC,UAAS,KAAK,kDAAkD;;AAIpE,SAAS,sBACP,MACA,QACA,UACA;AACA,KAAI,CAAC,KAAK,MAAM,2BAA2B,CACzC,QAAO,KAAK,2CAA2C;AAEzD,KAAI,CAAC,KAAK,SAAS,QAAQ,CACzB,QAAO,KAAK,oCAAoC;AAElD,KAAI,CAAC,KAAK,SAAS,QAAQ,CACzB,UAAS,KAAK,6CAA6C;AAE7D,KAAI,CAAC,KAAK,SAAS,eAAe,CAChC,UAAS,KAAK,mDAAmD;;;;;AAOrE,SAAS,kBAAkB,MAAc,QAAkB,UAAoB;AAC7E,KAAI,CAAC,KAAK,SAAS,cAAc,CAC/B,QAAO,KAAK,2BAA2B;AAGzC,KAAI,CAAC,KAAK,MAAM,yBAAyB,CACvC,QAAO,KAAK,gCAAgC;AAG9C,KAAI,CAAC,KAAK,MAAM,iBAAiB,CAC/B,QAAO,KAAK,mCAAmC;AAGjD,KAAI,CAAC,KAAK,SAAS,WAAW,CAC5B,QAAO,KAAK,wBAAwB;CAItC,MAAM,YAAY,KAAK,MAAM,2BAA2B;AACxD,KAAI,YAAY,IAEd;MAAI,EADc,UAAU,GAAG,MAAM,IAAI,CAAC,KAAK,IAAI,IACpC,MAAM,2CAA2C,CAC9D,UAAS,KACP,oEACD;;;;;;AAQP,SAAS,yBACP,MACA,QACA,WACA;AACA,KAAI,CAAC,KAAK,MAAM,2BAA2B,CACzC,QAAO,KAAK,2CAA2C;AAGzD,KAAI,CAAC,KAAK,SAAS,QAAQ,CACzB,QAAO,KAAK,uBAAuB;AAGrC,KAAI,CAAC,KAAK,SAAS,WAAW,CAC5B,QAAO,KAAK,0BAA0B;AAGxC,KAAI,CAAC,KAAK,MAAM,kDAAkD,CAChE,QAAO,KAAK,gCAAgC;;AAIhD,SAAS,qBACP,MACA,QACA,UACA;AACA,KAAI,CAAC,KAAK,MAAM,uBAAuB,CACrC,QAAO,KAAK,uCAAuC;AAGrD,KAAI,CAAC,KAAK,SAAS,cAAc,CAC/B,QAAO,KAAK,6BAA6B;AAG3C,KAAI,CAAC,KAAK,SAAS,SAAS,CAC1B,QAAO,KAAK,8BAA8B;AAG5C,KAAI,CAAC,KAAK,SAAS,eAAe,CAChC,UAAS,KACP,oEACD;AAGH,KAAI,CAAC,KAAK,MAAM,0BAA0B,CACxC,UAAS,KAAK,yBAAyB;AAGzC,KAAI,CAAC,KAAK,MAAM,2BAA2B,CACzC,UAAS,KAAK,uBAAuB;AAGvC,KAAI,KAAK,SAAS,OAAO,CACvB,UAAS,KAAK,2CAA2C;;AAI7D,SAAS,sBACP,MACA,QACA,UACA;AACA,KAAI,CAAC,KAAK,MAAM,wBAAwB,CACtC,QAAO,KAAK,wCAAwC;AAGtD,KAAI,CAAC,KAAK,SAAS,QAAQ,CACzB,QAAO,KAAK,uBAAuB;UAE/B,CAAC,KAAK,SAAS,MAAM,CACvB,QAAO,KAAK,6CAA6C;AAI7D,KAAI,CAAC,KAAK,MAAM,yBAAyB,CACvC,QAAO,KAAK,oCAAoC;AAGlD,KAAI,CAAC,KAAK,MAAM,iBAAiB,CAC/B,QAAO,KAAK,uCAAuC;AAGrD,KAAI,KAAK,SAAS,OAAO,CACvB,UAAS,KAAK,2CAA2C;;;;;AAO7D,SAAS,qBACP,MACA,QACA,UACA;AAEA,KACE,KAAK,SAAS,cAAc,IAC5B,CAAC,KAAK,SAAS,0BAA0B,CAEzC,QAAO,KAAK,uDAAuD;AAIrE,KAAI,CAAC,KAAK,SAAS,6BAA6B,CAC9C,QAAO,KAAK,0CAA0C;CAIxD,MAAM,cAAc,KAAK,MAAM,uBAAuB;AACtD,KAAI,cAAc,IAEhB;MAAI,CADkB,YAAY,GACf,SAAS,IAAI,CAC9B,UAAS,KAAK,+CAA6C;;AAK/D,KACE,CAAC,KAAK,MAAM,+DAA+D,CAE3E,UAAS,KAAK,qCAAqC;;AAIvD,SAAS,qBACP,MACA,QACA,WACA;AACA,KAAI,CAAC,KAAK,MAAM,uBAAuB,CACrC,QAAO,KAAK,uCAAuC;AAErD,KAAI,CAAC,KAAK,SAAS,QAAQ,CACzB,QAAO,KAAK,uBAAuB;AAErC,KAAI,CAAC,KAAK,SAAS,UAAU,CAC3B,QAAO,KAAK,yBAAyB;AAEvC,KAAI,CAAC,KAAK,SAAS,QAAQ,CACzB,QAAO,KAAK,uBAAuB;AAErC,KAAI,CAAC,KAAK,MAAM,2CAA2C,CACzD,QAAO,KAAK,wDAAwD;AAEtE,KAAI,CAAC,KAAK,MAAM,eAAe,CAE7B,QAAO,KAAK,kCAAkC"}
|
|
@@ -3,4 +3,5 @@ import { AppBlueprintSpecData } from "../types/spec-types.js";
|
|
|
3
3
|
//#region src/templates/app-config.d.ts
|
|
4
4
|
declare function generateAppBlueprintSpec(data: AppBlueprintSpecData): string;
|
|
5
5
|
//#endregion
|
|
6
|
-
export { generateAppBlueprintSpec };
|
|
6
|
+
export { generateAppBlueprintSpec };
|
|
7
|
+
//# sourceMappingURL=app-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-config.d.ts","names":[],"sources":["../../src/templates/app-config.ts"],"sourcesContent":[],"mappings":";;;iBAGgB,wBAAA,OAA+B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-config.js","names":[],"sources":["../../src/templates/app-config.ts"],"sourcesContent":["import type { AppBlueprintSpecData } from '../types/spec-types';\nimport { toPascalCase } from './utils';\n\nexport function generateAppBlueprintSpec(data: AppBlueprintSpecData): string {\n const exportName =\n toPascalCase(data.name.split('.').pop() ?? 'App') + 'AppConfig';\n\n const capabilitiesSection = buildCapabilitiesSection(data);\n const featuresSection = buildFeaturesSection(data);\n const dataViewsSection = buildMappingSection('dataViews', data.dataViews);\n const workflowsSection = buildMappingSection('workflows', data.workflows);\n const policiesSection = buildPolicySection(data);\n const themeSection = buildThemeSection(data);\n const telemetrySection = buildTelemetrySection(data);\n const experimentsSection = buildExperimentsSection(data);\n const flagsSection = buildFeatureFlagsSection(data);\n const routesSection = buildRoutesSection(data);\n const notesSection = data.notes\n ? ` notes: '${escapeString(data.notes)}',\\n`\n : '';\n\n return `import type { AppBlueprintSpec } from '@lssm/lib.contracts/app-config';\n\nexport const ${exportName}: AppBlueprintSpec = {\n meta: {\n name: '${escapeString(data.name)}',\n version: ${data.version},\n title: '${escapeString(data.title)}',\n description: '${escapeString(data.description)}',\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 appId: '${escapeString(data.appId)}',\n },\n${capabilitiesSection}${featuresSection}${dataViewsSection}${workflowsSection}${policiesSection}${themeSection}${telemetrySection}${experimentsSection}${flagsSection}${routesSection}${notesSection}};\\n`;\n}\n\nfunction buildCapabilitiesSection(data: AppBlueprintSpecData): string {\n if (\n data.capabilitiesEnabled.length === 0 &&\n data.capabilitiesDisabled.length === 0\n ) {\n return '';\n }\n const enabled =\n data.capabilitiesEnabled.length > 0\n ? ` enabled: [${data.capabilitiesEnabled.map((key) => formatCapabilityRef(key)).join(', ')}],\\n`\n : '';\n const disabled =\n data.capabilitiesDisabled.length > 0\n ? ` disabled: [${data.capabilitiesDisabled.map((key) => formatCapabilityRef(key)).join(', ')}],\\n`\n : '';\n return ` capabilities: {\\n${enabled}${disabled} },\\n`;\n}\n\nfunction buildFeaturesSection(data: AppBlueprintSpecData): string {\n if (data.featureIncludes.length === 0 && data.featureExcludes.length === 0) {\n return '';\n }\n const include =\n data.featureIncludes.length > 0\n ? ` include: [${data.featureIncludes.map((key) => `{ key: '${escapeString(key)}' }`).join(', ')}],\\n`\n : '';\n const exclude =\n data.featureExcludes.length > 0\n ? ` exclude: [${data.featureExcludes.map((key) => `{ key: '${escapeString(key)}' }`).join(', ')}],\\n`\n : '';\n return ` features: {\\n${include}${exclude} },\\n`;\n}\n\nfunction buildMappingSection(\n prop: 'dataViews' | 'workflows',\n mappings: AppBlueprintSpecData['dataViews']\n): string {\n if (mappings.length === 0) return '';\n const body = mappings\n .map(\n (mapping) => ` ${mapping.slot}: {\n name: '${escapeString(mapping.name)}',\n ${typeof mapping.version === 'number' ? `version: ${mapping.version},` : ''}\n }`\n )\n .join(',\\n');\n return ` ${prop}: {\\n${body}\\n },\\n`;\n}\n\nfunction buildPolicySection(data: AppBlueprintSpecData): string {\n if (data.policyRefs.length === 0) return '';\n const entries = data.policyRefs\n .map(\n (policy) => ` {\n name: '${escapeString(policy.name)}'${typeof policy.version === 'number' ? `,\\n version: ${policy.version}` : ''}\n }`\n )\n .join(',\\n');\n return ` policies: [\\n${entries}\\n ],\\n`;\n}\n\nfunction buildThemeSection(data: AppBlueprintSpecData): string {\n if (!data.theme) return '';\n const primary = ` primary: { name: '${escapeString(data.theme.name)}', version: ${data.theme.version} },\\n`;\n const fallbacks =\n data.themeFallbacks.length > 0\n ? ` fallbacks: [${data.themeFallbacks\n .map(\n (theme) =>\n `{ name: '${escapeString(theme.name)}', version: ${theme.version} }`\n )\n .join(', ')}],\\n`\n : '';\n return ` theme: {\\n${primary}${fallbacks} },\\n`;\n}\n\nfunction buildTelemetrySection(data: AppBlueprintSpecData): string {\n if (!data.telemetry) return '';\n return ` telemetry: {\n spec: {\n name: '${escapeString(data.telemetry.name)}'${\n typeof data.telemetry.version === 'number'\n ? `,\\n version: ${data.telemetry.version}`\n : ''\n }\n },\n },\\n`;\n}\n\nfunction buildExperimentsSection(data: AppBlueprintSpecData): string {\n if (\n data.activeExperiments.length === 0 &&\n data.pausedExperiments.length === 0\n ) {\n return '';\n }\n const active =\n data.activeExperiments.length > 0\n ? ` active: [${data.activeExperiments.map((exp) => formatExperimentRef(exp)).join(', ')}],\\n`\n : '';\n const paused =\n data.pausedExperiments.length > 0\n ? ` paused: [${data.pausedExperiments.map((exp) => formatExperimentRef(exp)).join(', ')}],\\n`\n : '';\n return ` experiments: {\\n${active}${paused} },\\n`;\n}\n\nfunction buildFeatureFlagsSection(data: AppBlueprintSpecData): string {\n if (data.featureFlags.length === 0) return '';\n const flags = data.featureFlags\n .map(\n (flag) => ` {\n key: '${escapeString(flag.key)}',\n enabled: ${flag.enabled},\n ${flag.variant ? `variant: '${escapeString(flag.variant)}',` : ''}\n ${flag.description ? `description: '${escapeString(flag.description)}',` : ''}\n }`\n )\n .join(',\\n');\n return ` featureFlags: [\\n${flags}\\n ],\\n`;\n}\n\nfunction buildRoutesSection(data: AppBlueprintSpecData): string {\n if (data.routes.length === 0) return '';\n const routes = data.routes\n .map((route) => {\n const entries = [\n `path: '${escapeString(route.path)}'`,\n route.label ? `label: '${escapeString(route.label)}'` : null,\n route.dataView ? `dataView: '${escapeString(route.dataView)}'` : null,\n route.workflow ? `workflow: '${escapeString(route.workflow)}'` : null,\n route.guardName\n ? `guard: { name: '${escapeString(route.guardName)}'${\n typeof route.guardVersion === 'number'\n ? `, version: ${route.guardVersion}`\n : ''\n } }`\n : null,\n route.featureFlag\n ? `featureFlag: '${escapeString(route.featureFlag)}'`\n : null,\n route.experimentName\n ? `experiment: { name: '${escapeString(route.experimentName)}'${\n typeof route.experimentVersion === 'number'\n ? `, version: ${route.experimentVersion}`\n : ''\n } }`\n : null,\n ].filter(Boolean);\n return ` { ${entries.join(', ')} }`;\n })\n .join(',\\n');\n return ` routes: [\\n${routes}\\n ],\\n`;\n}\n\nfunction formatCapabilityRef(key: string): string {\n return `{ key: '${escapeString(key)}' }`;\n}\n\nfunction formatExperimentRef(exp: { name: string; version?: number }): string {\n const version =\n typeof exp.version === 'number' ? `, version: ${exp.version}` : '';\n return `{ name: '${escapeString(exp.name)}'${version} }`;\n}\n\nfunction escapeString(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n"],"mappings":"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"}
|
|
@@ -3,4 +3,5 @@ import { DataViewSpecData } from "../types/spec-types.js";
|
|
|
3
3
|
//#region src/templates/data-view.d.ts
|
|
4
4
|
declare function generateDataViewSpec(data: DataViewSpecData): string;
|
|
5
5
|
//#endregion
|
|
6
|
-
export { generateDataViewSpec };
|
|
6
|
+
export { generateDataViewSpec };
|
|
7
|
+
//# sourceMappingURL=data-view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-view.d.ts","names":[],"sources":["../../src/templates/data-view.ts"],"sourcesContent":[],"mappings":";;;iBAGgB,oBAAA,OAA2B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-view.js","names":[],"sources":["../../src/templates/data-view.ts"],"sourcesContent":["import type { DataViewSpecData } from '../types/spec-types';\nimport { toPascalCase, escapeString } from './utils';\n\nexport function generateDataViewSpec(data: DataViewSpecData): string {\n const viewVarName =\n toPascalCase(data.name.split('.').pop() ?? 'DataView') + 'DataView';\n\n const fields = data.fields\n .map(\n (field) => ` {\n key: '${escapeString(field.key)}',\n label: '${escape(field.label)}',\n dataPath: '${escapeString(field.dataPath)}',\n ${field.format ? `format: '${escapeString(field.format)}',` : ''}\n ${field.sortable ? 'sortable: true,' : ''}\n ${field.filterable ? 'filterable: true,' : ''}\n }`\n )\n .join(',\\n');\n\n const secondaryFields = data.secondaryFields?.length\n ? `secondaryFields: [${data.secondaryFields\n .map((key) => `'${escapeString(key)}'`)\n .join(', ')}],`\n : '';\n\n const itemOperation = data.itemOperation\n ? `item: { name: '${escapeString(data.itemOperation.name)}', version: ${data.itemOperation.version} },`\n : '';\n\n return `import type { DataViewSpec } from '@lssm/lib.contracts/data-views';\n\nexport const ${viewVarName}: DataViewSpec = {\n meta: {\n name: '${escapeString(data.name)}',\n version: ${data.version},\n entity: '${escapeString(data.entity)}',\n title: '${escape(data.title)}',\n description: '${escape(\n data.description || 'Describe the purpose of this data view.'\n )}',\n domain: '${escape(data.domain || data.entity)}',\n owners: [${data.owners.map((owner) => `'${escapeString(owner)}'`).join(', ')}],\n tags: [${data.tags.map((tag) => `'${escapeString(tag)}'`).join(', ')}],\n stability: '${data.stability}',\n },\n source: {\n primary: {\n name: '${escapeString(data.primaryOperation.name)}',\n version: ${data.primaryOperation.version},\n },\n ${itemOperation}\n refreshEvents: [\n // { name: 'entity.updated', version: 1 },\n ],\n },\n view: {\n kind: '${data.kind}',\n fields: [\n${fields}\n ],\n ${data.primaryField ? `primaryField: '${escapeString(data.primaryField)}',` : ''}\n ${secondaryFields}\n filters: [\n // Example filter:\n // { key: 'search', label: 'Search', field: 'fullName', type: 'search' },\n ],\n actions: [\n // Example action:\n // { key: 'open', label: 'Open', kind: 'navigation' },\n ],\n },\n states: {\n // empty: { name: 'app.data.empty', version: 1 },\n // error: { name: 'app.data.error', version: 1 },\n },\n};\n`;\n}\n\nfunction escape(value: string): string {\n return value.replace(/'/g, \"\\\\'\");\n}\n"],"mappings":";;;AAGA,SAAgB,qBAAqB,MAAgC;CACnE,MAAM,cACJ,aAAa,KAAK,KAAK,MAAM,IAAI,CAAC,KAAK,IAAI,WAAW,GAAG;CAE3D,MAAM,SAAS,KAAK,OACjB,KACE,UAAU;gBACD,aAAa,MAAM,IAAI,CAAC;kBACtB,OAAO,MAAM,MAAM,CAAC;qBACjB,aAAa,MAAM,SAAS,CAAC;UACxC,MAAM,SAAS,YAAY,aAAa,MAAM,OAAO,CAAC,MAAM,GAAG;UAC/D,MAAM,WAAW,oBAAoB,GAAG;UACxC,MAAM,aAAa,sBAAsB,GAAG;SAEjD,CACA,KAAK,MAAM;CAEd,MAAM,kBAAkB,KAAK,iBAAiB,SAC1C,qBAAqB,KAAK,gBACvB,KAAK,QAAQ,IAAI,aAAa,IAAI,CAAC,GAAG,CACtC,KAAK,KAAK,CAAC,MACd;CAEJ,MAAM,gBAAgB,KAAK,gBACvB,kBAAkB,aAAa,KAAK,cAAc,KAAK,CAAC,cAAc,KAAK,cAAc,QAAQ,OACjG;AAEJ,QAAO;;eAEM,YAAY;;aAEd,aAAa,KAAK,KAAK,CAAC;eACtB,KAAK,QAAQ;eACb,aAAa,KAAK,OAAO,CAAC;cAC3B,OAAO,KAAK,MAAM,CAAC;oBACb,OACd,KAAK,eAAe,0CACrB,CAAC;eACS,OAAO,KAAK,UAAU,KAAK,OAAO,CAAC;eACnC,KAAK,OAAO,KAAK,UAAU,IAAI,aAAa,MAAM,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC;aACpE,KAAK,KAAK,KAAK,QAAQ,IAAI,aAAa,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC;kBACvD,KAAK,UAAU;;;;eAIlB,aAAa,KAAK,iBAAiB,KAAK,CAAC;iBACvC,KAAK,iBAAiB,QAAQ;;MAEzC,cAAc;;;;;;aAMP,KAAK,KAAK;;EAErB,OAAO;;MAEH,KAAK,eAAe,kBAAkB,aAAa,KAAK,aAAa,CAAC,MAAM,GAAG;MAC/E,gBAAgB;;;;;;;;;;;;;;;;;AAkBtB,SAAS,OAAO,OAAuB;AACrC,QAAO,MAAM,QAAQ,MAAM,MAAM"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event.d.ts","names":[],"sources":["../../src/templates/event.ts"],"sourcesContent":[],"mappings":";;;;;;;iBAWgB,iBAAA,OAAwB"}
|
package/dist/templates/event.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event.js","names":[],"sources":["../../src/templates/event.ts"],"sourcesContent":["/**\n * Event spec template generation.\n * Extracted from cli-contracts/src/templates/event.template.ts\n */\n\nimport type { EventSpecData } from '../types/spec-types';\nimport { toPascalCase } from './utils';\n\n/**\n * Generate event spec TypeScript code.\n */\nexport function generateEventSpec(data: EventSpecData): string {\n const { name, version, description, stability, owners, tags, piiFields } =\n data;\n\n const eventVarName = toPascalCase(name.replace(/\\./g, '_')) + 'V' + version;\n const payloadSchemaName = eventVarName + 'Payload';\n\n return `import { defineEvent } from '@lssm/lib.contracts';\nimport { ScalarTypeEnum, SchemaModel } from '@lssm/lib.schema';\n\n// TODO: Define event payload schema\nexport const ${payloadSchemaName} = new SchemaModel({\n name: '${payloadSchemaName}',\n description: 'Payload for ${name}',\n fields: {\n // Add your payload fields here\n // example: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n },\n});\n\nexport const ${eventVarName} = defineEvent({\n name: '${name}',\n version: ${version},\n description: '${description}',\n stability: '${stability}',\n owners: [${owners.map((o) => `'${o}'`).join(', ')}],\n tags: [${tags.map((t) => `'${t}'`).join(', ')}],\n ${piiFields.length > 0 ? `pii: [${piiFields.map((f) => `'${f}'`).join(', ')}],` : '// pii: [],'}\n payload: ${payloadSchemaName},\n});\n`;\n}\n"],"mappings":";;;;;;AAWA,SAAgB,kBAAkB,MAA6B;CAC7D,MAAM,EAAE,MAAM,SAAS,aAAa,WAAW,QAAQ,MAAM,cAC3D;CAEF,MAAM,eAAe,aAAa,KAAK,QAAQ,OAAO,IAAI,CAAC,GAAG,MAAM;CACpE,MAAM,oBAAoB,eAAe;AAEzC,QAAO;;;;eAIM,kBAAkB;WACtB,kBAAkB;8BACC,KAAK;;;;;;;eAOpB,aAAa;WACjB,KAAK;aACH,QAAQ;kBACH,YAAY;gBACd,UAAU;aACb,OAAO,KAAK,MAAM,IAAI,EAAE,GAAG,CAAC,KAAK,KAAK,CAAC;WACzC,KAAK,KAAK,MAAM,IAAI,EAAE,GAAG,CAAC,KAAK,KAAK,CAAC;IAC5C,UAAU,SAAS,IAAI,SAAS,UAAU,KAAK,MAAM,IAAI,EAAE,GAAG,CAAC,KAAK,KAAK,CAAC,MAAM,cAAc;aACrF,kBAAkB"}
|
|
@@ -3,4 +3,5 @@ import { ExperimentSpecData } from "../types/spec-types.js";
|
|
|
3
3
|
//#region src/templates/experiment.d.ts
|
|
4
4
|
declare function generateExperimentSpec(data: ExperimentSpecData): string;
|
|
5
5
|
//#endregion
|
|
6
|
-
export { generateExperimentSpec };
|
|
6
|
+
export { generateExperimentSpec };
|
|
7
|
+
//# sourceMappingURL=experiment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"experiment.d.ts","names":[],"sources":["../../src/templates/experiment.ts"],"sourcesContent":[],"mappings":";;;iBAGgB,sBAAA,OAA6B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"experiment.js","names":[],"sources":["../../src/templates/experiment.ts"],"sourcesContent":["import type { ExperimentSpecData } from '../types/spec-types';\nimport { toPascalCase } from './utils';\n\nexport function generateExperimentSpec(data: ExperimentSpecData): string {\n const specVar =\n toPascalCase(data.name.split('.').pop() ?? 'Experiment') + 'Experiment';\n\n const variants = data.variants\n .map((variant) => {\n const overrides = variant.overrides?.length\n ? ` overrides: [\n${variant.overrides\n .map(\n (override) => ` {\n type: '${override.type}',\n target: '${escapeString(override.target)}',\n ${typeof override.version === 'number' ? `version: ${override.version},` : ''}\n }`\n )\n .join(',\\n')}\n ],`\n : '';\n return ` {\n id: '${escapeString(variant.id)}',\n name: '${escapeString(variant.name)}',\n ${variant.description ? `description: '${escapeString(variant.description)}',` : ''}\n ${typeof variant.weight === 'number' ? `weight: ${variant.weight},` : ''}\n${overrides}\n }`;\n })\n .join(',\\n');\n\n const allocation = renderAllocation(data.allocation);\n\n const metrics = data.successMetrics?.length\n ? ` successMetrics: [\n${data.successMetrics\n .map(\n (metric) => ` {\n name: '${escapeString(metric.name)}',\n telemetryEvent: { name: '${escapeString(metric.eventName)}', version: ${metric.eventVersion} },\n aggregation: '${metric.aggregation}',\n ${typeof metric.target === 'number' ? `target: ${metric.target},` : ''}\n }`\n )\n .join(',\\n')}\n ],`\n : '';\n\n return `import type { ExperimentSpec } from '@lssm/lib.contracts/experiments';\n\nexport const ${specVar}: ExperimentSpec = {\n meta: {\n name: '${escapeString(data.name)}',\n version: ${data.version},\n title: '${escapeString(data.name)} experiment',\n description: '${escapeString(\n data.description || 'Describe the experiment goal.'\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 controlVariant: '${escapeString(data.controlVariant)}',\n variants: [\n${variants}\n ],\n allocation: ${allocation},\n${metrics}\n};\n`;\n}\n\nfunction renderAllocation(\n allocation: ExperimentSpecData['allocation']\n): string {\n switch (allocation.type) {\n case 'random':\n return `{\n type: 'random',\n ${allocation.salt ? `salt: '${escapeString(allocation.salt)}',` : ''}\n }`;\n case 'sticky':\n return `{\n type: 'sticky',\n attribute: '${allocation.attribute}',\n ${allocation.salt ? `salt: '${escapeString(allocation.salt)}',` : ''}\n }`;\n case 'targeted':\n return `{\n type: 'targeted',\n rules: [\n${allocation.rules\n .map(\n (rule) => ` {\n variantId: '${escapeString(rule.variantId)}',\n ${typeof rule.percentage === 'number' ? `percentage: ${rule.percentage},` : ''}\n ${\n rule.policy\n ? `policy: { name: '${escapeString(rule.policy.name)}'${typeof rule.policy.version === 'number' ? `, version: ${rule.policy.version}` : ''} },`\n : ''\n }\n ${rule.expression ? `expression: '${escapeString(rule.expression)}',` : ''}\n }`\n )\n .join(',\\n')}\n ],\n fallback: '${allocation.fallback ?? 'control'}',\n }`;\n default:\n return renderUnsupportedAllocation(allocation);\n }\n}\n\nfunction escapeString(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\nfunction renderUnsupportedAllocation(allocation: never): string {\n throw new Error(\n `Unsupported allocation type ${allocation as unknown as string}`\n );\n}\n"],"mappings":";;;AAGA,SAAgB,uBAAuB,MAAkC;CACvE,MAAM,UACJ,aAAa,KAAK,KAAK,MAAM,IAAI,CAAC,KAAK,IAAI,aAAa,GAAG;CAE7D,MAAM,WAAW,KAAK,SACnB,KAAK,YAAY;EAChB,MAAM,YAAY,QAAQ,WAAW,SACjC;EACR,QAAQ,UACP,KACE,aAAa;mBACC,SAAS,KAAK;qBACZ,aAAa,SAAS,OAAO,CAAC;YACvC,OAAO,SAAS,YAAY,WAAW,YAAY,SAAS,QAAQ,KAAK,GAAG;WAErF,CACA,KAAK,MAAM,CAAC;YAEL;AACJ,SAAO;aACA,aAAa,QAAQ,GAAG,CAAC;eACvB,aAAa,QAAQ,KAAK,CAAC;QAClC,QAAQ,cAAc,iBAAiB,aAAa,QAAQ,YAAY,CAAC,MAAM,GAAG;QAClF,OAAO,QAAQ,WAAW,WAAW,WAAW,QAAQ,OAAO,KAAK,GAAG;EAC7E,UAAU;;GAEN,CACD,KAAK,MAAM;CAEd,MAAM,aAAa,iBAAiB,KAAK,WAAW;CAEpD,MAAM,UAAU,KAAK,gBAAgB,SACjC;EACJ,KAAK,eACJ,KACE,WAAW;eACD,aAAa,OAAO,KAAK,CAAC;iCACR,aAAa,OAAO,UAAU,CAAC,cAAc,OAAO,aAAa;sBAC5E,OAAO,YAAY;QACjC,OAAO,OAAO,WAAW,WAAW,WAAW,OAAO,OAAO,KAAK,GAAG;OAE1E,CACA,KAAK,MAAM,CAAC;QAET;AAEJ,QAAO;;eAEM,QAAQ;;aAEV,aAAa,KAAK,KAAK,CAAC;eACtB,KAAK,QAAQ;cACd,aAAa,KAAK,KAAK,CAAC;oBAClB,aACd,KAAK,eAAe,gCACrB,CAAC;eACS,aAAa,KAAK,OAAO,CAAC;eAC1B,KAAK,OAAO,KAAK,UAAU,IAAI,aAAa,MAAM,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC;aACpE,KAAK,KAAK,KAAK,QAAQ,IAAI,aAAa,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC;kBACvD,KAAK,UAAU;;qBAEZ,aAAa,KAAK,eAAe,CAAC;;EAErD,SAAS;;gBAEK,WAAW;EACzB,QAAQ;;;;AAKV,SAAS,iBACP,YACQ;AACR,SAAQ,WAAW,MAAnB;EACE,KAAK,SACH,QAAO;;MAEP,WAAW,OAAO,UAAU,aAAa,WAAW,KAAK,CAAC,MAAM,GAAG;;EAErE,KAAK,SACH,QAAO;;kBAEK,WAAW,UAAU;MACjC,WAAW,OAAO,UAAU,aAAa,WAAW,KAAK,CAAC,MAAM,GAAG;;EAErE,KAAK,WACH,QAAO;;;EAGX,WAAW,MACV,KACE,SAAS;sBACQ,aAAa,KAAK,UAAU,CAAC;UACzC,OAAO,KAAK,eAAe,WAAW,eAAe,KAAK,WAAW,KAAK,GAAG;UAE7E,KAAK,SACD,oBAAoB,aAAa,KAAK,OAAO,KAAK,CAAC,GAAG,OAAO,KAAK,OAAO,YAAY,WAAW,cAAc,KAAK,OAAO,YAAY,GAAG,OACzI,GACL;UACC,KAAK,aAAa,gBAAgB,aAAa,KAAK,WAAW,CAAC,MAAM,GAAG;SAEhF,CACA,KAAK,MAAM,CAAC;;iBAEE,WAAW,YAAY,UAAU;;EAE9C,QACE,QAAO,4BAA4B,WAAW;;;AAIpD,SAAS,aAAa,OAAuB;AAC3C,QAAO,MAAM,QAAQ,OAAO,OAAO,CAAC,QAAQ,MAAM,MAAM;;AAG1D,SAAS,4BAA4B,YAA2B;AAC9D,OAAM,IAAI,MACR,+BAA+B,aAChC"}
|
|
@@ -16,4 +16,5 @@ declare function generateComponentTemplate(componentName: string, description: s
|
|
|
16
16
|
*/
|
|
17
17
|
declare function generateTestTemplate(targetName: string, type: 'handler' | 'component'): string;
|
|
18
18
|
//#endregion
|
|
19
|
-
export { generateComponentTemplate, generateHandlerTemplate, generateTestTemplate };
|
|
19
|
+
export { generateComponentTemplate, generateHandlerTemplate, generateTestTemplate };
|
|
20
|
+
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.d.ts","names":[],"sources":["../../src/templates/handler.ts"],"sourcesContent":[],"mappings":";;AAUA;AAyCA;AA6BA;;;;iBAtEgB,uBAAA;;;;iBAyCA,yBAAA;;;;iBA6BA,oBAAA"}
|
|
@@ -92,4 +92,5 @@ describe('${testName}', () => {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
//#endregion
|
|
95
|
-
export { generateComponentTemplate, generateHandlerTemplate, generateTestTemplate };
|
|
95
|
+
export { generateComponentTemplate, generateHandlerTemplate, generateTestTemplate };
|
|
96
|
+
//# sourceMappingURL=handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.js","names":[],"sources":["../../src/templates/handler.ts"],"sourcesContent":["/**\n * Handler and component template generation.\n * Extracted from cli-contracts/src/templates/handler.template.ts\n */\n\nimport { toPascalCase, toCamelCase, toKebabCase } from './utils';\n\n/**\n * Generate handler implementation template.\n */\nexport function generateHandlerTemplate(\n specName: string,\n kind: 'command' | 'query'\n): string {\n const handlerName =\n toCamelCase(specName.split('.').pop() ?? 'unknown') + 'Handler';\n const specVarName =\n toPascalCase(specName.split('.').pop() ?? 'Unknown') + 'Spec';\n\n return `import type { ContractHandler } from '@lssm/lib.contracts';\nimport { ${specVarName} } from '../contracts/${toKebabCase(specName)}.contracts';\n\n/**\n * Handler for ${specName}\n */\nexport const ${handlerName}: ContractHandler<typeof ${specVarName}> = async (\n input,\n context\n) => {\n // TODO: Implement ${kind} logic\n \n try {\n // 1. Validate prerequisites\n // 2. Perform business logic\n // 3. Emit events if needed\n // 4. Return result\n \n return {\n ok: true,\n };\n } catch (error) {\n // Handle and map errors to spec.io.errors\n throw error;\n }\n};\n`;\n}\n\n/**\n * Generate React component template.\n */\nexport function generateComponentTemplate(\n componentName: string,\n description: string\n): string {\n const pascalName = toPascalCase(componentName);\n\n return `import React from 'react';\n\ninterface ${pascalName}Props {\n // TODO: Define props based on presentation spec\n}\n\n/**\n * ${description}\n */\nexport const ${pascalName}: React.FC<${pascalName}Props> = (props) => {\n return (\n <div>\n {/* TODO: Implement component UI */}\n <p>Component: ${pascalName}</p>\n </div>\n );\n};\n`;\n}\n\n/**\n * Generate test template.\n */\nexport function generateTestTemplate(\n targetName: string,\n type: 'handler' | 'component'\n): string {\n const importPath = type === 'handler' ? '../handlers' : '../components';\n const testName = toPascalCase(targetName);\n\n return `import { describe, it, expect } from 'bun:test';\nimport { ${testName} } from '${importPath}/${toKebabCase(targetName)}';\n\ndescribe('${testName}', () => {\n it('should ${type === 'handler' ? 'handle valid input' : 'render correctly'}', async () => {\n // TODO: Implement test\n expect(true).toBe(true);\n });\n\n it('should handle edge cases', async () => {\n // TODO: Test edge cases\n });\n\n ${\n type === 'handler'\n ? `it('should handle errors appropriately', async () => {\n // TODO: Test error scenarios\n });`\n : `it('should be accessible', async () => {\n // TODO: Test accessibility\n });`\n }\n});\n`;\n}\n"],"mappings":";;;;;;;;;;AAUA,SAAgB,wBACd,UACA,MACQ;CACR,MAAM,cACJ,YAAY,SAAS,MAAM,IAAI,CAAC,KAAK,IAAI,UAAU,GAAG;CACxD,MAAM,cACJ,aAAa,SAAS,MAAM,IAAI,CAAC,KAAK,IAAI,UAAU,GAAG;AAEzD,QAAO;WACE,YAAY,wBAAwB,YAAY,SAAS,CAAC;;;iBAGpD,SAAS;;eAEX,YAAY,2BAA2B,YAAY;;;;uBAI3C,KAAK;;;;;;;;;;;;;;;;;;;;;AAsB5B,SAAgB,0BACd,eACA,aACQ;CACR,MAAM,aAAa,aAAa,cAAc;AAE9C,QAAO;;YAEG,WAAW;;;;;KAKlB,YAAY;;eAEF,WAAW,aAAa,WAAW;;;;sBAI5B,WAAW;;;;;;;;;AAUjC,SAAgB,qBACd,YACA,MACQ;CACR,MAAM,aAAa,SAAS,YAAY,gBAAgB;CACxD,MAAM,WAAW,aAAa,WAAW;AAEzC,QAAO;WACE,SAAS,WAAW,WAAW,GAAG,YAAY,WAAW,CAAC;;YAEzD,SAAS;eACN,SAAS,YAAY,uBAAuB,mBAAmB;;;;;;;;;IAU1E,SAAS,YACL;;SAGA;;OAGL"}
|
|
@@ -101,4 +101,5 @@ function escape(value) {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
//#endregion
|
|
104
|
-
export { escape, renderByokSetup, renderConfigExample, renderConfigSchema, renderConstraints, renderProvides, renderRequires, renderSecretExample, renderSecretSchema, stabilityToEnum };
|
|
104
|
+
export { escape, renderByokSetup, renderConfigExample, renderConfigSchema, renderConstraints, renderProvides, renderRequires, renderSecretExample, renderSecretSchema, stabilityToEnum };
|
|
105
|
+
//# sourceMappingURL=integration-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration-utils.js","names":["entries: string[]"],"sources":["../../src/templates/integration-utils.ts"],"sourcesContent":["import type {\n IntegrationConfigFieldData,\n IntegrationSecretFieldData,\n IntegrationSpecData,\n Stability,\n} from '../types/spec-types';\n\nexport function renderConfigSchema(\n fields: IntegrationConfigFieldData[]\n): string {\n const requiredFields = fields.filter((field) => field.required);\n const requiredBlock =\n requiredFields.length > 0\n ? ` required: [${requiredFields\n .map((field) => `'${field.key}'`)\n .join(', ')}],\n`\n : '';\n\n const properties = fields.length\n ? fields\n .map((field) => {\n const description = field.description\n ? `, description: '${escape(field.description)}'`\n : '';\n return ` ${field.key}: { type: '${mapConfigType(\n field.type\n )}'${description} }`;\n })\n .join(',\\n')\n : '';\n\n return ` schema: {\n type: 'object',\n${requiredBlock} properties: {\n${properties || ' '}\n },\n },\\n`;\n}\n\nexport function renderSecretSchema(\n fields: IntegrationSecretFieldData[]\n): string {\n const requiredFields = fields.filter((field) => field.required);\n const requiredBlock =\n requiredFields.length > 0\n ? ` required: [${requiredFields\n .map((field) => `'${field.key}'`)\n .join(', ')}],\n`\n : '';\n\n const properties = fields.length\n ? fields\n .map((field) => {\n const description = field.description\n ? `, description: '${escape(field.description)}'`\n : '';\n return ` ${field.key}: { type: 'string'${description} }`;\n })\n .join(',\\n')\n : '';\n\n return ` schema: {\n type: 'object',\n${requiredBlock} properties: {\n${properties || ' '}\n },\n },\\n`;\n}\n\nexport function renderConfigExample(\n fields: IntegrationConfigFieldData[]\n): string {\n if (fields.length === 0) {\n return `{}`;\n }\n\n const exampleEntries = fields.map((field) => {\n switch (field.type) {\n case 'number':\n return ` ${field.key}: 0`;\n case 'boolean':\n return ` ${field.key}: true`;\n case 'string':\n default:\n return ` ${field.key}: '${field.key.toUpperCase()}_VALUE'`;\n }\n });\n\n return `{\n${exampleEntries.join(',\\n')}\n }`;\n}\n\nexport function renderSecretExample(\n fields: IntegrationSecretFieldData[]\n): string {\n if (fields.length === 0) {\n return `{}`;\n }\n\n const exampleEntries = fields.map(\n (field) => ` ${field.key}: '${field.key.toUpperCase()}_SECRET'`\n );\n\n return `{\n${exampleEntries.join(',\\n')}\n }`;\n}\n\nexport function renderConstraints(rpm?: number, rph?: number): string {\n if (rpm == null && rph == null) return '';\n const entries: string[] = [];\n if (rpm != null) entries.push(` rpm: ${rpm}`);\n if (rph != null) entries.push(` rph: ${rph}`);\n return ` constraints: {\n rateLimit: {\n${entries.join(',\\n')}\n },\n },\n`;\n}\n\nexport function renderByokSetup(\n modes: string[],\n instructions?: string,\n scopes?: string[]\n): string {\n if (!modes.includes('byok')) {\n return '';\n }\n\n const instructionsLine = instructions\n ? ` setupInstructions: '${escape(instructions)}',\\n`\n : '';\n const scopesLine =\n scopes && scopes.length\n ? ` requiredScopes: [${scopes\n .map((scope) => `'${escape(scope)}'`)\n .join(', ')}],\\n`\n : '';\n\n if (!instructionsLine && !scopesLine) {\n return '';\n }\n\n return ` byokSetup: {\n${instructionsLine}${scopesLine} },\n`;\n}\n\nexport function mapConfigType(\n type: IntegrationConfigFieldData['type']\n): string {\n switch (type) {\n case 'number':\n return 'number';\n case 'boolean':\n return 'boolean';\n case 'string':\n default:\n return 'string';\n }\n}\n\nexport function stabilityToEnum(stability: Stability): string {\n switch (stability) {\n case 'beta':\n return 'Beta';\n case 'stable':\n return 'Stable';\n case 'deprecated':\n return 'Deprecated';\n case 'experimental':\n default:\n return 'Experimental';\n }\n}\n\nexport function renderProvides(data: IntegrationSpecData): string {\n return data.capabilitiesProvided\n .map((cap) => ` { key: '${cap.key}', version: ${cap.version} }`)\n .join(',\\n');\n}\n\nexport function renderRequires(data: IntegrationSpecData): string {\n if (data.capabilitiesRequired.length === 0) return '';\n\n return ` requires: [\n${data.capabilitiesRequired\n .map((req) => {\n const version =\n typeof req.version === 'number' ? `, version: ${req.version}` : '';\n const optional = req.optional ? ', optional: true' : '';\n const reason = req.reason ? `, reason: '${escape(req.reason)}'` : '';\n return ` { key: '${req.key}'${version}${optional}${reason} }`;\n })\n .join(',\\n')}\n ],`;\n}\n\nexport function escape(value: string): string {\n return value.replace(/`/g, '\\\\`').replace(/'/g, \"\\\\'\");\n}\n"],"mappings":";AAOA,SAAgB,mBACd,QACQ;CACR,MAAM,iBAAiB,OAAO,QAAQ,UAAU,MAAM,SAAS;AAsB/D,QAAO;;EApBL,eAAe,SAAS,IACpB,oBAAoB,eACjB,KAAK,UAAU,IAAI,MAAM,IAAI,GAAG,CAChC,KAAK,KAAK,CAAC;IAEd,GAiBQ;GAfK,OAAO,SACtB,OACG,KAAK,UAAU;EACd,MAAM,cAAc,MAAM,cACtB,mBAAmB,OAAO,MAAM,YAAY,CAAC,KAC7C;AACJ,SAAO,WAAW,MAAM,IAAI,aAAa,cACvC,MAAM,KACP,CAAC,GAAG,YAAY;GACjB,CACD,KAAK,MAAM,GACd,OAKU,SAAS;;;;AAKzB,SAAgB,mBACd,QACQ;CACR,MAAM,iBAAiB,OAAO,QAAQ,UAAU,MAAM,SAAS;AAoB/D,QAAO;;EAlBL,eAAe,SAAS,IACpB,oBAAoB,eACjB,KAAK,UAAU,IAAI,MAAM,IAAI,GAAG,CAChC,KAAK,KAAK,CAAC;IAEd,GAeQ;GAbK,OAAO,SACtB,OACG,KAAK,UAAU;EACd,MAAM,cAAc,MAAM,cACtB,mBAAmB,OAAO,MAAM,YAAY,CAAC,KAC7C;AACJ,SAAO,WAAW,MAAM,IAAI,oBAAoB,YAAY;GAC5D,CACD,KAAK,MAAM,GACd,OAKU,SAAS;;;;AAKzB,SAAgB,oBACd,QACQ;AACR,KAAI,OAAO,WAAW,EACpB,QAAO;AAeT,QAAO;EAZgB,OAAO,KAAK,UAAU;AAC3C,UAAQ,MAAM,MAAd;GACE,KAAK,SACH,QAAO,OAAO,MAAM,IAAI;GAC1B,KAAK,UACH,QAAO,OAAO,MAAM,IAAI;GAC1B,KAAK;GACL,QACE,QAAO,OAAO,MAAM,IAAI,KAAK,MAAM,IAAI,aAAa,CAAC;;GAEzD,CAGa,KAAK,MAAM,CAAC;;;AAI7B,SAAgB,oBACd,QACQ;AACR,KAAI,OAAO,WAAW,EACpB,QAAO;AAOT,QAAO;EAJgB,OAAO,KAC3B,UAAU,OAAO,MAAM,IAAI,KAAK,MAAM,IAAI,aAAa,CAAC,UAC1D,CAGc,KAAK,MAAM,CAAC;;;AAI7B,SAAgB,kBAAkB,KAAc,KAAsB;AACpE,KAAI,OAAO,QAAQ,OAAO,KAAM,QAAO;CACvC,MAAMA,UAAoB,EAAE;AAC5B,KAAI,OAAO,KAAM,SAAQ,KAAK,cAAc,MAAM;AAClD,KAAI,OAAO,KAAM,SAAQ,KAAK,cAAc,MAAM;AAClD,QAAO;;EAEP,QAAQ,KAAK,MAAM,CAAC;;;;;AAMtB,SAAgB,gBACd,OACA,cACA,QACQ;AACR,KAAI,CAAC,MAAM,SAAS,OAAO,CACzB,QAAO;CAGT,MAAM,mBAAmB,eACrB,2BAA2B,OAAO,aAAa,CAAC,QAChD;CACJ,MAAM,aACJ,UAAU,OAAO,SACb,wBAAwB,OACrB,KAAK,UAAU,IAAI,OAAO,MAAM,CAAC,GAAG,CACpC,KAAK,KAAK,CAAC,QACd;AAEN,KAAI,CAAC,oBAAoB,CAAC,WACxB,QAAO;AAGT,QAAO;EACP,mBAAmB,WAAW;;;AAIhC,SAAgB,cACd,MACQ;AACR,SAAQ,MAAR;EACE,KAAK,SACH,QAAO;EACT,KAAK,UACH,QAAO;EACT,KAAK;EACL,QACE,QAAO;;;AAIb,SAAgB,gBAAgB,WAA8B;AAC5D,SAAQ,WAAR;EACE,KAAK,OACH,QAAO;EACT,KAAK,SACH,QAAO;EACT,KAAK,aACH,QAAO;EACT,KAAK;EACL,QACE,QAAO;;;AAIb,SAAgB,eAAe,MAAmC;AAChE,QAAO,KAAK,qBACT,KAAK,QAAQ,iBAAiB,IAAI,IAAI,cAAc,IAAI,QAAQ,IAAI,CACpE,KAAK,MAAM;;AAGhB,SAAgB,eAAe,MAAmC;AAChE,KAAI,KAAK,qBAAqB,WAAW,EAAG,QAAO;AAEnD,QAAO;EACP,KAAK,qBACJ,KAAK,QAAQ;EACZ,MAAM,UACJ,OAAO,IAAI,YAAY,WAAW,cAAc,IAAI,YAAY;EAClE,MAAM,WAAW,IAAI,WAAW,qBAAqB;EACrD,MAAM,SAAS,IAAI,SAAS,cAAc,OAAO,IAAI,OAAO,CAAC,KAAK;AAClE,SAAO,iBAAiB,IAAI,IAAI,GAAG,UAAU,WAAW,OAAO;GAC/D,CACD,KAAK,MAAM,CAAC;;;AAIf,SAAgB,OAAO,OAAuB;AAC5C,QAAO,MAAM,QAAQ,MAAM,MAAM,CAAC,QAAQ,MAAM,MAAM"}
|
|
@@ -3,4 +3,5 @@ import { IntegrationSpecData } from "../types/spec-types.js";
|
|
|
3
3
|
//#region src/templates/integration.d.ts
|
|
4
4
|
declare function generateIntegrationSpec(data: IntegrationSpecData): string;
|
|
5
5
|
//#endregion
|
|
6
|
-
export { generateIntegrationSpec };
|
|
6
|
+
export { generateIntegrationSpec };
|
|
7
|
+
//# sourceMappingURL=integration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration.d.ts","names":[],"sources":["../../src/templates/integration.ts"],"sourcesContent":[],"mappings":";;;iBAegB,uBAAA,OAA8B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration.js","names":[],"sources":["../../src/templates/integration.ts"],"sourcesContent":["import type { IntegrationSpecData } from '../types/spec-types';\nimport { toPascalCase } from './utils';\nimport {\n escape,\n renderByokSetup,\n renderConfigExample,\n renderConfigSchema,\n renderConstraints,\n renderProvides,\n renderRequires,\n renderSecretExample,\n renderSecretSchema,\n stabilityToEnum,\n} from './integration-utils';\n\nexport function generateIntegrationSpec(data: IntegrationSpecData): string {\n const specName = toPascalCase(data.name.split('.').pop() ?? 'Integration');\n const varName = `${specName}IntegrationSpec`;\n const registerFn = `register${specName}Integration`;\n\n const supportedModes = data.supportedModes.length\n ? data.supportedModes\n : ['managed'];\n const supportedModesLine = supportedModes\n .map((mode) => `'${mode}'`)\n .join(', ');\n\n const provides = renderProvides(data);\n const requires = renderRequires(data);\n\n const configSchema = renderConfigSchema(data.configFields);\n const configExample = renderConfigExample(data.configFields);\n const secretSchema = renderSecretSchema(data.secretFields);\n const secretExample = renderSecretExample(data.secretFields);\n const docsUrl = data.docsUrl ? ` docsUrl: '${escape(data.docsUrl)}',\\n` : '';\n const constraints = renderConstraints(data.rateLimitRpm, data.rateLimitRph);\n const byokSetup = renderByokSetup(\n supportedModes,\n data.byokSetupInstructions,\n data.byokRequiredScopes\n );\n\n return `import { StabilityEnum } from '@lssm/lib.contracts/ownership';\nimport type { IntegrationSpec } from '@lssm/lib.contracts/integrations/spec';\nimport type { IntegrationSpecRegistry } from '@lssm/lib.contracts/integrations/spec';\n\nexport const ${varName}: IntegrationSpec = {\n meta: {\n key: '${escape(data.name)}',\n version: ${data.version},\n category: '${data.category}',\n displayName: '${escape(data.displayName)}',\n title: '${escape(data.title)}',\n description: '${escape(data.description)}',\n domain: '${escape(data.domain)}',\n owners: [${data.owners.map((owner) => `'${escape(owner)}'`).join(', ')}],\n tags: [${data.tags.map((tag) => `'${escape(tag)}'`).join(', ')}],\n stability: StabilityEnum.${stabilityToEnum(data.stability)},\n },\n supportedModes: [${supportedModesLine}],\n capabilities: {\n provides: [\n${provides}\n ],\n${requires.length > 0 ? `${requires}\\n` : ''} },\n configSchema: {\n${configSchema} example: ${configExample},\n },\n secretSchema: {\n${secretSchema} example: ${secretExample},\n },\n${docsUrl}${constraints}${byokSetup} healthCheck: {\n method: '${data.healthCheckMethod}',\n timeoutMs: ${data.healthCheckTimeoutMs ?? 5000},\n },\n};\n\nexport function ${registerFn}(registry: IntegrationSpecRegistry): IntegrationSpecRegistry {\n return registry.register(${varName});\n}\n`;\n}\n"],"mappings":";;;;AAeA,SAAgB,wBAAwB,MAAmC;CACzE,MAAM,WAAW,aAAa,KAAK,KAAK,MAAM,IAAI,CAAC,KAAK,IAAI,cAAc;CAC1E,MAAM,UAAU,GAAG,SAAS;CAC5B,MAAM,aAAa,WAAW,SAAS;CAEvC,MAAM,iBAAiB,KAAK,eAAe,SACvC,KAAK,iBACL,CAAC,UAAU;CACf,MAAM,qBAAqB,eACxB,KAAK,SAAS,IAAI,KAAK,GAAG,CAC1B,KAAK,KAAK;CAEb,MAAM,WAAW,eAAe,KAAK;CACrC,MAAM,WAAW,eAAe,KAAK;CAErC,MAAM,eAAe,mBAAmB,KAAK,aAAa;CAC1D,MAAM,gBAAgB,oBAAoB,KAAK,aAAa;CAC5D,MAAM,eAAe,mBAAmB,KAAK,aAAa;CAC1D,MAAM,gBAAgB,oBAAoB,KAAK,aAAa;CAC5D,MAAM,UAAU,KAAK,UAAU,eAAe,OAAO,KAAK,QAAQ,CAAC,QAAQ;CAC3E,MAAM,cAAc,kBAAkB,KAAK,cAAc,KAAK,aAAa;CAC3E,MAAM,YAAY,gBAChB,gBACA,KAAK,uBACL,KAAK,mBACN;AAED,QAAO;;;;eAIM,QAAQ;;YAEX,OAAO,KAAK,KAAK,CAAC;eACf,KAAK,QAAQ;iBACX,KAAK,SAAS;oBACX,OAAO,KAAK,YAAY,CAAC;cAC/B,OAAO,KAAK,MAAM,CAAC;oBACb,OAAO,KAAK,YAAY,CAAC;eAC9B,OAAO,KAAK,OAAO,CAAC;eACpB,KAAK,OAAO,KAAK,UAAU,IAAI,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC;aAC9D,KAAK,KAAK,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC;+BACpC,gBAAgB,KAAK,UAAU,CAAC;;qBAE1C,mBAAmB;;;EAGtC,SAAS;;EAET,SAAS,SAAS,IAAI,GAAG,SAAS,MAAM,GAAG;;EAE3C,aAAa,eAAe,cAAc;;;EAG1C,aAAa,eAAe,cAAc;;EAE1C,UAAU,cAAc,UAAU;eACrB,KAAK,kBAAkB;iBACrB,KAAK,wBAAwB,IAAK;;;;kBAIjC,WAAW;6BACA,QAAQ"}
|
|
@@ -3,4 +3,5 @@ import { KnowledgeSpaceSpecData } from "../types/spec-types.js";
|
|
|
3
3
|
//#region src/templates/knowledge.d.ts
|
|
4
4
|
declare function generateKnowledgeSpaceSpec(data: KnowledgeSpaceSpecData): string;
|
|
5
5
|
//#endregion
|
|
6
|
-
export { generateKnowledgeSpaceSpec };
|
|
6
|
+
export { generateKnowledgeSpaceSpec };
|
|
7
|
+
//# sourceMappingURL=knowledge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"knowledge.d.ts","names":[],"sources":["../../src/templates/knowledge.ts"],"sourcesContent":[],"mappings":";;;iBAGgB,0BAAA,OACR"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"knowledge.js","names":["entries: string[]"],"sources":["../../src/templates/knowledge.ts"],"sourcesContent":["import type { KnowledgeSpaceSpecData, Stability } from '../types/spec-types';\nimport { toPascalCase, escapeString } from './utils';\n\nexport function generateKnowledgeSpaceSpec(\n data: KnowledgeSpaceSpecData\n): string {\n const specName = toPascalCase(data.name.split('.').pop() ?? 'KnowledgeSpace');\n const varName = `${specName}KnowledgeSpace`;\n const registerFn = `register${specName}KnowledgeSpace`;\n\n const retention = renderRetention(data);\n const access = renderAccess(data);\n const indexing = renderIndexing(data);\n const policyComment =\n data.policyName && !data.policyVersion\n ? ` // defaults to latest version`\n : '';\n\n return `import { StabilityEnum } from '@lssm/lib.contracts/ownership';\nimport type { KnowledgeSpaceSpec } from '@lssm/lib.contracts/knowledge/spec';\nimport type { KnowledgeSpaceRegistry } from '@lssm/lib.contracts/knowledge/spec';\n\nexport const ${varName}: KnowledgeSpaceSpec = {\n meta: {\n key: '${escapeString(data.name)}',\n version: ${data.version},\n category: '${data.category}',\n displayName: '${escape(data.displayName)}',\n title: '${escape(data.title)}',\n description: '${escape(data.description)}',\n domain: '${escape(data.domain)}',\n owners: [${data.owners.map((owner) => `'${escapeString(owner)}'`).join(', ')}],\n tags: [${data.tags.map((tag) => `'${escapeString(tag)}'`).join(', ')}],\n stability: StabilityEnum.${stabilityToEnum(data.stability)},\n },\n retention: ${retention},\n access: {\n${access}${data.policyName ? ` policy: { name: '${escapeString(data.policyName)}',${data.policyVersion ? ` version: ${data.policyVersion}` : ''} },${policyComment}\\n` : ''} },\n${indexing} description: '${escape(data.description || data.displayName)}',\n};\n\nexport function ${registerFn}(registry: KnowledgeSpaceRegistry): KnowledgeSpaceRegistry {\n return registry.register(${varName});\n}\n`;\n}\n\nfunction renderRetention(data: KnowledgeSpaceSpecData): string {\n const ttl =\n data.retention.ttlDays === null\n ? 'null'\n : typeof data.retention.ttlDays === 'number'\n ? String(data.retention.ttlDays)\n : 'null';\n const archive =\n typeof data.retention.archiveAfterDays === 'number'\n ? `, archiveAfterDays: ${data.retention.archiveAfterDays}`\n : '';\n return `{ ttlDays: ${ttl}${archive} }`;\n}\n\nfunction renderAccess(data: KnowledgeSpaceSpecData): string {\n const trustLine = ` trustLevel: '${data.trustLevel}',\\n`;\n const automationLine = ` automationWritable: ${data.automationWritable},\\n`;\n return `${trustLine}${automationLine}`;\n}\n\nfunction renderIndexing(data: KnowledgeSpaceSpecData): string {\n const entries: string[] = [];\n if (data.embeddingModel) {\n entries.push(` embeddingModel: '${escape(data.embeddingModel)}'`);\n }\n if (typeof data.chunkSize === 'number') {\n entries.push(` chunkSize: ${data.chunkSize}`);\n }\n if (data.vectorDbIntegration) {\n entries.push(\n ` vectorDbIntegration: '${escape(data.vectorDbIntegration)}'`\n );\n }\n if (entries.length === 0) {\n return '';\n }\n return ` indexing: {\\n${entries.join(',\\n')}\\n },\\n`;\n}\n\nfunction stabilityToEnum(stability: Stability): string {\n switch (stability) {\n case 'beta':\n return 'Beta';\n case 'stable':\n return 'Stable';\n case 'deprecated':\n return 'Deprecated';\n case 'experimental':\n default:\n return 'Experimental';\n }\n}\n\nfunction escape(value: string): string {\n return value.replace(/`/g, '\\\\`').replace(/'/g, \"\\\\'\");\n}\n"],"mappings":";;;AAGA,SAAgB,2BACd,MACQ;CACR,MAAM,WAAW,aAAa,KAAK,KAAK,MAAM,IAAI,CAAC,KAAK,IAAI,iBAAiB;CAC7E,MAAM,UAAU,GAAG,SAAS;CAC5B,MAAM,aAAa,WAAW,SAAS;CAEvC,MAAM,YAAY,gBAAgB,KAAK;CACvC,MAAM,SAAS,aAAa,KAAK;CACjC,MAAM,WAAW,eAAe,KAAK;CACrC,MAAM,gBACJ,KAAK,cAAc,CAAC,KAAK,gBACrB,mCACA;AAEN,QAAO;;;;eAIM,QAAQ;;YAEX,aAAa,KAAK,KAAK,CAAC;eACrB,KAAK,QAAQ;iBACX,KAAK,SAAS;oBACX,OAAO,KAAK,YAAY,CAAC;cAC/B,OAAO,KAAK,MAAM,CAAC;oBACb,OAAO,KAAK,YAAY,CAAC;eAC9B,OAAO,KAAK,OAAO,CAAC;eACpB,KAAK,OAAO,KAAK,UAAU,IAAI,aAAa,MAAM,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC;aACpE,KAAK,KAAK,KAAK,QAAQ,IAAI,aAAa,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC;+BAC1C,gBAAgB,KAAK,UAAU,CAAC;;eAEhD,UAAU;;EAEvB,SAAS,KAAK,aAAa,wBAAwB,aAAa,KAAK,WAAW,CAAC,IAAI,KAAK,gBAAgB,aAAa,KAAK,kBAAkB,GAAG,KAAK,cAAc,MAAM,GAAG;EAC7K,SAAS,kBAAkB,OAAO,KAAK,eAAe,KAAK,YAAY,CAAC;;;kBAGxD,WAAW;6BACA,QAAQ;;;;AAKrC,SAAS,gBAAgB,MAAsC;AAW7D,QAAO,cATL,KAAK,UAAU,YAAY,OACvB,SACA,OAAO,KAAK,UAAU,YAAY,WAChC,OAAO,KAAK,UAAU,QAAQ,GAC9B,SAEN,OAAO,KAAK,UAAU,qBAAqB,WACvC,uBAAuB,KAAK,UAAU,qBACtC,GAC6B;;AAGrC,SAAS,aAAa,MAAsC;AAG1D,QAAO,GAFW,oBAAoB,KAAK,WAAW,QAC/B,2BAA2B,KAAK,mBAAmB;;AAI5E,SAAS,eAAe,MAAsC;CAC5D,MAAMA,UAAoB,EAAE;AAC5B,KAAI,KAAK,eACP,SAAQ,KAAK,wBAAwB,OAAO,KAAK,eAAe,CAAC,GAAG;AAEtE,KAAI,OAAO,KAAK,cAAc,SAC5B,SAAQ,KAAK,kBAAkB,KAAK,YAAY;AAElD,KAAI,KAAK,oBACP,SAAQ,KACN,6BAA6B,OAAO,KAAK,oBAAoB,CAAC,GAC/D;AAEH,KAAI,QAAQ,WAAW,EACrB,QAAO;AAET,QAAO,kBAAkB,QAAQ,KAAK,MAAM,CAAC;;AAG/C,SAAS,gBAAgB,WAA8B;AACrD,SAAQ,WAAR;EACE,KAAK,OACH,QAAO;EACT,KAAK,SACH,QAAO;EACT,KAAK,aACH,QAAO;EACT,KAAK;EACL,QACE,QAAO;;;AAIb,SAAS,OAAO,OAAuB;AACrC,QAAO,MAAM,QAAQ,MAAM,MAAM,CAAC,QAAQ,MAAM,MAAM"}
|
|
@@ -3,4 +3,5 @@ import { MigrationSpecData } from "../types/spec-types.js";
|
|
|
3
3
|
//#region src/templates/migration.d.ts
|
|
4
4
|
declare function generateMigrationSpec(data: MigrationSpecData): string;
|
|
5
5
|
//#endregion
|
|
6
|
-
export { generateMigrationSpec };
|
|
6
|
+
export { generateMigrationSpec };
|
|
7
|
+
//# sourceMappingURL=migration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration.d.ts","names":[],"sources":["../../src/templates/migration.ts"],"sourcesContent":[],"mappings":";;;iBAGgB,qBAAA,OAA4B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration.js","names":[],"sources":["../../src/templates/migration.ts"],"sourcesContent":["import type { MigrationSpecData } from '../types/spec-types';\nimport { toPascalCase, escapeString } from './utils';\n\nexport function generateMigrationSpec(data: MigrationSpecData): string {\n const specName = toPascalCase(data.name.split('.').pop() ?? 'Migration');\n const migrationVar = `${specName}Migration`;\n\n const dependencies =\n data.dependencies.length > 0\n ? `dependencies: [${data.dependencies\n .map((dep) => `'${escapeString(dep)}'`)\n .join(', ')}],`\n : '';\n\n return `import type { MigrationSpec } from '@lssm/lib.contracts/migrations';\n\nexport const ${migrationVar}: MigrationSpec = {\n meta: {\n name: '${escapeString(data.name)}',\n version: ${data.version},\n title: '${escape(data.title)}',\n description: '${escape(data.description ?? '')}',\n domain: '${escape(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 plan: {\n up: [\n${renderSteps(data.up)}\n ],${\n data.down && data.down.length\n ? `\n down: [\n${renderSteps(data.down)}\n ],`\n : ''\n }\n },\n ${dependencies}\n};\n`;\n}\n\nfunction renderSteps(steps: MigrationSpecData['up']) {\n return steps\n .map((step) => {\n const description = step.description\n ? `description: '${escape(step.description)}',`\n : '';\n switch (step.kind) {\n case 'schema':\n return ` {\n kind: 'schema',\n ${description}\n sql: \\`${escape(step.sql ?? '')}\\`,\n }`;\n case 'data':\n return ` {\n kind: 'data',\n ${description}\n script: \\`${escape(step.script ?? '')}\\`,\n }`;\n case 'validation':\n default:\n return ` {\n kind: 'validation',\n ${description}\n assertion: \\`${escape(step.assertion ?? '')}\\`,\n }`;\n }\n })\n .join(',\\n');\n}\n\nfunction escape(value: string): string {\n return value.replace(/`/g, '\\\\`').replace(/'/g, \"\\\\'\");\n}\n"],"mappings":";;;AAGA,SAAgB,sBAAsB,MAAiC;CAErE,MAAM,eAAe,GADJ,aAAa,KAAK,KAAK,MAAM,IAAI,CAAC,KAAK,IAAI,YAAY,CACvC;CAEjC,MAAM,eACJ,KAAK,aAAa,SAAS,IACvB,kBAAkB,KAAK,aACpB,KAAK,QAAQ,IAAI,aAAa,IAAI,CAAC,GAAG,CACtC,KAAK,KAAK,CAAC,MACd;AAEN,QAAO;;eAEM,aAAa;;aAEf,aAAa,KAAK,KAAK,CAAC;eACtB,KAAK,QAAQ;cACd,OAAO,KAAK,MAAM,CAAC;oBACb,OAAO,KAAK,eAAe,GAAG,CAAC;eACpC,OAAO,KAAK,OAAO,CAAC;eACpB,KAAK,OAAO,KAAK,UAAU,IAAI,aAAa,MAAM,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC;aACpE,KAAK,KAAK,KAAK,QAAQ,IAAI,aAAa,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC;kBACvD,KAAK,UAAU;;;;EAI/B,YAAY,KAAK,GAAG,CAAC;QAEjB,KAAK,QAAQ,KAAK,KAAK,SACnB;;EAER,YAAY,KAAK,KAAK,CAAC;UAEf,GACL;;IAED,aAAa;;;;AAKjB,SAAS,YAAY,OAAgC;AACnD,QAAO,MACJ,KAAK,SAAS;EACb,MAAM,cAAc,KAAK,cACrB,iBAAiB,OAAO,KAAK,YAAY,CAAC,MAC1C;AACJ,UAAQ,KAAK,MAAb;GACE,KAAK,SACH,QAAO;;UAEP,YAAY;iBACL,OAAO,KAAK,OAAO,GAAG,CAAC;;GAEhC,KAAK,OACH,QAAO;;UAEP,YAAY;oBACF,OAAO,KAAK,UAAU,GAAG,CAAC;;GAEtC,KAAK;GACL,QACE,QAAO;;UAEP,YAAY;uBACC,OAAO,KAAK,aAAa,GAAG,CAAC;;;GAG9C,CACD,KAAK,MAAM;;AAGhB,SAAS,OAAO,OAAuB;AACrC,QAAO,MAAM,QAAQ,MAAM,MAAM,CAAC,QAAQ,MAAM,MAAM"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operation.d.ts","names":[],"sources":["../../src/templates/operation.ts"],"sourcesContent":[],"mappings":";;;;;;;iBAWgB,qBAAA,OAA4B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operation.js","names":[],"sources":["../../src/templates/operation.ts"],"sourcesContent":["/**\n * Operation spec template generation.\n * Extracted from cli-contracts/src/templates/operation.template.ts\n */\n\nimport type { OperationSpecData } from '../types/spec-types';\nimport { toPascalCase, capitalize } from './utils';\n\n/**\n * Generate operation spec TypeScript code.\n */\nexport function generateOperationSpec(data: OperationSpecData): string {\n const {\n name,\n version,\n kind,\n description,\n goal,\n context,\n stability,\n owners,\n tags,\n auth,\n flags,\n } = data;\n\n const specVarName = toPascalCase(name.split('.').pop() ?? 'Unknown') + 'Spec';\n const inputSchemaName = specVarName.replace('Spec', 'Input');\n const outputSchemaName = specVarName.replace('Spec', 'Output');\n\n return `import { define${capitalize(kind)} } from '@lssm/lib.contracts';\nimport { ScalarTypeEnum, SchemaModel } from '@lssm/lib.schema';\n\n// TODO: Define input schema\nexport const ${inputSchemaName} = new SchemaModel({\n name: '${inputSchemaName}',\n description: 'Input for ${name}',\n fields: {\n // Add your fields here\n // example: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n },\n});\n\n// TODO: Define output schema\nexport const ${outputSchemaName} = new SchemaModel({\n name: '${outputSchemaName}',\n description: 'Output for ${name}',\n fields: {\n // Add your fields here\n ok: { type: ScalarTypeEnum.Boolean(), isOptional: false },\n },\n});\n\nexport const ${specVarName} = define${capitalize(kind)}({\n meta: {\n name: '${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 goal: '${goal}',\n context: '${context}',\n },\n\n io: {\n input: ${inputSchemaName},\n output: ${outputSchemaName},\n errors: {\n // Define possible errors\n // EXAMPLE_ERROR: {\n // description: 'Example error description',\n // http: 400,\n // when: 'When this error occurs',\n // },\n },\n },\n\n policy: {\n auth: '${auth}',\n ${flags.length > 0 ? `flags: [${flags.map((f) => `'${f}'`).join(', ')}],` : '// flags: [],'}\n },\n\n sideEffects: {\n ${data.emitsEvents ? \"emits: [\\n // Define events to emit\\n // { ref: SomeEventSpec, when: 'always' }\\n ],\" : '// emits: [],'}\n analytics: [\n // Define analytics events\n ],\n },\n\n transport: {\n rest: { method: '${kind === 'command' ? 'POST' : 'GET'}' },\n gql: { field: '${name.replace(/\\./g, '_')}' },\n mcp: { toolName: '${name}.v${version}' },\n },\n\n acceptance: {\n scenarios: [\n {\n name: 'Happy path',\n given: ['preconditions'],\n when: ['action taken'],\n then: ['expected outcome'],\n },\n ],\n examples: [\n {\n name: 'Example usage',\n input: { /* example input */ },\n output: { ok: true },\n },\n ],\n },\n});\n`;\n}\n"],"mappings":";;;;;;AAWA,SAAgB,sBAAsB,MAAiC;CACrE,MAAM,EACJ,MACA,SACA,MACA,aACA,MACA,SACA,WACA,QACA,MACA,MACA,UACE;CAEJ,MAAM,cAAc,aAAa,KAAK,MAAM,IAAI,CAAC,KAAK,IAAI,UAAU,GAAG;CACvE,MAAM,kBAAkB,YAAY,QAAQ,QAAQ,QAAQ;CAC5D,MAAM,mBAAmB,YAAY,QAAQ,QAAQ,SAAS;AAE9D,QAAO,kBAAkB,WAAW,KAAK,CAAC;;;;eAI7B,gBAAgB;WACpB,gBAAgB;4BACC,KAAK;;;;;;;;eAQlB,iBAAiB;WACrB,iBAAiB;6BACC,KAAK;;;;;;;eAOnB,YAAY,WAAW,WAAW,KAAK,CAAC;;aAE1C,KAAK;eACH,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;aACnB,KAAK;gBACF,QAAQ;;;;aAIX,gBAAgB;cACf,iBAAiB;;;;;;;;;;;;aAYlB,KAAK;MACZ,MAAM,SAAS,IAAI,WAAW,MAAM,KAAK,MAAM,IAAI,EAAE,GAAG,CAAC,KAAK,KAAK,CAAC,MAAM,gBAAgB;;;;MAI1F,KAAK,cAAc,sGAAsG,gBAAgB;;;;;;;uBAOxH,SAAS,YAAY,SAAS,MAAM;qBACtC,KAAK,QAAQ,OAAO,IAAI,CAAC;wBACtB,KAAK,IAAI,QAAQ"}
|
|
@@ -7,4 +7,5 @@ import { PresentationSpecData } from "../types/spec-types.js";
|
|
|
7
7
|
*/
|
|
8
8
|
declare function generatePresentationSpec(data: PresentationSpecData): string;
|
|
9
9
|
//#endregion
|
|
10
|
-
export { generatePresentationSpec };
|
|
10
|
+
export { generatePresentationSpec };
|
|
11
|
+
//# sourceMappingURL=presentation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentation.d.ts","names":[],"sources":["../../src/templates/presentation.ts"],"sourcesContent":[],"mappings":";;;;;;;iBAWgB,wBAAA,OAA+B"}
|
|
@@ -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-contracts/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 '@lssm/lib.contracts/presentations';\nimport { SchemaModel, ScalarTypeEnum } from '@lssm/lib.schema';\n\nexport const ${varName}: PresentationSpec = {\n meta: {\n name: '${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;;aAEV,KAAK;eACH,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"}
|
|
@@ -3,4 +3,5 @@ import { TelemetrySpecData } from "../types/spec-types.js";
|
|
|
3
3
|
//#region src/templates/telemetry.d.ts
|
|
4
4
|
declare function generateTelemetrySpec(data: TelemetrySpecData): string;
|
|
5
5
|
//#endregion
|
|
6
|
-
export { generateTelemetrySpec };
|
|
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 @@
|
|
|
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 '@lssm/lib.contracts/telemetry';\n\nexport const ${specVar}: TelemetrySpec = {\n meta: {\n name: '${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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"}
|
|
@@ -23,4 +23,5 @@ declare function capitalize(str: string): string;
|
|
|
23
23
|
*/
|
|
24
24
|
declare function escapeString(value: string): string;
|
|
25
25
|
//#endregion
|
|
26
|
-
export { capitalize, escapeString, toCamelCase, toKebabCase, toPascalCase };
|
|
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"}
|
package/dist/templates/utils.js
CHANGED
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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 '@lssm/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 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.d.ts","names":[],"sources":["../../src/templates/workflow.ts"],"sourcesContent":[],"mappings":";;;;;;;iBAWgB,oBAAA,OAA2B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.js","names":["lines: string[]","actionLines: string[]"],"sources":["../../src/templates/workflow.ts"],"sourcesContent":["/**\n * Workflow spec template generation.\n * Extracted from cli-contracts/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 '@lssm/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 name: '${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;;aAEd,KAAK,KAAK;eACR,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,MAAMA,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,MAAMC,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"}
|
|
@@ -122,4 +122,5 @@ interface ValidationResult {
|
|
|
122
122
|
warnings: string[];
|
|
123
123
|
}
|
|
124
124
|
//#endregion
|
|
125
|
-
export { AnalyzedOperationKind, AnalyzedSpecType, ContractGraph, ContractNode, ExtractedRef, FeatureScanResult, RefInfo, RefType, SemanticDiffItem, SemanticDiffOptions, SemanticDiffType, SpecScanResult, ValidationResult };
|
|
125
|
+
export { AnalyzedOperationKind, AnalyzedSpecType, ContractGraph, ContractNode, ExtractedRef, FeatureScanResult, RefInfo, RefType, SemanticDiffItem, SemanticDiffOptions, SemanticDiffType, SpecScanResult, ValidationResult };
|
|
126
|
+
//# 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":";;;;AAgCA;AAYA;AAKA;AAQA;AAWiB,KA1DL,gBAAA,GA0DmB,WAAA,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,YAAA,GAAA,QAAA,GAAA,WAAA,GAAA,SAAA;;;;AAoBb,KAxDN,OAAA,GAwDM,WAAA,GAAA,OAAA,GAAA,cAAA,GAAA,YAAA,GAAA,YAAA,GAAA,QAAA,GAAA,MAAA;;;;AAQD,KApDL,qBAAA,GAoDsB,SAAA,GAAA,OAAA,GAAA,SAAA;;;;AAajB,UA5DA,OAAA,CA4DA;EACF,IAAA,EAAA,MAAA;EAID,OAAA,EAAA,MAAA;;;;;AAWF,UApEK,YAAA,CAoEW;EAKX,IAAA,EAxET,OAwES;EAWA,IAAA,EAAA,MAAA;EAOA,OAAA,EAAA,MAAY;EAUjB,UAAA,EAAA,MAAa;EAKR,UAAA,CAAA,EAAA,MAAgB;;;;;UA/FhB,cAAA;;YAEL;;;SAGH;cACK;;;;;;;;;;kBAcI;eACH;aACF;;;;;UAMI,iBAAA;;;;;;cAMH;;;cAKA;UACJ;iBACO;eACF;;cAID;cACA;;;QAIiB;UAAe;;;;;;KAMlC,gBAAA;;;;UAKK,gBAAA;QACT;;;;;;;;;UAUS,mBAAA;;;;;;UAOA,YAAA;;;;;;;;;KAUL,aAAA,GAAgB,YAAY;;;;UAKvB,gBAAA"}
|
|
@@ -80,4 +80,5 @@ interface CodeGenerationContext {
|
|
|
80
80
|
existingCode?: string;
|
|
81
81
|
}
|
|
82
82
|
//#endregion
|
|
83
|
-
export { AIGenerationOptions, CodeGenerationContext, DEFAULT_WORKSPACE_CONFIG, GenerationResult, GenerationTarget, SpecBuildType, SpecGenerationContext, TestTarget, WorkspaceConfig };
|
|
83
|
+
export { AIGenerationOptions, CodeGenerationContext, DEFAULT_WORKSPACE_CONFIG, GenerationResult, GenerationTarget, SpecBuildType, SpecGenerationContext, TestTarget, WorkspaceConfig };
|
|
84
|
+
//# sourceMappingURL=generation-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generation-types.d.ts","names":[],"sources":["../../src/types/generation-types.ts"],"sourcesContent":[],"mappings":";;;;AAmBA;AASA;AAKA;AAKY,UA7BK,mBAAA,CA6BQ;EAkBR,QAAA,EAAA,QAAe,GAAA,QAAA,GAAA,QAAA,GAAA,QAAA;EA6BnB,KAAA,CAAA,EAAA,MAAA;EAiBI,QAAA,CAAA,EAAA,MAAA;EASA,MAAA,CAAA,EAAA,OAAA;;;;;UA5FA,gBAAA;;;YAGL;;;;;KAMA,gBAAA;;;;KAKA,UAAA;;;;KAKA,aAAA;;;;UAkBK,eAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA6BJ,0BAA0B;;;;UAiBtB,qBAAA;;SAER;qBACY;;;;;UAMJ,qBAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generation-types.js","names":["DEFAULT_WORKSPACE_CONFIG: WorkspaceConfig"],"sources":["../../src/types/generation-types.ts"],"sourcesContent":["/**\n * Code generation related type definitions.\n */\n\nimport type { SpecType, OpKind, PresentationKind } from './spec-types';\n\n/**\n * AI provider options for generation.\n */\nexport interface AIGenerationOptions {\n provider: 'claude' | 'openai' | 'ollama' | 'custom';\n model?: string;\n endpoint?: string;\n stream?: boolean;\n}\n\n/**\n * Result of code generation.\n */\nexport interface GenerationResult {\n code: string;\n filePath: string;\n specType: SpecType;\n}\n\n/**\n * Build target types.\n */\nexport type GenerationTarget = 'handler' | 'component' | 'form';\n\n/**\n * Test target types.\n */\nexport type TestTarget = 'handler' | 'component';\n\n/**\n * Spec build type detected during build.\n */\nexport type SpecBuildType =\n | 'operation'\n | 'presentation'\n | 'form'\n | 'event'\n | 'workflow'\n | 'data-view'\n | 'telemetry'\n | 'migration'\n | 'experiment'\n | 'app-config'\n | 'integration'\n | 'knowledge'\n | 'unknown';\n\n/**\n * Configuration for workspace operations.\n */\nexport interface WorkspaceConfig {\n aiProvider: 'claude' | 'openai' | 'ollama' | 'custom';\n aiModel?: string;\n agentMode: 'simple' | 'cursor' | 'claude-code' | 'openai-codex';\n customEndpoint?: string | null;\n customApiKey?: string | null;\n outputDir: string;\n conventions: {\n operations: string;\n events: string;\n presentations: string;\n forms: string;\n workflows?: string;\n 'data-views'?: string;\n dataViews?: string;\n migrations?: string;\n telemetry?: string;\n experiments?: string;\n appConfig?: string;\n integrations?: string;\n knowledge?: string;\n };\n defaultOwners: string[];\n defaultTags: string[];\n}\n\n/**\n * Default workspace configuration.\n */\nexport const DEFAULT_WORKSPACE_CONFIG: WorkspaceConfig = {\n aiProvider: 'claude',\n agentMode: 'simple',\n outputDir: './src',\n conventions: {\n operations: 'interactions/commands|queries',\n events: 'events',\n presentations: 'presentations',\n forms: 'forms',\n },\n defaultOwners: [],\n defaultTags: [],\n};\n\n/**\n * AI prompt context for spec generation.\n */\nexport interface SpecGenerationContext {\n description: string;\n kind?: OpKind;\n presentationKind?: PresentationKind;\n}\n\n/**\n * AI prompt context for code generation.\n */\nexport interface CodeGenerationContext {\n specCode: string;\n targetPath?: string;\n existingCode?: string;\n}\n"],"mappings":";;;;AAqFA,MAAaA,2BAA4C;CACvD,YAAY;CACZ,WAAW;CACX,WAAW;CACX,aAAa;EACX,YAAY;EACZ,QAAQ;EACR,eAAe;EACf,OAAO;EACR;CACD,eAAe,EAAE;CACjB,aAAa,EAAE;CAChB"}
|
|
@@ -341,4 +341,5 @@ interface KnowledgeSpaceSpecData extends BaseSpecData {
|
|
|
341
341
|
vectorDbIntegration?: string;
|
|
342
342
|
}
|
|
343
343
|
//#endregion
|
|
344
|
-
export { AppBlueprintSpecData, AppConfigFeatureFlagData, AppConfigMappingData, AppRouteConfigData, BaseSpecData, DataViewFieldData, DataViewKind, DataViewSpecData, EventSpecData, ExperimentAllocationData, ExperimentMetricData, ExperimentSpecData, ExperimentVariantData, ExperimentVariantOverrideData, FeatureSpecData, FormSpecData, IntegrationCapabilityRefData, IntegrationCapabilityRequirementData, IntegrationCategoryData, IntegrationConfigFieldData, IntegrationConfigFieldType, IntegrationHealthCheckMethod, IntegrationOwnershipModeData, IntegrationSecretFieldData, IntegrationSpecData, KnowledgeCategoryData, KnowledgeRetentionData, KnowledgeSpaceSpecData, KnowledgeTrustLevel, MigrationSpecData, MigrationStepData, MigrationStepKind, OpKind, OperationSpecData, PresentationKind, PresentationSpecData, RandomAllocationData, SpecType, Stability, StepType, StickyAllocationData, TargetedAllocationData, TargetingRuleData, TelemetryAnomalyRuleData, TelemetryEventData, TelemetryPrivacy, TelemetryPropertyData, TelemetryProviderData, TelemetrySpecData, WorkflowSpecData, WorkflowStepData, WorkflowTransitionData };
|
|
344
|
+
export { AppBlueprintSpecData, AppConfigFeatureFlagData, AppConfigMappingData, AppRouteConfigData, BaseSpecData, DataViewFieldData, DataViewKind, DataViewSpecData, EventSpecData, ExperimentAllocationData, ExperimentMetricData, ExperimentSpecData, ExperimentVariantData, ExperimentVariantOverrideData, FeatureSpecData, FormSpecData, IntegrationCapabilityRefData, IntegrationCapabilityRequirementData, IntegrationCategoryData, IntegrationConfigFieldData, IntegrationConfigFieldType, IntegrationHealthCheckMethod, IntegrationOwnershipModeData, IntegrationSecretFieldData, IntegrationSpecData, KnowledgeCategoryData, KnowledgeRetentionData, KnowledgeSpaceSpecData, KnowledgeTrustLevel, MigrationSpecData, MigrationStepData, MigrationStepKind, OpKind, OperationSpecData, PresentationKind, PresentationSpecData, RandomAllocationData, SpecType, Stability, StepType, StickyAllocationData, TargetedAllocationData, TargetingRuleData, TelemetryAnomalyRuleData, TelemetryEventData, TelemetryPrivacy, TelemetryPropertyData, TelemetryProviderData, TelemetrySpecData, WorkflowSpecData, WorkflowStepData, WorkflowTransitionData };
|
|
345
|
+
//# sourceMappingURL=spec-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-types.d.ts","names":[],"sources":["../../src/types/spec-types.ts"],"sourcesContent":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lssm/module.contractspec-workspace",
|
|
3
|
-
"version": "0.0.0-canary-
|
|
3
|
+
"version": "0.0.0-canary-20251219202229",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -23,14 +23,14 @@
|
|
|
23
23
|
"test": "bun run"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@lssm/lib.contracts": "0.0.0-canary-
|
|
27
|
-
"@lssm/lib.schema": "0.0.0-canary-
|
|
26
|
+
"@lssm/lib.contracts": "0.0.0-canary-20251219202229",
|
|
27
|
+
"@lssm/lib.schema": "0.0.0-canary-20251219202229",
|
|
28
28
|
"zod": "^4.1.13"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@lssm/tool.tsdown": "0.0.0-canary-
|
|
32
|
-
"@lssm/tool.typescript": "0.0.0-canary-
|
|
33
|
-
"tsdown": "^0.
|
|
31
|
+
"@lssm/tool.tsdown": "0.0.0-canary-20251219202229",
|
|
32
|
+
"@lssm/tool.typescript": "0.0.0-canary-20251219202229",
|
|
33
|
+
"tsdown": "^0.18.1",
|
|
34
34
|
"typescript": "^5.9.3"
|
|
35
35
|
},
|
|
36
36
|
"exports": {
|
|
@@ -43,5 +43,6 @@
|
|
|
43
43
|
".": "./dist/index.js",
|
|
44
44
|
"./*": "./*"
|
|
45
45
|
}
|
|
46
|
-
}
|
|
46
|
+
},
|
|
47
|
+
"license": "MIT"
|
|
47
48
|
}
|