openapi-typesafe 1.0.0-rc.1 → 1.0.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. package/README.md +12 -5
  2. package/dist/adapters/redocly-loader/configured-headers.cjs +32 -0
  3. package/dist/adapters/redocly-loader/configured-headers.cjs.map +1 -0
  4. package/dist/adapters/redocly-loader/configured-headers.mjs +30 -0
  5. package/dist/adapters/redocly-loader/configured-headers.mjs.map +1 -0
  6. package/dist/adapters/redocly-loader/redocly-schema-loader.cjs +19 -6
  7. package/dist/adapters/redocly-loader/redocly-schema-loader.cjs.map +1 -1
  8. package/dist/adapters/redocly-loader/redocly-schema-loader.mjs +18 -5
  9. package/dist/adapters/redocly-loader/redocly-schema-loader.mjs.map +1 -1
  10. package/dist/adapters/redocly-loader/ref-access.cjs +37 -4
  11. package/dist/adapters/redocly-loader/ref-access.cjs.map +1 -1
  12. package/dist/adapters/redocly-loader/ref-access.mjs +37 -4
  13. package/dist/adapters/redocly-loader/ref-access.mjs.map +1 -1
  14. package/dist/adapters/redocly-loader/ref-resolution-check.cjs +191 -0
  15. package/dist/adapters/redocly-loader/ref-resolution-check.cjs.map +1 -0
  16. package/dist/adapters/redocly-loader/ref-resolution-check.mjs +189 -0
  17. package/dist/adapters/redocly-loader/ref-resolution-check.mjs.map +1 -0
  18. package/dist/adapters/redocly-loader/ref-resolution-steps.cjs +73 -0
  19. package/dist/adapters/redocly-loader/ref-resolution-steps.cjs.map +1 -0
  20. package/dist/adapters/redocly-loader/ref-resolution-steps.mjs +60 -0
  21. package/dist/adapters/redocly-loader/ref-resolution-steps.mjs.map +1 -0
  22. package/dist/adapters/redocly-loader/remote-fetch.cjs +41 -14
  23. package/dist/adapters/redocly-loader/remote-fetch.cjs.map +1 -1
  24. package/dist/adapters/redocly-loader/remote-fetch.mjs +40 -14
  25. package/dist/adapters/redocly-loader/remote-fetch.mjs.map +1 -1
  26. package/dist/adapters/redocly-loader/schema-load-errors.cjs +23 -5
  27. package/dist/adapters/redocly-loader/schema-load-errors.cjs.map +1 -1
  28. package/dist/adapters/redocly-loader/schema-load-errors.mjs +23 -5
  29. package/dist/adapters/redocly-loader/schema-load-errors.mjs.map +1 -1
  30. package/dist/adapters/redocly-loader/unsupported-keys.cjs +9 -1
  31. package/dist/adapters/redocly-loader/unsupported-keys.cjs.map +1 -1
  32. package/dist/adapters/redocly-loader/unsupported-keys.mjs +9 -1
  33. package/dist/adapters/redocly-loader/unsupported-keys.mjs.map +1 -1
  34. package/dist/adapters/terminal-logger/terminal-logger.cjs +6 -4
  35. package/dist/adapters/terminal-logger/terminal-logger.cjs.map +1 -1
  36. package/dist/adapters/terminal-logger/terminal-logger.mjs +6 -4
  37. package/dist/adapters/terminal-logger/terminal-logger.mjs.map +1 -1
  38. package/dist/adapters/type-ast-bridge/ir-to-typescript.cjs +2 -1
  39. package/dist/adapters/type-ast-bridge/ir-to-typescript.cjs.map +1 -1
  40. package/dist/adapters/type-ast-bridge/ir-to-typescript.mjs +2 -1
  41. package/dist/adapters/type-ast-bridge/ir-to-typescript.mjs.map +1 -1
  42. package/dist/adapters/type-ast-bridge/print-typescript.cjs.map +1 -1
  43. package/dist/adapters/type-ast-bridge/print-typescript.mjs.map +1 -1
  44. package/dist/api/default-ports.cjs +9 -0
  45. package/dist/api/default-ports.cjs.map +1 -1
  46. package/dist/api/default-ports.mjs +8 -1
  47. package/dist/api/default-ports.mjs.map +1 -1
  48. package/dist/api/discriminator-patch.cjs +5 -1
  49. package/dist/api/discriminator-patch.cjs.map +1 -1
  50. package/dist/api/discriminator-patch.mjs +5 -1
  51. package/dist/api/discriminator-patch.mjs.map +1 -1
  52. package/dist/api/document-refs.cjs +15 -12
  53. package/dist/api/document-refs.cjs.map +1 -1
  54. package/dist/api/document-refs.mjs +15 -12
  55. package/dist/api/document-refs.mjs.map +1 -1
  56. package/dist/api/document-run.cjs +4 -2
  57. package/dist/api/document-run.cjs.map +1 -1
  58. package/dist/api/document-run.mjs +4 -2
  59. package/dist/api/document-run.mjs.map +1 -1
  60. package/dist/api/footer-sink.cjs +25 -2
  61. package/dist/api/footer-sink.cjs.map +1 -1
  62. package/dist/api/footer-sink.mjs +25 -2
  63. package/dist/api/footer-sink.mjs.map +1 -1
  64. package/dist/api/legacy-callback-warning.cjs +4 -1
  65. package/dist/api/legacy-callback-warning.cjs.map +1 -1
  66. package/dist/api/legacy-callback-warning.mjs +4 -1
  67. package/dist/api/legacy-callback-warning.mjs.map +1 -1
  68. package/dist/api/legacy-ts-helpers.cjs.map +1 -1
  69. package/dist/api/legacy-ts-helpers.mjs.map +1 -1
  70. package/dist/api/legacy-utils.cjs.map +1 -1
  71. package/dist/api/legacy-utils.mjs.map +1 -1
  72. package/dist/api/openapi-ts.cjs +2 -1
  73. package/dist/api/openapi-ts.cjs.map +1 -1
  74. package/dist/api/openapi-ts.mjs +3 -2
  75. package/dist/api/openapi-ts.mjs.map +1 -1
  76. package/dist/api/transform-context.cjs +1 -1
  77. package/dist/api/transform-context.cjs.map +1 -1
  78. package/dist/api/transform-context.mjs +1 -1
  79. package/dist/api/transform-context.mjs.map +1 -1
  80. package/dist/api/transform-schema.cjs.map +1 -1
  81. package/dist/api/transform-schema.mjs.map +1 -1
  82. package/dist/application/print/type-printer.cjs +2 -1
  83. package/dist/application/print/type-printer.cjs.map +1 -1
  84. package/dist/application/print/type-printer.mjs +2 -1
  85. package/dist/application/print/type-printer.mjs.map +1 -1
  86. package/dist/application/transform/document/parameters.cjs +1 -1
  87. package/dist/application/transform/document/parameters.cjs.map +1 -1
  88. package/dist/application/transform/document/parameters.mjs +1 -1
  89. package/dist/application/transform/document/parameters.mjs.map +1 -1
  90. package/dist/application/transform/document/paths.cjs +1 -1
  91. package/dist/application/transform/document/paths.cjs.map +1 -1
  92. package/dist/application/transform/document/paths.mjs +1 -1
  93. package/dist/application/transform/document/paths.mjs.map +1 -1
  94. package/dist/application/transform/footer/evaluation.cjs +9 -0
  95. package/dist/application/transform/footer/evaluation.cjs.map +1 -1
  96. package/dist/application/transform/footer/evaluation.mjs +8 -1
  97. package/dist/application/transform/footer/evaluation.mjs.map +1 -1
  98. package/dist/application/transform/footer/type-evaluation.cjs +4 -112
  99. package/dist/application/transform/footer/type-evaluation.cjs.map +1 -1
  100. package/dist/application/transform/footer/type-evaluation.mjs +4 -112
  101. package/dist/application/transform/footer/type-evaluation.mjs.map +1 -1
  102. package/dist/application/transform/footer/type-indexing.cjs +107 -0
  103. package/dist/application/transform/footer/type-indexing.cjs.map +1 -0
  104. package/dist/application/transform/footer/type-indexing.mjs +105 -0
  105. package/dist/application/transform/footer/type-indexing.mjs.map +1 -0
  106. package/dist/cli/api-settings.cjs +78 -0
  107. package/dist/cli/api-settings.cjs.map +1 -0
  108. package/dist/cli/api-settings.mjs +73 -0
  109. package/dist/cli/api-settings.mjs.map +1 -0
  110. package/dist/cli/cli-arguments.cjs +1 -0
  111. package/dist/cli/cli-arguments.cjs.map +1 -1
  112. package/dist/cli/cli-arguments.mjs +1 -1
  113. package/dist/cli/cli-arguments.mjs.map +1 -1
  114. package/dist/cli/help-text.cjs +3 -3
  115. package/dist/cli/help-text.cjs.map +1 -1
  116. package/dist/cli/help-text.mjs +3 -3
  117. package/dist/cli/help-text.mjs.map +1 -1
  118. package/dist/cli/redocly-apis.cjs +8 -4
  119. package/dist/cli/redocly-apis.cjs.map +1 -1
  120. package/dist/cli/redocly-apis.mjs +7 -3
  121. package/dist/cli/redocly-apis.mjs.map +1 -1
  122. package/dist/cli/run-cli.cjs +5 -1
  123. package/dist/cli/run-cli.cjs.map +1 -1
  124. package/dist/cli/run-cli.mjs +5 -1
  125. package/dist/cli/run-cli.mjs.map +1 -1
  126. package/dist/domain/errors.cjs +4 -1
  127. package/dist/domain/errors.cjs.map +1 -1
  128. package/dist/domain/errors.mjs +4 -1
  129. package/dist/domain/errors.mjs.map +1 -1
  130. package/dist/domain/ir/constructors.cjs +2 -0
  131. package/dist/domain/ir/constructors.cjs.map +1 -1
  132. package/dist/domain/ir/constructors.mjs +2 -1
  133. package/dist/domain/ir/constructors.mjs.map +1 -1
  134. package/dist/domain/openapi/path-templates.cjs +1 -1
  135. package/dist/domain/openapi/path-templates.cjs.map +1 -1
  136. package/dist/domain/openapi/path-templates.mjs +1 -1
  137. package/dist/domain/openapi/path-templates.mjs.map +1 -1
  138. package/dist/domain/url-credentials.cjs +10 -0
  139. package/dist/domain/url-credentials.cjs.map +1 -0
  140. package/dist/domain/url-credentials.mjs +8 -0
  141. package/dist/domain/url-credentials.mjs.map +1 -0
  142. package/dist/domain/warnings.cjs +9 -1
  143. package/dist/domain/warnings.cjs.map +1 -1
  144. package/dist/domain/warnings.mjs +9 -1
  145. package/dist/domain/warnings.mjs.map +1 -1
  146. package/dist/index.cjs +2 -0
  147. package/dist/index.cjs.map +1 -1
  148. package/dist/index.d.cts +1160 -53
  149. package/dist/index.d.mts +1160 -53
  150. package/dist/index.d.ts +1160 -53
  151. package/dist/index.mjs +1 -0
  152. package/dist/index.mjs.map +1 -1
  153. package/dist/transform/path-item-object.cjs.map +1 -1
  154. package/dist/transform/path-item-object.mjs.map +1 -1
  155. package/package.json +6 -5
  156. package/src/adapters/redocly-loader/configured-headers.ts +65 -0
  157. package/src/adapters/redocly-loader/redocly-schema-loader.ts +22 -7
  158. package/src/adapters/redocly-loader/ref-access.ts +60 -5
  159. package/src/adapters/redocly-loader/ref-resolution-check.ts +257 -0
  160. package/src/adapters/redocly-loader/ref-resolution-steps.ts +113 -0
  161. package/src/adapters/redocly-loader/remote-fetch.ts +77 -21
  162. package/src/adapters/redocly-loader/schema-load-errors.ts +33 -11
  163. package/src/adapters/redocly-loader/unsupported-keys.ts +17 -2
  164. package/src/adapters/terminal-logger/terminal-logger.ts +9 -5
  165. package/src/adapters/type-ast-bridge/ir-to-typescript.ts +2 -1
  166. package/src/adapters/type-ast-bridge/print-typescript.ts +3 -1
  167. package/src/adapters/type-ast-bridge/typescript-types.ts +57 -5
  168. package/src/api/default-ports.ts +16 -0
  169. package/src/api/discriminator-patch.ts +7 -2
  170. package/src/api/document-refs.ts +19 -15
  171. package/src/api/document-run.ts +9 -6
  172. package/src/api/footer-sink.ts +34 -2
  173. package/src/api/legacy-callback-warning.ts +7 -3
  174. package/src/api/legacy-ts-helpers.ts +7 -5
  175. package/src/api/legacy-utils.ts +1 -1
  176. package/src/api/openapi-ts.ts +2 -0
  177. package/src/api/run-context.ts +34 -0
  178. package/src/api/transform-context.ts +10 -8
  179. package/src/api/transform-schema.ts +6 -5
  180. package/src/application/print/type-printer.ts +2 -1
  181. package/src/application/transform/document/parameters.ts +2 -1
  182. package/src/application/transform/document/paths.ts +2 -1
  183. package/src/application/transform/footer/evaluation.ts +10 -0
  184. package/src/application/transform/footer/type-evaluation.ts +6 -133
  185. package/src/application/transform/footer/type-indexing.ts +152 -0
  186. package/src/cli/api-settings.ts +109 -0
  187. package/src/cli/cli-arguments.ts +5 -2
  188. package/src/cli/help-text.ts +4 -4
  189. package/src/cli/redocly-apis.ts +13 -7
  190. package/src/cli/run-cli.ts +5 -1
  191. package/src/domain/errors.ts +8 -2
  192. package/src/domain/ir/constructors.ts +3 -0
  193. package/src/domain/ir/nodes.ts +9 -6
  194. package/src/domain/openapi/path-templates.ts +2 -1
  195. package/src/domain/url-credentials.ts +18 -0
  196. package/src/domain/warnings.ts +8 -0
  197. package/src/index.ts +1 -0
  198. package/src/transform/path-item-object.ts +6 -2
  199. package/src/types/generator-options.ts +12 -32
  200. package/src/types/openapi-common.ts +1 -0
  201. package/src/types/openapi-request.ts +3 -0
  202. package/src/types/openapi-schema.ts +2 -0
  203. package/src/types/openapi-security.ts +1 -0
