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

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 (320) hide show
  1. package/CHANGELOG.md +141 -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-named-components.cjs +137 -0
  23. package/dist/adapters/redocly-loader/query-named-components.cjs.map +1 -0
  24. package/dist/adapters/redocly-loader/query-named-components.mjs +134 -0
  25. package/dist/adapters/redocly-loader/query-named-components.mjs.map +1 -0
  26. package/dist/adapters/redocly-loader/redocly-schema-loader.cjs +26 -14
  27. package/dist/adapters/redocly-loader/redocly-schema-loader.cjs.map +1 -1
  28. package/dist/adapters/redocly-loader/redocly-schema-loader.mjs +26 -14
  29. package/dist/adapters/redocly-loader/redocly-schema-loader.mjs.map +1 -1
  30. package/dist/adapters/redocly-loader/ref-access.cjs +16 -3
  31. package/dist/adapters/redocly-loader/ref-access.cjs.map +1 -1
  32. package/dist/adapters/redocly-loader/ref-access.mjs +16 -3
  33. package/dist/adapters/redocly-loader/ref-access.mjs.map +1 -1
  34. package/dist/adapters/redocly-loader/ref-holders.cjs +52 -10
  35. package/dist/adapters/redocly-loader/ref-holders.cjs.map +1 -1
  36. package/dist/adapters/redocly-loader/ref-holders.mjs +52 -11
  37. package/dist/adapters/redocly-loader/ref-holders.mjs.map +1 -1
  38. package/dist/adapters/redocly-loader/remote-fetch.cjs +5 -3
  39. package/dist/adapters/redocly-loader/remote-fetch.cjs.map +1 -1
  40. package/dist/adapters/redocly-loader/remote-fetch.mjs +5 -3
  41. package/dist/adapters/redocly-loader/remote-fetch.mjs.map +1 -1
  42. package/dist/adapters/redocly-loader/remote-node-limit.cjs +17 -3
  43. package/dist/adapters/redocly-loader/remote-node-limit.cjs.map +1 -1
  44. package/dist/adapters/redocly-loader/remote-node-limit.mjs +17 -3
  45. package/dist/adapters/redocly-loader/remote-node-limit.mjs.map +1 -1
  46. package/dist/adapters/redocly-loader/schema-source.cjs +7 -2
  47. package/dist/adapters/redocly-loader/schema-source.cjs.map +1 -1
  48. package/dist/adapters/redocly-loader/schema-source.mjs +8 -3
  49. package/dist/adapters/redocly-loader/schema-source.mjs.map +1 -1
  50. package/dist/adapters/terminal-logger/terminal-logger.cjs +7 -3
  51. package/dist/adapters/terminal-logger/terminal-logger.cjs.map +1 -1
  52. package/dist/adapters/terminal-logger/terminal-logger.mjs +7 -3
  53. package/dist/adapters/terminal-logger/terminal-logger.mjs.map +1 -1
  54. package/dist/api/document-refs.cjs +16 -1
  55. package/dist/api/document-refs.cjs.map +1 -1
  56. package/dist/api/document-refs.mjs +16 -1
  57. package/dist/api/document-refs.mjs.map +1 -1
  58. package/dist/api/document-run.cjs +4 -10
  59. package/dist/api/document-run.cjs.map +1 -1
  60. package/dist/api/document-run.mjs +4 -10
  61. package/dist/api/document-run.mjs.map +1 -1
  62. package/dist/api/openapi-ts.cjs +1 -2
  63. package/dist/api/openapi-ts.cjs.map +1 -1
  64. package/dist/api/openapi-ts.mjs +2 -3
  65. package/dist/api/openapi-ts.mjs.map +1 -1
  66. package/dist/api/ref-limit-options.cjs +63 -0
  67. package/dist/api/ref-limit-options.cjs.map +1 -0
  68. package/dist/api/ref-limit-options.mjs +57 -0
  69. package/dist/api/ref-limit-options.mjs.map +1 -0
  70. package/dist/api/transform-schema.cjs +12 -5
  71. package/dist/api/transform-schema.cjs.map +1 -1
  72. package/dist/api/transform-schema.mjs +12 -5
  73. package/dist/api/transform-schema.mjs.map +1 -1
  74. package/dist/application/transform/declared-value-types.cjs +36 -0
  75. package/dist/application/transform/declared-value-types.cjs.map +1 -0
  76. package/dist/application/transform/declared-value-types.mjs +34 -0
  77. package/dist/application/transform/declared-value-types.mjs.map +1 -0
  78. package/dist/application/transform/document/document.cjs +3 -1
  79. package/dist/application/transform/document/document.cjs.map +1 -1
  80. package/dist/application/transform/document/document.mjs +3 -1
  81. package/dist/application/transform/document/document.mjs.map +1 -1
  82. package/dist/application/transform/document/exploded-query-values.cjs +63 -0
  83. package/dist/application/transform/document/exploded-query-values.cjs.map +1 -0
  84. package/dist/application/transform/document/exploded-query-values.mjs +59 -0
  85. package/dist/application/transform/document/exploded-query-values.mjs.map +1 -0
  86. package/dist/application/transform/document/header.cjs +11 -3
  87. package/dist/application/transform/document/header.cjs.map +1 -1
  88. package/dist/application/transform/document/header.mjs +10 -2
  89. package/dist/application/transform/document/header.mjs.map +1 -1
  90. package/dist/application/transform/document/parameter.cjs +1 -1
  91. package/dist/application/transform/document/parameter.cjs.map +1 -1
  92. package/dist/application/transform/document/parameter.mjs +1 -1
  93. package/dist/application/transform/document/parameter.mjs.map +1 -1
  94. package/dist/application/transform/document/parameters.cjs +23 -5
  95. package/dist/application/transform/document/parameters.cjs.map +1 -1
  96. package/dist/application/transform/document/parameters.mjs +23 -5
  97. package/dist/application/transform/document/parameters.mjs.map +1 -1
  98. package/dist/application/transform/document/path-item.cjs +4 -3
  99. package/dist/application/transform/document/path-item.cjs.map +1 -1
  100. package/dist/application/transform/document/path-item.mjs +4 -4
  101. package/dist/application/transform/document/path-item.mjs.map +1 -1
  102. package/dist/application/transform/document/path-template-key.cjs +84 -0
  103. package/dist/application/transform/document/path-template-key.cjs.map +1 -0
  104. package/dist/application/transform/document/path-template-key.mjs +79 -0
  105. package/dist/application/transform/document/path-template-key.mjs.map +1 -0
  106. package/dist/application/transform/document/path-template-refs.cjs +70 -0
  107. package/dist/application/transform/document/path-template-refs.cjs.map +1 -0
  108. package/dist/application/transform/document/path-template-refs.mjs +67 -0
  109. package/dist/application/transform/document/path-template-refs.mjs.map +1 -0
  110. package/dist/application/transform/document/paths-enum.cjs +7 -6
  111. package/dist/application/transform/document/paths-enum.cjs.map +1 -1
  112. package/dist/application/transform/document/paths-enum.mjs +7 -6
  113. package/dist/application/transform/document/paths-enum.mjs.map +1 -1
  114. package/dist/application/transform/document/paths.cjs +38 -66
  115. package/dist/application/transform/document/paths.cjs.map +1 -1
  116. package/dist/application/transform/document/paths.mjs +36 -66
  117. package/dist/application/transform/document/paths.mjs.map +1 -1
  118. package/dist/application/transform/document/webhooks.cjs +10 -3
  119. package/dist/application/transform/document/webhooks.cjs.map +1 -1
  120. package/dist/application/transform/document/webhooks.mjs +9 -2
  121. package/dist/application/transform/document/webhooks.mjs.map +1 -1
  122. package/dist/application/transform/footer/document-footer.cjs +6 -3
  123. package/dist/application/transform/footer/document-footer.cjs.map +1 -1
  124. package/dist/application/transform/footer/document-footer.mjs +6 -3
  125. package/dist/application/transform/footer/document-footer.mjs.map +1 -1
  126. package/dist/application/transform/helper-types.cjs +3 -3
  127. package/dist/application/transform/helper-types.cjs.map +1 -1
  128. package/dist/application/transform/helper-types.mjs +3 -3
  129. package/dist/application/transform/helper-types.mjs.map +1 -1
  130. package/dist/application/transform/ref-pointer/generated-location.cjs +4 -4
  131. package/dist/application/transform/ref-pointer/generated-location.cjs.map +1 -1
  132. package/dist/application/transform/ref-pointer/generated-location.mjs +1 -1
  133. package/dist/application/transform/ref-pointer/generated-location.mjs.map +1 -1
  134. package/dist/application/transform/ref-pointer/generated-shape.cjs +47 -66
  135. package/dist/application/transform/ref-pointer/generated-shape.cjs.map +1 -1
  136. package/dist/application/transform/ref-pointer/generated-shape.mjs +36 -50
  137. package/dist/application/transform/ref-pointer/generated-shape.mjs.map +1 -1
  138. package/dist/application/transform/ref-pointer/inline-cycles.cjs +2 -2
  139. package/dist/application/transform/ref-pointer/inline-cycles.cjs.map +1 -1
  140. package/dist/application/transform/ref-pointer/inline-cycles.mjs +1 -1
  141. package/dist/application/transform/ref-pointer/inline-cycles.mjs.map +1 -1
  142. package/dist/application/transform/ref-pointer/located-node.cjs +23 -0
  143. package/dist/application/transform/ref-pointer/located-node.cjs.map +1 -0
  144. package/dist/application/transform/ref-pointer/located-node.mjs +18 -0
  145. package/dist/application/transform/ref-pointer/located-node.mjs.map +1 -0
  146. package/dist/application/transform/ref-pointer/original-index.cjs +68 -13
  147. package/dist/application/transform/ref-pointer/original-index.cjs.map +1 -1
  148. package/dist/application/transform/ref-pointer/original-index.mjs +70 -15
  149. package/dist/application/transform/ref-pointer/original-index.mjs.map +1 -1
  150. package/dist/application/transform/ref-pointer/pointer-type.cjs +2 -2
  151. package/dist/application/transform/ref-pointer/pointer-type.cjs.map +1 -1
  152. package/dist/application/transform/ref-pointer/pointer-type.mjs +1 -1
  153. package/dist/application/transform/ref-pointer/pointer-type.mjs.map +1 -1
  154. package/dist/application/transform/ref-pointer/pointer-walk.cjs +54 -13
  155. package/dist/application/transform/ref-pointer/pointer-walk.cjs.map +1 -1
  156. package/dist/application/transform/ref-pointer/pointer-walk.mjs +46 -7
  157. package/dist/application/transform/ref-pointer/pointer-walk.mjs.map +1 -1
  158. package/dist/application/transform/ref-pointer/property-shape.cjs +52 -0
  159. package/dist/application/transform/ref-pointer/property-shape.cjs.map +1 -0
  160. package/dist/application/transform/ref-pointer/property-shape.mjs +45 -0
  161. package/dist/application/transform/ref-pointer/property-shape.mjs.map +1 -0
  162. package/dist/application/transform/ref-pointer/typed-walk.cjs +79 -21
  163. package/dist/application/transform/ref-pointer/typed-walk.cjs.map +1 -1
  164. package/dist/application/transform/ref-pointer/typed-walk.mjs +76 -18
  165. package/dist/application/transform/ref-pointer/typed-walk.mjs.map +1 -1
  166. package/dist/application/transform/schema/access-flags.cjs.map +1 -1
  167. package/dist/application/transform/schema/access-flags.mjs.map +1 -1
  168. package/dist/application/transform/schema/index-signature-type.cjs +21 -0
  169. package/dist/application/transform/schema/index-signature-type.cjs.map +1 -0
  170. package/dist/application/transform/schema/index-signature-type.mjs +19 -0
  171. package/dist/application/transform/schema/index-signature-type.mjs.map +1 -0
  172. package/dist/application/transform/schema/input-location.cjs +23 -0
  173. package/dist/application/transform/schema/input-location.cjs.map +1 -0
  174. package/dist/application/transform/schema/input-location.mjs +21 -0
  175. package/dist/application/transform/schema/input-location.mjs.map +1 -0
  176. package/dist/application/transform/schema/object-type.cjs +15 -5
  177. package/dist/application/transform/schema/object-type.cjs.map +1 -1
  178. package/dist/application/transform/schema/object-type.mjs +15 -5
  179. package/dist/application/transform/schema/object-type.mjs.map +1 -1
  180. package/dist/application/transform/schema/schema-transform.cjs +2 -1
  181. package/dist/application/transform/schema/schema-transform.cjs.map +1 -1
  182. package/dist/application/transform/schema/schema-transform.mjs +2 -1
  183. package/dist/application/transform/schema/schema-transform.mjs.map +1 -1
  184. package/dist/application/transform/schema/unevaluated-properties.cjs +2 -30
  185. package/dist/application/transform/schema/unevaluated-properties.cjs.map +1 -1
  186. package/dist/application/transform/schema/unevaluated-properties.mjs +3 -31
  187. package/dist/application/transform/schema/unevaluated-properties.mjs.map +1 -1
  188. package/dist/cli/api-logger.cjs +13 -0
  189. package/dist/cli/api-logger.cjs.map +1 -0
  190. package/dist/cli/api-logger.mjs +11 -0
  191. package/dist/cli/api-logger.mjs.map +1 -0
  192. package/dist/cli/api-settings.cjs +7 -15
  193. package/dist/cli/api-settings.cjs.map +1 -1
  194. package/dist/cli/api-settings.mjs +8 -16
  195. package/dist/cli/api-settings.mjs.map +1 -1
  196. package/dist/cli/cli-arguments.cjs +51 -11
  197. package/dist/cli/cli-arguments.cjs.map +1 -1
  198. package/dist/cli/cli-arguments.mjs +51 -11
  199. package/dist/cli/cli-arguments.mjs.map +1 -1
  200. package/dist/cli/cli-errors.cjs +17 -0
  201. package/dist/cli/cli-errors.cjs.map +1 -1
  202. package/dist/cli/cli-errors.mjs +17 -1
  203. package/dist/cli/cli-errors.mjs.map +1 -1
  204. package/dist/cli/cli-output.cjs +6 -4
  205. package/dist/cli/cli-output.cjs.map +1 -1
  206. package/dist/cli/cli-output.mjs +7 -5
  207. package/dist/cli/cli-output.mjs.map +1 -1
  208. package/dist/cli/main.cjs +10 -4
  209. package/dist/cli/main.cjs.map +1 -1
  210. package/dist/cli/main.mjs +10 -4
  211. package/dist/cli/main.mjs.map +1 -1
  212. package/dist/cli/redocly-apis.cjs +20 -9
  213. package/dist/cli/redocly-apis.cjs.map +1 -1
  214. package/dist/cli/redocly-apis.mjs +22 -11
  215. package/dist/cli/redocly-apis.mjs.map +1 -1
  216. package/dist/cli/ref-limits.cjs +15 -1
  217. package/dist/cli/ref-limits.cjs.map +1 -1
  218. package/dist/cli/ref-limits.mjs +15 -2
  219. package/dist/cli/ref-limits.mjs.map +1 -1
  220. package/dist/cli/run-cli.cjs +24 -7
  221. package/dist/cli/run-cli.cjs.map +1 -1
  222. package/dist/cli/run-cli.mjs +25 -8
  223. package/dist/cli/run-cli.mjs.map +1 -1
  224. package/dist/domain/cause-secrets.cjs +31 -16
  225. package/dist/domain/cause-secrets.cjs.map +1 -1
  226. package/dist/domain/cause-secrets.mjs +31 -16
  227. package/dist/domain/cause-secrets.mjs.map +1 -1
  228. package/dist/domain/errors.cjs +2 -0
  229. package/dist/domain/errors.cjs.map +1 -1
  230. package/dist/domain/errors.mjs +2 -0
  231. package/dist/domain/errors.mjs.map +1 -1
  232. package/dist/domain/location-text.cjs +9 -0
  233. package/dist/domain/location-text.cjs.map +1 -0
  234. package/dist/domain/location-text.mjs +7 -0
  235. package/dist/domain/location-text.mjs.map +1 -0
  236. package/dist/domain/openapi/document-places.cjs +55 -0
  237. package/dist/domain/openapi/document-places.cjs.map +1 -0
  238. package/dist/domain/openapi/document-places.mjs +53 -0
  239. package/dist/domain/openapi/document-places.mjs.map +1 -0
  240. package/dist/domain/output-fixes.cjs +8 -2
  241. package/dist/domain/output-fixes.cjs.map +1 -1
  242. package/dist/domain/output-fixes.mjs +8 -2
  243. package/dist/domain/output-fixes.mjs.map +1 -1
  244. package/dist/domain/terminal-text.cjs +31 -0
  245. package/dist/domain/terminal-text.cjs.map +1 -0
  246. package/dist/domain/terminal-text.mjs +29 -0
  247. package/dist/domain/terminal-text.mjs.map +1 -0
  248. package/dist/domain/warnings.cjs +1 -0
  249. package/dist/domain/warnings.cjs.map +1 -1
  250. package/dist/domain/warnings.mjs +1 -0
  251. package/dist/domain/warnings.mjs.map +1 -1
  252. package/dist/index.d.cts +26 -18
  253. package/dist/index.d.mts +26 -18
  254. package/dist/index.d.ts +26 -18
  255. package/package.json +1 -1
  256. package/src/adapters/node-file-system/node-file-system.ts +14 -1
  257. package/src/adapters/pipe-safe-writer/pipe-safe-writer.ts +29 -0
  258. package/src/adapters/redocly-loader/bundled-mapping-copies.ts +7 -42
  259. package/src/adapters/redocly-loader/component-schemas.ts +19 -0
  260. package/src/adapters/redocly-loader/mapping-schema-names.ts +25 -0
  261. package/src/adapters/redocly-loader/query-named-components.ts +201 -0
  262. package/src/adapters/redocly-loader/redocly-schema-loader.ts +46 -14
  263. package/src/adapters/redocly-loader/ref-access.ts +16 -3
  264. package/src/adapters/redocly-loader/ref-holders.ts +75 -14
  265. package/src/adapters/redocly-loader/remote-fetch.ts +11 -2
  266. package/src/adapters/redocly-loader/remote-node-limit.ts +44 -4
  267. package/src/adapters/redocly-loader/schema-source.ts +15 -3
  268. package/src/adapters/terminal-logger/terminal-logger.ts +10 -4
  269. package/src/api/document-refs.ts +29 -1
  270. package/src/api/document-run.ts +6 -16
  271. package/src/api/openapi-ts.ts +6 -3
  272. package/src/api/ref-limit-options.ts +76 -0
  273. package/src/api/transform-schema.ts +20 -5
  274. package/src/application/ports/file-system.ts +8 -0
  275. package/src/application/transform/declared-value-types.ts +42 -0
  276. package/src/application/transform/document/document.ts +4 -2
  277. package/src/application/transform/document/exploded-query-values.ts +88 -0
  278. package/src/application/transform/document/header.ts +25 -5
  279. package/src/application/transform/document/parameter.ts +4 -4
  280. package/src/application/transform/document/parameters.ts +45 -10
  281. package/src/application/transform/document/path-item.ts +3 -3
  282. package/src/application/transform/document/path-template-key.ts +152 -0
  283. package/src/application/transform/document/path-template-refs.ts +106 -0
  284. package/src/application/transform/document/paths-enum.ts +23 -9
  285. package/src/application/transform/document/paths.ts +53 -123
  286. package/src/application/transform/document/webhooks.ts +18 -5
  287. package/src/application/transform/footer/document-footer.ts +18 -8
  288. package/src/application/transform/helper-types.ts +4 -4
  289. package/src/application/transform/ref-pointer/generated-location.ts +1 -1
  290. package/src/application/transform/ref-pointer/generated-shape.ts +67 -78
  291. package/src/application/transform/ref-pointer/inline-cycles.ts +1 -1
  292. package/src/application/transform/ref-pointer/located-node.ts +38 -0
  293. package/src/application/transform/ref-pointer/original-index.ts +100 -17
  294. package/src/application/transform/ref-pointer/pointer-type.ts +1 -1
  295. package/src/application/transform/ref-pointer/pointer-walk.ts +82 -8
  296. package/src/application/transform/ref-pointer/property-shape.ts +97 -0
  297. package/src/application/transform/ref-pointer/typed-walk.ts +117 -25
  298. package/src/application/transform/schema/access-flags.ts +5 -2
  299. package/src/application/transform/schema/index-signature-type.ts +31 -0
  300. package/src/application/transform/schema/input-location.ts +35 -0
  301. package/src/application/transform/schema/object-type.ts +18 -8
  302. package/src/application/transform/schema/schema-transform.ts +2 -1
  303. package/src/application/transform/schema/unevaluated-properties.ts +4 -44
  304. package/src/cli/api-logger.ts +17 -0
  305. package/src/cli/api-settings.ts +12 -20
  306. package/src/cli/cli-arguments.ts +90 -14
  307. package/src/cli/cli-dependencies.ts +7 -2
  308. package/src/cli/cli-errors.ts +22 -0
  309. package/src/cli/cli-output.ts +11 -10
  310. package/src/cli/main.ts +10 -4
  311. package/src/cli/redocly-apis.ts +37 -17
  312. package/src/cli/ref-limits.ts +21 -2
  313. package/src/cli/run-cli.ts +39 -7
  314. package/src/domain/cause-secrets.ts +59 -25
  315. package/src/domain/errors.ts +2 -0
  316. package/src/domain/location-text.ts +12 -0
  317. package/src/domain/openapi/document-places.ts +78 -0
  318. package/src/domain/output-fixes.ts +9 -2
  319. package/src/domain/terminal-text.ts +44 -0
  320. package/src/domain/warnings.ts +1 -0
