openapi-typesafe 1.0.0-rc.4 → 1.0.0-rc.6

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 (366) hide show
  1. package/CHANGELOG.md +214 -0
  2. package/dist/adapters/node-file-system/node-file-system.cjs +7 -0
  3. package/dist/adapters/node-file-system/node-file-system.cjs.map +1 -1
  4. package/dist/adapters/node-file-system/node-file-system.mjs +7 -0
  5. package/dist/adapters/node-file-system/node-file-system.mjs.map +1 -1
  6. package/dist/adapters/pipe-safe-writer/pipe-safe-writer.cjs +19 -0
  7. package/dist/adapters/pipe-safe-writer/pipe-safe-writer.cjs.map +1 -0
  8. package/dist/adapters/pipe-safe-writer/pipe-safe-writer.mjs +17 -0
  9. package/dist/adapters/pipe-safe-writer/pipe-safe-writer.mjs.map +1 -0
  10. package/dist/adapters/redocly-loader/bundled-mapping-copies.cjs +5 -32
  11. package/dist/adapters/redocly-loader/bundled-mapping-copies.cjs.map +1 -1
  12. package/dist/adapters/redocly-loader/bundled-mapping-copies.mjs +6 -33
  13. package/dist/adapters/redocly-loader/bundled-mapping-copies.mjs.map +1 -1
  14. package/dist/adapters/redocly-loader/component-schemas.cjs +17 -0
  15. package/dist/adapters/redocly-loader/component-schemas.cjs.map +1 -0
  16. package/dist/adapters/redocly-loader/component-schemas.mjs +14 -0
  17. package/dist/adapters/redocly-loader/component-schemas.mjs.map +1 -0
  18. package/dist/adapters/redocly-loader/mapping-schema-names.cjs +22 -0
  19. package/dist/adapters/redocly-loader/mapping-schema-names.cjs.map +1 -0
  20. package/dist/adapters/redocly-loader/mapping-schema-names.mjs +20 -0
  21. package/dist/adapters/redocly-loader/mapping-schema-names.mjs.map +1 -0
  22. package/dist/adapters/redocly-loader/query-document-names.cjs +50 -0
  23. package/dist/adapters/redocly-loader/query-document-names.cjs.map +1 -0
  24. package/dist/adapters/redocly-loader/query-document-names.mjs +48 -0
  25. package/dist/adapters/redocly-loader/query-document-names.mjs.map +1 -0
  26. package/dist/adapters/redocly-loader/query-named-components.cjs +129 -0
  27. package/dist/adapters/redocly-loader/query-named-components.cjs.map +1 -0
  28. package/dist/adapters/redocly-loader/query-named-components.mjs +126 -0
  29. package/dist/adapters/redocly-loader/query-named-components.mjs.map +1 -0
  30. package/dist/adapters/redocly-loader/redocly-config-source.cjs +3 -0
  31. package/dist/adapters/redocly-loader/redocly-config-source.cjs.map +1 -1
  32. package/dist/adapters/redocly-loader/redocly-config-source.mjs +4 -1
  33. package/dist/adapters/redocly-loader/redocly-config-source.mjs.map +1 -1
  34. package/dist/adapters/redocly-loader/redocly-schema-loader.cjs +39 -18
  35. package/dist/adapters/redocly-loader/redocly-schema-loader.cjs.map +1 -1
  36. package/dist/adapters/redocly-loader/redocly-schema-loader.mjs +40 -19
  37. package/dist/adapters/redocly-loader/redocly-schema-loader.mjs.map +1 -1
  38. package/dist/adapters/redocly-loader/ref-access.cjs +25 -4
  39. package/dist/adapters/redocly-loader/ref-access.cjs.map +1 -1
  40. package/dist/adapters/redocly-loader/ref-access.mjs +26 -5
  41. package/dist/adapters/redocly-loader/ref-access.mjs.map +1 -1
  42. package/dist/adapters/redocly-loader/ref-holders.cjs +52 -10
  43. package/dist/adapters/redocly-loader/ref-holders.cjs.map +1 -1
  44. package/dist/adapters/redocly-loader/ref-holders.mjs +52 -11
  45. package/dist/adapters/redocly-loader/ref-holders.mjs.map +1 -1
  46. package/dist/adapters/redocly-loader/remote-fetch.cjs +20 -3
  47. package/dist/adapters/redocly-loader/remote-fetch.cjs.map +1 -1
  48. package/dist/adapters/redocly-loader/remote-fetch.mjs +20 -4
  49. package/dist/adapters/redocly-loader/remote-fetch.mjs.map +1 -1
  50. package/dist/adapters/redocly-loader/remote-node-limit.cjs +17 -3
  51. package/dist/adapters/redocly-loader/remote-node-limit.cjs.map +1 -1
  52. package/dist/adapters/redocly-loader/remote-node-limit.mjs +17 -3
  53. package/dist/adapters/redocly-loader/remote-node-limit.mjs.map +1 -1
  54. package/dist/adapters/redocly-loader/schema-source.cjs +7 -2
  55. package/dist/adapters/redocly-loader/schema-source.cjs.map +1 -1
  56. package/dist/adapters/redocly-loader/schema-source.mjs +8 -3
  57. package/dist/adapters/redocly-loader/schema-source.mjs.map +1 -1
  58. package/dist/adapters/terminal-logger/terminal-logger.cjs +7 -3
  59. package/dist/adapters/terminal-logger/terminal-logger.cjs.map +1 -1
  60. package/dist/adapters/terminal-logger/terminal-logger.mjs +7 -3
  61. package/dist/adapters/terminal-logger/terminal-logger.mjs.map +1 -1
  62. package/dist/api/cwd-option.cjs +58 -0
  63. package/dist/api/cwd-option.cjs.map +1 -0
  64. package/dist/api/cwd-option.mjs +52 -0
  65. package/dist/api/cwd-option.mjs.map +1 -0
  66. package/dist/api/default-ports.cjs +15 -7
  67. package/dist/api/default-ports.cjs.map +1 -1
  68. package/dist/api/default-ports.mjs +14 -8
  69. package/dist/api/default-ports.mjs.map +1 -1
  70. package/dist/api/document-refs.cjs +16 -1
  71. package/dist/api/document-refs.cjs.map +1 -1
  72. package/dist/api/document-refs.mjs +16 -1
  73. package/dist/api/document-refs.mjs.map +1 -1
  74. package/dist/api/document-run.cjs +6 -26
  75. package/dist/api/document-run.cjs.map +1 -1
  76. package/dist/api/document-run.mjs +5 -21
  77. package/dist/api/document-run.mjs.map +1 -1
  78. package/dist/api/legacy-utils.cjs +1 -1
  79. package/dist/api/legacy-utils.cjs.map +1 -1
  80. package/dist/api/legacy-utils.mjs +1 -1
  81. package/dist/api/legacy-utils.mjs.map +1 -1
  82. package/dist/api/openapi-ts.cjs +1 -2
  83. package/dist/api/openapi-ts.cjs.map +1 -1
  84. package/dist/api/openapi-ts.mjs +2 -3
  85. package/dist/api/openapi-ts.mjs.map +1 -1
  86. package/dist/api/option-errors.cjs +24 -0
  87. package/dist/api/option-errors.cjs.map +1 -0
  88. package/dist/api/option-errors.mjs +21 -0
  89. package/dist/api/option-errors.mjs.map +1 -0
  90. package/dist/api/ref-limit-options.cjs +58 -0
  91. package/dist/api/ref-limit-options.cjs.map +1 -0
  92. package/dist/api/ref-limit-options.mjs +52 -0
  93. package/dist/api/ref-limit-options.mjs.map +1 -0
  94. package/dist/api/transform-schema.cjs +12 -5
  95. package/dist/api/transform-schema.cjs.map +1 -1
  96. package/dist/api/transform-schema.mjs +12 -5
  97. package/dist/api/transform-schema.mjs.map +1 -1
  98. package/dist/application/transform/declared-value-types.cjs +36 -0
  99. package/dist/application/transform/declared-value-types.cjs.map +1 -0
  100. package/dist/application/transform/declared-value-types.mjs +34 -0
  101. package/dist/application/transform/declared-value-types.mjs.map +1 -0
  102. package/dist/application/transform/document/document.cjs +3 -1
  103. package/dist/application/transform/document/document.cjs.map +1 -1
  104. package/dist/application/transform/document/document.mjs +3 -1
  105. package/dist/application/transform/document/document.mjs.map +1 -1
  106. package/dist/application/transform/document/exploded-query-values.cjs +63 -0
  107. package/dist/application/transform/document/exploded-query-values.cjs.map +1 -0
  108. package/dist/application/transform/document/exploded-query-values.mjs +59 -0
  109. package/dist/application/transform/document/exploded-query-values.mjs.map +1 -0
  110. package/dist/application/transform/document/header.cjs +11 -3
  111. package/dist/application/transform/document/header.cjs.map +1 -1
  112. package/dist/application/transform/document/header.mjs +10 -2
  113. package/dist/application/transform/document/header.mjs.map +1 -1
  114. package/dist/application/transform/document/parameter.cjs +1 -1
  115. package/dist/application/transform/document/parameter.cjs.map +1 -1
  116. package/dist/application/transform/document/parameter.mjs +1 -1
  117. package/dist/application/transform/document/parameter.mjs.map +1 -1
  118. package/dist/application/transform/document/parameters.cjs +23 -5
  119. package/dist/application/transform/document/parameters.cjs.map +1 -1
  120. package/dist/application/transform/document/parameters.mjs +23 -5
  121. package/dist/application/transform/document/parameters.mjs.map +1 -1
  122. package/dist/application/transform/document/path-item.cjs +4 -3
  123. package/dist/application/transform/document/path-item.cjs.map +1 -1
  124. package/dist/application/transform/document/path-item.mjs +4 -4
  125. package/dist/application/transform/document/path-item.mjs.map +1 -1
  126. package/dist/application/transform/document/path-template-key.cjs +84 -0
  127. package/dist/application/transform/document/path-template-key.cjs.map +1 -0
  128. package/dist/application/transform/document/path-template-key.mjs +79 -0
  129. package/dist/application/transform/document/path-template-key.mjs.map +1 -0
  130. package/dist/application/transform/document/path-template-refs.cjs +80 -0
  131. package/dist/application/transform/document/path-template-refs.cjs.map +1 -0
  132. package/dist/application/transform/document/path-template-refs.mjs +77 -0
  133. package/dist/application/transform/document/path-template-refs.mjs.map +1 -0
  134. package/dist/application/transform/document/paths-enum.cjs +7 -6
  135. package/dist/application/transform/document/paths-enum.cjs.map +1 -1
  136. package/dist/application/transform/document/paths-enum.mjs +7 -6
  137. package/dist/application/transform/document/paths-enum.mjs.map +1 -1
  138. package/dist/application/transform/document/paths.cjs +38 -66
  139. package/dist/application/transform/document/paths.cjs.map +1 -1
  140. package/dist/application/transform/document/paths.mjs +36 -66
  141. package/dist/application/transform/document/paths.mjs.map +1 -1
  142. package/dist/application/transform/document/webhooks.cjs +10 -3
  143. package/dist/application/transform/document/webhooks.cjs.map +1 -1
  144. package/dist/application/transform/document/webhooks.mjs +9 -2
  145. package/dist/application/transform/document/webhooks.mjs.map +1 -1
  146. package/dist/application/transform/footer/document-footer.cjs +6 -3
  147. package/dist/application/transform/footer/document-footer.cjs.map +1 -1
  148. package/dist/application/transform/footer/document-footer.mjs +6 -3
  149. package/dist/application/transform/footer/document-footer.mjs.map +1 -1
  150. package/dist/application/transform/helper-types.cjs +3 -3
  151. package/dist/application/transform/helper-types.cjs.map +1 -1
  152. package/dist/application/transform/helper-types.mjs +3 -3
  153. package/dist/application/transform/helper-types.mjs.map +1 -1
  154. package/dist/application/transform/ref-pointer/generated-location.cjs +4 -4
  155. package/dist/application/transform/ref-pointer/generated-location.cjs.map +1 -1
  156. package/dist/application/transform/ref-pointer/generated-location.mjs +1 -1
  157. package/dist/application/transform/ref-pointer/generated-location.mjs.map +1 -1
  158. package/dist/application/transform/ref-pointer/generated-shape.cjs +63 -64
  159. package/dist/application/transform/ref-pointer/generated-shape.cjs.map +1 -1
  160. package/dist/application/transform/ref-pointer/generated-shape.mjs +57 -53
  161. package/dist/application/transform/ref-pointer/generated-shape.mjs.map +1 -1
  162. package/dist/application/transform/ref-pointer/inline-cycles.cjs +2 -2
  163. package/dist/application/transform/ref-pointer/inline-cycles.cjs.map +1 -1
  164. package/dist/application/transform/ref-pointer/inline-cycles.mjs +1 -1
  165. package/dist/application/transform/ref-pointer/inline-cycles.mjs.map +1 -1
  166. package/dist/application/transform/ref-pointer/located-node.cjs +23 -0
  167. package/dist/application/transform/ref-pointer/located-node.cjs.map +1 -0
  168. package/dist/application/transform/ref-pointer/located-node.mjs +18 -0
  169. package/dist/application/transform/ref-pointer/located-node.mjs.map +1 -0
  170. package/dist/application/transform/ref-pointer/original-index.cjs +69 -14
  171. package/dist/application/transform/ref-pointer/original-index.cjs.map +1 -1
  172. package/dist/application/transform/ref-pointer/original-index.mjs +71 -16
  173. package/dist/application/transform/ref-pointer/original-index.mjs.map +1 -1
  174. package/dist/application/transform/ref-pointer/pointer-type.cjs +2 -2
  175. package/dist/application/transform/ref-pointer/pointer-type.cjs.map +1 -1
  176. package/dist/application/transform/ref-pointer/pointer-type.mjs +1 -1
  177. package/dist/application/transform/ref-pointer/pointer-type.mjs.map +1 -1
  178. package/dist/application/transform/ref-pointer/pointer-walk.cjs +54 -13
  179. package/dist/application/transform/ref-pointer/pointer-walk.cjs.map +1 -1
  180. package/dist/application/transform/ref-pointer/pointer-walk.mjs +46 -7
  181. package/dist/application/transform/ref-pointer/pointer-walk.mjs.map +1 -1
  182. package/dist/application/transform/ref-pointer/property-shape.cjs +57 -0
  183. package/dist/application/transform/ref-pointer/property-shape.cjs.map +1 -0
  184. package/dist/application/transform/ref-pointer/property-shape.mjs +49 -0
  185. package/dist/application/transform/ref-pointer/property-shape.mjs.map +1 -0
  186. package/dist/application/transform/ref-pointer/typed-walk.cjs +90 -22
  187. package/dist/application/transform/ref-pointer/typed-walk.cjs.map +1 -1
  188. package/dist/application/transform/ref-pointer/typed-walk.mjs +87 -19
  189. package/dist/application/transform/ref-pointer/typed-walk.mjs.map +1 -1
  190. package/dist/application/transform/schema/access-flags.cjs.map +1 -1
  191. package/dist/application/transform/schema/access-flags.mjs.map +1 -1
  192. package/dist/application/transform/schema/index-signature-type.cjs +21 -0
  193. package/dist/application/transform/schema/index-signature-type.cjs.map +1 -0
  194. package/dist/application/transform/schema/index-signature-type.mjs +19 -0
  195. package/dist/application/transform/schema/index-signature-type.mjs.map +1 -0
  196. package/dist/application/transform/schema/input-location.cjs +23 -0
  197. package/dist/application/transform/schema/input-location.cjs.map +1 -0
  198. package/dist/application/transform/schema/input-location.mjs +21 -0
  199. package/dist/application/transform/schema/input-location.mjs.map +1 -0
  200. package/dist/application/transform/schema/object-type.cjs +15 -5
  201. package/dist/application/transform/schema/object-type.cjs.map +1 -1
  202. package/dist/application/transform/schema/object-type.mjs +15 -5
  203. package/dist/application/transform/schema/object-type.mjs.map +1 -1
  204. package/dist/application/transform/schema/schema-transform.cjs +2 -1
  205. package/dist/application/transform/schema/schema-transform.cjs.map +1 -1
  206. package/dist/application/transform/schema/schema-transform.mjs +2 -1
  207. package/dist/application/transform/schema/schema-transform.mjs.map +1 -1
  208. package/dist/application/transform/schema/unevaluated-properties.cjs +2 -30
  209. package/dist/application/transform/schema/unevaluated-properties.cjs.map +1 -1
  210. package/dist/application/transform/schema/unevaluated-properties.mjs +3 -31
  211. package/dist/application/transform/schema/unevaluated-properties.mjs.map +1 -1
  212. package/dist/cli/api-logger.cjs +13 -0
  213. package/dist/cli/api-logger.cjs.map +1 -0
  214. package/dist/cli/api-logger.mjs +11 -0
  215. package/dist/cli/api-logger.mjs.map +1 -0
  216. package/dist/cli/api-settings.cjs +10 -17
  217. package/dist/cli/api-settings.cjs.map +1 -1
  218. package/dist/cli/api-settings.mjs +10 -17
  219. package/dist/cli/api-settings.mjs.map +1 -1
  220. package/dist/cli/api-writes.cjs +7 -1
  221. package/dist/cli/api-writes.cjs.map +1 -1
  222. package/dist/cli/api-writes.mjs +7 -1
  223. package/dist/cli/api-writes.mjs.map +1 -1
  224. package/dist/cli/cli-arguments.cjs +32 -74
  225. package/dist/cli/cli-arguments.cjs.map +1 -1
  226. package/dist/cli/cli-arguments.mjs +28 -70
  227. package/dist/cli/cli-arguments.mjs.map +1 -1
  228. package/dist/cli/cli-errors.cjs +18 -0
  229. package/dist/cli/cli-errors.cjs.map +1 -1
  230. package/dist/cli/cli-errors.mjs +18 -1
  231. package/dist/cli/cli-errors.mjs.map +1 -1
  232. package/dist/cli/cli-flag-names.cjs +77 -0
  233. package/dist/cli/cli-flag-names.cjs.map +1 -0
  234. package/dist/cli/cli-flag-names.mjs +64 -0
  235. package/dist/cli/cli-flag-names.mjs.map +1 -0
  236. package/dist/cli/cli-output.cjs +13 -6
  237. package/dist/cli/cli-output.cjs.map +1 -1
  238. package/dist/cli/cli-output.mjs +14 -7
  239. package/dist/cli/cli-output.mjs.map +1 -1
  240. package/dist/cli/main.cjs +11 -5
  241. package/dist/cli/main.cjs.map +1 -1
  242. package/dist/cli/main.mjs +11 -5
  243. package/dist/cli/main.mjs.map +1 -1
  244. package/dist/cli/redocly-apis.cjs +33 -12
  245. package/dist/cli/redocly-apis.cjs.map +1 -1
  246. package/dist/cli/redocly-apis.mjs +35 -14
  247. package/dist/cli/redocly-apis.mjs.map +1 -1
  248. package/dist/cli/ref-limits.cjs +15 -1
  249. package/dist/cli/ref-limits.cjs.map +1 -1
  250. package/dist/cli/ref-limits.mjs +15 -2
  251. package/dist/cli/ref-limits.mjs.map +1 -1
  252. package/dist/cli/run-cli.cjs +24 -7
  253. package/dist/cli/run-cli.cjs.map +1 -1
  254. package/dist/cli/run-cli.mjs +25 -8
  255. package/dist/cli/run-cli.mjs.map +1 -1
  256. package/dist/cli/written-flags.cjs +83 -0
  257. package/dist/cli/written-flags.cjs.map +1 -0
  258. package/dist/cli/written-flags.mjs +77 -0
  259. package/dist/cli/written-flags.mjs.map +1 -0
  260. package/dist/domain/cause-secrets.cjs +31 -16
  261. package/dist/domain/cause-secrets.cjs.map +1 -1
  262. package/dist/domain/cause-secrets.mjs +31 -16
  263. package/dist/domain/cause-secrets.mjs.map +1 -1
  264. package/dist/domain/errors.cjs +3 -0
  265. package/dist/domain/errors.cjs.map +1 -1
  266. package/dist/domain/errors.mjs +3 -0
  267. package/dist/domain/errors.mjs.map +1 -1
  268. package/dist/domain/location-text.cjs +15 -0
  269. package/dist/domain/location-text.cjs.map +1 -0
  270. package/dist/domain/location-text.mjs +13 -0
  271. package/dist/domain/location-text.mjs.map +1 -0
  272. package/dist/domain/openapi/document-places.cjs +55 -0
  273. package/dist/domain/openapi/document-places.cjs.map +1 -0
  274. package/dist/domain/openapi/document-places.mjs +53 -0
  275. package/dist/domain/openapi/document-places.mjs.map +1 -0
  276. package/dist/domain/output-fixes.cjs +8 -2
  277. package/dist/domain/output-fixes.cjs.map +1 -1
  278. package/dist/domain/output-fixes.mjs +8 -2
  279. package/dist/domain/output-fixes.mjs.map +1 -1
  280. package/dist/domain/terminal-text.cjs +31 -0
  281. package/dist/domain/terminal-text.cjs.map +1 -0
  282. package/dist/domain/terminal-text.mjs +29 -0
  283. package/dist/domain/terminal-text.mjs.map +1 -0
  284. package/dist/domain/warnings.cjs +1 -0
  285. package/dist/domain/warnings.cjs.map +1 -1
  286. package/dist/domain/warnings.mjs +1 -0
  287. package/dist/domain/warnings.mjs.map +1 -1
  288. package/dist/index.d.cts +29 -18
  289. package/dist/index.d.mts +29 -18
  290. package/dist/index.d.ts +29 -18
  291. package/package.json +1 -1
  292. package/src/adapters/node-file-system/node-file-system.ts +14 -1
  293. package/src/adapters/pipe-safe-writer/pipe-safe-writer.ts +29 -0
  294. package/src/adapters/redocly-loader/bundled-mapping-copies.ts +7 -42
  295. package/src/adapters/redocly-loader/component-schemas.ts +19 -0
  296. package/src/adapters/redocly-loader/mapping-schema-names.ts +25 -0
  297. package/src/adapters/redocly-loader/query-document-names.ts +79 -0
  298. package/src/adapters/redocly-loader/query-named-components.ts +200 -0
  299. package/src/adapters/redocly-loader/redocly-config-source.ts +11 -1
  300. package/src/adapters/redocly-loader/redocly-schema-loader.ts +63 -17
  301. package/src/adapters/redocly-loader/ref-access.ts +32 -5
  302. package/src/adapters/redocly-loader/ref-holders.ts +75 -14
  303. package/src/adapters/redocly-loader/remote-fetch.ts +37 -2
  304. package/src/adapters/redocly-loader/remote-node-limit.ts +44 -4
  305. package/src/adapters/redocly-loader/schema-source.ts +15 -3
  306. package/src/adapters/terminal-logger/terminal-logger.ts +10 -4
  307. package/src/api/cwd-option.ts +76 -0
  308. package/src/api/default-ports.ts +33 -10
  309. package/src/api/document-refs.ts +29 -1
  310. package/src/api/document-run.ts +7 -32
  311. package/src/api/legacy-utils.ts +1 -1
  312. package/src/api/openapi-ts.ts +20 -4
  313. package/src/api/option-errors.ts +22 -0
  314. package/src/api/ref-limit-options.ts +69 -0
  315. package/src/api/transform-schema.ts +20 -5
  316. package/src/application/ports/file-system.ts +8 -0
  317. package/src/application/ports/redocly-config-source.ts +5 -0
  318. package/src/application/transform/declared-value-types.ts +42 -0
  319. package/src/application/transform/document/document.ts +4 -2
  320. package/src/application/transform/document/exploded-query-values.ts +88 -0
  321. package/src/application/transform/document/header.ts +25 -5
  322. package/src/application/transform/document/parameter.ts +4 -4
  323. package/src/application/transform/document/parameters.ts +45 -10
  324. package/src/application/transform/document/path-item.ts +3 -3
  325. package/src/application/transform/document/path-template-key.ts +152 -0
  326. package/src/application/transform/document/path-template-refs.ts +127 -0
  327. package/src/application/transform/document/paths-enum.ts +23 -9
  328. package/src/application/transform/document/paths.ts +53 -123
  329. package/src/application/transform/document/webhooks.ts +18 -5
  330. package/src/application/transform/footer/document-footer.ts +18 -8
  331. package/src/application/transform/helper-types.ts +4 -4
  332. package/src/application/transform/ref-pointer/generated-location.ts +1 -1
  333. package/src/application/transform/ref-pointer/generated-shape.ts +115 -83
  334. package/src/application/transform/ref-pointer/inline-cycles.ts +1 -1
  335. package/src/application/transform/ref-pointer/located-node.ts +38 -0
  336. package/src/application/transform/ref-pointer/original-index.ts +106 -20
  337. package/src/application/transform/ref-pointer/pointer-type.ts +1 -1
  338. package/src/application/transform/ref-pointer/pointer-walk.ts +82 -8
  339. package/src/application/transform/ref-pointer/property-shape.ts +106 -0
  340. package/src/application/transform/ref-pointer/typed-walk.ts +143 -29
  341. package/src/application/transform/schema/access-flags.ts +5 -2
  342. package/src/application/transform/schema/index-signature-type.ts +31 -0
  343. package/src/application/transform/schema/input-location.ts +35 -0
  344. package/src/application/transform/schema/object-type.ts +18 -8
  345. package/src/application/transform/schema/schema-transform.ts +2 -1
  346. package/src/application/transform/schema/unevaluated-properties.ts +4 -44
  347. package/src/cli/api-logger.ts +17 -0
  348. package/src/cli/api-settings.ts +12 -20
  349. package/src/cli/api-writes.ts +11 -3
  350. package/src/cli/cli-arguments.ts +57 -92
  351. package/src/cli/cli-dependencies.ts +7 -2
  352. package/src/cli/cli-errors.ts +23 -0
  353. package/src/cli/cli-flag-names.ts +99 -0
  354. package/src/cli/cli-output.ts +31 -16
  355. package/src/cli/main.ts +12 -5
  356. package/src/cli/redocly-apis.ts +56 -20
  357. package/src/cli/ref-limits.ts +21 -2
  358. package/src/cli/run-cli.ts +39 -7
  359. package/src/cli/written-flags.ts +131 -0
  360. package/src/domain/cause-secrets.ts +59 -25
  361. package/src/domain/errors.ts +3 -0
  362. package/src/domain/location-text.ts +27 -0
  363. package/src/domain/openapi/document-places.ts +78 -0
  364. package/src/domain/output-fixes.ts +9 -2
  365. package/src/domain/terminal-text.ts +44 -0
  366. package/src/domain/warnings.ts +1 -0
