@contractspec/bundle.workspace 1.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +79 -0
- package/dist/_virtual/rolldown_runtime.js +36 -0
- package/dist/adapters/ai.d.ts +12 -0
- package/dist/adapters/ai.d.ts.map +1 -0
- package/dist/adapters/ai.js +83 -0
- package/dist/adapters/ai.js.map +1 -0
- package/dist/adapters/factory.d.ts +29 -0
- package/dist/adapters/factory.d.ts.map +1 -0
- package/dist/adapters/factory.js +37 -0
- package/dist/adapters/factory.js.map +1 -0
- package/dist/adapters/fs.d.ts +11 -0
- package/dist/adapters/fs.d.ts.map +1 -0
- package/dist/adapters/fs.js +131 -0
- package/dist/adapters/fs.js.map +1 -0
- package/dist/adapters/git.d.ts +11 -0
- package/dist/adapters/git.d.ts.map +1 -0
- package/dist/adapters/git.js +55 -0
- package/dist/adapters/git.js.map +1 -0
- package/dist/adapters/index.d.ts +7 -0
- package/dist/adapters/index.js +7 -0
- package/dist/adapters/logger.d.ts +18 -0
- package/dist/adapters/logger.d.ts.map +1 -0
- package/dist/adapters/logger.js +81 -0
- package/dist/adapters/logger.js.map +1 -0
- package/dist/adapters/watcher.d.ts +11 -0
- package/dist/adapters/watcher.d.ts.map +1 -0
- package/dist/adapters/watcher.js +74 -0
- package/dist/adapters/watcher.js.map +1 -0
- package/dist/adapters/workspace.d.ts +148 -0
- package/dist/adapters/workspace.d.ts.map +1 -0
- package/dist/adapters/workspace.js +275 -0
- package/dist/adapters/workspace.js.map +1 -0
- package/dist/ai/agents/claude-code-agent.d.ts +22 -0
- package/dist/ai/agents/claude-code-agent.d.ts.map +1 -0
- package/dist/ai/agents/claude-code-agent.js +182 -0
- package/dist/ai/agents/claude-code-agent.js.map +1 -0
- package/dist/ai/agents/cursor-agent.d.ts +68 -0
- package/dist/ai/agents/cursor-agent.d.ts.map +1 -0
- package/dist/ai/agents/cursor-agent.js +436 -0
- package/dist/ai/agents/cursor-agent.js.map +1 -0
- package/dist/ai/agents/index.js +5 -0
- package/dist/ai/agents/openai-codex-agent.d.ts +22 -0
- package/dist/ai/agents/openai-codex-agent.d.ts.map +1 -0
- package/dist/ai/agents/openai-codex-agent.js +167 -0
- package/dist/ai/agents/openai-codex-agent.js.map +1 -0
- package/dist/ai/agents/orchestrator.d.ts +50 -0
- package/dist/ai/agents/orchestrator.d.ts.map +1 -0
- package/dist/ai/agents/orchestrator.js +143 -0
- package/dist/ai/agents/orchestrator.js.map +1 -0
- package/dist/ai/agents/simple-agent.d.ts +17 -0
- package/dist/ai/agents/simple-agent.d.ts.map +1 -0
- package/dist/ai/agents/simple-agent.js +92 -0
- package/dist/ai/agents/simple-agent.js.map +1 -0
- package/dist/ai/agents/types.d.ts +36 -0
- package/dist/ai/agents/types.d.ts.map +1 -0
- package/dist/ai/client.d.ts +83 -0
- package/dist/ai/client.d.ts.map +1 -0
- package/dist/ai/client.js +163 -0
- package/dist/ai/client.js.map +1 -0
- package/dist/ai/index.d.ts +17 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +28 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/prompts/code-generation.d.ts +26 -0
- package/dist/ai/prompts/code-generation.d.ts.map +1 -0
- package/dist/ai/prompts/code-generation.js +143 -0
- package/dist/ai/prompts/code-generation.js.map +1 -0
- package/dist/ai/prompts/index.d.ts +10 -0
- package/dist/ai/prompts/index.d.ts.map +1 -0
- package/dist/ai/prompts/index.js +13 -0
- package/dist/ai/prompts/index.js.map +1 -0
- package/dist/ai/prompts/spec-creation.d.ts +29 -0
- package/dist/ai/prompts/spec-creation.d.ts.map +1 -0
- package/dist/ai/prompts/spec-creation.js +111 -0
- package/dist/ai/prompts/spec-creation.js.map +1 -0
- package/dist/ai/providers.d.ts +29 -0
- package/dist/ai/providers.d.ts.map +1 -0
- package/dist/ai/providers.js +39 -0
- package/dist/ai/providers.js.map +1 -0
- package/dist/formatters/index.d.ts +11 -0
- package/dist/formatters/index.d.ts.map +1 -0
- package/dist/formatters/index.js +19 -0
- package/dist/formatters/index.js.map +1 -0
- package/dist/formatters/json.d.ts +89 -0
- package/dist/formatters/json.d.ts.map +1 -0
- package/dist/formatters/json.js +72 -0
- package/dist/formatters/json.js.map +1 -0
- package/dist/formatters/sarif.d.ts +101 -0
- package/dist/formatters/sarif.d.ts.map +1 -0
- package/dist/formatters/sarif.js +163 -0
- package/dist/formatters/sarif.js.map +1 -0
- package/dist/formatters/text.d.ts +35 -0
- package/dist/formatters/text.d.ts.map +1 -0
- package/dist/formatters/text.js +209 -0
- package/dist/formatters/text.js.map +1 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +204 -0
- package/dist/index.js.map +1 -0
- package/dist/ports/ai.d.ts +59 -0
- package/dist/ports/ai.d.ts.map +1 -0
- package/dist/ports/fs.d.ts +81 -0
- package/dist/ports/fs.d.ts.map +1 -0
- package/dist/ports/git.d.ts +33 -0
- package/dist/ports/git.d.ts.map +1 -0
- package/dist/ports/index.d.ts +5 -0
- package/dist/ports/logger.d.ts +88 -0
- package/dist/ports/logger.d.ts.map +1 -0
- package/dist/ports/watcher.d.ts +52 -0
- package/dist/ports/watcher.d.ts.map +1 -0
- package/dist/services/agent-guide/adapters/claude-code.d.ts +35 -0
- package/dist/services/agent-guide/adapters/claude-code.d.ts.map +1 -0
- package/dist/services/agent-guide/adapters/claude-code.js +144 -0
- package/dist/services/agent-guide/adapters/claude-code.js.map +1 -0
- package/dist/services/agent-guide/adapters/cursor-cli.d.ts +39 -0
- package/dist/services/agent-guide/adapters/cursor-cli.d.ts.map +1 -0
- package/dist/services/agent-guide/adapters/cursor-cli.js +135 -0
- package/dist/services/agent-guide/adapters/cursor-cli.js.map +1 -0
- package/dist/services/agent-guide/adapters/generic-mcp.d.ts +53 -0
- package/dist/services/agent-guide/adapters/generic-mcp.d.ts.map +1 -0
- package/dist/services/agent-guide/adapters/generic-mcp.js +159 -0
- package/dist/services/agent-guide/adapters/generic-mcp.js.map +1 -0
- package/dist/services/agent-guide/adapters/index.d.ts +23 -0
- package/dist/services/agent-guide/adapters/index.d.ts.map +1 -0
- package/dist/services/agent-guide/adapters/index.js +31 -0
- package/dist/services/agent-guide/adapters/index.js.map +1 -0
- package/dist/services/agent-guide/agent-guide-service.d.ts +56 -0
- package/dist/services/agent-guide/agent-guide-service.d.ts.map +1 -0
- package/dist/services/agent-guide/agent-guide-service.js +147 -0
- package/dist/services/agent-guide/agent-guide-service.js.map +1 -0
- package/dist/services/agent-guide/index.d.ts +6 -0
- package/dist/services/agent-guide/index.js +5 -0
- package/dist/services/agent-guide/types.d.ts +58 -0
- package/dist/services/agent-guide/types.d.ts.map +1 -0
- package/dist/services/build.d.ts +59 -0
- package/dist/services/build.d.ts.map +1 -0
- package/dist/services/build.js +140 -0
- package/dist/services/build.js.map +1 -0
- package/dist/services/ci-check/ci-check-service.d.ts +16 -0
- package/dist/services/ci-check/ci-check-service.d.ts.map +1 -0
- package/dist/services/ci-check/ci-check-service.js +392 -0
- package/dist/services/ci-check/ci-check-service.js.map +1 -0
- package/dist/services/ci-check/index.d.ts +2 -0
- package/dist/services/ci-check/index.js +2 -0
- package/dist/services/ci-check/types.d.ts +143 -0
- package/dist/services/ci-check/types.d.ts.map +1 -0
- package/dist/services/ci-check/types.js +29 -0
- package/dist/services/ci-check/types.js.map +1 -0
- package/dist/services/clean.d.ts +41 -0
- package/dist/services/clean.d.ts.map +1 -0
- package/dist/services/clean.js +72 -0
- package/dist/services/clean.js.map +1 -0
- package/dist/services/config.d.ts +26 -0
- package/dist/services/config.d.ts.map +1 -0
- package/dist/services/config.js +77 -0
- package/dist/services/config.js.map +1 -0
- package/dist/services/deps.d.ts +53 -0
- package/dist/services/deps.d.ts.map +1 -0
- package/dist/services/deps.js +62 -0
- package/dist/services/deps.js.map +1 -0
- package/dist/services/diff.d.ts +34 -0
- package/dist/services/diff.d.ts.map +1 -0
- package/dist/services/diff.js +34 -0
- package/dist/services/diff.js.map +1 -0
- package/dist/services/doctor/checks/ai.js +119 -0
- package/dist/services/doctor/checks/ai.js.map +1 -0
- package/dist/services/doctor/checks/cli.js +147 -0
- package/dist/services/doctor/checks/cli.js.map +1 -0
- package/dist/services/doctor/checks/config.js +171 -0
- package/dist/services/doctor/checks/config.js.map +1 -0
- package/dist/services/doctor/checks/deps.js +247 -0
- package/dist/services/doctor/checks/deps.js.map +1 -0
- package/dist/services/doctor/checks/index.js +6 -0
- package/dist/services/doctor/checks/mcp.js +145 -0
- package/dist/services/doctor/checks/mcp.js.map +1 -0
- package/dist/services/doctor/checks/workspace.js +244 -0
- package/dist/services/doctor/checks/workspace.js.map +1 -0
- package/dist/services/doctor/doctor-service.d.ts +24 -0
- package/dist/services/doctor/doctor-service.d.ts.map +1 -0
- package/dist/services/doctor/doctor-service.js +116 -0
- package/dist/services/doctor/doctor-service.js.map +1 -0
- package/dist/services/doctor/index.d.ts +2 -0
- package/dist/services/doctor/index.js +2 -0
- package/dist/services/doctor/types.d.ts +118 -0
- package/dist/services/doctor/types.d.ts.map +1 -0
- package/dist/services/doctor/types.js +27 -0
- package/dist/services/doctor/types.js.map +1 -0
- package/dist/services/impact/formatters.d.ts +27 -0
- package/dist/services/impact/formatters.d.ts.map +1 -0
- package/dist/services/impact/formatters.js +111 -0
- package/dist/services/impact/formatters.js.map +1 -0
- package/dist/services/impact/impact-detection-service.d.ts +22 -0
- package/dist/services/impact/impact-detection-service.d.ts.map +1 -0
- package/dist/services/impact/impact-detection-service.js +96 -0
- package/dist/services/impact/impact-detection-service.js.map +1 -0
- package/dist/services/impact/index.d.ts +11 -0
- package/dist/services/impact/index.d.ts.map +1 -0
- package/dist/services/impact/index.js +16 -0
- package/dist/services/impact/index.js.map +1 -0
- package/dist/services/impact/types.d.ts +58 -0
- package/dist/services/impact/types.d.ts.map +1 -0
- package/dist/services/implementation/discovery.d.ts +30 -0
- package/dist/services/implementation/discovery.d.ts.map +1 -0
- package/dist/services/implementation/discovery.js +144 -0
- package/dist/services/implementation/discovery.js.map +1 -0
- package/dist/services/implementation/index.d.ts +3 -0
- package/dist/services/implementation/index.js +2 -0
- package/dist/services/implementation/resolver.d.ts +44 -0
- package/dist/services/implementation/resolver.d.ts.map +1 -0
- package/dist/services/implementation/resolver.js +224 -0
- package/dist/services/implementation/resolver.js.map +1 -0
- package/dist/services/implementation/types.d.ts +79 -0
- package/dist/services/implementation/types.d.ts.map +1 -0
- package/dist/services/index.d.ts +60 -0
- package/dist/services/index.js +57 -0
- package/dist/services/integrity-diagram.d.ts +36 -0
- package/dist/services/integrity-diagram.d.ts.map +1 -0
- package/dist/services/integrity-diagram.js +275 -0
- package/dist/services/integrity-diagram.js.map +1 -0
- package/dist/services/integrity.d.ts +134 -0
- package/dist/services/integrity.d.ts.map +1 -0
- package/dist/services/integrity.js +272 -0
- package/dist/services/integrity.js.map +1 -0
- package/dist/services/list.d.ts +31 -0
- package/dist/services/list.d.ts.map +1 -0
- package/dist/services/list.js +36 -0
- package/dist/services/list.js.map +1 -0
- package/dist/services/openapi/export-service.d.ts +53 -0
- package/dist/services/openapi/export-service.d.ts.map +1 -0
- package/dist/services/openapi/export-service.js +50 -0
- package/dist/services/openapi/export-service.js.map +1 -0
- package/dist/services/openapi/import-service.d.ts +17 -0
- package/dist/services/openapi/import-service.d.ts.map +1 -0
- package/dist/services/openapi/import-service.js +74 -0
- package/dist/services/openapi/import-service.js.map +1 -0
- package/dist/services/openapi/index.d.ts +5 -0
- package/dist/services/openapi/index.js +4 -0
- package/dist/services/openapi/sync-service.d.ts +17 -0
- package/dist/services/openapi/sync-service.d.ts.map +1 -0
- package/dist/services/openapi/sync-service.js +120 -0
- package/dist/services/openapi/sync-service.js.map +1 -0
- package/dist/services/openapi/types.d.ts +162 -0
- package/dist/services/openapi/types.d.ts.map +1 -0
- package/dist/services/openapi/validate-service.d.ts +16 -0
- package/dist/services/openapi/validate-service.d.ts.map +1 -0
- package/dist/services/openapi/validate-service.js +130 -0
- package/dist/services/openapi/validate-service.js.map +1 -0
- package/dist/services/quickstart/dependencies.d.ts +31 -0
- package/dist/services/quickstart/dependencies.d.ts.map +1 -0
- package/dist/services/quickstart/dependencies.js +57 -0
- package/dist/services/quickstart/dependencies.js.map +1 -0
- package/dist/services/quickstart/index.js +2 -0
- package/dist/services/quickstart/quickstart-service.d.ts +20 -0
- package/dist/services/quickstart/quickstart-service.d.ts.map +1 -0
- package/dist/services/quickstart/quickstart-service.js +196 -0
- package/dist/services/quickstart/quickstart-service.js.map +1 -0
- package/dist/services/quickstart/types.d.ts +81 -0
- package/dist/services/quickstart/types.d.ts.map +1 -0
- package/dist/services/regenerator.d.ts +18 -0
- package/dist/services/regenerator.d.ts.map +1 -0
- package/dist/services/regenerator.js +23 -0
- package/dist/services/regenerator.js.map +1 -0
- package/dist/services/registry.d.ts +53 -0
- package/dist/services/registry.d.ts.map +1 -0
- package/dist/services/registry.js +74 -0
- package/dist/services/registry.js.map +1 -0
- package/dist/services/setup/config-generators.d.ts +42 -0
- package/dist/services/setup/config-generators.d.ts.map +1 -0
- package/dist/services/setup/config-generators.js +238 -0
- package/dist/services/setup/config-generators.js.map +1 -0
- package/dist/services/setup/file-merger.d.ts +27 -0
- package/dist/services/setup/file-merger.d.ts.map +1 -0
- package/dist/services/setup/file-merger.js +61 -0
- package/dist/services/setup/file-merger.js.map +1 -0
- package/dist/services/setup/index.js +4 -0
- package/dist/services/setup/setup-service.d.ts +12 -0
- package/dist/services/setup/setup-service.d.ts.map +1 -0
- package/dist/services/setup/setup-service.js +96 -0
- package/dist/services/setup/setup-service.js.map +1 -0
- package/dist/services/setup/targets/agents-md.js +47 -0
- package/dist/services/setup/targets/agents-md.js.map +1 -0
- package/dist/services/setup/targets/cli-config.js +60 -0
- package/dist/services/setup/targets/cli-config.js.map +1 -0
- package/dist/services/setup/targets/cursor-rules.js +48 -0
- package/dist/services/setup/targets/cursor-rules.js.map +1 -0
- package/dist/services/setup/targets/mcp-claude.js +60 -0
- package/dist/services/setup/targets/mcp-claude.js.map +1 -0
- package/dist/services/setup/targets/mcp-cursor.js +59 -0
- package/dist/services/setup/targets/mcp-cursor.js.map +1 -0
- package/dist/services/setup/targets/vscode-settings.js +63 -0
- package/dist/services/setup/targets/vscode-settings.js.map +1 -0
- package/dist/services/setup/types.d.ts +85 -0
- package/dist/services/setup/types.d.ts.map +1 -0
- package/dist/services/setup/types.js +27 -0
- package/dist/services/setup/types.js.map +1 -0
- package/dist/services/sync.d.ts +41 -0
- package/dist/services/sync.d.ts.map +1 -0
- package/dist/services/sync.js +63 -0
- package/dist/services/sync.js.map +1 -0
- package/dist/services/test.d.ts +15 -0
- package/dist/services/test.d.ts.map +1 -0
- package/dist/services/test.js +30 -0
- package/dist/services/test.js.map +1 -0
- package/dist/services/validate-implementation.d.ts +32 -0
- package/dist/services/validate-implementation.d.ts.map +1 -0
- package/dist/services/validate-implementation.js +64 -0
- package/dist/services/validate-implementation.js.map +1 -0
- package/dist/services/validate.d.ts +41 -0
- package/dist/services/validate.d.ts.map +1 -0
- package/dist/services/validate.js +48 -0
- package/dist/services/validate.js.map +1 -0
- package/dist/services/verification-cache/adapters/filesystem.d.ts +46 -0
- package/dist/services/verification-cache/adapters/filesystem.d.ts.map +1 -0
- package/dist/services/verification-cache/adapters/filesystem.js +120 -0
- package/dist/services/verification-cache/adapters/filesystem.js.map +1 -0
- package/dist/services/verification-cache/adapters/in-memory.d.ts +27 -0
- package/dist/services/verification-cache/adapters/in-memory.d.ts.map +1 -0
- package/dist/services/verification-cache/adapters/in-memory.js +46 -0
- package/dist/services/verification-cache/adapters/in-memory.js.map +1 -0
- package/dist/services/verification-cache/adapters/index.d.ts +3 -0
- package/dist/services/verification-cache/adapters/index.js +3 -0
- package/dist/services/verification-cache/adapters/workspace-state.d.ts +49 -0
- package/dist/services/verification-cache/adapters/workspace-state.d.ts.map +1 -0
- package/dist/services/verification-cache/adapters/workspace-state.js +91 -0
- package/dist/services/verification-cache/adapters/workspace-state.js.map +1 -0
- package/dist/services/verification-cache/cache-service.d.ts +70 -0
- package/dist/services/verification-cache/cache-service.d.ts.map +1 -0
- package/dist/services/verification-cache/cache-service.js +256 -0
- package/dist/services/verification-cache/cache-service.js.map +1 -0
- package/dist/services/verification-cache/index.d.ts +6 -0
- package/dist/services/verification-cache/index.js +6 -0
- package/dist/services/verification-cache/types.d.ts +124 -0
- package/dist/services/verification-cache/types.d.ts.map +1 -0
- package/dist/services/verification-cache/types.js +16 -0
- package/dist/services/verification-cache/types.js.map +1 -0
- package/dist/services/verify/ai-verifier.d.ts +25 -0
- package/dist/services/verify/ai-verifier.d.ts.map +1 -0
- package/dist/services/verify/ai-verifier.js +403 -0
- package/dist/services/verify/ai-verifier.js.map +1 -0
- package/dist/services/verify/behavior-verifier.d.ts +12 -0
- package/dist/services/verify/behavior-verifier.d.ts.map +1 -0
- package/dist/services/verify/behavior-verifier.js +186 -0
- package/dist/services/verify/behavior-verifier.js.map +1 -0
- package/dist/services/verify/index.d.ts +5 -0
- package/dist/services/verify/index.js +4 -0
- package/dist/services/verify/structure-verifier.d.ts +12 -0
- package/dist/services/verify/structure-verifier.d.ts.map +1 -0
- package/dist/services/verify/structure-verifier.js +196 -0
- package/dist/services/verify/structure-verifier.js.map +1 -0
- package/dist/services/verify/types.d.ts +137 -0
- package/dist/services/verify/types.d.ts.map +1 -0
- package/dist/services/verify/verify-service.d.ts +60 -0
- package/dist/services/verify/verify-service.d.ts.map +1 -0
- package/dist/services/verify/verify-service.js +204 -0
- package/dist/services/verify/verify-service.js.map +1 -0
- package/dist/services/watch.d.ts +25 -0
- package/dist/services/watch.d.ts.map +1 -0
- package/dist/services/watch.js +32 -0
- package/dist/services/watch.js.map +1 -0
- package/dist/services/workspace-info.d.ts +62 -0
- package/dist/services/workspace-info.d.ts.map +1 -0
- package/dist/services/workspace-info.js +103 -0
- package/dist/services/workspace-info.js.map +1 -0
- package/dist/templates/app-config.template.d.ts +7 -0
- package/dist/templates/app-config.template.d.ts.map +1 -0
- package/dist/templates/app-config.template.js +107 -0
- package/dist/templates/app-config.template.js.map +1 -0
- package/dist/templates/data-view.template.d.ts +7 -0
- package/dist/templates/data-view.template.d.ts.map +1 -0
- package/dist/templates/data-view.template.js +70 -0
- package/dist/templates/data-view.template.js.map +1 -0
- package/dist/templates/event.template.d.ts +11 -0
- package/dist/templates/event.template.d.ts.map +1 -0
- package/dist/templates/event.template.js +40 -0
- package/dist/templates/event.template.js.map +1 -0
- package/dist/templates/experiment.template.d.ts +7 -0
- package/dist/templates/experiment.template.d.ts.map +1 -0
- package/dist/templates/experiment.template.js +89 -0
- package/dist/templates/experiment.template.js.map +1 -0
- package/dist/templates/handler.template.d.ts +16 -0
- package/dist/templates/handler.template.d.ts.map +1 -0
- package/dist/templates/handler.template.js +100 -0
- package/dist/templates/handler.template.js.map +1 -0
- package/dist/templates/index.d.ts +21 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +37 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/templates/integration.template.d.ts +7 -0
- package/dist/templates/integration.template.d.ts.map +1 -0
- package/dist/templates/integration.template.js +160 -0
- package/dist/templates/integration.template.js.map +1 -0
- package/dist/templates/knowledge.template.d.ts +7 -0
- package/dist/templates/knowledge.template.d.ts.map +1 -0
- package/dist/templates/knowledge.template.js +75 -0
- package/dist/templates/knowledge.template.js.map +1 -0
- package/dist/templates/migration.template.d.ts +7 -0
- package/dist/templates/migration.template.d.ts.map +1 -0
- package/dist/templates/migration.template.js +62 -0
- package/dist/templates/migration.template.js.map +1 -0
- package/dist/templates/operation.template.d.ts +11 -0
- package/dist/templates/operation.template.d.ts.map +1 -0
- package/dist/templates/operation.template.js +105 -0
- package/dist/templates/operation.template.js.map +1 -0
- package/dist/templates/presentation.template.d.ts +11 -0
- package/dist/templates/presentation.template.d.ts.map +1 -0
- package/dist/templates/presentation.template.js +80 -0
- package/dist/templates/presentation.template.js.map +1 -0
- package/dist/templates/telemetry.template.d.ts +7 -0
- package/dist/templates/telemetry.template.d.ts.map +1 -0
- package/dist/templates/telemetry.template.js +91 -0
- package/dist/templates/telemetry.template.js.map +1 -0
- package/dist/templates/workflow-runner.template.d.ts +16 -0
- package/dist/templates/workflow-runner.template.d.ts.map +1 -0
- package/dist/templates/workflow-runner.template.js +50 -0
- package/dist/templates/workflow-runner.template.js.map +1 -0
- package/dist/templates/workflow.template.d.ts +7 -0
- package/dist/templates/workflow.template.d.ts.map +1 -0
- package/dist/templates/workflow.template.js +69 -0
- package/dist/templates/workflow.template.js.map +1 -0
- package/dist/types/config.d.ts +34 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types.d.ts +324 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { FsAdapter } from "../ports/fs.js";
|
|
2
|
+
import { LoggerAdapter } from "../ports/logger.js";
|
|
3
|
+
import { AnalyzedSpecType, FeatureScanResult, RefInfo } from "@contractspec/module.workspace";
|
|
4
|
+
|
|
5
|
+
//#region src/services/integrity.d.ts
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Options for integrity analysis.
|
|
9
|
+
*/
|
|
10
|
+
interface IntegrityAnalysisOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Glob pattern for file discovery.
|
|
13
|
+
*/
|
|
14
|
+
pattern?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Scan all packages in monorepo.
|
|
17
|
+
*/
|
|
18
|
+
all?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Analyze only a specific feature by key.
|
|
21
|
+
*/
|
|
22
|
+
featureKey?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Filter by spec type.
|
|
25
|
+
*/
|
|
26
|
+
specType?: AnalyzedSpecType;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Location of a spec in the codebase.
|
|
30
|
+
*/
|
|
31
|
+
interface SpecLocation {
|
|
32
|
+
key: string;
|
|
33
|
+
version: number;
|
|
34
|
+
file: string;
|
|
35
|
+
type: AnalyzedSpecType;
|
|
36
|
+
stability?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Inventory of all discovered specs organized by type.
|
|
40
|
+
*/
|
|
41
|
+
interface SpecInventory {
|
|
42
|
+
operations: Map<string, SpecLocation>;
|
|
43
|
+
events: Map<string, SpecLocation>;
|
|
44
|
+
presentations: Map<string, SpecLocation>;
|
|
45
|
+
capabilities: Map<string, SpecLocation>;
|
|
46
|
+
workflows: Map<string, SpecLocation>;
|
|
47
|
+
dataViews: Map<string, SpecLocation>;
|
|
48
|
+
forms: Map<string, SpecLocation>;
|
|
49
|
+
migrations: Map<string, SpecLocation>;
|
|
50
|
+
experiments: Map<string, SpecLocation>;
|
|
51
|
+
integrations: Map<string, SpecLocation>;
|
|
52
|
+
knowledge: Map<string, SpecLocation>;
|
|
53
|
+
telemetry: Map<string, SpecLocation>;
|
|
54
|
+
appConfigs: Map<string, SpecLocation>;
|
|
55
|
+
policies: Map<string, SpecLocation>;
|
|
56
|
+
testSpecs: Map<string, SpecLocation>;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* An integrity issue found during analysis.
|
|
60
|
+
*/
|
|
61
|
+
interface IntegrityIssue {
|
|
62
|
+
severity: 'error' | 'warning';
|
|
63
|
+
type: 'orphaned' | 'unresolved-ref' | 'missing-feature' | 'broken-link';
|
|
64
|
+
message: string;
|
|
65
|
+
file: string;
|
|
66
|
+
specKey?: string;
|
|
67
|
+
specType?: AnalyzedSpecType;
|
|
68
|
+
ref?: RefInfo;
|
|
69
|
+
featureKey?: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Coverage metrics by spec type.
|
|
73
|
+
*/
|
|
74
|
+
interface CoverageByType {
|
|
75
|
+
total: number;
|
|
76
|
+
covered: number;
|
|
77
|
+
orphaned: number;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Result of integrity analysis.
|
|
81
|
+
*/
|
|
82
|
+
interface IntegrityAnalysisResult {
|
|
83
|
+
/**
|
|
84
|
+
* All discovered specs organized by type.
|
|
85
|
+
*/
|
|
86
|
+
inventory: SpecInventory;
|
|
87
|
+
/**
|
|
88
|
+
* All discovered features.
|
|
89
|
+
*/
|
|
90
|
+
features: FeatureScanResult[];
|
|
91
|
+
/**
|
|
92
|
+
* Coverage metrics.
|
|
93
|
+
*/
|
|
94
|
+
coverage: {
|
|
95
|
+
total: number;
|
|
96
|
+
linkedToFeature: number;
|
|
97
|
+
orphaned: number;
|
|
98
|
+
byType: Record<string, CoverageByType>;
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Issues found during analysis.
|
|
102
|
+
*/
|
|
103
|
+
issues: IntegrityIssue[];
|
|
104
|
+
/**
|
|
105
|
+
* Specs not linked to any feature.
|
|
106
|
+
*/
|
|
107
|
+
orphanedSpecs: SpecLocation[];
|
|
108
|
+
/**
|
|
109
|
+
* Overall health status.
|
|
110
|
+
*/
|
|
111
|
+
healthy: boolean;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Analyze contract integrity.
|
|
115
|
+
*/
|
|
116
|
+
declare function analyzeIntegrity(adapters: {
|
|
117
|
+
fs: FsAdapter;
|
|
118
|
+
logger: LoggerAdapter;
|
|
119
|
+
}, options?: IntegrityAnalysisOptions): Promise<IntegrityAnalysisResult>;
|
|
120
|
+
/**
|
|
121
|
+
* Get all specs from inventory as a flat list.
|
|
122
|
+
*/
|
|
123
|
+
declare function getAllSpecs(inventory: SpecInventory): SpecLocation[];
|
|
124
|
+
/**
|
|
125
|
+
* Filter issues by type.
|
|
126
|
+
*/
|
|
127
|
+
declare function filterIssuesByType(issues: IntegrityIssue[], type: IntegrityIssue['type']): IntegrityIssue[];
|
|
128
|
+
/**
|
|
129
|
+
* Filter issues by severity.
|
|
130
|
+
*/
|
|
131
|
+
declare function filterIssuesBySeverity(issues: IntegrityIssue[], severity: IntegrityIssue['severity']): IntegrityIssue[];
|
|
132
|
+
//#endregion
|
|
133
|
+
export { CoverageByType, IntegrityAnalysisOptions, IntegrityAnalysisResult, IntegrityIssue, SpecInventory, SpecLocation, analyzeIntegrity, filterIssuesBySeverity, filterIssuesByType, getAllSpecs };
|
|
134
|
+
//# sourceMappingURL=integrity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integrity.d.ts","names":[],"sources":["../../src/services/integrity.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AA+D4B,UAxCX,wBAAA,CAwCW;EAAZ;;;EAES,OAAA,CAAA,EAAA,MAAA;EAAZ;;;EAEa,GAAA,CAAA,EAAA,OAAA;EAAZ;;;EAEc,UAAA,CAAA,EAAA,MAAA;EAAZ;;;EAES,QAAA,CAAA,EA7BZ,gBA6BY;;;;;AAEb,UAzBK,YAAA,CAyBL;EACa,GAAA,EAAA,MAAA;EAAZ,OAAA,EAAA,MAAA;EAAG,IAAA,EAAA,MAAA;EAMC,IAAA,EA5BT,gBA4BuB;EAcd,SAAA,CAAA,EAAA,MAAc;AAS/B;;;;AAkBY,UA9DK,aAAA,CA8DL;EAMF,UAAA,EAnEI,GAmEJ,CAAA,MAAA,EAnEgB,YAmEhB,CAAA;EAKO,MAAA,EAvEP,GAuEO,CAAA,MAAA,EAvEK,YAuEL,CAAA;EAAY,aAAA,EAtEZ,GAsEY,CAAA,MAAA,EAtEA,YAsEA,CAAA;EAqEP,YAAA,EA1IN,GA0IM,CAAA,MAAgB,EA1IV,YA0IU,CAAA;EACpB,SAAA,EA1IL,GA0IK,CAAA,MAAA,EA1IO,YA0IP,CAAA;EAAmB,SAAA,EAzIxB,GAyIwB,CAAA,MAAA,EAzIZ,YAyIY,CAAA;EAC1B,KAAA,EAzIF,GAyIE,CAAA,MAAA,EAzIU,YAyIV,CAAA;EACA,UAAA,EAzIG,GAyIH,CAAA,MAAA,EAzIe,YAyIf,CAAA;EAAR,WAAA,EAxIY,GAwIZ,CAAA,MAAA,EAxIwB,YAwIxB,CAAA;EAAO,YAAA,EAvIM,GAuIN,CAAA,MAAA,EAvIkB,YAuIlB,CAAA;EAgRM,SAAA,EAtZH,GAsZc,CAAA,MAAA,EAtZF,YAsZc,CAAA;EAevB,SAAA,EApaH,GAoaG,CAAA,MAAkB,EApaT,YAoaS,CAAA;EACxB,UAAA,EApaI,GAoaJ,CAAA,MAAA,EApagB,YAoahB,CAAA;EACF,QAAA,EApaI,GAoaJ,CAAA,MAAA,EApagB,YAoahB,CAAA;EACL,SAAA,EApaU,GAoaV,CAAA,MAAA,EApasB,YAoatB,CAAA;;AAOH;;;AAGG,UAxac,cAAA,CAwad;EAAc,QAAA,EAAA,OAAA,GAAA,SAAA;;;;;aAlaJ;QACL;;;;;;UAOS,cAAA;;;;;;;;UASA,uBAAA;;;;aAIJ;;;;YAKD;;;;;;;;YASA,eAAe;;;;;UAMjB;;;;iBAKO;;;;;;;;;iBAqEK,gBAAA;MACJ;UAAmB;aAC1B,2BACR,QAAQ;;;;iBAgRK,WAAA,YAAuB,gBAAgB;;;;iBAevC,kBAAA,SACN,wBACF,yBACL;;;;iBAOa,sBAAA,SACN,4BACE,6BACT"}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { isFeatureFile, scanAllSpecsFromSource, scanFeatureSource } from "@contractspec/module.workspace";
|
|
2
|
+
|
|
3
|
+
//#region src/services/integrity.ts
|
|
4
|
+
/**
|
|
5
|
+
* Contract integrity analysis service.
|
|
6
|
+
*
|
|
7
|
+
* Analyzes contract specs and features to detect:
|
|
8
|
+
* - Orphaned specs (not linked to any feature)
|
|
9
|
+
* - Unresolved references (broken event/op/presentation refs)
|
|
10
|
+
* - Feature coverage metrics
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Build a spec key from name and version.
|
|
14
|
+
*/
|
|
15
|
+
function specKey(key, version) {
|
|
16
|
+
return `${key}.v${version}`;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create an empty spec inventory.
|
|
20
|
+
*/
|
|
21
|
+
function createEmptyInventory() {
|
|
22
|
+
return {
|
|
23
|
+
operations: /* @__PURE__ */ new Map(),
|
|
24
|
+
events: /* @__PURE__ */ new Map(),
|
|
25
|
+
presentations: /* @__PURE__ */ new Map(),
|
|
26
|
+
capabilities: /* @__PURE__ */ new Map(),
|
|
27
|
+
workflows: /* @__PURE__ */ new Map(),
|
|
28
|
+
dataViews: /* @__PURE__ */ new Map(),
|
|
29
|
+
forms: /* @__PURE__ */ new Map(),
|
|
30
|
+
migrations: /* @__PURE__ */ new Map(),
|
|
31
|
+
experiments: /* @__PURE__ */ new Map(),
|
|
32
|
+
integrations: /* @__PURE__ */ new Map(),
|
|
33
|
+
knowledge: /* @__PURE__ */ new Map(),
|
|
34
|
+
telemetry: /* @__PURE__ */ new Map(),
|
|
35
|
+
appConfigs: /* @__PURE__ */ new Map(),
|
|
36
|
+
policies: /* @__PURE__ */ new Map(),
|
|
37
|
+
testSpecs: /* @__PURE__ */ new Map()
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get the inventory map for a spec type.
|
|
42
|
+
*/
|
|
43
|
+
function getInventoryMap(inventory, specType) {
|
|
44
|
+
return {
|
|
45
|
+
operation: inventory.operations,
|
|
46
|
+
event: inventory.events,
|
|
47
|
+
presentation: inventory.presentations,
|
|
48
|
+
capability: inventory.capabilities,
|
|
49
|
+
workflow: inventory.workflows,
|
|
50
|
+
"data-view": inventory.dataViews,
|
|
51
|
+
form: inventory.forms,
|
|
52
|
+
migration: inventory.migrations,
|
|
53
|
+
experiment: inventory.experiments,
|
|
54
|
+
integration: inventory.integrations,
|
|
55
|
+
knowledge: inventory.knowledge,
|
|
56
|
+
telemetry: inventory.telemetry,
|
|
57
|
+
"app-config": inventory.appConfigs,
|
|
58
|
+
policy: inventory.policies,
|
|
59
|
+
"test-spec": inventory.testSpecs
|
|
60
|
+
}[specType];
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Analyze contract integrity.
|
|
64
|
+
*/
|
|
65
|
+
async function analyzeIntegrity(adapters, options = {}) {
|
|
66
|
+
const { fs, logger } = adapters;
|
|
67
|
+
logger.info("Starting integrity analysis...", { options });
|
|
68
|
+
const files = await fs.glob({ pattern: options.pattern });
|
|
69
|
+
const inventory = createEmptyInventory();
|
|
70
|
+
const features = [];
|
|
71
|
+
const issues = [];
|
|
72
|
+
for (const file of files) {
|
|
73
|
+
const content = await fs.readFile(file);
|
|
74
|
+
if (isFeatureFile(file)) {
|
|
75
|
+
const feature = scanFeatureSource(content, file);
|
|
76
|
+
features.push(feature);
|
|
77
|
+
} else {
|
|
78
|
+
const specs = scanAllSpecsFromSource(content, file);
|
|
79
|
+
for (const spec of specs) if (spec.specType !== "unknown" && spec.specType !== "feature") {
|
|
80
|
+
const map = getInventoryMap(inventory, spec.specType);
|
|
81
|
+
if (map && spec.key && spec.version !== void 0) {
|
|
82
|
+
const key = specKey(spec.key, spec.version);
|
|
83
|
+
map.set(key, {
|
|
84
|
+
key: spec.key,
|
|
85
|
+
version: spec.version,
|
|
86
|
+
file: spec.filePath,
|
|
87
|
+
type: spec.specType,
|
|
88
|
+
stability: spec.stability
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const relevantFeatures = options.featureKey ? features.filter((f) => f.key === options.featureKey) : features;
|
|
95
|
+
const referencedSpecs = /* @__PURE__ */ new Set();
|
|
96
|
+
for (const feature of relevantFeatures) {
|
|
97
|
+
for (const ref of feature.operations) {
|
|
98
|
+
const key = specKey(ref.key, ref.version);
|
|
99
|
+
referencedSpecs.add(`operation:${key}`);
|
|
100
|
+
if (!inventory.operations.has(key)) issues.push({
|
|
101
|
+
severity: "error",
|
|
102
|
+
type: "unresolved-ref",
|
|
103
|
+
message: `Operation ${ref.key}.v${ref.version} not found`,
|
|
104
|
+
file: feature.filePath,
|
|
105
|
+
featureKey: feature.key,
|
|
106
|
+
specType: "operation",
|
|
107
|
+
ref
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
for (const ref of feature.events) {
|
|
111
|
+
const key = specKey(ref.key, ref.version);
|
|
112
|
+
referencedSpecs.add(`event:${key}`);
|
|
113
|
+
if (!inventory.events.has(key)) issues.push({
|
|
114
|
+
severity: "error",
|
|
115
|
+
type: "unresolved-ref",
|
|
116
|
+
message: `Event ${ref.key}.v${ref.version} not found`,
|
|
117
|
+
file: feature.filePath,
|
|
118
|
+
featureKey: feature.key,
|
|
119
|
+
specType: "event",
|
|
120
|
+
ref
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
for (const ref of feature.presentations) {
|
|
124
|
+
const key = specKey(ref.key, ref.version);
|
|
125
|
+
referencedSpecs.add(`presentation:${key}`);
|
|
126
|
+
if (!inventory.presentations.has(key)) issues.push({
|
|
127
|
+
severity: "error",
|
|
128
|
+
type: "unresolved-ref",
|
|
129
|
+
message: `Presentation ${ref.key}.v${ref.version} not found`,
|
|
130
|
+
file: feature.filePath,
|
|
131
|
+
featureKey: feature.key,
|
|
132
|
+
specType: "presentation",
|
|
133
|
+
ref
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
for (const ref of feature.experiments) {
|
|
137
|
+
const key = specKey(ref.key, ref.version);
|
|
138
|
+
referencedSpecs.add(`experiment:${key}`);
|
|
139
|
+
if (!inventory.experiments.has(key)) issues.push({
|
|
140
|
+
severity: "error",
|
|
141
|
+
type: "unresolved-ref",
|
|
142
|
+
message: `Experiment ${ref.key}.v${ref.version} not found`,
|
|
143
|
+
file: feature.filePath,
|
|
144
|
+
featureKey: feature.key,
|
|
145
|
+
specType: "experiment",
|
|
146
|
+
ref
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
for (const ref of feature.capabilities.provides) {
|
|
150
|
+
const key = specKey(ref.key, ref.version);
|
|
151
|
+
referencedSpecs.add(`capability:${key}`);
|
|
152
|
+
if (!inventory.capabilities.has(key)) issues.push({
|
|
153
|
+
severity: "warning",
|
|
154
|
+
type: "unresolved-ref",
|
|
155
|
+
message: `Provided capability ${ref.key}.v${ref.version} not found`,
|
|
156
|
+
file: feature.filePath,
|
|
157
|
+
featureKey: feature.key,
|
|
158
|
+
specType: "capability",
|
|
159
|
+
ref
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
for (const ref of feature.capabilities.requires) {
|
|
163
|
+
const key = specKey(ref.key, ref.version);
|
|
164
|
+
referencedSpecs.add(`capability:${key}`);
|
|
165
|
+
}
|
|
166
|
+
for (const link of feature.opToPresentationLinks) {
|
|
167
|
+
const opKey = specKey(link.op.key, link.op.version);
|
|
168
|
+
const presKey = specKey(link.pres.key, link.pres.version);
|
|
169
|
+
if (!inventory.operations.has(opKey)) issues.push({
|
|
170
|
+
severity: "error",
|
|
171
|
+
type: "broken-link",
|
|
172
|
+
message: `Linked operation ${link.op.key}.v${link.op.version} not found`,
|
|
173
|
+
file: feature.filePath,
|
|
174
|
+
featureKey: feature.key,
|
|
175
|
+
specType: "operation",
|
|
176
|
+
ref: link.op
|
|
177
|
+
});
|
|
178
|
+
if (!inventory.presentations.has(presKey)) issues.push({
|
|
179
|
+
severity: "error",
|
|
180
|
+
type: "broken-link",
|
|
181
|
+
message: `Linked presentation ${link.pres.key}.v${link.pres.version} not found`,
|
|
182
|
+
file: feature.filePath,
|
|
183
|
+
featureKey: feature.key,
|
|
184
|
+
specType: "presentation",
|
|
185
|
+
ref: link.pres
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const orphanedSpecs = [];
|
|
190
|
+
const typesThatCanBeOrphaned = [
|
|
191
|
+
"operation",
|
|
192
|
+
"event",
|
|
193
|
+
"presentation",
|
|
194
|
+
"experiment"
|
|
195
|
+
];
|
|
196
|
+
for (const type of typesThatCanBeOrphaned) {
|
|
197
|
+
const map = getInventoryMap(inventory, type);
|
|
198
|
+
if (!map) continue;
|
|
199
|
+
for (const [key, location] of map) if (!referencedSpecs.has(`${type}:${key}`)) {
|
|
200
|
+
orphanedSpecs.push(location);
|
|
201
|
+
issues.push({
|
|
202
|
+
severity: "warning",
|
|
203
|
+
type: "orphaned",
|
|
204
|
+
message: `${type} ${location.key}.v${location.version} is not linked to any feature`,
|
|
205
|
+
file: location.file,
|
|
206
|
+
specKey: location.key,
|
|
207
|
+
specType: location.type
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const coverageByType = {};
|
|
212
|
+
for (const type of typesThatCanBeOrphaned) {
|
|
213
|
+
const map = getInventoryMap(inventory, type);
|
|
214
|
+
if (!map) continue;
|
|
215
|
+
const total = map.size;
|
|
216
|
+
let covered = 0;
|
|
217
|
+
for (const key of map.keys()) if (referencedSpecs.has(`${type}:${key}`)) covered++;
|
|
218
|
+
coverageByType[type] = {
|
|
219
|
+
total,
|
|
220
|
+
covered,
|
|
221
|
+
orphaned: total - covered
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
const totalSpecs = Object.values(coverageByType).reduce((sum, c) => sum + c.total, 0);
|
|
225
|
+
const coveredSpecs = Object.values(coverageByType).reduce((sum, c) => sum + c.covered, 0);
|
|
226
|
+
const coverage = {
|
|
227
|
+
total: totalSpecs,
|
|
228
|
+
linkedToFeature: coveredSpecs,
|
|
229
|
+
orphaned: totalSpecs - coveredSpecs,
|
|
230
|
+
byType: coverageByType
|
|
231
|
+
};
|
|
232
|
+
const healthy = !issues.some((i) => i.severity === "error");
|
|
233
|
+
logger.info("Integrity analysis complete", {
|
|
234
|
+
features: features.length,
|
|
235
|
+
totalSpecs,
|
|
236
|
+
orphaned: orphanedSpecs.length,
|
|
237
|
+
issues: issues.length,
|
|
238
|
+
healthy
|
|
239
|
+
});
|
|
240
|
+
return {
|
|
241
|
+
inventory,
|
|
242
|
+
features: relevantFeatures,
|
|
243
|
+
coverage,
|
|
244
|
+
issues,
|
|
245
|
+
orphanedSpecs,
|
|
246
|
+
healthy
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Get all specs from inventory as a flat list.
|
|
251
|
+
*/
|
|
252
|
+
function getAllSpecs(inventory) {
|
|
253
|
+
const all = [];
|
|
254
|
+
for (const map of Object.values(inventory)) for (const spec of map.values()) all.push(spec);
|
|
255
|
+
return all;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Filter issues by type.
|
|
259
|
+
*/
|
|
260
|
+
function filterIssuesByType(issues, type) {
|
|
261
|
+
return issues.filter((i) => i.type === type);
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Filter issues by severity.
|
|
265
|
+
*/
|
|
266
|
+
function filterIssuesBySeverity(issues, severity) {
|
|
267
|
+
return issues.filter((i) => i.severity === severity);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
//#endregion
|
|
271
|
+
export { analyzeIntegrity, filterIssuesBySeverity, filterIssuesByType, getAllSpecs };
|
|
272
|
+
//# sourceMappingURL=integrity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integrity.js","names":["features: FeatureScanResult[]","issues: IntegrityIssue[]","orphanedSpecs: SpecLocation[]","typesThatCanBeOrphaned: AnalyzedSpecType[]","coverageByType: Record<string, CoverageByType>","all: SpecLocation[]"],"sources":["../../src/services/integrity.ts"],"sourcesContent":["/**\n * Contract integrity analysis service.\n *\n * Analyzes contract specs and features to detect:\n * - Orphaned specs (not linked to any feature)\n * - Unresolved references (broken event/op/presentation refs)\n * - Feature coverage metrics\n */\n\nimport {\n type AnalyzedSpecType,\n type FeatureScanResult,\n isFeatureFile,\n type RefInfo,\n scanAllSpecsFromSource,\n scanFeatureSource,\n} from '@contractspec/module.workspace';\nimport type { FsAdapter } from '../ports/fs';\nimport type { LoggerAdapter } from '../ports/logger';\n\n/**\n * Options for integrity analysis.\n */\nexport interface IntegrityAnalysisOptions {\n /**\n * Glob pattern for file discovery.\n */\n pattern?: string;\n\n /**\n * Scan all packages in monorepo.\n */\n all?: boolean;\n\n /**\n * Analyze only a specific feature by key.\n */\n featureKey?: string;\n\n /**\n * Filter by spec type.\n */\n specType?: AnalyzedSpecType;\n}\n\n/**\n * Location of a spec in the codebase.\n */\nexport interface SpecLocation {\n key: string;\n version: number;\n file: string;\n type: AnalyzedSpecType;\n stability?: string;\n}\n\n/**\n * Inventory of all discovered specs organized by type.\n */\nexport interface SpecInventory {\n operations: Map<string, SpecLocation>;\n events: Map<string, SpecLocation>;\n presentations: Map<string, SpecLocation>;\n capabilities: Map<string, SpecLocation>;\n workflows: Map<string, SpecLocation>;\n dataViews: Map<string, SpecLocation>;\n forms: Map<string, SpecLocation>;\n migrations: Map<string, SpecLocation>;\n experiments: Map<string, SpecLocation>;\n integrations: Map<string, SpecLocation>;\n knowledge: Map<string, SpecLocation>;\n telemetry: Map<string, SpecLocation>;\n appConfigs: Map<string, SpecLocation>;\n policies: Map<string, SpecLocation>;\n testSpecs: Map<string, SpecLocation>;\n}\n\n/**\n * An integrity issue found during analysis.\n */\nexport interface IntegrityIssue {\n severity: 'error' | 'warning';\n type: 'orphaned' | 'unresolved-ref' | 'missing-feature' | 'broken-link';\n message: string;\n file: string;\n specKey?: string;\n specType?: AnalyzedSpecType;\n ref?: RefInfo;\n featureKey?: string;\n}\n\n/**\n * Coverage metrics by spec type.\n */\nexport interface CoverageByType {\n total: number;\n covered: number;\n orphaned: number;\n}\n\n/**\n * Result of integrity analysis.\n */\nexport interface IntegrityAnalysisResult {\n /**\n * All discovered specs organized by type.\n */\n inventory: SpecInventory;\n\n /**\n * All discovered features.\n */\n features: FeatureScanResult[];\n\n /**\n * Coverage metrics.\n */\n coverage: {\n total: number;\n linkedToFeature: number;\n orphaned: number;\n byType: Record<string, CoverageByType>;\n };\n\n /**\n * Issues found during analysis.\n */\n issues: IntegrityIssue[];\n\n /**\n * Specs not linked to any feature.\n */\n orphanedSpecs: SpecLocation[];\n\n /**\n * Overall health status.\n */\n healthy: boolean;\n}\n\n/**\n * Build a spec key from name and version.\n */\nfunction specKey(key: string, version: number): string {\n return `${key}.v${version}`;\n}\n\n/**\n * Create an empty spec inventory.\n */\nfunction createEmptyInventory(): SpecInventory {\n return {\n operations: new Map(),\n events: new Map(),\n presentations: new Map(),\n capabilities: new Map(),\n workflows: new Map(),\n dataViews: new Map(),\n forms: new Map(),\n migrations: new Map(),\n experiments: new Map(),\n integrations: new Map(),\n knowledge: new Map(),\n telemetry: new Map(),\n appConfigs: new Map(),\n policies: new Map(),\n testSpecs: new Map(),\n };\n}\n\n/**\n * Get the inventory map for a spec type.\n */\nfunction getInventoryMap(\n inventory: SpecInventory,\n specType: AnalyzedSpecType\n): Map<string, SpecLocation> | undefined {\n const typeToMap: Record<string, Map<string, SpecLocation>> = {\n operation: inventory.operations,\n event: inventory.events,\n presentation: inventory.presentations,\n capability: inventory.capabilities,\n workflow: inventory.workflows,\n 'data-view': inventory.dataViews,\n form: inventory.forms,\n migration: inventory.migrations,\n experiment: inventory.experiments,\n integration: inventory.integrations,\n knowledge: inventory.knowledge,\n telemetry: inventory.telemetry,\n 'app-config': inventory.appConfigs,\n policy: inventory.policies,\n 'test-spec': inventory.testSpecs,\n };\n\n return typeToMap[specType];\n}\n\n/**\n * Analyze contract integrity.\n */\nexport async function analyzeIntegrity(\n adapters: { fs: FsAdapter; logger: LoggerAdapter },\n options: IntegrityAnalysisOptions = {}\n): Promise<IntegrityAnalysisResult> {\n const { fs, logger } = adapters;\n\n logger.info('Starting integrity analysis...', { options });\n\n // Discover all spec and feature files\n const files = await fs.glob({ pattern: options.pattern });\n\n const inventory = createEmptyInventory();\n const features: FeatureScanResult[] = [];\n const issues: IntegrityIssue[] = [];\n\n // Scan all files\n for (const file of files) {\n const content = await fs.readFile(file);\n\n if (isFeatureFile(file)) {\n // Scan as feature\n const feature = scanFeatureSource(content, file);\n features.push(feature);\n } else {\n // Scan as spec - use the multi-spec scanner to find ALL specs in the file\n const specs = scanAllSpecsFromSource(content, file);\n\n for (const spec of specs) {\n if (spec.specType !== 'unknown' && spec.specType !== 'feature') {\n const map = getInventoryMap(inventory, spec.specType);\n\n if (map && spec.key && spec.version !== undefined) {\n const key = specKey(spec.key, spec.version);\n map.set(key, {\n key: spec.key,\n version: spec.version,\n file: spec.filePath,\n type: spec.specType,\n stability: spec.stability,\n });\n }\n }\n }\n }\n }\n\n // Filter features if featureKey is specified\n const relevantFeatures = options.featureKey\n ? features.filter((f) => f.key === options.featureKey)\n : features;\n\n // Build set of specs referenced by features\n const referencedSpecs = new Set<string>();\n\n for (const feature of relevantFeatures) {\n // Check operation refs\n for (const ref of feature.operations) {\n const key = specKey(ref.key, ref.version);\n referencedSpecs.add(`operation:${key}`);\n\n if (!inventory.operations.has(key)) {\n issues.push({\n severity: 'error',\n type: 'unresolved-ref',\n message: `Operation ${ref.key}.v${ref.version} not found`,\n file: feature.filePath,\n featureKey: feature.key,\n specType: 'operation',\n ref,\n });\n }\n }\n\n // Check event refs\n for (const ref of feature.events) {\n const key = specKey(ref.key, ref.version);\n referencedSpecs.add(`event:${key}`);\n\n if (!inventory.events.has(key)) {\n issues.push({\n severity: 'error',\n type: 'unresolved-ref',\n message: `Event ${ref.key}.v${ref.version} not found`,\n file: feature.filePath,\n featureKey: feature.key,\n specType: 'event',\n ref,\n });\n }\n }\n\n // Check presentation refs\n for (const ref of feature.presentations) {\n const key = specKey(ref.key, ref.version);\n referencedSpecs.add(`presentation:${key}`);\n\n if (!inventory.presentations.has(key)) {\n issues.push({\n severity: 'error',\n type: 'unresolved-ref',\n message: `Presentation ${ref.key}.v${ref.version} not found`,\n file: feature.filePath,\n featureKey: feature.key,\n specType: 'presentation',\n ref,\n });\n }\n }\n\n // Check experiment refs\n for (const ref of feature.experiments) {\n const key = specKey(ref.key, ref.version);\n referencedSpecs.add(`experiment:${key}`);\n\n if (!inventory.experiments.has(key)) {\n issues.push({\n severity: 'error',\n type: 'unresolved-ref',\n message: `Experiment ${ref.key}.v${ref.version} not found`,\n file: feature.filePath,\n featureKey: feature.key,\n specType: 'experiment',\n ref,\n });\n }\n }\n\n // Check capability refs (provides and requires)\n for (const ref of feature.capabilities.provides) {\n const key = specKey(ref.key, ref.version);\n referencedSpecs.add(`capability:${key}`);\n\n if (!inventory.capabilities.has(key)) {\n issues.push({\n severity: 'warning',\n type: 'unresolved-ref',\n message: `Provided capability ${ref.key}.v${ref.version} not found`,\n file: feature.filePath,\n featureKey: feature.key,\n specType: 'capability',\n ref,\n });\n }\n }\n\n for (const ref of feature.capabilities.requires) {\n const key = specKey(ref.key, ref.version);\n // Required capabilities are expected to be provided by other features\n // We just track the reference\n referencedSpecs.add(`capability:${key}`);\n }\n\n // Check op to presentation links\n for (const link of feature.opToPresentationLinks) {\n const opKey = specKey(link.op.key, link.op.version);\n const presKey = specKey(link.pres.key, link.pres.version);\n\n if (!inventory.operations.has(opKey)) {\n issues.push({\n severity: 'error',\n type: 'broken-link',\n message: `Linked operation ${link.op.key}.v${link.op.version} not found`,\n file: feature.filePath,\n featureKey: feature.key,\n specType: 'operation',\n ref: link.op,\n });\n }\n\n if (!inventory.presentations.has(presKey)) {\n issues.push({\n severity: 'error',\n type: 'broken-link',\n message: `Linked presentation ${link.pres.key}.v${link.pres.version} not found`,\n file: feature.filePath,\n featureKey: feature.key,\n specType: 'presentation',\n ref: link.pres,\n });\n }\n }\n }\n\n // Find orphaned specs (not referenced by any feature)\n const orphanedSpecs: SpecLocation[] = [];\n const typesThatCanBeOrphaned: AnalyzedSpecType[] = [\n 'operation',\n 'event',\n 'presentation',\n 'experiment',\n ];\n\n for (const type of typesThatCanBeOrphaned) {\n const map = getInventoryMap(inventory, type);\n if (!map) continue;\n\n for (const [key, location] of map) {\n if (!referencedSpecs.has(`${type}:${key}`)) {\n orphanedSpecs.push(location);\n issues.push({\n severity: 'warning',\n type: 'orphaned',\n message: `${type} ${location.key}.v${location.version} is not linked to any feature`,\n file: location.file,\n specKey: location.key,\n specType: location.type,\n });\n }\n }\n }\n\n // Calculate coverage metrics\n const coverageByType: Record<string, CoverageByType> = {};\n\n for (const type of typesThatCanBeOrphaned) {\n const map = getInventoryMap(inventory, type);\n if (!map) continue;\n\n const total = map.size;\n let covered = 0;\n\n for (const key of map.keys()) {\n if (referencedSpecs.has(`${type}:${key}`)) {\n covered++;\n }\n }\n\n coverageByType[type] = {\n total,\n covered,\n orphaned: total - covered,\n };\n }\n\n const totalSpecs = Object.values(coverageByType).reduce(\n (sum, c) => sum + c.total,\n 0\n );\n const coveredSpecs = Object.values(coverageByType).reduce(\n (sum, c) => sum + c.covered,\n 0\n );\n\n const coverage = {\n total: totalSpecs,\n linkedToFeature: coveredSpecs,\n orphaned: totalSpecs - coveredSpecs,\n byType: coverageByType,\n };\n\n // Determine overall health\n const hasErrors = issues.some((i) => i.severity === 'error');\n const healthy = !hasErrors;\n\n logger.info('Integrity analysis complete', {\n features: features.length,\n totalSpecs,\n orphaned: orphanedSpecs.length,\n issues: issues.length,\n healthy,\n });\n\n return {\n inventory,\n features: relevantFeatures,\n coverage,\n issues,\n orphanedSpecs,\n healthy,\n };\n}\n\n/**\n * Get all specs from inventory as a flat list.\n */\nexport function getAllSpecs(inventory: SpecInventory): SpecLocation[] {\n const all: SpecLocation[] = [];\n\n for (const map of Object.values(inventory)) {\n for (const spec of map.values()) {\n all.push(spec);\n }\n }\n\n return all;\n}\n\n/**\n * Filter issues by type.\n */\nexport function filterIssuesByType(\n issues: IntegrityIssue[],\n type: IntegrityIssue['type']\n): IntegrityIssue[] {\n return issues.filter((i) => i.type === type);\n}\n\n/**\n * Filter issues by severity.\n */\nexport function filterIssuesBySeverity(\n issues: IntegrityIssue[],\n severity: IntegrityIssue['severity']\n): IntegrityIssue[] {\n return issues.filter((i) => i.severity === severity);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { FsAdapter } from "../ports/fs.js";
|
|
2
|
+
import { SpecScanResult } from "@contractspec/module.workspace";
|
|
3
|
+
|
|
4
|
+
//#region src/services/list.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Options for listing specs.
|
|
8
|
+
*/
|
|
9
|
+
interface ListSpecsOptions {
|
|
10
|
+
/**
|
|
11
|
+
* File pattern to search.
|
|
12
|
+
*/
|
|
13
|
+
pattern?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Filter by spec type.
|
|
16
|
+
*/
|
|
17
|
+
type?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* List all spec files in the workspace.
|
|
21
|
+
*/
|
|
22
|
+
declare function listSpecs(adapters: {
|
|
23
|
+
fs: FsAdapter;
|
|
24
|
+
}, options?: ListSpecsOptions): Promise<SpecScanResult[]>;
|
|
25
|
+
/**
|
|
26
|
+
* Group specs by type.
|
|
27
|
+
*/
|
|
28
|
+
declare function groupSpecsByType(specs: SpecScanResult[]): Map<string, SpecScanResult[]>;
|
|
29
|
+
//#endregion
|
|
30
|
+
export { ListSpecsOptions, groupSpecsByType, listSpecs };
|
|
31
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","names":[],"sources":["../../src/services/list.ts"],"sourcesContent":[],"mappings":";;;;;AA4BA;;;AAGW,UAlBM,gBAAA,CAkBN;EAAR;;AAuBH;EACS,OAAA,CAAA,EAAA,MAAA;EACM;;;;;;;;iBA5BO,SAAA;MACJ;aACP,mBACR,QAAQ;;;;iBAuBK,gBAAA,QACP,mBACN,YAAY"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { scanSpecSource } from "@contractspec/module.workspace";
|
|
2
|
+
|
|
3
|
+
//#region src/services/list.ts
|
|
4
|
+
/**
|
|
5
|
+
* List specs service.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* List all spec files in the workspace.
|
|
9
|
+
*/
|
|
10
|
+
async function listSpecs(adapters, options = {}) {
|
|
11
|
+
const { fs } = adapters;
|
|
12
|
+
const files = await fs.glob({ pattern: options.pattern });
|
|
13
|
+
const results = [];
|
|
14
|
+
for (const file of files) {
|
|
15
|
+
const result = scanSpecSource(await fs.readFile(file), file);
|
|
16
|
+
if (options.type && result.specType !== options.type) continue;
|
|
17
|
+
results.push(result);
|
|
18
|
+
}
|
|
19
|
+
return results;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Group specs by type.
|
|
23
|
+
*/
|
|
24
|
+
function groupSpecsByType(specs) {
|
|
25
|
+
const groups = /* @__PURE__ */ new Map();
|
|
26
|
+
for (const spec of specs) {
|
|
27
|
+
const group = groups.get(spec.specType) ?? [];
|
|
28
|
+
group.push(spec);
|
|
29
|
+
groups.set(spec.specType, group);
|
|
30
|
+
}
|
|
31
|
+
return groups;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
35
|
+
export { groupSpecsByType, listSpecs };
|
|
36
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","names":["results: SpecScanResult[]"],"sources":["../../src/services/list.ts"],"sourcesContent":["/**\n * List specs service.\n */\n\nimport {\n scanSpecSource,\n type SpecScanResult,\n} from '@contractspec/module.workspace';\nimport type { FsAdapter } from '../ports/fs';\n\n/**\n * Options for listing specs.\n */\nexport interface ListSpecsOptions {\n /**\n * File pattern to search.\n */\n pattern?: string;\n\n /**\n * Filter by spec type.\n */\n type?: string;\n}\n\n/**\n * List all spec files in the workspace.\n */\nexport async function listSpecs(\n adapters: { fs: FsAdapter },\n options: ListSpecsOptions = {}\n): Promise<SpecScanResult[]> {\n const { fs } = adapters;\n\n const files = await fs.glob({ pattern: options.pattern });\n const results: SpecScanResult[] = [];\n\n for (const file of files) {\n const content = await fs.readFile(file);\n const result = scanSpecSource(content, file);\n\n if (options.type && result.specType !== options.type) {\n continue;\n }\n\n results.push(result);\n }\n\n return results;\n}\n\n/**\n * Group specs by type.\n */\nexport function groupSpecsByType(\n specs: SpecScanResult[]\n): Map<string, SpecScanResult[]> {\n const groups = new Map<string, SpecScanResult[]>();\n\n for (const spec of specs) {\n const group = groups.get(spec.specType) ?? [];\n group.push(spec);\n groups.set(spec.specType, group);\n }\n\n return groups;\n}\n"],"mappings":";;;;;;;;;AA4BA,eAAsB,UACpB,UACA,UAA4B,EAAE,EACH;CAC3B,MAAM,EAAE,OAAO;CAEf,MAAM,QAAQ,MAAM,GAAG,KAAK,EAAE,SAAS,QAAQ,SAAS,CAAC;CACzD,MAAMA,UAA4B,EAAE;AAEpC,MAAK,MAAM,QAAQ,OAAO;EAExB,MAAM,SAAS,eADC,MAAM,GAAG,SAAS,KAAK,EACA,KAAK;AAE5C,MAAI,QAAQ,QAAQ,OAAO,aAAa,QAAQ,KAC9C;AAGF,UAAQ,KAAK,OAAO;;AAGtB,QAAO;;;;;AAMT,SAAgB,iBACd,OAC+B;CAC/B,MAAM,yBAAS,IAAI,KAA+B;AAElD,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,QAAQ,OAAO,IAAI,KAAK,SAAS,IAAI,EAAE;AAC7C,QAAM,KAAK,KAAK;AAChB,SAAO,IAAI,KAAK,UAAU,MAAM;;AAGlC,QAAO"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { FsAdapter } from "../../ports/fs.js";
|
|
2
|
+
import { LoggerAdapter } from "../../ports/logger.js";
|
|
3
|
+
import { OpenApiDocument, OpenApiServer } from "@contractspec/lib.contracts";
|
|
4
|
+
|
|
5
|
+
//#region src/services/openapi/export-service.d.ts
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Options for OpenAPI export.
|
|
9
|
+
*/
|
|
10
|
+
interface OpenApiExportOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Path to module exporting OperationSpecRegistry.
|
|
13
|
+
*/
|
|
14
|
+
registryPath: string;
|
|
15
|
+
/**
|
|
16
|
+
* Output file path.
|
|
17
|
+
*/
|
|
18
|
+
outputPath?: string;
|
|
19
|
+
/**
|
|
20
|
+
* OpenAPI title.
|
|
21
|
+
*/
|
|
22
|
+
title?: string;
|
|
23
|
+
/**
|
|
24
|
+
* OpenAPI version.
|
|
25
|
+
*/
|
|
26
|
+
version?: string;
|
|
27
|
+
/**
|
|
28
|
+
* OpenAPI description.
|
|
29
|
+
*/
|
|
30
|
+
description?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Server URLs to include.
|
|
33
|
+
*/
|
|
34
|
+
servers?: OpenApiServer[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Result of OpenAPI export.
|
|
38
|
+
*/
|
|
39
|
+
interface OpenApiExportResult {
|
|
40
|
+
document: OpenApiDocument;
|
|
41
|
+
outputPath: string;
|
|
42
|
+
json: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Export OpenAPI document from a OperationSpecRegistry.
|
|
46
|
+
*/
|
|
47
|
+
declare function exportOpenApi(options: OpenApiExportOptions, adapters: {
|
|
48
|
+
fs: FsAdapter;
|
|
49
|
+
logger: LoggerAdapter;
|
|
50
|
+
}): Promise<OpenApiExportResult>;
|
|
51
|
+
//#endregion
|
|
52
|
+
export { OpenApiExportOptions, OpenApiExportResult, exportOpenApi };
|
|
53
|
+
//# sourceMappingURL=export-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export-service.d.ts","names":[],"sources":["../../../src/services/openapi/export-service.ts"],"sourcesContent":[],"mappings":";;;;;;AAmDA;AAkBA;;AAEkB,UAvDD,oBAAA,CAuDC;EAAmB;;;EAC3B,YAAA,EAAA,MAAA;;;;;;;;;;;;;;;;;;;;YA3BE;;;;;UAMK,mBAAA;YACL;;;;;;;iBAiBU,aAAA,UACX;MACO;UAAmB;IAClC,QAAQ"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { OperationSpecRegistry, openApiForRegistry } from "@contractspec/lib.contracts";
|
|
2
|
+
|
|
3
|
+
//#region src/services/openapi/export-service.ts
|
|
4
|
+
/**
|
|
5
|
+
* OpenAPI export service - generates OpenAPI documents from OperationSpecRegistry.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Export OpenAPI document from a OperationSpecRegistry.
|
|
9
|
+
*/
|
|
10
|
+
async function exportOpenApi(options, adapters) {
|
|
11
|
+
const { fs, logger } = adapters;
|
|
12
|
+
const { registryPath, outputPath = "./openapi.json" } = options;
|
|
13
|
+
logger.info("Loading registry...", { registryPath });
|
|
14
|
+
const registry = await loadRegistry(registryPath, fs);
|
|
15
|
+
logger.info("Generating OpenAPI document...");
|
|
16
|
+
const document = openApiForRegistry(registry, {
|
|
17
|
+
title: options.title,
|
|
18
|
+
version: options.version,
|
|
19
|
+
description: options.description,
|
|
20
|
+
servers: options.servers
|
|
21
|
+
});
|
|
22
|
+
const json = JSON.stringify(document, null, 2) + "\n";
|
|
23
|
+
const resolvedPath = fs.resolve(outputPath);
|
|
24
|
+
await fs.mkdir(fs.dirname(resolvedPath));
|
|
25
|
+
await fs.writeFile(resolvedPath, json);
|
|
26
|
+
logger.info(`OpenAPI document written to ${resolvedPath}`);
|
|
27
|
+
return {
|
|
28
|
+
document,
|
|
29
|
+
outputPath: resolvedPath,
|
|
30
|
+
json
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Load a OperationSpecRegistry from a module.
|
|
35
|
+
*/
|
|
36
|
+
async function loadRegistry(modulePath, fs) {
|
|
37
|
+
const exports = await import(fs.resolve(modulePath));
|
|
38
|
+
if (exports instanceof OperationSpecRegistry) return exports;
|
|
39
|
+
if (exports.registry instanceof OperationSpecRegistry) return exports.registry;
|
|
40
|
+
const factory = typeof exports.createRegistry === "function" ? exports.createRegistry : typeof exports.default === "function" ? exports.default : void 0;
|
|
41
|
+
if (factory) {
|
|
42
|
+
const result = await factory();
|
|
43
|
+
if (result instanceof OperationSpecRegistry) return result;
|
|
44
|
+
}
|
|
45
|
+
throw new Error(`Registry module ${modulePath} must export a OperationSpecRegistry instance or a factory function returning one.`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
//#endregion
|
|
49
|
+
export { exportOpenApi };
|
|
50
|
+
//# sourceMappingURL=export-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export-service.js","names":[],"sources":["../../../src/services/openapi/export-service.ts"],"sourcesContent":["/**\n * OpenAPI export service - generates OpenAPI documents from OperationSpecRegistry.\n */\n\nimport {\n type OpenApiDocument,\n openApiForRegistry,\n type OpenApiServer,\n OperationSpecRegistry,\n} from '@contractspec/lib.contracts';\nimport type { FsAdapter } from '../../ports/fs';\nimport type { LoggerAdapter } from '../../ports/logger';\n\n/**\n * Options for OpenAPI export.\n */\nexport interface OpenApiExportOptions {\n /**\n * Path to module exporting OperationSpecRegistry.\n */\n registryPath: string;\n\n /**\n * Output file path.\n */\n outputPath?: string;\n\n /**\n * OpenAPI title.\n */\n title?: string;\n\n /**\n * OpenAPI version.\n */\n version?: string;\n\n /**\n * OpenAPI description.\n */\n description?: string;\n\n /**\n * Server URLs to include.\n */\n servers?: OpenApiServer[];\n}\n\n/**\n * Result of OpenAPI export.\n */\nexport interface OpenApiExportResult {\n document: OpenApiDocument;\n outputPath: string;\n json: string;\n}\n\n/**\n * Module that exports a OperationSpecRegistry.\n */\ninterface LoadedRegistryModule {\n default?: unknown;\n createRegistry?: () => Promise<OperationSpecRegistry> | OperationSpecRegistry;\n registry?: OperationSpecRegistry;\n}\n\n/**\n * Export OpenAPI document from a OperationSpecRegistry.\n */\nexport async function exportOpenApi(\n options: OpenApiExportOptions,\n adapters: { fs: FsAdapter; logger: LoggerAdapter }\n): Promise<OpenApiExportResult> {\n const { fs, logger } = adapters;\n const { registryPath, outputPath = './openapi.json' } = options;\n\n logger.info('Loading registry...', { registryPath });\n\n // Load the registry\n const registry = await loadRegistry(registryPath, fs);\n\n logger.info('Generating OpenAPI document...');\n\n // Generate OpenAPI document\n const document = openApiForRegistry(registry, {\n title: options.title,\n version: options.version,\n description: options.description,\n servers: options.servers,\n });\n\n // Serialize to JSON\n const json = JSON.stringify(document, null, 2) + '\\n';\n\n // Resolve output path\n const resolvedPath = fs.resolve(outputPath);\n\n // Ensure directory exists\n await fs.mkdir(fs.dirname(resolvedPath));\n\n // Write file\n await fs.writeFile(resolvedPath, json);\n\n logger.info(`OpenAPI document written to ${resolvedPath}`);\n\n return {\n document,\n outputPath: resolvedPath,\n json,\n };\n}\n\n/**\n * Load a OperationSpecRegistry from a module.\n */\nasync function loadRegistry(\n modulePath: string,\n fs: FsAdapter\n): Promise<OperationSpecRegistry> {\n // Resolve absolute path\n const absPath = fs.resolve(modulePath);\n\n // Dynamic import\n const exports = (await import(absPath)) as LoadedRegistryModule;\n\n // Check if exports is already a registry\n if (exports instanceof OperationSpecRegistry) {\n return exports;\n }\n\n // Check if registry property exists\n if (exports.registry instanceof OperationSpecRegistry) {\n return exports.registry;\n }\n\n // Check for factory function\n const factory =\n typeof exports.createRegistry === 'function'\n ? exports.createRegistry\n : typeof exports.default === 'function'\n ? (exports.default as () =>\n | Promise<OperationSpecRegistry>\n | OperationSpecRegistry)\n : undefined;\n\n if (factory) {\n const result = await factory();\n if (result instanceof OperationSpecRegistry) {\n return result;\n }\n }\n\n throw new Error(\n `Registry module ${modulePath} must export a OperationSpecRegistry instance or a factory function returning one.`\n );\n}\n"],"mappings":";;;;;;;;;AAqEA,eAAsB,cACpB,SACA,UAC8B;CAC9B,MAAM,EAAE,IAAI,WAAW;CACvB,MAAM,EAAE,cAAc,aAAa,qBAAqB;AAExD,QAAO,KAAK,uBAAuB,EAAE,cAAc,CAAC;CAGpD,MAAM,WAAW,MAAM,aAAa,cAAc,GAAG;AAErD,QAAO,KAAK,iCAAiC;CAG7C,MAAM,WAAW,mBAAmB,UAAU;EAC5C,OAAO,QAAQ;EACf,SAAS,QAAQ;EACjB,aAAa,QAAQ;EACrB,SAAS,QAAQ;EAClB,CAAC;CAGF,MAAM,OAAO,KAAK,UAAU,UAAU,MAAM,EAAE,GAAG;CAGjD,MAAM,eAAe,GAAG,QAAQ,WAAW;AAG3C,OAAM,GAAG,MAAM,GAAG,QAAQ,aAAa,CAAC;AAGxC,OAAM,GAAG,UAAU,cAAc,KAAK;AAEtC,QAAO,KAAK,+BAA+B,eAAe;AAE1D,QAAO;EACL;EACA,YAAY;EACZ;EACD;;;;;AAMH,eAAe,aACb,YACA,IACgC;CAKhC,MAAM,UAAW,MAAM,OAHP,GAAG,QAAQ,WAAW;AAMtC,KAAI,mBAAmB,sBACrB,QAAO;AAIT,KAAI,QAAQ,oBAAoB,sBAC9B,QAAO,QAAQ;CAIjB,MAAM,UACJ,OAAO,QAAQ,mBAAmB,aAC9B,QAAQ,iBACR,OAAO,QAAQ,YAAY,aACxB,QAAQ,UAGT;AAER,KAAI,SAAS;EACX,MAAM,SAAS,MAAM,SAAS;AAC9B,MAAI,kBAAkB,sBACpB,QAAO;;AAIX,OAAM,IAAI,MACR,mBAAmB,WAAW,oFAC/B"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { FsAdapter } from "../../ports/fs.js";
|
|
2
|
+
import { LoggerAdapter } from "../../ports/logger.js";
|
|
3
|
+
import { OpenApiImportServiceOptions, OpenApiImportServiceResult } from "./types.js";
|
|
4
|
+
import { ContractsrcConfig } from "@contractspec/lib.contracts";
|
|
5
|
+
|
|
6
|
+
//#region src/services/openapi/import-service.d.ts
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Import ContractSpec specs from an OpenAPI document.
|
|
10
|
+
*/
|
|
11
|
+
declare function importFromOpenApiService(contractspecOptions: ContractsrcConfig, options: OpenApiImportServiceOptions, adapters: {
|
|
12
|
+
fs: FsAdapter;
|
|
13
|
+
logger: LoggerAdapter;
|
|
14
|
+
}): Promise<OpenApiImportServiceResult>;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { importFromOpenApiService };
|
|
17
|
+
//# sourceMappingURL=import-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-service.d.ts","names":[],"sources":["../../../src/services/openapi/import-service.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAuBqC,iBAHf,wBAAA,CAGe,mBAAA,EAFd,iBAEc,EAAA,OAAA,EAD1B,2BAC0B,EAAA,QAAA,EAAA;EAC1B,EAAA,EADO,SACP;EAAR,MAAA,EADkC,aAClC;CAAO,CAAA,EAAP,OAAO,CAAC,0BAAD,CAAA"}
|