@contractkit/plugin-openapi 0.8.13 → 0.8.14

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.
@@ -5,9 +5,9 @@ $ tsup src/index.ts --format esm --sourcemap --dts && tsc --emitDeclarationOnly
5
5
  CLI tsup v8.5.1
6
6
  CLI Target: esnext
7
7
  ESM Build start
8
- ESM dist/index.js 19.85 KB
9
- ESM dist/index.js.map 44.92 KB
10
- ESM ⚡️ Build success in 137ms
8
+ ESM dist/index.js 20.17 KB
9
+ ESM dist/index.js.map 46.70 KB
10
+ ESM ⚡️ Build success in 155ms
11
11
  DTS Build start
12
- DTS ⚡️ Build success in 4307ms
13
- DTS dist/index.d.ts 1.33 KB
12
+ DTS ⚡️ Build success in 5042ms
13
+ DTS dist/index.d.ts 1.60 KB
@@ -3,20 +3,20 @@ $ vitest run --coverage
3
3
   RUN  v4.1.5 /home/runner/work/ContractKit/ContractKit/packages/plugin-openapi
4
4
  Coverage enabled with v8
5
5
 
6
- ✓ tests/codegen-openapi.test.ts (53 tests) 107ms
6
+ ✓ tests/codegen-openapi.test.ts (56 tests) 259ms
7
7
 
8
8
   Test Files  1 passed (1)
9
-  Tests  53 passed (53)
10
-  Start at  15:55:38
11
-  Duration  2.66s (transform 697ms, setup 0ms, import 1.57s, tests 107ms, environment 0ms)
9
+  Tests  56 passed (56)
10
+  Start at  17:06:40
11
+  Duration  5.47s (transform 1.23s, setup 0ms, import 3.72s, tests 259ms, environment 0ms)
12
12
 
13
13
   % Coverage report from v8
14
14
  -------------------|---------|----------|---------|---------|-------------------
15
15
  File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
16
16
  -------------------|---------|----------|---------|---------|-------------------
17
- All files | 78.88 | 74.52 | 82.25 | 81.03 |
18
- src | 79.5 | 75.26 | 86.11 | 81.5 |
19
- ...en-openapi.ts | 79.5 | 75.26 | 86.11 | 81.5 | ...69-672,696,706
17
+ All files | 79.25 | 74.76 | 82.25 | 81.42 |
18
+ src | 79.9 | 75.51 | 86.11 | 81.92 |
19
+ ...en-openapi.ts | 79.9 | 75.51 | 86.11 | 81.92 | ...01-704,728,738
20
20
  tests | 73.33 | 67.74 | 76.92 | 76.92 |
21
21
  helpers.ts | 73.33 | 67.74 | 76.92 | 76.92 | ...18,138,149-150
22
22
  -------------------|---------|----------|---------|---------|-------------------
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @contractkit/contractkit-plugin-openapi
2
2
 
3
+ ## 0.8.14
4
+
5
+ ### Patch Changes
6
+
7
+ - 2bf01f1: Emit explicit schemas for the `time` and `interval` scalars instead of type-less (permissive) schemas, and throw on an unmapped scalar type so a missing mapping fails loudly rather than producing an empty schema.
8
+ - Updated dependencies [2bf01f1]
9
+ - @contractkit/core@0.23.0
10
+
3
11
  ## 0.8.13
4
12
 
5
13
  ### Patch Changes
@@ -1,8 +1,10 @@
1
1
  import type { ContractRootNode, OpRootNode } from '@contractkit/core';
2
+ /** A single entry for the OpenAPI `servers` array. */
2
3
  export interface OpenApiServerEntry {
3
4
  url: string;
4
5
  description?: string;
5
6
  }
