@lssm/lib.contracts-transformers 0.0.0-canary-20251217080011 → 0.0.0-canary-20251219202229

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Chaman Ventures, SASU
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -59,15 +59,15 @@ interface ImportResult {
59
59
  /** Successfully imported specs */
60
60
  specs: ImportedSpec[];
61
61
  /** Specs that were skipped (e.g., unsupported features) */
62
- skipped: Array<{
62
+ skipped: {
63
63
  sourceId: string;
64
64
  reason: string;
65
- }>;
65
+ }[];
66
66
  /** Errors encountered during import */
67
- errors: Array<{
67
+ errors: {
68
68
  sourceId: string;
69
69
  error: string;
70
- }>;
70
+ }[];
71
71
  /** Summary statistics */
72
72
  summary: {
73
73
  total: number;
@@ -119,10 +119,10 @@ interface SyncResult {
119
119
  /** Specs that were added (new imports) */
120
120
  added: ImportedSpec[];
121
121
  /** Specs that were updated */
122
- updated: Array<{
122
+ updated: {
123
123
  spec: ImportedSpec;
124
124
  changes: DiffChange[];
125
- }>;
125
+ }[];
126
126
  /** Specs that were kept unchanged */
127
127
  unchanged: string[];
128
128
  /** Specs that had conflicts requiring resolution */
@@ -149,4 +149,5 @@ interface ValidationResult {
149
149
  warnings: string[];
150
150
  }
151
151
  //#endregion
152
- export { DiffChange, DiffChangeType, ImportResult, ImportedSpec, SpecDiff, SpecSource, SyncResult, TransportHints, ValidationResult };
152
+ export { DiffChange, DiffChangeType, ImportResult, ImportedSpec, SpecDiff, SpecSource, SyncResult, TransportHints, ValidationResult };
153
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/common/types.ts"],"sourcesContent":[],"mappings":";;;;AA0BA;AAoBA;;AAQU,UA7CO,UAAA,CA6CP;EAEQ;EAAc,IAAA,EAAA,SAAA,GAAA,UAAA,GAAA,SAAA,GAAA,UAAA;EAMf;EAyBL,GAAA,CAAA,EAAA,MAAA;EAUK;EAgBA,IAAA,CAAA,EAAA,MAAQ;EAIZ;EAED,QAAA,EAAA,MAAA;EAED;EAAU,UAAA,EAtGP,IAsGO;AAUrB;;;;;AAWqB,UApHJ,cAAA,CAoHI;EAaJ,IAAA,CAAA,EAAA;;;;;;;;;;;;;;;;;;UA7GA,YAAA;;QAET;;;;;;UAME;;kBAEQ;;;;;UAMD,YAAA;;SAER;;;;;;;;;;;;;;;;;;;;;;KAuBG,cAAA;;;;UAUK,UAAA;;;;QAIT;;;;;;;;;;;UAYS,QAAA;;;;aAIJ;;YAED;;WAED;;;;;;;;;UAUM,UAAA;;SAER;;;UAGC;aACG;;;;;aAKA;;;;;;;;;;;;UAaI,gBAAA;;;;SAIR"}
@@ -48,4 +48,5 @@ declare function extractPathParams(path: string): string[];
48
48
  */
49
49
  declare function normalizePath(path: string): string;
50
50
  //#endregion
51
- export { deepEqual, extractPathParams, getByPath, normalizePath, toCamelCase, toFileName, toKebabCase, toPascalCase, toSnakeCase, toSpecName, toValidIdentifier };
51
+ export { deepEqual, extractPathParams, getByPath, normalizePath, toCamelCase, toFileName, toKebabCase, toPascalCase, toSnakeCase, toSpecName, toValidIdentifier };
52
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","names":[],"sources":["../../src/common/utils.ts"],"sourcesContent":[],"mappings":";;AAOA;AASA;AAQA;AAUA;AAUA;AAagB,iBAlDA,YAAA,CAkDU,GAAA,EAAA,MAAA,CAAA,EAAA,MAAA;AAQ1B;AAOA;AA4BA;AAiBgB,iBArGA,WAAA,CAqGiB,GAAA,EAAA,MAAA,CAAA,EAAA,MAAA;AAQjC;;;iBArGgB,WAAA;;;;iBAUA,WAAA;;;;iBAUA,iBAAA;;;;iBAaA,UAAA;;;;iBAQA,UAAA;;;;iBAOA,SAAA;;;;iBA4BA,SAAA;;;;;iBAiBA,iBAAA;;;;iBAQA,aAAA"}
@@ -99,4 +99,5 @@ function normalizePath(path) {
99
99
  }
100
100
 
101
101
  //#endregion
102
- export { deepEqual, extractPathParams, getByPath, normalizePath, toCamelCase, toFileName, toKebabCase, toPascalCase, toSnakeCase, toSpecName, toValidIdentifier };
102
+ export { deepEqual, extractPathParams, getByPath, normalizePath, toCamelCase, toFileName, toKebabCase, toPascalCase, toSnakeCase, toSpecName, toValidIdentifier };
103
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","names":["current: unknown"],"sources":["../../src/common/utils.ts"],"sourcesContent":["/**\n * Common utilities for contract transformations.\n */\n\n/**\n * Convert a string to PascalCase.\n */\nexport function toPascalCase(str: string): string {\n return str\n .replace(/[-_./\\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))\n .replace(/^./, (c) => c.toUpperCase());\n}\n\n/**\n * Convert a string to camelCase.\n */\nexport function toCamelCase(str: string): string {\n const pascal = toPascalCase(str);\n return pascal.charAt(0).toLowerCase() + pascal.slice(1);\n}\n\n/**\n * Convert a string to kebab-case.\n */\nexport function toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_./]+/g, '-')\n .toLowerCase();\n}\n\n/**\n * Convert a string to snake_case.\n */\nexport function toSnakeCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1_$2')\n .replace(/[\\s\\-./]+/g, '_')\n .toLowerCase();\n}\n\n/**\n * Sanitize a string to be a valid TypeScript identifier.\n */\nexport function toValidIdentifier(str: string): string {\n // Remove invalid characters\n let result = str.replace(/[^a-zA-Z0-9_$]/g, '_');\n // Ensure it doesn't start with a number\n if (/^[0-9]/.test(result)) {\n result = '_' + result;\n }\n return result;\n}\n\n/**\n * Generate a ContractSpec name from an operation identifier.\n */\nexport function toSpecName(operationId: string, prefix?: string): string {\n const name = toCamelCase(operationId);\n return prefix ? `${prefix}.${name}` : name;\n}\n\n/**\n * Generate a file name from a spec name.\n */\nexport function toFileName(specName: string): string {\n return toKebabCase(specName.replace(/\\./g, '-')) + '.ts';\n}\n\n/**\n * Deep equality check for objects.\n */\nexport function deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a === null || b === null) return false;\n if (typeof a !== typeof b) return false;\n\n if (typeof a === 'object') {\n const aObj = a as Record<string, unknown>;\n const bObj = b as Record<string, unknown>;\n\n const aKeys = Object.keys(aObj);\n const bKeys = Object.keys(bObj);\n\n if (aKeys.length !== bKeys.length) return false;\n\n for (const key of aKeys) {\n if (!bKeys.includes(key)) return false;\n if (!deepEqual(aObj[key], bObj[key])) return false;\n }\n\n return true;\n }\n\n return false;\n}\n\n/**\n * Get a value from an object by JSON path.\n */\nexport function getByPath(obj: unknown, path: string): unknown {\n const parts = path.split('.').filter(Boolean);\n let current: unknown = obj;\n\n for (const part of parts) {\n if (current === null || current === undefined) return undefined;\n if (typeof current !== 'object') return undefined;\n current = (current as Record<string, unknown>)[part];\n }\n\n return current;\n}\n\n/**\n * Extract path parameters from a URL path template.\n * e.g., \"/users/{userId}/orders/{orderId}\" -> [\"userId\", \"orderId\"]\n */\nexport function extractPathParams(path: string): string[] {\n const matches = path.match(/\\{([^}]+)\\}/g) || [];\n return matches.map((m) => m.slice(1, -1));\n}\n\n/**\n * Normalize a URL path for comparison.\n */\nexport function normalizePath(path: string): string {\n // Remove leading/trailing slashes\n let normalized = path.replace(/^\\/+|\\/+$/g, '');\n // Replace multiple slashes with single\n normalized = normalized.replace(/\\/+/g, '/');\n // Add leading slash\n return '/' + normalized;\n}\n"],"mappings":";;;;;;;AAOA,SAAgB,aAAa,KAAqB;AAChD,QAAO,IACJ,QAAQ,mBAAmB,GAAG,MAAO,IAAI,EAAE,aAAa,GAAG,GAAI,CAC/D,QAAQ,OAAO,MAAM,EAAE,aAAa,CAAC;;;;;AAM1C,SAAgB,YAAY,KAAqB;CAC/C,MAAM,SAAS,aAAa,IAAI;AAChC,QAAO,OAAO,OAAO,EAAE,CAAC,aAAa,GAAG,OAAO,MAAM,EAAE;;;;;AAMzD,SAAgB,YAAY,KAAqB;AAC/C,QAAO,IACJ,QAAQ,mBAAmB,QAAQ,CACnC,QAAQ,aAAa,IAAI,CACzB,aAAa;;;;;AAMlB,SAAgB,YAAY,KAAqB;AAC/C,QAAO,IACJ,QAAQ,mBAAmB,QAAQ,CACnC,QAAQ,cAAc,IAAI,CAC1B,aAAa;;;;;AAMlB,SAAgB,kBAAkB,KAAqB;CAErD,IAAI,SAAS,IAAI,QAAQ,mBAAmB,IAAI;AAEhD,KAAI,SAAS,KAAK,OAAO,CACvB,UAAS,MAAM;AAEjB,QAAO;;;;;AAMT,SAAgB,WAAW,aAAqB,QAAyB;CACvE,MAAM,OAAO,YAAY,YAAY;AACrC,QAAO,SAAS,GAAG,OAAO,GAAG,SAAS;;;;;AAMxC,SAAgB,WAAW,UAA0B;AACnD,QAAO,YAAY,SAAS,QAAQ,OAAO,IAAI,CAAC,GAAG;;;;;AAMrD,SAAgB,UAAU,GAAY,GAAqB;AACzD,KAAI,MAAM,EAAG,QAAO;AACpB,KAAI,MAAM,QAAQ,MAAM,KAAM,QAAO;AACrC,KAAI,OAAO,MAAM,OAAO,EAAG,QAAO;AAElC,KAAI,OAAO,MAAM,UAAU;EACzB,MAAM,OAAO;EACb,MAAM,OAAO;EAEb,MAAM,QAAQ,OAAO,KAAK,KAAK;EAC/B,MAAM,QAAQ,OAAO,KAAK,KAAK;AAE/B,MAAI,MAAM,WAAW,MAAM,OAAQ,QAAO;AAE1C,OAAK,MAAM,OAAO,OAAO;AACvB,OAAI,CAAC,MAAM,SAAS,IAAI,CAAE,QAAO;AACjC,OAAI,CAAC,UAAU,KAAK,MAAM,KAAK,KAAK,CAAE,QAAO;;AAG/C,SAAO;;AAGT,QAAO;;;;;AAMT,SAAgB,UAAU,KAAc,MAAuB;CAC7D,MAAM,QAAQ,KAAK,MAAM,IAAI,CAAC,OAAO,QAAQ;CAC7C,IAAIA,UAAmB;AAEvB,MAAK,MAAM,QAAQ,OAAO;AACxB,MAAI,YAAY,QAAQ,YAAY,OAAW,QAAO;AACtD,MAAI,OAAO,YAAY,SAAU,QAAO;AACxC,YAAW,QAAoC;;AAGjD,QAAO;;;;;;AAOT,SAAgB,kBAAkB,MAAwB;AAExD,SADgB,KAAK,MAAM,eAAe,IAAI,EAAE,EACjC,KAAK,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC;;;;;AAM3C,SAAgB,cAAc,MAAsB;CAElD,IAAI,aAAa,KAAK,QAAQ,cAAc,GAAG;AAE/C,cAAa,WAAW,QAAQ,QAAQ,IAAI;AAE5C,QAAO,MAAM"}
@@ -38,4 +38,5 @@ declare function diffAll(existingSpecs: Map<string, AnyContractSpec>, importedSp
38
38
  */
39
39
  declare function formatDiffChanges(changes: DiffChange[]): string;
40
40
  //#endregion
41
- export { DiffOptions, createSpecDiff, diffAll, diffSpecVsOperation, diffSpecs, formatDiffChanges };
41
+ export { DiffOptions, createSpecDiff, diffAll, diffSpecVsOperation, diffSpecs, formatDiffChanges };
42
+ //# sourceMappingURL=differ.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"differ.d.ts","names":[],"sources":["../../src/openapi/differ.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AAwIG,UAtHc,WAAA,CAsHd;EAAU;EA2EG,kBAAS,CAAA,EAAA,OAAA;EACd;EACA,UAAA,CAAA,EAAA,OAAA;EACA;EACR,eAAA,CAAA,EAAA,OAAA;EAAU;EA+CG,WAAA,CAAA,EAAA,MAAc,EAAA;;;;;AAKnB,iBAvIK,mBAAA,CAuIL,IAAA,EAtIH,eAsIG,EAAA,SAAA,EArIE,eAqIF,EAAA,OAAA,CAAA,EApIA,WAoIA,CAAA,EAnIR,UAmIQ,EAAA;AAgCX;;;AAEiB,iBA1FD,SAAA,CA0FC,OAAA,EAzFN,eAyFM,EAAA,OAAA,EAxFN,eAwFM,EAAA,OAAA,CAAA,EAvFN,WAuFM,CAAA,EAtFd,UAsFc,EAAA;;;;AAsDD,iBA7FA,cAAA,CA6F2B,WAAU,EAAA,MAAA,EAAA,QAAA,EA3FzC,eA2FyC,GAAA,SAAA,EAAA,QAAA,EA1FzC,YA0FyC,EAAA,OAAA,CAAA,EAzF1C,WAyF0C,CAAA,EAxFlD,QAwFkD;;;;iBAxDrC,OAAA,gBACC,YAAY,iCACZ,0BACN,cACR;;;;iBAoDa,iBAAA,UAA2B"}
@@ -211,4 +211,5 @@ function formatDiffChanges(changes) {
211
211
  }
212
212
 
213
213
  //#endregion
214
- export { createSpecDiff, diffAll, diffSpecVsOperation, diffSpecs, formatDiffChanges };
214
+ export { createSpecDiff, diffAll, diffSpecVsOperation, diffSpecs, formatDiffChanges };
215
+ //# sourceMappingURL=differ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"differ.js","names":["changeType: DiffChangeType","changes: DiffChange[]","diffs: SpecDiff[]","existing: AnyContractSpec | undefined","lines: string[]"],"sources":["../../src/openapi/differ.ts"],"sourcesContent":["/**\n * Diff ContractSpec specs against OpenAPI operations.\n * Used for sync operations to detect changes.\n */\n\nimport type { AnyContractSpec } from '@lssm/lib.contracts';\nimport type { ParsedOperation } from './types';\nimport type {\n SpecDiff,\n DiffChange,\n DiffChangeType,\n ImportedSpec,\n} from '../common/types';\nimport { deepEqual, getByPath } from '../common/utils';\n\n/**\n * Options for diffing specs.\n */\nexport interface DiffOptions {\n /** Ignore description changes */\n ignoreDescriptions?: boolean;\n /** Ignore tag changes */\n ignoreTags?: boolean;\n /** Ignore transport changes (path, method) */\n ignoreTransport?: boolean;\n /** Custom paths to ignore */\n ignorePaths?: string[];\n}\n\n/**\n * Compare two values and generate a diff change if different.\n */\nfunction compareValues(\n path: string,\n oldValue: unknown,\n newValue: unknown,\n description: string\n): DiffChange | null {\n if (deepEqual(oldValue, newValue)) {\n return null;\n }\n\n let changeType: DiffChangeType = 'modified';\n if (oldValue === undefined || oldValue === null) {\n changeType = 'added';\n } else if (newValue === undefined || newValue === null) {\n changeType = 'removed';\n } else if (typeof oldValue !== typeof newValue) {\n changeType = 'type_changed';\n }\n\n return {\n path,\n type: changeType,\n oldValue,\n newValue,\n description,\n };\n}\n\n/**\n * Diff two objects recursively.\n */\nfunction diffObjects(\n path: string,\n oldObj: Record<string, unknown> | undefined,\n newObj: Record<string, unknown> | undefined,\n options: DiffOptions\n): DiffChange[] {\n const changes: DiffChange[] = [];\n\n if (!oldObj && !newObj) return changes;\n if (!oldObj) {\n changes.push({\n path,\n type: 'added',\n newValue: newObj,\n description: `Added ${path}`,\n });\n return changes;\n }\n if (!newObj) {\n changes.push({\n path,\n type: 'removed',\n oldValue: oldObj,\n description: `Removed ${path}`,\n });\n return changes;\n }\n\n const allKeys = new Set([...Object.keys(oldObj), ...Object.keys(newObj)]);\n\n for (const key of allKeys) {\n const keyPath = path ? `${path}.${key}` : key;\n\n // Skip ignored paths\n if (options.ignorePaths?.some((p) => keyPath.startsWith(p))) {\n continue;\n }\n\n const oldVal = oldObj[key];\n const newVal = newObj[key];\n\n if (typeof oldVal === 'object' && typeof newVal === 'object') {\n changes.push(\n ...diffObjects(\n keyPath,\n oldVal as Record<string, unknown>,\n newVal as Record<string, unknown>,\n options\n )\n );\n } else {\n const change = compareValues(\n keyPath,\n oldVal,\n newVal,\n `Changed ${keyPath}`\n );\n if (change) {\n changes.push(change);\n }\n }\n }\n\n return changes;\n}\n\n/**\n * Diff a ContractSpec against an OpenAPI operation.\n */\nexport function diffSpecVsOperation(\n spec: AnyContractSpec,\n operation: ParsedOperation,\n options: DiffOptions = {}\n): DiffChange[] {\n const changes: DiffChange[] = [];\n\n // Compare basic metadata\n if (!options.ignoreDescriptions) {\n const descChange = compareValues(\n 'meta.description',\n spec.meta.description,\n operation.summary ?? operation.description,\n 'Description changed'\n );\n if (descChange) changes.push(descChange);\n }\n\n if (!options.ignoreTags) {\n const oldTags = [...(spec.meta.tags ?? [])].sort();\n const newTags = [...operation.tags].sort();\n if (!deepEqual(oldTags, newTags)) {\n changes.push({\n path: 'meta.tags',\n type: 'modified',\n oldValue: oldTags,\n newValue: newTags,\n description: 'Tags changed',\n });\n }\n }\n\n // Compare transport\n if (!options.ignoreTransport) {\n const specMethod =\n spec.transport?.rest?.method ??\n (spec.meta.kind === 'query' ? 'GET' : 'POST');\n const opMethod = operation.method.toUpperCase();\n\n if (specMethod !== opMethod) {\n changes.push({\n path: 'transport.rest.method',\n type: 'modified',\n oldValue: specMethod,\n newValue: opMethod,\n description: 'HTTP method changed',\n });\n }\n\n const specPath = spec.transport?.rest?.path;\n if (specPath && specPath !== operation.path) {\n changes.push({\n path: 'transport.rest.path',\n type: 'modified',\n oldValue: specPath,\n newValue: operation.path,\n description: 'Path changed',\n });\n }\n }\n\n // Compare deprecation status\n const specDeprecated = spec.meta.stability === 'deprecated';\n if (specDeprecated !== operation.deprecated) {\n changes.push({\n path: 'meta.stability',\n type: 'modified',\n oldValue: spec.meta.stability,\n newValue: operation.deprecated ? 'deprecated' : 'stable',\n description: 'Deprecation status changed',\n });\n }\n\n return changes;\n}\n\n/**\n * Diff two ContractSpecs.\n */\nexport function diffSpecs(\n oldSpec: AnyContractSpec,\n newSpec: AnyContractSpec,\n options: DiffOptions = {}\n): DiffChange[] {\n const changes: DiffChange[] = [];\n\n // Compare meta\n const metaChanges = diffObjects(\n 'meta',\n oldSpec.meta as unknown as Record<string, unknown>,\n newSpec.meta as unknown as Record<string, unknown>,\n {\n ...options,\n ignorePaths: [\n ...(options.ignorePaths ?? []),\n ...(options.ignoreDescriptions\n ? ['meta.description', 'meta.goal', 'meta.context']\n : []),\n ...(options.ignoreTags ? ['meta.tags'] : []),\n ],\n }\n );\n changes.push(...metaChanges);\n\n // Compare transport\n if (!options.ignoreTransport) {\n const transportChanges = diffObjects(\n 'transport',\n oldSpec.transport as unknown as Record<string, unknown>,\n newSpec.transport as unknown as Record<string, unknown>,\n options\n );\n changes.push(...transportChanges);\n }\n\n // Compare policy\n const policyChanges = diffObjects(\n 'policy',\n oldSpec.policy as unknown as Record<string, unknown>,\n newSpec.policy as unknown as Record<string, unknown>,\n options\n );\n changes.push(...policyChanges);\n\n return changes;\n}\n\n/**\n * Create a SpecDiff from an existing spec and an imported spec.\n */\nexport function createSpecDiff(\n operationId: string,\n existing: AnyContractSpec | undefined,\n incoming: ImportedSpec,\n options: DiffOptions = {}\n): SpecDiff {\n let changes: DiffChange[] = [];\n let isEquivalent = false;\n\n if (existing) {\n // Compare existing vs incoming\n changes = diffSpecs(existing, incoming.spec, options);\n isEquivalent = changes.length === 0;\n } else {\n // New spec - mark as added\n changes = [\n {\n path: '',\n type: 'added',\n newValue: incoming.spec,\n description: 'New spec imported from OpenAPI',\n },\n ];\n }\n\n return {\n operationId,\n existing,\n incoming,\n changes,\n isEquivalent,\n };\n}\n\n/**\n * Batch diff multiple specs against OpenAPI operations.\n */\nexport function diffAll(\n existingSpecs: Map<string, AnyContractSpec>,\n importedSpecs: ImportedSpec[],\n options: DiffOptions = {}\n): SpecDiff[] {\n const diffs: SpecDiff[] = [];\n\n // Track which existing specs have been matched\n const matchedExisting = new Set<string>();\n\n for (const imported of importedSpecs) {\n const operationId = imported.source.sourceId;\n\n // Try to find matching existing spec\n // Match by operationId in x-contractspec extension or by name\n let existing: AnyContractSpec | undefined;\n\n for (const [key, spec] of existingSpecs) {\n // Check x-contractspec match or name match\n const specName = spec.meta.name;\n if (key === operationId || specName.includes(operationId)) {\n existing = spec;\n matchedExisting.add(key);\n break;\n }\n }\n\n diffs.push(createSpecDiff(operationId, existing, imported, options));\n }\n\n // Add diffs for existing specs that weren't matched (removed from OpenAPI)\n for (const [key, spec] of existingSpecs) {\n if (!matchedExisting.has(key)) {\n diffs.push({\n operationId: key,\n existing: spec,\n incoming: undefined as unknown as ImportedSpec,\n changes: [\n {\n path: '',\n type: 'removed',\n oldValue: spec,\n description: 'Spec no longer exists in OpenAPI source',\n },\n ],\n isEquivalent: false,\n });\n }\n }\n\n return diffs;\n}\n\n/**\n * Format diff changes for display.\n */\nexport function formatDiffChanges(changes: DiffChange[]): string {\n if (changes.length === 0) {\n return 'No changes detected';\n }\n\n const lines: string[] = [];\n\n for (const change of changes) {\n const prefix = {\n added: '+',\n removed: '-',\n modified: '~',\n type_changed: '!',\n required_changed: '?',\n }[change.type];\n\n lines.push(`${prefix} ${change.path}: ${change.description}`);\n\n if (change.type === 'modified' || change.type === 'type_changed') {\n lines.push(` old: ${JSON.stringify(change.oldValue)}`);\n lines.push(` new: ${JSON.stringify(change.newValue)}`);\n } else if (change.type === 'added') {\n lines.push(` value: ${JSON.stringify(change.newValue)}`);\n } else if (change.type === 'removed') {\n lines.push(` was: ${JSON.stringify(change.oldValue)}`);\n }\n }\n\n return lines.join('\\n');\n}\n"],"mappings":"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"}
@@ -24,4 +24,5 @@ declare function openApiToJson(registry: SpecRegistry, options?: OpenApiExportOp
24
24
  */
25
25
  declare function openApiToYaml(registry: SpecRegistry, options?: OpenApiExportOptions): string;
26
26
  //#endregion
27
- export { defaultRestPath, openApiForRegistry, openApiToJson, openApiToYaml };
27
+ export { defaultRestPath, openApiForRegistry, openApiToJson, openApiToYaml };
28
+ //# sourceMappingURL=exporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exporter.d.ts","names":[],"sources":["../../src/openapi/exporter.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAqH8B,iBAjEd,eAAA,CAiEc,IAAA,EAAA,MAAA,EAAA,OAAA,EAAA,MAAA,CAAA,EAAA,MAAA;AA+F9B;AAWA;;;;;;iBA7GgB,kBAAA,WACJ,wBACD,uBACR;;;;iBA+Fa,aAAA,WACJ,wBACD;;;;iBASK,aAAA,WACJ,wBACD"}
@@ -147,4 +147,5 @@ function jsonToYaml(obj, indent = 0) {
147
147
  }
148
148
 
149
149
  //#endregion
150
- export { defaultRestPath, openApiForRegistry, openApiToJson, openApiToYaml };
150
+ export { defaultRestPath, openApiForRegistry, openApiToJson, openApiToYaml };
151
+ //# sourceMappingURL=exporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exporter.js","names":["doc: ContractSpecOpenApiDocument","op: Record<string, unknown>","responses: Record<string, unknown>"],"sources":["../../src/openapi/exporter.ts"],"sourcesContent":["/**\n * Export ContractSpec specs to OpenAPI 3.1 format.\n * Moved from @lssm/lib.contracts/openapi.ts with enhancements.\n */\n\nimport type {\n SpecRegistry,\n AnyContractSpec,\n ContractSpec,\n} from '@lssm/lib.contracts';\nimport type { AnySchemaModel } from '@lssm/lib.schema';\nimport { z } from 'zod';\nimport type {\n OpenApiExportOptions,\n OpenApiServer,\n ContractSpecOpenApiDocument,\n} from './types';\n\ntype OpenApiSchemaObject = Record<string, unknown>;\n\n/**\n * Convert a spec name and version to an operationId.\n */\nfunction toOperationId(name: string, version: number): string {\n return `${name.replace(/\\./g, '_')}_v${version}`;\n}\n\n/**\n * Convert a spec name and version to a schema name.\n */\nfunction toSchemaName(\n prefix: 'Input' | 'Output',\n name: string,\n version: number\n): string {\n return `${prefix}_${toOperationId(name, version)}`;\n}\n\n/**\n * Determine HTTP method from spec kind and override.\n */\nfunction toHttpMethod(\n kind: 'command' | 'query',\n override?: 'GET' | 'POST'\n): string {\n const method = override ?? (kind === 'query' ? 'GET' : 'POST');\n return method.toLowerCase();\n}\n\n/**\n * Generate default REST path from spec name and version.\n */\nexport function defaultRestPath(name: string, version: number): string {\n return `/${name.replace(/\\./g, '/')}/v${version}`;\n}\n\n/**\n * Get REST path from spec, using transport override or default.\n */\nfunction toRestPath(spec: AnyContractSpec): string {\n const path =\n spec.transport?.rest?.path ??\n defaultRestPath(spec.meta.name, spec.meta.version);\n return path.startsWith('/') ? path : `/${path}`;\n}\n\n/**\n * Convert a SchemaModel to JSON Schema using Zod.\n */\nfunction schemaModelToJsonSchema(\n schema: AnySchemaModel | null\n): OpenApiSchemaObject | null {\n if (!schema) return null;\n return z.toJSONSchema(schema.getZod()) as OpenApiSchemaObject;\n}\n\n/**\n * Extract JSON Schema for a spec's input and output.\n */\nfunction jsonSchemaForSpec(\n spec: ContractSpec<AnySchemaModel, AnySchemaModel>\n): {\n input: OpenApiSchemaObject | null;\n output: OpenApiSchemaObject | null;\n meta: {\n name: string;\n version: number;\n kind: 'command' | 'query';\n description: string;\n tags: string[];\n stability: string;\n };\n} {\n return {\n input: schemaModelToJsonSchema(spec.io.input),\n output: schemaModelToJsonSchema(spec.io.output as AnySchemaModel | null),\n meta: {\n name: spec.meta.name,\n version: spec.meta.version,\n kind: spec.meta.kind,\n description: spec.meta.description,\n tags: spec.meta.tags ?? [],\n stability: spec.meta.stability ?? 'stable',\n },\n };\n}\n\n/**\n * Export a SpecRegistry to an OpenAPI 3.1 document.\n *\n * @param registry - The SpecRegistry containing specs to export\n * @param options - Export options (title, version, description, servers)\n * @returns OpenAPI 3.1 document\n */\nexport function openApiForRegistry(\n registry: SpecRegistry,\n options: OpenApiExportOptions = {}\n): ContractSpecOpenApiDocument {\n const specs = registry\n .listSpecs()\n .filter(\n (s): s is AnyContractSpec =>\n s.meta.kind === 'command' || s.meta.kind === 'query'\n )\n .slice()\n .sort((a, b) => {\n const byName = a.meta.name.localeCompare(b.meta.name);\n return byName !== 0 ? byName : a.meta.version - b.meta.version;\n });\n\n const doc: ContractSpecOpenApiDocument = {\n openapi: '3.1.0',\n info: {\n title: options.title ?? 'ContractSpec API',\n version: options.version ?? '0.0.0',\n ...(options.description ? { description: options.description } : {}),\n },\n ...(options.servers ? { servers: options.servers } : {}),\n paths: {},\n components: { schemas: {} },\n };\n\n for (const spec of specs) {\n const schema = jsonSchemaForSpec(\n spec as unknown as ContractSpec<AnySchemaModel, AnySchemaModel>\n );\n const method = toHttpMethod(spec.meta.kind, spec.transport?.rest?.method);\n const path = toRestPath(spec);\n\n const operationId = toOperationId(spec.meta.name, spec.meta.version);\n\n const pathItem = (doc.paths[path] ??= {});\n const op: Record<string, unknown> = {\n operationId,\n summary: spec.meta.description ?? spec.meta.name,\n description: spec.meta.description,\n tags: spec.meta.tags ?? [],\n 'x-contractspec': {\n name: spec.meta.name,\n version: spec.meta.version,\n kind: spec.meta.kind,\n },\n responses: {},\n };\n\n if (schema.input) {\n const inputName = toSchemaName(\n 'Input',\n spec.meta.name,\n spec.meta.version\n );\n doc.components.schemas[inputName] = schema.input;\n op['requestBody'] = {\n required: true,\n content: {\n 'application/json': {\n schema: { $ref: `#/components/schemas/${inputName}` },\n },\n },\n };\n }\n\n const responses: Record<string, unknown> = {};\n if (schema.output) {\n const outputName = toSchemaName(\n 'Output',\n spec.meta.name,\n spec.meta.version\n );\n doc.components.schemas[outputName] = schema.output;\n responses['200'] = {\n description: 'OK',\n content: {\n 'application/json': {\n schema: { $ref: `#/components/schemas/${outputName}` },\n },\n },\n };\n } else {\n responses['200'] = { description: 'OK' };\n }\n op['responses'] = responses;\n\n pathItem[method] = op;\n }\n\n return doc;\n}\n\n/**\n * Export a SpecRegistry to OpenAPI JSON string.\n */\nexport function openApiToJson(\n registry: SpecRegistry,\n options: OpenApiExportOptions = {}\n): string {\n const doc = openApiForRegistry(registry, options);\n return JSON.stringify(doc, null, 2);\n}\n\n/**\n * Export a SpecRegistry to OpenAPI YAML string.\n */\nexport function openApiToYaml(\n registry: SpecRegistry,\n options: OpenApiExportOptions = {}\n): string {\n const doc = openApiForRegistry(registry, options);\n return jsonToYaml(doc);\n}\n\n/**\n * Simple JSON to YAML conversion.\n */\nfunction jsonToYaml(obj: unknown, indent = 0): string {\n const spaces = ' '.repeat(indent);\n let yaml = '';\n\n if (Array.isArray(obj)) {\n for (const item of obj) {\n if (typeof item === 'object' && item !== null) {\n yaml += `${spaces}-\\n${jsonToYaml(item, indent + 1)}`;\n } else {\n yaml += `${spaces}- ${JSON.stringify(item)}\\n`;\n }\n }\n } else if (typeof obj === 'object' && obj !== null) {\n for (const [key, value] of Object.entries(obj)) {\n if (Array.isArray(value)) {\n yaml += `${spaces}${key}:\\n${jsonToYaml(value, indent + 1)}`;\n } else if (typeof value === 'object' && value !== null) {\n yaml += `${spaces}${key}:\\n${jsonToYaml(value, indent + 1)}`;\n } else {\n yaml += `${spaces}${key}: ${JSON.stringify(value)}\\n`;\n }\n }\n }\n\n return yaml;\n}\n\n// Re-export types for convenience\nexport type {\n OpenApiExportOptions,\n OpenApiServer,\n ContractSpecOpenApiDocument,\n};\n"],"mappings":"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"}
@@ -12,4 +12,5 @@ declare function importFromOpenApi(parseResult: ParseResult, options?: OpenApiIm
12
12
  */
13
13
  declare function importOperation(operation: ParsedOperation, options?: OpenApiImportOptions): string;
14
14
  //#endregion
15
- export { importFromOpenApi, importOperation };
15
+ export { importFromOpenApi, importOperation };
16
+ //# sourceMappingURL=importer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"importer.d.ts","names":[],"sources":["../../src/openapi/importer.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAyagB,iBAjIA,iBAAA,CAkIH,WACF,EAlII,WAkIJ,EAAA,OAAyB,CAAA,EAjIzB,oBAiIyB,CAAA,EAhIjC,YAgIiC;;;;iBAFpB,eAAA,YACH,2BACF"}
@@ -261,4 +261,5 @@ function importOperation(operation, options = {}) {
261
261
  }
262
262
 
263
263
  //#endregion
264
- export { importFromOpenApi, importOperation };
264
+ export { importFromOpenApi, importOperation };
265
+ //# sourceMappingURL=importer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"importer.js","names":["fields: {\n name: string;\n schema: OpenApiSchema;\n required: boolean;\n }[]","lines: string[]","specs: ImportedSpec[]","skipped: ImportResult['skipped']","errors: ImportResult['errors']","transportHints: OpenApiTransportHints","source: OpenApiSource"],"sources":["../../src/openapi/importer.ts"],"sourcesContent":["/**\n * Import OpenAPI specifications into ContractSpec format.\n * Converts OpenAPI operations to ContractSpec command/query definitions.\n */\n\nimport type {\n OpenApiImportOptions,\n ParseResult,\n ParsedOperation,\n OpenApiSchema,\n OpenApiTransportHints,\n OpenApiSource,\n} from './types';\nimport type { ImportResult, ImportedSpec } from '../common/types';\nimport {\n toSpecName,\n toFileName,\n toPascalCase,\n toValidIdentifier,\n} from '../common/utils';\nimport {\n generateSchemaModelCode,\n generateImports,\n type GeneratedModel,\n} from './schema-converter';\n\n/**\n * HTTP methods that typically indicate a command (state-changing).\n */\nconst COMMAND_METHODS = ['post', 'put', 'delete', 'patch'];\n\n/**\n * Determine if an operation is a command or query based on HTTP method.\n */\nfunction inferOpKind(method: string): 'command' | 'query' {\n return COMMAND_METHODS.includes(method.toLowerCase()) ? 'command' : 'query';\n}\n\n/**\n * Determine auth level based on security requirements.\n */\nfunction inferAuthLevel(\n operation: ParsedOperation,\n defaultAuth: 'anonymous' | 'user' | 'admin'\n): 'anonymous' | 'user' | 'admin' {\n if (!operation.security || operation.security.length === 0) {\n // Check if any security scheme is present\n return defaultAuth;\n }\n\n // If there's an empty security requirement, it's anonymous\n for (const sec of operation.security) {\n if (Object.keys(sec).length === 0) {\n return 'anonymous';\n }\n }\n\n return 'user';\n}\n\n/**\n * Build a merged input schema from all parameter sources.\n */\nfunction buildInputSchema(operation: ParsedOperation): {\n schema: OpenApiSchema | null;\n fields: { name: string; schema: OpenApiSchema; required: boolean }[];\n} {\n const fields: {\n name: string;\n schema: OpenApiSchema;\n required: boolean;\n }[] = [];\n\n // Add path parameters\n for (const param of operation.pathParams) {\n fields.push({\n name: param.name,\n schema: param.schema,\n required: true, // Path params are always required\n });\n }\n\n // Add query parameters\n for (const param of operation.queryParams) {\n fields.push({\n name: param.name,\n schema: param.schema,\n required: param.required,\n });\n }\n\n // Add header parameters (excluding common headers)\n const excludedHeaders = [\n 'authorization',\n 'content-type',\n 'accept',\n 'user-agent',\n ];\n for (const param of operation.headerParams) {\n if (!excludedHeaders.includes(param.name.toLowerCase())) {\n fields.push({\n name: param.name,\n schema: param.schema,\n required: param.required,\n });\n }\n }\n\n // Add request body fields\n if (operation.requestBody?.schema) {\n const bodySchema = operation.requestBody.schema;\n if (!('$ref' in bodySchema)) {\n const schemaObj = bodySchema as Record<string, unknown>;\n const properties = schemaObj['properties'] as\n | Record<string, OpenApiSchema>\n | undefined;\n const required = (schemaObj['required'] as string[]) ?? [];\n\n if (properties) {\n for (const [propName, propSchema] of Object.entries(properties)) {\n fields.push({\n name: propName,\n schema: propSchema,\n required: required.includes(propName),\n });\n }\n }\n } else {\n // Reference to a schema - add as a single field\n fields.push({\n name: 'body',\n schema: bodySchema,\n required: operation.requestBody.required,\n });\n }\n }\n\n if (fields.length === 0) {\n return { schema: null, fields: [] };\n }\n\n // Build a merged schema\n const mergedSchema: OpenApiSchema = {\n type: 'object',\n properties: fields.reduce(\n (acc, f) => {\n acc[f.name] = f.schema;\n return acc;\n },\n {} as Record<string, OpenApiSchema>\n ),\n required: fields.filter((f) => f.required).map((f) => f.name),\n } as unknown as OpenApiSchema;\n\n return { schema: mergedSchema, fields };\n}\n\n/**\n * Get the output schema from the operation responses.\n */\nfunction getOutputSchema(operation: ParsedOperation): OpenApiSchema | null {\n // Prefer 200, then 201, then 2xx responses\n const successCodes = ['200', '201', '202', '204'];\n\n for (const code of successCodes) {\n const response = operation.responses[code];\n if (response?.schema) {\n return response.schema;\n }\n }\n\n // Check for any 2xx response\n for (const [code, response] of Object.entries(operation.responses)) {\n if (code.startsWith('2') && response.schema) {\n return response.schema;\n }\n }\n\n return null;\n}\n\n/**\n * Generate ContractSpec TypeScript code for an operation.\n */\nfunction generateSpecCode(\n operation: ParsedOperation,\n options: OpenApiImportOptions,\n inputModel: GeneratedModel | null,\n outputModel: GeneratedModel | null\n): string {\n const specName = toSpecName(operation.operationId, options.prefix);\n const kind = inferOpKind(operation.method);\n const auth = inferAuthLevel(operation, options.defaultAuth ?? 'user');\n\n const lines: string[] = [];\n\n // Imports\n lines.push(\n \"import { defineCommand, defineQuery } from '@lssm/lib.contracts';\"\n );\n if (inputModel || outputModel) {\n lines.push(\n generateImports([\n ...(inputModel?.fields ?? []),\n ...(outputModel?.fields ?? []),\n ])\n );\n }\n lines.push('');\n\n // Generate input model if present\n if (inputModel && inputModel.code) {\n lines.push('// Input schema');\n lines.push(inputModel.code);\n lines.push('');\n }\n\n // Generate output model if present\n if (outputModel && outputModel.code) {\n lines.push('// Output schema');\n lines.push(outputModel.code);\n lines.push('');\n }\n\n // Generate spec\n const defineFunc = kind === 'command' ? 'defineCommand' : 'defineQuery';\n const safeName = toValidIdentifier(toPascalCase(operation.operationId));\n\n lines.push(`/**`);\n lines.push(` * ${operation.summary ?? operation.operationId}`);\n if (operation.description) {\n lines.push(` *`);\n lines.push(` * ${operation.description}`);\n }\n lines.push(` *`);\n lines.push(\n ` * @source OpenAPI: ${operation.method.toUpperCase()} ${operation.path}`\n );\n lines.push(` */`);\n lines.push(`export const ${safeName}Spec = ${defineFunc}({`);\n\n // Meta\n lines.push(' meta: {');\n lines.push(` name: '${specName}',`);\n lines.push(' version: 1,');\n lines.push(` stability: '${options.defaultStability ?? 'stable'}',`);\n lines.push(\n ` owners: [${(options.defaultOwners ?? []).map((o) => `'${o}'`).join(', ')}],`\n );\n lines.push(` tags: [${operation.tags.map((t) => `'${t}'`).join(', ')}],`);\n lines.push(\n ` description: ${JSON.stringify(operation.summary ?? operation.operationId)},`\n );\n lines.push(\n ` goal: ${JSON.stringify(operation.description ?? 'Imported from OpenAPI')},`\n );\n lines.push(\n ` context: 'Imported from OpenAPI: ${operation.method.toUpperCase()} ${operation.path}',`\n );\n lines.push(' },');\n\n // IO\n lines.push(' io: {');\n if (inputModel) {\n lines.push(` input: ${inputModel.name},`);\n } else {\n lines.push(' input: null,');\n }\n if (outputModel) {\n lines.push(` output: ${outputModel.name},`);\n } else {\n lines.push(' output: null, // TODO: Define output schema');\n }\n lines.push(' },');\n\n // Policy\n lines.push(' policy: {');\n lines.push(` auth: '${auth}',`);\n lines.push(' },');\n\n // Transport hints\n lines.push(' transport: {');\n lines.push(' rest: {');\n lines.push(` method: '${operation.method.toUpperCase()}',`);\n lines.push(` path: '${operation.path}',`);\n lines.push(' },');\n lines.push(' },');\n\n lines.push('});');\n\n return lines.join('\\n');\n}\n\n/**\n * Import operations from a parsed OpenAPI document.\n */\nexport function importFromOpenApi(\n parseResult: ParseResult,\n options: OpenApiImportOptions = {}\n): ImportResult {\n const { tags, exclude = [], include } = options;\n const specs: ImportedSpec[] = [];\n const skipped: ImportResult['skipped'] = [];\n const errors: ImportResult['errors'] = [];\n\n for (const operation of parseResult.operations) {\n // Filter by tags if specified\n if (tags && tags.length > 0) {\n const hasMatchingTag = operation.tags.some((t) => tags.includes(t));\n if (!hasMatchingTag) {\n skipped.push({\n sourceId: operation.operationId,\n reason: `No matching tags (has: ${operation.tags.join(', ')})`,\n });\n continue;\n }\n }\n\n // Filter by include/exclude\n if (include && include.length > 0) {\n if (!include.includes(operation.operationId)) {\n skipped.push({\n sourceId: operation.operationId,\n reason: 'Not in include list',\n });\n continue;\n }\n } else if (exclude.includes(operation.operationId)) {\n skipped.push({\n sourceId: operation.operationId,\n reason: 'In exclude list',\n });\n continue;\n }\n\n // Skip deprecated operations by default\n if (operation.deprecated && options.defaultStability !== 'deprecated') {\n skipped.push({\n sourceId: operation.operationId,\n reason: 'Deprecated operation',\n });\n continue;\n }\n\n try {\n // Build input schema\n const { schema: inputSchema } = buildInputSchema(operation);\n const inputModel = inputSchema\n ? generateSchemaModelCode(inputSchema, `${operation.operationId}Input`)\n : null;\n\n // Get output schema\n const outputSchema = getOutputSchema(operation);\n const outputModel = outputSchema\n ? generateSchemaModelCode(\n outputSchema,\n `${operation.operationId}Output`\n )\n : null;\n\n // Generate spec code\n const code = generateSpecCode(\n operation,\n options,\n inputModel,\n outputModel\n );\n const specName = toSpecName(operation.operationId, options.prefix);\n const fileName = toFileName(specName);\n\n // Build transport hints\n const transportHints: OpenApiTransportHints = {\n rest: {\n method:\n operation.method.toUpperCase() as OpenApiTransportHints['rest']['method'],\n path: operation.path,\n params: {\n path: operation.pathParams.map((p) => p.name),\n query: operation.queryParams.map((p) => p.name),\n header: operation.headerParams.map((p) => p.name),\n cookie: operation.cookieParams.map((p) => p.name),\n },\n },\n };\n\n // Build source info\n const source: OpenApiSource = {\n type: 'openapi',\n sourceId: operation.operationId,\n operationId: operation.operationId,\n openApiVersion: parseResult.version,\n importedAt: new Date(),\n };\n\n specs.push({\n spec: {} as ImportedSpec['spec'], // Placeholder - actual spec would be built at runtime\n code,\n fileName,\n source,\n transportHints,\n });\n } catch (error) {\n errors.push({\n sourceId: operation.operationId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n return {\n specs,\n skipped,\n errors,\n summary: {\n total: parseResult.operations.length,\n imported: specs.length,\n skipped: skipped.length,\n errors: errors.length,\n },\n };\n}\n\n/**\n * Import a single operation to ContractSpec code.\n */\nexport function importOperation(\n operation: ParsedOperation,\n options: OpenApiImportOptions = {}\n): string {\n const { schema: inputSchema } = buildInputSchema(operation);\n const inputModel = inputSchema\n ? generateSchemaModelCode(inputSchema, `${operation.operationId}Input`)\n : null;\n\n const outputSchema = getOutputSchema(operation);\n const outputModel = outputSchema\n ? generateSchemaModelCode(outputSchema, `${operation.operationId}Output`)\n : null;\n\n return generateSpecCode(operation, options, inputModel, outputModel);\n}\n"],"mappings":"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"}
@@ -28,4 +28,5 @@ declare function parseOpenApi(source: string, options?: OpenApiParseOptions & {
28
28
  readFile?: (path: string) => Promise<string>;
29
29
  }): Promise<ParseResult>;
30
30
  //#endregion
31
- export { detectFormat, detectVersion, parseOpenApi, parseOpenApiDocument, parseOpenApiString };
31
+ export { detectFormat, detectVersion, parseOpenApi, parseOpenApiDocument, parseOpenApiString };
32
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","names":[],"sources":["../../src/openapi/parser.ts"],"sourcesContent":[],"mappings":";;;;AA0DA;AAmNA;;AAEY,iBA7OI,kBAAA,CA6OJ,OAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAAA,MAAA,GAAA,MAAA,CAAA,EA1OT,eA0OS;;;AA2EZ;AAEW,iBA7SK,YAAA,CA6SL,OAAA,EAAA,MAAA,CAAA,EAAA,MAAA,GAAA,MAAA;;;;AAIR,iBAtSa,aAAA,CAsSb,GAAA,EAtSgC,eAsShC,CAAA,EAtSkD,cAsSlD;;;;iBAnFa,oBAAA,MACT,4BACK,sBACT;;;;;;iBA0EmB,YAAA,2BAEX;iBACQ,UAAA,CAAW;+BACG;IAE9B,QAAQ"}
@@ -228,4 +228,5 @@ async function parseOpenApi(source, options = {}) {
228
228
  }
229
229
 
230
230
  //#endregion
231
- export { detectFormat, detectVersion, parseOpenApi, parseOpenApiDocument, parseOpenApiString };
231
+ export { detectFormat, detectVersion, parseOpenApi, parseOpenApiDocument, parseOpenApiString };
232
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","names":["HTTP_METHODS: HttpMethod[]","parseYaml","current: unknown","resolved: OpenAPIV3.ParameterObject | OpenAPIV3_1.ParameterObject","parsed: ParsedParameter","requestBody: ParsedOperation['requestBody']","responses: ParsedOperation['responses']","warnings: string[]","operations: ParsedOperation[]","schemas: Record<string, OpenApiSchema>","servers: OpenApiServer[]","content: string","format: 'json' | 'yaml'"],"sources":["../../src/openapi/parser.ts"],"sourcesContent":["/**\n * OpenAPI document parser.\n * Parses OpenAPI 3.x documents from JSON/YAML files or URLs.\n */\n\nimport { parse as parseYaml } from 'yaml';\nimport type {\n OpenApiDocument,\n OpenApiParseOptions,\n ParseResult,\n ParsedOperation,\n ParsedParameter,\n HttpMethod,\n OpenApiVersion,\n OpenApiSchema,\n OpenApiParameter,\n OpenApiServer,\n} from './types';\nimport type { OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';\n\nconst HTTP_METHODS: HttpMethod[] = [\n 'get',\n 'post',\n 'put',\n 'delete',\n 'patch',\n 'head',\n 'options',\n 'trace',\n];\n\n/**\n * Parse an OpenAPI document from a string (JSON or YAML).\n */\nexport function parseOpenApiString(\n content: string,\n format: 'json' | 'yaml' = 'json'\n): OpenApiDocument {\n if (format === 'yaml') {\n return parseYaml(content) as OpenApiDocument;\n }\n return JSON.parse(content) as OpenApiDocument;\n}\n\n/**\n * Detect the format of content (JSON or YAML).\n */\nexport function detectFormat(content: string): 'json' | 'yaml' {\n const trimmed = content.trim();\n if (trimmed.startsWith('{') || trimmed.startsWith('[')) {\n return 'json';\n }\n return 'yaml';\n}\n\n/**\n * Detect OpenAPI version from document.\n */\nexport function detectVersion(doc: OpenApiDocument): OpenApiVersion {\n const version = doc.openapi;\n if (version.startsWith('3.1')) {\n return '3.1';\n }\n return '3.0';\n}\n\n/**\n * Check if a value is a reference object.\n */\nfunction isReference(\n obj: unknown\n): obj is OpenAPIV3.ReferenceObject | OpenAPIV3_1.ReferenceObject {\n return typeof obj === 'object' && obj !== null && '$ref' in obj;\n}\n\n/**\n * Resolve a $ref reference in the document.\n */\nfunction resolveRef<T>(doc: OpenApiDocument, ref: string): T | undefined {\n // Only support local refs for now\n if (!ref.startsWith('#/')) {\n return undefined;\n }\n\n const path = ref.slice(2).split('/');\n let current: unknown = doc;\n\n for (const part of path) {\n if (current === null || current === undefined) return undefined;\n if (typeof current !== 'object') return undefined;\n current = (current as Record<string, unknown>)[part];\n }\n\n return current as T;\n}\n\n/**\n * Resolve a schema, following $ref if needed.\n */\nfunction resolveSchema(\n doc: OpenApiDocument,\n schema: OpenApiSchema | undefined\n): OpenApiSchema | undefined {\n if (!schema) return undefined;\n if (isReference(schema)) {\n return resolveRef<OpenApiSchema>(doc, schema.$ref) ?? schema;\n }\n return schema;\n}\n\n/**\n * Parse parameters from an operation.\n */\nfunction parseParameters(\n doc: OpenApiDocument,\n params: OpenApiParameter[] | undefined\n): {\n path: ParsedParameter[];\n query: ParsedParameter[];\n header: ParsedParameter[];\n cookie: ParsedParameter[];\n} {\n const result = {\n path: [] as ParsedParameter[],\n query: [] as ParsedParameter[],\n header: [] as ParsedParameter[],\n cookie: [] as ParsedParameter[],\n };\n\n if (!params) return result;\n\n for (const param of params) {\n let resolved: OpenAPIV3.ParameterObject | OpenAPIV3_1.ParameterObject;\n\n if (isReference(param)) {\n const ref = resolveRef<\n OpenAPIV3.ParameterObject | OpenAPIV3_1.ParameterObject\n >(doc, param.$ref);\n if (!ref) continue;\n resolved = ref;\n } else {\n resolved = param;\n }\n\n const parsed: ParsedParameter = {\n name: resolved.name,\n in: resolved.in as ParsedParameter['in'],\n required: resolved.required ?? resolved.in === 'path',\n description: resolved.description,\n schema: resolved.schema as OpenApiSchema,\n deprecated: resolved.deprecated ?? false,\n };\n\n result[resolved.in as keyof typeof result]?.push(parsed);\n }\n\n return result;\n}\n\n/**\n * Generate an operationId if not present.\n */\nfunction generateOperationId(method: HttpMethod, path: string): string {\n // Convert path to camelCase operationId\n const pathParts = path\n .split('/')\n .filter(Boolean)\n .map((part) => {\n // Remove path parameters\n if (part.startsWith('{') && part.endsWith('}')) {\n return (\n 'By' + part.slice(1, -1).charAt(0).toUpperCase() + part.slice(2, -1)\n );\n }\n return part.charAt(0).toUpperCase() + part.slice(1);\n });\n\n return method + pathParts.join('');\n}\n\n/**\n * Parse a single operation.\n */\nfunction parseOperation(\n doc: OpenApiDocument,\n method: HttpMethod,\n path: string,\n operation: OpenAPIV3.OperationObject | OpenAPIV3_1.OperationObject,\n pathParams: OpenApiParameter[] | undefined\n): ParsedOperation {\n // Merge path-level and operation-level parameters\n const allParams = [...(pathParams ?? []), ...(operation.parameters ?? [])];\n const params = parseParameters(doc, allParams as OpenApiParameter[]);\n\n // Parse request body\n let requestBody: ParsedOperation['requestBody'];\n if (operation.requestBody) {\n const body = isReference(operation.requestBody)\n ? resolveRef<OpenAPIV3.RequestBodyObject | OpenAPIV3_1.RequestBodyObject>(\n doc,\n operation.requestBody.$ref\n )\n : operation.requestBody;\n\n if (body) {\n const contentType =\n Object.keys(body.content ?? {})[0] ?? 'application/json';\n const content = body.content?.[contentType];\n if (content?.schema) {\n requestBody = {\n required: body.required ?? false,\n schema: resolveSchema(doc, content.schema as OpenApiSchema)!,\n contentType,\n };\n }\n }\n }\n\n // Parse responses\n const responses: ParsedOperation['responses'] = {};\n for (const [status, response] of Object.entries(operation.responses ?? {})) {\n const resolved = isReference(response)\n ? resolveRef<OpenAPIV3.ResponseObject | OpenAPIV3_1.ResponseObject>(\n doc,\n response.$ref\n )\n : response;\n\n if (resolved) {\n const contentType = Object.keys(resolved.content ?? {})[0];\n const content = contentType ? resolved.content?.[contentType] : undefined;\n\n responses[status] = {\n description: resolved.description,\n schema: content?.schema\n ? resolveSchema(doc, content.schema as OpenApiSchema)\n : undefined,\n contentType,\n };\n }\n }\n\n // Check for x-contractspec extension\n const contractSpecMeta = (operation as Record<string, unknown>)?.[\n 'x-contractspec'\n ] as ParsedOperation['contractSpecMeta'];\n\n return {\n operationId: operation.operationId ?? generateOperationId(method, path),\n method,\n path,\n summary: operation.summary,\n description: operation.description,\n tags: operation.tags ?? [],\n pathParams: params.path,\n queryParams: params.query,\n headerParams: params.header,\n cookieParams: params.cookie,\n requestBody,\n responses,\n deprecated: operation.deprecated ?? false,\n security: operation.security as ParsedOperation['security'],\n contractSpecMeta,\n };\n}\n\n/**\n * Parse an OpenAPI document into a structured result.\n */\nexport function parseOpenApiDocument(\n doc: OpenApiDocument,\n _options: OpenApiParseOptions = {}\n): ParseResult {\n const version = detectVersion(doc);\n const warnings: string[] = [];\n const operations: ParsedOperation[] = [];\n\n // Parse operations from paths\n for (const [path, pathItem] of Object.entries(doc.paths ?? {})) {\n if (!pathItem) continue;\n\n // Get path-level parameters\n const pathParams = (pathItem as OpenAPIV3.PathItemObject).parameters;\n\n for (const method of HTTP_METHODS) {\n const operation = (pathItem as Record<string, unknown>)[method] as\n | OpenAPIV3.OperationObject\n | OpenAPIV3_1.OperationObject\n | undefined;\n\n if (operation) {\n try {\n operations.push(\n parseOperation(\n doc,\n method,\n path,\n operation,\n pathParams as OpenApiParameter[]\n )\n );\n } catch (error) {\n warnings.push(\n `Failed to parse ${method.toUpperCase()} ${path}: ${error}`\n );\n }\n }\n }\n }\n\n // Extract component schemas\n const schemas: Record<string, OpenApiSchema> = {};\n const components = doc.components;\n if (components?.schemas) {\n for (const [name, schema] of Object.entries(components.schemas)) {\n schemas[name] = schema as OpenApiSchema;\n }\n }\n\n // Parse servers\n const servers: OpenApiServer[] = (doc.servers ?? []).map((s) => ({\n url: s.url,\n description: s.description,\n variables: s.variables as OpenApiServer['variables'],\n }));\n\n return {\n document: doc,\n version,\n info: {\n title: doc.info.title,\n version: doc.info.version,\n description: doc.info.description,\n },\n operations,\n schemas,\n servers,\n warnings,\n };\n}\n\n/**\n * Parse OpenAPI from a file path or URL.\n * Note: This is an async function that requires I/O adapters.\n * For pure parsing, use parseOpenApiString or parseOpenApiDocument.\n */\nexport async function parseOpenApi(\n source: string,\n options: OpenApiParseOptions & {\n fetch?: typeof globalThis.fetch;\n readFile?: (path: string) => Promise<string>;\n } = {}\n): Promise<ParseResult> {\n const {\n fetch: fetchFn = globalThis.fetch,\n readFile,\n timeout = 30000,\n } = options;\n\n let content: string;\n let format: 'json' | 'yaml';\n\n if (source.startsWith('http://') || source.startsWith('https://')) {\n // Fetch from URL\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetchFn(source, { signal: controller.signal });\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n content = await response.text();\n } finally {\n clearTimeout(timeoutId);\n }\n\n // Detect format from URL or content\n if (source.endsWith('.yaml') || source.endsWith('.yml')) {\n format = 'yaml';\n } else if (source.endsWith('.json')) {\n format = 'json';\n } else {\n format = detectFormat(content);\n }\n } else {\n // Read from file\n if (!readFile) {\n throw new Error('readFile adapter required for file paths');\n }\n content = await readFile(source);\n\n // Detect format from extension or content\n if (source.endsWith('.yaml') || source.endsWith('.yml')) {\n format = 'yaml';\n } else if (source.endsWith('.json')) {\n format = 'json';\n } else {\n format = detectFormat(content);\n }\n }\n\n const doc = parseOpenApiString(content, format);\n return parseOpenApiDocument(doc, options);\n}\n"],"mappings":"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"}
@@ -66,4 +66,5 @@ declare function generateSchemaModelCode(schema: OpenApiSchema, modelName: strin
66
66
  */
67
67
  declare function generateImports(fields: SchemaField[]): string;
68
68
  //#endregion
69
- export { GeneratedModel, SchemaField, TypescriptType, generateImports, generateSchemaModelCode, getScalarType, jsonSchemaToField, jsonSchemaToType };
69
+ export { GeneratedModel, SchemaField, TypescriptType, generateImports, generateSchemaModelCode, getScalarType, jsonSchemaToField, jsonSchemaToType };
70
+ //# sourceMappingURL=schema-converter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-converter.d.ts","names":[],"sources":["../../src/openapi/schema-converter.ts"],"sourcesContent":[],"mappings":";;;;AA2CA;AA6CA;AAgGA;AAkBgB,UA/LC,cAAA,CA+LgB;EAmCjB;EAgHA,IAAA,EAAA,MAAA;;;;;;;;;;;;;UAlUC,WAAA;;;;QAIT;;;;;;gBAMQ;;;;;UAMC,cAAA;;;;;;UAMP;;;;;;;iBAuCM,gBAAA,SACN,+BAEP;;;;iBA6Fa,aAAA,SAAsB;;;;iBAkBtB,iBAAA,SACN,sDAGP;;;;iBA+Ba,uBAAA,SACN,oDAGP;;;;iBA4Ga,eAAA,SAAwB"}
@@ -198,4 +198,5 @@ function generateImports(fields) {
198
198
  }
199
199
 
200
200
  //#endregion
201
- export { generateImports, generateSchemaModelCode, getScalarType, jsonSchemaToField, jsonSchemaToType };
201
+ export { generateImports, generateSchemaModelCode, getScalarType, jsonSchemaToField, jsonSchemaToType };
202
+ //# sourceMappingURL=schema-converter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-converter.js","names":["JSON_SCHEMA_TO_SCALAR: Record<string, string>","enumValues: string[] | undefined","fields: SchemaField[]","description: string | undefined","lines: string[]"],"sources":["../../src/openapi/schema-converter.ts"],"sourcesContent":["/**\n * JSON Schema to SchemaModel conversion utilities.\n * Converts OpenAPI JSON Schema to ContractSpec SchemaModel definitions.\n */\n\nimport type { OpenApiSchema } from './types';\nimport { toPascalCase, toCamelCase, toValidIdentifier } from '../common/utils';\n\n/**\n * TypeScript type representation for code generation.\n */\nexport interface TypescriptType {\n /** The type expression (e.g., \"string\", \"number\", \"MyModel\") */\n type: string;\n /** Whether the type is optional */\n optional: boolean;\n /** Whether the type is an array */\n array: boolean;\n /** Whether this is a primitive type */\n primitive: boolean;\n /** Description for documentation */\n description?: string;\n}\n\n/**\n * SchemaModel field representation for code generation.\n */\nexport interface SchemaField {\n /** Field name */\n name: string;\n /** Field type */\n type: TypescriptType;\n /** Scalar type enum value (for FieldType) */\n scalarType?: string;\n /** Enum values if this is an enum type */\n enumValues?: string[];\n /** Nested model if this is an object type */\n nestedModel?: GeneratedModel;\n}\n\n/**\n * Generated model representation.\n */\nexport interface GeneratedModel {\n /** Model name (PascalCase) */\n name: string;\n /** Model description */\n description?: string;\n /** Fields */\n fields: SchemaField[];\n /** Generated TypeScript code */\n code: string;\n}\n\n/**\n * Map JSON Schema types to ContractSpec ScalarTypeEnum values.\n */\nconst JSON_SCHEMA_TO_SCALAR: Record<string, string> = {\n string: 'ScalarTypeEnum.STRING',\n integer: 'ScalarTypeEnum.INT',\n number: 'ScalarTypeEnum.FLOAT',\n boolean: 'ScalarTypeEnum.BOOLEAN',\n // Special formats\n 'string:date': 'ScalarTypeEnum.DATE',\n 'string:date-time': 'ScalarTypeEnum.DATE_TIME',\n 'string:email': 'ScalarTypeEnum.EMAIL',\n 'string:uri': 'ScalarTypeEnum.URL',\n 'string:uuid': 'ScalarTypeEnum.ID',\n};\n\n/**\n * Check if a schema is a reference object.\n */\nfunction isReference(schema: OpenApiSchema): schema is { $ref: string } {\n return '$ref' in schema;\n}\n\n/**\n * Extract type name from a $ref.\n */\nfunction typeNameFromRef(ref: string): string {\n const parts = ref.split('/');\n return parts[parts.length - 1] ?? 'Unknown';\n}\n\n/**\n * Convert a JSON Schema to a TypeScript type representation.\n */\nexport function jsonSchemaToType(\n schema: OpenApiSchema,\n name?: string\n): TypescriptType {\n if (isReference(schema)) {\n return {\n type: toPascalCase(typeNameFromRef(schema.$ref)),\n optional: false,\n array: false,\n primitive: false,\n };\n }\n\n const schemaObj = schema as Record<string, unknown>;\n const type = schemaObj['type'] as string | undefined;\n const format = schemaObj['format'] as string | undefined;\n const nullable = schemaObj['nullable'] as boolean | undefined;\n\n // Handle arrays\n if (type === 'array') {\n const items = schemaObj['items'] as OpenApiSchema | undefined;\n if (items) {\n const itemType = jsonSchemaToType(items, name);\n return {\n ...itemType,\n array: true,\n optional: nullable ?? false,\n };\n }\n return {\n type: 'unknown',\n optional: nullable ?? false,\n array: true,\n primitive: false,\n };\n }\n\n // Handle objects\n if (type === 'object' || schemaObj['properties']) {\n return {\n type: name ? toPascalCase(name) : 'Record<string, unknown>',\n optional: nullable ?? false,\n array: false,\n primitive: false,\n };\n }\n\n // Handle enums\n if (schemaObj['enum']) {\n return {\n type: name ? toPascalCase(name) : 'string',\n optional: nullable ?? false,\n array: false,\n primitive: false,\n };\n }\n\n // Handle primitives\n const scalarKey = format ? `${type}:${format}` : type;\n if (type === 'string') {\n return {\n type: 'string',\n optional: nullable ?? false,\n array: false,\n primitive: true,\n };\n }\n if (type === 'integer' || type === 'number') {\n return {\n type: 'number',\n optional: nullable ?? false,\n array: false,\n primitive: true,\n };\n }\n if (type === 'boolean') {\n return {\n type: 'boolean',\n optional: nullable ?? false,\n array: false,\n primitive: true,\n };\n }\n\n // Default to unknown\n return {\n type: 'unknown',\n optional: nullable ?? false,\n array: false,\n primitive: false,\n };\n}\n\n/**\n * Get the ScalarTypeEnum value for a JSON Schema type.\n */\nexport function getScalarType(schema: OpenApiSchema): string | undefined {\n if (isReference(schema)) {\n return undefined;\n }\n\n const schemaObj = schema as Record<string, unknown>;\n const type = schemaObj['type'] as string | undefined;\n const format = schemaObj['format'] as string | undefined;\n\n if (!type) return undefined;\n\n const key = format ? `${type}:${format}` : type;\n return JSON_SCHEMA_TO_SCALAR[key] ?? JSON_SCHEMA_TO_SCALAR[type];\n}\n\n/**\n * Convert a JSON Schema to a SchemaModel field definition.\n */\nexport function jsonSchemaToField(\n schema: OpenApiSchema,\n fieldName: string,\n required: boolean\n): SchemaField {\n const type = jsonSchemaToType(schema, fieldName);\n const scalarType = getScalarType(schema);\n\n // Handle enums\n let enumValues: string[] | undefined;\n if (!isReference(schema)) {\n const schemaObj = schema as Record<string, unknown>;\n const enumArr = schemaObj['enum'] as unknown[] | undefined;\n if (enumArr) {\n enumValues = enumArr.map(String);\n }\n }\n\n return {\n name: toValidIdentifier(toCamelCase(fieldName)),\n type: {\n ...type,\n optional: !required || type.optional,\n description: !isReference(schema)\n ? ((schema as Record<string, unknown>)['description'] as string)\n : undefined,\n },\n scalarType,\n enumValues,\n };\n}\n\n/**\n * Generate SchemaModel TypeScript code for a JSON Schema object.\n */\nexport function generateSchemaModelCode(\n schema: OpenApiSchema,\n modelName: string,\n indent = 0\n): GeneratedModel {\n const spaces = ' '.repeat(indent);\n const fields: SchemaField[] = [];\n let description: string | undefined;\n\n if (isReference(schema)) {\n // Reference type - just use the referenced type\n return {\n name: toPascalCase(typeNameFromRef(schema.$ref)),\n fields: [],\n code: `// Reference to ${schema.$ref}`,\n };\n }\n\n const schemaObj = schema as Record<string, unknown>;\n description = schemaObj['description'] as string | undefined;\n const properties = schemaObj['properties'] as\n | Record<string, OpenApiSchema>\n | undefined;\n const required = (schemaObj['required'] as string[]) ?? [];\n\n if (!properties) {\n // No properties - generate an empty model or type alias\n return {\n name: toPascalCase(modelName),\n description,\n fields: [],\n code: `${spaces}// Empty schema for ${modelName}`,\n };\n }\n\n // Generate fields\n for (const [propName, propSchema] of Object.entries(properties)) {\n const isRequired = required.includes(propName);\n fields.push(jsonSchemaToField(propSchema, propName, isRequired));\n }\n\n // Generate code\n const lines: string[] = [];\n\n // Model definition\n const safeModelName = toPascalCase(toValidIdentifier(modelName));\n lines.push(`${spaces}export const ${safeModelName} = defineSchemaModel({`);\n lines.push(`${spaces} name: '${safeModelName}',`);\n if (description) {\n lines.push(`${spaces} description: ${JSON.stringify(description)},`);\n }\n lines.push(`${spaces} fields: {`);\n\n for (const field of fields) {\n const fieldLines = generateFieldCode(field, indent + 2);\n lines.push(fieldLines);\n }\n\n lines.push(`${spaces} },`);\n lines.push(`${spaces}});`);\n\n return {\n name: safeModelName,\n description,\n fields,\n code: lines.join('\\n'),\n };\n}\n\n/**\n * Generate TypeScript code for a single field.\n */\nfunction generateFieldCode(field: SchemaField, indent: number): string {\n const spaces = ' '.repeat(indent);\n const lines: string[] = [];\n\n lines.push(`${spaces}${field.name}: {`);\n\n // Type\n if (field.enumValues) {\n // Enum type\n lines.push(\n `${spaces} type: new EnumType([${field.enumValues.map((v) => `'${v}'`).join(', ')}]),`\n );\n } else if (field.scalarType) {\n // Scalar type\n lines.push(`${spaces} type: ${field.scalarType},`);\n } else {\n // Nested model or reference\n lines.push(\n `${spaces} type: ${field.type.type}, // TODO: Define or import this type`\n );\n }\n\n // Optional\n if (field.type.optional) {\n lines.push(`${spaces} isOptional: true,`);\n }\n\n // Array\n if (field.type.array) {\n lines.push(`${spaces} isArray: true,`);\n }\n\n lines.push(`${spaces}},`);\n\n return lines.join('\\n');\n}\n\n/**\n * Generate import statements for a SchemaModel.\n */\nexport function generateImports(fields: SchemaField[]): string {\n const imports = new Set<string>();\n\n imports.add(\n \"import { defineSchemaModel, ScalarTypeEnum, EnumType } from '@lssm/lib.schema';\"\n );\n\n // Check if we need any custom type imports\n for (const field of fields) {\n if (!field.type.primitive && !field.enumValues && !field.scalarType) {\n // This is a reference to another model - would need import\n // imports.add(`import { ${field.type.type} } from './${toKebabCase(field.type.type)}';`);\n }\n }\n\n return Array.from(imports).join('\\n');\n}\n"],"mappings":"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"}
@@ -127,7 +127,7 @@ interface ParsedOperation {
127
127
  /** Whether the operation is deprecated */
128
128
  deprecated: boolean;
129
129
  /** Security requirements */
130
- security?: Array<Record<string, string[]>>;
130
+ security?: Record<string, string[]>[];
131
131
  /** ContractSpec extension data if present */
132
132
  contractSpecMeta?: {
133
133
  name: string;
@@ -218,4 +218,5 @@ interface ContractSpecOpenApiDocument {
218
218
  };
219
219
  }
220
220
  //#endregion
221
- export { ContractSpecOpenApiDocument, HttpMethod, OpenApiDocument, OpenApiExportOptions, OpenApiImportOptions, OpenApiOperation, OpenApiParameter, OpenApiParseOptions, OpenApiSchema, OpenApiServer, OpenApiSource, OpenApiTransportHints, OpenApiVersion, ParameterLocation, ParseResult, ParsedOperation, ParsedParameter };
221
+ export { ContractSpecOpenApiDocument, HttpMethod, OpenApiDocument, OpenApiExportOptions, OpenApiImportOptions, OpenApiOperation, OpenApiParameter, OpenApiParseOptions, OpenApiSchema, OpenApiServer, OpenApiSource, OpenApiTransportHints, OpenApiVersion, ParameterLocation, ParseResult, ParsedOperation, ParsedParameter };
222
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/openapi/types.ts"],"sourcesContent":[],"mappings":";;;;;AAeA;AAKA;AAOA;AACI,KAlBQ,cAAA,GAkBE,KAAA,GAAA,KAAA;;;;AAGiB,KAhBnB,eAAA,GAAkB,SAAA,CAAU,QAgBT,GAhBoB,WAAA,CAAY,QAgBhC;AAK/B;;;AAGI,KAnBQ,gBAAA,GACR,SAAA,CAAU,eAkBA,GAjBV,WAAA,CAAY,eAiBF;;;AAMd;AAaY,KA/BA,aAAA,GACR,SAAA,CAAU,YA8Be,GA7BzB,WAAA,CAAY,YA6Ba,GA5BzB,SAAA,CAAU,eA4Be,GA3BzB,WAAA,CAAY,eA2Ba;AAK7B;AAgBA;AAgBA;AAoBiB,KA/EL,gBAAA,GACR,SAAA,CAAU,eA8EsB,GA7EhC,WAAA,CAAY,eA6EoB,GA5EhC,SAAA,CAAU,eA4EsB,GA3EhC,WAAA,CAAY,eA2EoB;AAYpC;;;AAgBe,KAlGH,UAAA,GAkGG,KAAA,GAAA,MAAA,GAAA,KAAA,GAAA,QAAA,GAAA,OAAA,GAAA,MAAA,GAAA,SAAA,GAAA,OAAA;;;;AAgBA,KArGH,iBAAA,GAqGG,MAAA,GAAA,OAAA,GAAA,QAAA,GAAA,QAAA;;;;AAmBE,UAnHA,aAAA,CAmHe;EAkBf,GAAA,EAAA,MAAA;EAEL,WAAA,CAAA,EAAA,MAAA;EAED,SAAA,CAAA,EAtIG,MAsIH,CAAA,MAAA,EAAA;IAQG,OAAA,EAAA,MAAA;IAEY,IAAA,CAAA,EAAA,MAAA,EAAA;IAAf,WAAA,CAAA,EAAA,MAAA;EAEA,CAAA,CAAA;;AAQX;AAgBA;AAYA;AAOY,UAhLK,oBAAA,CAgLL;EACY;EAAf,KAAA,CAAA,EAAA,MAAA;EAEmB;EAAf,OAAA,CAAA,EAAA,MAAA;EAAM;;;YA3KP;;eAEG;;;;;UAME,oBAAA;;;;;;;;;;;;;;;;;;;UAoBA,mBAAA;;;;;;;;;;;UAYA,eAAA;;;;UAIP;;;;;;;;;;cAUI;;eAEC;;gBAEC;;gBAEA;;;;YAIJ;;;;aAIC;;aAIE;;;;;;aAOF;;;;;;;;;;;UAYI,eAAA;;;;MAIX;;;;;;UAMI;;;;;;;UAQO,WAAA;;YAEL;;WAED;;;;;;;;cAQG;;WAEH,eAAe;;WAEf;;;;;;;UAQM,qBAAA,SAA8B;;;;;;;;;;;;;;;UAgB9B,aAAA,SAAsB;;;kBAGrB;;;;;;;;UASD,2BAAA;;;;;;;YAOL;SACH,eAAe;;aAEX,eAAe"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lssm/lib.contracts-transformers",
3
- "version": "0.0.0-canary-20251217080011",
3
+ "version": "0.0.0-canary-20251219202229",
4
4
  "description": "Contract format transformations: import/export between ContractSpec and external formats (OpenAPI, AsyncAPI, etc.)",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -17,16 +17,16 @@
17
17
  "test": "bun test"
18
18
  },
19
19
  "dependencies": {
20
- "@lssm/lib.contracts": "0.0.0-canary-20251217080011",
21
- "@lssm/lib.schema": "0.0.0-canary-20251217080011",
20
+ "@lssm/lib.contracts": "0.0.0-canary-20251219202229",
21
+ "@lssm/lib.schema": "0.0.0-canary-20251219202229",
22
22
  "openapi-types": "^12.1.3",
23
23
  "yaml": "^2.7.1",
24
24
  "zod": "^4.1.13"
25
25
  },
26
26
  "devDependencies": {
27
- "@lssm/tool.tsdown": "0.0.0-canary-20251217080011",
28
- "@lssm/tool.typescript": "0.0.0-canary-20251217080011",
29
- "tsdown": "^0.17.4",
27
+ "@lssm/tool.tsdown": "0.0.0-canary-20251219202229",
28
+ "@lssm/tool.typescript": "0.0.0-canary-20251219202229",
29
+ "tsdown": "^0.18.1",
30
30
  "typescript": "^5.9.3"
31
31
  },
32
32
  "main": "./dist/index.js",
@@ -50,5 +50,6 @@
50
50
  "./openapi": "./dist/openapi/index.js",
51
51
  "./*": "./*"
52
52
  }
53
- }
53
+ },
54
+ "license": "MIT"
54
55
  }