@lssm/lib.contracts-transformers 0.0.0-canary-20251220041653 → 0.0.0-canary-20251221114240

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.
Files changed (60) hide show
  1. package/README.md +2 -2
  2. package/dist/common/index.d.ts +2 -2
  3. package/dist/common/types.d.ts +14 -10
  4. package/dist/common/types.d.ts.map +1 -1
  5. package/dist/index.d.ts +6 -5
  6. package/dist/index.js +3 -2
  7. package/dist/openapi/differ.d.ts +6 -6
  8. package/dist/openapi/differ.d.ts.map +1 -1
  9. package/dist/openapi/differ.js +11 -4
  10. package/dist/openapi/differ.js.map +1 -1
  11. package/dist/openapi/exporter.d.ts +8 -8
  12. package/dist/openapi/exporter.d.ts.map +1 -1
  13. package/dist/openapi/exporter.js +4 -4
  14. package/dist/openapi/exporter.js.map +1 -1
  15. package/dist/openapi/importer/analyzer.js +28 -0
  16. package/dist/openapi/importer/analyzer.js.map +1 -0
  17. package/dist/openapi/importer/events.js +36 -0
  18. package/dist/openapi/importer/events.js.map +1 -0
  19. package/dist/openapi/importer/generator.js +71 -0
  20. package/dist/openapi/importer/generator.js.map +1 -0
  21. package/dist/openapi/importer/index.d.ts +17 -0
  22. package/dist/openapi/importer/index.d.ts.map +1 -0
  23. package/dist/openapi/importer/index.js +154 -0
  24. package/dist/openapi/importer/index.js.map +1 -0
  25. package/dist/openapi/importer/models.js +19 -0
  26. package/dist/openapi/importer/models.js.map +1 -0
  27. package/dist/openapi/importer/schemas.js +80 -0
  28. package/dist/openapi/importer/schemas.js.map +1 -0
  29. package/dist/openapi/index.d.ts +5 -4
  30. package/dist/openapi/index.js +4 -2
  31. package/dist/openapi/parser/document.d.ts +20 -0
  32. package/dist/openapi/parser/document.d.ts.map +1 -0
  33. package/dist/openapi/parser/document.js +95 -0
  34. package/dist/openapi/parser/document.js.map +1 -0
  35. package/dist/openapi/parser/index.js +5 -0
  36. package/dist/openapi/parser/operation.js +59 -0
  37. package/dist/openapi/parser/operation.js.map +1 -0
  38. package/dist/openapi/parser/parameters.js +37 -0
  39. package/dist/openapi/parser/parameters.js.map +1 -0
  40. package/dist/openapi/parser/resolvers.js +63 -0
  41. package/dist/openapi/parser/resolvers.js.map +1 -0
  42. package/dist/openapi/parser/utils.d.ts +19 -0
  43. package/dist/openapi/parser/utils.d.ts.map +1 -0
  44. package/dist/openapi/parser/utils.js +48 -0
  45. package/dist/openapi/parser/utils.js.map +1 -0
  46. package/dist/openapi/parser.js +6 -232
  47. package/dist/openapi/schema-converter.d.ts +7 -1
  48. package/dist/openapi/schema-converter.d.ts.map +1 -1
  49. package/dist/openapi/schema-converter.js +117 -20
  50. package/dist/openapi/schema-converter.js.map +1 -1
  51. package/dist/openapi/types.d.ts +14 -20
  52. package/dist/openapi/types.d.ts.map +1 -1
  53. package/package.json +5 -5
  54. package/dist/openapi/importer.d.ts +0 -16
  55. package/dist/openapi/importer.d.ts.map +0 -1
  56. package/dist/openapi/importer.js +0 -265
  57. package/dist/openapi/importer.js.map +0 -1
  58. package/dist/openapi/parser.d.ts +0 -32
  59. package/dist/openapi/parser.d.ts.map +0 -1
  60. package/dist/openapi/parser.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolvers.js","names":["current: unknown","newProps: Record<string, OpenApiSchema>"],"sources":["../../../src/openapi/parser/resolvers.ts"],"sourcesContent":["import type { OpenApiDocument, OpenApiSchema } from '../types';\nimport type { OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';\n\n/**\n * Check if a value is a reference object.\n */\nexport function 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 */\nexport function resolveRef<T>(\n doc: OpenApiDocument,\n ref: string\n): 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 */\nexport function 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 * Recursively dereference a schema.\n * Replaces all $ref with their resolved values.\n * Preserves `_originalRef` to track where the schema came from.\n */\nexport function dereferenceSchema(\n doc: OpenApiDocument,\n schema: OpenApiSchema | undefined,\n seen = new Set<string>()\n): OpenApiSchema | undefined {\n if (!schema) return undefined;\n\n // Handle references\n if (isReference(schema)) {\n // Avoid infinite recursion for cycles\n if (seen.has(schema.$ref)) {\n return schema; // Keep reference for cycles\n }\n\n // Create new seen set for this branch\n const newSeen = new Set(seen);\n newSeen.add(schema.$ref);\n\n const resolved = resolveRef<OpenApiSchema>(doc, schema.$ref);\n if (!resolved) return schema;\n\n // Recursively dereference the resolved schema\n const dereferenced = dereferenceSchema(doc, resolved, newSeen);\n if (!dereferenced) return schema;\n\n // IMPORTANT: Preserve the original $ref so we can generate correct imports\n // Extract the type name from the $ref (e.g., '#/components/schemas/PaginationMeta' -> 'PaginationMeta')\n const refParts = schema.$ref.split('/');\n const typeName = refParts[refParts.length - 1];\n return {\n ...dereferenced,\n _originalRef: schema.$ref,\n _originalTypeName: typeName,\n } as unknown as OpenApiSchema;\n }\n\n // Deep clone to avoid mutating original doc (if we were modifying in place, but here we return new objects mostly)\n // For simplicity, we just walk properties\n const schemaObj = { ...schema } as Record<string, unknown>;\n\n // Handle nested schemas in properties\n if (schemaObj.properties) {\n const props = schemaObj.properties as Record<string, OpenApiSchema>;\n const newProps: Record<string, OpenApiSchema> = {};\n for (const [key, prop] of Object.entries(props)) {\n newProps[key] = dereferenceSchema(doc, prop, seen) ?? prop;\n }\n schemaObj.properties = newProps;\n }\n\n // Handle nested schema in items (array)\n if (schemaObj.items) {\n schemaObj.items = dereferenceSchema(\n doc,\n schemaObj.items as OpenApiSchema,\n seen\n );\n }\n\n // Handle allOf, anyOf, oneOf\n const combinators = ['allOf', 'anyOf', 'oneOf'];\n for (const comb of combinators) {\n if (Array.isArray(schemaObj[comb])) {\n schemaObj[comb] = (schemaObj[comb] as OpenApiSchema[]).map(\n (s) => dereferenceSchema(doc, s, seen) ?? s\n );\n }\n }\n\n return schemaObj as OpenApiSchema;\n}\n"],"mappings":";;;;AAMA,SAAgB,YACd,KACgE;AAChE,QAAO,OAAO,QAAQ,YAAY,QAAQ,QAAQ,UAAU;;;;;AAM9D,SAAgB,WACd,KACA,KACe;AAEf,KAAI,CAAC,IAAI,WAAW,KAAK,CACvB;CAGF,MAAM,OAAO,IAAI,MAAM,EAAE,CAAC,MAAM,IAAI;CACpC,IAAIA,UAAmB;AAEvB,MAAK,MAAM,QAAQ,MAAM;AACvB,MAAI,YAAY,QAAQ,YAAY,OAAW,QAAO;AACtD,MAAI,OAAO,YAAY,SAAU,QAAO;AACxC,YAAW,QAAoC;;AAGjD,QAAO;;;;;;;AAsBT,SAAgB,kBACd,KACA,QACA,uBAAO,IAAI,KAAa,EACG;AAC3B,KAAI,CAAC,OAAQ,QAAO;AAGpB,KAAI,YAAY,OAAO,EAAE;AAEvB,MAAI,KAAK,IAAI,OAAO,KAAK,CACvB,QAAO;EAIT,MAAM,UAAU,IAAI,IAAI,KAAK;AAC7B,UAAQ,IAAI,OAAO,KAAK;EAExB,MAAM,WAAW,WAA0B,KAAK,OAAO,KAAK;AAC5D,MAAI,CAAC,SAAU,QAAO;EAGtB,MAAM,eAAe,kBAAkB,KAAK,UAAU,QAAQ;AAC9D,MAAI,CAAC,aAAc,QAAO;EAI1B,MAAM,WAAW,OAAO,KAAK,MAAM,IAAI;EACvC,MAAM,WAAW,SAAS,SAAS,SAAS;AAC5C,SAAO;GACL,GAAG;GACH,cAAc,OAAO;GACrB,mBAAmB;GACpB;;CAKH,MAAM,YAAY,EAAE,GAAG,QAAQ;AAG/B,KAAI,UAAU,YAAY;EACxB,MAAM,QAAQ,UAAU;EACxB,MAAMC,WAA0C,EAAE;AAClD,OAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,MAAM,CAC7C,UAAS,OAAO,kBAAkB,KAAK,MAAM,KAAK,IAAI;AAExD,YAAU,aAAa;;AAIzB,KAAI,UAAU,MACZ,WAAU,QAAQ,kBAChB,KACA,UAAU,OACV,KACD;AAKH,MAAK,MAAM,QADS;EAAC;EAAS;EAAS;EAAQ,CAE7C,KAAI,MAAM,QAAQ,UAAU,MAAM,CAChC,WAAU,QAAS,UAAU,MAA0B,KACpD,MAAM,kBAAkB,KAAK,GAAG,KAAK,IAAI,EAC3C;AAIL,QAAO"}
@@ -0,0 +1,19 @@
1
+ import { OpenApiDocument, OpenApiVersion } from "../types.js";
2
+
3
+ //#region src/openapi/parser/utils.d.ts
4
+
5
+ /**
6
+ * Parse an OpenAPI document from a string (JSON or YAML).
7
+ */
8
+ declare function parseOpenApiString(content: string, format?: 'json' | 'yaml'): OpenApiDocument;
9
+ /**
10
+ * Detect the format of content (JSON or YAML).
11
+ */
12
+ declare function detectFormat(content: string): 'json' | 'yaml';
13
+ /**
14
+ * Detect OpenAPI version from document.
15
+ */
16
+ declare function detectVersion(doc: OpenApiDocument): OpenApiVersion;
17
+ //#endregion
18
+ export { detectFormat, detectVersion, parseOpenApiString };
19
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","names":[],"sources":["../../../src/openapi/parser/utils.ts"],"sourcesContent":[],"mappings":";;;;;AAiBA;AAaA;AAWgB,iBAxBA,kBAAA,CAwBmB,OAAkB,EAAA,MAAA,EAAA,MAAc,CAAA,EAAA,MAAA,GAAA,MAAA,CAAA,EArBhE,eAqBgE;;;;iBAXnD,YAAA;;;;iBAWA,aAAA,MAAmB,kBAAkB"}
@@ -0,0 +1,48 @@
1
+ import { parse } from "yaml";
2
+
3
+ //#region src/openapi/parser/utils.ts
4
+ const HTTP_METHODS = [
5
+ "get",
6
+ "post",
7
+ "put",
8
+ "delete",
9
+ "patch",
10
+ "head",
11
+ "options",
12
+ "trace"
13
+ ];
14
+ /**
15
+ * Parse an OpenAPI document from a string (JSON or YAML).
16
+ */
17
+ function parseOpenApiString(content, format = "json") {
18
+ if (format === "yaml") return parse(content);
19
+ return JSON.parse(content);
20
+ }
21
+ /**
22
+ * Detect the format of content (JSON or YAML).
23
+ */
24
+ function detectFormat(content) {
25
+ const trimmed = content.trim();
26
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) return "json";
27
+ return "yaml";
28
+ }
29
+ /**
30
+ * Detect OpenAPI version from document.
31
+ */
32
+ function detectVersion(doc) {
33
+ if (doc.openapi.startsWith("3.1")) return "3.1";
34
+ return "3.0";
35
+ }
36
+ /**
37
+ * Generate an operationId if not present.
38
+ */
39
+ function generateOperationId(method, path) {
40
+ return method + path.split("/").filter(Boolean).map((part) => {
41
+ if (part.startsWith("{") && part.endsWith("}")) return "By" + part.slice(1, -1).charAt(0).toUpperCase() + part.slice(2, -1);
42
+ return part.charAt(0).toUpperCase() + part.slice(1);
43
+ }).join("");
44
+ }
45
+
46
+ //#endregion
47
+ export { HTTP_METHODS, detectFormat, detectVersion, generateOperationId, parseOpenApiString };
48
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","names":["HTTP_METHODS: HttpMethod[]","parseYaml"],"sources":["../../../src/openapi/parser/utils.ts"],"sourcesContent":["import { parse as parseYaml } from 'yaml';\nimport type { OpenApiDocument, HttpMethod, OpenApiVersion } from '../types';\n\nexport const 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 * Generate an operationId if not present.\n */\nexport function 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"],"mappings":";;;AAGA,MAAaA,eAA6B;CACxC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;;;AAKD,SAAgB,mBACd,SACA,SAA0B,QACT;AACjB,KAAI,WAAW,OACb,QAAOC,MAAU,QAAQ;AAE3B,QAAO,KAAK,MAAM,QAAQ;;;;;AAM5B,SAAgB,aAAa,SAAkC;CAC7D,MAAM,UAAU,QAAQ,MAAM;AAC9B,KAAI,QAAQ,WAAW,IAAI,IAAI,QAAQ,WAAW,IAAI,CACpD,QAAO;AAET,QAAO;;;;;AAMT,SAAgB,cAAc,KAAsC;AAElE,KADgB,IAAI,QACR,WAAW,MAAM,CAC3B,QAAO;AAET,QAAO;;;;;AAMT,SAAgB,oBAAoB,QAAoB,MAAsB;AAe5E,QAAO,SAbW,KACf,MAAM,IAAI,CACV,OAAO,QAAQ,CACf,KAAK,SAAS;AAEb,MAAI,KAAK,WAAW,IAAI,IAAI,KAAK,SAAS,IAAI,CAC5C,QACE,OAAO,KAAK,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,aAAa,GAAG,KAAK,MAAM,GAAG,GAAG;AAGxE,SAAO,KAAK,OAAO,EAAE,CAAC,aAAa,GAAG,KAAK,MAAM,EAAE;GACnD,CAEsB,KAAK,GAAG"}
@@ -1,232 +1,6 @@
1
- import { parse } from "yaml";
2
-
3
- //#region src/openapi/parser.ts
4
- /**
5
- * OpenAPI document parser.
6
- * Parses OpenAPI 3.x documents from JSON/YAML files or URLs.
7
- */
8
- const HTTP_METHODS = [
9
- "get",
10
- "post",
11
- "put",
12
- "delete",
13
- "patch",
14
- "head",
15
- "options",
16
- "trace"
17
- ];
18
- /**
19
- * Parse an OpenAPI document from a string (JSON or YAML).
20
- */
21
- function parseOpenApiString(content, format = "json") {
22
- if (format === "yaml") return parse(content);
23
- return JSON.parse(content);
24
- }
25
- /**
26
- * Detect the format of content (JSON or YAML).
27
- */
28
- function detectFormat(content) {
29
- const trimmed = content.trim();
30
- if (trimmed.startsWith("{") || trimmed.startsWith("[")) return "json";
31
- return "yaml";
32
- }
33
- /**
34
- * Detect OpenAPI version from document.
35
- */
36
- function detectVersion(doc) {
37
- if (doc.openapi.startsWith("3.1")) return "3.1";
38
- return "3.0";
39
- }
40
- /**
41
- * Check if a value is a reference object.
42
- */
43
- function isReference(obj) {
44
- return typeof obj === "object" && obj !== null && "$ref" in obj;
45
- }
46
- /**
47
- * Resolve a $ref reference in the document.
48
- */
49
- function resolveRef(doc, ref) {
50
- if (!ref.startsWith("#/")) return;
51
- const path = ref.slice(2).split("/");
52
- let current = doc;
53
- for (const part of path) {
54
- if (current === null || current === void 0) return void 0;
55
- if (typeof current !== "object") return void 0;
56
- current = current[part];
57
- }
58
- return current;
59
- }
60
- /**
61
- * Resolve a schema, following $ref if needed.
62
- */
63
- function resolveSchema(doc, schema) {
64
- if (!schema) return void 0;
65
- if (isReference(schema)) return resolveRef(doc, schema.$ref) ?? schema;
66
- return schema;
67
- }
68
- /**
69
- * Parse parameters from an operation.
70
- */
71
- function parseParameters(doc, params) {
72
- const result = {
73
- path: [],
74
- query: [],
75
- header: [],
76
- cookie: []
77
- };
78
- if (!params) return result;
79
- for (const param of params) {
80
- let resolved;
81
- if (isReference(param)) {
82
- const ref = resolveRef(doc, param.$ref);
83
- if (!ref) continue;
84
- resolved = ref;
85
- } else resolved = param;
86
- const parsed = {
87
- name: resolved.name,
88
- in: resolved.in,
89
- required: resolved.required ?? resolved.in === "path",
90
- description: resolved.description,
91
- schema: resolved.schema,
92
- deprecated: resolved.deprecated ?? false
93
- };
94
- result[resolved.in]?.push(parsed);
95
- }
96
- return result;
97
- }
98
- /**
99
- * Generate an operationId if not present.
100
- */
101
- function generateOperationId(method, path) {
102
- return method + path.split("/").filter(Boolean).map((part) => {
103
- if (part.startsWith("{") && part.endsWith("}")) return "By" + part.slice(1, -1).charAt(0).toUpperCase() + part.slice(2, -1);
104
- return part.charAt(0).toUpperCase() + part.slice(1);
105
- }).join("");
106
- }
107
- /**
108
- * Parse a single operation.
109
- */
110
- function parseOperation(doc, method, path, operation, pathParams) {
111
- const params = parseParameters(doc, [...pathParams ?? [], ...operation.parameters ?? []]);
112
- let requestBody;
113
- if (operation.requestBody) {
114
- const body = isReference(operation.requestBody) ? resolveRef(doc, operation.requestBody.$ref) : operation.requestBody;
115
- if (body) {
116
- const contentType = Object.keys(body.content ?? {})[0] ?? "application/json";
117
- const content = body.content?.[contentType];
118
- if (content?.schema) requestBody = {
119
- required: body.required ?? false,
120
- schema: resolveSchema(doc, content.schema) ?? {},
121
- contentType
122
- };
123
- }
124
- }
125
- const responses = {};
126
- for (const [status, response] of Object.entries(operation.responses ?? {})) {
127
- const resolved = isReference(response) ? resolveRef(doc, response.$ref) : response;
128
- if (resolved) {
129
- const contentType = Object.keys(resolved.content ?? {})[0];
130
- const content = contentType ? resolved.content?.[contentType] : void 0;
131
- responses[status] = {
132
- description: resolved.description,
133
- schema: content?.schema ? resolveSchema(doc, content.schema) : void 0,
134
- contentType
135
- };
136
- }
137
- }
138
- const contractSpecMeta = operation?.["x-contractspec"];
139
- return {
140
- operationId: operation.operationId ?? generateOperationId(method, path),
141
- method,
142
- path,
143
- summary: operation.summary,
144
- description: operation.description,
145
- tags: operation.tags ?? [],
146
- pathParams: params.path,
147
- queryParams: params.query,
148
- headerParams: params.header,
149
- cookieParams: params.cookie,
150
- requestBody,
151
- responses,
152
- deprecated: operation.deprecated ?? false,
153
- security: operation.security,
154
- contractSpecMeta
155
- };
156
- }
157
- /**
158
- * Parse an OpenAPI document into a structured result.
159
- */
160
- function parseOpenApiDocument(doc, _options = {}) {
161
- const version = detectVersion(doc);
162
- const warnings = [];
163
- const operations = [];
164
- for (const [path, pathItem] of Object.entries(doc.paths ?? {})) {
165
- if (!pathItem) continue;
166
- const pathParams = pathItem.parameters;
167
- for (const method of HTTP_METHODS) {
168
- const operation = pathItem[method];
169
- if (operation) try {
170
- operations.push(parseOperation(doc, method, path, operation, pathParams));
171
- } catch (error) {
172
- warnings.push(`Failed to parse ${method.toUpperCase()} ${path}: ${error}`);
173
- }
174
- }
175
- }
176
- const schemas = {};
177
- const components = doc.components;
178
- if (components?.schemas) for (const [name, schema] of Object.entries(components.schemas)) schemas[name] = schema;
179
- const servers = (doc.servers ?? []).map((s) => ({
180
- url: s.url,
181
- description: s.description,
182
- variables: s.variables
183
- }));
184
- return {
185
- document: doc,
186
- version,
187
- info: {
188
- title: doc.info.title,
189
- version: doc.info.version,
190
- description: doc.info.description
191
- },
192
- operations,
193
- schemas,
194
- servers,
195
- warnings
196
- };
197
- }
198
- /**
199
- * Parse OpenAPI from a file path or URL.
200
- * Note: This is an async function that requires I/O adapters.
201
- * For pure parsing, use parseOpenApiString or parseOpenApiDocument.
202
- */
203
- async function parseOpenApi(source, options = {}) {
204
- const { fetch: fetchFn = globalThis.fetch, readFile, timeout = 3e4 } = options;
205
- let content;
206
- let format;
207
- if (source.startsWith("http://") || source.startsWith("https://")) {
208
- const controller = new AbortController();
209
- const timeoutId = setTimeout(() => controller.abort(), timeout);
210
- try {
211
- const response = await fetchFn(source, { signal: controller.signal });
212
- if (!response.ok) throw new Error(`HTTP ${response.status}: ${response.statusText}`);
213
- content = await response.text();
214
- } finally {
215
- clearTimeout(timeoutId);
216
- }
217
- if (source.endsWith(".yaml") || source.endsWith(".yml")) format = "yaml";
218
- else if (source.endsWith(".json")) format = "json";
219
- else format = detectFormat(content);
220
- } else {
221
- if (!readFile) throw new Error("readFile adapter required for file paths");
222
- content = await readFile(source);
223
- if (source.endsWith(".yaml") || source.endsWith(".yml")) format = "yaml";
224
- else if (source.endsWith(".json")) format = "json";
225
- else format = detectFormat(content);
226
- }
227
- return parseOpenApiDocument(parseOpenApiString(content, format), options);
228
- }
229
-
230
- //#endregion
231
- export { detectFormat, detectVersion, parseOpenApi, parseOpenApiDocument, parseOpenApiString };
232
- //# sourceMappingURL=parser.js.map
1
+ import { HTTP_METHODS, detectFormat, detectVersion, generateOperationId, parseOpenApiString } from "./parser/utils.js";
2
+ import { dereferenceSchema, isReference, resolveRef } from "./parser/resolvers.js";
3
+ import { parseParameters } from "./parser/parameters.js";
4
+ import { parseOperation } from "./parser/operation.js";
5
+ import { parseOpenApi, parseOpenApiDocument } from "./parser/document.js";
6
+ import "./parser/index.js";
@@ -1,4 +1,5 @@
1
1
  import { OpenApiSchema } from "./types.js";
