openapi-typesafe 1.0.0-rc.0 → 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 (513) 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-config-source.cjs +21 -2
  7. package/dist/adapters/redocly-loader/redocly-config-source.cjs.map +1 -1
  8. package/dist/adapters/redocly-loader/redocly-config-source.mjs +22 -3
  9. package/dist/adapters/redocly-loader/redocly-config-source.mjs.map +1 -1
  10. package/dist/adapters/redocly-loader/redocly-schema-loader.cjs +34 -11
  11. package/dist/adapters/redocly-loader/redocly-schema-loader.cjs.map +1 -1
  12. package/dist/adapters/redocly-loader/redocly-schema-loader.mjs +33 -10
  13. package/dist/adapters/redocly-loader/redocly-schema-loader.mjs.map +1 -1
  14. package/dist/adapters/redocly-loader/ref-access.cjs +37 -4
  15. package/dist/adapters/redocly-loader/ref-access.cjs.map +1 -1
  16. package/dist/adapters/redocly-loader/ref-access.mjs +37 -4
  17. package/dist/adapters/redocly-loader/ref-access.mjs.map +1 -1
  18. package/dist/adapters/redocly-loader/ref-resolution-check.cjs +191 -0
  19. package/dist/adapters/redocly-loader/ref-resolution-check.cjs.map +1 -0
  20. package/dist/adapters/redocly-loader/ref-resolution-check.mjs +189 -0
  21. package/dist/adapters/redocly-loader/ref-resolution-check.mjs.map +1 -0
  22. package/dist/adapters/redocly-loader/ref-resolution-steps.cjs +73 -0
  23. package/dist/adapters/redocly-loader/ref-resolution-steps.cjs.map +1 -0
  24. package/dist/adapters/redocly-loader/ref-resolution-steps.mjs +60 -0
  25. package/dist/adapters/redocly-loader/ref-resolution-steps.mjs.map +1 -0
  26. package/dist/adapters/redocly-loader/remote-fetch.cjs +41 -14
  27. package/dist/adapters/redocly-loader/remote-fetch.cjs.map +1 -1
  28. package/dist/adapters/redocly-loader/remote-fetch.mjs +40 -14
  29. package/dist/adapters/redocly-loader/remote-fetch.mjs.map +1 -1
  30. package/dist/adapters/redocly-loader/schema-load-errors.cjs +23 -5
  31. package/dist/adapters/redocly-loader/schema-load-errors.cjs.map +1 -1
  32. package/dist/adapters/redocly-loader/schema-load-errors.mjs +23 -5
  33. package/dist/adapters/redocly-loader/schema-load-errors.mjs.map +1 -1
  34. package/dist/adapters/redocly-loader/unsupported-keys.cjs +9 -1
  35. package/dist/adapters/redocly-loader/unsupported-keys.cjs.map +1 -1
  36. package/dist/adapters/redocly-loader/unsupported-keys.mjs +9 -1
  37. package/dist/adapters/redocly-loader/unsupported-keys.mjs.map +1 -1
  38. package/dist/adapters/terminal-logger/terminal-logger.cjs +6 -4
  39. package/dist/adapters/terminal-logger/terminal-logger.cjs.map +1 -1
  40. package/dist/adapters/terminal-logger/terminal-logger.mjs +6 -4
  41. package/dist/adapters/terminal-logger/terminal-logger.mjs.map +1 -1
  42. package/dist/adapters/type-ast-bridge/ir-to-typescript.cjs +5 -1
  43. package/dist/adapters/type-ast-bridge/ir-to-typescript.cjs.map +1 -1
  44. package/dist/adapters/type-ast-bridge/ir-to-typescript.mjs +5 -1
  45. package/dist/adapters/type-ast-bridge/ir-to-typescript.mjs.map +1 -1
  46. package/dist/adapters/type-ast-bridge/print-typescript.cjs.map +1 -1
  47. package/dist/adapters/type-ast-bridge/print-typescript.mjs.map +1 -1
  48. package/dist/adapters/type-ast-bridge/typescript-to-ir.cjs +15 -9
  49. package/dist/adapters/type-ast-bridge/typescript-to-ir.cjs.map +1 -1
  50. package/dist/adapters/type-ast-bridge/typescript-to-ir.mjs +15 -9
  51. package/dist/adapters/type-ast-bridge/typescript-to-ir.mjs.map +1 -1
  52. package/dist/api/default-ports.cjs +9 -0
  53. package/dist/api/default-ports.cjs.map +1 -1
  54. package/dist/api/default-ports.mjs +8 -1
  55. package/dist/api/default-ports.mjs.map +1 -1
  56. package/dist/api/discriminator-conflict-warnings.cjs +25 -0
  57. package/dist/api/discriminator-conflict-warnings.cjs.map +1 -0
  58. package/dist/api/discriminator-conflict-warnings.mjs +23 -0
  59. package/dist/api/discriminator-conflict-warnings.mjs.map +1 -0
  60. package/dist/api/discriminator-enum-names.cjs +19 -0
  61. package/dist/api/discriminator-enum-names.cjs.map +1 -0
  62. package/dist/api/discriminator-enum-names.mjs +17 -0
  63. package/dist/api/discriminator-enum-names.mjs.map +1 -0
  64. package/dist/api/discriminator-enum-parent.cjs +59 -0
  65. package/dist/api/discriminator-enum-parent.cjs.map +1 -0
  66. package/dist/api/discriminator-enum-parent.mjs +57 -0
  67. package/dist/api/discriminator-enum-parent.mjs.map +1 -0
  68. package/dist/api/discriminator-enum.cjs +25 -0
  69. package/dist/api/discriminator-enum.cjs.map +1 -1
  70. package/dist/api/discriminator-enum.mjs +25 -1
  71. package/dist/api/discriminator-enum.mjs.map +1 -1
  72. package/dist/api/discriminator-other-owners.cjs +67 -0
  73. package/dist/api/discriminator-other-owners.cjs.map +1 -0
  74. package/dist/api/discriminator-other-owners.mjs +64 -0
  75. package/dist/api/discriminator-other-owners.mjs.map +1 -0
  76. package/dist/api/discriminator-patch.cjs +92 -0
  77. package/dist/api/discriminator-patch.cjs.map +1 -0
  78. package/dist/api/discriminator-patch.mjs +86 -0
  79. package/dist/api/discriminator-patch.mjs.map +1 -0
  80. package/dist/api/discriminator-scan.cjs +50 -65
  81. package/dist/api/discriminator-scan.cjs.map +1 -1
  82. package/dist/api/discriminator-scan.mjs +44 -59
  83. package/dist/api/discriminator-scan.mjs.map +1 -1
  84. package/dist/api/document-refs.cjs +15 -12
  85. package/dist/api/document-refs.cjs.map +1 -1
  86. package/dist/api/document-refs.mjs +15 -12
  87. package/dist/api/document-refs.mjs.map +1 -1
  88. package/dist/api/document-run.cjs +21 -4
  89. package/dist/api/document-run.cjs.map +1 -1
  90. package/dist/api/document-run.mjs +22 -5
  91. package/dist/api/document-run.mjs.map +1 -1
  92. package/dist/api/enum-values-warnings.cjs +16 -0
  93. package/dist/api/enum-values-warnings.cjs.map +1 -0
  94. package/dist/api/enum-values-warnings.mjs +14 -0
  95. package/dist/api/enum-values-warnings.mjs.map +1 -0
  96. package/dist/api/footer-sink.cjs +25 -2
  97. package/dist/api/footer-sink.cjs.map +1 -1
  98. package/dist/api/footer-sink.mjs +25 -2
  99. package/dist/api/footer-sink.mjs.map +1 -1
  100. package/dist/api/legacy-callback-warning.cjs +4 -1
  101. package/dist/api/legacy-callback-warning.cjs.map +1 -1
  102. package/dist/api/legacy-callback-warning.mjs +4 -1
  103. package/dist/api/legacy-callback-warning.mjs.map +1 -1
  104. package/dist/api/legacy-ts-helpers.cjs.map +1 -1
  105. package/dist/api/legacy-ts-helpers.mjs.map +1 -1
  106. package/dist/api/legacy-utils.cjs.map +1 -1
  107. package/dist/api/legacy-utils.mjs.map +1 -1
  108. package/dist/api/openapi-ts.cjs +2 -1
  109. package/dist/api/openapi-ts.cjs.map +1 -1
  110. package/dist/api/openapi-ts.mjs +3 -2
  111. package/dist/api/openapi-ts.mjs.map +1 -1
  112. package/dist/api/path-template-warnings.cjs +21 -0
  113. package/dist/api/path-template-warnings.cjs.map +1 -0
  114. package/dist/api/path-template-warnings.mjs +19 -0
  115. package/dist/api/path-template-warnings.mjs.map +1 -0
  116. package/dist/api/transform-context.cjs +4 -2
  117. package/dist/api/transform-context.cjs.map +1 -1
  118. package/dist/api/transform-context.mjs +4 -2
  119. package/dist/api/transform-context.mjs.map +1 -1
  120. package/dist/api/transform-schema.cjs +52 -3
  121. package/dist/api/transform-schema.cjs.map +1 -1
  122. package/dist/api/transform-schema.mjs +53 -4
  123. package/dist/api/transform-schema.mjs.map +1 -1
  124. package/dist/api/unsupported-feature-warnings.cjs +6 -1
  125. package/dist/api/unsupported-feature-warnings.cjs.map +1 -1
  126. package/dist/api/unsupported-feature-warnings.mjs +6 -1
  127. package/dist/api/unsupported-feature-warnings.mjs.map +1 -1
  128. package/dist/application/print/type-printer.cjs +7 -1
  129. package/dist/application/print/type-printer.cjs.map +1 -1
  130. package/dist/application/print/type-printer.mjs +7 -1
  131. package/dist/application/print/type-printer.mjs.map +1 -1
  132. package/dist/application/transform/document/assignability.cjs +144 -0
  133. package/dist/application/transform/document/assignability.cjs.map +1 -0
  134. package/dist/application/transform/document/assignability.mjs +138 -0
  135. package/dist/application/transform/document/assignability.mjs.map +1 -0
  136. package/dist/application/transform/document/components.cjs +2 -2
  137. package/dist/application/transform/document/components.cjs.map +1 -1
  138. package/dist/application/transform/document/components.mjs +4 -4
  139. package/dist/application/transform/document/components.mjs.map +1 -1
  140. package/dist/application/transform/document/declared-types.cjs +66 -0
  141. package/dist/application/transform/document/declared-types.cjs.map +1 -0
  142. package/dist/application/transform/document/declared-types.mjs +63 -0
  143. package/dist/application/transform/document/declared-types.mjs.map +1 -0
  144. package/dist/application/transform/document/document.cjs +32 -9
  145. package/dist/application/transform/document/document.cjs.map +1 -1
  146. package/dist/application/transform/document/document.mjs +34 -11
  147. package/dist/application/transform/document/document.mjs.map +1 -1
  148. package/dist/application/transform/document/exploded-query.cjs +46 -0
  149. package/dist/application/transform/document/exploded-query.cjs.map +1 -0
  150. package/dist/application/transform/document/exploded-query.mjs +43 -0
  151. package/dist/application/transform/document/exploded-query.mjs.map +1 -0
  152. package/dist/application/transform/document/global-type-references.cjs +63 -0
  153. package/dist/application/transform/document/global-type-references.cjs.map +1 -0
  154. package/dist/application/transform/document/global-type-references.mjs +61 -0
  155. package/dist/application/transform/document/global-type-references.mjs.map +1 -0
  156. package/dist/application/transform/document/list-assignability.cjs +54 -0
  157. package/dist/application/transform/document/list-assignability.cjs.map +1 -0
  158. package/dist/application/transform/document/list-assignability.mjs +52 -0
  159. package/dist/application/transform/document/list-assignability.mjs.map +1 -0
  160. package/dist/application/transform/document/parameters.cjs +41 -9
  161. package/dist/application/transform/document/parameters.cjs.map +1 -1
  162. package/dist/application/transform/document/parameters.mjs +42 -10
  163. package/dist/application/transform/document/parameters.mjs.map +1 -1
  164. package/dist/application/transform/document/path-key-overlaps.cjs +83 -33
  165. package/dist/application/transform/document/path-key-overlaps.cjs.map +1 -1
  166. package/dist/application/transform/document/path-key-overlaps.mjs +83 -33
  167. package/dist/application/transform/document/path-key-overlaps.mjs.map +1 -1
  168. package/dist/application/transform/document/path-template-replace.cjs +48 -0
  169. package/dist/application/transform/document/path-template-replace.cjs.map +1 -0
  170. package/dist/application/transform/document/path-template-replace.mjs +45 -0
  171. package/dist/application/transform/document/path-template-replace.mjs.map +1 -0
  172. package/dist/application/transform/document/paths.cjs +55 -29
  173. package/dist/application/transform/document/paths.cjs.map +1 -1
  174. package/dist/application/transform/document/paths.mjs +54 -30
  175. package/dist/application/transform/document/paths.mjs.map +1 -1
  176. package/dist/application/transform/document/root-type-aliases.cjs +15 -14
  177. package/dist/application/transform/document/root-type-aliases.cjs.map +1 -1
  178. package/dist/application/transform/document/root-type-aliases.mjs +15 -13
  179. package/dist/application/transform/document/root-type-aliases.mjs.map +1 -1
  180. package/dist/application/transform/document/template-key-match.cjs +128 -0
  181. package/dist/application/transform/document/template-key-match.cjs.map +1 -0
  182. package/dist/application/transform/document/template-key-match.mjs +125 -0
  183. package/dist/application/transform/document/template-key-match.mjs.map +1 -0
  184. package/dist/application/transform/document/type-assignability.cjs +192 -0
  185. package/dist/application/transform/document/type-assignability.cjs.map +1 -0
  186. package/dist/application/transform/document/type-assignability.mjs +190 -0
  187. package/dist/application/transform/document/type-assignability.mjs.map +1 -0
  188. package/dist/application/transform/document/type-key.cjs +70 -0
  189. package/dist/application/transform/document/type-key.cjs.map +1 -0
  190. package/dist/application/transform/document/type-key.mjs +68 -0
  191. package/dist/application/transform/document/type-key.mjs.map +1 -0
  192. package/dist/application/transform/document/type-resolution.cjs +131 -0
  193. package/dist/application/transform/document/type-resolution.cjs.map +1 -0
  194. package/dist/application/transform/document/type-resolution.mjs +125 -0
  195. package/dist/application/transform/document/type-resolution.mjs.map +1 -0
  196. package/dist/application/transform/footer/document-footer.cjs +66 -4
  197. package/dist/application/transform/footer/document-footer.cjs.map +1 -1
  198. package/dist/application/transform/footer/document-footer.mjs +67 -5
  199. package/dist/application/transform/footer/document-footer.mjs.map +1 -1
  200. package/dist/application/transform/footer/enum-naming.cjs +17 -0
  201. package/dist/application/transform/footer/enum-naming.cjs.map +1 -1
  202. package/dist/application/transform/footer/enum-naming.mjs +17 -1
  203. package/dist/application/transform/footer/enum-naming.mjs.map +1 -1
  204. package/dist/application/transform/footer/enum-values-check.cjs +129 -0
  205. package/dist/application/transform/footer/enum-values-check.cjs.map +1 -0
  206. package/dist/application/transform/footer/enum-values-check.mjs +127 -0
  207. package/dist/application/transform/footer/enum-values-check.mjs.map +1 -0
  208. package/dist/application/transform/footer/evaluation.cjs +42 -0
  209. package/dist/application/transform/footer/evaluation.cjs.map +1 -0
  210. package/dist/application/transform/footer/evaluation.mjs +33 -0
  211. package/dist/application/transform/footer/evaluation.mjs.map +1 -0
  212. package/dist/application/transform/footer/shared-enum-names.cjs +60 -0
  213. package/dist/application/transform/footer/shared-enum-names.cjs.map +1 -0
  214. package/dist/application/transform/footer/shared-enum-names.mjs +57 -0
  215. package/dist/application/transform/footer/shared-enum-names.mjs.map +1 -0
  216. package/dist/application/transform/footer/type-evaluation.cjs +138 -0
  217. package/dist/application/transform/footer/type-evaluation.cjs.map +1 -0
  218. package/dist/application/transform/footer/type-evaluation.mjs +136 -0
  219. package/dist/application/transform/footer/type-evaluation.mjs.map +1 -0
  220. package/dist/application/transform/footer/type-indexing.cjs +107 -0
  221. package/dist/application/transform/footer/type-indexing.cjs.map +1 -0
  222. package/dist/application/transform/footer/type-indexing.mjs +105 -0
  223. package/dist/application/transform/footer/type-indexing.mjs.map +1 -0
  224. package/dist/application/transform/footer/type-rules.cjs +172 -0
  225. package/dist/application/transform/footer/type-rules.cjs.map +1 -0
  226. package/dist/application/transform/footer/type-rules.mjs +166 -0
  227. package/dist/application/transform/footer/type-rules.mjs.map +1 -0
  228. package/dist/application/transform/ref-pointer/generated-location.cjs +138 -0
  229. package/dist/application/transform/ref-pointer/generated-location.cjs.map +1 -0
  230. package/dist/application/transform/ref-pointer/generated-location.mjs +136 -0
  231. package/dist/application/transform/ref-pointer/generated-location.mjs.map +1 -0
  232. package/dist/application/transform/ref-pointer/generated-shape.cjs +171 -0
  233. package/dist/application/transform/ref-pointer/generated-shape.cjs.map +1 -0
  234. package/dist/application/transform/ref-pointer/generated-shape.mjs +162 -0
  235. package/dist/application/transform/ref-pointer/generated-shape.mjs.map +1 -0
  236. package/dist/application/transform/ref-pointer/inline-cycles.cjs +44 -0
  237. package/dist/application/transform/ref-pointer/inline-cycles.cjs.map +1 -0
  238. package/dist/application/transform/ref-pointer/inline-cycles.mjs +42 -0
  239. package/dist/application/transform/ref-pointer/inline-cycles.mjs.map +1 -0
  240. package/dist/application/transform/ref-pointer/original-index.cjs +62 -0
  241. package/dist/application/transform/ref-pointer/original-index.cjs.map +1 -0
  242. package/dist/application/transform/ref-pointer/original-index.mjs +60 -0
  243. package/dist/application/transform/ref-pointer/original-index.mjs.map +1 -0
  244. package/dist/application/transform/ref-pointer/pointer-type.cjs +60 -0
  245. package/dist/application/transform/ref-pointer/pointer-type.cjs.map +1 -0
  246. package/dist/application/transform/ref-pointer/pointer-type.mjs +57 -0
  247. package/dist/application/transform/ref-pointer/pointer-type.mjs.map +1 -0
  248. package/dist/application/transform/ref-pointer/pointer-walk.cjs +66 -0
  249. package/dist/application/transform/ref-pointer/pointer-walk.cjs.map +1 -0
  250. package/dist/application/transform/ref-pointer/pointer-walk.mjs +56 -0
  251. package/dist/application/transform/ref-pointer/pointer-walk.mjs.map +1 -0
  252. package/dist/application/transform/ref-pointer/typed-walk.cjs +124 -0
  253. package/dist/application/transform/ref-pointer/typed-walk.cjs.map +1 -0
  254. package/dist/application/transform/ref-pointer/typed-walk.mjs +122 -0
  255. package/dist/application/transform/ref-pointer/typed-walk.mjs.map +1 -0
  256. package/dist/application/transform/ref-type.cjs +7 -2
  257. package/dist/application/transform/ref-type.cjs.map +1 -1
  258. package/dist/application/transform/ref-type.mjs +3 -2
  259. package/dist/application/transform/ref-type.mjs.map +1 -1
  260. package/dist/application/transform/schema/access-flags.cjs +38 -0
  261. package/dist/application/transform/schema/access-flags.cjs.map +1 -0
  262. package/dist/application/transform/schema/access-flags.mjs +36 -0
  263. package/dist/application/transform/schema/access-flags.mjs.map +1 -0
  264. package/dist/application/transform/schema/array-type.cjs +32 -1
  265. package/dist/application/transform/schema/array-type.cjs.map +1 -1
  266. package/dist/application/transform/schema/array-type.mjs +33 -2
  267. package/dist/application/transform/schema/array-type.mjs.map +1 -1
  268. package/dist/application/transform/schema/composition-type.cjs +50 -15
  269. package/dist/application/transform/schema/composition-type.cjs.map +1 -1
  270. package/dist/application/transform/schema/composition-type.mjs +50 -15
  271. package/dist/application/transform/schema/composition-type.mjs.map +1 -1
  272. package/dist/application/transform/schema/core-type.cjs +3 -1
  273. package/dist/application/transform/schema/core-type.cjs.map +1 -1
  274. package/dist/application/transform/schema/core-type.mjs +3 -1
  275. package/dist/application/transform/schema/core-type.mjs.map +1 -1
  276. package/dist/application/transform/schema/discriminated-union.cjs +30 -0
  277. package/dist/application/transform/schema/discriminated-union.cjs.map +1 -0
  278. package/dist/application/transform/schema/discriminated-union.mjs +27 -0
  279. package/dist/application/transform/schema/discriminated-union.mjs.map +1 -0
  280. package/dist/application/transform/schema/discriminator-property.cjs +3 -2
  281. package/dist/application/transform/schema/discriminator-property.cjs.map +1 -1
  282. package/dist/application/transform/schema/discriminator-property.mjs +3 -2
  283. package/dist/application/transform/schema/discriminator-property.mjs.map +1 -1
  284. package/dist/application/transform/schema/enum-rule.cjs +66 -10
  285. package/dist/application/transform/schema/enum-rule.cjs.map +1 -1
  286. package/dist/application/transform/schema/enum-rule.mjs +67 -12
  287. package/dist/application/transform/schema/enum-rule.mjs.map +1 -1
  288. package/dist/application/transform/schema/inherited-discriminator.cjs +29 -0
  289. package/dist/application/transform/schema/inherited-discriminator.cjs.map +1 -0
  290. package/dist/application/transform/schema/inherited-discriminator.mjs +26 -0
  291. package/dist/application/transform/schema/inherited-discriminator.mjs.map +1 -0
  292. package/dist/application/transform/schema/object-type.cjs +38 -25
  293. package/dist/application/transform/schema/object-type.cjs.map +1 -1
  294. package/dist/application/transform/schema/object-type.mjs +39 -27
  295. package/dist/application/transform/schema/object-type.mjs.map +1 -1
  296. package/dist/application/transform/schema/required-variants.cjs +45 -0
  297. package/dist/application/transform/schema/required-variants.cjs.map +1 -0
  298. package/dist/application/transform/schema/required-variants.mjs +42 -0
  299. package/dist/application/transform/schema/required-variants.mjs.map +1 -0
  300. package/dist/application/transform/schema/schema-transform.cjs +2 -2
  301. package/dist/application/transform/schema/schema-transform.cjs.map +1 -1
  302. package/dist/application/transform/schema/schema-transform.mjs +2 -2
  303. package/dist/application/transform/schema/schema-transform.mjs.map +1 -1
  304. package/dist/application/transform/schema-comment.cjs +51 -5
  305. package/dist/application/transform/schema-comment.cjs.map +1 -1
  306. package/dist/application/transform/schema-comment.mjs +50 -6
  307. package/dist/application/transform/schema-comment.mjs.map +1 -1
  308. package/dist/application/transform/type-combinators.mjs +1 -1
  309. package/dist/cli/api-settings.cjs +78 -0
  310. package/dist/cli/api-settings.cjs.map +1 -0
  311. package/dist/cli/api-settings.mjs +73 -0
  312. package/dist/cli/api-settings.mjs.map +1 -0
  313. package/dist/cli/cli-arguments.cjs +12 -3
  314. package/dist/cli/cli-arguments.cjs.map +1 -1
  315. package/dist/cli/cli-arguments.mjs +12 -4
  316. package/dist/cli/cli-arguments.mjs.map +1 -1
  317. package/dist/cli/cli-errors.cjs +3 -2
  318. package/dist/cli/cli-errors.cjs.map +1 -1
  319. package/dist/cli/cli-errors.mjs +3 -2
  320. package/dist/cli/cli-errors.mjs.map +1 -1
  321. package/dist/cli/cli-output.cjs +8 -3
  322. package/dist/cli/cli-output.cjs.map +1 -1
  323. package/dist/cli/cli-output.mjs +9 -4
  324. package/dist/cli/cli-output.mjs.map +1 -1
  325. package/dist/cli/help-text.cjs +3 -3
  326. package/dist/cli/help-text.cjs.map +1 -1
  327. package/dist/cli/help-text.mjs +3 -3
  328. package/dist/cli/help-text.mjs.map +1 -1
  329. package/dist/cli/main.cjs +5 -0
  330. package/dist/cli/main.cjs.map +1 -1
  331. package/dist/cli/main.mjs +5 -0
  332. package/dist/cli/main.mjs.map +1 -1
  333. package/dist/cli/redocly-apis.cjs +15 -7
  334. package/dist/cli/redocly-apis.cjs.map +1 -1
  335. package/dist/cli/redocly-apis.mjs +15 -7
  336. package/dist/cli/redocly-apis.mjs.map +1 -1
  337. package/dist/cli/ref-limits.cjs +1 -1
  338. package/dist/cli/ref-limits.cjs.map +1 -1
  339. package/dist/cli/ref-limits.mjs +2 -2
  340. package/dist/cli/ref-limits.mjs.map +1 -1
  341. package/dist/cli/run-cli.cjs +20 -3
  342. package/dist/cli/run-cli.cjs.map +1 -1
  343. package/dist/cli/run-cli.mjs +21 -4
  344. package/dist/cli/run-cli.mjs.map +1 -1
  345. package/dist/domain/errors.cjs +6 -1
  346. package/dist/domain/errors.cjs.map +1 -1
  347. package/dist/domain/errors.mjs +6 -1
  348. package/dist/domain/errors.mjs.map +1 -1
  349. package/dist/domain/ir/constructors.cjs +7 -1
  350. package/dist/domain/ir/constructors.cjs.map +1 -1
  351. package/dist/domain/ir/constructors.mjs +6 -2
  352. package/dist/domain/ir/constructors.mjs.map +1 -1
  353. package/dist/domain/openapi/admitted-values.cjs +75 -0
  354. package/dist/domain/openapi/admitted-values.cjs.map +1 -0
  355. package/dist/domain/openapi/admitted-values.mjs +72 -0
  356. package/dist/domain/openapi/admitted-values.mjs.map +1 -0
  357. package/dist/domain/openapi/discriminated-union.cjs +68 -0
  358. package/dist/domain/openapi/discriminated-union.cjs.map +1 -0
  359. package/dist/domain/openapi/discriminated-union.mjs +62 -0
  360. package/dist/domain/openapi/discriminated-union.mjs.map +1 -0
  361. package/dist/domain/openapi/discriminator-conflicts.cjs +143 -0
  362. package/dist/domain/openapi/discriminator-conflicts.cjs.map +1 -0
  363. package/dist/domain/openapi/discriminator-conflicts.mjs +141 -0
  364. package/dist/domain/openapi/discriminator-conflicts.mjs.map +1 -0
  365. package/dist/domain/openapi/parameter-object.cjs.map +1 -1
  366. package/dist/domain/openapi/parameter-object.mjs.map +1 -1
  367. package/dist/domain/openapi/path-templates.cjs +23 -0
  368. package/dist/domain/openapi/path-templates.cjs.map +1 -0
  369. package/dist/domain/openapi/path-templates.mjs +21 -0
  370. package/dist/domain/openapi/path-templates.mjs.map +1 -0
  371. package/dist/domain/output-fixes.cjs +36 -1
  372. package/dist/domain/output-fixes.cjs.map +1 -1
  373. package/dist/domain/output-fixes.mjs +36 -1
  374. package/dist/domain/output-fixes.mjs.map +1 -1
  375. package/dist/domain/url-credentials.cjs +10 -0
  376. package/dist/domain/url-credentials.cjs.map +1 -0
  377. package/dist/domain/url-credentials.mjs +8 -0
  378. package/dist/domain/url-credentials.mjs.map +1 -0
  379. package/dist/domain/warnings.cjs +23 -0
  380. package/dist/domain/warnings.cjs.map +1 -0
  381. package/dist/domain/warnings.mjs +20 -0
  382. package/dist/domain/warnings.mjs.map +1 -0
  383. package/dist/index.cjs +2 -0
  384. package/dist/index.cjs.map +1 -1
  385. package/dist/index.d.cts +1182 -46
  386. package/dist/index.d.mts +1182 -46
  387. package/dist/index.d.ts +1182 -46
  388. package/dist/index.mjs +1 -0
  389. package/dist/index.mjs.map +1 -1
  390. package/dist/transform/components-object.cjs +2 -1
  391. package/dist/transform/components-object.cjs.map +1 -1
  392. package/dist/transform/components-object.mjs +2 -1
  393. package/dist/transform/components-object.mjs.map +1 -1
  394. package/dist/transform/path-item-object.cjs.map +1 -1
  395. package/dist/transform/path-item-object.mjs.map +1 -1
  396. package/package.json +6 -5
  397. package/src/adapters/redocly-loader/configured-headers.ts +65 -0
  398. package/src/adapters/redocly-loader/redocly-config-source.ts +41 -6
  399. package/src/adapters/redocly-loader/redocly-schema-loader.ts +44 -13
  400. package/src/adapters/redocly-loader/ref-access.ts +60 -5
  401. package/src/adapters/redocly-loader/ref-resolution-check.ts +257 -0
  402. package/src/adapters/redocly-loader/ref-resolution-steps.ts +113 -0
  403. package/src/adapters/redocly-loader/remote-fetch.ts +77 -21
  404. package/src/adapters/redocly-loader/schema-load-errors.ts +33 -11
  405. package/src/adapters/redocly-loader/unsupported-keys.ts +17 -2
  406. package/src/adapters/terminal-logger/terminal-logger.ts +9 -5
  407. package/src/adapters/type-ast-bridge/ir-to-typescript.ts +5 -1
  408. package/src/adapters/type-ast-bridge/print-typescript.ts +3 -1
  409. package/src/adapters/type-ast-bridge/typescript-to-ir.ts +26 -12
  410. package/src/adapters/type-ast-bridge/typescript-types.ts +57 -5
  411. package/src/api/default-ports.ts +16 -0
  412. package/src/api/discriminator-conflict-warnings.ts +43 -0
  413. package/src/api/discriminator-enum-names.ts +26 -0
  414. package/src/api/discriminator-enum-parent.ts +129 -0
  415. package/src/api/discriminator-enum.ts +39 -0
  416. package/src/api/discriminator-other-owners.ts +97 -0
  417. package/src/api/discriminator-patch.ts +152 -0
  418. package/src/api/discriminator-scan.ts +78 -90
  419. package/src/api/document-refs.ts +19 -15
  420. package/src/api/document-run.ts +32 -11
  421. package/src/api/enum-values-warnings.ts +21 -0
  422. package/src/api/footer-sink.ts +34 -2
  423. package/src/api/legacy-callback-warning.ts +7 -3
  424. package/src/api/legacy-ts-helpers.ts +7 -5
  425. package/src/api/legacy-utils.ts +1 -1
  426. package/src/api/openapi-ts.ts +2 -0
  427. package/src/api/path-template-warnings.ts +27 -0
  428. package/src/api/run-context.ts +34 -0
  429. package/src/api/transform-context.ts +17 -9
  430. package/src/api/transform-schema.ts +90 -5
  431. package/src/api/unsupported-feature-warnings.ts +8 -1
  432. package/src/application/ports/redocly-config-source.ts +5 -1
  433. package/src/application/print/type-printer.ts +8 -1
  434. package/src/application/transform/document/assignability.ts +203 -0
  435. package/src/application/transform/document/components.ts +6 -6
  436. package/src/application/transform/document/declared-types.ts +93 -0
  437. package/src/application/transform/document/document.ts +71 -13
  438. package/src/application/transform/document/exploded-query.ts +91 -0
  439. package/src/application/transform/document/global-type-references.ts +78 -0
  440. package/src/application/transform/document/list-assignability.ts +87 -0
  441. package/src/application/transform/document/parameters.ts +78 -12
  442. package/src/application/transform/document/path-key-overlaps.ts +148 -59
  443. package/src/application/transform/document/path-template-replace.ts +90 -0
  444. package/src/application/transform/document/paths.ts +101 -38
  445. package/src/application/transform/document/root-type-aliases.ts +29 -28
  446. package/src/application/transform/document/template-key-match.ts +183 -0
  447. package/src/application/transform/document/type-assignability.ts +268 -0
  448. package/src/application/transform/document/type-key.ts +80 -0
  449. package/src/application/transform/document/type-resolution.ts +163 -0
  450. package/src/application/transform/footer/document-footer.ts +91 -6
  451. package/src/application/transform/footer/enum-naming.ts +29 -0
  452. package/src/application/transform/footer/enum-values-check.ts +171 -0
  453. package/src/application/transform/footer/evaluation.ts +57 -0
  454. package/src/application/transform/footer/shared-enum-names.ts +86 -0
  455. package/src/application/transform/footer/type-evaluation.ts +167 -0
  456. package/src/application/transform/footer/type-indexing.ts +152 -0
  457. package/src/application/transform/footer/type-rules.ts +269 -0
  458. package/src/application/transform/ref-pointer/generated-location.ts +211 -0
  459. package/src/application/transform/ref-pointer/generated-shape.ts +275 -0
  460. package/src/application/transform/ref-pointer/inline-cycles.ts +56 -0
  461. package/src/application/transform/ref-pointer/original-index.ts +95 -0
  462. package/src/application/transform/ref-pointer/pointer-type.ts +92 -0
  463. package/src/application/transform/ref-pointer/pointer-walk.ts +96 -0
  464. package/src/application/transform/ref-pointer/typed-walk.ts +192 -0
  465. package/src/application/transform/ref-type.ts +11 -6
  466. package/src/application/transform/schema/access-flags.ts +63 -0
  467. package/src/application/transform/schema/array-type.ts +66 -5
  468. package/src/application/transform/schema/composition-type.ts +96 -24
  469. package/src/application/transform/schema/core-type.ts +8 -4
  470. package/src/application/transform/schema/discriminated-union.ts +58 -0
  471. package/src/application/transform/schema/discriminator-property.ts +8 -3
  472. package/src/application/transform/schema/enum-rule.ts +136 -13
  473. package/src/application/transform/schema/inherited-discriminator.ts +54 -0
  474. package/src/application/transform/schema/object-type.ts +51 -33
  475. package/src/application/transform/schema/required-variants.ts +88 -0
  476. package/src/application/transform/schema/schema-context.ts +26 -0
  477. package/src/application/transform/schema/schema-transform.ts +2 -2
  478. package/src/application/transform/schema-comment.ts +84 -4
  479. package/src/cli/api-settings.ts +109 -0
  480. package/src/cli/cli-arguments.ts +18 -5
  481. package/src/cli/cli-dependencies.ts +5 -0
  482. package/src/cli/cli-errors.ts +4 -2
  483. package/src/cli/cli-output.ts +18 -4
  484. package/src/cli/help-text.ts +4 -4
  485. package/src/cli/main.ts +6 -0
  486. package/src/cli/redocly-apis.ts +21 -11
  487. package/src/cli/ref-limits.ts +2 -2
  488. package/src/cli/run-cli.ts +25 -4
  489. package/src/domain/errors.ts +10 -2
  490. package/src/domain/ir/constructors.ts +9 -1
  491. package/src/domain/ir/nodes.ts +11 -7
  492. package/src/domain/openapi/admitted-values.ts +113 -0
  493. package/src/domain/openapi/discriminated-union.ts +109 -0
  494. package/src/domain/openapi/discriminator-conflicts.ts +251 -0
  495. package/src/domain/openapi/parameter-object.ts +4 -0
  496. package/src/domain/openapi/path-templates.ts +32 -0
  497. package/src/domain/openapi/schema-object.ts +2 -0
  498. package/src/domain/output-fixes.ts +43 -2
  499. package/src/domain/url-credentials.ts +18 -0
  500. package/src/domain/warnings.ts +28 -0
  501. package/src/index.ts +1 -0
  502. package/src/transform/components-object.ts +3 -1
  503. package/src/transform/path-item-object.ts +6 -2
  504. package/src/types/generator-options.ts +12 -21
  505. package/src/types/openapi-common.ts +1 -0
  506. package/src/types/openapi-request.ts +3 -0
  507. package/src/types/openapi-schema.ts +2 -0
  508. package/src/types/openapi-security.ts +1 -0
  509. package/dist/application/transform/document/path-item-conflicts.cjs +0 -51
  510. package/dist/application/transform/document/path-item-conflicts.cjs.map +0 -1
  511. package/dist/application/transform/document/path-item-conflicts.mjs +0 -49
  512. package/dist/application/transform/document/path-item-conflicts.mjs.map +0 -1
  513. package/src/application/transform/document/path-item-conflicts.ts +0 -79
