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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/common/types.d.ts +2 -0
  2. package/dist/common/types.d.ts.map +1 -1
  3. package/dist/index.d.ts +10 -2
  4. package/dist/index.js +10 -2
  5. package/dist/openapi/exporter/data-views.d.ts +38 -0
  6. package/dist/openapi/exporter/data-views.d.ts.map +1 -0
  7. package/dist/openapi/exporter/data-views.js +47 -0
  8. package/dist/openapi/exporter/data-views.js.map +1 -0
  9. package/dist/openapi/exporter/events.d.ts +28 -0
  10. package/dist/openapi/exporter/events.d.ts.map +1 -0
  11. package/dist/openapi/exporter/events.js +39 -0
  12. package/dist/openapi/exporter/events.js.map +1 -0
  13. package/dist/openapi/exporter/features.d.ts +37 -0
  14. package/dist/openapi/exporter/features.d.ts.map +1 -0
  15. package/dist/openapi/exporter/features.js +46 -0
  16. package/dist/openapi/exporter/features.js.map +1 -0
  17. package/dist/openapi/exporter/forms.d.ts +30 -0
  18. package/dist/openapi/exporter/forms.d.ts.map +1 -0
  19. package/dist/openapi/exporter/forms.js +49 -0
  20. package/dist/openapi/exporter/forms.js.map +1 -0
  21. package/dist/openapi/exporter/index.js +8 -0
  22. package/dist/openapi/exporter/operations.d.ts +65 -0
  23. package/dist/openapi/exporter/operations.d.ts.map +1 -0
  24. package/dist/openapi/exporter/operations.js +142 -0
  25. package/dist/openapi/exporter/operations.js.map +1 -0
  26. package/dist/openapi/exporter/presentations.d.ts +48 -0
  27. package/dist/openapi/exporter/presentations.d.ts.map +1 -0
  28. package/dist/openapi/exporter/presentations.js +66 -0
  29. package/dist/openapi/exporter/presentations.js.map +1 -0
  30. package/dist/openapi/exporter/registries.d.ts +23 -0
  31. package/dist/openapi/exporter/registries.d.ts.map +1 -0
  32. package/dist/openapi/exporter/registries.js +29 -0
  33. package/dist/openapi/exporter/registries.js.map +1 -0
  34. package/dist/openapi/exporter/workflows.d.ts +36 -0
  35. package/dist/openapi/exporter/workflows.d.ts.map +1 -0
  36. package/dist/openapi/exporter/workflows.js +54 -0
  37. package/dist/openapi/exporter/workflows.js.map +1 -0
  38. package/dist/openapi/exporter.d.ts +29 -9
  39. package/dist/openapi/exporter.d.ts.map +1 -1
  40. package/dist/openapi/exporter.js +76 -102
  41. package/dist/openapi/exporter.js.map +1 -1
  42. package/dist/openapi/importer/grouping.js +73 -0
  43. package/dist/openapi/importer/grouping.js.map +1 -0
  44. package/dist/openapi/importer/index.d.ts.map +1 -1
  45. package/dist/openapi/importer/index.js +7 -0
  46. package/dist/openapi/importer/index.js.map +1 -1
  47. package/dist/openapi/index.d.ts +10 -2
  48. package/dist/openapi/index.js +11 -2
  49. package/dist/openapi/schema-converter.d.ts.map +1 -1
  50. package/dist/openapi/schema-converter.js.map +1 -1
  51. package/dist/openapi/types.d.ts +62 -1
  52. package/dist/openapi/types.d.ts.map +1 -1
  53. package/package.json +5 -5
@@ -1,73 +1,43 @@
1
- import { z } from "zod";
1
+ import { defaultRestPath, exportOperations, generateOperationsRegistry } from "./exporter/operations.js";
2
+ import { exportEvents, generateEventsExports } from "./exporter/events.js";
3
+ import { exportFeatures, generateFeaturesRegistry } from "./exporter/features.js";
4
+ import { exportPresentations, generatePresentationsRegistry } from "./exporter/presentations.js";
5
+ import { exportForms, generateFormsRegistry } from "./exporter/forms.js";
6
+ import { exportDataViews, generateDataViewsRegistry } from "./exporter/data-views.js";
7
+ import { exportWorkflows, generateWorkflowsRegistry } from "./exporter/workflows.js";
8
+ import { generateRegistryIndex } from "./exporter/registries.js";
2
9
 
3
10
  //#region src/openapi/exporter.ts
4
11
  /**
5
- * Convert a spec name and version to an operationId.
6
- */
7
- function toOperationId(name, version) {
8
- return `${name.replace(/\./g, "_")}_v${version}`;
9
- }
10
- /**
11
- * Convert a spec name and version to a schema name.
12
- */
13
- function toSchemaName(prefix, name, version) {
14
- return `${prefix}_${toOperationId(name, version)}`;
15
- }
16
- /**
17
- * Determine HTTP method from spec kind and override.
18
- */
19
- function toHttpMethod(kind, override) {
20
- return (override ?? (kind === "query" ? "GET" : "POST")).toLowerCase();
21
- }
22
- /**
23
- * Generate default REST path from spec name and version.
24
- */
25
- function defaultRestPath(name, version) {
26
- return `/${name.replace(/\./g, "/")}/v${version}`;
27
- }
28
- /**
29
- * Get REST path from spec, using transport override or default.
30
- */
31
- function toRestPath(spec) {
32
- const path = spec.transport?.rest?.path ?? defaultRestPath(spec.meta.name, spec.meta.version);
33
- return path.startsWith("/") ? path : `/${path}`;
34
- }
35
- /**
36
- * Convert a SchemaModel to JSON Schema using Zod.
37
- */
38
- function schemaModelToJsonSchema(schema) {
39
- if (!schema) return null;
40
- return z.toJSONSchema(schema.getZod());
41
- }
42
- /**
43
- * Extract JSON Schema for a spec's input and output.
12
+ * Export a OperationSpecRegistry to an OpenAPI 3.1 document.
13
+ * @deprecated Use exportContractSpec for full surface support.
44
14
  */