2
+ import { ContractsrcConfig } from "@lssm/lib.contracts";
2
3
 
3
4
  //#region src/openapi/schema-converter.d.ts
4
5
 
@@ -16,6 +17,8 @@ interface TypescriptType {
16
17
  primitive: boolean;
17
18
  /** Description for documentation */
18
19
  description?: string;
20
+ /** Whether this type is a reference to another schema (needs import) vs inline */
21
+ isReference?: boolean;
19
22
  }
20
23
  /**
21
24
  * SchemaModel field representation for code generation.
@@ -63,8 +66,11 @@ declare function jsonSchemaToField(schema: OpenApiSchema, fieldName: string, req
63
66
  declare function generateSchemaModelCode(schema: OpenApiSchema, modelName: string, indent?: number): GeneratedModel;
64
67
  /**
65
68
  * Generate import statements for a SchemaModel.
69
+ * @param fields - The fields to generate imports for
70
+ * @param options - Configuration for import generation
71
+ * @param sameDirectory - If true, imports use './' (for model-to-model). If false, uses '../models/' (for operations/events)
66
72
  */
67
- declare function generateImports(fields: SchemaField[]): string;
73
+ declare function generateImports(fields: SchemaField[], options: ContractsrcConfig, sameDirectory?: boolean): string;
68
74
  //#endregion