@@ -1,6 +1,6 @@
1
1
  import { appendPointer, ROOT_POINTER } from "../../../domain/openapi/json-pointer.js";
2
2
  import type { RefResolver } from "../schema/schema-context.js";
3
- import { isJsonObject } from "./generated-shape.js";
3
+ import { isJsonObject } from "./located-node.js";
4
4
  import {
5
5
  leadingSegmentsOf,
6
6
  type RefPointer,
@@ -1,5 +1,18 @@
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
+ isExcludedProperty,
12
+ isMarkedProperty,
13
+ isNullableSchema,
14
+ isOptionalProperty,
15
+ } from "./property-shape.js";
3
16
 
4
17
  /**
5
18
  * What the generated type of a schema has under a key, read from the schema itself. It answers the
@@ -8,14 +21,19 @@ import type { RefResolver, SchemaOptions } from "../schema/schema-context.js";
8
21
  */
9
22
 
10
23
  export type GeneratedMember =
11
- | { readonly kind: "property"; readonly node: unknown; readonly isOptional: boolean }
24
+ | {
25
+ readonly kind: "property";
26
+ readonly node: unknown;
27
+ readonly location: string | undefined;
28
+ readonly isOptional: boolean;
29
+ /** `$Read<T>` or `$Write<T>` (`isMarkedProperty`): no member but the marker's own. */
30
+ readonly isMarked: boolean;
31
+ }
12
32
  /** An index signature; `node` is undefined when its value type is `unknown`. */
