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
@@ -6,6 +6,10 @@ import {
6
6
  withEnumsRenamed,
7
7
  } from "../application/transform/document/enum-names-given-back.js";
8
8
  import { operationKeysWritten } from "../application/transform/document/operation-keys-written.js";
9
+ import {
10
+ unmatchedTemplateKeys,
11
+ withTemplatePathRefs,
12
+ } from "../application/transform/document/path-template-refs.js";
9
13
  import { renameTakenAliases } from "../application/transform/document/root-type-aliases.js";
10
14
  import { RunFooter, type RunFooterNames } from "../application/transform/footer/document-footer.js";
11
15
  import { EnumNameClaims } from "../application/transform/footer/enum-name-claims.js";
@@ -144,6 +148,20 @@ function enumValuesChecked(
144
148
  return checked.footer;
145
149
  }
146
150
 
151
+ /** The document with its references into templated paths indexed by their templates. */
152
+ function withTemplateRefs(
153
+ { body, footer, closing }: TransformedDocument,
154
+ keys: ReadonlyMap<string, string>,
155
+ ): TransformedDocument {
156
+ return {
157
+ body: withTemplatePathRefs(body, keys),
158
+ footer: footer.map((entry) =>
159
+ isIrDeclaration(entry) ? (withTemplatePathRefs([entry], keys)[0] ?? entry) : entry,
160
+ ),
161
+ closing: withTemplatePathRefs(closing, keys),
162
+ };
163
+ }
164
+
147
165
  /** @internal Root types, the footer, then the closing declarations (Phase 5, step 6). */
148
166
  export function transformDocument(schema: OpenAPI3, ctx: RunContext): TransformedDocument {
149
167
  const document = schema as DocumentObject;
@@ -160,11 +178,8 @@ export function transformDocument(schema: OpenAPI3, ctx: RunContext): Transforme
160
178
  const rawClosing = documentClosing(document, context, rawFooter.some(isOperations));
161
179
  const parts = { body: rawBody, footer: rawFooter, closing: rawClosing };
162
180
  const { body, footer, closing } = withEnumNamesGivenBack(parts, names);
163
- return {
164
- body: renameTakenAliases(body, footer.filter(isIrDeclaration), closing),
165
- footer,
166
- closing,
167
- };
181
+ const named = { body: renameTakenAliases(body, footer.filter(isIrDeclaration), closing), footer };
182
+ return withTemplateRefs({ ...named, closing }, unmatchedTemplateKeys(document.paths, context));
168
183
  }
169
184
 
170
185
  /**
@@ -29,6 +29,14 @@ export interface DirectoryCheck {
29
29
  isDirectory(file: URL): boolean;
30
30
  }
31
31
 
32
+ /**
33
+ * Whether a `file:` location is an existing file. A schema argument with a `*` is a glob pattern
34
+ * only when no file has that name.
35
+ */
36
+ export interface FileCheck {
37
+ isFile(file: URL): boolean;
38
+ }
39
+
32
40
  /**
33
41
  * An output file that exists before its content is written: the claim created it, empty, when it
34
42
  * was missing, so the file system has given it its own identity.
@@ -17,4 +17,9 @@ export interface RedoclyConfigSource {
17
17
  * when the ignore file of the working directory is bad.
18
18
  */
19
19
  createDefault(): Promise<RedoclyConfig>;
20
+ /**
21
+ * The config one API of `config` is linted with: the API's own `rules` (and other lint
22
+ * settings) under `apis.<name>` in place of the root's, as `redocly lint <name>` reads them.
23
+ */
24
+ forApi(config: RedoclyConfig, apiName: string): RedoclyConfig;
20
25
  }
