@contractspec/bundle.workspace 1.56.0 → 1.57.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/{rolldown_runtime.mjs → _rolldown/runtime.mjs} +3 -3
- package/dist/adapters/ai.d.mts +0 -1
- package/dist/adapters/ai.d.mts.map +1 -1
- package/dist/adapters/factory.d.mts +0 -1
- package/dist/adapters/factory.d.mts.map +1 -1
- package/dist/adapters/fs.bun.d.mts +0 -1
- package/dist/adapters/fs.bun.d.mts.map +1 -1
- package/dist/adapters/fs.bun.mjs +18 -18
- package/dist/adapters/fs.bun.mjs.map +1 -1
- package/dist/adapters/fs.d.mts.map +1 -1
- package/dist/adapters/fs.node.d.mts +0 -1
- package/dist/adapters/fs.node.d.mts.map +1 -1
- package/dist/adapters/fs.node.mjs +18 -18
- package/dist/adapters/fs.node.mjs.map +1 -1
- package/dist/adapters/git.d.mts +0 -1
- package/dist/adapters/git.d.mts.map +1 -1
- package/dist/adapters/git.mjs +2 -2
- package/dist/adapters/git.mjs.map +1 -1
- package/dist/adapters/logger.d.mts +0 -1
- package/dist/adapters/logger.d.mts.map +1 -1
- package/dist/adapters/watcher.d.mts +0 -1
- package/dist/adapters/watcher.d.mts.map +1 -1
- package/dist/adapters/workspace.d.mts.map +1 -1
- package/dist/adapters/workspace.mjs +4 -4
- package/dist/adapters/workspace.mjs.map +1 -1
- package/dist/ai/agents/claude-code-agent.d.mts +0 -1
- package/dist/ai/agents/claude-code-agent.d.mts.map +1 -1
- package/dist/ai/agents/cursor-agent.d.mts +0 -1
- package/dist/ai/agents/cursor-agent.d.mts.map +1 -1
- package/dist/ai/agents/cursor-agent.mjs +5 -5
- package/dist/ai/agents/cursor-agent.mjs.map +1 -1
- package/dist/ai/agents/openai-codex-agent.d.mts +0 -1
- package/dist/ai/agents/openai-codex-agent.d.mts.map +1 -1
- package/dist/ai/agents/orchestrator.d.mts +0 -1
- package/dist/ai/agents/orchestrator.d.mts.map +1 -1
- package/dist/ai/agents/simple-agent.d.mts +0 -1
- package/dist/ai/agents/simple-agent.d.mts.map +1 -1
- package/dist/ai/agents/types.d.mts +0 -1
- package/dist/ai/agents/types.d.mts.map +1 -1
- package/dist/ai/prompts/code-generation.d.mts.map +1 -1
- package/dist/ai/prompts/code-generation.mjs +1 -1
- package/dist/ai/prompts/index.d.mts.map +1 -1
- package/dist/ai/prompts/index.mjs +1 -1
- package/dist/ai/prompts/spec-creation.d.mts.map +1 -1
- package/dist/ai/prompts/spec-creation.mjs +1 -1
- package/dist/ai/providers.d.mts +0 -1
- package/dist/ai/providers.d.mts.map +1 -1
- package/dist/formatters/index.d.mts.map +1 -1
- package/dist/formatters/index.mjs +1 -1
- package/dist/formatters/json.d.mts +0 -1
- package/dist/formatters/json.d.mts.map +1 -1
- package/dist/formatters/sarif.d.mts +0 -1
- package/dist/formatters/sarif.d.mts.map +1 -1
- package/dist/formatters/text.d.mts +0 -1
- package/dist/formatters/text.d.mts.map +1 -1
- package/dist/ports/ai.d.mts +0 -1
- package/dist/ports/ai.d.mts.map +1 -1
- package/dist/ports/fs.d.mts.map +1 -1
- package/dist/ports/git.d.mts.map +1 -1
- package/dist/ports/logger.d.mts.map +1 -1
- package/dist/ports/rulesync.d.mts +0 -1
- package/dist/ports/rulesync.d.mts.map +1 -1
- package/dist/ports/watcher.d.mts.map +1 -1
- package/dist/registry.d.mts +0 -1
- package/dist/registry.d.mts.map +1 -1
- package/dist/services/action-drift/service.d.mts.map +1 -1
- package/dist/services/action-drift/types.d.mts.map +1 -1
- package/dist/services/action-pr/service.d.mts.map +1 -1
- package/dist/services/action-pr/service.mjs +1 -1
- package/dist/services/action-pr/service.mjs.map +1 -1
- package/dist/services/action-pr/types.d.mts.map +1 -1
- package/dist/services/agent-guide/adapters/claude-code.d.mts +0 -1
- package/dist/services/agent-guide/adapters/claude-code.d.mts.map +1 -1
- package/dist/services/agent-guide/adapters/cursor-cli.d.mts +0 -1
- package/dist/services/agent-guide/adapters/cursor-cli.d.mts.map +1 -1
- package/dist/services/agent-guide/adapters/generic-mcp.d.mts +0 -1
- package/dist/services/agent-guide/adapters/generic-mcp.d.mts.map +1 -1
- package/dist/services/agent-guide/adapters/index.d.mts +0 -1
- package/dist/services/agent-guide/adapters/index.d.mts.map +1 -1
- package/dist/services/agent-guide/agent-guide-service.d.mts +0 -1
- package/dist/services/agent-guide/agent-guide-service.d.mts.map +1 -1
- package/dist/services/agent-guide/types.d.mts +0 -1
- package/dist/services/agent-guide/types.d.mts.map +1 -1
- package/dist/services/build.d.mts +0 -1
- package/dist/services/build.d.mts.map +1 -1
- package/dist/services/ci-check/ci-check-service.d.mts +0 -1
- package/dist/services/ci-check/ci-check-service.d.mts.map +1 -1
- package/dist/services/ci-check/types.d.mts +3 -8
- package/dist/services/ci-check/types.d.mts.map +1 -1
- package/dist/services/clean.d.mts +0 -1
- package/dist/services/clean.d.mts.map +1 -1
- package/dist/services/config.d.mts +0 -1
- package/dist/services/config.d.mts.map +1 -1
- package/dist/services/create/ai-generator.d.mts +0 -1
- package/dist/services/create/ai-generator.d.mts.map +1 -1
- package/dist/services/create/index.d.mts.map +1 -1
- package/dist/services/create/templates.d.mts.map +1 -1
- package/dist/services/create/templates.mjs +1 -1
- package/dist/services/deps.d.mts +0 -1
- package/dist/services/deps.d.mts.map +1 -1
- package/dist/services/diff.d.mts +0 -1
- package/dist/services/diff.d.mts.map +1 -1
- package/dist/services/docs/docs-service.d.mts.map +1 -1
- package/dist/services/doctor/doctor-service.d.mts +0 -1
- package/dist/services/doctor/doctor-service.d.mts.map +1 -1
- package/dist/services/doctor/types.d.mts.map +1 -1
- package/dist/services/extract.d.mts.map +1 -1
- package/dist/services/features/completion.d.mts +0 -1
- package/dist/services/features/completion.d.mts.map +1 -1
- package/dist/services/features/completion.mjs +1 -1
- package/dist/services/features/completion.mjs.map +1 -1
- package/dist/services/features/feature-editor.d.mts.map +1 -1
- package/dist/services/features/index.d.mts.map +1 -1
- package/dist/services/features/index.mjs +1 -1
- package/dist/services/features/validation.d.mts +0 -1
- package/dist/services/features/validation.d.mts.map +1 -1
- package/dist/services/fix/fix-link-formatter.d.mts +0 -1
- package/dist/services/fix/fix-link-formatter.d.mts.map +1 -1
- package/dist/services/fix/fix-service.d.mts +0 -1
- package/dist/services/fix/fix-service.d.mts.map +1 -1
- package/dist/services/fix/index.d.mts.map +1 -1
- package/dist/services/fix/index.mjs +1 -1
- package/dist/services/fix/schemas.d.mts +0 -1
- package/dist/services/fix/schemas.d.mts.map +1 -1
- package/dist/services/fix/strategies/implement-ai.d.mts +0 -1
- package/dist/services/fix/strategies/implement-ai.d.mts.map +1 -1
- package/dist/services/fix/strategies/implement-skeleton.d.mts +0 -1
- package/dist/services/fix/strategies/implement-skeleton.d.mts.map +1 -1
- package/dist/services/fix/strategies/remove-reference.d.mts +0 -1
- package/dist/services/fix/strategies/remove-reference.d.mts.map +1 -1
- package/dist/services/fix/types.d.mts +0 -1
- package/dist/services/fix/types.d.mts.map +1 -1
- package/dist/services/formatter.d.mts.map +1 -1
- package/dist/services/gap.d.mts.map +1 -1
- package/dist/services/generate-artifacts.d.mts.map +1 -1
- package/dist/services/hooks/hooks-service.d.mts +0 -1
- package/dist/services/hooks/hooks-service.d.mts.map +1 -1
- package/dist/services/hooks/index.d.mts.map +1 -1
- package/dist/services/hooks/index.mjs +1 -1
- package/dist/services/hooks/types.d.mts.map +1 -1
- package/dist/services/impact/formatters.d.mts +0 -1
- package/dist/services/impact/formatters.d.mts.map +1 -1
- package/dist/services/impact/impact-detection-service.d.mts +0 -1
- package/dist/services/impact/impact-detection-service.d.mts.map +1 -1
- package/dist/services/impact/index.d.mts.map +1 -1
- package/dist/services/impact/index.mjs +1 -1
- package/dist/services/impact/types.d.mts +0 -1
- package/dist/services/impact/types.d.mts.map +1 -1
- package/dist/services/implementation/discovery.d.mts +0 -1
- package/dist/services/implementation/discovery.d.mts.map +1 -1
- package/dist/services/implementation/resolver/conventions.d.mts +0 -1
- package/dist/services/implementation/resolver/conventions.d.mts.map +1 -1
- package/dist/services/implementation/resolver/index.d.mts +0 -1
- package/dist/services/implementation/resolver/index.d.mts.map +1 -1
- package/dist/services/implementation/resolver/index.mjs +7 -7
- package/dist/services/implementation/resolver/index.mjs.map +1 -1
- package/dist/services/implementation/resolver/parsers.d.mts +0 -1
- package/dist/services/implementation/resolver/parsers.d.mts.map +1 -1
- package/dist/services/implementation/resolver/parsers.mjs +6 -6
- package/dist/services/implementation/resolver/parsers.mjs.map +1 -1
- package/dist/services/implementation/resolver/status.d.mts +0 -1
- package/dist/services/implementation/resolver/status.d.mts.map +1 -1
- package/dist/services/implementation/types.d.mts +0 -1
- package/dist/services/implementation/types.d.mts.map +1 -1
- package/dist/services/import/import-service.d.mts +0 -1
- package/dist/services/import/import-service.d.mts.map +1 -1
- package/dist/services/import/import-service.mjs +3 -3
- package/dist/services/import/import-service.mjs.map +1 -1
- package/dist/services/import/report-service.d.mts +0 -1
- package/dist/services/import/report-service.d.mts.map +1 -1
- package/dist/services/import/verify-service.d.mts +0 -1
- package/dist/services/import/verify-service.d.mts.map +1 -1
- package/dist/services/integrity-diagram.d.mts +0 -1
- package/dist/services/integrity-diagram.d.mts.map +1 -1
- package/dist/services/integrity.d.mts +0 -1
- package/dist/services/integrity.d.mts.map +1 -1
- package/dist/services/layer-discovery.d.mts +0 -1
- package/dist/services/layer-discovery.d.mts.map +1 -1
- package/dist/services/list.d.mts +0 -1
- package/dist/services/list.d.mts.map +1 -1
- package/dist/services/llm/index.d.mts +0 -1
- package/dist/services/llm/index.d.mts.map +1 -1
- package/dist/services/llm/index.mjs +0 -1
- package/dist/services/llm/index.mjs.map +1 -1
- package/dist/services/llm/verify-static.d.mts +0 -1
- package/dist/services/llm/verify-static.d.mts.map +1 -1
- package/dist/services/openapi/export-service.d.mts +0 -1
- package/dist/services/openapi/export-service.d.mts.map +1 -1
- package/dist/services/openapi/import-service.d.mts +0 -1
- package/dist/services/openapi/import-service.d.mts.map +1 -1
- package/dist/services/openapi/import-service.mjs +1 -1
- package/dist/services/openapi/import-service.mjs.map +1 -1
- package/dist/services/openapi/sync-service.d.mts +0 -1
- package/dist/services/openapi/sync-service.d.mts.map +1 -1
- package/dist/services/openapi/sync-service.mjs +1 -1
- package/dist/services/openapi/sync-service.mjs.map +1 -1
- package/dist/services/openapi/types.d.mts +0 -1
- package/dist/services/openapi/types.d.mts.map +1 -1
- package/dist/services/openapi/validate-service.d.mts +0 -1
- package/dist/services/openapi/validate-service.d.mts.map +1 -1
- package/dist/services/openapi/validate-service.mjs +3 -3
- package/dist/services/openapi/validate-service.mjs.map +1 -1
- package/dist/services/quickstart/dependencies.d.mts +0 -1
- package/dist/services/quickstart/dependencies.d.mts.map +1 -1
- package/dist/services/quickstart/quickstart-service.d.mts +0 -1
- package/dist/services/quickstart/quickstart-service.d.mts.map +1 -1
- package/dist/services/quickstart/types.d.mts.map +1 -1
- package/dist/services/regenerator.d.mts +0 -1
- package/dist/services/regenerator.d.mts.map +1 -1
- package/dist/services/registry.d.mts +0 -1
- package/dist/services/registry.d.mts.map +1 -1
- package/dist/services/rulesync.d.mts +0 -1
- package/dist/services/rulesync.d.mts.map +1 -1
- package/dist/services/setup/config-generators.d.mts +0 -1
- package/dist/services/setup/config-generators.d.mts.map +1 -1
- package/dist/services/setup/file-merger.d.mts.map +1 -1
- package/dist/services/setup/setup-service.d.mts +0 -1
- package/dist/services/setup/setup-service.d.mts.map +1 -1
- package/dist/services/setup/types.d.mts.map +1 -1
- package/dist/services/sync.d.mts +0 -1
- package/dist/services/sync.d.mts.map +1 -1
- package/dist/services/test/test-generator-service.d.mts +1 -2
- package/dist/services/test/test-generator-service.d.mts.map +1 -1
- package/dist/services/test/test-service.d.mts.map +1 -1
- package/dist/services/test-link/index.d.mts +0 -1
- package/dist/services/test-link/index.d.mts.map +1 -1
- package/dist/services/upgrade/index.d.mts.map +1 -1
- package/dist/services/upgrade/index.mjs +1 -1
- package/dist/services/upgrade/types.d.mts.map +1 -1
- package/dist/services/upgrade/upgrade-service.d.mts +0 -1
- package/dist/services/upgrade/upgrade-service.d.mts.map +1 -1
- package/dist/services/validate/blueprint-validator.d.mts +0 -1
- package/dist/services/validate/blueprint-validator.d.mts.map +1 -1
- package/dist/services/validate/implementation-agent-validator.d.mts.map +1 -1
- package/dist/services/validate/implementation-agent-validator.mjs +2 -2
- package/dist/services/validate/implementation-agent-validator.mjs.map +1 -1
- package/dist/services/validate/implementation-validator.d.mts +0 -1
- package/dist/services/validate/implementation-validator.d.mts.map +1 -1
- package/dist/services/validate/implementation-validator.mjs +1 -1
- package/dist/services/validate/implementation-validator.mjs.map +1 -1
- package/dist/services/validate/spec-validator.d.mts +0 -1
- package/dist/services/validate/spec-validator.d.mts.map +1 -1
- package/dist/services/validate/tenant-validator.d.mts.map +1 -1
- package/dist/services/validate/tenant-validator.mjs +5 -5
- package/dist/services/validate/tenant-validator.mjs.map +1 -1
- package/dist/services/verification-cache/adapters/filesystem.d.mts +0 -1
- package/dist/services/verification-cache/adapters/filesystem.d.mts.map +1 -1
- package/dist/services/verification-cache/adapters/in-memory.d.mts +0 -1
- package/dist/services/verification-cache/adapters/in-memory.d.mts.map +1 -1
- package/dist/services/verification-cache/adapters/workspace-state.d.mts +0 -1
- package/dist/services/verification-cache/adapters/workspace-state.d.mts.map +1 -1
- package/dist/services/verification-cache/cache-service.d.mts +0 -1
- package/dist/services/verification-cache/cache-service.d.mts.map +1 -1
- package/dist/services/verification-cache/types.d.mts +0 -1
- package/dist/services/verification-cache/types.d.mts.map +1 -1
- package/dist/services/verify/ai-verifier.d.mts +0 -1
- package/dist/services/verify/ai-verifier.d.mts.map +1 -1
- package/dist/services/verify/behavior-verifier.d.mts +0 -1
- package/dist/services/verify/behavior-verifier.d.mts.map +1 -1
- package/dist/services/verify/structure-verifier.d.mts +0 -1
- package/dist/services/verify/structure-verifier.d.mts.map +1 -1
- package/dist/services/verify/types.d.mts +0 -1
- package/dist/services/verify/types.d.mts.map +1 -1
- package/dist/services/verify/verify-service.d.mts +0 -1
- package/dist/services/verify/verify-service.d.mts.map +1 -1
- package/dist/services/versioning/changelog-formatter.d.mts +0 -1
- package/dist/services/versioning/changelog-formatter.d.mts.map +1 -1
- package/dist/services/versioning/conventional-commits.d.mts +0 -1
- package/dist/services/versioning/conventional-commits.d.mts.map +1 -1
- package/dist/services/versioning/index.d.mts.map +1 -1
- package/dist/services/versioning/index.mjs +1 -1
- package/dist/services/versioning/types.d.mts +0 -1
- package/dist/services/versioning/types.d.mts.map +1 -1
- package/dist/services/versioning/versioning-service.d.mts +0 -1
- package/dist/services/versioning/versioning-service.d.mts.map +1 -1
- package/dist/services/versioning/versioning-service.mjs +1 -1
- package/dist/services/versioning/versioning-service.mjs.map +1 -1
- package/dist/services/vibe/config.d.mts +0 -1
- package/dist/services/vibe/config.d.mts.map +1 -1
- package/dist/services/vibe/context.d.mts.map +1 -1
- package/dist/services/vibe/definitions.d.mts +0 -1
- package/dist/services/vibe/definitions.d.mts.map +1 -1
- package/dist/services/vibe/engine.d.mts +0 -1
- package/dist/services/vibe/engine.d.mts.map +1 -1
- package/dist/services/vibe/index.d.mts.map +1 -1
- package/dist/services/vibe/index.mjs +1 -1
- package/dist/services/vibe/loader.d.mts +0 -1
- package/dist/services/vibe/loader.d.mts.map +1 -1
- package/dist/services/vibe/pack.d.mts.map +1 -1
- package/dist/services/vibe/types.d.mts.map +1 -1
- package/dist/services/view/index.d.mts.map +1 -1
- package/dist/services/watch.d.mts +0 -1
- package/dist/services/watch.d.mts.map +1 -1
- package/dist/services/workspace-info.d.mts +0 -1
- package/dist/services/workspace-info.d.mts.map +1 -1
- package/dist/templates/app-config.template.d.mts.map +1 -1
- package/dist/templates/data-view.template.d.mts.map +1 -1
- package/dist/templates/event.template.d.mts +0 -1
- package/dist/templates/event.template.d.mts.map +1 -1
- package/dist/templates/experiment.template.d.mts.map +1 -1
- package/dist/templates/feature.template.d.mts.map +1 -1
- package/dist/templates/handler.template.d.mts.map +1 -1
- package/dist/templates/index.d.mts.map +1 -1
- package/dist/templates/index.mjs +1 -1
- package/dist/templates/integration.template.d.mts.map +1 -1
- package/dist/templates/integration.template.mjs +0 -3
- package/dist/templates/integration.template.mjs.map +1 -1
- package/dist/templates/knowledge.template.d.mts.map +1 -1
- package/dist/templates/knowledge.template.mjs +0 -1
- package/dist/templates/knowledge.template.mjs.map +1 -1
- package/dist/templates/migration.template.d.mts.map +1 -1
- package/dist/templates/migration.template.mjs +0 -1
- package/dist/templates/migration.template.mjs.map +1 -1
- package/dist/templates/operation.template.d.mts +0 -1
- package/dist/templates/operation.template.d.mts.map +1 -1
- package/dist/templates/presentation.template.d.mts +0 -1
- package/dist/templates/presentation.template.d.mts.map +1 -1
- package/dist/templates/telemetry.template.d.mts.map +1 -1
- package/dist/templates/workflow-runner.template.d.mts.map +1 -1
- package/dist/templates/workflow.template.d.mts.map +1 -1
- package/dist/types.d.mts +1 -1
- package/dist/types.d.mts.map +1 -1
- package/dist/utils/filter.d.mts +0 -1
- package/dist/utils/filter.d.mts.map +1 -1
- package/dist/utils/index.d.mts.map +1 -1
- package/dist/utils/index.mjs +1 -1
- package/dist/utils/module-loader.d.mts.map +1 -1
- package/dist/utils/validation.d.mts +0 -1
- package/dist/utils/validation.d.mts.map +1 -1
- package/package.json +16 -16
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import-service.mjs","names":["path"],"sources":["../../../src/services/openapi/import-service.ts"],"sourcesContent":["/**\n * OpenAPI import service - imports specs from OpenAPI documents.\n */\n\nimport {\n importFromOpenApi,\n parseOpenApi,\n} from '@contractspec/lib.contracts-transformers/openapi';\nimport type { FsAdapter } from '../../ports/fs';\nimport type { LoggerAdapter } from '../../ports/logger';\nimport type {\n OpenApiImportServiceOptions,\n OpenApiImportServiceResult,\n} from './types';\nimport { dirname, join, basename } from 'path';\nimport type { ResolvedContractsrcConfig } from '@contractspec/lib.contracts';\n\n/**\n * Get output directory for spec type\n */\nfunction getOutputDir(\n type: 'operation' | 'event' | 'model',\n options: OpenApiImportServiceOptions,\n config: ResolvedContractsrcConfig\n): string {\n // If outputDir is explicitly set in options, use it for all types\n if (options.outputDir) {\n return options.outputDir;\n }\n\n // Default base\n const baseDir = config.outputDir;\n const conventions = config.conventions;\n\n switch (type) {\n case 'operation':\n // Conventions usually format like \"operations/**\" or \"operations\"\n return join(\n baseDir,\n conventions.operations.split('|')[0] ?? 'operations'\n );\n case 'event':\n return join(baseDir, conventions.events);\n case 'model':\n return join(baseDir, 'models'); // Standardize on 'models' for now\n default:\n return baseDir;\n }\n}\n\n/**\n * Import ContractSpec specs from an OpenAPI document.\n */\nexport async function importFromOpenApiService(\n contractspecOptions: ResolvedContractsrcConfig,\n options: OpenApiImportServiceOptions,\n adapters: { fs: FsAdapter; logger: LoggerAdapter }\n): Promise<OpenApiImportServiceResult> {\n const { fs, logger } = adapters;\n const {\n source,\n\n prefix,\n tags,\n exclude,\n defaultStability,\n defaultOwners,\n defaultAuth,\n dryRun = false,\n } = options;\n\n logger.info(`Importing from OpenAPI: ${source}`);\n\n // Parse the OpenAPI document\n // Use globalThis.fetch because adapters don't have networking yet\n // but we use fs.readFile for local files\n const parseResult = await parseOpenApi(source, {\n fetch: globalThis.fetch,\n readFile: (path) => fs.readFile(path),\n });\n\n if (parseResult.warnings.length > 0) {\n for (const warning of parseResult.warnings) {\n logger.warn(`Parse warning: ${warning}`);\n }\n }\n\n logger.info(\n `Parsed ${parseResult.operations.length} operations from ${parseResult.info.title} v${parseResult.info.version}`\n );\n\n // Import operations\n const importResult = importFromOpenApi(parseResult, contractspecOptions, {\n prefix,\n tags,\n exclude,\n defaultStability,\n defaultOwners,\n defaultAuth,\n });\n\n logger.info(\n `Import result: ${importResult.summary.imported} imported, ${importResult.summary.skipped} skipped, ${importResult.summary.errors} errors`\n );\n\n const files: OpenApiImportServiceResult['files'] = [];\n const skippedOperations: OpenApiImportServiceResult['skippedOperations'] = [];\n const errorMessages: OpenApiImportServiceResult['errorMessages'] = [];\n\n // Write imported specs\n const specsByDir = new Map<\n string,\n { file: string; name: string; type: 'operation' | 'event' | 'model' }[]\n >();\n\n for (const spec of importResult.operationSpecs) {\n // Determine type FIRST to resolve output directory\n let type: 'operation' | 'event' | 'model' = 'operation';\n let match: RegExpMatchArray | null = null;\n if (spec.code.includes('defineEvent(')) {\n type = 'event';\n match = spec.code.match(/export const (\\w+)\\s*=\\s*defineEvent/);\n } else if (\n (spec.code.includes('defineSchemaModel(') ||\n spec.code.includes('new EnumType(') ||\n spec.code.includes('ScalarTypeEnum.') ||\n spec.code.includes('new ZodSchemaType(') ||\n spec.code.includes('z.enum(') ||\n spec.code.includes('new JsonSchemaType(') ||\n spec.code.includes('new GraphQLSchemaType(')) &&\n !spec.code.includes('defineCommand(') &&\n !spec.code.includes('defineQuery(')\n ) {\n type = 'model';\n } else {\n type = 'operation';\n match = spec.code.match(\n /export const (\\w+)\\s*=\\s*define(?:Command|Query)/\n );\n }\n\n // Resolve output directory based on type\n const targetDir = getOutputDir(type, options, contractspecOptions);\n const filePath = join(targetDir, spec.fileName);\n\n if (!match && type === 'model') {\n if (spec.code.includes('new ZodSchemaType(')) {\n match = spec.code.match(/export const (\\w+)\\s*=\\s*new ZodSchemaType\\(/);\n } else if (spec.code.includes('new JsonSchemaType(')) {\n match = spec.code.match(\n /export const (\\w+)\\s*=\\s*new JsonSchemaType\\(/\n );\n } else if (spec.code.includes('new GraphQLSchemaType(')) {\n match = spec.code.match(\n /export const (\\w+)\\s*=\\s*new GraphQLSchemaType\\(/\n );\n }\n if (!match) {\n match = spec.code.match(/export const (\\w+)\\s*=/);\n }\n }\n\n if (dryRun) {\n logger.info(`[DRY RUN] Would create: ${filePath}`);\n } else {\n // Ensure directory exists\n const dir = dirname(filePath);\n const exists = await fs.exists(dir);\n if (!exists) {\n await fs.mkdir(dir);\n }\n\n // Write spec file\n await fs.writeFile(filePath, spec.code);\n logger.info(`Created: ${filePath}`);\n }\n\n files.push({\n path: filePath,\n operationId: spec.source.sourceId,\n specName: spec.fileName.replace('.ts', ''),\n });\n\n if (match) {\n const dir = dirname(filePath);\n const existing = specsByDir.get(dir) || [];\n existing.push({\n file: basename(filePath),\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n name: match[1]!,\n type,\n });\n specsByDir.set(dir, existing);\n }\n }\n\n // Generate registries\n if (!dryRun && files.length > 0) {\n for (const [dir, specs] of specsByDir.entries()) {\n if (specs.length === 0) continue;\n\n // Detect dominant type\n const types = specs.map((s) => s.type);\n const isOperations = types.every((t) => t === 'operation');\n const isEvents = types.every((t) => t === 'event');\n const isModels = types.every((t) => t === 'model');\n\n // Generate Registry File\n let registryCode = `/**\\n * Auto-generated registry file.\\n */\\n`;\n specs.forEach((s) => {\n const importPath = `./${basename(s.file, '.ts')}`;\n registryCode += `import { ${s.name} } from '${importPath}';\\n`;\n });\n registryCode += '\\n';\n\n let hasRegistry = false;\n if (isOperations) {\n registryCode += `import { OperationSpecRegistry } from '@contractspec/lib.contracts';\\n\\n`;\n registryCode += `export const operationRegistry = new OperationSpecRegistry();\\n`;\n specs.forEach((s) => {\n registryCode += `operationRegistry.register(${s.name});\\n`;\n });\n hasRegistry = true;\n } else if (isEvents) {\n registryCode += `import { EventRegistry } from '@contractspec/lib.contracts';\\n\\n`;\n registryCode += `export const eventRegistry = new EventRegistry();\\n`;\n specs.forEach((s) => {\n registryCode += `eventRegistry.register(${s.name});\\n`;\n });\n hasRegistry = true;\n } else if (isModels) {\n registryCode += `import { ModelRegistry } from '@contractspec/lib.contracts';\\n\\n`;\n registryCode += `export const modelRegistry = new ModelRegistry();\\n`;\n specs.forEach((s) => {\n registryCode += `modelRegistry.register(${s.name});\\n`;\n });\n hasRegistry = true;\n }\n\n if (hasRegistry) {\n const registryPath = join(dir, 'registry.ts');\n await fs.writeFile(registryPath, registryCode);\n logger.info(`Created/Updated registry: ${registryPath}`);\n }\n\n // Generate Index File\n let indexCode = `/**\\n * Auto-generated barrel file.\\n */\\n\\n`;\n specs.forEach((s) => {\n const importPath = `./${basename(s.file, '.ts')}`;\n indexCode += `export * from '${importPath}';\\n`;\n });\n\n if (hasRegistry) {\n indexCode += `export * from './registry';\\n`;\n }\n\n const indexPath = join(dir, 'index.ts');\n await fs.writeFile(indexPath, indexCode);\n logger.info(`Created/Updated index: ${indexPath}`);\n }\n }\n\n // Record skipped operations\n for (const skipped of importResult.skipped) {\n skippedOperations.push({\n operationId: skipped.sourceId,\n reason: skipped.reason,\n });\n logger.debug(`Skipped: ${skipped.sourceId} - ${skipped.reason}`);\n }\n\n // Record errors\n for (const error of importResult.errors) {\n errorMessages.push({\n operationId: error.sourceId,\n error: error.error,\n });\n logger.error(`Error: ${error.sourceId} - ${error.error}`);\n }\n\n return {\n imported: importResult.summary.imported,\n skipped: importResult.summary.skipped,\n errors: importResult.summary.errors,\n files,\n skippedOperations,\n errorMessages,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"import-service.mjs","names":[],"sources":["../../../src/services/openapi/import-service.ts"],"sourcesContent":["/**\n * OpenAPI import service - imports specs from OpenAPI documents.\n */\n\nimport {\n importFromOpenApi,\n parseOpenApi,\n} from '@contractspec/lib.contracts-transformers/openapi';\nimport type { FsAdapter } from '../../ports/fs';\nimport type { LoggerAdapter } from '../../ports/logger';\nimport type {\n OpenApiImportServiceOptions,\n OpenApiImportServiceResult,\n} from './types';\nimport { dirname, join, basename } from 'path';\nimport type { ResolvedContractsrcConfig } from '@contractspec/lib.contracts';\n\n/**\n * Get output directory for spec type\n */\nfunction getOutputDir(\n type: 'operation' | 'event' | 'model',\n options: OpenApiImportServiceOptions,\n config: ResolvedContractsrcConfig\n): string {\n // If outputDir is explicitly set in options, use it for all types\n if (options.outputDir) {\n return options.outputDir;\n }\n\n // Default base\n const baseDir = config.outputDir;\n const conventions = config.conventions;\n\n switch (type) {\n case 'operation':\n // Conventions usually format like \"operations/**\" or \"operations\"\n return join(\n baseDir,\n conventions.operations.split('|')[0] ?? 'operations'\n );\n case 'event':\n return join(baseDir, conventions.events);\n case 'model':\n return join(baseDir, 'models'); // Standardize on 'models' for now\n default:\n return baseDir;\n }\n}\n\n/**\n * Import ContractSpec specs from an OpenAPI document.\n */\nexport async function importFromOpenApiService(\n contractspecOptions: ResolvedContractsrcConfig,\n options: OpenApiImportServiceOptions,\n adapters: { fs: FsAdapter; logger: LoggerAdapter }\n): Promise<OpenApiImportServiceResult> {\n const { fs, logger } = adapters;\n const {\n source,\n\n prefix,\n tags,\n exclude,\n defaultStability,\n defaultOwners,\n defaultAuth,\n dryRun = false,\n } = options;\n\n logger.info(`Importing from OpenAPI: ${source}`);\n\n // Parse the OpenAPI document\n // Use globalThis.fetch because adapters don't have networking yet\n // but we use fs.readFile for local files\n const parseResult = await parseOpenApi(source, {\n fetch: globalThis.fetch,\n readFile: (path) => fs.readFile(path),\n });\n\n if (parseResult.warnings.length > 0) {\n for (const warning of parseResult.warnings) {\n logger.warn(`Parse warning: ${warning}`);\n }\n }\n\n logger.info(\n `Parsed ${parseResult.operations.length} operations from ${parseResult.info.title} v${parseResult.info.version}`\n );\n\n // Import operations\n const importResult = importFromOpenApi(parseResult, contractspecOptions, {\n prefix,\n tags,\n exclude,\n defaultStability,\n defaultOwners,\n defaultAuth,\n });\n\n logger.info(\n `Import result: ${importResult.summary.imported} imported, ${importResult.summary.skipped} skipped, ${importResult.summary.errors} errors`\n );\n\n const files: OpenApiImportServiceResult['files'] = [];\n const skippedOperations: OpenApiImportServiceResult['skippedOperations'] = [];\n const errorMessages: OpenApiImportServiceResult['errorMessages'] = [];\n\n // Write imported specs\n const specsByDir = new Map<\n string,\n { file: string; name: string; type: 'operation' | 'event' | 'model' }[]\n >();\n\n for (const spec of importResult.operationSpecs) {\n // Determine type FIRST to resolve output directory\n let type: 'operation' | 'event' | 'model' = 'operation';\n let match: RegExpMatchArray | null = null;\n if (spec.code.includes('defineEvent(')) {\n type = 'event';\n match = spec.code.match(/export const (\\w+)\\s*=\\s*defineEvent/);\n } else if (\n (spec.code.includes('defineSchemaModel(') ||\n spec.code.includes('new EnumType(') ||\n spec.code.includes('ScalarTypeEnum.') ||\n spec.code.includes('new ZodSchemaType(') ||\n spec.code.includes('z.enum(') ||\n spec.code.includes('new JsonSchemaType(') ||\n spec.code.includes('new GraphQLSchemaType(')) &&\n !spec.code.includes('defineCommand(') &&\n !spec.code.includes('defineQuery(')\n ) {\n type = 'model';\n } else {\n type = 'operation';\n match = spec.code.match(\n /export const (\\w+)\\s*=\\s*define(?:Command|Query)/\n );\n }\n\n // Resolve output directory based on type\n const targetDir = getOutputDir(type, options, contractspecOptions);\n const filePath = join(targetDir, spec.fileName);\n\n if (!match && type === 'model') {\n if (spec.code.includes('new ZodSchemaType(')) {\n match = spec.code.match(/export const (\\w+)\\s*=\\s*new ZodSchemaType\\(/);\n } else if (spec.code.includes('new JsonSchemaType(')) {\n match = spec.code.match(\n /export const (\\w+)\\s*=\\s*new JsonSchemaType\\(/\n );\n } else if (spec.code.includes('new GraphQLSchemaType(')) {\n match = spec.code.match(\n /export const (\\w+)\\s*=\\s*new GraphQLSchemaType\\(/\n );\n }\n if (!match) {\n match = spec.code.match(/export const (\\w+)\\s*=/);\n }\n }\n\n if (dryRun) {\n logger.info(`[DRY RUN] Would create: ${filePath}`);\n } else {\n // Ensure directory exists\n const dir = dirname(filePath);\n const exists = await fs.exists(dir);\n if (!exists) {\n await fs.mkdir(dir);\n }\n\n // Write spec file\n await fs.writeFile(filePath, spec.code);\n logger.info(`Created: ${filePath}`);\n }\n\n files.push({\n path: filePath,\n operationId: spec.source.sourceId,\n specName: spec.fileName.replace('.ts', ''),\n });\n\n if (match) {\n const dir = dirname(filePath);\n const existing = specsByDir.get(dir) || [];\n existing.push({\n file: basename(filePath),\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n name: match[1]!,\n type,\n });\n specsByDir.set(dir, existing);\n }\n }\n\n // Generate registries\n if (!dryRun && files.length > 0) {\n for (const [dir, specs] of specsByDir.entries()) {\n if (specs.length === 0) continue;\n\n // Detect dominant type\n const types = specs.map((s) => s.type);\n const isOperations = types.every((t) => t === 'operation');\n const isEvents = types.every((t) => t === 'event');\n const isModels = types.every((t) => t === 'model');\n\n // Generate Registry File\n let registryCode = `/**\\n * Auto-generated registry file.\\n */\\n`;\n specs.forEach((s) => {\n const importPath = `./${basename(s.file, '.ts')}`;\n registryCode += `import { ${s.name} } from '${importPath}';\\n`;\n });\n registryCode += '\\n';\n\n let hasRegistry = false;\n if (isOperations) {\n registryCode += `import { OperationSpecRegistry } from '@contractspec/lib.contracts';\\n\\n`;\n registryCode += `export const operationRegistry = new OperationSpecRegistry();\\n`;\n specs.forEach((s) => {\n registryCode += `operationRegistry.register(${s.name});\\n`;\n });\n hasRegistry = true;\n } else if (isEvents) {\n registryCode += `import { EventRegistry } from '@contractspec/lib.contracts';\\n\\n`;\n registryCode += `export const eventRegistry = new EventRegistry();\\n`;\n specs.forEach((s) => {\n registryCode += `eventRegistry.register(${s.name});\\n`;\n });\n hasRegistry = true;\n } else if (isModels) {\n registryCode += `import { ModelRegistry } from '@contractspec/lib.contracts';\\n\\n`;\n registryCode += `export const modelRegistry = new ModelRegistry();\\n`;\n specs.forEach((s) => {\n registryCode += `modelRegistry.register(${s.name});\\n`;\n });\n hasRegistry = true;\n }\n\n if (hasRegistry) {\n const registryPath = join(dir, 'registry.ts');\n await fs.writeFile(registryPath, registryCode);\n logger.info(`Created/Updated registry: ${registryPath}`);\n }\n\n // Generate Index File\n let indexCode = `/**\\n * Auto-generated barrel file.\\n */\\n\\n`;\n specs.forEach((s) => {\n const importPath = `./${basename(s.file, '.ts')}`;\n indexCode += `export * from '${importPath}';\\n`;\n });\n\n if (hasRegistry) {\n indexCode += `export * from './registry';\\n`;\n }\n\n const indexPath = join(dir, 'index.ts');\n await fs.writeFile(indexPath, indexCode);\n logger.info(`Created/Updated index: ${indexPath}`);\n }\n }\n\n // Record skipped operations\n for (const skipped of importResult.skipped) {\n skippedOperations.push({\n operationId: skipped.sourceId,\n reason: skipped.reason,\n });\n logger.debug(`Skipped: ${skipped.sourceId} - ${skipped.reason}`);\n }\n\n // Record errors\n for (const error of importResult.errors) {\n errorMessages.push({\n operationId: error.sourceId,\n error: error.error,\n });\n logger.error(`Error: ${error.sourceId} - ${error.error}`);\n }\n\n return {\n imported: importResult.summary.imported,\n skipped: importResult.summary.skipped,\n errors: importResult.summary.errors,\n files,\n skippedOperations,\n errorMessages,\n };\n}\n"],"mappings":"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"}
|
|
@@ -4,7 +4,6 @@ import { OpenApiSyncServiceOptions, OpenApiSyncServiceResult } from "./types.mjs
|
|
|
4
4
|
import { ResolvedContractsrcConfig } from "@contractspec/lib.contracts";
|
|
5
5
|
|
|
6
6
|
//#region src/services/openapi/sync-service.d.ts
|
|
7
|
-
|
|
8
7
|
/**
|
|
9
8
|
* Sync ContractSpec specs with OpenAPI sources.
|
|
10
9
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-service.d.mts","names":[],"sources":["../../../src/services/openapi/sync-service.ts"],"
|
|
1
|
+
{"version":3,"file":"sync-service.d.mts","names":[],"sources":["../../../src/services/openapi/sync-service.ts"],"mappings":";;;;;;;;;iBAoBsB,sBAAA,CACpB,OAAA,EAAS,yBAAA,EACT,MAAA,EAAQ,yBAAA,EACR,QAAA;EAAY,EAAA,EAAI,SAAA;EAAW,MAAA,EAAQ,aAAA;AAAA,IAClC,OAAA,CAAQ,wBAAA"}
|
|
@@ -43,7 +43,7 @@ async function syncWithOpenApiService(options, config, adapters) {
|
|
|
43
43
|
}
|
|
44
44
|
const parseResult = await parseOpenApi(sourceLocation, {
|
|
45
45
|
fetch: globalThis.fetch,
|
|
46
|
-
readFile: (path
|
|
46
|
+
readFile: (path) => fs.readFile(path)
|
|
47
47
|
});
|
|
48
48
|
logger.info(`Parsed ${parseResult.operations.length} operations from ${source.name}`);
|
|
49
49
|
const importResult = importFromOpenApi(parseResult, config, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-service.mjs","names":[
|
|
1
|
+
{"version":3,"file":"sync-service.mjs","names":[],"sources":["../../../src/services/openapi/sync-service.ts"],"sourcesContent":["/**\n * OpenAPI sync service - syncs specs with OpenAPI sources.\n */\n\nimport {\n importFromOpenApi,\n parseOpenApi,\n} from '@contractspec/lib.contracts-transformers/openapi';\nimport type { FsAdapter } from '../../ports/fs';\nimport type { LoggerAdapter } from '../../ports/logger';\nimport type {\n OpenApiSyncServiceOptions,\n OpenApiSyncServiceResult,\n} from './types';\nimport { dirname, join } from 'path';\nimport type { ResolvedContractsrcConfig } from '@contractspec/lib.contracts';\n\n/**\n * Sync ContractSpec specs with OpenAPI sources.\n */\nexport async function syncWithOpenApiService(\n options: OpenApiSyncServiceOptions,\n config: ResolvedContractsrcConfig,\n adapters: { fs: FsAdapter; logger: LoggerAdapter }\n): Promise<OpenApiSyncServiceResult> {\n const { fs, logger } = adapters;\n const {\n sources: optSources,\n sourceName,\n interactive,\n force,\n dryRun,\n } = options;\n const { outputDir } = config;\n\n // Determine which sources to sync\n let sourcesToSync = optSources ?? config.openapi?.sources ?? [];\n\n if (sourceName) {\n sourcesToSync = sourcesToSync.filter((s) => s.name === sourceName);\n if (sourcesToSync.length === 0) {\n throw new Error(`Source not found: ${sourceName}`);\n }\n }\n\n if (sourcesToSync.length === 0) {\n logger.warn(\n 'No OpenAPI sources configured. Add sources to .contractsrc.json'\n );\n return {\n added: 0,\n updated: 0,\n unchanged: 0,\n conflicts: 0,\n changes: [],\n };\n }\n\n const result: OpenApiSyncServiceResult = {\n added: 0,\n updated: 0,\n unchanged: 0,\n conflicts: 0,\n changes: [],\n };\n\n for (const source of sourcesToSync) {\n logger.info(`Syncing with source: ${source.name}`);\n\n // Get source URL or file\n const sourceLocation = source.url ?? source.file;\n if (!sourceLocation) {\n logger.warn(`Source ${source.name} has no url or file configured`);\n continue;\n }\n\n // Parse the OpenAPI document\n const parseResult = await parseOpenApi(sourceLocation, {\n fetch: globalThis.fetch,\n readFile: (path) => fs.readFile(path),\n });\n\n logger.info(\n `Parsed ${parseResult.operations.length} operations from ${source.name}`\n );\n\n // Import operations to get the new specs\n const importResult = importFromOpenApi(parseResult, config, {\n prefix: source.prefix,\n tags: source.tags,\n exclude: source.exclude,\n defaultStability: source.defaultStability,\n defaultAuth: source.defaultAuth,\n });\n\n // Process each imported spec\n for (const imported of importResult.operationSpecs) {\n const filePath = join(outputDir, imported.fileName);\n const exists = await fs.exists(filePath);\n\n if (!exists) {\n // New spec - add it\n if (!dryRun) {\n const dir = dirname(filePath);\n await fs.mkdir(dir);\n await fs.writeFile(filePath, imported.code);\n }\n\n result.added++;\n result.changes.push({\n operationId: imported.source.sourceId,\n action: 'added',\n path: filePath,\n });\n logger.info(`Added: ${imported.source.sourceId}`);\n } else {\n // Existing spec - check for differences\n const existingCode = await fs.readFile(filePath);\n\n if (existingCode === imported.code) {\n // No changes\n result.unchanged++;\n result.changes.push({\n operationId: imported.source.sourceId,\n action: 'unchanged',\n path: filePath,\n });\n } else {\n // Differences detected\n if (force === 'openapi') {\n // Overwrite with OpenAPI version\n if (!dryRun) {\n await fs.writeFile(filePath, imported.code);\n }\n result.updated++;\n result.changes.push({\n operationId: imported.source.sourceId,\n action: 'updated',\n path: filePath,\n });\n logger.info(`Updated: ${imported.source.sourceId}`);\n } else if (force === 'contractspec') {\n // Keep ContractSpec version\n result.unchanged++;\n result.changes.push({\n operationId: imported.source.sourceId,\n action: 'unchanged',\n path: filePath,\n });\n logger.info(`Kept: ${imported.source.sourceId}`);\n } else if (interactive) {\n // Would prompt for resolution in CLI\n result.conflicts++;\n result.changes.push({\n operationId: imported.source.sourceId,\n action: 'conflict',\n path: filePath,\n });\n logger.warn(\n `Conflict: ${imported.source.sourceId} - needs resolution`\n );\n } else {\n // Default: report conflict\n result.conflicts++;\n result.changes.push({\n operationId: imported.source.sourceId,\n action: 'conflict',\n path: filePath,\n });\n logger.warn(`Conflict: ${imported.source.sourceId}`);\n }\n }\n }\n }\n }\n\n logger.info(\n `Sync complete: ${result.added} added, ${result.updated} updated, ${result.unchanged} unchanged, ${result.conflicts} conflicts`\n );\n\n return result;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","names":[],"sources":["../../../src/services/openapi/types.ts"],"
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../../../src/services/openapi/types.ts"],"mappings":";;;;;;UASiB,2BAAA;EAIf;EAFA,MAAA;EAMA;EAJA,SAAA;EAQA;EANA,MAAA;EAUA;EARA,IAAA;EAUM;EARN,OAAA;EAce;EAZf,gBAAA;;EAEA,aAAA;EAYA;EAVA,WAAA;EAcA;EAZA,MAAA;AAAA;;;;UAMe,0BAAA;EAgBb;EAdF,QAAA;EAkBE;EAhBF,OAAA;EAiBO;EAfP,MAAA;EAsBe;EApBf,KAAA;IACE,IAAA;IACA,WAAA;IACA,QAAA;EAAA;EAqBF;EAlBA,iBAAA;IACE,WAAA;IACA,MAAA;EAAA;EAsBI;EAnBN,aAAA;IACE,WAAA;IACA,KAAA;EAAA;AAAA;;;;UAOa,yBAAA;EA2Bb;EAzBF,OAAA,GAAU,mBAAA;EA2BR;EAzBF,UAAA;EA0Ba;EAxBb,WAAA;EA+Be;EA7Bf,KAAA;;EAEA,MAAA;AAAA;;;;UAMe,wBAAA;EA+BA;EA7Bf,KAAA;EAmCe;EAjCf,OAAA;;EAEA,SAAA;EAiCA;EA/BA,SAAA;EAmCA;EAjCA,OAAA;IACE,WAAA;IACA,MAAA;IACA,IAAA;IACA,WAAA;EAAA;AAAA;;;;UAOa,6BAAA;EAuC2B;EArC1C,QAAA;EAqC0C;EAnC1C,aAAA;EAuCA;EArCA,kBAAA;EAyCA;EAvCA,UAAA;EA2CA;EAzCA,eAAA;AAAA;;;;UAMe,4BAAA;EA8C0B;EA5CzC,KAAA;EA4CyC;EA1CzC,cAAA;EA8CA;EA5CA,cAAA;EA8Cc;EA5Cd,OAAA;IACE,QAAA;IACA,WAAA;IACA,KAAA;IACA,KAAA;MACE,IAAA;MACA,IAAA;MACA,WAAA;IAAA;EAAA;AAAA;;;;UAQW,2BAAA;;EAEf,YAAA;;EAEA,UAAA;;EAEA,MAAA;;EAEA,KAAA;;EAEA,OAAA;;EAEA,WAAA;;EAEA,OAAA;IACE,GAAA;IACA,WAAA;EAAA;AAAA;;;;UAOa,0BAAA;;EAEf,UAAA;;EAEA,OAAA;;EAEA,cAAA;AAAA"}
|
|
@@ -3,7 +3,6 @@ import { LoggerAdapter } from "../../ports/logger.mjs";
|
|
|
3
3
|
import { OpenApiValidateServiceOptions, OpenApiValidateServiceResult } from "./types.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/services/openapi/validate-service.d.ts
|
|
6
|
-
|
|
7
6
|
/**
|
|
8
7
|
* Validate ContractSpec specs against an OpenAPI source.
|
|
9
8
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-service.d.mts","names":[],"sources":["../../../src/services/openapi/validate-service.ts"],"
|
|
1
|
+
{"version":3,"file":"validate-service.d.mts","names":[],"sources":["../../../src/services/openapi/validate-service.ts"],"mappings":";;;;;;;;iBAkBsB,6BAAA,CACpB,OAAA,EAAS,6BAAA,EACT,QAAA;EAAY,EAAA,EAAI,SAAA;EAAW,MAAA,EAAQ,aAAA;AAAA,IAClC,OAAA,CAAQ,4BAAA"}
|
|
@@ -94,12 +94,12 @@ async function validateAgainstOpenApiService(options, adapters) {
|
|
|
94
94
|
description: `Method mismatch: spec has "${methodMatch[1]}", OpenAPI has "${matchingOp.method.toUpperCase()}"`
|
|
95
95
|
});
|
|
96
96
|
}
|
|
97
|
-
const valid
|
|
98
|
-
if (!valid
|
|
97
|
+
const valid = diffs.length === 0;
|
|
98
|
+
if (!valid) specsWithDiffs++;
|
|
99
99
|
results.push({
|
|
100
100
|
specPath: file,
|
|
101
101
|
operationId: matchingOp.operationId,
|
|
102
|
-
valid
|
|
102
|
+
valid,
|
|
103
103
|
diffs
|
|
104
104
|
});
|
|
105
105
|
} catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-service.mjs","names":[
|
|
1
|
+
{"version":3,"file":"validate-service.mjs","names":[],"sources":["../../../src/services/openapi/validate-service.ts"],"sourcesContent":["/**\n * OpenAPI validation service - validates specs against OpenAPI sources.\n */\n\nimport {\n parseOpenApi,\n type ParsedOperation,\n} from '@contractspec/lib.contracts-transformers/openapi';\nimport type { FsAdapter } from '../../ports/fs';\nimport type { LoggerAdapter } from '../../ports/logger';\nimport type {\n OpenApiValidateServiceOptions,\n OpenApiValidateServiceResult,\n} from './types';\n\n/**\n * Validate ContractSpec specs against an OpenAPI source.\n */\nexport async function validateAgainstOpenApiService(\n options: OpenApiValidateServiceOptions,\n adapters: { fs: FsAdapter; logger: LoggerAdapter }\n): Promise<OpenApiValidateServiceResult> {\n const { fs, logger } = adapters;\n const {\n specPath,\n openApiSource,\n ignoreDescriptions: _ignoreDescriptions,\n ignoreTags: _ignoreTags,\n ignoreTransport,\n } = options;\n\n logger.info(`Validating specs against OpenAPI: ${openApiSource}`);\n\n // Parse the OpenAPI document\n const parseResult = await parseOpenApi(openApiSource, {\n fetch: globalThis.fetch,\n readFile: (path) => fs.readFile(path),\n });\n\n logger.info(\n `Parsed ${parseResult.operations.length} operations from ${parseResult.info.title}`\n );\n\n // Build a map of operations by operationId\n const operationsMap = new Map<string, ParsedOperation>();\n for (const op of parseResult.operations) {\n operationsMap.set(op.operationId, op);\n }\n\n const results: OpenApiValidateServiceResult['results'] = [];\n let specsValidated = 0;\n let specsWithDiffs = 0;\n\n // Check if specPath is a directory or file\n const stat = await fs.stat(specPath);\n const specFiles: string[] = [];\n\n if (stat.isDirectory) {\n // Find all spec files in directory\n const files = await fs.glob({\n pattern: '**/*.ts',\n cwd: specPath,\n ignore: ['node_modules/**', 'dist/**', '*.test.ts', '*.spec.ts'],\n absolute: true,\n });\n specFiles.push(...files);\n } else {\n specFiles.push(specPath);\n }\n\n logger.info(`Found ${specFiles.length} spec files to validate`);\n\n for (const file of specFiles) {\n try {\n // Read the spec file\n const content = await fs.readFile(file);\n\n // Try to extract operationId from the spec file\n // Look for x-contractspec metadata or transport.rest.path\n const operationIdMatch =\n content.match(/operationId:\\s*['\"]([^'\"]+)['\"]/) ||\n content.match(/name:\\s*['\"]([^'\"]+)['\"]/) ||\n content.match(/export\\s+const\\s+(\\w+)Spec\\s*=/);\n\n if (!operationIdMatch || !operationIdMatch[1]) {\n logger.debug(`Could not extract operationId from ${file}`);\n continue;\n }\n\n const specName: string = operationIdMatch[1];\n specsValidated++;\n\n // Try to find matching OpenAPI operation\n // Match by operationId or by similar naming\n let matchingOp: ParsedOperation | undefined;\n\n // Direct match\n matchingOp = operationsMap.get(specName);\n\n // Try variations if no direct match\n if (!matchingOp) {\n // Try camelCase to snake_case\n const snakeName = specName.replace(/([A-Z])/g, '_$1').toLowerCase();\n matchingOp = operationsMap.get(snakeName);\n }\n\n if (!matchingOp) {\n // Try matching by partial name\n for (const [opId, op] of operationsMap) {\n if (\n opId.toLowerCase().includes(specName.toLowerCase()) ||\n specName.toLowerCase().includes(opId.toLowerCase())\n ) {\n matchingOp = op;\n break;\n }\n }\n }\n\n if (!matchingOp) {\n results.push({\n specPath: file,\n valid: false,\n diffs: [\n {\n path: '',\n type: 'removed',\n description: `No matching operation found in OpenAPI for spec: ${specName}`,\n },\n ],\n });\n specsWithDiffs++;\n continue;\n }\n\n // For now, we'll do a basic validation\n // In a full implementation, we would load the actual spec and compare\n const diffs: OpenApiValidateServiceResult['results'][0]['diffs'] = [];\n\n // Check if spec mentions deprecated when OpenAPI says deprecated\n if (matchingOp.deprecated && !content.includes('deprecated')) {\n diffs.push({\n path: 'meta.stability',\n type: 'modified',\n description:\n 'OpenAPI operation is deprecated but spec does not indicate deprecation',\n });\n }\n\n // Check path match\n if (!ignoreTransport) {\n const pathMatch = content.match(/path:\\s*['\"]([^'\"]+)['\"]/);\n if (pathMatch && pathMatch[1] !== matchingOp.path) {\n diffs.push({\n path: 'transport.rest.path',\n type: 'modified',\n description: `Path mismatch: spec has \"${pathMatch[1]}\", OpenAPI has \"${matchingOp.path}\"`,\n });\n }\n }\n\n // Check method match\n if (!ignoreTransport) {\n const methodMatch = content.match(/method:\\s*['\"]([^'\"]+)['\"]/);\n if (\n methodMatch?.[1] &&\n methodMatch[1].toLowerCase() !== matchingOp.method.toLowerCase()\n ) {\n diffs.push({\n path: 'transport.rest.method',\n type: 'modified',\n description: `Method mismatch: spec has \"${methodMatch[1]}\", OpenAPI has \"${matchingOp.method.toUpperCase()}\"`,\n });\n }\n }\n\n const valid = diffs.length === 0;\n if (!valid) {\n specsWithDiffs++;\n }\n\n results.push({\n specPath: file,\n operationId: matchingOp.operationId,\n valid,\n diffs,\n });\n } catch (error) {\n logger.error(`Error validating ${file}: ${error}`);\n results.push({\n specPath: file,\n valid: false,\n diffs: [\n {\n path: '',\n type: 'modified',\n description: `Error: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n });\n specsWithDiffs++;\n }\n }\n\n const valid = specsWithDiffs === 0;\n\n logger.info(\n `Validation ${valid ? 'passed' : 'failed'}: ${specsValidated} specs checked, ${specsWithDiffs} with differences`\n );\n\n return {\n valid,\n specsValidated,\n specsWithDiffs,\n results,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dependencies.d.mts","names":[],"sources":["../../../src/services/quickstart/dependencies.ts"],"
|
|
1
|
+
{"version":3,"file":"dependencies.d.mts","names":[],"sources":["../../../src/services/quickstart/dependencies.ts"],"mappings":";;;;AA+BA;;;;cAjBa,oBAAA,EAAsB,oBAAA;AA0CnC;;;;;AAAA,cAzBa,iBAAA,EAAmB,oBAAA;;;;iBAyBhB,eAAA,CACd,IAAA,uBACC,oBAAA;;;;iBAOa,yBAAA,CACd,YAAA,EAAc,oBAAA,KACb,oBAAA;AAOH;;;AAAA,iBAAgB,kBAAA,CACd,YAAA,EAAc,oBAAA,KACb,oBAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quickstart-service.d.mts","names":[],"sources":["../../../src/services/quickstart/quickstart-service.ts"],"
|
|
1
|
+
{"version":3,"file":"quickstart-service.d.mts","names":[],"sources":["../../../src/services/quickstart/quickstart-service.ts"],"mappings":";;;;;;;iBAyCsB,aAAA,CACpB,EAAA,EAAI,SAAA,EACJ,OAAA,EAAS,iBAAA,EACT,OAAA,GAAS,yBAAA,GACR,OAAA,CAAQ,gBAAA;;;;iBA2NW,uBAAA,CACpB,EAAA,EAAI,SAAA,EACJ,aAAA,WACC,OAAA;;;;iBAwBa,uBAAA,CAAwB,IAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","names":[],"sources":["../../../src/services/quickstart/types.ts"],"
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../../../src/services/quickstart/types.ts"],"mappings":";;AASA;;;;;AAKA;;KALY,cAAA;;;;UAKK,oBAAA;EAQf;EANA,IAAA;EAQW;EANX,OAAA;EAYe;EAVf,GAAA;;EAEA,QAAA;EAUA;EARA,WAAA;AAAA;;;;UAMe,iBAAA;EAYR;EAVP,aAAA;EAgBe;EAdf,IAAA,EAAM,cAAA;;EAEN,MAAA;EAaA;EAXA,WAAA;EAaA;EAXA,KAAA;EAYG;EAVH,OAAA;AAAA;;;;UAMe,oBAAA;EACf,IAAA;EACA,MAAA;EACA,OAAA;EACA,GAAA;AAAA;;;;UAMe,gBAAA;EAQP;EANR,OAAA;EAQO;EANP,SAAA,EAAW,oBAAA;EAYI;EAVf,OAAA,EAAS,oBAAA;EAU+B;EARxC,MAAA,EAAQ,oBAAA;EAcY;EAZpB,OAAA;AAAA;;;;UAMe,yBAAA;EAEe;EAA9B,OAAA,GAAU,OAAA,aAAoB,OAAA;EAErB;EAAT,MAAA,qBACE,OAAA,UACA,OAAA;IAAW,KAAA,EAAO,CAAA;IAAG,KAAA;EAAA,QAClB,OAAA,CAAQ,CAAA;AAAA"}
|
|
@@ -3,7 +3,6 @@ import { ProposalSink, RegenerationContext, RegenerationRule } from "@contractsp
|
|
|
3
3
|
import { SignalAdapters } from "@contractspec/lib.contracts/regenerator/adapters";
|
|
4
4
|
|
|
5
5
|
//#region src/services/regenerator.d.ts
|
|
6
|
-
|
|
7
6
|
interface CreateRegeneratorOptions {
|
|
8
7
|
contexts: RegenerationContext[];
|
|
9
8
|
rules: RegenerationRule[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"regenerator.d.mts","names":[],"sources":["../../src/services/regenerator.ts"],"
|
|
1
|
+
{"version":3,"file":"regenerator.d.mts","names":[],"sources":["../../src/services/regenerator.ts"],"mappings":";;;;;UAeiB,wBAAA;EACf,QAAA,EAAU,mBAAA;EACV,KAAA,EAAO,gBAAA;EACP,IAAA,EAAM,YAAA;EACN,QAAA,GAAW,cAAA;EACX,cAAA;EACA,eAAA;AAAA;AAAA,iBAGc,wBAAA,CACd,OAAA,EAAS,wBAAA,GACR,kBAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.mts","names":[],"sources":["../../src/services/registry.ts"],"
|
|
1
|
+
{"version":3,"file":"registry.d.mts","names":[],"sources":["../../src/services/registry.ts"],"mappings":";;;;;;UASiB,qBAAA;EACf,WAAA;AAAA;;;;cAMW,cAAA;EAAA,iBACM,WAAA;cAEL,IAAA,EAAM,qBAAA;EAFD;;;EASX,OAAA,GAAA,CAAW,IAAA,WAAe,OAAA,CAAQ,CAAA;AAAA;;;;iBA6B1B,kBAAA,CAAmB,cAAA;;;AAAnC;iBAWsB,aAAA,CACpB,QAAA,UACA,OAAA;EAAW,WAAA;AAAA,GACX,QAAA;EAAY,MAAA,EAAQ,aAAA;AAAA,IACnB,OAAA;;;;iBAkBmB,gBAAA,CACpB,OAAA;EAAW,WAAA;EAAsB,MAAA;AAAA,GACjC,QAAA;EAAY,MAAA,EAAQ,aAAA;AAAA,IACnB,OAAA;;;;iBAqBmB,cAAA,CACpB,KAAA,UACA,OAAA;EAAW,WAAA;AAAA,GACX,QAAA;EAAY,MAAA,EAAQ,aAAA;AAAA,IACnB,OAAA"}
|
|
@@ -3,7 +3,6 @@ import { LoggerAdapter } from "../ports/logger.mjs";
|
|
|
3
3
|
import { RuleSyncOptions, RuleSyncPort, RuleSyncResult } from "../ports/rulesync.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/services/rulesync.d.ts
|
|
6
|
-
|
|
7
6
|
declare class RuleSyncService implements RuleSyncPort {
|
|
8
7
|
private readonly fs;
|
|
9
8
|
private readonly logger;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rulesync.d.mts","names":[],"sources":["../../src/services/rulesync.ts"],"
|
|
1
|
+
{"version":3,"file":"rulesync.d.mts","names":[],"sources":["../../src/services/rulesync.ts"],"mappings":";;;;;cAgBa,eAAA,YAA2B,YAAA;EAAA,iBAEnB,EAAA;EAAA,iBACA,MAAA;cADA,EAAA,EAAI,SAAA,EACJ,MAAA,EAAQ,aAAA;EAGrB,IAAA,CAAK,OAAA,EAAS,eAAA,GAAkB,OAAA,CAAQ,cAAA;EA0ExC,cAAA,CAAe,OAAA,EAAS,eAAA,GAAkB,OAAA;EAAA,QAexC,iBAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-generators.d.mts","names":[],"sources":["../../../src/services/setup/config-generators.ts"],"
|
|
1
|
+
{"version":3,"file":"config-generators.d.mts","names":[],"sources":["../../../src/services/setup/config-generators.ts"],"mappings":";;;;;AA4DA;;;iBA/CgB,yBAAA,CAA0B,OAAA,EAAS,YAAA;;AA+DnD;;iBAhBgB,sBAAA,CAAA;;;AA+BhB;iBAfgB,uBAAA,CAAA;;;;AA+BhB;iBAhBgB,uBAAA,CAAA;;;;AAwFhB;;iBAxEgB,mBAAA,CAAoB,OAAA,EAAS,YAAA;;;AAoL7C;;;iBA5GgB,gBAAA,CAAiB,OAAA,EAAS,YAAA;;;;iBA4G1B,0BAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-merger.d.mts","names":[],"sources":["../../../src/services/setup/file-merger.ts"],"
|
|
1
|
+
{"version":3,"file":"file-merger.d.mts","names":[],"sources":["../../../src/services/setup/file-merger.ts"],"mappings":";;AAUA;;;;;;;;iBAAgB,iBAAA,WAA4B,MAAA,kBAAA,CAC1C,QAAA,EAAU,CAAA,EACV,QAAA,EAAU,CAAA,GACT,CAAA;;;;;iBA2Ba,kBAAA,WAA6B,MAAA,kBAAA,CAC3C,QAAA,EAAU,CAAA,EACV,OAAA,EAAS,OAAA,CAAQ,CAAA,IAChB,CAAA;;;;iBAuCa,aAAA,GAAA,CAAiB,OAAA,WAAkB,CAAA;AA1CnD;;;AAAA,iBAqDgB,UAAA,CAAW,GAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup-service.d.mts","names":[],"sources":["../../../src/services/setup/setup-service.ts"],"
|
|
1
|
+
{"version":3,"file":"setup-service.d.mts","names":[],"sources":["../../../src/services/setup/setup-service.ts"],"mappings":";;;;;;;iBA6CsB,QAAA,CACpB,EAAA,EAAI,SAAA,EACJ,OAAA,EAAS,YAAA,EACT,OAAA,GAAS,oBAAA,GACR,OAAA,CAAQ,WAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","names":[],"sources":["../../../src/services/setup/types.ts"],"
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../../../src/services/setup/types.ts"],"mappings":";;AAOA;;;;;KAAY,WAAA;;;;cAWC,iBAAA,EAAmB,WAAA;AAYhC;;;AAAA,cAAa,mBAAA,EAAqB,MAAA,CAAO,WAAA;;AAYzC;;KAAY,UAAA;;;AAKZ;UAAiB,YAAA;;EAEf,aAAA;EAAA;EAEA,WAAA;EAEA;EAAA,UAAA;EAEQ;EAAR,KAAA,GAAQ,UAAA;EAIR;EAFA,WAAA;EAIS;EAFT,WAAA;EAMA;EAJA,OAAA,EAAS,WAAA;EAII;EAFb,WAAA;EAQ8B;EAN9B,aAAA;AAAA;;;;UAMe,eAAA;EAQf;EANA,MAAA,EAAQ,WAAA;EAMD;EAJP,QAAA;EAU0B;EAR1B,MAAA;EAYsB;EAVtB,OAAA;AAAA;;;;UAMe,WAAA;EAYA;EAVf,OAAA;EAUmC;EARnC,KAAA,EAAO,eAAA;EAca;EAZpB,OAAA;AAAA;;;;UAMe,oBAAA;EAEL;EAAV,OAAA,GAAU,OAAA,aAAoB,OAAA;EAE9B;EAAA,WAAA,qBACE,OAAA,UACA,OAAA;IAAW,KAAA,EAAO,CAAA;IAAG,KAAA;IAAe,QAAA;EAAA,QACjC,OAAA,CAAQ,CAAA;EADyB;EAGtC,KAAA,GAAQ,OAAA,UAAiB,YAAA,cAA0B,OAAA;AAAA"}
|
package/dist/services/sync.d.mts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.d.mts","names":[],"sources":["../../src/services/sync.ts"],"
|
|
1
|
+
{"version":3,"file":"sync.d.mts","names":[],"sources":["../../src/services/sync.ts"],"mappings":";;;;;;;;UAaiB,gBAAA;EACf,OAAA;EACA,UAAA;EACA,QAAA;EACA,YAAA,GAAe,IAAA,CAAK,gBAAA;EACpB,MAAA;AAAA;AAAA,UAGe,kBAAA;EACf,QAAA;EACA,SAAA;EACA,UAAA,GAAa,kBAAA;EACb,KAAA;EACA,KAAA;IACE,KAAA;IACA,OAAA;EAAA;AAAA;AAAA,UAIa,eAAA;EACf,KAAA;EACA,IAAA,EAAM,kBAAA;AAAA;AAAA,KAGI,WAAA,OACV,QAAA,UACA,SAAA,yBACG,OAAA,CAAQ,CAAA;AAAA,KAED,cAAA,IAAkB,QAAA,aAAqB,OAAA,CAAQ,kBAAA;AAAA,iBAErC,SAAA,CACpB,QAAA;EAAY,EAAA,EAAI,SAAA;EAAW,MAAA,EAAQ,aAAA;AAAA,GACnC,MAAA,EAAQ,yBAAA,EACR,OAAA,GAAS,gBAAA,EACT,SAAA;EACE,KAAA,GAAQ,WAAA;EACR,QAAA,GAAW,cAAA;AAAA,IAEZ,OAAA,CAAQ,eAAA"}
|
|
@@ -12,8 +12,7 @@ declare class TestGeneratorService {
|
|
|
12
12
|
private readonly logger;
|
|
13
13
|
private readonly defaultModel?;
|
|
14
14
|
constructor(logger: LoggerAdapter, defaultModel?: LanguageModel | undefined);
|
|
15
|
-
generateTests(spec: OperationSpec<any, any>,
|
|
16
|
-
// Use any to satisfy generics for now
|
|
15
|
+
generateTests(spec: OperationSpec<any, any>, // Use any to satisfy generics for now
|
|
17
16
|
options?: TestGeneratorOptions): Promise<TestSpec>;
|
|
18
17
|
private parseResponse;
|
|
19
18
|
private enrichSpec;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-generator-service.d.mts","names":[],"sources":["../../../src/services/test/test-generator-service.ts"],"
|
|
1
|
+
{"version":3,"file":"test-generator-service.d.mts","names":[],"sources":["../../../src/services/test/test-generator-service.ts"],"mappings":";;;;;;UAYiB,oBAAA;EACf,KAAA,GAAQ,aAAA;EACR,YAAA;AAAA;AAAA,cAuBW,oBAAA;EAAA,iBAEQ,MAAA;EAAA,iBACA,YAAA;cADA,MAAA,EAAQ,aAAA,EACR,YAAA,GAAe,aAAA;EAG5B,aAAA,CAEJ,IAAA,EAAM,aAAA;EACN,OAAA,GAAS,oBAAA,GACR,OAAA,CAAQ,QAAA;EAAA,QAoCH,aAAA;EAAA,QAUA,UAAA;EAAA,QA4BA,QAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-service.d.mts","names":[],"sources":["../../../src/services/test/test-service.ts"],"
|
|
1
|
+
{"version":3,"file":"test-service.d.mts","names":[],"sources":["../../../src/services/test/test-service.ts"],"mappings":";;;;;UAUiB,kBAAA;EACf,QAAA;EACA,OAAA;AAAA;AAAA,UAGe,iBAAA;EACf,OAAA,EAAS,aAAA;EACT,MAAA;AAAA;AAAA,UAGe,cAAA;EACf,OAAA,EAAS,aAAA;EACT,MAAA;EACA,MAAA;AAAA;AAAA,iBAGoB,QAAA,CACpB,KAAA,EAAO,QAAA,IACP,QAAA,EAAU,qBAAA,GACT,OAAA,CAAQ,cAAA;AAAA,iBAuBW,YAAA,CACpB,SAAA,YACA,OAAA,EAAS,kBAAA,EACT,QAAA,EAAU,iBAAA,GACT,OAAA,CAAQ,iBAAA;;AApCX;;iBA+FsB,SAAA,CACpB,SAAA,YACA,QAAA,EAAU,iBAAA,GACT,OAAA,CAAQ,QAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/services/test-link/index.ts"],"
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/services/test-link/index.ts"],"mappings":";;;;;;;;;UAciB,mBAAA;EACf,IAAA;EACA,GAAA;EACA,OAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/services/upgrade/index.ts"],"
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/services/upgrade/index.ts"],"mappings":""}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exportAll } from "../../_virtual/
|
|
1
|
+
import { __exportAll } from "../../_virtual/_rolldown/runtime.mjs";
|
|
2
2
|
import { analyzeUpgrades, applyConfigUpgrades, getDefaultHooksConfig, getDefaultVersioningConfig, getPackageUpgradeCommand } from "./upgrade-service.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/services/upgrade/index.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","names":[],"sources":["../../../src/services/upgrade/types.ts"],"
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../../../src/services/upgrade/types.ts"],"mappings":";;AAaA;;;;;;;UAAiB,cAAA;EAUf;EARA,aAAA;EAQS;EANT,eAAA;EAYiC;EAVjC,aAAA;EAUiC;EARjC,MAAA;EAYA;EAVA,SAAA;AAAA;;;AAoBF;UAdiB,kBAAA;;EAEf,IAAA;EAcA;EAZA,cAAA;EAgBA;EAdA,aAAA;EAgBK;EAdL,eAAA;AAAA;;;;UAMe,iBAAA;EAkBf;EAhBA,GAAA;EAkBA;EAhBA,YAAA;EAkBA;EAhBA,cAAA;EAgBW;EAdX,KAAA;AAAA;;;;UAMe,qBAAA;EAoBf;EAlBA,cAAA;EAsBA;EApBA,QAAA,EAAU,kBAAA;EAoBH;EAlBP,cAAA,EAAgB,iBAAA;;EAEhB,WAAA;AAAA;;;;UAMe,kBAAA;;EAEf,OAAA;;EAEA,gBAAA;;EAEA,sBAAA;;EAEA,KAAA;;EAEA,OAAA;AAAA"}
|
|
@@ -3,7 +3,6 @@ import { LoggerAdapter } from "../../ports/logger.mjs";
|
|
|
3
3
|
import { PackageUpgradeInfo, UpgradeAnalysisResult, UpgradeApplyResult, UpgradeOptions } from "./types.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/services/upgrade/upgrade-service.d.ts
|
|
6
|
-
|
|
7
6
|
interface ServiceAdapters {
|
|
8
7
|
fs: FsAdapter;
|
|
9
8
|
logger: LoggerAdapter;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upgrade-service.d.mts","names":[],"sources":["../../../src/services/upgrade/upgrade-service.ts"],"
|
|
1
|
+
{"version":3,"file":"upgrade-service.d.mts","names":[],"sources":["../../../src/services/upgrade/upgrade-service.ts"],"mappings":";;;;;UAmCU,eAAA;EACR,EAAA,EAAI,SAAA;EACJ,MAAA,EAAQ,aAAA;AAAA;AAUV;;;AAAA,iBAAsB,eAAA,CACpB,QAAA,EAAU,eAAA,EACV,OAAA,EAAS,cAAA,GACR,OAAA,CAAQ,qBAAA;;;;;;;iBAoJW,mBAAA,CACpB,QAAA,EAAU,eAAA,EACV,OAAA,EAAS,cAAA,GACR,OAAA,CAAQ,kBAAA;;;;;;iBA0FK,wBAAA,CACd,cAAA,UACA,QAAA,EAAU,kBAAA,IACV,SAAA;AAhGF;;;AAAA,iBAyHgB,0BAAA,CAAA,GAA8B,MAAA;;;;iBAe9B,qBAAA,CAAA,GAAyB,MAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blueprint-validator.d.mts","names":[],"sources":["../../../src/services/validate/blueprint-validator.ts"],"
|
|
1
|
+
{"version":3,"file":"blueprint-validator.d.mts","names":[],"sources":["../../../src/services/validate/blueprint-validator.ts"],"mappings":";;;;;;AAWA;UAAiB,yBAAA;EACf,IAAA,GAAO,gBAAA;EACP,MAAA,GAAS,UAAA,QAAkB,iBAAA;EAC3B,KAAA;EACA,MAAA;AAAA;;;;iBAMoB,mBAAA,CACpB,aAAA,UACA,QAAA;EAAY,EAAA,EAAI,SAAA;AAAA,IACf,OAAA,CAAQ,yBAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"implementation-agent-validator.d.mts","names":[],"sources":["../../../src/services/validate/implementation-agent-validator.ts"],"
|
|
1
|
+
{"version":3,"file":"implementation-agent-validator.d.mts","names":[],"sources":["../../../src/services/validate/implementation-agent-validator.ts"],"mappings":";;;;UAKiB,8BAAA;EACf,kBAAA;AAAA;AAAA,UAGe,8BAAA;EACf,OAAA;EACA,MAAA;EACA,QAAA;EACA,WAAA;EACA,MAAA;AAAA;AAAA,iBAGoB,+BAAA,CACpB,QAAA,UACA,QAAA,UACA,MAAA,EAAQ,yBAAA,EACR,OAAA,EAAS,8BAAA,EACT,QAAA;EAAY,EAAA,EAAI,SAAA;AAAA,IACf,OAAA,CAAQ,8BAAA"}
|
|
@@ -15,8 +15,8 @@ async function validateImplementationWithAgent(specFile, specCode, config, optio
|
|
|
15
15
|
join(dirname(specDir), "handlers", specBaseName.replace(".contracts", ".handler") + ".ts"),
|
|
16
16
|
join(dirname(specDir), "components", specBaseName.replace(".presentation", "") + ".tsx")
|
|
17
17
|
];
|
|
18
|
-
for (const path
|
|
19
|
-
implementationPath = path
|
|
18
|
+
for (const path of possiblePaths) if (await fs.exists(path)) {
|
|
19
|
+
implementationPath = path;
|
|
20
20
|
break;
|
|
21
21
|
}
|
|
22
22
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"implementation-agent-validator.mjs","names":[
|
|
1
|
+
{"version":3,"file":"implementation-agent-validator.mjs","names":[],"sources":["../../../src/services/validate/implementation-agent-validator.ts"],"sourcesContent":["import type { FsAdapter } from '../../ports/fs';\nimport { basename, dirname, join } from 'path';\nimport { AgentOrchestrator } from '../../ai/agents/orchestrator';\nimport type { ResolvedContractsrcConfig } from '@contractspec/lib.contracts';\n\nexport interface ImplementationValidatorOptions {\n implementationPath?: string;\n}\n\nexport interface ImplementationValidationResult {\n success: boolean;\n errors: string[];\n warnings: string[];\n suggestions: string[];\n report?: string;\n}\n\nexport async function validateImplementationWithAgent(\n specFile: string,\n specCode: string,\n config: ResolvedContractsrcConfig,\n options: ImplementationValidatorOptions,\n adapters: { fs: FsAdapter }\n): Promise<ImplementationValidationResult> {\n const { fs } = adapters;\n\n // Find implementation file\n let implementationPath = options.implementationPath;\n\n if (!implementationPath) {\n // Try to infer from spec file path\n const specDir = dirname(specFile);\n const specBaseName = basename(specFile, '.ts');\n\n // Try common patterns\n const possiblePaths = [\n join(specDir, specBaseName.replace('.contracts', '.handler') + '.ts'),\n join(specDir, specBaseName.replace('.presentation', '') + '.tsx'),\n join(specDir, specBaseName.replace('.form', '.form') + '.tsx'),\n join(\n dirname(specDir),\n 'handlers',\n specBaseName.replace('.contracts', '.handler') + '.ts'\n ),\n join(\n dirname(specDir),\n 'components',\n specBaseName.replace('.presentation', '') + '.tsx'\n ),\n ];\n\n for (const path of possiblePaths) {\n if (await fs.exists(path)) {\n implementationPath = path;\n break;\n }\n }\n }\n\n if (!implementationPath || !(await fs.exists(implementationPath))) {\n return {\n success: true, // Not an error if file not found, just nothing to validate\n errors: [],\n warnings: [\n 'Implementation file not found. Specify with --implementation-path',\n ],\n suggestions: [],\n };\n }\n\n const implementationCode = await fs.readFile(implementationPath);\n\n // Use agent orchestrator to validate\n const orchestrator = new AgentOrchestrator(config);\n const result = await orchestrator.validate(specCode, implementationCode);\n\n return {\n success: result.success,\n errors: result.errors || [],\n warnings: result.warnings || [],\n suggestions: result.suggestions || [],\n report: result.code,\n };\n}\n"],"mappings":";;;;AAiBA,eAAsB,gCACpB,UACA,UACA,QACA,SACA,UACyC;CACzC,MAAM,EAAE,OAAO;CAGf,IAAI,qBAAqB,QAAQ;AAEjC,KAAI,CAAC,oBAAoB;EAEvB,MAAM,UAAU,QAAQ,SAAS;EACjC,MAAM,eAAe,SAAS,UAAU,MAAM;EAG9C,MAAM,gBAAgB;GACpB,KAAK,SAAS,aAAa,QAAQ,cAAc,WAAW,GAAG,MAAM;GACrE,KAAK,SAAS,aAAa,QAAQ,iBAAiB,GAAG,GAAG,OAAO;GACjE,KAAK,SAAS,aAAa,QAAQ,SAAS,QAAQ,GAAG,OAAO;GAC9D,KACE,QAAQ,QAAQ,EAChB,YACA,aAAa,QAAQ,cAAc,WAAW,GAAG,MAClD;GACD,KACE,QAAQ,QAAQ,EAChB,cACA,aAAa,QAAQ,iBAAiB,GAAG,GAAG,OAC7C;GACF;AAED,OAAK,MAAM,QAAQ,cACjB,KAAI,MAAM,GAAG,OAAO,KAAK,EAAE;AACzB,wBAAqB;AACrB;;;AAKN,KAAI,CAAC,sBAAsB,CAAE,MAAM,GAAG,OAAO,mBAAmB,CAC9D,QAAO;EACL,SAAS;EACT,QAAQ,EAAE;EACV,UAAU,CACR,oEACD;EACD,aAAa,EAAE;EAChB;CAGH,MAAM,qBAAqB,MAAM,GAAG,SAAS,mBAAmB;CAIhE,MAAM,SAAS,MADM,IAAI,kBAAkB,OAAO,CAChB,SAAS,UAAU,mBAAmB;AAExE,QAAO;EACL,SAAS,OAAO;EAChB,QAAQ,OAAO,UAAU,EAAE;EAC3B,UAAU,OAAO,YAAY,EAAE;EAC/B,aAAa,OAAO,eAAe,EAAE;EACrC,QAAQ,OAAO;EAChB"}
|
|
@@ -3,7 +3,6 @@ import { SpecScanResult } from "@contractspec/module.workspace";
|
|
|
3
3
|
import { ResolvedContractsrcConfig } from "@contractspec/lib.contracts";
|
|
4
4
|
|
|
5
5
|
//#region src/services/validate/implementation-validator.d.ts
|
|
6
|
-
|
|
7
6
|
interface ValidateImplementationOptions {
|
|
8
7
|
checkHandlers?: boolean;
|
|
9
8
|
checkTests?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"implementation-validator.d.mts","names":[],"sources":["../../../src/services/validate/implementation-validator.ts"],"
|
|
1
|
+
{"version":3,"file":"implementation-validator.d.mts","names":[],"sources":["../../../src/services/validate/implementation-validator.ts"],"mappings":";;;;;UAWiB,6BAAA;EACf,aAAA;EACA,UAAA;EAIS;;AAGX;EAHE,SAAA;AAAA;AAAA,UAGe,4BAAA;EACf,KAAA;EACA,MAAA;EACA,QAAA;EACA,QAAA;IACE,WAAA;IACA,eAAA;IACA,aAAA;IACA,iBAAA;IACA,QAAA;IACA,YAAA;EAAA;AAAA;AAAA,iBAmBkB,2BAAA,CACpB,QAAA,EAAU,cAAA,EACV,QAAA;EAAY,EAAA,EAAI,SAAA;AAAA,GAChB,MAAA,EAAQ,yBAAA,EACR,OAAA,GAAS,6BAAA,GACR,OAAA,CAAQ,4BAAA"}
|
|
@@ -30,7 +30,7 @@ async function validateImplementationFiles(specFile, adapters, config, options =
|
|
|
30
30
|
const handlerCode = await fs.readFile(expected.handlerPath);
|
|
31
31
|
const expectedSpecVar = `${toPascalCase(specName.split(".").pop() ?? specName)}Spec`;
|
|
32
32
|
const hasContractHandlerType = /ContractHandler<\s*typeof\s+\w+\s*>/.test(handlerCode);
|
|
33
|
-
const referencesExpectedSpec =
|
|
33
|
+
const referencesExpectedSpec = new RegExp(`typeof\\s+${expectedSpecVar}\\b`).test(handlerCode);
|
|
34
34
|
if (!hasContractHandlerType) warnings.push(`Handler does not appear to type itself as ContractHandler<typeof Spec>: ${expected.handlerPath}`);
|
|
35
35
|
else if (!referencesExpectedSpec) warnings.push(`Handler ContractHandler typing does not reference expected spec var (${expectedSpecVar}): ${expected.handlerPath}`);
|
|
36
36
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"implementation-validator.mjs","names":[],"sources":["../../../src/services/validate/implementation-validator.ts"],"sourcesContent":["/**\n * Implementation validation service (handlers + tests).\n *\n * Deterministic, static checks intended for reuse across CLI/VSCode/web tooling.\n * This does NOT execute spec modules.\n */\n\nimport type { SpecScanResult } from '@contractspec/module.workspace';\nimport type { FsAdapter } from '../../ports/fs';\nimport type { ResolvedContractsrcConfig } from '@contractspec/lib.contracts';\n\nexport interface ValidateImplementationOptions {\n checkHandlers?: boolean;\n checkTests?: boolean;\n /**\n * Override workspace outputDir (defaults to config.outputDir).\n */\n outputDir?: string;\n}\n\nexport interface ValidateImplementationResult {\n valid: boolean;\n errors: string[];\n warnings: string[];\n expected: {\n handlerPath?: string;\n handlerTestPath?: string;\n componentPath?: string;\n componentTestPath?: string;\n formPath?: string;\n formTestPath?: string;\n };\n}\n\nfunction toKebabCase(value: string): string {\n return value\n .replace(/\\./g, '-')\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .toLowerCase();\n}\n\nfunction toPascalCase(value: string): string {\n return value\n .split(/[-_.]/)\n .filter(Boolean)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('');\n}\n\nexport async function validateImplementationFiles(\n specFile: SpecScanResult,\n adapters: { fs: FsAdapter },\n config: ResolvedContractsrcConfig,\n options: ValidateImplementationOptions = {}\n): Promise<ValidateImplementationResult> {\n const { fs } = adapters;\n const errors: string[] = [];\n const warnings: string[] = [];\n\n const specName =\n specFile.key ?? fs.basename(specFile.filePath).replace(/\\.[jt]s$/, '');\n const outRoot = options.outputDir ?? config.outputDir ?? './src';\n const kebab = toKebabCase(specName);\n\n const expected: ValidateImplementationResult['expected'] = {};\n\n if (specFile.specType === 'operation') {\n expected.handlerPath = fs.join(outRoot, 'handlers', `${kebab}.handler.ts`);\n expected.handlerTestPath = fs.join(\n outRoot,\n 'handlers',\n `${kebab}.handler.test.ts`\n );\n }\n if (specFile.specType === 'presentation') {\n expected.componentPath = fs.join(outRoot, 'components', `${kebab}.tsx`);\n expected.componentTestPath = fs.join(\n outRoot,\n 'components',\n `${kebab}.test.tsx`\n );\n }\n if (specFile.specType === 'form') {\n expected.formPath = fs.join(outRoot, 'forms', `${kebab}.form.tsx`);\n expected.formTestPath = fs.join(outRoot, 'forms', `${kebab}.form.test.tsx`);\n }\n\n if (options.checkHandlers && expected.handlerPath) {\n const handlerExists = await fs.exists(expected.handlerPath);\n if (!handlerExists) {\n errors.push(`Missing handler file: ${expected.handlerPath}`);\n } else {\n const handlerCode = await fs.readFile(expected.handlerPath);\n\n const expectedSpecVar = `${toPascalCase(specName.split('.').pop() ?? specName)}Spec`;\n const hasContractHandlerType = /ContractHandler<\\s*typeof\\s+\\w+\\s*>/.test(\n handlerCode\n );\n const referencesExpectedSpec = new RegExp(\n `typeof\\\\s+${expectedSpecVar}\\\\b`\n ).test(handlerCode);\n if (!hasContractHandlerType) {\n warnings.push(\n `Handler does not appear to type itself as ContractHandler<typeof Spec>: ${expected.handlerPath}`\n );\n } else if (!referencesExpectedSpec) {\n warnings.push(\n `Handler ContractHandler typing does not reference expected spec var (${expectedSpecVar}): ${expected.handlerPath}`\n );\n }\n }\n }\n\n if (options.checkTests) {\n const candidateTests = [\n expected.handlerTestPath,\n expected.componentTestPath,\n expected.formTestPath,\n ].filter((p): p is string => typeof p === 'string');\n\n for (const testPath of candidateTests) {\n const testExists = await fs.exists(testPath);\n if (!testExists) {\n errors.push(`Missing test file: ${testPath}`);\n }\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n expected,\n };\n}\n"],"mappings":";AAkCA,SAAS,YAAY,OAAuB;AAC1C,QAAO,MACJ,QAAQ,OAAO,IAAI,CACnB,QAAQ,mBAAmB,QAAQ,CACnC,aAAa;;AAGlB,SAAS,aAAa,OAAuB;AAC3C,QAAO,MACJ,MAAM,QAAQ,CACd,OAAO,QAAQ,CACf,KAAK,SAAS,KAAK,OAAO,EAAE,CAAC,aAAa,GAAG,KAAK,MAAM,EAAE,CAAC,CAC3D,KAAK,GAAG;;AAGb,eAAsB,4BACpB,UACA,UACA,QACA,UAAyC,EAAE,EACJ;CACvC,MAAM,EAAE,OAAO;CACf,MAAM,SAAmB,EAAE;CAC3B,MAAM,WAAqB,EAAE;CAE7B,MAAM,WACJ,SAAS,OAAO,GAAG,SAAS,SAAS,SAAS,CAAC,QAAQ,YAAY,GAAG;CACxE,MAAM,UAAU,QAAQ,aAAa,OAAO,aAAa;CACzD,MAAM,QAAQ,YAAY,SAAS;CAEnC,MAAM,WAAqD,EAAE;AAE7D,KAAI,SAAS,aAAa,aAAa;AACrC,WAAS,cAAc,GAAG,KAAK,SAAS,YAAY,GAAG,MAAM,aAAa;AAC1E,WAAS,kBAAkB,GAAG,KAC5B,SACA,YACA,GAAG,MAAM,kBACV;;AAEH,KAAI,SAAS,aAAa,gBAAgB;AACxC,WAAS,gBAAgB,GAAG,KAAK,SAAS,cAAc,GAAG,MAAM,MAAM;AACvE,WAAS,oBAAoB,GAAG,KAC9B,SACA,cACA,GAAG,MAAM,WACV;;AAEH,KAAI,SAAS,aAAa,QAAQ;AAChC,WAAS,WAAW,GAAG,KAAK,SAAS,SAAS,GAAG,MAAM,WAAW;AAClE,WAAS,eAAe,GAAG,KAAK,SAAS,SAAS,GAAG,MAAM,gBAAgB;;AAG7E,KAAI,QAAQ,iBAAiB,SAAS,YAEpC,KAAI,CADkB,MAAM,GAAG,OAAO,SAAS,YAAY,CAEzD,QAAO,KAAK,yBAAyB,SAAS,cAAc;MACvD;EACL,MAAM,cAAc,MAAM,GAAG,SAAS,SAAS,YAAY;EAE3D,MAAM,kBAAkB,GAAG,aAAa,SAAS,MAAM,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC;EAC/E,MAAM,yBAAyB,sCAAsC,KACnE,YACD;EACD,MAAM,
|
|
1
|
+
{"version":3,"file":"implementation-validator.mjs","names":[],"sources":["../../../src/services/validate/implementation-validator.ts"],"sourcesContent":["/**\n * Implementation validation service (handlers + tests).\n *\n * Deterministic, static checks intended for reuse across CLI/VSCode/web tooling.\n * This does NOT execute spec modules.\n */\n\nimport type { SpecScanResult } from '@contractspec/module.workspace';\nimport type { FsAdapter } from '../../ports/fs';\nimport type { ResolvedContractsrcConfig } from '@contractspec/lib.contracts';\n\nexport interface ValidateImplementationOptions {\n checkHandlers?: boolean;\n checkTests?: boolean;\n /**\n * Override workspace outputDir (defaults to config.outputDir).\n */\n outputDir?: string;\n}\n\nexport interface ValidateImplementationResult {\n valid: boolean;\n errors: string[];\n warnings: string[];\n expected: {\n handlerPath?: string;\n handlerTestPath?: string;\n componentPath?: string;\n componentTestPath?: string;\n formPath?: string;\n formTestPath?: string;\n };\n}\n\nfunction toKebabCase(value: string): string {\n return value\n .replace(/\\./g, '-')\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .toLowerCase();\n}\n\nfunction toPascalCase(value: string): string {\n return value\n .split(/[-_.]/)\n .filter(Boolean)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('');\n}\n\nexport async function validateImplementationFiles(\n specFile: SpecScanResult,\n adapters: { fs: FsAdapter },\n config: ResolvedContractsrcConfig,\n options: ValidateImplementationOptions = {}\n): Promise<ValidateImplementationResult> {\n const { fs } = adapters;\n const errors: string[] = [];\n const warnings: string[] = [];\n\n const specName =\n specFile.key ?? fs.basename(specFile.filePath).replace(/\\.[jt]s$/, '');\n const outRoot = options.outputDir ?? config.outputDir ?? './src';\n const kebab = toKebabCase(specName);\n\n const expected: ValidateImplementationResult['expected'] = {};\n\n if (specFile.specType === 'operation') {\n expected.handlerPath = fs.join(outRoot, 'handlers', `${kebab}.handler.ts`);\n expected.handlerTestPath = fs.join(\n outRoot,\n 'handlers',\n `${kebab}.handler.test.ts`\n );\n }\n if (specFile.specType === 'presentation') {\n expected.componentPath = fs.join(outRoot, 'components', `${kebab}.tsx`);\n expected.componentTestPath = fs.join(\n outRoot,\n 'components',\n `${kebab}.test.tsx`\n );\n }\n if (specFile.specType === 'form') {\n expected.formPath = fs.join(outRoot, 'forms', `${kebab}.form.tsx`);\n expected.formTestPath = fs.join(outRoot, 'forms', `${kebab}.form.test.tsx`);\n }\n\n if (options.checkHandlers && expected.handlerPath) {\n const handlerExists = await fs.exists(expected.handlerPath);\n if (!handlerExists) {\n errors.push(`Missing handler file: ${expected.handlerPath}`);\n } else {\n const handlerCode = await fs.readFile(expected.handlerPath);\n\n const expectedSpecVar = `${toPascalCase(specName.split('.').pop() ?? specName)}Spec`;\n const hasContractHandlerType = /ContractHandler<\\s*typeof\\s+\\w+\\s*>/.test(\n handlerCode\n );\n const referencesExpectedSpec = new RegExp(\n `typeof\\\\s+${expectedSpecVar}\\\\b`\n ).test(handlerCode);\n if (!hasContractHandlerType) {\n warnings.push(\n `Handler does not appear to type itself as ContractHandler<typeof Spec>: ${expected.handlerPath}`\n );\n } else if (!referencesExpectedSpec) {\n warnings.push(\n `Handler ContractHandler typing does not reference expected spec var (${expectedSpecVar}): ${expected.handlerPath}`\n );\n }\n }\n }\n\n if (options.checkTests) {\n const candidateTests = [\n expected.handlerTestPath,\n expected.componentTestPath,\n expected.formTestPath,\n ].filter((p): p is string => typeof p === 'string');\n\n for (const testPath of candidateTests) {\n const testExists = await fs.exists(testPath);\n if (!testExists) {\n errors.push(`Missing test file: ${testPath}`);\n }\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n expected,\n };\n}\n"],"mappings":";AAkCA,SAAS,YAAY,OAAuB;AAC1C,QAAO,MACJ,QAAQ,OAAO,IAAI,CACnB,QAAQ,mBAAmB,QAAQ,CACnC,aAAa;;AAGlB,SAAS,aAAa,OAAuB;AAC3C,QAAO,MACJ,MAAM,QAAQ,CACd,OAAO,QAAQ,CACf,KAAK,SAAS,KAAK,OAAO,EAAE,CAAC,aAAa,GAAG,KAAK,MAAM,EAAE,CAAC,CAC3D,KAAK,GAAG;;AAGb,eAAsB,4BACpB,UACA,UACA,QACA,UAAyC,EAAE,EACJ;CACvC,MAAM,EAAE,OAAO;CACf,MAAM,SAAmB,EAAE;CAC3B,MAAM,WAAqB,EAAE;CAE7B,MAAM,WACJ,SAAS,OAAO,GAAG,SAAS,SAAS,SAAS,CAAC,QAAQ,YAAY,GAAG;CACxE,MAAM,UAAU,QAAQ,aAAa,OAAO,aAAa;CACzD,MAAM,QAAQ,YAAY,SAAS;CAEnC,MAAM,WAAqD,EAAE;AAE7D,KAAI,SAAS,aAAa,aAAa;AACrC,WAAS,cAAc,GAAG,KAAK,SAAS,YAAY,GAAG,MAAM,aAAa;AAC1E,WAAS,kBAAkB,GAAG,KAC5B,SACA,YACA,GAAG,MAAM,kBACV;;AAEH,KAAI,SAAS,aAAa,gBAAgB;AACxC,WAAS,gBAAgB,GAAG,KAAK,SAAS,cAAc,GAAG,MAAM,MAAM;AACvE,WAAS,oBAAoB,GAAG,KAC9B,SACA,cACA,GAAG,MAAM,WACV;;AAEH,KAAI,SAAS,aAAa,QAAQ;AAChC,WAAS,WAAW,GAAG,KAAK,SAAS,SAAS,GAAG,MAAM,WAAW;AAClE,WAAS,eAAe,GAAG,KAAK,SAAS,SAAS,GAAG,MAAM,gBAAgB;;AAG7E,KAAI,QAAQ,iBAAiB,SAAS,YAEpC,KAAI,CADkB,MAAM,GAAG,OAAO,SAAS,YAAY,CAEzD,QAAO,KAAK,yBAAyB,SAAS,cAAc;MACvD;EACL,MAAM,cAAc,MAAM,GAAG,SAAS,SAAS,YAAY;EAE3D,MAAM,kBAAkB,GAAG,aAAa,SAAS,MAAM,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC;EAC/E,MAAM,yBAAyB,sCAAsC,KACnE,YACD;EACD,MAAM,yBAAyB,IAAI,OACjC,aAAa,gBAAgB,KAC9B,CAAC,KAAK,YAAY;AACnB,MAAI,CAAC,uBACH,UAAS,KACP,2EAA2E,SAAS,cACrF;WACQ,CAAC,uBACV,UAAS,KACP,wEAAwE,gBAAgB,KAAK,SAAS,cACvG;;AAKP,KAAI,QAAQ,YAAY;EACtB,MAAM,iBAAiB;GACrB,SAAS;GACT,SAAS;GACT,SAAS;GACV,CAAC,QAAQ,MAAmB,OAAO,MAAM,SAAS;AAEnD,OAAK,MAAM,YAAY,eAErB,KAAI,CADe,MAAM,GAAG,OAAO,SAAS,CAE1C,QAAO,KAAK,sBAAsB,WAAW;;AAKnD,QAAO;EACL,OAAO,OAAO,WAAW;EACzB;EACA;EACA;EACD"}
|