13
- | { readonly kind: "index"; readonly node: unknown }
33
+ | { readonly kind: "index"; readonly node: unknown; readonly location: string | undefined }
14
34
  | { readonly kind: "missing" }
15
35
  | { readonly kind: "opaque" };
16
36
 
17
- type JsonObject = Readonly<Record<string, unknown>>;
18
-
19
37
  const OPAQUE_KEYS = ["not", "enum", "const", "$ref"] as const;
20
38
  /** How deep `allOf`/`anyOf`/`oneOf` members are read; deeper shapes count as opaque. */
21
39
  const MAX_DEPTH = 8;
@@ -23,23 +41,6 @@ const INDEX_RE = /^\d+$/;
23
41
  const MISSING: GeneratedMember = { kind: "missing" };
24
42
  const OPAQUE: GeneratedMember = { kind: "opaque" };
25
43
 
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
44
  function typeNames(node: JsonObject): readonly unknown[] {
44
45
  return Array.isArray(node.type) ? node.type : [node.type];
45
46
  }
@@ -90,39 +91,37 @@ function isBuiltInMember(key: string, prototype: object): boolean {
90
91
  return key in prototype;
91
92
  }
92
93
 
93
- function indexMember(node: JsonObject, options: SchemaOptions): GeneratedMember | null {
94
- const { additionalProperties: values, patternProperties: patterns } = node;
94
+ function indexMember(owner: LocatedNode & { node: JsonObject }, options: SchemaOptions) {
95
+ const { additionalProperties: values, patternProperties: patterns } = owner.node;
95
96
  if (isJsonObject(patterns) && Object.keys(patterns).length > 0) {
96
97
  return OPAQUE;
97
98
  }
98
99
  if (isJsonObject(values) && Object.keys(values).length > 0) {
99
- return { kind: "index", node: values };
100
+ const location = childLocation(owner.location, "additionalProperties");
101
+ return { kind: "index", node: values, location } satisfies GeneratedMember;
100
102
  }
101
103
  const isImplicit = values === true || (isJsonObject(values) && Object.keys(values).length === 0);
102
104
  return isImplicit || (!values && options.additionalProperties)
103
- ? { kind: "index", node: undefined }
105
+ ? ({ kind: "index", node: undefined, location: undefined } satisfies GeneratedMember)
104
106
  : null;
105
107
  }
106
108
 
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;
116
- }
117
-
118
- function objectMember(node: JsonObject, key: string, options: SchemaOptions): GeneratedMember {
109
+ function objectMember(
110
+ owner: LocatedNode & { node: JsonObject },
111
+ key: string,
112
+ input: MemberInput,
113
+ ): GeneratedMember {
114
+ const { options } = input;
115
+ const { node } = owner;
119
116
  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) };
