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

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 (404) hide show
  1. package/dist/adapters/redocly-loader/redocly-config-source.cjs +21 -2
  2. package/dist/adapters/redocly-loader/redocly-config-source.cjs.map +1 -1
  3. package/dist/adapters/redocly-loader/redocly-config-source.mjs +22 -3
  4. package/dist/adapters/redocly-loader/redocly-config-source.mjs.map +1 -1
  5. package/dist/adapters/redocly-loader/redocly-schema-loader.cjs +15 -5
  6. package/dist/adapters/redocly-loader/redocly-schema-loader.cjs.map +1 -1
  7. package/dist/adapters/redocly-loader/redocly-schema-loader.mjs +15 -5
  8. package/dist/adapters/redocly-loader/redocly-schema-loader.mjs.map +1 -1
  9. package/dist/adapters/type-ast-bridge/ir-to-typescript.cjs +3 -0
  10. package/dist/adapters/type-ast-bridge/ir-to-typescript.cjs.map +1 -1
  11. package/dist/adapters/type-ast-bridge/ir-to-typescript.mjs +3 -0
  12. package/dist/adapters/type-ast-bridge/ir-to-typescript.mjs.map +1 -1
  13. package/dist/adapters/type-ast-bridge/typescript-to-ir.cjs +15 -9
  14. package/dist/adapters/type-ast-bridge/typescript-to-ir.cjs.map +1 -1
  15. package/dist/adapters/type-ast-bridge/typescript-to-ir.mjs +15 -9
  16. package/dist/adapters/type-ast-bridge/typescript-to-ir.mjs.map +1 -1
  17. package/dist/api/discriminator-conflict-warnings.cjs +25 -0
  18. package/dist/api/discriminator-conflict-warnings.cjs.map +1 -0
  19. package/dist/api/discriminator-conflict-warnings.mjs +23 -0
  20. package/dist/api/discriminator-conflict-warnings.mjs.map +1 -0
  21. package/dist/api/discriminator-enum-names.cjs +19 -0
  22. package/dist/api/discriminator-enum-names.cjs.map +1 -0
  23. package/dist/api/discriminator-enum-names.mjs +17 -0
  24. package/dist/api/discriminator-enum-names.mjs.map +1 -0
  25. package/dist/api/discriminator-enum-parent.cjs +59 -0
  26. package/dist/api/discriminator-enum-parent.cjs.map +1 -0
  27. package/dist/api/discriminator-enum-parent.mjs +57 -0
  28. package/dist/api/discriminator-enum-parent.mjs.map +1 -0
  29. package/dist/api/discriminator-enum.cjs +25 -0
  30. package/dist/api/discriminator-enum.cjs.map +1 -1
  31. package/dist/api/discriminator-enum.mjs +25 -1
  32. package/dist/api/discriminator-enum.mjs.map +1 -1
  33. package/dist/api/discriminator-other-owners.cjs +67 -0
  34. package/dist/api/discriminator-other-owners.cjs.map +1 -0
  35. package/dist/api/discriminator-other-owners.mjs +64 -0
  36. package/dist/api/discriminator-other-owners.mjs.map +1 -0
  37. package/dist/api/discriminator-patch.cjs +88 -0
  38. package/dist/api/discriminator-patch.cjs.map +1 -0
  39. package/dist/api/discriminator-patch.mjs +82 -0
  40. package/dist/api/discriminator-patch.mjs.map +1 -0
  41. package/dist/api/discriminator-scan.cjs +50 -65
  42. package/dist/api/discriminator-scan.cjs.map +1 -1
  43. package/dist/api/discriminator-scan.mjs +44 -59
  44. package/dist/api/discriminator-scan.mjs.map +1 -1
  45. package/dist/api/document-run.cjs +18 -3
  46. package/dist/api/document-run.cjs.map +1 -1
  47. package/dist/api/document-run.mjs +19 -4
  48. package/dist/api/document-run.mjs.map +1 -1
  49. package/dist/api/enum-values-warnings.cjs +16 -0
  50. package/dist/api/enum-values-warnings.cjs.map +1 -0
  51. package/dist/api/enum-values-warnings.mjs +14 -0
  52. package/dist/api/enum-values-warnings.mjs.map +1 -0
  53. package/dist/api/path-template-warnings.cjs +21 -0
  54. package/dist/api/path-template-warnings.cjs.map +1 -0
  55. package/dist/api/path-template-warnings.mjs +19 -0
  56. package/dist/api/path-template-warnings.mjs.map +1 -0
  57. package/dist/api/transform-context.cjs +3 -1
  58. package/dist/api/transform-context.cjs.map +1 -1
  59. package/dist/api/transform-context.mjs +3 -1
  60. package/dist/api/transform-context.mjs.map +1 -1
  61. package/dist/api/transform-schema.cjs +52 -3
  62. package/dist/api/transform-schema.cjs.map +1 -1
  63. package/dist/api/transform-schema.mjs +53 -4
  64. package/dist/api/transform-schema.mjs.map +1 -1
  65. package/dist/api/unsupported-feature-warnings.cjs +6 -1
  66. package/dist/api/unsupported-feature-warnings.cjs.map +1 -1
  67. package/dist/api/unsupported-feature-warnings.mjs +6 -1
  68. package/dist/api/unsupported-feature-warnings.mjs.map +1 -1
  69. package/dist/application/print/type-printer.cjs +5 -0
  70. package/dist/application/print/type-printer.cjs.map +1 -1
  71. package/dist/application/print/type-printer.mjs +5 -0
  72. package/dist/application/print/type-printer.mjs.map +1 -1
  73. package/dist/application/transform/document/assignability.cjs +144 -0
  74. package/dist/application/transform/document/assignability.cjs.map +1 -0
  75. package/dist/application/transform/document/assignability.mjs +138 -0
  76. package/dist/application/transform/document/assignability.mjs.map +1 -0
  77. package/dist/application/transform/document/components.cjs +2 -2
  78. package/dist/application/transform/document/components.cjs.map +1 -1
  79. package/dist/application/transform/document/components.mjs +4 -4
  80. package/dist/application/transform/document/components.mjs.map +1 -1
  81. package/dist/application/transform/document/declared-types.cjs +66 -0
  82. package/dist/application/transform/document/declared-types.cjs.map +1 -0
  83. package/dist/application/transform/document/declared-types.mjs +63 -0
  84. package/dist/application/transform/document/declared-types.mjs.map +1 -0
  85. package/dist/application/transform/document/document.cjs +32 -9
  86. package/dist/application/transform/document/document.cjs.map +1 -1
  87. package/dist/application/transform/document/document.mjs +34 -11
  88. package/dist/application/transform/document/document.mjs.map +1 -1
  89. package/dist/application/transform/document/exploded-query.cjs +46 -0
  90. package/dist/application/transform/document/exploded-query.cjs.map +1 -0
  91. package/dist/application/transform/document/exploded-query.mjs +43 -0
  92. package/dist/application/transform/document/exploded-query.mjs.map +1 -0
  93. package/dist/application/transform/document/global-type-references.cjs +63 -0
  94. package/dist/application/transform/document/global-type-references.cjs.map +1 -0
  95. package/dist/application/transform/document/global-type-references.mjs +61 -0
  96. package/dist/application/transform/document/global-type-references.mjs.map +1 -0
  97. package/dist/application/transform/document/list-assignability.cjs +54 -0
  98. package/dist/application/transform/document/list-assignability.cjs.map +1 -0
  99. package/dist/application/transform/document/list-assignability.mjs +52 -0
  100. package/dist/application/transform/document/list-assignability.mjs.map +1 -0
  101. package/dist/application/transform/document/parameters.cjs +40 -8
  102. package/dist/application/transform/document/parameters.cjs.map +1 -1
  103. package/dist/application/transform/document/parameters.mjs +41 -9
  104. package/dist/application/transform/document/parameters.mjs.map +1 -1
  105. package/dist/application/transform/document/path-key-overlaps.cjs +83 -33
  106. package/dist/application/transform/document/path-key-overlaps.cjs.map +1 -1
  107. package/dist/application/transform/document/path-key-overlaps.mjs +83 -33
  108. package/dist/application/transform/document/path-key-overlaps.mjs.map +1 -1
  109. package/dist/application/transform/document/path-template-replace.cjs +48 -0
  110. package/dist/application/transform/document/path-template-replace.cjs.map +1 -0
  111. package/dist/application/transform/document/path-template-replace.mjs +45 -0
  112. package/dist/application/transform/document/path-template-replace.mjs.map +1 -0
  113. package/dist/application/transform/document/paths.cjs +54 -28
  114. package/dist/application/transform/document/paths.cjs.map +1 -1
  115. package/dist/application/transform/document/paths.mjs +53 -29
  116. package/dist/application/transform/document/paths.mjs.map +1 -1
  117. package/dist/application/transform/document/root-type-aliases.cjs +15 -14
  118. package/dist/application/transform/document/root-type-aliases.cjs.map +1 -1
  119. package/dist/application/transform/document/root-type-aliases.mjs +15 -13
  120. package/dist/application/transform/document/root-type-aliases.mjs.map +1 -1
  121. package/dist/application/transform/document/template-key-match.cjs +128 -0
  122. package/dist/application/transform/document/template-key-match.cjs.map +1 -0
  123. package/dist/application/transform/document/template-key-match.mjs +125 -0
  124. package/dist/application/transform/document/template-key-match.mjs.map +1 -0
  125. package/dist/application/transform/document/type-assignability.cjs +192 -0
  126. package/dist/application/transform/document/type-assignability.cjs.map +1 -0
  127. package/dist/application/transform/document/type-assignability.mjs +190 -0
  128. package/dist/application/transform/document/type-assignability.mjs.map +1 -0
  129. package/dist/application/transform/document/type-key.cjs +70 -0
  130. package/dist/application/transform/document/type-key.cjs.map +1 -0
  131. package/dist/application/transform/document/type-key.mjs +68 -0
  132. package/dist/application/transform/document/type-key.mjs.map +1 -0
  133. package/dist/application/transform/document/type-resolution.cjs +131 -0
  134. package/dist/application/transform/document/type-resolution.cjs.map +1 -0
  135. package/dist/application/transform/document/type-resolution.mjs +125 -0
  136. package/dist/application/transform/document/type-resolution.mjs.map +1 -0
  137. package/dist/application/transform/footer/document-footer.cjs +66 -4
  138. package/dist/application/transform/footer/document-footer.cjs.map +1 -1
  139. package/dist/application/transform/footer/document-footer.mjs +67 -5
  140. package/dist/application/transform/footer/document-footer.mjs.map +1 -1
  141. package/dist/application/transform/footer/enum-naming.cjs +17 -0
  142. package/dist/application/transform/footer/enum-naming.cjs.map +1 -1
  143. package/dist/application/transform/footer/enum-naming.mjs +17 -1
  144. package/dist/application/transform/footer/enum-naming.mjs.map +1 -1
  145. package/dist/application/transform/footer/enum-values-check.cjs +129 -0
  146. package/dist/application/transform/footer/enum-values-check.cjs.map +1 -0
  147. package/dist/application/transform/footer/enum-values-check.mjs +127 -0
  148. package/dist/application/transform/footer/enum-values-check.mjs.map +1 -0
  149. package/dist/application/transform/footer/evaluation.cjs +33 -0
  150. package/dist/application/transform/footer/evaluation.cjs.map +1 -0
  151. package/dist/application/transform/footer/evaluation.mjs +26 -0
  152. package/dist/application/transform/footer/evaluation.mjs.map +1 -0
  153. package/dist/application/transform/footer/shared-enum-names.cjs +60 -0
  154. package/dist/application/transform/footer/shared-enum-names.cjs.map +1 -0
  155. package/dist/application/transform/footer/shared-enum-names.mjs +57 -0
  156. package/dist/application/transform/footer/shared-enum-names.mjs.map +1 -0
  157. package/dist/application/transform/footer/type-evaluation.cjs +246 -0
  158. package/dist/application/transform/footer/type-evaluation.cjs.map +1 -0
  159. package/dist/application/transform/footer/type-evaluation.mjs +244 -0
  160. package/dist/application/transform/footer/type-evaluation.mjs.map +1 -0
  161. package/dist/application/transform/footer/type-rules.cjs +172 -0
  162. package/dist/application/transform/footer/type-rules.cjs.map +1 -0
  163. package/dist/application/transform/footer/type-rules.mjs +166 -0
  164. package/dist/application/transform/footer/type-rules.mjs.map +1 -0
  165. package/dist/application/transform/ref-pointer/generated-location.cjs +138 -0
  166. package/dist/application/transform/ref-pointer/generated-location.cjs.map +1 -0
  167. package/dist/application/transform/ref-pointer/generated-location.mjs +136 -0
  168. package/dist/application/transform/ref-pointer/generated-location.mjs.map +1 -0
  169. package/dist/application/transform/ref-pointer/generated-shape.cjs +171 -0
  170. package/dist/application/transform/ref-pointer/generated-shape.cjs.map +1 -0
  171. package/dist/application/transform/ref-pointer/generated-shape.mjs +162 -0
  172. package/dist/application/transform/ref-pointer/generated-shape.mjs.map +1 -0
  173. package/dist/application/transform/ref-pointer/inline-cycles.cjs +44 -0
  174. package/dist/application/transform/ref-pointer/inline-cycles.cjs.map +1 -0
  175. package/dist/application/transform/ref-pointer/inline-cycles.mjs +42 -0
  176. package/dist/application/transform/ref-pointer/inline-cycles.mjs.map +1 -0
  177. package/dist/application/transform/ref-pointer/original-index.cjs +62 -0
  178. package/dist/application/transform/ref-pointer/original-index.cjs.map +1 -0
  179. package/dist/application/transform/ref-pointer/original-index.mjs +60 -0
  180. package/dist/application/transform/ref-pointer/original-index.mjs.map +1 -0
  181. package/dist/application/transform/ref-pointer/pointer-type.cjs +60 -0
  182. package/dist/application/transform/ref-pointer/pointer-type.cjs.map +1 -0
  183. package/dist/application/transform/ref-pointer/pointer-type.mjs +57 -0
  184. package/dist/application/transform/ref-pointer/pointer-type.mjs.map +1 -0
  185. package/dist/application/transform/ref-pointer/pointer-walk.cjs +66 -0
  186. package/dist/application/transform/ref-pointer/pointer-walk.cjs.map +1 -0
  187. package/dist/application/transform/ref-pointer/pointer-walk.mjs +56 -0
  188. package/dist/application/transform/ref-pointer/pointer-walk.mjs.map +1 -0
  189. package/dist/application/transform/ref-pointer/typed-walk.cjs +124 -0
  190. package/dist/application/transform/ref-pointer/typed-walk.cjs.map +1 -0
  191. package/dist/application/transform/ref-pointer/typed-walk.mjs +122 -0
  192. package/dist/application/transform/ref-pointer/typed-walk.mjs.map +1 -0
  193. package/dist/application/transform/ref-type.cjs +7 -2
  194. package/dist/application/transform/ref-type.cjs.map +1 -1
  195. package/dist/application/transform/ref-type.mjs +3 -2
  196. package/dist/application/transform/ref-type.mjs.map +1 -1
  197. package/dist/application/transform/schema/access-flags.cjs +38 -0
  198. package/dist/application/transform/schema/access-flags.cjs.map +1 -0
  199. package/dist/application/transform/schema/access-flags.mjs +36 -0
  200. package/dist/application/transform/schema/access-flags.mjs.map +1 -0
  201. package/dist/application/transform/schema/array-type.cjs +32 -1
  202. package/dist/application/transform/schema/array-type.cjs.map +1 -1
  203. package/dist/application/transform/schema/array-type.mjs +33 -2
  204. package/dist/application/transform/schema/array-type.mjs.map +1 -1
  205. package/dist/application/transform/schema/composition-type.cjs +50 -15
  206. package/dist/application/transform/schema/composition-type.cjs.map +1 -1
  207. package/dist/application/transform/schema/composition-type.mjs +50 -15
  208. package/dist/application/transform/schema/composition-type.mjs.map +1 -1
  209. package/dist/application/transform/schema/core-type.cjs +3 -1
  210. package/dist/application/transform/schema/core-type.cjs.map +1 -1
  211. package/dist/application/transform/schema/core-type.mjs +3 -1
  212. package/dist/application/transform/schema/core-type.mjs.map +1 -1
  213. package/dist/application/transform/schema/discriminated-union.cjs +30 -0
  214. package/dist/application/transform/schema/discriminated-union.cjs.map +1 -0
  215. package/dist/application/transform/schema/discriminated-union.mjs +27 -0
  216. package/dist/application/transform/schema/discriminated-union.mjs.map +1 -0
  217. package/dist/application/transform/schema/discriminator-property.cjs +3 -2
  218. package/dist/application/transform/schema/discriminator-property.cjs.map +1 -1
  219. package/dist/application/transform/schema/discriminator-property.mjs +3 -2
  220. package/dist/application/transform/schema/discriminator-property.mjs.map +1 -1
  221. package/dist/application/transform/schema/enum-rule.cjs +66 -10
  222. package/dist/application/transform/schema/enum-rule.cjs.map +1 -1
  223. package/dist/application/transform/schema/enum-rule.mjs +67 -12
  224. package/dist/application/transform/schema/enum-rule.mjs.map +1 -1
  225. package/dist/application/transform/schema/inherited-discriminator.cjs +29 -0
  226. package/dist/application/transform/schema/inherited-discriminator.cjs.map +1 -0
  227. package/dist/application/transform/schema/inherited-discriminator.mjs +26 -0
  228. package/dist/application/transform/schema/inherited-discriminator.mjs.map +1 -0
  229. package/dist/application/transform/schema/object-type.cjs +38 -25
  230. package/dist/application/transform/schema/object-type.cjs.map +1 -1
  231. package/dist/application/transform/schema/object-type.mjs +39 -27
  232. package/dist/application/transform/schema/object-type.mjs.map +1 -1
  233. package/dist/application/transform/schema/required-variants.cjs +45 -0
  234. package/dist/application/transform/schema/required-variants.cjs.map +1 -0
  235. package/dist/application/transform/schema/required-variants.mjs +42 -0
  236. package/dist/application/transform/schema/required-variants.mjs.map +1 -0
  237. package/dist/application/transform/schema/schema-transform.cjs +2 -2
  238. package/dist/application/transform/schema/schema-transform.cjs.map +1 -1
  239. package/dist/application/transform/schema/schema-transform.mjs +2 -2
  240. package/dist/application/transform/schema/schema-transform.mjs.map +1 -1
  241. package/dist/application/transform/schema-comment.cjs +51 -5
  242. package/dist/application/transform/schema-comment.cjs.map +1 -1
  243. package/dist/application/transform/schema-comment.mjs +50 -6
  244. package/dist/application/transform/schema-comment.mjs.map +1 -1
  245. package/dist/application/transform/type-combinators.mjs +1 -1
  246. package/dist/cli/cli-arguments.cjs +11 -3
  247. package/dist/cli/cli-arguments.cjs.map +1 -1
  248. package/dist/cli/cli-arguments.mjs +11 -3
  249. package/dist/cli/cli-arguments.mjs.map +1 -1
  250. package/dist/cli/cli-errors.cjs +3 -2
  251. package/dist/cli/cli-errors.cjs.map +1 -1
  252. package/dist/cli/cli-errors.mjs +3 -2
  253. package/dist/cli/cli-errors.mjs.map +1 -1
  254. package/dist/cli/cli-output.cjs +8 -3
  255. package/dist/cli/cli-output.cjs.map +1 -1
  256. package/dist/cli/cli-output.mjs +9 -4
  257. package/dist/cli/cli-output.mjs.map +1 -1
  258. package/dist/cli/main.cjs +5 -0
  259. package/dist/cli/main.cjs.map +1 -1
  260. package/dist/cli/main.mjs +5 -0
  261. package/dist/cli/main.mjs.map +1 -1
  262. package/dist/cli/redocly-apis.cjs +7 -3
  263. package/dist/cli/redocly-apis.cjs.map +1 -1
  264. package/dist/cli/redocly-apis.mjs +8 -4
  265. package/dist/cli/redocly-apis.mjs.map +1 -1
  266. package/dist/cli/ref-limits.cjs +1 -1
  267. package/dist/cli/ref-limits.cjs.map +1 -1
  268. package/dist/cli/ref-limits.mjs +2 -2
  269. package/dist/cli/ref-limits.mjs.map +1 -1
  270. package/dist/cli/run-cli.cjs +15 -2
  271. package/dist/cli/run-cli.cjs.map +1 -1
  272. package/dist/cli/run-cli.mjs +16 -3
  273. package/dist/cli/run-cli.mjs.map +1 -1
  274. package/dist/domain/errors.cjs +2 -0
  275. package/dist/domain/errors.cjs.map +1 -1
  276. package/dist/domain/errors.mjs +2 -0
  277. package/dist/domain/errors.mjs.map +1 -1
  278. package/dist/domain/ir/constructors.cjs +5 -1
  279. package/dist/domain/ir/constructors.cjs.map +1 -1
  280. package/dist/domain/ir/constructors.mjs +5 -2
  281. package/dist/domain/ir/constructors.mjs.map +1 -1
  282. package/dist/domain/openapi/admitted-values.cjs +75 -0
  283. package/dist/domain/openapi/admitted-values.cjs.map +1 -0
  284. package/dist/domain/openapi/admitted-values.mjs +72 -0
  285. package/dist/domain/openapi/admitted-values.mjs.map +1 -0
  286. package/dist/domain/openapi/discriminated-union.cjs +68 -0
  287. package/dist/domain/openapi/discriminated-union.cjs.map +1 -0
  288. package/dist/domain/openapi/discriminated-union.mjs +62 -0
  289. package/dist/domain/openapi/discriminated-union.mjs.map +1 -0
  290. package/dist/domain/openapi/discriminator-conflicts.cjs +143 -0
  291. package/dist/domain/openapi/discriminator-conflicts.cjs.map +1 -0
  292. package/dist/domain/openapi/discriminator-conflicts.mjs +141 -0
  293. package/dist/domain/openapi/discriminator-conflicts.mjs.map +1 -0
  294. package/dist/domain/openapi/parameter-object.cjs.map +1 -1
  295. package/dist/domain/openapi/parameter-object.mjs.map +1 -1
  296. package/dist/domain/openapi/path-templates.cjs +23 -0
  297. package/dist/domain/openapi/path-templates.cjs.map +1 -0
  298. package/dist/domain/openapi/path-templates.mjs +21 -0
  299. package/dist/domain/openapi/path-templates.mjs.map +1 -0
  300. package/dist/domain/output-fixes.cjs +36 -1
  301. package/dist/domain/output-fixes.cjs.map +1 -1
  302. package/dist/domain/output-fixes.mjs +36 -1
  303. package/dist/domain/output-fixes.mjs.map +1 -1
  304. package/dist/domain/warnings.cjs +15 -0
  305. package/dist/domain/warnings.cjs.map +1 -0
  306. package/dist/domain/warnings.mjs +12 -0
  307. package/dist/domain/warnings.mjs.map +1 -0
  308. package/dist/index.d.cts +29 -0
  309. package/dist/index.d.mts +29 -0
  310. package/dist/index.d.ts +29 -0
  311. package/dist/transform/components-object.cjs +2 -1
  312. package/dist/transform/components-object.cjs.map +1 -1
  313. package/dist/transform/components-object.mjs +2 -1
  314. package/dist/transform/components-object.mjs.map +1 -1
  315. package/package.json +1 -1
  316. package/src/adapters/redocly-loader/redocly-config-source.ts +41 -6
  317. package/src/adapters/redocly-loader/redocly-schema-loader.ts +22 -6
  318. package/src/adapters/type-ast-bridge/ir-to-typescript.ts +3 -0
  319. package/src/adapters/type-ast-bridge/typescript-to-ir.ts +26 -12
  320. package/src/api/discriminator-conflict-warnings.ts +43 -0
  321. package/src/api/discriminator-enum-names.ts +26 -0
  322. package/src/api/discriminator-enum-parent.ts +129 -0
  323. package/src/api/discriminator-enum.ts +39 -0
  324. package/src/api/discriminator-other-owners.ts +97 -0
  325. package/src/api/discriminator-patch.ts +147 -0
  326. package/src/api/discriminator-scan.ts +78 -90
  327. package/src/api/document-run.ts +24 -6
  328. package/src/api/enum-values-warnings.ts +21 -0
  329. package/src/api/path-template-warnings.ts +27 -0
  330. package/src/api/transform-context.ts +7 -1
  331. package/src/api/transform-schema.ts +88 -4
  332. package/src/api/unsupported-feature-warnings.ts +8 -1
  333. package/src/application/ports/redocly-config-source.ts +5 -1
  334. package/src/application/print/type-printer.ts +6 -0
  335. package/src/application/transform/document/assignability.ts +203 -0
  336. package/src/application/transform/document/components.ts +6 -6
  337. package/src/application/transform/document/declared-types.ts +93 -0
  338. package/src/application/transform/document/document.ts +71 -13
  339. package/src/application/transform/document/exploded-query.ts +91 -0
  340. package/src/application/transform/document/global-type-references.ts +78 -0
  341. package/src/application/transform/document/list-assignability.ts +87 -0
  342. package/src/application/transform/document/parameters.ts +76 -11
  343. package/src/application/transform/document/path-key-overlaps.ts +148 -59
  344. package/src/application/transform/document/path-template-replace.ts +90 -0
  345. package/src/application/transform/document/paths.ts +99 -37
  346. package/src/application/transform/document/root-type-aliases.ts +29 -28
  347. package/src/application/transform/document/template-key-match.ts +183 -0
  348. package/src/application/transform/document/type-assignability.ts +268 -0
  349. package/src/application/transform/document/type-key.ts +80 -0
  350. package/src/application/transform/document/type-resolution.ts +163 -0
  351. package/src/application/transform/footer/document-footer.ts +91 -6
  352. package/src/application/transform/footer/enum-naming.ts +29 -0
  353. package/src/application/transform/footer/enum-values-check.ts +171 -0
  354. package/src/application/transform/footer/evaluation.ts +47 -0
  355. package/src/application/transform/footer/shared-enum-names.ts +86 -0
  356. package/src/application/transform/footer/type-evaluation.ts +294 -0
  357. package/src/application/transform/footer/type-rules.ts +269 -0
  358. package/src/application/transform/ref-pointer/generated-location.ts +211 -0
  359. package/src/application/transform/ref-pointer/generated-shape.ts +275 -0
  360. package/src/application/transform/ref-pointer/inline-cycles.ts +56 -0
  361. package/src/application/transform/ref-pointer/original-index.ts +95 -0
  362. package/src/application/transform/ref-pointer/pointer-type.ts +92 -0
  363. package/src/application/transform/ref-pointer/pointer-walk.ts +96 -0
  364. package/src/application/transform/ref-pointer/typed-walk.ts +192 -0
  365. package/src/application/transform/ref-type.ts +11 -6
  366. package/src/application/transform/schema/access-flags.ts +63 -0
  367. package/src/application/transform/schema/array-type.ts +66 -5
  368. package/src/application/transform/schema/composition-type.ts +96 -24
  369. package/src/application/transform/schema/core-type.ts +8 -4
  370. package/src/application/transform/schema/discriminated-union.ts +58 -0
  371. package/src/application/transform/schema/discriminator-property.ts +8 -3
  372. package/src/application/transform/schema/enum-rule.ts +136 -13
  373. package/src/application/transform/schema/inherited-discriminator.ts +54 -0
  374. package/src/application/transform/schema/object-type.ts +51 -33
  375. package/src/application/transform/schema/required-variants.ts +88 -0
  376. package/src/application/transform/schema/schema-context.ts +26 -0
  377. package/src/application/transform/schema/schema-transform.ts +2 -2
  378. package/src/application/transform/schema-comment.ts +84 -4
  379. package/src/cli/cli-arguments.ts +13 -3
  380. package/src/cli/cli-dependencies.ts +5 -0
  381. package/src/cli/cli-errors.ts +4 -2
  382. package/src/cli/cli-output.ts +18 -4
  383. package/src/cli/main.ts +6 -0
  384. package/src/cli/redocly-apis.ts +8 -4
  385. package/src/cli/ref-limits.ts +2 -2
  386. package/src/cli/run-cli.ts +20 -3
  387. package/src/domain/errors.ts +2 -0
  388. package/src/domain/ir/constructors.ts +6 -1
  389. package/src/domain/ir/nodes.ts +2 -1
  390. package/src/domain/openapi/admitted-values.ts +113 -0
  391. package/src/domain/openapi/discriminated-union.ts +109 -0
  392. package/src/domain/openapi/discriminator-conflicts.ts +251 -0
  393. package/src/domain/openapi/parameter-object.ts +4 -0
  394. package/src/domain/openapi/path-templates.ts +31 -0
  395. package/src/domain/openapi/schema-object.ts +2 -0
  396. package/src/domain/output-fixes.ts +43 -2
  397. package/src/domain/warnings.ts +20 -0
  398. package/src/transform/components-object.ts +3 -1
  399. package/src/types/generator-options.ts +11 -0
  400. package/dist/application/transform/document/path-item-conflicts.cjs +0 -51
  401. package/dist/application/transform/document/path-item-conflicts.cjs.map +0 -1
  402. package/dist/application/transform/document/path-item-conflicts.mjs +0 -49
  403. package/dist/application/transform/document/path-item-conflicts.mjs.map +0 -1
  404. package/src/application/transform/document/path-item-conflicts.ts +0 -79
