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
@@ -83,23 +83,95 @@ const REMOVED_FLAGS: readonly (readonly [string, string])[] = [
83
83
  ];
84
84
 
85
85
  /** Flags that only work together with `--root-types`. */
86
- const ROOT_TYPES_FLAGS = ["--root-types-no-schema-prefix", "--root-types-keep-casing"] as const;
86
+ const ROOT_TYPES_FLAGS = ["rootTypesNoSchemaPrefix", "rootTypesKeepCasing"] as const;
87
87
 
88
- function rejectRemovedFlags(argv: readonly string[]): void {
88
+ const OPTIONS_END = "--";
89
+ const LONG_PREFIX = "--";
90
+ const NEGATION_PREFIX = "--no-";
91
+ const VALUE_SEPARATOR = "=";
92
+ const BOOLEAN_VALUES: ReadonlySet<string> = new Set(["true", "false"]);
93
+
94
+ /** A flag as written before `--`: its name (`--redoc`, `-o`) and the text after `=`, if any. */
95
+ interface WrittenFlag {
96
+ readonly name: string;
97
+ readonly value: string | undefined;
98
+ }
99
+
100
+ function writtenFlags(argv: readonly string[]): WrittenFlag[] {
101
+ const end = argv.indexOf(OPTIONS_END);
102
+ return (end === -1 ? argv : argv.slice(0, end))
103
+ .filter((arg) => arg.startsWith("-") && arg !== "-")
104
+ .map((arg) => {
105
+ const at = arg.indexOf(VALUE_SEPARATOR);
106
+ return at === -1
107
+ ? { name: arg, value: undefined }
108
+ : { name: arg.slice(0, at), value: arg.slice(at + 1) };
109
+ });
110
+ }
111
+
112
+ /**
113
+ * A long flag as yargs-parser reads it: in kebab-case and without `--no-`, so `--immutableTypes`
114
+ * and `--no-immutable-types` are `--immutable-types`. A short flag stays as written.
115
+ */
116
+ function canonicalFlagName(name: string): string {
117
+ if (!name.startsWith(LONG_PREFIX)) {
118
+ return name;
119
+ }
120
+ const bare = name.startsWith(NEGATION_PREFIX)
121
+ ? name.slice(NEGATION_PREFIX.length)
122
+ : name.slice(LONG_PREFIX.length);
123
+ return `${LONG_PREFIX}${kebabCase(bare)}`;
124
+ }
125
+
126
+ /** An old flag fails by its name in any spelling, also with a value (`--redoc=redocly.yaml`). */
127
+ function rejectRemovedFlags(flags: readonly WrittenFlag[]): void {
128
+ const names = new Set(flags.map(({ name }) => canonicalFlagName(name)));
89
129
  for (const [flag, message] of REMOVED_FLAGS) {
90
- if (argv.includes(flag)) {
130
+ if (names.has(flag)) {
91
131
  throw cliError("CLI_FLAG_REMOVED", message);
92
132
  }
93
133
  }
94
134
  }
95
135
 
136
+ const ALIASES = { redocly: ["c"], exportType: ["t"], output: ["o"] };
137
+
138
+ /** The short aliases of boolean flags (`-t`), which take a value the same way (`-t=true`). */
139
+ const BOOLEAN_ALIASES = Object.entries(ALIASES)
140
+ .filter(([flag]) => CAMEL_CASE_BOOLEAN_FLAGS.includes(flag))
141
+ .flatMap(([, aliases]) => aliases.map((alias) => `-${alias}`));
142
+
143
+ const BOOLEAN_FLAG_NAMES: ReadonlySet<string> = new Set([
144
+ ...BOOLEAN_FLAGS.map((flag) => `${LONG_PREFIX}${flag}`),
145
+ ...BOOLEAN_ALIASES,
146
+ ]);
147
+
148
+ /**
149
+ * A boolean flag takes `=true` or `=false`, and its `--no-` form takes no value. yargs-parser read
150
+ * any other value as false (`--enum=1`, `--alphabetize=yes`), which turned the option off.
151
+ */
152
+ function rejectInvalidBooleans(flags: readonly WrittenFlag[]): void {
153
+ for (const { name, value } of flags) {
154
+ const negated = name.startsWith(NEGATION_PREFIX)
155
+ ? `${LONG_PREFIX}${name.slice(NEGATION_PREFIX.length)}`
156
+ : undefined;
157
+ const isNegatedWithValue = negated !== undefined && BOOLEAN_FLAG_NAMES.has(negated);
158
+ const isInvalid = BOOLEAN_FLAG_NAMES.has(name) && !BOOLEAN_VALUES.has(value ?? "true");
159
+ if (value !== undefined && (isNegatedWithValue || isInvalid)) {
160
+ throw cliError(
161
+ "CLI_FLAG_INVALID",
162
+ `${name}=${value}: a boolean flag takes no value, or =true or =false.`,
163
+ );
164
+ }
165
+ }
166
+ }
167
+
96
168
  /** Notices for flags that have no effect in this combination, printed before the run. */
97
- export function ineffectiveFlagNotices(argv: readonly string[]): string[] {
98
- if (argv.includes("--root-types")) {
169
+ export function ineffectiveFlagNotices(flags: GeneratorFlags): string[] {
170
+ if (flags.rootTypes === true) {
99
171
  return [];
100
172
  }
101
- return ROOT_TYPES_FLAGS.filter((flag) => argv.includes(flag)).map(
102
- (flag) => `${flag} has no effect without --root-types flag`,
173
+ return ROOT_TYPES_FLAGS.filter((flag) => flags[flag] === true).map(
174
+ (flag) => `--${kebabCase(flag)} has no effect without --root-types flag`,
103
175
  );
104
176
  }
105
177
 
@@ -117,7 +189,10 @@ function optionalString(value: unknown): string | undefined {
117
189
  return value === undefined ? undefined : String(value);
118
190
  }
119
191
 
120
- /** The last value of a flag that may be given more than once. */
192
+ /**
193
+ * The last value of a flag that takes one value: given twice, the last one wins, as for the
194
+ * boolean flags (yargs-parser gives a list of every value).
195
+ */
121
196
  function lastString(value: unknown): string | undefined {
122
197
  return optionalString(Array.isArray(value) ? value.at(-1) : value);
123
198
  }
@@ -154,8 +229,6 @@ const STRING_FLAGS = [
154
229
  ...["localRefRoot", "remoteRefHosts"].flatMap((flag) => [flag, kebabCase(flag)]),
155
230
  ];
156
231
 
157
- const ALIASES = { redocly: ["c"], exportType: ["t"], output: ["o"] };
158
-
159
232
  /** Every name yargs-parser can return for a flag this CLI reads. */
160
233
  const KNOWN_FLAGS = new Set<string>([
161
234
  ...BOOLEAN_FLAGS,
@@ -186,11 +259,14 @@ function writtenFlagName(key: string, argv: readonly string[]): string {
186
259
  }
187
260
 
188
261
  /**
189
- * Parse the arguments after `node cli.js`. Fails with `CLI_FLAG_REMOVED` for an old flag and with
262
+ * Parse the arguments after `node cli.js`. Fails with `CLI_FLAG_REMOVED` for an old flag, with
263
+ * `CLI_FLAG_INVALID` for a boolean flag with another value than true or false, and with
190
264
  * `OPTION_FIX_UNKNOWN` for an unknown `--fix` name.
191
265
  */
192
266
  export function parseCliArguments(argv: readonly string[]): CliArguments {
193
- rejectRemovedFlags(argv);
267
+ const flags = writtenFlags(argv);
268
+ rejectRemovedFlags(flags);
269
+ rejectInvalidBooleans(flags);
194
270
  const parsed = parser([...argv], {
195
271
  boolean: BOOLEAN_FLAGS,
196
272
  string: STRING_FLAGS,
@@ -198,8 +274,8 @@ export function parseCliArguments(argv: readonly string[]): CliArguments {
198
274
  });
199
275
  return {
200
276
  input: optionalString(parsed._[0]),
201
- output: optionalString(parsed.output),
202
- redocly: optionalString(parsed.redocly),
277
+ output: lastString(parsed.output),
278
+ redocly: lastString(parsed.redocly),
203
279
  isCheck: parsed.check === true,
204
280
  isHelp: "help" in parsed,
205
281
  isVersion: "version" in parsed,
@@ -1,6 +1,7 @@
1
1
  import type { Readable } from "node:stream";
2
2
  import type {
3
3
  DirectoryCheck,
4
+ FileCheck,
4
5
  FileClaims,
5
6
  FileIdentity,
6
7
  FileReader,
@@ -33,10 +34,14 @@ export interface GeneratedTypes {
33
34
  readonly localFiles: readonly URL[];
34
35
  }
35
36
 
36
- /** Generate the types of one schema. */
37
+ /**
38
+ * Generate the types of one schema. With `apiName`, an API of `redocly.yaml`, every line the
39
+ * generation logs names that API.
40
+ */
37
41
  export type GenerateTypes = (
38
42
  source: SchemaSource,
39
43
  options: GeneratorOptions,
44
+ apiName?: string,
40
45
  ) => Promise<GeneratedTypes>;
41
46
 
42
47
  export interface CliDependencies {
@@ -55,7 +60,7 @@ export interface CliDependencies {
55
60
  * input with no prompt, which looks like a hang (upstream #1905).
56
61
  */
57
62
  readonly isStdinTerminal: () => boolean;
58
- readonly files: FileReader & FileWriter & FileIdentity & DirectoryCheck & FileClaims;
63
+ readonly files: FileReader & FileWriter & FileIdentity & DirectoryCheck & FileCheck & FileClaims;
59
64
  readonly redoclyConfigs: RedoclyConfigSource;
60
65
  readonly generate: GenerateTypes;
61
66
  /** A monotonic time in milliseconds, for the time printed after each output. */
@@ -99,8 +99,10 @@ const CLI_ERROR_REPORTS: Readonly<Record<ErrorCode, CliErrorReport>> = {
99
99
  ENUM_NAME_EMPTY: { exitCode: EXIT_CODES.SCHEMA },
100
100
  CALLBACK_RESULT_UNREADABLE: { exitCode: EXIT_CODES.USAGE },
101
101
  OPTION_FIX_UNKNOWN: { exitCode: EXIT_CODES.USAGE },
102
+ OPTION_INVALID: { exitCode: EXIT_CODES.USAGE },
102
103
  TYPESCRIPT_NOT_FOUND: { exitCode: EXIT_CODES.USAGE },
103
104
  CLI_FLAG_REMOVED: { exitCode: EXIT_CODES.USAGE },
105
+ CLI_FLAG_INVALID: { exitCode: EXIT_CODES.USAGE },
104
106
  CLI_GLOB_UNSUPPORTED: { exitCode: EXIT_CODES.USAGE },
105
107
  CLI_CONFIG_NOT_FOUND: { exitCode: EXIT_CODES.USAGE },
106
108
  CLI_CONFIG_INVALID: { exitCode: EXIT_CODES.USAGE },
@@ -127,6 +129,10 @@ export interface CliFailure {
127
129
  * else is a bug and prints its stack, so it can be reported.
128
130
  */
129
131
  export function describeCliFailure(error: unknown): CliFailure {
132
+ if (error instanceof ApiFailure) {
133
+ const failure = describeCliFailure(error.cause);
134
+ return { ...failure, message: `API ${error.apiName}: ${failure.message}` };
135
+ }
130
136
  if (!isOpenAPITypesafeError(error)) {
131
137
  const text = error instanceof Error ? (error.stack ?? error.message) : String(error);
132
138
  return { exitCode: EXIT_CODES.INTERNAL, message: `Unexpected error: ${text}` };
@@ -136,6 +142,22 @@ export function describeCliFailure(error: unknown): CliFailure {
136
142
  return { exitCode: report.exitCode, message: `${message} (${error.code})` };
137
143
  }
138
144
 
145
+ /**
146
+ * A failure of one API of a Redocly config. The CLI reports its cause with the API named first,
147
+ * as the config errors of an API are; the cause keeps its code and so its exit code.
148
+ */
149
+ export class ApiFailure extends Error {
150
+ override readonly name = "ApiFailure";
151
+ override readonly cause: unknown;
152
+ readonly apiName: string;
153
+
154
+ constructor(apiName: string, cause: unknown) {
155
+ super(`API ${apiName} failed`, { cause });
156
+ this.apiName = apiName;
157
+ this.cause = cause;
158
+ }
159
+ }
160
+
139
161
  /** Errors of the CLI itself; its messages are the original CLI's messages. */
140
162
  export function cliError(
141
163
  code: Extract<ErrorCode, `CLI_${string}` | `OUTPUT_${string}`>,
@@ -2,7 +2,9 @@ import path from "node:path";
2
2
  import { fileURLToPath, pathToFileURL } from "node:url";
3
3
  import { formatDuration } from "../adapters/terminal-logger/terminal-logger.js";
4
4
  import type { RedoclyConfig } from "../application/ports/redocly-config-source.js";
5
- import { redactUnparsedUrl } from "../domain/url-secrets.js";
5
+ import { hasUrlScheme } from "../domain/location-text.js";
6
+ import { terminalSafeText } from "../domain/terminal-text.js";
7
+ import { redactUnparsedUrl, redactUrlSecrets } from "../domain/url-secrets.js";
6
8
  import type { CliArguments } from "./cli-arguments.js";
7
9
  import type { CliDependencies, GeneratedTypes } from "./cli-dependencies.js";
8
10
  import { cliError } from "./cli-errors.js";
@@ -27,12 +29,6 @@ export interface OutputFile extends NamedOutput {
27
29
  readonly file: URL;
28
30
  }
29
31
 
30
- /**
31
- * A scheme of two or more characters (`https:`, `file:`). One letter is a Windows drive (`C:`), so
32
- * `C:\\specs\\api.yaml` stays a path.
33
- */
34
- const URL_SCHEME = /^[a-z][a-z\d+.-]+:/i;
35
-
36
32
  /**
37
33
  * The URL of a location the user wrote: a URL, else a file path, absolute or relative to the
38
34
  * directory of `base` (a directory or file URL). A relative `file:` URL (`file:api.yaml`) resolves
@@ -41,7 +37,7 @@ const URL_SCHEME = /^[a-z][a-z\d+.-]+:/i;
41
37
  * (`http://[::1/x`) fails with `CLI_LOCATION_INVALID`.
42
38
  */
43
39
  export function resolveLocationUrl(location: string, base: URL): URL {
44
- if (URL_SCHEME.test(location)) {
40
+ if (hasUrlScheme(location)) {
45
41
  const url = URL.parse(location, base.href);
46
42
  if (url === null) {
47
43
  const shown = redactUnparsedUrl(location);
@@ -202,15 +198,20 @@ export function duplicateOutputError(output: NamedOutput, others: readonly strin
202
198
 
203
199
  /** As `resolveLocationUrl`, but undefined for a URL that does not parse instead of a throw. */
204
200
  export function parseLocationUrl(location: string, base: URL): URL | undefined {
205
- if (URL_SCHEME.test(location)) {
201
+ if (hasUrlScheme(location)) {
206
202
  return URL.parse(location, base.href) ?? undefined;
207
203
  }
208
204
  return resolveLocationUrl(location, base);
209
205
  }
210
206
 
207
+ /**
208
+ * The line for a written file. It goes to the job log, so a source URL shows no secrets, and a
209
+ * line break or escape sequence in a name cannot start a forged line.
210
+ */
211
211
  function printDone(run: CliRun, output: OutputFile): void {
212
212
  const { style, now } = run.deps;
213
- const target = style.green(`${output.source} → ${style.bold(output.output)}`);
213
+ const source = terminalSafeText(redactUrlSecrets(output.source));
214
+ const target = style.green(`${source} → ${style.bold(terminalSafeText(output.output))}`);
214
215
  const duration = style.dim(`[${formatDuration(now() - run.startedAt)}]`);
215
216
  run.deps.console.info(`🚀 ${target} ${duration}`);
216
217
  }
package/src/cli/main.ts CHANGED
@@ -3,11 +3,14 @@ import { isatty } from "node:tty";
3
3
  import { pathToFileURL } from "node:url";
4
4
  import colors from "ansi-colors";
5
5
  import { createNodeFileSystem } from "../adapters/node-file-system/node-file-system.js";
6
+ import { createPipeSafeWriter } from "../adapters/pipe-safe-writer/pipe-safe-writer.js";
6
7
  import { createRedoclyConfigSource } from "../adapters/redocly-loader/redocly-config-source.js";
7
8
  import { astToString } from "../api/ast-to-string.js";
8
9
  import { COMMENT_HEADER } from "../api/comment-header.js";
9
10
  import { defaultLogger, monotonicNow, terminalSupportsColor } from "../api/default-ports.js";
10
11
  import { defaultGeneratorPorts, generateDocument } from "../api/openapi-ts.js";
12
+ import { terminalSafeText } from "../domain/terminal-text.js";
13
+ import { apiLogger } from "./api-logger.js";
11
14
  import type { CliConsole, CliDependencies, GenerateTypes, TextStyle } from "./cli-dependencies.js";
12
15
  import { runCli } from "./run-cli.js";
13
16
 
@@ -36,8 +39,10 @@ function terminalStyle(): TextStyle {
36
39
 
37
40
  const STDIN_DESCRIPTOR = 0;
38
41
 
39
- const generateTypes: GenerateTypes = async (source, options) => {
40
- const ports = await defaultGeneratorPorts(options);
42
+ const generateTypes: GenerateTypes = async (source, options, apiName) => {
43
+ const terminalLogger = defaultLogger(options.silent ?? false);
44
+ const logger = apiName === undefined ? terminalLogger : apiLogger(terminalLogger, apiName);
45
+ const ports = await defaultGeneratorPorts(options, logger);
41
46
  const { declarations, localFiles } = await generateDocument(source, options, ports);
42
47
  return { contents: `${COMMENT_HEADER}${astToString(declarations)}`, localFiles };
43
48
  };
@@ -46,8 +51,9 @@ function terminalConsole(): CliConsole {
46
51
  return {
47
52
  // biome-ignore lint/suspicious/noConsole: the CLI's own output lines
48
53
  info: (text) => console.info(text),
54
+ // A notice names flags and API names as written, so it is shown as one plain line.
49
55
  // biome-ignore lint/suspicious/noConsole: the CLI's own notices
50
- notice: (text) => console.warn(text),
56
+ notice: (text) => console.warn(terminalSafeText(text)),
51
57
  };
52
58
  }
53
59
 
@@ -58,7 +64,7 @@ function processDependencies(): CliDependencies {
58
64
  version: readVersion(),
59
65
  logger: defaultLogger(false),
60
66
  console: terminalConsole(),
61
- writeStdout: (text) => process.stdout.write(text),
67
+ writeStdout: createPipeSafeWriter(process.stdout),
62
68
  stdin: () => process.stdin,
63
69
  // `isatty` reads the descriptor without opening `process.stdin`, which would keep the
64
70
  // process alive.
@@ -10,7 +10,8 @@ import {
10
10
  unknownSettingWarnings,
11
11
  } from "./api-settings.js";
12
12
  import { type GeneratedApi, writeGeneratedApis } from "./api-writes.js";
13
- import { cliError } from "./cli-errors.js";
13
+ import { ineffectiveFlagNotices } from "./cli-arguments.js";
14
+ import { ApiFailure, cliError } from "./cli-errors.js";
14
15
  import {
15
16
  type CliRun,
16
17
  ensureOutputIsNotSchema,
@@ -24,7 +25,7 @@ import {
24
25
  } from "./cli-output.js";
25
26
  import { MULTIPLE_SCHEMAS_DOCS_URL } from "./docs-links.js";
26
27
  import { fixOption } from "./fix-option.js";
27
- import { refLimitOptions } from "./ref-limits.js";
28
+ import { type RefLimitOptions, refLimitOptions } from "./ref-limits.js";
28
29
 
29
30
  /** The `apis` of a Redocly config: each API is generated into its `x-openapi-ts.output`. */
30
31
 
@@ -92,16 +93,33 @@ function apiTarget(api: RedoclyApi, configRoot: URL): ApiTarget {
92
93
  return { name, root, settings, configRoot };
93
94
  }
94
95
 
95
- /** The generator options of one API: its own settings win over the CLI's flags. */
96
- function apiOptions(run: CliRun, redocly: RedoclyConfig, target: ApiTarget): GeneratorOptions {
96
+ /**
97
+ * What every API of a run shares: the config, the files of all APIs, and the reference limits of
98
+ * the command line, which are checked once before any API, so an invalid flag fails the run once.
99
+ */
100
+ interface ApiRun {
101
+ readonly redocly: RedoclyConfig;
102
+ readonly files: ConfigFiles;
103
+ readonly refLimits: RefLimitOptions;
104
+ }
105
+
106
+ /**
107
+ * The generator options of one API: its own settings win over the CLI's flags. A flag that has
108
+ * no effect with the merged flags is named for this API, since its settings may turn on the flag
109
+ * that the command line lacks, or set one that has no effect themselves.
110
+ */
111
+ function apiOptions(run: CliRun, apiRun: ApiRun, target: ApiTarget): GeneratorOptions {
97
112
  const { name, settings, configRoot } = target;
113
+ const flags = { ...run.args.generatorFlags, ...apiFlags(name, settings) };
114
+ for (const notice of ineffectiveFlagNotices(flags)) {
115
+ run.deps.console.notice(`API ${name}: ${notice}`);
116
+ }
98
117
  return {
99
- ...run.args.generatorFlags,
100
- ...apiFlags(name, settings),
101
- ...refLimitOptions(run.args, run.deps.cwd),
118
+ ...flags,
119
+ ...apiRun.refLimits,
102
120
  ...apiRefLimitOptions(name, settings, configRoot),
103
121
  ...fixOption(apiFixNames(name, settings) ?? run.args.fix),
104
- redocly,
122
+ redocly: apiRun.redocly,
105
123
  };
106
124
  }
107
125
 
@@ -122,12 +140,8 @@ function otherOutputs(files: ConfigFiles, apiName: string): NamedFile[] {
122
140
  * Generate the types of one API. Its output must not be a file the run reads before any API is
123
141
  * loaded (the root of any API, the Redocly config) nor another API's output.
124
142
  */
125
- async function generateApi(
126
- run: CliRun,
127
- redocly: RedoclyConfig,
128
- target: ApiTarget,
129
- files: ConfigFiles,
130
- ): Promise<GeneratedApi> {
143
+ async function generateApi(run: CliRun, apiRun: ApiRun, target: ApiTarget): Promise<GeneratedApi> {
144
+ const { files } = apiRun;
131
145
  for (const warning of unknownSettingWarnings(target.name, target.settings)) {
132
146
  run.deps.logger.warn(warning);
133
147
  }
@@ -136,8 +150,13 @@ async function generateApi(
136
150
  ensureOutputIsNotSchema(run, outputFile, files.schemas);
137
151
  ensureOutputIsOwn(run, outputFile, otherOutputs(files, target.name));
138
152
  const source = resolveLocationUrl(target.root, target.configRoot);
139
- const types = await run.deps.generate(source, apiOptions(run, redocly, target));
140
- return { name: target.name, outputFile, types };
153
+ const options = apiOptions(run, apiRun, target);
154
+ try {
155
+ const types = await run.deps.generate(source, options, target.name);
156
+ return { name: target.name, outputFile, types };
157
+ } catch (error) {
158
+ throw new ApiFailure(target.name, error);
159
+ }
141
160
  }
142
161
 
143
162
  /**
@@ -192,8 +211,9 @@ async function settledInTurn<T, R>(
192
211
  export async function generateRedoclyApis(run: CliRun, redocly: RedoclyConfig): Promise<unknown[]> {
193
212
  const apis = redoclyApisOf(redocly);
194
213
  const { configRoot, files } = configFilesOf(run, redocly, apis);
214
+ const apiRun = { redocly, files, refLimits: refLimitOptions(run.args, run.deps.cwd) };
195
215
  const results = await settledInTurn(apis, (api) =>
196
- generateApi(run, redocly, apiTarget(api, configRoot), files),
216
+ generateApi(run, apiRun, apiTarget(api, configRoot)),
197
217
  );
198
218
  const generated = results.flatMap((result) =>
199
219
  result.status === "fulfilled" ? [result.value] : [],
@@ -1,16 +1,35 @@
1
1
  import type { GeneratorOptions } from "../types.js";
2
2
  import type { CliArguments } from "./cli-arguments.js";
3
+ import { cliError } from "./cli-errors.js";
3
4
  import { resolveLocationUrl } from "./cli-output.js";
4
5
 
5
6
  /** The `$ref` limits of the CLI flags as generator options (threat model R1, R2, ADR-017). */
6
7
 
7
8
  export type RefLimitOptions = Pick<GeneratorOptions, "localRefRoot" | "remoteRefHosts">;
8
9
 
9
- /** `--local-ref-root` resolves against the working directory, like every other CLI path. */
10
+ const FILE_PROTOCOL = "file:";
11
+
12
+ /** A local `$ref` root as a URL; undefined for a URL of another protocol, which names no folder. */
13
+ export function localRootUrl(location: string, base: URL): URL | undefined {
14
+ const url = resolveLocationUrl(location, base);
15
+ return url.protocol === FILE_PROTOCOL ? url : undefined;
16
+ }
17
+
18
+ /**
19
+ * `--local-ref-root` resolves against the working directory, like every other CLI path. A URL of
20
+ * another protocol (`https://…`) fails with `CLI_FLAG_INVALID`.
21
+ */
10
22
  export function refLimitOptions(args: CliArguments, cwd: URL): RefLimitOptions {
11
23
  const { localRefRoot, remoteRefHosts } = args.refLimits;
24
+ const localRoot = localRefRoot === undefined ? undefined : localRootUrl(localRefRoot, cwd);
25
+ if (localRefRoot !== undefined && localRoot === undefined) {
26
+ throw cliError(
27
+ "CLI_FLAG_INVALID",
28
+ `--local-ref-root ${localRefRoot}: a directory path or a file: URL.`,
29
+ );
30
+ }
12
31
  return {
13
- ...(localRefRoot === undefined ? {} : { localRefRoot: resolveLocationUrl(localRefRoot, cwd) }),
32
+ ...(localRoot === undefined ? {} : { localRefRoot: localRoot }),
14
33
  ...(remoteRefHosts === undefined ? {} : { remoteRefHosts }),
15
34
  };
16
35
  }
@@ -1,5 +1,6 @@
1
1
  import type { Logger } from "../application/ports/logger.js";
2
2
  import type { RedoclyConfig } from "../application/ports/redocly-config-source.js";
3
+ import { hasUrlScheme } from "../domain/location-text.js";
3
4
  import { WARNING_CODES, warningText } from "../domain/warnings.js";
4
5
  import type { SchemaSource } from "../types.js";
5
6
  import { ineffectiveFlagNotices, parseCliArguments } from "./cli-arguments.js";
@@ -52,13 +53,29 @@ function schemaSource(run: CliRun): SchemaSource {
52
53
  return run.deps.stdin();
53
54
  }
54
55
 
56
+ /** The character that made the original CLI read a schema argument as a glob pattern. */
57
+ const GLOB_WILDCARD = "*";
58
+
59
+ /**
60
+ * Whether the schema argument is a glob pattern, which the CLI no longer expands: a path with a
61
+ * `*` that names no file. A URL is no pattern (`?fields=*` is its query), nor a file whose name
62
+ * has a `*`, which the CLI reads as any other file.
63
+ */
64
+ function isGlobPattern(run: CliRun, input: string): boolean {
65
+ return (
66
+ input.includes(GLOB_WILDCARD) &&
67
+ !hasUrlScheme(input) &&
68
+ !run.deps.files.isFile(resolveLocationUrl(input, run.deps.cwd))
69
+ );
70
+ }
71
+
55
72
  /**
56
73
  * One schema from a path, a URL or stdin; without `--output`, the types go to stdout. Warnings and
57
74
  * errors go to stderr either way, so they never mix with the types (upstream dropped warnings).
58
75
  */
59
76
  async function generateSingleSchema(run: CliRun, redocly: RedoclyConfig): Promise<void> {
60
77
  const { input, output } = run.args;
61
- if (input?.includes("*")) {
78
+ if (input !== undefined && isGlobPattern(run, input)) {
62
79
  throw cliError(
63
80
  "CLI_GLOB_UNSUPPORTED",
64
81
  "Globbing has been deprecated in favor of redocly.yaml’s `apis` keys. " +
@@ -72,6 +89,9 @@ async function generateSingleSchema(run: CliRun, redocly: RedoclyConfig): Promis
72
89
  "--check needs the generated file to compare with: add --output <file>.",
73
90
  );
74
91
  }
92
+ for (const notice of ineffectiveFlagNotices(run.args.generatorFlags)) {
93
+ run.deps.console.notice(notice);
94
+ }
75
95
  const source = schemaSource(run);
76
96
  const outputFile = output ? singleOutputFile(run, output, source, redocly) : undefined;
77
97
  const options = {
@@ -112,23 +132,35 @@ async function generate(run: CliRun): Promise<unknown[]> {
112
132
  await generateSingleSchema(run, redocly);
113
133
  return [];
114
134
  }
115
- if (run.args.input) {
116
- run.deps.logger.warn(
135
+ warnAboutIgnoredArguments(run);
136
+ return generateRedoclyApis(run, redocly);
137
+ }
138
+
139
+ /** With the APIs of a Redocly config, the input and the output of the command line are unused. */
140
+ function warnAboutIgnoredArguments(run: CliRun): void {
141
+ const { args, deps } = run;
142
+ if (args.input) {
143
+ deps.logger.warn(
117
144
  warningText(
118
145
  "APIs are specified both in Redocly Config and CLI argument. Only using Redocly config.",
119
146
  WARNING_CODES.CLI_INPUT_IGNORED,
120
147
  ),
121
148
  );
122
149
  }
123
- return generateRedoclyApis(run, redocly);
150
+ if (args.output) {
151
+ deps.logger.warn(
152
+ warningText(
153
+ `APIs are specified in Redocly Config, so --output ${args.output} is ignored: ` +
154
+ "each API is written to its x-openapi-ts.output.",
155
+ WARNING_CODES.CLI_OUTPUT_IGNORED,
156
+ ),
157
+ );
158
+ }
124
159
  }
125
160
 
126
161
  /** Run the command; the failures it returns did not stop the other outputs. */
127
162
  async function runCommand(argv: readonly string[], deps: CliDependencies): Promise<unknown[]> {
128
163
  const startedAt = deps.now();
129
- for (const notice of ineffectiveFlagNotices(argv)) {
130
- deps.console.notice(notice);
131
- }
132
164
  const args = parseCliArguments(argv);
133
165
  for (const flag of args.unknownFlags) {
134
166
  deps.console.notice(`Unknown flag ${flag} is ignored (see --help)`);