@@ -1,5 +1,19 @@
1
1
  import { isRawBinarySchema } from "../../../domain/openapi/binary-content.js";
2
2
  import type { RefResolver, SchemaOptions } from "../schema/schema-context.js";
3
+ import {
4
+ childLocation,
5
+ followLocated,
6
+ isJsonObject,
7
+ type JsonObject,
8
+ type LocatedNode,
9
+ } from "./located-node.js";
10
+ import {
11
+ hasKeptProperties,
12
+ isExcludedProperty,
13
+ isMarkedProperty,
14
+ isNullableSchema,
15
+ isOptionalProperty,
16
+ } from "./property-shape.js";
3
17
 
4
18
  /**
5
19
  * What the generated type of a schema has under a key, read from the schema itself. It answers the
@@ -8,14 +22,27 @@ import type { RefResolver, SchemaOptions } from "../schema/schema-context.js";
8
22
  */
9
23
 
10
24
  export type GeneratedMember =
11
- | { readonly kind: "property"; readonly node: unknown; readonly isOptional: boolean }
12
- /** An index signature; `node` is undefined when its value type is `unknown`. */
13
- | { readonly kind: "index"; readonly node: unknown }
25
+ | {
26
+ readonly kind: "property";
27
+ readonly node: unknown;
28
+ readonly location: string | undefined;
29
+ readonly isOptional: boolean;
30
+ /** `$Read<T>` or `$Write<T>` (`isMarkedProperty`): no member but the marker's own. */
31
+ readonly isMarked: boolean;
32
+ }
33
+ /**
34
+ * An index signature; `node` is undefined when its value type is `unknown`. `isOtherType`: the
35
+ * type read is not the type of the node the key names (`indexMember`).
36
+ */
37
+ | {
38
+ readonly kind: "index";
39
+ readonly node: unknown;
40
+ readonly location: string | undefined;
41
+ readonly isOtherType: boolean;
42
+ }
14
43
  | { readonly kind: "missing" }
