@lssm/lib.contracts-transformers 1.42.10 → 1.43.2
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 +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/openapi/importer/events.js +4 -2
- package/dist/openapi/importer/events.js.map +1 -1
- package/dist/openapi/importer/generator.js +46 -12
- package/dist/openapi/importer/generator.js.map +1 -1
- package/dist/openapi/importer/index.d.ts.map +1 -1
- package/dist/openapi/importer/index.js +25 -11
- package/dist/openapi/importer/index.js.map +1 -1
- package/dist/openapi/importer/models.js +5 -2
- package/dist/openapi/importer/models.js.map +1 -1
- package/dist/openapi/importer/schemas.js +30 -50
- package/dist/openapi/importer/schemas.js.map +1 -1
- package/dist/openapi/index.d.ts +2 -2
- package/dist/openapi/index.js +3 -2
- package/dist/openapi/parser/index.js +5 -0
- package/dist/openapi/parser.js +6 -0
- package/dist/openapi/schema-converter.d.ts +6 -11
- package/dist/openapi/schema-converter.d.ts.map +1 -1
- package/dist/openapi/schema-converter.js +24 -161
- package/dist/openapi/schema-converter.js.map +1 -1
- package/dist/openapi/schema-generators/index.js +462 -0
- package/dist/openapi/schema-generators/index.js.map +1 -0
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -49,6 +49,7 @@ const importResult = importFromOpenApi(openApiDoc, {
|
|
|
49
49
|
prefix: 'myApi',
|
|
50
50
|
tags: ['users', 'orders'], // Optional: filter by tags
|
|
51
51
|
exclude: ['deprecated_endpoint'], // Optional: exclude by operationId
|
|
52
|
+
schemaFormat: 'contractspec', // Optional: 'contractspec' | 'zod' | 'json-schema' | 'graphql'
|
|
52
53
|
});
|
|
53
54
|
|
|
54
55
|
// importResult contains generated spec code as strings
|
package/dist/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { ExportedForm, exportForms, generateFormsRegistry } from "./openapi/expo
|
|
|
12
12
|
import { ExportedDataView, exportDataViews, generateDataViewsRegistry } from "./openapi/exporter/data-views.js";
|
|
13
13
|
import { ExportedWorkflow, exportWorkflows, generateWorkflowsRegistry } from "./openapi/exporter/workflows.js";
|
|
14
14
|
import { RegistryGenerationOptions, generateRegistryIndex } from "./openapi/exporter/registries.js";
|
|
15
|
-
import { GeneratedModel, SchemaField, TypescriptType, generateImports, generateSchemaModelCode, getScalarType,
|
|
15
|
+
import { GeneratedModel, SchemaField, TypescriptType, generateImports, generateSchemaModelCode, getScalarType, jsonSchemaToType } from "./openapi/schema-converter.js";
|
|
16
16
|
import { importFromOpenApi, importOperation } from "./openapi/importer/index.js";
|
|
17
17
|
import { DiffOptions, createSpecDiff, diffAll, diffSpecVsOperation, diffSpecs, formatDiffChanges } from "./openapi/differ.js";
|
|
18
|
-
export { ContractSpecOpenApiDocument, ContractSpecRegistries, DiffChange, DiffChangeType, DiffOptions, ExportedDataView, ExportedEvent, ExportedFeature, ExportedForm, ExportedPresentation, ExportedWorkflow, GeneratedModel, HttpMethod, ImportResult, ImportedOperationSpec, OpenApiDocument, OpenApiExportOptions, OpenApiOperation, OpenApiParameter, OpenApiParseOptions, OpenApiSchema, OpenApiServer, OpenApiSource, OpenApiTransportHints, OpenApiVersion, OperationsExportResult, ParameterLocation, ParseResult, ParsedOperation, ParsedParameter, RegistryGenerationOptions, SchemaField, SpecDiff, SpecSource, SyncResult, TransportHints, TypescriptType, ValidationResult, contractSpecToJson, contractSpecToYaml, createSpecDiff, deepEqual, defaultRestPath, detectFormat, detectVersion, diffAll, diffSpecVsOperation, diffSpecs, exportContractSpec, exportDataViews, exportEvents, exportFeatures, exportForms, exportOperations, exportPresentations, exportPresentationsFromArray, exportWorkflows, extractPathParams, formatDiffChanges, generateDataViewsRegistry, generateEventsExports, generateFeaturesRegistry, generateFormsRegistry, generateImports, generateOperationsRegistry, generatePresentationsRegistry, generateRegistryIndex, generateSchemaModelCode, generateWorkflowsRegistry, getByPath, getScalarType, importFromOpenApi, importOperation, jsonSchemaForSpec,
|
|
18
|
+
export { ContractSpecOpenApiDocument, ContractSpecRegistries, DiffChange, DiffChangeType, DiffOptions, ExportedDataView, ExportedEvent, ExportedFeature, ExportedForm, ExportedPresentation, ExportedWorkflow, GeneratedModel, HttpMethod, ImportResult, ImportedOperationSpec, OpenApiDocument, OpenApiExportOptions, OpenApiOperation, OpenApiParameter, OpenApiParseOptions, OpenApiSchema, OpenApiServer, OpenApiSource, OpenApiTransportHints, OpenApiVersion, OperationsExportResult, ParameterLocation, ParseResult, ParsedOperation, ParsedParameter, RegistryGenerationOptions, SchemaField, SpecDiff, SpecSource, SyncResult, TransportHints, TypescriptType, ValidationResult, contractSpecToJson, contractSpecToYaml, createSpecDiff, deepEqual, defaultRestPath, detectFormat, detectVersion, diffAll, diffSpecVsOperation, diffSpecs, exportContractSpec, exportDataViews, exportEvents, exportFeatures, exportForms, exportOperations, exportPresentations, exportPresentationsFromArray, exportWorkflows, extractPathParams, formatDiffChanges, generateDataViewsRegistry, generateEventsExports, generateFeaturesRegistry, generateFormsRegistry, generateImports, generateOperationsRegistry, generatePresentationsRegistry, generateRegistryIndex, generateSchemaModelCode, generateWorkflowsRegistry, getByPath, getScalarType, importFromOpenApi, importOperation, jsonSchemaForSpec, jsonSchemaToType, normalizePath, openApiForRegistry, openApiToJson, openApiToYaml, parseOpenApi, parseOpenApiDocument, parseOpenApiString, schemaModelToJsonSchema, toCamelCase, toFileName, toHttpMethod, toKebabCase, toOperationId, toPascalCase, toRestPath, toSchemaName, toSnakeCase, toSpecKey, toValidIdentifier };
|
package/dist/index.js
CHANGED
|
@@ -10,9 +10,9 @@ import { exportWorkflows, generateWorkflowsRegistry } from "./openapi/exporter/w
|
|
|
10
10
|
import { generateRegistryIndex } from "./openapi/exporter/registries.js";
|
|
11
11
|
import { contractSpecToJson, contractSpecToYaml, exportContractSpec, openApiForRegistry, openApiToJson, openApiToYaml } from "./openapi/exporter.js";
|
|
12
12
|
import { deepEqual, extractPathParams, getByPath, normalizePath, toCamelCase, toFileName, toKebabCase, toPascalCase, toSnakeCase, toSpecKey, toValidIdentifier } from "./common/utils.js";
|
|
13
|
-
import { generateImports, generateSchemaModelCode, getScalarType,
|
|
13
|
+
import { generateImports, generateSchemaModelCode, getScalarType, jsonSchemaToType } from "./openapi/schema-converter.js";
|
|
14
14
|
import { importFromOpenApi, importOperation } from "./openapi/importer/index.js";
|
|
15
15
|
import { createSpecDiff, diffAll, diffSpecVsOperation, diffSpecs, formatDiffChanges } from "./openapi/differ.js";
|
|
16
16
|
import "./openapi/index.js";
|
|
17
17
|
|
|
18
|
-
export { contractSpecToJson, contractSpecToYaml, createSpecDiff, deepEqual, defaultRestPath, detectFormat, detectVersion, diffAll, diffSpecVsOperation, diffSpecs, exportContractSpec, exportDataViews, exportEvents, exportFeatures, exportForms, exportOperations, exportPresentations, exportPresentationsFromArray, exportWorkflows, extractPathParams, formatDiffChanges, generateDataViewsRegistry, generateEventsExports, generateFeaturesRegistry, generateFormsRegistry, generateImports, generateOperationsRegistry, generatePresentationsRegistry, generateRegistryIndex, generateSchemaModelCode, generateWorkflowsRegistry, getByPath, getScalarType, importFromOpenApi, importOperation, jsonSchemaForSpec,
|
|
18
|
+
export { contractSpecToJson, contractSpecToYaml, createSpecDiff, deepEqual, defaultRestPath, detectFormat, detectVersion, diffAll, diffSpecVsOperation, diffSpecs, exportContractSpec, exportDataViews, exportEvents, exportFeatures, exportForms, exportOperations, exportPresentations, exportPresentationsFromArray, exportWorkflows, extractPathParams, formatDiffChanges, generateDataViewsRegistry, generateEventsExports, generateFeaturesRegistry, generateFormsRegistry, generateImports, generateOperationsRegistry, generatePresentationsRegistry, generateRegistryIndex, generateSchemaModelCode, generateWorkflowsRegistry, getByPath, getScalarType, importFromOpenApi, importOperation, jsonSchemaForSpec, jsonSchemaToType, normalizePath, openApiForRegistry, openApiToJson, openApiToYaml, parseOpenApi, parseOpenApiDocument, parseOpenApiString, schemaModelToJsonSchema, toCamelCase, toFileName, toHttpMethod, toKebabCase, toOperationId, toPascalCase, toRestPath, toSchemaName, toSnakeCase, toSpecKey, toValidIdentifier };
|
|
@@ -8,10 +8,12 @@ import { generateImports, generateSchemaModelCode } from "../schema-converter.js
|
|
|
8
8
|
function generateEventCode(event, options) {
|
|
9
9
|
const eventName = toValidIdentifier(event.name);
|
|
10
10
|
const modelName = toPascalCase(eventName) + "Payload";
|
|
11
|
-
const
|
|
11
|
+
const schemaFormat = options.schemaFormat || "contractspec";
|
|
12
|
+
const payloadModel = generateSchemaModelCode(event.payload, modelName, schemaFormat, options);
|
|
12
13
|
const imports = /* @__PURE__ */ new Set();
|
|
13
14
|
imports.add("import { defineEvent, type EventSpec } from '@lssm/lib.contracts';");
|
|
14
|
-
|
|
15
|
+
if (payloadModel.imports && payloadModel.imports.length > 0) payloadModel.imports.forEach((i) => imports.add(i));
|
|
16
|
+
else if (payloadModel.fields && payloadModel.fields.length > 0) generateImports(payloadModel.fields, options).split("\n").filter(Boolean).forEach((i) => imports.add(i));
|
|
15
17
|
if (payloadModel.name !== modelName) {
|
|
16
18
|
const modelsDir = `../${options.conventions.models}`;
|
|
17
19
|
const kebabName = payloadModel.name.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","names":[],"sources":["../../../src/openapi/importer/events.ts"],"sourcesContent":["import type { ParsedEvent } from '../types';\nimport { generateImports, generateSchemaModelCode } from '../schema-converter';\nimport { toPascalCase, toValidIdentifier } from '../../common/utils';\nimport type { ContractsrcConfig } from '@lssm/lib.contracts';\n\n/**\n * Generate code for an event.\n */\nexport function generateEventCode(\n event: ParsedEvent,\n options: ContractsrcConfig\n): string {\n const eventName = toValidIdentifier(event.name);\n const modelName = toPascalCase(eventName) + 'Payload';\n\n // Generate payload model inline or referenced?\n // Let's generate the payload schema definition first\n const payloadModel = generateSchemaModelCode(event.payload
|
|
1
|
+
{"version":3,"file":"events.js","names":[],"sources":["../../../src/openapi/importer/events.ts"],"sourcesContent":["import type { ParsedEvent } from '../types';\nimport { generateImports, generateSchemaModelCode } from '../schema-converter';\nimport { toPascalCase, toValidIdentifier } from '../../common/utils';\nimport type { ContractsrcConfig } from '@lssm/lib.contracts';\n\n/**\n * Generate code for an event.\n */\nexport function generateEventCode(\n event: ParsedEvent,\n options: ContractsrcConfig\n): string {\n const eventName = toValidIdentifier(event.name);\n const modelName = toPascalCase(eventName) + 'Payload';\n\n const schemaFormat = options.schemaFormat || 'contractspec';\n // Generate payload model inline or referenced?\n // Let's generate the payload schema definition first\n const payloadModel = generateSchemaModelCode(\n event.payload,\n modelName,\n schemaFormat,\n options\n );\n\n const imports = new Set<string>();\n imports.add(\n \"import { defineEvent, type EventSpec } from '@lssm/lib.contracts';\"\n );\n\n if (payloadModel.imports && payloadModel.imports.length > 0) {\n payloadModel.imports.forEach((i) => imports.add(i));\n } else if (payloadModel.fields && payloadModel.fields.length > 0) {\n const modelImports = generateImports(payloadModel.fields, options);\n // Merge imports - this is a bit hacky string manipulation but works for now\n modelImports\n .split('\\n')\n .filter(Boolean)\n .forEach((i) => imports.add(i));\n }\n\n // If payloadModel is a reference (empty fields and different name), import it\n if (payloadModel.name !== modelName) {\n const modelsDir = `../${options.conventions.models}`;\n const kebabName = payloadModel.name\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .toLowerCase();\n imports.add(\n `import { ${payloadModel.name} } from '${modelsDir}/${kebabName}';`\n );\n }\n\n const allImports = Array.from(imports).join('\\n');\n\n return `\n${allImports}\n\n${payloadModel.code}\n\nexport const ${eventName} = defineEvent({\n meta: {\n key: '${event.name}',\n version: 1,\n description: ${JSON.stringify(event.description ?? '')},\n },\n payload: ${payloadModel.name},\n});\n`.trim();\n}\n"],"mappings":";;;;;;;AAQA,SAAgB,kBACd,OACA,SACQ;CACR,MAAM,YAAY,kBAAkB,MAAM,KAAK;CAC/C,MAAM,YAAY,aAAa,UAAU,GAAG;CAE5C,MAAM,eAAe,QAAQ,gBAAgB;CAG7C,MAAM,eAAe,wBACnB,MAAM,SACN,WACA,cACA,QACD;CAED,MAAM,0BAAU,IAAI,KAAa;AACjC,SAAQ,IACN,qEACD;AAED,KAAI,aAAa,WAAW,aAAa,QAAQ,SAAS,EACxD,cAAa,QAAQ,SAAS,MAAM,QAAQ,IAAI,EAAE,CAAC;UAC1C,aAAa,UAAU,aAAa,OAAO,SAAS,EAG7D,CAFqB,gBAAgB,aAAa,QAAQ,QAAQ,CAG/D,MAAM,KAAK,CACX,OAAO,QAAQ,CACf,SAAS,MAAM,QAAQ,IAAI,EAAE,CAAC;AAInC,KAAI,aAAa,SAAS,WAAW;EACnC,MAAM,YAAY,MAAM,QAAQ,YAAY;EAC5C,MAAM,YAAY,aAAa,KAC5B,QAAQ,sBAAsB,QAAQ,CACtC,aAAa;AAChB,UAAQ,IACN,YAAY,aAAa,KAAK,WAAW,UAAU,GAAG,UAAU,IACjE;;AAKH,QAAO;EAFY,MAAM,KAAK,QAAQ,CAAC,KAAK,KAAK,CAGtC;;EAEX,aAAa,KAAK;;eAEL,UAAU;;YAEb,MAAM,KAAK;;mBAEJ,KAAK,UAAU,MAAM,eAAe,GAAG,CAAC;;aAE9C,aAAa,KAAK;;EAE7B,MAAM"}
|
|
@@ -6,22 +6,54 @@ import { inferAuthLevel, inferOpKind } from "./analyzer.js";
|
|
|
6
6
|
/**
|
|
7
7
|
* Generate ContractSpec TypeScript code for an operation.
|
|
8
8
|
*/
|
|
9
|
-
function generateSpecCode(operation, contractspecConfig, options = {}, inputModel, outputModel) {
|
|
9
|
+
function generateSpecCode(operation, contractspecConfig, options = {}, inputModel, outputModel, queryModel = null, paramsModel = null, headersModel = null) {
|
|
10
10
|
const specKey = toSpecKey(operation.operationId, options.prefix);
|
|
11
11
|
const kind = inferOpKind(operation.method);
|
|
12
12
|
const auth = inferAuthLevel(operation, options.defaultAuth ?? "user");
|
|
13
13
|
const lines = [];
|
|
14
14
|
lines.push("import { defineCommand, defineQuery } from '@lssm/lib.contracts';");
|
|
15
|
-
if (inputModel || outputModel
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
if (inputModel || outputModel || queryModel || paramsModel || headersModel) {
|
|
16
|
+
const collectedImports = /* @__PURE__ */ new Set();
|
|
17
|
+
const models = [
|
|
18
|
+
inputModel,
|
|
19
|
+
outputModel,
|
|
20
|
+
queryModel,
|
|
21
|
+
paramsModel,
|
|
22
|
+
headersModel
|
|
23
|
+
].filter((m) => !!m);
|
|
24
|
+
models.forEach((m) => {
|
|
25
|
+
if (m.imports && m.imports.length > 0) m.imports.forEach((i) => collectedImports.add(i));
|
|
26
|
+
});
|
|
27
|
+
const legacyFields = models.filter((m) => !m.imports || m.imports.length === 0).flatMap((m) => m.fields);
|
|
28
|
+
if (legacyFields.length > 0) generateImports(legacyFields, contractspecConfig, false).split("\n").filter(Boolean).forEach((i) => collectedImports.add(i));
|
|
29
|
+
if (collectedImports.size > 0) lines.push(Array.from(collectedImports).sort().join("\n"));
|
|
21
30
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
31
|
+
lines.push("");
|
|
32
|
+
const schemaSections = [
|
|
33
|
+
{
|
|
34
|
+
label: "Input schema",
|
|
35
|
+
model: inputModel
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
label: "Query schema",
|
|
39
|
+
model: queryModel
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
label: "Path schema",
|
|
43
|
+
model: paramsModel
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
label: "Header schema",
|
|
47
|
+
model: headersModel
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
label: "Output schema",
|
|
51
|
+
model: outputModel
|
|
52
|
+
}
|
|
53
|
+
];
|
|
54
|
+
for (const section of schemaSections) if (section.model && section.model.code) {
|
|
55
|
+
lines.push(`// ${section.label}`);
|
|
56
|
+
lines.push(section.model.code);
|
|
25
57
|
lines.push("");
|
|
26
58
|
}
|
|
27
59
|
const defineFunc = kind === "command" ? "defineCommand" : "defineQuery";
|
|
@@ -47,8 +79,10 @@ function generateSpecCode(operation, contractspecConfig, options = {}, inputMode
|
|
|
47
79
|
lines.push(` context: 'Imported from OpenAPI: ${operation.method.toUpperCase()} ${operation.path}',`);
|
|
48
80
|
lines.push(" },");
|
|
49
81
|
lines.push(" io: {");
|
|
50
|
-
|
|
51
|
-
|
|
82
|
+
lines.push(` input: ${inputModel?.name ?? "null"},`);
|
|
83
|
+
if (queryModel) lines.push(` query: ${queryModel.name},`);
|
|
84
|
+
if (paramsModel) lines.push(` params: ${paramsModel.name},`);
|
|
85
|
+
if (headersModel) lines.push(` headers: ${headersModel.name},`);
|
|
52
86
|
if (outputModel) lines.push(` output: ${outputModel.name},`);
|
|
53
87
|
else lines.push(" output: null, // TODO: Define output schema");
|
|
54
88
|
lines.push(" },");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.js","names":["lines: string[]"],"sources":["../../../src/openapi/importer/generator.ts"],"sourcesContent":["import type { ParsedOperation } from '../types';\nimport { toPascalCase, toSpecKey, toValidIdentifier } from '../../common/utils';\nimport { type GeneratedModel, generateImports } from '../schema-converter';\nimport { inferAuthLevel, inferOpKind } from './analyzer';\nimport type {\n ContractsrcConfig,\n OpenApiSourceConfig,\n} from '@lssm/lib.contracts';\n\n/**\n * Generate ContractSpec TypeScript code for an operation.\n */\nexport function generateSpecCode(\n operation: ParsedOperation,\n contractspecConfig: ContractsrcConfig,\n options: Partial<OpenApiSourceConfig> = {},\n inputModel: GeneratedModel | null,\n outputModel: GeneratedModel | null\n): string {\n const specKey = toSpecKey(operation.operationId, options.prefix);\n const kind = inferOpKind(operation.method);\n const auth = inferAuthLevel(operation, options.defaultAuth ?? 'user');\n\n const lines: string[] = [];\n\n // Imports\n lines.push(\n \"import { defineCommand, defineQuery } from '@lssm/lib.contracts';\"\n );\n if (inputModel || outputModel) {\n
|
|
1
|
+
{"version":3,"file":"generator.js","names":["lines: string[]"],"sources":["../../../src/openapi/importer/generator.ts"],"sourcesContent":["import type { ParsedOperation } from '../types';\nimport { toPascalCase, toSpecKey, toValidIdentifier } from '../../common/utils';\nimport { type GeneratedModel, generateImports } from '../schema-converter';\nimport { inferAuthLevel, inferOpKind } from './analyzer';\nimport type {\n ContractsrcConfig,\n OpenApiSourceConfig,\n} from '@lssm/lib.contracts';\n\n/**\n * Generate ContractSpec TypeScript code for an operation.\n */\nexport function generateSpecCode(\n operation: ParsedOperation,\n contractspecConfig: ContractsrcConfig,\n options: Partial<OpenApiSourceConfig> = {},\n inputModel: GeneratedModel | null,\n outputModel: GeneratedModel | null,\n queryModel: GeneratedModel | null = null,\n paramsModel: GeneratedModel | null = null,\n headersModel: GeneratedModel | null = null\n): string {\n const specKey = toSpecKey(operation.operationId, options.prefix);\n const kind = inferOpKind(operation.method);\n const auth = inferAuthLevel(operation, options.defaultAuth ?? 'user');\n\n const lines: string[] = [];\n\n // Imports\n lines.push(\n \"import { defineCommand, defineQuery } from '@lssm/lib.contracts';\"\n );\n if (inputModel || outputModel || queryModel || paramsModel || headersModel) {\n const collectedImports = new Set<string>();\n const models = [\n inputModel,\n outputModel,\n queryModel,\n paramsModel,\n headersModel,\n ].filter((m): m is GeneratedModel => !!m);\n\n // Add explicit imports from generators (e.g. Zod, JsonSchema)\n models.forEach((m) => {\n if (m.imports && m.imports.length > 0) {\n m.imports.forEach((i) => collectedImports.add(i));\n }\n });\n\n // Add legacy fields-based imports (ContractSpec format)\n const legacyModels = models.filter(\n (m) => !m.imports || m.imports.length === 0\n );\n const legacyFields = legacyModels.flatMap((m) => m.fields);\n\n if (legacyFields.length > 0) {\n const legacyImportStr = generateImports(\n legacyFields,\n contractspecConfig,\n false\n );\n legacyImportStr\n .split('\\n')\n .filter(Boolean)\n .forEach((i) => collectedImports.add(i));\n }\n\n if (collectedImports.size > 0) {\n lines.push(Array.from(collectedImports).sort().join('\\n'));\n }\n }\n lines.push('');\n\n // Generate schemas\n const schemaSections = [\n { label: 'Input schema', model: inputModel },\n { label: 'Query schema', model: queryModel },\n { label: 'Path schema', model: paramsModel },\n { label: 'Header schema', model: headersModel },\n { label: 'Output schema', model: outputModel },\n ];\n\n for (const section of schemaSections) {\n if (section.model && section.model.code) {\n lines.push(`// ${section.label}`);\n lines.push(section.model.code);\n lines.push('');\n }\n }\n\n // Generate spec\n const defineFunc = kind === 'command' ? 'defineCommand' : 'defineQuery';\n const safeName = toValidIdentifier(toPascalCase(operation.operationId));\n\n lines.push(`/**`);\n lines.push(` * ${operation.summary ?? operation.operationId}`);\n if (operation.description) {\n lines.push(` *`);\n lines.push(` * ${operation.description}`);\n }\n lines.push(` *`);\n lines.push(\n ` * @source OpenAPI: ${operation.method.toUpperCase()} ${operation.path}`\n );\n lines.push(` */`);\n lines.push(`export const ${safeName}Spec = ${defineFunc}({`);\n\n // Meta\n lines.push(' meta: {');\n lines.push(` key: '${specKey}',`);\n lines.push(' version: 1,');\n lines.push(` stability: '${options.defaultStability ?? 'stable'}',`);\n lines.push(\n ` owners: [${(options.defaultOwners ?? []).map((o) => `'${o}'`).join(', ')}],`\n );\n lines.push(` tags: [${operation.tags.map((t) => `'${t}'`).join(', ')}],`);\n lines.push(\n ` description: ${JSON.stringify(operation.summary ?? operation.operationId)},`\n );\n lines.push(\n ` goal: ${JSON.stringify(operation.description ?? 'Imported from OpenAPI')},`\n );\n lines.push(\n ` context: 'Imported from OpenAPI: ${operation.method.toUpperCase()} ${operation.path}',`\n );\n lines.push(' },');\n\n // IO\n lines.push(' io: {');\n lines.push(` input: ${inputModel?.name ?? 'null'},`);\n if (queryModel) lines.push(` query: ${queryModel.name},`);\n if (paramsModel) lines.push(` params: ${paramsModel.name},`);\n if (headersModel) lines.push(` headers: ${headersModel.name},`);\n\n if (outputModel) {\n lines.push(` output: ${outputModel.name},`);\n } else {\n lines.push(' output: null, // TODO: Define output schema');\n }\n lines.push(' },');\n\n // Policy\n lines.push(' policy: {');\n lines.push(` auth: '${auth}',`);\n lines.push(' },');\n\n // Transport hints\n const httpMethod = operation.method.toUpperCase();\n const restMethod = httpMethod === 'GET' ? 'GET' : 'POST';\n lines.push(' transport: {');\n lines.push(' rest: {');\n lines.push(` method: '${restMethod}',`);\n lines.push(` path: '${operation.path}',`);\n lines.push(' },');\n lines.push(' },');\n\n lines.push('});');\n\n return lines.join('\\n');\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/openapi/importer/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/openapi/importer/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AAgTgB,cA/QH,iBA+QkB,EAAA,CAAA,WAAA,EA9QhB,WA8QgB,EAAA,mBAAA,EA7QR,iBA6QQ,EAAA,aAAA,CAAA,EA5Qd,OA4Qc,CA5QN,mBA4QM,CAAA,EAAA,GA3Q5B,YA2Q4B;;;;AAGR,iBAHP,eAAA,CAGO,SAAA,EAFV,eAEU,EAAA,OAAA,EADZ,OACY,CADJ,mBACI,CAAA,GAAA,SAAA,EAAA,mBAAA,EAAA,iBAAA,CAAA,EAAA,MAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { toFileName, toSpecKey } from "../../common/utils.js";
|
|
2
2
|
import { generateSchemaModelCode } from "../schema-converter.js";
|
|
3
|
-
import {
|
|
3
|
+
import { buildInputSchemas, getOutputSchema } from "./schemas.js";
|
|
4
4
|
import { COMMAND_METHODS, inferAuthLevel, inferOpKind } from "./analyzer.js";
|
|
5
5
|
import { generateSpecCode } from "./generator.js";
|
|
6
6
|
import { generateModelCode } from "./models.js";
|
|
@@ -49,12 +49,16 @@ const importFromOpenApi = (parseResult, contractspecOptions, importOptions = {})
|
|
|
49
49
|
continue;
|
|
50
50
|
}
|
|
51
51
|
try {
|
|
52
|
-
const
|
|
53
|
-
const
|
|
52
|
+
const inputSchemas = buildInputSchemas(operation);
|
|
53
|
+
const schemaFormat = importOptions.schemaFormat || contractspecOptions.schemaFormat || "contractspec";
|
|
54
|
+
const inputModel = inputSchemas.body ? generateSchemaModelCode(inputSchemas.body, `${operation.operationId}Input`, schemaFormat, contractspecOptions) : null;
|
|
55
|
+
const queryModel = inputSchemas.query ? generateSchemaModelCode(inputSchemas.query, `${operation.operationId}Query`, schemaFormat, contractspecOptions) : null;
|
|
56
|
+
const paramsModel = inputSchemas.params ? generateSchemaModelCode(inputSchemas.params, `${operation.operationId}Params`, schemaFormat, contractspecOptions) : null;
|
|
57
|
+
const headersModel = inputSchemas.headers ? generateSchemaModelCode(inputSchemas.headers, `${operation.operationId}Headers`, schemaFormat, contractspecOptions) : null;
|
|
54
58
|
const outputSchema = getOutputSchema(operation);
|
|
55
|
-
let outputModel = outputSchema ? generateSchemaModelCode(outputSchema, `${operation.operationId}Output
|
|
56
|
-
if (outputModel && !outputModel.code.includes("defineSchemaModel")) outputModel = null;
|
|
57
|
-
const code = generateSpecCode(operation, contractspecOptions, importOptions, inputModel, outputModel);
|
|
59
|
+
let outputModel = outputSchema ? generateSchemaModelCode(outputSchema, `${operation.operationId}Output`, schemaFormat, contractspecOptions) : null;
|
|
60
|
+
if (outputModel && schemaFormat === "contractspec" && !outputModel.code.includes("defineSchemaModel")) outputModel = null;
|
|
61
|
+
const code = generateSpecCode(operation, contractspecOptions, importOptions, inputModel, outputModel, queryModel, paramsModel, headersModel);
|
|
58
62
|
const fileName = toFileName(toSpecKey(operation.operationId, importOptions.prefix));
|
|
59
63
|
const transportHints = { rest: {
|
|
60
64
|
method: operation.method.toUpperCase(),
|
|
@@ -89,7 +93,10 @@ const importFromOpenApi = (parseResult, contractspecOptions, importOptions = {})
|
|
|
89
93
|
}
|
|
90
94
|
}
|
|
91
95
|
for (const [name, schema] of Object.entries(parseResult.schemas)) try {
|
|
92
|
-
const code = generateModelCode(name, schema,
|
|
96
|
+
const code = generateModelCode(name, schema, {
|
|
97
|
+
...contractspecOptions,
|
|
98
|
+
schemaFormat: importOptions.schemaFormat || contractspecOptions.schemaFormat
|
|
99
|
+
});
|
|
93
100
|
const fileName = toFileName(toSpecKey(name, importOptions.prefix));
|
|
94
101
|
const groupFolder = resolveModelGroupFolder(name, contractspecOptions.conventions);
|
|
95
102
|
specs.push({
|
|
@@ -112,7 +119,10 @@ const importFromOpenApi = (parseResult, contractspecOptions, importOptions = {})
|
|
|
112
119
|
});
|
|
113
120
|
}
|
|
114
121
|
for (const event of parseResult.events) try {
|
|
115
|
-
const code = generateEventCode(event,
|
|
122
|
+
const code = generateEventCode(event, {
|
|
123
|
+
...contractspecOptions,
|
|
124
|
+
schemaFormat: importOptions.schemaFormat || contractspecOptions.schemaFormat
|
|
125
|
+
});
|
|
116
126
|
const fileName = toFileName(toSpecKey(event.name, importOptions.prefix));
|
|
117
127
|
const groupFolder = resolveEventGroupFolder(event.name, contractspecOptions.conventions);
|
|
118
128
|
specs.push({
|
|
@@ -150,10 +160,14 @@ const importFromOpenApi = (parseResult, contractspecOptions, importOptions = {})
|
|
|
150
160
|
* Import a single operation to ContractSpec code.
|
|
151
161
|
*/
|
|
152
162
|
function importOperation(operation, options = {}, contractspecOptions) {
|
|
153
|
-
const
|
|
154
|
-
const
|
|
163
|
+
const inputSchemas = buildInputSchemas(operation);
|
|
164
|
+
const schemaFormat = options.schemaFormat || contractspecOptions.schemaFormat || "contractspec";
|
|
165
|
+
const inputModel = inputSchemas.body ? generateSchemaModelCode(inputSchemas.body, `${operation.operationId}Input`, schemaFormat, contractspecOptions) : null;
|
|
166
|
+
const queryModel = inputSchemas.query ? generateSchemaModelCode(inputSchemas.query, `${operation.operationId}Query`, schemaFormat, contractspecOptions) : null;
|
|
167
|
+
const paramsModel = inputSchemas.params ? generateSchemaModelCode(inputSchemas.params, `${operation.operationId}Params`, schemaFormat, contractspecOptions) : null;
|
|
168
|
+
const headersModel = inputSchemas.headers ? generateSchemaModelCode(inputSchemas.headers, `${operation.operationId}Headers`, schemaFormat, contractspecOptions) : null;
|
|
155
169
|
const outputSchema = getOutputSchema(operation);
|
|
156
|
-
return generateSpecCode(operation, contractspecOptions, options, inputModel, outputSchema ? generateSchemaModelCode(outputSchema, `${operation.operationId}Output
|
|
170
|
+
return generateSpecCode(operation, contractspecOptions, options, inputModel, outputSchema ? generateSchemaModelCode(outputSchema, `${operation.operationId}Output`, schemaFormat, contractspecOptions) : null, queryModel, paramsModel, headersModel);
|
|
157
171
|
}
|
|
158
172
|
|
|
159
173
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["specs: ImportedOperationSpec[]","skipped: ImportResult['skipped']","errors: ImportResult['errors']","transportHints: OpenApiTransportHints","source: OpenApiSource"],"sources":["../../../src/openapi/importer/index.ts"],"sourcesContent":["import type {\n OpenApiSource,\n OpenApiTransportHints,\n ParsedOperation,\n ParseResult,\n} from '../types';\nimport type { ImportedOperationSpec, ImportResult } from '../../common/types';\nimport { toFileName, toSpecKey } from '../../common/utils';\nimport { generateSchemaModelCode } from '../schema-converter';\nimport { buildInputSchema, getOutputSchema } from './schemas';\nimport { generateSpecCode } from './generator';\nimport { generateModelCode } from './models';\nimport { generateEventCode } from './events';\nimport {\n resolveOperationGroupFolder,\n resolveModelGroupFolder,\n resolveEventGroupFolder,\n} from './grouping';\nimport type {\n ContractsrcConfig,\n OpenApiSourceConfig,\n} from '@lssm/lib.contracts';\n\nexport * from './analyzer';\nexport * from './schemas';\nexport * from './generator';\nexport * from './models';\nexport * from './events';\nexport * from './grouping';\n\n/**\n * Import operations from a parsed OpenAPI document.\n */\nexport const importFromOpenApi = (\n parseResult: ParseResult,\n contractspecOptions: ContractsrcConfig,\n importOptions: Partial<OpenApiSourceConfig> = {}\n): ImportResult => {\n const { tags, exclude = [], include } = importOptions;\n const specs: ImportedOperationSpec[] = [];\n const skipped: ImportResult['skipped'] = [];\n const errors: ImportResult['errors'] = [];\n\n for (const operation of parseResult.operations) {\n // Filter by tags if specified\n if (tags && tags.length > 0) {\n const hasMatchingTag = operation.tags.some((t) => tags.includes(t));\n if (!hasMatchingTag) {\n skipped.push({\n sourceId: operation.operationId,\n reason: `No matching tags (has: ${operation.tags.join(', ')})`,\n });\n continue;\n }\n }\n\n // Filter by include/exclude\n if (include && include.length > 0) {\n if (!include.includes(operation.operationId)) {\n skipped.push({\n sourceId: operation.operationId,\n reason: 'Not in include list',\n });\n continue;\n }\n } else if (exclude.includes(operation.operationId)) {\n skipped.push({\n sourceId: operation.operationId,\n reason: 'In exclude list',\n });\n continue;\n }\n\n // Skip deprecated operations by default\n if (\n operation.deprecated &&\n importOptions.defaultStability !== 'deprecated'\n ) {\n skipped.push({\n sourceId: operation.operationId,\n reason: 'Deprecated operation',\n });\n continue;\n }\n\n try {\n // Build input schema\n const { schema: inputSchema } = buildInputSchema(operation);\n const inputModel = inputSchema\n ? generateSchemaModelCode(inputSchema, `${operation.operationId}Input`)\n : null;\n\n // Get output schema\n const outputSchema = getOutputSchema(operation);\n let outputModel = outputSchema\n ? generateSchemaModelCode(\n outputSchema,\n `${operation.operationId}Output`\n )\n : null;\n\n // Filter out empty/comment-only output models\n if (outputModel && !outputModel.code.includes('defineSchemaModel')) {\n outputModel = null;\n }\n\n // Generate spec code\n const code = generateSpecCode(\n operation,\n contractspecOptions,\n importOptions,\n inputModel,\n outputModel\n );\n const specName = toSpecKey(operation.operationId, importOptions.prefix);\n const fileName = toFileName(specName);\n\n // Build transport hints\n const transportHints: OpenApiTransportHints = {\n rest: {\n method:\n operation.method.toUpperCase() as OpenApiTransportHints['rest']['method'],\n path: operation.path,\n params: {\n path: operation.pathParams.map((p) => p.name),\n query: operation.queryParams.map((p) => p.name),\n header: operation.headerParams.map((p) => p.name),\n cookie: operation.cookieParams.map((p) => p.name),\n },\n },\n };\n\n // Build source info\n const source: OpenApiSource = {\n type: 'openapi',\n sourceId: operation.operationId,\n operationId: operation.operationId,\n openApiVersion: parseResult.version,\n importedAt: new Date(),\n };\n\n // Resolve group folder based on config\n const groupFolder = resolveOperationGroupFolder(\n operation,\n contractspecOptions.conventions\n );\n\n specs.push({\n code,\n fileName,\n groupFolder: groupFolder || undefined,\n source,\n transportHints,\n });\n } catch (error) {\n errors.push({\n sourceId: operation.operationId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // Import standalone models\n for (const [name, schema] of Object.entries(parseResult.schemas)) {\n try {\n const code = generateModelCode(name, schema, contractspecOptions);\n const fileName = toFileName(toSpecKey(name, importOptions.prefix));\n const groupFolder = resolveModelGroupFolder(\n name,\n contractspecOptions.conventions\n );\n\n specs.push({\n code,\n fileName,\n groupFolder: groupFolder || undefined,\n source: {\n type: 'openapi',\n sourceId: name,\n operationId: name,\n openApiVersion: parseResult.version,\n importedAt: new Date(),\n } as OpenApiSource,\n transportHints: {},\n });\n } catch (error) {\n errors.push({\n sourceId: name,\n error:\n error instanceof Error\n ? 'Model conversion failed: ' + error.message\n : String(error),\n });\n }\n }\n\n // Import events\n for (const event of parseResult.events) {\n try {\n const code = generateEventCode(event, contractspecOptions);\n const fileName = toFileName(toSpecKey(event.name, importOptions.prefix));\n const groupFolder = resolveEventGroupFolder(\n event.name,\n contractspecOptions.conventions\n );\n\n specs.push({\n code,\n fileName,\n groupFolder: groupFolder || undefined,\n source: {\n type: 'openapi',\n sourceId: event.name,\n operationId: event.name,\n openApiVersion: parseResult.version,\n importedAt: new Date(),\n } as OpenApiSource,\n transportHints: {},\n });\n } catch (error) {\n errors.push({\n sourceId: event.name,\n error:\n error instanceof Error\n ? 'Event conversion failed: ' + error.message\n : String(error),\n });\n }\n }\n\n return {\n operationSpecs: specs,\n skipped,\n errors,\n summary: {\n total:\n parseResult.operations.length +\n Object.keys(parseResult.schemas).length +\n parseResult.events.length,\n imported: specs.length,\n skipped: skipped.length,\n errors: errors.length,\n },\n };\n};\n\n/**\n * Import a single operation to ContractSpec code.\n */\nexport function importOperation(\n operation: ParsedOperation,\n options: Partial<OpenApiSourceConfig> = {},\n contractspecOptions: ContractsrcConfig\n): string {\n const { schema: inputSchema } = buildInputSchema(operation);\n const inputModel = inputSchema\n ? generateSchemaModelCode(inputSchema, `${operation.operationId}Input`)\n : null;\n\n const outputSchema = getOutputSchema(operation);\n const outputModel = outputSchema\n ? generateSchemaModelCode(outputSchema, `${operation.operationId}Output`)\n : null;\n\n return generateSpecCode(\n operation,\n contractspecOptions,\n options,\n inputModel,\n outputModel\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAiCA,MAAa,qBACX,aACA,qBACA,gBAA8C,EAAE,KAC/B;CACjB,MAAM,EAAE,MAAM,UAAU,EAAE,EAAE,YAAY;CACxC,MAAMA,QAAiC,EAAE;CACzC,MAAMC,UAAmC,EAAE;CAC3C,MAAMC,SAAiC,EAAE;AAEzC,MAAK,MAAM,aAAa,YAAY,YAAY;AAE9C,MAAI,QAAQ,KAAK,SAAS,GAExB;OAAI,CADmB,UAAU,KAAK,MAAM,MAAM,KAAK,SAAS,EAAE,CAAC,EAC9C;AACnB,YAAQ,KAAK;KACX,UAAU,UAAU;KACpB,QAAQ,0BAA0B,UAAU,KAAK,KAAK,KAAK,CAAC;KAC7D,CAAC;AACF;;;AAKJ,MAAI,WAAW,QAAQ,SAAS,GAC9B;OAAI,CAAC,QAAQ,SAAS,UAAU,YAAY,EAAE;AAC5C,YAAQ,KAAK;KACX,UAAU,UAAU;KACpB,QAAQ;KACT,CAAC;AACF;;aAEO,QAAQ,SAAS,UAAU,YAAY,EAAE;AAClD,WAAQ,KAAK;IACX,UAAU,UAAU;IACpB,QAAQ;IACT,CAAC;AACF;;AAIF,MACE,UAAU,cACV,cAAc,qBAAqB,cACnC;AACA,WAAQ,KAAK;IACX,UAAU,UAAU;IACpB,QAAQ;IACT,CAAC;AACF;;AAGF,MAAI;GAEF,MAAM,EAAE,QAAQ,gBAAgB,iBAAiB,UAAU;GAC3D,MAAM,aAAa,cACf,wBAAwB,aAAa,GAAG,UAAU,YAAY,OAAO,GACrE;GAGJ,MAAM,eAAe,gBAAgB,UAAU;GAC/C,IAAI,cAAc,eACd,wBACE,cACA,GAAG,UAAU,YAAY,QAC1B,GACD;AAGJ,OAAI,eAAe,CAAC,YAAY,KAAK,SAAS,oBAAoB,CAChE,eAAc;GAIhB,MAAM,OAAO,iBACX,WACA,qBACA,eACA,YACA,YACD;GAED,MAAM,WAAW,WADA,UAAU,UAAU,aAAa,cAAc,OAAO,CAClC;GAGrC,MAAMC,iBAAwC,EAC5C,MAAM;IACJ,QACE,UAAU,OAAO,aAAa;IAChC,MAAM,UAAU;IAChB,QAAQ;KACN,MAAM,UAAU,WAAW,KAAK,MAAM,EAAE,KAAK;KAC7C,OAAO,UAAU,YAAY,KAAK,MAAM,EAAE,KAAK;KAC/C,QAAQ,UAAU,aAAa,KAAK,MAAM,EAAE,KAAK;KACjD,QAAQ,UAAU,aAAa,KAAK,MAAM,EAAE,KAAK;KAClD;IACF,EACF;GAGD,MAAMC,SAAwB;IAC5B,MAAM;IACN,UAAU,UAAU;IACpB,aAAa,UAAU;IACvB,gBAAgB,YAAY;IAC5B,4BAAY,IAAI,MAAM;IACvB;GAGD,MAAM,cAAc,4BAClB,WACA,oBAAoB,YACrB;AAED,SAAM,KAAK;IACT;IACA;IACA,aAAa,eAAe;IAC5B;IACA;IACD,CAAC;WACK,OAAO;AACd,UAAO,KAAK;IACV,UAAU,UAAU;IACpB,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAC9D,CAAC;;;AAKN,MAAK,MAAM,CAAC,MAAM,WAAW,OAAO,QAAQ,YAAY,QAAQ,CAC9D,KAAI;EACF,MAAM,OAAO,kBAAkB,MAAM,QAAQ,oBAAoB;EACjE,MAAM,WAAW,WAAW,UAAU,MAAM,cAAc,OAAO,CAAC;EAClE,MAAM,cAAc,wBAClB,MACA,oBAAoB,YACrB;AAED,QAAM,KAAK;GACT;GACA;GACA,aAAa,eAAe;GAC5B,QAAQ;IACN,MAAM;IACN,UAAU;IACV,aAAa;IACb,gBAAgB,YAAY;IAC5B,4BAAY,IAAI,MAAM;IACvB;GACD,gBAAgB,EAAE;GACnB,CAAC;UACK,OAAO;AACd,SAAO,KAAK;GACV,UAAU;GACV,OACE,iBAAiB,QACb,8BAA8B,MAAM,UACpC,OAAO,MAAM;GACpB,CAAC;;AAKN,MAAK,MAAM,SAAS,YAAY,OAC9B,KAAI;EACF,MAAM,OAAO,kBAAkB,OAAO,oBAAoB;EAC1D,MAAM,WAAW,WAAW,UAAU,MAAM,MAAM,cAAc,OAAO,CAAC;EACxE,MAAM,cAAc,wBAClB,MAAM,MACN,oBAAoB,YACrB;AAED,QAAM,KAAK;GACT;GACA;GACA,aAAa,eAAe;GAC5B,QAAQ;IACN,MAAM;IACN,UAAU,MAAM;IAChB,aAAa,MAAM;IACnB,gBAAgB,YAAY;IAC5B,4BAAY,IAAI,MAAM;IACvB;GACD,gBAAgB,EAAE;GACnB,CAAC;UACK,OAAO;AACd,SAAO,KAAK;GACV,UAAU,MAAM;GAChB,OACE,iBAAiB,QACb,8BAA8B,MAAM,UACpC,OAAO,MAAM;GACpB,CAAC;;AAIN,QAAO;EACL,gBAAgB;EAChB;EACA;EACA,SAAS;GACP,OACE,YAAY,WAAW,SACvB,OAAO,KAAK,YAAY,QAAQ,CAAC,SACjC,YAAY,OAAO;GACrB,UAAU,MAAM;GAChB,SAAS,QAAQ;GACjB,QAAQ,OAAO;GAChB;EACF;;;;;AAMH,SAAgB,gBACd,WACA,UAAwC,EAAE,EAC1C,qBACQ;CACR,MAAM,EAAE,QAAQ,gBAAgB,iBAAiB,UAAU;CAC3D,MAAM,aAAa,cACf,wBAAwB,aAAa,GAAG,UAAU,YAAY,OAAO,GACrE;CAEJ,MAAM,eAAe,gBAAgB,UAAU;AAK/C,QAAO,iBACL,WACA,qBACA,SACA,YARkB,eAChB,wBAAwB,cAAc,GAAG,UAAU,YAAY,QAAQ,GACvE,KAQH"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["specs: ImportedOperationSpec[]","skipped: ImportResult['skipped']","errors: ImportResult['errors']","transportHints: OpenApiTransportHints","source: OpenApiSource"],"sources":["../../../src/openapi/importer/index.ts"],"sourcesContent":["import type {\n OpenApiSource,\n OpenApiTransportHints,\n ParsedOperation,\n ParseResult,\n} from '../types';\nimport type { ImportedOperationSpec, ImportResult } from '../../common/types';\nimport { toFileName, toSpecKey } from '../../common/utils';\nimport { generateSchemaModelCode } from '../schema-converter';\nimport { buildInputSchemas, getOutputSchema } from './schemas';\nimport { generateSpecCode } from './generator';\nimport { generateModelCode } from './models';\nimport { generateEventCode } from './events';\nimport {\n resolveEventGroupFolder,\n resolveModelGroupFolder,\n resolveOperationGroupFolder,\n} from './grouping';\nimport type {\n ContractsrcConfig,\n OpenApiSourceConfig,\n} from '@lssm/lib.contracts';\n\nexport * from './analyzer';\nexport * from './schemas';\nexport * from './generator';\nexport * from './models';\nexport * from './events';\nexport * from './grouping';\n\n/**\n * Import operations from a parsed OpenAPI document.\n */\nexport const importFromOpenApi = (\n parseResult: ParseResult,\n contractspecOptions: ContractsrcConfig,\n importOptions: Partial<OpenApiSourceConfig> = {}\n): ImportResult => {\n const { tags, exclude = [], include } = importOptions;\n const specs: ImportedOperationSpec[] = [];\n const skipped: ImportResult['skipped'] = [];\n const errors: ImportResult['errors'] = [];\n\n for (const operation of parseResult.operations) {\n // Filter by tags if specified\n if (tags && tags.length > 0) {\n const hasMatchingTag = operation.tags.some((t) => tags.includes(t));\n if (!hasMatchingTag) {\n skipped.push({\n sourceId: operation.operationId,\n reason: `No matching tags (has: ${operation.tags.join(', ')})`,\n });\n continue;\n }\n }\n\n // Filter by include/exclude\n if (include && include.length > 0) {\n if (!include.includes(operation.operationId)) {\n skipped.push({\n sourceId: operation.operationId,\n reason: 'Not in include list',\n });\n continue;\n }\n } else if (exclude.includes(operation.operationId)) {\n skipped.push({\n sourceId: operation.operationId,\n reason: 'In exclude list',\n });\n continue;\n }\n\n // Skip deprecated operations by default\n if (\n operation.deprecated &&\n importOptions.defaultStability !== 'deprecated'\n ) {\n skipped.push({\n sourceId: operation.operationId,\n reason: 'Deprecated operation',\n });\n continue;\n }\n\n try {\n // Build input schemas\n const inputSchemas = buildInputSchemas(operation);\n const schemaFormat =\n importOptions.schemaFormat ||\n contractspecOptions.schemaFormat ||\n 'contractspec';\n\n // Generate models for each input source\n const inputModel = inputSchemas.body\n ? generateSchemaModelCode(\n inputSchemas.body,\n `${operation.operationId}Input`,\n schemaFormat,\n contractspecOptions\n )\n : null;\n\n const queryModel = inputSchemas.query\n ? generateSchemaModelCode(\n inputSchemas.query,\n `${operation.operationId}Query`,\n schemaFormat,\n contractspecOptions\n )\n : null;\n\n const paramsModel = inputSchemas.params\n ? generateSchemaModelCode(\n inputSchemas.params,\n `${operation.operationId}Params`,\n schemaFormat,\n contractspecOptions\n )\n : null;\n\n const headersModel = inputSchemas.headers\n ? generateSchemaModelCode(\n inputSchemas.headers,\n `${operation.operationId}Headers`,\n schemaFormat,\n contractspecOptions\n )\n : null;\n\n // Get output schema\n const outputSchema = getOutputSchema(operation);\n let outputModel = outputSchema\n ? generateSchemaModelCode(\n outputSchema,\n `${operation.operationId}Output`,\n schemaFormat,\n contractspecOptions\n )\n : null;\n\n // Filter out empty/comment-only output models ONLY for ContractSpec format\n if (\n outputModel &&\n schemaFormat === 'contractspec' &&\n !outputModel.code.includes('defineSchemaModel')\n ) {\n outputModel = null;\n }\n\n // Generate spec code\n const code = generateSpecCode(\n operation,\n contractspecOptions,\n importOptions,\n inputModel,\n outputModel,\n queryModel,\n paramsModel,\n headersModel\n );\n const specName = toSpecKey(operation.operationId, importOptions.prefix);\n const fileName = toFileName(specName);\n\n // Build transport hints\n const transportHints: OpenApiTransportHints = {\n rest: {\n method:\n operation.method.toUpperCase() as OpenApiTransportHints['rest']['method'],\n path: operation.path,\n params: {\n path: operation.pathParams.map((p) => p.name),\n query: operation.queryParams.map((p) => p.name),\n header: operation.headerParams.map((p) => p.name),\n cookie: operation.cookieParams.map((p) => p.name),\n },\n },\n };\n\n // Build source info\n const source: OpenApiSource = {\n type: 'openapi',\n sourceId: operation.operationId,\n operationId: operation.operationId,\n openApiVersion: parseResult.version,\n importedAt: new Date(),\n };\n\n // Resolve group folder based on config\n const groupFolder = resolveOperationGroupFolder(\n operation,\n contractspecOptions.conventions\n );\n\n specs.push({\n code,\n fileName,\n groupFolder: groupFolder || undefined,\n source,\n transportHints,\n });\n } catch (error) {\n errors.push({\n sourceId: operation.operationId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // Import standalone models\n for (const [name, schema] of Object.entries(parseResult.schemas)) {\n try {\n const code = generateModelCode(name, schema, {\n ...contractspecOptions,\n schemaFormat:\n importOptions.schemaFormat || contractspecOptions.schemaFormat,\n });\n const fileName = toFileName(toSpecKey(name, importOptions.prefix));\n const groupFolder = resolveModelGroupFolder(\n name,\n contractspecOptions.conventions\n );\n\n specs.push({\n code,\n fileName,\n groupFolder: groupFolder || undefined,\n source: {\n type: 'openapi',\n sourceId: name,\n operationId: name,\n openApiVersion: parseResult.version,\n importedAt: new Date(),\n } as OpenApiSource,\n transportHints: {},\n });\n } catch (error) {\n errors.push({\n sourceId: name,\n error:\n error instanceof Error\n ? 'Model conversion failed: ' + error.message\n : String(error),\n });\n }\n }\n\n // Import events\n for (const event of parseResult.events) {\n try {\n const code = generateEventCode(event, {\n ...contractspecOptions,\n schemaFormat:\n importOptions.schemaFormat || contractspecOptions.schemaFormat,\n });\n const fileName = toFileName(toSpecKey(event.name, importOptions.prefix));\n const groupFolder = resolveEventGroupFolder(\n event.name,\n contractspecOptions.conventions\n );\n\n specs.push({\n code,\n fileName,\n groupFolder: groupFolder || undefined,\n source: {\n type: 'openapi',\n sourceId: event.name,\n operationId: event.name,\n openApiVersion: parseResult.version,\n importedAt: new Date(),\n } as OpenApiSource,\n transportHints: {},\n });\n } catch (error) {\n errors.push({\n sourceId: event.name,\n error:\n error instanceof Error\n ? 'Event conversion failed: ' + error.message\n : String(error),\n });\n }\n }\n\n return {\n operationSpecs: specs,\n skipped,\n errors,\n summary: {\n total:\n parseResult.operations.length +\n Object.keys(parseResult.schemas).length +\n parseResult.events.length,\n imported: specs.length,\n skipped: skipped.length,\n errors: errors.length,\n },\n };\n};\n\n/**\n * Import a single operation to ContractSpec code.\n */\nexport function importOperation(\n operation: ParsedOperation,\n options: Partial<OpenApiSourceConfig> = {},\n contractspecOptions: ContractsrcConfig\n): string {\n // Build input schemas\n const inputSchemas = buildInputSchemas(operation);\n const schemaFormat =\n options.schemaFormat || contractspecOptions.schemaFormat || 'contractspec';\n\n // Generate models for each input source\n const inputModel = inputSchemas.body\n ? generateSchemaModelCode(\n inputSchemas.body,\n `${operation.operationId}Input`,\n schemaFormat,\n contractspecOptions\n )\n : null;\n\n const queryModel = inputSchemas.query\n ? generateSchemaModelCode(\n inputSchemas.query,\n `${operation.operationId}Query`,\n schemaFormat,\n contractspecOptions\n )\n : null;\n\n const paramsModel = inputSchemas.params\n ? generateSchemaModelCode(\n inputSchemas.params,\n `${operation.operationId}Params`,\n schemaFormat,\n contractspecOptions\n )\n : null;\n\n const headersModel = inputSchemas.headers\n ? generateSchemaModelCode(\n inputSchemas.headers,\n `${operation.operationId}Headers`,\n schemaFormat,\n contractspecOptions\n )\n : null;\n\n const outputSchema = getOutputSchema(operation);\n const outputModel = outputSchema\n ? generateSchemaModelCode(\n outputSchema,\n `${operation.operationId}Output`,\n schemaFormat,\n contractspecOptions\n )\n : null;\n\n return generateSpecCode(\n operation,\n contractspecOptions,\n options,\n inputModel,\n outputModel,\n queryModel,\n paramsModel,\n headersModel\n );\n}\n"],"mappings":"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"}
|
|
@@ -6,9 +6,12 @@ import { generateImports, generateSchemaModelCode } from "../schema-converter.js
|
|
|
6
6
|
* Generate code for a standalone model.
|
|
7
7
|
*/
|
|
8
8
|
function generateModelCode(name, schema, options) {
|
|
9
|
-
const model = generateSchemaModelCode(schema, toPascalCase(toValidIdentifier(name)));
|
|
9
|
+
const model = generateSchemaModelCode(schema, toPascalCase(toValidIdentifier(name)), options.schemaFormat || "contractspec", options);
|
|
10
|
+
let imports = "";
|
|
11
|
+
if (model.imports && model.imports.length > 0) imports = model.imports.join("\n");
|
|
12
|
+
else if (model.fields.length > 0) imports = generateImports(model.fields, options);
|
|
10
13
|
return `
|
|
11
|
-
${
|
|
14
|
+
${imports}
|
|
12
15
|
|
|
13
16
|
${model.code}
|
|
14
17
|
`.trim();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models.js","names":[],"sources":["../../../src/openapi/importer/models.ts"],"sourcesContent":["import type { OpenApiSchema } from '../types';\nimport { generateImports, generateSchemaModelCode } from '../schema-converter';\nimport { toPascalCase, toValidIdentifier } from '../../common/utils';\nimport type { ContractsrcConfig } from '@lssm/lib.contracts';\n\n/**\n * Generate code for a standalone model.\n */\nexport function generateModelCode(\n name: string,\n schema: OpenApiSchema,\n options: ContractsrcConfig\n): string {\n const modelName = toPascalCase(toValidIdentifier(name));\n const model = generateSchemaModelCode(schema
|
|
1
|
+
{"version":3,"file":"models.js","names":[],"sources":["../../../src/openapi/importer/models.ts"],"sourcesContent":["import type { OpenApiSchema } from '../types';\nimport { generateImports, generateSchemaModelCode } from '../schema-converter';\nimport { toPascalCase, toValidIdentifier } from '../../common/utils';\nimport type { ContractsrcConfig } from '@lssm/lib.contracts';\n\n/**\n * Generate code for a standalone model.\n */\nexport function generateModelCode(\n name: string,\n schema: OpenApiSchema,\n options: ContractsrcConfig\n): string {\n const modelName = toPascalCase(toValidIdentifier(name));\n const schemaFormat = options.schemaFormat || 'contractspec';\n\n const model = generateSchemaModelCode(\n schema,\n modelName,\n schemaFormat,\n options\n );\n\n let imports = '';\n if (model.imports && model.imports.length > 0) {\n imports = model.imports.join('\\n');\n } else if (model.fields.length > 0) {\n imports = generateImports(model.fields, options);\n }\n\n return `\n${imports}\n\n${model.code}\n`.trim();\n}\n"],"mappings":";;;;;;;AAQA,SAAgB,kBACd,MACA,QACA,SACQ;CAIR,MAAM,QAAQ,wBACZ,QAJgB,aAAa,kBAAkB,KAAK,CAAC,EAClC,QAAQ,gBAAgB,gBAM3C,QACD;CAED,IAAI,UAAU;AACd,KAAI,MAAM,WAAW,MAAM,QAAQ,SAAS,EAC1C,WAAU,MAAM,QAAQ,KAAK,KAAK;UACzB,MAAM,OAAO,SAAS,EAC/B,WAAU,gBAAgB,MAAM,QAAQ,QAAQ;AAGlD,QAAO;EACP,QAAQ;;EAER,MAAM,KAAK;EACX,MAAM"}
|
|
@@ -1,62 +1,42 @@
|
|
|
1
1
|
//#region src/openapi/importer/schemas.ts
|
|
2
2
|
/**
|
|
3
|
-
* Build
|
|
3
|
+
* Build separate input schemas for each parameter source.
|
|
4
4
|
*/
|
|
5
|
-
function
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
5
|
+
function buildInputSchemas(operation) {
|
|
6
|
+
const result = {};
|
|
7
|
+
if (operation.pathParams.length > 0) result.params = {
|
|
8
|
+
type: "object",
|
|
9
|
+
properties: operation.pathParams.reduce((acc, p) => {
|
|
10
|
+
acc[p.name] = p.schema;
|
|
11
|
+
return acc;
|
|
12
|
+
}, {}),
|
|
13
|
+
required: operation.pathParams.map((p) => p.name)
|
|
14
|
+
};
|
|
15
|
+
if (operation.queryParams.length > 0) result.query = {
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: operation.queryParams.reduce((acc, p) => {
|
|
18
|
+
acc[p.name] = p.schema;
|
|
19
|
+
return acc;
|
|
20
|
+
}, {}),
|
|
21
|
+
required: operation.queryParams.filter((p) => p.required).map((p) => p.name)
|
|
22
|
+
};
|
|
17
23
|
const excludedHeaders = [
|
|
18
24
|
"authorization",
|
|
19
25
|
"content-type",
|
|
20
26
|
"accept",
|
|
21
27
|
"user-agent"
|
|
22
28
|
];
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const schemaObj = bodySchema;
|
|
32
|
-
const properties = schemaObj["properties"];
|
|
33
|
-
const required = schemaObj["required"] ?? [];
|
|
34
|
-
if (properties) for (const [propName, propSchema] of Object.entries(properties)) fields.push({
|
|
35
|
-
name: propName,
|
|
36
|
-
schema: propSchema,
|
|
37
|
-
required: required.includes(propName)
|
|
38
|
-
});
|
|
39
|
-
} else fields.push({
|
|
40
|
-
name: "body",
|
|
41
|
-
schema: bodySchema,
|
|
42
|
-
required: operation.requestBody.required
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
if (fields.length === 0) return {
|
|
46
|
-
schema: null,
|
|
47
|
-
fields: []
|
|
48
|
-
};
|
|
49
|
-
return {
|
|
50
|
-
schema: {
|
|
51
|
-
type: "object",
|
|
52
|
-
properties: fields.reduce((acc, f) => {
|
|
53
|
-
acc[f.name] = f.schema;
|
|
54
|
-
return acc;
|
|
55
|
-
}, {}),
|
|
56
|
-
required: fields.filter((f) => f.required).map((f) => f.name)
|
|
57
|
-
},
|
|
58
|
-
fields
|
|
29
|
+
const actualHeaders = operation.headerParams.filter((p) => !excludedHeaders.includes(p.name.toLowerCase()));
|
|
30
|
+
if (actualHeaders.length > 0) result.headers = {
|
|
31
|
+
type: "object",
|
|
32
|
+
properties: actualHeaders.reduce((acc, p) => {
|
|
33
|
+
acc[p.name] = p.schema;
|
|
34
|
+
return acc;
|
|
35
|
+
}, {}),
|
|
36
|
+
required: actualHeaders.filter((p) => p.required).map((p) => p.name)
|
|
59
37
|
};
|
|
38
|
+
if (operation.requestBody?.schema) result.body = operation.requestBody.schema;
|
|
39
|
+
return result;
|
|
60
40
|
}
|
|
61
41
|
/**
|
|
62
42
|
* Get the output schema from the operation responses.
|
|
@@ -76,5 +56,5 @@ function getOutputSchema(operation) {
|
|
|
76
56
|
}
|
|
77
57
|
|
|
78
58
|
//#endregion
|
|
79
|
-
export {
|
|
59
|
+
export { buildInputSchemas, getOutputSchema };
|
|
80
60
|
//# sourceMappingURL=schemas.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.js","names":["
|
|
1
|
+
{"version":3,"file":"schemas.js","names":["result: {\n body?: OpenApiSchema;\n query?: OpenApiSchema;\n params?: OpenApiSchema;\n headers?: OpenApiSchema;\n }"],"sources":["../../../src/openapi/importer/schemas.ts"],"sourcesContent":["import type { OpenApiSchema, ParsedOperation } from '../types';\n\n/**\n * Build separate input schemas for each parameter source.\n */\nexport function buildInputSchemas(operation: ParsedOperation): {\n body?: OpenApiSchema;\n query?: OpenApiSchema;\n params?: OpenApiSchema;\n headers?: OpenApiSchema;\n} {\n const result: {\n body?: OpenApiSchema;\n query?: OpenApiSchema;\n params?: OpenApiSchema;\n headers?: OpenApiSchema;\n } = {};\n\n // Path parameters -> params\n if (operation.pathParams.length > 0) {\n result.params = {\n type: 'object',\n properties: operation.pathParams.reduce(\n (acc, p) => {\n acc[p.name] = p.schema;\n return acc;\n },\n {} as Record<string, OpenApiSchema>\n ),\n required: operation.pathParams.map((p) => p.name),\n } as unknown as OpenApiSchema;\n }\n\n // Query parameters -> query\n if (operation.queryParams.length > 0) {\n result.query = {\n type: 'object',\n properties: operation.queryParams.reduce(\n (acc, p) => {\n acc[p.name] = p.schema;\n return acc;\n },\n {} as Record<string, OpenApiSchema>\n ),\n required: operation.queryParams\n .filter((p) => p.required)\n .map((p) => p.name),\n } as unknown as OpenApiSchema;\n }\n\n // Header parameters -> headers\n const excludedHeaders = [\n 'authorization',\n 'content-type',\n 'accept',\n 'user-agent',\n ];\n const actualHeaders = operation.headerParams.filter(\n (p) => !excludedHeaders.includes(p.name.toLowerCase())\n );\n if (actualHeaders.length > 0) {\n result.headers = {\n type: 'object',\n properties: actualHeaders.reduce(\n (acc, p) => {\n acc[p.name] = p.schema;\n return acc;\n },\n {} as Record<string, OpenApiSchema>\n ),\n required: actualHeaders.filter((p) => p.required).map((p) => p.name),\n } as unknown as OpenApiSchema;\n }\n\n // Request body -> body\n if (operation.requestBody?.schema) {\n result.body = operation.requestBody.schema;\n }\n\n return result;\n}\n\n/**\n * Get the output schema from the operation responses.\n */\nexport function getOutputSchema(\n operation: ParsedOperation\n): OpenApiSchema | null {\n // Prefer 200, then 201, then 2xx responses\n const successCodes = ['200', '201', '202', '204'];\n\n for (const code of successCodes) {\n const response = operation.responses[code];\n if (response?.schema) {\n return response.schema;\n }\n }\n\n // Check for any 2xx response\n for (const [code, response] of Object.entries(operation.responses)) {\n if (code.startsWith('2') && response.schema) {\n return response.schema;\n }\n }\n\n return null;\n}\n"],"mappings":";;;;AAKA,SAAgB,kBAAkB,WAKhC;CACA,MAAMA,SAKF,EAAE;AAGN,KAAI,UAAU,WAAW,SAAS,EAChC,QAAO,SAAS;EACd,MAAM;EACN,YAAY,UAAU,WAAW,QAC9B,KAAK,MAAM;AACV,OAAI,EAAE,QAAQ,EAAE;AAChB,UAAO;KAET,EAAE,CACH;EACD,UAAU,UAAU,WAAW,KAAK,MAAM,EAAE,KAAK;EAClD;AAIH,KAAI,UAAU,YAAY,SAAS,EACjC,QAAO,QAAQ;EACb,MAAM;EACN,YAAY,UAAU,YAAY,QAC/B,KAAK,MAAM;AACV,OAAI,EAAE,QAAQ,EAAE;AAChB,UAAO;KAET,EAAE,CACH;EACD,UAAU,UAAU,YACjB,QAAQ,MAAM,EAAE,SAAS,CACzB,KAAK,MAAM,EAAE,KAAK;EACtB;CAIH,MAAM,kBAAkB;EACtB;EACA;EACA;EACA;EACD;CACD,MAAM,gBAAgB,UAAU,aAAa,QAC1C,MAAM,CAAC,gBAAgB,SAAS,EAAE,KAAK,aAAa,CAAC,CACvD;AACD,KAAI,cAAc,SAAS,EACzB,QAAO,UAAU;EACf,MAAM;EACN,YAAY,cAAc,QACvB,KAAK,MAAM;AACV,OAAI,EAAE,QAAQ,EAAE;AAChB,UAAO;KAET,EAAE,CACH;EACD,UAAU,cAAc,QAAQ,MAAM,EAAE,SAAS,CAAC,KAAK,MAAM,EAAE,KAAK;EACrE;AAIH,KAAI,UAAU,aAAa,OACzB,QAAO,OAAO,UAAU,YAAY;AAGtC,QAAO;;;;;AAMT,SAAgB,gBACd,WACsB;AAItB,MAAK,MAAM,QAFU;EAAC;EAAO;EAAO;EAAO;EAAM,EAEhB;EAC/B,MAAM,WAAW,UAAU,UAAU;AACrC,MAAI,UAAU,OACZ,QAAO,SAAS;;AAKpB,MAAK,MAAM,CAAC,MAAM,aAAa,OAAO,QAAQ,UAAU,UAAU,CAChE,KAAI,KAAK,WAAW,IAAI,IAAI,SAAS,OACnC,QAAO,SAAS;AAIpB,QAAO"}
|
package/dist/openapi/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { ExportedForm, exportForms, generateFormsRegistry } from "./exporter/for
|
|
|
10
10
|
import { ExportedDataView, exportDataViews, generateDataViewsRegistry } from "./exporter/data-views.js";
|
|
11
11
|
import { ExportedWorkflow, exportWorkflows, generateWorkflowsRegistry } from "./exporter/workflows.js";
|
|
12
12
|
import { RegistryGenerationOptions, generateRegistryIndex } from "./exporter/registries.js";
|
|
13
|
-
import { GeneratedModel, SchemaField, TypescriptType, generateImports, generateSchemaModelCode, getScalarType,
|
|
13
|
+
import { GeneratedModel, SchemaField, TypescriptType, generateImports, generateSchemaModelCode, getScalarType, jsonSchemaToType } from "./schema-converter.js";
|
|
14
14
|
import { importFromOpenApi, importOperation } from "./importer/index.js";
|
|
15
15
|
import { DiffOptions, createSpecDiff, diffAll, diffSpecVsOperation, diffSpecs, formatDiffChanges } from "./differ.js";
|
|
16
|
-
export { type ContractSpecOpenApiDocument, type ContractSpecRegistries, type DiffOptions, ExportedDataView, ExportedEvent, ExportedFeature, ExportedForm, ExportedPresentation, ExportedWorkflow, type GeneratedModel, type HttpMethod, type OpenApiDocument, type OpenApiExportOptions, type OpenApiOperation, type OpenApiParameter, type OpenApiParseOptions, type OpenApiSchema, type OpenApiServer, type OpenApiSource, type OpenApiTransportHints, type OpenApiVersion, OperationsExportResult, type ParameterLocation, type ParseResult, type ParsedOperation, type ParsedParameter, RegistryGenerationOptions, type SchemaField, type TypescriptType, contractSpecToJson, contractSpecToYaml, createSpecDiff, defaultRestPath, detectFormat, detectVersion, diffAll, diffSpecVsOperation, diffSpecs, exportContractSpec, exportDataViews, exportEvents, exportFeatures, exportForms, exportOperations, exportPresentations, exportPresentationsFromArray, exportWorkflows, formatDiffChanges, generateDataViewsRegistry, generateEventsExports, generateFeaturesRegistry, generateFormsRegistry, generateImports, generateOperationsRegistry, generatePresentationsRegistry, generateRegistryIndex, generateSchemaModelCode, generateWorkflowsRegistry, getScalarType, importFromOpenApi, importOperation, jsonSchemaForSpec,
|
|
16
|
+
export { type ContractSpecOpenApiDocument, type ContractSpecRegistries, type DiffOptions, ExportedDataView, ExportedEvent, ExportedFeature, ExportedForm, ExportedPresentation, ExportedWorkflow, type GeneratedModel, type HttpMethod, type OpenApiDocument, type OpenApiExportOptions, type OpenApiOperation, type OpenApiParameter, type OpenApiParseOptions, type OpenApiSchema, type OpenApiServer, type OpenApiSource, type OpenApiTransportHints, type OpenApiVersion, OperationsExportResult, type ParameterLocation, type ParseResult, type ParsedOperation, type ParsedParameter, RegistryGenerationOptions, type SchemaField, type TypescriptType, contractSpecToJson, contractSpecToYaml, createSpecDiff, defaultRestPath, detectFormat, detectVersion, diffAll, diffSpecVsOperation, diffSpecs, exportContractSpec, exportDataViews, exportEvents, exportFeatures, exportForms, exportOperations, exportPresentations, exportPresentationsFromArray, exportWorkflows, formatDiffChanges, generateDataViewsRegistry, generateEventsExports, generateFeaturesRegistry, generateFormsRegistry, generateImports, generateOperationsRegistry, generatePresentationsRegistry, generateRegistryIndex, generateSchemaModelCode, generateWorkflowsRegistry, getScalarType, importFromOpenApi, importOperation, jsonSchemaForSpec, jsonSchemaToType, openApiForRegistry, openApiToJson, openApiToYaml, parseOpenApi, parseOpenApiDocument, parseOpenApiString, schemaModelToJsonSchema, toHttpMethod, toOperationId, toRestPath, toSchemaName };
|
package/dist/openapi/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { detectFormat, detectVersion, parseOpenApiString } from "./parser/utils.js";
|
|
2
2
|
import { parseOpenApi, parseOpenApiDocument } from "./parser/document.js";
|
|
3
|
+
import "./parser.js";
|
|
3
4
|
import { defaultRestPath, exportOperations, generateOperationsRegistry, jsonSchemaForSpec, schemaModelToJsonSchema, toHttpMethod, toOperationId, toRestPath, toSchemaName } from "./exporter/operations.js";
|
|
4
5
|
import { exportEvents, generateEventsExports } from "./exporter/events.js";
|
|
5
6
|
import { exportFeatures, generateFeaturesRegistry } from "./exporter/features.js";
|
|
@@ -10,8 +11,8 @@ import { exportWorkflows, generateWorkflowsRegistry } from "./exporter/workflows
|
|
|
10
11
|
import { generateRegistryIndex } from "./exporter/registries.js";
|
|
11
12
|
import { contractSpecToJson, contractSpecToYaml, exportContractSpec, openApiForRegistry, openApiToJson, openApiToYaml } from "./exporter.js";
|
|
12
13
|
import "./exporter/index.js";
|
|
13
|
-
import { generateImports, generateSchemaModelCode, getScalarType,
|
|
14
|
+
import { generateImports, generateSchemaModelCode, getScalarType, jsonSchemaToType } from "./schema-converter.js";
|
|
14
15
|
import { importFromOpenApi, importOperation } from "./importer/index.js";
|
|
15
16
|
import { createSpecDiff, diffAll, diffSpecVsOperation, diffSpecs, formatDiffChanges } from "./differ.js";
|
|
16
17
|
|
|
17
|
-
export { contractSpecToJson, contractSpecToYaml, createSpecDiff, defaultRestPath, detectFormat, detectVersion, diffAll, diffSpecVsOperation, diffSpecs, exportContractSpec, exportDataViews, exportEvents, exportFeatures, exportForms, exportOperations, exportPresentations, exportPresentationsFromArray, exportWorkflows, formatDiffChanges, generateDataViewsRegistry, generateEventsExports, generateFeaturesRegistry, generateFormsRegistry, generateImports, generateOperationsRegistry, generatePresentationsRegistry, generateRegistryIndex, generateSchemaModelCode, generateWorkflowsRegistry, getScalarType, importFromOpenApi, importOperation, jsonSchemaForSpec,
|
|
18
|
+
export { contractSpecToJson, contractSpecToYaml, createSpecDiff, defaultRestPath, detectFormat, detectVersion, diffAll, diffSpecVsOperation, diffSpecs, exportContractSpec, exportDataViews, exportEvents, exportFeatures, exportForms, exportOperations, exportPresentations, exportPresentationsFromArray, exportWorkflows, formatDiffChanges, generateDataViewsRegistry, generateEventsExports, generateFeaturesRegistry, generateFormsRegistry, generateImports, generateOperationsRegistry, generatePresentationsRegistry, generateRegistryIndex, generateSchemaModelCode, generateWorkflowsRegistry, getScalarType, importFromOpenApi, importOperation, jsonSchemaForSpec, jsonSchemaToType, openApiForRegistry, openApiToJson, openApiToYaml, parseOpenApi, parseOpenApiDocument, parseOpenApiString, schemaModelToJsonSchema, toHttpMethod, toOperationId, toRestPath, toSchemaName };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { HTTP_METHODS, detectFormat, detectVersion, generateOperationId, parseOpenApiString } from "./utils.js";
|
|
2
|
+
import { dereferenceSchema, isReference, resolveRef } from "./resolvers.js";
|
|
3
|
+
import { parseParameters } from "./parameters.js";
|
|
4
|
+
import { parseOperation } from "./operation.js";
|
|
5
|
+
import { parseOpenApi, parseOpenApiDocument } from "./document.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
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,5 +1,5 @@
|
|
|
1
1
|
import { OpenApiSchema } from "./types.js";
|
|
2
|
-
import { ContractsrcConfig } from "@lssm/lib.contracts";
|
|
2
|
+
import { ContractsrcConfig, SchemaFormat } from "@lssm/lib.contracts";
|
|
3
3
|
|
|
4
4
|
//#region src/openapi/schema-converter.d.ts
|
|
5
5
|
|
|
@@ -47,6 +47,8 @@ interface GeneratedModel {
|
|
|
47
47
|
fields: SchemaField[];
|
|
48
48
|
/** Generated TypeScript code */
|
|
49
49
|
code: string;
|
|
50
|
+
/** Required imports */
|
|
51
|
+
imports?: string[];
|
|
50
52
|
}
|
|
51
53
|
/**
|
|
52
54
|
* Convert a JSON Schema to a TypeScript type representation.
|
|
@@ -57,20 +59,13 @@ declare function jsonSchemaToType(schema: OpenApiSchema, name?: string): Typescr
|
|
|
57
59
|
*/
|
|
58
60
|
declare function getScalarType(schema: OpenApiSchema): string | undefined;
|
|
59
61
|
/**
|
|
60
|
-
*
|
|
62
|
+
* Generate code for a schema model using the specified format.
|
|
61
63
|
*/
|
|
62
|
-
declare function
|
|
63
|
-
/**
|
|
64
|
-
* Generate SchemaModel TypeScript code for a JSON Schema object.
|
|
65
|
-
*/
|
|
66
|
-
declare function generateSchemaModelCode(schema: OpenApiSchema, modelName: string, indent?: number): GeneratedModel;
|
|
64
|
+
declare function generateSchemaModelCode(schema: OpenApiSchema, modelName: string, schemaFormat?: SchemaFormat, config?: ContractsrcConfig): GeneratedModel;
|
|
67
65
|
/**
|
|
68
66
|
* 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)
|
|
72
67
|
*/
|
|
73
68
|
declare function generateImports(fields: SchemaField[], options: ContractsrcConfig, sameDirectory?: boolean): string;
|
|
74
69
|
//#endregion
|
|
75
|
-
export { GeneratedModel, SchemaField, TypescriptType, generateImports, generateSchemaModelCode, getScalarType,
|
|
70
|
+
export { GeneratedModel, SchemaField, TypescriptType, generateImports, generateSchemaModelCode, getScalarType, jsonSchemaToType };
|
|
76
71
|
//# sourceMappingURL=schema-converter.d.ts.map
|