@@ -1 +1 @@
1
- {"version":3,"file":"unsupported-keys.cjs","sources":["../../../src/adapters/redocly-loader/unsupported-keys.ts"],"sourcesContent":["import { ERROR_CODES, OpenAPITypesafeError } from \"../../domain/errors.js\";\n\n/**\n * Keys Redocly 1.34 cannot walk. It looks up the type of every key with `type.properties[key]`,\n * which also finds inherited `Object.prototype` members; it then calls a found function with no\n * `this`, and these methods throw a `TypeError` for that. Redocly 2.x looks up own keys only\n * (ADR-005 keeps 1.34). `toString` and `constructor` do not throw, and load as they should.\n *\n * Redocly does not walk every value (`default` and `const` are data), so a document with such a\n * key is not rejected up front: the loader looks for them only after Redocly threw a `TypeError`.\n */\nexport const UNSUPPORTED_KEYS: ReadonlySet<string> = new Set([\n \"hasOwnProperty\",\n \"isPrototypeOf\",\n \"propertyIsEnumerable\",\n \"toLocaleString\",\n \"valueOf\",\n \"__defineGetter__\",\n \"__defineSetter__\",\n \"__lookupGetter__\",\n \"__lookupSetter__\",\n]);\n\n/** Enough found keys in the message to act on; `details.keys` has all of them. */\nconst KEYS_IN_MESSAGE = 5;\n\n/** A parsed document and where it was loaded from. */\nexport interface LoadedDocument {\n readonly source: string;\n readonly parsed: unknown;\n}\n\n/** An unsupported key: its JSON pointer and the document that has it. */\nexport interface UnsupportedKey {\n readonly key: string;\n readonly pointer: string;\n readonly source: string;\n}\n\ninterface PendingNode {\n readonly value: object;\n readonly pointer: string;\n}\n\n/** RFC 6901: `~` becomes `~0` and `/` becomes `~1`. */\nfunction escapePointerSegment(segment: string): string {\n return segment.replaceAll(\"~\", \"~0\").replaceAll(\"/\", \"~1\");\n}\n\n/**\n * The unsupported keys of one parsed document. The walk uses its own stack, so a deeply nested\n * document is checked without running out of call stack; nodes shared by YAML aliases are checked\n * once.\n */\nfunction unsupportedKeysOf(document: LoadedDocument): UnsupportedKey[] {\n const found: UnsupportedKey[] = [];\n const visited = new WeakSet<object>();\n const pending: PendingNode[] = [];\n const enqueue = (value: unknown, pointer: string): void => {\n if (typeof value === \"object\" && value !== null && !visited.has(value)) {\n visited.add(value);\n pending.push({ value, pointer });\n }\n };\n enqueue(document.parsed, \"#\");\n for (let node = pending.pop(); node !== undefined; node = pending.pop()) {\n for (const [key, child] of Object.entries(node.value)) {\n const pointer = `${node.pointer}/${escapePointerSegment(key)}`;\n if (UNSUPPORTED_KEYS.has(key)) {\n found.push({ key, pointer, source: document.source });\n }\n enqueue(child, pointer);\n }\n }\n return found;\n}\n\n/** Every unsupported key of the given documents. */\nexport function findUnsupportedKeys(documents: readonly LoadedDocument[]): UnsupportedKey[] {\n return documents.flatMap(unsupportedKeysOf);\n}\n\nfunction describeKey(found: UnsupportedKey): string {\n return `\"${found.key}\" at ${found.pointer} in ${found.source}`;\n}\n\n/** The typed error for the keys the schema loader failed on; `cause` is Redocly's `TypeError`. */\nexport function unsupportedKeysError(\n keys: readonly UnsupportedKey[],\n cause: unknown,\n): OpenAPITypesafeError {\n const listed = keys.slice(0, KEYS_IN_MESSAGE).map(describeKey);\n const more = keys.length > KEYS_IN_MESSAGE ? ` and ${keys.length - KEYS_IN_MESSAGE} more` : \"\";\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_KEY_UNSUPPORTED,\n message:\n \"The schema loader (Redocly 1.x) failed on a key named like a built-in object method. \" +\n `Rename it: ${listed.join(\", \")}${more}.`,\n details: { keys: keys.map((found) => ({ ...found })) },\n cause,\n });\n}\n"],"names":["OpenAPITypesafeError","ERROR_CODES"],"mappings":";;;;AAWO,MAAM,gBAAA,uBAA4C,GAAA,CAAI;AAAA,EAC3D,gBAAA;AAAA,EACA,eAAA;AAAA,EACA,sBAAA;AAAA,EACA,gBAAA;AAAA,EACA,SAAA;AAAA,EACA,kBAAA;AAAA,EACA,kBAAA;AAAA,EACA,kBAAA;AAAA,EACA;AACF,CAAC;AAGD,MAAM,eAAA,GAAkB,CAAA;AAqBxB,SAAS,qBAAqB,OAAA,EAAyB;AACrD,EAAA,OAAO,QAAQ,UAAA,CAAW,GAAA,EAAK,IAAI,CAAA,CAAE,UAAA,CAAW,KAAK,IAAI,CAAA;AAC3D;AAOA,SAAS,kBAAkB,QAAA,EAA4C;AACrE,EAAA,MAAM,QAA0B,EAAC;AACjC,EAAA,MAAM,OAAA,uBAAc,OAAA,EAAgB;AACpC,EAAA,MAAM,UAAyB,EAAC;AAChC,EAAA,MAAM,OAAA,GAAU,CAAC,KAAA,EAAgB,OAAA,KAA0B;AACzD,IAAA,IAAI,OAAO,UAAU,QAAA,IAAY,KAAA,KAAU,QAAQ,CAAC,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA,EAAG;AACtE,MAAA,OAAA,CAAQ,IAAI,KAAK,CAAA;AACjB,MAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,KAAA,EAAO,OAAA,EAAS,CAAA;AAAA,IACjC;AAAA,EACF,CAAA;AACA,EAAA,OAAA,CAAQ,QAAA,CAAS,QAAQ,GAAG,CAAA;AAC5B,EAAA,KAAA,IAAS,IAAA,GAAO,QAAQ,GAAA,EAAI,EAAG,SAAS,MAAA,EAAW,IAAA,GAAO,OAAA,CAAQ,GAAA,EAAI,EAAG;AACvE,IAAA,KAAA,MAAW,CAAC,KAAK,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,EAAG;AACrD,MAAA,MAAM,UAAU,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,CAAA,EAAI,oBAAA,CAAqB,GAAG,CAAC,CAAA,CAAA;AAC5D,MAAA,IAAI,gBAAA,CAAiB,GAAA,CAAI,GAAG,CAAA,EAAG;AAC7B,QAAA,KAAA,CAAM,KAAK,EAAE,GAAA,EAAK,SAAS,MAAA,EAAQ,QAAA,CAAS,QAAQ,CAAA;AAAA,MACtD;AACA,MAAA,OAAA,CAAQ,OAAO,OAAO,CAAA;AAAA,IACxB;AAAA,EACF;AACA,EAAA,OAAO,KAAA;AACT;AAGO,SAAS,oBAAoB,SAAA,EAAwD;AAC1F,EAAA,OAAO,SAAA,CAAU,QAAQ,iBAAiB,CAAA;AAC5C;AAEA,SAAS,YAAY,KAAA,EAA+B;AAClD,EAAA,OAAO,CAAA,CAAA,EAAI,MAAM,GAAG,CAAA,KAAA,EAAQ,MAAM,OAAO,CAAA,IAAA,EAAO,MAAM,MAAM,CAAA,CAAA;AAC9D;AAGO,SAAS,oBAAA,CACd,MACA,KAAA,EACsB;AACtB,EAAA,MAAM,SAAS,IAAA,CAAK,KAAA,CAAM,GAAG,eAAe,CAAA,CAAE,IAAI,WAAW,CAAA;AAC7D,EAAA,MAAM,IAAA,GAAO,KAAK,MAAA,GAAS,eAAA,GAAkB,QAAQ,IAAA,CAAK,MAAA,GAAS,eAAe,CAAA,KAAA,CAAA,GAAU,EAAA;AAC5F,EAAA,OAAO,IAAIA,2BAAA,CAAqB;AAAA,IAC9B,MAAMC,kBAAA,CAAY,sBAAA;AAAA,IAClB,SACE,CAAA,gGAAA,EACc,MAAA,CAAO,KAAK,IAAI,CAAC,GAAG,IAAI,CAAA,CAAA,CAAA;AAAA,IACxC,OAAA,EAAS,EAAE,IAAA,EAAM,IAAA,CAAK,GAAA,CAAI,CAAC,KAAA,MAAW,EAAE,GAAG,KAAA,EAAM,CAAE,CAAA,EAAE;AAAA,IACrD;AAAA,GACD,CAAA;AACH;;;;"}
1
+ {"version":3,"file":"unsupported-keys.cjs","sources":["../../../src/adapters/redocly-loader/unsupported-keys.ts"],"sourcesContent":["import { ERROR_CODES, OpenAPITypesafeError } from \"../../domain/errors.js\";\n\n/**\n * Keys Redocly 1.34 cannot walk. It looks up the type of every key with `type.properties[key]`,\n * which also finds inherited `Object.prototype` members; it then calls a found function with no\n * `this`, and these methods throw a `TypeError` for that. Redocly 2.x looks up own keys only\n * (ADR-005 keeps 1.34). `toString` does not throw, and loads as it should.\n *\n * Redocly does not walk every value (`default` and `const` are data), so a document with such a\n * key is not rejected up front: the loader looks for them only after Redocly threw a `TypeError`.\n */\nexport const UNSUPPORTED_KEYS: ReadonlySet<string> = new Set([\n \"hasOwnProperty\",\n \"isPrototypeOf\",\n \"propertyIsEnumerable\",\n \"toLocaleString\",\n \"valueOf\",\n \"__defineGetter__\",\n \"__defineSetter__\",\n \"__lookupGetter__\",\n \"__lookupSetter__\",\n]);\n\n/**\n * `constructor` finds `Object`, which returns the value it is called with. Redocly then takes the\n * value for a node type when it has a string `name` (a security scheme, a header with a `name`),\n * and fails reading the type's fields. Any other `constructor` key loads.\n */\nconst CONSTRUCTOR_KEY = \"constructor\";\n\nfunction isUnsupportedEntry(key: string, value: unknown): boolean {\n if (UNSUPPORTED_KEYS.has(key)) {\n return true;\n }\n const name = (value as { name?: unknown } | null | undefined)?.name;\n return key === CONSTRUCTOR_KEY && typeof value === \"object\" && typeof name === \"string\";\n}\n\n/** Enough found keys in the message to act on; `details.keys` has all of them. */\nconst KEYS_IN_MESSAGE = 5;\n\n/** A parsed document and where it was loaded from. */\nexport interface LoadedDocument {\n readonly source: string;\n readonly parsed: unknown;\n}\n\n/** An unsupported key: its JSON pointer and the document that has it. */\nexport interface UnsupportedKey {\n readonly key: string;\n readonly pointer: string;\n readonly source: string;\n}\n\ninterface PendingNode {\n readonly value: object;\n readonly pointer: string;\n}\n\n/** RFC 6901: `~` becomes `~0` and `/` becomes `~1`. */\nfunction escapePointerSegment(segment: string): string {\n return segment.replaceAll(\"~\", \"~0\").replaceAll(\"/\", \"~1\");\n}\n\n/**\n * The unsupported keys of one parsed document. The walk uses its own stack, so a deeply nested\n * document is checked without running out of call stack; nodes shared by YAML aliases are checked\n * once.\n */\nfunction unsupportedKeysOf(document: LoadedDocument): UnsupportedKey[] {\n const found: UnsupportedKey[] = [];\n const visited = new WeakSet<object>();\n const pending: PendingNode[] = [];\n const enqueue = (value: unknown, pointer: string): void => {\n if (typeof value === \"object\" && value !== null && !visited.has(value)) {\n visited.add(value);\n pending.push({ value, pointer });\n }\n };\n enqueue(document.parsed, \"#\");\n for (let node = pending.pop(); node !== undefined; node = pending.pop()) {\n for (const [key, child] of Object.entries(node.value)) {\n const pointer = `${node.pointer}/${escapePointerSegment(key)}`;\n if (isUnsupportedEntry(key, child)) {\n found.push({ key, pointer, source: document.source });\n }\n enqueue(child, pointer);\n }\n }\n return found;\n}\n\n/** Every unsupported key of the given documents. */\nexport function findUnsupportedKeys(documents: readonly LoadedDocument[]): UnsupportedKey[] {\n return documents.flatMap(unsupportedKeysOf);\n}\n\nfunction describeKey(found: UnsupportedKey): string {\n return `\"${found.key}\" at ${found.pointer} in ${found.source}`;\n}\n\n/** The typed error for the keys the schema loader failed on; `cause` is Redocly's `TypeError`. */\nexport function unsupportedKeysError(\n keys: readonly UnsupportedKey[],\n cause: unknown,\n): OpenAPITypesafeError {\n const listed = keys.slice(0, KEYS_IN_MESSAGE).map(describeKey);\n const more = keys.length > KEYS_IN_MESSAGE ? ` and ${keys.length - KEYS_IN_MESSAGE} more` : \"\";\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_KEY_UNSUPPORTED,\n message:\n \"The schema loader (Redocly 1.x) failed on a key named like a built-in object method. \" +\n `Rename it: ${listed.join(\", \")}${more}.`,\n details: { keys: keys.map((found) => ({ ...found })) },\n cause,\n });\n}\n"],"names":["OpenAPITypesafeError","ERROR_CODES"],"mappings":";;;;AAWO,MAAM,gBAAA,uBAA4C,GAAA,CAAI;AAAA,EAC3D,gBAAA;AAAA,EACA,eAAA;AAAA,EACA,sBAAA;AAAA,EACA,gBAAA;AAAA,EACA,SAAA;AAAA,EACA,kBAAA;AAAA,EACA,kBAAA;AAAA,EACA,kBAAA;AAAA,EACA;AACF,CAAC;AAOD,MAAM,eAAA,GAAkB,aAAA;AAExB,SAAS,kBAAA,CAAmB,KAAa,KAAA,EAAyB;AAChE,EAAA,IAAI,gBAAA,CAAiB,GAAA,CAAI,GAAG,CAAA,EAAG;AAC7B,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,OAAQ,KAAA,EAAiD,IAAA;AAC/D,EAAA,OAAO,QAAQ,eAAA,IAAmB,OAAO,KAAA,KAAU,QAAA,IAAY,OAAO,IAAA,KAAS,QAAA;AACjF;AAGA,MAAM,eAAA,GAAkB,CAAA;AAqBxB,SAAS,qBAAqB,OAAA,EAAyB;AACrD,EAAA,OAAO,QAAQ,UAAA,CAAW,GAAA,EAAK,IAAI,CAAA,CAAE,UAAA,CAAW,KAAK,IAAI,CAAA;AAC3D;AAOA,SAAS,kBAAkB,QAAA,EAA4C;AACrE,EAAA,MAAM,QAA0B,EAAC;AACjC,EAAA,MAAM,OAAA,uBAAc,OAAA,EAAgB;AACpC,EAAA,MAAM,UAAyB,EAAC;AAChC,EAAA,MAAM,OAAA,GAAU,CAAC,KAAA,EAAgB,OAAA,KAA0B;AACzD,IAAA,IAAI,OAAO,UAAU,QAAA,IAAY,KAAA,KAAU,QAAQ,CAAC,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA,EAAG;AACtE,MAAA,OAAA,CAAQ,IAAI,KAAK,CAAA;AACjB,MAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,KAAA,EAAO,OAAA,EAAS,CAAA;AAAA,IACjC;AAAA,EACF,CAAA;AACA,EAAA,OAAA,CAAQ,QAAA,CAAS,QAAQ,GAAG,CAAA;AAC5B,EAAA,KAAA,IAAS,IAAA,GAAO,QAAQ,GAAA,EAAI,EAAG,SAAS,MAAA,EAAW,IAAA,GAAO,OAAA,CAAQ,GAAA,EAAI,EAAG;AACvE,IAAA,KAAA,MAAW,CAAC,KAAK,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,EAAG;AACrD,MAAA,MAAM,UAAU,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,CAAA,EAAI,oBAAA,CAAqB,GAAG,CAAC,CAAA,CAAA;AAC5D,MAAA,IAAI,kBAAA,CAAmB,GAAA,EAAK,KAAK,CAAA,EAAG;AAClC,QAAA,KAAA,CAAM,KAAK,EAAE,GAAA,EAAK,SAAS,MAAA,EAAQ,QAAA,CAAS,QAAQ,CAAA;AAAA,MACtD;AACA,MAAA,OAAA,CAAQ,OAAO,OAAO,CAAA;AAAA,IACxB;AAAA,EACF;AACA,EAAA,OAAO,KAAA;AACT;AAGO,SAAS,oBAAoB,SAAA,EAAwD;AAC1F,EAAA,OAAO,SAAA,CAAU,QAAQ,iBAAiB,CAAA;AAC5C;AAEA,SAAS,YAAY,KAAA,EAA+B;AAClD,EAAA,OAAO,CAAA,CAAA,EAAI,MAAM,GAAG,CAAA,KAAA,EAAQ,MAAM,OAAO,CAAA,IAAA,EAAO,MAAM,MAAM,CAAA,CAAA;AAC9D;AAGO,SAAS,oBAAA,CACd,MACA,KAAA,EACsB;AACtB,EAAA,MAAM,SAAS,IAAA,CAAK,KAAA,CAAM,GAAG,eAAe,CAAA,CAAE,IAAI,WAAW,CAAA;AAC7D,EAAA,MAAM,IAAA,GAAO,KAAK,MAAA,GAAS,eAAA,GAAkB,QAAQ,IAAA,CAAK,MAAA,GAAS,eAAe,CAAA,KAAA,CAAA,GAAU,EAAA;AAC5F,EAAA,OAAO,IAAIA,2BAAA,CAAqB;AAAA,IAC9B,MAAMC,kBAAA,CAAY,sBAAA;AAAA,IAClB,SACE,CAAA,gGAAA,EACc,MAAA,CAAO,KAAK,IAAI,CAAC,GAAG,IAAI,CAAA,CAAA,CAAA;AAAA,IACxC,OAAA,EAAS,EAAE,IAAA,EAAM,IAAA,CAAK,GAAA,CAAI,CAAC,KAAA,MAAW,EAAE,GAAG,KAAA,EAAM,CAAE,CAAA,EAAE;AAAA,IACrD;AAAA,GACD,CAAA;AACH;;;;"}
@@ -11,6 +11,14 @@ const UNSUPPORTED_KEYS = /* @__PURE__ */ new Set([
11
11
  "__lookupGetter__",
12
12
  "__lookupSetter__"
13
13
  ]);
14
+ const CONSTRUCTOR_KEY = "constructor";
15
+ function isUnsupportedEntry(key, value) {
16
+ if (UNSUPPORTED_KEYS.has(key)) {
17
+ return true;
18
+ }
19
+ const name = value?.name;
20
+ return key === CONSTRUCTOR_KEY && typeof value === "object" && typeof name === "string";
21
+ }
14
22
  const KEYS_IN_MESSAGE = 5;