@@ -0,0 +1,42 @@
1
+ import { irKeyword, irReference } from "../../domain/ir/constructors.js";
2
+ import type { IrMember, IrType } from "../../domain/ir/nodes.js";
3
+ import { HELPER_TYPES } from "./helper-types.js";
4
+ import type { FooterDeclarations } from "./schema/schema-context.js";
5
+
6
+ /** The footer part that declares the `PropertyValues` helper type. */
7
+ export type PropertyValuesFooter = Pick<FooterDeclarations, "requirePropertyValues">;
8
+
9
+ function memberValueTypes(member: IrMember): IrType[] {
10
+ if (member.kind === "indexSignature") {
11
+ return [member.type];
12
+ }
13
+ return member.isOptional ? [member.type, irKeyword("undefined")] : [member.type];
14
+ }
15
+
16
+ /**
17
+ * The value types a key of the type can have, read from its IR: the members of object types,
18
+ * through unions and intersections. A reference (a `$ref`, `Omit`, `WithRequired`) or a raw
19
+ * type is read with `PropertyValues`. Primitives, literals and arrays declare no keys.
20
+ */
21
+ export function declaredValueTypes(type: IrType, footer: PropertyValuesFooter): IrType[] {
22
+ switch (type.kind) {
23
+ case "object":
24
+ return type.members.flatMap(memberValueTypes);
25
+ case "union":
26
+ case "intersection":
27
+ return type.types.flatMap((member) => declaredValueTypes(member, footer));
28
+ case "reference":
29
+ case "indexedAccess":
30
+ case "raw":
31
+ footer.requirePropertyValues();
32
+ return [irReference(HELPER_TYPES.propertyValues.name, [type])];
33
+ case "keyword":
34
+ case "stringLiteral":
35
+ case "numberLiteral":
36
+ case "booleanLiteral":
37
+ case "array":
38
+ case "tuple":
39
+ case "readonly":
40
+ return [];
41
+ }
42
+ }
@@ -9,13 +9,14 @@ import type {
9
9
  } from "../../../domain/ir/nodes.js";
10
10
  import type { ComponentsObject } from "../../../domain/openapi/components-object.js";
11
11
  import type { DocumentObject } from "../../../domain/openapi/document-object.js";
12
- import type { PathsObject } from "../../../domain/openapi/path-item-object.js";
12
+ import type { OperationEntry, PathsObject } from "../../../domain/openapi/path-item-object.js";
13
13
  import { READ_WRITE_MARKER_TYPES } from "../helper-types.js";
14
14
  import type { TransformContext, TransformOptions } from "../transform-context.js";
15
15
  import { componentsType } from "./components.js";
16
16
  import { type DeclaredTypeLookup, declaredTypeLookup } from "./declared-types.js";
17
17
  import { defsRootType } from "./defs-root.js";
18
18
  import { keptDeprecatedComponents } from "./kept-deprecated.js";
19
+ import { isIncludedOperation } from "./path-item.js";
19
20
  import { pathMembers, pathsObjectType } from "./paths.js";
20
21
  import { apiPathsEnumDeclaration } from "./paths-enum.js";
21
22
  import { webhooksType } from "./webhooks.js";
@@ -210,7 +211,8 @@ export function documentClosing(
210
211
  declarations.push(emptyAlias(OPERATIONS_NAME));
211
212
  }
212
213
  if (context.options.makePathsEnum && document.paths) {
213
- declarations.push(apiPathsEnumDeclaration(document.paths));
214
+ const isIncluded = (operation: OperationEntry) => isIncludedOperation(operation, context);
215
+ declarations.push(apiPathsEnumDeclaration(document.paths, isIncluded));
214
216
  }
215
217
  return declarations;
216
218
  }