@@ -1 +1 @@
1
- {"version":3,"file":"remote-fetch.mjs","sources":["../../../src/adapters/redocly-loader/remote-fetch.ts"],"sourcesContent":["import type { Config as RedoclyConfig } from \"@redocly/openapi-core\";\nimport type { RefAccess } from \"../../application/ports/schema-loader.js\";\nimport { isHostAllowed } from \"./allowed-hosts.js\";\nimport { refForbiddenError } from \"./schema-load-errors.js\";\n\n/** How the loader fetches remote documents: a time limit, and the host limit on redirects. */\n\ntype ResolveConfig = RedoclyConfig[\"resolve\"];\n\n/** The fetch Redocly calls for a remote document (`resolve.http.customFetch`). */\nexport type RemoteFetch = (input: string, init?: RequestInit) => Promise<Response>;\n\n/**\n * Redirects followed for a remote `$ref` when hosts are limited. Each hop is checked, so fetch\n * cannot follow them on its own; 5 covers http → https plus a moved file, and a loop stops early.\n */\nexport const MAX_CHECKED_REDIRECTS = 5;\n\nconst REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);\n\n/** Statuses whose responses have no body; `new Response()` refuses a body for them. */\nconst NULL_BODY_STATUSES = new Set([101, 103, 204, 205, 304]);\n\n/** A response whose body is already read, so that reading it again cannot wait or fail. */\nasync function bufferedResponse(response: Response): Promise<Response> {\n const body = await response.arrayBuffer();\n const { status, statusText, headers } = response;\n return new Response(NULL_BODY_STATUSES.has(status) ? null : body, {\n status,\n statusText,\n headers,\n });\n}\n\n/**\n * Fetch with a time limit for the whole response, body included: Node's own fetch waits five\n * minutes for a server that never answers, and a server that sends its body one byte at a time\n * never finishes. The body is read here, inside the limit; when Redocly read it, the abort\n * surfaced as a `DOMException` whose read-only `message` Redocly tried to change, which gave\n * \"Cannot set property message of which has only a getter\" instead of the time limit.\n */\nfunction fetchWithTimeout(timeoutMs: number): RemoteFetch {\n return async (input, init = {}) => {\n try {\n const response = await fetch(input, { ...init, signal: AbortSignal.timeout(timeoutMs) });\n return await bufferedResponse(response);\n } catch (cause) {\n const isTimeout = cause instanceof Error && cause.name === \"TimeoutError\";\n throw isTimeout ? new Error(`Timed out after ${timeoutMs} ms loading ${input}`) : cause;\n }\n };\n}\n\n/**\n * Follow redirects one by one, and refuse a redirect to a host that is not listed. The first URL\n * was checked by the resolver (or is the root document). As fetch does, the configured headers\n * (often credentials) are not sent on to another origin.\n */\nexport function fetchWithCheckedRedirects(\n fetchImpl: RemoteFetch,\n hosts: readonly string[],\n): RemoteFetch {\n return async (input, init = {}) => {\n const firstOrigin = new URL(input).origin;\n let url = new URL(input);\n for (let hop = 0; hop <= MAX_CHECKED_REDIRECTS; hop += 1) {\n if (hop > 0 && !isHostAllowed(url, hosts)) {\n throw refForbiddenError(url.href, { reason: \"host-not-allowed\", allowedHosts: [...hosts] });\n }\n const { headers, ...rest } = init;\n const hopInit: RequestInit =\n url.origin === firstOrigin && headers !== undefined ? { ...rest, headers } : rest;\n const response = await fetchImpl(url.href, { ...hopInit, redirect: \"manual\" });\n const location = response.headers.get(\"location\");\n if (!REDIRECT_STATUSES.has(response.status) || location === null) {\n return response;\n }\n url = new URL(location, url);\n }\n throw new Error(`More than ${MAX_CHECKED_REDIRECTS} redirects loading ${input}`);\n };\n}\n\nexport interface RemoteFetchOptions {\n /** Time limit of one fetch and its body, unless the Redocly config has its own `customFetch`. */\n readonly timeoutMs: number;\n readonly access: RefAccess;\n}\n\n/**\n * The resolve config with the fetch the loader uses. A `customFetch` of the Redocly config is\n * kept; with a host limit, it is wrapped so that each redirect is checked.\n */\nexport function resolveConfigWithAccess(\n resolve: ResolveConfig,\n options: RemoteFetchOptions,\n): ResolveConfig {\n // Redocly types `customFetch` as `Function`; it is called as fetch is.\n const configured = resolve.http.customFetch as RemoteFetch | undefined;\n const base = configured ?? fetchWithTimeout(options.timeoutMs);\n const hosts = options.access.remoteHosts;\n const customFetch = hosts === undefined ? base : fetchWithCheckedRedirects(base, hosts);\n return { ...resolve, http: { ...resolve.http, customFetch } };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"remote-fetch.mjs","sources":["../../../src/adapters/redocly-loader/remote-fetch.ts"],"sourcesContent":["import type { Config as RedoclyConfig } from \"@redocly/openapi-core\";\nimport type { RefAccess } from \"../../application/ports/schema-loader.js\";\nimport { isHostAllowed } from \"./allowed-hosts.js\";\nimport { type ConfiguredHeader, headersFor } from \"./configured-headers.js\";\nimport { refForbiddenError } from \"./schema-load-errors.js\";\n\n/**\n * How the loader fetches remote documents: a time limit, the host limit and the configured headers\n * checked on every redirect.\n */\n\ntype ResolveConfig = RedoclyConfig[\"resolve\"];\n\n/** The fetch Redocly calls for a remote document (`resolve.http.customFetch`). */\nexport type RemoteFetch = (input: string, init?: RequestInit) => Promise<Response>;\n\n/**\n * Redirects followed for one remote document. The loader follows them itself, so that each hop is\n * checked; 20 is the limit of the Fetch standard, which fetch applied before.\n */\nexport const MAX_REDIRECTS = 20;\n\nconst REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);\n\n/** Statuses whose responses have no body; `new Response()` refuses a body for them. */\nconst NULL_BODY_STATUSES = new Set([101, 103, 204, 205, 304]);\n\n/** A response whose body is already read, so that reading it again cannot wait or fail. */\nasync function bufferedResponse(response: Response): Promise<Response> {\n const body = await response.arrayBuffer();\n const { status, statusText, headers } = response;\n return new Response(NULL_BODY_STATUSES.has(status) ? null : body, {\n status,\n statusText,\n headers,\n });\n}\n\n/**\n * Fetch with a time limit for the whole response, body included: Node's own fetch waits five\n * minutes for a server that never answers, and a server that sends its body one byte at a time\n * never finishes. The body is read here, inside the limit; when Redocly read it, the abort\n * surfaced as a `DOMException` whose read-only `message` Redocly tried to change, which gave\n * \"Cannot set property message of which has only a getter\" instead of the time limit.\n */\nfunction fetchWithTimeout(timeoutMs: number): RemoteFetch {\n return async (input, init = {}) => {\n try {\n const response = await fetch(input, { ...init, signal: AbortSignal.timeout(timeoutMs) });\n return await bufferedResponse(response);\n } catch (cause) {\n const isTimeout = cause instanceof Error && cause.name === \"TimeoutError\";\n throw isTimeout ? new Error(`Timed out after ${timeoutMs} ms loading ${input}`) : cause;\n }\n };\n}\n\n/** What every hop of a remote fetch is checked against. */\nexport interface RedirectPolicy {\n /** `resolve.http.headers` of the Redocly config; chosen again for the URL of every hop. */\n readonly headers: readonly ConfiguredHeader[];\n /** `--remote-ref-hosts`; undefined allows every host. */\n readonly hosts: readonly string[] | undefined;\n}\n\n/**\n * Follow redirects one by one. Fetch drops only `Authorization`, `Cookie` and\n * `Proxy-Authorization` on a redirect to another origin and keeps every other header (an\n * `X-Api-Key`), so the configured headers are chosen for each hop's own URL instead, and a hop to\n * a host that is not listed is refused before it is fetched. The first URL was checked by the\n * resolver (or is the root document). Redocly passes only the configured headers in `init`, and\n * it gets an empty list of them (`resolveConfigWithAccess`), so `init.headers` is replaced.\n */\nexport function fetchWithCheckedRedirects(\n fetchImpl: RemoteFetch,\n policy: RedirectPolicy,\n): RemoteFetch {\n return async (input, init = {}) => {\n let url = new URL(input);\n for (let hop = 0; hop <= MAX_REDIRECTS; hop += 1) {\n if (hop > 0 && policy.hosts !== undefined && !isHostAllowed(url, policy.hosts)) {\n throw refForbiddenError(url.href, {\n reason: \"host-not-allowed\",\n allowedHosts: [...policy.hosts],\n });\n }\n const headers = await headersFor(url, policy.headers);\n const response = await fetchImpl(url.href, { ...init, headers, redirect: \"manual\" });\n const location = response.headers.get(\"location\");\n if (!REDIRECT_STATUSES.has(response.status) || location === null) {\n return response;\n }\n url = new URL(location, url);\n }\n throw new Error(`More than ${MAX_REDIRECTS} redirects loading ${input}`);\n };\n}\n\n/** Bounds on the remote documents of one load (threat model T2, ADR-033). */\nexport interface RemoteDocumentLimits {\n /** Remote documents one load may fetch, the root included; one more is refused. */\n readonly maxDocuments: number;\n /** Remote documents fetched at the same time; the others wait for a free slot. */\n readonly maxParallelFetches: number;\n}\n\n/**\n * At most `limit` calls of the fetch run at once; the others wait in order. A finished call hands\n * its slot to the next waiting one.\n */\nexport function fetchWithConcurrencyLimit(fetchImpl: RemoteFetch, limit: number): RemoteFetch {\n let running = 0;\n const waiting: (() => void)[] = [];\n return async (input, init) => {\n if (running < limit) {\n running += 1;\n } else {\n await new Promise<void>((resolve) => waiting.push(resolve));\n }\n try {\n return await fetchImpl(input, init);\n } finally {\n const next = waiting.shift();\n if (next === undefined) {\n running -= 1;\n } else {\n next();\n }\n }\n };\n}\n\nexport interface RemoteFetchOptions {\n /** Time limit of one fetch and its body, unless the Redocly config has its own `customFetch`. */\n readonly timeoutMs: number;\n readonly access: RefAccess;\n readonly maxParallelFetches: number;\n}\n\n/**\n * The resolve config with the fetch the loader uses. A `customFetch` of the Redocly config is\n * kept and wrapped, so that each redirect is checked and only a few documents load at once. The\n * configured headers move into that wrapper: Redocly would match them against the raw URL and\n * send them on through redirects.\n */\nexport function resolveConfigWithAccess(\n resolve: ResolveConfig,\n options: RemoteFetchOptions,\n): ResolveConfig {\n // Redocly types `customFetch` as `Function`; it is called as fetch is.\n const configured = resolve.http.customFetch as RemoteFetch | undefined;\n const base = configured ?? fetchWithTimeout(options.timeoutMs);\n const checked = fetchWithCheckedRedirects(base, {\n headers: resolve.http.headers,\n hosts: options.access.remoteHosts,\n });\n // The limit is outside the redirects, so all hops of one document share one slot.\n const customFetch = fetchWithConcurrencyLimit(checked, options.maxParallelFetches);\n return { ...resolve, http: { ...resolve.http, headers: [], customFetch } };\n}\n"],"names":[],"mappings":"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"}
@@ -1,6 +1,8 @@
1
1
  'use strict';