@@ -0,0 +1,147 @@
1
+ import type { Logger } from "../application/ports/logger.js";
2
+ import { OutputFix } from "../domain/output-fixes.js";
3
+ import type { DiscriminatorObject, OpenAPI3, SchemaObject } from "../types.js";
4
+ import { addEnumProperty, declaresValues, type EnumPatch } from "./discriminator-enum.js";
5
+ import {
6
+ type DiscriminatorOwner,
7
+ type EnumParent,
8
+ enumParentOf,
9
+ } from "./discriminator-enum-parent.js";
10
+ import { resolveDocumentRef } from "./document-refs.js";
11
+
12
+ /**
13
+ * The state of the discriminator pre-pass and the in-place patch of a mapped schema: the enum
14
+ * property that the generated union narrows by. Two discriminators of one property may patch one
15
+ * schema; how they combine is the `discriminator-values` fix (ADR-021, roadmap R12).
16
+ */
17
+
18
+ /** How to scan: the warnings, and the output fixes of the run (ADR-021). */
19
+ export interface DiscriminatorScanOptions {
20
+ readonly silent: boolean;
21
+ readonly logger: Logger;
22
+ readonly fixes: ReadonlySet<OutputFix>;
23
+ }
24
+
25
+ /** What the two passes share: the document they patch and what they found so far. */
26
+ export interface ScanState extends DiscriminatorScanOptions {
27
+ readonly schema: OpenAPI3;
28
+ readonly objects: Record<string, DiscriminatorObject>;
29
+ /** The schemas that define a discriminator themselves (pass 1), not by inheritance. */
30
+ readonly owners: Set<string>;
31
+ readonly refsHandled: string[];
32
+ /** With the fix: the enum added to each schema, by schema and property, so values merge. */
33
+ readonly patchedEnums: Map<string, SchemaObject>;
34
+ /** With the fix: schema-name values, applied after both passes where no mapping names one. */
35
+ readonly inferredPatches: EnumPatch[];
36
+ /** With the fix: schema-name values of other properties (`inheritOtherOwners`). */
37
+ readonly otherInferredPatches: EnumPatch[];
38
+ /** With the fix: the other properties each schema got a value of (`inheritOtherOwners`). */
39
+ readonly otherProperties: Record<string, string[]>;
40
+ /** With `discriminator-values`: the enum keys that a schema declares itself. */
41
+ readonly declaredKeys: Set<string>;
42
+ /** With `discriminator-values`: the owner's enum of each added enum, by that enum. */
43
+ readonly enumParents: Map<object, EnumParent>;
44
+ }
45
+
46
+ /** Whether `discriminator-values` is on: values of two discriminators merge into one enum. */
47
+ export function mergesValues(state: ScanState): boolean {
48
+ return state.fixes.has(OutputFix.DISCRIMINATOR_VALUES);
49
+ }
50
+
51
+ function patchedSchema(state: ScanState, patch: EnumPatch): SchemaObject | undefined {
52
+ const { silent, logger } = state;
53
+ return resolveDocumentRef<SchemaObject>(state.schema, patch.ref, { silent, logger });
54
+ }
55
+
56
+ /**
57
+ * With `discriminator-values`: the schema at `patch.ref` requires the property with
58
+ * exactly these values already, so a patch would only repeat it (#2124).
59
+ */
60
+ function isDeclared(state: ScanState, patch: EnumPatch): boolean {
61
+ return (
62
+ state.fixes.has(OutputFix.DISCRIMINATOR_VALUES) &&
63
+ declaresValues(patchedSchema(state, patch), patch)
64
+ );
65
+ }
66
+
67
+ /**
68
+ * With `discriminator-values`: the enum of the owner's property, for `key`: an enum the scan
69
+ * added, or a discriminator object that a schema inherited.
70
+ */
71
+ export function recordEnumParent(state: ScanState, owner: DiscriminatorOwner, key: object): void {
72
+ if (!state.fixes.has(OutputFix.DISCRIMINATOR_VALUES)) {
73
+ return;
74
+ }
75
+ const { silent, logger } = state;
76
+ const parent = enumParentOf(owner, (ref) =>
77
+ resolveDocumentRef(state.schema, ref, { silent, logger }),
78
+ );
79
+ if (parent !== undefined) {
80
+ state.enumParents.set(key, parent);
81
+ }
82
+ }
83
+
84
+ /** The enum the schema at `patch.ref` gets, or null (with a warning) for another kind of schema. */
85
+ function addDiscriminatorEnum(state: ScanState, patch: EnumPatch): SchemaObject | null {
86
+ const added = addEnumProperty(patchedSchema(state, patch), patch);
87
+ if (added === null) {
88
+ warnInvalidMapping(patch, state.logger);
89
+ } else {
90
+ recordEnumParent(state, patch, added);
91
+ }
92
+ return added;
93
+ }
94
+
95
+ /** One schema and discriminator property; two discriminators of one property share an enum. */
96
+ export function enumKey(patch: EnumPatch): string {
97
+ return `${patch.ref}\n${patch.discriminator.propertyName}`;
98
+ }
99
+
100
+ /** With the fix, a second discriminator of the same property adds its values to the first enum. */
101
+ function mergeIntoPatchedEnum(state: ScanState, key: string, values: readonly string[]): boolean {
102
+ const patched = state.patchedEnums.get(key);
103
+ if (patched === undefined) {
104
+ return false;
105
+ }
106
+ const merged = patched.enum as unknown[];
107
+ merged.push(...values.filter((value) => !merged.includes(value)));
108
+ return true;
109
+ }
110
+
111
+ /**
112
+ * Add or replace the discriminator enum in the schema at `patch.ref`. Returns false, with a
113
+ * warning, when that schema is neither an `allOf` nor an object schema. Without the fix every
114
+ * patch adds a property, so two discriminators with different values intersect to `never`.
115
+ */
116
+ export function patchDiscriminatorEnum(state: ScanState, patch: EnumPatch): boolean {
117
+ if (isDeclared(state, patch)) {
118
+ state.declaredKeys.add(enumKey(patch));
119
+ return true;
120
+ }
121
+ if (!mergesValues(state)) {
122
+ return addDiscriminatorEnum(state, patch) !== null;
123
+ }
124
+ const key = enumKey(patch);
125
+ if (mergeIntoPatchedEnum(state, key, patch.values)) {
126
+ return true;
127
+ }
128
+ const added = addDiscriminatorEnum(state, patch);
129
+ if (added !== null) {
130
+ state.patchedEnums.set(key, added);
131
+ }
132
+ return added !== null;
133
+ }
134
+
135
+ export function markHandled(state: ScanState, ref: string): void {
136
+ if (!state.refsHandled.includes(ref)) {
137
+ state.refsHandled.push(ref);
138
+ }
139
+ }
140
+
141
+ function warnInvalidMapping(patch: EnumPatch, logger: Logger): void {
142
+ const mapped = `${patch.ref} => ${patch.values.join(", ")}`;
143
+ logger.warn(
144
+ "Discriminator mapping has an invalid schema (neither an object schema nor an allOf array): " +
145
+ `${mapped} (Discriminator: ${patch.discriminatorRef})`,
146
+ );
147
+ }
@@ -1,4 +1,6 @@
1
1
  import type { Logger } from "../application/ports/logger.js";