45
- function jsonSchemaForSpec(spec) {
15
+ function openApiForRegistry(registry, options = {}) {
16
+ const { paths, schemas } = exportOperations(registry);
46
17
  return {
47
- input: schemaModelToJsonSchema(spec.io.input),
48
- output: schemaModelToJsonSchema(spec.io.output),
49
- meta: {
50
- name: spec.meta.name,
51
- version: spec.meta.version,
52
- kind: spec.meta.kind,
53
- description: spec.meta.description,
54
- tags: spec.meta.tags ?? [],
55
- stability: spec.meta.stability ?? "stable"
56
- }
18
+ openapi: "3.1.0",
19
+ info: {
20
+ title: options.title ?? "ContractSpec API",
21
+ version: options.version ?? "0.0.0",
22
+ ...options.description ? { description: options.description } : {}
23
+ },
24
+ ...options.servers ? { servers: options.servers } : {},
25
+ paths,
26
+ components: { schemas }
57
27
  };
58
28
  }
59
29
  /**
60
- * Export a OperationSpecRegistry to an OpenAPI 3.1 document.
61
- *
62
- * @param registry - The OperationSpecRegistry containing specs to export
63
- * @param options - Export options (title, version, description, servers)
64
- * @returns OpenAPI 3.1 document
30
+ * Export all ContractSpec surfaces to OpenAPI document with extensions.
65
31
  */
66
- function openApiForRegistry(registry, options = {}) {
67
- const specs = registry.listSpecs().filter((s) => s.meta.kind === "command" || s.meta.kind === "query").slice().sort((a, b) => {
68
- const byName = a.meta.name.localeCompare(b.meta.name);
69
- return byName !== 0 ? byName : a.meta.version - b.meta.version;
70
- });
32
+ function exportContractSpec(registries, options = {}) {
33
+ const { operations: includeOps = true, events: includeEvents = true, features: includeFeatures = true, presentations: includePresentations = true, forms: includeForms = true, dataViews: includeDataViews = true, workflows: includeWorkflows = true, generateRegistries = true } = options;
34
+ let paths = {};
35
+ let schemas = {};
36
+ if (includeOps && registries.operations) {
37
+ const opResult = exportOperations(registries.operations);
38
+ paths = opResult.paths;
39
+ schemas = opResult.schemas;
40
+ }
71
41
  const doc = {
72
42
  openapi: "3.1.0",
73
43
  info: {
@@ -76,48 +46,39 @@ function openApiForRegistry(registry, options = {}) {
76
46
  ...options.description ? { description: options.description } : {}
77
47
  },
78
48
  ...options.servers ? { servers: options.servers } : {},
79
- paths: {},
80
- components: { schemas: {} }
49
+ paths,
50
+ components: { schemas }
81
51
  };
82
- for (const spec of specs) {
83
- const schema = jsonSchemaForSpec(spec);
84
- const method = toHttpMethod(spec.meta.kind, spec.transport?.rest?.method);
85
- const path = toRestPath(spec);
86
- const operationId = toOperationId(spec.meta.name, spec.meta.version);
87
- const pathItem = doc.paths[path] ??= {};
88
- const op = {
89
- operationId,
90
- summary: spec.meta.description ?? spec.meta.name,
91
- description: spec.meta.description,
92
- tags: spec.meta.tags ?? [],
93
- "x-contractspec": {
94
- name: spec.meta.name,
95
- version: spec.meta.version,
96
- kind: spec.meta.kind
97
- },
98
- responses: {}
99
- };
100
- if (schema.input) {
101
- const inputName = toSchemaName("Input", spec.meta.name, spec.meta.version);
102
- doc.components.schemas[inputName] = schema.input;
103
- op["requestBody"] = {
104
- required: true,
105
- content: { "application/json": { schema: { $ref: `#/components/schemas/${inputName}` } } }
106
- };
107
- }
108
- const responses = {};
109
- if (schema.output) {
110
- const outputName = toSchemaName("Output", spec.meta.name, spec.meta.version);
111
- doc.components.schemas[outputName] = schema.output;
112
- responses["200"] = {
113
- description: "OK",
114
- content: { "application/json": { schema: { $ref: `#/components/schemas/${outputName}` } } }
115
- };
116
- } else responses["200"] = { description: "OK" };
117
- op["responses"] = responses;
118
- pathItem[method] = op;
52
+ if (includeEvents && registries.events?.length) doc["x-contractspec-events"] = exportEvents(registries.events);
53
+ if (includeFeatures && registries.features) doc["x-contractspec-features"] = exportFeatures(registries.features);
54
+ if (includePresentations && registries.presentations) {
55
+ const presExport = exportPresentations(registries.presentations, registries.presentationsV2);
56
+ doc["x-contractspec-presentations"] = [...presExport.v1, ...presExport.v2];
57
+ }
58
+ if (includeForms && registries.forms) doc["x-contractspec-forms"] = exportForms(registries.forms);
59
+ if (includeDataViews && registries.dataViews) doc["x-contractspec-dataviews"] = exportDataViews(registries.dataViews);
60
+ if (includeWorkflows && registries.workflows) doc["x-contractspec-workflows"] = exportWorkflows(registries.workflows);
61
+ const result = { openApi: doc };
62
+ if (generateRegistries) {
63
+ result.registries = {};
64
+ if (includeOps && registries.operations) result.registries.operations = generateOperationsRegistry(registries.operations);
65
+ if (includeEvents && registries.events?.length) result.registries.events = generateEventsExports(registries.events);
66
+ if (includeFeatures && registries.features) result.registries.features = generateFeaturesRegistry(registries.features);
67
+ if (includePresentations && registries.presentations) result.registries.presentations = generatePresentationsRegistry(registries.presentations);
68
+ if (includeForms && registries.forms) result.registries.forms = generateFormsRegistry(registries.forms);
69
+ if (includeDataViews && registries.dataViews) result.registries.dataViews = generateDataViewsRegistry(registries.dataViews);
70
+ if (includeWorkflows && registries.workflows) result.registries.workflows = generateWorkflowsRegistry(registries.workflows);
71
+ result.registries.index = generateRegistryIndex({
72
+ operations: includeOps && !!registries.operations,
73
+ events: includeEvents && !!registries.events?.length,
74
+ features: includeFeatures && !!registries.features,
75
+ presentations: includePresentations && !!registries.presentations,
76
+ forms: includeForms && !!registries.forms,
77
+ dataViews: includeDataViews && !!registries.dataViews,
78
+ workflows: includeWorkflows && !!registries.workflows
79
+ });
119
80
  }
120
- return doc;
81
+ return result;
121
82
  }
122
83
  /**
123
84
  * Export a OperationSpecRegistry to OpenAPI JSON string.
@@ -133,6 +94,19 @@ function openApiToYaml(registry, options = {}) {
133
94
  return jsonToYaml(openApiForRegistry(registry, options));
134
95
  }
135
96
  /**
97
+ * Export ContractSpec to JSON string (all surfaces).
98
+ */
99
+ function contractSpecToJson(registries, options = {}) {
100
+ const result = exportContractSpec(registries, options);
101
+ return JSON.stringify(result.openApi, null, 2);
102
+ }
103
+ /**
104
+ * Export ContractSpec to YAML string (all surfaces).
105
+ */
106
+ function contractSpecToYaml(registries, options = {}) {
107
+ return jsonToYaml(exportContractSpec(registries, options).openApi);
108
+ }
109
+ /**
136
110
  * Simple JSON to YAML conversion.
137
111
  */
138
112
  function jsonToYaml(obj, indent = 0) {
@@ -147,5 +121,5 @@ function jsonToYaml(obj, indent = 0) {
147
121
  }
148
122
 
149
123
  //#endregion
150
- export { defaultRestPath, openApiForRegistry, openApiToJson, openApiToYaml };
124
+ export { contractSpecToJson, contractSpecToYaml, exportContractSpec, openApiForRegistry, openApiToJson, openApiToYaml };
151
125
  //# sourceMappingURL=exporter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"exporter.js","names":["doc: ContractSpecOpenApiDocument","op: Record<string, unknown>","responses: Record<string, unknown>"],"sources":["../../src/openapi/exporter.ts"],"sourcesContent":["/**\n * Export ContractSpec specs to OpenAPI 3.1 format.\n * Moved from @lssm/lib.contracts/openapi.ts with enhancements.\n */\n\nimport type {\n AnyOperationSpec,\n OperationSpec,\n OperationSpecRegistry,\n} from '@lssm/lib.contracts';\nimport type { AnySchemaModel } from '@lssm/lib.schema';\nimport { z } from 'zod';\nimport type {\n ContractSpecOpenApiDocument,\n OpenApiExportOptions,\n OpenApiServer,\n} from './types';\n\ntype OpenApiSchemaObject = Record<string, unknown>;\n\n/**\n * Convert a spec name and version to an operationId.\n */\nfunction toOperationId(name: string, version: number): string {\n return `${name.replace(/\\./g, '_')}_v${version}`;\n}\n\n/**\n * Convert a spec name and version to a schema name.\n */\nfunction toSchemaName(\n prefix: 'Input' | 'Output',\n name: string,\n version: number\n): string {\n return `${prefix}_${toOperationId(name, version)}`;\n}\n\n/**\n * Determine HTTP method from spec kind and override.\n */\nfunction toHttpMethod(\n kind: 'command' | 'query',\n override?: 'GET' | 'POST'\n): string {\n const method = override ?? (kind === 'query' ? 'GET' : 'POST');\n return method.toLowerCase();\n}\n\n/**\n * Generate default REST path from spec name and version.\n */\nexport function defaultRestPath(name: string, version: number): string {\n return `/${name.replace(/\\./g, '/')}/v${version}`;\n}\n\n/**\n * Get REST path from spec, using transport override or default.\n */\nfunction toRestPath(spec: AnyOperationSpec): string {\n const path =\n spec.transport?.rest?.path ??\n defaultRestPath(spec.meta.name, spec.meta.version);\n return path.startsWith('/') ? path : `/${path}`;\n}\n\n/**\n * Convert a SchemaModel to JSON Schema using Zod.\n */\nfunction schemaModelToJsonSchema(\n schema: AnySchemaModel | null\n): OpenApiSchemaObject | null {\n if (!schema) return null;\n return z.toJSONSchema(schema.getZod()) as OpenApiSchemaObject;\n}\n\n/**\n * Extract JSON Schema for a spec's input and output.\n */\nfunction jsonSchemaForSpec(\n spec: OperationSpec<AnySchemaModel, AnySchemaModel>\n): {\n input: OpenApiSchemaObject | null;\n output: OpenApiSchemaObject | null;\n meta: {\n name: string;\n version: number;\n kind: 'command' | 'query';\n description: string;\n tags: string[];\n stability: string;\n };\n} {\n return {\n input: schemaModelToJsonSchema(spec.io.input),\n output: schemaModelToJsonSchema(spec.io.output as AnySchemaModel | null),\n meta: {\n name: spec.meta.name,\n version: spec.meta.version,\n kind: spec.meta.kind,\n description: spec.meta.description,\n tags: spec.meta.tags ?? [],\n stability: spec.meta.stability ?? 'stable',\n },\n };\n}\n\n/**\n * Export a OperationSpecRegistry to an OpenAPI 3.1 document.\n *\n * @param registry - The OperationSpecRegistry containing specs to export\n * @param options - Export options (title, version, description, servers)\n * @returns OpenAPI 3.1 document\n */\nexport function openApiForRegistry(\n registry: OperationSpecRegistry,\n options: OpenApiExportOptions = {}\n): ContractSpecOpenApiDocument {\n const specs = registry\n .listSpecs()\n .filter(\n (s): s is AnyOperationSpec =>\n s.meta.kind === 'command' || s.meta.kind === 'query'\n )\n .slice()\n .sort((a, b) => {\n const byName = a.meta.name.localeCompare(b.meta.name);\n return byName !== 0 ? byName : a.meta.version - b.meta.version;\n });\n\n const doc: ContractSpecOpenApiDocument = {\n openapi: '3.1.0',\n info: {\n title: options.title ?? 'ContractSpec API',\n version: options.version ?? '0.0.0',\n ...(options.description ? { description: options.description } : {}),\n },\n ...(options.servers ? { servers: options.servers } : {}),\n paths: {},\n components: { schemas: {} },\n };\n\n for (const spec of specs) {\n const schema = jsonSchemaForSpec(\n spec as unknown as OperationSpec<AnySchemaModel, AnySchemaModel>\n );\n const method = toHttpMethod(spec.meta.kind, spec.transport?.rest?.method);\n const path = toRestPath(spec);\n\n const operationId = toOperationId(spec.meta.name, spec.meta.version);\n\n const pathItem = (doc.paths[path] ??= {});\n const op: Record<string, unknown> = {\n operationId,\n summary: spec.meta.description ?? spec.meta.name,\n description: spec.meta.description,\n tags: spec.meta.tags ?? [],\n 'x-contractspec': {\n name: spec.meta.name,\n version: spec.meta.version,\n kind: spec.meta.kind,\n },\n responses: {},\n };\n\n if (schema.input) {\n const inputName = toSchemaName(\n 'Input',\n spec.meta.name,\n spec.meta.version\n );\n doc.components.schemas[inputName] = schema.input;\n op['requestBody'] = {\n required: true,\n content: {\n 'application/json': {\n schema: { $ref: `#/components/schemas/${inputName}` },\n },\n },\n };\n }\n\n const responses: Record<string, unknown> = {};\n if (schema.output) {\n const outputName = toSchemaName(\n 'Output',\n spec.meta.name,\n spec.meta.version\n );\n doc.components.schemas[outputName] = schema.output;\n responses['200'] = {\n description: 'OK',\n content: {\n 'application/json': {\n schema: { $ref: `#/components/schemas/${outputName}` },\n },\n },\n };\n } else {\n responses['200'] = { description: 'OK' };\n }\n op['responses'] = responses;\n\n pathItem[method] = op;\n }\n\n return doc;\n}\n\n/**\n * Export a OperationSpecRegistry to OpenAPI JSON string.\n */\nexport function openApiToJson(\n registry: OperationSpecRegistry,\n options: OpenApiExportOptions = {}\n): string {\n const doc = openApiForRegistry(registry, options);\n return JSON.stringify(doc, null, 2);\n}\n\n/**\n * Export a OperationSpecRegistry to OpenAPI YAML string.\n */\nexport function openApiToYaml(\n registry: OperationSpecRegistry,\n options: OpenApiExportOptions = {}\n): string {\n const doc = openApiForRegistry(registry, options);\n return jsonToYaml(doc);\n}\n\n/**\n * Simple JSON to YAML conversion.\n */\nfunction jsonToYaml(obj: unknown, indent = 0): string {\n const spaces = ' '.repeat(indent);\n let yaml = '';\n\n if (Array.isArray(obj)) {\n for (const item of obj) {\n if (typeof item === 'object' && item !== null) {\n yaml += `${spaces}-\\n${jsonToYaml(item, indent + 1)}`;\n } else {\n yaml += `${spaces}- ${JSON.stringify(item)}\\n`;\n }\n }\n } else if (typeof obj === 'object' && obj !== null) {\n for (const [key, value] of Object.entries(obj)) {\n if (Array.isArray(value)) {\n yaml += `${spaces}${key}:\\n${jsonToYaml(value, indent + 1)}`;\n } else if (typeof value === 'object' && value !== null) {\n yaml += `${spaces}${key}:\\n${jsonToYaml(value, indent + 1)}`;\n } else {\n yaml += `${spaces}${key}: ${JSON.stringify(value)}\\n`;\n }\n }\n }\n\n return yaml;\n}\n\n// Re-export types for convenience\nexport type {\n OpenApiExportOptions,\n OpenApiServer,\n ContractSpecOpenApiDocument,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"exporter.js","names":["paths: Record<string, Record<string, unknown>>","schemas: Record<string, Record<string, unknown>>","doc: ContractSpecOpenApiDocument","result: ContractSpecExportResult"],"sources":["../../src/openapi/exporter.ts"],"sourcesContent":["/**\n * Export ContractSpec specs to OpenAPI 3.1 format.\n * Refactored to use modular exporters for all surfaces.\n */\nimport type {\n OperationSpecRegistry,\n FeatureRegistry,\n PresentationRegistry,\n FormRegistry,\n DataViewRegistry,\n WorkflowRegistry,\n EventSpec,\n PresentationDescriptorV2,\n} from '@lssm/lib.contracts';\nimport type { AnySchemaModel } from '@lssm/lib.schema';\nimport type {\n ContractSpecOpenApiDocument,\n OpenApiExportOptions,\n OpenApiServer,\n ContractSpecExportOptions,\n ContractSpecExportResult,\n} from './types';\nimport {\n exportOperations,\n generateOperationsRegistry,\n defaultRestPath as defaultRestPathFn,\n} from './exporter/operations';\nimport { exportEvents, generateEventsExports } from './exporter/events';\nimport { exportFeatures, generateFeaturesRegistry } from './exporter/features';\nimport {\n exportPresentations,\n generatePresentationsRegistry,\n} from './exporter/presentations';\nimport { exportForms, generateFormsRegistry } from './exporter/forms';\nimport {\n exportDataViews,\n generateDataViewsRegistry,\n} from './exporter/data-views';\nimport {\n exportWorkflows,\n generateWorkflowsRegistry,\n} from './exporter/workflows';\nimport { generateRegistryIndex } from './exporter/registries';\n\n/**\n * Input registries for unified export.\n */\nexport interface ContractSpecRegistries {\n operations?: OperationSpecRegistry;\n events?: EventSpec<AnySchemaModel>[];\n features?: FeatureRegistry;\n presentations?: PresentationRegistry;\n presentationsV2?: PresentationDescriptorV2[];\n forms?: FormRegistry;\n dataViews?: DataViewRegistry;\n workflows?: WorkflowRegistry;\n}\n\n// Re-export for backwards compatibility\nexport { defaultRestPathFn as defaultRestPath };\n\n/**\n * Export a OperationSpecRegistry to an OpenAPI 3.1 document.\n * @deprecated Use exportContractSpec for full surface support.\n */\nexport function openApiForRegistry(\n registry: OperationSpecRegistry,\n options: OpenApiExportOptions = {}\n): ContractSpecOpenApiDocument {\n const { paths, schemas } = exportOperations(registry);\n\n return {\n openapi: '3.1.0',\n info: {\n title: options.title ?? 'ContractSpec API',\n version: options.version ?? '0.0.0',\n ...(options.description ? { description: options.description } : {}),\n },\n ...(options.servers ? { servers: options.servers } : {}),\n paths,\n components: { schemas },\n };\n}\n\n/**\n * Export all ContractSpec surfaces to OpenAPI document with extensions.\n */\nexport function exportContractSpec(\n registries: ContractSpecRegistries,\n options: ContractSpecExportOptions = {}\n): ContractSpecExportResult {\n const {\n operations: includeOps = true,\n events: includeEvents = true,\n features: includeFeatures = true,\n presentations: includePresentations = true,\n forms: includeForms = true,\n dataViews: includeDataViews = true,\n workflows: includeWorkflows = true,\n generateRegistries = true,\n } = options;\n\n // Build OpenAPI document\n let paths: Record<string, Record<string, unknown>> = {};\n let schemas: Record<string, Record<string, unknown>> = {};\n\n // Export operations\n if (includeOps && registries.operations) {\n const opResult = exportOperations(registries.operations);\n paths = opResult.paths;\n schemas = opResult.schemas;\n }\n\n const doc: ContractSpecOpenApiDocument = {\n openapi: '3.1.0',\n info: {\n title: options.title ?? 'ContractSpec API',\n version: options.version ?? '0.0.0',\n ...(options.description ? { description: options.description } : {}),\n },\n ...(options.servers ? { servers: options.servers } : {}),\n paths,\n components: { schemas },\n };\n\n // Add extensions for other surfaces\n if (includeEvents && registries.events?.length) {\n doc['x-contractspec-events'] = exportEvents(registries.events);\n }\n\n if (includeFeatures && registries.features) {\n doc['x-contractspec-features'] = exportFeatures(registries.features);\n }\n\n if (includePresentations && registries.presentations) {\n const presExport = exportPresentations(\n registries.presentations,\n registries.presentationsV2\n );\n doc['x-contractspec-presentations'] = [\n ...presExport.v1,\n ...presExport.v2,\n ];\n }\n\n if (includeForms && registries.forms) {\n doc['x-contractspec-forms'] = exportForms(registries.forms);\n }\n\n if (includeDataViews && registries.dataViews) {\n doc['x-contractspec-dataviews'] = exportDataViews(registries.dataViews);\n }\n\n if (includeWorkflows && registries.workflows) {\n doc['x-contractspec-workflows'] = exportWorkflows(registries.workflows);\n }\n\n const result: ContractSpecExportResult = {\n openApi: doc,\n };\n\n // Generate registry code if requested\n if (generateRegistries) {\n result.registries = {};\n\n if (includeOps && registries.operations) {\n result.registries.operations = generateOperationsRegistry(\n registries.operations\n );\n }\n\n if (includeEvents && registries.events?.length) {\n result.registries.events = generateEventsExports(registries.events);\n }\n\n if (includeFeatures && registries.features) {\n result.registries.features = generateFeaturesRegistry(registries.features);\n }\n\n if (includePresentations && registries.presentations) {\n result.registries.presentations = generatePresentationsRegistry(\n registries.presentations\n );\n }\n\n if (includeForms && registries.forms) {\n result.registries.forms = generateFormsRegistry(registries.forms);\n }\n\n if (includeDataViews && registries.dataViews) {\n result.registries.dataViews = generateDataViewsRegistry(\n registries.dataViews\n );\n }\n\n if (includeWorkflows && registries.workflows) {\n result.registries.workflows = generateWorkflowsRegistry(\n registries.workflows\n );\n }\n\n // Generate index file\n result.registries.index = generateRegistryIndex({\n operations: includeOps && !!registries.operations,\n events: includeEvents && !!registries.events?.length,\n features: includeFeatures && !!registries.features,\n presentations: includePresentations && !!registries.presentations,\n forms: includeForms && !!registries.forms,\n dataViews: includeDataViews && !!registries.dataViews,\n workflows: includeWorkflows && !!registries.workflows,\n });\n }\n\n return result;\n}\n\n/**\n * Export a OperationSpecRegistry to OpenAPI JSON string.\n */\nexport function openApiToJson(\n registry: OperationSpecRegistry,\n options: OpenApiExportOptions = {}\n): string {\n const doc = openApiForRegistry(registry, options);\n return JSON.stringify(doc, null, 2);\n}\n\n/**\n * Export a OperationSpecRegistry to OpenAPI YAML string.\n */\nexport function openApiToYaml(\n registry: OperationSpecRegistry,\n options: OpenApiExportOptions = {}\n): string {\n const doc = openApiForRegistry(registry, options);\n return jsonToYaml(doc);\n}\n\n/**\n * Export ContractSpec to JSON string (all surfaces).\n */\nexport function contractSpecToJson(\n registries: ContractSpecRegistries,\n options: ContractSpecExportOptions = {}\n): string {\n const result = exportContractSpec(registries, options);\n return JSON.stringify(result.openApi, null, 2);\n}\n\n/**\n * Export ContractSpec to YAML string (all surfaces).\n */\nexport function contractSpecToYaml(\n registries: ContractSpecRegistries,\n options: ContractSpecExportOptions = {}\n): string {\n const result = exportContractSpec(registries, options);\n return jsonToYaml(result.openApi);\n}\n\n/**\n * Simple JSON to YAML conversion.\n */\nfunction jsonToYaml(obj: unknown, indent = 0): string {\n const spaces = ' '.repeat(indent);\n let yaml = '';\n\n if (Array.isArray(obj)) {\n for (const item of obj) {\n if (typeof item === 'object' && item !== null) {\n yaml += `${spaces}-\\n${jsonToYaml(item, indent + 1)}`;\n } else {\n yaml += `${spaces}- ${JSON.stringify(item)}\\n`;\n }\n }\n } else if (typeof obj === 'object' && obj !== null) {\n for (const [key, value] of Object.entries(obj)) {\n if (Array.isArray(value)) {\n yaml += `${spaces}${key}:\\n${jsonToYaml(value, indent + 1)}`;\n } else if (typeof value === 'object' && value !== null) {\n yaml += `${spaces}${key}:\\n${jsonToYaml(value, indent + 1)}`;\n } else {\n yaml += `${spaces}${key}: ${JSON.stringify(value)}\\n`;\n }\n }\n }\n\n return yaml;\n}\n\n// Re-export types for convenience\nexport type {\n OpenApiExportOptions,\n OpenApiServer,\n ContractSpecOpenApiDocument,\n ContractSpecExportOptions,\n ContractSpecExportResult,\n};\n"],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ //#region src/openapi/importer/grouping.ts
2
+ /**
3
+ * Resolve the group folder for an operation based on grouping config.
4
+ */
5
+ function resolveOperationGroupFolder(operation, conventions) {
6
+ const groupingRule = conventions.operationsGrouping;
7
+ if (!groupingRule || groupingRule.strategy === "none") return "";
8
+ return applyGroupingStrategy(groupingRule, {
9
+ name: operation.operationId,
10
+ tags: operation.tags,
11
+ path: operation.path
12
+ });
13
+ }
14
+ /**
15
+ * Resolve the group folder for a model based on grouping config.
16
+ */
17
+ function resolveModelGroupFolder(modelName, conventions, relatedPath, relatedTags) {
18
+ const groupingRule = conventions.modelsGrouping;
19
+ if (!groupingRule || groupingRule.strategy === "none") return "";
20
+ return applyGroupingStrategy(groupingRule, {
21
+ name: modelName,
22
+ tags: relatedTags ?? [],
23
+ path: relatedPath
24
+ });
25
+ }
26
+ /**
27
+ * Resolve the group folder for an event based on grouping config.
28
+ */
29
+ function resolveEventGroupFolder(eventName, conventions, relatedTags) {
30
+ const groupingRule = conventions.eventsGrouping;
31
+ if (!groupingRule || groupingRule.strategy === "none") return "";
32
+ return applyGroupingStrategy(groupingRule, {
33
+ name: eventName,
34
+ tags: relatedTags ?? []
35
+ });
36
+ }
37
+ /**
38
+ * Apply grouping strategy to extract folder name.
39
+ */
40
+ function applyGroupingStrategy(rule, context) {
41
+ switch (rule.strategy) {
42
+ case "by-tag": return context.tags?.[0] ?? "untagged";
43
+ case "by-owner": return context.owners?.[0] ?? "unowned";
44
+ case "by-domain": return extractDomain(context.name);
45
+ case "by-url-path-single": return extractUrlPathLevel(context.path, 1);
46
+ case "by-url-path-multi": return extractUrlPathLevel(context.path, rule.urlPathLevel ?? 2);
47
+ case "by-feature": return extractDomain(context.name);
48
+ case "none":
49
+ default: return "";
50
+ }
51
+ }
52
+ /**
53
+ * Extract domain from operation/model name.
54
+ * e.g., "users.create" -> "users"
55
+ */
56
+ function extractDomain(name) {
57
+ if (name.includes(".")) return name.split(".")[0] ?? "default";
58
+ if (name.includes("_")) return name.split("_")[0] ?? "default";
59
+ return name.match(/^([a-z]+)/i)?.[1]?.toLowerCase() ?? "default";
60
+ }
61
+ /**
62
+ * Extract URL path segments for grouping.
63
+ */
64
+ function extractUrlPathLevel(path, level) {
65
+ if (!path) return "root";
66
+ const nonParamSegments = path.split("/").filter(Boolean).filter((s) => !s.startsWith("{"));
67
+ if (nonParamSegments.length === 0) return "root";
68
+ return nonParamSegments.slice(0, level).join("/");
69
+ }
70
+
71
+ //#endregion
72
+ export { resolveEventGroupFolder, resolveModelGroupFolder, resolveOperationGroupFolder };
73
+ //# sourceMappingURL=grouping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grouping.js","names":[],"sources":["../../../src/openapi/importer/grouping.ts"],"sourcesContent":["/**\n * Grouping utilities for OpenAPI import/export.\n * Determines output folder structure based on configuration.\n */\nimport type {\n FolderConventions,\n} from '@lssm/lib.contracts';\nimport type { ParsedOperation } from '../types';\n\n/**\n * Grouping strategy type (matches ContractSpec config).\n */\ntype GroupingStrategy =\n | 'by-tag'\n | 'by-owner'\n | 'by-domain'\n | 'by-url-path-single'\n | 'by-url-path-multi'\n | 'by-feature'\n | 'none';\n\n/**\n * Grouping rule configuration.\n */\ninterface GroupingRule {\n strategy: GroupingStrategy;\n urlPathLevel?: number;\n pattern?: string;\n}\n\n/**\n * Resolve the group folder for an operation based on grouping config.\n */\nexport function resolveOperationGroupFolder(\n operation: ParsedOperation,\n conventions: FolderConventions\n): string {\n const groupingRule = conventions.operationsGrouping as GroupingRule | undefined;\n \n if (!groupingRule || groupingRule.strategy === 'none') {\n return '';\n }\n\n return applyGroupingStrategy(groupingRule, {\n name: operation.operationId,\n tags: operation.tags,\n path: operation.path,\n });\n}\n\n/**\n * Resolve the group folder for a model based on grouping config.\n */\nexport function resolveModelGroupFolder(\n modelName: string,\n conventions: FolderConventions,\n relatedPath?: string,\n relatedTags?: string[]\n): string {\n const groupingRule = conventions.modelsGrouping as GroupingRule | undefined;\n \n if (!groupingRule || groupingRule.strategy === 'none') {\n return '';\n }\n\n return applyGroupingStrategy(groupingRule, {\n name: modelName,\n tags: relatedTags ?? [],\n path: relatedPath,\n });\n}\n\n/**\n * Resolve the group folder for an event based on grouping config.\n */\nexport function resolveEventGroupFolder(\n eventName: string,\n conventions: FolderConventions,\n relatedTags?: string[]\n): string {\n const groupingRule = conventions.eventsGrouping as GroupingRule | undefined;\n \n if (!groupingRule || groupingRule.strategy === 'none') {\n return '';\n }\n\n return applyGroupingStrategy(groupingRule, {\n name: eventName,\n tags: relatedTags ?? [],\n });\n}\n\n/**\n * Apply grouping strategy to extract folder name.\n */\nfunction applyGroupingStrategy(\n rule: GroupingRule,\n context: {\n name: string;\n tags?: string[];\n path?: string;\n owners?: string[];\n }\n): string {\n switch (rule.strategy) {\n case 'by-tag':\n return context.tags?.[0] ?? 'untagged';\n\n case 'by-owner':\n return context.owners?.[0] ?? 'unowned';\n\n case 'by-domain':\n return extractDomain(context.name);\n\n case 'by-url-path-single':\n return extractUrlPathLevel(context.path, 1);\n\n case 'by-url-path-multi':\n return extractUrlPathLevel(context.path, rule.urlPathLevel ?? 2);\n\n case 'by-feature':\n // Use domain extraction for feature grouping\n return extractDomain(context.name);\n\n case 'none':\n default:\n return '';\n }\n}\n\n/**\n * Extract domain from operation/model name.\n * e.g., \"users.create\" -> \"users\"\n */\nfunction extractDomain(name: string): string {\n // Handle camelCase/PascalCase names\n if (name.includes('.')) {\n return name.split('.')[0] ?? 'default';\n }\n if (name.includes('_')) {\n return name.split('_')[0] ?? 'default';\n }\n // Extract from camelCase like \"createUser\" -> \"create\"\n const match = name.match(/^([a-z]+)/i);\n return match?.[1]?.toLowerCase() ?? 'default';\n}\n\n/**\n * Extract URL path segments for grouping.\n */\nfunction extractUrlPathLevel(path: string | undefined, level: number): string {\n if (!path) return 'root';\n const segments = path.split('/').filter(Boolean);\n \n // Filter out path parameters like {id}\n const nonParamSegments = segments.filter((s) => !s.startsWith('{'));\n \n if (nonParamSegments.length === 0) return 'root';\n \n return nonParamSegments.slice(0, level).join('/');\n}\n\n/**\n * Build full output path including group folder.\n */\nexport function buildOutputPath(\n baseDir: string,\n surfaceDir: string,\n groupFolder: string,\n fileName: string\n): string {\n const parts = [baseDir, surfaceDir];\n \n if (groupFolder) {\n parts.push(groupFolder);\n }\n \n parts.push(fileName);\n \n return parts.filter(Boolean).join('/');\n}\n\n/**\n * Determine if feature-based grouping should be applied.\n */\nexport function shouldGroupByFeature(conventions: FolderConventions): boolean {\n return conventions.groupByFeature;\n}\n"],"mappings":";;;;AAiCA,SAAgB,4BACd,WACA,aACQ;CACR,MAAM,eAAe,YAAY;AAEjC,KAAI,CAAC,gBAAgB,aAAa,aAAa,OAC7C,QAAO;AAGT,QAAO,sBAAsB,cAAc;EACzC,MAAM,UAAU;EAChB,MAAM,UAAU;EAChB,MAAM,UAAU;EACjB,CAAC;;;;;AAMJ,SAAgB,wBACd,WACA,aACA,aACA,aACQ;CACR,MAAM,eAAe,YAAY;AAEjC,KAAI,CAAC,gBAAgB,aAAa,aAAa,OAC7C,QAAO;AAGT,QAAO,sBAAsB,cAAc;EACzC,MAAM;EACN,MAAM,eAAe,EAAE;EACvB,MAAM;EACP,CAAC;;;;;AAMJ,SAAgB,wBACd,WACA,aACA,aACQ;CACR,MAAM,eAAe,YAAY;AAEjC,KAAI,CAAC,gBAAgB,aAAa,aAAa,OAC7C,QAAO;AAGT,QAAO,sBAAsB,cAAc;EACzC,MAAM;EACN,MAAM,eAAe,EAAE;EACxB,CAAC;;;;;AAMJ,SAAS,sBACP,MACA,SAMQ;AACR,SAAQ,KAAK,UAAb;EACE,KAAK,SACH,QAAO,QAAQ,OAAO,MAAM;EAE9B,KAAK,WACH,QAAO,QAAQ,SAAS,MAAM;EAEhC,KAAK,YACH,QAAO,cAAc,QAAQ,KAAK;EAEpC,KAAK,qBACH,QAAO,oBAAoB,QAAQ,MAAM,EAAE;EAE7C,KAAK,oBACH,QAAO,oBAAoB,QAAQ,MAAM,KAAK,gBAAgB,EAAE;EAElE,KAAK,aAEH,QAAO,cAAc,QAAQ,KAAK;EAEpC,KAAK;EACL,QACE,QAAO;;;;;;;AAQb,SAAS,cAAc,MAAsB;AAE3C,KAAI,KAAK,SAAS,IAAI,CACpB,QAAO,KAAK,MAAM,IAAI,CAAC,MAAM;AAE/B,KAAI,KAAK,SAAS,IAAI,CACpB,QAAO,KAAK,MAAM,IAAI,CAAC,MAAM;AAI/B,QADc,KAAK,MAAM,aAAa,GACvB,IAAI,aAAa,IAAI;;;;;AAMtC,SAAS,oBAAoB,MAA0B,OAAuB;AAC5E,KAAI,CAAC,KAAM,QAAO;CAIlB,MAAM,mBAHW,KAAK,MAAM,IAAI,CAAC,OAAO,QAAQ,CAGd,QAAQ,MAAM,CAAC,EAAE,WAAW,IAAI,CAAC;AAEnE,KAAI,iBAAiB,WAAW,EAAG,QAAO;AAE1C,QAAO,iBAAiB,MAAM,GAAG,MAAM,CAAC,KAAK,IAAI"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/openapi/importer/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AA6NC,cAlMY,iBAkMZ,EAAA,CAAA,WAAA,EAjMc,WAiMd,EAAA,mBAAA,EAhMsB,iBAgMtB,EAAA,aAAA,CAAA,EA/LgB,OA+LhB,CA/LwB,mBA+LxB,CAAA,EAAA,GA9LE,YA8LF;AAKD;;;AAEW,iBAFK,eAAA,CAEL,SAAA,EADE,eACF,EAAA,OAAA,EAAA,OAAA,CAAQ,mBAAR,CAAA,GAAA,SAAA,EAAA,mBAAA,EACY,iBADZ,CAAA,EAAA,MAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/openapi/importer/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AAyPgB,cAxNH,iBAwNkB,EAAA,CAAA,WAAA,EAvNhB,WAuNgB,EAAA,mBAAA,EAtNR,iBAsNQ,EAAA,aAAA,CAAA,EArNd,OAqNc,CArNN,mBAqNM,CAAA,EAAA,GApN5B,YAoN4B;;;;AAGR,iBAHP,eAAA,CAGO,SAAA,EAFV,eAEU,EAAA,OAAA,EADZ,OACY,CADJ,mBACI,CAAA,GAAA,SAAA,EAAA,mBAAA,EAAA,iBAAA,CAAA,EAAA,MAAA"}
@@ -5,6 +5,7 @@ import { COMMAND_METHODS, inferAuthLevel, inferOpKind } from "./analyzer.js";
5
5
  import { generateSpecCode } from "./generator.js";
6
6
  import { generateModelCode } from "./models.js";
7
7
  import { generateEventCode } from "./events.js";
8
+ import { resolveEventGroupFolder, resolveModelGroupFolder, resolveOperationGroupFolder } from "./grouping.js";
8
9
 
9
10
  //#region src/openapi/importer/index.ts
10
11
  /**
@@ -72,9 +73,11 @@ const importFromOpenApi = (parseResult, contractspecOptions, importOptions = {})
72
73
  openApiVersion: parseResult.version,
73
74
  importedAt: /* @__PURE__ */ new Date()
74
75
  };
76
+ const groupFolder = resolveOperationGroupFolder(operation, contractspecOptions.conventions);
75
77
  specs.push({
76
78
  code,
77
79
  fileName,
80
+ groupFolder: groupFolder || void 0,
78
81
  source,
79
82
  transportHints
80
83
  });
@@ -88,9 +91,11 @@ const importFromOpenApi = (parseResult, contractspecOptions, importOptions = {})
88
91
  for (const [name, schema] of Object.entries(parseResult.schemas)) try {
89
92
  const code = generateModelCode(name, schema, contractspecOptions);
90
93
  const fileName = toFileName(toSpecName(name, importOptions.prefix));
94
+ const groupFolder = resolveModelGroupFolder(name, contractspecOptions.conventions);
91
95
  specs.push({
92
96
  code,
93
97
  fileName,
98
+ groupFolder: groupFolder || void 0,
94
99
  source: {
95
100
  type: "openapi",
96
101
  sourceId: name,
@@ -109,9 +114,11 @@ const importFromOpenApi = (parseResult, contractspecOptions, importOptions = {})
109
114
  for (const event of parseResult.events) try {
110
115
  const code = generateEventCode(event, contractspecOptions);
111
116
  const fileName = toFileName(toSpecName(event.name, importOptions.prefix));
117
+ const groupFolder = resolveEventGroupFolder(event.name, contractspecOptions.conventions);
112
118
  specs.push({
113
119
  code,
114
120
  fileName,
121
+ groupFolder: groupFolder || void 0,
115
122
  source: {
116
123
  type: "openapi",
117
124
  sourceId: event.name,
@@ -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, toSpecName } 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 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';\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 = toSpecName(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 specs.push({\n code,\n fileName,\n source,\n transportHints,\n });\n } catch (error) {\n errors.push({\n sourceId: operation.operationId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // 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(toSpecName(name, importOptions.prefix));\n\n specs.push({\n code,\n fileName,\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(toSpecName(event.name, importOptions.prefix));\n\n specs.push({\n code,\n fileName,\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":"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"}
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, toSpecName } 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 = toSpecName(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(toSpecName(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(toSpecName(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":"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"}
@@ -1,8 +1,16 @@
1
1
  import { ContractSpecOpenApiDocument, HttpMethod, OpenApiDocument, OpenApiExportOptions, OpenApiOperation, OpenApiParameter, OpenApiParseOptions, OpenApiSchema, OpenApiServer, OpenApiSource, OpenApiTransportHints, OpenApiVersion, ParameterLocation, ParseResult, ParsedOperation, ParsedParameter } from "./types.js";
2
2
  import { detectFormat, detectVersion, parseOpenApiString } from "./parser/utils.js";
3
3
  import { parseOpenApi, parseOpenApiDocument } from "./parser/document.js";
4
- import { defaultRestPath, openApiForRegistry, openApiToJson, openApiToYaml } from "./exporter.js";
4
+ import { OperationsExportResult, defaultRestPath, exportOperations, generateOperationsRegistry, jsonSchemaForSpec, schemaModelToJsonSchema, toHttpMethod, toOperationId, toRestPath, toSchemaName } from "./exporter/operations.js";
5
+ import { ContractSpecRegistries, contractSpecToJson, contractSpecToYaml, exportContractSpec, openApiForRegistry, openApiToJson, openApiToYaml } from "./exporter.js";
6
+ import { ExportedEvent, exportEvents, generateEventsExports } from "./exporter/events.js";
7
+ import { ExportedFeature, exportFeatures, generateFeaturesRegistry } from "./exporter/features.js";
8
+ import { ExportedPresentation, ExportedPresentationV2, exportPresentations, exportPresentationsV1, exportPresentationsV2, generatePresentationsRegistry } from "./exporter/presentations.js";
9
+ import { ExportedForm, exportForms, generateFormsRegistry } from "./exporter/forms.js";
10
+ import { ExportedDataView, exportDataViews, generateDataViewsRegistry } from "./exporter/data-views.js";
11
+ import { ExportedWorkflow, exportWorkflows, generateWorkflowsRegistry } from "./exporter/workflows.js";
12
+ import { RegistryGenerationOptions, generateRegistryIndex } from "./exporter/registries.js";
5
13
  import { GeneratedModel, SchemaField, TypescriptType, generateImports, generateSchemaModelCode, getScalarType, jsonSchemaToField, jsonSchemaToType } from "./schema-converter.js";
6
14
  import { importFromOpenApi, importOperation } from "./importer/index.js";
7
15
  import { DiffOptions, createSpecDiff, diffAll, diffSpecVsOperation, diffSpecs, formatDiffChanges } from "./differ.js";
8
- export { type ContractSpecOpenApiDocument, type DiffOptions, type GeneratedModel, type HttpMethod, type OpenApiDocument, type OpenApiExportOptions, type OpenApiOperation, type OpenApiParameter, type OpenApiParseOptions, type OpenApiSchema, type OpenApiServer, type OpenApiSource, type OpenApiTransportHints, type OpenApiVersion, type ParameterLocation, type ParseResult, type ParsedOperation, type ParsedParameter, type SchemaField, type TypescriptType, createSpecDiff, defaultRestPath, detectFormat, detectVersion, diffAll, diffSpecVsOperation, diffSpecs, formatDiffChanges, generateImports, generateSchemaModelCode, getScalarType, importFromOpenApi, importOperation, jsonSchemaToField, jsonSchemaToType, openApiForRegistry, openApiToJson, openApiToYaml, parseOpenApi, parseOpenApiDocument, parseOpenApiString };
16
+ export { type ContractSpecOpenApiDocument, type ContractSpecRegistries, type DiffOptions, ExportedDataView, ExportedEvent, ExportedFeature, ExportedForm, ExportedPresentation, ExportedPresentationV2, 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, exportPresentationsV1, exportPresentationsV2, exportWorkflows, formatDiffChanges, generateDataViewsRegistry, generateEventsExports, generateFeaturesRegistry, generateFormsRegistry, generateImports, generateOperationsRegistry, generatePresentationsRegistry, generateRegistryIndex, generateSchemaModelCode, generateWorkflowsRegistry, getScalarType, importFromOpenApi, importOperation, jsonSchemaForSpec, jsonSchemaToField, jsonSchemaToType, openApiForRegistry, openApiToJson, openApiToYaml, parseOpenApi, parseOpenApiDocument, parseOpenApiString, schemaModelToJsonSchema, toHttpMethod, toOperationId, toRestPath, toSchemaName };
@@ -1,9 +1,18 @@
1
1
  import { detectFormat, detectVersion, parseOpenApiString } from "./parser/utils.js";
2
2
  import { parseOpenApi, parseOpenApiDocument } from "./parser/document.js";
3
3
  import "./parser.js";
4
- import { defaultRestPath, openApiForRegistry, openApiToJson, openApiToYaml } from "./exporter.js";
4
+ import { defaultRestPath, exportOperations, generateOperationsRegistry, jsonSchemaForSpec, schemaModelToJsonSchema, toHttpMethod, toOperationId, toRestPath, toSchemaName } from "./exporter/operations.js";
5
+ import { exportEvents, generateEventsExports } from "./exporter/events.js";
6
+ import { exportFeatures, generateFeaturesRegistry } from "./exporter/features.js";
7
+ import { exportPresentations, exportPresentationsV1, exportPresentationsV2, generatePresentationsRegistry } from "./exporter/presentations.js";
8
+ import { exportForms, generateFormsRegistry } from "./exporter/forms.js";
9
+ import { exportDataViews, generateDataViewsRegistry } from "./exporter/data-views.js";
10
+ import { exportWorkflows, generateWorkflowsRegistry } from "./exporter/workflows.js";
11
+ import { generateRegistryIndex } from "./exporter/registries.js";
12
+ import { contractSpecToJson, contractSpecToYaml, exportContractSpec, openApiForRegistry, openApiToJson, openApiToYaml } from "./exporter.js";
13
+ import "./exporter/index.js";
5
14
  import { generateImports, generateSchemaModelCode, getScalarType, jsonSchemaToField, jsonSchemaToType } from "./schema-converter.js";
6
15
  import { importFromOpenApi, importOperation } from "./importer/index.js";
7
16
  import { createSpecDiff, diffAll, diffSpecVsOperation, diffSpecs, formatDiffChanges } from "./differ.js";
8
17
 
9
- export { createSpecDiff, defaultRestPath, detectFormat, detectVersion, diffAll, diffSpecVsOperation, diffSpecs, formatDiffChanges, generateImports, generateSchemaModelCode, getScalarType, importFromOpenApi, importOperation, jsonSchemaToField, jsonSchemaToType, openApiForRegistry, openApiToJson, openApiToYaml, parseOpenApi, parseOpenApiDocument, parseOpenApiString };
18
+ export { contractSpecToJson, contractSpecToYaml, createSpecDiff, defaultRestPath, detectFormat, detectVersion, diffAll, diffSpecVsOperation, diffSpecs, exportContractSpec, exportDataViews, exportEvents, exportFeatures, exportForms, exportOperations, exportPresentations, exportPresentationsV1, exportPresentationsV2, exportWorkflows, formatDiffChanges, generateDataViewsRegistry, generateEventsExports, generateFeaturesRegistry, generateFormsRegistry, generateImports, generateOperationsRegistry, generatePresentationsRegistry, generateRegistryIndex, generateSchemaModelCode, generateWorkflowsRegistry, getScalarType, importFromOpenApi, importOperation, jsonSchemaForSpec, jsonSchemaToField, jsonSchemaToType, openApiForRegistry, openApiToJson, openApiToYaml, parseOpenApi, parseOpenApiDocument, parseOpenApiString, schemaModelToJsonSchema, toHttpMethod, toOperationId, toRestPath, toSchemaName };
@@ -1 +1 @@
1
- {"version":3,"file":"schema-converter.d.ts","names":[],"sources":["../../src/openapi/schema-converter.ts"],"sourcesContent":[],"mappings":";;;;;AA8CA;AA6CA;AA6GA;AA2BgB,UAvNC,cAAA,CAuNgB;EAmCjB;EAmOA,IAAA,EAAA,MAAA;;;;;;;;;;;;;;;UA3cC,WAAA;;;;QAIT;;;;;;gBAMQ;;;;;UAMC,cAAA;;;;;;UAMP;;;;;;;iBAuCM,gBAAA,SACN,+BAEP;;;;iBA0Ga,aAAA,SAAsB;;;;iBA2BtB,iBAAA,SACN,sDAGP;;;;iBA+Ba,uBAAA,SACN,oDAGP;;;;;;;iBA+Na,eAAA,SACN,wBACC"}
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"}