15
44
  | { readonly kind: "opaque" };
16
45
 
17
- type JsonObject = Readonly<Record<string, unknown>>;
18
-
19
46
  const OPAQUE_KEYS = ["not", "enum", "const", "$ref"] as const;
20
47
  /** How deep `allOf`/`anyOf`/`oneOf` members are read; deeper shapes count as opaque. */
21
48
  const MAX_DEPTH = 8;
@@ -23,23 +50,6 @@ const INDEX_RE = /^\d+$/;
23
50
  const MISSING: GeneratedMember = { kind: "missing" };
24
51
  const OPAQUE: GeneratedMember = { kind: "opaque" };
25
52
 
26
- export function isJsonObject(value: unknown): value is JsonObject {
27
- return typeof value === "object" && value !== null && !Array.isArray(value);
28
- }
29
-
30
- /** The schema a node stands for: a `$ref` is followed to its target. */
31
- export function followRefs(node: unknown, refs: RefResolver): unknown {
32
- return isJsonObject(node) && typeof node.$ref === "string" ? refs.resolve(node.$ref) : node;
33
- }
34
-
35
- /** `nullable: true` or a `type` list with `null`: the generated type includes `null`. */
36
- export function isNullableSchema(node: unknown): boolean {
37
- if (!isJsonObject(node)) {
38
- return false;
39
- }
40
- return node.nullable === true || (Array.isArray(node.type) && node.type.includes("null"));
41
- }
42
-
43
53
  function typeNames(node: JsonObject): readonly unknown[] {
44
54
  return Array.isArray(node.type) ? node.type : [node.type];
45
55
  }
