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
@@ -0,0 +1,257 @@
1
+ import {
2
+ type BaseResolver,
3
+ type Document,
4
+ detectSpec,
5
+ getTypes,
6
+ isRef,
7
+ normalizeTypes,
8
+ type Config as RedoclyConfig,
9
+ } from "@redocly/openapi-core";
10
+ import {
11
+ ANCHOR_REF,
12
+ escapePointer,
13
+ hasRef,
14
+ isExternalValue,
15
+ isNamedType,
16
+ joinPointer,
17
+ nextTick,
18
+ parseRef,
19
+ propertyType,
20
+ REF_CYCLE_MESSAGE,
21
+ type Ref,
22
+ type RefStack,
23
+ type ResolvedRef,
24
+ UNKNOWN_TYPE,
25
+ type WalkType,
26
+ } from "./ref-resolution-steps.js";
27
+
28
+ /**
29
+ * Redocly 1.34 resolves `$ref`s with `Promise.all` over the lookups it has started and stops at
30
+ * the first one that fails. Lookups it starts after that (the walk of a document that was still
31
+ * loading) are never awaited: when one of them fails too, its rejection is unhandled, and Node.js
32
+ * ends the process on an unhandled rejection (ADR-031). Redocly 2.x has the same loop.
33
+ *
34
+ * This is a port of Redocly's `resolveDocument` (`lib/resolve.js`, 1.34.22, MIT) that waits for
35
+ * every lookup and then throws the first failure. The loader runs it before Redocly lints or
36
+ * bundles, so Redocly only resolves documents in which no lookup fails. It walks the same nodes
37
+ * with the same types and throws the same errors: the "Self-referencing circular pointer" Error,
38
+ * the URIError of a malformed percent escape, and the TypeError of a key such as `valueOf`.
39
+ */
40
+
41
+ /** One walk of the documents a root reaches, with every `$ref` lookup it starts. */
42
+ class RefResolutionWalk {
43
+ readonly #resolver: BaseResolver;
44
+ /** Redocly's `SpecExtension` type: its values are walked like values of no known type. */
45
+ readonly specExtension: WalkType;
46
+ /** Walked nodes per type name; a node walked again with the same type starts the same lookups. */
47
+ readonly #seenNodes = new Map<string, WeakSet<object>>();
48
+ readonly #lookups: Promise<void>[] = [];
49
+
50
+ constructor(resolver: BaseResolver, specExtension: WalkType) {
51
+ this.#resolver = resolver;
52
+ this.specExtension = specExtension;
53
+ }
54
+
55
+ isWalkedLikeUnknown(type: WalkType): boolean {
56
+ return type === UNKNOWN_TYPE || type === this.specExtension;
57
+ }
58
+
59
+ /** Wait for every lookup, including those started while waiting; return the first failure. */
60
+ async settle(): Promise<PromiseRejectedResult | undefined> {
61
+ let settled: PromiseSettledResult<void>[];
62
+ do {
63
+ settled = await Promise.allSettled(this.#lookups);
64
+ } while (settled.length !== this.#lookups.length);
65
+ return settled.find((result) => result.status === "rejected");
66
+ }
67
+
68
+ walkFrom(node: unknown, document: Document, pointer: string, type: WalkType): void {
69
+ new DocumentWalk(this, document).walk(node, type, document.source.absoluteRef + pointer);
70
+ }
71
+
72
+ /** Whether the node was walked with this type before; marks it walked. */
73
+ isSeen(type: WalkType, node: object): boolean {
74
+ let seen = this.#seenNodes.get(type.name);
75
+ if (seen === undefined) {
76
+ seen = new WeakSet();
77
+ this.#seenNodes.set(type.name, seen);
78
+ }
79
+ if (seen.has(node)) {
80
+ return true;
81
+ }
82
+ seen.add(node);
83
+ return false;
84
+ }
85
+
86
+ track(lookup: Promise<ResolvedRef>, type: WalkType): void {
87
+ this.#lookups.push(
88
+ lookup.then((resolved) => {
89
+ if (resolved.resolved && resolved.document !== undefined) {
90
+ this.walkFrom(resolved.node, resolved.document, resolved.nodePointer ?? "#/", type);
91
+ }
92
+ }),
93
+ );
94
+ }
95
+
96
+ async loadDocument(base: Document, uri: string): Promise<Document | undefined> {
97
+ try {
98
+ return (await this.#resolver.resolveDocument(base.source.absoluteRef, uri)) as Document;
99
+ } catch {
100
+ // Redocly records the failed lookup as an unresolved `$ref`; the lint reports it.
101
+ return undefined;
102
+ }
103
+ }
104
+ }
105
+
106
+ /** The walk of one document from one node, with the anchors it collects (as in Redocly). */
107
+ class DocumentWalk {
108
+ readonly #walk: RefResolutionWalk;
109
+ readonly #document: Document;
110
+ readonly #anchors = new Map<string, unknown>();
111
+
112
+ constructor(walk: RefResolutionWalk, document: Document) {
113
+ this.#walk = walk;
114
+ this.#document = document;
115
+ }
116
+
117
+ walk(node: unknown, type: WalkType, absoluteRef: string): void {
118
+ if (typeof node !== "object" || node === null || this.#walk.isSeen(type, node)) {
119
+ return;
120
+ }
121
+ const anchor = (node as { $anchor?: unknown }).$anchor;
122
+ if (Object.hasOwn(node, "$anchor") && anchor) {
123
+ this.#anchors.set(`#${String(anchor)}`, node);
124
+ }
125
+ if (Array.isArray(node)) {
126
+ this.#walkItems(node, type, absoluteRef);
127
+ return;
128
+ }
129
+ for (const name of Object.keys(node)) {
130
+ const value = (node as Record<string, unknown>)[name];
131
+ const [propType, walked] = propertyType(type, name, value, this.#walk.specExtension);
132
+ if (isNamedType(propType) && typeof walked === "object") {
133
+ this.walk(walked, propType, joinPointer(absoluteRef, escapePointer(name)));
134
+ }
135
+ }
136
+ if (isRef(node)) {
137
+ this.#walk.track(this.#follow(this.#document, node, { prev: null, node }), type);
138
+ }
139
+ if (isExternalValue(node)) {
140
+ const ref = { $ref: node.externalValue };
141
+ this.#walk.track(this.#follow(this.#document, ref, { prev: null, node }), type);
142
+ }
143
+ }
144
+
145
+ #walkItems(items: readonly unknown[], type: WalkType, absoluteRef: string): void {
146
+ const itemsType = type.items;
147
+ if (itemsType === undefined && !this.#walk.isWalkedLikeUnknown(type)) {
148
+ return;
149
+ }
150
+ items.forEach((item, index) => {
151
+ const pointer = joinPointer(absoluteRef, index);
152
+ const itemType = typeof itemsType === "function" ? itemsType(item, pointer) : itemsType;
153
+ if (itemType === undefined && !this.#walk.isWalkedLikeUnknown(type)) {
154
+ return;
155
+ }
156
+ this.walk(item, isNamedType(itemType) ? itemType : UNKNOWN_TYPE, pointer);
157
+ });
158
+ }
159
+
160
+ async #follow(document: Document, ref: Ref, refStack: RefStack): Promise<ResolvedRef> {
161
+ if (hasRef(refStack.prev, ref)) {
162
+ throw new Error(REF_CYCLE_MESSAGE);
163
+ }
164
+ if (ANCHOR_REF.test(ref.$ref)) {
165
+ await nextTick();
166
+ return { resolved: true, node: this.#anchors.get(ref.$ref), document, nodePointer: ref.$ref };
167
+ }
168
+ const { uri, pointer } = parseRef(ref.$ref);
169
+ const targetDocument = uri === null ? document : await this.#walk.loadDocument(document, uri);
170
+ if (targetDocument === undefined) {
171
+ return { resolved: false };
172
+ }
173
+ const found = await this.#followSegments(targetDocument, pointer, refStack);
174
+ if (found.document !== undefined && isRef(found.node)) {
175
+ return this.#follow(found.document, found.node, pushRef(refStack, found.node));
176
+ }
177
+ return found;
178
+ }
179
+
180
+ /** Follow the pointer segments; a `$ref` met on the way is resolved first. */
181
+ async #followSegments(
182
+ targetDocument: Document,
183
+ segments: readonly string[],
184
+ refStack: RefStack,
185
+ ): Promise<ResolvedRef> {
186
+ let document = targetDocument;
187
+ let nodePointer = "#/";
188
+ let target: unknown = targetDocument.parsed;
189
+ for (const segment of segments) {
190
+ if (typeof target !== "object") {
191
+ return { resolved: true, node: undefined, document, nodePointer };
192
+ }
193
+ // A `null` target throws a TypeError here, as it does in Redocly.
194
+ const step = (target as Record<string, unknown>)[segment];
195
+ if (step !== undefined) {
196
+ target = step;
197
+ } else if (isRef(target)) {
198
+ const resolved = await this.#follow(document, target, pushRef(refStack, target));
199
+ document = resolved.document ?? document;
200
+ if (typeof resolved.node !== "object") {
201
+ return {
202
+ resolved: true,
203
+ node: undefined,
204
+ document,
205
+ nodePointer: resolved.nodePointer ?? nodePointer,
206
+ };
207
+ }
208
+ target = (resolved.node as Record<string, unknown>)[segment];
209
+ nodePointer = resolved.nodePointer ?? nodePointer;
210
+ } else {
211
+ return { resolved: true, node: undefined, document, nodePointer };
212
+ }
213
+ nodePointer = joinPointer(nodePointer, escapePointer(segment));
214
+ }
215
+ return { resolved: true, node: target, document, nodePointer };
216
+ }
217
+ }
218
+
219
+ function pushRef(head: RefStack, node: unknown): RefStack {
220
+ return { prev: head, node };
221
+ }
222
+
223
+ /**
224
+ * Resolve every `$ref` the document reaches, as Redocly's lint and bundle do, and throw the first
225
+ * failure only after all lookups have finished. Documents are loaded through the given resolver,
226
+ * whose cache Redocly then reuses.
227
+ */
228
+ export async function checkRefsResolve(
229
+ document: Document,
230
+ resolver: BaseResolver,
231
+ styleguide: RedoclyConfig["styleguide"],
232
+ ): Promise<void> {
233
+ const specVersion = detectSpec(document.parsed);
234
+ const types = normalizeTypes(
235
+ styleguide.extendTypes(getTypes(specVersion), specVersion),
236
+ styleguide,
237
+ );
238
+ const rootType = types.Root;
239
+ const specExtension = types.SpecExtension;
240
+ if (rootType === undefined || specExtension === undefined) {
241
+ // Redocly gives every spec version both types; a missing one is a Redocly change to port.
242
+ throw new Error(`Redocly has no Root or SpecExtension type for ${specVersion}`);
243
+ }
244
+ const walk = new RefResolutionWalk(resolver, specExtension);
245
+ let rootFailure: PromiseRejectedResult | undefined;
246
+ try {
247
+ walk.walkFrom(document.parsed, document, "#/", rootType);
248
+ } catch (error) {
249
+ // The walk of the root can fail after it started lookups; they are awaited all the same.
250
+ rootFailure = { status: "rejected", reason: error };
251
+ }
252
+ const lookupFailure = await walk.settle();
253
+ const failure = rootFailure ?? lookupFailure;
254
+ if (failure !== undefined) {
255
+ throw failure.reason;
256
+ }
257
+ }
@@ -0,0 +1,113 @@
1
+ import type { Document, normalizeTypes } from "@redocly/openapi-core";
2
+ import { parseRefPointer } from "../../domain/openapi/json-pointer.js";
3
+
4
+ /**
5
+ * The pieces of Redocly 1.34's `$ref` resolution (`lib/resolve.js`, `lib/ref-utils.js`, MIT) that
6
+ * the resolution check (`ref-resolution-check.ts`, ADR-031) walks with, kept as Redocly has them.
7
+ */
8
+
9
+ type RedoclyTypes = ReturnType<typeof normalizeTypes>;
10
+ export type WalkType = RedoclyTypes[string];
11
+ type PropTypeOrFunction = WalkType["properties"][string] | WalkType["additionalProperties"];
12
+ /** The type of a property or array item, after Redocly called a type function. */
13
+ export type PropType = Exclude<PropTypeOrFunction, (...args: never[]) => unknown>;
14
+
15
+ /** Redocly's own placeholders: a node of no known type, and a scalar that is a `$ref`. */
16
+ export const UNKNOWN_TYPE: WalkType = { name: "unknown", properties: {} };
17
+ export const RESOLVABLE_SCALAR_TYPE: WalkType = { name: "scalar", properties: {} };
18
+
19
+ /** Redocly's test for an anchor reference (`#name`), which waits for the whole document walk. */
20
+ export const ANCHOR_REF = /^#[A-Za-z][A-Za-z0-9\-_:.]*$/;
21
+
22
+ /** Redocly throws a plain Error with this message for a `$ref` chain that points back to itself. */
23
+ export const REF_CYCLE_MESSAGE = "Self-referencing circular pointer";
24
+
25
+ export interface RefStack {
26
+ readonly prev: RefStack | null;
27
+ readonly node: unknown;
28
+ }
29
+
30
+ export interface ResolvedRef {
31
+ readonly resolved: boolean;
32
+ readonly node?: unknown;
33
+ readonly document?: Document;
34
+ readonly nodePointer?: string;
35
+ }
36
+
37
+ export type Ref = { readonly $ref: string };
38
+
39
+ export function isNamedType(type: PropType): type is WalkType {
40
+ return typeof (type as { name?: unknown } | null | undefined)?.name === "string";
41
+ }
42
+
43
+ export function joinPointer(base: string, key: string | number): string {
44
+ const start = base === "" ? "#/" : base;
45
+ return start.endsWith("/") ? `${start}${key}` : `${start}/${key}`;
46
+ }
47
+
48
+ export function escapePointer(fragment: string): string {
49
+ return fragment.replaceAll("~", "~0").replaceAll("/", "~1");
50
+ }
51
+
52
+ /** Redocly's `parseRef`: the document part (null for a local ref) and the unescaped segments. */
53
+ export function parseRef(ref: string): { uri: string | null; pointer: string[] } {
54
+ const [uri = ""] = ref.split("#/");
55
+ return {
56
+ uri: (uri.endsWith("#") ? uri.slice(0, -1) : uri) || null,
57
+ pointer: parseRefPointer(ref),
58
+ };
59
+ }
60
+
61
+ export function hasRef(head: RefStack | null, node: unknown): boolean {
62
+ for (let entry = head; entry !== null; entry = entry.prev) {
63
+ if (entry.node === node) {
64
+ return true;
65
+ }
66
+ }
67
+ return false;
68
+ }
69
+
70
+ export function isExternalValue(node: object): node is { externalValue: string } {
71
+ return typeof (node as { externalValue?: unknown }).externalValue === "string";
72
+ }
73
+
74
+ /** Wait one macrotask, as Redocly does before it reads the anchors of a document. */
75
+ export function nextTick(): Promise<void> {
76
+ return new Promise((resolve) => setTimeout(resolve));
77
+ }
78
+
79
+ /**
80
+ * The type Redocly gives one property value, and the value to walk (a `directResolveAs` string
81
+ * becomes a `$ref`). A value whose type has no name is not walked.
82
+ */
83
+ export function propertyType(
84
+ type: WalkType,
85
+ name: string,
86
+ value: unknown,
87
+ specExtension: WalkType,
88
+ ): [PropType, unknown] {
89
+ // `properties[name]` also finds `Object.prototype` members, as in Redocly; for `valueOf` and the
90
+ // like the call below throws the TypeError that the loader turns into SCHEMA_KEY_UNSUPPORTED.
91
+ let declared: PropTypeOrFunction = type.properties[name];
92
+ if (declared === undefined) {
93
+ declared = type.additionalProperties;
94
+ }
95
+ let propType: PropType = typeof declared === "function" ? declared(value, name) : declared;
96
+ if (propType === undefined) {
97
+ propType = UNKNOWN_TYPE;
98
+ }
99
+ if (
100
+ type.extensionsPrefix &&
101
+ name.startsWith(type.extensionsPrefix) &&
102
+ propType === UNKNOWN_TYPE
103
+ ) {
104
+ return [specExtension, value];
105
+ }
106
+ if (!isNamedType(propType) && propType?.directResolveAs) {
107
+ return [propType.directResolveAs, { $ref: value }];
108
+ }
109
+ if (propType && !isNamedType(propType) && propType.resolvable !== false) {
110
+ return [RESOLVABLE_SCALAR_TYPE, value];
111
+ }
112
+ return [propType, value];
113
+ }
@@ -1,9 +1,13 @@
1
1
  import type { Config as RedoclyConfig } from "@redocly/openapi-core";
2
2
  import type { RefAccess } from "../../application/ports/schema-loader.js";
3
3
  import { isHostAllowed } from "./allowed-hosts.js";
4
+ import { type ConfiguredHeader, headersFor } from "./configured-headers.js";
4
5
  import { refForbiddenError } from "./schema-load-errors.js";
5
6
 
6
- /** How the loader fetches remote documents: a time limit, and the host limit on redirects. */
7
+ /**
8
+ * How the loader fetches remote documents: a time limit, the host limit and the configured headers
9
+ * checked on every redirect.
10
+ */
7
11
 
8
12
  type ResolveConfig = RedoclyConfig["resolve"];
9
13
 
@@ -11,10 +15,10 @@ type ResolveConfig = RedoclyConfig["resolve"];
11
15
  export type RemoteFetch = (input: string, init?: RequestInit) => Promise<Response>;
12
16
 
13
17
  /**
14
- * Redirects followed for a remote `$ref` when hosts are limited. Each hop is checked, so fetch
15
- * cannot follow them on its own; 5 covers http → https plus a moved file, and a loop stops early.
18
+ * Redirects followed for one remote document. The loader follows them itself, so that each hop is
19
+ * checked; 20 is the limit of the Fetch standard, which fetch applied before.
16
20
  */
17
- export const MAX_CHECKED_REDIRECTS = 5;
21
+ export const MAX_REDIRECTS = 20;
18
22
 
19
23
  const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
20
24
 
@@ -51,33 +55,78 @@ function fetchWithTimeout(timeoutMs: number): RemoteFetch {
51
55
  };
52
56
  }