117
+ if (Object.hasOwn(properties, key) && !isExcludedProperty(properties[key], options, input.refs)) {
118
+ if (isJsonObject(node.discriminator)) {
119
+ return OPAQUE;
120
+ }
121
+ const location = childLocation(owner.location, "properties", key);
122
+ const isOptional = isOptionalProperty(owner, key, options);
123
+ const isMarked = isMarkedProperty(properties[key], options, input.refs);
124
+ return { kind: "property", node: properties[key], location, isOptional, isMarked };
126
125
  }
127
126
  // `unevaluatedProperties` adds an index signature with its fix, so it counts as opaque too.
128
127
  const isUnknownShape =
@@ -131,38 +130,23 @@ function objectMember(node: JsonObject, key: string, options: SchemaOptions): Ge
131
130
  return OPAQUE;
132
131
  }
133
132
  return hasObjectKeywords(node)
134
- ? (indexMember(node, options) ?? MISSING)
133
+ ? (indexMember(owner, options) ?? MISSING)
135
134
  : emptyObjectMember(node, options);
136
135
  }
137
136
 
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
137
  function membersOf(node: JsonObject, keyword: string): readonly unknown[] {
162
138
  const members = node[keyword];
163
139
  return Array.isArray(members) ? members : [];
164
140
  }