@@ -90,39 +100,71 @@ function isBuiltInMember(key: string, prototype: object): boolean {
90
100
  return key in prototype;
91
101
  }
92
102
 
93
- function indexMember(node: JsonObject, options: SchemaOptions): GeneratedMember | null {
94
- const { additionalProperties: values, patternProperties: patterns } = node;
95
- if (isJsonObject(patterns) && Object.keys(patterns).length > 0) {
96
- return OPAQUE;
103
+ /** `additionalProperties: true` or `{}` (also as a pattern's schema): a value of `unknown`. */
104
+ function isUnknownValue(value: unknown): boolean {
105
+ return value === true || (isJsonObject(value) && Object.keys(value).length === 0);
106
+ }
107
+
108
+ /** The value schemas of an index signature none of whose values is `unknown`, located. */
109
+ function typedIndexValues(owner: LocatedNode & { node: JsonObject }): LocatedNode[] {
110
+ const { additionalProperties: values, patternProperties: patterns } = owner.node;
111
+ const located: LocatedNode[] = [];
112
+ if (isJsonObject(values)) {
113
+ located.push({ node: values, location: childLocation(owner.location, "additionalProperties") });
97
114
  }
98
- if (isJsonObject(values) && Object.keys(values).length > 0) {
99
- return { kind: "index", node: values };
115
+ for (const [pattern, node] of isJsonObject(patterns) ? Object.entries(patterns) : []) {
116
+ located.push({ node, location: childLocation(owner.location, "patternProperties", pattern) });
100
117
  }
101
- const isImplicit = values === true || (isJsonObject(values) && Object.keys(values).length === 0);
102
- return isImplicit || (!values && options.additionalProperties)
103
- ? { kind: "index", node: undefined }
104
- : null;
118
+ return located;
105
119
  }
106
120
 
107
- function isOptionalProperty(node: JsonObject, key: string, options: SchemaOptions): boolean {
108
- const required = Array.isArray(node.required) ? node.required : undefined;
109
- const property = (node.properties as JsonObject)[key];
110
- const hasDefault = isJsonObject(property) && property.default !== undefined;
111
- const isRequired =
112
- required?.includes(key) === true ||
113
- (required === undefined && options.propertiesRequiredByDefault) ||
114
- (hasDefault && options.defaultNonNullable);
115
- return !isRequired;
121
+ /**
122
+ * The index signature of an object schema, or null without one. Its type is the union of its
123
+ * value schemas' types (`unknown` if one is `unknown`); a union of several counts as opaque. It
124
+ * also holds the kept property types (`withPropertyTypes`), and a key that names a property
125
+ * `--exclude-deprecated` left out reads it instead of that property: both are `isOtherType`.
126
+ */
127
+ function indexMember(
128
+ owner: LocatedNode & { node: JsonObject },
129
+ isExcludedKey: boolean,
130
+ input: MemberInput,
131
+ ): GeneratedMember | null {
132
+ const { additionalProperties: values, patternProperties: patterns } = owner.node;
133
+ const patternValues = isJsonObject(patterns) ? Object.values(patterns) : [];
134
+ const isUnknown =
135
+ isUnknownValue(values) ||
136
+ patternValues.some(isUnknownValue) ||
137
+ (!values && input.options.additionalProperties);
138
+ if (isUnknown) {
139
+ return { kind: "index", node: undefined, location: undefined, isOtherType: isExcludedKey };
140
+ }
141
+ const typed = typedIndexValues(owner);
142
+ const [only] = typed;
143
+ if (only === undefined || typed.length > 1) {
144
+ return only === undefined ? null : OPAQUE;
145
+ }
146
+ const isOtherType = isExcludedKey || hasKeptProperties(owner.node, input.options, input.refs);
147
+ return { kind: "index", ...only, isOtherType };
116
148
  }
117
149
 
118
- function objectMember(node: JsonObject, key: string, options: SchemaOptions): GeneratedMember {
150
+ function objectMember(
151
+ owner: LocatedNode & { node: JsonObject },
152
+ key: string,
153
+ input: MemberInput,
154
+ ): GeneratedMember {
155
+ const { options } = input;
156
+ const { node } = owner;
119
157
  const properties = isJsonObject(node.properties) ? node.properties : {};
120
- if (Object.hasOwn(properties, key)) {
121
- const property = properties[key];
122
- const isExcluded = options.excludeDeprecated && isJsonObject(property) && property.deprecated;
123
- return isExcluded || isJsonObject(node.discriminator)
124
- ? OPAQUE
125
- : { kind: "property", node: property, isOptional: isOptionalProperty(node, key, options) };
158
+ const isExcludedKey =
159
+ Object.hasOwn(properties, key) && isExcludedProperty(properties[key], options, input.refs);
160
+ if (Object.hasOwn(properties, key) && !isExcludedKey) {
161
+ if (isJsonObject(node.discriminator)) {
162
+ return OPAQUE;
163
+ }
164
+ const location = childLocation(owner.location, "properties", key);
165
+ const isOptional = isOptionalProperty(owner, key, options);
166
+ const isMarked = isMarkedProperty(properties[key], options, input.refs);
167
+ return { kind: "property", node: properties[key], location, isOptional, isMarked };
126
168
  }
127
169
  // `unevaluatedProperties` adds an index signature with its fix, so it counts as opaque too.
128
170
  const isUnknownShape =
@@ -131,38 +173,23 @@ function objectMember(node: JsonObject, key: string, options: SchemaOptions): Ge
131
173
  return OPAQUE;
132
174
  }
133
175
  return hasObjectKeywords(node)
134
- ? (indexMember(node, options) ?? MISSING)
176
+ ? (indexMember(owner, isExcludedKey, input) ?? MISSING)
135
177
  : emptyObjectMember(node, options);
136
178
  }
137
179
 
138
- /** Whether a value is there: `present`, `absent` (may be `undefined` or `null`) or `unknown`. */
139
- export type Presence = "present" | "absent" | "unknown";
140
-
141
- /** The presence of a value of `schema` itself: `absent` when its type includes `null`. */
142
- export function schemaPresence(schema: unknown, refs: RefResolver): Presence {
143
- return isNullableSchema(followRefs(schema, refs)) ? "absent" : "present";
144
- }
145
-
146
- /** The presence of property `key` of `schema`: optional or nullable is `absent`. */
147
- export function propertyPresence(
148
- schema: unknown,
149
- key: string,
150
- options: SchemaOptions,
151
- refs: RefResolver,
152
- ): Presence {
153
- const node = followRefs(schema, refs);
154
- const properties = isJsonObject(node) && isJsonObject(node.properties) ? node.properties : {};
155
- if (!isJsonObject(node) || !Object.hasOwn(properties, key)) {
156
- return "unknown";
157
- }
158
- return isOptionalProperty(node, key, options) ? "absent" : schemaPresence(properties[key], refs);
159
- }
160
-
161
180
  function membersOf(node: JsonObject, keyword: string): readonly unknown[] {
162
181
  const members = node[keyword];
163
182
  return Array.isArray(members) ? members : [];
164
183
  }
165
184
 
185
+ /** The members of a composition keyword with their locations. */
186
+ function locatedMembers(owner: LocatedNode & { node: JsonObject }, keyword: string): LocatedNode[] {
187
+ return membersOf(owner.node, keyword).map((node, index) => ({
188
+ node,
189
+ location: childLocation(owner.location, keyword, String(index)),
190
+ }));
191
+ }
192
+
166
193
  function withoutComposition(node: JsonObject): JsonObject {
167
194
  const { allOf: _allOf, anyOf: _anyOf, oneOf: _oneOf, ...own } = node;
168
195
  return own;
@@ -178,8 +205,13 @@ function hasOwnObjectType(own: JsonObject): boolean {
178
205
  * `anyOf` or `oneOf` alone is a union: a key is missing if one member misses it. A mix of both
179
206
  * is written in more than one way (`anyof-properties`), so it counts as opaque.
180
207
  */
181
- function composedMember(node: JsonObject, key: string, input: MemberInput): GeneratedMember {
182
- const variants = [...membersOf(node, "anyOf"), ...membersOf(node, "oneOf")];
208
+ function composedMember(
209
+ owner: LocatedNode & { node: JsonObject },
210
+ key: string,
211
+ input: MemberInput,
212
+ ): GeneratedMember {
213
+ const { node } = owner;
214
+ const variants = [...locatedMembers(owner, "anyOf"), ...locatedMembers(owner, "oneOf")];
183
215
  const own = withoutComposition(node);
184
216
  const hasOwn = hasOwnObjectType(own);
185
217
  if (variants.length > 0) {
@@ -187,7 +219,8 @@ function composedMember(node: JsonObject, key: string, input: MemberInput): Gene
187
219
  const members = variants.map((variant) => memberAt(variant, key, input));
188
220
  return isAlone && members.some((member) => member.kind === "missing") ? MISSING : OPAQUE;
189
221
  }
190
- const parts = [...membersOf(node, "allOf"), ...(hasOwn ? [own] : [])];
222
+ const ownPart = { node: own, location: owner.location };
223
+ const parts = [...locatedMembers(owner, "allOf"), ...(hasOwn ? [ownPart] : [])];
191
224
  return intersectionMember(parts.map((part) => memberAt(part, key, input)));
192
225
  }
193
226
 
@@ -216,23 +249,22 @@ interface MemberInput {
216
249
  readonly depth: number;
217
250
  }
218
251
 
219
- function memberAt(schema: unknown, key: string, input: MemberInput): GeneratedMember {
220
- const node = followRefs(schema, input.refs);
252
+ function memberAt(schema: LocatedNode, key: string, input: MemberInput): GeneratedMember {
253
+ const followed = followLocated(schema, input.refs);
254
+ const { node } = followed;
221
255
  if (!isJsonObject(node) || OPAQUE_KEYS.some((name) => name in node) || input.depth > MAX_DEPTH) {
222
256
  return OPAQUE;
223
257
  }
258
+ const owner = { ...followed, node };
224
259
  if (isNullableSchema(node)) {
225
260
  // Every key of `T | null` is an error, unless `T` is unknown (then the type is `unknown`).
226
261
  return isObjectShape(node) || isArrayShape(node) ? MISSING : OPAQUE;
227
262
  }
228
- if (input.options.readWriteMarkers) {
229
- return OPAQUE;
230
- }
231
263
  if ("allOf" in node || "anyOf" in node || "oneOf" in node) {
232
- return composedMember(node, key, { ...input, depth: input.depth + 1 });
264
+ return composedMember(owner, key, { ...input, depth: input.depth + 1 });
233
265
  }
234
266
  if (isObjectShape(node)) {
235
- return objectMember(node, key, input.options);
267
+ return objectMember(owner, key, input);
236
268
  }
237
269
  if (isArrayShape(node)) {
238
270
  return INDEX_RE.test(key) || isBuiltInMember(key, []) ? OPAQUE : MISSING;
@@ -266,7 +298,7 @@ function primitiveMember(node: JsonObject, key: string): GeneratedMember {
266
298
 
267
299
  /** The member `key` of the type generated for `schema` (a `$ref` is followed first). */
268
300
  export function generatedMember(
269
- schema: unknown,
301
+ schema: LocatedNode,
270
302
  key: string,
271
303
  options: SchemaOptions,
272
304
  refs: RefResolver,
@@ -1,5 +1,5 @@
1
1
  import type { RefResolver, SchemaOptions } from "../schema/schema-context.js";
2
- import { isJsonObject } from "./generated-shape.js";
2
+ import { isJsonObject } from "./located-node.js";
3
3
  import { pointerNode, refPointerOf } from "./pointer-walk.js";
4
4
  import { typedWalk } from "./typed-walk.js";
5
5
 
@@ -0,0 +1,38 @@
1
+ import { appendPointer } from "../../../domain/openapi/json-pointer.js";
2
+ import type { RefResolver } from "../schema/schema-context.js";
3
+
4
+ /** Document nodes as the `$ref` pointer walks read them: with their place in the document. */
5
+
6
+ export type JsonObject = Readonly<Record<string, unknown>>;
7
+
8
+ /**
9
+ * A schema node and its JSON Pointer in the document. The generator writes the type of a schema
10
+ * reached by a `$ref` at the target, and the location decides whether a property with a `default`
11
+ * is required (`isInputLocation`). Undefined for a node that is not in the document.
12
+ */
13
+ export interface LocatedNode {
14
+ readonly node: unknown;
15
+ readonly location: string | undefined;
16
+ }
17
+
18
+ export function isJsonObject(value: unknown): value is JsonObject {
19
+ return typeof value === "object" && value !== null && !Array.isArray(value);
20
+ }
21
+
22
+ /** The schema a node stands for: a `$ref` is followed to its target. */
23
+ export function followRefs(node: unknown, refs: RefResolver): unknown {
24
+ return isJsonObject(node) && typeof node.$ref === "string" ? refs.resolve(node.$ref) : node;
25
+ }
26
+
27
+ /** `followRefs` with the location: a `$ref` is followed to its target and the target's pointer. */
28
+ export function followLocated(located: LocatedNode, refs: RefResolver): LocatedNode {
29
+ const { node } = located;
30
+ return isJsonObject(node) && typeof node.$ref === "string"
31
+ ? { node: refs.resolve(node.$ref), location: node.$ref }
32
+ : located;
33
+ }
34
+
35
+ /** The location of a child of a node at `location`, or undefined outside the document. */
36
+ export function childLocation(location: string | undefined, ...segments: string[]) {
37
+ return location === undefined ? undefined : appendPointer(location, segments);
38
+ }
@@ -1,11 +1,15 @@
1
1
  import type { RefResolver, SchemaOptions } from "../schema/schema-context.js";
2
- import { followRefs, generatedMember, isJsonObject } from "./generated-shape.js";
2
+ import { generatedMember } from "./generated-shape.js";
3
+ import { childLocation, followLocated, isJsonObject } from "./located-node.js";
3
4
  import {
5
+ type ContentForm,
6
+ headerParameterContentForm,
7
+ isExcludedOperation,
4
8
  isOptionalHeader,
5
9
  isOptionalRequestBody,
6
10
  isParameterList,
7
11
  isTypedAsSchema,
8
- leadingNode,
12
+ leadingLocated,
9
13
  leadingSegmentsOf,
10
14
  type RefPointer,
11
15
  startsInSchema,
@@ -14,14 +18,18 @@ import {
14
18
  /**
15
19
  * Whether the type the original wrote for a `$ref` (`refType`: every segment indexed by name,
16
20
  * `properties` skipped) surely fails to compile. It walks the document as TypeScript walks the
17
- * generated types and answers true only where TypeScript reports an error for sure; where the
18
- * answer depends on a shape it does not model, it answers false, so that output stays as it was.
21
+ * generated types and answers true only where TypeScript reports an error for sure, or where the
22
+ * type compiles but is read through an index signature that is not the target's type alone
23
+ * (`isOtherType`); where the answer depends on a shape it does not model, it answers false, so
24
+ * that output stays as it was.
19
25
  */
20
26
 
21
27
  type Step = "fails" | "compiles" | "continue";
22
28
 
23
29
  interface OriginalWalk {
24
30
  readonly node: unknown;
31
+ /** The node's JSON Pointer (`LocatedNode`). */
32
+ readonly location: string | undefined;
25
33
  readonly isSchema: boolean;
26
34
  }
27
35
 
@@ -35,57 +43,135 @@ function schemaStep(walk: OriginalWalk, segment: string, isLast: boolean, input:
35
43
  if (segment === "properties") {
36
44
  return { step: "continue" as Step, walk };
37
45
  }
38
- const member = generatedMember(walk.node, segment, input.options, input.refs);
39
- if (member.kind === "missing") {
46
+ const member = generatedMember(walk, segment, input.options, input.refs);
47
+ // Such an index signature compiles, but its type is not the target's alone.
48
+ if (member.kind === "missing" || (member.kind === "index" && member.isOtherType)) {
40
49
  return { step: "fails" as Step, walk };
41
50
  }
42
51
  if (member.kind === "opaque") {
43
52
  return { step: "compiles" as Step, walk };
44
53
  }
45
54
  const isAbsentValue = member.kind === "index" && member.node === undefined;
46
- const isUnsafe = member.kind === "property" ? member.isOptional : isAbsentValue;
55
+ const isUnsafe =
56
+ member.kind === "property" ? member.isOptional || member.isMarked : isAbsentValue;
47
57
  return {
48
58
  step: (isUnsafe && !isLast ? "fails" : "continue") as Step,
49
- walk: { ...walk, node: member.node },
59
+ walk: { ...walk, node: member.node, location: member.location },
50
60
  };
51
61
  }
52
62
 
53
63
  function containerStep(walk: OriginalWalk, index: number, input: WalkInput) {
54
64
  const segment = input.pointer.segments[index] as string;
55
65
  const isLast = index === input.pointer.segments.length - 1;
66
+ if (isExcludedOperation(input.pointer, index, walk.node, input)) {
67
+ return { step: "fails" as Step, walk };
68
+ }
56
69
  const isOptional =
57
70
  (segment === "requestBody" && isOptionalRequestBody(walk.node, input.refs)) ||
58
71
  isOptionalHeader(input.pointer, index, walk.node);
59
72
  if (isOptional && !isLast) {
60
73
  return { step: "fails" as Step, walk };
61
74
  }
62
- const child = isJsonObject(walk.node) ? followRefs(walk.node[segment], input.refs) : undefined;
75
+ const child = followLocated(
76
+ {
77
+ node: isJsonObject(walk.node) ? walk.node[segment] : undefined,
78
+ location: childLocation(walk.location, segment),
79
+ },
80
+ input.refs,
81
+ );
63
82
  return {
64
- step: (child === undefined ? "compiles" : "continue") as Step,
65
- walk: { ...walk, node: child },
83
+ step: (child.node === undefined ? "compiles" : "continue") as Step,
84
+ walk: { ...walk, ...child },
66
85
  };
67
86
  }
68
87
 
88
+ /** The schema of the first media type of a `content` map, `$ref`s followed. */
89
+ function firstMediaTypeSchema(walk: OriginalWalk, refs: RefResolver): OriginalWalk | null {
90
+ const content = isJsonObject(walk.node) ? walk.node.content : undefined;
91
+ if (!isJsonObject(content)) {
92
+ return null;
93
+ }
94
+ const [mediaType] = Object.keys(content);
95
+ if (mediaType === undefined) {
96
+ return null;
97
+ }
98
+ const location = childLocation(childLocation(walk.location, "content"), mediaType);
99
+ const entry = followLocated({ node: content[mediaType], location }, refs);
100
+ return ownSchema({ ...entry, isSchema: false }, refs);
101
+ }
102
+
103
+ /** The schema a header or parameter is typed by, `$ref`s followed. */
104
+ function ownSchema(walk: OriginalWalk, refs: RefResolver): OriginalWalk {
105
+ const schema = isJsonObject(walk.node) ? walk.node.schema : undefined;
106
+ const location = childLocation(walk.location, "schema");
107
+ return { ...followLocated({ node: schema, location }, refs), isSchema: true };
108
+ }
109
+
110
+ /** The schema whose type a header or parameter is, when not its media type members. */
111
+ function contentSchema(
112
+ walk: OriginalWalk,
113
+ form: Exclude<ContentForm, "media-type-members">,
114
+ refs: RefResolver,
115
+ ): OriginalWalk | null {
116
+ switch (form) {
117
+ case "first-media-type":
118
+ return firstMediaTypeSchema(walk, refs);
119
+ case "schema":
120
+ return ownSchema(walk, refs);
121
+ case "string":
122
+ return null;
123
+ }
124
+ }
125
+
126
+ /**
127
+ * The original indexes the `content` of a header or parameter by name. The media type members
128
+ * have no `content` unless a media type is named so, and `string` and `unknown` (no media type)
129
+ * have none; the schema of the first media type, or the `schema` next to `content`, is walked on.
130
+ */
131
+ function contentStep(walk: OriginalWalk, form: ContentForm, isLast: boolean, input: WalkInput) {
132
+ const content = isJsonObject(walk.node) ? walk.node.content : undefined;
133
+ if (form === "media-type-members") {
134
+ const hasMember = isJsonObject(content) && Object.hasOwn(content, "content");
135
+ return { step: (hasMember ? "compiles" : "fails") as Step, walk };
136
+ }
137
+ const schema = contentSchema(walk, form, input.refs);
138
+ return schema === null
139
+ ? { step: "fails" as Step, walk }
140
+ : schemaStep(schema, "content", isLast, input);
141
+ }
142
+
143
+ /**
144
+ * A step outside a schema: a header's or parameter's `content`, a schema's container, or another.
145
+ */
146
+ function documentStep(walk: OriginalWalk, index: number, input: WalkInput) {
147
+ const segment = input.pointer.segments[index] as string;
148
+ const isLast = index === input.pointer.segments.length - 1;
149
+ const form = headerParameterContentForm(input.pointer, index, walk.node, input.options);
150
+ if (form !== null) {
151
+ return contentStep(walk, form, isLast, input);
152
+ }
153
+ if (isTypedAsSchema(input.pointer, index) && isJsonObject(walk.node)) {
154
+ // The container's type is its schema's type: the segment indexes that type.
155
+ return schemaStep(ownSchema(walk, input.refs), segment, isLast, input);
156
+ }
157
+ return containerStep(walk, index, input);
158
+ }
159
+
69
160
  /** True when the original type of the `$ref` does not compile for sure. */
70
161
  export function originalIndexFails(input: WalkInput): boolean {
71
162
  const { segments } = input.pointer;
72
163
  let walk: OriginalWalk = {
73
- node: leadingNode(input.pointer, input.refs),
164
+ ...leadingLocated(input.pointer, input.refs),
74
165
  isSchema: startsInSchema(input.pointer),
75
166
  };
76
167
  for (let index = leadingSegmentsOf(input.pointer); index < segments.length; index++) {
77
- const segment = segments[index] as string;
78
- const isLast = index === segments.length - 1;
79
168
  if (!walk.isSchema && isParameterList(input.pointer, index)) {
80
169
  return true;
81
170
  }
82
- if (!walk.isSchema && isTypedAsSchema(input.pointer, index) && isJsonObject(walk.node)) {
83
- // The container's type is its schema's type: the segment indexes that type.
84
- walk = { node: followRefs(walk.node.schema, input.refs), isSchema: true };
85
- }
171
+ const isLast = index === segments.length - 1;
86
172
  const result = walk.isSchema
87
- ? schemaStep(walk, segment, isLast, input)
88
- : containerStep(walk, index, input);
173
+ ? schemaStep(walk, segments[index] as string, isLast, input)
174
+ : documentStep(walk, index, input);
89
175
  if (result.step !== "continue") {
90
176
  return result.step === "fails";
91
177
  }
@@ -4,8 +4,8 @@ import { FIX } from "../../../domain/output-fixes.js";
4
4
  import { InvalidRefError, refType } from "../ref-type.js";
5
5
  import type { SchemaRequest } from "../schema/schema-rule.js";
6
6
  import { generatedLocationOf } from "./generated-location.js";
7
- import { isJsonObject } from "./generated-shape.js";
8
7
  import { hasInlineCycle } from "./inline-cycles.js";
8
+ import { isJsonObject } from "./located-node.js";
9
9
  import { originalIndexFails } from "./original-index.js";
10
10
  import { leadingSegmentsOf, pointerNode, type RefPointer, refPointerOf } from "./pointer-walk.js";
11
11
  import { typedWalk } from "./typed-walk.js";
@@ -1,6 +1,15 @@
1
- import { parseRefPointer } from "../../../domain/openapi/json-pointer.js";
2
- import type { RefResolver } from "../schema/schema-context.js";
3
- import { followRefs, isJsonObject } from "./generated-shape.js";
1
+ import { placeOf } from "../../../domain/openapi/document-places.js";
2
+ import { parseRefPointer, ROOT_POINTER } from "../../../domain/openapi/json-pointer.js";
3
+ import { QUERYSTRING_LOCATION } from "../../../domain/openapi/parameter-object.js";
4
+ import { FIX } from "../../../domain/output-fixes.js";
5
+ import type { RefResolver, SchemaOptions } from "../schema/schema-context.js";
6
+ import {
7
+ childLocation,
8
+ followLocated,
9
+ followRefs,
10
+ isJsonObject,
11
+ type LocatedNode,
12
+ } from "./located-node.js";
4
13
 
5
14
  /** The parts of a `$ref` pointer that both the original and the new types walk. */
6
15
 
@@ -27,13 +36,18 @@ export function refPointerOf(ref: string): RefPointer | null {
27
36
  return rootSegment === undefined ? null : { rootSegment, segments };
28
37
  }
29
38
 
30
- /** The document node at the end of the leading segments, `$ref`s followed. */
31
- export function leadingNode(pointer: RefPointer, refs: RefResolver): unknown {
32
- let node = refs.resolve(`#/${pointer.rootSegment}`);
39
+ /** The document node at the end of the leading segments, `$ref`s followed, with its location. */
40
+ export function leadingLocated(pointer: RefPointer, refs: RefResolver): LocatedNode {
41
+ let located: LocatedNode = {
42
+ node: refs.resolve(`#/${pointer.rootSegment}`),
43
+ location: childLocation(ROOT_POINTER, pointer.rootSegment),
44
+ };
33
45
  for (const segment of pointer.segments.slice(0, leadingSegmentsOf(pointer))) {
34
- node = isJsonObject(node) ? followRefs(node[segment], refs) : undefined;
46
+ const { node, location } = located;
47
+ const child = isJsonObject(node) ? node[segment] : undefined;
48
+ located = followLocated({ node: child, location: childLocation(location, segment) }, refs);
35
49
  }
36
- return node;
50
+ return located;
37
51
  }
38
52
 
39
53
  /** The node at the whole pointer, without following a `$ref` at its end. */
@@ -62,6 +76,47 @@ export function isTypedAsSchema(pointer: RefPointer, index: number): boolean {
62
76
  return owner === "content" || owner === "headers" || isComponentParameter;
63
77
  }
64
78
 
79
+ /**
80
+ * How the generated type of a header or component parameter holds its `content` (header.ts,
81
+ * parameter.ts): one member per media type, the type of the first media type, `string` (a
82
+ * parameter without the `parameter-header-content` fix), or not at all (a `schema` wins).
83
+ */
84
+ export type ContentForm = "media-type-members" | "first-media-type" | "string" | "schema";
85
+
86
+ /**
87
+ * The form of the `content` at `index` when it belongs to a header or a component parameter; null
88
+ * for any other segment. An `in: querystring` parameter is typed by its `content` even next to a
89
+ * `schema`.
90
+ */
91
+ export function headerParameterContentForm(
92
+ pointer: RefPointer,
93
+ index: number,
94
+ owner: unknown,
95
+ options: SchemaOptions,
96
+ ): ContentForm | null {
97
+ const isHeader = pointer.segments[index - 2] === "headers";
98
+ const isComponentParameter =
99
+ pointer.rootSegment === "components" && index === 2 && pointer.segments[0] === "parameters";
100
+ const isOwnContent = pointer.segments[index] === "content" && (isHeader || isComponentParameter);
101
+ if (!isOwnContent || !isJsonObject(owner)) {
102
+ return null;
103
+ }
104
+ const isFixed = options.fixes.has(FIX.PARAMETER_HEADER_CONTENT);
105
+ if (isHeader) {
106
+ if (owner.schema) {
107
+ return "schema";
108
+ }
109
+ return isFixed ? "first-media-type" : "media-type-members";
110
+ }
111
+ if (owner.in === QUERYSTRING_LOCATION) {
112
+ return "first-media-type";
113
+ }
114
+ if (owner.schema !== undefined) {
115
+ return "schema";
116
+ }
117
+ return isFixed ? "first-media-type" : "string";
118
+ }
119
+
65
120
  /**
66
121
  * Whether the segment at `index` is an operation's or path item's `parameters` list, indexed by
67
122
  * position next. The generated type groups parameters by `in` (`query`, `path`), so it has no
@@ -86,6 +141,25 @@ export function isOptionalHeader(pointer: RefPointer, index: number, headers: un
86
141
  return isJsonObject(header) && header.$ref === undefined && header.required !== true;
87
142
  }
88
143
 
144
+ /**
145
+ * Whether the segment at `index` names an operation that `--exclude-deprecated` leaves out: the
146
+ * path item types it `never`, which has no member to index (`isIncludedOperation`).
147
+ */
148
+ export function isExcludedOperation(
149
+ pointer: RefPointer,
150
+ index: number,
151
+ pathItem: unknown,
152
+ input: { readonly options: SchemaOptions; readonly refs: RefResolver },
153
+ ): boolean {
154
+ const segments = [pointer.rootSegment, ...pointer.segments.slice(0, index + 1)];
155
+ if (!input.options.excludeDeprecated || placeOf(segments) !== "operation") {
156
+ return false;
157
+ }
158
+ const segment = pointer.segments[index] as string;
159
+ const operation = isJsonObject(pathItem) ? followRefs(pathItem[segment], input.refs) : undefined;
160
+ return isJsonObject(operation) && Boolean(operation.deprecated);
161
+ }
162
+
89
163
  /** A `requestBody` the operation does not mark `required` is an optional member. */
90
164
  export function isOptionalRequestBody(container: unknown, refs: RefResolver): boolean {
91
165
  if (!isJsonObject(container) || container.requestBody === undefined) {