7
+ /** A named entry for `components.securitySchemes` (e.g. an HTTP bearer or API-key scheme). */
6
8
  export interface OpenApiSecurityScheme {
7
9
  type: string;
8
10
  scheme?: string;
@@ -10,6 +12,7 @@ export interface OpenApiSecurityScheme {
10
12
  name?: string;
11
13
  in?: string;
12
14
  }
15
+ /** Plugin configuration controlling the generated OpenAPI document (info block, servers, security, internal-op visibility). */
13
16
  export interface OpenApiConfig {
14
17
  baseDir?: string;
15
18
  output?: string;
@@ -28,6 +31,7 @@ export interface OpenApiConfig {
28
31
  */
29
32
  includeInternal?: boolean;
30
33
  }
34
+ /** Inputs to {@link generateOpenApi}: the parsed contracts/operations plus the OpenAPI config and shared security schemes. */
31
35
  export interface OpenApiCodegenContext {
32
36
  contractRoots: ContractRootNode[];
33
37
  opRoots: OpRootNode[];
@@ -35,7 +39,24 @@ export interface OpenApiCodegenContext {
35
39
  /** Named OpenAPI security scheme definitions to include in components.securitySchemes */
36
40
  securitySchemes?: Record<string, OpenApiSecurityScheme>;
37
41
  }
42
+ /**
43
+ * Generate an OpenAPI 3.0 document (YAML) from the parsed contracts and operations.
44
+ *
45
+ * Emits `paths` from the operations and `components.schemas` from the contracts, honoring
46
+ * `config.includeInternal` for `operation(internal)` visibility.
47
+ *
48
+ * @returns The OpenAPI document serialized as a YAML string.
49
+ */
38
50
  export declare function generateOpenApi(ctx: OpenApiCodegenContext): string;
51
+ /**
52
+ * Map a ContractKit scalar type node to its OpenAPI schema object (`{ type, format, ... }`),
53
+ * carrying across constraints like min/max/length.
54
+ *
55
+ * @throws {Error} If the scalar name is not mapped — every member of the closed scalar set must
56
+ * have an explicit case, so an unmapped name signals a scalar was added to core without updating
57
+ * this plugin (rather than silently emitting a type-less, permissive schema).
58
+ */
59
+ export declare function scalarToSchema(type: import('@contractkit/core').ScalarTypeNode): Record<string, unknown>;
39
60
  /**
40
61
  * Minimal YAML serializer sufficient for OpenAPI documents.
41
62
  * Avoids external dependency while producing clean, readable output.
@@ -1 +1 @@
1
- {"version":3,"file":"codegen-openapi.d.ts","sourceRoot":"","sources":["../src/codegen-openapi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,gBAAgB,EAChB,UAAU,EAOb,MAAM,mBAAmB,CAAC;AAG3B,MAAM,WAAW,kBAAkB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE;QACH,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,OAAO,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC/B,0GAA0G;IAC1G,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IACtC;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AA8FD,MAAM,WAAW,qBAAqB;IAClC,aAAa,EAAE,gBAAgB,EAAE,CAAC;IAClC,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,MAAM,EAAE,aAAa,CAAC;IACtB,yFAAyF;IACzF,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;CAC3D;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,qBAAqB,GAAG,MAAM,CAoFlE;AAiZD;;;GAGG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,SAAI,GAAG,MAAM,CA+DzD"}
1
+ {"version":3,"file":"codegen-openapi.d.ts","sourceRoot":"","sources":["../src/codegen-openapi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,gBAAgB,EAChB,UAAU,EAOb,MAAM,mBAAmB,CAAC;AAG3B,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,8FAA8F;AAC9F,MAAM,WAAW,qBAAqB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;CACf;AAED,+HAA+H;AAC/H,MAAM,WAAW,aAAa;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE;QACH,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,OAAO,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC/B,0GAA0G;IAC1G,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IACtC;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AA8FD,8HAA8H;AAC9H,MAAM,WAAW,qBAAqB;IAClC,aAAa,EAAE,gBAAgB,EAAE,CAAC;IAClC,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,MAAM,EAAE,aAAa,CAAC;IACtB,yFAAyF;IACzF,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;CAC3D;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,qBAAqB,GAAG,MAAM,CAoFlE;AA0ID;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,mBAAmB,EAAE,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsFxG;AA6LD;;;GAGG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,SAAI,GAAG,MAAM,CA+DzD"}
package/dist/index.js CHANGED
@@ -341,6 +341,10 @@ function scalarToSchema(type) {
341
341
  s.type = "string";
342
342
  s.format = "date";
343
343
  break;
344
+ case "time":
345
+ s.type = "string";
346
+ s.format = "time";
347
+ break;
344
348
  case "datetime":
345
349
  s.type = "string";
346
350
  s.format = "date-time";
@@ -349,6 +353,10 @@ function scalarToSchema(type) {
349
353
  s.type = "string";
350
354
  s.format = "duration";
351
355
  break;
356
+ case "interval":
357
+ s.type = "string";
358
+ s.format = "interval";
359
+ break;
352
360
  case "email":
353
361
  s.type = "string";
354
362
  s.format = "email";
@@ -375,6 +383,10 @@ function scalarToSchema(type) {
375
383
  break;
376
384
  case "json":
377
385
  break;
386
+ default: {
387
+ const _exhaustive = type.name;
388
+ throw new Error(`plugin-openapi: unmapped scalar '${String(_exhaustive)}' \u2014 add a case`);
389
+ }
378
390
  }
379
391
  return s;
380
392
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/codegen-openapi.ts"],"sourcesContent":["import { resolve } from 'node:path';\nimport { generateOpenApi } from './codegen-openapi.js';\nimport type { ContractKitPlugin } from '@contractkit/core';\nimport type { OpenApiConfig, OpenApiSecurityScheme } from './codegen-openapi.js';\nexport type { OpenApiServerEntry, OpenApiConfig, OpenApiSecurityScheme } from './codegen-openapi.js';\n\nexport interface OpenApiPluginOptions extends OpenApiConfig {\n securitySchemes?: Record<string, OpenApiSecurityScheme>;\n}\n\n// ─── Default export: loaded via plugins array, reads config from ctx.options ─\n\nconst plugin: ContractKitPlugin = {\n name: 'openapi',\n cacheKey: 'openapi',\n async generateTargets({ contractRoots, opRoots }, ctx) {\n const { securitySchemes, ...openapiConfig } = ctx.options as OpenApiPluginOptions;\n const base = openapiConfig.baseDir ? resolve(ctx.rootDir, openapiConfig.baseDir) : ctx.rootDir;\n const outPath = resolve(base, openapiConfig.output ?? 'openapi.yaml');\n ctx.emitFile(outPath, generateOpenApi({ contractRoots, opRoots, config: openapiConfig, securitySchemes }));\n },\n};\n\nexport default plugin;\n\n// ─── Factory: for programmatic use with explicit config ────────────────────\n\nexport function createOpenApiPlugin(\n openapiConfig: OpenApiConfig,\n rootDir: string,\n securitySchemes?: Record<string, OpenApiSecurityScheme>,\n): ContractKitPlugin {\n return {\n name: 'openapi',\n cacheKey: `openapi:${JSON.stringify(openapiConfig)}`,\n async generateTargets({ contractRoots, opRoots }, ctx) {\n const base = openapiConfig.baseDir ? resolve(rootDir, openapiConfig.baseDir) : rootDir;\n const outPath = resolve(base, openapiConfig.output ?? 'openapi.yaml');\n const content = generateOpenApi({ contractRoots, opRoots, config: openapiConfig, securitySchemes });\n ctx.emitFile(outPath, content);\n },\n };\n}\n","import type {\n ContractRootNode,\n OpRootNode,\n ContractTypeNode,\n FieldNode,\n ModelNode,\n OpRouteNode,\n OpOperationNode,\n ParamSource,\n} from '@contractkit/core';\nimport { resolveModifiers, resolveSecurity, SECURITY_NONE } from '@contractkit/core';\n\nexport interface OpenApiServerEntry {\n url: string;\n description?: string;\n}\n\nexport interface OpenApiSecurityScheme {\n type: string;\n scheme?: string;\n bearerFormat?: string;\n name?: string;\n in?: string;\n}\n\nexport interface OpenApiConfig {\n baseDir?: string;\n output?: string;\n info?: {\n title?: string;\n version?: string;\n description?: string;\n };\n servers?: OpenApiServerEntry[];\n /** Global OpenAPI security requirements (e.g. [{ bearerAuth: [] }]). Distinct from scheme definitions. */\n security?: Record<string, string[]>[];\n /**\n * Whether to document operations marked `internal`. Defaults to `false` — internal ops\n * are omitted from the spec so external consumers don't see them. Set to `true` for an\n * internal-use spec.\n */\n includeInternal?: boolean;\n}\n\n// ─── Type reachability ────────────────────────────────────────────────────\n\nfunction collectRefsFromType(type: ContractTypeNode, out: Set<string>): void {\n switch (type.kind) {\n case 'ref':\n out.add(type.name);\n break;\n case 'array':\n collectRefsFromType(type.item, out);\n break;\n case 'tuple':\n for (const item of type.items) collectRefsFromType(item, out);\n break;\n case 'record':\n collectRefsFromType(type.value, out);\n break;\n case 'union':\n case 'discriminatedUnion':\n case 'intersection':\n for (const member of type.members) collectRefsFromType(member, out);\n break;\n case 'lazy':\n collectRefsFromType(type.inner, out);\n break;\n case 'inlineObject':\n for (const field of type.fields) collectRefsFromType(field.type, out);\n break;\n }\n}\n\nfunction collectParamSourceRefs(source: ParamSource | undefined, out: Set<string>): void {\n if (!source) return;\n if (source.kind === 'ref') {\n out.add(source.name);\n return;\n }\n if (source.kind === 'params') {\n for (const p of source.nodes) collectRefsFromType(p.type, out);\n return;\n }\n collectRefsFromType(source.node, out);\n}\n\n/** Collect all type names directly referenced by public operations (seed set). */\nfunction collectPublicTypeRefs(opRoots: OpRootNode[], includeInternal = false): Set<string> {\n const refs = new Set<string>();\n for (const opRoot of opRoots) {\n for (const route of opRoot.routes) {\n for (const op of route.operations) {\n if (!includeInternal && resolveModifiers(route, op).includes('internal')) continue;\n if (op.request) {\n for (const body of op.request.bodies) collectRefsFromType(body.bodyType, refs);\n }\n for (const resp of op.responses) {\n if (resp.bodyType) collectRefsFromType(resp.bodyType, refs);\n if (resp.headers) {\n for (const h of resp.headers) collectRefsFromType(h.type, refs);\n }\n }\n collectParamSourceRefs(route.params, refs);\n collectParamSourceRefs(op.query, refs);\n collectParamSourceRefs(op.headers, refs);\n }\n }\n }\n return refs;\n}\n\n/** BFS-expand seed type names through the contract model graph. */\nfunction computeReachableSchemas(seeds: Set<string>, modelMap: Map<string, ModelNode>): Set<string> {\n const reachable = new Set<string>(seeds);\n const frontier = [...seeds];\n while (frontier.length > 0) {\n const name = frontier.pop()!;\n const model = modelMap.get(name);\n if (!model) continue;\n const refs = new Set<string>();\n if (model.type) collectRefsFromType(model.type, refs);\n for (const field of model.fields) collectRefsFromType(field.type, refs);\n if (model.bases) for (const b of model.bases) refs.add(b);\n for (const ref of refs) {\n if (!reachable.has(ref)) {\n reachable.add(ref);\n frontier.push(ref);\n }\n }\n }\n return reachable;\n}\n\n// ─── Public entry point ────────────────────────────────────────────────────\n\nexport interface OpenApiCodegenContext {\n contractRoots: ContractRootNode[];\n opRoots: OpRootNode[];\n config: OpenApiConfig;\n /** Named OpenAPI security scheme definitions to include in components.securitySchemes */\n securitySchemes?: Record<string, OpenApiSecurityScheme>;\n}\n\nexport function generateOpenApi(ctx: OpenApiCodegenContext): string {\n const { contractRoots, opRoots, config, securitySchemes } = ctx;\n const includeInternal = config.includeInternal ?? false;\n\n const doc: Record<string, unknown> = {\n openapi: '3.1.0',\n info: {\n title: config.info?.title ?? 'API',\n version: config.info?.version ?? '0.0.1',\n ...(config.info?.description ? { description: config.info.description } : {}),\n },\n };\n\n if (config.servers && config.servers.length > 0) {\n doc.servers = config.servers;\n }\n\n if (config.security && config.security.length > 0) {\n doc.security = config.security;\n }\n\n // Build component schemas from all contract models\n const allSchemas: Record<string, unknown> = {};\n const modelMap = new Map<string, ModelNode>();\n\n for (const contractRoot of contractRoots) {\n for (const model of contractRoot.models) {\n modelMap.set(model.name, model);\n }\n }\n for (const contractRoot of contractRoots) {\n for (const model of contractRoot.models) {\n allSchemas[model.name] = modelToSchema(model, modelMap);\n }\n }\n\n // Build paths from all operation files\n const paths: Record<string, Record<string, unknown>> = {};\n\n for (const opRoot of opRoots) {\n for (const route of opRoot.routes) {\n const oaPath = convertPath(route.path);\n\n for (const op of route.operations) {\n const mods = resolveModifiers(route, op);\n if (!includeInternal && mods.includes('internal')) continue;\n // Lazily initialize the path object so all-internal routes\n // leave no empty entry in the output\n if (!paths[oaPath]) paths[oaPath] = {};\n const operation = buildOperation(route, op);\n if (mods.includes('deprecated')) (operation as Record<string, unknown>).deprecated = true;\n paths[oaPath][op.method] = operation;\n }\n }\n }\n\n doc.paths = paths;\n\n // Filter schemas to only include types reachable from public operations.\n // When there are no op files, all schemas are included (no filtering).\n const schemas: Record<string, unknown> =\n opRoots.length > 0\n ? (() => {\n const reachable = computeReachableSchemas(collectPublicTypeRefs(opRoots, includeInternal), modelMap);\n const filtered: Record<string, unknown> = {};\n for (const [name, schema] of Object.entries(allSchemas)) {\n if (reachable.has(name)) filtered[name] = schema;\n }\n return filtered;\n })()\n : allSchemas;\n\n const components: Record<string, unknown> = {};\n if (Object.keys(schemas).length > 0) {\n components.schemas = schemas;\n }\n if (securitySchemes && Object.keys(securitySchemes).length > 0) {\n components.securitySchemes = securitySchemes;\n }\n if (Object.keys(components).length > 0) {\n doc.components = components;\n }\n\n return toYaml(doc);\n}\n\n// ─── Path conversion ──────────────────────────────────────────────────────\n\n/** Path is already in OpenAPI `{param}` style — return as-is. */\nfunction convertPath(path: string): string {\n return path;\n}\n\n// ─── Schema conversion ───────────────────────────────────────────────────\n\nfunction modelToSchema(model: ModelNode, modelMap?: Map<string, ModelNode>): Record<string, unknown> {\n // Type alias (no fields)\n if (model.type) {\n const schema = typeToSchema(model.type, modelMap);\n if (model.description) schema.description = model.description;\n return schema;\n }\n\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n\n for (const field of model.fields) {\n const prop = fieldToSchema(field, modelMap);\n properties[field.name] = prop;\n if (!field.optional) {\n required.push(field.name);\n }\n }\n\n const schema: Record<string, unknown> = {\n type: 'object',\n properties,\n };\n\n if (required.length > 0) {\n schema.required = required;\n }\n\n if (model.bases && model.bases.length > 0) {\n return {\n allOf: [...model.bases.map(b => ({ $ref: `#/components/schemas/${b}` })), schema],\n };\n }\n\n if (model.description) {\n schema.description = model.description;\n }\n if (model.deprecated) {\n schema.deprecated = true;\n }\n\n return schema;\n}\n\nfunction fieldToSchema(field: FieldNode, modelMap?: Map<string, ModelNode>): Record<string, unknown> {\n let schema = typeToSchema(field.type, modelMap);\n\n if (field.nullable) {\n schema = wrapNullable(schema);\n }\n if (field.visibility === 'readonly') {\n schema.readOnly = true;\n } else if (field.visibility === 'writeonly') {\n schema.writeOnly = true;\n }\n if (field.default !== undefined) {\n schema.default = field.default;\n }\n if (field.description) {\n schema.description = field.description;\n }\n if (field.deprecated) {\n schema.deprecated = true;\n }\n\n return schema;\n}\n\nfunction typeToSchema(type: ContractTypeNode, modelMap?: Map<string, ModelNode>): Record<string, unknown> {\n switch (type.kind) {\n case 'scalar':\n return scalarToSchema(type);\n case 'array':\n return arrayToSchema(type, modelMap);\n case 'tuple':\n return { type: 'array', prefixItems: type.items.map(i => typeToSchema(i, modelMap)) };\n case 'record':\n return { type: 'object', additionalProperties: typeToSchema(type.value, modelMap) };\n case 'enum':\n return { type: 'string', enum: type.values };\n case 'literal':\n return { const: type.value };\n case 'union':\n return { oneOf: type.members.map(m => typeToSchema(m, modelMap)) };\n case 'discriminatedUnion': {\n const oneOf = type.members.map(m => typeToSchema(m, modelMap));\n const mapping: Record<string, string> = {};\n for (const member of type.members) {\n if (member.kind !== 'ref') continue;\n const literalValues = resolveDiscriminatorLiterals(member.name, type.discriminator, modelMap);\n if (literalValues.length === 0) continue;\n for (const v of literalValues) {\n mapping[v] = `#/components/schemas/${member.name}`;\n }\n }\n const result: Record<string, unknown> = {\n oneOf,\n discriminator: { propertyName: type.discriminator },\n };\n if (Object.keys(mapping).length > 0) {\n (result.discriminator as Record<string, unknown>).mapping = mapping;\n }\n return result;\n }\n case 'intersection':\n return { allOf: type.members.map(m => typeToSchema(m, modelMap)) };\n case 'ref':\n return { $ref: `#/components/schemas/${type.name}` };\n case 'inlineObject':\n return inlineObjectToSchema(type.fields, modelMap);\n case 'lazy':\n return typeToSchema(type.inner, modelMap);\n }\n}\n\n/** Resolve literal values of a model's discriminator field. Returns [] if not resolvable. */\nfunction resolveDiscriminatorLiterals(modelName: string, discriminator: string, modelMap?: Map<string, ModelNode>): string[] {\n if (!modelMap) return [];\n const model = modelMap.get(modelName);\n if (!model) return [];\n const field = model.fields.find(f => f.name === discriminator);\n if (!field) return [];\n if (field.type.kind === 'literal') return [String(field.type.value)];\n if (field.type.kind === 'enum') return field.type.values;\n return [];\n}\n\nfunction scalarToSchema(type: import('@contractkit/core').ScalarTypeNode): Record<string, unknown> {\n const s: Record<string, unknown> = {};\n\n switch (type.name) {\n case 'string':\n s.type = 'string';\n if (type.min !== undefined) s.minLength = Number(type.min);\n if (type.max !== undefined) s.maxLength = Number(type.max);\n if (type.len !== undefined) {\n s.minLength = type.len;\n s.maxLength = type.len;\n }\n if (type.regex) s.pattern = type.regex;\n break;\n case 'number':\n s.type = 'number';\n if (type.min !== undefined) s.minimum = Number(type.min);\n if (type.max !== undefined) s.maximum = Number(type.max);\n break;\n case 'int':\n s.type = 'integer';\n if (type.min !== undefined) s.minimum = Number(type.min);\n if (type.max !== undefined) s.maximum = Number(type.max);\n break;\n case 'bigint':\n s.type = 'integer';\n s.format = 'int64';\n break;\n case 'boolean':\n s.type = 'boolean';\n break;\n case 'date':\n s.type = 'string';\n s.format = 'date';\n break;\n case 'datetime':\n s.type = 'string';\n s.format = 'date-time';\n break;\n case 'duration':\n s.type = 'string';\n s.format = 'duration';\n break;\n case 'email':\n s.type = 'string';\n s.format = 'email';\n break;\n case 'url':\n s.type = 'string';\n s.format = 'uri';\n break;\n case 'uuid':\n s.type = 'string';\n s.format = 'uuid';\n break;\n case 'unknown':\n // No type constraint\n break;\n case 'null':\n s.type = 'null';\n break;\n case 'object':\n s.type = 'object';\n break;\n case 'binary':\n s.type = 'string';\n s.format = 'binary';\n break;\n case 'json':\n // Any JSON value — no type constraint\n break;\n }\n\n return s;\n}\n\nfunction arrayToSchema(type: import('@contractkit/core').ArrayTypeNode, modelMap?: Map<string, ModelNode>): Record<string, unknown> {\n const s: Record<string, unknown> = { type: 'array', items: typeToSchema(type.item, modelMap) };\n if (type.min !== undefined) s.minItems = type.min;\n if (type.max !== undefined) s.maxItems = type.max;\n return s;\n}\n\nfunction inlineObjectToSchema(fields: FieldNode[], modelMap?: Map<string, ModelNode>): Record<string, unknown> {\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n\n for (const field of fields) {\n properties[field.name] = fieldToSchema(field, modelMap);\n if (!field.optional) {\n required.push(field.name);\n }\n }\n\n const schema: Record<string, unknown> = { type: 'object', properties };\n if (required.length > 0) schema.required = required;\n return schema;\n}\n\nfunction wrapNullable(schema: Record<string, unknown>): Record<string, unknown> {\n // OpenAPI 3.1 uses JSON Schema nullable via oneOf or type array\n if (schema.$ref) {\n return { oneOf: [schema, { type: 'null' }] };\n }\n if (typeof schema.type === 'string') {\n schema.type = [schema.type, 'null'];\n }\n return schema;\n}\n\n// ─── Operation building ─────────────────────────────────────────────────\n\nfunction buildOperation(route: OpRouteNode, op: OpOperationNode): Record<string, unknown> {\n const operation: Record<string, unknown> = {};\n\n // operationId from service binding or SDK name\n if (op.sdk) {\n operation.operationId = op.sdk;\n } else if (op.service) {\n const methodPart = op.service.split('.').pop();\n if (methodPart) operation.operationId = methodPart;\n }\n\n if (op.description) {\n operation.description = op.description;\n }\n\n // Parameters: path params + query + headers\n const parameters: Record<string, unknown>[] = [];\n\n if (route.params) {\n parameters.push(...paramSourceToParams(route.params, 'path'));\n }\n if (op.query) {\n parameters.push(...paramSourceToParams(op.query, 'query'));\n }\n if (op.headers) {\n parameters.push(...paramSourceToParams(op.headers, 'header'));\n }\n\n if (parameters.length > 0) {\n operation.parameters = parameters;\n }\n\n // Request body\n if (op.request && op.request.bodies.length > 0) {\n const content: Record<string, { schema: ReturnType<typeof typeToSchema> }> = {};\n for (const body of op.request.bodies) {\n content[body.contentType] = { schema: typeToSchema(body.bodyType) };\n }\n operation.requestBody = { required: true, content };\n }\n\n // Effective security (operation-level wins; falls back to route-level)\n // security: none → empty array (explicit public endpoint, overrides global default)\n // security: { fields } → omit operation-level entry (rely on global security from config)\n const effectiveSecurity = resolveSecurity(route, op);\n if (effectiveSecurity === SECURITY_NONE) {\n operation.security = [];\n }\n\n // Responses\n const responses: Record<string, unknown> = {};\n for (const resp of op.responses) {\n const statusKey = String(resp.statusCode);\n const responseObject: Record<string, unknown> = {\n description: statusDescription(resp.statusCode),\n };\n if (resp.bodyType && resp.contentType) {\n responseObject.content = {\n [resp.contentType]: {\n schema: typeToSchema(resp.bodyType),\n },\n };\n }\n if (resp.headers && resp.headers.length > 0) {\n const headers: Record<string, unknown> = {};\n for (const h of resp.headers) {\n const headerObject: Record<string, unknown> = {\n schema: typeToSchema(h.type),\n };\n if (!h.optional) headerObject.required = true;\n if (h.description) headerObject.description = h.description;\n headers[h.name] = headerObject;\n }\n responseObject.headers = headers;\n }\n responses[statusKey] = responseObject;\n }\n\n if (Object.keys(responses).length > 0) {\n operation.responses = responses;\n }\n\n return operation;\n}\n\nfunction paramSourceToParams(source: ParamSource, location: 'path' | 'query' | 'header'): Record<string, unknown>[] {\n if (source.kind === 'ref') {\n // Type reference name used as param source — emit a single $ref\n return [\n {\n name: source.name,\n in: location,\n required: location === 'path',\n schema: { $ref: `#/components/schemas/${source.name}` },\n },\n ];\n }\n\n if (source.kind === 'params') {\n // Inline param declarations\n return source.nodes.map(p => ({\n name: p.name,\n in: location,\n required: location === 'path',\n schema: typeToSchema(p.type),\n }));\n }\n\n // ContractTypeNode (inline object or other type) — if it's an inlineObject, expand fields\n if (source.node.kind === 'inlineObject') {\n return source.node.fields.map(f => ({\n name: f.name,\n in: location,\n required: location === 'path' ? true : !f.optional,\n schema: typeToSchema(f.type),\n }));\n }\n\n // For a ref type used as param source\n if (source.node.kind === 'ref') {\n return [\n {\n name: source.node.name,\n in: location,\n required: location === 'path',\n schema: { $ref: `#/components/schemas/${source.node.name}` },\n },\n ];\n }\n\n return [];\n}\n\nfunction statusDescription(code: number): string {\n const descriptions: Record<number, string> = {\n 200: 'Successful response',\n 201: 'Created',\n 204: 'No content',\n 400: 'Bad request',\n 401: 'Unauthorized',\n 403: 'Forbidden',\n 404: 'Not found',\n 409: 'Conflict',\n 422: 'Unprocessable entity',\n 500: 'Internal server error',\n };\n return descriptions[code] ?? `Response ${code}`;\n}\n\n// ─── YAML serializer ──────────────────────────────────────────────────────\n\n/**\n * Minimal YAML serializer sufficient for OpenAPI documents.\n * Avoids external dependency while producing clean, readable output.\n */\nexport function toYaml(value: unknown, indent = 0): string {\n if (value === null || value === undefined) return 'null';\n if (typeof value === 'boolean') return value ? 'true' : 'false';\n if (typeof value === 'number') return String(value);\n if (typeof value === 'bigint') return String(value);\n\n if (typeof value === 'string') {\n return yamlString(value);\n }\n\n if (Array.isArray(value)) {\n if (value.length === 0) return '[]';\n\n // Check if all items are simple scalars (for inline arrays like enum values, required lists)\n if (value.every(v => typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean')) {\n const items = value.map(v => (typeof v === 'string' ? yamlString(v) : String(v)));\n const inline = `[${items.join(', ')}]`;\n if (inline.length < 80) return inline;\n }\n\n const lines: string[] = [];\n const pad = ' '.repeat(indent);\n for (const item of value) {\n if (isPlainObject(item)) {\n const entries = Object.entries(item as Record<string, unknown>);\n if (entries.length > 0) {\n const [firstKey, firstVal] = entries[0]!;\n const firstValStr = isComplex(firstVal) ? `\\n${toYamlValue(firstVal, indent + 2)}` : ` ${toYaml(firstVal, indent + 2)}`;\n lines.push(`${pad}- ${yamlKey(firstKey)}:${firstValStr}`);\n for (let i = 1; i < entries.length; i++) {\n const [k, v] = entries[i]!;\n const valStr = isComplex(v) ? `\\n${toYamlValue(v, indent + 2)}` : ` ${toYaml(v, indent + 2)}`;\n lines.push(`${pad} ${yamlKey(k)}:${valStr}`);\n }\n } else {\n lines.push(`${pad}- {}`);\n }\n } else {\n lines.push(`${pad}- ${toYaml(item, indent + 1)}`);\n }\n }\n return lines.join('\\n');\n }\n\n if (isPlainObject(value)) {\n const obj = value as Record<string, unknown>;\n const entries = Object.entries(obj);\n if (entries.length === 0) return '{}';\n\n const pad = ' '.repeat(indent);\n const lines: string[] = [];\n for (const [key, val] of entries) {\n if (isComplex(val)) {\n lines.push(`${pad}${yamlKey(key)}:`);\n lines.push(toYamlValue(val, indent + 1));\n } else {\n lines.push(`${pad}${yamlKey(key)}: ${toYaml(val, indent + 1)}`);\n }\n }\n return lines.join('\\n');\n }\n\n return String(value);\n}\n\nfunction toYamlValue(value: unknown, indent: number): string {\n if (Array.isArray(value)) {\n return toYaml(value, indent);\n }\n if (isPlainObject(value)) {\n return toYaml(value, indent);\n }\n return ' '.repeat(indent) + toYaml(value, indent);\n}\n\nfunction isComplex(value: unknown): boolean {\n if (Array.isArray(value)) {\n // Simple scalar arrays can be inlined\n if (value.every(v => typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean')) {\n const items = value.map(v => (typeof v === 'string' ? yamlString(v) : String(v)));\n return `[${items.join(', ')}]`.length >= 80;\n }\n return true;\n }\n return isPlainObject(value);\n}\n\nfunction isPlainObject(value: unknown): boolean {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction yamlString(s: string): string {\n // Use plain style if safe, otherwise single-quoted\n if (s === '') return \"''\";\n if (/^[\\w./-]+$/.test(s) && !/^(true|false|null|yes|no|on|off)$/i.test(s) && !/^\\d/.test(s)) {\n return s;\n }\n // Single-quote, escaping internal single quotes by doubling\n return `'${s.replace(/'/g, \"''\")}'`;\n}\n\nfunction yamlKey(key: string): string {\n // Keys with special chars need quoting\n if (/^[\\w-]+$/.test(key) && !/^(true|false|null|yes|no|on|off)$/i.test(key)) {\n return key;\n }\n return `'${key.replace(/'/g, \"''\")}'`;\n}\n"],"mappings":"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","names":["resolve","resolveModifiers","resolveSecurity","SECURITY_NONE","collectRefsFromType","type","out","kind","add","name","item","items","value","member","members","inner","field","fields","collectParamSourceRefs","source","p","nodes","node","collectPublicTypeRefs","opRoots","includeInternal","refs","Set","opRoot","route","routes","op","operations","resolveModifiers","includes","request","body","bodies","bodyType","resp","responses","headers","h","params","query","computeReachableSchemas","seeds","modelMap","reachable","frontier","length","pop","model","get","bases","b","ref","has","push","generateOpenApi","ctx","contractRoots","config","securitySchemes","doc","openapi","info","title","version","description","servers","security","allSchemas","Map","contractRoot","models","set","modelToSchema","paths","oaPath","convertPath","path","mods","operation","buildOperation","deprecated","method","schemas","filtered","schema","Object","entries","components","keys","toYaml","typeToSchema","properties","required","prop","fieldToSchema","optional","allOf","map","$ref","nullable","wrapNullable","visibility","readOnly","writeOnly","default","undefined","scalarToSchema","arrayToSchema","prefixItems","i","additionalProperties","enum","values","const","oneOf","m","mapping","literalValues","resolveDiscriminatorLiterals","discriminator","v","result","propertyName","inlineObjectToSchema","modelName","find","f","String","s","min","minLength","Number","max","maxLength","len","regex","pattern","minimum","maximum","format","minItems","maxItems","sdk","operationId","service","methodPart","split","parameters","paramSourceToParams","content","contentType","requestBody","effectiveSecurity","resolveSecurity","SECURITY_NONE","statusKey","statusCode","responseObject","statusDescription","headerObject","location","in","code","descriptions","indent","yamlString","Array","isArray","every","inline","join","lines","pad","repeat","isPlainObject","firstKey","firstVal","firstValStr","isComplex","toYamlValue","yamlKey","k","valStr","obj","key","val","test","replace","plugin","name","cacheKey","generateTargets","contractRoots","opRoots","ctx","securitySchemes","openapiConfig","options","base","baseDir","resolve","rootDir","outPath","output","emitFile","generateOpenApi","config","createOpenApiPlugin","JSON","stringify","content"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/codegen-openapi.ts"],"sourcesContent":["import { resolve } from 'node:path';\nimport { generateOpenApi } from './codegen-openapi.js';\nimport type { ContractKitPlugin } from '@contractkit/core';\nimport type { OpenApiConfig, OpenApiSecurityScheme } from './codegen-openapi.js';\nexport type { OpenApiServerEntry, OpenApiConfig, OpenApiSecurityScheme } from './codegen-openapi.js';\n\nexport interface OpenApiPluginOptions extends OpenApiConfig {\n securitySchemes?: Record<string, OpenApiSecurityScheme>;\n}\n\n// ─── Default export: loaded via plugins array, reads config from ctx.options ─\n\nconst plugin: ContractKitPlugin = {\n name: 'openapi',\n cacheKey: 'openapi',\n async generateTargets({ contractRoots, opRoots }, ctx) {\n const { securitySchemes, ...openapiConfig } = ctx.options as OpenApiPluginOptions;\n const base = openapiConfig.baseDir ? resolve(ctx.rootDir, openapiConfig.baseDir) : ctx.rootDir;\n const outPath = resolve(base, openapiConfig.output ?? 'openapi.yaml');\n ctx.emitFile(outPath, generateOpenApi({ contractRoots, opRoots, config: openapiConfig, securitySchemes }));\n },\n};\n\nexport default plugin;\n\n// ─── Factory: for programmatic use with explicit config ────────────────────\n\nexport function createOpenApiPlugin(\n openapiConfig: OpenApiConfig,\n rootDir: string,\n securitySchemes?: Record<string, OpenApiSecurityScheme>,\n): ContractKitPlugin {\n return {\n name: 'openapi',\n cacheKey: `openapi:${JSON.stringify(openapiConfig)}`,\n async generateTargets({ contractRoots, opRoots }, ctx) {\n const base = openapiConfig.baseDir ? resolve(rootDir, openapiConfig.baseDir) : rootDir;\n const outPath = resolve(base, openapiConfig.output ?? 'openapi.yaml');\n const content = generateOpenApi({ contractRoots, opRoots, config: openapiConfig, securitySchemes });\n ctx.emitFile(outPath, content);\n },\n };\n}\n","import type {\n ContractRootNode,\n OpRootNode,\n ContractTypeNode,\n FieldNode,\n ModelNode,\n OpRouteNode,\n OpOperationNode,\n ParamSource,\n} from '@contractkit/core';\nimport { resolveModifiers, resolveSecurity, SECURITY_NONE } from '@contractkit/core';\n\n/** A single entry for the OpenAPI `servers` array. */\nexport interface OpenApiServerEntry {\n url: string;\n description?: string;\n}\n\n/** A named entry for `components.securitySchemes` (e.g. an HTTP bearer or API-key scheme). */\nexport interface OpenApiSecurityScheme {\n type: string;\n scheme?: string;\n bearerFormat?: string;\n name?: string;\n in?: string;\n}\n\n/** Plugin configuration controlling the generated OpenAPI document (info block, servers, security, internal-op visibility). */\nexport interface OpenApiConfig {\n baseDir?: string;\n output?: string;\n info?: {\n title?: string;\n version?: string;\n description?: string;\n };\n servers?: OpenApiServerEntry[];\n /** Global OpenAPI security requirements (e.g. [{ bearerAuth: [] }]). Distinct from scheme definitions. */\n security?: Record<string, string[]>[];\n /**\n * Whether to document operations marked `internal`. Defaults to `false` — internal ops\n * are omitted from the spec so external consumers don't see them. Set to `true` for an\n * internal-use spec.\n */\n includeInternal?: boolean;\n}\n\n// ─── Type reachability ────────────────────────────────────────────────────\n\nfunction collectRefsFromType(type: ContractTypeNode, out: Set<string>): void {\n switch (type.kind) {\n case 'ref':\n out.add(type.name);\n break;\n case 'array':\n collectRefsFromType(type.item, out);\n break;\n case 'tuple':\n for (const item of type.items) collectRefsFromType(item, out);\n break;\n case 'record':\n collectRefsFromType(type.value, out);\n break;\n case 'union':\n case 'discriminatedUnion':\n case 'intersection':\n for (const member of type.members) collectRefsFromType(member, out);\n break;\n case 'lazy':\n collectRefsFromType(type.inner, out);\n break;\n case 'inlineObject':\n for (const field of type.fields) collectRefsFromType(field.type, out);\n break;\n }\n}\n\nfunction collectParamSourceRefs(source: ParamSource | undefined, out: Set<string>): void {\n if (!source) return;\n if (source.kind === 'ref') {\n out.add(source.name);\n return;\n }\n if (source.kind === 'params') {\n for (const p of source.nodes) collectRefsFromType(p.type, out);\n return;\n }\n collectRefsFromType(source.node, out);\n}\n\n/** Collect all type names directly referenced by public operations (seed set). */\nfunction collectPublicTypeRefs(opRoots: OpRootNode[], includeInternal = false): Set<string> {\n const refs = new Set<string>();\n for (const opRoot of opRoots) {\n for (const route of opRoot.routes) {\n for (const op of route.operations) {\n if (!includeInternal && resolveModifiers(route, op).includes('internal')) continue;\n if (op.request) {\n for (const body of op.request.bodies) collectRefsFromType(body.bodyType, refs);\n }\n for (const resp of op.responses) {\n if (resp.bodyType) collectRefsFromType(resp.bodyType, refs);\n if (resp.headers) {\n for (const h of resp.headers) collectRefsFromType(h.type, refs);\n }\n }\n collectParamSourceRefs(route.params, refs);\n collectParamSourceRefs(op.query, refs);\n collectParamSourceRefs(op.headers, refs);\n }\n }\n }\n return refs;\n}\n\n/** BFS-expand seed type names through the contract model graph. */\nfunction computeReachableSchemas(seeds: Set<string>, modelMap: Map<string, ModelNode>): Set<string> {\n const reachable = new Set<string>(seeds);\n const frontier = [...seeds];\n while (frontier.length > 0) {\n const name = frontier.pop()!;\n const model = modelMap.get(name);\n if (!model) continue;\n const refs = new Set<string>();\n if (model.type) collectRefsFromType(model.type, refs);\n for (const field of model.fields) collectRefsFromType(field.type, refs);\n if (model.bases) for (const b of model.bases) refs.add(b);\n for (const ref of refs) {\n if (!reachable.has(ref)) {\n reachable.add(ref);\n frontier.push(ref);\n }\n }\n }\n return reachable;\n}\n\n// ─── Public entry point ────────────────────────────────────────────────────\n\n/** Inputs to {@link generateOpenApi}: the parsed contracts/operations plus the OpenAPI config and shared security schemes. */\nexport interface OpenApiCodegenContext {\n contractRoots: ContractRootNode[];\n opRoots: OpRootNode[];\n config: OpenApiConfig;\n /** Named OpenAPI security scheme definitions to include in components.securitySchemes */\n securitySchemes?: Record<string, OpenApiSecurityScheme>;\n}\n\n/**\n * Generate an OpenAPI 3.0 document (YAML) from the parsed contracts and operations.\n *\n * Emits `paths` from the operations and `components.schemas` from the contracts, honoring\n * `config.includeInternal` for `operation(internal)` visibility.\n *\n * @returns The OpenAPI document serialized as a YAML string.\n */\nexport function generateOpenApi(ctx: OpenApiCodegenContext): string {\n const { contractRoots, opRoots, config, securitySchemes } = ctx;\n const includeInternal = config.includeInternal ?? false;\n\n const doc: Record<string, unknown> = {\n openapi: '3.1.0',\n info: {\n title: config.info?.title ?? 'API',\n version: config.info?.version ?? '0.0.1',\n ...(config.info?.description ? { description: config.info.description } : {}),\n },\n };\n\n if (config.servers && config.servers.length > 0) {\n doc.servers = config.servers;\n }\n\n if (config.security && config.security.length > 0) {\n doc.security = config.security;\n }\n\n // Build component schemas from all contract models\n const allSchemas: Record<string, unknown> = {};\n const modelMap = new Map<string, ModelNode>();\n\n for (const contractRoot of contractRoots) {\n for (const model of contractRoot.models) {\n modelMap.set(model.name, model);\n }\n }\n for (const contractRoot of contractRoots) {\n for (const model of contractRoot.models) {\n allSchemas[model.name] = modelToSchema(model, modelMap);\n }\n }\n\n // Build paths from all operation files\n const paths: Record<string, Record<string, unknown>> = {};\n\n for (const opRoot of opRoots) {\n for (const route of opRoot.routes) {\n const oaPath = convertPath(route.path);\n\n for (const op of route.operations) {\n const mods = resolveModifiers(route, op);\n if (!includeInternal && mods.includes('internal')) continue;\n // Lazily initialize the path object so all-internal routes\n // leave no empty entry in the output\n if (!paths[oaPath]) paths[oaPath] = {};\n const operation = buildOperation(route, op);\n if (mods.includes('deprecated')) (operation as Record<string, unknown>).deprecated = true;\n paths[oaPath][op.method] = operation;\n }\n }\n }\n\n doc.paths = paths;\n\n // Filter schemas to only include types reachable from public operations.\n // When there are no op files, all schemas are included (no filtering).\n const schemas: Record<string, unknown> =\n opRoots.length > 0\n ? (() => {\n const reachable = computeReachableSchemas(collectPublicTypeRefs(opRoots, includeInternal), modelMap);\n const filtered: Record<string, unknown> = {};\n for (const [name, schema] of Object.entries(allSchemas)) {\n if (reachable.has(name)) filtered[name] = schema;\n }\n return filtered;\n })()\n : allSchemas;\n\n const components: Record<string, unknown> = {};\n if (Object.keys(schemas).length > 0) {\n components.schemas = schemas;\n }\n if (securitySchemes && Object.keys(securitySchemes).length > 0) {\n components.securitySchemes = securitySchemes;\n }\n if (Object.keys(components).length > 0) {\n doc.components = components;\n }\n\n return toYaml(doc);\n}\n\n// ─── Path conversion ──────────────────────────────────────────────────────\n\n/** Path is already in OpenAPI `{param}` style — return as-is. */\nfunction convertPath(path: string): string {\n return path;\n}\n\n// ─── Schema conversion ───────────────────────────────────────────────────\n\nfunction modelToSchema(model: ModelNode, modelMap?: Map<string, ModelNode>): Record<string, unknown> {\n // Type alias (no fields)\n if (model.type) {\n const schema = typeToSchema(model.type, modelMap);\n if (model.description) schema.description = model.description;\n return schema;\n }\n\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n\n for (const field of model.fields) {\n const prop = fieldToSchema(field, modelMap);\n properties[field.name] = prop;\n if (!field.optional) {\n required.push(field.name);\n }\n }\n\n const schema: Record<string, unknown> = {\n type: 'object',\n properties,\n };\n\n if (required.length > 0) {\n schema.required = required;\n }\n\n if (model.bases && model.bases.length > 0) {\n return {\n allOf: [...model.bases.map(b => ({ $ref: `#/components/schemas/${b}` })), schema],\n };\n }\n\n if (model.description) {\n schema.description = model.description;\n }\n if (model.deprecated) {\n schema.deprecated = true;\n }\n\n return schema;\n}\n\nfunction fieldToSchema(field: FieldNode, modelMap?: Map<string, ModelNode>): Record<string, unknown> {\n let schema = typeToSchema(field.type, modelMap);\n\n if (field.nullable) {\n schema = wrapNullable(schema);\n }\n if (field.visibility === 'readonly') {\n schema.readOnly = true;\n } else if (field.visibility === 'writeonly') {\n schema.writeOnly = true;\n }\n if (field.default !== undefined) {\n schema.default = field.default;\n }\n if (field.description) {\n schema.description = field.description;\n }\n if (field.deprecated) {\n schema.deprecated = true;\n }\n\n return schema;\n}\n\nfunction typeToSchema(type: ContractTypeNode, modelMap?: Map<string, ModelNode>): Record<string, unknown> {\n switch (type.kind) {\n case 'scalar':\n return scalarToSchema(type);\n case 'array':\n return arrayToSchema(type, modelMap);\n case 'tuple':\n return { type: 'array', prefixItems: type.items.map(i => typeToSchema(i, modelMap)) };\n case 'record':\n return { type: 'object', additionalProperties: typeToSchema(type.value, modelMap) };\n case 'enum':\n return { type: 'string', enum: type.values };\n case 'literal':\n return { const: type.value };\n case 'union':\n return { oneOf: type.members.map(m => typeToSchema(m, modelMap)) };\n case 'discriminatedUnion': {\n const oneOf = type.members.map(m => typeToSchema(m, modelMap));\n const mapping: Record<string, string> = {};\n for (const member of type.members) {\n if (member.kind !== 'ref') continue;\n const literalValues = resolveDiscriminatorLiterals(member.name, type.discriminator, modelMap);\n if (literalValues.length === 0) continue;\n for (const v of literalValues) {\n mapping[v] = `#/components/schemas/${member.name}`;\n }\n }\n const result: Record<string, unknown> = {\n oneOf,\n discriminator: { propertyName: type.discriminator },\n };\n if (Object.keys(mapping).length > 0) {\n (result.discriminator as Record<string, unknown>).mapping = mapping;\n }\n return result;\n }\n case 'intersection':\n return { allOf: type.members.map(m => typeToSchema(m, modelMap)) };\n case 'ref':\n return { $ref: `#/components/schemas/${type.name}` };\n case 'inlineObject':\n return inlineObjectToSchema(type.fields, modelMap);\n case 'lazy':\n return typeToSchema(type.inner, modelMap);\n }\n}\n\n/** Resolve literal values of a model's discriminator field. Returns [] if not resolvable. */\nfunction resolveDiscriminatorLiterals(modelName: string, discriminator: string, modelMap?: Map<string, ModelNode>): string[] {\n if (!modelMap) return [];\n const model = modelMap.get(modelName);\n if (!model) return [];\n const field = model.fields.find(f => f.name === discriminator);\n if (!field) return [];\n if (field.type.kind === 'literal') return [String(field.type.value)];\n if (field.type.kind === 'enum') return field.type.values;\n return [];\n}\n\n/**\n * Map a ContractKit scalar type node to its OpenAPI schema object (`{ type, format, ... }`),\n * carrying across constraints like min/max/length.\n *\n * @throws {Error} If the scalar name is not mapped — every member of the closed scalar set must\n * have an explicit case, so an unmapped name signals a scalar was added to core without updating\n * this plugin (rather than silently emitting a type-less, permissive schema).\n */\nexport function scalarToSchema(type: import('@contractkit/core').ScalarTypeNode): Record<string, unknown> {\n const s: Record<string, unknown> = {};\n\n switch (type.name) {\n case 'string':\n s.type = 'string';\n if (type.min !== undefined) s.minLength = Number(type.min);\n if (type.max !== undefined) s.maxLength = Number(type.max);\n if (type.len !== undefined) {\n s.minLength = type.len;\n s.maxLength = type.len;\n }\n if (type.regex) s.pattern = type.regex;\n break;\n case 'number':\n s.type = 'number';\n if (type.min !== undefined) s.minimum = Number(type.min);\n if (type.max !== undefined) s.maximum = Number(type.max);\n break;\n case 'int':\n s.type = 'integer';\n if (type.min !== undefined) s.minimum = Number(type.min);\n if (type.max !== undefined) s.maximum = Number(type.max);\n break;\n case 'bigint':\n s.type = 'integer';\n s.format = 'int64';\n break;\n case 'boolean':\n s.type = 'boolean';\n break;\n case 'date':\n s.type = 'string';\n s.format = 'date';\n break;\n case 'time':\n s.type = 'string';\n s.format = 'time';\n break;\n case 'datetime':\n s.type = 'string';\n s.format = 'date-time';\n break;\n case 'duration':\n s.type = 'string';\n s.format = 'duration';\n break;\n case 'interval':\n s.type = 'string';\n s.format = 'interval';\n break;\n case 'email':\n s.type = 'string';\n s.format = 'email';\n break;\n case 'url':\n s.type = 'string';\n s.format = 'uri';\n break;\n case 'uuid':\n s.type = 'string';\n s.format = 'uuid';\n break;\n case 'unknown':\n // No type constraint\n break;\n case 'null':\n s.type = 'null';\n break;\n case 'object':\n s.type = 'object';\n break;\n case 'binary':\n s.type = 'string';\n s.format = 'binary';\n break;\n case 'json':\n // Any JSON value — no type constraint\n break;\n default: {\n const _exhaustive: never = type.name;\n throw new Error(`plugin-openapi: unmapped scalar '${String(_exhaustive)}' — add a case`);\n }\n }\n\n return s;\n}\n\nfunction arrayToSchema(type: import('@contractkit/core').ArrayTypeNode, modelMap?: Map<string, ModelNode>): Record<string, unknown> {\n const s: Record<string, unknown> = { type: 'array', items: typeToSchema(type.item, modelMap) };\n if (type.min !== undefined) s.minItems = type.min;\n if (type.max !== undefined) s.maxItems = type.max;\n return s;\n}\n\nfunction inlineObjectToSchema(fields: FieldNode[], modelMap?: Map<string, ModelNode>): Record<string, unknown> {\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n\n for (const field of fields) {\n properties[field.name] = fieldToSchema(field, modelMap);\n if (!field.optional) {\n required.push(field.name);\n }\n }\n\n const schema: Record<string, unknown> = { type: 'object', properties };\n if (required.length > 0) schema.required = required;\n return schema;\n}\n\nfunction wrapNullable(schema: Record<string, unknown>): Record<string, unknown> {\n // OpenAPI 3.1 uses JSON Schema nullable via oneOf or type array\n if (schema.$ref) {\n return { oneOf: [schema, { type: 'null' }] };\n }\n if (typeof schema.type === 'string') {\n schema.type = [schema.type, 'null'];\n }\n return schema;\n}\n\n// ─── Operation building ─────────────────────────────────────────────────\n\nfunction buildOperation(route: OpRouteNode, op: OpOperationNode): Record<string, unknown> {\n const operation: Record<string, unknown> = {};\n\n // operationId from service binding or SDK name\n if (op.sdk) {\n operation.operationId = op.sdk;\n } else if (op.service) {\n const methodPart = op.service.split('.').pop();\n if (methodPart) operation.operationId = methodPart;\n }\n\n if (op.description) {\n operation.description = op.description;\n }\n\n // Parameters: path params + query + headers\n const parameters: Record<string, unknown>[] = [];\n\n if (route.params) {\n parameters.push(...paramSourceToParams(route.params, 'path'));\n }\n if (op.query) {\n parameters.push(...paramSourceToParams(op.query, 'query'));\n }\n if (op.headers) {\n parameters.push(...paramSourceToParams(op.headers, 'header'));\n }\n\n if (parameters.length > 0) {\n operation.parameters = parameters;\n }\n\n // Request body\n if (op.request && op.request.bodies.length > 0) {\n const content: Record<string, { schema: ReturnType<typeof typeToSchema> }> = {};\n for (const body of op.request.bodies) {\n content[body.contentType] = { schema: typeToSchema(body.bodyType) };\n }\n operation.requestBody = { required: true, content };\n }\n\n // Effective security (operation-level wins; falls back to route-level)\n // security: none → empty array (explicit public endpoint, overrides global default)\n // security: { fields } → omit operation-level entry (rely on global security from config)\n const effectiveSecurity = resolveSecurity(route, op);\n if (effectiveSecurity === SECURITY_NONE) {\n operation.security = [];\n }\n\n // Responses\n const responses: Record<string, unknown> = {};\n for (const resp of op.responses) {\n const statusKey = String(resp.statusCode);\n const responseObject: Record<string, unknown> = {\n description: statusDescription(resp.statusCode),\n };\n if (resp.bodyType && resp.contentType) {\n responseObject.content = {\n [resp.contentType]: {\n schema: typeToSchema(resp.bodyType),\n },\n };\n }\n if (resp.headers && resp.headers.length > 0) {\n const headers: Record<string, unknown> = {};\n for (const h of resp.headers) {\n const headerObject: Record<string, unknown> = {\n schema: typeToSchema(h.type),\n };\n if (!h.optional) headerObject.required = true;\n if (h.description) headerObject.description = h.description;\n headers[h.name] = headerObject;\n }\n responseObject.headers = headers;\n }\n responses[statusKey] = responseObject;\n }\n\n if (Object.keys(responses).length > 0) {\n operation.responses = responses;\n }\n\n return operation;\n}\n\nfunction paramSourceToParams(source: ParamSource, location: 'path' | 'query' | 'header'): Record<string, unknown>[] {\n if (source.kind === 'ref') {\n // Type reference name used as param source — emit a single $ref\n return [\n {\n name: source.name,\n in: location,\n required: location === 'path',\n schema: { $ref: `#/components/schemas/${source.name}` },\n },\n ];\n }\n\n if (source.kind === 'params') {\n // Inline param declarations\n return source.nodes.map(p => ({\n name: p.name,\n in: location,\n required: location === 'path',\n schema: typeToSchema(p.type),\n }));\n }\n\n // ContractTypeNode (inline object or other type) — if it's an inlineObject, expand fields\n if (source.node.kind === 'inlineObject') {\n return source.node.fields.map(f => ({\n name: f.name,\n in: location,\n required: location === 'path' ? true : !f.optional,\n schema: typeToSchema(f.type),\n }));\n }\n\n // For a ref type used as param source\n if (source.node.kind === 'ref') {\n return [\n {\n name: source.node.name,\n in: location,\n required: location === 'path',\n schema: { $ref: `#/components/schemas/${source.node.name}` },\n },\n ];\n }\n\n return [];\n}\n\nfunction statusDescription(code: number): string {\n const descriptions: Record<number, string> = {\n 200: 'Successful response',\n 201: 'Created',\n 204: 'No content',\n 400: 'Bad request',\n 401: 'Unauthorized',\n 403: 'Forbidden',\n 404: 'Not found',\n 409: 'Conflict',\n 422: 'Unprocessable entity',\n 500: 'Internal server error',\n };\n return descriptions[code] ?? `Response ${code}`;\n}\n\n// ─── YAML serializer ──────────────────────────────────────────────────────\n\n/**\n * Minimal YAML serializer sufficient for OpenAPI documents.\n * Avoids external dependency while producing clean, readable output.\n */\nexport function toYaml(value: unknown, indent = 0): string {\n if (value === null || value === undefined) return 'null';\n if (typeof value === 'boolean') return value ? 'true' : 'false';\n if (typeof value === 'number') return String(value);\n if (typeof value === 'bigint') return String(value);\n\n if (typeof value === 'string') {\n return yamlString(value);\n }\n\n if (Array.isArray(value)) {\n if (value.length === 0) return '[]';\n\n // Check if all items are simple scalars (for inline arrays like enum values, required lists)\n if (value.every(v => typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean')) {\n const items = value.map(v => (typeof v === 'string' ? yamlString(v) : String(v)));\n const inline = `[${items.join(', ')}]`;\n if (inline.length < 80) return inline;\n }\n\n const lines: string[] = [];\n const pad = ' '.repeat(indent);\n for (const item of value) {\n if (isPlainObject(item)) {\n const entries = Object.entries(item as Record<string, unknown>);\n if (entries.length > 0) {\n const [firstKey, firstVal] = entries[0]!;\n const firstValStr = isComplex(firstVal) ? `\\n${toYamlValue(firstVal, indent + 2)}` : ` ${toYaml(firstVal, indent + 2)}`;\n lines.push(`${pad}- ${yamlKey(firstKey)}:${firstValStr}`);\n for (let i = 1; i < entries.length; i++) {\n const [k, v] = entries[i]!;\n const valStr = isComplex(v) ? `\\n${toYamlValue(v, indent + 2)}` : ` ${toYaml(v, indent + 2)}`;\n lines.push(`${pad} ${yamlKey(k)}:${valStr}`);\n }\n } else {\n lines.push(`${pad}- {}`);\n }\n } else {\n lines.push(`${pad}- ${toYaml(item, indent + 1)}`);\n }\n }\n return lines.join('\\n');\n }\n\n if (isPlainObject(value)) {\n const obj = value as Record<string, unknown>;\n const entries = Object.entries(obj);\n if (entries.length === 0) return '{}';\n\n const pad = ' '.repeat(indent);\n const lines: string[] = [];\n for (const [key, val] of entries) {\n if (isComplex(val)) {\n lines.push(`${pad}${yamlKey(key)}:`);\n lines.push(toYamlValue(val, indent + 1));\n } else {\n lines.push(`${pad}${yamlKey(key)}: ${toYaml(val, indent + 1)}`);\n }\n }\n return lines.join('\\n');\n }\n\n return String(value);\n}\n\nfunction toYamlValue(value: unknown, indent: number): string {\n if (Array.isArray(value)) {\n return toYaml(value, indent);\n }\n if (isPlainObject(value)) {\n return toYaml(value, indent);\n }\n return ' '.repeat(indent) + toYaml(value, indent);\n}\n\nfunction isComplex(value: unknown): boolean {\n if (Array.isArray(value)) {\n // Simple scalar arrays can be inlined\n if (value.every(v => typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean')) {\n const items = value.map(v => (typeof v === 'string' ? yamlString(v) : String(v)));\n return `[${items.join(', ')}]`.length >= 80;\n }\n return true;\n }\n return isPlainObject(value);\n}\n\nfunction isPlainObject(value: unknown): boolean {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction yamlString(s: string): string {\n // Use plain style if safe, otherwise single-quoted\n if (s === '') return \"''\";\n if (/^[\\w./-]+$/.test(s) && !/^(true|false|null|yes|no|on|off)$/i.test(s) && !/^\\d/.test(s)) {\n return s;\n }\n // Single-quote, escaping internal single quotes by doubling\n return `'${s.replace(/'/g, \"''\")}'`;\n}\n\nfunction yamlKey(key: string): string {\n // Keys with special chars need quoting\n if (/^[\\w-]+$/.test(key) && !/^(true|false|null|yes|no|on|off)$/i.test(key)) {\n return key;\n }\n return `'${key.replace(/'/g, \"''\")}'`;\n}\n"],"mappings":";;;;AAAA,SAASA,eAAe;;;ACUxB,SAASC,kBAAkBC,iBAAiBC,qBAAqB;AAuCjE,SAASC,oBAAoBC,MAAwBC,KAAgB;AACjE,UAAQD,KAAKE,MAAI;IACb,KAAK;AACDD,UAAIE,IAAIH,KAAKI,IAAI;AACjB;IACJ,KAAK;AACDL,0BAAoBC,KAAKK,MAAMJ,GAAAA;AAC/B;IACJ,KAAK;AACD,iBAAWI,QAAQL,KAAKM,MAAOP,qBAAoBM,MAAMJ,GAAAA;AACzD;IACJ,KAAK;AACDF,0BAAoBC,KAAKO,OAAON,GAAAA;AAChC;IACJ,KAAK;IACL,KAAK;IACL,KAAK;AACD,iBAAWO,UAAUR,KAAKS,QAASV,qBAAoBS,QAAQP,GAAAA;AAC/D;IACJ,KAAK;AACDF,0BAAoBC,KAAKU,OAAOT,GAAAA;AAChC;IACJ,KAAK;AACD,iBAAWU,SAASX,KAAKY,OAAQb,qBAAoBY,MAAMX,MAAMC,GAAAA;AACjE;EACR;AACJ;AA1BSF;AA4BT,SAASc,uBAAuBC,QAAiCb,KAAgB;AAC7E,MAAI,CAACa,OAAQ;AACb,MAAIA,OAAOZ,SAAS,OAAO;AACvBD,QAAIE,IAAIW,OAAOV,IAAI;AACnB;EACJ;AACA,MAAIU,OAAOZ,SAAS,UAAU;AAC1B,eAAWa,KAAKD,OAAOE,MAAOjB,qBAAoBgB,EAAEf,MAAMC,GAAAA;AAC1D;EACJ;AACAF,sBAAoBe,OAAOG,MAAMhB,GAAAA;AACrC;AAXSY;AAcT,SAASK,sBAAsBC,SAAuBC,kBAAkB,OAAK;AACzE,QAAMC,OAAO,oBAAIC,IAAAA;AACjB,aAAWC,UAAUJ,SAAS;AAC1B,eAAWK,SAASD,OAAOE,QAAQ;AAC/B,iBAAWC,MAAMF,MAAMG,YAAY;AAC/B,YAAI,CAACP,mBAAmBQ,iBAAiBJ,OAAOE,EAAAA,EAAIG,SAAS,UAAA,EAAa;AAC1E,YAAIH,GAAGI,SAAS;AACZ,qBAAWC,QAAQL,GAAGI,QAAQE,OAAQjC,qBAAoBgC,KAAKE,UAAUZ,IAAAA;QAC7E;AACA,mBAAWa,QAAQR,GAAGS,WAAW;AAC7B,cAAID,KAAKD,SAAUlC,qBAAoBmC,KAAKD,UAAUZ,IAAAA;AACtD,cAAIa,KAAKE,SAAS;AACd,uBAAWC,KAAKH,KAAKE,QAASrC,qBAAoBsC,EAAErC,MAAMqB,IAAAA;UAC9D;QACJ;AACAR,+BAAuBW,MAAMc,QAAQjB,IAAAA;AACrCR,+BAAuBa,GAAGa,OAAOlB,IAAAA;AACjCR,+BAAuBa,GAAGU,SAASf,IAAAA;MACvC;IACJ;EACJ;AACA,SAAOA;AACX;AAtBSH;AAyBT,SAASsB,wBAAwBC,OAAoBC,UAAgC;AACjF,QAAMC,YAAY,IAAIrB,IAAYmB,KAAAA;AAClC,QAAMG,WAAW;OAAIH;;AACrB,SAAOG,SAASC,SAAS,GAAG;AACxB,UAAMzC,OAAOwC,SAASE,IAAG;AACzB,UAAMC,QAAQL,SAASM,IAAI5C,IAAAA;AAC3B,QAAI,CAAC2C,MAAO;AACZ,UAAM1B,OAAO,oBAAIC,IAAAA;AACjB,QAAIyB,MAAM/C,KAAMD,qBAAoBgD,MAAM/C,MAAMqB,IAAAA;AAChD,eAAWV,SAASoC,MAAMnC,OAAQb,qBAAoBY,MAAMX,MAAMqB,IAAAA;AAClE,QAAI0B,MAAME,MAAO,YAAWC,KAAKH,MAAME,MAAO5B,MAAKlB,IAAI+C,CAAAA;AACvD,eAAWC,OAAO9B,MAAM;AACpB,UAAI,CAACsB,UAAUS,IAAID,GAAAA,GAAM;AACrBR,kBAAUxC,IAAIgD,GAAAA;AACdP,iBAASS,KAAKF,GAAAA;MAClB;IACJ;EACJ;AACA,SAAOR;AACX;AAnBSH;AAwCF,SAASc,gBAAgBC,KAA0B;AACtD,QAAM,EAAEC,eAAerC,SAASsC,QAAQC,gBAAe,IAAKH;AAC5D,QAAMnC,kBAAkBqC,OAAOrC,mBAAmB;AAElD,QAAMuC,MAA+B;IACjCC,SAAS;IACTC,MAAM;MACFC,OAAOL,OAAOI,MAAMC,SAAS;MAC7BC,SAASN,OAAOI,MAAME,WAAW;MACjC,GAAIN,OAAOI,MAAMG,cAAc;QAAEA,aAAaP,OAAOI,KAAKG;MAAY,IAAI,CAAC;IAC/E;EACJ;AAEA,MAAIP,OAAOQ,WAAWR,OAAOQ,QAAQpB,SAAS,GAAG;AAC7Cc,QAAIM,UAAUR,OAAOQ;EACzB;AAEA,MAAIR,OAAOS,YAAYT,OAAOS,SAASrB,SAAS,GAAG;AAC/Cc,QAAIO,WAAWT,OAAOS;EAC1B;AAGA,QAAMC,aAAsC,CAAC;AAC7C,QAAMzB,WAAW,oBAAI0B,IAAAA;AAErB,aAAWC,gBAAgBb,eAAe;AACtC,eAAWT,SAASsB,aAAaC,QAAQ;AACrC5B,eAAS6B,IAAIxB,MAAM3C,MAAM2C,KAAAA;IAC7B;EACJ;AACA,aAAWsB,gBAAgBb,eAAe;AACtC,eAAWT,SAASsB,aAAaC,QAAQ;AACrCH,iBAAWpB,MAAM3C,IAAI,IAAIoE,cAAczB,OAAOL,QAAAA;IAClD;EACJ;AAGA,QAAM+B,QAAiD,CAAC;AAExD,aAAWlD,UAAUJ,SAAS;AAC1B,eAAWK,SAASD,OAAOE,QAAQ;AAC/B,YAAMiD,SAASC,YAAYnD,MAAMoD,IAAI;AAErC,iBAAWlD,MAAMF,MAAMG,YAAY;AAC/B,cAAMkD,OAAOjD,iBAAiBJ,OAAOE,EAAAA;AACrC,YAAI,CAACN,mBAAmByD,KAAKhD,SAAS,UAAA,EAAa;AAGnD,YAAI,CAAC4C,MAAMC,MAAAA,EAASD,OAAMC,MAAAA,IAAU,CAAC;AACrC,cAAMI,YAAYC,eAAevD,OAAOE,EAAAA;AACxC,YAAImD,KAAKhD,SAAS,YAAA,EAAgBiD,WAAsCE,aAAa;AACrFP,cAAMC,MAAAA,EAAQhD,GAAGuD,MAAM,IAAIH;MAC/B;IACJ;EACJ;AAEAnB,MAAIc,QAAQA;AAIZ,QAAMS,UACF/D,QAAQ0B,SAAS,KACV,MAAA;AACG,UAAMF,YAAYH,wBAAwBtB,sBAAsBC,SAASC,eAAAA,GAAkBsB,QAAAA;AAC3F,UAAMyC,WAAoC,CAAC;AAC3C,eAAW,CAAC/E,MAAMgF,MAAAA,KAAWC,OAAOC,QAAQnB,UAAAA,GAAa;AACrD,UAAIxB,UAAUS,IAAIhD,IAAAA,EAAO+E,UAAS/E,IAAAA,IAAQgF;IAC9C;AACA,WAAOD;EACX,GAAA,IACAhB;AAEV,QAAMoB,aAAsC,CAAC;AAC7C,MAAIF,OAAOG,KAAKN,OAAAA,EAASrC,SAAS,GAAG;AACjC0C,eAAWL,UAAUA;EACzB;AACA,MAAIxB,mBAAmB2B,OAAOG,KAAK9B,eAAAA,EAAiBb,SAAS,GAAG;AAC5D0C,eAAW7B,kBAAkBA;EACjC;AACA,MAAI2B,OAAOG,KAAKD,UAAAA,EAAY1C,SAAS,GAAG;AACpCc,QAAI4B,aAAaA;EACrB;AAEA,SAAOE,OAAO9B,GAAAA;AAClB;AApFgBL;AAyFhB,SAASqB,YAAYC,MAAY;AAC7B,SAAOA;AACX;AAFSD;AAMT,SAASH,cAAczB,OAAkBL,UAAiC;AAEtE,MAAIK,MAAM/C,MAAM;AACZ,UAAMoF,UAASM,aAAa3C,MAAM/C,MAAM0C,QAAAA;AACxC,QAAIK,MAAMiB,YAAaoB,CAAAA,QAAOpB,cAAcjB,MAAMiB;AAClD,WAAOoB;EACX;AAEA,QAAMO,aAAsC,CAAC;AAC7C,QAAMC,WAAqB,CAAA;AAE3B,aAAWjF,SAASoC,MAAMnC,QAAQ;AAC9B,UAAMiF,OAAOC,cAAcnF,OAAO+B,QAAAA;AAClCiD,eAAWhF,MAAMP,IAAI,IAAIyF;AACzB,QAAI,CAAClF,MAAMoF,UAAU;AACjBH,eAASvC,KAAK1C,MAAMP,IAAI;IAC5B;EACJ;AAEA,QAAMgF,SAAkC;IACpCpF,MAAM;IACN2F;EACJ;AAEA,MAAIC,SAAS/C,SAAS,GAAG;AACrBuC,WAAOQ,WAAWA;EACtB;AAEA,MAAI7C,MAAME,SAASF,MAAME,MAAMJ,SAAS,GAAG;AACvC,WAAO;MACHmD,OAAO;WAAIjD,MAAME,MAAMgD,IAAI/C,CAAAA,OAAM;UAAEgD,MAAM,wBAAwBhD,CAAAA;QAAI,EAAA;QAAKkC;;IAC9E;EACJ;AAEA,MAAIrC,MAAMiB,aAAa;AACnBoB,WAAOpB,cAAcjB,MAAMiB;EAC/B;AACA,MAAIjB,MAAMiC,YAAY;AAClBI,WAAOJ,aAAa;EACxB;AAEA,SAAOI;AACX;AA1CSZ;AA4CT,SAASsB,cAAcnF,OAAkB+B,UAAiC;AACtE,MAAI0C,SAASM,aAAa/E,MAAMX,MAAM0C,QAAAA;AAEtC,MAAI/B,MAAMwF,UAAU;AAChBf,aAASgB,aAAahB,MAAAA;EAC1B;AACA,MAAIzE,MAAM0F,eAAe,YAAY;AACjCjB,WAAOkB,WAAW;EACtB,WAAW3F,MAAM0F,eAAe,aAAa;AACzCjB,WAAOmB,YAAY;EACvB;AACA,MAAI5F,MAAM6F,YAAYC,QAAW;AAC7BrB,WAAOoB,UAAU7F,MAAM6F;EAC3B;AACA,MAAI7F,MAAMqD,aAAa;AACnBoB,WAAOpB,cAAcrD,MAAMqD;EAC/B;AACA,MAAIrD,MAAMqE,YAAY;AAClBI,WAAOJ,aAAa;EACxB;AAEA,SAAOI;AACX;AAtBSU;AAwBT,SAASJ,aAAa1F,MAAwB0C,UAAiC;AAC3E,UAAQ1C,KAAKE,MAAI;IACb,KAAK;AACD,aAAOwG,eAAe1G,IAAAA;IAC1B,KAAK;AACD,aAAO2G,cAAc3G,MAAM0C,QAAAA;IAC/B,KAAK;AACD,aAAO;QAAE1C,MAAM;QAAS4G,aAAa5G,KAAKM,MAAM2F,IAAIY,CAAAA,MAAKnB,aAAamB,GAAGnE,QAAAA,CAAAA;MAAW;IACxF,KAAK;AACD,aAAO;QAAE1C,MAAM;QAAU8G,sBAAsBpB,aAAa1F,KAAKO,OAAOmC,QAAAA;MAAU;IACtF,KAAK;AACD,aAAO;QAAE1C,MAAM;QAAU+G,MAAM/G,KAAKgH;MAAO;IAC/C,KAAK;AACD,aAAO;QAAEC,OAAOjH,KAAKO;MAAM;IAC/B,KAAK;AACD,aAAO;QAAE2G,OAAOlH,KAAKS,QAAQwF,IAAIkB,CAAAA,MAAKzB,aAAayB,GAAGzE,QAAAA,CAAAA;MAAW;IACrE,KAAK,sBAAsB;AACvB,YAAMwE,QAAQlH,KAAKS,QAAQwF,IAAIkB,CAAAA,MAAKzB,aAAayB,GAAGzE,QAAAA,CAAAA;AACpD,YAAM0E,UAAkC,CAAC;AACzC,iBAAW5G,UAAUR,KAAKS,SAAS;AAC/B,YAAID,OAAON,SAAS,MAAO;AAC3B,cAAMmH,gBAAgBC,6BAA6B9G,OAAOJ,MAAMJ,KAAKuH,eAAe7E,QAAAA;AACpF,YAAI2E,cAAcxE,WAAW,EAAG;AAChC,mBAAW2E,KAAKH,eAAe;AAC3BD,kBAAQI,CAAAA,IAAK,wBAAwBhH,OAAOJ,IAAI;QACpD;MACJ;AACA,YAAMqH,SAAkC;QACpCP;QACAK,eAAe;UAAEG,cAAc1H,KAAKuH;QAAc;MACtD;AACA,UAAIlC,OAAOG,KAAK4B,OAAAA,EAASvE,SAAS,GAAG;AAChC4E,eAAOF,cAA0CH,UAAUA;MAChE;AACA,aAAOK;IACX;IACA,KAAK;AACD,aAAO;QAAEzB,OAAOhG,KAAKS,QAAQwF,IAAIkB,CAAAA,MAAKzB,aAAayB,GAAGzE,QAAAA,CAAAA;MAAW;IACrE,KAAK;AACD,aAAO;QAAEwD,MAAM,wBAAwBlG,KAAKI,IAAI;MAAG;IACvD,KAAK;AACD,aAAOuH,qBAAqB3H,KAAKY,QAAQ8B,QAAAA;IAC7C,KAAK;AACD,aAAOgD,aAAa1F,KAAKU,OAAOgC,QAAAA;EACxC;AACJ;AA7CSgD;AAgDT,SAAS4B,6BAA6BM,WAAmBL,eAAuB7E,UAAiC;AAC7G,MAAI,CAACA,SAAU,QAAO,CAAA;AACtB,QAAMK,QAAQL,SAASM,IAAI4E,SAAAA;AAC3B,MAAI,CAAC7E,MAAO,QAAO,CAAA;AACnB,QAAMpC,QAAQoC,MAAMnC,OAAOiH,KAAKC,CAAAA,MAAKA,EAAE1H,SAASmH,aAAAA;AAChD,MAAI,CAAC5G,MAAO,QAAO,CAAA;AACnB,MAAIA,MAAMX,KAAKE,SAAS,UAAW,QAAO;IAAC6H,OAAOpH,MAAMX,KAAKO,KAAK;;AAClE,MAAII,MAAMX,KAAKE,SAAS,OAAQ,QAAOS,MAAMX,KAAKgH;AAClD,SAAO,CAAA;AACX;AATSM;AAmBF,SAASZ,eAAe1G,MAAgD;AAC3E,QAAMgI,IAA6B,CAAC;AAEpC,UAAQhI,KAAKI,MAAI;IACb,KAAK;AACD4H,QAAEhI,OAAO;AACT,UAAIA,KAAKiI,QAAQxB,OAAWuB,GAAEE,YAAYC,OAAOnI,KAAKiI,GAAG;AACzD,UAAIjI,KAAKoI,QAAQ3B,OAAWuB,GAAEK,YAAYF,OAAOnI,KAAKoI,GAAG;AACzD,UAAIpI,KAAKsI,QAAQ7B,QAAW;AACxBuB,UAAEE,YAAYlI,KAAKsI;AACnBN,UAAEK,YAAYrI,KAAKsI;MACvB;AACA,UAAItI,KAAKuI,MAAOP,GAAEQ,UAAUxI,KAAKuI;AACjC;IACJ,KAAK;AACDP,QAAEhI,OAAO;AACT,UAAIA,KAAKiI,QAAQxB,OAAWuB,GAAES,UAAUN,OAAOnI,KAAKiI,GAAG;AACvD,UAAIjI,KAAKoI,QAAQ3B,OAAWuB,GAAEU,UAAUP,OAAOnI,KAAKoI,GAAG;AACvD;IACJ,KAAK;AACDJ,QAAEhI,OAAO;AACT,UAAIA,KAAKiI,QAAQxB,OAAWuB,GAAES,UAAUN,OAAOnI,KAAKiI,GAAG;AACvD,UAAIjI,KAAKoI,QAAQ3B,OAAWuB,GAAEU,UAAUP,OAAOnI,KAAKoI,GAAG;AACvD;IACJ,KAAK;AACDJ,QAAEhI,OAAO;AACTgI,QAAEW,SAAS;AACX;IACJ,KAAK;AACDX,QAAEhI,OAAO;AACT;IACJ,KAAK;AACDgI,QAAEhI,OAAO;AACTgI,QAAEW,SAAS;AACX;IACJ,KAAK;AACDX,QAAEhI,OAAO;AACTgI,QAAEW,SAAS;AACX;IACJ,KAAK;AACDX,QAAEhI,OAAO;AACTgI,QAAEW,SAAS;AACX;IACJ,KAAK;AACDX,QAAEhI,OAAO;AACTgI,QAAEW,SAAS;AACX;IACJ,KAAK;AACDX,QAAEhI,OAAO;AACTgI,QAAEW,SAAS;AACX;IACJ,KAAK;AACDX,QAAEhI,OAAO;AACTgI,QAAEW,SAAS;AACX;IACJ,KAAK;AACDX,QAAEhI,OAAO;AACTgI,QAAEW,SAAS;AACX;IACJ,KAAK;AACDX,QAAEhI,OAAO;AACTgI,QAAEW,SAAS;AACX;IACJ,KAAK;AAED;IACJ,KAAK;AACDX,QAAEhI,OAAO;AACT;IACJ,KAAK;AACDgI,QAAEhI,OAAO;AACT;IACJ,KAAK;AACDgI,QAAEhI,OAAO;AACTgI,QAAEW,SAAS;AACX;IACJ,KAAK;AAED;IACJ,SAAS;AACL,YAAMC,cAAqB5I,KAAKI;AAChC,YAAM,IAAIyI,MAAM,oCAAoCd,OAAOa,WAAAA,CAAAA,qBAA4B;IAC3F;EACJ;AAEA,SAAOZ;AACX;AAtFgBtB;AAwFhB,SAASC,cAAc3G,MAAiD0C,UAAiC;AACrG,QAAMsF,IAA6B;IAAEhI,MAAM;IAASM,OAAOoF,aAAa1F,KAAKK,MAAMqC,QAAAA;EAAU;AAC7F,MAAI1C,KAAKiI,QAAQxB,OAAWuB,GAAEc,WAAW9I,KAAKiI;AAC9C,MAAIjI,KAAKoI,QAAQ3B,OAAWuB,GAAEe,WAAW/I,KAAKoI;AAC9C,SAAOJ;AACX;AALSrB;AAOT,SAASgB,qBAAqB/G,QAAqB8B,UAAiC;AAChF,QAAMiD,aAAsC,CAAC;AAC7C,QAAMC,WAAqB,CAAA;AAE3B,aAAWjF,SAASC,QAAQ;AACxB+E,eAAWhF,MAAMP,IAAI,IAAI0F,cAAcnF,OAAO+B,QAAAA;AAC9C,QAAI,CAAC/B,MAAMoF,UAAU;AACjBH,eAASvC,KAAK1C,MAAMP,IAAI;IAC5B;EACJ;AAEA,QAAMgF,SAAkC;IAAEpF,MAAM;IAAU2F;EAAW;AACrE,MAAIC,SAAS/C,SAAS,EAAGuC,QAAOQ,WAAWA;AAC3C,SAAOR;AACX;AAdSuC;AAgBT,SAASvB,aAAahB,QAA+B;AAEjD,MAAIA,OAAOc,MAAM;AACb,WAAO;MAAEgB,OAAO;QAAC9B;QAAQ;UAAEpF,MAAM;QAAO;;IAAG;EAC/C;AACA,MAAI,OAAOoF,OAAOpF,SAAS,UAAU;AACjCoF,WAAOpF,OAAO;MAACoF,OAAOpF;MAAM;;EAChC;AACA,SAAOoF;AACX;AATSgB;AAaT,SAASrB,eAAevD,OAAoBE,IAAmB;AAC3D,QAAMoD,YAAqC,CAAC;AAG5C,MAAIpD,GAAGsH,KAAK;AACRlE,cAAUmE,cAAcvH,GAAGsH;EAC/B,WAAWtH,GAAGwH,SAAS;AACnB,UAAMC,aAAazH,GAAGwH,QAAQE,MAAM,GAAA,EAAKtG,IAAG;AAC5C,QAAIqG,WAAYrE,WAAUmE,cAAcE;EAC5C;AAEA,MAAIzH,GAAGsC,aAAa;AAChBc,cAAUd,cAActC,GAAGsC;EAC/B;AAGA,QAAMqF,aAAwC,CAAA;AAE9C,MAAI7H,MAAMc,QAAQ;AACd+G,eAAWhG,KAAI,GAAIiG,oBAAoB9H,MAAMc,QAAQ,MAAA,CAAA;EACzD;AACA,MAAIZ,GAAGa,OAAO;AACV8G,eAAWhG,KAAI,GAAIiG,oBAAoB5H,GAAGa,OAAO,OAAA,CAAA;EACrD;AACA,MAAIb,GAAGU,SAAS;AACZiH,eAAWhG,KAAI,GAAIiG,oBAAoB5H,GAAGU,SAAS,QAAA,CAAA;EACvD;AAEA,MAAIiH,WAAWxG,SAAS,GAAG;AACvBiC,cAAUuE,aAAaA;EAC3B;AAGA,MAAI3H,GAAGI,WAAWJ,GAAGI,QAAQE,OAAOa,SAAS,GAAG;AAC5C,UAAM0G,UAAuE,CAAC;AAC9E,eAAWxH,QAAQL,GAAGI,QAAQE,QAAQ;AAClCuH,cAAQxH,KAAKyH,WAAW,IAAI;QAAEpE,QAAQM,aAAa3D,KAAKE,QAAQ;MAAE;IACtE;AACA6C,cAAU2E,cAAc;MAAE7D,UAAU;MAAM2D;IAAQ;EACtD;AAKA,QAAMG,oBAAoBC,gBAAgBnI,OAAOE,EAAAA;AACjD,MAAIgI,sBAAsBE,eAAe;AACrC9E,cAAUZ,WAAW,CAAA;EACzB;AAGA,QAAM/B,YAAqC,CAAC;AAC5C,aAAWD,QAAQR,GAAGS,WAAW;AAC7B,UAAM0H,YAAY9B,OAAO7F,KAAK4H,UAAU;AACxC,UAAMC,iBAA0C;MAC5C/F,aAAagG,kBAAkB9H,KAAK4H,UAAU;IAClD;AACA,QAAI5H,KAAKD,YAAYC,KAAKsH,aAAa;AACnCO,qBAAeR,UAAU;QACrB,CAACrH,KAAKsH,WAAW,GAAG;UAChBpE,QAAQM,aAAaxD,KAAKD,QAAQ;QACtC;MACJ;IACJ;AACA,QAAIC,KAAKE,WAAWF,KAAKE,QAAQS,SAAS,GAAG;AACzC,YAAMT,UAAmC,CAAC;AAC1C,iBAAWC,KAAKH,KAAKE,SAAS;AAC1B,cAAM6H,eAAwC;UAC1C7E,QAAQM,aAAarD,EAAErC,IAAI;QAC/B;AACA,YAAI,CAACqC,EAAE0D,SAAUkE,cAAarE,WAAW;AACzC,YAAIvD,EAAE2B,YAAaiG,cAAajG,cAAc3B,EAAE2B;AAChD5B,gBAAQC,EAAEjC,IAAI,IAAI6J;MACtB;AACAF,qBAAe3H,UAAUA;IAC7B;AACAD,cAAU0H,SAAAA,IAAaE;EAC3B;AAEA,MAAI1E,OAAOG,KAAKrD,SAAAA,EAAWU,SAAS,GAAG;AACnCiC,cAAU3C,YAAYA;EAC1B;AAEA,SAAO2C;AACX;AAnFSC;AAqFT,SAASuE,oBAAoBxI,QAAqBoJ,UAAqC;AACnF,MAAIpJ,OAAOZ,SAAS,OAAO;AAEvB,WAAO;MACH;QACIE,MAAMU,OAAOV;QACb+J,IAAID;QACJtE,UAAUsE,aAAa;QACvB9E,QAAQ;UAAEc,MAAM,wBAAwBpF,OAAOV,IAAI;QAAG;MAC1D;;EAER;AAEA,MAAIU,OAAOZ,SAAS,UAAU;AAE1B,WAAOY,OAAOE,MAAMiF,IAAIlF,CAAAA,OAAM;MAC1BX,MAAMW,EAAEX;MACR+J,IAAID;MACJtE,UAAUsE,aAAa;MACvB9E,QAAQM,aAAa3E,EAAEf,IAAI;IAC/B,EAAA;EACJ;AAGA,MAAIc,OAAOG,KAAKf,SAAS,gBAAgB;AACrC,WAAOY,OAAOG,KAAKL,OAAOqF,IAAI6B,CAAAA,OAAM;MAChC1H,MAAM0H,EAAE1H;MACR+J,IAAID;MACJtE,UAAUsE,aAAa,SAAS,OAAO,CAACpC,EAAE/B;MAC1CX,QAAQM,aAAaoC,EAAE9H,IAAI;IAC/B,EAAA;EACJ;AAGA,MAAIc,OAAOG,KAAKf,SAAS,OAAO;AAC5B,WAAO;MACH;QACIE,MAAMU,OAAOG,KAAKb;QAClB+J,IAAID;QACJtE,UAAUsE,aAAa;QACvB9E,QAAQ;UAAEc,MAAM,wBAAwBpF,OAAOG,KAAKb,IAAI;QAAG;MAC/D;;EAER;AAEA,SAAO,CAAA;AACX;AA9CSkJ;AAgDT,SAASU,kBAAkBI,MAAY;AACnC,QAAMC,eAAuC;IACzC,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;EACT;AACA,SAAOA,aAAaD,IAAAA,KAAS,YAAYA,IAAAA;AAC7C;AAdSJ;AAsBF,SAASvE,OAAOlF,OAAgB+J,SAAS,GAAC;AAC7C,MAAI/J,UAAU,QAAQA,UAAUkG,OAAW,QAAO;AAClD,MAAI,OAAOlG,UAAU,UAAW,QAAOA,QAAQ,SAAS;AACxD,MAAI,OAAOA,UAAU,SAAU,QAAOwH,OAAOxH,KAAAA;AAC7C,MAAI,OAAOA,UAAU,SAAU,QAAOwH,OAAOxH,KAAAA;AAE7C,MAAI,OAAOA,UAAU,UAAU;AAC3B,WAAOgK,WAAWhK,KAAAA;EACtB;AAEA,MAAIiK,MAAMC,QAAQlK,KAAAA,GAAQ;AACtB,QAAIA,MAAMsC,WAAW,EAAG,QAAO;AAG/B,QAAItC,MAAMmK,MAAMlD,CAAAA,MAAK,OAAOA,MAAM,YAAY,OAAOA,MAAM,YAAY,OAAOA,MAAM,SAAA,GAAY;AAC5F,YAAMlH,QAAQC,MAAM0F,IAAIuB,CAAAA,MAAM,OAAOA,MAAM,WAAW+C,WAAW/C,CAAAA,IAAKO,OAAOP,CAAAA,CAAAA;AAC7E,YAAMmD,SAAS,IAAIrK,MAAMsK,KAAK,IAAA,CAAA;AAC9B,UAAID,OAAO9H,SAAS,GAAI,QAAO8H;IACnC;AAEA,UAAME,QAAkB,CAAA;AACxB,UAAMC,MAAM,KAAKC,OAAOT,MAAAA;AACxB,eAAWjK,QAAQE,OAAO;AACtB,UAAIyK,cAAc3K,IAAAA,GAAO;AACrB,cAAMiF,UAAUD,OAAOC,QAAQjF,IAAAA;AAC/B,YAAIiF,QAAQzC,SAAS,GAAG;AACpB,gBAAM,CAACoI,UAAUC,QAAAA,IAAY5F,QAAQ,CAAA;AACrC,gBAAM6F,cAAcC,UAAUF,QAAAA,IAAY;EAAKG,YAAYH,UAAUZ,SAAS,CAAA,CAAA,KAAO,IAAI7E,OAAOyF,UAAUZ,SAAS,CAAA,CAAA;AACnHO,gBAAMxH,KAAK,GAAGyH,GAAAA,KAAQQ,QAAQL,QAAAA,CAAAA,IAAaE,WAAAA,EAAa;AACxD,mBAAStE,IAAI,GAAGA,IAAIvB,QAAQzC,QAAQgE,KAAK;AACrC,kBAAM,CAAC0E,GAAG/D,CAAAA,IAAKlC,QAAQuB,CAAAA;AACvB,kBAAM2E,SAASJ,UAAU5D,CAAAA,IAAK;EAAK6D,YAAY7D,GAAG8C,SAAS,CAAA,CAAA,KAAO,IAAI7E,OAAO+B,GAAG8C,SAAS,CAAA,CAAA;AACzFO,kBAAMxH,KAAK,GAAGyH,GAAAA,KAAQQ,QAAQC,CAAAA,CAAAA,IAAMC,MAAAA,EAAQ;UAChD;QACJ,OAAO;AACHX,gBAAMxH,KAAK,GAAGyH,GAAAA,MAAS;QAC3B;MACJ,OAAO;AACHD,cAAMxH,KAAK,GAAGyH,GAAAA,KAAQrF,OAAOpF,MAAMiK,SAAS,CAAA,CAAA,EAAI;MACpD;IACJ;AACA,WAAOO,MAAMD,KAAK,IAAA;EACtB;AAEA,MAAII,cAAczK,KAAAA,GAAQ;AACtB,UAAMkL,MAAMlL;AACZ,UAAM+E,UAAUD,OAAOC,QAAQmG,GAAAA;AAC/B,QAAInG,QAAQzC,WAAW,EAAG,QAAO;AAEjC,UAAMiI,MAAM,KAAKC,OAAOT,MAAAA;AACxB,UAAMO,QAAkB,CAAA;AACxB,eAAW,CAACa,KAAKC,GAAAA,KAAQrG,SAAS;AAC9B,UAAI8F,UAAUO,GAAAA,GAAM;AAChBd,cAAMxH,KAAK,GAAGyH,GAAAA,GAAMQ,QAAQI,GAAAA,CAAAA,GAAO;AACnCb,cAAMxH,KAAKgI,YAAYM,KAAKrB,SAAS,CAAA,CAAA;MACzC,OAAO;AACHO,cAAMxH,KAAK,GAAGyH,GAAAA,GAAMQ,QAAQI,GAAAA,CAAAA,KAASjG,OAAOkG,KAAKrB,SAAS,CAAA,CAAA,EAAI;MAClE;IACJ;AACA,WAAOO,MAAMD,KAAK,IAAA;EACtB;AAEA,SAAO7C,OAAOxH,KAAAA;AAClB;AA/DgBkF;AAiEhB,SAAS4F,YAAY9K,OAAgB+J,QAAc;AAC/C,MAAIE,MAAMC,QAAQlK,KAAAA,GAAQ;AACtB,WAAOkF,OAAOlF,OAAO+J,MAAAA;EACzB;AACA,MAAIU,cAAczK,KAAAA,GAAQ;AACtB,WAAOkF,OAAOlF,OAAO+J,MAAAA;EACzB;AACA,SAAO,KAAKS,OAAOT,MAAAA,IAAU7E,OAAOlF,OAAO+J,MAAAA;AAC/C;AARSe;AAUT,SAASD,UAAU7K,OAAc;AAC7B,MAAIiK,MAAMC,QAAQlK,KAAAA,GAAQ;AAEtB,QAAIA,MAAMmK,MAAMlD,CAAAA,MAAK,OAAOA,MAAM,YAAY,OAAOA,MAAM,YAAY,OAAOA,MAAM,SAAA,GAAY;AAC5F,YAAMlH,QAAQC,MAAM0F,IAAIuB,CAAAA,MAAM,OAAOA,MAAM,WAAW+C,WAAW/C,CAAAA,IAAKO,OAAOP,CAAAA,CAAAA;AAC7E,aAAO,IAAIlH,MAAMsK,KAAK,IAAA,CAAA,IAAS/H,UAAU;IAC7C;AACA,WAAO;EACX;AACA,SAAOmI,cAAczK,KAAAA;AACzB;AAVS6K;AAYT,SAASJ,cAAczK,OAAc;AACjC,SAAO,OAAOA,UAAU,YAAYA,UAAU,QAAQ,CAACiK,MAAMC,QAAQlK,KAAAA;AACzE;AAFSyK;AAIT,SAAST,WAAWvC,GAAS;AAEzB,MAAIA,MAAM,GAAI,QAAO;AACrB,MAAI,aAAa4D,KAAK5D,CAAAA,KAAM,CAAC,qCAAqC4D,KAAK5D,CAAAA,KAAM,CAAC,MAAM4D,KAAK5D,CAAAA,GAAI;AACzF,WAAOA;EACX;AAEA,SAAO,IAAIA,EAAE6D,QAAQ,MAAM,IAAA,CAAA;AAC/B;AARStB;AAUT,SAASe,QAAQI,KAAW;AAExB,MAAI,WAAWE,KAAKF,GAAAA,KAAQ,CAAC,qCAAqCE,KAAKF,GAAAA,GAAM;AACzE,WAAOA;EACX;AACA,SAAO,IAAIA,IAAIG,QAAQ,MAAM,IAAA,CAAA;AACjC;AANSP;;;ADlvBT,IAAMQ,SAA4B;EAC9BC,MAAM;EACNC,UAAU;EACV,MAAMC,gBAAgB,EAAEC,eAAeC,QAAO,GAAIC,KAAG;AACjD,UAAM,EAAEC,iBAAiB,GAAGC,cAAAA,IAAkBF,IAAIG;AAClD,UAAMC,OAAOF,cAAcG,UAAUC,QAAQN,IAAIO,SAASL,cAAcG,OAAO,IAAIL,IAAIO;AACvF,UAAMC,UAAUF,QAAQF,MAAMF,cAAcO,UAAU,cAAA;AACtDT,QAAIU,SAASF,SAASG,gBAAgB;MAAEb;MAAeC;MAASa,QAAQV;MAAeD;IAAgB,CAAA,CAAA;EAC3G;AACJ;AAEA,IAAA,gBAAeP;AAIR,SAASmB,oBACZX,eACAK,SACAN,iBAAuD;AAEvD,SAAO;IACHN,MAAM;IACNC,UAAU,WAAWkB,KAAKC,UAAUb,aAAAA,CAAAA;IACpC,MAAML,gBAAgB,EAAEC,eAAeC,QAAO,GAAIC,KAAG;AACjD,YAAMI,OAAOF,cAAcG,UAAUC,QAAQC,SAASL,cAAcG,OAAO,IAAIE;AAC/E,YAAMC,UAAUF,QAAQF,MAAMF,cAAcO,UAAU,cAAA;AACtD,YAAMO,UAAUL,gBAAgB;QAAEb;QAAeC;QAASa,QAAQV;QAAeD;MAAgB,CAAA;AACjGD,UAAIU,SAASF,SAASQ,OAAAA;IAC1B;EACJ;AACJ;AAfgBH;","names":["resolve","resolveModifiers","resolveSecurity","SECURITY_NONE","collectRefsFromType","type","out","kind","add","name","item","items","value","member","members","inner","field","fields","collectParamSourceRefs","source","p","nodes","node","collectPublicTypeRefs","opRoots","includeInternal","refs","Set","opRoot","route","routes","op","operations","resolveModifiers","includes","request","body","bodies","bodyType","resp","responses","headers","h","params","query","computeReachableSchemas","seeds","modelMap","reachable","frontier","length","pop","model","get","bases","b","ref","has","push","generateOpenApi","ctx","contractRoots","config","securitySchemes","doc","openapi","info","title","version","description","servers","security","allSchemas","Map","contractRoot","models","set","modelToSchema","paths","oaPath","convertPath","path","mods","operation","buildOperation","deprecated","method","schemas","filtered","schema","Object","entries","components","keys","toYaml","typeToSchema","properties","required","prop","fieldToSchema","optional","allOf","map","$ref","nullable","wrapNullable","visibility","readOnly","writeOnly","default","undefined","scalarToSchema","arrayToSchema","prefixItems","i","additionalProperties","enum","values","const","oneOf","m","mapping","literalValues","resolveDiscriminatorLiterals","discriminator","v","result","propertyName","inlineObjectToSchema","modelName","find","f","String","s","min","minLength","Number","max","maxLength","len","regex","pattern","minimum","maximum","format","_exhaustive","Error","minItems","maxItems","sdk","operationId","service","methodPart","split","parameters","paramSourceToParams","content","contentType","requestBody","effectiveSecurity","resolveSecurity","SECURITY_NONE","statusKey","statusCode","responseObject","statusDescription","headerObject","location","in","code","descriptions","indent","yamlString","Array","isArray","every","inline","join","lines","pad","repeat","isPlainObject","firstKey","firstVal","firstValStr","isComplex","toYamlValue","yamlKey","k","valStr","obj","key","val","test","replace","plugin","name","cacheKey","generateTargets","contractRoots","opRoots","ctx","securitySchemes","openapiConfig","options","base","baseDir","resolve","rootDir","outPath","output","emitFile","generateOpenApi","config","createOpenApiPlugin","JSON","stringify","content"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contractkit/plugin-openapi",
3
- "version": "0.8.13",
3
+ "version": "0.8.14",
4
4
  "description": "ContractKit built-in plugin: OpenAPI 3.0 YAML generation",
5
5
  "author": {
6
6
  "name": "Marooned Software",
@@ -26,7 +26,7 @@
26
26
  ".": "./dist/index.js"
27
27
  },
28
28
  "dependencies": {
29
- "@contractkit/core": "0.22.0"
29
+ "@contractkit/core": "0.23.0"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@repo/config-eslint": "0.3.1",
@@ -10,11 +10,13 @@ import type {
10
10
  } from '@contractkit/core';
11
11
  import { resolveModifiers, resolveSecurity, SECURITY_NONE } from '@contractkit/core';
12
12
 
13
+ /** A single entry for the OpenAPI `servers` array. */
13
14
  export interface OpenApiServerEntry {
14
15
  url: string;
15
16
  description?: string;
16
17
  }
17
18
 
19
+ /** A named entry for `components.securitySchemes` (e.g. an HTTP bearer or API-key scheme). */
18
20
  export interface OpenApiSecurityScheme {
19
21
  type: string;
20
22
  scheme?: string;
@@ -23,6 +25,7 @@ export interface OpenApiSecurityScheme {
23
25
  in?: string;
24
26
  }
25
27
 
28
+ /** Plugin configuration controlling the generated OpenAPI document (info block, servers, security, internal-op visibility). */
26
29
  export interface OpenApiConfig {
27
30
  baseDir?: string;
28
31
  output?: string;
@@ -134,6 +137,7 @@ function computeReachableSchemas(seeds: Set<string>, modelMap: Map<string, Model
134
137
 
135
138
  // ─── Public entry point ────────────────────────────────────────────────────
136
139
 
140
+ /** Inputs to {@link generateOpenApi}: the parsed contracts/operations plus the OpenAPI config and shared security schemes. */
137
141
  export interface OpenApiCodegenContext {
138
142
  contractRoots: ContractRootNode[];
139
143
  opRoots: OpRootNode[];
@@ -142,6 +146,14 @@ export interface OpenApiCodegenContext {
142
146
  securitySchemes?: Record<string, OpenApiSecurityScheme>;
143
147
  }
144
148
 
149
+ /**
150
+ * Generate an OpenAPI 3.0 document (YAML) from the parsed contracts and operations.
151
+ *
152
+ * Emits `paths` from the operations and `components.schemas` from the contracts, honoring
153
+ * `config.includeInternal` for `operation(internal)` visibility.
154
+ *
155
+ * @returns The OpenAPI document serialized as a YAML string.
156
+ */
145
157
  export function generateOpenApi(ctx: OpenApiCodegenContext): string {
146
158
  const { contractRoots, opRoots, config, securitySchemes } = ctx;
147
159
  const includeInternal = config.includeInternal ?? false;
@@ -364,7 +376,15 @@ function resolveDiscriminatorLiterals(modelName: string, discriminator: string,
364
376
  return [];
365
377
  }
366
378
 
367
- function scalarToSchema(type: import('@contractkit/core').ScalarTypeNode): Record<string, unknown> {
379
+ /**
380
+ * Map a ContractKit scalar type node to its OpenAPI schema object (`{ type, format, ... }`),
381
+ * carrying across constraints like min/max/length.
382
+ *
383
+ * @throws {Error} If the scalar name is not mapped — every member of the closed scalar set must
384
+ * have an explicit case, so an unmapped name signals a scalar was added to core without updating
385
+ * this plugin (rather than silently emitting a type-less, permissive schema).
386
+ */
387
+ export function scalarToSchema(type: import('@contractkit/core').ScalarTypeNode): Record<string, unknown> {
368
388
  const s: Record<string, unknown> = {};
369
389
 
370
390
  switch (type.name) {
@@ -399,6 +419,10 @@ function scalarToSchema(type: import('@contractkit/core').ScalarTypeNode): Recor
399
419
  s.type = 'string';
400
420
  s.format = 'date';
401
421
  break;
422
+ case 'time':
423
+ s.type = 'string';
424
+ s.format = 'time';
425
+ break;
402
426
  case 'datetime':
403
427
  s.type = 'string';
404
428
  s.format = 'date-time';
@@ -407,6 +431,10 @@ function scalarToSchema(type: import('@contractkit/core').ScalarTypeNode): Recor
407
431
  s.type = 'string';
408
432
  s.format = 'duration';
409
433
  break;
434
+ case 'interval':
435
+ s.type = 'string';
436
+ s.format = 'interval';
437
+ break;
410
438
  case 'email':
411
439
  s.type = 'string';
412
440
  s.format = 'email';
@@ -435,6 +463,10 @@ function scalarToSchema(type: import('@contractkit/core').ScalarTypeNode): Recor
435
463
  case 'json':
436
464
  // Any JSON value — no type constraint
437
465
  break;
466
+ default: {
467
+ const _exhaustive: never = type.name;
468
+ throw new Error(`plugin-openapi: unmapped scalar '${String(_exhaustive)}' — add a case`);
469
+ }
438
470
  }
439
471
 
440
472
  return s;
@@ -1,6 +1,6 @@
1
1
  import { describe, it, expect } from 'vitest';
2
2
  import { parseCk, decomposeCk, applyOptionsDefaults, DiagnosticCollector } from '@contractkit/core';
3
- import { generateOpenApi, toYaml } from '../src/codegen-openapi.js';
3
+ import { generateOpenApi, toYaml, scalarToSchema } from '../src/codegen-openapi.js';
4
4
  import {
5
5
  scalarType,
6
6
  arrayType,
@@ -23,6 +23,22 @@ import {
23
23
  opRoot,
24
24
  } from './helpers.js';
25
25
 
26
+ // ─── scalarToSchema ───────────────────────────────────────────────────────
27
+
28
+ describe('scalarToSchema', () => {
29
+ it('maps time to string with format time', () => {
30
+ expect(scalarToSchema({ kind: 'scalar', name: 'time' })).toEqual({ type: 'string', format: 'time' });
31
+ });
32
+
33
+ it('maps interval to string with format interval', () => {
34
+ expect(scalarToSchema({ kind: 'scalar', name: 'interval' })).toEqual({ type: 'string', format: 'interval' });
35
+ });
36
+
37
+ it('throws on an unmapped scalar name', () => {
38
+ expect(() => scalarToSchema({ kind: 'scalar', name: 'decimal' } as any)).toThrow(/unmapped scalar 'decimal'/);
39
+ });
40
+ });
41
+
26
42
  // ─── YAML serializer ──────────────────────────────────────────────────────
27
43
 
28
44
  describe('toYaml', () => {