69
75
  export { GeneratedModel, SchemaField, TypescriptType, generateImports, generateSchemaModelCode, getScalarType, jsonSchemaToField, jsonSchemaToType };
70
76
  //# sourceMappingURL=schema-converter.d.ts.map
@@ -1 +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;EA+GA,IAAA,EAAA,MAAA;;;;;;;;;;;;;UAjUC,WAAA;;;;QAIT;;;;;;gBAMQ;;;;;UAMC,cAAA;;;;;;UAMP;;;;;;;iBAuCM,gBAAA,SACN,+BAEP;;;;iBA6Fa,aAAA,SAAsB;;;;iBAkBtB,iBAAA,SACN,sDAGP;;;;iBA+Ba,uBAAA,SACN,oDAGP;;;;iBA2Ga,eAAA,SAAwB"}
1
+ {"version":3,"file":"schema-converter.d.ts","names":[],"sources":["../../src/openapi/schema-converter.ts"],"sourcesContent":[],"mappings":";;;;;AA8CA;AA6CA;AA6GA;AA2BgB,UAvNC,cAAA,CAuNgB;EAmCjB;EAmOA,IAAA,EAAA,MAAA;;;;;;;;;;;;;;;UA3cC,WAAA;;;;QAIT;;;;;;gBAMQ;;;;;UAMC,cAAA;;;;;;UAMP;;;;;;;iBAuCM,gBAAA,SACN,+BAEP;;;;iBA0Ga,aAAA,SAAsB;;;;iBA2BtB,iBAAA,SACN,sDAGP;;;;iBA+Ba,uBAAA,SACN,oDAGP;;;;;;;iBA+Na,eAAA,SACN,wBACC"}
@@ -5,13 +5,13 @@ import { toCamelCase, toPascalCase, toValidIdentifier } from "../common/utils.js
5
5
  * Map JSON Schema types to ContractSpec ScalarTypeEnum values.