@@ -0,0 +1,88 @@
1
+ import type { IrMember, IrType } from "../../../domain/ir/nodes.js";
2
+ import type { Schema } from "../../../domain/openapi/schema-object.js";
3
+ import { transformSchema } from "../schema/schema-transform.js";
4
+ import type { TransformContext } from "../transform-context.js";
5
+ import { unionOf } from "../type-combinators.js";
6
+ import type { ResolvedEntry } from "./parameter-entries.js";
7
+
8
+ /**
9
+ * `exploded-query-objects` and index signatures. The keys of an exploded object are keys of
10
+ * `query`, next to the other parameters. TypeScript checks an index signature against every key
11
+ * of a value, so `{ page?: number } & { [key: string]: string }` admits no `page`, and no value
12
+ * with another parameter at all. An index signature of an exploded object therefore also takes
13
+ * the value types of the other keys of `query`: those keys carry their own values.
14
+ */
15
+
16
+ function refOf(value: unknown): string | undefined {
17
+ const ref = (value as { $ref?: unknown } | undefined)?.$ref;
18
+ return typeof ref === "string" ? ref : undefined;
19
+ }
20
+
21
+ /** A schema `$ref` chain followed to its end, with the pointer where that schema is declared. */
22
+ function declaredSchema(schema: Schema | undefined, ref: string, context: TransformContext) {
23
+ let declared = { schema, path: ref };
24
+ const seen = new Set<string>();
25
+ for (let next = refOf(schema); next !== undefined && !seen.has(next); ) {
26
+ seen.add(next);
27
+ declared = { schema: context.refs.resolve(next) as Schema | undefined, path: next };
28
+ next = refOf(declared.schema);
29
+ }
30
+ return declared;
31
+ }
32
+
33
+ /**
34
+ * The type of an exploded parameter whose own type is a reference (its `$ref`, or the `$ref` of
35
+ * its schema), written out where its schema is declared: the index signature of a referenced type
36
+ * cannot be changed. The location is the one `components` types it at, so the enums it declares
37
+ * are the ones the reference names. Null when no `$ref` is involved.
38
+ */
39
+ export function declaredObjectType(entry: ResolvedEntry, context: TransformContext): IrType | null {
40
+ const { original, resolved } = entry;
41
+ const schemaRef = refOf(resolved.schema);
42
+ if (schemaRef !== undefined) {
43
+ const { schema, path } = declaredSchema(resolved.schema, schemaRef, context);
44
+ return transformSchema(schema, { path, schema }, context);
45
+ }
46
+ const parameterRef = refOf(original);
47
+ return parameterRef === undefined
48
+ ? null
49
+ : transformSchema(resolved.schema, { path: parameterRef, schema: resolved }, context);
50
+ }
51
+
52
+ function isIndexSignature(member: IrMember): boolean {
53
+ return member.kind === "indexSignature";
54
+ }
55
+
56
+ /** Whether the type has an index signature in its objects, through unions and intersections. */
57
+ export function hasIndexSignature(type: IrType): boolean {
58
+ switch (type.kind) {
59
+ case "object":
60
+ return type.members.some(isIndexSignature);
61
+ case "union":
62
+ case "intersection":
63
+ return type.types.some(hasIndexSignature);
64
+ default:
65
+ return false;
66
+ }
67
+ }
68
+
69
+ function widenedMember(member: IrMember, values: readonly IrType[]): IrMember {
70
+ // `unknown` takes every value already.
71
+ const isUnknown = member.type.kind === "keyword" && member.type.keyword === "unknown";
72
+ return isIndexSignature(member) && !isUnknown
73
+ ? { ...member, type: unionOf([member.type, ...values]) }
74
+ : member;
75
+ }
76
+
77
+ /** The type with the values added to each index signature of its objects. */
78
+ export function withIndexValues(type: IrType, values: readonly IrType[]): IrType {
79
+ switch (type.kind) {
80
+ case "object":
81
+ return { ...type, members: type.members.map((member) => widenedMember(member, values)) };
82
+ case "union":
83
+ case "intersection":
84
+ return { ...type, types: type.types.map((member) => withIndexValues(member, values)) };
85
+ default:
86
+ return type;
87
+ }
88
+ }
@@ -2,6 +2,8 @@ import { irObject } from "../../../domain/ir/constructors.js";
2
2
  import type { IrType } from "../../../domain/ir/nodes.js";
3
3
  import type { HeaderObject } from "../../../domain/openapi/header-object.js";
4
4
  import { escapePointerSegment } from "../../../domain/openapi/json-pointer.js";
5
+ import type { ContentMap } from "../../../domain/openapi/media-type-object.js";
6
+ import { FIX } from "../../../domain/output-fixes.js";
5
7
  import { documentEntries } from "../document-entries.js";
6
8
  import type { SchemaContext, SchemaLocation } from "../schema/schema-context.js";
7
9
  import { transformSchema } from "../schema/schema-transform.js";
@@ -10,8 +12,10 @@ import { documentMember } from "./document-member.js";
10
12
  import { contentEntryType } from "./media-type.js";
11
13
 
12
14
  /**
13
- * A header's type (OpenAPI 3.1 §4.8.21): its schema, else an object with one property per media
14
- * type in `content`, else `unknown`.
15
+ * A header's type (OpenAPI 3.1 §4.8.21): its schema, else the type of its `content`, else
16
+ * `unknown`. `content` holds one media type whose schema describes the value; the original typed
17
+ * it as an object with one property per media type, which the `parameter-header-content` fix
18
+ * replaces by the media type's type, as for a parameter.
15
19
  */
