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
@@ -179,3 +179,32 @@ export function enumDeclaration(
179
179
  comments: [],
180
180
  };
181
181
  }
182
+
183
+ /** The member names an enum name has so far, with their values. */
184
+ export type DeclaredMembers = ReadonlyMap<string, string | number>;
185
+
186
+ /**
187
+ * A later declaration of an enum name merges with the earlier ones, and a member name declared
188
+ * twice does not compile (TS2300): a property and an inline `allOf` item of one schema give one
189
+ * name. A member that repeats one by name and value is left out; one whose name another value has
190
+ * gets the next free number (`a_b_2`).
191
+ */
192
+ export function withoutDeclaredMembers(
193
+ declaration: IrEnumDeclaration,
194
+ declared: DeclaredMembers,
195
+ ): IrEnumDeclaration {
196
+ const taken = new Set(declared.keys());
197
+ const members: IrEnumDeclaration["members"][number][] = [];
198
+ for (const member of declaration.members) {
199
+ if (declared.get(member.name) === member.value) {
200
+ continue;
201
+ }
202
+ let name = member.name;
203
+ for (let count = 2; taken.has(name); count++) {
204
+ name = numberedMemberName(member.name, count);
205
+ }
206
+ taken.add(name);
207
+ members.push(name === member.name ? member : { ...member, name });
208
+ }
209
+ return { ...declaration, members };
210
+ }
@@ -0,0 +1,171 @@
1
+ import { irArray, irReadonly, irReference } from "../../../domain/ir/constructors.js";
2
+ import type { IrConstArrayDeclaration, IrDeclaration, IrType } from "../../../domain/ir/nodes.js";
3
+ import { HELPER_TYPES } from "../helper-types.js";
4
+ import { literalType } from "../literal-type.js";
5
+ import { unionOf } from "../type-combinators.js";
6
+ import { type Evaluated, type Evaluation, NEVER } from "./evaluation.js";
7
+ import { TypeEvaluator } from "./type-evaluation.js";
8
+
9
+ /**
10
+ * `--enum-values` arrays are typed by the location of their schema in the generated types
11
+ * (`FlattenedDeepRequired<components>["schemas"]["A"]["status"]`). Where that type surely does not
12
+ * hold the values (ADR-027), the array is typed by its own values instead, so it compiles:
13
+ * - the location indexes a key the generated type does not have (`definitions`, `allOf`, a
14
+ * property of `unknown`), or
15
+ * - the type there does not admit a listed value (an `allOf` of different enums, a discriminator
16
+ * value the property enum does not list, an array next to other `anyOf` members).
17
+ * Everything else stays as it was.
18
+ */
19
+
20
+ /** Why an array got its own values as its type. */
21
+ export type EnumValuesRetype =
22
+ /** The location's type admits only other values, or none: the document contradicts itself. */
23
+ | { readonly kind: "excluded"; readonly name: string; readonly excluded: readonly unknown[] }
24
+ /** The location could not be typed; nothing to report, the array is right now. */
25
+ | { readonly kind: "untyped"; readonly name: string };
26
+
27
+ type Admission = "yes" | "no" | "opaque";
28
+
29
+ function literalAdmission(type: IrType, value: string | number): Admission {
30
+ switch (type.kind) {
31
+ case "stringLiteral":
32
+ case "numberLiteral":
33
+ return type.value === value ? "yes" : "no";
34
+ case "booleanLiteral":
35
+ return "no";
36
+ case "keyword":
37
+ if (type.keyword === "unknown") {
38
+ return "yes";
39
+ }
40
+ return type.keyword === typeof value ? "yes" : "no";
41
+ case "object":
42
+ // `{}` (as in `string & {}`) admits every value but `null` and `undefined`.
43
+ return type.members.length === 0 ? "yes" : "no";
44
+ case "array":
45
+ return "no";
46
+ default:
47
+ return "opaque";
48
+ }
49
+ }
50
+
51
+ function admission(evaluator: TypeEvaluator, value: Evaluated, item: string | number): Admission {
52
+ const { type } = value;
53
+ if (type.kind === "union" || type.kind === "intersection") {
54
+ const parts = type.types.map((part) => {
55
+ const expanded = evaluator.expand({ ...value, type: part });
56
+ return expanded.kind === "type" ? admission(evaluator, expanded, item) : "opaque";
57
+ });
58
+ // A union admits a value one member admits; an intersection excludes one a part excludes.
59
+ const decisive: Admission = type.kind === "union" ? "yes" : "no";
60
+ if (parts.includes(decisive)) {
61
+ return decisive;
62
+ }
63
+ return parts.includes("opaque") ? "opaque" : decisive === "yes" ? "no" : "yes";
64
+ }
65
+ return literalAdmission(type, item);
66
+ }
67
+
68
+ /** `ReadonlyArray<T>`: an array type `T` is the array itself, so its elements are checked. */
69
+ function elementOf(evaluator: TypeEvaluator, value: Evaluated): Evaluation {
70
+ const members = evaluator.membersOf(value);
71
+ const elements = members.map((member) =>
72
+ member.kind === "type" && member.type.kind === "array" ? member.type.element : null,
73
+ );
74
+ if (members.length === 0 || elements.some((element) => element === null)) {
75
+ return value;
76
+ }
77
+ return evaluator.expand({ ...value, type: unionOf(elements as IrType[]) });
78
+ }
79
+
80
+ const LITERAL_KINDS: ReadonlySet<string> = new Set([
81
+ "stringLiteral",
82
+ "numberLiteral",
83
+ "booleanLiteral",
84
+ ]);
85
+
86
+ /** Whether a type is made of literals only (or `never`): a finite set of values. */
87
+ function isFiniteType(evaluator: TypeEvaluator, value: Evaluated): boolean {
88
+ const { type } = value;
89
+ if (type.kind === "union" || type.kind === "intersection") {
90
+ return type.types.every((part) => {
91
+ const expanded = evaluator.expand({ ...value, type: part });
92
+ return expanded.kind === "type" && isFiniteType(evaluator, expanded);
93
+ });
94
+ }
95
+ return LITERAL_KINDS.has(type.kind) || (type.kind === "keyword" && type.keyword === "never");
96
+ }
97
+
98
+ function locationType(declaration: IrConstArrayDeclaration): IrType | null {
99
+ const { type } = declaration;
100
+ const isTyped = type.kind === "reference" && type.name === HELPER_TYPES.readonlyArray.name;
101
+ return isTyped ? (type.typeArguments[0] ?? null) : null;
102
+ }
103
+
104
+ function retypeOf(
105
+ evaluator: TypeEvaluator,
106
+ declaration: IrConstArrayDeclaration,
107
+ ): EnumValuesRetype | null {
108
+ const location = locationType(declaration);
109
+ const evaluated = location === null ? null : evaluator.evaluate(location);
110
+ if (evaluated === null || evaluated.kind === "opaque") {
111
+ return null;
112
+ }
113
+ if (evaluated.kind === "missing") {
114
+ return { kind: "untyped", name: declaration.name };
115
+ }
116
+ const element = elementOf(evaluator, evaluated);
117
+ if (element.kind !== "type") {
118
+ return element.kind === "missing" ? { kind: "untyped", name: declaration.name } : null;
119
+ }
120
+ if (declaration.values.length === 0 && isNever(element.type)) {
121
+ // The `ReadonlyArray` helper of `never` is `never` (`never` extends an array): not even `[]`.
122
+ return { kind: "untyped", name: declaration.name };
123
+ }
124
+ const results = declaration.values.map((value) => admission(evaluator, element, value));
125
+ if (!results.includes("no")) {
126
+ return null;
127
+ }
128
+ if (!isFiniteType(evaluator, element)) {
129
+ return { kind: "untyped", name: declaration.name };
130
+ }
131
+ const excluded = declaration.values.filter((_, index) => results[index] === "no");
132
+ return { kind: "excluded", name: declaration.name, excluded };
133
+ }
134
+
135
+ function isNever(type: IrType): boolean {
136
+ return type.kind === "keyword" && type.keyword === "never";
137
+ }
138
+
139
+ /** The values' own type; with no values `readonly never[]` (`ReadonlyArray<never>` is never). */
140
+ function ownValuesType(declaration: IrConstArrayDeclaration): IrType {
141
+ if (declaration.values.length === 0) {
142
+ return irReadonly(irArray(NEVER));
143
+ }
144
+ const values = unionOf(declaration.values.map((value) => literalType(value)));
145
+ return irReference(HELPER_TYPES.readonlyArray.name, [values]);
146
+ }
147
+
148
+ /**
149
+ * The footer with each `--enum-values` array whose location type does not hold its values typed
150
+ * by its own values, and why each one changed. `declarations` are the document's types.
151
+ */
152
+ export function checkedEnumValues<T>(
153
+ footer: readonly (T | IrDeclaration)[],
154
+ declarations: readonly IrDeclaration[],
155
+ isDeclaration: (entry: T | IrDeclaration) => entry is IrDeclaration,
156
+ ): { footer: (T | IrDeclaration)[]; retyped: EnumValuesRetype[] } {
157
+ const evaluator = new TypeEvaluator([...declarations, ...footer.filter(isDeclaration)]);
158
+ const retyped: EnumValuesRetype[] = [];
159
+ const checked = footer.map((entry) => {
160
+ if (!isDeclaration(entry) || entry.kind !== "constArray") {
161
+ return entry;
162
+ }
163
+ const retype = retypeOf(evaluator, entry);
164
+ if (retype === null) {
165
+ return entry;
166
+ }
167
+ retyped.push(retype);
168
+ return { ...entry, type: ownValuesType(entry) };
169
+ });
170
+ return { footer: checked, retyped };
171
+ }
@@ -0,0 +1,47 @@
1
+ import type { IrPropertyName, IrType } from "../../../domain/ir/nodes.js";
2
+
3
+ /** The values the evaluator of the `--enum-values` check works with (ADR-027). */
4
+
5
+ /** A type as evaluated: `deep` is set inside `FlattenedDeepRequired`. */
6
+ export interface Evaluated {
7
+ readonly kind: "type";
8
+ readonly type: IrType;
9
+ readonly deep: boolean;
10
+ }
11
+
12
+ export type Evaluation = Evaluated | { readonly kind: "missing" } | { readonly kind: "opaque" };
13
+
14
+ export const MISSING: Evaluation = { kind: "missing" };
15
+ export const OPAQUE: Evaluation = { kind: "opaque" };
16
+
17
+ export const NEVER: IrType = { kind: "keyword", keyword: "never" };
18
+
19
+ export function unionType(types: readonly IrType[]): IrType {
20
+ if (types.length === 1) {
21
+ return types[0] as IrType;
22
+ }
23
+ return types.length === 0 ? NEVER : { kind: "union", types };
24
+ }
25
+
26
+ export function propertyKey(name: IrPropertyName): string {
27
+ return name.kind === "string" ? name.value : name.text;
28
+ }
29
+
30
+ function isKeyword(member: Evaluation, keyword: string): boolean {
31
+ return (
32
+ member.kind === "type" && member.type.kind === "keyword" && member.type.keyword === keyword
33
+ );
34
+ }
35
+
36
+ /**
37
+ * Union members as TypeScript reduces them: `any` absorbs every member, `unknown` every member
38
+ * but `any`, so `{ a: X } | unknown` is `unknown`. An opaque member may be `any`.
39
+ */
40
+ export function absorbed(members: readonly Evaluation[]): readonly Evaluation[] {
41
+ const any = members.find((member) => isKeyword(member, "any"));
42
+ const unknown = members.find((member) => isKeyword(member, "unknown"));
43
+ if (any !== undefined || unknown === undefined) {
44
+ return any === undefined ? members : [any];
45
+ }
46
+ return members.some((member) => member.kind !== "type") ? [OPAQUE] : [unknown];
47
+ }
@@ -0,0 +1,86 @@
1
+ import type { EnumDeclarationRequest } from "../schema/schema-context.js";
2
+ import { EnumNaming } from "./enum-naming.js";
3
+
4
+ /**
5
+ * How `--dedupe-enums` names the one enum that schemas with the same members share. `key` is the
6
+ * dedupe key of the members; `name` is the name the schema gives with the run's naming state.
7
+ */
8
+ export interface SharedEnumNames {
9
+ /** Called for every schema of the enum, in document order; returns the name to declare. */
10
+ nameOf(key: string, name: string, request: EnumDeclarationRequest): string;
11
+ }
12
+
13
+ /** The original: the enum takes the name of the first schema in the document. */
14
+ export const FIRST_SCHEMA_NAMES: SharedEnumNames = { nameOf: (_key, name) => name };
15
+
16
+ interface NameCandidate {
17
+ readonly name: string;
18
+ readonly isComponentSchema: boolean;
19
+ }
20
+
21
+ /**
22
+ * Whether `candidate` names the enum better than `other`: a component schema that is the enum
23
+ * itself, then the shorter name, then the earlier one in code-unit order. No part depends on the
24
+ * document order, so adding or moving a schema changes the name only when the new one ranks first.
25
+ */
26
+ function isBetterName(candidate: NameCandidate, other: NameCandidate): boolean {
27
+ if (candidate.isComponentSchema !== other.isComponentSchema) {
28
+ return candidate.isComponentSchema;
29
+ }
30
+ if (candidate.name.length !== other.name.length) {
31
+ return candidate.name.length < other.name.length;
32
+ }
33
+ return candidate.name < other.name;
34
+ }
35
+
36
+ /** The candidates from best to worst. */
37
+ function ranked(candidates: readonly NameCandidate[]): NameCandidate[] {
38
+ return [...candidates].sort((left, right) => {
39
+ if (left.name === right.name && left.isComponentSchema === right.isComponentSchema) {
40
+ return 0;
41
+ }
42
+ return isBetterName(left, right) ? -1 : 1;
43
+ });
44
+ }
45
+
46
+ /**
47
+ * The `dedupe-enum-names` fix (ADR-021, upstream #1683), first pass: records every schema of each
48
+ * shared enum and keeps the run's own names. `chosenNames` gives the names for the second pass.
49
+ */
50
+ export class SharedEnumNameRecorder implements SharedEnumNames {
51
+ private readonly candidatesByKey = new Map<string, NameCandidate[]>();
52
+
53
+ nameOf(key: string, name: string, request: EnumDeclarationRequest): string {
54
+ // A fresh naming state: the run's state depends on the names built before (EnumNaming).
55
+ const candidate = {
56
+ name: new EnumNaming().enumName(request.name),
57
+ isComponentSchema: request.isComponentSchema,
58
+ };
59
+ const candidates = this.candidatesByKey.get(key);
60
+ if (candidates === undefined) {
61
+ this.candidatesByKey.set(key, [candidate]);
62
+ } else {
63
+ candidates.push(candidate);
64
+ }
65
+ return name;
66
+ }
67
+
68
+ /**
69
+ * The best name of each enum. Two enums whose best names are the same (two schemas that give
70
+ * one name) are resolved in key order: the later one takes its next name that is free.
71
+ */
72
+ chosenNames(): SharedEnumNames {
73
+ const chosen = new Map<string, string>();
74
+ const taken = new Set<string>();
75
+ const keys = [...this.candidatesByKey.keys()].sort();
76
+ for (const key of keys) {
77
+ const names = ranked(this.candidatesByKey.get(key) ?? []).map(({ name }) => name);
78
+ const name = names.find((candidate) => !taken.has(candidate)) ?? names[0];
79
+ if (name !== undefined) {
80
+ chosen.set(key, name);
81
+ taken.add(name);
82
+ }
83
+ }
84
+ return { nameOf: (key, name) => chosen.get(key) ?? name };
85
+ }
86
+ }
@@ -0,0 +1,294 @@
1
+ import type { IrDeclaration, IrMember, IrType } from "../../../domain/ir/nodes.js";
2
+ import {
3
+ absorbed,
4
+ type Evaluated,
5
+ type Evaluation,
6
+ MISSING,
7
+ NEVER,
8
+ OPAQUE,
9
+ propertyKey,
10
+ unionType,
11
+ } from "./evaluation.js";
12
+ import {
13
+ declaredFirst,
14
+ extracted,
15
+ isNeverIntersection,
16
+ markerObject,
17
+ omitted,
18
+ } from "./type-rules.js";
19
+
20
+ /**
21
+ * A small evaluator of the generated types, as TypeScript reads them, for the `--enum-values`
22
+ * check (ADR-027). It follows the declarations of the document and the helper types the generator
23
+ * writes (`NonNullable`, `Extract`, `WithRequired`, `Omit`, `Record`, `FlattenedDeepRequired`). Its
24
+ * answers are sure: a key is `missing` only where TypeScript reports it, and every type it does
25
+ * not model is `opaque`, which never counts as an error.
26
+ */
27
+
28
+ /** How many references one evaluation expands; a deeper one is opaque. */
29
+ const MAX_EXPANSIONS = 200;
30
+ const DEEP_PREFIX = "FlattenedDeepRequired<";
31
+ /** How many members distributing an intersection may give; more is opaque. */
32
+ const MAX_DISTRIBUTED = 64;
33
+ const NULLISH: ReadonlySet<string> = new Set(["null", "undefined"]);
34
+
35
+ export class TypeEvaluator {
36
+ private readonly declared = new Map<string, IrType>();
37
+ private expansions = 0;
38
+
39
+ constructor(declarations: readonly IrDeclaration[]) {
40
+ for (const declaration of declarations) {
41
+ if (declaration.kind === "interface") {
42
+ this.declared.set(declaration.name, { kind: "object", members: declaration.members });
43
+ } else if (declaration.kind === "typeAlias") {
44
+ this.declared.set(declaration.name, declaration.type);
45
+ }
46
+ }
47
+ }
48
+
49
+ /** Evaluate a type written in the footer; the expansion budget starts again. */
50
+ evaluate(type: IrType): Evaluation {
51
+ this.expansions = 0;
52
+ return this.expand({ kind: "type", type, deep: false });
53
+ }
54
+
55
+ /** The type with references, `readonly` and indexed access resolved at the top. */
56
+ expand(value: Evaluated): Evaluation {
57
+ const { type } = value;
58
+ switch (type.kind) {
59
+ case "readonly":
60
+ return this.expand({ ...value, type: type.type });
61
+ case "indexedAccess":
62
+ return this.indexedAccess(value, type.object, type.index);
63
+ case "reference":
64
+ return this.reference(value, type.name, type.typeArguments);
65
+ case "raw":
66
+ case "tuple":
67
+ return OPAQUE;
68
+ default:
69
+ return value;
70
+ }
71
+ }
72
+
73
+ private indexedAccess(value: Evaluated, object: IrType, index: IrType): Evaluation {
74
+ const owner = this.expand({ ...value, type: object });
75
+ return owner.kind === "type" ? this.index(owner, index) : owner;
76
+ }
77
+
78
+ private reference(value: Evaluated, name: string, args: readonly IrType[]): Evaluation {
79
+ // Only references cost budget: re-expanding an already expanded value (as the checks after
80
+ // `evaluate` do) is free, so a large evaluation does not leave its checks opaque.
81
+ if (this.expansions++ > MAX_EXPANSIONS) {
82
+ return OPAQUE;
83
+ }
84
+ if (name.startsWith(DEEP_PREFIX) && name.endsWith(">")) {
85
+ const root = this.declared.get(name.slice(DEEP_PREFIX.length, -1));
86
+ return root === undefined ? OPAQUE : this.expand({ kind: "type", type: root, deep: true });
87
+ }
88
+ const declared = args.length === 0 ? this.declared.get(name) : undefined;
89
+ if (declared !== undefined) {
90
+ return this.expand({ ...value, type: declared });
91
+ }
92
+ const [first, second] = args;
93
+ if (first === undefined) {
94
+ return OPAQUE;
95
+ }
96
+ const argument = this.expand({ ...value, type: first });
97
+ if (argument.kind !== "type") {
98
+ return argument;
99
+ }
100
+ return this.helper(name, argument, second);
101
+ }
102
+
103
+ private helper(name: string, argument: Evaluated, second: IrType | undefined): Evaluation {
104
+ switch (name) {
105
+ case "NonNullable":
106
+ return this.withoutNullish(argument);
107
+ case "WithRequired":
108
+ case "Readonly":
109
+ return argument;
110
+ case "Extract":
111
+ return second === undefined ? OPAQUE : this.extract(argument, second);
112
+ case "Omit":
113
+ return second === undefined ? OPAQUE : omitted(this, argument, second);
114
+ default:
115
+ return markerObject(name, argument) ?? OPAQUE;
116
+ }
117
+ }
118
+
119
+ /**
120
+ * The members of a union, each expanded; an intersection with unions in it is distributed over
121
+ * them (`A & (B | C)` is `(A & B) | (A & C)`), as TypeScript normalizes it. A type that is not a
122
+ * union is its only member. A union with an `any` or `unknown` member is that keyword alone.
123
+ */
124
+ membersOf(value: Evaluated): readonly Evaluation[] {
125
+ const expanded = this.expand(value);
126
+ if (expanded.kind !== "type") {
127
+ return [expanded];
128
+ }
129
+ const { type } = expanded;
130
+ if (type.kind === "union") {
131
+ return absorbed(
132
+ type.types.flatMap((member) => this.membersOf({ ...expanded, type: member })),
133
+ );
134
+ }
135
+ return type.kind === "intersection" ? this.distributed(expanded, type.types) : [expanded];
136
+ }
137
+
138
+ private distributed(value: Evaluated, parts: readonly IrType[]): readonly Evaluation[] {
139
+ const memberLists = parts.map((part) => this.membersOf({ ...value, type: part }));
140
+ const size = memberLists.reduce((product, list) => product * list.length, 1);
141
+ if (size > MAX_DISTRIBUTED || memberLists.some((list) => list.some((m) => m.kind !== "type"))) {
142
+ return [OPAQUE];
143
+ }
144
+ let combinations: IrType[][] = [[]];
145
+ for (const list of memberLists as Evaluated[][]) {
146
+ combinations = combinations.flatMap((done) => list.map((member) => [...done, member.type]));
147
+ }
148
+ return combinations.map((types) => ({ ...value, type: intersectionType(types) }));
149
+ }
150
+
151
+ private withoutNullish(value: Evaluated): Evaluation {
152
+ const members = this.membersOf(value);
153
+ if (members.some((member) => member.kind !== "type")) {
154
+ return OPAQUE;
155
+ }
156
+ const kept = (members as Evaluated[]).filter((member) => !isNullish(member.type));
157
+ return { ...value, type: unionType(kept.map((member) => member.type)) };
158
+ }
159
+
160
+ /** `Extract<T, { key: unknown }>` keeps the members that have `key`; other probes are opaque. */
161
+ private extract(value: Evaluated, probe: IrType): Evaluation {
162
+ const [member] = probe.kind === "object" ? probe.members : [];
163
+ if (probe.kind !== "object" || probe.members.length !== 1 || member?.kind !== "property") {
164
+ return OPAQUE;
165
+ }
166
+ return extracted(this, value, propertyKey(member.name));
167
+ }
168
+
169
+ /** `value[index]` for a string literal, `string` or `number` index. */
170
+ index(value: Evaluated, index: IrType): Evaluation {
171
+ const owner = this.expand(value);
172
+ if (owner.kind !== "type") {
173
+ return owner;
174
+ }
175
+ if (this.membersOf(owner).length > 1) {
176
+ return this.unionIndex(owner, index);
177
+ }
178
+ const { type } = owner;
179
+ switch (type.kind) {
180
+ case "object":
181
+ return this.memberType(owner, type.members, index);
182
+ case "intersection":
183
+ return this.partsIndex(owner, type.types, index);
184
+ case "union":
185
+ return this.unionIndex(owner, index);
186
+ case "array":
187
+ return isNumberIndex(index) ? this.flattened(owner, type.element) : builtInIndex(index);
188
+ case "keyword":
189
+ return type.keyword === "never" ? owner : builtInIndex(index);
190
+ default:
191
+ return builtInIndex(index);
192
+ }
193
+ }
194
+
195
+ private memberType(owner: Evaluated, members: readonly IrMember[], index: IrType): Evaluation {
196
+ const key = indexKey(index);
197
+ const property = members.find(
198
+ (member) => member.kind === "property" && key !== null && propertyKey(member.name) === key,
199
+ );
200
+ if (property !== undefined) {
201
+ return this.flattened(owner, property.type);
202
+ }
203
+ const signature = members.find((member) => member.kind === "indexSignature");
204
+ if (signature !== undefined) {
205
+ return this.flattened(owner, signature.type);
206
+ }
207
+ return key === null || isObjectBuiltIn(key) ? OPAQUE : MISSING;
208
+ }
209
+
210
+ private partsIndex(owner: Evaluated, parts: readonly IrType[], index: IrType): Evaluation {
211
+ if (isNeverIntersection(this, owner, parts)) {
212
+ return { ...owner, type: NEVER };
213
+ }
214
+ const found = parts.map((type) => this.index({ ...owner, type }, index));
215
+ if (found.some((part) => part.kind === "opaque")) {
216
+ return OPAQUE;
217
+ }
218
+ const read = parts.map((type, at) => ({ type, found: found[at] as Evaluation }));
219
+ const types = declaredFirst(this, owner, indexKey(index), read).flatMap((part) =>
220
+ part.kind === "type" ? [part.type] : [],
221
+ );
222
+ return types.length === 0 ? MISSING : { ...owner, type: intersectionType(types) };
223
+ }
224
+
225
+ private unionIndex(owner: Evaluated, index: IrType): Evaluation {
226
+ const found = this.membersOf(owner).map((member) =>
227
+ member.kind === "type" ? this.index(member, index) : member,
228
+ );
229
+ if (found.some((member) => member.kind === "missing")) {
230
+ return MISSING;
231
+ }
232
+ if (found.some((member) => member.kind === "opaque")) {
233
+ return OPAQUE;
234
+ }
235
+ return { ...owner, type: unionType((found as Evaluated[]).map((member) => member.type)) };
236
+ }
237
+
238
+ /**
239
+ * A member read through `FlattenedDeepRequired`: a value that is only arrays (and `undefined` or
240
+ * `null`) is replaced by its elements, anything else loses `undefined` and `null`.
241
+ */
242
+ private flattened(owner: Evaluated, type: IrType): Evaluation {
243
+ const member: Evaluated = { ...owner, type };
244
+ if (!owner.deep) {
245
+ return this.expand(member);
246
+ }
247
+ const members = this.membersOf(member);
248
+ if (members.some((candidate) => candidate.kind !== "type")) {
249
+ return OPAQUE;
250
+ }
251
+ const present = (members as Evaluated[]).filter((candidate) => !isNullish(candidate.type));
252
+ const elements = present.map((candidate) => arrayElement(candidate.type));
253
+ if (present.length > 0 && elements.every((element) => element !== null)) {
254
+ return this.expand({ ...owner, type: unionType(elements as IrType[]) });
255
+ }
256
+ return { ...owner, type: unionType(present.map((candidate) => candidate.type)) };
257
+ }
258
+ }
259
+
260
+ function isNullish(type: IrType): boolean {
261
+ return type.kind === "keyword" && NULLISH.has(type.keyword);
262
+ }
263
+
264
+ /** The element of an expanded member; expanding already dropped `readonly`. */
265
+ function arrayElement(type: IrType): IrType | null {
266
+ return type.kind === "array" ? type.element : null;
267
+ }
268
+
269
+ function intersectionType(types: readonly IrType[]): IrType {
270
+ return types.length === 1 ? (types[0] as IrType) : { kind: "intersection", types };
271
+ }
272
+
273
+ function indexKey(index: IrType): string | null {
274
+ if (index.kind === "stringLiteral") {
275
+ return index.value;
276
+ }
277
+ return index.kind === "numberLiteral" ? String(index.value) : null;
278
+ }
279
+
280
+ function isNumberIndex(index: IrType): boolean {
281
+ const key = indexKey(index);
282
+ return (index.kind === "keyword" && index.keyword === "number") || /^\d+$/.test(key ?? "");
283
+ }
284
+
285
+ function isObjectBuiltIn(key: string): boolean {
286
+ return key in {};
287
+ }
288
+
289
+ /** A key of a primitive or an array: a built-in member is opaque, any other key is missing. */
290
+ function builtInIndex(index: IrType): Evaluation {
291
+ const key = indexKey(index);
292
+ const isBuiltIn = key === null || key in String.prototype || key in Array.prototype;
293
+ return isBuiltIn || key in Number.prototype ? OPAQUE : MISSING;
294
+ }