6
6
  */
7
7
  const JSON_SCHEMA_TO_SCALAR = {
8
- string: "ScalarTypeEnum.STRING",
9
- integer: "ScalarTypeEnum.INT",
10
- number: "ScalarTypeEnum.FLOAT",
11
- boolean: "ScalarTypeEnum.BOOLEAN",
12
- "string:date": "ScalarTypeEnum.DATE",
13
- "string:date-time": "ScalarTypeEnum.DATE_TIME",
14
- "string:email": "ScalarTypeEnum.EMAIL",
8
+ string: "ScalarTypeEnum.String_unsecure",
9
+ integer: "ScalarTypeEnum.Int_unsecure",
10
+ number: "ScalarTypeEnum.Float_unsecure",
11
+ boolean: "ScalarTypeEnum.Boolean",
12
+ "string:date": "ScalarTypeEnum.Date",
13
+ "string:date-time": "ScalarTypeEnum.DateTime",
14
+ "string:email": "ScalarTypeEnum.EmailAddress",
15
15
  "string:uri": "ScalarTypeEnum.URL",
16
16
  "string:uuid": "ScalarTypeEnum.ID"
17
17
  };
@@ -36,12 +36,21 @@ function jsonSchemaToType(schema, name) {
36
36
  type: toPascalCase(typeNameFromRef(schema.$ref)),
37
37
  optional: false,
38
38
  array: false,
39
- primitive: false
39
+ primitive: false,
40
+ isReference: true
40
41
  };