16
20
  export function headerType(
17
21
  header: HeaderObject,
@@ -24,11 +28,27 @@ export function headerType(
24
28
  if (!header.content) {
25
29
  return UNKNOWN_TYPE;
26
30
  }
31
+ if (context.options.fixes.has(FIX.PARAMETER_HEADER_CONTENT)) {
32
+ // The first media type in document order, as for a parameter: `--alphabetize` sorts only
33
+ // the members it writes.
34
+ const first = Object.entries(header.content)[0];
35
+ return first === undefined ? UNKNOWN_TYPE : mediaType(...first, location, context);
36
+ }
27
37
  const members = documentEntries(header.content, context.options).map(([contentType, entry]) => {
28
- // Unlike other content maps, the original joins this path by hand: a missing path is `#`.
29
- const path = `${location.path ?? "#"}/${escapePointerSegment(contentType)}`;
30
- const type = contentEntryType(entry, { ...location, path }, context);
38
+ const type = mediaType(contentType, entry, location, context);
31
39
  return documentMember(contentType, type, entry, { isReadonly: context.options.immutable });
32
40
  });
33
41
  return irObject(members);
34
42
  }
43
+
44
+ /** The type of one media type of a header, at the path the original gave it. */
45
+ function mediaType(
46
+ contentType: string,
47
+ entry: ContentMap[string],
48
+ location: SchemaLocation,
49
+ context: SchemaContext,
50
+ ): IrType {
51
+ // Unlike other content maps, the original joins this path by hand: a missing path is `#`.
52
+ const path = `${location.path ?? "#"}/${escapePointerSegment(contentType)}`;
53
+ return contentEntryType(entry, { ...location, path }, context);
54
+ }
@@ -13,7 +13,7 @@ import { contentEntryType } from "./media-type.js";
13
13
  /**
14
14
  * A parameter typed by the schema of its one `content` media type. An `in: querystring` parameter
15
15
  * (OpenAPI 3.2) is the whole query string (ADR-020); without a media type it is `string`, the
16
- * query string as text. With the `parameter-content` fix, any other parameter with `content`
16
+ * query string as text. With the `parameter-header-content` fix, any other parameter with `content`
17
17
  * (OpenAPI 3.0 and later, for a JSON value in a query parameter) is typed the same way.
18
18
  */
19
19
  function contentParameterType(
@@ -34,14 +34,14 @@ function isTypedByContent(parameter: ParameterObject, context: SchemaContext): b
34
34
  return true;
35
35
  }
36
36
  const hasContent = parameter.schema === undefined && parameter.content !== undefined;
37
- return hasContent && context.options.fixes.has(FIX.PARAMETER_CONTENT);
37
+ return hasContent && context.options.fixes.has(FIX.PARAMETER_HEADER_CONTENT);
38
38
  }
39
39
 
40
40
  /**
41
41
  * A parameter's type (OpenAPI 3.2 §4.8.12). Without a schema it is `string`, not `unknown`:
42
42
  * query, path, header and cookie values all arrive as text. `content` is read for
43
- * `in: querystring`, and with the `parameter-content` fix for every parameter; without the fix
44
- * other parameters with `content` keep the original's `string`.
43
+ * `in: querystring`, and with the `parameter-header-content` fix for every parameter; without
44
+ * the fix other parameters with `content` keep the original's `string`.
45
45
  */
46
46
  export function parameterType(
47
47
  parameter: ParameterObject,
@@ -16,10 +16,12 @@ import {
16
16
  QUERYSTRING_LOCATION,
17
17
  } from "../../../domain/openapi/parameter-object.js";
18
18
  import { FIX } from "../../../domain/output-fixes.js";
19
+ import { declaredValueTypes } from "../declared-value-types.js";
19
20
  import type { SchemaLocation } from "../schema/schema-context.js";
20
21
  import { withSchemaComment } from "../schema-comment.js";
21
22
  import type { TransformContext } from "../transform-context.js";
22
23
  import { isExplodedQueryObject } from "./exploded-query.js";
24
+ import { declaredObjectType, hasIndexSignature, withIndexValues } from "./exploded-query-values.js";
23
25
  import { parameterType } from "./parameter.js";
24
26
  import {
25
27
  type ParameterEntry,
@@ -126,17 +128,50 @@ function isExplodedEntry(entry: ResolvedEntry, context: TransformContext): boole
126
128
  );
127
129
  }
