@contractspec/bundle.workspace 0.0.0-canary-20260113173657 → 0.0.0-canary-20260119222405
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +6 -3
- package/dist/index.mjs +4 -1
- package/dist/services/import/import-service.d.mts +47 -0
- package/dist/services/import/import-service.d.mts.map +1 -0
- package/dist/services/import/import-service.mjs +196 -0
- package/dist/services/import/import-service.mjs.map +1 -0
- package/dist/services/import/index.d.mts +3 -0
- package/dist/services/import/index.mjs +5 -0
- package/dist/services/import/report-service.d.mts +31 -0
- package/dist/services/import/report-service.d.mts.map +1 -0
- package/dist/services/import/report-service.mjs +124 -0
- package/dist/services/import/report-service.mjs.map +1 -0
- package/dist/services/import/verify-service.d.mts +67 -0
- package/dist/services/import/verify-service.d.mts.map +1 -0
- package/dist/services/import/verify-service.mjs +105 -0
- package/dist/services/import/verify-service.mjs.map +1 -0
- package/dist/services/index.d.mts +5 -1
- package/dist/services/index.mjs +4 -0
- package/dist/services/openapi/import-service.d.mts +2 -2
- package/dist/services/openapi/import-service.d.mts.map +1 -1
- package/dist/services/openapi/import-service.mjs +3 -6
- package/dist/services/openapi/import-service.mjs.map +1 -1
- package/dist/services/openapi/sync-service.d.mts +2 -2
- package/dist/services/openapi/sync-service.d.mts.map +1 -1
- package/dist/services/openapi/sync-service.mjs.map +1 -1
- package/dist/services/rulesync.d.mts.map +1 -1
- package/dist/services/rulesync.mjs +4 -3
- package/dist/services/rulesync.mjs.map +1 -1
- package/package.json +9 -8
package/dist/index.d.mts
CHANGED
|
@@ -55,7 +55,7 @@ import { ClaudeCodeAdapter, claudeCodeAdapter } from "./services/agent-guide/ada
|
|
|
55
55
|
import { CursorCLIAdapter, cursorCLIAdapter } from "./services/agent-guide/adapters/cursor-cli.mjs";
|
|
56
56
|
import { GenericMCPAdapter, genericMCPAdapter } from "./services/agent-guide/adapters/generic-mcp.mjs";
|
|
57
57
|
import { agentAdapters, getAgentAdapter, listAgentTypes } from "./services/agent-guide/adapters/index.mjs";
|
|
58
|
-
import { VerificationIssue, formatVerificationReport, verifyImplementationAgainstParsedSpec } from "./services/llm/verify-static.mjs";
|
|
58
|
+
import { VerificationIssue as VerificationIssue$1, formatVerificationReport, verifyImplementationAgainstParsedSpec } from "./services/llm/verify-static.mjs";
|
|
59
59
|
import { exportSpecForLLM, generateCursorRulesFromParsedSpec, generateFeatureContextMarkdown, generateGuideFromParsedSpec } from "./services/llm/index.mjs";
|
|
60
60
|
import { AIGenerator } from "./services/create/ai-generator.mjs";
|
|
61
61
|
import { generateOperationSpec } from "./templates/operation.template.mjs";
|
|
@@ -74,7 +74,7 @@ import { generateWorkflowRunnerTemplate } from "./templates/workflow-runner.temp
|
|
|
74
74
|
import { FeatureSpecParams, generateFeatureSpec } from "./templates/feature.template.mjs";
|
|
75
75
|
import { index_d_exports as index_d_exports$6 } from "./templates/index.mjs";
|
|
76
76
|
import { SpecCreatorService, createSpecCreator } from "./services/create/index.mjs";
|
|
77
|
-
import { AIReviewResult, BehaviorCheck, FieldMapping, FieldMatchType, IntentAlignment, SemanticVerificationResult, StructureCheck, VerifyConfig, VerifyInput, VerifyOptions, VerifyResult } from "./services/verify/types.mjs";
|
|
77
|
+
import { AIReviewResult, BehaviorCheck, FieldMapping, FieldMatchType, IntentAlignment, SemanticVerificationResult, StructureCheck, VerifyConfig, VerifyInput, VerifyOptions as VerifyOptions$1, VerifyResult as VerifyResult$1 } from "./services/verify/types.mjs";
|
|
78
78
|
import { VerifyService, createVerifyService, verifyService } from "./services/verify/verify-service.mjs";
|
|
79
79
|
import { verifyStructure } from "./services/verify/structure-verifier.mjs";
|
|
80
80
|
import { verifyBehavior } from "./services/verify/behavior-verifier.mjs";
|
|
@@ -108,6 +108,9 @@ import { GapAnalysisResult, analyzeGap } from "./services/gap.mjs";
|
|
|
108
108
|
import { GenerateArtifactsResult, generateArtifacts } from "./services/generate-artifacts.mjs";
|
|
109
109
|
import { ExtractOptions, extractContracts } from "./services/extract.mjs";
|
|
110
110
|
import { index_d_exports as index_d_exports$10 } from "./services/vibe/index.mjs";
|
|
111
|
+
import { ImportServiceAdapters, ImportServiceOptions, ImportServiceResult, importFromSourceService } from "./services/import/import-service.mjs";
|
|
112
|
+
import { EndpointVerification, VerificationIssue, VerifyOptions, VerifyResult, verifyImportedContracts } from "./services/import/verify-service.mjs";
|
|
113
|
+
import { ReportOptions, generateCliReport, generateMarkdownReport } from "./services/import/report-service.mjs";
|
|
111
114
|
import "./services/index.mjs";
|
|
112
115
|
import { index_d_exports as index_d_exports$2 } from "./formatters/index.mjs";
|
|
113
116
|
import { AIClient } from "./ai/client.mjs";
|
|
@@ -122,4 +125,4 @@ import { index_d_exports as index_d_exports$5 } from "./ai/prompts/index.mjs";
|
|
|
122
125
|
import "./ai/index.mjs";
|
|
123
126
|
import { index_d_exports as index_d_exports$8 } from "./utils/index.mjs";
|
|
124
127
|
import * as module from "@contractspec/module.workspace";
|
|
125
|
-
export { AIClient, AIGenerator, AIReviewResult, ALL_CHECK_CATEGORIES, ALL_CI_CHECK_CATEGORIES, ALL_SETUP_TARGETS, AgentAdapter, AgentConfig, AgentGuideConfig, AgentGuideService, type AgentMode, AgentOrchestrator, AgentProvider, AgentResult, AgentTask, AiAdapter, AiGenerateOptions, AiGenerateResult, AiGenerateStructuredOptions, type AiProvider, AiValidationResult, AnalyzeDepsOptions, AnalyzeDepsResult, BehaviorCheck, BlueprintValidationResult, BuildSpecOptions, BuildSpecResult, BuildTarget, BuildTargetResult, CHECK_CATEGORY_LABELS, CICheckCategory, CICheckCategorySummary, CICheckOptions, CICheckResult, CIFormatOptions, CIIssue, CIIssueSeverity, CIOutputFormat, CI_CHECK_CATEGORY_LABELS, CacheEntryMeta, CacheKeyString, CacheLookupResult, CacheMissReason, CacheStats, CacheStorageAdapter, CheckCategory, CheckContext, CheckResult, CheckStatus, ClaudeCodeAdapter, ClaudeCodeAgent, CleanOptions, CleanResult, CompareSpecsOptions, CompareSpecsResult, type Config, CoverageByType, CreateAdaptersOptions, CreateRegeneratorOptions, CursorAgent, CursorCLIAdapter, DEFAULT_CACHE_CONFIG, DEFAULT_SPEC_PATTERNS, DiagramOptions, DiagramType, DiscoverOptions, DiscoveryOptions, DocsServiceOptions, DocsServiceResult, DoctorOptions, DoctorPromptCallbacks, DoctorResult, ExtendedWorkspaceInfo, ExtractOptions, FULL_DEPENDENCIES, FeatureSpecParams, FieldMapping, FieldMatchType, FileStat, FileSystemCacheStorage, FixAction, FixResult, type FixStrategyType, type FixableIssue, FormatOptions, FormatterOptions, FsAdapter, GapAnalysisResult, GenerateArtifactsResult, GenericMCPAdapter, GitAdapter, GitCleanOptions, GitLogEntry, GuideOptions, GuideResult, ImplementationSource, ImplementationStatus, ImplementationValidationResult, ImplementationValidatorOptions, InMemoryCacheStorage, IntegrityAnalysisOptions, IntegrityAnalysisResult, IntegrityIssue, IntentAlignment, KeyValueStore, LayerDiscoveryOptions, LayerDiscoveryResult, LayerInventory, LayerLocation, OpenApiExportOptions as LegacyOpenApiExportOptions, OpenApiExportResult as LegacyOpenApiExportResult, ListSpecsOptions, LogLevel, LoggerAdapter, MINIMAL_DEPENDENCIES, MetaRepoInfo, MonorepoConfig, OpenAICodexAgent, OpenApiExportServiceOptions, OpenApiExportServiceResult, OpenApiImportServiceOptions, OpenApiImportServiceResult, OpenApiSyncServiceOptions, OpenApiSyncServiceResult, OpenApiValidateServiceOptions, OpenApiValidateServiceResult, PackageInstallResult, PackageManager, ProgressReporter, ProgressUpdate, QuickstartDependency, QuickstartMode, QuickstartOptions, QuickstartPromptCallbacks, QuickstartResult, RegistryClient, RegistryClientOptions, RepositoryType, ResolvedImplementation, ResolverOptions, RuleSyncOptions, RuleSyncPort, RuleSyncResult, RuleSyncService, RunTestsResult, SETUP_TARGET_LABELS, SemanticVerificationResult, SetupFileResult, SetupOptions, SetupPromptCallbacks, SetupResult, SetupScope, SetupTarget, SimpleAgent, SpecCreatorService, SpecImplementationResult, SpecInventory, SpecLocation, SpecReferenceMatch, SpecVersionAnalysis, StructureCheck, SubmoduleInfo, SyncBuildFn, SyncSpecsOptions, SyncSpecsResult, SyncSpecsRunResult, SyncValidateFn, TenantValidationContext, TenantValidationResult, TestGeneratorOptions, TestGeneratorService, TestServiceOptions, TestServiceResult, ValidateImplementationOptions, ValidateImplementationResult, ValidateSpecOptions, ValidateSpecResult, VerificationCacheConfig, VerificationCacheEntry, VerificationCacheKey, VerificationCacheService, VerificationIssue, VerifyConfig, VerifyInput, VerifyOptions, VerifyResult, VerifyService, ViewAudience, WatchBuildFn, WatchEvent, WatchEventHandler, WatchEventType, WatchOptions, WatchSpecsOptions, WatchValidateFn, Watcher, WatcherAdapter, WorkspaceAdapters, WorkspaceConfigInfo, WorkspaceInfo, WorkspaceStateCacheStorage, addToRegistry, agentAdapters, agentGuideService, analyzeDeps, analyzeGap, analyzeIntegrity, buildSpec, cacheKeyToString, claudeCodeAdapter, cleanArtifacts, compareSpecs, computeContentHash, createAgentGuideService, createConsoleLoggerAdapter, createEmptyLayerInventory, createFileSystemCacheStorage, createInMemoryCacheStorage, createNodeAdapters, createNodeAiAdapter, createNodeFsAdapter, createNodeGitAdapter, createNodeWatcherAdapter, createNoopLoggerAdapter, createQuickAIReview, createRegeneratorService, createSpecCreator, createVerificationCacheService, createVerifyService, createWorkspaceStateCacheStorage, cursorCLIAdapter, deepMergeOverwrite, deepMergePreserve, detectPackageManager, detectRepositoryType, determineStatus, discoverAllImplementations, discoverImplementationsForSpec, discoverLayers, exportGraphAsDot, exportOpenApi, exportSpecForLLM, extractContracts, extractSpecReferences, index_d_exports as features, filterIssuesBySeverity, filterIssuesByType, findAllConfigFiles, findMetaRepoRoot, findPackageRoot, findWorkspaceRoot, index_d_exports$1 as fix, formatCheckResult, formatDoctorSummary, formatFiles, formatJson, formatQuickstartPreview, formatVerificationReport, formatWorkspaceInfo, index_d_exports$2 as formatters, generateAgentsMd, generateAppBlueprintSpec, generateArtifacts, generateClaudeMcpConfig, generateComponentTemplate, generateContractsrcConfig, generateCursorMcpConfig, generateCursorRules, generateCursorRulesFromParsedSpec, generateDataViewSpec, generateDocsFromSpecs, generateEventSpec, generateExperimentSpec, generateFeatureContextMarkdown, generateFeatureSpec, generateGuideFromParsedSpec, generateHandlerTemplate, generateIntegrationSpec, generateKnowledgeSpaceSpec, generateMermaidDiagram, generateMigrationSpec, generateOperationSpec, generatePresentationSpec, generateTelemetrySpec, generateTestTemplate, generateView, generateVscodeSettings, generateWorkflowRunnerTemplate, generateWorkflowSpec, genericMCPAdapter, getAIProvider, getAgentAdapter, getAllLayerLocations, getAllSpecs, getApiKey, getClaudeDesktopConfigPath, getContractNode, getConventionPaths, getDependencies, getDevDependencies, getExecCommand, getExtendedWorkspaceInfo, getGraphStats, getImplementationSummary, getInstallCommand, getMetaRepoInfo, getPackageName, getProductionDependencies, getRecommendedModels, getRunCommand, getSpecKeyVariants, getWorkspaceInfo, getWorkspacePackages, groupSpecsByType, index_d_exports$3 as hooks, index_d_exports$4 as impact, importFromOpenApiService, inferImplementationType, isContractSpecInstalled, isMonorepo, listAgentTypes, listFromRegistry, listSpecs, listTests, loadWorkspaceConfig, mergeMonorepoConfigs, module, parseExplicitImplementations, parseGitModules, index_d_exports$5 as prompts, resolveAllImplementations, resolveImplementations, resolveRegistryUrl, runCIChecks, runDoctor, runQuickstart, runSetup, runTestSpecs, runTests, safeParseJson, searchRegistry, stringToCacheKey, syncSpecs, syncWithOpenApiService, index_d_exports$6 as templates, toKebabCase, index_d_exports$7 as upgrade, index_d_exports$8 as utils, validateAgainstOpenApiService, validateBlueprint, validateImplementationFiles, validateImplementationWithAgent, validateProvider, validateSpec, validateSpecs, validateTenantConfig, verifyBehavior, verifyImplementationAgainstParsedSpec, verifySemanticFields, verifyService, verifyStructure, verifyWithAI, verifyWithAIEnhanced, index_d_exports$9 as versioning, index_d_exports$10 as vibe, watchSpecs };
|
|
128
|
+
export { AIClient, AIGenerator, AIReviewResult, ALL_CHECK_CATEGORIES, ALL_CI_CHECK_CATEGORIES, ALL_SETUP_TARGETS, AgentAdapter, AgentConfig, AgentGuideConfig, AgentGuideService, type AgentMode, AgentOrchestrator, AgentProvider, AgentResult, AgentTask, AiAdapter, AiGenerateOptions, AiGenerateResult, AiGenerateStructuredOptions, type AiProvider, AiValidationResult, AnalyzeDepsOptions, AnalyzeDepsResult, BehaviorCheck, BlueprintValidationResult, BuildSpecOptions, BuildSpecResult, BuildTarget, BuildTargetResult, CHECK_CATEGORY_LABELS, CICheckCategory, CICheckCategorySummary, CICheckOptions, CICheckResult, CIFormatOptions, CIIssue, CIIssueSeverity, CIOutputFormat, CI_CHECK_CATEGORY_LABELS, CacheEntryMeta, CacheKeyString, CacheLookupResult, CacheMissReason, CacheStats, CacheStorageAdapter, CheckCategory, CheckContext, CheckResult, CheckStatus, ClaudeCodeAdapter, ClaudeCodeAgent, CleanOptions, CleanResult, CompareSpecsOptions, CompareSpecsResult, type Config, CoverageByType, CreateAdaptersOptions, CreateRegeneratorOptions, CursorAgent, CursorCLIAdapter, DEFAULT_CACHE_CONFIG, DEFAULT_SPEC_PATTERNS, DiagramOptions, DiagramType, DiscoverOptions, DiscoveryOptions, DocsServiceOptions, DocsServiceResult, DoctorOptions, DoctorPromptCallbacks, DoctorResult, EndpointVerification, ExtendedWorkspaceInfo, ExtractOptions, FULL_DEPENDENCIES, FeatureSpecParams, FieldMapping, FieldMatchType, FileStat, FileSystemCacheStorage, FixAction, FixResult, type FixStrategyType, type FixableIssue, FormatOptions, FormatterOptions, FsAdapter, GapAnalysisResult, GenerateArtifactsResult, GenericMCPAdapter, GitAdapter, GitCleanOptions, GitLogEntry, GuideOptions, GuideResult, ImplementationSource, ImplementationStatus, ImplementationValidationResult, ImplementationValidatorOptions, ImportServiceAdapters, ImportServiceOptions, ImportServiceResult, VerificationIssue as ImportVerificationIssue, VerifyOptions as ImportVerifyOptions, VerifyResult as ImportVerifyResult, InMemoryCacheStorage, IntegrityAnalysisOptions, IntegrityAnalysisResult, IntegrityIssue, IntentAlignment, KeyValueStore, LayerDiscoveryOptions, LayerDiscoveryResult, LayerInventory, LayerLocation, OpenApiExportOptions as LegacyOpenApiExportOptions, OpenApiExportResult as LegacyOpenApiExportResult, ListSpecsOptions, LogLevel, LoggerAdapter, MINIMAL_DEPENDENCIES, MetaRepoInfo, MonorepoConfig, OpenAICodexAgent, OpenApiExportServiceOptions, OpenApiExportServiceResult, OpenApiImportServiceOptions, OpenApiImportServiceResult, OpenApiSyncServiceOptions, OpenApiSyncServiceResult, OpenApiValidateServiceOptions, OpenApiValidateServiceResult, PackageInstallResult, PackageManager, ProgressReporter, ProgressUpdate, QuickstartDependency, QuickstartMode, QuickstartOptions, QuickstartPromptCallbacks, QuickstartResult, RegistryClient, RegistryClientOptions, ReportOptions, RepositoryType, ResolvedImplementation, ResolverOptions, RuleSyncOptions, RuleSyncPort, RuleSyncResult, RuleSyncService, RunTestsResult, SETUP_TARGET_LABELS, SemanticVerificationResult, SetupFileResult, SetupOptions, SetupPromptCallbacks, SetupResult, SetupScope, SetupTarget, SimpleAgent, SpecCreatorService, SpecImplementationResult, SpecInventory, SpecLocation, SpecReferenceMatch, SpecVersionAnalysis, StructureCheck, SubmoduleInfo, SyncBuildFn, SyncSpecsOptions, SyncSpecsResult, SyncSpecsRunResult, SyncValidateFn, TenantValidationContext, TenantValidationResult, TestGeneratorOptions, TestGeneratorService, TestServiceOptions, TestServiceResult, ValidateImplementationOptions, ValidateImplementationResult, ValidateSpecOptions, ValidateSpecResult, VerificationCacheConfig, VerificationCacheEntry, VerificationCacheKey, VerificationCacheService, VerificationIssue$1 as VerificationIssue, VerifyConfig, VerifyInput, VerifyOptions$1 as VerifyOptions, VerifyResult$1 as VerifyResult, VerifyService, ViewAudience, WatchBuildFn, WatchEvent, WatchEventHandler, WatchEventType, WatchOptions, WatchSpecsOptions, WatchValidateFn, Watcher, WatcherAdapter, WorkspaceAdapters, WorkspaceConfigInfo, WorkspaceInfo, WorkspaceStateCacheStorage, addToRegistry, agentAdapters, agentGuideService, analyzeDeps, analyzeGap, analyzeIntegrity, buildSpec, cacheKeyToString, claudeCodeAdapter, cleanArtifacts, compareSpecs, computeContentHash, createAgentGuideService, createConsoleLoggerAdapter, createEmptyLayerInventory, createFileSystemCacheStorage, createInMemoryCacheStorage, createNodeAdapters, createNodeAiAdapter, createNodeFsAdapter, createNodeGitAdapter, createNodeWatcherAdapter, createNoopLoggerAdapter, createQuickAIReview, createRegeneratorService, createSpecCreator, createVerificationCacheService, createVerifyService, createWorkspaceStateCacheStorage, cursorCLIAdapter, deepMergeOverwrite, deepMergePreserve, detectPackageManager, detectRepositoryType, determineStatus, discoverAllImplementations, discoverImplementationsForSpec, discoverLayers, exportGraphAsDot, exportOpenApi, exportSpecForLLM, extractContracts, extractSpecReferences, index_d_exports as features, filterIssuesBySeverity, filterIssuesByType, findAllConfigFiles, findMetaRepoRoot, findPackageRoot, findWorkspaceRoot, index_d_exports$1 as fix, formatCheckResult, formatDoctorSummary, formatFiles, formatJson, formatQuickstartPreview, formatVerificationReport, formatWorkspaceInfo, index_d_exports$2 as formatters, generateAgentsMd, generateAppBlueprintSpec, generateArtifacts, generateClaudeMcpConfig, generateCliReport, generateComponentTemplate, generateContractsrcConfig, generateCursorMcpConfig, generateCursorRules, generateCursorRulesFromParsedSpec, generateDataViewSpec, generateDocsFromSpecs, generateEventSpec, generateExperimentSpec, generateFeatureContextMarkdown, generateFeatureSpec, generateGuideFromParsedSpec, generateHandlerTemplate, generateIntegrationSpec, generateKnowledgeSpaceSpec, generateMarkdownReport, generateMermaidDiagram, generateMigrationSpec, generateOperationSpec, generatePresentationSpec, generateTelemetrySpec, generateTestTemplate, generateView, generateVscodeSettings, generateWorkflowRunnerTemplate, generateWorkflowSpec, genericMCPAdapter, getAIProvider, getAgentAdapter, getAllLayerLocations, getAllSpecs, getApiKey, getClaudeDesktopConfigPath, getContractNode, getConventionPaths, getDependencies, getDevDependencies, getExecCommand, getExtendedWorkspaceInfo, getGraphStats, getImplementationSummary, getInstallCommand, getMetaRepoInfo, getPackageName, getProductionDependencies, getRecommendedModels, getRunCommand, getSpecKeyVariants, getWorkspaceInfo, getWorkspacePackages, groupSpecsByType, index_d_exports$3 as hooks, index_d_exports$4 as impact, importFromOpenApiService, importFromSourceService, inferImplementationType, isContractSpecInstalled, isMonorepo, listAgentTypes, listFromRegistry, listSpecs, listTests, loadWorkspaceConfig, mergeMonorepoConfigs, module, parseExplicitImplementations, parseGitModules, index_d_exports$5 as prompts, resolveAllImplementations, resolveImplementations, resolveRegistryUrl, runCIChecks, runDoctor, runQuickstart, runSetup, runTestSpecs, runTests, safeParseJson, searchRegistry, stringToCacheKey, syncSpecs, syncWithOpenApiService, index_d_exports$6 as templates, toKebabCase, index_d_exports$7 as upgrade, index_d_exports$8 as utils, validateAgainstOpenApiService, validateBlueprint, validateImplementationFiles, validateImplementationWithAgent, validateProvider, validateSpec, validateSpecs, validateTenantConfig, verifyBehavior, verifyImplementationAgainstParsedSpec, verifyImportedContracts, verifySemanticFields, verifyService, verifyStructure, verifyWithAI, verifyWithAIEnhanced, index_d_exports$9 as versioning, index_d_exports$10 as vibe, watchSpecs };
|
package/dist/index.mjs
CHANGED
|
@@ -100,6 +100,9 @@ import { generateView } from "./services/view/index.mjs";
|
|
|
100
100
|
import { analyzeGap } from "./services/gap.mjs";
|
|
101
101
|
import { extractContracts } from "./services/extract.mjs";
|
|
102
102
|
import { vibe_exports } from "./services/vibe/index.mjs";
|
|
103
|
+
import { importFromSourceService } from "./services/import/import-service.mjs";
|
|
104
|
+
import { verifyImportedContracts } from "./services/import/verify-service.mjs";
|
|
105
|
+
import { generateCliReport, generateMarkdownReport } from "./services/import/report-service.mjs";
|
|
103
106
|
import "./services/index.mjs";
|
|
104
107
|
import { formatters_exports } from "./formatters/index.mjs";
|
|
105
108
|
import { AIClient } from "./ai/client.mjs";
|
|
@@ -107,4 +110,4 @@ import { prompts_exports } from "./ai/prompts/index.mjs";
|
|
|
107
110
|
import "./ai/index.mjs";
|
|
108
111
|
import * as module from "@contractspec/module.workspace";
|
|
109
112
|
|
|
110
|
-
export { AIClient, AIGenerator, ALL_CHECK_CATEGORIES, ALL_CI_CHECK_CATEGORIES, ALL_SETUP_TARGETS, AgentGuideService, AgentOrchestrator, CHECK_CATEGORY_LABELS, CI_CHECK_CATEGORY_LABELS, ClaudeCodeAdapter, ClaudeCodeAgent, CursorAgent, CursorCLIAdapter, DEFAULT_CACHE_CONFIG, DEFAULT_SPEC_PATTERNS, FULL_DEPENDENCIES, FileSystemCacheStorage, GenericMCPAdapter, InMemoryCacheStorage, MINIMAL_DEPENDENCIES, OpenAICodexAgent, RegistryClient, RuleSyncService, SETUP_TARGET_LABELS, SimpleAgent, SpecCreatorService, TestGeneratorService, VerificationCacheService, VerifyService, WorkspaceStateCacheStorage, addToRegistry, agentAdapters, agentGuideService, analyzeDeps, analyzeGap, analyzeIntegrity, buildSpec, cacheKeyToString, claudeCodeAdapter, cleanArtifacts, compareSpecs, computeContentHash, createAgentGuideService, createConsoleLoggerAdapter, createEmptyLayerInventory, createFileSystemCacheStorage, createInMemoryCacheStorage, createNodeAdapters, createNodeAiAdapter, createNodeFsAdapter, createNodeGitAdapter, createNodeWatcherAdapter, createNoopLoggerAdapter, createQuickAIReview, createRegeneratorService, createSpecCreator, createVerificationCacheService, createVerifyService, createWorkspaceStateCacheStorage, cursorCLIAdapter, deepMergeOverwrite, deepMergePreserve, detectPackageManager, detectRepositoryType, determineStatus, discoverAllImplementations, discoverImplementationsForSpec, discoverLayers, exportGraphAsDot, exportOpenApi, exportSpecForLLM, extractContracts, extractSpecReferences, features_exports as features, filterIssuesBySeverity, filterIssuesByType, findAllConfigFiles, findMetaRepoRoot, findPackageRoot, findWorkspaceRoot, fix_exports as fix, formatCheckResult, formatDoctorSummary, formatFiles, formatJson, formatQuickstartPreview, formatVerificationReport, formatWorkspaceInfo, formatters_exports as formatters, generateAgentsMd, generateAppBlueprintSpec, generateArtifacts, generateClaudeMcpConfig, generateComponentTemplate, generateContractsrcConfig, generateCursorMcpConfig, generateCursorRules, generateCursorRulesFromParsedSpec, generateDataViewSpec, generateDocsFromSpecs, generateEventSpec, generateExperimentSpec, generateFeatureContextMarkdown, generateFeatureSpec, generateGuideFromParsedSpec, generateHandlerTemplate, generateIntegrationSpec, generateKnowledgeSpaceSpec, generateMermaidDiagram, generateMigrationSpec, generateOperationSpec, generatePresentationSpec, generateTelemetrySpec, generateTestTemplate, generateView, generateVscodeSettings, generateWorkflowRunnerTemplate, generateWorkflowSpec, genericMCPAdapter, getAIProvider, getAgentAdapter, getAllLayerLocations, getAllSpecs, getApiKey, getClaudeDesktopConfigPath, getContractNode, getConventionPaths, getDependencies, getDevDependencies, getExecCommand, getExtendedWorkspaceInfo, getGraphStats, getImplementationSummary, getInstallCommand, getMetaRepoInfo, getPackageName, getProductionDependencies, getRecommendedModels, getRunCommand, getSpecKeyVariants, getWorkspaceInfo, getWorkspacePackages, groupSpecsByType, hooks_exports as hooks, impact_exports as impact, importFromOpenApiService, inferImplementationType, isContractSpecInstalled, isMonorepo, listAgentTypes, listFromRegistry, listSpecs, listTests, loadWorkspaceConfig, mergeMonorepoConfigs, module, parseExplicitImplementations, parseGitModules, prompts_exports as prompts, resolveAllImplementations, resolveImplementations, resolveRegistryUrl, runCIChecks, runDoctor, runQuickstart, runSetup, runTestSpecs, runTests, safeParseJson, searchRegistry, stringToCacheKey, syncSpecs, syncWithOpenApiService, templates_exports as templates, toKebabCase, upgrade_exports as upgrade, utils_exports as utils, validateAgainstOpenApiService, validateBlueprint, validateImplementationFiles, validateImplementationWithAgent, validateProvider, validateSpec, validateSpecs, validateTenantConfig, verifyBehavior, verifyImplementationAgainstParsedSpec, verifySemanticFields, verifyService, verifyStructure, verifyWithAI, verifyWithAIEnhanced, versioning_exports as versioning, vibe_exports as vibe, watchSpecs };
|
|
113
|
+
export { AIClient, AIGenerator, ALL_CHECK_CATEGORIES, ALL_CI_CHECK_CATEGORIES, ALL_SETUP_TARGETS, AgentGuideService, AgentOrchestrator, CHECK_CATEGORY_LABELS, CI_CHECK_CATEGORY_LABELS, ClaudeCodeAdapter, ClaudeCodeAgent, CursorAgent, CursorCLIAdapter, DEFAULT_CACHE_CONFIG, DEFAULT_SPEC_PATTERNS, FULL_DEPENDENCIES, FileSystemCacheStorage, GenericMCPAdapter, InMemoryCacheStorage, MINIMAL_DEPENDENCIES, OpenAICodexAgent, RegistryClient, RuleSyncService, SETUP_TARGET_LABELS, SimpleAgent, SpecCreatorService, TestGeneratorService, VerificationCacheService, VerifyService, WorkspaceStateCacheStorage, addToRegistry, agentAdapters, agentGuideService, analyzeDeps, analyzeGap, analyzeIntegrity, buildSpec, cacheKeyToString, claudeCodeAdapter, cleanArtifacts, compareSpecs, computeContentHash, createAgentGuideService, createConsoleLoggerAdapter, createEmptyLayerInventory, createFileSystemCacheStorage, createInMemoryCacheStorage, createNodeAdapters, createNodeAiAdapter, createNodeFsAdapter, createNodeGitAdapter, createNodeWatcherAdapter, createNoopLoggerAdapter, createQuickAIReview, createRegeneratorService, createSpecCreator, createVerificationCacheService, createVerifyService, createWorkspaceStateCacheStorage, cursorCLIAdapter, deepMergeOverwrite, deepMergePreserve, detectPackageManager, detectRepositoryType, determineStatus, discoverAllImplementations, discoverImplementationsForSpec, discoverLayers, exportGraphAsDot, exportOpenApi, exportSpecForLLM, extractContracts, extractSpecReferences, features_exports as features, filterIssuesBySeverity, filterIssuesByType, findAllConfigFiles, findMetaRepoRoot, findPackageRoot, findWorkspaceRoot, fix_exports as fix, formatCheckResult, formatDoctorSummary, formatFiles, formatJson, formatQuickstartPreview, formatVerificationReport, formatWorkspaceInfo, formatters_exports as formatters, generateAgentsMd, generateAppBlueprintSpec, generateArtifacts, generateClaudeMcpConfig, generateCliReport, generateComponentTemplate, generateContractsrcConfig, generateCursorMcpConfig, generateCursorRules, generateCursorRulesFromParsedSpec, generateDataViewSpec, generateDocsFromSpecs, generateEventSpec, generateExperimentSpec, generateFeatureContextMarkdown, generateFeatureSpec, generateGuideFromParsedSpec, generateHandlerTemplate, generateIntegrationSpec, generateKnowledgeSpaceSpec, generateMarkdownReport, generateMermaidDiagram, generateMigrationSpec, generateOperationSpec, generatePresentationSpec, generateTelemetrySpec, generateTestTemplate, generateView, generateVscodeSettings, generateWorkflowRunnerTemplate, generateWorkflowSpec, genericMCPAdapter, getAIProvider, getAgentAdapter, getAllLayerLocations, getAllSpecs, getApiKey, getClaudeDesktopConfigPath, getContractNode, getConventionPaths, getDependencies, getDevDependencies, getExecCommand, getExtendedWorkspaceInfo, getGraphStats, getImplementationSummary, getInstallCommand, getMetaRepoInfo, getPackageName, getProductionDependencies, getRecommendedModels, getRunCommand, getSpecKeyVariants, getWorkspaceInfo, getWorkspacePackages, groupSpecsByType, hooks_exports as hooks, impact_exports as impact, importFromOpenApiService, importFromSourceService, inferImplementationType, isContractSpecInstalled, isMonorepo, listAgentTypes, listFromRegistry, listSpecs, listTests, loadWorkspaceConfig, mergeMonorepoConfigs, module, parseExplicitImplementations, parseGitModules, prompts_exports as prompts, resolveAllImplementations, resolveImplementations, resolveRegistryUrl, runCIChecks, runDoctor, runQuickstart, runSetup, runTestSpecs, runTests, safeParseJson, searchRegistry, stringToCacheKey, syncSpecs, syncWithOpenApiService, templates_exports as templates, toKebabCase, upgrade_exports as upgrade, utils_exports as utils, validateAgainstOpenApiService, validateBlueprint, validateImplementationFiles, validateImplementationWithAgent, validateProvider, validateSpec, validateSpecs, validateTenantConfig, verifyBehavior, verifyImplementationAgainstParsedSpec, verifyImportedContracts, verifySemanticFields, verifyService, verifyStructure, verifyWithAI, verifyWithAIEnhanced, versioning_exports as versioning, vibe_exports as vibe, watchSpecs };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { FsAdapter } from "../../ports/fs.mjs";
|
|
2
|
+
import { LoggerAdapter } from "../../ports/logger.mjs";
|
|
3
|
+
import { ResolvedContractsrcConfig } from "@contractspec/lib.contracts";
|
|
4
|
+
import { ImportIR } from "@contractspec/lib.source-extractors";
|
|
5
|
+
import { GenerationResult } from "@contractspec/lib.source-extractors/codegen";
|
|
6
|
+
|
|
7
|
+
//#region src/services/import/import-service.d.ts
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Options for the import service.
|
|
11
|
+
*/
|
|
12
|
+
interface ImportServiceOptions {
|
|
13
|
+
/** Limit extraction to specific paths */
|
|
14
|
+
scope?: string[];
|
|
15
|
+
/** Force specific framework */
|
|
16
|
+
framework?: string;
|
|
17
|
+
/** Dry run mode - don't write files */
|
|
18
|
+
dryRun?: boolean;
|
|
19
|
+
/** Analysis only - extract IR without generating code */
|
|
20
|
+
analyzeOnly?: boolean;
|
|
21
|
+
/** Output directory for generated contracts */
|
|
22
|
+
outputDir?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Result of the import service.
|
|
26
|
+
*/
|
|
27
|
+
interface ImportServiceResult {
|
|
28
|
+
success: boolean;
|
|
29
|
+
ir?: ImportIR;
|
|
30
|
+
generation?: GenerationResult;
|
|
31
|
+
report: string;
|
|
32
|
+
errors?: string[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Adapters needed by the import service.
|
|
36
|
+
*/
|
|
37
|
+
interface ImportServiceAdapters {
|
|
38
|
+
fs: FsAdapter;
|
|
39
|
+
logger: LoggerAdapter;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Import contracts from source code.
|
|
43
|
+
*/
|
|
44
|
+
declare function importFromSourceService(config: ResolvedContractsrcConfig, options: ImportServiceOptions, adapters: ImportServiceAdapters, cwd?: string): Promise<ImportServiceResult>;
|
|
45
|
+
//#endregion
|
|
46
|
+
export { ImportServiceAdapters, ImportServiceOptions, ImportServiceResult, importFromSourceService };
|
|
47
|
+
//# sourceMappingURL=import-service.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-service.d.mts","names":[],"sources":["../../../src/services/import/import-service.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAkEA;;;AAGY,UAtCK,oBAAA,CAsCL;EAED;EAAR,KAAA,CAAA,EAAA,MAAA,EAAA;EAAO;;;;;;;;;;;;UAxBO,mBAAA;;OAEV;eACQ;;;;;;;UAQE,qBAAA;MACX;UACI;;;;;iBAMY,uBAAA,SACZ,oCACC,gCACC,sCAET,QAAQ"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { dirname, join } from "path";
|
|
2
|
+
import { detectFramework, extractFromProject } from "@contractspec/lib.source-extractors";
|
|
3
|
+
import { registerAllExtractors } from "@contractspec/lib.source-extractors/extractors";
|
|
4
|
+
import { generateOperations, generateRegistry, generateSchemas } from "@contractspec/lib.source-extractors/codegen";
|
|
5
|
+
|
|
6
|
+
//#region src/services/import/import-service.ts
|
|
7
|
+
/**
|
|
8
|
+
* Import contracts from source code.
|
|
9
|
+
*/
|
|
10
|
+
async function importFromSourceService(config, options, adapters, cwd) {
|
|
11
|
+
const { fs, logger } = adapters;
|
|
12
|
+
const rootPath = cwd ?? process.cwd();
|
|
13
|
+
registerAllExtractors();
|
|
14
|
+
logger.info(`Scanning source code in ${rootPath}...`);
|
|
15
|
+
const extractorFs = {
|
|
16
|
+
readFile: (path$1) => fs.readFile(path$1),
|
|
17
|
+
glob: (pattern, opts) => fs.glob({
|
|
18
|
+
pattern,
|
|
19
|
+
cwd: opts?.cwd
|
|
20
|
+
}),
|
|
21
|
+
exists: (path$1) => fs.exists(path$1)
|
|
22
|
+
};
|
|
23
|
+
const project = await detectFramework(rootPath, {
|
|
24
|
+
readFile: (path$1) => fs.readFile(path$1),
|
|
25
|
+
glob: (pattern) => fs.glob({ pattern })
|
|
26
|
+
});
|
|
27
|
+
if (project.frameworks.length === 0) {
|
|
28
|
+
logger.warn("No supported frameworks detected");
|
|
29
|
+
return {
|
|
30
|
+
success: false,
|
|
31
|
+
report: generateNoFrameworkReport(),
|
|
32
|
+
errors: ["No supported frameworks detected in project"]
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
logger.info(`Detected frameworks: ${project.frameworks.map((f) => f.name).join(", ")}`);
|
|
36
|
+
const { extractorRegistry } = await import("@contractspec/lib.source-extractors");
|
|
37
|
+
for (const extractor of extractorRegistry.getAll()) if ("setFs" in extractor && typeof extractor.setFs === "function") extractor.setFs(extractorFs);
|
|
38
|
+
const extractResult = await extractFromProject(project, {
|
|
39
|
+
scope: options.scope,
|
|
40
|
+
framework: options.framework
|
|
41
|
+
});
|
|
42
|
+
if (!extractResult.success || !extractResult.ir) return {
|
|
43
|
+
success: false,
|
|
44
|
+
report: generateErrorReport(extractResult.errors ?? []),
|
|
45
|
+
errors: extractResult.errors?.map((e) => e.message)
|
|
46
|
+
};
|
|
47
|
+
const ir = extractResult.ir;
|
|
48
|
+
logger.info(`Extracted ${ir.endpoints.length} endpoints, ${ir.schemas.length} schemas`);
|
|
49
|
+
if (options.analyzeOnly) return {
|
|
50
|
+
success: true,
|
|
51
|
+
ir,
|
|
52
|
+
report: generateAnalysisReport(ir)
|
|
53
|
+
};
|
|
54
|
+
const outputDir = options.outputDir ?? join(config.outputDir, "generated");
|
|
55
|
+
const generationOptions = {
|
|
56
|
+
outputDir,
|
|
57
|
+
defaultAuth: "user"
|
|
58
|
+
};
|
|
59
|
+
const operationFiles = generateOperations(ir, generationOptions);
|
|
60
|
+
const schemaFiles = generateSchemas(ir, generationOptions);
|
|
61
|
+
const registryFile = generateRegistry(operationFiles);
|
|
62
|
+
const allFiles = [
|
|
63
|
+
...operationFiles,
|
|
64
|
+
...schemaFiles,
|
|
65
|
+
registryFile
|
|
66
|
+
];
|
|
67
|
+
if (!options.dryRun) for (const file of allFiles) {
|
|
68
|
+
const fullPath = join(outputDir, file.path);
|
|
69
|
+
const dir = dirname(fullPath);
|
|
70
|
+
if (!await fs.exists(dir)) await fs.mkdir(dir);
|
|
71
|
+
await fs.writeFile(fullPath, file.content);
|
|
72
|
+
logger.info(`Created: ${fullPath}`);
|
|
73
|
+
}
|
|
74
|
+
else for (const file of allFiles) logger.info(`[DRY RUN] Would create: ${join(outputDir, file.path)}`);
|
|
75
|
+
const generationResult = {
|
|
76
|
+
files: allFiles,
|
|
77
|
+
operationsGenerated: operationFiles.length,
|
|
78
|
+
schemasGenerated: schemaFiles.length,
|
|
79
|
+
warnings: []
|
|
80
|
+
};
|
|
81
|
+
return {
|
|
82
|
+
success: true,
|
|
83
|
+
ir,
|
|
84
|
+
generation: generationResult,
|
|
85
|
+
report: generateSuccessReport(ir, generationResult, options)
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Generate report when no frameworks are detected.
|
|
90
|
+
*/
|
|
91
|
+
function generateNoFrameworkReport() {
|
|
92
|
+
return `# Import Report
|
|
93
|
+
|
|
94
|
+
## ❌ No Supported Frameworks Detected
|
|
95
|
+
|
|
96
|
+
No supported frameworks were detected in the project.
|
|
97
|
+
|
|
98
|
+
### Supported Frameworks
|
|
99
|
+
|
|
100
|
+
- NestJS
|
|
101
|
+
- Express
|
|
102
|
+
- Fastify
|
|
103
|
+
- Hono
|
|
104
|
+
- Elysia
|
|
105
|
+
- tRPC
|
|
106
|
+
- Next.js API Routes
|
|
107
|
+
|
|
108
|
+
Please ensure your project uses one of these frameworks and has the appropriate dependencies installed.
|
|
109
|
+
`;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Generate error report.
|
|
113
|
+
*/
|
|
114
|
+
function generateErrorReport(errors) {
|
|
115
|
+
return `# Import Report
|
|
116
|
+
|
|
117
|
+
## ❌ Extraction Failed
|
|
118
|
+
|
|
119
|
+
${errors.map((e) => `- ${e.message}`).join("\n")}
|
|
120
|
+
`;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Generate analysis-only report.
|
|
124
|
+
*/
|
|
125
|
+
function generateAnalysisReport(ir) {
|
|
126
|
+
return `# Import Analysis Report
|
|
127
|
+
|
|
128
|
+
## Summary
|
|
129
|
+
|
|
130
|
+
- **Files Scanned**: ${ir.stats.filesScanned}
|
|
131
|
+
- **Endpoints Found**: ${ir.stats.endpointsFound}
|
|
132
|
+
- **Schemas Found**: ${ir.stats.schemasFound}
|
|
133
|
+
- **Errors Found**: ${ir.stats.errorsFound}
|
|
134
|
+
- **Events Found**: ${ir.stats.eventsFound}
|
|
135
|
+
|
|
136
|
+
## Confidence Breakdown
|
|
137
|
+
|
|
138
|
+
| Level | Count |
|
|
139
|
+
|-------|-------|
|
|
140
|
+
| High | ${ir.stats.highConfidence} |
|
|
141
|
+
| Medium | ${ir.stats.mediumConfidence} |
|
|
142
|
+
| Low/Ambiguous | ${ir.stats.lowConfidence} |
|
|
143
|
+
|
|
144
|
+
## Detected Frameworks
|
|
145
|
+
|
|
146
|
+
${ir.project.frameworks.map((f) => `- ${f.name} (${f.confidence})`).join("\n")}
|
|
147
|
+
|
|
148
|
+
## Endpoints
|
|
149
|
+
|
|
150
|
+
${ir.endpoints.map((e) => `- \`${e.method} ${e.path}\` - ${e.confidence.level}`).join("\n")}
|
|
151
|
+
|
|
152
|
+
## Ambiguities (Require Review)
|
|
153
|
+
|
|
154
|
+
${ir.ambiguities.length > 0 ? ir.ambiguities.map((a) => `- ${a.description}`).join("\n") : "None"}
|
|
155
|
+
`;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Generate success report.
|
|
159
|
+
*/
|
|
160
|
+
function generateSuccessReport(ir, gen, options) {
|
|
161
|
+
return `# Import Report${options.dryRun ? " (Dry Run)" : ""}
|
|
162
|
+
|
|
163
|
+
## ✅ Import Successful
|
|
164
|
+
|
|
165
|
+
### Extraction Summary
|
|
166
|
+
|
|
167
|
+
- **Files Scanned**: ${ir.stats.filesScanned}
|
|
168
|
+
- **Endpoints Found**: ${ir.stats.endpointsFound}
|
|
169
|
+
- **Schemas Found**: ${ir.stats.schemasFound}
|
|
170
|
+
|
|
171
|
+
### Generation Summary
|
|
172
|
+
|
|
173
|
+
- **Operations Generated**: ${gen.operationsGenerated}
|
|
174
|
+
- **Schemas Generated**: ${gen.schemasGenerated}
|
|
175
|
+
- **Total Files**: ${gen.files.length}
|
|
176
|
+
|
|
177
|
+
### Confidence Breakdown
|
|
178
|
+
|
|
179
|
+
| Level | Count |
|
|
180
|
+
|-------|-------|
|
|
181
|
+
| High | ${ir.stats.highConfidence} |
|
|
182
|
+
| Medium | ${ir.stats.mediumConfidence} |
|
|
183
|
+
| Low/Ambiguous | ${ir.stats.lowConfidence} |
|
|
184
|
+
|
|
185
|
+
### Next Steps
|
|
186
|
+
|
|
187
|
+
1. Review generated contracts in \`${options.outputDir ?? "generated/"}\`
|
|
188
|
+
2. Fill in TODO placeholders with business context
|
|
189
|
+
3. Run \`contractspec validate\` to verify contracts
|
|
190
|
+
4. Move stable contracts from \`generated/\` to \`curated/\`
|
|
191
|
+
`;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
//#endregion
|
|
195
|
+
export { importFromSourceService };
|
|
196
|
+
//# sourceMappingURL=import-service.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-service.mjs","names":["path"],"sources":["../../../src/services/import/import-service.ts"],"sourcesContent":["/**\n * Import service for source-extractors.\n *\n * Integrates source extraction into the workspace bundle.\n */\n\nimport type { FsAdapter } from '../../ports/fs';\nimport type { LoggerAdapter } from '../../ports/logger';\nimport type { ResolvedContractsrcConfig } from '@contractspec/lib.contracts';\nimport {\n detectFramework,\n extractFromProject,\n type ExtractOptions,\n type ImportIR,\n} from '@contractspec/lib.source-extractors';\nimport {\n type ExtractorFsAdapter,\n registerAllExtractors,\n} from '@contractspec/lib.source-extractors/extractors';\nimport {\n generateOperations,\n generateRegistry,\n generateSchemas,\n type GenerationOptions,\n type GenerationResult,\n} from '@contractspec/lib.source-extractors/codegen';\nimport { dirname, join } from 'path';\n\n/**\n * Options for the import service.\n */\nexport interface ImportServiceOptions {\n /** Limit extraction to specific paths */\n scope?: string[];\n /** Force specific framework */\n framework?: string;\n /** Dry run mode - don't write files */\n dryRun?: boolean;\n /** Analysis only - extract IR without generating code */\n analyzeOnly?: boolean;\n /** Output directory for generated contracts */\n outputDir?: string;\n}\n\n/**\n * Result of the import service.\n */\nexport interface ImportServiceResult {\n success: boolean;\n ir?: ImportIR;\n generation?: GenerationResult;\n report: string;\n errors?: string[];\n}\n\n/**\n * Adapters needed by the import service.\n */\nexport interface ImportServiceAdapters {\n fs: FsAdapter;\n logger: LoggerAdapter;\n}\n\n/**\n * Import contracts from source code.\n */\nexport async function importFromSourceService(\n config: ResolvedContractsrcConfig,\n options: ImportServiceOptions,\n adapters: ImportServiceAdapters,\n cwd?: string\n): Promise<ImportServiceResult> {\n const { fs, logger } = adapters;\n const rootPath = cwd ?? process.cwd();\n\n // Register all extractors\n registerAllExtractors();\n\n logger.info(`Scanning source code in ${rootPath}...`);\n\n // Create adapter bridge\n const extractorFs: ExtractorFsAdapter = {\n readFile: (path) => fs.readFile(path),\n glob: (pattern, opts) => fs.glob({ pattern, cwd: opts?.cwd }),\n exists: (path) => fs.exists(path),\n };\n\n // Detect frameworks\n const project = await detectFramework(rootPath, {\n readFile: (path) => fs.readFile(path),\n glob: (pattern) => fs.glob({ pattern }),\n });\n\n if (project.frameworks.length === 0) {\n logger.warn('No supported frameworks detected');\n return {\n success: false,\n report: generateNoFrameworkReport(),\n errors: ['No supported frameworks detected in project'],\n };\n }\n\n logger.info(\n `Detected frameworks: ${project.frameworks.map((f) => f.name).join(', ')}`\n );\n\n // Set up extractors with fs adapter\n const { extractorRegistry } =\n await import('@contractspec/lib.source-extractors');\n for (const extractor of extractorRegistry.getAll()) {\n if ('setFs' in extractor && typeof extractor.setFs === 'function') {\n extractor.setFs(extractorFs);\n }\n }\n\n // Extract contracts\n const extractOptions: ExtractOptions = {\n scope: options.scope,\n framework: options.framework,\n };\n\n const extractResult = await extractFromProject(project, extractOptions);\n\n if (!extractResult.success || !extractResult.ir) {\n return {\n success: false,\n report: generateErrorReport(extractResult.errors ?? []),\n errors: extractResult.errors?.map((e) => e.message),\n };\n }\n\n const ir = extractResult.ir;\n\n logger.info(\n `Extracted ${ir.endpoints.length} endpoints, ${ir.schemas.length} schemas`\n );\n\n // If analyze-only mode, just return the IR\n if (options.analyzeOnly) {\n return {\n success: true,\n ir,\n report: generateAnalysisReport(ir),\n };\n }\n\n // Generate code\n const outputDir = options.outputDir ?? join(config.outputDir, 'generated');\n const generationOptions: GenerationOptions = {\n outputDir,\n defaultAuth: 'user',\n };\n\n const operationFiles = generateOperations(ir, generationOptions);\n const schemaFiles = generateSchemas(ir, generationOptions);\n const registryFile = generateRegistry(operationFiles);\n\n const allFiles = [...operationFiles, ...schemaFiles, registryFile];\n\n // Write files if not dry-run\n if (!options.dryRun) {\n for (const file of allFiles) {\n const fullPath = join(outputDir, file.path);\n const dir = dirname(fullPath);\n\n if (!(await fs.exists(dir))) {\n await fs.mkdir(dir);\n }\n\n await fs.writeFile(fullPath, file.content);\n logger.info(`Created: ${fullPath}`);\n }\n } else {\n for (const file of allFiles) {\n logger.info(`[DRY RUN] Would create: ${join(outputDir, file.path)}`);\n }\n }\n\n const generationResult: GenerationResult = {\n files: allFiles,\n operationsGenerated: operationFiles.length,\n schemasGenerated: schemaFiles.length,\n warnings: [],\n };\n\n return {\n success: true,\n ir,\n generation: generationResult,\n report: generateSuccessReport(ir, generationResult, options),\n };\n}\n\n/**\n * Generate report when no frameworks are detected.\n */\nfunction generateNoFrameworkReport(): string {\n return `# Import Report\n\n## ❌ No Supported Frameworks Detected\n\nNo supported frameworks were detected in the project.\n\n### Supported Frameworks\n\n- NestJS\n- Express\n- Fastify\n- Hono\n- Elysia\n- tRPC\n- Next.js API Routes\n\nPlease ensure your project uses one of these frameworks and has the appropriate dependencies installed.\n`;\n}\n\n/**\n * Generate error report.\n */\nfunction generateErrorReport(errors: { message: string }[]): string {\n return `# Import Report\n\n## ❌ Extraction Failed\n\n${errors.map((e) => `- ${e.message}`).join('\\n')}\n`;\n}\n\n/**\n * Generate analysis-only report.\n */\nfunction generateAnalysisReport(ir: ImportIR): string {\n return `# Import Analysis Report\n\n## Summary\n\n- **Files Scanned**: ${ir.stats.filesScanned}\n- **Endpoints Found**: ${ir.stats.endpointsFound}\n- **Schemas Found**: ${ir.stats.schemasFound}\n- **Errors Found**: ${ir.stats.errorsFound}\n- **Events Found**: ${ir.stats.eventsFound}\n\n## Confidence Breakdown\n\n| Level | Count |\n|-------|-------|\n| High | ${ir.stats.highConfidence} |\n| Medium | ${ir.stats.mediumConfidence} |\n| Low/Ambiguous | ${ir.stats.lowConfidence} |\n\n## Detected Frameworks\n\n${ir.project.frameworks.map((f) => `- ${f.name} (${f.confidence})`).join('\\n')}\n\n## Endpoints\n\n${ir.endpoints.map((e) => `- \\`${e.method} ${e.path}\\` - ${e.confidence.level}`).join('\\n')}\n\n## Ambiguities (Require Review)\n\n${ir.ambiguities.length > 0 ? ir.ambiguities.map((a) => `- ${a.description}`).join('\\n') : 'None'}\n`;\n}\n\n/**\n * Generate success report.\n */\nfunction generateSuccessReport(\n ir: ImportIR,\n gen: GenerationResult,\n options: ImportServiceOptions\n): string {\n const mode = options.dryRun ? ' (Dry Run)' : '';\n return `# Import Report${mode}\n\n## ✅ Import Successful\n\n### Extraction Summary\n\n- **Files Scanned**: ${ir.stats.filesScanned}\n- **Endpoints Found**: ${ir.stats.endpointsFound}\n- **Schemas Found**: ${ir.stats.schemasFound}\n\n### Generation Summary\n\n- **Operations Generated**: ${gen.operationsGenerated}\n- **Schemas Generated**: ${gen.schemasGenerated}\n- **Total Files**: ${gen.files.length}\n\n### Confidence Breakdown\n\n| Level | Count |\n|-------|-------|\n| High | ${ir.stats.highConfidence} |\n| Medium | ${ir.stats.mediumConfidence} |\n| Low/Ambiguous | ${ir.stats.lowConfidence} |\n\n### Next Steps\n\n1. Review generated contracts in \\`${options.outputDir ?? 'generated/'}\\`\n2. Fill in TODO placeholders with business context\n3. Run \\`contractspec validate\\` to verify contracts\n4. Move stable contracts from \\`generated/\\` to \\`curated/\\`\n`;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { ImportServiceAdapters, ImportServiceOptions, ImportServiceResult, importFromSourceService } from "./import-service.mjs";
|
|
2
|
+
import { EndpointVerification, VerificationIssue, VerifyOptions, VerifyResult, verifyImportedContracts } from "./verify-service.mjs";
|
|
3
|
+
import { ReportOptions, generateCliReport, generateMarkdownReport } from "./report-service.mjs";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { VerifyResult } from "./verify-service.mjs";
|
|
2
|
+
import { ImportIR } from "@contractspec/lib.source-extractors";
|
|
3
|
+
|
|
4
|
+
//#region src/services/import/report-service.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Options for report generation.
|
|
8
|
+
*/
|
|
9
|
+
interface ReportOptions {
|
|
10
|
+
/** Include endpoint details */
|
|
11
|
+
includeEndpoints?: boolean;
|
|
12
|
+
/** Include schema details */
|
|
13
|
+
includeSchemas?: boolean;
|
|
14
|
+
/** Include verification issues */
|
|
15
|
+
includeIssues?: boolean;
|
|
16
|
+
/** Include ambiguities */
|
|
17
|
+
includeAmbiguities?: boolean;
|
|
18
|
+
/** Include statistics */
|
|
19
|
+
includeStats?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Generate a markdown report from IR and optional verification.
|
|
23
|
+
*/
|
|
24
|
+
declare function generateMarkdownReport(ir: ImportIR, verification?: VerifyResult, options?: ReportOptions): string;
|
|
25
|
+
/**
|
|
26
|
+
* Generate CLI-friendly report output.
|
|
27
|
+
*/
|
|
28
|
+
declare function generateCliReport(ir: ImportIR, verification?: VerifyResult): string;
|
|
29
|
+
//#endregion
|
|
30
|
+
export { ReportOptions, generateCliReport, generateMarkdownReport };
|
|
31
|
+
//# sourceMappingURL=report-service.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report-service.d.mts","names":[],"sources":["../../../src/services/import/report-service.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAoKgB,UAxJC,aAAA,CAwJgB;;;;;;;;;;;;;;;iBAxIjB,sBAAA,KACV,yBACW,wBACN;;;;iBAqIK,iBAAA,KACV,yBACW"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
//#region src/services/import/report-service.ts
|
|
2
|
+
/**
|
|
3
|
+
* Generate a markdown report from IR and optional verification.
|
|
4
|
+
*/
|
|
5
|
+
function generateMarkdownReport(ir, verification, options = {}) {
|
|
6
|
+
const lines = [];
|
|
7
|
+
lines.push("# Import Report");
|
|
8
|
+
lines.push("");
|
|
9
|
+
lines.push(`**Generated**: ${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
10
|
+
lines.push("");
|
|
11
|
+
lines.push("## Summary");
|
|
12
|
+
lines.push("");
|
|
13
|
+
lines.push(`| Metric | Count |`);
|
|
14
|
+
lines.push(`|--------|-------|`);
|
|
15
|
+
lines.push(`| Files Scanned | ${ir.stats.filesScanned} |`);
|
|
16
|
+
lines.push(`| Endpoints Found | ${ir.stats.endpointsFound} |`);
|
|
17
|
+
lines.push(`| Schemas Found | ${ir.stats.schemasFound} |`);
|
|
18
|
+
lines.push(`| Errors Found | ${ir.stats.errorsFound} |`);
|
|
19
|
+
lines.push(`| Events Found | ${ir.stats.eventsFound} |`);
|
|
20
|
+
lines.push("");
|
|
21
|
+
if (options.includeStats !== false) {
|
|
22
|
+
lines.push("### Confidence");
|
|
23
|
+
lines.push("");
|
|
24
|
+
lines.push(`| Level | Count |`);
|
|
25
|
+
lines.push(`|-------|-------|`);
|
|
26
|
+
lines.push(`| High | ${ir.stats.highConfidence} |`);
|
|
27
|
+
lines.push(`| Medium | ${ir.stats.mediumConfidence} |`);
|
|
28
|
+
lines.push(`| Low/Ambiguous | ${ir.stats.lowConfidence} |`);
|
|
29
|
+
lines.push("");
|
|
30
|
+
}
|
|
31
|
+
lines.push("### Frameworks Detected");
|
|
32
|
+
lines.push("");
|
|
33
|
+
for (const fw of ir.project.frameworks) lines.push(`- **${fw.name}** (${fw.confidence})`);
|
|
34
|
+
lines.push("");
|
|
35
|
+
if (options.includeEndpoints !== false && ir.endpoints.length > 0) {
|
|
36
|
+
lines.push("## Endpoints");
|
|
37
|
+
lines.push("");
|
|
38
|
+
lines.push("| Method | Path | Kind | Confidence |");
|
|
39
|
+
lines.push("|--------|------|------|------------|");
|
|
40
|
+
for (const ep of ir.endpoints) lines.push(`| ${ep.method} | \`${ep.path}\` | ${ep.kind} | ${ep.confidence.level} |`);
|
|
41
|
+
lines.push("");
|
|
42
|
+
}
|
|
43
|
+
if (options.includeSchemas !== false && ir.schemas.length > 0) {
|
|
44
|
+
lines.push("## Schemas");
|
|
45
|
+
lines.push("");
|
|
46
|
+
lines.push("| Name | Type | Confidence |");
|
|
47
|
+
lines.push("|------|------|------------|");
|
|
48
|
+
for (const schema of ir.schemas) lines.push(`| ${schema.name} | ${schema.schemaType} | ${schema.confidence.level} |`);
|
|
49
|
+
lines.push("");
|
|
50
|
+
}
|
|
51
|
+
if (verification && options.includeIssues !== false) {
|
|
52
|
+
lines.push("## Verification");
|
|
53
|
+
lines.push("");
|
|
54
|
+
lines.push(`| Status | Count |`);
|
|
55
|
+
lines.push(`|--------|-------|`);
|
|
56
|
+
lines.push(`| Valid | ${verification.summary.validEndpoints} |`);
|
|
57
|
+
lines.push(`| Warnings | ${verification.summary.warningEndpoints} |`);
|
|
58
|
+
lines.push(`| Errors | ${verification.summary.errorEndpoints} |`);
|
|
59
|
+
lines.push("");
|
|
60
|
+
const issueEndpoints = verification.endpointResults.filter((r) => r.issues.length > 0);
|
|
61
|
+
if (issueEndpoints.length > 0) {
|
|
62
|
+
lines.push("### Issues");
|
|
63
|
+
lines.push("");
|
|
64
|
+
for (const result of issueEndpoints) {
|
|
65
|
+
lines.push(`#### ${result.endpoint.method} ${result.endpoint.path}`);
|
|
66
|
+
for (const issue of result.issues) {
|
|
67
|
+
const icon = issue.severity === "error" ? "❌" : issue.severity === "warning" ? "⚠️" : "ℹ️";
|
|
68
|
+
lines.push(`- ${icon} **${issue.code}**: ${issue.message}`);
|
|
69
|
+
if (issue.suggestion) lines.push(` - *Suggestion*: ${issue.suggestion}`);
|
|
70
|
+
}
|
|
71
|
+
lines.push("");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (options.includeAmbiguities !== false && ir.ambiguities.length > 0) {
|
|
76
|
+
lines.push("## Ambiguities (Require Review)");
|
|
77
|
+
lines.push("");
|
|
78
|
+
for (const amb of ir.ambiguities) {
|
|
79
|
+
lines.push(`- **${amb.type}** (${amb.itemId}): ${amb.description}`);
|
|
80
|
+
if (amb.suggestion) lines.push(` - *Suggestion*: ${amb.suggestion}`);
|
|
81
|
+
}
|
|
82
|
+
lines.push("");
|
|
83
|
+
}
|
|
84
|
+
lines.push("## Next Steps");
|
|
85
|
+
lines.push("");
|
|
86
|
+
lines.push("1. Review generated contracts in the output directory");
|
|
87
|
+
lines.push("2. Fill in TODO placeholders with business context");
|
|
88
|
+
lines.push("3. Run `contractspec validate` to verify contracts");
|
|
89
|
+
lines.push("4. Move stable contracts from `generated/` to `curated/`");
|
|
90
|
+
lines.push("");
|
|
91
|
+
return lines.join("\n");
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Generate CLI-friendly report output.
|
|
95
|
+
*/
|
|
96
|
+
function generateCliReport(ir, verification) {
|
|
97
|
+
const lines = [];
|
|
98
|
+
lines.push("");
|
|
99
|
+
lines.push("📊 Summary");
|
|
100
|
+
lines.push(` Files scanned: ${ir.stats.filesScanned}`);
|
|
101
|
+
lines.push(` Endpoints: ${ir.stats.endpointsFound}`);
|
|
102
|
+
lines.push(` Schemas: ${ir.stats.schemasFound}`);
|
|
103
|
+
lines.push("");
|
|
104
|
+
lines.push("📈 Confidence");
|
|
105
|
+
lines.push(` High: ${ir.stats.highConfidence}`);
|
|
106
|
+
lines.push(` Medium: ${ir.stats.mediumConfidence}`);
|
|
107
|
+
lines.push(` Low: ${ir.stats.lowConfidence}`);
|
|
108
|
+
lines.push("");
|
|
109
|
+
lines.push("🔧 Frameworks");
|
|
110
|
+
for (const fw of ir.project.frameworks) lines.push(` • ${fw.name}`);
|
|
111
|
+
lines.push("");
|
|
112
|
+
if (verification) {
|
|
113
|
+
lines.push("✅ Verification");
|
|
114
|
+
lines.push(` Valid: ${verification.summary.validEndpoints}`);
|
|
115
|
+
lines.push(` Warnings: ${verification.summary.warningEndpoints}`);
|
|
116
|
+
lines.push(` Errors: ${verification.summary.errorEndpoints}`);
|
|
117
|
+
lines.push("");
|
|
118
|
+
}
|
|
119
|
+
return lines.join("\n");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
//#endregion
|
|
123
|
+
export { generateCliReport, generateMarkdownReport };
|
|
124
|
+
//# sourceMappingURL=report-service.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report-service.mjs","names":[],"sources":["../../../src/services/import/report-service.ts"],"sourcesContent":["/**\n * Report service for imported contracts.\n *\n * Generates markdown and CLI reports from IR and verification results.\n */\n\nimport type { ImportIR } from '@contractspec/lib.source-extractors';\nimport type { VerifyResult } from './verify-service';\n\n/**\n * Options for report generation.\n */\nexport interface ReportOptions {\n /** Include endpoint details */\n includeEndpoints?: boolean;\n /** Include schema details */\n includeSchemas?: boolean;\n /** Include verification issues */\n includeIssues?: boolean;\n /** Include ambiguities */\n includeAmbiguities?: boolean;\n /** Include statistics */\n includeStats?: boolean;\n}\n\n/**\n * Generate a markdown report from IR and optional verification.\n */\nexport function generateMarkdownReport(\n ir: ImportIR,\n verification?: VerifyResult,\n options: ReportOptions = {}\n): string {\n const lines: string[] = [];\n\n lines.push('# Import Report');\n lines.push('');\n lines.push(`**Generated**: ${new Date().toISOString()}`);\n lines.push('');\n\n // Summary section\n lines.push('## Summary');\n lines.push('');\n lines.push(`| Metric | Count |`);\n lines.push(`|--------|-------|`);\n lines.push(`| Files Scanned | ${ir.stats.filesScanned} |`);\n lines.push(`| Endpoints Found | ${ir.stats.endpointsFound} |`);\n lines.push(`| Schemas Found | ${ir.stats.schemasFound} |`);\n lines.push(`| Errors Found | ${ir.stats.errorsFound} |`);\n lines.push(`| Events Found | ${ir.stats.eventsFound} |`);\n lines.push('');\n\n // Confidence breakdown\n if (options.includeStats !== false) {\n lines.push('### Confidence');\n lines.push('');\n lines.push(`| Level | Count |`);\n lines.push(`|-------|-------|`);\n lines.push(`| High | ${ir.stats.highConfidence} |`);\n lines.push(`| Medium | ${ir.stats.mediumConfidence} |`);\n lines.push(`| Low/Ambiguous | ${ir.stats.lowConfidence} |`);\n lines.push('');\n }\n\n // Frameworks detected\n lines.push('### Frameworks Detected');\n lines.push('');\n for (const fw of ir.project.frameworks) {\n lines.push(`- **${fw.name}** (${fw.confidence})`);\n }\n lines.push('');\n\n // Endpoints section\n if (options.includeEndpoints !== false && ir.endpoints.length > 0) {\n lines.push('## Endpoints');\n lines.push('');\n lines.push('| Method | Path | Kind | Confidence |');\n lines.push('|--------|------|------|------------|');\n for (const ep of ir.endpoints) {\n lines.push(\n `| ${ep.method} | \\`${ep.path}\\` | ${ep.kind} | ${ep.confidence.level} |`\n );\n }\n lines.push('');\n }\n\n // Schemas section\n if (options.includeSchemas !== false && ir.schemas.length > 0) {\n lines.push('## Schemas');\n lines.push('');\n lines.push('| Name | Type | Confidence |');\n lines.push('|------|------|------------|');\n for (const schema of ir.schemas) {\n lines.push(\n `| ${schema.name} | ${schema.schemaType} | ${schema.confidence.level} |`\n );\n }\n lines.push('');\n }\n\n // Verification results\n if (verification && options.includeIssues !== false) {\n lines.push('## Verification');\n lines.push('');\n lines.push(`| Status | Count |`);\n lines.push(`|--------|-------|`);\n lines.push(`| Valid | ${verification.summary.validEndpoints} |`);\n lines.push(`| Warnings | ${verification.summary.warningEndpoints} |`);\n lines.push(`| Errors | ${verification.summary.errorEndpoints} |`);\n lines.push('');\n\n const issueEndpoints = verification.endpointResults.filter(\n (r) => r.issues.length > 0\n );\n if (issueEndpoints.length > 0) {\n lines.push('### Issues');\n lines.push('');\n for (const result of issueEndpoints) {\n lines.push(`#### ${result.endpoint.method} ${result.endpoint.path}`);\n for (const issue of result.issues) {\n const icon =\n issue.severity === 'error'\n ? '❌'\n : issue.severity === 'warning'\n ? '⚠️'\n : 'ℹ️';\n lines.push(`- ${icon} **${issue.code}**: ${issue.message}`);\n if (issue.suggestion) {\n lines.push(` - *Suggestion*: ${issue.suggestion}`);\n }\n }\n lines.push('');\n }\n }\n }\n\n // Ambiguities section\n if (options.includeAmbiguities !== false && ir.ambiguities.length > 0) {\n lines.push('## Ambiguities (Require Review)');\n lines.push('');\n for (const amb of ir.ambiguities) {\n lines.push(`- **${amb.type}** (${amb.itemId}): ${amb.description}`);\n if (amb.suggestion) {\n lines.push(` - *Suggestion*: ${amb.suggestion}`);\n }\n }\n lines.push('');\n }\n\n // Next steps\n lines.push('## Next Steps');\n lines.push('');\n lines.push('1. Review generated contracts in the output directory');\n lines.push('2. Fill in TODO placeholders with business context');\n lines.push('3. Run `contractspec validate` to verify contracts');\n lines.push('4. Move stable contracts from `generated/` to `curated/`');\n lines.push('');\n\n return lines.join('\\n');\n}\n\n/**\n * Generate CLI-friendly report output.\n */\nexport function generateCliReport(\n ir: ImportIR,\n verification?: VerifyResult\n): string {\n const lines: string[] = [];\n\n // Summary\n lines.push('');\n lines.push('📊 Summary');\n lines.push(` Files scanned: ${ir.stats.filesScanned}`);\n lines.push(` Endpoints: ${ir.stats.endpointsFound}`);\n lines.push(` Schemas: ${ir.stats.schemasFound}`);\n lines.push('');\n\n // Confidence\n lines.push('📈 Confidence');\n lines.push(` High: ${ir.stats.highConfidence}`);\n lines.push(` Medium: ${ir.stats.mediumConfidence}`);\n lines.push(` Low: ${ir.stats.lowConfidence}`);\n lines.push('');\n\n // Frameworks\n lines.push('🔧 Frameworks');\n for (const fw of ir.project.frameworks) {\n lines.push(` • ${fw.name}`);\n }\n lines.push('');\n\n // Verification\n if (verification) {\n lines.push('✅ Verification');\n lines.push(` Valid: ${verification.summary.validEndpoints}`);\n lines.push(` Warnings: ${verification.summary.warningEndpoints}`);\n lines.push(` Errors: ${verification.summary.errorEndpoints}`);\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { FsAdapter } from "../../ports/fs.mjs";
|
|
2
|
+
import { LoggerAdapter } from "../../ports/logger.mjs";
|
|
3
|
+
import { Ambiguity, EndpointCandidate, ImportIR } from "@contractspec/lib.source-extractors";
|
|
4
|
+
|
|
5
|
+
//#region src/services/import/verify-service.d.ts
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Verification result for a single endpoint.
|
|
9
|
+
*/
|
|
10
|
+
interface EndpointVerification {
|
|
11
|
+
endpoint: EndpointCandidate;
|
|
12
|
+
status: 'valid' | 'warning' | 'error';
|
|
13
|
+
issues: VerificationIssue[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A single verification issue.
|
|
17
|
+
*/
|
|
18
|
+
interface VerificationIssue {
|
|
19
|
+
code: string;
|
|
20
|
+
message: string;
|
|
21
|
+
severity: 'error' | 'warning' | 'info';
|
|
22
|
+
suggestion?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Options for verification.
|
|
26
|
+
*/
|
|
27
|
+
interface VerifyOptions {
|
|
28
|
+
/** Check for duplicate endpoints */
|
|
29
|
+
checkDuplicates?: boolean;
|
|
30
|
+
/** Check for conflicting paths */
|
|
31
|
+
checkConflicts?: boolean;
|
|
32
|
+
/** Validate schema completeness */
|
|
33
|
+
validateSchemas?: boolean;
|
|
34
|
+
/** Compare against existing specs */
|
|
35
|
+
compareExisting?: boolean;
|
|
36
|
+
/** Path to existing specs */
|
|
37
|
+
existingSpecsPath?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Result of verification.
|
|
41
|
+
*/
|
|
42
|
+
interface VerifyResult {
|
|
43
|
+
valid: boolean;
|
|
44
|
+
endpointResults: EndpointVerification[];
|
|
45
|
+
ambiguities: Ambiguity[];
|
|
46
|
+
summary: {
|
|
47
|
+
totalEndpoints: number;
|
|
48
|
+
validEndpoints: number;
|
|
49
|
+
warningEndpoints: number;
|
|
50
|
+
errorEndpoints: number;
|
|
51
|
+
totalIssues: number;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Adapters for verification service.
|
|
56
|
+
*/
|
|
57
|
+
interface VerifyServiceAdapters {
|
|
58
|
+
fs: FsAdapter;
|
|
59
|
+
logger: LoggerAdapter;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Verify extracted contracts from IR.
|
|
63
|
+
*/
|
|
64
|
+
declare function verifyImportedContracts(ir: ImportIR, options: VerifyOptions, adapters: VerifyServiceAdapters): Promise<VerifyResult>;
|
|
65
|
+
//#endregion
|
|
66
|
+
export { EndpointVerification, VerificationIssue, VerifyOptions, VerifyResult, verifyImportedContracts };
|
|
67
|
+
//# sourceMappingURL=verify-service.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-service.d.mts","names":[],"sources":["../../../src/services/import/verify-service.ts"],"sourcesContent":[],"mappings":";;;;;;AAoDA;AAgBA;AAQA;AACM,UA5DW,oBAAA,CA4DX;EACK,QAAA,EA5DC,iBA4DD;EACC,MAAA,EAAA,OAAA,GAAA,SAAA,GAAA,OAAA;EACD,MAAA,EA5DD,iBA4DC,EAAA;;;;;UAtDM,iBAAA;;;;;;;;;UAUA,aAAA;;;;;;;;;;;;;;;UAgBA,YAAA;;mBAEE;eACJ;;;;;;;;;;;;UAaE,qBAAA;MACX;UACI;;;;;iBAMY,uBAAA,KAChB,mBACK,yBACC,wBACT,QAAQ"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
//#region src/services/import/verify-service.ts
|
|
2
|
+
/**
|
|
3
|
+
* Verify extracted contracts from IR.
|
|
4
|
+
*/
|
|
5
|
+
async function verifyImportedContracts(ir, options, adapters) {
|
|
6
|
+
const { logger } = adapters;
|
|
7
|
+
const endpointResults = [];
|
|
8
|
+
const ambiguities = [...ir.ambiguities];
|
|
9
|
+
logger.info(`Verifying ${ir.endpoints.length} endpoints...`);
|
|
10
|
+
for (const endpoint of ir.endpoints) {
|
|
11
|
+
const issues = [];
|
|
12
|
+
if (endpoint.confidence.level === "low" || endpoint.confidence.level === "ambiguous") issues.push({
|
|
13
|
+
code: "LOW_CONFIDENCE",
|
|
14
|
+
message: `Endpoint has ${endpoint.confidence.level} confidence`,
|
|
15
|
+
severity: "warning",
|
|
16
|
+
suggestion: "Review source code and add explicit schema annotations"
|
|
17
|
+
});
|
|
18
|
+
if (!endpoint.input && (endpoint.method === "POST" || endpoint.method === "PUT" || endpoint.method === "PATCH")) issues.push({
|
|
19
|
+
code: "MISSING_INPUT_SCHEMA",
|
|
20
|
+
message: "Command endpoint missing input schema",
|
|
21
|
+
severity: "warning",
|
|
22
|
+
suggestion: "Add Zod schema or class-validator DTO"
|
|
23
|
+
});
|
|
24
|
+
if (!endpoint.output) issues.push({
|
|
25
|
+
code: "MISSING_OUTPUT_SCHEMA",
|
|
26
|
+
message: "Endpoint missing output schema",
|
|
27
|
+
severity: "info",
|
|
28
|
+
suggestion: "Infer from return type or add explicit schema"
|
|
29
|
+
});
|
|
30
|
+
if (options.checkDuplicates) {
|
|
31
|
+
if (ir.endpoints.filter((e) => e.id !== endpoint.id && e.path === endpoint.path && e.method === endpoint.method).length > 0) issues.push({
|
|
32
|
+
code: "DUPLICATE_ENDPOINT",
|
|
33
|
+
message: `Duplicate ${endpoint.method} ${endpoint.path} found`,
|
|
34
|
+
severity: "error"
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
if (options.checkConflicts) {
|
|
38
|
+
const conflicts = findPathConflicts(endpoint, ir.endpoints);
|
|
39
|
+
for (const conflict of conflicts) issues.push({
|
|
40
|
+
code: "PATH_CONFLICT",
|
|
41
|
+
message: `Path may conflict with ${conflict.method} ${conflict.path}`,
|
|
42
|
+
severity: "warning"
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
const status = issues.some((i) => i.severity === "error") ? "error" : issues.some((i) => i.severity === "warning") ? "warning" : "valid";
|
|
46
|
+
endpointResults.push({
|
|
47
|
+
endpoint,
|
|
48
|
+
status,
|
|
49
|
+
issues
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
if (options.validateSchemas) {
|
|
53
|
+
for (const schema of ir.schemas) if (!schema.fields || schema.fields.length === 0) ambiguities.push({
|
|
54
|
+
type: "schema",
|
|
55
|
+
itemId: schema.id,
|
|
56
|
+
description: `Schema ${schema.name} has no extracted fields`,
|
|
57
|
+
suggestion: "Review schema definition and add explicit field types",
|
|
58
|
+
source: schema.source
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
const summary = {
|
|
62
|
+
totalEndpoints: endpointResults.length,
|
|
63
|
+
validEndpoints: endpointResults.filter((r) => r.status === "valid").length,
|
|
64
|
+
warningEndpoints: endpointResults.filter((r) => r.status === "warning").length,
|
|
65
|
+
errorEndpoints: endpointResults.filter((r) => r.status === "error").length,
|
|
66
|
+
totalIssues: endpointResults.reduce((sum, r) => sum + r.issues.length, 0)
|
|
67
|
+
};
|
|
68
|
+
logger.info(`Verification complete: ${summary.validEndpoints} valid, ${summary.warningEndpoints} warnings, ${summary.errorEndpoints} errors`);
|
|
69
|
+
return {
|
|
70
|
+
valid: summary.errorEndpoints === 0,
|
|
71
|
+
endpointResults,
|
|
72
|
+
ambiguities,
|
|
73
|
+
summary
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Find path conflicts (e.g., /users/:id vs /users/profile).
|
|
78
|
+
*/
|
|
79
|
+
function findPathConflicts(endpoint, allEndpoints) {
|
|
80
|
+
const conflicts = [];
|
|
81
|
+
const endpointParts = endpoint.path.split("/").filter(Boolean);
|
|
82
|
+
for (const other of allEndpoints) {
|
|
83
|
+
if (other.id === endpoint.id) continue;
|
|
84
|
+
if (other.method !== endpoint.method) continue;
|
|
85
|
+
const otherParts = other.path.split("/").filter(Boolean);
|
|
86
|
+
if (otherParts.length !== endpointParts.length) continue;
|
|
87
|
+
let mightConflict = true;
|
|
88
|
+
for (let i = 0; i < endpointParts.length; i++) {
|
|
89
|
+
const a = endpointParts[i] ?? "";
|
|
90
|
+
const b = otherParts[i] ?? "";
|
|
91
|
+
const aIsParam = a.startsWith(":") || a.startsWith("{");
|
|
92
|
+
const bIsParam = b.startsWith(":") || b.startsWith("{");
|
|
93
|
+
if (!aIsParam && !bIsParam && a !== b) {
|
|
94
|
+
mightConflict = false;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (mightConflict && endpoint.path !== other.path) conflicts.push(other);
|
|
99
|
+
}
|
|
100
|
+
return conflicts;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
//#endregion
|
|
104
|
+
export { verifyImportedContracts };
|
|
105
|
+
//# sourceMappingURL=verify-service.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-service.mjs","names":[],"sources":["../../../src/services/import/verify-service.ts"],"sourcesContent":["/**\n * Verify service for imported contracts.\n *\n * Validates extracted contracts against existing codebase and specs.\n */\n\nimport type {\n ImportIR,\n EndpointCandidate,\n Ambiguity,\n} from '@contractspec/lib.source-extractors';\nimport type { FsAdapter } from '../../ports/fs';\nimport type { LoggerAdapter } from '../../ports/logger';\n\n/**\n * Verification result for a single endpoint.\n */\nexport interface EndpointVerification {\n endpoint: EndpointCandidate;\n status: 'valid' | 'warning' | 'error';\n issues: VerificationIssue[];\n}\n\n/**\n * A single verification issue.\n */\nexport interface VerificationIssue {\n code: string;\n message: string;\n severity: 'error' | 'warning' | 'info';\n suggestion?: string;\n}\n\n/**\n * Options for verification.\n */\nexport interface VerifyOptions {\n /** Check for duplicate endpoints */\n checkDuplicates?: boolean;\n /** Check for conflicting paths */\n checkConflicts?: boolean;\n /** Validate schema completeness */\n validateSchemas?: boolean;\n /** Compare against existing specs */\n compareExisting?: boolean;\n /** Path to existing specs */\n existingSpecsPath?: string;\n}\n\n/**\n * Result of verification.\n */\nexport interface VerifyResult {\n valid: boolean;\n endpointResults: EndpointVerification[];\n ambiguities: Ambiguity[];\n summary: {\n totalEndpoints: number;\n validEndpoints: number;\n warningEndpoints: number;\n errorEndpoints: number;\n totalIssues: number;\n };\n}\n\n/**\n * Adapters for verification service.\n */\nexport interface VerifyServiceAdapters {\n fs: FsAdapter;\n logger: LoggerAdapter;\n}\n\n/**\n * Verify extracted contracts from IR.\n */\nexport async function verifyImportedContracts(\n ir: ImportIR,\n options: VerifyOptions,\n adapters: VerifyServiceAdapters\n): Promise<VerifyResult> {\n const { logger } = adapters;\n const endpointResults: EndpointVerification[] = [];\n const ambiguities: Ambiguity[] = [...ir.ambiguities];\n\n logger.info(`Verifying ${ir.endpoints.length} endpoints...`);\n\n // Check each endpoint\n for (const endpoint of ir.endpoints) {\n const issues: VerificationIssue[] = [];\n\n // Check confidence level\n if (\n endpoint.confidence.level === 'low' ||\n endpoint.confidence.level === 'ambiguous'\n ) {\n issues.push({\n code: 'LOW_CONFIDENCE',\n message: `Endpoint has ${endpoint.confidence.level} confidence`,\n severity: 'warning',\n suggestion: 'Review source code and add explicit schema annotations',\n });\n }\n\n // Check for missing input schema\n if (\n !endpoint.input &&\n (endpoint.method === 'POST' ||\n endpoint.method === 'PUT' ||\n endpoint.method === 'PATCH')\n ) {\n issues.push({\n code: 'MISSING_INPUT_SCHEMA',\n message: 'Command endpoint missing input schema',\n severity: 'warning',\n suggestion: 'Add Zod schema or class-validator DTO',\n });\n }\n\n // Check for missing output schema\n if (!endpoint.output) {\n issues.push({\n code: 'MISSING_OUTPUT_SCHEMA',\n message: 'Endpoint missing output schema',\n severity: 'info',\n suggestion: 'Infer from return type or add explicit schema',\n });\n }\n\n // Check for duplicate paths\n if (options.checkDuplicates) {\n const duplicates = ir.endpoints.filter(\n (e) =>\n e.id !== endpoint.id &&\n e.path === endpoint.path &&\n e.method === endpoint.method\n );\n if (duplicates.length > 0) {\n issues.push({\n code: 'DUPLICATE_ENDPOINT',\n message: `Duplicate ${endpoint.method} ${endpoint.path} found`,\n severity: 'error',\n });\n }\n }\n\n // Check for path conflicts\n if (options.checkConflicts) {\n const conflicts = findPathConflicts(endpoint, ir.endpoints);\n for (const conflict of conflicts) {\n issues.push({\n code: 'PATH_CONFLICT',\n message: `Path may conflict with ${conflict.method} ${conflict.path}`,\n severity: 'warning',\n });\n }\n }\n\n const status = issues.some((i) => i.severity === 'error')\n ? 'error'\n : issues.some((i) => i.severity === 'warning')\n ? 'warning'\n : 'valid';\n\n endpointResults.push({ endpoint, status, issues });\n }\n\n // Validate schemas if requested\n if (options.validateSchemas) {\n for (const schema of ir.schemas) {\n if (!schema.fields || schema.fields.length === 0) {\n ambiguities.push({\n type: 'schema',\n itemId: schema.id,\n description: `Schema ${schema.name} has no extracted fields`,\n suggestion: 'Review schema definition and add explicit field types',\n source: schema.source,\n });\n }\n }\n }\n\n const summary = {\n totalEndpoints: endpointResults.length,\n validEndpoints: endpointResults.filter((r) => r.status === 'valid').length,\n warningEndpoints: endpointResults.filter((r) => r.status === 'warning')\n .length,\n errorEndpoints: endpointResults.filter((r) => r.status === 'error').length,\n totalIssues: endpointResults.reduce((sum, r) => sum + r.issues.length, 0),\n };\n\n logger.info(\n `Verification complete: ${summary.validEndpoints} valid, ` +\n `${summary.warningEndpoints} warnings, ${summary.errorEndpoints} errors`\n );\n\n return {\n valid: summary.errorEndpoints === 0,\n endpointResults,\n ambiguities,\n summary,\n };\n}\n\n/**\n * Find path conflicts (e.g., /users/:id vs /users/profile).\n */\nfunction findPathConflicts(\n endpoint: EndpointCandidate,\n allEndpoints: EndpointCandidate[]\n): EndpointCandidate[] {\n const conflicts: EndpointCandidate[] = [];\n\n const endpointParts = endpoint.path.split('/').filter(Boolean);\n\n for (const other of allEndpoints) {\n if (other.id === endpoint.id) continue;\n if (other.method !== endpoint.method) continue;\n\n const otherParts = other.path.split('/').filter(Boolean);\n if (otherParts.length !== endpointParts.length) continue;\n\n let mightConflict = true;\n for (let i = 0; i < endpointParts.length; i++) {\n const a = endpointParts[i] ?? '';\n const b = otherParts[i] ?? '';\n\n const aIsParam = a.startsWith(':') || a.startsWith('{');\n const bIsParam = b.startsWith(':') || b.startsWith('{');\n\n if (!aIsParam && !bIsParam && a !== b) {\n mightConflict = false;\n break;\n }\n }\n\n if (mightConflict && endpoint.path !== other.path) {\n conflicts.push(other);\n }\n }\n\n return conflicts;\n}\n"],"mappings":"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"}
|
|
@@ -100,4 +100,8 @@ import { ViewAudience, generateView } from "./view/index.mjs";
|
|
|
100
100
|
import { GapAnalysisResult, analyzeGap } from "./gap.mjs";
|
|
101
101
|
import { GenerateArtifactsResult, generateArtifacts } from "./generate-artifacts.mjs";
|
|
102
102
|
import { ExtractOptions, extractContracts } from "./extract.mjs";
|
|
103
|
-
import { index_d_exports as index_d_exports$6 } from "./vibe/index.mjs";
|
|
103
|
+
import { index_d_exports as index_d_exports$6 } from "./vibe/index.mjs";
|
|
104
|
+
import { ImportServiceAdapters, ImportServiceOptions, ImportServiceResult, importFromSourceService } from "./import/import-service.mjs";
|
|
105
|
+
import { EndpointVerification, VerificationIssue as VerificationIssue$1, VerifyOptions as VerifyOptions$1, VerifyResult as VerifyResult$1, verifyImportedContracts } from "./import/verify-service.mjs";
|
|
106
|
+
import { ReportOptions, generateCliReport, generateMarkdownReport } from "./import/report-service.mjs";
|
|
107
|
+
import "./import/index.mjs";
|
package/dist/services/index.mjs
CHANGED
|
@@ -96,5 +96,9 @@ import { generateView } from "./view/index.mjs";
|
|
|
96
96
|
import { analyzeGap } from "./gap.mjs";
|
|
97
97
|
import { extractContracts } from "./extract.mjs";
|
|
98
98
|
import { vibe_exports } from "./vibe/index.mjs";
|
|
99
|
+
import { importFromSourceService } from "./import/import-service.mjs";
|
|
100
|
+
import { verifyImportedContracts } from "./import/verify-service.mjs";
|
|
101
|
+
import { generateCliReport, generateMarkdownReport } from "./import/report-service.mjs";
|
|
102
|
+
import "./import/index.mjs";
|
|
99
103
|
|
|
100
104
|
export { };
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { FsAdapter } from "../../ports/fs.mjs";
|
|
2
2
|
import { LoggerAdapter } from "../../ports/logger.mjs";
|
|
3
3
|
import { OpenApiImportServiceOptions, OpenApiImportServiceResult } from "./types.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { ResolvedContractsrcConfig } from "@contractspec/lib.contracts";
|
|
5
5
|
|
|
6
6
|
//#region src/services/openapi/import-service.d.ts
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Import ContractSpec specs from an OpenAPI document.
|
|
10
10
|
*/
|
|
11
|
-
declare function importFromOpenApiService(contractspecOptions:
|
|
11
|
+
declare function importFromOpenApiService(contractspecOptions: ResolvedContractsrcConfig, options: OpenApiImportServiceOptions, adapters: {
|
|
12
12
|
fs: FsAdapter;
|
|
13
13
|
logger: LoggerAdapter;
|
|
14
14
|
}): Promise<OpenApiImportServiceResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import-service.d.mts","names":[],"sources":["../../../src/services/openapi/import-service.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"import-service.d.mts","names":[],"sources":["../../../src/services/openapi/import-service.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAwDqC,iBAHf,wBAAA,CAGe,mBAAA,EAFd,yBAEc,EAAA,OAAA,EAD1B,2BAC0B,EAAA,QAAA,EAAA;EAC1B,EAAA,EADO,SACP;EAAR,MAAA,EADkC,aAClC;CAAO,CAAA,EAAP,OAAO,CAAC,0BAAD,CAAA"}
|
|
@@ -10,14 +10,11 @@ import { importFromOpenApi, parseOpenApi } from "@contractspec/lib.contracts-tra
|
|
|
10
10
|
*/
|
|
11
11
|
function getOutputDir(type, options, config) {
|
|
12
12
|
if (options.outputDir) return options.outputDir;
|
|
13
|
-
const baseDir = config.outputDir
|
|
14
|
-
const conventions = config.conventions
|
|
15
|
-
operations: "operations",
|
|
16
|
-
events: "events"
|
|
17
|
-
};
|
|
13
|
+
const baseDir = config.outputDir;
|
|
14
|
+
const conventions = config.conventions;
|
|
18
15
|
switch (type) {
|
|
19
16
|
case "operation": return join(baseDir, conventions.operations.split("|")[0] ?? "operations");
|
|
20
|
-
case "event": return join(baseDir, conventions.events
|
|
17
|
+
case "event": return join(baseDir, conventions.events);
|
|
21
18
|
case "model": return join(baseDir, "models");
|
|
22
19
|
default: return baseDir;
|
|
23
20
|
}
|
|
@@ -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 { ContractsrcConfig } 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: ContractsrcConfig\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 ?? 'src';\n const conventions = config.conventions ?? {\n operations: 'operations',\n events: 'events',\n };\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 ?? '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: ContractsrcConfig,\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":["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":";;;;;;;;;;AAoBA,SAAS,aACP,MACA,SACA,QACQ;AAER,KAAI,QAAQ,UACV,QAAO,QAAQ;CAIjB,MAAM,UAAU,OAAO;CACvB,MAAM,cAAc,OAAO;AAE3B,SAAQ,MAAR;EACE,KAAK,YAEH,QAAO,KACL,SACA,YAAY,WAAW,MAAM,IAAI,CAAC,MAAM,aACzC;EACH,KAAK,QACH,QAAO,KAAK,SAAS,YAAY,OAAO;EAC1C,KAAK,QACH,QAAO,KAAK,SAAS,SAAS;EAChC,QACE,QAAO;;;;;;AAOb,eAAsB,yBACpB,qBACA,SACA,UACqC;CACrC,MAAM,EAAE,IAAI,WAAW;CACvB,MAAM,EACJ,QAEA,QACA,MACA,SACA,kBACA,eACA,aACA,SAAS,UACP;AAEJ,QAAO,KAAK,2BAA2B,SAAS;CAKhD,MAAM,cAAc,MAAM,aAAa,QAAQ;EAC7C,OAAO,WAAW;EAClB,WAAW,WAAS,GAAG,SAASA,OAAK;EACtC,CAAC;AAEF,KAAI,YAAY,SAAS,SAAS,EAChC,MAAK,MAAM,WAAW,YAAY,SAChC,QAAO,KAAK,kBAAkB,UAAU;AAI5C,QAAO,KACL,UAAU,YAAY,WAAW,OAAO,mBAAmB,YAAY,KAAK,MAAM,IAAI,YAAY,KAAK,UACxG;CAGD,MAAM,eAAe,kBAAkB,aAAa,qBAAqB;EACvE;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;AAEF,QAAO,KACL,kBAAkB,aAAa,QAAQ,SAAS,aAAa,aAAa,QAAQ,QAAQ,YAAY,aAAa,QAAQ,OAAO,SACnI;CAED,MAAM,QAA6C,EAAE;CACrD,MAAM,oBAAqE,EAAE;CAC7E,MAAM,gBAA6D,EAAE;CAGrE,MAAM,6BAAa,IAAI,KAGpB;AAEH,MAAK,MAAM,QAAQ,aAAa,gBAAgB;EAE9C,IAAI,OAAwC;EAC5C,IAAI,QAAiC;AACrC,MAAI,KAAK,KAAK,SAAS,eAAe,EAAE;AACtC,UAAO;AACP,WAAQ,KAAK,KAAK,MAAM,uCAAuC;cAE9D,KAAK,KAAK,SAAS,qBAAqB,IACvC,KAAK,KAAK,SAAS,gBAAgB,IACnC,KAAK,KAAK,SAAS,kBAAkB,IACrC,KAAK,KAAK,SAAS,qBAAqB,IACxC,KAAK,KAAK,SAAS,UAAU,IAC7B,KAAK,KAAK,SAAS,sBAAsB,IACzC,KAAK,KAAK,SAAS,yBAAyB,KAC9C,CAAC,KAAK,KAAK,SAAS,iBAAiB,IACrC,CAAC,KAAK,KAAK,SAAS,eAAe,CAEnC,QAAO;OACF;AACL,UAAO;AACP,WAAQ,KAAK,KAAK,MAChB,mDACD;;EAKH,MAAM,WAAW,KADC,aAAa,MAAM,SAAS,oBAAoB,EACjC,KAAK,SAAS;AAE/C,MAAI,CAAC,SAAS,SAAS,SAAS;AAC9B,OAAI,KAAK,KAAK,SAAS,qBAAqB,CAC1C,SAAQ,KAAK,KAAK,MAAM,+CAA+C;YAC9D,KAAK,KAAK,SAAS,sBAAsB,CAClD,SAAQ,KAAK,KAAK,MAChB,gDACD;YACQ,KAAK,KAAK,SAAS,yBAAyB,CACrD,SAAQ,KAAK,KAAK,MAChB,mDACD;AAEH,OAAI,CAAC,MACH,SAAQ,KAAK,KAAK,MAAM,yBAAyB;;AAIrD,MAAI,OACF,QAAO,KAAK,2BAA2B,WAAW;OAC7C;GAEL,MAAM,MAAM,QAAQ,SAAS;AAE7B,OAAI,CADW,MAAM,GAAG,OAAO,IAAI,CAEjC,OAAM,GAAG,MAAM,IAAI;AAIrB,SAAM,GAAG,UAAU,UAAU,KAAK,KAAK;AACvC,UAAO,KAAK,YAAY,WAAW;;AAGrC,QAAM,KAAK;GACT,MAAM;GACN,aAAa,KAAK,OAAO;GACzB,UAAU,KAAK,SAAS,QAAQ,OAAO,GAAG;GAC3C,CAAC;AAEF,MAAI,OAAO;GACT,MAAM,MAAM,QAAQ,SAAS;GAC7B,MAAM,WAAW,WAAW,IAAI,IAAI,IAAI,EAAE;AAC1C,YAAS,KAAK;IACZ,MAAM,SAAS,SAAS;IAExB,MAAM,MAAM;IACZ;IACD,CAAC;AACF,cAAW,IAAI,KAAK,SAAS;;;AAKjC,KAAI,CAAC,UAAU,MAAM,SAAS,EAC5B,MAAK,MAAM,CAAC,KAAK,UAAU,WAAW,SAAS,EAAE;AAC/C,MAAI,MAAM,WAAW,EAAG;EAGxB,MAAM,QAAQ,MAAM,KAAK,MAAM,EAAE,KAAK;EACtC,MAAM,eAAe,MAAM,OAAO,MAAM,MAAM,YAAY;EAC1D,MAAM,WAAW,MAAM,OAAO,MAAM,MAAM,QAAQ;EAClD,MAAM,WAAW,MAAM,OAAO,MAAM,MAAM,QAAQ;EAGlD,IAAI,eAAe;AACnB,QAAM,SAAS,MAAM;GACnB,MAAM,aAAa,KAAK,SAAS,EAAE,MAAM,MAAM;AAC/C,mBAAgB,YAAY,EAAE,KAAK,WAAW,WAAW;IACzD;AACF,kBAAgB;EAEhB,IAAI,cAAc;AAClB,MAAI,cAAc;AAChB,mBAAgB;AAChB,mBAAgB;AAChB,SAAM,SAAS,MAAM;AACnB,oBAAgB,8BAA8B,EAAE,KAAK;KACrD;AACF,iBAAc;aACL,UAAU;AACnB,mBAAgB;AAChB,mBAAgB;AAChB,SAAM,SAAS,MAAM;AACnB,oBAAgB,0BAA0B,EAAE,KAAK;KACjD;AACF,iBAAc;aACL,UAAU;AACnB,mBAAgB;AAChB,mBAAgB;AAChB,SAAM,SAAS,MAAM;AACnB,oBAAgB,0BAA0B,EAAE,KAAK;KACjD;AACF,iBAAc;;AAGhB,MAAI,aAAa;GACf,MAAM,eAAe,KAAK,KAAK,cAAc;AAC7C,SAAM,GAAG,UAAU,cAAc,aAAa;AAC9C,UAAO,KAAK,6BAA6B,eAAe;;EAI1D,IAAI,YAAY;AAChB,QAAM,SAAS,MAAM;GACnB,MAAM,aAAa,KAAK,SAAS,EAAE,MAAM,MAAM;AAC/C,gBAAa,kBAAkB,WAAW;IAC1C;AAEF,MAAI,YACF,cAAa;EAGf,MAAM,YAAY,KAAK,KAAK,WAAW;AACvC,QAAM,GAAG,UAAU,WAAW,UAAU;AACxC,SAAO,KAAK,0BAA0B,YAAY;;AAKtD,MAAK,MAAM,WAAW,aAAa,SAAS;AAC1C,oBAAkB,KAAK;GACrB,aAAa,QAAQ;GACrB,QAAQ,QAAQ;GACjB,CAAC;AACF,SAAO,MAAM,YAAY,QAAQ,SAAS,KAAK,QAAQ,SAAS;;AAIlE,MAAK,MAAM,SAAS,aAAa,QAAQ;AACvC,gBAAc,KAAK;GACjB,aAAa,MAAM;GACnB,OAAO,MAAM;GACd,CAAC;AACF,SAAO,MAAM,UAAU,MAAM,SAAS,KAAK,MAAM,QAAQ;;AAG3D,QAAO;EACL,UAAU,aAAa,QAAQ;EAC/B,SAAS,aAAa,QAAQ;EAC9B,QAAQ,aAAa,QAAQ;EAC7B;EACA;EACA;EACD"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { FsAdapter } from "../../ports/fs.mjs";
|
|
2
2
|
import { LoggerAdapter } from "../../ports/logger.mjs";
|
|
3
3
|
import { OpenApiSyncServiceOptions, OpenApiSyncServiceResult } from "./types.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { ResolvedContractsrcConfig } from "@contractspec/lib.contracts";
|
|
5
5
|
|
|
6
6
|
//#region src/services/openapi/sync-service.d.ts
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Sync ContractSpec specs with OpenAPI sources.
|
|
10
10
|
*/
|
|
11
|
-
declare function syncWithOpenApiService(options: OpenApiSyncServiceOptions, config:
|
|
11
|
+
declare function syncWithOpenApiService(options: OpenApiSyncServiceOptions, config: ResolvedContractsrcConfig, adapters: {
|
|
12
12
|
fs: FsAdapter;
|
|
13
13
|
logger: LoggerAdapter;
|
|
14
14
|
}): Promise<OpenApiSyncServiceResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-service.d.mts","names":[],"sources":["../../../src/services/openapi/sync-service.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAuBqC,iBAHf,sBAAA,CAGe,OAAA,EAF1B,yBAE0B,EAAA,MAAA,EAD3B,
|
|
1
|
+
{"version":3,"file":"sync-service.d.mts","names":[],"sources":["../../../src/services/openapi/sync-service.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAuBqC,iBAHf,sBAAA,CAGe,OAAA,EAF1B,yBAE0B,EAAA,MAAA,EAD3B,yBAC2B,EAAA,QAAA,EAAA;EAC1B,EAAA,EADO,SACP;EAAR,MAAA,EADkC,aAClC;CAAO,CAAA,EAAP,OAAO,CAAC,wBAAD,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-service.mjs","names":["path"],"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 {
|
|
1
|
+
{"version":3,"file":"sync-service.mjs","names":["path"],"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":"rulesync.d.mts","names":[],"sources":["../../src/services/rulesync.ts"],"sourcesContent":[],"mappings":";;;;;;AAkByB,cAFZ,eAAA,YAA2B,YAEf,CAAA;EACI,iBAAA,EAAA;EAGP,iBAAA,MAAA;EAA0B,WAAA,CAAA,EAAA,EAJvB,SAIuB,EAAA,MAAA,EAHnB,aAGmB;EAAR,IAAA,CAAA,OAAA,EAAlB,eAAkB,CAAA,EAAA,OAAA,CAAQ,cAAR,CAAA;
|
|
1
|
+
{"version":3,"file":"rulesync.d.mts","names":[],"sources":["../../src/services/rulesync.ts"],"sourcesContent":[],"mappings":";;;;;;AAkByB,cAFZ,eAAA,YAA2B,YAEf,CAAA;EACI,iBAAA,EAAA;EAGP,iBAAA,MAAA;EAA0B,WAAA,CAAA,EAAA,EAJvB,SAIuB,EAAA,MAAA,EAHnB,aAGmB;EAAR,IAAA,CAAA,OAAA,EAAlB,eAAkB,CAAA,EAAA,OAAA,CAAQ,cAAR,CAAA;EA0ER,cAAA,CAAA,OAAA,EAAA,eAAA,CAAA,EAAkB,OAAlB,CAAA,MAAA,CAAA;EAAkB,QAAA,iBAAA"}
|
|
@@ -5,7 +5,8 @@ var RuleSyncService = class {
|
|
|
5
5
|
this.logger = logger;
|
|
6
6
|
}
|
|
7
7
|
async sync(options) {
|
|
8
|
-
const { config, cwd
|
|
8
|
+
const { config, cwd } = options;
|
|
9
|
+
const targets = options.targets ?? config.targets ?? [];
|
|
9
10
|
if (!config.enabled && !options.targets) return {
|
|
10
11
|
success: true,
|
|
11
12
|
files: [],
|
|
@@ -13,7 +14,7 @@ var RuleSyncService = class {
|
|
|
13
14
|
};
|
|
14
15
|
this.logger.info(`Synchronizing rules for targets: ${targets.join(", ")}...`);
|
|
15
16
|
try {
|
|
16
|
-
const rulesDir = this.fs.join(cwd, config.rulesDir);
|
|
17
|
+
const rulesDir = this.fs.join(cwd, config.rulesDir ?? ".rules");
|
|
17
18
|
if (!await this.fs.exists(rulesDir)) return {
|
|
18
19
|
success: false,
|
|
19
20
|
files: [],
|
|
@@ -47,7 +48,7 @@ var RuleSyncService = class {
|
|
|
47
48
|
async generateConfig(options) {
|
|
48
49
|
const { config } = options;
|
|
49
50
|
const rulesyncConfig = {
|
|
50
|
-
rules: config.rules.map((r) => this.fs.join(config.rulesDir, r)),
|
|
51
|
+
rules: (config.rules ?? []).map((r) => this.fs.join(config.rulesDir ?? ".rules", r)),
|
|
51
52
|
targets: options.targets || config.targets
|
|
52
53
|
};
|
|
53
54
|
return JSON.stringify(rulesyncConfig, null, 2);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rulesync.mjs","names":[],"sources":["../../src/services/rulesync.ts"],"sourcesContent":["/**\n * Service for synchronizing AI agent rules.\n */\n\nimport type {\n RuleSyncPort,\n RuleSyncOptions,\n RuleSyncResult,\n} from '../ports/rulesync';\nimport type { FsAdapter } from '../ports/fs';\nimport type { LoggerAdapter } from '../ports/logger';\n\n// We import rulesync dynamically to avoid issues if it's not present or has ESM/CJS mismatches\n// In a real implementation, we would use the actual programmatic API of rulesync if available.\n// For now, we'll implement it by generating the config and potentially calling the CLI or using its core logic.\n\nexport class RuleSyncService implements RuleSyncPort {\n constructor(\n private readonly fs: FsAdapter,\n private readonly logger: LoggerAdapter\n ) {}\n\n async sync(options: RuleSyncOptions): Promise<RuleSyncResult> {\n const { config, cwd
|
|
1
|
+
{"version":3,"file":"rulesync.mjs","names":[],"sources":["../../src/services/rulesync.ts"],"sourcesContent":["/**\n * Service for synchronizing AI agent rules.\n */\n\nimport type {\n RuleSyncPort,\n RuleSyncOptions,\n RuleSyncResult,\n} from '../ports/rulesync';\nimport type { FsAdapter } from '../ports/fs';\nimport type { LoggerAdapter } from '../ports/logger';\n\n// We import rulesync dynamically to avoid issues if it's not present or has ESM/CJS mismatches\n// In a real implementation, we would use the actual programmatic API of rulesync if available.\n// For now, we'll implement it by generating the config and potentially calling the CLI or using its core logic.\n\nexport class RuleSyncService implements RuleSyncPort {\n constructor(\n private readonly fs: FsAdapter,\n private readonly logger: LoggerAdapter\n ) {}\n\n async sync(options: RuleSyncOptions): Promise<RuleSyncResult> {\n const { config, cwd } = options;\n const targets = options.targets ?? config.targets ?? [];\n\n if (!config.enabled && !options.targets) {\n return {\n success: true,\n files: [],\n logs: ['Rule synchronization is disabled.'],\n };\n }\n\n this.logger.info(\n `Synchronizing rules for targets: ${targets.join(', ')}...`\n );\n\n try {\n // 1. Ensure rules directory exists\n const rulesDir = this.fs.join(cwd, config.rulesDir ?? '.rules');\n const rulesDirExists = await this.fs.exists(rulesDir);\n if (!rulesDirExists) {\n return {\n success: false,\n files: [],\n errors: [`Rules directory not found: ${rulesDir}`],\n };\n }\n\n // 2. Implementation choice:\n // If ejectMode is true, we just copy rules to targets if possible,\n // but usually rulesync is better for merging and formatting.\n\n // For now, let's implement the logic that leverages 'rulesync' patterns.\n // We generate a temporary rulesync.config.json if needed, or use their API.\n\n const rsConfig = await this.generateConfig(options);\n\n // In a real-world scenario, we would call the rulesync programmatic API here:\n // const { sync } = await import('rulesync');\n // await sync({ config: JSON.parse(rsConfig), cwd });\n\n this.logger.debug(`Generated rulesync config: ${rsConfig}`);\n\n // For this implementation, we'll simulate the file generation matching rulesync's behavior\n // until we have the full API details of the library.\n\n const files: string[] = [];\n for (const target of targets) {\n const targetFile = this.getTargetFileName(target);\n if (targetFile) {\n const fullPath = this.fs.join(cwd, targetFile);\n // Logic to aggregate rules from config.rulesDir and write to fullPath\n // would go here. rulesync handles this by parsing the files and\n // combining them based on the target.\n files.push(fullPath);\n }\n }\n\n return {\n success: true,\n files,\n logs: [`Successfully synchronized rules to ${files.length} targets.`],\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n this.logger.error(`Rule synchronization failed: ${message}`);\n return {\n success: false,\n files: [],\n errors: [message],\n };\n }\n }\n\n async generateConfig(options: RuleSyncOptions): Promise<string> {\n const { config } = options;\n\n // Convert our ContractSpec RuleSyncConfig to rulesync's config format\n const rulesyncConfig = {\n rules: (config.rules ?? []).map((r: string) =>\n this.fs.join(config.rulesDir ?? '.rules', r)\n ),\n targets: options.targets || config.targets,\n // Add other rulesync specific options here\n };\n\n return JSON.stringify(rulesyncConfig, null, 2);\n }\n\n private getTargetFileName(target: string): string | undefined {\n switch (target) {\n case 'cursor':\n return '.cursorrules';\n case 'windsurf':\n return '.windsurfrules';\n case 'cline':\n return '.clinerules';\n case 'claude-code':\n return 'CLAUDE.md';\n case 'copilot':\n return '.github/copilot-instructions.md';\n case 'subagent':\n return '.subagent';\n case 'skill':\n return '.skill';\n default:\n return undefined;\n }\n }\n}\n"],"mappings":";AAgBA,IAAa,kBAAb,MAAqD;CACnD,YACE,AAAiB,IACjB,AAAiB,QACjB;EAFiB;EACA;;CAGnB,MAAM,KAAK,SAAmD;EAC5D,MAAM,EAAE,QAAQ,QAAQ;EACxB,MAAM,UAAU,QAAQ,WAAW,OAAO,WAAW,EAAE;AAEvD,MAAI,CAAC,OAAO,WAAW,CAAC,QAAQ,QAC9B,QAAO;GACL,SAAS;GACT,OAAO,EAAE;GACT,MAAM,CAAC,oCAAoC;GAC5C;AAGH,OAAK,OAAO,KACV,oCAAoC,QAAQ,KAAK,KAAK,CAAC,KACxD;AAED,MAAI;GAEF,MAAM,WAAW,KAAK,GAAG,KAAK,KAAK,OAAO,YAAY,SAAS;AAE/D,OAAI,CADmB,MAAM,KAAK,GAAG,OAAO,SAAS,CAEnD,QAAO;IACL,SAAS;IACT,OAAO,EAAE;IACT,QAAQ,CAAC,8BAA8B,WAAW;IACnD;GAUH,MAAM,WAAW,MAAM,KAAK,eAAe,QAAQ;AAMnD,QAAK,OAAO,MAAM,8BAA8B,WAAW;GAK3D,MAAM,QAAkB,EAAE;AAC1B,QAAK,MAAM,UAAU,SAAS;IAC5B,MAAM,aAAa,KAAK,kBAAkB,OAAO;AACjD,QAAI,YAAY;KACd,MAAM,WAAW,KAAK,GAAG,KAAK,KAAK,WAAW;AAI9C,WAAM,KAAK,SAAS;;;AAIxB,UAAO;IACL,SAAS;IACT;IACA,MAAM,CAAC,sCAAsC,MAAM,OAAO,WAAW;IACtE;WACM,OAAO;GACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACtE,QAAK,OAAO,MAAM,gCAAgC,UAAU;AAC5D,UAAO;IACL,SAAS;IACT,OAAO,EAAE;IACT,QAAQ,CAAC,QAAQ;IAClB;;;CAIL,MAAM,eAAe,SAA2C;EAC9D,MAAM,EAAE,WAAW;EAGnB,MAAM,iBAAiB;GACrB,QAAQ,OAAO,SAAS,EAAE,EAAE,KAAK,MAC/B,KAAK,GAAG,KAAK,OAAO,YAAY,UAAU,EAAE,CAC7C;GACD,SAAS,QAAQ,WAAW,OAAO;GAEpC;AAED,SAAO,KAAK,UAAU,gBAAgB,MAAM,EAAE;;CAGhD,AAAQ,kBAAkB,QAAoC;AAC5D,UAAQ,QAAR;GACE,KAAK,SACH,QAAO;GACT,KAAK,WACH,QAAO;GACT,KAAK,QACH,QAAO;GACT,KAAK,cACH,QAAO;GACT,KAAK,UACH,QAAO;GACT,KAAK,WACH,QAAO;GACT,KAAK,QACH,QAAO;GACT,QACE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contractspec/bundle.workspace",
|
|
3
|
-
"version": "0.0.0-canary-
|
|
3
|
+
"version": "0.0.0-canary-20260119222405",
|
|
4
4
|
"description": "Workspace utilities for monorepo development",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"contractspec",
|
|
@@ -31,11 +31,12 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@ai-sdk/anthropic": "3.0.11",
|
|
33
33
|
"@ai-sdk/openai": "3.0.8",
|
|
34
|
-
"@contractspec/lib.ai-agent": "0.0.0-canary-
|
|
35
|
-
"@contractspec/lib.ai-providers": "
|
|
36
|
-
"@contractspec/lib.contracts": "0.0.0-canary-
|
|
37
|
-
"@contractspec/lib.contracts-transformers": "0.0.0-canary-
|
|
38
|
-
"@contractspec/
|
|
34
|
+
"@contractspec/lib.ai-agent": "0.0.0-canary-20260119222405",
|
|
35
|
+
"@contractspec/lib.ai-providers": "1.48.0",
|
|
36
|
+
"@contractspec/lib.contracts": "0.0.0-canary-20260119222405",
|
|
37
|
+
"@contractspec/lib.contracts-transformers": "0.0.0-canary-20260119222405",
|
|
38
|
+
"@contractspec/lib.source-extractors": "0.0.0-canary-20260119222405",
|
|
39
|
+
"@contractspec/module.workspace": "0.0.0-canary-20260119222405",
|
|
39
40
|
"ai": "6.0.29",
|
|
40
41
|
"chalk": "^5.6.2",
|
|
41
42
|
"chokidar": "^5.0.0",
|
|
@@ -47,8 +48,8 @@
|
|
|
47
48
|
"zod": "^4.3.5"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
|
-
"@contractspec/tool.tsdown": "
|
|
51
|
-
"@contractspec/tool.typescript": "
|
|
51
|
+
"@contractspec/tool.tsdown": "1.48.0",
|
|
52
|
+
"@contractspec/tool.typescript": "1.48.0",
|
|
52
53
|
"@types/micromatch": "^4.0.10",
|
|
53
54
|
"@types/node": "^25.0.6",
|
|
54
55
|
"tsdown": "^0.19.0",
|