2
2
 
3
+ const assertNever = require('../../domain/assert-never.cjs');
3
4
  const errors = require('../../domain/errors.cjs');
5
+ const urlCredentials = require('../../domain/url-credentials.cjs');
4
6
 
5
7
  function sourceEmptyError(message) {
6
8
  return new errors.OpenAPITypesafeError({ code: errors.ERROR_CODES.SCHEMA_SOURCE_EMPTY, message });
@@ -29,7 +31,7 @@ function loadFailedError(absoluteRef, cause) {
29
31
  return new errors.OpenAPITypesafeError({
30
32
  code: errors.ERROR_CODES.SCHEMA_LOAD_FAILED,
31
33
  message: causeMessage(cause),
32
- details: { source: absoluteRef },
34
+ details: { source: urlCredentials.redactUrlCredentials(absoluteRef) },
33
35
  cause
34
36
  });
35
37
  }
@@ -37,7 +39,7 @@ function parseFailedError(format, absoluteRef, cause) {
37
39
  return new errors.OpenAPITypesafeError({
38
40
  code: errors.ERROR_CODES.SCHEMA_PARSE_FAILED,
39
41
  message: causeMessage(cause),
40
- details: { format, source: absoluteRef },
42
+ details: { format, source: urlCredentials.redactUrlCredentials(absoluteRef) },
41
43
  cause
42
44
  });
43
45
  }
@@ -52,7 +54,7 @@ function schemaInvalidError(problems) {
52
54
  return new errors.OpenAPITypesafeError({
53
55
  code: errors.ERROR_CODES.SCHEMA_INVALID,
54
56
  message: problems.at(-1) ?? "",
55
- details: { problems: [...problems] }
57
+ details: { problems: problems.map(urlCredentials.redactUrlCredentials) }
56
58
  });
57
59
  }
58
60
  function refCycleError(cause) {
@@ -66,12 +68,28 @@ function refCycleError(cause) {
66
68
  function hostListText(hosts) {
67
69
  return hosts.length === 0 ? "none" : hosts.join(", ");
68
70
  }
71
+ function limitText(details) {
72
+ switch (details.reason) {
73
+ case "outside-local-root":
74
+ return `it is outside the local $ref root ${details.localRoot}`;
75
+ case "host-not-allowed": {
76
+ const hosts = hostListText(details.allowedHosts);
77
+ return `its host is not in the allowed remote $ref hosts (${hosts})`;
78
+ }
79
+ case "local-ref-from-remote":
80
+ return `it is not an http(s) URL, and the $ref is in the remote document ${details.base}`;
81
+ case "too-many-remote-documents":
82
+ return `the document refers to more than ${details.maxDocuments} remote documents`;
83
+ default:
84
+ return assertNever.assertNever(details);
85
+ }
86
+ }
69
87
  function refForbiddenError(ref, details) {
70
- const limit = details.reason === "outside-local-root" ? `it is outside the local $ref root ${details.localRoot}` : `its host is not in the allowed remote $ref hosts (${hostListText(details.allowedHosts)})`;
88
+ const limit = limitText(details);
71
89
  return new errors.OpenAPITypesafeError({
72
90
  code: errors.ERROR_CODES.SCHEMA_REF_FORBIDDEN,
73
91
  message: `Refused to load ${ref}: ${limit}`,
74
- details: { ref, ...details }
92
+ details: { ref: urlCredentials.redactUrlCredentials(ref), ...details }
75
93
  });
76
94
  }
77
95
 
@@ -1 +1 @@
1
- {"version":3,"file":"schema-load-errors.cjs","sources":["../../../src/adapters/redocly-loader/schema-load-errors.ts"],"sourcesContent":["import { ERROR_CODES, OpenAPITypesafeError } from \"../../domain/errors.js\";\n\n/**\n * The typed errors of loading, validating and bundling a document (ADR-011). Messages are the\n * original messages, so Node API users who match on them keep working.\n */\n\n/** No source was given, or the source is empty. */\nexport function sourceEmptyError(message: string): OpenAPITypesafeError {\n return new OpenAPITypesafeError({ code: ERROR_CODES.SCHEMA_SOURCE_EMPTY, message });\n}\n\n/** The source is neither a URL, text, buffer, stream nor plain object. */\nexport function sourceInvalidError(source: unknown): OpenAPITypesafeError {\n const received = Array.isArray(source) ? \"Array\" : typeof source;\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_SOURCE_INVALID,\n message: `Expected string, object, or Buffer. Got ${received}`,\n details: { received },\n });\n}\n\nfunction causeMessage(cause: unknown): string {\n return cause instanceof Error ? cause.message : String(cause);\n}\n\n/** Enough of a source string to recognise it in the message. */\nconst SOURCE_TEXT_IN_MESSAGE = 200;\n\n/**\n * A string source is document text, so a file path parses as a YAML string scalar, not as a\n * document (docs/node.md). The message says how to load the file instead.\n */\nexport function pathStringError(text: string): OpenAPITypesafeError {\n const shown =\n text.length > SOURCE_TEXT_IN_MESSAGE ? `${text.slice(0, SOURCE_TEXT_IN_MESSAGE)}…` : text;\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_SOURCE_INVALID,\n message:\n `The string \"${shown}\" was parsed as YAML text, not loaded as a file. ` +\n \"To load a file, pass a URL: openapiTS(pathToFileURL(path)) from node:url.\",\n details: { reason: \"path\", received: \"string\" },\n });\n}\n\n/** Reading the document from a file or URL failed; the message is the reader's message. */\nexport function loadFailedError(absoluteRef: string, cause: unknown): OpenAPITypesafeError {\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_LOAD_FAILED,\n message: causeMessage(cause),\n details: { source: absoluteRef },\n cause,\n });\n}\n\n/** The document text is not valid JSON or YAML; the message is the parser's message. */\nexport function parseFailedError(\n format: \"json\" | \"yaml\",\n absoluteRef: string,\n cause: unknown,\n): OpenAPITypesafeError {\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_PARSE_FAILED,\n message: causeMessage(cause),\n details: { format, source: absoluteRef },\n cause,\n });\n}\n\n/** The document is not OpenAPI 3.x. */\nexport function versionUnsupportedError(\n message: string,\n parsed: Readonly<Record<string, unknown>>,\n): OpenAPITypesafeError {\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_VERSION_UNSUPPORTED,\n message,\n details: { openapi: parsed.openapi, swagger: parsed.swagger },\n });\n}\n\n/**\n * Linting or bundling found errors. The message is the last error, as in the original; all error\n * messages are in `details.problems`.\n */\nexport function schemaInvalidError(problems: readonly string[]): OpenAPITypesafeError {\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_INVALID,\n message: problems.at(-1) ?? \"\",\n details: { problems: [...problems] },\n });\n}\n\n/** A `$ref` chain points back to itself with no schema in between (`A: $ref B`, `B: $ref A`). */\nexport function refCycleError(cause: Error): OpenAPITypesafeError {\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_REF_INVALID,\n message: cause.message,\n details: { reason: \"cycle\" },\n cause,\n });\n}\n\nfunction hostListText(hosts: readonly string[]): string {\n return hosts.length === 0 ? \"none\" : hosts.join(\", \");\n}\n\n/** Why a `$ref` document was refused, with the limit it broke (ADR-017). */\nexport type RefRefusalDetails =\n | { readonly reason: \"outside-local-root\"; readonly localRoot: string }\n | { readonly reason: \"host-not-allowed\"; readonly allowedHosts: readonly string[] };\n\n/** A `$ref` is outside the local root, or its host is not allowed (threat model R1, R2). */\nexport function refForbiddenError(ref: string, details: RefRefusalDetails): OpenAPITypesafeError {\n const limit =\n details.reason === \"outside-local-root\"\n ? `it is outside the local $ref root ${details.localRoot}`\n : `its host is not in the allowed remote $ref hosts (${hostListText(details.allowedHosts)})`;\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_REF_FORBIDDEN,\n message: `Refused to load ${ref}: ${limit}`,\n details: { ref, ...details },\n });\n}\n"],"names":["OpenAPITypesafeError","ERROR_CODES"],"mappings":"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"}
1
+ {"version":3,"file":"schema-load-errors.cjs","sources":["../../../src/adapters/redocly-loader/schema-load-errors.ts"],"sourcesContent":["import { assertNever } from \"../../domain/assert-never.js\";\nimport { ERROR_CODES, OpenAPITypesafeError } from \"../../domain/errors.js\";\nimport { redactUrlCredentials } from \"../../domain/url-credentials.js\";\n\n/**\n * The typed errors of loading, validating and bundling a document (ADR-011). Messages are the\n * original messages, so Node API users who match on them keep working; URLs in them and in the\n * details never show user info.\n */\n\n/** No source was given, or the source is empty. */\nexport function sourceEmptyError(message: string): OpenAPITypesafeError {\n return new OpenAPITypesafeError({ code: ERROR_CODES.SCHEMA_SOURCE_EMPTY, message });\n}\n\n/** The source is neither a URL, text, buffer, stream nor plain object. */\nexport function sourceInvalidError(source: unknown): OpenAPITypesafeError {\n const received = Array.isArray(source) ? \"Array\" : typeof source;\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_SOURCE_INVALID,\n message: `Expected string, object, or Buffer. Got ${received}`,\n details: { received },\n });\n}\n\nfunction causeMessage(cause: unknown): string {\n return cause instanceof Error ? cause.message : String(cause);\n}\n\n/** Enough of a source string to recognise it in the message. */\nconst SOURCE_TEXT_IN_MESSAGE = 200;\n\n/**\n * A string source is document text, so a file path parses as a YAML string scalar, not as a\n * document (docs/node.md). The message says how to load the file instead.\n */\nexport function pathStringError(text: string): OpenAPITypesafeError {\n const shown =\n text.length > SOURCE_TEXT_IN_MESSAGE ? `${text.slice(0, SOURCE_TEXT_IN_MESSAGE)}…` : text;\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_SOURCE_INVALID,\n message:\n `The string \"${shown}\" was parsed as YAML text, not loaded as a file. ` +\n \"To load a file, pass a URL: openapiTS(pathToFileURL(path)) from node:url.\",\n details: { reason: \"path\", received: \"string\" },\n });\n}\n\n/** Reading the document from a file or URL failed; the message is the reader's message. */\nexport function loadFailedError(absoluteRef: string, cause: unknown): OpenAPITypesafeError {\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_LOAD_FAILED,\n message: causeMessage(cause),\n details: { source: redactUrlCredentials(absoluteRef) },\n cause,\n });\n}\n\n/** The document text is not valid JSON or YAML; the message is the parser's message. */\nexport function parseFailedError(\n format: \"json\" | \"yaml\",\n absoluteRef: string,\n cause: unknown,\n): OpenAPITypesafeError {\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_PARSE_FAILED,\n message: causeMessage(cause),\n details: { format, source: redactUrlCredentials(absoluteRef) },\n cause,\n });\n}\n\n/** The document is not OpenAPI 3.x. */\nexport function versionUnsupportedError(\n message: string,\n parsed: Readonly<Record<string, unknown>>,\n): OpenAPITypesafeError {\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_VERSION_UNSUPPORTED,\n message,\n details: { openapi: parsed.openapi, swagger: parsed.swagger },\n });\n}\n\n/**\n * Linting or bundling found errors. The message is the last error, as in the original; all error\n * messages are in `details.problems`.\n */\nexport function schemaInvalidError(problems: readonly string[]): OpenAPITypesafeError {\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_INVALID,\n message: problems.at(-1) ?? \"\",\n details: { problems: problems.map(redactUrlCredentials) },\n });\n}\n\n/** A `$ref` chain points back to itself with no schema in between (`A: $ref B`, `B: $ref A`). */\nexport function refCycleError(cause: Error): OpenAPITypesafeError {\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_REF_INVALID,\n message: cause.message,\n details: { reason: \"cycle\" },\n cause,\n });\n}\n\nfunction hostListText(hosts: readonly string[]): string {\n return hosts.length === 0 ? \"none\" : hosts.join(\", \");\n}\n\n/** Why a `$ref` document was refused, with the limit it broke (ADR-017). */\nexport type RefRefusalDetails =\n | { readonly reason: \"outside-local-root\"; readonly localRoot: string }\n | { readonly reason: \"host-not-allowed\"; readonly allowedHosts: readonly string[] }\n | { readonly reason: \"local-ref-from-remote\"; readonly base: string }\n | { readonly reason: \"too-many-remote-documents\"; readonly maxDocuments: number };\n\nfunction limitText(details: RefRefusalDetails): string {\n switch (details.reason) {\n case \"outside-local-root\":\n return `it is outside the local $ref root ${details.localRoot}`;\n case \"host-not-allowed\": {\n const hosts = hostListText(details.allowedHosts);\n return `its host is not in the allowed remote $ref hosts (${hosts})`;\n }\n case \"local-ref-from-remote\":\n return `it is not an http(s) URL, and the $ref is in the remote document ${details.base}`;\n case \"too-many-remote-documents\":\n return `the document refers to more than ${details.maxDocuments} remote documents`;\n default:\n return assertNever(details);\n }\n}\n\n/**\n * A `$ref` is outside the local root, its host is not allowed (threat model R1, R2), a remote\n * document refers to a local file (T3), or there are too many remote documents (T2).\n */\nexport function refForbiddenError(ref: string, details: RefRefusalDetails): OpenAPITypesafeError {\n const limit = limitText(details);\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_REF_FORBIDDEN,\n message: `Refused to load ${ref}: ${limit}`,\n details: { ref: redactUrlCredentials(ref), ...details },\n });\n}\n"],"names":["OpenAPITypesafeError","ERROR_CODES","redactUrlCredentials","assertNever"],"mappings":"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"}
@@ -1,4 +1,6 @@
1
+ import { assertNever } from '../../domain/assert-never.mjs';
1
2
  import { OpenAPITypesafeError, ERROR_CODES } from '../../domain/errors.mjs';
3
+ import { redactUrlCredentials } from '../../domain/url-credentials.mjs';
2
4
 
3
5
  function sourceEmptyError(message) {
4
6
  return new OpenAPITypesafeError({ code: ERROR_CODES.SCHEMA_SOURCE_EMPTY, message });
@@ -27,7 +29,7 @@ function loadFailedError(absoluteRef, cause) {
27
29
  return new OpenAPITypesafeError({
28
30
  code: ERROR_CODES.SCHEMA_LOAD_FAILED,
29
31
  message: causeMessage(cause),
30
- details: { source: absoluteRef },
32
+ details: { source: redactUrlCredentials(absoluteRef) },
31
33
  cause
32
34
  });
33
35
  }
@@ -35,7 +37,7 @@ function parseFailedError(format, absoluteRef, cause) {
35
37
  return new OpenAPITypesafeError({
36
38
  code: ERROR_CODES.SCHEMA_PARSE_FAILED,
37
39
  message: causeMessage(cause),
38
- details: { format, source: absoluteRef },
40
+ details: { format, source: redactUrlCredentials(absoluteRef) },
39
41
  cause
40
42
  });
41
43
  }
@@ -50,7 +52,7 @@ function schemaInvalidError(problems) {
50
52
  return new OpenAPITypesafeError({
51
53
  code: ERROR_CODES.SCHEMA_INVALID,
52
54
  message: problems.at(-1) ?? "",
53
- details: { problems: [...problems] }
55
+ details: { problems: problems.map(redactUrlCredentials) }
54
56
  });
55
57
  }
56
58
  function refCycleError(cause) {
@@ -64,12 +66,28 @@ function refCycleError(cause) {
64
66
  function hostListText(hosts) {
65
67
  return hosts.length === 0 ? "none" : hosts.join(", ");
66
68
  }
69
+ function limitText(details) {
70
+ switch (details.reason) {
71
+ case "outside-local-root":
72
+ return `it is outside the local $ref root ${details.localRoot}`;
73
+ case "host-not-allowed": {
74
+ const hosts = hostListText(details.allowedHosts);
75
+ return `its host is not in the allowed remote $ref hosts (${hosts})`;
76
+ }
77
+ case "local-ref-from-remote":
78
+ return `it is not an http(s) URL, and the $ref is in the remote document ${details.base}`;
79
+ case "too-many-remote-documents":
80
+ return `the document refers to more than ${details.maxDocuments} remote documents`;
81
+ default:
82
+ return assertNever(details);
83
+ }
84
+ }
67
85
  function refForbiddenError(ref, details) {
68
- const limit = details.reason === "outside-local-root" ? `it is outside the local $ref root ${details.localRoot}` : `its host is not in the allowed remote $ref hosts (${hostListText(details.allowedHosts)})`;
86
+ const limit = limitText(details);
69
87
  return new OpenAPITypesafeError({
70
88
  code: ERROR_CODES.SCHEMA_REF_FORBIDDEN,
71
89
  message: `Refused to load ${ref}: ${limit}`,
72
- details: { ref, ...details }
90
+ details: { ref: redactUrlCredentials(ref), ...details }
73
91
  });
74
92
  }
75
93
 
@@ -1 +1 @@
1
- {"version":3,"file":"schema-load-errors.mjs","sources":["../../../src/adapters/redocly-loader/schema-load-errors.ts"],"sourcesContent":["import { ERROR_CODES, OpenAPITypesafeError } from \"../../domain/errors.js\";\n\n/**\n * The typed errors of loading, validating and bundling a document (ADR-011). Messages are the\n * original messages, so Node API users who match on them keep working.\n */\n\n/** No source was given, or the source is empty. */\nexport function sourceEmptyError(message: string): OpenAPITypesafeError {\n return new OpenAPITypesafeError({ code: ERROR_CODES.SCHEMA_SOURCE_EMPTY, message });\n}\n\n/** The source is neither a URL, text, buffer, stream nor plain object. */\nexport function sourceInvalidError(source: unknown): OpenAPITypesafeError {\n const received = Array.isArray(source) ? \"Array\" : typeof source;\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_SOURCE_INVALID,\n message: `Expected string, object, or Buffer. Got ${received}`,\n details: { received },\n });\n}\n\nfunction causeMessage(cause: unknown): string {\n return cause instanceof Error ? cause.message : String(cause);\n}\n\n/** Enough of a source string to recognise it in the message. */\nconst SOURCE_TEXT_IN_MESSAGE = 200;\n\n/**\n * A string source is document text, so a file path parses as a YAML string scalar, not as a\n * document (docs/node.md). The message says how to load the file instead.\n */\nexport function pathStringError(text: string): OpenAPITypesafeError {\n const shown =\n text.length > SOURCE_TEXT_IN_MESSAGE ? `${text.slice(0, SOURCE_TEXT_IN_MESSAGE)}…` : text;\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_SOURCE_INVALID,\n message:\n `The string \"${shown}\" was parsed as YAML text, not loaded as a file. ` +\n \"To load a file, pass a URL: openapiTS(pathToFileURL(path)) from node:url.\",\n details: { reason: \"path\", received: \"string\" },\n });\n}\n\n/** Reading the document from a file or URL failed; the message is the reader's message. */\nexport function loadFailedError(absoluteRef: string, cause: unknown): OpenAPITypesafeError {\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_LOAD_FAILED,\n message: causeMessage(cause),\n details: { source: absoluteRef },\n cause,\n });\n}\n\n/** The document text is not valid JSON or YAML; the message is the parser's message. */\nexport function parseFailedError(\n format: \"json\" | \"yaml\",\n absoluteRef: string,\n cause: unknown,\n): OpenAPITypesafeError {\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_PARSE_FAILED,\n message: causeMessage(cause),\n details: { format, source: absoluteRef },\n cause,\n });\n}\n\n/** The document is not OpenAPI 3.x. */\nexport function versionUnsupportedError(\n message: string,\n parsed: Readonly<Record<string, unknown>>,\n): OpenAPITypesafeError {\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_VERSION_UNSUPPORTED,\n message,\n details: { openapi: parsed.openapi, swagger: parsed.swagger },\n });\n}\n\n/**\n * Linting or bundling found errors. The message is the last error, as in the original; all error\n * messages are in `details.problems`.\n */\nexport function schemaInvalidError(problems: readonly string[]): OpenAPITypesafeError {\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_INVALID,\n message: problems.at(-1) ?? \"\",\n details: { problems: [...problems] },\n });\n}\n\n/** A `$ref` chain points back to itself with no schema in between (`A: $ref B`, `B: $ref A`). */\nexport function refCycleError(cause: Error): OpenAPITypesafeError {\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_REF_INVALID,\n message: cause.message,\n details: { reason: \"cycle\" },\n cause,\n });\n}\n\nfunction hostListText(hosts: readonly string[]): string {\n return hosts.length === 0 ? \"none\" : hosts.join(\", \");\n}\n\n/** Why a `$ref` document was refused, with the limit it broke (ADR-017). */\nexport type RefRefusalDetails =\n | { readonly reason: \"outside-local-root\"; readonly localRoot: string }\n | { readonly reason: \"host-not-allowed\"; readonly allowedHosts: readonly string[] };\n\n/** A `$ref` is outside the local root, or its host is not allowed (threat model R1, R2). */\nexport function refForbiddenError(ref: string, details: RefRefusalDetails): OpenAPITypesafeError {\n const limit =\n details.reason === \"outside-local-root\"\n ? `it is outside the local $ref root ${details.localRoot}`\n : `its host is not in the allowed remote $ref hosts (${hostListText(details.allowedHosts)})`;\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_REF_FORBIDDEN,\n message: `Refused to load ${ref}: ${limit}`,\n details: { ref, ...details },\n });\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema-load-errors.mjs","sources":["../../../src/adapters/redocly-loader/schema-load-errors.ts"],"sourcesContent":["import { assertNever } from \"../../domain/assert-never.js\";\nimport { ERROR_CODES, OpenAPITypesafeError } from \"../../domain/errors.js\";\nimport { redactUrlCredentials } from \"../../domain/url-credentials.js\";\n\n/**\n * The typed errors of loading, validating and bundling a document (ADR-011). Messages are the\n * original messages, so Node API users who match on them keep working; URLs in them and in the\n * details never show user info.\n */\n\n/** No source was given, or the source is empty. */\nexport function sourceEmptyError(message: string): OpenAPITypesafeError {\n return new OpenAPITypesafeError({ code: ERROR_CODES.SCHEMA_SOURCE_EMPTY, message });\n}\n\n/** The source is neither a URL, text, buffer, stream nor plain object. */\nexport function sourceInvalidError(source: unknown): OpenAPITypesafeError {\n const received = Array.isArray(source) ? \"Array\" : typeof source;\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_SOURCE_INVALID,\n message: `Expected string, object, or Buffer. Got ${received}`,\n details: { received },\n });\n}\n\nfunction causeMessage(cause: unknown): string {\n return cause instanceof Error ? cause.message : String(cause);\n}\n\n/** Enough of a source string to recognise it in the message. */\nconst SOURCE_TEXT_IN_MESSAGE = 200;\n\n/**\n * A string source is document text, so a file path parses as a YAML string scalar, not as a\n * document (docs/node.md). The message says how to load the file instead.\n */\nexport function pathStringError(text: string): OpenAPITypesafeError {\n const shown =\n text.length > SOURCE_TEXT_IN_MESSAGE ? `${text.slice(0, SOURCE_TEXT_IN_MESSAGE)}…` : text;\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_SOURCE_INVALID,\n message:\n `The string \"${shown}\" was parsed as YAML text, not loaded as a file. ` +\n \"To load a file, pass a URL: openapiTS(pathToFileURL(path)) from node:url.\",\n details: { reason: \"path\", received: \"string\" },\n });\n}\n\n/** Reading the document from a file or URL failed; the message is the reader's message. */\nexport function loadFailedError(absoluteRef: string, cause: unknown): OpenAPITypesafeError {\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_LOAD_FAILED,\n message: causeMessage(cause),\n details: { source: redactUrlCredentials(absoluteRef) },\n cause,\n });\n}\n\n/** The document text is not valid JSON or YAML; the message is the parser's message. */\nexport function parseFailedError(\n format: \"json\" | \"yaml\",\n absoluteRef: string,\n cause: unknown,\n): OpenAPITypesafeError {\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_PARSE_FAILED,\n message: causeMessage(cause),\n details: { format, source: redactUrlCredentials(absoluteRef) },\n cause,\n });\n}\n\n/** The document is not OpenAPI 3.x. */\nexport function versionUnsupportedError(\n message: string,\n parsed: Readonly<Record<string, unknown>>,\n): OpenAPITypesafeError {\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_VERSION_UNSUPPORTED,\n message,\n details: { openapi: parsed.openapi, swagger: parsed.swagger },\n });\n}\n\n/**\n * Linting or bundling found errors. The message is the last error, as in the original; all error\n * messages are in `details.problems`.\n */\nexport function schemaInvalidError(problems: readonly string[]): OpenAPITypesafeError {\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_INVALID,\n message: problems.at(-1) ?? \"\",\n details: { problems: problems.map(redactUrlCredentials) },\n });\n}\n\n/** A `$ref` chain points back to itself with no schema in between (`A: $ref B`, `B: $ref A`). */\nexport function refCycleError(cause: Error): OpenAPITypesafeError {\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_REF_INVALID,\n message: cause.message,\n details: { reason: \"cycle\" },\n cause,\n });\n}\n\nfunction hostListText(hosts: readonly string[]): string {\n return hosts.length === 0 ? \"none\" : hosts.join(\", \");\n}\n\n/** Why a `$ref` document was refused, with the limit it broke (ADR-017). */\nexport type RefRefusalDetails =\n | { readonly reason: \"outside-local-root\"; readonly localRoot: string }\n | { readonly reason: \"host-not-allowed\"; readonly allowedHosts: readonly string[] }\n | { readonly reason: \"local-ref-from-remote\"; readonly base: string }\n | { readonly reason: \"too-many-remote-documents\"; readonly maxDocuments: number };\n\nfunction limitText(details: RefRefusalDetails): string {\n switch (details.reason) {\n case \"outside-local-root\":\n return `it is outside the local $ref root ${details.localRoot}`;\n case \"host-not-allowed\": {\n const hosts = hostListText(details.allowedHosts);\n return `its host is not in the allowed remote $ref hosts (${hosts})`;\n }\n case \"local-ref-from-remote\":\n return `it is not an http(s) URL, and the $ref is in the remote document ${details.base}`;\n case \"too-many-remote-documents\":\n return `the document refers to more than ${details.maxDocuments} remote documents`;\n default:\n return assertNever(details);\n }\n}\n\n/**\n * A `$ref` is outside the local root, its host is not allowed (threat model R1, R2), a remote\n * document refers to a local file (T3), or there are too many remote documents (T2).\n */\nexport function refForbiddenError(ref: string, details: RefRefusalDetails): OpenAPITypesafeError {\n const limit = limitText(details);\n return new OpenAPITypesafeError({\n code: ERROR_CODES.SCHEMA_REF_FORBIDDEN,\n message: `Refused to load ${ref}: ${limit}`,\n details: { ref: redactUrlCredentials(ref), ...details },\n });\n}\n"],"names":[],"mappings":"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"}
@@ -13,6 +13,14 @@ const UNSUPPORTED_KEYS = /* @__PURE__ */ new Set([
13
13
  "__lookupGetter__",
14
14
  "__lookupSetter__"
15
15
  ]);
16
+ const CONSTRUCTOR_KEY = "constructor";
17
+ function isUnsupportedEntry(key, value) {
18
+ if (UNSUPPORTED_KEYS.has(key)) {
19
+ return true;
20
+ }
21
+ const name = value?.name;
22
+ return key === CONSTRUCTOR_KEY && typeof value === "object" && typeof name === "string";
23
+ }
16
24
  const KEYS_IN_MESSAGE = 5;
17
25
  function escapePointerSegment(segment) {
18
26
  return segment.replaceAll("~", "~0").replaceAll("/", "~1");
@@ -31,7 +39,7 @@ function unsupportedKeysOf(document) {
31
39
  for (let node = pending.pop(); node !== void 0; node = pending.pop()) {
32
40
  for (const [key, child] of Object.entries(node.value)) {
33
41
  const pointer = `${node.pointer}/${escapePointerSegment(key)}`;
34
- if (UNSUPPORTED_KEYS.has(key)) {
42
+ if (isUnsupportedEntry(key, child)) {
35
43
  found.push({ key, pointer, source: document.source });
36
44
  }
37
45
  enqueue(child, pointer);
@@ -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":"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"}
@@ -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":";;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,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,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 = {
@@ -30,6 +31,9 @@ function toStringLiteralType(ts, value, encoding) {
30
31
  }
31
32
  function toTupleElement(ts, element) {
32
33
  const type = toTypeNode(ts, element.type);
34
+ if (element.isOptional) {
35
+ return ts.factory.createOptionalTypeNode(type);
36
+ }
33
37
  return element.isRest ? ts.factory.createRestTypeNode(type) : type;
34
38
  }
35
39
  function toLeafTypeNode(ts, type) {
@@ -37,7 +41,7 @@ function toLeafTypeNode(ts, type) {
37
41
  case "keyword":
38
42
  return toKeywordType(ts, type.keyword);
39
43
  case "stringLiteral":
40
- return toStringLiteralType(ts, type.value, type.encoding);
44
+ return toStringLiteralType(ts, type.value, type.encoding ?? constructors.DEFAULT_STRING_ENCODING);
41
45
  case "numberLiteral":
42
46
  return ts.factory.createLiteralTypeNode(toNumberExpression(ts, type.value));
43
47
  case "booleanLiteral":