41
42
  const schemaObj = schema;
42
43
  const type = schemaObj["type"];
43
44
  const format = schemaObj["format"];
44
45
  const nullable = schemaObj["nullable"];
46
+ const originalTypeName = schemaObj["_originalTypeName"];
47
+ if (originalTypeName) return {
48
+ type: toPascalCase(originalTypeName),
49
+ optional: nullable ?? false,
50
+ array: false,
51
+ primitive: false,
52
+ isReference: true
53
+ };
45
54
  if (type === "array") {
46
55
  const items = schemaObj["items"];
47
56
  if (items) return {
@@ -103,6 +112,11 @@ function getScalarType(schema) {
103
112
  const type = schemaObj["type"];
104
113
  const format = schemaObj["format"];
105
114
  if (!type) return void 0;
115
+ if (type === "array") {
116
+ const items = schemaObj["items"];
117
+ if (items) return getScalarType(items);
118
+ return;
119
+ }
106
120
  return JSON_SCHEMA_TO_SCALAR[format ? `${type}:${format}` : type] ?? JSON_SCHEMA_TO_SCALAR[type];
107
121
  }
108
122
  /**
@@ -142,12 +156,81 @@ function generateSchemaModelCode(schema, modelName, indent = 0) {
142
156
  const description = schemaObj["description"];
143
157
  const properties = schemaObj["properties"];
144
158
  const required = schemaObj["required"] ?? [];
145
- if (!properties) return {
146
- name: toPascalCase(modelName),
147
- description,
148
- fields: [],
149
- code: `${spaces}// Empty schema for ${modelName}`
150
- };
159
+ const enumValues = schemaObj["enum"];
160
+ if (enumValues && enumValues.length > 0) {
161
+ const safeModelName$1 = toPascalCase(toValidIdentifier(modelName));
162
+ return {
163
+ name: safeModelName$1,
164
+ description,
165
+ fields: [],
166
+ code: [
167
+ `${spaces}/**`,
168
+ `${spaces} * Enum type: ${safeModelName$1}`,
169
+ description ? `${spaces} * ${description}` : null,
170
+ `${spaces} */`,
171
+ `${spaces}export const ${safeModelName$1} = new EnumType('${safeModelName$1}', [${enumValues.map((v) => `'${String(v)}'`).join(", ")}]);`
172
+ ].filter((line) => line !== null).join("\n")
173
+ };
174
+ }
175
+ const schemaType = schemaObj["type"];
176
+ if (schemaType && !properties && !enumValues) {
177
+ const safeModelName$1 = toPascalCase(toValidIdentifier(modelName));
178
+ const format = schemaObj["format"];
179
+ const scalarType = JSON_SCHEMA_TO_SCALAR[format ? `${schemaType}:${format}` : schemaType] ?? JSON_SCHEMA_TO_SCALAR[schemaType];
180
+ if (scalarType) return {
181
+ name: safeModelName$1,
182
+ description,
183
+ fields: [],
184
+ code: [
185
+ `${spaces}/**`,
186
+ `${spaces} * Type alias: ${safeModelName$1}`,
187
+ description ? `${spaces} * ${description}` : null,
188
+ `${spaces} * Underlying type: ${scalarType}`,
189
+ `${spaces} */`,
190
+ `${spaces}export const ${safeModelName$1} = defineSchemaModel({`,
191
+ `${spaces} name: '${safeModelName$1}',`,
192
+ description ? `${spaces} description: ${JSON.stringify(description)},` : null,
193
+ `${spaces} fields: {`,
194
+ `${spaces} value: {`,
195
+ `${spaces} type: ${scalarType}(),`,
196
+ `${spaces} isOptional: false,`,
197
+ `${spaces} },`,
198
+ `${spaces} },`,
199
+ `${spaces}});`
200
+ ].filter((line) => line !== null).join("\n")
201
+ };
202
+ }
203
+ if (schemaObj["additionalProperties"] && !properties) {
204
+ const safeModelName$1 = toPascalCase(toValidIdentifier(modelName));
205
+ return {
206
+ name: safeModelName$1,
207
+ description,
208
+ fields: [],
209
+ code: [
210
+ `${spaces}/**`,
211
+ `${spaces} * Dictionary/Record type: ${safeModelName$1}`,
212
+ description ? `${spaces} * ${description}` : null,
213
+ `${spaces} * Use as: Record<string, unknown> - access via record[key]`,
214
+ `${spaces} */`,
215
+ `${spaces}export const ${safeModelName$1} = ScalarTypeEnum.JSONObject();`
216
+ ].filter((line) => line !== null).join("\n")
217
+ };
218
+ }
219
+ if (!properties) {
220
+ const safeModelName$1 = toPascalCase(toValidIdentifier(modelName));
221
+ return {
222
+ name: safeModelName$1,
223
+ description,
224
+ fields: [],
225
+ code: [
226
+ `${spaces}export const ${safeModelName$1} = defineSchemaModel({`,
227
+ `${spaces} name: '${safeModelName$1}',`,
228
+ description ? `${spaces} description: ${JSON.stringify(description)},` : null,
229
+ `${spaces} fields: {},`,
230
+ `${spaces}});`
231
+ ].filter((line) => line !== null).join("\n")
232
+ };
233
+ }
151
234
  for (const [propName, propSchema] of Object.entries(properties)) {
152
235
  const isRequired = required.includes(propName);
153
236
  fields.push(jsonSchemaToField(propSchema, propName, isRequired));
@@ -178,21 +261,35 @@ function generateFieldCode(field, indent) {
178
261
  const spaces = " ".repeat(indent);
179
262
  const lines = [];
180
263
  lines.push(`${spaces}${field.name}: {`);
181
- if (field.enumValues) lines.push(`${spaces} type: new EnumType([${field.enumValues.map((v) => `'${v}'`).join(", ")}]),`);
182
- else if (field.scalarType) lines.push(`${spaces} type: ${field.scalarType},`);
183
- else lines.push(`${spaces} type: ${field.type.type}, // TODO: Define or import this type`);
184
- if (field.type.optional) lines.push(`${spaces} isOptional: true,`);
264
+ if (field.enumValues) {
265
+ const enumName = toPascalCase(field.name) + "Enum";
266
+ lines.push(`${spaces} type: new EnumType('${enumName}', [${field.enumValues.map((v) => `'${v}'`).join(", ")}]),`);
267
+ } else if (field.scalarType) lines.push(`${spaces} type: ${field.scalarType}(),`);
268
+ else if (field.type.primitive) {
269
+ const fallbackScalar = field.type.type === "number" ? "ScalarTypeEnum.Float_unsecure" : field.type.type === "boolean" ? "ScalarTypeEnum.Boolean_unsecure" : "ScalarTypeEnum.String_unsecure";
270
+ lines.push(`${spaces} type: ${fallbackScalar}(),`);
271
+ } else if (field.type.isReference) lines.push(`${spaces} type: ${field.type.type},`);
272
+ else lines.push(`${spaces} type: ScalarTypeEnum.JSONObject(), // TODO: Define nested model for ${field.type.type}`);
273
+ lines.push(`${spaces} isOptional: ${field.type.optional},`);
185
274
  if (field.type.array) lines.push(`${spaces} isArray: true,`);
186
275
  lines.push(`${spaces}},`);
187
276
  return lines.join("\n");
188
277
  }
189
278
  /**
190
279
  * Generate import statements for a SchemaModel.
280
+ * @param fields - The fields to generate imports for
281
+ * @param options - Configuration for import generation
282
+ * @param sameDirectory - If true, imports use './' (for model-to-model). If false, uses '../models/' (for operations/events)
191
283
  */
192
- function generateImports(fields) {
284
+ function generateImports(fields, options, sameDirectory = true) {
193
285
  const imports = /* @__PURE__ */ new Set();
286
+ const modelsDir = sameDirectory ? "." : `../${options.conventions.models}`;
194
287
  imports.add("import { defineSchemaModel, ScalarTypeEnum, EnumType } from '@lssm/lib.schema';");
195
- for (const field of fields) if (!field.type.primitive && !field.enumValues && !field.scalarType) {}
288
+ for (const field of fields) if (field.type.isReference && !field.type.primitive && !field.enumValues && !field.scalarType && !field.nestedModel) {
289
+ const modelName = field.type.type;
290
+ const kebabName = modelName.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
291
+ imports.add(`import { ${modelName} } from '${modelsDir}/${kebabName}';`);
292
+ }
196
293
  return Array.from(imports).join("\n");
197
294
  }
198
295
 
@@ -1 +1 @@
1
- {"version":3,"file":"schema-converter.js","names":["JSON_SCHEMA_TO_SCALAR: Record<string, string>","enumValues: string[] | undefined","fields: SchemaField[]","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 { toCamelCase, toPascalCase, 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 (scalarKey === 'string') {\n return {\n type: 'string',\n optional: nullable ?? false,\n array: false,\n primitive: true,\n };\n }\n if (scalarKey === 'integer' || type === 'number') {\n return {\n type: 'number',\n optional: nullable ?? false,\n array: false,\n primitive: true,\n };\n }\n if (scalarKey === '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\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 const 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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"}
1
+ {"version":3,"file":"schema-converter.js","names":["JSON_SCHEMA_TO_SCALAR: Record<string, string>","enumValues: string[] | undefined","fields: SchemaField[]","safeModelName","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 { toCamelCase, toPascalCase, toValidIdentifier } from '../common/utils';\nimport type { ContractsrcConfig } from '@lssm/lib.contracts';\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 /** Whether this type is a reference to another schema (needs import) vs inline */\n isReference?: boolean;\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_unsecure',\n integer: 'ScalarTypeEnum.Int_unsecure',\n number: 'ScalarTypeEnum.Float_unsecure',\n boolean: 'ScalarTypeEnum.Boolean',\n // Special formats\n 'string:date': 'ScalarTypeEnum.Date',\n 'string:date-time': 'ScalarTypeEnum.DateTime',\n 'string:email': 'ScalarTypeEnum.EmailAddress',\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 isReference: true,\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 // Check if this schema was dereferenced from a $ref - use the original type name\n const originalTypeName = schemaObj['_originalTypeName'] as string | undefined;\n if (originalTypeName) {\n return {\n type: toPascalCase(originalTypeName),\n optional: nullable ?? false,\n array: false,\n primitive: false,\n isReference: true,\n };\n }\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 (scalarKey === 'string') {\n return {\n type: 'string',\n optional: nullable ?? false,\n array: false,\n primitive: true,\n };\n }\n if (scalarKey === 'integer' || type === 'number') {\n return {\n type: 'number',\n optional: nullable ?? false,\n array: false,\n primitive: true,\n };\n }\n if (scalarKey === '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 // For arrays, get the scalar type of the items\n if (type === 'array') {\n const items = schemaObj['items'] as OpenApiSchema | undefined;\n if (items) {\n return getScalarType(items);\n }\n return undefined;\n }\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\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 const 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 // Handle enum types (generate an EnumType export instead of a model)\n const enumValues = schemaObj['enum'] as unknown[] | undefined;\n if (enumValues && enumValues.length > 0) {\n const safeModelName = toPascalCase(toValidIdentifier(modelName));\n const enumCode = [\n `${spaces}/**`,\n `${spaces} * Enum type: ${safeModelName}`,\n description ? `${spaces} * ${description}` : null,\n `${spaces} */`,\n `${spaces}export const ${safeModelName} = new EnumType('${safeModelName}', [${enumValues.map((v) => `'${String(v)}'`).join(', ')}]);`,\n ]\n .filter((line) => line !== null)\n .join('\\n');\n\n return {\n name: safeModelName,\n description,\n fields: [],\n code: enumCode,\n };\n }\n\n // Handle primitive types (string, number, boolean) - generate type alias\n const schemaType = schemaObj['type'] as string | undefined;\n if (schemaType && !properties && !enumValues) {\n const safeModelName = toPascalCase(toValidIdentifier(modelName));\n const format = schemaObj['format'] as string | undefined;\n const scalarKey = format ? `${schemaType}:${format}` : schemaType;\n const scalarType =\n JSON_SCHEMA_TO_SCALAR[scalarKey] ?? JSON_SCHEMA_TO_SCALAR[schemaType];\n\n if (scalarType) {\n const aliasCode = [\n `${spaces}/**`,\n `${spaces} * Type alias: ${safeModelName}`,\n description ? `${spaces} * ${description}` : null,\n `${spaces} * Underlying type: ${scalarType}`,\n `${spaces} */`,\n `${spaces}export const ${safeModelName} = defineSchemaModel({`,\n `${spaces} name: '${safeModelName}',`,\n description\n ? `${spaces} description: ${JSON.stringify(description)},`\n : null,\n `${spaces} fields: {`,\n `${spaces} value: {`,\n `${spaces} type: ${scalarType}(),`,\n `${spaces} isOptional: false,`,\n `${spaces} },`,\n `${spaces} },`,\n `${spaces}});`,\n ]\n .filter((line) => line !== null)\n .join('\\n');\n\n return {\n name: safeModelName,\n description,\n fields: [],\n code: aliasCode,\n };\n }\n }\n\n // Handle additionalProperties (dictionary/map types)\n const additionalProperties = schemaObj['additionalProperties'];\n if (additionalProperties && !properties) {\n const safeModelName = toPascalCase(toValidIdentifier(modelName));\n\n // For dictionary types, we use JSONObject which is Record<string, unknown>\n // This is the correct representation in the schema library\n const dictCode = [\n `${spaces}/**`,\n `${spaces} * Dictionary/Record type: ${safeModelName}`,\n description ? `${spaces} * ${description}` : null,\n `${spaces} * Use as: Record<string, unknown> - access via record[key]`,\n `${spaces} */`,\n `${spaces}export const ${safeModelName} = ScalarTypeEnum.JSONObject();`,\n ]\n .filter((line) => line !== null)\n .join('\\n');\n\n return {\n name: safeModelName,\n description,\n fields: [],\n code: dictCode,\n };\n }\n\n if (!properties) {\n // No properties - generate an empty model (for empty object response types)\n const safeModelName = toPascalCase(toValidIdentifier(modelName));\n const emptyModelCode = [\n `${spaces}export const ${safeModelName} = defineSchemaModel({`,\n `${spaces} name: '${safeModelName}',`,\n description\n ? `${spaces} description: ${JSON.stringify(description)},`\n : null,\n `${spaces} fields: {},`,\n `${spaces}});`,\n ]\n .filter((line) => line !== null)\n .join('\\n');\n\n return {\n name: safeModelName,\n description,\n fields: [],\n code: emptyModelCode,\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 // Generate a name based on the field name\n const enumName = toPascalCase(field.name) + 'Enum';\n lines.push(\n `${spaces} type: new EnumType('${enumName}', [${field.enumValues.map((v) => `'${v}'`).join(', ')}]),`\n );\n } else if (field.scalarType) {\n // Scalar type\n lines.push(`${spaces} type: ${field.scalarType}(),`);\n } else if (field.type.primitive) {\n // Primitive type without a specific scalar mapping - use generic fallback\n const fallbackScalar = field.type.type === 'number' \n ? 'ScalarTypeEnum.Float_unsecure'\n : field.type.type === 'boolean'\n ? 'ScalarTypeEnum.Boolean_unsecure'\n : 'ScalarTypeEnum.String_unsecure';\n lines.push(`${spaces} type: ${fallbackScalar}(),`);\n } else if (field.type.isReference) {\n // Reference to another schema model\n lines.push(`${spaces} type: ${field.type.type},`);\n } else {\n // Inline nested object - TODO: Generate nested model\n lines.push(\n `${spaces} type: ScalarTypeEnum.JSONObject(), // TODO: Define nested model for ${field.type.type}`\n );\n }\n\n // Optional\n lines.push(`${spaces} isOptional: ${field.type.optional},`);\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 * @param fields - The fields to generate imports for\n * @param options - Configuration for import generation\n * @param sameDirectory - If true, imports use './' (for model-to-model). If false, uses '../models/' (for operations/events)\n */\nexport function generateImports(\n fields: SchemaField[],\n options: ContractsrcConfig,\n sameDirectory = true\n): string {\n const imports = new Set<string>();\n // Determine import path based on whether we're in the same directory\n const modelsDir = sameDirectory ? '.' : `../${options.conventions.models}`;\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 it's a reference (represented as a custom type not being scalar or enum)\n // In our simplified generator, referencing models often means just using the type name.\n // If we assume all models are generated in the same directory or available via barrel export,\n // we might not need explicit imports if we are in the same module,\n // BUT ContractSpec usually requires importing dependencies.\n // For now, let's assume we import from specific files.\n\n // Only import fields that are actual references to other schemas (not inline types)\n // Check isReference flag which is set when type came from $ref or _originalTypeName\n if (\n field.type.isReference &&\n !field.type.primitive &&\n !field.enumValues &&\n !field.scalarType &&\n !field.nestedModel\n ) {\n // This is a reference to another schema model\n const modelName = field.type.type;\n // Convert PascalCase model name to kebab-case file name\n const kebabName = modelName\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .toLowerCase();\n imports.add(`import { ${modelName} } from '${modelsDir}/${kebabName}';`);\n }\n }\n\n return Array.from(imports).join('\\n');\n}\n"],"mappings":"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"}