165
141
 
142
+ /** The members of a composition keyword with their locations. */
143
+ function locatedMembers(owner: LocatedNode & { node: JsonObject }, keyword: string): LocatedNode[] {
144
+ return membersOf(owner.node, keyword).map((node, index) => ({
145
+ node,
146
+ location: childLocation(owner.location, keyword, String(index)),
147
+ }));
148
+ }
149
+
166
150
  function withoutComposition(node: JsonObject): JsonObject {
167
151
  const { allOf: _allOf, anyOf: _anyOf, oneOf: _oneOf, ...own } = node;
168
152
  return own;
@@ -178,8 +162,13 @@ function hasOwnObjectType(own: JsonObject): boolean {
178
162
  * `anyOf` or `oneOf` alone is a union: a key is missing if one member misses it. A mix of both
179
163
  * is written in more than one way (`anyof-properties`), so it counts as opaque.
180
164
  */
181
- function composedMember(node: JsonObject, key: string, input: MemberInput): GeneratedMember {
182
- const variants = [...membersOf(node, "anyOf"), ...membersOf(node, "oneOf")];
165
+ function composedMember(
166
+ owner: LocatedNode & { node: JsonObject },
167
+ key: string,
168
+ input: MemberInput,
169
+ ): GeneratedMember {
170
+ const { node } = owner;
171
+ const variants = [...locatedMembers(owner, "anyOf"), ...locatedMembers(owner, "oneOf")];
183
172
  const own = withoutComposition(node);
184
173
  const hasOwn = hasOwnObjectType(own);
185
174
  if (variants.length > 0) {
@@ -187,7 +176,8 @@ function composedMember(node: JsonObject, key: string, input: MemberInput): Gene
187
176
  const members = variants.map((variant) => memberAt(variant, key, input));
188
177
  return isAlone && members.some((member) => member.kind === "missing") ? MISSING : OPAQUE;
189
178
  }
190
- const parts = [...membersOf(node, "allOf"), ...(hasOwn ? [own] : [])];
179
+ const ownPart = { node: own, location: owner.location };
180
+ const parts = [...locatedMembers(owner, "allOf"), ...(hasOwn ? [ownPart] : [])];
191
181
  return intersectionMember(parts.map((part) => memberAt(part, key, input)));
192
182
  }
193
183
 
@@ -216,23 +206,22 @@ interface MemberInput {
216
206
  readonly depth: number;
217
207
  }
218
208
 
219
- function memberAt(schema: unknown, key: string, input: MemberInput): GeneratedMember {
220
- const node = followRefs(schema, input.refs);
209
+ function memberAt(schema: LocatedNode, key: string, input: MemberInput): GeneratedMember {
210
+ const followed = followLocated(schema, input.refs);
211
+ const { node } = followed;
221
212
  if (!isJsonObject(node) || OPAQUE_KEYS.some((name) => name in node) || input.depth > MAX_DEPTH) {
222
213
  return OPAQUE;
223
214
  }
215
+ const owner = { ...followed, node };
224
216
  if (isNullableSchema(node)) {
225
217
  // Every key of `T | null` is an error, unless `T` is unknown (then the type is `unknown`).
226
218
  return isObjectShape(node) || isArrayShape(node) ? MISSING : OPAQUE;
227
219
  }
228
- if (input.options.readWriteMarkers) {
229
- return OPAQUE;
230
- }
231
220
  if ("allOf" in node || "anyOf" in node || "oneOf" in node) {
232
- return composedMember(node, key, { ...input, depth: input.depth + 1 });
221
+ return composedMember(owner, key, { ...input, depth: input.depth + 1 });
233
222
  }
234
223
  if (isObjectShape(node)) {
235
- return objectMember(node, key, input.options);
224
+ return objectMember(owner, key, input);
236
225
  }
237
226
  if (isArrayShape(node)) {
238
227
  return INDEX_RE.test(key) || isBuiltInMember(key, []) ? OPAQUE : MISSING;
@@ -266,7 +255,7 @@ function primitiveMember(node: JsonObject, key: string): GeneratedMember {
266
255
 
267
256
  /** The member `key` of the type generated for `schema` (a `$ref` is followed first). */
268
257
  export function generatedMember(
269
- schema: unknown,
258
+ schema: LocatedNode,
270
259
  key: string,
271
260
  options: SchemaOptions,
272
261
  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,
@@ -22,6 +26,8 @@ type Step = "fails" | "compiles" | "continue";
22
26
 
23
27
  interface OriginalWalk {
24
28
  readonly node: unknown;
29
+ /** The node's JSON Pointer (`LocatedNode`). */
30
+ readonly location: string | undefined;
25
31
  readonly isSchema: boolean;
26
32
  }
27
33
 
@@ -35,7 +41,7 @@ function schemaStep(walk: OriginalWalk, segment: string, isLast: boolean, input:
35
41
  if (segment === "properties") {
36
42
  return { step: "continue" as Step, walk };
37
43
  }
38
- const member = generatedMember(walk.node, segment, input.options, input.refs);
44
+ const member = generatedMember(walk, segment, input.options, input.refs);
39
45
  if (member.kind === "missing") {
40
46
  return { step: "fails" as Step, walk };
41
47
  }
@@ -43,49 +49,126 @@ function schemaStep(walk: OriginalWalk, segment: string, isLast: boolean, input:
43
49
  return { step: "compiles" as Step, walk };
44
50
  }
45
51
  const isAbsentValue = member.kind === "index" && member.node === undefined;
46
- const isUnsafe = member.kind === "property" ? member.isOptional : isAbsentValue;
52
+ const isUnsafe =
53
+ member.kind === "property" ? member.isOptional || member.isMarked : isAbsentValue;
47
54
  return {
48
55
  step: (isUnsafe && !isLast ? "fails" : "continue") as Step,
49
- walk: { ...walk, node: member.node },
56
+ walk: { ...walk, node: member.node, location: member.location },
50
57
  };
51
58
  }
52
59
 
53
60
  function containerStep(walk: OriginalWalk, index: number, input: WalkInput) {
54
61
  const segment = input.pointer.segments[index] as string;
55
62
  const isLast = index === input.pointer.segments.length - 1;
63
+ if (isExcludedOperation(input.pointer, index, walk.node, input)) {
64
+ return { step: "fails" as Step, walk };
65
+ }
56
66
  const isOptional =
57
67
  (segment === "requestBody" && isOptionalRequestBody(walk.node, input.refs)) ||
58
68
  isOptionalHeader(input.pointer, index, walk.node);
59
69
  if (isOptional && !isLast) {
60
70
  return { step: "fails" as Step, walk };
61
71
  }
62
- const child = isJsonObject(walk.node) ? followRefs(walk.node[segment], input.refs) : undefined;
72
+ const child = followLocated(
73
+ {
74
+ node: isJsonObject(walk.node) ? walk.node[segment] : undefined,
75
+ location: childLocation(walk.location, segment),
76
+ },
77
+ input.refs,
78
+ );
63
79
  return {
64
- step: (child === undefined ? "compiles" : "continue") as Step,
65
- walk: { ...walk, node: child },
80
+ step: (child.node === undefined ? "compiles" : "continue") as Step,
81
+ walk: { ...walk, ...child },
66
82
  };
67
83
  }
68
84
 
85
+ /** The schema of the first media type of a `content` map, `$ref`s followed. */
86
+ function firstMediaTypeSchema(walk: OriginalWalk, refs: RefResolver): OriginalWalk | null {
87
+ const content = isJsonObject(walk.node) ? walk.node.content : undefined;
88
+ if (!isJsonObject(content)) {
89
+ return null;
90
+ }
91
+ const [mediaType] = Object.keys(content);
92
+ if (mediaType === undefined) {
93
+ return null;
94
+ }
95
+ const location = childLocation(childLocation(walk.location, "content"), mediaType);
96
+ const entry = followLocated({ node: content[mediaType], location }, refs);
97
+ return ownSchema({ ...entry, isSchema: false }, refs);
98
+ }
99
+
100
+ /** The schema a header or parameter is typed by, `$ref`s followed. */
101
+ function ownSchema(walk: OriginalWalk, refs: RefResolver): OriginalWalk {
102
+ const schema = isJsonObject(walk.node) ? walk.node.schema : undefined;
103
+ const location = childLocation(walk.location, "schema");
104
+ return { ...followLocated({ node: schema, location }, refs), isSchema: true };
105
+ }
106
+
107
+ /** The schema whose type a header or parameter is, when not its media type members. */
108
+ function contentSchema(
109
+ walk: OriginalWalk,
110
+ form: Exclude<ContentForm, "media-type-members">,
111
+ refs: RefResolver,
112
+ ): OriginalWalk | null {
113
+ switch (form) {
114
+ case "first-media-type":
115
+ return firstMediaTypeSchema(walk, refs);
116
+ case "schema":
117
+ return ownSchema(walk, refs);
118
+ case "string":
119
+ return null;
120
+ }
121
+ }
122
+
123
+ /**
124
+ * The original indexes the `content` of a header or parameter by name. The media type members
125
+ * have no `content` unless a media type is named so, and `string` and `unknown` (no media type)
126
+ * have none; the schema of the first media type, or the `schema` next to `content`, is walked on.
127
+ */
128
+ function contentStep(walk: OriginalWalk, form: ContentForm, isLast: boolean, input: WalkInput) {
129
+ const content = isJsonObject(walk.node) ? walk.node.content : undefined;
130
+ if (form === "media-type-members") {
131
+ const hasMember = isJsonObject(content) && Object.hasOwn(content, "content");
132
+ return { step: (hasMember ? "compiles" : "fails") as Step, walk };
133
+ }
134
+ const schema = contentSchema(walk, form, input.refs);
135
+ return schema === null
136
+ ? { step: "fails" as Step, walk }
137
+ : schemaStep(schema, "content", isLast, input);
138
+ }
139
+
140
+ /**
141
+ * A step outside a schema: a header's or parameter's `content`, a schema's container, or another.
142
+ */
143
+ function documentStep(walk: OriginalWalk, index: number, input: WalkInput) {
144
+ const segment = input.pointer.segments[index] as string;
145
+ const isLast = index === input.pointer.segments.length - 1;
146
+ const form = headerParameterContentForm(input.pointer, index, walk.node, input.options);
147
+ if (form !== null) {
148
+ return contentStep(walk, form, isLast, input);
149
+ }
150
+ if (isTypedAsSchema(input.pointer, index) && isJsonObject(walk.node)) {
151
+ // The container's type is its schema's type: the segment indexes that type.
152
+ return schemaStep(ownSchema(walk, input.refs), segment, isLast, input);
153
+ }
154
+ return containerStep(walk, index, input);
155
+ }
156
+
69
157
  /** True when the original type of the `$ref` does not compile for sure. */
70
158
  export function originalIndexFails(input: WalkInput): boolean {
71
159
  const { segments } = input.pointer;
72
160
  let walk: OriginalWalk = {
73
- node: leadingNode(input.pointer, input.refs),
161
+ ...leadingLocated(input.pointer, input.refs),
74
162
  isSchema: startsInSchema(input.pointer),
75
163
  };
76
164
  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
165
  if (!walk.isSchema && isParameterList(input.pointer, index)) {
80
166
  return true;
81
167
  }
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
- }
168
+ const isLast = index === segments.length - 1;
86
169
  const result = walk.isSchema
87
- ? schemaStep(walk, segment, isLast, input)
88
- : containerStep(walk, index, input);
170
+ ? schemaStep(walk, segments[index] as string, isLast, input)
171
+ : documentStep(walk, index, input);
89
172
  if (result.step !== "continue") {
90
173
  return result.step === "fails";
91
174
  }
@@ -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) {