53
57
 
58
+ /** What every hop of a remote fetch is checked against. */
59
+ export interface RedirectPolicy {
60
+ /** `resolve.http.headers` of the Redocly config; chosen again for the URL of every hop. */
61
+ readonly headers: readonly ConfiguredHeader[];
62
+ /** `--remote-ref-hosts`; undefined allows every host. */
63
+ readonly hosts: readonly string[] | undefined;
64
+ }
65
+
54
66
  /**
55
- * Follow redirects one by one, and refuse a redirect to a host that is not listed. The first URL
56
- * was checked by the resolver (or is the root document). As fetch does, the configured headers
57
- * (often credentials) are not sent on to another origin.
67
+ * Follow redirects one by one. Fetch drops only `Authorization`, `Cookie` and
68
+ * `Proxy-Authorization` on a redirect to another origin and keeps every other header (an
69
+ * `X-Api-Key`), so the configured headers are chosen for each hop's own URL instead, and a hop to
70
+ * a host that is not listed is refused before it is fetched. The first URL was checked by the
71
+ * resolver (or is the root document). Redocly passes only the configured headers in `init`, and
72
+ * it gets an empty list of them (`resolveConfigWithAccess`), so `init.headers` is replaced.
58
73
  */
59
74
  export function fetchWithCheckedRedirects(
60
75
  fetchImpl: RemoteFetch,
61
- hosts: readonly string[],
76
+ policy: RedirectPolicy,
62
77
  ): RemoteFetch {
63
78
  return async (input, init = {}) => {
64
- const firstOrigin = new URL(input).origin;
65
79
  let url = new URL(input);
66
- for (let hop = 0; hop <= MAX_CHECKED_REDIRECTS; hop += 1) {
67
- if (hop > 0 && !isHostAllowed(url, hosts)) {
68
- throw refForbiddenError(url.href, { reason: "host-not-allowed", allowedHosts: [...hosts] });
80
+ for (let hop = 0; hop <= MAX_REDIRECTS; hop += 1) {
81
+ if (hop > 0 && policy.hosts !== undefined && !isHostAllowed(url, policy.hosts)) {
82
+ throw refForbiddenError(url.href, {
83
+ reason: "host-not-allowed",
84
+ allowedHosts: [...policy.hosts],
85
+ });
69
86
  }
70
- const { headers, ...rest } = init;
71
- const hopInit: RequestInit =
72
- url.origin === firstOrigin && headers !== undefined ? { ...rest, headers } : rest;
73
- const response = await fetchImpl(url.href, { ...hopInit, redirect: "manual" });
87
+ const headers = await headersFor(url, policy.headers);
88
+ const response = await fetchImpl(url.href, { ...init, headers, redirect: "manual" });
74
89
  const location = response.headers.get("location");
75
90
  if (!REDIRECT_STATUSES.has(response.status) || location === null) {
76
91
  return response;
77
92
  }
78
93
  url = new URL(location, url);
79
94
  }
80
- throw new Error(`More than ${MAX_CHECKED_REDIRECTS} redirects loading ${input}`);
95
+ throw new Error(`More than ${MAX_REDIRECTS} redirects loading ${input}`);
96
+ };
97
+ }
98
+
99
+ /** Bounds on the remote documents of one load (threat model T2, ADR-033). */
100
+ export interface RemoteDocumentLimits {
101
+ /** Remote documents one load may fetch, the root included; one more is refused. */
102
+ readonly maxDocuments: number;
103
+ /** Remote documents fetched at the same time; the others wait for a free slot. */
104
+ readonly maxParallelFetches: number;
105
+ }
106
+
107
+ /**
108
+ * At most `limit` calls of the fetch run at once; the others wait in order. A finished call hands
109
+ * its slot to the next waiting one.
110
+ */
111
+ export function fetchWithConcurrencyLimit(fetchImpl: RemoteFetch, limit: number): RemoteFetch {
112
+ let running = 0;
113
+ const waiting: (() => void)[] = [];
114
+ return async (input, init) => {
115
+ if (running < limit) {
116
+ running += 1;
117
+ } else {
118
+ await new Promise<void>((resolve) => waiting.push(resolve));
119
+ }
120
+ try {
121
+ return await fetchImpl(input, init);
122
+ } finally {
123
+ const next = waiting.shift();
124
+ if (next === undefined) {
125
+ running -= 1;
126
+ } else {
127
+ next();
128
+ }
129
+ }
81
130
  };
82
131
  }
83
132
 
@@ -85,11 +134,14 @@ export interface RemoteFetchOptions {
85
134
  /** Time limit of one fetch and its body, unless the Redocly config has its own `customFetch`. */
86
135
  readonly timeoutMs: number;
87
136
  readonly access: RefAccess;
137
+ readonly maxParallelFetches: number;
88
138
  }
89
139
 
90
140
  /**
91
141
  * The resolve config with the fetch the loader uses. A `customFetch` of the Redocly config is
92
- * kept; with a host limit, it is wrapped so that each redirect is checked.
142
+ * kept and wrapped, so that each redirect is checked and only a few documents load at once. The
143
+ * configured headers move into that wrapper: Redocly would match them against the raw URL and
144
+ * send them on through redirects.
93
145
  */
94
146
  export function resolveConfigWithAccess(
95
147
  resolve: ResolveConfig,
@@ -98,7 +150,11 @@ export function resolveConfigWithAccess(
98
150
  // Redocly types `customFetch` as `Function`; it is called as fetch is.
99
151
  const configured = resolve.http.customFetch as RemoteFetch | undefined;
100
152
  const base = configured ?? fetchWithTimeout(options.timeoutMs);
101
- const hosts = options.access.remoteHosts;
102
- const customFetch = hosts === undefined ? base : fetchWithCheckedRedirects(base, hosts);
103
- return { ...resolve, http: { ...resolve.http, customFetch } };
153
+ const checked = fetchWithCheckedRedirects(base, {
154
+ headers: resolve.http.headers,
155
+ hosts: options.access.remoteHosts,
156
+ });
157
+ // The limit is outside the redirects, so all hops of one document share one slot.
158
+ const customFetch = fetchWithConcurrencyLimit(checked, options.maxParallelFetches);
159
+ return { ...resolve, http: { ...resolve.http, headers: [], customFetch } };
104
160
  }
@@ -1,8 +1,11 @@
1
+ import { assertNever } from "../../domain/assert-never.js";
1
2
  import { ERROR_CODES, OpenAPITypesafeError } from "../../domain/errors.js";
3
+ import { redactUrlCredentials } from "../../domain/url-credentials.js";
2
4
 
3
5
  /**
4
6
  * The typed errors of loading, validating and bundling a document (ADR-011). Messages are the
5
- * original messages, so Node API users who match on them keep working.
7
+ * original messages, so Node API users who match on them keep working; URLs in them and in the
8
+ * details never show user info.
6
9
  */
7
10
 
8
11
  /** No source was given, or the source is empty. */
@@ -48,7 +51,7 @@ export function loadFailedError(absoluteRef: string, cause: unknown): OpenAPITyp
48
51
  return new OpenAPITypesafeError({
49
52
  code: ERROR_CODES.SCHEMA_LOAD_FAILED,
50
53
  message: causeMessage(cause),
51
- details: { source: absoluteRef },
54
+ details: { source: redactUrlCredentials(absoluteRef) },
52
55
  cause,
53
56
  });
54
57
  }
@@ -62,7 +65,7 @@ export function parseFailedError(
62
65
  return new OpenAPITypesafeError({
63
66
  code: ERROR_CODES.SCHEMA_PARSE_FAILED,
64
67
  message: causeMessage(cause),
65
- details: { format, source: absoluteRef },
68
+ details: { format, source: redactUrlCredentials(absoluteRef) },
66
69
  cause,
67
70
  });
68
71
  }
@@ -87,7 +90,7 @@ export function schemaInvalidError(problems: readonly string[]): OpenAPITypesafe
87
90
  return new OpenAPITypesafeError({
88
91
  code: ERROR_CODES.SCHEMA_INVALID,
89
92
  message: problems.at(-1) ?? "",
90
- details: { problems: [...problems] },
93
+ details: { problems: problems.map(redactUrlCredentials) },
91
94
  });
92
95
  }
93
96
 
@@ -108,17 +111,36 @@ function hostListText(hosts: readonly string[]): string {
108
111
  /** Why a `$ref` document was refused, with the limit it broke (ADR-017). */
109
112
  export type RefRefusalDetails =
110
113
  | { readonly reason: "outside-local-root"; readonly localRoot: string }
111
- | { readonly reason: "host-not-allowed"; readonly allowedHosts: readonly string[] };
114
+ | { readonly reason: "host-not-allowed"; readonly allowedHosts: readonly string[] }
115
+ | { readonly reason: "local-ref-from-remote"; readonly base: string }
116
+ | { readonly reason: "too-many-remote-documents"; readonly maxDocuments: number };
112
117
 
113
- /** A `$ref` is outside the local root, or its host is not allowed (threat model R1, R2). */
118
+ function limitText(details: RefRefusalDetails): string {
119
+ switch (details.reason) {
120
+ case "outside-local-root":
121
+ return `it is outside the local $ref root ${details.localRoot}`;
122
+ case "host-not-allowed": {
123
+ const hosts = hostListText(details.allowedHosts);
124
+ return `its host is not in the allowed remote $ref hosts (${hosts})`;
125
+ }
126
+ case "local-ref-from-remote":
127
+ return `it is not an http(s) URL, and the $ref is in the remote document ${details.base}`;
128
+ case "too-many-remote-documents":
129
+ return `the document refers to more than ${details.maxDocuments} remote documents`;
130
+ default:
131
+ return assertNever(details);
132
+ }
133
+ }
134
+
135
+ /**
136
+ * A `$ref` is outside the local root, its host is not allowed (threat model R1, R2), a remote
137
+ * document refers to a local file (T3), or there are too many remote documents (T2).
138
+ */
114
139
  export function refForbiddenError(ref: string, details: RefRefusalDetails): OpenAPITypesafeError {
115
- const limit =
116
- details.reason === "outside-local-root"
117
- ? `it is outside the local $ref root ${details.localRoot}`
118
- : `its host is not in the allowed remote $ref hosts (${hostListText(details.allowedHosts)})`;
140
+ const limit = limitText(details);
119
141
  return new OpenAPITypesafeError({
120
142
  code: ERROR_CODES.SCHEMA_REF_FORBIDDEN,
121
143
  message: `Refused to load ${ref}: ${limit}`,
122
- details: { ref, ...details },
144
+ details: { ref: redactUrlCredentials(ref), ...details },
123
145
  });
124
146
  }
@@ -4,7 +4,7 @@ import { ERROR_CODES, OpenAPITypesafeError } from "../../domain/errors.js";
4
4
  * Keys Redocly 1.34 cannot walk. It looks up the type of every key with `type.properties[key]`,
5
5
  * which also finds inherited `Object.prototype` members; it then calls a found function with no
6
6
  * `this`, and these methods throw a `TypeError` for that. Redocly 2.x looks up own keys only
7
- * (ADR-005 keeps 1.34). `toString` and `constructor` do not throw, and load as they should.
7
+ * (ADR-005 keeps 1.34). `toString` does not throw, and loads as it should.
8
8
  *
9
9
  * Redocly does not walk every value (`default` and `const` are data), so a document with such a
10
10
  * key is not rejected up front: the loader looks for them only after Redocly threw a `TypeError`.
@@ -21,6 +21,21 @@ export const UNSUPPORTED_KEYS: ReadonlySet<string> = new Set([
21
21
  "__lookupSetter__",
22
22
  ]);
23
23
 
24
+ /**
25
+ * `constructor` finds `Object`, which returns the value it is called with. Redocly then takes the
26
+ * value for a node type when it has a string `name` (a security scheme, a header with a `name`),
27
+ * and fails reading the type's fields. Any other `constructor` key loads.
28
+ */
29
+ const CONSTRUCTOR_KEY = "constructor";
30
+
31
+ function isUnsupportedEntry(key: string, value: unknown): boolean {
32
+ if (UNSUPPORTED_KEYS.has(key)) {
33
+ return true;
34
+ }
35
+ const name = (value as { name?: unknown } | null | undefined)?.name;
36
+ return key === CONSTRUCTOR_KEY && typeof value === "object" && typeof name === "string";
37
+ }
38
+
24
39
  /** Enough found keys in the message to act on; `details.keys` has all of them. */
25
40
  const KEYS_IN_MESSAGE = 5;
26
41
 
@@ -66,7 +81,7 @@ function unsupportedKeysOf(document: LoadedDocument): UnsupportedKey[] {
66
81
  for (let node = pending.pop(); node !== undefined; node = pending.pop()) {
67
82
  for (const [key, child] of Object.entries(node.value)) {
68
83
  const pointer = `${node.pointer}/${escapePointerSegment(key)}`;
69
- if (UNSUPPORTED_KEYS.has(key)) {
84
+ if (isUnsupportedEntry(key, child)) {
70
85
  found.push({ key, pointer, source: document.source });
71
86
  }
72
87
  enqueue(child, pointer);
@@ -1,9 +1,11 @@
1
1
  import colors from "ansi-colors";
2
2
  import type { DebugGroup, Logger } from "../../application/ports/logger.js";
3
+ import { redactUrlCredentials } from "../../domain/url-credentials.js";
3
4
 
4
5
  /**
5
6
  * The Logger port on a terminal, with the original output format: ` ⚠ ` warnings, ` ✘ `
6
- * errors, and `openapi-ts:<group>` debug lines filtered by `DEBUG` (ENGINEERING_PLAN 4.5).
7
+ * errors, and `openapi-ts:<group>` debug lines filtered by `DEBUG` (ENGINEERING_PLAN 4.5). No
8
+ * line shows the user info of a URL.
7
9
  */
8
10
 
9
11
  /** Where the lines go: `console` in production, a recording sink in tests. */
@@ -76,19 +78,21 @@ class TerminalLogger implements Logger {
76
78
  return;
77
79
  }
78
80
  const name = groupColor(this.#palette, group)(`openapi-ts:${group ?? "info"}`);
81
+ // The original wrote no space without a duration (`openapi-ts:lintIgnored …`).
79
82
  const time =
80
- durationMs === undefined ? "" : this.#palette.green(` ${formatDuration(durationMs)} `);
81
- this.#options.sink.debug(` ${this.#palette.bold(name)}${time}${message}`);
83
+ durationMs === undefined ? " " : this.#palette.green(` ${formatDuration(durationMs)} `);
84
+ const text = redactUrlCredentials(message);
85
+ this.#options.sink.debug(` ${this.#palette.bold(name)}${time}${text}`);
82
86
  }
83
87
 
84
88
  warn(message: string): void {
85
89
  if (!this.#options.silent) {
86
- this.#options.sink.warn(this.#palette.yellow(` ⚠ ${message}`));
90
+ this.#options.sink.warn(this.#palette.yellow(` ⚠ ${redactUrlCredentials(message)}`));
87
91
  }
88
92
  }
89
93
 
90
94
  error(message: string): void {
91
- this.#options.sink.error(this.#palette.red(` ✘ ${message}`));
95
+ this.#options.sink.error(this.#palette.red(` ✘ ${redactUrlCredentials(message)}`));
92
96
  }
93
97
  }
94
98