15
23
  function escapePointerSegment(segment) {
16
24
  return segment.replaceAll("~", "~0").replaceAll("/", "~1");
@@ -29,7 +37,7 @@ function unsupportedKeysOf(document) {
29
37
  for (let node = pending.pop(); node !== void 0; node = pending.pop()) {
30
38
  for (const [key, child] of Object.entries(node.value)) {
31
39
  const pointer = `${node.pointer}/${escapePointerSegment(key)}`;
32
- if (UNSUPPORTED_KEYS.has(key)) {
40
+ if (isUnsupportedEntry(key, child)) {
33
41
  found.push({ key, pointer, source: document.source });
34
42
  }
35
43
  enqueue(child, pointer);
@@ -1 +1 @@
1
- {"version":3,"file":"unsupported-keys.mjs","sources":["../../../src/adapters/redocly-loader/unsupported-keys.ts"],"sourcesContent":["import { ERROR_CODES, OpenAPITypesafeError } from \"../../domain/errors.js\";\n\n/**\n * Keys Redocly 1.34 cannot walk. It looks up the type of every key with `type.properties[key]`,\n * which also finds inherited `Object.prototype` members; it then calls a found function with no\n * `this`, and these methods throw a `TypeError` for that. Redocly 2.x looks up own keys only\n * (ADR-005 keeps 1.34). `toString` and `constructor` do not throw, and load as they should.\n *\n * Redocly does not walk every value (`default` and `const` are data), so a document with such a\n * key is not rejected up front: the loader looks for them only after Redocly threw a `TypeError`.\n */\nexport const UNSUPPORTED_KEYS: ReadonlySet<string> = new Set([\n \"hasOwnProperty\",\n \"isPrototypeOf\",\n \"propertyIsEnumerable\",\n \"toLocaleString\",\n \"valueOf\",\n \"__defineGetter__\",\n \"__defineSetter__\",\n \"__lookupGetter__\",\n \"__lookupSetter__\",\n]);\n\n/** Enough found keys in the message to act on; `details.keys` has all of them. */\nconst KEYS_IN_MESSAGE = 5;\n\n/** A parsed document and where it was loaded from. */\nexport interface LoadedDocument {\n readonly source: string;\n readonly parsed: unknown;\n}\n\n/** An unsupported key: its JSON pointer and the document that has it. */\nexport interface UnsupportedKey {\n readonly key: string;\n readonly pointer: string;\n readonly source: string;\n}\n\ninterface PendingNode {\n readonly value: object;\n readonly pointer: string;\n}\n\n/** RFC 6901: `~` becomes `~0` and `/` becomes `~1`. */\nfunction escapePointerSegment(segment: string): string {\n return segment.replaceAll(\"~\", \"~0\").replaceAll(\"/\", \"~1\");\n}\n\n/**\n * The unsupported keys of one parsed document. The walk uses its own stack, so a deeply nested\n * document is checked without running out of call stack; nodes shared by YAML aliases are checked\n * once.\n */\nfunction unsupportedKeysOf(document: LoadedDocument): UnsupportedKey[] {\n const found: UnsupportedKey[] = [];\n const visited = new WeakSet<object>();\n const pending: PendingNode[] = [];\n const enqueue = (value: unknown, pointer: string): void => {\n if (typeof value === \"object\" && value !== null && !visited.has(value)) {\n visited.add(value);\n pending.push({ value, pointer });\n }\n };\n enqueue(document.parsed, \"#\");\n for (let node = pending.pop(); node !== undefined; node = pending.pop()) {\n for (const [key, child] of Object.entries(node.value)) {\n const pointer = `${node.pointer}/${escapePointerSegment(key)}`;\n if (UNSUPPORTED_KEYS.has(key)) {\n found.push({ key, pointer, source: document.source });\n }\n enqueue(child, pointer);\n }\n }\n return found;\n}\n\n/** Every unsupported key of the given documents. */\nexport function findUnsupportedKeys(documents: readonly LoadedDocument[]): UnsupportedKey[] {\n return documents.flatMap(unsupportedKeysOf);\n}\n\nfunction describeKey(found: UnsupportedKey): string {\n return `\"${found.key}\" at ${found.pointer} in ${found.source}`;\n}\n\n/** The typed error for the keys the schema loader failed on; `cause` is Redocly's `TypeError`. */\nexport function unsupportedKeysError(\n keys: readonly UnsupportedKey[],\n cause: unknown,\n): OpenAPITypesafeError {\n const listed = keys.slice(0, KEYS_IN_MESSAGE).map(describeKey);\n const more = keys.length > KEYS_IN_MESSAGE ? ` and ${keys.length - KEYS_IN_MESSAGE} more` : \"\";\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_KEY_UNSUPPORTED,\n message:\n \"The schema loader (Redocly 1.x) failed on a key named like a built-in object method. \" +\n `Rename it: ${listed.join(\", \")}${more}.`,\n details: { keys: keys.map((found) => ({ ...found })) },\n cause,\n });\n}\n"],"names":[],"mappings":";;AAWO,MAAM,gBAAA,uBAA4C,GAAA,CAAI;AAAA,EAC3D,gBAAA;AAAA,EACA,eAAA;AAAA,EACA,sBAAA;AAAA,EACA,gBAAA;AAAA,EACA,SAAA;AAAA,EACA,kBAAA;AAAA,EACA,kBAAA;AAAA,EACA,kBAAA;AAAA,EACA;AACF,CAAC;AAGD,MAAM,eAAA,GAAkB,CAAA;AAqBxB,SAAS,qBAAqB,OAAA,EAAyB;AACrD,EAAA,OAAO,QAAQ,UAAA,CAAW,GAAA,EAAK,IAAI,CAAA,CAAE,UAAA,CAAW,KAAK,IAAI,CAAA;AAC3D;AAOA,SAAS,kBAAkB,QAAA,EAA4C;AACrE,EAAA,MAAM,QAA0B,EAAC;AACjC,EAAA,MAAM,OAAA,uBAAc,OAAA,EAAgB;AACpC,EAAA,MAAM,UAAyB,EAAC;AAChC,EAAA,MAAM,OAAA,GAAU,CAAC,KAAA,EAAgB,OAAA,KAA0B;AACzD,IAAA,IAAI,OAAO,UAAU,QAAA,IAAY,KAAA,KAAU,QAAQ,CAAC,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA,EAAG;AACtE,MAAA,OAAA,CAAQ,IAAI,KAAK,CAAA;AACjB,MAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,KAAA,EAAO,OAAA,EAAS,CAAA;AAAA,IACjC;AAAA,EACF,CAAA;AACA,EAAA,OAAA,CAAQ,QAAA,CAAS,QAAQ,GAAG,CAAA;AAC5B,EAAA,KAAA,IAAS,IAAA,GAAO,QAAQ,GAAA,EAAI,EAAG,SAAS,MAAA,EAAW,IAAA,GAAO,OAAA,CAAQ,GAAA,EAAI,EAAG;AACvE,IAAA,KAAA,MAAW,CAAC,KAAK,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,EAAG;AACrD,MAAA,MAAM,UAAU,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,CAAA,EAAI,oBAAA,CAAqB,GAAG,CAAC,CAAA,CAAA;AAC5D,MAAA,IAAI,gBAAA,CAAiB,GAAA,CAAI,GAAG,CAAA,EAAG;AAC7B,QAAA,KAAA,CAAM,KAAK,EAAE,GAAA,EAAK,SAAS,MAAA,EAAQ,QAAA,CAAS,QAAQ,CAAA;AAAA,MACtD;AACA,MAAA,OAAA,CAAQ,OAAO,OAAO,CAAA;AAAA,IACxB;AAAA,EACF;AACA,EAAA,OAAO,KAAA;AACT;AAGO,SAAS,oBAAoB,SAAA,EAAwD;AAC1F,EAAA,OAAO,SAAA,CAAU,QAAQ,iBAAiB,CAAA;AAC5C;AAEA,SAAS,YAAY,KAAA,EAA+B;AAClD,EAAA,OAAO,CAAA,CAAA,EAAI,MAAM,GAAG,CAAA,KAAA,EAAQ,MAAM,OAAO,CAAA,IAAA,EAAO,MAAM,MAAM,CAAA,CAAA;AAC9D;AAGO,SAAS,oBAAA,CACd,MACA,KAAA,EACsB;AACtB,EAAA,MAAM,SAAS,IAAA,CAAK,KAAA,CAAM,GAAG,eAAe,CAAA,CAAE,IAAI,WAAW,CAAA;AAC7D,EAAA,MAAM,IAAA,GAAO,KAAK,MAAA,GAAS,eAAA,GAAkB,QAAQ,IAAA,CAAK,MAAA,GAAS,eAAe,CAAA,KAAA,CAAA,GAAU,EAAA;AAC5F,EAAA,OAAO,IAAI,oBAAA,CAAqB;AAAA,IAC9B,MAAM,WAAA,CAAY,sBAAA;AAAA,IAClB,SACE,CAAA,gGAAA,EACc,MAAA,CAAO,KAAK,IAAI,CAAC,GAAG,IAAI,CAAA,CAAA,CAAA;AAAA,IACxC,OAAA,EAAS,EAAE,IAAA,EAAM,IAAA,CAAK,GAAA,CAAI,CAAC,KAAA,MAAW,EAAE,GAAG,KAAA,EAAM,CAAE,CAAA,EAAE;AAAA,IACrD;AAAA,GACD,CAAA;AACH;;"}
1
+ {"version":3,"file":"unsupported-keys.mjs","sources":["../../../src/adapters/redocly-loader/unsupported-keys.ts"],"sourcesContent":["import { ERROR_CODES, OpenAPITypesafeError } from \"../../domain/errors.js\";\n\n/**\n * Keys Redocly 1.34 cannot walk. It looks up the type of every key with `type.properties[key]`,\n * which also finds inherited `Object.prototype` members; it then calls a found function with no\n * `this`, and these methods throw a `TypeError` for that. Redocly 2.x looks up own keys only\n * (ADR-005 keeps 1.34). `toString` does not throw, and loads as it should.\n *\n * Redocly does not walk every value (`default` and `const` are data), so a document with such a\n * key is not rejected up front: the loader looks for them only after Redocly threw a `TypeError`.\n */\nexport const UNSUPPORTED_KEYS: ReadonlySet<string> = new Set([\n \"hasOwnProperty\",\n \"isPrototypeOf\",\n \"propertyIsEnumerable\",\n \"toLocaleString\",\n \"valueOf\",\n \"__defineGetter__\",\n \"__defineSetter__\",\n \"__lookupGetter__\",\n \"__lookupSetter__\",\n]);\n\n/**\n * `constructor` finds `Object`, which returns the value it is called with. Redocly then takes the\n * value for a node type when it has a string `name` (a security scheme, a header with a `name`),\n * and fails reading the type's fields. Any other `constructor` key loads.\n */\nconst CONSTRUCTOR_KEY = \"constructor\";\n\nfunction isUnsupportedEntry(key: string, value: unknown): boolean {\n if (UNSUPPORTED_KEYS.has(key)) {\n return true;\n }\n const name = (value as { name?: unknown } | null | undefined)?.name;\n return key === CONSTRUCTOR_KEY && typeof value === \"object\" && typeof name === \"string\";\n}\n\n/** Enough found keys in the message to act on; `details.keys` has all of them. */\nconst KEYS_IN_MESSAGE = 5;\n\n/** A parsed document and where it was loaded from. */\nexport interface LoadedDocument {\n readonly source: string;\n readonly parsed: unknown;\n}\n\n/** An unsupported key: its JSON pointer and the document that has it. */\nexport interface UnsupportedKey {\n readonly key: string;\n readonly pointer: string;\n readonly source: string;\n}\n\ninterface PendingNode {\n readonly value: object;\n readonly pointer: string;\n}\n\n/** RFC 6901: `~` becomes `~0` and `/` becomes `~1`. */\nfunction escapePointerSegment(segment: string): string {\n return segment.replaceAll(\"~\", \"~0\").replaceAll(\"/\", \"~1\");\n}\n\n/**\n * The unsupported keys of one parsed document. The walk uses its own stack, so a deeply nested\n * document is checked without running out of call stack; nodes shared by YAML aliases are checked\n * once.\n */\nfunction unsupportedKeysOf(document: LoadedDocument): UnsupportedKey[] {\n const found: UnsupportedKey[] = [];\n const visited = new WeakSet<object>();\n const pending: PendingNode[] = [];\n const enqueue = (value: unknown, pointer: string): void => {\n if (typeof value === \"object\" && value !== null && !visited.has(value)) {\n visited.add(value);\n pending.push({ value, pointer });\n }\n };\n enqueue(document.parsed, \"#\");\n for (let node = pending.pop(); node !== undefined; node = pending.pop()) {\n for (const [key, child] of Object.entries(node.value)) {\n const pointer = `${node.pointer}/${escapePointerSegment(key)}`;\n if (isUnsupportedEntry(key, child)) {\n found.push({ key, pointer, source: document.source });\n }\n enqueue(child, pointer);\n }\n }\n return found;\n}\n\n/** Every unsupported key of the given documents. */\nexport function findUnsupportedKeys(documents: readonly LoadedDocument[]): UnsupportedKey[] {\n return documents.flatMap(unsupportedKeysOf);\n}\n\nfunction describeKey(found: UnsupportedKey): string {\n return `\"${found.key}\" at ${found.pointer} in ${found.source}`;\n}\n\n/** The typed error for the keys the schema loader failed on; `cause` is Redocly's `TypeError`. */\nexport function unsupportedKeysError(\n keys: readonly UnsupportedKey[],\n cause: unknown,\n): OpenAPITypesafeError {\n const listed = keys.slice(0, KEYS_IN_MESSAGE).map(describeKey);\n const more = keys.length > KEYS_IN_MESSAGE ? ` and ${keys.length - KEYS_IN_MESSAGE} more` : \"\";\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_KEY_UNSUPPORTED,\n message:\n \"The schema loader (Redocly 1.x) failed on a key named like a built-in object method. \" +\n `Rename it: ${listed.join(\", \")}${more}.`,\n details: { keys: keys.map((found) => ({ ...found })) },\n cause,\n });\n}\n"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const colors = require('ansi-colors');
4
+ const urlCredentials = require('../../domain/url-credentials.cjs');
4
5
 
5
6
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
6
7
 
@@ -45,16 +46,17 @@ class TerminalLogger {
45
46
  return;
46
47
  }
47
48
  const name = groupColor(this.#palette, group)(`openapi-ts:${group ?? "info"}`);
48
- const time = durationMs === void 0 ? "" : this.#palette.green(` ${formatDuration(durationMs)} `);
49
- this.#options.sink.debug(` ${this.#palette.bold(name)}${time}${message}`);
49
+ const time = durationMs === void 0 ? " " : this.#palette.green(` ${formatDuration(durationMs)} `);
50
+ const text = urlCredentials.redactUrlCredentials(message);
51
+ this.#options.sink.debug(` ${this.#palette.bold(name)}${time}${text}`);
50
52
  }
51
53
  warn(message) {
52
54
  if (!this.#options.silent) {
53
- this.#options.sink.warn(this.#palette.yellow(` \u26A0 ${message}`));
55
+ this.#options.sink.warn(this.#palette.yellow(` \u26A0 ${urlCredentials.redactUrlCredentials(message)}`));
54
56
  }
55
57
  }
56
58
  error(message) {
57
- this.#options.sink.error(this.#palette.red(` \u2718 ${message}`));
59
+ this.#options.sink.error(this.#palette.red(` \u2718 ${urlCredentials.redactUrlCredentials(message)}`));
58
60
  }
59
61
  }
60
62
  function createTerminalLogger(options) {
@@ -1 +1 @@
1
- {"version":3,"file":"terminal-logger.cjs","sources":["../../../src/adapters/terminal-logger/terminal-logger.ts"],"sourcesContent":["import colors from \"ansi-colors\";\nimport type { DebugGroup, Logger } from \"../../application/ports/logger.js\";\n\n/**\n * The Logger port on a terminal, with the original output format: ` ⚠ ` warnings, ` ✘ `\n * errors, and `openapi-ts:<group>` debug lines filtered by `DEBUG` (ENGINEERING_PLAN 4.5).\n */\n\n/** Where the lines go: `console` in production, a recording sink in tests. */\nexport interface TerminalSink {\n debug(line: string): void;\n warn(line: string): void;\n error(line: string): void;\n}\n\nexport interface TerminalLoggerOptions {\n /** Drop warnings (errors and debug lines are still written). */\n readonly silent: boolean;\n /** The value of `DEBUG`: `*`, `openapi-ts:*` or `openapi-ts:<group>` turn debug lines on. */\n readonly debugFilter: string | undefined;\n readonly useColors: boolean;\n readonly sink: TerminalSink;\n}\n\ntype Colors = ReturnType<typeof colors.create>;\n\nconst MILLISECONDS_PER_SECOND = 1000;\nconst MILLISECONDS_PER_MINUTE = 60_000;\n\n/** A duration as the original prints it: one decimal, in ms, s or m. */\nexport function formatDuration(milliseconds: number): string {\n if (milliseconds < MILLISECONDS_PER_SECOND) {\n return `${Math.round(10 * milliseconds) / 10}ms`;\n }\n if (milliseconds < MILLISECONDS_PER_MINUTE) {\n return `${Math.round(milliseconds / 100) / 10}s`;\n }\n return `${Math.round(milliseconds / 6000) / 10}m`;\n}\n\nfunction groupColor(palette: Colors, group: DebugGroup | undefined): (text: string) => string {\n const byGroup: Readonly<Partial<Record<DebugGroup, (text: string) => string>>> = {\n redoc: palette.cyanBright,\n lint: palette.yellowBright,\n bundle: palette.magentaBright,\n ts: palette.blueBright,\n };\n return (group && byGroup[group]) || palette.whiteBright;\n}\n\n/** Whether `DEBUG` asks for this group (the original check, case-insensitive for the group). */\nexport function isDebugEnabled(filter: string | undefined, group: DebugGroup | undefined): boolean {\n if (!filter) {\n return false;\n }\n return (\n !group ||\n filter === \"*\" ||\n filter === \"openapi-ts:*\" ||\n filter.toLocaleLowerCase() === `openapi-ts:${group.toLocaleLowerCase()}`\n );\n}\n\nclass TerminalLogger implements Logger {\n readonly #options: TerminalLoggerOptions;\n readonly #palette: Colors;\n\n constructor(options: TerminalLoggerOptions) {\n this.#options = options;\n this.#palette = colors.create();\n this.#palette.enabled = options.useColors;\n }\n\n debug(message: string, group?: DebugGroup, durationMs?: number): void {\n if (!isDebugEnabled(this.#options.debugFilter, group)) {\n return;\n }\n const name = groupColor(this.#palette, group)(`openapi-ts:${group ?? \"info\"}`);\n const time =\n durationMs === undefined ? \"\" : this.#palette.green(` ${formatDuration(durationMs)} `);\n this.#options.sink.debug(` ${this.#palette.bold(name)}${time}${message}`);\n }\n\n warn(message: string): void {\n if (!this.#options.silent) {\n this.#options.sink.warn(this.#palette.yellow(` ⚠ ${message}`));\n }\n }\n\n error(message: string): void {\n this.#options.sink.error(this.#palette.red(` ✘ ${message}`));\n }\n}\n\n/** A Logger that writes to a terminal sink. */\nexport function createTerminalLogger(options: TerminalLoggerOptions): Logger {\n return new TerminalLogger(options);\n}\n"],"names":["colors"],"mappings":"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"}
1
+ {"version":3,"file":"terminal-logger.cjs","sources":["../../../src/adapters/terminal-logger/terminal-logger.ts"],"sourcesContent":["import colors from \"ansi-colors\";\nimport type { DebugGroup, Logger } from \"../../application/ports/logger.js\";\nimport { redactUrlCredentials } from \"../../domain/url-credentials.js\";\n\n/**\n * The Logger port on a terminal, with the original output format: ` ⚠ ` warnings, ` ✘ `\n * errors, and `openapi-ts:<group>` debug lines filtered by `DEBUG` (ENGINEERING_PLAN 4.5). No\n * line shows the user info of a URL.\n */\n\n/** Where the lines go: `console` in production, a recording sink in tests. */\nexport interface TerminalSink {\n debug(line: string): void;\n warn(line: string): void;\n error(line: string): void;\n}\n\nexport interface TerminalLoggerOptions {\n /** Drop warnings (errors and debug lines are still written). */\n readonly silent: boolean;\n /** The value of `DEBUG`: `*`, `openapi-ts:*` or `openapi-ts:<group>` turn debug lines on. */\n readonly debugFilter: string | undefined;\n readonly useColors: boolean;\n readonly sink: TerminalSink;\n}\n\ntype Colors = ReturnType<typeof colors.create>;\n\nconst MILLISECONDS_PER_SECOND = 1000;\nconst MILLISECONDS_PER_MINUTE = 60_000;\n\n/** A duration as the original prints it: one decimal, in ms, s or m. */\nexport function formatDuration(milliseconds: number): string {\n if (milliseconds < MILLISECONDS_PER_SECOND) {\n return `${Math.round(10 * milliseconds) / 10}ms`;\n }\n if (milliseconds < MILLISECONDS_PER_MINUTE) {\n return `${Math.round(milliseconds / 100) / 10}s`;\n }\n return `${Math.round(milliseconds / 6000) / 10}m`;\n}\n\nfunction groupColor(palette: Colors, group: DebugGroup | undefined): (text: string) => string {\n const byGroup: Readonly<Partial<Record<DebugGroup, (text: string) => string>>> = {\n redoc: palette.cyanBright,\n lint: palette.yellowBright,\n bundle: palette.magentaBright,\n ts: palette.blueBright,\n };\n return (group && byGroup[group]) || palette.whiteBright;\n}\n\n/** Whether `DEBUG` asks for this group (the original check, case-insensitive for the group). */\nexport function isDebugEnabled(filter: string | undefined, group: DebugGroup | undefined): boolean {\n if (!filter) {\n return false;\n }\n return (\n !group ||\n filter === \"*\" ||\n filter === \"openapi-ts:*\" ||\n filter.toLocaleLowerCase() === `openapi-ts:${group.toLocaleLowerCase()}`\n );\n}\n\nclass TerminalLogger implements Logger {\n readonly #options: TerminalLoggerOptions;\n readonly #palette: Colors;\n\n constructor(options: TerminalLoggerOptions) {\n this.#options = options;\n this.#palette = colors.create();\n this.#palette.enabled = options.useColors;\n }\n\n debug(message: string, group?: DebugGroup, durationMs?: number): void {\n if (!isDebugEnabled(this.#options.debugFilter, group)) {\n return;\n }\n const name = groupColor(this.#palette, group)(`openapi-ts:${group ?? \"info\"}`);\n // The original wrote no space without a duration (`openapi-ts:lintIgnored …`).\n const time =\n durationMs === undefined ? \" \" : this.#palette.green(` ${formatDuration(durationMs)} `);\n const text = redactUrlCredentials(message);\n this.#options.sink.debug(` ${this.#palette.bold(name)}${time}${text}`);\n }\n\n warn(message: string): void {\n if (!this.#options.silent) {\n this.#options.sink.warn(this.#palette.yellow(` ⚠ ${redactUrlCredentials(message)}`));\n }\n }\n\n error(message: string): void {\n this.#options.sink.error(this.#palette.red(` ✘ ${redactUrlCredentials(message)}`));\n }\n}\n\n/** A Logger that writes to a terminal sink. */\nexport function createTerminalLogger(options: TerminalLoggerOptions): Logger {\n return new TerminalLogger(options);\n}\n"],"names":["colors","redactUrlCredentials"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import colors from 'ansi-colors';
2
+ import { redactUrlCredentials } from '../../domain/url-credentials.mjs';
2
3
 
3
4
  const MILLISECONDS_PER_SECOND = 1e3;
4
5
  const MILLISECONDS_PER_MINUTE = 6e4;
@@ -39,16 +40,17 @@ class TerminalLogger {
39
40
  return;
40
41
  }
41
42
  const name = groupColor(this.#palette, group)(`openapi-ts:${group ?? "info"}`);
42
- const time = durationMs === void 0 ? "" : this.#palette.green(` ${formatDuration(durationMs)} `);
43
- this.#options.sink.debug(` ${this.#palette.bold(name)}${time}${message}`);
43
+ const time = durationMs === void 0 ? " " : this.#palette.green(` ${formatDuration(durationMs)} `);
44
+ const text = redactUrlCredentials(message);
45
+ this.#options.sink.debug(` ${this.#palette.bold(name)}${time}${text}`);
44
46
  }
45
47
  warn(message) {
46
48
  if (!this.#options.silent) {
47
- this.#options.sink.warn(this.#palette.yellow(` \u26A0 ${message}`));
49
+ this.#options.sink.warn(this.#palette.yellow(` \u26A0 ${redactUrlCredentials(message)}`));
48
50
  }
49
51
  }
50
52
  error(message) {
51
- this.#options.sink.error(this.#palette.red(` \u2718 ${message}`));
53
+ this.#options.sink.error(this.#palette.red(` \u2718 ${redactUrlCredentials(message)}`));
52
54
  }
53
55
  }
54
56
  function createTerminalLogger(options) {
@@ -1 +1 @@
1
- {"version":3,"file":"terminal-logger.mjs","sources":["../../../src/adapters/terminal-logger/terminal-logger.ts"],"sourcesContent":["import colors from \"ansi-colors\";\nimport type { DebugGroup, Logger } from \"../../application/ports/logger.js\";\n\n/**\n * The Logger port on a terminal, with the original output format: ` ⚠ ` warnings, ` ✘ `\n * errors, and `openapi-ts:<group>` debug lines filtered by `DEBUG` (ENGINEERING_PLAN 4.5).\n */\n\n/** Where the lines go: `console` in production, a recording sink in tests. */\nexport interface TerminalSink {\n debug(line: string): void;\n warn(line: string): void;\n error(line: string): void;\n}\n\nexport interface TerminalLoggerOptions {\n /** Drop warnings (errors and debug lines are still written). */\n readonly silent: boolean;\n /** The value of `DEBUG`: `*`, `openapi-ts:*` or `openapi-ts:<group>` turn debug lines on. */\n readonly debugFilter: string | undefined;\n readonly useColors: boolean;\n readonly sink: TerminalSink;\n}\n\ntype Colors = ReturnType<typeof colors.create>;\n\nconst MILLISECONDS_PER_SECOND = 1000;\nconst MILLISECONDS_PER_MINUTE = 60_000;\n\n/** A duration as the original prints it: one decimal, in ms, s or m. */\nexport function formatDuration(milliseconds: number): string {\n if (milliseconds < MILLISECONDS_PER_SECOND) {\n return `${Math.round(10 * milliseconds) / 10}ms`;\n }\n if (milliseconds < MILLISECONDS_PER_MINUTE) {\n return `${Math.round(milliseconds / 100) / 10}s`;\n }\n return `${Math.round(milliseconds / 6000) / 10}m`;\n}\n\nfunction groupColor(palette: Colors, group: DebugGroup | undefined): (text: string) => string {\n const byGroup: Readonly<Partial<Record<DebugGroup, (text: string) => string>>> = {\n redoc: palette.cyanBright,\n lint: palette.yellowBright,\n bundle: palette.magentaBright,\n ts: palette.blueBright,\n };\n return (group && byGroup[group]) || palette.whiteBright;\n}\n\n/** Whether `DEBUG` asks for this group (the original check, case-insensitive for the group). */\nexport function isDebugEnabled(filter: string | undefined, group: DebugGroup | undefined): boolean {\n if (!filter) {\n return false;\n }\n return (\n !group ||\n filter === \"*\" ||\n filter === \"openapi-ts:*\" ||\n filter.toLocaleLowerCase() === `openapi-ts:${group.toLocaleLowerCase()}`\n );\n}\n\nclass TerminalLogger implements Logger {\n readonly #options: TerminalLoggerOptions;\n readonly #palette: Colors;\n\n constructor(options: TerminalLoggerOptions) {\n this.#options = options;\n this.#palette = colors.create();\n this.#palette.enabled = options.useColors;\n }\n\n debug(message: string, group?: DebugGroup, durationMs?: number): void {\n if (!isDebugEnabled(this.#options.debugFilter, group)) {\n return;\n }\n const name = groupColor(this.#palette, group)(`openapi-ts:${group ?? \"info\"}`);\n const time =\n durationMs === undefined ? \"\" : this.#palette.green(` ${formatDuration(durationMs)} `);\n this.#options.sink.debug(` ${this.#palette.bold(name)}${time}${message}`);\n }\n\n warn(message: string): void {\n if (!this.#options.silent) {\n this.#options.sink.warn(this.#palette.yellow(` ⚠ ${message}`));\n }\n }\n\n error(message: string): void {\n this.#options.sink.error(this.#palette.red(` ✘ ${message}`));\n }\n}\n\n/** A Logger that writes to a terminal sink. */\nexport function createTerminalLogger(options: TerminalLoggerOptions): Logger {\n return new TerminalLogger(options);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"terminal-logger.mjs","sources":["../../../src/adapters/terminal-logger/terminal-logger.ts"],"sourcesContent":["import colors from \"ansi-colors\";\nimport type { DebugGroup, Logger } from \"../../application/ports/logger.js\";\nimport { redactUrlCredentials } from \"../../domain/url-credentials.js\";\n\n/**\n * The Logger port on a terminal, with the original output format: ` ⚠ ` warnings, ` ✘ `\n * errors, and `openapi-ts:<group>` debug lines filtered by `DEBUG` (ENGINEERING_PLAN 4.5). No\n * line shows the user info of a URL.\n */\n\n/** Where the lines go: `console` in production, a recording sink in tests. */\nexport interface TerminalSink {\n debug(line: string): void;\n warn(line: string): void;\n error(line: string): void;\n}\n\nexport interface TerminalLoggerOptions {\n /** Drop warnings (errors and debug lines are still written). */\n readonly silent: boolean;\n /** The value of `DEBUG`: `*`, `openapi-ts:*` or `openapi-ts:<group>` turn debug lines on. */\n readonly debugFilter: string | undefined;\n readonly useColors: boolean;\n readonly sink: TerminalSink;\n}\n\ntype Colors = ReturnType<typeof colors.create>;\n\nconst MILLISECONDS_PER_SECOND = 1000;\nconst MILLISECONDS_PER_MINUTE = 60_000;\n\n/** A duration as the original prints it: one decimal, in ms, s or m. */\nexport function formatDuration(milliseconds: number): string {\n if (milliseconds < MILLISECONDS_PER_SECOND) {\n return `${Math.round(10 * milliseconds) / 10}ms`;\n }\n if (milliseconds < MILLISECONDS_PER_MINUTE) {\n return `${Math.round(milliseconds / 100) / 10}s`;\n }\n return `${Math.round(milliseconds / 6000) / 10}m`;\n}\n\nfunction groupColor(palette: Colors, group: DebugGroup | undefined): (text: string) => string {\n const byGroup: Readonly<Partial<Record<DebugGroup, (text: string) => string>>> = {\n redoc: palette.cyanBright,\n lint: palette.yellowBright,\n bundle: palette.magentaBright,\n ts: palette.blueBright,\n };\n return (group && byGroup[group]) || palette.whiteBright;\n}\n\n/** Whether `DEBUG` asks for this group (the original check, case-insensitive for the group). */\nexport function isDebugEnabled(filter: string | undefined, group: DebugGroup | undefined): boolean {\n if (!filter) {\n return false;\n }\n return (\n !group ||\n filter === \"*\" ||\n filter === \"openapi-ts:*\" ||\n filter.toLocaleLowerCase() === `openapi-ts:${group.toLocaleLowerCase()}`\n );\n}\n\nclass TerminalLogger implements Logger {\n readonly #options: TerminalLoggerOptions;\n readonly #palette: Colors;\n\n constructor(options: TerminalLoggerOptions) {\n this.#options = options;\n this.#palette = colors.create();\n this.#palette.enabled = options.useColors;\n }\n\n debug(message: string, group?: DebugGroup, durationMs?: number): void {\n if (!isDebugEnabled(this.#options.debugFilter, group)) {\n return;\n }\n const name = groupColor(this.#palette, group)(`openapi-ts:${group ?? \"info\"}`);\n // The original wrote no space without a duration (`openapi-ts:lintIgnored …`).\n const time =\n durationMs === undefined ? \" \" : this.#palette.green(` ${formatDuration(durationMs)} `);\n const text = redactUrlCredentials(message);\n this.#options.sink.debug(` ${this.#palette.bold(name)}${time}${text}`);\n }\n\n warn(message: string): void {\n if (!this.#options.silent) {\n this.#options.sink.warn(this.#palette.yellow(` ⚠ ${redactUrlCredentials(message)}`));\n }\n }\n\n error(message: string): void {\n this.#options.sink.error(this.#palette.red(` ✘ ${redactUrlCredentials(message)}`));\n }\n}\n\n/** A Logger that writes to a terminal sink. */\nexport function createTerminalLogger(options: TerminalLoggerOptions): Logger {\n return new TerminalLogger(options);\n}\n"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const assertNever = require('../../domain/assert-never.cjs');
4
+ const constructors = require('../../domain/ir/constructors.cjs');
4
5
 
5
6
  function keywordKind(ts, keyword) {
6
7
  const kinds = {
@@ -40,7 +41,7 @@ function toLeafTypeNode(ts, type) {
40
41
  case "keyword":
41
42
  return toKeywordType(ts, type.keyword);
42
43
  case "stringLiteral":
43
- return toStringLiteralType(ts, type.value, type.encoding);
44
+ return toStringLiteralType(ts, type.value, type.encoding ?? constructors.DEFAULT_STRING_ENCODING);
44
45
  case "numberLiteral":
45
46
  return ts.factory.createLiteralTypeNode(toNumberExpression(ts, type.value));
46
47
  case "booleanLiteral":
@@ -1 +1 @@
1
- {"version":3,"file":"ir-to-typescript.cjs","sources":["../../../src/adapters/type-ast-bridge/ir-to-typescript.ts"],"sourcesContent":["import type ts from \"typescript\";\nimport { assertNever } from \"../../domain/assert-never.js\";\nimport type {\n IrComment,\n IrKeyword,\n IrMember,\n IrPropertyName,\n IrPropertySignature,\n IrTupleElement,\n IrType,\n} from \"../../domain/ir/nodes.js\";\nimport type { TypeScriptModule } from \"./load-typescript.js\";\n\n/**\n * Convert IR to TypeScript AST nodes with the same factory calls the original generator makes.\n * Printing the result with the TypeScript printer gives the original output, which is how the\n * printer parity tests (ENGINEERING_PLAN 4.3) define \"byte-identical\". Every function takes the\n * TypeScript module to build with (ADR-004, decision 4): the nodes must come from the same module\n * that later reads or prints them.\n */\n\ntype KeywordName = Exclude<IrKeyword, \"null\">;\n\nfunction keywordKind(ts: TypeScriptModule, keyword: KeywordName): ts.KeywordTypeSyntaxKind {\n const kinds: Readonly<Record<KeywordName, ts.KeywordTypeSyntaxKind>> = {\n string: ts.SyntaxKind.StringKeyword,\n number: ts.SyntaxKind.NumberKeyword,\n boolean: ts.SyntaxKind.BooleanKeyword,\n undefined: ts.SyntaxKind.UndefinedKeyword,\n unknown: ts.SyntaxKind.UnknownKeyword,\n never: ts.SyntaxKind.NeverKeyword,\n };\n return kinds[keyword];\n}\n\nfunction toKeywordType(ts: TypeScriptModule, keyword: IrKeyword): ts.TypeNode {\n return keyword === \"null\"\n ? ts.factory.createLiteralTypeNode(ts.factory.createNull())\n : ts.factory.createKeywordTypeNode(keywordKind(ts, keyword));\n}\n\n/**\n * Numbers as the original writes them: a negative value is a prefix minus on its absolute value.\n */\nfunction toNumberExpression(\n ts: TypeScriptModule,\n value: number,\n): ts.PrefixUnaryExpression | ts.NumericLiteral {\n return value < 0\n ? ts.factory.createPrefixUnaryExpression(\n ts.SyntaxKind.MinusToken,\n ts.factory.createNumericLiteral(Math.abs(value)),\n )\n : ts.factory.createNumericLiteral(value);\n}\n\n/** An enum member or array element value, written as the original writes it. */\nexport function toValueExpression(ts: TypeScriptModule, value: string | number): ts.Expression {\n return typeof value === \"number\"\n ? toNumberExpression(ts, value)\n : ts.factory.createStringLiteral(value);\n}\n\n/** The original writes JSON-encoded literal types as identifiers to keep UTF-8 readable. */\nfunction toStringLiteralType(\n ts: TypeScriptModule,\n value: string,\n encoding: \"json\" | \"escaped\",\n): ts.TypeNode {\n return encoding === \"json\"\n ? (ts.factory.createIdentifier(JSON.stringify(value)) as unknown as ts.TypeNode)\n : ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(value));\n}\n\nfunction toTupleElement(ts: TypeScriptModule, element: IrTupleElement): ts.TypeNode {\n const type = toTypeNode(ts, element.type);\n if (element.isOptional) {\n return ts.factory.createOptionalTypeNode(type);\n }\n return element.isRest ? ts.factory.createRestTypeNode(type) : type;\n}\n\ntype LeafType = Extract<\n IrType,\n { kind: \"keyword\" | \"stringLiteral\" | \"numberLiteral\" | \"booleanLiteral\" | \"raw\" }\n>;\n\nfunction toLeafTypeNode(ts: TypeScriptModule, type: LeafType): ts.TypeNode {\n switch (type.kind) {\n case \"keyword\":\n return toKeywordType(ts, type.keyword);\n case \"stringLiteral\":\n return toStringLiteralType(ts, type.value, type.encoding);\n case \"numberLiteral\":\n return ts.factory.createLiteralTypeNode(toNumberExpression(ts, type.value));\n case \"booleanLiteral\":\n return ts.factory.createLiteralTypeNode(\n type.value ? ts.factory.createTrue() : ts.factory.createFalse(),\n );\n case \"raw\":\n // A node read from TypeScript goes back as it was, so the TypeScript printer indents it.\n return (\n (type.origin as ts.TypeNode | undefined) ??\n (ts.factory.createIdentifier(type.text) as unknown as ts.TypeNode)\n );\n default:\n return assertNever(type);\n }\n}\n\nfunction toReferenceNode(\n ts: TypeScriptModule,\n type: Extract<IrType, { kind: \"reference\" }>,\n): ts.TypeNode {\n const typeArguments =\n type.typeArguments.length > 0\n ? type.typeArguments.map((argument) => toTypeNode(ts, argument))\n : undefined;\n return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(type.name), typeArguments);\n}\n\n/** Convert one IR type. */\nexport function toTypeNode(ts: TypeScriptModule, type: IrType): ts.TypeNode {\n const convert = (inner: IrType) => toTypeNode(ts, inner);\n const { factory } = ts;\n switch (type.kind) {\n case \"keyword\":\n case \"stringLiteral\":\n case \"numberLiteral\":\n case \"booleanLiteral\":\n case \"raw\":\n return toLeafTypeNode(ts, type);\n case \"reference\":\n return toReferenceNode(ts, type);\n case \"array\":\n return factory.createArrayTypeNode(convert(type.element));\n case \"tuple\":\n return factory.createTupleTypeNode(\n type.elements.map((element) => toTupleElement(ts, element)),\n );\n case \"union\":\n return factory.createUnionTypeNode(type.types.map(convert));\n case \"intersection\":\n return factory.createIntersectionTypeNode(type.types.map(convert));\n case \"object\":\n return factory.createTypeLiteralNode(type.members.map((member) => toTypeElement(ts, member)));\n case \"indexedAccess\":\n return factory.createIndexedAccessTypeNode(convert(type.object), convert(type.index));\n case \"readonly\":\n return factory.createTypeOperatorNode(ts.SyntaxKind.ReadonlyKeyword, convert(type.type));\n default:\n return assertNever(type);\n }\n}\n\n/** Attach IR comments to a node as synthetic leading comments, as the original does. */\nexport function withComments<T extends ts.Node>(\n ts: TypeScriptModule,\n node: T,\n comments: readonly IrComment[],\n): T {\n for (const comment of comments) {\n const kind =\n comment.kind === \"block\"\n ? ts.SyntaxKind.MultiLineCommentTrivia\n : ts.SyntaxKind.SingleLineCommentTrivia;\n ts.addSyntheticLeadingComment(node, kind, comment.text, true);\n }\n return node;\n}\n\nfunction toPropertyName(ts: TypeScriptModule, name: IrPropertyName): ts.PropertyName {\n switch (name.kind) {\n case \"identifier\":\n return ts.factory.createIdentifier(name.text);\n case \"string\":\n return ts.factory.createStringLiteral(name.value);\n case \"number\":\n return ts.factory.createNumericLiteral(name.text);\n default:\n return assertNever(name);\n }\n}\n\nfunction readonlyModifiers(ts: TypeScriptModule, isReadonly: boolean): ts.Modifier[] | undefined {\n return isReadonly ? [ts.factory.createModifier(ts.SyntaxKind.ReadonlyKeyword)] : undefined;\n}\n\n/** Convert one property signature (for callbacks that receive a `ts.PropertySignature`). */\nexport function toPropertySignature(\n ts: TypeScriptModule,\n property: IrPropertySignature,\n): ts.PropertySignature {\n const questionToken = property.isOptional\n ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)\n : undefined;\n const signature = ts.factory.createPropertySignature(\n readonlyModifiers(ts, property.isReadonly),\n toPropertyName(ts, property.name),\n questionToken,\n toTypeNode(ts, property.type),\n );\n return withComments(ts, signature, property.comments);\n}\n\nexport function toTypeElement(ts: TypeScriptModule, member: IrMember): ts.TypeElement {\n if (member.kind === \"property\") {\n return toPropertySignature(ts, member);\n }\n const parameter = ts.factory.createParameterDeclaration(\n undefined,\n undefined,\n member.parameterName,\n undefined,\n toTypeNode(ts, member.parameterType),\n );\n const signature = ts.factory.createIndexSignature(\n readonlyModifiers(ts, member.isReadonly),\n [parameter],\n toTypeNode(ts, member.type),\n );\n return withComments(ts, signature, member.comments);\n}\n"],"names":["assertNever"],"mappings":"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"}
1
+ {"version":3,"file":"ir-to-typescript.cjs","sources":["../../../src/adapters/type-ast-bridge/ir-to-typescript.ts"],"sourcesContent":["import type ts from \"typescript\";\nimport { assertNever } from \"../../domain/assert-never.js\";\nimport { DEFAULT_STRING_ENCODING } from \"../../domain/ir/constructors.js\";\nimport type {\n IrComment,\n IrKeyword,\n IrMember,\n IrPropertyName,\n IrPropertySignature,\n IrTupleElement,\n IrType,\n} from \"../../domain/ir/nodes.js\";\nimport type { TypeScriptModule } from \"./load-typescript.js\";\n\n/**\n * Convert IR to TypeScript AST nodes with the same factory calls the original generator makes.\n * Printing the result with the TypeScript printer gives the original output, which is how the\n * printer parity tests (ENGINEERING_PLAN 4.3) define \"byte-identical\". Every function takes the\n * TypeScript module to build with (ADR-004, decision 4): the nodes must come from the same module\n * that later reads or prints them.\n */\n\ntype KeywordName = Exclude<IrKeyword, \"null\">;\n\nfunction keywordKind(ts: TypeScriptModule, keyword: KeywordName): ts.KeywordTypeSyntaxKind {\n const kinds: Readonly<Record<KeywordName, ts.KeywordTypeSyntaxKind>> = {\n string: ts.SyntaxKind.StringKeyword,\n number: ts.SyntaxKind.NumberKeyword,\n boolean: ts.SyntaxKind.BooleanKeyword,\n undefined: ts.SyntaxKind.UndefinedKeyword,\n unknown: ts.SyntaxKind.UnknownKeyword,\n never: ts.SyntaxKind.NeverKeyword,\n };\n return kinds[keyword];\n}\n\nfunction toKeywordType(ts: TypeScriptModule, keyword: IrKeyword): ts.TypeNode {\n return keyword === \"null\"\n ? ts.factory.createLiteralTypeNode(ts.factory.createNull())\n : ts.factory.createKeywordTypeNode(keywordKind(ts, keyword));\n}\n\n/**\n * Numbers as the original writes them: a negative value is a prefix minus on its absolute value.\n */\nfunction toNumberExpression(\n ts: TypeScriptModule,\n value: number,\n): ts.PrefixUnaryExpression | ts.NumericLiteral {\n return value < 0\n ? ts.factory.createPrefixUnaryExpression(\n ts.SyntaxKind.MinusToken,\n ts.factory.createNumericLiteral(Math.abs(value)),\n )\n : ts.factory.createNumericLiteral(value);\n}\n\n/** An enum member or array element value, written as the original writes it. */\nexport function toValueExpression(ts: TypeScriptModule, value: string | number): ts.Expression {\n return typeof value === \"number\"\n ? toNumberExpression(ts, value)\n : ts.factory.createStringLiteral(value);\n}\n\n/** The original writes JSON-encoded literal types as identifiers to keep UTF-8 readable. */\nfunction toStringLiteralType(\n ts: TypeScriptModule,\n value: string,\n encoding: \"json\" | \"escaped\",\n): ts.TypeNode {\n return encoding === \"json\"\n ? (ts.factory.createIdentifier(JSON.stringify(value)) as unknown as ts.TypeNode)\n : ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(value));\n}\n\nfunction toTupleElement(ts: TypeScriptModule, element: IrTupleElement): ts.TypeNode {\n const type = toTypeNode(ts, element.type);\n if (element.isOptional) {\n return ts.factory.createOptionalTypeNode(type);\n }\n return element.isRest ? ts.factory.createRestTypeNode(type) : type;\n}\n\ntype LeafType = Extract<\n IrType,\n { kind: \"keyword\" | \"stringLiteral\" | \"numberLiteral\" | \"booleanLiteral\" | \"raw\" }\n>;\n\nfunction toLeafTypeNode(ts: TypeScriptModule, type: LeafType): ts.TypeNode {\n switch (type.kind) {\n case \"keyword\":\n return toKeywordType(ts, type.keyword);\n case \"stringLiteral\":\n return toStringLiteralType(ts, type.value, type.encoding ?? DEFAULT_STRING_ENCODING);\n case \"numberLiteral\":\n return ts.factory.createLiteralTypeNode(toNumberExpression(ts, type.value));\n case \"booleanLiteral\":\n return ts.factory.createLiteralTypeNode(\n type.value ? ts.factory.createTrue() : ts.factory.createFalse(),\n );\n case \"raw\":\n // A node read from TypeScript goes back as it was, so the TypeScript printer indents it.\n return (\n (type.origin as ts.TypeNode | undefined) ??\n (ts.factory.createIdentifier(type.text) as unknown as ts.TypeNode)\n );\n default:\n return assertNever(type);\n }\n}\n\nfunction toReferenceNode(\n ts: TypeScriptModule,\n type: Extract<IrType, { kind: \"reference\" }>,\n): ts.TypeNode {\n const typeArguments =\n type.typeArguments.length > 0\n ? type.typeArguments.map((argument) => toTypeNode(ts, argument))\n : undefined;\n return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(type.name), typeArguments);\n}\n\n/** Convert one IR type. */\nexport function toTypeNode(ts: TypeScriptModule, type: IrType): ts.TypeNode {\n const convert = (inner: IrType) => toTypeNode(ts, inner);\n const { factory } = ts;\n switch (type.kind) {\n case \"keyword\":\n case \"stringLiteral\":\n case \"numberLiteral\":\n case \"booleanLiteral\":\n case \"raw\":\n return toLeafTypeNode(ts, type);\n case \"reference\":\n return toReferenceNode(ts, type);\n case \"array\":\n return factory.createArrayTypeNode(convert(type.element));\n case \"tuple\":\n return factory.createTupleTypeNode(\n type.elements.map((element) => toTupleElement(ts, element)),\n );\n case \"union\":\n return factory.createUnionTypeNode(type.types.map(convert));\n case \"intersection\":\n return factory.createIntersectionTypeNode(type.types.map(convert));\n case \"object\":\n return factory.createTypeLiteralNode(type.members.map((member) => toTypeElement(ts, member)));\n case \"indexedAccess\":\n return factory.createIndexedAccessTypeNode(convert(type.object), convert(type.index));\n case \"readonly\":\n return factory.createTypeOperatorNode(ts.SyntaxKind.ReadonlyKeyword, convert(type.type));\n default:\n return assertNever(type);\n }\n}\n\n/** Attach IR comments to a node as synthetic leading comments, as the original does. */\nexport function withComments<T extends ts.Node>(\n ts: TypeScriptModule,\n node: T,\n comments: readonly IrComment[],\n): T {\n for (const comment of comments) {\n const kind =\n comment.kind === \"block\"\n ? ts.SyntaxKind.MultiLineCommentTrivia\n : ts.SyntaxKind.SingleLineCommentTrivia;\n ts.addSyntheticLeadingComment(node, kind, comment.text, true);\n }\n return node;\n}\n\nfunction toPropertyName(ts: TypeScriptModule, name: IrPropertyName): ts.PropertyName {\n switch (name.kind) {\n case \"identifier\":\n return ts.factory.createIdentifier(name.text);\n case \"string\":\n return ts.factory.createStringLiteral(name.value);\n case \"number\":\n return ts.factory.createNumericLiteral(name.text);\n default:\n return assertNever(name);\n }\n}\n\nfunction readonlyModifiers(ts: TypeScriptModule, isReadonly: boolean): ts.Modifier[] | undefined {\n return isReadonly ? [ts.factory.createModifier(ts.SyntaxKind.ReadonlyKeyword)] : undefined;\n}\n\n/** Convert one property signature (for callbacks that receive a `ts.PropertySignature`). */\nexport function toPropertySignature(\n ts: TypeScriptModule,\n property: IrPropertySignature,\n): ts.PropertySignature {\n const questionToken = property.isOptional\n ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)\n : undefined;\n const signature = ts.factory.createPropertySignature(\n readonlyModifiers(ts, property.isReadonly),\n toPropertyName(ts, property.name),\n questionToken,\n toTypeNode(ts, property.type),\n );\n return withComments(ts, signature, property.comments);\n}\n\nexport function toTypeElement(ts: TypeScriptModule, member: IrMember): ts.TypeElement {\n if (member.kind === \"property\") {\n return toPropertySignature(ts, member);\n }\n const parameter = ts.factory.createParameterDeclaration(\n undefined,\n undefined,\n member.parameterName,\n undefined,\n toTypeNode(ts, member.parameterType),\n );\n const signature = ts.factory.createIndexSignature(\n readonlyModifiers(ts, member.isReadonly),\n [parameter],\n toTypeNode(ts, member.type),\n );\n return withComments(ts, signature, member.comments);\n}\n"],"names":["DEFAULT_STRING_ENCODING","assertNever"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { assertNever } from '../../domain/assert-never.mjs';
2
+ import { DEFAULT_STRING_ENCODING } from '../../domain/ir/constructors.mjs';
2
3
 
3
4
  function keywordKind(ts, keyword) {
4
5
  const kinds = {
@@ -38,7 +39,7 @@ function toLeafTypeNode(ts, type) {
38
39
  case "keyword":
39
40
  return toKeywordType(ts, type.keyword);
40
41
  case "stringLiteral":
41
- return toStringLiteralType(ts, type.value, type.encoding);
42
+ return toStringLiteralType(ts, type.value, type.encoding ?? DEFAULT_STRING_ENCODING);
42
43
  case "numberLiteral":
43
44
  return ts.factory.createLiteralTypeNode(toNumberExpression(ts, type.value));
44
45
  case "booleanLiteral":
@@ -1 +1 @@
1
- {"version":3,"file":"ir-to-typescript.mjs","sources":["../../../src/adapters/type-ast-bridge/ir-to-typescript.ts"],"sourcesContent":["import type ts from \"typescript\";\nimport { assertNever } from \"../../domain/assert-never.js\";\nimport type {\n IrComment,\n IrKeyword,\n IrMember,\n IrPropertyName,\n IrPropertySignature,\n IrTupleElement,\n IrType,\n} from \"../../domain/ir/nodes.js\";\nimport type { TypeScriptModule } from \"./load-typescript.js\";\n\n/**\n * Convert IR to TypeScript AST nodes with the same factory calls the original generator makes.\n * Printing the result with the TypeScript printer gives the original output, which is how the\n * printer parity tests (ENGINEERING_PLAN 4.3) define \"byte-identical\". Every function takes the\n * TypeScript module to build with (ADR-004, decision 4): the nodes must come from the same module\n * that later reads or prints them.\n */\n\ntype KeywordName = Exclude<IrKeyword, \"null\">;\n\nfunction keywordKind(ts: TypeScriptModule, keyword: KeywordName): ts.KeywordTypeSyntaxKind {\n const kinds: Readonly<Record<KeywordName, ts.KeywordTypeSyntaxKind>> = {\n string: ts.SyntaxKind.StringKeyword,\n number: ts.SyntaxKind.NumberKeyword,\n boolean: ts.SyntaxKind.BooleanKeyword,\n undefined: ts.SyntaxKind.UndefinedKeyword,\n unknown: ts.SyntaxKind.UnknownKeyword,\n never: ts.SyntaxKind.NeverKeyword,\n };\n return kinds[keyword];\n}\n\nfunction toKeywordType(ts: TypeScriptModule, keyword: IrKeyword): ts.TypeNode {\n return keyword === \"null\"\n ? ts.factory.createLiteralTypeNode(ts.factory.createNull())\n : ts.factory.createKeywordTypeNode(keywordKind(ts, keyword));\n}\n\n/**\n * Numbers as the original writes them: a negative value is a prefix minus on its absolute value.\n */\nfunction toNumberExpression(\n ts: TypeScriptModule,\n value: number,\n): ts.PrefixUnaryExpression | ts.NumericLiteral {\n return value < 0\n ? ts.factory.createPrefixUnaryExpression(\n ts.SyntaxKind.MinusToken,\n ts.factory.createNumericLiteral(Math.abs(value)),\n )\n : ts.factory.createNumericLiteral(value);\n}\n\n/** An enum member or array element value, written as the original writes it. */\nexport function toValueExpression(ts: TypeScriptModule, value: string | number): ts.Expression {\n return typeof value === \"number\"\n ? toNumberExpression(ts, value)\n : ts.factory.createStringLiteral(value);\n}\n\n/** The original writes JSON-encoded literal types as identifiers to keep UTF-8 readable. */\nfunction toStringLiteralType(\n ts: TypeScriptModule,\n value: string,\n encoding: \"json\" | \"escaped\",\n): ts.TypeNode {\n return encoding === \"json\"\n ? (ts.factory.createIdentifier(JSON.stringify(value)) as unknown as ts.TypeNode)\n : ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(value));\n}\n\nfunction toTupleElement(ts: TypeScriptModule, element: IrTupleElement): ts.TypeNode {\n const type = toTypeNode(ts, element.type);\n if (element.isOptional) {\n return ts.factory.createOptionalTypeNode(type);\n }\n return element.isRest ? ts.factory.createRestTypeNode(type) : type;\n}\n\ntype LeafType = Extract<\n IrType,\n { kind: \"keyword\" | \"stringLiteral\" | \"numberLiteral\" | \"booleanLiteral\" | \"raw\" }\n>;\n\nfunction toLeafTypeNode(ts: TypeScriptModule, type: LeafType): ts.TypeNode {\n switch (type.kind) {\n case \"keyword\":\n return toKeywordType(ts, type.keyword);\n case \"stringLiteral\":\n return toStringLiteralType(ts, type.value, type.encoding);\n case \"numberLiteral\":\n return ts.factory.createLiteralTypeNode(toNumberExpression(ts, type.value));\n case \"booleanLiteral\":\n return ts.factory.createLiteralTypeNode(\n type.value ? ts.factory.createTrue() : ts.factory.createFalse(),\n );\n case \"raw\":\n // A node read from TypeScript goes back as it was, so the TypeScript printer indents it.\n return (\n (type.origin as ts.TypeNode | undefined) ??\n (ts.factory.createIdentifier(type.text) as unknown as ts.TypeNode)\n );\n default:\n return assertNever(type);\n }\n}\n\nfunction toReferenceNode(\n ts: TypeScriptModule,\n type: Extract<IrType, { kind: \"reference\" }>,\n): ts.TypeNode {\n const typeArguments =\n type.typeArguments.length > 0\n ? type.typeArguments.map((argument) => toTypeNode(ts, argument))\n : undefined;\n return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(type.name), typeArguments);\n}\n\n/** Convert one IR type. */\nexport function toTypeNode(ts: TypeScriptModule, type: IrType): ts.TypeNode {\n const convert = (inner: IrType) => toTypeNode(ts, inner);\n const { factory } = ts;\n switch (type.kind) {\n case \"keyword\":\n case \"stringLiteral\":\n case \"numberLiteral\":\n case \"booleanLiteral\":\n case \"raw\":\n return toLeafTypeNode(ts, type);\n case \"reference\":\n return toReferenceNode(ts, type);\n case \"array\":\n return factory.createArrayTypeNode(convert(type.element));\n case \"tuple\":\n return factory.createTupleTypeNode(\n type.elements.map((element) => toTupleElement(ts, element)),\n );\n case \"union\":\n return factory.createUnionTypeNode(type.types.map(convert));\n case \"intersection\":\n return factory.createIntersectionTypeNode(type.types.map(convert));\n case \"object\":\n return factory.createTypeLiteralNode(type.members.map((member) => toTypeElement(ts, member)));\n case \"indexedAccess\":\n return factory.createIndexedAccessTypeNode(convert(type.object), convert(type.index));\n case \"readonly\":\n return factory.createTypeOperatorNode(ts.SyntaxKind.ReadonlyKeyword, convert(type.type));\n default:\n return assertNever(type);\n }\n}\n\n/** Attach IR comments to a node as synthetic leading comments, as the original does. */\nexport function withComments<T extends ts.Node>(\n ts: TypeScriptModule,\n node: T,\n comments: readonly IrComment[],\n): T {\n for (const comment of comments) {\n const kind =\n comment.kind === \"block\"\n ? ts.SyntaxKind.MultiLineCommentTrivia\n : ts.SyntaxKind.SingleLineCommentTrivia;\n ts.addSyntheticLeadingComment(node, kind, comment.text, true);\n }\n return node;\n}\n\nfunction toPropertyName(ts: TypeScriptModule, name: IrPropertyName): ts.PropertyName {\n switch (name.kind) {\n case \"identifier\":\n return ts.factory.createIdentifier(name.text);\n case \"string\":\n return ts.factory.createStringLiteral(name.value);\n case \"number\":\n return ts.factory.createNumericLiteral(name.text);\n default:\n return assertNever(name);\n }\n}\n\nfunction readonlyModifiers(ts: TypeScriptModule, isReadonly: boolean): ts.Modifier[] | undefined {\n return isReadonly ? [ts.factory.createModifier(ts.SyntaxKind.ReadonlyKeyword)] : undefined;\n}\n\n/** Convert one property signature (for callbacks that receive a `ts.PropertySignature`). */\nexport function toPropertySignature(\n ts: TypeScriptModule,\n property: IrPropertySignature,\n): ts.PropertySignature {\n const questionToken = property.isOptional\n ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)\n : undefined;\n const signature = ts.factory.createPropertySignature(\n readonlyModifiers(ts, property.isReadonly),\n toPropertyName(ts, property.name),\n questionToken,\n toTypeNode(ts, property.type),\n );\n return withComments(ts, signature, property.comments);\n}\n\nexport function toTypeElement(ts: TypeScriptModule, member: IrMember): ts.TypeElement {\n if (member.kind === \"property\") {\n return toPropertySignature(ts, member);\n }\n const parameter = ts.factory.createParameterDeclaration(\n undefined,\n undefined,\n member.parameterName,\n undefined,\n toTypeNode(ts, member.parameterType),\n );\n const signature = ts.factory.createIndexSignature(\n readonlyModifiers(ts, member.isReadonly),\n [parameter],\n toTypeNode(ts, member.type),\n );\n return withComments(ts, signature, member.comments);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ir-to-typescript.mjs","sources":["../../../src/adapters/type-ast-bridge/ir-to-typescript.ts"],"sourcesContent":["import type ts from \"typescript\";\nimport { assertNever } from \"../../domain/assert-never.js\";\nimport { DEFAULT_STRING_ENCODING } from \"../../domain/ir/constructors.js\";\nimport type {\n IrComment,\n IrKeyword,\n IrMember,\n IrPropertyName,\n IrPropertySignature,\n IrTupleElement,\n IrType,\n} from \"../../domain/ir/nodes.js\";\nimport type { TypeScriptModule } from \"./load-typescript.js\";\n\n/**\n * Convert IR to TypeScript AST nodes with the same factory calls the original generator makes.\n * Printing the result with the TypeScript printer gives the original output, which is how the\n * printer parity tests (ENGINEERING_PLAN 4.3) define \"byte-identical\". Every function takes the\n * TypeScript module to build with (ADR-004, decision 4): the nodes must come from the same module\n * that later reads or prints them.\n */\n\ntype KeywordName = Exclude<IrKeyword, \"null\">;\n\nfunction keywordKind(ts: TypeScriptModule, keyword: KeywordName): ts.KeywordTypeSyntaxKind {\n const kinds: Readonly<Record<KeywordName, ts.KeywordTypeSyntaxKind>> = {\n string: ts.SyntaxKind.StringKeyword,\n number: ts.SyntaxKind.NumberKeyword,\n boolean: ts.SyntaxKind.BooleanKeyword,\n undefined: ts.SyntaxKind.UndefinedKeyword,\n unknown: ts.SyntaxKind.UnknownKeyword,\n never: ts.SyntaxKind.NeverKeyword,\n };\n return kinds[keyword];\n}\n\nfunction toKeywordType(ts: TypeScriptModule, keyword: IrKeyword): ts.TypeNode {\n return keyword === \"null\"\n ? ts.factory.createLiteralTypeNode(ts.factory.createNull())\n : ts.factory.createKeywordTypeNode(keywordKind(ts, keyword));\n}\n\n/**\n * Numbers as the original writes them: a negative value is a prefix minus on its absolute value.\n */\nfunction toNumberExpression(\n ts: TypeScriptModule,\n value: number,\n): ts.PrefixUnaryExpression | ts.NumericLiteral {\n return value < 0\n ? ts.factory.createPrefixUnaryExpression(\n ts.SyntaxKind.MinusToken,\n ts.factory.createNumericLiteral(Math.abs(value)),\n )\n : ts.factory.createNumericLiteral(value);\n}\n\n/** An enum member or array element value, written as the original writes it. */\nexport function toValueExpression(ts: TypeScriptModule, value: string | number): ts.Expression {\n return typeof value === \"number\"\n ? toNumberExpression(ts, value)\n : ts.factory.createStringLiteral(value);\n}\n\n/** The original writes JSON-encoded literal types as identifiers to keep UTF-8 readable. */\nfunction toStringLiteralType(\n ts: TypeScriptModule,\n value: string,\n encoding: \"json\" | \"escaped\",\n): ts.TypeNode {\n return encoding === \"json\"\n ? (ts.factory.createIdentifier(JSON.stringify(value)) as unknown as ts.TypeNode)\n : ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(value));\n}\n\nfunction toTupleElement(ts: TypeScriptModule, element: IrTupleElement): ts.TypeNode {\n const type = toTypeNode(ts, element.type);\n if (element.isOptional) {\n return ts.factory.createOptionalTypeNode(type);\n }\n return element.isRest ? ts.factory.createRestTypeNode(type) : type;\n}\n\ntype LeafType = Extract<\n IrType,\n { kind: \"keyword\" | \"stringLiteral\" | \"numberLiteral\" | \"booleanLiteral\" | \"raw\" }\n>;\n\nfunction toLeafTypeNode(ts: TypeScriptModule, type: LeafType): ts.TypeNode {\n switch (type.kind) {\n case \"keyword\":\n return toKeywordType(ts, type.keyword);\n case \"stringLiteral\":\n return toStringLiteralType(ts, type.value, type.encoding ?? DEFAULT_STRING_ENCODING);\n case \"numberLiteral\":\n return ts.factory.createLiteralTypeNode(toNumberExpression(ts, type.value));\n case \"booleanLiteral\":\n return ts.factory.createLiteralTypeNode(\n type.value ? ts.factory.createTrue() : ts.factory.createFalse(),\n );\n case \"raw\":\n // A node read from TypeScript goes back as it was, so the TypeScript printer indents it.\n return (\n (type.origin as ts.TypeNode | undefined) ??\n (ts.factory.createIdentifier(type.text) as unknown as ts.TypeNode)\n );\n default:\n return assertNever(type);\n }\n}\n\nfunction toReferenceNode(\n ts: TypeScriptModule,\n type: Extract<IrType, { kind: \"reference\" }>,\n): ts.TypeNode {\n const typeArguments =\n type.typeArguments.length > 0\n ? type.typeArguments.map((argument) => toTypeNode(ts, argument))\n : undefined;\n return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(type.name), typeArguments);\n}\n\n/** Convert one IR type. */\nexport function toTypeNode(ts: TypeScriptModule, type: IrType): ts.TypeNode {\n const convert = (inner: IrType) => toTypeNode(ts, inner);\n const { factory } = ts;\n switch (type.kind) {\n case \"keyword\":\n case \"stringLiteral\":\n case \"numberLiteral\":\n case \"booleanLiteral\":\n case \"raw\":\n return toLeafTypeNode(ts, type);\n case \"reference\":\n return toReferenceNode(ts, type);\n case \"array\":\n return factory.createArrayTypeNode(convert(type.element));\n case \"tuple\":\n return factory.createTupleTypeNode(\n type.elements.map((element) => toTupleElement(ts, element)),\n );\n case \"union\":\n return factory.createUnionTypeNode(type.types.map(convert));\n case \"intersection\":\n return factory.createIntersectionTypeNode(type.types.map(convert));\n case \"object\":\n return factory.createTypeLiteralNode(type.members.map((member) => toTypeElement(ts, member)));\n case \"indexedAccess\":\n return factory.createIndexedAccessTypeNode(convert(type.object), convert(type.index));\n case \"readonly\":\n return factory.createTypeOperatorNode(ts.SyntaxKind.ReadonlyKeyword, convert(type.type));\n default:\n return assertNever(type);\n }\n}\n\n/** Attach IR comments to a node as synthetic leading comments, as the original does. */\nexport function withComments<T extends ts.Node>(\n ts: TypeScriptModule,\n node: T,\n comments: readonly IrComment[],\n): T {\n for (const comment of comments) {\n const kind =\n comment.kind === \"block\"\n ? ts.SyntaxKind.MultiLineCommentTrivia\n : ts.SyntaxKind.SingleLineCommentTrivia;\n ts.addSyntheticLeadingComment(node, kind, comment.text, true);\n }\n return node;\n}\n\nfunction toPropertyName(ts: TypeScriptModule, name: IrPropertyName): ts.PropertyName {\n switch (name.kind) {\n case \"identifier\":\n return ts.factory.createIdentifier(name.text);\n case \"string\":\n return ts.factory.createStringLiteral(name.value);\n case \"number\":\n return ts.factory.createNumericLiteral(name.text);\n default:\n return assertNever(name);\n }\n}\n\nfunction readonlyModifiers(ts: TypeScriptModule, isReadonly: boolean): ts.Modifier[] | undefined {\n return isReadonly ? [ts.factory.createModifier(ts.SyntaxKind.ReadonlyKeyword)] : undefined;\n}\n\n/** Convert one property signature (for callbacks that receive a `ts.PropertySignature`). */\nexport function toPropertySignature(\n ts: TypeScriptModule,\n property: IrPropertySignature,\n): ts.PropertySignature {\n const questionToken = property.isOptional\n ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)\n : undefined;\n const signature = ts.factory.createPropertySignature(\n readonlyModifiers(ts, property.isReadonly),\n toPropertyName(ts, property.name),\n questionToken,\n toTypeNode(ts, property.type),\n );\n return withComments(ts, signature, property.comments);\n}\n\nexport function toTypeElement(ts: TypeScriptModule, member: IrMember): ts.TypeElement {\n if (member.kind === \"property\") {\n return toPropertySignature(ts, member);\n }\n const parameter = ts.factory.createParameterDeclaration(\n undefined,\n undefined,\n member.parameterName,\n undefined,\n toTypeNode(ts, member.parameterType),\n );\n const signature = ts.factory.createIndexSignature(\n readonlyModifiers(ts, member.isReadonly),\n [parameter],\n toTypeNode(ts, member.type),\n );\n return withComments(ts, signature, member.comments);\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"print-typescript.cjs","sources":["../../../src/adapters/type-ast-bridge/print-typescript.ts"],"sourcesContent":["import type ts from \"typescript\";\nimport type { TypeScriptModule } from \"./load-typescript.js\";\n\n/** Options of `astToString` for the TypeScript printer, as in the original. */\nexport interface AstToStringOptions {\n fileName?: string;\n sourceText?: string;\n formatOptions?: ts.PrinterOptions;\n}\n\n/** Print TypeScript nodes as the original `astToString` did. */\nexport function printWithTypeScript(\n ts: TypeScriptModule,\n nodes: readonly ts.Node[],\n options?: AstToStringOptions,\n): string {\n const sourceFile = ts.createSourceFile(\n options?.fileName ?? \"openapi-ts.ts\",\n options?.sourceText ?? \"\",\n ts.ScriptTarget.ESNext,\n false,\n ts.ScriptKind.TS,\n );\n // The source file is new and not shared, so its statements can be set once.\n (sourceFile as { statements: ts.NodeArray<ts.Statement> }).statements =\n ts.factory.createNodeArray(nodes as readonly ts.Statement[]);\n const printer = ts.createPrinter({\n newLine: ts.NewLineKind.LineFeed,\n removeComments: false,\n ...options?.formatOptions,\n });\n return printer.printFile(sourceFile);\n}\n"],"names":[],"mappings":";;AAWO,SAAS,mBAAA,CACd,EAAA,EACA,KAAA,EACA,OAAA,EACQ;AACR,EAAA,MAAM,aAAa,EAAA,CAAG,gBAAA;AAAA,IACpB,SAAS,QAAA,IAAY,eAAA;AAAA,IACrB,SAAS,UAAA,IAAc,EAAA;AAAA,IACvB,GAAG,YAAA,CAAa,MAAA;AAAA,IAChB,KAAA;AAAA,IACA,GAAG,UAAA,CAAW;AAAA,GAChB;AAEA,EAAC,UAAA,CAA0D,UAAA,GACzD,EAAA,CAAG,OAAA,CAAQ,gBAAgB,KAAgC,CAAA;AAC7D,EAAA,MAAM,OAAA,GAAU,GAAG,aAAA,CAAc;AAAA,IAC/B,OAAA,EAAS,GAAG,WAAA,CAAY,QAAA;AAAA,IACxB,cAAA,EAAgB,KAAA;AAAA,IAChB,GAAG,OAAA,EAAS;AAAA,GACb,CAAA;AACD,EAAA,OAAO,OAAA,CAAQ,UAAU,UAAU,CAAA;AACrC;;"}
1
+ {"version":3,"file":"print-typescript.cjs","sources":["../../../src/adapters/type-ast-bridge/print-typescript.ts"],"sourcesContent":["import type ts from \"typescript\";\nimport type { TypeScriptModule } from \"./load-typescript.js\";\nimport type { ts as CompilerTypes } from \"./typescript-types.js\";\n\n/** Options of `astToString` for the TypeScript printer, as in the original. */\nexport interface AstToStringOptions {\n fileName?: string;\n sourceText?: string;\n /** The installed compiler's printer options (ADR-032: named without `ts.PrinterOptions`). */\n formatOptions?: CompilerTypes.PrinterOptions;\n}\n\n/** Print TypeScript nodes as the original `astToString` did. */\nexport function printWithTypeScript(\n ts: TypeScriptModule,\n nodes: readonly ts.Node[],\n options?: AstToStringOptions,\n): string {\n const sourceFile = ts.createSourceFile(\n options?.fileName ?? \"openapi-ts.ts\",\n options?.sourceText ?? \"\",\n ts.ScriptTarget.ESNext,\n false,\n ts.ScriptKind.TS,\n );\n // The source file is new and not shared, so its statements can be set once.\n (sourceFile as { statements: ts.NodeArray<ts.Statement> }).statements =\n ts.factory.createNodeArray(nodes as readonly ts.Statement[]);\n const printer = ts.createPrinter({\n newLine: ts.NewLineKind.LineFeed,\n removeComments: false,\n ...options?.formatOptions,\n });\n return printer.printFile(sourceFile);\n}\n"],"names":[],"mappings":";;AAaO,SAAS,mBAAA,CACd,EAAA,EACA,KAAA,EACA,OAAA,EACQ;AACR,EAAA,MAAM,aAAa,EAAA,CAAG,gBAAA;AAAA,IACpB,SAAS,QAAA,IAAY,eAAA;AAAA,IACrB,SAAS,UAAA,IAAc,EAAA;AAAA,IACvB,GAAG,YAAA,CAAa,MAAA;AAAA,IAChB,KAAA;AAAA,IACA,GAAG,UAAA,CAAW;AAAA,GAChB;AAEA,EAAC,UAAA,CAA0D,UAAA,GACzD,EAAA,CAAG,OAAA,CAAQ,gBAAgB,KAAgC,CAAA;AAC7D,EAAA,MAAM,OAAA,GAAU,GAAG,aAAA,CAAc;AAAA,IAC/B,OAAA,EAAS,GAAG,WAAA,CAAY,QAAA;AAAA,IACxB,cAAA,EAAgB,KAAA;AAAA,IAChB,GAAG,OAAA,EAAS;AAAA,GACb,CAAA;AACD,EAAA,OAAO,OAAA,CAAQ,UAAU,UAAU,CAAA;AACrC;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"print-typescript.mjs","sources":["../../../src/adapters/type-ast-bridge/print-typescript.ts"],"sourcesContent":["import type ts from \"typescript\";\nimport type { TypeScriptModule } from \"./load-typescript.js\";\n\n/** Options of `astToString` for the TypeScript printer, as in the original. */\nexport interface AstToStringOptions {\n fileName?: string;\n sourceText?: string;\n formatOptions?: ts.PrinterOptions;\n}\n\n/** Print TypeScript nodes as the original `astToString` did. */\nexport function printWithTypeScript(\n ts: TypeScriptModule,\n nodes: readonly ts.Node[],\n options?: AstToStringOptions,\n): string {\n const sourceFile = ts.createSourceFile(\n options?.fileName ?? \"openapi-ts.ts\",\n options?.sourceText ?? \"\",\n ts.ScriptTarget.ESNext,\n false,\n ts.ScriptKind.TS,\n );\n // The source file is new and not shared, so its statements can be set once.\n (sourceFile as { statements: ts.NodeArray<ts.Statement> }).statements =\n ts.factory.createNodeArray(nodes as readonly ts.Statement[]);\n const printer = ts.createPrinter({\n newLine: ts.NewLineKind.LineFeed,\n removeComments: false,\n ...options?.formatOptions,\n });\n return printer.printFile(sourceFile);\n}\n"],"names":[],"mappings":"AAWO,SAAS,mBAAA,CACd,EAAA,EACA,KAAA,EACA,OAAA,EACQ;AACR,EAAA,MAAM,aAAa,EAAA,CAAG,gBAAA;AAAA,IACpB,SAAS,QAAA,IAAY,eAAA;AAAA,IACrB,SAAS,UAAA,IAAc,EAAA;AAAA,IACvB,GAAG,YAAA,CAAa,MAAA;AAAA,IAChB,KAAA;AAAA,IACA,GAAG,UAAA,CAAW;AAAA,GAChB;AAEA,EAAC,UAAA,CAA0D,UAAA,GACzD,EAAA,CAAG,OAAA,CAAQ,gBAAgB,KAAgC,CAAA;AAC7D,EAAA,MAAM,OAAA,GAAU,GAAG,aAAA,CAAc;AAAA,IAC/B,OAAA,EAAS,GAAG,WAAA,CAAY,QAAA;AAAA,IACxB,cAAA,EAAgB,KAAA;AAAA,IAChB,GAAG,OAAA,EAAS;AAAA,GACb,CAAA;AACD,EAAA,OAAO,OAAA,CAAQ,UAAU,UAAU,CAAA;AACrC;;"}
1
+ {"version":3,"file":"print-typescript.mjs","sources":["../../../src/adapters/type-ast-bridge/print-typescript.ts"],"sourcesContent":["import type ts from \"typescript\";\nimport type { TypeScriptModule } from \"./load-typescript.js\";\nimport type { ts as CompilerTypes } from \"./typescript-types.js\";\n\n/** Options of `astToString` for the TypeScript printer, as in the original. */\nexport interface AstToStringOptions {\n fileName?: string;\n sourceText?: string;\n /** The installed compiler's printer options (ADR-032: named without `ts.PrinterOptions`). */\n formatOptions?: CompilerTypes.PrinterOptions;\n}\n\n/** Print TypeScript nodes as the original `astToString` did. */\nexport function printWithTypeScript(\n ts: TypeScriptModule,\n nodes: readonly ts.Node[],\n options?: AstToStringOptions,\n): string {\n const sourceFile = ts.createSourceFile(\n options?.fileName ?? \"openapi-ts.ts\",\n options?.sourceText ?? \"\",\n ts.ScriptTarget.ESNext,\n false,\n ts.ScriptKind.TS,\n );\n // The source file is new and not shared, so its statements can be set once.\n (sourceFile as { statements: ts.NodeArray<ts.Statement> }).statements =\n ts.factory.createNodeArray(nodes as readonly ts.Statement[]);\n const printer = ts.createPrinter({\n newLine: ts.NewLineKind.LineFeed,\n removeComments: false,\n ...options?.formatOptions,\n });\n return printer.printFile(sourceFile);\n}\n"],"names":[],"mappings":"AAaO,SAAS,mBAAA,CACd,EAAA,EACA,KAAA,EACA,OAAA,EACQ;AACR,EAAA,MAAM,aAAa,EAAA,CAAG,gBAAA;AAAA,IACpB,SAAS,QAAA,IAAY,eAAA;AAAA,IACrB,SAAS,UAAA,IAAc,EAAA;AAAA,IACvB,GAAG,YAAA,CAAa,MAAA;AAAA,IAChB,KAAA;AAAA,IACA,GAAG,UAAA,CAAW;AAAA,GAChB;AAEA,EAAC,UAAA,CAA0D,UAAA,GACzD,EAAA,CAAG,OAAA,CAAQ,gBAAgB,KAAgC,CAAA;AAC7D,EAAA,MAAM,OAAA,GAAU,GAAG,aAAA,CAAc;AAAA,IAC/B,OAAA,EAAS,GAAG,WAAA,CAAY,QAAA;AAAA,IACxB,cAAA,EAAgB,KAAA;AAAA,IAChB,GAAG,OAAA,EAAS;AAAA,GACb,CAAA;AACD,EAAA,OAAO,OAAA,CAAQ,UAAU,UAAU,CAAA;AACrC;;"}
@@ -22,6 +22,13 @@ function defaultLogger(silent) {
22
22
  });
23
23
  }
24
24
  const REMOTE_REF_TIMEOUT_MS = 6e4;
25
+ const DEFAULT_REMOTE_DOCUMENT_LIMITS = {
26
+ maxDocuments: 1e4,
27
+ maxParallelFetches: 16
28
+ };
29
+ function processCwd() {
30
+ return process.cwd();
31
+ }
25
32
  function monotonicNow() {
26
33
  return node_perf_hooks.performance.now();
27
34
  }
@@ -30,9 +37,11 @@ function defaultRedoclyConfig() {
30
37
  return openapiCore.createConfig({ rules }, { extends: ["minimal"] });
31
38
  }
32
39
 
40
+ exports.DEFAULT_REMOTE_DOCUMENT_LIMITS = DEFAULT_REMOTE_DOCUMENT_LIMITS;
33
41
  exports.REMOTE_REF_TIMEOUT_MS = REMOTE_REF_TIMEOUT_MS;
34
42
  exports.defaultLogger = defaultLogger;
35
43
  exports.defaultRedoclyConfig = defaultRedoclyConfig;
36
44
  exports.monotonicNow = monotonicNow;
45
+ exports.processCwd = processCwd;
37
46
  exports.terminalSupportsColor = terminalSupportsColor;
38
47
  //# sourceMappingURL=default-ports.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"default-ports.cjs","sources":["../../src/api/default-ports.ts"],"sourcesContent":["import { performance } from \"node:perf_hooks\";\nimport { createConfig, type Config as RedoclyConfig } from \"@redocly/openapi-core\";\nimport supportsColor from \"supports-color\";\nimport { createTerminalLogger } from \"../adapters/terminal-logger/terminal-logger.js\";\nimport type { Logger } from \"../application/ports/logger.js\";\n\n/**\n * The default adapters of the Node API (ENGINEERING_PLAN 4.5): this module and the CLI's\n * composition root are where the process environment is read.\n */\n\n/** Colors when the terminal supports them, as the original decided. */\nexport function terminalSupportsColor(): boolean {\n const stdout = supportsColor.stdout;\n return Boolean(stdout) && stdout !== false && stdout.hasBasic !== false;\n}\n\n/** The terminal logger with `DEBUG` from the environment, writing to the console. */\nexport function defaultLogger(silent: boolean): Logger {\n return createTerminalLogger({\n silent,\n debugFilter: process.env.DEBUG,\n useColors: terminalSupportsColor(),\n sink: console,\n });\n}\n\n/**\n * How long one remote `$ref` (or a remote source) may take to load. Large documents (the 27 MB\n * Cloudflare spec) download in seconds; a minute covers slow hosts, while Node's own fetch would\n * wait five minutes for a server that never answers (ENGINEERING_PLAN 8.5).\n */\nexport const REMOTE_REF_TIMEOUT_MS = 60_000;\n\n/** A monotonic clock in milliseconds, for debug durations. */\nexport function monotonicNow(): number {\n return performance.now();\n}\n\n/** The default Redocly config: minimal rules, and duplicate operation IDs are an error. */\nexport function defaultRedoclyConfig(): Promise<RedoclyConfig> {\n const rules = { \"operation-operationId-unique\": { severity: \"error\" as const } };\n return createConfig({ rules }, { extends: [\"minimal\"] });\n}\n"],"names":["supportsColor","createTerminalLogger","performance","createConfig"],"mappings":";;;;;;;;;;;AAYO,SAAS,qBAAA,GAAiC;AAC/C,EAAA,MAAM,SAASA,sBAAA,CAAc,MAAA;AAC7B,EAAA,OAAO,QAAQ,MAAM,CAAA,IAAK,MAAA,KAAW,KAAA,IAAS,OAAO,QAAA,KAAa,KAAA;AACpE;AAGO,SAAS,cAAc,MAAA,EAAyB;AACrD,EAAA,OAAOC,mCAAA,CAAqB;AAAA,IAC1B,MAAA;AAAA,IACA,WAAA,EAAa,QAAQ,GAAA,CAAI,KAAA;AAAA,IACzB,WAAW,qBAAA,EAAsB;AAAA,IACjC,IAAA,EAAM;AAAA,GACP,CAAA;AACH;AAOO,MAAM,qBAAA,GAAwB;AAG9B,SAAS,YAAA,GAAuB;AACrC,EAAA,OAAOC,4BAAY,GAAA,EAAI;AACzB;AAGO,SAAS,oBAAA,GAA+C;AAC7D,EAAA,MAAM,QAAQ,EAAE,8BAAA,EAAgC,EAAE,QAAA,EAAU,SAAiB,EAAE;AAC/E,EAAA,OAAOC,wBAAA,CAAa,EAAE,KAAA,EAAM,EAAG,EAAE,OAAA,EAAS,CAAC,SAAS,CAAA,EAAG,CAAA;AACzD;;;;;;"}
1
+ {"version":3,"file":"default-ports.cjs","sources":["../../src/api/default-ports.ts"],"sourcesContent":["import { performance } from \"node:perf_hooks\";\nimport { createConfig, type Config as RedoclyConfig } from \"@redocly/openapi-core\";\nimport supportsColor from \"supports-color\";\nimport type { RemoteDocumentLimits } from \"../adapters/redocly-loader/remote-fetch.js\";\nimport { createTerminalLogger } from \"../adapters/terminal-logger/terminal-logger.js\";\nimport type { Logger } from \"../application/ports/logger.js\";\n\n/**\n * The default adapters of the Node API (ENGINEERING_PLAN 4.5): this module and the CLI's\n * composition root are where the process environment is read.\n */\n\n/** Colors when the terminal supports them, as the original decided. */\nexport function terminalSupportsColor(): boolean {\n const stdout = supportsColor.stdout;\n return Boolean(stdout) && stdout !== false && stdout.hasBasic !== false;\n}\n\n/** The terminal logger with `DEBUG` from the environment, writing to the console. */\nexport function defaultLogger(silent: boolean): Logger {\n return createTerminalLogger({\n silent,\n debugFilter: process.env.DEBUG,\n useColors: terminalSupportsColor(),\n sink: console,\n });\n}\n\n/**\n * How long one remote `$ref` (or a remote source) may take to load. Large documents (the 27 MB\n * Cloudflare spec) download in seconds; a minute covers slow hosts, while Node's own fetch would\n * wait five minutes for a server that never answers (ENGINEERING_PLAN 8.5).\n */\nexport const REMOTE_REF_TIMEOUT_MS = 60_000;\n\n/**\n * Bounds on the remote documents of one run (ADR-033). Large split documents have a few thousand\n * files, so 10,000 leaves room and still ends an endless fan-out. 16 parallel fetches keep a\n * multi-file document fast without exhausting local ports.\n */\nexport const DEFAULT_REMOTE_DOCUMENT_LIMITS: RemoteDocumentLimits = {\n maxDocuments: 10_000,\n maxParallelFetches: 16,\n};\n\n/** The working directory of the process: the default `cwd` of an inline source. */\nexport function processCwd(): string {\n return process.cwd();\n}\n\n/** A monotonic clock in milliseconds, for debug durations. */\nexport function monotonicNow(): number {\n return performance.now();\n}\n\n/** The default Redocly config: minimal rules, and duplicate operation IDs are an error. */\nexport function defaultRedoclyConfig(): Promise<RedoclyConfig> {\n const rules = { \"operation-operationId-unique\": { severity: \"error\" as const } };\n return createConfig({ rules }, { extends: [\"minimal\"] });\n}\n"],"names":["supportsColor","createTerminalLogger","performance","createConfig"],"mappings":";;;;;;;;;;;AAaO,SAAS,qBAAA,GAAiC;AAC/C,EAAA,MAAM,SAASA,sBAAA,CAAc,MAAA;AAC7B,EAAA,OAAO,QAAQ,MAAM,CAAA,IAAK,MAAA,KAAW,KAAA,IAAS,OAAO,QAAA,KAAa,KAAA;AACpE;AAGO,SAAS,cAAc,MAAA,EAAyB;AACrD,EAAA,OAAOC,mCAAA,CAAqB;AAAA,IAC1B,MAAA;AAAA,IACA,WAAA,EAAa,QAAQ,GAAA,CAAI,KAAA;AAAA,IACzB,WAAW,qBAAA,EAAsB;AAAA,IACjC,IAAA,EAAM;AAAA,GACP,CAAA;AACH;AAOO,MAAM,qBAAA,GAAwB;AAO9B,MAAM,8BAAA,GAAuD;AAAA,EAClE,YAAA,EAAc,GAAA;AAAA,EACd,kBAAA,EAAoB;AACtB;AAGO,SAAS,UAAA,GAAqB;AACnC,EAAA,OAAO,QAAQ,GAAA,EAAI;AACrB;AAGO,SAAS,YAAA,GAAuB;AACrC,EAAA,OAAOC,4BAAY,GAAA,EAAI;AACzB;AAGO,SAAS,oBAAA,GAA+C;AAC7D,EAAA,MAAM,QAAQ,EAAE,8BAAA,EAAgC,EAAE,QAAA,EAAU,SAAiB,EAAE;AAC/E,EAAA,OAAOC,wBAAA,CAAa,EAAE,KAAA,EAAM,EAAG,EAAE,OAAA,EAAS,CAAC,SAAS,CAAA,EAAG,CAAA;AACzD;;;;;;;;"}
@@ -16,6 +16,13 @@ function defaultLogger(silent) {
16
16
  });
17
17
  }
18
18
  const REMOTE_REF_TIMEOUT_MS = 6e4;
19
+ const DEFAULT_REMOTE_DOCUMENT_LIMITS = {
20
+ maxDocuments: 1e4,
21
+ maxParallelFetches: 16
22
+ };
23
+ function processCwd() {
24
+ return process.cwd();
25
+ }
19
26
  function monotonicNow() {
20
27
  return performance.now();
21
28
  }
@@ -24,5 +31,5 @@ function defaultRedoclyConfig() {
24
31
  return createConfig({ rules }, { extends: ["minimal"] });
25
32
  }
26
33
 
27
- export { REMOTE_REF_TIMEOUT_MS, defaultLogger, defaultRedoclyConfig, monotonicNow, terminalSupportsColor };
34
+ export { DEFAULT_REMOTE_DOCUMENT_LIMITS, REMOTE_REF_TIMEOUT_MS, defaultLogger, defaultRedoclyConfig, monotonicNow, processCwd, terminalSupportsColor };
28
35
  //# sourceMappingURL=default-ports.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"default-ports.mjs","sources":["../../src/api/default-ports.ts"],"sourcesContent":["import { performance } from \"node:perf_hooks\";\nimport { createConfig, type Config as RedoclyConfig } from \"@redocly/openapi-core\";\nimport supportsColor from \"supports-color\";\nimport { createTerminalLogger } from \"../adapters/terminal-logger/terminal-logger.js\";\nimport type { Logger } from \"../application/ports/logger.js\";\n\n/**\n * The default adapters of the Node API (ENGINEERING_PLAN 4.5): this module and the CLI's\n * composition root are where the process environment is read.\n */\n\n/** Colors when the terminal supports them, as the original decided. */\nexport function terminalSupportsColor(): boolean {\n const stdout = supportsColor.stdout;\n return Boolean(stdout) && stdout !== false && stdout.hasBasic !== false;\n}\n\n/** The terminal logger with `DEBUG` from the environment, writing to the console. */\nexport function defaultLogger(silent: boolean): Logger {\n return createTerminalLogger({\n silent,\n debugFilter: process.env.DEBUG,\n useColors: terminalSupportsColor(),\n sink: console,\n });\n}\n\n/**\n * How long one remote `$ref` (or a remote source) may take to load. Large documents (the 27 MB\n * Cloudflare spec) download in seconds; a minute covers slow hosts, while Node's own fetch would\n * wait five minutes for a server that never answers (ENGINEERING_PLAN 8.5).\n */\nexport const REMOTE_REF_TIMEOUT_MS = 60_000;\n\n/** A monotonic clock in milliseconds, for debug durations. */\nexport function monotonicNow(): number {\n return performance.now();\n}\n\n/** The default Redocly config: minimal rules, and duplicate operation IDs are an error. */\nexport function defaultRedoclyConfig(): Promise<RedoclyConfig> {\n const rules = { \"operation-operationId-unique\": { severity: \"error\" as const } };\n return createConfig({ rules }, { extends: [\"minimal\"] });\n}\n"],"names":[],"mappings":";;;;;AAYO,SAAS,qBAAA,GAAiC;AAC/C,EAAA,MAAM,SAAS,aAAA,CAAc,MAAA;AAC7B,EAAA,OAAO,QAAQ,MAAM,CAAA,IAAK,MAAA,KAAW,KAAA,IAAS,OAAO,QAAA,KAAa,KAAA;AACpE;AAGO,SAAS,cAAc,MAAA,EAAyB;AACrD,EAAA,OAAO,oBAAA,CAAqB;AAAA,IAC1B,MAAA;AAAA,IACA,WAAA,EAAa,QAAQ,GAAA,CAAI,KAAA;AAAA,IACzB,WAAW,qBAAA,EAAsB;AAAA,IACjC,IAAA,EAAM;AAAA,GACP,CAAA;AACH;AAOO,MAAM,qBAAA,GAAwB;AAG9B,SAAS,YAAA,GAAuB;AACrC,EAAA,OAAO,YAAY,GAAA,EAAI;AACzB;AAGO,SAAS,oBAAA,GAA+C;AAC7D,EAAA,MAAM,QAAQ,EAAE,8BAAA,EAAgC,EAAE,QAAA,EAAU,SAAiB,EAAE;AAC/E,EAAA,OAAO,YAAA,CAAa,EAAE,KAAA,EAAM,EAAG,EAAE,OAAA,EAAS,CAAC,SAAS,CAAA,EAAG,CAAA;AACzD;;"}
1
+ {"version":3,"file":"default-ports.mjs","sources":["../../src/api/default-ports.ts"],"sourcesContent":["import { performance } from \"node:perf_hooks\";\nimport { createConfig, type Config as RedoclyConfig } from \"@redocly/openapi-core\";\nimport supportsColor from \"supports-color\";\nimport type { RemoteDocumentLimits } from \"../adapters/redocly-loader/remote-fetch.js\";\nimport { createTerminalLogger } from \"../adapters/terminal-logger/terminal-logger.js\";\nimport type { Logger } from \"../application/ports/logger.js\";\n\n/**\n * The default adapters of the Node API (ENGINEERING_PLAN 4.5): this module and the CLI's\n * composition root are where the process environment is read.\n */\n\n/** Colors when the terminal supports them, as the original decided. */\nexport function terminalSupportsColor(): boolean {\n const stdout = supportsColor.stdout;\n return Boolean(stdout) && stdout !== false && stdout.hasBasic !== false;\n}\n\n/** The terminal logger with `DEBUG` from the environment, writing to the console. */\nexport function defaultLogger(silent: boolean): Logger {\n return createTerminalLogger({\n silent,\n debugFilter: process.env.DEBUG,\n useColors: terminalSupportsColor(),\n sink: console,\n });\n}\n\n/**\n * How long one remote `$ref` (or a remote source) may take to load. Large documents (the 27 MB\n * Cloudflare spec) download in seconds; a minute covers slow hosts, while Node's own fetch would\n * wait five minutes for a server that never answers (ENGINEERING_PLAN 8.5).\n */\nexport const REMOTE_REF_TIMEOUT_MS = 60_000;\n\n/**\n * Bounds on the remote documents of one run (ADR-033). Large split documents have a few thousand\n * files, so 10,000 leaves room and still ends an endless fan-out. 16 parallel fetches keep a\n * multi-file document fast without exhausting local ports.\n */\nexport const DEFAULT_REMOTE_DOCUMENT_LIMITS: RemoteDocumentLimits = {\n maxDocuments: 10_000,\n maxParallelFetches: 16,\n};\n\n/** The working directory of the process: the default `cwd` of an inline source. */\nexport function processCwd(): string {\n return process.cwd();\n}\n\n/** A monotonic clock in milliseconds, for debug durations. */\nexport function monotonicNow(): number {\n return performance.now();\n}\n\n/** The default Redocly config: minimal rules, and duplicate operation IDs are an error. */\nexport function defaultRedoclyConfig(): Promise<RedoclyConfig> {\n const rules = { \"operation-operationId-unique\": { severity: \"error\" as const } };\n return createConfig({ rules }, { extends: [\"minimal\"] });\n}\n"],"names":[],"mappings":";;;;;AAaO,SAAS,qBAAA,GAAiC;AAC/C,EAAA,MAAM,SAAS,aAAA,CAAc,MAAA;AAC7B,EAAA,OAAO,QAAQ,MAAM,CAAA,IAAK,MAAA,KAAW,KAAA,IAAS,OAAO,QAAA,KAAa,KAAA;AACpE;AAGO,SAAS,cAAc,MAAA,EAAyB;AACrD,EAAA,OAAO,oBAAA,CAAqB;AAAA,IAC1B,MAAA;AAAA,IACA,WAAA,EAAa,QAAQ,GAAA,CAAI,KAAA;AAAA,IACzB,WAAW,qBAAA,EAAsB;AAAA,IACjC,IAAA,EAAM;AAAA,GACP,CAAA;AACH;AAOO,MAAM,qBAAA,GAAwB;AAO9B,MAAM,8BAAA,GAAuD;AAAA,EAClE,YAAA,EAAc,GAAA;AAAA,EACd,kBAAA,EAAoB;AACtB;AAGO,SAAS,UAAA,GAAqB;AACnC,EAAA,OAAO,QAAQ,GAAA,EAAI;AACrB;AAGO,SAAS,YAAA,GAAuB;AACrC,EAAA,OAAO,YAAY,GAAA,EAAI;AACzB;AAGO,SAAS,oBAAA,GAA+C;AAC7D,EAAA,MAAM,QAAQ,EAAE,8BAAA,EAAgC,EAAE,QAAA,EAAU,SAAiB,EAAE;AAC/E,EAAA,OAAO,YAAA,CAAa,EAAE,KAAA,EAAM,EAAG,EAAE,OAAA,EAAS,CAAC,SAAS,CAAA,EAAG,CAAA;AACzD;;"}
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const outputFixes = require('../domain/output-fixes.cjs');
4
+ const warnings = require('../domain/warnings.cjs');
4
5
  const discriminatorEnum = require('./discriminator-enum.cjs');
5
6
  const discriminatorEnumParent = require('./discriminator-enum-parent.cjs');
6
7
  const documentRefs = require('./document-refs.cjs');
@@ -76,7 +77,10 @@ function markHandled(state, ref) {
76
77
  function warnInvalidMapping(patch, logger) {
77
78
  const mapped = `${patch.ref} => ${patch.values.join(", ")}`;
78
79
  logger.warn(
79
- `Discriminator mapping has an invalid schema (neither an object schema nor an allOf array): ${mapped} (Discriminator: ${patch.discriminatorRef})`
80
+ warnings.warningText(
81
+ `Discriminator mapping has an invalid schema (neither an object schema nor an allOf array): ${mapped} (Discriminator: ${patch.discriminatorRef})`,
82
+ warnings.WARNING_CODES.DISCRIMINATOR_MAPPING_INVALID
83
+ )
80
84
  );
81
85
  }
82
86
 
@@ -1 +1 @@
1
- {"version":3,"file":"discriminator-patch.cjs","sources":["../../src/api/discriminator-patch.ts"],"sourcesContent":["import type { Logger } from \"../application/ports/logger.js\";\nimport { OutputFix } from \"../domain/output-fixes.js\";\nimport type { DiscriminatorObject, OpenAPI3, SchemaObject } from \"../types.js\";\nimport { addEnumProperty, declaresValues, type EnumPatch } from \"./discriminator-enum.js\";\nimport {\n type DiscriminatorOwner,\n type EnumParent,\n enumParentOf,\n} from \"./discriminator-enum-parent.js\";\nimport { resolveDocumentRef } from \"./document-refs.js\";\n\n/**\n * The state of the discriminator pre-pass and the in-place patch of a mapped schema: the enum\n * property that the generated union narrows by. Two discriminators of one property may patch one\n * schema; how they combine is the `discriminator-values` fix (ADR-021, roadmap R12).\n */\n\n/** How to scan: the warnings, and the output fixes of the run (ADR-021). */\nexport interface DiscriminatorScanOptions {\n readonly silent: boolean;\n readonly logger: Logger;\n readonly fixes: ReadonlySet<OutputFix>;\n}\n\n/** What the two passes share: the document they patch and what they found so far. */\nexport interface ScanState extends DiscriminatorScanOptions {\n readonly schema: OpenAPI3;\n readonly objects: Record<string, DiscriminatorObject>;\n /** The schemas that define a discriminator themselves (pass 1), not by inheritance. */\n readonly owners: Set<string>;\n readonly refsHandled: string[];\n /** With the fix: the enum added to each schema, by schema and property, so values merge. */\n readonly patchedEnums: Map<string, SchemaObject>;\n /** With the fix: schema-name values, applied after both passes where no mapping names one. */\n readonly inferredPatches: EnumPatch[];\n /** With the fix: schema-name values of other properties (`inheritOtherOwners`). */\n readonly otherInferredPatches: EnumPatch[];\n /** With the fix: the other properties each schema got a value of (`inheritOtherOwners`). */\n readonly otherProperties: Record<string, string[]>;\n /** With `discriminator-values`: the enum keys that a schema declares itself. */\n readonly declaredKeys: Set<string>;\n /** With `discriminator-values`: the owner's enum of each added enum, by that enum. */\n readonly enumParents: Map<object, EnumParent>;\n}\n\n/** Whether `discriminator-values` is on: values of two discriminators merge into one enum. */\nexport function mergesValues(state: ScanState): boolean {\n return state.fixes.has(OutputFix.DISCRIMINATOR_VALUES);\n}\n\nfunction patchedSchema(state: ScanState, patch: EnumPatch): SchemaObject | undefined {\n const { silent, logger } = state;\n return resolveDocumentRef<SchemaObject>(state.schema, patch.ref, { silent, logger });\n}\n\n/**\n * With `discriminator-values`: the schema at `patch.ref` requires the property with\n * exactly these values already, so a patch would only repeat it (#2124).\n */\nfunction isDeclared(state: ScanState, patch: EnumPatch): boolean {\n return (\n state.fixes.has(OutputFix.DISCRIMINATOR_VALUES) &&\n declaresValues(patchedSchema(state, patch), patch)\n );\n}\n\n/**\n * With `discriminator-values`: the enum of the owner's property, for `key`: an enum the scan\n * added, or a discriminator object that a schema inherited.\n */\nexport function recordEnumParent(state: ScanState, owner: DiscriminatorOwner, key: object): void {\n if (!state.fixes.has(OutputFix.DISCRIMINATOR_VALUES)) {\n return;\n }\n const { silent, logger } = state;\n const parent = enumParentOf(owner, (ref) =>\n resolveDocumentRef(state.schema, ref, { silent, logger }),\n );\n if (parent !== undefined) {\n state.enumParents.set(key, parent);\n }\n}\n\n/** The enum the schema at `patch.ref` gets, or null (with a warning) for another kind of schema. */\nfunction addDiscriminatorEnum(state: ScanState, patch: EnumPatch): SchemaObject | null {\n const added = addEnumProperty(patchedSchema(state, patch), patch);\n if (added === null) {\n warnInvalidMapping(patch, state.logger);\n } else {\n recordEnumParent(state, patch, added);\n }\n return added;\n}\n\n/** One schema and discriminator property; two discriminators of one property share an enum. */\nexport function enumKey(patch: EnumPatch): string {\n return `${patch.ref}\\n${patch.discriminator.propertyName}`;\n}\n\n/** With the fix, a second discriminator of the same property adds its values to the first enum. */\nfunction mergeIntoPatchedEnum(state: ScanState, key: string, values: readonly string[]): boolean {\n const patched = state.patchedEnums.get(key);\n if (patched === undefined) {\n return false;\n }\n const merged = patched.enum as unknown[];\n merged.push(...values.filter((value) => !merged.includes(value)));\n return true;\n}\n\n/**\n * Add or replace the discriminator enum in the schema at `patch.ref`. Returns false, with a\n * warning, when that schema is neither an `allOf` nor an object schema. Without the fix every\n * patch adds a property, so two discriminators with different values intersect to `never`.\n */\nexport function patchDiscriminatorEnum(state: ScanState, patch: EnumPatch): boolean {\n if (isDeclared(state, patch)) {\n state.declaredKeys.add(enumKey(patch));\n return true;\n }\n if (!mergesValues(state)) {\n return addDiscriminatorEnum(state, patch) !== null;\n }\n const key = enumKey(patch);\n if (mergeIntoPatchedEnum(state, key, patch.values)) {\n return true;\n }\n const added = addDiscriminatorEnum(state, patch);\n if (added !== null) {\n state.patchedEnums.set(key, added);\n }\n return added !== null;\n}\n\nexport function markHandled(state: ScanState, ref: string): void {\n if (!state.refsHandled.includes(ref)) {\n state.refsHandled.push(ref);\n }\n}\n\nfunction warnInvalidMapping(patch: EnumPatch, logger: Logger): void {\n const mapped = `${patch.ref} => ${patch.values.join(\", \")}`;\n logger.warn(\n \"Discriminator mapping has an invalid schema (neither an object schema nor an allOf array): \" +\n `${mapped} (Discriminator: ${patch.discriminatorRef})`,\n );\n}\n"],"names":["OutputFix","resolveDocumentRef","declaresValues","enumParentOf","addEnumProperty"],"mappings":"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"}
1
+ {"version":3,"file":"discriminator-patch.cjs","sources":["../../src/api/discriminator-patch.ts"],"sourcesContent":["import type { Logger } from \"../application/ports/logger.js\";\nimport { OutputFix } from \"../domain/output-fixes.js\";\nimport { WARNING_CODES, warningText } from \"../domain/warnings.js\";\nimport type { DiscriminatorObject, OpenAPI3, SchemaObject } from \"../types.js\";\nimport { addEnumProperty, declaresValues, type EnumPatch } from \"./discriminator-enum.js\";\nimport {\n type DiscriminatorOwner,\n type EnumParent,\n enumParentOf,\n} from \"./discriminator-enum-parent.js\";\nimport { resolveDocumentRef } from \"./document-refs.js\";\n\n/**\n * The state of the discriminator pre-pass and the in-place patch of a mapped schema: the enum\n * property that the generated union narrows by. Two discriminators of one property may patch one\n * schema; how they combine is the `discriminator-values` fix (ADR-021, roadmap R12).\n */\n\n/** How to scan: the warnings, and the output fixes of the run (ADR-021). */\nexport interface DiscriminatorScanOptions {\n readonly silent: boolean;\n readonly logger: Logger;\n readonly fixes: ReadonlySet<OutputFix>;\n}\n\n/** What the two passes share: the document they patch and what they found so far. */\nexport interface ScanState extends DiscriminatorScanOptions {\n readonly schema: OpenAPI3;\n readonly objects: Record<string, DiscriminatorObject>;\n /** The schemas that define a discriminator themselves (pass 1), not by inheritance. */\n readonly owners: Set<string>;\n readonly refsHandled: string[];\n /** With the fix: the enum added to each schema, by schema and property, so values merge. */\n readonly patchedEnums: Map<string, SchemaObject>;\n /** With the fix: schema-name values, applied after both passes where no mapping names one. */\n readonly inferredPatches: EnumPatch[];\n /** With the fix: schema-name values of other properties (`inheritOtherOwners`). */\n readonly otherInferredPatches: EnumPatch[];\n /** With the fix: the other properties each schema got a value of (`inheritOtherOwners`). */\n readonly otherProperties: Record<string, string[]>;\n /** With `discriminator-values`: the enum keys that a schema declares itself. */\n readonly declaredKeys: Set<string>;\n /** With `discriminator-values`: the owner's enum of each added enum, by that enum. */\n readonly enumParents: Map<object, EnumParent>;\n}\n\n/** Whether `discriminator-values` is on: values of two discriminators merge into one enum. */\nexport function mergesValues(state: ScanState): boolean {\n return state.fixes.has(OutputFix.DISCRIMINATOR_VALUES);\n}\n\nfunction patchedSchema(state: ScanState, patch: EnumPatch): SchemaObject | undefined {\n const { silent, logger } = state;\n return resolveDocumentRef<SchemaObject>(state.schema, patch.ref, { silent, logger });\n}\n\n/**\n * With `discriminator-values`: the schema at `patch.ref` requires the property with\n * exactly these values already, so a patch would only repeat it (#2124).\n */\nfunction isDeclared(state: ScanState, patch: EnumPatch): boolean {\n return (\n state.fixes.has(OutputFix.DISCRIMINATOR_VALUES) &&\n declaresValues(patchedSchema(state, patch), patch)\n );\n}\n\n/**\n * With `discriminator-values`: the enum of the owner's property, for `key`: an enum the scan\n * added, or a discriminator object that a schema inherited.\n */\nexport function recordEnumParent(state: ScanState, owner: DiscriminatorOwner, key: object): void {\n if (!state.fixes.has(OutputFix.DISCRIMINATOR_VALUES)) {\n return;\n }\n const { silent, logger } = state;\n const parent = enumParentOf(owner, (ref) =>\n resolveDocumentRef(state.schema, ref, { silent, logger }),\n );\n if (parent !== undefined) {\n state.enumParents.set(key, parent);\n }\n}\n\n/** The enum the schema at `patch.ref` gets, or null (with a warning) for another kind of schema. */\nfunction addDiscriminatorEnum(state: ScanState, patch: EnumPatch): SchemaObject | null {\n const added = addEnumProperty(patchedSchema(state, patch), patch);\n if (added === null) {\n warnInvalidMapping(patch, state.logger);\n } else {\n recordEnumParent(state, patch, added);\n }\n return added;\n}\n\n/** One schema and discriminator property; two discriminators of one property share an enum. */\nexport function enumKey(patch: EnumPatch): string {\n return `${patch.ref}\\n${patch.discriminator.propertyName}`;\n}\n\n/** With the fix, a second discriminator of the same property adds its values to the first enum. */\nfunction mergeIntoPatchedEnum(state: ScanState, key: string, values: readonly string[]): boolean {\n const patched = state.patchedEnums.get(key);\n if (patched === undefined) {\n return false;\n }\n const merged = patched.enum as unknown[];\n merged.push(...values.filter((value) => !merged.includes(value)));\n return true;\n}\n\n/**\n * Add or replace the discriminator enum in the schema at `patch.ref`. Returns false, with a\n * warning, when that schema is neither an `allOf` nor an object schema. Without the fix every\n * patch adds a property, so two discriminators with different values intersect to `never`.\n */\nexport function patchDiscriminatorEnum(state: ScanState, patch: EnumPatch): boolean {\n if (isDeclared(state, patch)) {\n state.declaredKeys.add(enumKey(patch));\n return true;\n }\n if (!mergesValues(state)) {\n return addDiscriminatorEnum(state, patch) !== null;\n }\n const key = enumKey(patch);\n if (mergeIntoPatchedEnum(state, key, patch.values)) {\n return true;\n }\n const added = addDiscriminatorEnum(state, patch);\n if (added !== null) {\n state.patchedEnums.set(key, added);\n }\n return added !== null;\n}\n\nexport function markHandled(state: ScanState, ref: string): void {\n if (!state.refsHandled.includes(ref)) {\n state.refsHandled.push(ref);\n }\n}\n\nfunction warnInvalidMapping(patch: EnumPatch, logger: Logger): void {\n const mapped = `${patch.ref} => ${patch.values.join(\", \")}`;\n logger.warn(\n warningText(\n \"Discriminator mapping has an invalid schema \" +\n \"(neither an object schema nor an allOf array): \" +\n `${mapped} (Discriminator: ${patch.discriminatorRef})`,\n WARNING_CODES.DISCRIMINATOR_MAPPING_INVALID,\n ),\n );\n}\n"],"names":["OutputFix","resolveDocumentRef","declaresValues","enumParentOf","addEnumProperty","warningText","WARNING_CODES"],"mappings":";;;;;;;;AA+CO,SAAS,aAAa,KAAA,EAA2B;AACtD,EAAA,OAAO,KAAA,CAAM,KAAA,CAAM,GAAA,CAAIA,qBAAA,CAAU,oBAAoB,CAAA;AACvD;AAEA,SAAS,aAAA,CAAc,OAAkB,KAAA,EAA4C;AACnF,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAO,GAAI,KAAA;AAC3B,EAAA,OAAOC,+BAAA,CAAiC,MAAM,MAAA,EAAQ,KAAA,CAAM,KAAK,EAAE,MAAA,EAAQ,QAAQ,CAAA;AACrF;AAMA,SAAS,UAAA,CAAW,OAAkB,KAAA,EAA2B;AAC/D,EAAA,OACE,KAAA,CAAM,KAAA,CAAM,GAAA,CAAID,qBAAA,CAAU,oBAAoB,CAAA,IAC9CE,gCAAA,CAAe,aAAA,CAAc,KAAA,EAAO,KAAK,CAAA,EAAG,KAAK,CAAA;AAErD;AAMO,SAAS,gBAAA,CAAiB,KAAA,EAAkB,KAAA,EAA2B,GAAA,EAAmB;AAC/F,EAAA,IAAI,CAAC,KAAA,CAAM,KAAA,CAAM,GAAA,CAAIF,qBAAA,CAAU,oBAAoB,CAAA,EAAG;AACpD,IAAA;AAAA,EACF;AACA,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAO,GAAI,KAAA;AAC3B,EAAA,MAAM,MAAA,GAASG,oCAAA;AAAA,IAAa,KAAA;AAAA,IAAO,CAAC,QAClCF,+BAAA,CAAmB,KAAA,CAAM,QAAQ,GAAA,EAAK,EAAE,MAAA,EAAQ,MAAA,EAAQ;AAAA,GAC1D;AACA,EAAA,IAAI,WAAW,MAAA,EAAW;AACxB,IAAA,KAAA,CAAM,WAAA,CAAY,GAAA,CAAI,GAAA,EAAK,MAAM,CAAA;AAAA,EACnC;AACF;AAGA,SAAS,oBAAA,CAAqB,OAAkB,KAAA,EAAuC;AACrF,EAAA,MAAM,QAAQG,iCAAA,CAAgB,aAAA,CAAc,KAAA,EAAO,KAAK,GAAG,KAAK,CAAA;AAChE,EAAA,IAAI,UAAU,IAAA,EAAM;AAClB,IAAA,kBAAA,CAAmB,KAAA,EAAO,MAAM,MAAM,CAAA;AAAA,EACxC,CAAA,MAAO;AACL,IAAA,gBAAA,CAAiB,KAAA,EAAO,OAAO,KAAK,CAAA;AAAA,EACtC;AACA,EAAA,OAAO,KAAA;AACT;AAGO,SAAS,QAAQ,KAAA,EAA0B;AAChD,EAAA,OAAO,CAAA,EAAG,MAAM,GAAG;AAAA,EAAK,KAAA,CAAM,cAAc,YAAY,CAAA,CAAA;AAC1D;AAGA,SAAS,oBAAA,CAAqB,KAAA,EAAkB,GAAA,EAAa,MAAA,EAAoC;AAC/F,EAAA,MAAM,OAAA,GAAU,KAAA,CAAM,YAAA,CAAa,GAAA,CAAI,GAAG,CAAA;AAC1C,EAAA,IAAI,YAAY,MAAA,EAAW;AACzB,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,MAAM,SAAS,OAAA,CAAQ,IAAA;AACvB,EAAA,MAAA,CAAO,IAAA,CAAK,GAAG,MAAA,CAAO,MAAA,CAAO,CAAC,KAAA,KAAU,CAAC,MAAA,CAAO,QAAA,CAAS,KAAK,CAAC,CAAC,CAAA;AAChE,EAAA,OAAO,IAAA;AACT;AAOO,SAAS,sBAAA,CAAuB,OAAkB,KAAA,EAA2B;AAClF,EAAA,IAAI,UAAA,CAAW,KAAA,EAAO,KAAK,CAAA,EAAG;AAC5B,IAAA,KAAA,CAAM,YAAA,CAAa,GAAA,CAAI,OAAA,CAAQ,KAAK,CAAC,CAAA;AACrC,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,CAAC,YAAA,CAAa,KAAK,CAAA,EAAG;AACxB,IAAA,OAAO,oBAAA,CAAqB,KAAA,EAAO,KAAK,CAAA,KAAM,IAAA;AAAA,EAChD;AACA,EAAA,MAAM,GAAA,GAAM,QAAQ,KAAK,CAAA;AACzB,EAAA,IAAI,oBAAA,CAAqB,KAAA,EAAO,GAAA,EAAK,KAAA,CAAM,MAAM,CAAA,EAAG;AAClD,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,KAAA,GAAQ,oBAAA,CAAqB,KAAA,EAAO,KAAK,CAAA;AAC/C,EAAA,IAAI,UAAU,IAAA,EAAM;AAClB,IAAA,KAAA,CAAM,YAAA,CAAa,GAAA,CAAI,GAAA,EAAK,KAAK,CAAA;AAAA,EACnC;AACA,EAAA,OAAO,KAAA,KAAU,IAAA;AACnB;AAEO,SAAS,WAAA,CAAY,OAAkB,GAAA,EAAmB;AAC/D,EAAA,IAAI,CAAC,KAAA,CAAM,WAAA,CAAY,QAAA,CAAS,GAAG,CAAA,EAAG;AACpC,IAAA,KAAA,CAAM,WAAA,CAAY,KAAK,GAAG,CAAA;AAAA,EAC5B;AACF;AAEA,SAAS,kBAAA,CAAmB,OAAkB,MAAA,EAAsB;AAClE,EAAA,MAAM,MAAA,GAAS,GAAG,KAAA,CAAM,GAAG,OAAO,KAAA,CAAM,MAAA,CAAO,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AACzD,EAAA,MAAA,CAAO,IAAA;AAAA,IACLC,oBAAA;AAAA,MACE,CAAA,2FAAA,EAEK,MAAM,CAAA,iBAAA,EAAoB,KAAA,CAAM,gBAAgB,CAAA,CAAA,CAAA;AAAA,MACrDC,sBAAA,CAAc;AAAA;AAChB,GACF;AACF;;;;;;"}
@@ -1,4 +1,5 @@
1
1
  import { OutputFix } from '../domain/output-fixes.mjs';
2
+ import { warningText, WARNING_CODES } from '../domain/warnings.mjs';
2
3
  import { declaresValues, addEnumProperty } from './discriminator-enum.mjs';
3
4
  import { enumParentOf } from './discriminator-enum-parent.mjs';
4
5
  import { resolveDocumentRef } from './document-refs.mjs';
@@ -74,7 +75,10 @@ function markHandled(state, ref) {
74
75
  function warnInvalidMapping(patch, logger) {
75
76
  const mapped = `${patch.ref} => ${patch.values.join(", ")}`;
76
77
  logger.warn(
77
- `Discriminator mapping has an invalid schema (neither an object schema nor an allOf array): ${mapped} (Discriminator: ${patch.discriminatorRef})`
78
+ warningText(
79
+ `Discriminator mapping has an invalid schema (neither an object schema nor an allOf array): ${mapped} (Discriminator: ${patch.discriminatorRef})`,
80
+ WARNING_CODES.DISCRIMINATOR_MAPPING_INVALID
81
+ )
78
82
  );
79
83
  }
80
84