2
+ import { isUnionMember, unionAt } from "../domain/openapi/discriminated-union.js";
3
+ import { OutputFix } from "../domain/output-fixes.js";
2
4
  import type {
3
5
  DiscriminatorObject,
4
6
  GeneratorOptions,
@@ -7,7 +9,18 @@ import type {
7
9
  SchemaObject,
8
10
  } from "../types.js";
9
11
  import { defaultLogger } from "./default-ports.js";
10
- import { addEnumProperty, type EnumPatch } from "./discriminator-enum.js";
12
+ import type { EnumPatch } from "./discriminator-enum.js";
13
+ import type { EnumParent } from "./discriminator-enum-parent.js";
14
+ import { applyOtherInferredPatches, inheritOtherOwners } from "./discriminator-other-owners.js";
15
+ import {
16
+ type DiscriminatorScanOptions,
17
+ enumKey,
18
+ markHandled,
19
+ mergesValues,
20
+ patchDiscriminatorEnum,
21
+ recordEnumParent,
22
+ type ScanState,
23
+ } from "./discriminator-patch.js";
11
24
  import { resolveDocumentRef, walkDocument } from "./document-refs.js";
12
25
  import { createRef } from "./legacy-utils.js";
13
26
 
@@ -19,85 +32,6 @@ import { createRef } from "./legacy-utils.js";
19
32
 
20
33
  type DiscriminatorMapping = Record<string, { inferred?: string; defined?: string[] }>;
21
34
 
22
- /** How to scan; `fixesValueConflicts` is the `discriminator-values` fix (ADR-021, roadmap R12). */
23
- export interface DiscriminatorScanOptions {
24
- readonly silent: boolean;
25
- readonly logger: Logger;
26
- readonly fixesValueConflicts: boolean;
27
- }
28
-
29
- /** What the two passes share: the document they patch and what they found so far. */
30
- interface ScanState extends DiscriminatorScanOptions {
31
- readonly schema: OpenAPI3;
32
- readonly objects: Record<string, DiscriminatorObject>;
33
- readonly refsHandled: string[];
34
- /** With the fix: the enum added to each schema, by schema and property, so values merge. */
35
- readonly patchedEnums: Map<string, SchemaObject>;
36
- /** With the fix: schema-name values, applied after both passes where no mapping names one. */
37
- readonly inferredPatches: EnumPatch[];
38
- }
39
-
40
- /** The enum the schema at `patch.ref` gets, or null (with a warning) for another kind of schema. */
41
- function addDiscriminatorEnum(state: ScanState, patch: EnumPatch): SchemaObject | null {
42
- const { silent, logger } = state;
43
- const resolved = resolveDocumentRef<SchemaObject>(state.schema, patch.ref, { silent, logger });
44
- const added = addEnumProperty(resolved, patch);
45
- if (added === null) {
46
- warnInvalidMapping(patch, state.logger);
47
- }
48
- return added;
49
- }
50
-
51
- /** One schema and discriminator property; two discriminators of one property share an enum. */
52
- function enumKey(patch: EnumPatch): string {
53
- return `${patch.ref}\n${patch.discriminator.propertyName}`;
54
- }
55
-
56
- /** With the fix, a second discriminator of the same property adds its values to the first enum. */
57
- function mergeIntoPatchedEnum(state: ScanState, key: string, values: readonly string[]): boolean {
58
- const patched = state.patchedEnums.get(key);
59
- if (patched === undefined) {
60
- return false;
61
- }
62
- const merged = patched.enum as unknown[];
63
- merged.push(...values.filter((value) => !merged.includes(value)));
64
- return true;
65
- }
66
-
67
- /**
68
- * Add or replace the discriminator enum in the schema at `patch.ref`. Returns false, with a
69
- * warning, when that schema is neither an `allOf` nor an object schema. Without the fix every
70
- * patch adds a property, so two discriminators with different values intersect to `never`.
71
- */
72
- function patchDiscriminatorEnum(state: ScanState, patch: EnumPatch): boolean {
73
- if (!state.fixesValueConflicts) {
74
- return addDiscriminatorEnum(state, patch) !== null;
75
- }
76
- const key = enumKey(patch);
77
- if (mergeIntoPatchedEnum(state, key, patch.values)) {
78
- return true;
79
- }
80
- const added = addDiscriminatorEnum(state, patch);
81
- if (added !== null) {
82
- state.patchedEnums.set(key, added);
83
- }
84
- return added !== null;
85
- }
86
-
87
- function markHandled(state: ScanState, ref: string): void {
88
- if (!state.refsHandled.includes(ref)) {
89
- state.refsHandled.push(ref);
90
- }
91
- }
92
-
93
- function warnInvalidMapping(patch: EnumPatch, logger: Logger): void {
94
- const mapped = `${patch.ref} => ${patch.values.join(", ")}`;
95
- logger.warn(
96
- "Discriminator mapping has an invalid schema (neither an object schema nor an allOf array): " +
97
- `${mapped} (Discriminator: ${patch.discriminatorRef})`,
98
- );
99
- }
100
-
101
35
  /** The schema name at the end of each `oneOf` `$ref` is the inferred discriminator value. */
102
36
  function inferredMapping(oneOf: (SchemaObject | ReferenceObject)[]): DiscriminatorMapping {
103
37
  const mapping: DiscriminatorMapping = {};
@@ -116,9 +50,9 @@ function inferredMapping(oneOf: (SchemaObject | ReferenceObject)[]): Discriminat
116
50
  /** Values defined in `discriminator.mapping` replace inferred ones for the same schema. */
117
51
  function addDefinedMapping(
118
52
  mapping: DiscriminatorMapping,
119
- discriminator: DiscriminatorObject,
53
+ defined: Readonly<Record<string, string>>,
120
54
  ): void {
121
- for (const [mappedValue, mappedRef] of Object.entries(discriminator.mapping ?? {})) {
55
+ for (const [mappedValue, mappedRef] of Object.entries(defined)) {
122
56
  if (!mappedRef) {
123
57
  continue;
124
58
  }
@@ -135,13 +69,13 @@ function patchMappedSchemas(
135
69
  discriminator: Omit<EnumPatch, "ref" | "values">,
136
70
  ): void {
137
71
  for (const [ref, { inferred, defined }] of Object.entries(mapping)) {
138
- const isSkipped = !state.fixesValueConflicts && state.refsHandled.includes(ref);
72
+ const isSkipped = !mergesValues(state) && state.refsHandled.includes(ref);
139
73
  if (isSkipped || (!inferred && !defined)) {
140
74
  continue;
141
75
  }
142
76
  // A defined value wins: the schema name may not be the value the API sends.
143
77
  const values = defined ?? [inferred as string];
144
- if (state.fixesValueConflicts && defined === undefined) {
78
+ if (mergesValues(state) && defined === undefined) {
145
79
  // A mapping found later, in this pass or the next, may name the schema.
146
80
  state.inferredPatches.push({ ...discriminator, ref, values });
147
81
  } else if (patchDiscriminatorEnum(state, { ...discriminator, ref, values })) {
@@ -162,12 +96,13 @@ function collectDiscriminator(
162
96
  }
163
97
  const discriminatorRef = createRef(path);
164
98
  state.objects[discriminatorRef] = discriminator;
99
+ state.owners.add(discriminatorRef);
165
100
  if (!Array.isArray(value.oneOf)) {
166
101
  return;
167
102
  }
168
103
  const mapping = inferredMapping(value.oneOf);
169
104
  if (discriminator.mapping) {
170
- addDefinedMapping(mapping, discriminator);
105
+ addDefinedMapping(mapping, discriminator.mapping);
171
106
  }
172
107
  patchMappedSchemas(state, mapping, { discriminator, discriminatorRef });
173
108
  }
@@ -179,6 +114,41 @@ function valuesMappedTo(discriminator: DiscriminatorObject, ref: string): string
179
114
  .map(([mappedValue]) => mappedValue);
180
115
  }
181
116
 
117
+ /**
118
+ * Whether the schema at `ref` takes the discriminator of its `allOf` parent at `parentRef`. With
119
+ * `allof-discriminated-union`, a schema that `allOf`s a discriminated union that does not contain
120
+ * it is that union, not one of its members, so it gets no value of its own (#1464, #1690). A
121
+ * schema that the union's mapping names is a member.
122
+ */
123
+ function inheritsDiscriminator(state: ScanState, parentRef: string, ref: string): boolean {
124
+ if (!state.fixes.has(OutputFix.ALLOF_DISCRIMINATED_UNION)) {
125
+ return true;
126
+ }
127
+ const resolve = (target: string) => resolveDocumentRef(state.schema, target, state);
128
+ const union = unionAt(parentRef, resolve);
129
+ return union === undefined || isUnionMember(union, ref, resolve);
130
+ }
131
+
132
+ /**
133
+ * The schema at `ref` inherits `discriminator`. With `discriminator-values`, a schema that
134
+ * defines a discriminator keeps it: the inherited one replaced its mapping, so the members walked
135
+ * after this schema got their schema name instead of the mapped value (#2200). `ownerRef` is the
136
+ * schema that declares the discriminator property, whose enum `--enum` values use (#1700).
137
+ */
138
+ function recordInherited(
139
+ state: ScanState,
140
+ ref: string,
141
+ discriminator: DiscriminatorObject,
142
+ ownerRef: string,
143
+ ): void {
144
+ if (state.fixes.has(OutputFix.DISCRIMINATOR_VALUES) && state.owners.has(ref)) {
145
+ return;
146
+ }
147
+ const inherited = { ...discriminator };
148
+ state.objects[ref] = inherited;
149
+ recordEnumParent(state, { discriminator, discriminatorRef: ownerRef }, inherited);
150
+ }
151
+
182
152
  /**
183
153
  * An `allOf` item that is a `$ref` to a discriminator owner: the schema at `ref` inherits the
184
154
  * discriminator, and gets its enum when the parent's mapping names it. Returns false when the
@@ -194,7 +164,12 @@ function inheritFromRef(state: ScanState, parentRef: string, ref: string): boole
194
164
  if (values.length > 0 && patchDiscriminatorEnum(state, patch)) {
195
165
  markHandled(state, ref);
196
166
  }
197
- state.objects[ref] = { ...discriminator };
167
+ if (inheritsDiscriminator(state, parentRef, ref)) {
168
+ recordInherited(state, ref, discriminator, parentRef);
169
+ if (mergesValues(state)) {
170
+ inheritOtherOwners(state, parentRef, ref);
171
+ }
172
+ }
198
173
  return true;
199
174
  }
200
175
 
@@ -213,7 +188,8 @@ function inheritDiscriminators(
213
188
  return;
214
189
  }
215
190
  } else if (item.discriminator?.propertyName) {
216
- state.objects[createRef(path)] = { ...item.discriminator };
191
+ // The inline item is typed at the schema's own location.
192
+ recordInherited(state, createRef(path), item.discriminator, createRef(path));
217
193
  }
218
194
  }
219
195
  }
@@ -222,6 +198,10 @@ function inheritDiscriminators(
222
198
  export interface DiscriminatorScan {
223
199
  objects: Record<string, DiscriminatorObject>;
224
200
  refsHandled: string[];
201
+ /** With `discriminator-values`: the owner's enum of each enum the scan added. */
202
+ enumParents: ReadonlyMap<object, EnumParent>;
203
+ /** With `discriminator-values`: the properties of the other discriminators a schema inherits. */
204
+ otherProperties: Readonly<Record<string, readonly string[]>>;
225
205
  }
226
206
 
227
207
  /**
@@ -229,12 +209,14 @@ export interface DiscriminatorScan {
229
209
  * Every enum patched so far came from a mapping, since schema-name values wait for this step.
230
210
  */
231
211
  function applyInferredPatches(state: ScanState): void {
232
- const mapped = new Set(state.patchedEnums.keys());
212
+ // A value that a schema declares itself came from a mapping as well.
213
+ const mapped = new Set([...state.patchedEnums.keys(), ...state.declaredKeys]);
233
214
  for (const patch of state.inferredPatches) {
234
215
  if (!mapped.has(enumKey(patch)) && patchDiscriminatorEnum(state, patch)) {
235
216
  markHandled(state, patch.ref);
236
217
  }
237
218
  }
219
+ applyOtherInferredPatches(state, mapped);
238
220
  }
239
221
 
240
222
  /** Find every discriminator in `schema`; warnings go to `logger` unless `silent`. */
@@ -246,15 +228,21 @@ export function findDiscriminators(
246
228
  ...options,
247
229
  schema,
248
230
  objects: {},
231
+ owners: new Set(),
249
232
  refsHandled: [],
250
233
  patchedEnums: new Map(),
251
234
  inferredPatches: [],
235
+ otherInferredPatches: [],
236
+ otherProperties: {},
237
+ declaredKeys: new Set(),
238
+ enumParents: new Map(),
252
239
  };
253
240
  walkDocument(schema, (value, path) => collectDiscriminator(state, value, path));
254
241
  // A second pass, because an `allOf` may name a discriminator that is defined later.
255
242
  walkDocument(schema, (value, path) => inheritDiscriminators(state, value, path));
256
243
  applyInferredPatches(state);
257
- return { objects: state.objects, refsHandled: state.refsHandled };
244
+ const { objects, refsHandled, enumParents, otherProperties } = state;
245
+ return { objects, refsHandled, enumParents, otherProperties };
258
246
  }
259
247
 
260
248
  /**
@@ -268,5 +256,5 @@ export function scanDiscriminators(
268
256
  logger: Logger = defaultLogger(options.silent ?? false),
269
257
  ): DiscriminatorScan {
270
258
  const silent = options.silent ?? false;
271
- return findDiscriminators(schema, { silent, logger, fixesValueConflicts: false });
259
+ return findDiscriminators(schema, { silent, logger, fixes: new Set() });
272
260
  }
@@ -7,13 +7,15 @@ import type { RefAccess, SchemaLoader } from "../application/ports/schema-loader
7
7
  import { withStackOverflowReported } from "../application/stack-overflow.js";
8
8
  import {
9
9
  ineffectiveFixNotices,
10
- OutputFix,
10
+ type OutputFix,
11
11
  outputFixNamesOf,
12
12
  resolveOutputFixes,
13
13
  } from "../domain/output-fixes.js";
14
14
  import type { GeneratorOptions, GlobalContext, OpenAPI3, SchemaSource } from "../types.js";
15
+ import { warnDiscriminatorValueConflicts } from "./discriminator-conflict-warnings.js";
15
16
  import { findDiscriminators } from "./discriminator-scan.js";
16
17
  import { resolveDocumentRef } from "./document-refs.js";
18
+ import { warnIdenticalPathTemplates } from "./path-template-warnings.js";
17
19
  import { warnUnsupportedFeatures } from "./unsupported-feature-warnings.js";
18
20
 
19
21
  /** The ports of one generator run, wired by the Node API or the CLI (ENGINEERING_PLAN 4.5). */
@@ -45,10 +47,17 @@ type ContextFlags = Omit<
45
47
  | "fix"
46
48
  >;
47
49
 
50
+ /**
51
+ * The directory that relative `$ref`s of an inline source resolve against, as a URL that ends in
52
+ * a slash. A path is resolved and encoded (`#`, `%`, spaces); a URL without the slash gets one.
53
+ */
48
54
  function sourceCwd(options: GeneratorOptions): URL {
49
- return options.cwd instanceof URL
50
- ? options.cwd
51
- : new URL(`file://${options.cwd ?? process.cwd()}/`);
55
+ const { cwd } = options;
56
+ if (cwd instanceof URL) {
57
+ return cwd.pathname.endsWith("/") ? cwd : new URL(`${cwd.pathname}/`, cwd);
58
+ }
59
+ const directory = path.resolve(cwd === undefined ? process.cwd() : cwd.toString());
60
+ return pathToFileURL(path.join(directory, path.sep));
52
61
  }
53
62
 
54
63
  /** The `$ref` limits of the options; a relative local root resolves against the cwd. */
@@ -115,6 +124,15 @@ function outputFixesOf(options: GeneratorOptions, logger: Logger): readonly Outp
115
124
  return [...resolveOutputFixes(names)];
116
125
  }
117
126
 
127
+ /** The warnings about the loaded document itself, before it is transformed. */
128
+ function warnAboutDocument(schema: OpenAPI3, fix: readonly OutputFix[], logger: Logger): void {
129
+ withStackOverflowReported("transform", () => warnUnsupportedFeatures(schema, logger));
130
+ withStackOverflowReported("transform", () =>
131
+ warnDiscriminatorValueConflicts(schema, fix, logger),
132
+ );
133
+ warnIdenticalPathTemplates(schema, logger);
134
+ }
135
+
118
136
  /**
119
137
  * Load the source through the ports, then build the run's context from the options. The fix names
120
138
  * are checked first, so a typo fails before the document is read.
@@ -137,7 +155,7 @@ export async function createDocumentRun(
137
155
  shouldLint: options.lint ?? true,
138
156
  refAccess: refAccessOf(options, cwd),
139
157
  });
140
- withStackOverflowReported("transform", () => warnUnsupportedFeatures(schema, logger));
158
+ warnAboutDocument(schema, fix, logger);
141
159
  const ctx: GlobalContext = {
142
160
  ...contextFlags(options),
143
161
  fix,
@@ -147,7 +165,7 @@ export async function createDocumentRun(
147
165
  findDiscriminators(schema, {
148
166
  silent,
149
167
  logger,
150
- fixesValueConflicts: fix.includes(OutputFix.DISCRIMINATOR_VALUES),
168
+ fixes: new Set(fix),
151
169
  }),
152
170
  ),
153
171
  injectFooter: [],
@@ -0,0 +1,21 @@
1
+ import { WARNING_CODES, warningText } from "../domain/warnings.js";
2
+
3
+ const DOCS_BASE_URL = "https://github.com/openapi-typesafe/openapi-typesafe/blob/main/docs";
4
+ const DOCS_URL = `${DOCS_BASE_URL}/advanced.md#enum-values-arrays`;
5
+
6
+ /**
7
+ * The warning for an `--enum-values` array whose schema's location in the generated types admits
8
+ * none or only some of its values (ADR-027): the schema contradicts itself, for example an `allOf`
9
+ * of enums with different values or a discriminator value that the property enum does not list.
10
+ */
11
+ export function excludedValuesWarning(name: string, excluded: readonly unknown[]): string {
12
+ const values = excluded.map((value) => JSON.stringify(value)).join(", ");
13
+ return warningText(
14
+ `${name}: the generated type at the location of this enum does not admit ${values}; ` +
15
+ "other keywords of the document exclude these values (an allOf of enums with other " +
16
+ "values, or a discriminator value the enum does not list). The array is typed by its own " +
17
+ "values. " +
18
+ `See ${DOCS_URL}`,
19
+ WARNING_CODES.ENUM_VALUES_EXCLUDED,
20
+ );
21
+ }
@@ -0,0 +1,27 @@
1
+ import type { Logger } from "../application/ports/logger.js";
2
+ import { findIdenticalPathTemplates } from "../domain/openapi/path-templates.js";
3
+ import { WARNING_CODES, warningText } from "../domain/warnings.js";
4
+
5
+ const DOCS_URL =
6
+ "https://github.com/openapi-typesafe/openapi-typesafe/blob/main/docs/cli.md#pathparamsastypes";
7
+ const SPEC_RULE =
8
+ "OpenAPI does not allow this (Paths Object): templated paths with the same hierarchy but " +
9
+ "different templated names MUST NOT exist as they are identical";
10
+
11
+ /** `"/a"`, `"/a" and "/b"`, `"/a", "/b" and "/c"`. */
12
+ function quotedList(urls: readonly string[]): string {
13
+ const quoted = urls.map((url) => `"${url}"`);
14
+ const last = quoted.pop();
15
+ return quoted.length === 0 ? (last ?? "") : `${quoted.join(", ")} and ${last}`;
16
+ }
17
+
18
+ /**
19
+ * Warn once per group of paths that differ only in parameter names, which the spec forbids: a URL
20
+ * cannot tell them apart, and `--path-params-as-types` gives them the same key type.
21
+ */
22
+ export function warnIdenticalPathTemplates(document: unknown, logger: Logger): void {
23
+ for (const urls of findIdenticalPathTemplates(document)) {
24
+ const message = `Paths ${quotedList(urls)} differ only in their parameter names. ${SPEC_RULE}`;
25
+ logger.warn(warningText(`${message}. See ${DOCS_URL}`, WARNING_CODES.PATH_TEMPLATES_IDENTICAL));
26
+ }
27
+ }
@@ -1,6 +1,9 @@
1
1
  import * as changeCase from "change-case";
2
2
  import { RunFooter } from "../application/transform/footer/document-footer.js";
3
- import type { SchemaLocation } from "../application/transform/schema/schema-context.js";
3
+ import type {
4
+ DiscriminatorEnumParent,
5
+ SchemaLocation,
6
+ } from "../application/transform/schema/schema-context.js";
4
7
  import type {
5
8
  DocumentFooter,
6
9
  NameCasing,
@@ -73,6 +76,9 @@ export function createTransformContext(ctx: GlobalContext): TransformContext {
73
76
  discriminators: {
74
77
  objectAt: (ref) => ctx.discriminators.objects[ref],
75
78
  isHandled: (ref) => ctx.discriminators.refsHandled.includes(ref),
79
+ otherPropertiesAt: (ref) => ctx.discriminators.otherProperties?.[ref] ?? [],
80
+ enumParentOf: (schema) =>
81
+ ctx.discriminators.enumParents?.get(schema) as DiscriminatorEnumParent | undefined,
76
82
  },
77
83
  footer: runFooter(ctx),
78
84
  callbacks: schemaCallbacks(ctx),
@@ -1,11 +1,21 @@
1
1
  import type { ts } from "../adapters/type-ast-bridge/typescript-types.js";
2
2
  import { documentBody, documentClosing } from "../application/transform/document/document.js";
3
- import { renameAliasesTakenByFooter } from "../application/transform/document/root-type-aliases.js";
3
+ import { renameTakenAliases } from "../application/transform/document/root-type-aliases.js";
4
+ import { RunFooter } from "../application/transform/footer/document-footer.js";
5
+ import { checkedEnumValues } from "../application/transform/footer/enum-values-check.js";
6
+ import {
7
+ SharedEnumNameRecorder,
8
+ type SharedEnumNames,
9
+ } from "../application/transform/footer/shared-enum-names.js";
4
10
  import type { IrDeclaration } from "../domain/ir/nodes.js";
5
11
  import type { DocumentObject } from "../domain/openapi/document-object.js";
12
+ import { OutputFix } from "../domain/output-fixes.js";
6
13
  import type { GlobalContext, OpenAPI3 } from "../types.js";
14
+ import { FirstSchemaNameRecorder } from "./discriminator-enum-names.js";
7
15
  import { documentDeclarations, type TransformedDocument } from "./document-declarations.js";
16
+ import { excludedValuesWarning } from "./enum-values-warnings.js";
8
17
  import { type FooterEntry, isIrDeclaration } from "./footer-entry.js";
18
+ import { ContextFooterSink } from "./footer-sink.js";
9
19
  import { createTransformContext } from "./transform-context.js";
10
20
 
11
21
  const OPERATIONS_NAME = "operations";
@@ -18,15 +28,89 @@ function isOperations(entry: FooterEntry): boolean {
18
28
  return name === OPERATIONS_NAME;
19
29
  }
20
30
 
31
+ /** Drops a message: the first pass must not repeat the run's warnings or debug lines. */
32
+ const dropMessage = (): void => undefined;
33
+ const DROPPED_MESSAGES = { debug: dropMessage, warn: dropMessage, error: dropMessage };
34
+
35
+ /** A shared enum name recorder of a first pass, and the names it gives the second. */
36
+ interface EnumNameRecorder extends SharedEnumNames {
37
+ chosenNames(): SharedEnumNames;
38
+ }
39
+
40
+ /**
41
+ * The names of shared enums, known only at the end: a first pass transforms the document into a
42
+ * scratch footer that `recorder` watches; its output is dropped. User callbacks run in both
43
+ * passes. The `dedupe-enum-names` fix (ADR-021, upstream #1683) names an enum by all of its
44
+ * schemas; `discriminator-values` keeps the first declaring schema's name
45
+ * (`FirstSchemaNameRecorder`).
46
+ */
47
+ function sharedEnumNamesOf(
48
+ document: DocumentObject,
49
+ ctx: GlobalContext,
50
+ recorder: EnumNameRecorder,
51
+ ): SharedEnumNames {
52
+ const injectFooter: FooterEntry[] = [];
53
+ const scratch: GlobalContext = {
54
+ ...ctx,
55
+ injectFooter,
56
+ runFooter: new RunFooter(new ContextFooterSink(injectFooter), true, recorder),
57
+ logger: DROPPED_MESSAGES,
58
+ legacyCallbackWarnings: new Set(),
59
+ };
60
+ const scratchContext = createTransformContext(scratch);
61
+ documentBody(document, scratchContext, () => injectFooter.filter(isIrDeclaration));
62
+ return recorder.chosenNames();
63
+ }
64
+
65
+ /** The recorder of the run's fixes, or null where the first schema's name needs no first pass. */
66
+ function enumNameRecorderOf(ctx: GlobalContext): EnumNameRecorder | null {
67
+ if (ctx.fix?.includes(OutputFix.DEDUPE_ENUM_NAMES)) {
68
+ return new SharedEnumNameRecorder();
69
+ }
70
+ return ctx.fix?.includes(OutputFix.DISCRIMINATOR_VALUES) ? new FirstSchemaNameRecorder() : null;
71
+ }
72
+
73
+ /** With a naming fix, `--enum` and `--dedupe-enums`, the run's footer names shared enums. */
74
+ function withSharedEnumNames(document: DocumentObject, ctx: GlobalContext): void {
75
+ const recorder = ctx.runFooter === undefined ? enumNameRecorderOf(ctx) : null;
76
+ if (recorder === null || !ctx.enum || !ctx.dedupeEnums) {
77
+ return;
78
+ }
79
+ const names = sharedEnumNamesOf(document, ctx, recorder);
80
+ ctx.runFooter = new RunFooter(new ContextFooterSink(ctx.injectFooter), true, names);
81
+ }
82
+
83
+ /**
84
+ * With `--enum-values`, arrays whose location type does not hold their values are typed by their
85
+ * values (ADR-027); a location that excludes listed values is a contradiction of the document.
86
+ */
87
+ function enumValuesChecked(
88
+ body: readonly IrDeclaration[],
89
+ footer: FooterEntry[],
90
+ ctx: GlobalContext,
91
+ ): FooterEntry[] {
92
+ if (!ctx.enumValues) {
93
+ return footer;
94
+ }
95
+ const checked = checkedEnumValues(footer, body, isIrDeclaration);
96
+ for (const retype of checked.retyped) {
97
+ if (retype.kind === "excluded") {
98
+ ctx.logger?.warn(excludedValuesWarning(retype.name, retype.excluded));
99
+ }
100
+ }
101
+ return checked.footer;
102
+ }
103
+
21
104
  /** @internal Root types, the footer, then the closing declarations (Phase 5, step 6). */
22
105
  export function transformDocument(schema: OpenAPI3, ctx: GlobalContext): TransformedDocument {
23
106
  const document = schema as DocumentObject;
107
+ withSharedEnumNames(document, ctx);
24
108
  const context = createTransformContext(ctx);
25
109
  // documentBody registers the enums in the footer, so the footer is read after it.
26
- const rawBody = documentBody(document, context);
27
- const footer: FooterEntry[] = [...ctx.injectFooter];
28
- const body = renameAliasesTakenByFooter(rawBody, footer.filter(isIrDeclaration));
110
+ const rawBody = documentBody(document, context, () => ctx.injectFooter.filter(isIrDeclaration));
111
+ const footer = enumValuesChecked(rawBody, [...ctx.injectFooter], ctx);
29
112
  const closing = documentClosing(document, context, footer.some(isOperations));
113
+ const body = renameTakenAliases(rawBody, footer.filter(isIrDeclaration), closing);
30
114
  return { body, footer, closing };
31
115
  }
32
116