@lssm/lib.contracts-transformers 0.0.0-canary-20251220041653 → 0.0.0-canary-20251221132705
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/README.md +2 -2
- package/dist/common/index.d.ts +2 -2
- package/dist/common/types.d.ts +16 -10
- package/dist/common/types.d.ts.map +1 -1
- package/dist/index.d.ts +15 -6
- package/dist/index.js +13 -4
- package/dist/openapi/differ.d.ts +6 -6
- package/dist/openapi/differ.d.ts.map +1 -1
- package/dist/openapi/differ.js +11 -4
- package/dist/openapi/differ.js.map +1 -1
- package/dist/openapi/exporter/data-views.d.ts +38 -0
- package/dist/openapi/exporter/data-views.d.ts.map +1 -0
- package/dist/openapi/exporter/data-views.js +47 -0
- package/dist/openapi/exporter/data-views.js.map +1 -0
- package/dist/openapi/exporter/events.d.ts +28 -0
- package/dist/openapi/exporter/events.d.ts.map +1 -0
- package/dist/openapi/exporter/events.js +39 -0
- package/dist/openapi/exporter/events.js.map +1 -0
- package/dist/openapi/exporter/features.d.ts +37 -0
- package/dist/openapi/exporter/features.d.ts.map +1 -0
- package/dist/openapi/exporter/features.js +46 -0
- package/dist/openapi/exporter/features.js.map +1 -0
- package/dist/openapi/exporter/forms.d.ts +30 -0
- package/dist/openapi/exporter/forms.d.ts.map +1 -0
- package/dist/openapi/exporter/forms.js +49 -0
- package/dist/openapi/exporter/forms.js.map +1 -0
- package/dist/openapi/exporter/index.js +8 -0
- package/dist/openapi/exporter/operations.d.ts +65 -0
- package/dist/openapi/exporter/operations.d.ts.map +1 -0
- package/dist/openapi/exporter/operations.js +142 -0
- package/dist/openapi/exporter/operations.js.map +1 -0
- package/dist/openapi/exporter/presentations.d.ts +48 -0
- package/dist/openapi/exporter/presentations.d.ts.map +1 -0
- package/dist/openapi/exporter/presentations.js +66 -0
- package/dist/openapi/exporter/presentations.js.map +1 -0
- package/dist/openapi/exporter/registries.d.ts +23 -0
- package/dist/openapi/exporter/registries.d.ts.map +1 -0
- package/dist/openapi/exporter/registries.js +29 -0
- package/dist/openapi/exporter/registries.js.map +1 -0
- package/dist/openapi/exporter/workflows.d.ts +36 -0
- package/dist/openapi/exporter/workflows.d.ts.map +1 -0
- package/dist/openapi/exporter/workflows.js +54 -0
- package/dist/openapi/exporter/workflows.js.map +1 -0
- package/dist/openapi/exporter.d.ts +35 -15
- package/dist/openapi/exporter.d.ts.map +1 -1
- package/dist/openapi/exporter.js +78 -104
- package/dist/openapi/exporter.js.map +1 -1
- package/dist/openapi/importer/analyzer.js +28 -0
- package/dist/openapi/importer/analyzer.js.map +1 -0
- package/dist/openapi/importer/events.js +36 -0
- package/dist/openapi/importer/events.js.map +1 -0
- package/dist/openapi/importer/generator.js +71 -0
- package/dist/openapi/importer/generator.js.map +1 -0
- package/dist/openapi/importer/grouping.js +73 -0
- package/dist/openapi/importer/grouping.js.map +1 -0
- package/dist/openapi/importer/index.d.ts +17 -0
- package/dist/openapi/importer/index.d.ts.map +1 -0
- package/dist/openapi/importer/index.js +161 -0
- package/dist/openapi/importer/index.js.map +1 -0
- package/dist/openapi/importer/models.js +19 -0
- package/dist/openapi/importer/models.js.map +1 -0
- package/dist/openapi/importer/schemas.js +80 -0
- package/dist/openapi/importer/schemas.js.map +1 -0
- package/dist/openapi/index.d.ts +14 -5
- package/dist/openapi/index.js +15 -4
- package/dist/openapi/parser/document.d.ts +20 -0
- package/dist/openapi/parser/document.d.ts.map +1 -0
- package/dist/openapi/parser/document.js +95 -0
- package/dist/openapi/parser/document.js.map +1 -0
- package/dist/openapi/parser/index.js +5 -0
- package/dist/openapi/parser/operation.js +59 -0
- package/dist/openapi/parser/operation.js.map +1 -0
- package/dist/openapi/parser/parameters.js +37 -0
- package/dist/openapi/parser/parameters.js.map +1 -0
- package/dist/openapi/parser/resolvers.js +63 -0
- package/dist/openapi/parser/resolvers.js.map +1 -0
- package/dist/openapi/parser/utils.d.ts +19 -0
- package/dist/openapi/parser/utils.d.ts.map +1 -0
- package/dist/openapi/parser/utils.js +48 -0
- package/dist/openapi/parser/utils.js.map +1 -0
- package/dist/openapi/parser.js +6 -232
- package/dist/openapi/schema-converter.d.ts +7 -1
- package/dist/openapi/schema-converter.d.ts.map +1 -1
- package/dist/openapi/schema-converter.js +117 -20
- package/dist/openapi/schema-converter.js.map +1 -1
- package/dist/openapi/types.d.ts +75 -20
- package/dist/openapi/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/dist/openapi/importer.d.ts +0 -16
- package/dist/openapi/importer.d.ts.map +0 -1
- package/dist/openapi/importer.js +0 -265
- package/dist/openapi/importer.js.map +0 -1
- package/dist/openapi/parser.d.ts +0 -32
- package/dist/openapi/parser.d.ts.map +0 -1
- package/dist/openapi/parser.js.map +0 -1
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
//#region src/openapi/parser/resolvers.ts
|
|
2
|
+
/**
|
|
3
|
+
* Check if a value is a reference object.
|
|
4
|
+
*/
|
|
5
|
+
function isReference(obj) {
|
|
6
|
+
return typeof obj === "object" && obj !== null && "$ref" in obj;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Resolve a $ref reference in the document.
|
|
10
|
+
*/
|
|
11
|
+
function resolveRef(doc, ref) {
|
|
12
|
+
if (!ref.startsWith("#/")) return;
|
|
13
|
+
const path = ref.slice(2).split("/");
|
|
14
|
+
let current = doc;
|
|
15
|
+
for (const part of path) {
|
|
16
|
+
if (current === null || current === void 0) return void 0;
|
|
17
|
+
if (typeof current !== "object") return void 0;
|
|
18
|
+
current = current[part];
|
|
19
|
+
}
|
|
20
|
+
return current;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Recursively dereference a schema.
|
|
24
|
+
* Replaces all $ref with their resolved values.
|
|
25
|
+
* Preserves `_originalRef` to track where the schema came from.
|
|
26
|
+
*/
|
|
27
|
+
function dereferenceSchema(doc, schema, seen = /* @__PURE__ */ new Set()) {
|
|
28
|
+
if (!schema) return void 0;
|
|
29
|
+
if (isReference(schema)) {
|
|
30
|
+
if (seen.has(schema.$ref)) return schema;
|
|
31
|
+
const newSeen = new Set(seen);
|
|
32
|
+
newSeen.add(schema.$ref);
|
|
33
|
+
const resolved = resolveRef(doc, schema.$ref);
|
|
34
|
+
if (!resolved) return schema;
|
|
35
|
+
const dereferenced = dereferenceSchema(doc, resolved, newSeen);
|
|
36
|
+
if (!dereferenced) return schema;
|
|
37
|
+
const refParts = schema.$ref.split("/");
|
|
38
|
+
const typeName = refParts[refParts.length - 1];
|
|
39
|
+
return {
|
|
40
|
+
...dereferenced,
|
|
41
|
+
_originalRef: schema.$ref,
|
|
42
|
+
_originalTypeName: typeName
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const schemaObj = { ...schema };
|
|
46
|
+
if (schemaObj.properties) {
|
|
47
|
+
const props = schemaObj.properties;
|
|
48
|
+
const newProps = {};
|
|
49
|
+
for (const [key, prop] of Object.entries(props)) newProps[key] = dereferenceSchema(doc, prop, seen) ?? prop;
|
|
50
|
+
schemaObj.properties = newProps;
|
|
51
|
+
}
|
|
52
|
+
if (schemaObj.items) schemaObj.items = dereferenceSchema(doc, schemaObj.items, seen);
|
|
53
|
+
for (const comb of [
|
|
54
|
+
"allOf",
|
|
55
|
+
"anyOf",
|
|
56
|
+
"oneOf"
|
|
57
|
+
]) if (Array.isArray(schemaObj[comb])) schemaObj[comb] = schemaObj[comb].map((s) => dereferenceSchema(doc, s, seen) ?? s);
|
|
58
|
+
return schemaObj;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
//#endregion
|
|
62
|
+
export { dereferenceSchema, isReference, resolveRef };
|
|
63
|
+
//# sourceMappingURL=resolvers.js.map
|
|
@@ -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"}
|
package/dist/openapi/parser.js
CHANGED
|
@@ -1,232 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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":"
|
|
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;EAoOA,IAAA,EAAA,MAAA;;;;;;;;;;;;;;;UA5cC,WAAA;;;;QAIT;;;;;;gBAMQ;;;;;UAMC,cAAA;;;;;;UAMP;;;;;;;iBAuCM,gBAAA,SACN,+BAEP;;;;iBA0Ga,aAAA,SAAsB;;;;iBA2BtB,iBAAA,SACN,sDAGP;;;;iBA+Ba,uBAAA,SACN,oDAGP;;;;;;;iBAgOa,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.
|
|
9
|
-
integer: "ScalarTypeEnum.
|
|
10
|
-
number: "ScalarTypeEnum.
|
|
11
|
-
boolean: "ScalarTypeEnum.
|
|
12
|
-
"string:date": "ScalarTypeEnum.
|
|
13
|
-
"string:date-time": "ScalarTypeEnum.
|
|
14
|
-
"string:email": "ScalarTypeEnum.
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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)
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
if (field.
|
|
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
|
|