128
130
 
131
+ /** An exploded object parameter with its type, typed in document order. */
132
+ interface ExplodedEntry {
133
+ readonly entry: ResolvedEntry;
134
+ readonly type: IrType;
135
+ }
136
+
129
137
  /**
130
- * An exploded object parameter's part of `query`: its object type. A parameter that may be left
131
- * out sends none of its keys then, so they are optional: `Partial<…>`.
138
+ * The object type of an exploded parameter, written out when it is a reference to a type with an
139
+ * index signature and `query` has other keys, which that signature must then admit. Without
140
+ * other keys the reference is kept.
132
141
  */
133
- function explodedPart(
134
- entry: ResolvedEntry,
135
- location: SchemaLocation,
142
+ function explodedObjectType(
143
+ { entry, type }: ExplodedEntry,
144
+ hasOtherKeys: boolean,
136
145
  context: TransformContext,
137
146
  ): IrType {
138
- const type = entryType(entry, location, context);
139
- return entry.resolved.required ? type : irReference("Partial", [type]);
147
+ if (!hasOtherKeys) {
148
+ return type;
149
+ }
150
+ const declared = declaredObjectType(entry, context);
151
+ return declared !== null && hasIndexSignature(declared) ? declared : type;
152
+ }
153
+
154
+ /**
155
+ * The exploded object parameters' parts of `query`: their object types, each index signature
156
+ * widened by the value types of the other keys (see `exploded-query-values.ts`). A parameter that
157
+ * may be left out sends none of its keys then, so they are optional: `Partial<…>`.
158
+ */
159
+ function explodedParts(
160
+ exploded: readonly ExplodedEntry[],
161
+ members: readonly IrPropertySignature[],
162
+ context: TransformContext,
163
+ ): IrType[] {
164
+ const hasOtherKeys = members.length > 0 || exploded.length > 1;
165
+ const types = exploded.map((part) => explodedObjectType(part, hasOtherKeys, context));
166
+ const others = (index: number) => [
167
+ ...(members.length > 0 ? [irObject(members)] : []),
168
+ ...types.filter((_type, other) => other !== index),
169
+ ];
170
+ return types.map((type, index) => {
171
+ const values = others(index).flatMap((other) => declaredValueTypes(other, context.footer));
172
+ const widened = withIndexValues(type, values);
173
+ return exploded[index]?.entry.resolved.required ? widened : irReference("Partial", [widened]);
174
+ });
140
175
  }
141
176
 
142
177
  /** A location's parameters as members, and the object types of its exploded parameters. */
@@ -153,11 +188,11 @@ function locationParts(
153
188
  context: TransformContext,
154
189
  ): LocationParts {
155
190
  const members: IrPropertySignature[] = [];
156
- const exploded: IrType[] = [];
191
+ const exploded: ExplodedEntry[] = [];
157
192
  let isOptional = true;
158
193
  for (const entry of entries) {
159
194
  if (isExplodedEntry(entry, context)) {
160
- exploded.push(explodedPart(entry, location, context));
195
+ exploded.push({ entry, type: entryType(entry, location, context) });
161
196
  isOptional &&= !entry.resolved.required;
162
197
  continue;
163
198
  }
@@ -165,7 +200,7 @@ function locationParts(
165
200
  members.push(member);
166
201
  isOptional &&= member.isOptional;
167
202
  }
168
- return { members, exploded, isOptional };
203
+ return { members, exploded: explodedParts(exploded, members, context), isOptional };
169
204
  }
170
205
 
171
206
  /** The members' object, intersected with the exploded parameters' types; `never` for none. */
@@ -29,7 +29,7 @@ export function operationKeyOf(operationId: string): string {
29
29
  }
30
30
 
31
31
  /** Whether the method has an operation, not removed by `--exclude-deprecated`. */
32
- function isIncluded(
32
+ export function isIncludedOperation(
33
33
  operation: OperationEntry | undefined,
34
34
  context: TransformContext,
35
35
  ): operation is OperationEntry {
@@ -94,7 +94,7 @@ function methodMember(
94
94
  context: TransformContext,
95
95
  ): IrPropertySignature {
96
96
  const operation = pathItem[method];
97
- if (!isIncluded(operation, context)) {
97
+ if (!isIncludedOperation(operation, context)) {
98
98
  const isReadonly = context.options.immutable;
99
99
  return irProperty(toPropertyName(method), irKeyword("never"), { isOptional: true, isReadonly });
100
100
  }
@@ -113,7 +113,7 @@ function additionalOperationsMember(
113
113
  ): IrPropertySignature | null {
114
114
  const entries = documentEntries(pathItem.additionalOperations ?? {}, context.options);
115
115
  const members = entries
116
- .filter(([, operation]) => isIncluded(operation, context))
116
+ .filter(([, operation]) => isIncludedOperation(operation, context))
117
117
  .map(([method, operation]) => {
118
118
  const path = appendPointer(location.path, [ADDITIONAL_OPERATIONS_KEY, method]);
119
119
  return operationMember({ name: method, operation, path }, pathItem, location, context);
@@ -0,0 +1,152 @@
1
+ import { escapeTemplateText } from "../../../domain/ir/raw-text-escapes.js";
2
+ import type { OperationObject } from "../../../domain/openapi/operation-object.js";
3
+ import type {
4
+ ParameterObject,
5
+ ParameterOrReference,
6
+ } from "../../../domain/openapi/parameter-object.js";
7
+ import {
8
+ type PathItemObject,
9
+ pathItemOperations,
10
+ } from "../../../domain/openapi/path-item-object.js";
11
+ import type { ReferenceSchema, SchemaObject } from "../../../domain/openapi/schema-object.js";
12
+ import { FIX } from "../../../domain/output-fixes.js";
13
+ import type { TransformContext } from "../transform-context.js";
14
+ import type { PathKeyPart, PathPlaceholder } from "./path-key-overlaps.js";
15
+ import {
16
+ type PathParameterMatch,
17
+ placeholderText,
18
+ replacedTemplateParts,
19
+ } from "./path-template-replace.js";
20
+
21
+ /** The `--path-params-as-types` key of a path: its URL with a placeholder per parameter. */
22
+
23
+ /** `[^{}]` keeps the scan linear: `[^}]` retried from every `{` of a long run of them. */
24
+ const PATH_PARAMETER_RE = /\{[^{}]+\}/g;
25
+
26
+ /** Placeholders by parameter schema type; anything else is a string placeholder. */
27
+ const PLACEHOLDERS: ReadonlyMap<unknown, PathPlaceholder> = new Map([
28
+ ["number", "number"],
29
+ ["integer", "number"],
30
+ ["boolean", "boolean"],
31
+ ]);
32
+ const STRING_PLACEHOLDER: PathPlaceholder = "string";
33
+
34
+ function resolvedParameter(
35
+ parameter: ParameterOrReference,
36
+ context: TransformContext,
37
+ ): ParameterObject | undefined {
38
+ return "$ref" in parameter && parameter.$ref
39
+ ? (context.refs.resolve(parameter.$ref) as ParameterObject | undefined)
40
+ : (parameter as ParameterObject);
41
+ }
42
+
43
+ function addPathParameters(
44
+ parameters: readonly ParameterOrReference[],
45
+ byName: Map<string, ParameterObject>,
46
+ context: TransformContext,
47
+ ): void {
48
+ for (const parameter of parameters) {
49
+ const resolved = resolvedParameter(parameter, context);
50
+ if (resolved && resolved.in === "path") {
51
+ byName.set(resolved.name, resolved);
52
+ }
53
+ }
54
+ }
55
+
56
+ /** Path parameters of the path item and of its operations; later definitions win. */
57
+ function pathParameters(
58
+ pathItem: PathItemObject,
59
+ context: TransformContext,
60
+ ): Map<string, ParameterObject> {
61
+ const byName = new Map<string, ParameterObject>();
62
+ addPathParameters(pathItem.parameters ?? [], byName, context);
63
+ for (const { operation: entry } of pathItemOperations(pathItem)) {
64
+ const operation = (entry as ReferenceSchema).$ref
65
+ ? (context.refs.resolve((entry as ReferenceSchema).$ref) as OperationObject | undefined)
66
+ : (entry as OperationObject);
67
+ addPathParameters(operation?.parameters ?? [], byName, context);
68
+ }
69
+ return byName;
70
+ }
71
+
72
+ /** Each `{name}` of the URL and its own placeholder, from the URL split at the matches. */
73
+ function splitTemplateParts(url: string, matches: readonly PathParameterMatch[]): PathKeyPart[] {
74
+ return url.split(PATH_PARAMETER_RE).flatMap((text, index): PathKeyPart[] => {
75
+ const type = matches[index]?.type;
76
+ const textPart: PathKeyPart = { kind: "text", text };
77
+ return type === undefined ? [textPart] : [textPart, { kind: "placeholder", type }];
78
+ });
79
+ }
80
+
81
+ /**
82
+ * `--path-params-as-types`: the URL as template parts, each `{name}` replaced by a placeholder for
83
+ * its parameter's type, the way the original replaces them unless the `path-param-type-names` fix
84
+ * is on (see `replacedTemplateParts`). Null when the URL has no complete `{…}` placeholder.
85
+ */
86
+ export function pathTemplateParts(
87
+ url: string,
88
+ pathItem: PathItemObject,
89
+ context: TransformContext,
90
+ ): PathKeyPart[] | null {
91
+ const found = url.match(PATH_PARAMETER_RE);
92
+ if (!found) {
93
+ return null;
94
+ }
95
+ const parameters = pathParameters(pathItem, context);
96
+ const matches = found.map((match): PathParameterMatch => {
97
+ const schema = parameters.get(match.slice(1, -1))?.schema as SchemaObject | undefined;
98
+ return { match, type: PLACEHOLDERS.get(schema?.type) ?? STRING_PLACEHOLDER };
99
+ });
100
+ return context.options.fixes.has(FIX.PATH_PARAM_TYPE_NAMES)
101
+ ? splitTemplateParts(url, matches)
102
+ : replacedTemplateParts(url, matches);
103
+ }
104
+
105
+ /**
106
+ * The template literal type of the parts. The original escaped only backticks: a backslash or
107
+ * `${` in the URL could end the literal or open a placeholder, and add code to the generated file
108
+ * (intentional fix). So the text parts are escaped.
109
+ */
110
+ export function templateText(parts: readonly PathKeyPart[]): string {
111
+ const text = parts
112
+ .map((part) =>
113
+ part.kind === "text" ? escapeTemplateText(part.text) : placeholderText(part.type),
114
+ )
115
+ .join("");
116
+ return `\`${text}\``;
117
+ }
118
+
119
+ const BOOLEAN_TEXTS = ["true", "false"] as const;
120
+
121
+ const isBooleanPlaceholder = (part: PathKeyPart): boolean =>
122
+ part.kind === "placeholder" && part.type === "boolean";
123
+
124
+ /**
125
+ * The keys of a template whose only placeholders are `${boolean}`, with each written as `true`
126
+ * and as `false`. Such a template is a union of literals, and an index signature takes none
127
+ * (TS1337), so the original's `` [path: `/flags/${boolean}`] `` did not compile. A path with n
128
+ * boolean parameters gets 2ⁿ plain URLs (`/flags/true`), all with the same path item type. Next to
129
+ * another placeholder the template is a pattern, a valid signature that admits the same URLs, so
130
+ * those parts stay one key.
131
+ */
132
+ export function booleanExpandedKeys(parts: readonly PathKeyPart[]): PathKeyPart[][] {
133
+ const isBooleanOnly = parts.every((part) => part.kind === "text" || isBooleanPlaceholder(part));
134
+ if (!isBooleanOnly) {
135
+ return [[...parts]];
136
+ }
137
+ return parts.reduce<PathKeyPart[][]>(
138
+ (keys, part) => {
139
+ const choices: readonly PathKeyPart[] = isBooleanPlaceholder(part)
140
+ ? BOOLEAN_TEXTS.map((text) => ({ kind: "text", text }))
141
+ : [part];
142
+ return keys.flatMap((key) => choices.map((choice) => [...key, choice]));
143
+ },
144
+ [[]],
145
+ );
146
+ }
147
+
148
+ /** The URL of parts without placeholders; null when one is left. */
149
+ export function plainUrlOf(parts: readonly PathKeyPart[]): string | null {
150
+ const texts = parts.map((part) => (part.kind === "text" ? part.text : null));
151
+ return texts.includes(null) ? null : texts.join("");
152
+ }