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
@@ -2,7 +2,7 @@
2
2
 
3
3
  const constructors = require('../../../domain/ir/constructors.cjs');
4
4
  const outputFixes = require('../../../domain/output-fixes.cjs');
5
- const helperTypes = require('../helper-types.cjs');
5
+ const declaredValueTypes = require('../declared-value-types.cjs');
6
6
  const sharedTypes = require('../shared-types.cjs');
7
7
  const typeCombinators = require('../type-combinators.cjs');
8
8
 
@@ -16,34 +16,6 @@ function unevaluatedSchemaOf(schema, request) {
16
16
  function isAnySchema(schema) {
17
17
  return schema === true || typeof schema === "object" && Object.keys(schema).length === 0;
18
18
  }
19
- function memberValueTypes(member) {
20
- if (member.kind === "indexSignature") {
21
- return [member.type];
22
- }
23
- return member.isOptional ? [member.type, constructors.irKeyword("undefined")] : [member.type];
24
- }
25
- function declaredValueTypes(type, request) {
26
- switch (type.kind) {
27
- case "object":
28
- return type.members.flatMap(memberValueTypes);
29
- case "union":
30
- case "intersection":
31
- return type.types.flatMap((member) => declaredValueTypes(member, request));
32
- case "reference":
33
- case "indexedAccess":
34
- case "raw":
35
- request.context.footer.requirePropertyValues();
36
- return [constructors.irReference(helperTypes.HELPER_TYPES.propertyValues.name, [type])];
37
- case "keyword":
38
- case "stringLiteral":
39
- case "numberLiteral":
40
- case "booleanLiteral":
41
- case "array":
42
- case "tuple":
43
- case "readonly":
44
- return [];
45
- }
46
- }
47
19
  function unevaluatedPropertiesType(schema, composed, request) {
48
20
  const unevaluated = unevaluatedSchemaOf(schema, request);
49
21
  if (unevaluated === null) {
@@ -51,7 +23,7 @@ function unevaluatedPropertiesType(schema, composed, request) {
51
23
  }
52
24
  const valueTypes = isAnySchema(unevaluated) ? [sharedTypes.UNKNOWN_TYPE] : [
53
25
  request.transformNested(unevaluated, request.location, true),
54
- ...composed === null ? [] : declaredValueTypes(composed, request)
26
+ ...composed === null ? [] : declaredValueTypes.declaredValueTypes(composed, request.context.footer)
55
27
  ];
56
28
  const { immutable } = request.context.options;
57
29
  return constructors.irObject([constructors.irStringIndexSignature("key", typeCombinators.unionOf(valueTypes), immutable)]);
@@ -1 +1 @@
1
- {"version":3,"file":"unevaluated-properties.cjs","sources":["../../../../src/application/transform/schema/unevaluated-properties.ts"],"sourcesContent":["import {\n irKeyword,\n irObject,\n irReference,\n irStringIndexSignature,\n} from \"../../../domain/ir/constructors.js\";\nimport type { IrMember, IrType } from \"../../../domain/ir/nodes.js\";\nimport type { Schema, SchemaObject } from \"../../../domain/openapi/schema-object.js\";\nimport { FIX } from \"../../../domain/output-fixes.js\";\nimport { HELPER_TYPES } from \"../helper-types.js\";\nimport { UNKNOWN_TYPE } from \"../shared-types.js\";\nimport { unionOf } from \"../type-combinators.js\";\nimport type { SchemaRequest } from \"./schema-rule.js\";\n\n/**\n * The `unevaluated-properties` fix (ADR-021, roadmap R11; upstream #2839, #2880). Without it\n * `unevaluatedProperties` is ignored, so its value type is lost and an object with only that\n * keyword is `Record<string, never>`. With it the composed type is intersected with an index\n * signature, as `additionalProperties` gives: every key that no other keyword declares has the\n * `unevaluatedProperties` type. TypeScript checks that index signature against every key of a\n * value, declared ones included, so its type also holds the types of the declared properties\n * (of this schema and of its `allOf`, `anyOf` and `oneOf` members); otherwise a valid value would\n * not be assignable. `false` adds nothing, like `additionalProperties: false`: TypeScript has no\n * closed object type.\n */\n\n/**\n * Whether `unevaluatedProperties` applies. It types the keys left over at this level, so it\n * does nothing next to `additionalProperties` (which already types them all), and only an object\n * schema has keys. A `type` list is typed one listed type at a time, so its object gets it.\n */\nfunction unevaluatedSchemaOf(schema: SchemaObject, request: SchemaRequest): Schema | null {\n const { unevaluatedProperties } = schema;\n if (\n !request.context.options.fixes.has(FIX.UNEVALUATED_PROPERTIES) ||\n unevaluatedProperties === undefined ||\n unevaluatedProperties === false ||\n schema.additionalProperties !== undefined\n ) {\n return null;\n }\n return schema.type === undefined || schema.type === \"object\" ? unevaluatedProperties : null;\n}\n\nfunction isAnySchema(schema: Schema): boolean {\n return schema === true || (typeof schema === \"object\" && Object.keys(schema).length === 0);\n}\n\nfunction memberValueTypes(member: IrMember): IrType[] {\n if (member.kind === \"indexSignature\") {\n return [member.type];\n }\n return member.isOptional ? [member.type, irKeyword(\"undefined\")] : [member.type];\n}\n\n/**\n * The value types a key of the composed type can have, read from its IR: the members of object\n * types, through unions and intersections. A reference (a `$ref`, `Omit`, `WithRequired`) or a raw\n * type is read with `PropertyValues`. Primitives, literals and arrays declare no keys.\n */\nfunction declaredValueTypes(type: IrType, request: SchemaRequest): IrType[] {\n switch (type.kind) {\n case \"object\":\n return type.members.flatMap(memberValueTypes);\n case \"union\":\n case \"intersection\":\n return type.types.flatMap((member) => declaredValueTypes(member, request));\n case \"reference\":\n case \"indexedAccess\":\n case \"raw\":\n request.context.footer.requirePropertyValues();\n return [irReference(HELPER_TYPES.propertyValues.name, [type])];\n case \"keyword\":\n case \"stringLiteral\":\n case \"numberLiteral\":\n case \"booleanLiteral\":\n case \"array\":\n case \"tuple\":\n case \"readonly\":\n return [];\n }\n}\n\n/**\n * The index signature object for `unevaluatedProperties`, given the composed type of the other\n * keywords (null when there is none). Null when the fix is off or the keyword does not apply.\n */\nexport function unevaluatedPropertiesType(\n schema: SchemaObject,\n composed: IrType | null,\n request: SchemaRequest,\n): IrType | null {\n const unevaluated = unevaluatedSchemaOf(schema, request);\n if (unevaluated === null) {\n return null;\n }\n const valueTypes = isAnySchema(unevaluated)\n ? [UNKNOWN_TYPE]\n : [\n request.transformNested(unevaluated, request.location, true),\n ...(composed === null ? [] : declaredValueTypes(composed, request)),\n ];\n const { immutable } = request.context.options;\n return irObject([irStringIndexSignature(\"key\", unionOf(valueTypes), immutable)]);\n}\n"],"names":["FIX","irKeyword","irReference","HELPER_TYPES","UNKNOWN_TYPE","irObject","irStringIndexSignature","unionOf"],"mappings":";;;;;;;;AA+BA,SAAS,mBAAA,CAAoB,QAAsB,OAAA,EAAuC;AACxF,EAAA,MAAM,EAAE,uBAAsB,GAAI,MAAA;AAClC,EAAA,IACE,CAAC,OAAA,CAAQ,OAAA,CAAQ,OAAA,CAAQ,MAAM,GAAA,CAAIA,eAAA,CAAI,sBAAsB,CAAA,IAC7D,0BAA0B,MAAA,IAC1B,qBAAA,KAA0B,KAAA,IAC1B,MAAA,CAAO,yBAAyB,MAAA,EAChC;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,OAAO,IAAA,KAAS,MAAA,IAAa,MAAA,CAAO,IAAA,KAAS,WAAW,qBAAA,GAAwB,IAAA;AACzF;AAEA,SAAS,YAAY,MAAA,EAAyB;AAC5C,EAAA,OAAO,MAAA,KAAW,QAAS,OAAO,MAAA,KAAW,YAAY,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,CAAE,MAAA,KAAW,CAAA;AAC1F;AAEA,SAAS,iBAAiB,MAAA,EAA4B;AACpD,EAAA,IAAI,MAAA,CAAO,SAAS,gBAAA,EAAkB;AACpC,IAAA,OAAO,CAAC,OAAO,IAAI,CAAA;AAAA,EACrB;AACA,EAAA,OAAO,MAAA,CAAO,UAAA,GAAa,CAAC,MAAA,CAAO,IAAA,EAAMC,sBAAA,CAAU,WAAW,CAAC,CAAA,GAAI,CAAC,MAAA,CAAO,IAAI,CAAA;AACjF;AAOA,SAAS,kBAAA,CAAmB,MAAc,OAAA,EAAkC;AAC1E,EAAA,QAAQ,KAAK,IAAA;AAAM,IACjB,KAAK,QAAA;AACH,MAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,gBAAgB,CAAA;AAAA,IAC9C,KAAK,OAAA;AAAA,IACL,KAAK,cAAA;AACH,MAAA,OAAO,IAAA,CAAK,MAAM,OAAA,CAAQ,CAAC,WAAW,kBAAA,CAAmB,MAAA,EAAQ,OAAO,CAAC,CAAA;AAAA,IAC3E,KAAK,WAAA;AAAA,IACL,KAAK,eAAA;AAAA,IACL,KAAK,KAAA;AACH,MAAA,OAAA,CAAQ,OAAA,CAAQ,OAAO,qBAAA,EAAsB;AAC7C,MAAA,OAAO,CAACC,yBAAYC,wBAAA,CAAa,cAAA,CAAe,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;AAAA,IAC/D,KAAK,SAAA;AAAA,IACL,KAAK,eAAA;AAAA,IACL,KAAK,eAAA;AAAA,IACL,KAAK,gBAAA;AAAA,IACL,KAAK,OAAA;AAAA,IACL,KAAK,OAAA;AAAA,IACL,KAAK,UAAA;AACH,MAAA,OAAO,EAAC;AAAA;AAEd;AAMO,SAAS,yBAAA,CACd,MAAA,EACA,QAAA,EACA,OAAA,EACe;AACf,EAAA,MAAM,WAAA,GAAc,mBAAA,CAAoB,MAAA,EAAQ,OAAO,CAAA;AACvD,EAAA,IAAI,gBAAgB,IAAA,EAAM;AACxB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,aAAa,WAAA,CAAY,WAAW,CAAA,GACtC,CAACC,wBAAY,CAAA,GACb;AAAA,IACE,OAAA,CAAQ,eAAA,CAAgB,WAAA,EAAa,OAAA,CAAQ,UAAU,IAAI,CAAA;AAAA,IAC3D,GAAI,QAAA,KAAa,IAAA,GAAO,EAAC,GAAI,kBAAA,CAAmB,UAAU,OAAO;AAAA,GACnE;AACJ,EAAA,MAAM,EAAE,SAAA,EAAU,GAAI,OAAA,CAAQ,OAAA,CAAQ,OAAA;AACtC,EAAA,OAAOC,qBAAA,CAAS,CAACC,mCAAA,CAAuB,KAAA,EAAOC,wBAAQ,UAAU,CAAA,EAAG,SAAS,CAAC,CAAC,CAAA;AACjF;;"}
1
+ {"version":3,"file":"unevaluated-properties.cjs","sources":["../../../../src/application/transform/schema/unevaluated-properties.ts"],"sourcesContent":["import { irObject, irStringIndexSignature } from \"../../../domain/ir/constructors.js\";\nimport type { IrType } from \"../../../domain/ir/nodes.js\";\nimport type { Schema, SchemaObject } from \"../../../domain/openapi/schema-object.js\";\nimport { FIX } from \"../../../domain/output-fixes.js\";\nimport { declaredValueTypes } from \"../declared-value-types.js\";\nimport { UNKNOWN_TYPE } from \"../shared-types.js\";\nimport { unionOf } from \"../type-combinators.js\";\nimport type { SchemaRequest } from \"./schema-rule.js\";\n\n/**\n * The `unevaluated-properties` fix (ADR-021, roadmap R11; upstream #2839, #2880). Without it\n * `unevaluatedProperties` is ignored, so its value type is lost and an object with only that\n * keyword is `Record<string, never>`. With it the composed type is intersected with an index\n * signature, as `additionalProperties` gives: every key that no other keyword declares has the\n * `unevaluatedProperties` type. TypeScript checks that index signature against every key of a\n * value, declared ones included, so its type also holds the types of the declared properties\n * (of this schema and of its `allOf`, `anyOf` and `oneOf` members); otherwise a valid value would\n * not be assignable. `false` adds nothing, like `additionalProperties: false`: TypeScript has no\n * closed object type.\n */\n\n/**\n * Whether `unevaluatedProperties` applies. It types the keys left over at this level, so it\n * does nothing next to `additionalProperties` (which already types them all), and only an object\n * schema has keys. A `type` list is typed one listed type at a time, so its object gets it.\n */\nfunction unevaluatedSchemaOf(schema: SchemaObject, request: SchemaRequest): Schema | null {\n const { unevaluatedProperties } = schema;\n if (\n !request.context.options.fixes.has(FIX.UNEVALUATED_PROPERTIES) ||\n unevaluatedProperties === undefined ||\n unevaluatedProperties === false ||\n schema.additionalProperties !== undefined\n ) {\n return null;\n }\n return schema.type === undefined || schema.type === \"object\" ? unevaluatedProperties : null;\n}\n\nfunction isAnySchema(schema: Schema): boolean {\n return schema === true || (typeof schema === \"object\" && Object.keys(schema).length === 0);\n}\n\n/**\n * The index signature object for `unevaluatedProperties`, given the composed type of the other\n * keywords (null when there is none). Null when the fix is off or the keyword does not apply.\n */\nexport function unevaluatedPropertiesType(\n schema: SchemaObject,\n composed: IrType | null,\n request: SchemaRequest,\n): IrType | null {\n const unevaluated = unevaluatedSchemaOf(schema, request);\n if (unevaluated === null) {\n return null;\n }\n const valueTypes = isAnySchema(unevaluated)\n ? [UNKNOWN_TYPE]\n : [\n request.transformNested(unevaluated, request.location, true),\n ...(composed === null ? [] : declaredValueTypes(composed, request.context.footer)),\n ];\n const { immutable } = request.context.options;\n return irObject([irStringIndexSignature(\"key\", unionOf(valueTypes), immutable)]);\n}\n"],"names":["FIX","UNKNOWN_TYPE","declaredValueTypes","irObject","irStringIndexSignature","unionOf"],"mappings":";;;;;;;;AA0BA,SAAS,mBAAA,CAAoB,QAAsB,OAAA,EAAuC;AACxF,EAAA,MAAM,EAAE,uBAAsB,GAAI,MAAA;AAClC,EAAA,IACE,CAAC,OAAA,CAAQ,OAAA,CAAQ,OAAA,CAAQ,MAAM,GAAA,CAAIA,eAAA,CAAI,sBAAsB,CAAA,IAC7D,0BAA0B,MAAA,IAC1B,qBAAA,KAA0B,KAAA,IAC1B,MAAA,CAAO,yBAAyB,MAAA,EAChC;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,OAAO,IAAA,KAAS,MAAA,IAAa,MAAA,CAAO,IAAA,KAAS,WAAW,qBAAA,GAAwB,IAAA;AACzF;AAEA,SAAS,YAAY,MAAA,EAAyB;AAC5C,EAAA,OAAO,MAAA,KAAW,QAAS,OAAO,MAAA,KAAW,YAAY,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,CAAE,MAAA,KAAW,CAAA;AAC1F;AAMO,SAAS,yBAAA,CACd,MAAA,EACA,QAAA,EACA,OAAA,EACe;AACf,EAAA,MAAM,WAAA,GAAc,mBAAA,CAAoB,MAAA,EAAQ,OAAO,CAAA;AACvD,EAAA,IAAI,gBAAgB,IAAA,EAAM;AACxB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,aAAa,WAAA,CAAY,WAAW,CAAA,GACtC,CAACC,wBAAY,CAAA,GACb;AAAA,IACE,OAAA,CAAQ,eAAA,CAAgB,WAAA,EAAa,OAAA,CAAQ,UAAU,IAAI,CAAA;AAAA,IAC3D,GAAI,aAAa,IAAA,GAAO,KAAKC,qCAAA,CAAmB,QAAA,EAAU,OAAA,CAAQ,OAAA,CAAQ,MAAM;AAAA,GAClF;AACJ,EAAA,MAAM,EAAE,SAAA,EAAU,GAAI,OAAA,CAAQ,OAAA,CAAQ,OAAA;AACtC,EAAA,OAAOC,qBAAA,CAAS,CAACC,mCAAA,CAAuB,KAAA,EAAOC,wBAAQ,UAAU,CAAA,EAAG,SAAS,CAAC,CAAC,CAAA;AACjF;;"}
@@ -1,6 +1,6 @@
1
- import { irObject, irStringIndexSignature, irReference, irKeyword } from '../../../domain/ir/constructors.mjs';
1
+ import { irObject, irStringIndexSignature } from '../../../domain/ir/constructors.mjs';
2
2
  import { FIX } from '../../../domain/output-fixes.mjs';
3
- import { HELPER_TYPES } from '../helper-types.mjs';
3
+ import { declaredValueTypes } from '../declared-value-types.mjs';
4
4
  import { UNKNOWN_TYPE } from '../shared-types.mjs';
5
5
  import { unionOf } from '../type-combinators.mjs';
6
6
 
@@ -14,34 +14,6 @@ function unevaluatedSchemaOf(schema, request) {
14
14
  function isAnySchema(schema) {
15
15
  return schema === true || typeof schema === "object" && Object.keys(schema).length === 0;
16
16
  }
17
- function memberValueTypes(member) {
18
- if (member.kind === "indexSignature") {
19
- return [member.type];
20
- }
21
- return member.isOptional ? [member.type, irKeyword("undefined")] : [member.type];
22
- }
23
- function declaredValueTypes(type, request) {
24
- switch (type.kind) {
25
- case "object":
26
- return type.members.flatMap(memberValueTypes);
27
- case "union":
28
- case "intersection":
29
- return type.types.flatMap((member) => declaredValueTypes(member, request));
30
- case "reference":
31
- case "indexedAccess":
32
- case "raw":
33
- request.context.footer.requirePropertyValues();
34
- return [irReference(HELPER_TYPES.propertyValues.name, [type])];
35
- case "keyword":
36
- case "stringLiteral":
37
- case "numberLiteral":
38
- case "booleanLiteral":
39
- case "array":
40
- case "tuple":
41
- case "readonly":
42
- return [];
43
- }
44
- }
45
17
  function unevaluatedPropertiesType(schema, composed, request) {
46
18
  const unevaluated = unevaluatedSchemaOf(schema, request);
47
19
  if (unevaluated === null) {
@@ -49,7 +21,7 @@ function unevaluatedPropertiesType(schema, composed, request) {
49
21
  }
50
22
  const valueTypes = isAnySchema(unevaluated) ? [UNKNOWN_TYPE] : [
51
23
  request.transformNested(unevaluated, request.location, true),
52
- ...composed === null ? [] : declaredValueTypes(composed, request)
24
+ ...composed === null ? [] : declaredValueTypes(composed, request.context.footer)
53
25
  ];
54
26
  const { immutable } = request.context.options;
55
27
  return irObject([irStringIndexSignature("key", unionOf(valueTypes), immutable)]);
@@ -1 +1 @@
1
- {"version":3,"file":"unevaluated-properties.mjs","sources":["../../../../src/application/transform/schema/unevaluated-properties.ts"],"sourcesContent":["import {\n irKeyword,\n irObject,\n irReference,\n irStringIndexSignature,\n} from \"../../../domain/ir/constructors.js\";\nimport type { IrMember, IrType } from \"../../../domain/ir/nodes.js\";\nimport type { Schema, SchemaObject } from \"../../../domain/openapi/schema-object.js\";\nimport { FIX } from \"../../../domain/output-fixes.js\";\nimport { HELPER_TYPES } from \"../helper-types.js\";\nimport { UNKNOWN_TYPE } from \"../shared-types.js\";\nimport { unionOf } from \"../type-combinators.js\";\nimport type { SchemaRequest } from \"./schema-rule.js\";\n\n/**\n * The `unevaluated-properties` fix (ADR-021, roadmap R11; upstream #2839, #2880). Without it\n * `unevaluatedProperties` is ignored, so its value type is lost and an object with only that\n * keyword is `Record<string, never>`. With it the composed type is intersected with an index\n * signature, as `additionalProperties` gives: every key that no other keyword declares has the\n * `unevaluatedProperties` type. TypeScript checks that index signature against every key of a\n * value, declared ones included, so its type also holds the types of the declared properties\n * (of this schema and of its `allOf`, `anyOf` and `oneOf` members); otherwise a valid value would\n * not be assignable. `false` adds nothing, like `additionalProperties: false`: TypeScript has no\n * closed object type.\n */\n\n/**\n * Whether `unevaluatedProperties` applies. It types the keys left over at this level, so it\n * does nothing next to `additionalProperties` (which already types them all), and only an object\n * schema has keys. A `type` list is typed one listed type at a time, so its object gets it.\n */\nfunction unevaluatedSchemaOf(schema: SchemaObject, request: SchemaRequest): Schema | null {\n const { unevaluatedProperties } = schema;\n if (\n !request.context.options.fixes.has(FIX.UNEVALUATED_PROPERTIES) ||\n unevaluatedProperties === undefined ||\n unevaluatedProperties === false ||\n schema.additionalProperties !== undefined\n ) {\n return null;\n }\n return schema.type === undefined || schema.type === \"object\" ? unevaluatedProperties : null;\n}\n\nfunction isAnySchema(schema: Schema): boolean {\n return schema === true || (typeof schema === \"object\" && Object.keys(schema).length === 0);\n}\n\nfunction memberValueTypes(member: IrMember): IrType[] {\n if (member.kind === \"indexSignature\") {\n return [member.type];\n }\n return member.isOptional ? [member.type, irKeyword(\"undefined\")] : [member.type];\n}\n\n/**\n * The value types a key of the composed type can have, read from its IR: the members of object\n * types, through unions and intersections. A reference (a `$ref`, `Omit`, `WithRequired`) or a raw\n * type is read with `PropertyValues`. Primitives, literals and arrays declare no keys.\n */\nfunction declaredValueTypes(type: IrType, request: SchemaRequest): IrType[] {\n switch (type.kind) {\n case \"object\":\n return type.members.flatMap(memberValueTypes);\n case \"union\":\n case \"intersection\":\n return type.types.flatMap((member) => declaredValueTypes(member, request));\n case \"reference\":\n case \"indexedAccess\":\n case \"raw\":\n request.context.footer.requirePropertyValues();\n return [irReference(HELPER_TYPES.propertyValues.name, [type])];\n case \"keyword\":\n case \"stringLiteral\":\n case \"numberLiteral\":\n case \"booleanLiteral\":\n case \"array\":\n case \"tuple\":\n case \"readonly\":\n return [];\n }\n}\n\n/**\n * The index signature object for `unevaluatedProperties`, given the composed type of the other\n * keywords (null when there is none). Null when the fix is off or the keyword does not apply.\n */\nexport function unevaluatedPropertiesType(\n schema: SchemaObject,\n composed: IrType | null,\n request: SchemaRequest,\n): IrType | null {\n const unevaluated = unevaluatedSchemaOf(schema, request);\n if (unevaluated === null) {\n return null;\n }\n const valueTypes = isAnySchema(unevaluated)\n ? [UNKNOWN_TYPE]\n : [\n request.transformNested(unevaluated, request.location, true),\n ...(composed === null ? [] : declaredValueTypes(composed, request)),\n ];\n const { immutable } = request.context.options;\n return irObject([irStringIndexSignature(\"key\", unionOf(valueTypes), immutable)]);\n}\n"],"names":[],"mappings":";;;;;;AA+BA,SAAS,mBAAA,CAAoB,QAAsB,OAAA,EAAuC;AACxF,EAAA,MAAM,EAAE,uBAAsB,GAAI,MAAA;AAClC,EAAA,IACE,CAAC,OAAA,CAAQ,OAAA,CAAQ,OAAA,CAAQ,MAAM,GAAA,CAAI,GAAA,CAAI,sBAAsB,CAAA,IAC7D,0BAA0B,MAAA,IAC1B,qBAAA,KAA0B,KAAA,IAC1B,MAAA,CAAO,yBAAyB,MAAA,EAChC;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,OAAO,IAAA,KAAS,MAAA,IAAa,MAAA,CAAO,IAAA,KAAS,WAAW,qBAAA,GAAwB,IAAA;AACzF;AAEA,SAAS,YAAY,MAAA,EAAyB;AAC5C,EAAA,OAAO,MAAA,KAAW,QAAS,OAAO,MAAA,KAAW,YAAY,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,CAAE,MAAA,KAAW,CAAA;AAC1F;AAEA,SAAS,iBAAiB,MAAA,EAA4B;AACpD,EAAA,IAAI,MAAA,CAAO,SAAS,gBAAA,EAAkB;AACpC,IAAA,OAAO,CAAC,OAAO,IAAI,CAAA;AAAA,EACrB;AACA,EAAA,OAAO,MAAA,CAAO,UAAA,GAAa,CAAC,MAAA,CAAO,IAAA,EAAM,SAAA,CAAU,WAAW,CAAC,CAAA,GAAI,CAAC,MAAA,CAAO,IAAI,CAAA;AACjF;AAOA,SAAS,kBAAA,CAAmB,MAAc,OAAA,EAAkC;AAC1E,EAAA,QAAQ,KAAK,IAAA;AAAM,IACjB,KAAK,QAAA;AACH,MAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,gBAAgB,CAAA;AAAA,IAC9C,KAAK,OAAA;AAAA,IACL,KAAK,cAAA;AACH,MAAA,OAAO,IAAA,CAAK,MAAM,OAAA,CAAQ,CAAC,WAAW,kBAAA,CAAmB,MAAA,EAAQ,OAAO,CAAC,CAAA;AAAA,IAC3E,KAAK,WAAA;AAAA,IACL,KAAK,eAAA;AAAA,IACL,KAAK,KAAA;AACH,MAAA,OAAA,CAAQ,OAAA,CAAQ,OAAO,qBAAA,EAAsB;AAC7C,MAAA,OAAO,CAAC,YAAY,YAAA,CAAa,cAAA,CAAe,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;AAAA,IAC/D,KAAK,SAAA;AAAA,IACL,KAAK,eAAA;AAAA,IACL,KAAK,eAAA;AAAA,IACL,KAAK,gBAAA;AAAA,IACL,KAAK,OAAA;AAAA,IACL,KAAK,OAAA;AAAA,IACL,KAAK,UAAA;AACH,MAAA,OAAO,EAAC;AAAA;AAEd;AAMO,SAAS,yBAAA,CACd,MAAA,EACA,QAAA,EACA,OAAA,EACe;AACf,EAAA,MAAM,WAAA,GAAc,mBAAA,CAAoB,MAAA,EAAQ,OAAO,CAAA;AACvD,EAAA,IAAI,gBAAgB,IAAA,EAAM;AACxB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,aAAa,WAAA,CAAY,WAAW,CAAA,GACtC,CAAC,YAAY,CAAA,GACb;AAAA,IACE,OAAA,CAAQ,eAAA,CAAgB,WAAA,EAAa,OAAA,CAAQ,UAAU,IAAI,CAAA;AAAA,IAC3D,GAAI,QAAA,KAAa,IAAA,GAAO,EAAC,GAAI,kBAAA,CAAmB,UAAU,OAAO;AAAA,GACnE;AACJ,EAAA,MAAM,EAAE,SAAA,EAAU,GAAI,OAAA,CAAQ,OAAA,CAAQ,OAAA;AACtC,EAAA,OAAO,QAAA,CAAS,CAAC,sBAAA,CAAuB,KAAA,EAAO,QAAQ,UAAU,CAAA,EAAG,SAAS,CAAC,CAAC,CAAA;AACjF;;"}
1
+ {"version":3,"file":"unevaluated-properties.mjs","sources":["../../../../src/application/transform/schema/unevaluated-properties.ts"],"sourcesContent":["import { irObject, irStringIndexSignature } from \"../../../domain/ir/constructors.js\";\nimport type { IrType } from \"../../../domain/ir/nodes.js\";\nimport type { Schema, SchemaObject } from \"../../../domain/openapi/schema-object.js\";\nimport { FIX } from \"../../../domain/output-fixes.js\";\nimport { declaredValueTypes } from \"../declared-value-types.js\";\nimport { UNKNOWN_TYPE } from \"../shared-types.js\";\nimport { unionOf } from \"../type-combinators.js\";\nimport type { SchemaRequest } from \"./schema-rule.js\";\n\n/**\n * The `unevaluated-properties` fix (ADR-021, roadmap R11; upstream #2839, #2880). Without it\n * `unevaluatedProperties` is ignored, so its value type is lost and an object with only that\n * keyword is `Record<string, never>`. With it the composed type is intersected with an index\n * signature, as `additionalProperties` gives: every key that no other keyword declares has the\n * `unevaluatedProperties` type. TypeScript checks that index signature against every key of a\n * value, declared ones included, so its type also holds the types of the declared properties\n * (of this schema and of its `allOf`, `anyOf` and `oneOf` members); otherwise a valid value would\n * not be assignable. `false` adds nothing, like `additionalProperties: false`: TypeScript has no\n * closed object type.\n */\n\n/**\n * Whether `unevaluatedProperties` applies. It types the keys left over at this level, so it\n * does nothing next to `additionalProperties` (which already types them all), and only an object\n * schema has keys. A `type` list is typed one listed type at a time, so its object gets it.\n */\nfunction unevaluatedSchemaOf(schema: SchemaObject, request: SchemaRequest): Schema | null {\n const { unevaluatedProperties } = schema;\n if (\n !request.context.options.fixes.has(FIX.UNEVALUATED_PROPERTIES) ||\n unevaluatedProperties === undefined ||\n unevaluatedProperties === false ||\n schema.additionalProperties !== undefined\n ) {\n return null;\n }\n return schema.type === undefined || schema.type === \"object\" ? unevaluatedProperties : null;\n}\n\nfunction isAnySchema(schema: Schema): boolean {\n return schema === true || (typeof schema === \"object\" && Object.keys(schema).length === 0);\n}\n\n/**\n * The index signature object for `unevaluatedProperties`, given the composed type of the other\n * keywords (null when there is none). Null when the fix is off or the keyword does not apply.\n */\nexport function unevaluatedPropertiesType(\n schema: SchemaObject,\n composed: IrType | null,\n request: SchemaRequest,\n): IrType | null {\n const unevaluated = unevaluatedSchemaOf(schema, request);\n if (unevaluated === null) {\n return null;\n }\n const valueTypes = isAnySchema(unevaluated)\n ? [UNKNOWN_TYPE]\n : [\n request.transformNested(unevaluated, request.location, true),\n ...(composed === null ? [] : declaredValueTypes(composed, request.context.footer)),\n ];\n const { immutable } = request.context.options;\n return irObject([irStringIndexSignature(\"key\", unionOf(valueTypes), immutable)]);\n}\n"],"names":[],"mappings":";;;;;;AA0BA,SAAS,mBAAA,CAAoB,QAAsB,OAAA,EAAuC;AACxF,EAAA,MAAM,EAAE,uBAAsB,GAAI,MAAA;AAClC,EAAA,IACE,CAAC,OAAA,CAAQ,OAAA,CAAQ,OAAA,CAAQ,MAAM,GAAA,CAAI,GAAA,CAAI,sBAAsB,CAAA,IAC7D,0BAA0B,MAAA,IAC1B,qBAAA,KAA0B,KAAA,IAC1B,MAAA,CAAO,yBAAyB,MAAA,EAChC;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,OAAO,IAAA,KAAS,MAAA,IAAa,MAAA,CAAO,IAAA,KAAS,WAAW,qBAAA,GAAwB,IAAA;AACzF;AAEA,SAAS,YAAY,MAAA,EAAyB;AAC5C,EAAA,OAAO,MAAA,KAAW,QAAS,OAAO,MAAA,KAAW,YAAY,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,CAAE,MAAA,KAAW,CAAA;AAC1F;AAMO,SAAS,yBAAA,CACd,MAAA,EACA,QAAA,EACA,OAAA,EACe;AACf,EAAA,MAAM,WAAA,GAAc,mBAAA,CAAoB,MAAA,EAAQ,OAAO,CAAA;AACvD,EAAA,IAAI,gBAAgB,IAAA,EAAM;AACxB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,aAAa,WAAA,CAAY,WAAW,CAAA,GACtC,CAAC,YAAY,CAAA,GACb;AAAA,IACE,OAAA,CAAQ,eAAA,CAAgB,WAAA,EAAa,OAAA,CAAQ,UAAU,IAAI,CAAA;AAAA,IAC3D,GAAI,aAAa,IAAA,GAAO,KAAK,kBAAA,CAAmB,QAAA,EAAU,OAAA,CAAQ,OAAA,CAAQ,MAAM;AAAA,GAClF;AACJ,EAAA,MAAM,EAAE,SAAA,EAAU,GAAI,OAAA,CAAQ,OAAA,CAAQ,OAAA;AACtC,EAAA,OAAO,QAAA,CAAS,CAAC,sBAAA,CAAuB,KAAA,EAAO,QAAQ,UAAU,CAAA,EAAG,SAAS,CAAC,CAAC,CAAA;AACjF;;"}
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ function apiLogger(logger, apiName) {
4
+ const prefix = `API ${apiName}: `;
5
+ return {
6
+ debug: (message, group, durationMs) => logger.debug(`${prefix}${message}`, group, durationMs),
7
+ warn: (message) => logger.warn(`${prefix}${message}`),
8
+ error: (message) => logger.error(`${prefix}${message}`)
9
+ };
10
+ }
11
+
12
+ exports.apiLogger = apiLogger;
13
+ //# sourceMappingURL=api-logger.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-logger.cjs","sources":["../../src/cli/api-logger.ts"],"sourcesContent":["import type { DebugGroup, Logger } from \"../application/ports/logger.js\";\n\n/**\n * A logger whose lines name the API they are about. With several APIs in `redocly.yaml`, each is\n * loaded and linted in turn, and a problem line such as \"Can't resolve $ref\" is the same for\n * each, so without the name the user cannot tell which API it belongs to. The summary of a\n * failed API names it the same way (`API a: …`).\n */\nexport function apiLogger(logger: Logger, apiName: string): Logger {\n const prefix = `API ${apiName}: `;\n return {\n debug: (message: string, group?: DebugGroup, durationMs?: number) =>\n logger.debug(`${prefix}${message}`, group, durationMs),\n warn: (message: string) => logger.warn(`${prefix}${message}`),\n error: (message: string) => logger.error(`${prefix}${message}`),\n };\n}\n"],"names":[],"mappings":";;AAQO,SAAS,SAAA,CAAU,QAAgB,OAAA,EAAyB;AACjE,EAAA,MAAM,MAAA,GAAS,OAAO,OAAO,CAAA,EAAA,CAAA;AAC7B,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,CAAC,OAAA,EAAiB,KAAA,EAAoB,UAAA,KAC3C,MAAA,CAAO,KAAA,CAAM,CAAA,EAAG,MAAM,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,OAAO,UAAU,CAAA;AAAA,IACvD,IAAA,EAAM,CAAC,OAAA,KAAoB,MAAA,CAAO,KAAK,CAAA,EAAG,MAAM,CAAA,EAAG,OAAO,CAAA,CAAE,CAAA;AAAA,IAC5D,KAAA,EAAO,CAAC,OAAA,KAAoB,MAAA,CAAO,MAAM,CAAA,EAAG,MAAM,CAAA,EAAG,OAAO,CAAA,CAAE;AAAA,GAChE;AACF;;"}
@@ -0,0 +1,11 @@
1
+ function apiLogger(logger, apiName) {
2
+ const prefix = `API ${apiName}: `;
3
+ return {
4
+ debug: (message, group, durationMs) => logger.debug(`${prefix}${message}`, group, durationMs),
5
+ warn: (message) => logger.warn(`${prefix}${message}`),
6
+ error: (message) => logger.error(`${prefix}${message}`)
7
+ };
8
+ }
9
+
10
+ export { apiLogger };
11
+ //# sourceMappingURL=api-logger.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-logger.mjs","sources":["../../src/cli/api-logger.ts"],"sourcesContent":["import type { DebugGroup, Logger } from \"../application/ports/logger.js\";\n\n/**\n * A logger whose lines name the API they are about. With several APIs in `redocly.yaml`, each is\n * loaded and linted in turn, and a problem line such as \"Can't resolve $ref\" is the same for\n * each, so without the name the user cannot tell which API it belongs to. The summary of a\n * failed API names it the same way (`API a: …`).\n */\nexport function apiLogger(logger: Logger, apiName: string): Logger {\n const prefix = `API ${apiName}: `;\n return {\n debug: (message: string, group?: DebugGroup, durationMs?: number) =>\n logger.debug(`${prefix}${message}`, group, durationMs),\n warn: (message: string) => logger.warn(`${prefix}${message}`),\n error: (message: string) => logger.error(`${prefix}${message}`),\n };\n}\n"],"names":[],"mappings":"AAQO,SAAS,SAAA,CAAU,QAAgB,OAAA,EAAyB;AACjE,EAAA,MAAM,MAAA,GAAS,OAAO,OAAO,CAAA,EAAA,CAAA;AAC7B,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,CAAC,OAAA,EAAiB,KAAA,EAAoB,UAAA,KAC3C,MAAA,CAAO,KAAA,CAAM,CAAA,EAAG,MAAM,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,OAAO,UAAU,CAAA;AAAA,IACvD,IAAA,EAAM,CAAC,OAAA,KAAoB,MAAA,CAAO,KAAK,CAAA,EAAG,MAAM,CAAA,EAAG,OAAO,CAAA,CAAE,CAAA;AAAA,IAC5D,KAAA,EAAO,CAAC,OAAA,KAAoB,MAAA,CAAO,MAAM,CAAA,EAAG,MAAM,CAAA,EAAG,OAAO,CAAA,CAAE;AAAA,GAChE;AACF;;"}
@@ -1,16 +1,17 @@
1
1
  'use strict';
2
2
 
3
3
  const scule = require('scule');
4
- const errors = require('../domain/errors.cjs');
5
4
  const warnings = require('../domain/warnings.cjs');
6
5
  const cliArguments = require('./cli-arguments.cjs');
7
6
  const cliErrors = require('./cli-errors.cjs');
8
- const cliOutput = require('./cli-output.cjs');
9
7
  const fixOption = require('./fix-option.cjs');
8
+ const refLimits = require('./ref-limits.cjs');
9
+ const cliFlagNames = require('./cli-flag-names.cjs');
10
10
 
11
11
  const OUTPUT_SETTING = "output";
12
12
  const FIX_SETTING = "fix";
13
13
  const LOCAL_REF_ROOT_SETTING = "localRefRoot";
14
+ const LOCAL_ROOT_EXPECTED = "a directory path or a file: URL";
14
15
  const REMOTE_REF_HOSTS_SETTING = "remoteRefHosts";
15
16
  const IGNORED_SETTINGS = ["contentNever"];
16
17
  const CAMEL_CASE_SETTINGS = [
@@ -18,7 +19,7 @@ const CAMEL_CASE_SETTINGS = [
18
19
  FIX_SETTING,
19
20
  LOCAL_REF_ROOT_SETTING,
20
21
  REMOTE_REF_HOSTS_SETTING,
21
- ...cliArguments.GENERATOR_FLAGS,
22
+ ...cliFlagNames.GENERATOR_FLAGS,
22
23
  ...IGNORED_SETTINGS
23
24
  ];
24
25
  const KNOWN_SETTINGS = /* @__PURE__ */ new Set([
@@ -56,7 +57,7 @@ function invalidSetting(apiName, settings, name, expected) {
56
57
  }
57
58
  function apiFlags(apiName, settings) {
58
59
  const flags = {};
59
- for (const name of cliArguments.GENERATOR_FLAGS) {
60
+ for (const name of cliFlagNames.GENERATOR_FLAGS) {
60
61
  const value = settingValue(settings, name);
61
62
  if (typeof value === "boolean") {
62
63
  flags[name] = value;
@@ -84,27 +85,19 @@ function apiFixNames(apiName, settings) {
84
85
  try {
85
86
  return fixOption.fixNamesOf(entries);
86
87
  } catch (error) {
87
- throw errors.isOpenAPITypesafeError(error) ? withApiName(apiName, error) : error;
88
+ throw new cliErrors.ApiFailure(apiName, error);
88
89
  }
89
90
  }
90
- function withApiName(apiName, error) {
91
- const { code, details, cause } = error;
92
- return new errors.OpenAPITypesafeError({
93
- code,
94
- message: `API ${apiName}: ${error.message}`,
95
- details,
96
- cause
97
- });
98
- }
99
91
  function localRefRootOf(apiName, settings, configRoot) {
100
92
  if (!hasSetting(settings, LOCAL_REF_ROOT_SETTING)) {
101
93
  return {};
102
94
  }
103
95
  const value = settingValue(settings, LOCAL_REF_ROOT_SETTING) ?? "";
104
- if (typeof value !== "string") {
105
- throw invalidSetting(apiName, settings, LOCAL_REF_ROOT_SETTING, "a directory path");
96
+ const localRoot = typeof value === "string" ? refLimits.localRootUrl(value, configRoot) : void 0;
97
+ if (localRoot === void 0) {
98
+ throw invalidSetting(apiName, settings, LOCAL_REF_ROOT_SETTING, LOCAL_ROOT_EXPECTED);
106
99
  }
107
- return { localRefRoot: cliOutput.resolveLocationUrl(value === "" ? "." : value, configRoot) };
100
+ return { localRefRoot: localRoot };
108
101
  }
109
102
  function remoteRefHostsOf(apiName, settings) {
110
103
  if (!hasSetting(settings, REMOTE_REF_HOSTS_SETTING)) {
@@ -1 +1 @@
1
- {"version":3,"file":"api-settings.cjs","sources":["../../src/cli/api-settings.ts"],"sourcesContent":["import { kebabCase } from \"scule\";\nimport { isOpenAPITypesafeError, OpenAPITypesafeError } from \"../domain/errors.js\";\nimport type { OutputFixName } from \"../domain/output-fixes.js\";\nimport { WARNING_CODES, warningText } from \"../domain/warnings.js\";\nimport { GENERATOR_FLAGS, type GeneratorFlags, hostList } from \"./cli-arguments.js\";\nimport { cliError } from \"./cli-errors.js\";\nimport { resolveLocationUrl } from \"./cli-output.js\";\nimport { fixNamesOf } from \"./fix-option.js\";\nimport type { RefLimitOptions } from \"./ref-limits.js\";\n\n/**\n * The settings of one API in `redocly.yaml` (`apis.<name>.x-openapi-ts`). A setting has the name\n * of its CLI flag, in kebab-case or camelCase (ADR-021, decision 1); a setting the CLI does not\n * read gets a warning, as an unknown flag gets a notice.\n */\n\nexport type ApiSettings = Readonly<Record<string, unknown>>;\n\n/** The setting that names the output file. */\nexport const OUTPUT_SETTING = \"output\";\n\n/** The setting that lists the API's output fixes. */\nexport const FIX_SETTING = \"fix\";\n\nconst LOCAL_REF_ROOT_SETTING = \"localRefRoot\";\nconst REMOTE_REF_HOSTS_SETTING = \"remoteRefHosts\";\n\n/** `--content-never` is accepted and has no effect, as on the command line. */\nconst IGNORED_SETTINGS = [\"contentNever\"] as const;\n\nconst CAMEL_CASE_SETTINGS = [\n OUTPUT_SETTING,\n FIX_SETTING,\n LOCAL_REF_ROOT_SETTING,\n REMOTE_REF_HOSTS_SETTING,\n ...GENERATOR_FLAGS,\n ...IGNORED_SETTINGS,\n];\n\nconst KNOWN_SETTINGS = new Set<string>([\n ...CAMEL_CASE_SETTINGS,\n ...CAMEL_CASE_SETTINGS.map((name) => kebabCase(name)),\n]);\n\n/** The warning for each setting of an API that no code reads. */\nexport function unknownSettingWarnings(apiName: string, settings: ApiSettings): string[] {\n return Object.keys(settings)\n .filter((key) => !KNOWN_SETTINGS.has(key))\n .map((key) =>\n warningText(\n `API ${apiName}: the setting \\`${key}\\` is not an openapi-typesafe option and is ignored`,\n WARNING_CODES.CONFIG_SETTING_UNKNOWN,\n ),\n );\n}\n\n/** The key a setting is written with: camelCase, else kebab-case; undefined when it is absent. */\nfunction settingKey(settings: ApiSettings, name: string): string | undefined {\n if (name in settings) {\n return name;\n }\n const kebabName = kebabCase(name);\n return kebabName in settings ? kebabName : undefined;\n}\n\n/** The value of a setting in camelCase, else in kebab-case; `undefined` when it is absent. */\nfunction settingValue(settings: ApiSettings, name: string): unknown {\n const key = settingKey(settings, name);\n return key === undefined ? undefined : settings[key];\n}\n\nfunction hasSetting(settings: ApiSettings, name: string): boolean {\n return settingKey(settings, name) !== undefined;\n}\n\n/** `CLI_CONFIG_INVALID` for the setting `name` of an API, named as the user wrote it. */\nfunction invalidSetting(apiName: string, settings: ApiSettings, name: string, expected: string) {\n const key = settingKey(settings, name) ?? kebabCase(name);\n return cliError(\n \"CLI_CONFIG_INVALID\",\n `API ${apiName}: \\`${key}\\` in x-openapi-ts must be ${expected}`,\n );\n}\n\n/**\n * The boolean flags an API sets, in camelCase or kebab-case; they win over the CLI's flags. A\n * value of another type (`root-types: \"true\"`) fails with `CLI_CONFIG_INVALID`: ignoring it\n * would generate other types than the config asks for, without a word.\n */\nexport function apiFlags(apiName: string, settings: ApiSettings): GeneratorFlags {\n const flags: Partial<Record<(typeof GENERATOR_FLAGS)[number], boolean>> = {};\n for (const name of GENERATOR_FLAGS) {\n const value = settingValue(settings, name);\n if (typeof value === \"boolean\") {\n flags[name] = value;\n } else if (hasSetting(settings, name)) {\n throw invalidSetting(apiName, settings, name, \"true or false\");\n }\n }\n return flags;\n}\n\n/** The API's `output` file as written; fails with `CLI_CONFIG_INVALID` when it is not text. */\nexport function apiOutputOf(apiName: string, settings: ApiSettings): string {\n const output = settings[OUTPUT_SETTING];\n if (typeof output !== \"string\") {\n throw invalidSetting(apiName, settings, OUTPUT_SETTING, \"a file path\");\n }\n return output;\n}\n\n/**\n * The API's `fix` names, which replace the CLI's `--fix` (ADR-021). An entry that is not text\n * fails with `CLI_CONFIG_INVALID`; an unknown name with `OPTION_FIX_UNKNOWN`, naming the API.\n */\nexport function apiFixNames(\n apiName: string,\n settings: ApiSettings,\n): readonly OutputFixName[] | undefined {\n if (!hasSetting(settings, FIX_SETTING)) {\n return undefined;\n }\n const entries = [settingValue(settings, FIX_SETTING)].flat();\n if (entries.some((entry) => typeof entry !== \"string\")) {\n throw invalidSetting(apiName, settings, FIX_SETTING, \"a list of fix names or a comma list\");\n }\n try {\n return fixNamesOf(entries);\n } catch (error) {\n throw isOpenAPITypesafeError(error) ? withApiName(apiName, error) : error;\n }\n}\n\n/** The same error, with the API named first in its message. */\nfunction withApiName(apiName: string, error: OpenAPITypesafeError): OpenAPITypesafeError {\n const { code, details, cause } = error;\n return new OpenAPITypesafeError({\n code,\n message: `API ${apiName}: ${error.message}`,\n details,\n cause,\n });\n}\n\n/** `local-ref-root: dir`, relative to the config file; empty means the config file's directory. */\nfunction localRefRootOf(apiName: string, settings: ApiSettings, configRoot: URL): RefLimitOptions {\n if (!hasSetting(settings, LOCAL_REF_ROOT_SETTING)) {\n return {};\n }\n const value = settingValue(settings, LOCAL_REF_ROOT_SETTING) ?? \"\";\n if (typeof value !== \"string\") {\n throw invalidSetting(apiName, settings, LOCAL_REF_ROOT_SETTING, \"a directory path\");\n }\n return { localRefRoot: resolveLocationUrl(value === \"\" ? \".\" : value, configRoot) };\n}\n\n/** `remote-ref-hosts: [a, b]` or `a,b`; an empty list or value allows no host. */\nfunction remoteRefHostsOf(apiName: string, settings: ApiSettings): RefLimitOptions {\n if (!hasSetting(settings, REMOTE_REF_HOSTS_SETTING)) {\n return {};\n }\n const value = settingValue(settings, REMOTE_REF_HOSTS_SETTING) ?? [];\n const entries = [value].flat();\n if (entries.some((entry) => typeof entry !== \"string\")) {\n throw invalidSetting(apiName, settings, REMOTE_REF_HOSTS_SETTING, \"a host list\");\n }\n return { remoteRefHosts: hostList(entries) ?? [] };\n}\n\n/**\n * The `$ref` limits an API sets (threat model R1, R2). Each one replaces the CLI flag of the same\n * name for this API, as its boolean settings and `fix` do; fails with `CLI_CONFIG_INVALID` for a\n * value of another type.\n */\nexport function apiRefLimitOptions(\n apiName: string,\n settings: ApiSettings,\n configRoot: URL,\n): RefLimitOptions {\n return {\n ...localRefRootOf(apiName, settings, configRoot),\n ...remoteRefHostsOf(apiName, settings),\n };\n}\n"],"names":["GENERATOR_FLAGS","kebabCase","warningText","WARNING_CODES","cliError","fixNamesOf","isOpenAPITypesafeError","OpenAPITypesafeError","resolveLocationUrl","hostList"],"mappings":"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"}
1
+ {"version":3,"file":"api-settings.cjs","sources":["../../src/cli/api-settings.ts"],"sourcesContent":["import { kebabCase } from \"scule\";\nimport type { OutputFixName } from \"../domain/output-fixes.js\";\nimport { WARNING_CODES, warningText } from \"../domain/warnings.js\";\nimport { GENERATOR_FLAGS, type GeneratorFlags, hostList } from \"./cli-arguments.js\";\nimport { ApiFailure, cliError } from \"./cli-errors.js\";\nimport { fixNamesOf } from \"./fix-option.js\";\nimport { localRootUrl, type RefLimitOptions } from \"./ref-limits.js\";\n\n/**\n * The settings of one API in `redocly.yaml` (`apis.<name>.x-openapi-ts`). A setting has the name\n * of its CLI flag, in kebab-case or camelCase (ADR-021, decision 1); a setting the CLI does not\n * read gets a warning, as an unknown flag gets a notice.\n */\n\nexport type ApiSettings = Readonly<Record<string, unknown>>;\n\n/** The setting that names the output file. */\nexport const OUTPUT_SETTING = \"output\";\n\n/** The setting that lists the API's output fixes. */\nexport const FIX_SETTING = \"fix\";\n\nconst LOCAL_REF_ROOT_SETTING = \"localRefRoot\";\nconst LOCAL_ROOT_EXPECTED = \"a directory path or a file: URL\";\nconst REMOTE_REF_HOSTS_SETTING = \"remoteRefHosts\";\n\n/** `--content-never` is accepted and has no effect, as on the command line. */\nconst IGNORED_SETTINGS = [\"contentNever\"] as const;\n\nconst CAMEL_CASE_SETTINGS = [\n OUTPUT_SETTING,\n FIX_SETTING,\n LOCAL_REF_ROOT_SETTING,\n REMOTE_REF_HOSTS_SETTING,\n ...GENERATOR_FLAGS,\n ...IGNORED_SETTINGS,\n];\n\nconst KNOWN_SETTINGS = new Set<string>([\n ...CAMEL_CASE_SETTINGS,\n ...CAMEL_CASE_SETTINGS.map((name) => kebabCase(name)),\n]);\n\n/** The warning for each setting of an API that no code reads. */\nexport function unknownSettingWarnings(apiName: string, settings: ApiSettings): string[] {\n return Object.keys(settings)\n .filter((key) => !KNOWN_SETTINGS.has(key))\n .map((key) =>\n warningText(\n `API ${apiName}: the setting \\`${key}\\` is not an openapi-typesafe option and is ignored`,\n WARNING_CODES.CONFIG_SETTING_UNKNOWN,\n ),\n );\n}\n\n/** The key a setting is written with: camelCase, else kebab-case; undefined when it is absent. */\nfunction settingKey(settings: ApiSettings, name: string): string | undefined {\n if (name in settings) {\n return name;\n }\n const kebabName = kebabCase(name);\n return kebabName in settings ? kebabName : undefined;\n}\n\n/** The value of a setting in camelCase, else in kebab-case; `undefined` when it is absent. */\nfunction settingValue(settings: ApiSettings, name: string): unknown {\n const key = settingKey(settings, name);\n return key === undefined ? undefined : settings[key];\n}\n\nfunction hasSetting(settings: ApiSettings, name: string): boolean {\n return settingKey(settings, name) !== undefined;\n}\n\n/** `CLI_CONFIG_INVALID` for the setting `name` of an API, named as the user wrote it. */\nfunction invalidSetting(apiName: string, settings: ApiSettings, name: string, expected: string) {\n const key = settingKey(settings, name) ?? kebabCase(name);\n return cliError(\n \"CLI_CONFIG_INVALID\",\n `API ${apiName}: \\`${key}\\` in x-openapi-ts must be ${expected}`,\n );\n}\n\n/**\n * The boolean flags an API sets, in camelCase or kebab-case; they win over the CLI's flags. A\n * value of another type (`root-types: \"true\"`) fails with `CLI_CONFIG_INVALID`: ignoring it\n * would generate other types than the config asks for, without a word.\n */\nexport function apiFlags(apiName: string, settings: ApiSettings): GeneratorFlags {\n const flags: Partial<Record<(typeof GENERATOR_FLAGS)[number], boolean>> = {};\n for (const name of GENERATOR_FLAGS) {\n const value = settingValue(settings, name);\n if (typeof value === \"boolean\") {\n flags[name] = value;\n } else if (hasSetting(settings, name)) {\n throw invalidSetting(apiName, settings, name, \"true or false\");\n }\n }\n return flags;\n}\n\n/** The API's `output` file as written; fails with `CLI_CONFIG_INVALID` when it is not text. */\nexport function apiOutputOf(apiName: string, settings: ApiSettings): string {\n const output = settings[OUTPUT_SETTING];\n if (typeof output !== \"string\") {\n throw invalidSetting(apiName, settings, OUTPUT_SETTING, \"a file path\");\n }\n return output;\n}\n\n/**\n * The API's `fix` names, which replace the CLI's `--fix` (ADR-021). An entry that is not text\n * fails with `CLI_CONFIG_INVALID`; an unknown name with `OPTION_FIX_UNKNOWN`, naming the API.\n */\nexport function apiFixNames(\n apiName: string,\n settings: ApiSettings,\n): readonly OutputFixName[] | undefined {\n if (!hasSetting(settings, FIX_SETTING)) {\n return undefined;\n }\n const entries = [settingValue(settings, FIX_SETTING)].flat();\n if (entries.some((entry) => typeof entry !== \"string\")) {\n throw invalidSetting(apiName, settings, FIX_SETTING, \"a list of fix names or a comma list\");\n }\n try {\n return fixNamesOf(entries);\n } catch (error) {\n throw new ApiFailure(apiName, error);\n }\n}\n\n/**\n * `local-ref-root: dir`, relative to the config file; empty means the config file's directory. A\n * value that is no text or a URL of another protocol fails with `CLI_CONFIG_INVALID`.\n */\nfunction localRefRootOf(apiName: string, settings: ApiSettings, configRoot: URL): RefLimitOptions {\n if (!hasSetting(settings, LOCAL_REF_ROOT_SETTING)) {\n return {};\n }\n const value = settingValue(settings, LOCAL_REF_ROOT_SETTING) ?? \"\";\n const localRoot = typeof value === \"string\" ? localRootUrl(value, configRoot) : undefined;\n if (localRoot === undefined) {\n throw invalidSetting(apiName, settings, LOCAL_REF_ROOT_SETTING, LOCAL_ROOT_EXPECTED);\n }\n return { localRefRoot: localRoot };\n}\n\n/** `remote-ref-hosts: [a, b]` or `a,b`; an empty list or value allows no host. */\nfunction remoteRefHostsOf(apiName: string, settings: ApiSettings): RefLimitOptions {\n if (!hasSetting(settings, REMOTE_REF_HOSTS_SETTING)) {\n return {};\n }\n const value = settingValue(settings, REMOTE_REF_HOSTS_SETTING) ?? [];\n const entries = [value].flat();\n if (entries.some((entry) => typeof entry !== \"string\")) {\n throw invalidSetting(apiName, settings, REMOTE_REF_HOSTS_SETTING, \"a host list\");\n }\n return { remoteRefHosts: hostList(entries) ?? [] };\n}\n\n/**\n * The `$ref` limits an API sets (threat model R1, R2). Each one replaces the CLI flag of the same\n * name for this API, as its boolean settings and `fix` do; fails with `CLI_CONFIG_INVALID` for a\n * value of another type.\n */\nexport function apiRefLimitOptions(\n apiName: string,\n settings: ApiSettings,\n configRoot: URL,\n): RefLimitOptions {\n return {\n ...localRefRootOf(apiName, settings, configRoot),\n ...remoteRefHostsOf(apiName, settings),\n };\n}\n"],"names":["GENERATOR_FLAGS","kebabCase","warningText","WARNING_CODES","cliError","fixNamesOf","ApiFailure","localRootUrl","hostList"],"mappings":"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"}
@@ -1,14 +1,15 @@
1
1
  import { kebabCase } from 'scule';
2
- import { isOpenAPITypesafeError, OpenAPITypesafeError } from '../domain/errors.mjs';
3
2
  import { warningText, WARNING_CODES } from '../domain/warnings.mjs';
4
- import { GENERATOR_FLAGS, hostList } from './cli-arguments.mjs';
5
- import { cliError } from './cli-errors.mjs';
6
- import { resolveLocationUrl } from './cli-output.mjs';
3
+ import { hostList } from './cli-arguments.mjs';
4
+ import { cliError, ApiFailure } from './cli-errors.mjs';
7
5
  import { fixNamesOf } from './fix-option.mjs';
6
+ import { localRootUrl } from './ref-limits.mjs';
7
+ import { GENERATOR_FLAGS } from './cli-flag-names.mjs';
8
8
 
9
9
  const OUTPUT_SETTING = "output";
10
10
  const FIX_SETTING = "fix";
11
11
  const LOCAL_REF_ROOT_SETTING = "localRefRoot";
12
+ const LOCAL_ROOT_EXPECTED = "a directory path or a file: URL";
12
13
  const REMOTE_REF_HOSTS_SETTING = "remoteRefHosts";
13
14
  const IGNORED_SETTINGS = ["contentNever"];
14
15
  const CAMEL_CASE_SETTINGS = [
@@ -82,27 +83,19 @@ function apiFixNames(apiName, settings) {
82
83
  try {
83
84
  return fixNamesOf(entries);
84
85
  } catch (error) {
85
- throw isOpenAPITypesafeError(error) ? withApiName(apiName, error) : error;
86
+ throw new ApiFailure(apiName, error);
86
87
  }
87
88
  }
88
- function withApiName(apiName, error) {
89
- const { code, details, cause } = error;
90
- return new OpenAPITypesafeError({
91
- code,
92
- message: `API ${apiName}: ${error.message}`,
93
- details,
94
- cause
95
- });
96
- }
97
89
  function localRefRootOf(apiName, settings, configRoot) {
98
90
  if (!hasSetting(settings, LOCAL_REF_ROOT_SETTING)) {
99
91
  return {};
100
92
  }
101
93
  const value = settingValue(settings, LOCAL_REF_ROOT_SETTING) ?? "";
102
- if (typeof value !== "string") {
103
- throw invalidSetting(apiName, settings, LOCAL_REF_ROOT_SETTING, "a directory path");
94
+ const localRoot = typeof value === "string" ? localRootUrl(value, configRoot) : void 0;
95
+ if (localRoot === void 0) {
96
+ throw invalidSetting(apiName, settings, LOCAL_REF_ROOT_SETTING, LOCAL_ROOT_EXPECTED);
104
97
  }
105
- return { localRefRoot: resolveLocationUrl(value === "" ? "." : value, configRoot) };
98
+ return { localRefRoot: localRoot };
106
99
  }
107
100
  function remoteRefHostsOf(apiName, settings) {
108
101
  if (!hasSetting(settings, REMOTE_REF_HOSTS_SETTING)) {
@@ -1 +1 @@
1
- {"version":3,"file":"api-settings.mjs","sources":["../../src/cli/api-settings.ts"],"sourcesContent":["import { kebabCase } from \"scule\";\nimport { isOpenAPITypesafeError, OpenAPITypesafeError } from \"../domain/errors.js\";\nimport type { OutputFixName } from \"../domain/output-fixes.js\";\nimport { WARNING_CODES, warningText } from \"../domain/warnings.js\";\nimport { GENERATOR_FLAGS, type GeneratorFlags, hostList } from \"./cli-arguments.js\";\nimport { cliError } from \"./cli-errors.js\";\nimport { resolveLocationUrl } from \"./cli-output.js\";\nimport { fixNamesOf } from \"./fix-option.js\";\nimport type { RefLimitOptions } from \"./ref-limits.js\";\n\n/**\n * The settings of one API in `redocly.yaml` (`apis.<name>.x-openapi-ts`). A setting has the name\n * of its CLI flag, in kebab-case or camelCase (ADR-021, decision 1); a setting the CLI does not\n * read gets a warning, as an unknown flag gets a notice.\n */\n\nexport type ApiSettings = Readonly<Record<string, unknown>>;\n\n/** The setting that names the output file. */\nexport const OUTPUT_SETTING = \"output\";\n\n/** The setting that lists the API's output fixes. */\nexport const FIX_SETTING = \"fix\";\n\nconst LOCAL_REF_ROOT_SETTING = \"localRefRoot\";\nconst REMOTE_REF_HOSTS_SETTING = \"remoteRefHosts\";\n\n/** `--content-never` is accepted and has no effect, as on the command line. */\nconst IGNORED_SETTINGS = [\"contentNever\"] as const;\n\nconst CAMEL_CASE_SETTINGS = [\n OUTPUT_SETTING,\n FIX_SETTING,\n LOCAL_REF_ROOT_SETTING,\n REMOTE_REF_HOSTS_SETTING,\n ...GENERATOR_FLAGS,\n ...IGNORED_SETTINGS,\n];\n\nconst KNOWN_SETTINGS = new Set<string>([\n ...CAMEL_CASE_SETTINGS,\n ...CAMEL_CASE_SETTINGS.map((name) => kebabCase(name)),\n]);\n\n/** The warning for each setting of an API that no code reads. */\nexport function unknownSettingWarnings(apiName: string, settings: ApiSettings): string[] {\n return Object.keys(settings)\n .filter((key) => !KNOWN_SETTINGS.has(key))\n .map((key) =>\n warningText(\n `API ${apiName}: the setting \\`${key}\\` is not an openapi-typesafe option and is ignored`,\n WARNING_CODES.CONFIG_SETTING_UNKNOWN,\n ),\n );\n}\n\n/** The key a setting is written with: camelCase, else kebab-case; undefined when it is absent. */\nfunction settingKey(settings: ApiSettings, name: string): string | undefined {\n if (name in settings) {\n return name;\n }\n const kebabName = kebabCase(name);\n return kebabName in settings ? kebabName : undefined;\n}\n\n/** The value of a setting in camelCase, else in kebab-case; `undefined` when it is absent. */\nfunction settingValue(settings: ApiSettings, name: string): unknown {\n const key = settingKey(settings, name);\n return key === undefined ? undefined : settings[key];\n}\n\nfunction hasSetting(settings: ApiSettings, name: string): boolean {\n return settingKey(settings, name) !== undefined;\n}\n\n/** `CLI_CONFIG_INVALID` for the setting `name` of an API, named as the user wrote it. */\nfunction invalidSetting(apiName: string, settings: ApiSettings, name: string, expected: string) {\n const key = settingKey(settings, name) ?? kebabCase(name);\n return cliError(\n \"CLI_CONFIG_INVALID\",\n `API ${apiName}: \\`${key}\\` in x-openapi-ts must be ${expected}`,\n );\n}\n\n/**\n * The boolean flags an API sets, in camelCase or kebab-case; they win over the CLI's flags. A\n * value of another type (`root-types: \"true\"`) fails with `CLI_CONFIG_INVALID`: ignoring it\n * would generate other types than the config asks for, without a word.\n */\nexport function apiFlags(apiName: string, settings: ApiSettings): GeneratorFlags {\n const flags: Partial<Record<(typeof GENERATOR_FLAGS)[number], boolean>> = {};\n for (const name of GENERATOR_FLAGS) {\n const value = settingValue(settings, name);\n if (typeof value === \"boolean\") {\n flags[name] = value;\n } else if (hasSetting(settings, name)) {\n throw invalidSetting(apiName, settings, name, \"true or false\");\n }\n }\n return flags;\n}\n\n/** The API's `output` file as written; fails with `CLI_CONFIG_INVALID` when it is not text. */\nexport function apiOutputOf(apiName: string, settings: ApiSettings): string {\n const output = settings[OUTPUT_SETTING];\n if (typeof output !== \"string\") {\n throw invalidSetting(apiName, settings, OUTPUT_SETTING, \"a file path\");\n }\n return output;\n}\n\n/**\n * The API's `fix` names, which replace the CLI's `--fix` (ADR-021). An entry that is not text\n * fails with `CLI_CONFIG_INVALID`; an unknown name with `OPTION_FIX_UNKNOWN`, naming the API.\n */\nexport function apiFixNames(\n apiName: string,\n settings: ApiSettings,\n): readonly OutputFixName[] | undefined {\n if (!hasSetting(settings, FIX_SETTING)) {\n return undefined;\n }\n const entries = [settingValue(settings, FIX_SETTING)].flat();\n if (entries.some((entry) => typeof entry !== \"string\")) {\n throw invalidSetting(apiName, settings, FIX_SETTING, \"a list of fix names or a comma list\");\n }\n try {\n return fixNamesOf(entries);\n } catch (error) {\n throw isOpenAPITypesafeError(error) ? withApiName(apiName, error) : error;\n }\n}\n\n/** The same error, with the API named first in its message. */\nfunction withApiName(apiName: string, error: OpenAPITypesafeError): OpenAPITypesafeError {\n const { code, details, cause } = error;\n return new OpenAPITypesafeError({\n code,\n message: `API ${apiName}: ${error.message}`,\n details,\n cause,\n });\n}\n\n/** `local-ref-root: dir`, relative to the config file; empty means the config file's directory. */\nfunction localRefRootOf(apiName: string, settings: ApiSettings, configRoot: URL): RefLimitOptions {\n if (!hasSetting(settings, LOCAL_REF_ROOT_SETTING)) {\n return {};\n }\n const value = settingValue(settings, LOCAL_REF_ROOT_SETTING) ?? \"\";\n if (typeof value !== \"string\") {\n throw invalidSetting(apiName, settings, LOCAL_REF_ROOT_SETTING, \"a directory path\");\n }\n return { localRefRoot: resolveLocationUrl(value === \"\" ? \".\" : value, configRoot) };\n}\n\n/** `remote-ref-hosts: [a, b]` or `a,b`; an empty list or value allows no host. */\nfunction remoteRefHostsOf(apiName: string, settings: ApiSettings): RefLimitOptions {\n if (!hasSetting(settings, REMOTE_REF_HOSTS_SETTING)) {\n return {};\n }\n const value = settingValue(settings, REMOTE_REF_HOSTS_SETTING) ?? [];\n const entries = [value].flat();\n if (entries.some((entry) => typeof entry !== \"string\")) {\n throw invalidSetting(apiName, settings, REMOTE_REF_HOSTS_SETTING, \"a host list\");\n }\n return { remoteRefHosts: hostList(entries) ?? [] };\n}\n\n/**\n * The `$ref` limits an API sets (threat model R1, R2). Each one replaces the CLI flag of the same\n * name for this API, as its boolean settings and `fix` do; fails with `CLI_CONFIG_INVALID` for a\n * value of another type.\n */\nexport function apiRefLimitOptions(\n apiName: string,\n settings: ApiSettings,\n configRoot: URL,\n): RefLimitOptions {\n return {\n ...localRefRootOf(apiName, settings, configRoot),\n ...remoteRefHostsOf(apiName, settings),\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api-settings.mjs","sources":["../../src/cli/api-settings.ts"],"sourcesContent":["import { kebabCase } from \"scule\";\nimport type { OutputFixName } from \"../domain/output-fixes.js\";\nimport { WARNING_CODES, warningText } from \"../domain/warnings.js\";\nimport { GENERATOR_FLAGS, type GeneratorFlags, hostList } from \"./cli-arguments.js\";\nimport { ApiFailure, cliError } from \"./cli-errors.js\";\nimport { fixNamesOf } from \"./fix-option.js\";\nimport { localRootUrl, type RefLimitOptions } from \"./ref-limits.js\";\n\n/**\n * The settings of one API in `redocly.yaml` (`apis.<name>.x-openapi-ts`). A setting has the name\n * of its CLI flag, in kebab-case or camelCase (ADR-021, decision 1); a setting the CLI does not\n * read gets a warning, as an unknown flag gets a notice.\n */\n\nexport type ApiSettings = Readonly<Record<string, unknown>>;\n\n/** The setting that names the output file. */\nexport const OUTPUT_SETTING = \"output\";\n\n/** The setting that lists the API's output fixes. */\nexport const FIX_SETTING = \"fix\";\n\nconst LOCAL_REF_ROOT_SETTING = \"localRefRoot\";\nconst LOCAL_ROOT_EXPECTED = \"a directory path or a file: URL\";\nconst REMOTE_REF_HOSTS_SETTING = \"remoteRefHosts\";\n\n/** `--content-never` is accepted and has no effect, as on the command line. */\nconst IGNORED_SETTINGS = [\"contentNever\"] as const;\n\nconst CAMEL_CASE_SETTINGS = [\n OUTPUT_SETTING,\n FIX_SETTING,\n LOCAL_REF_ROOT_SETTING,\n REMOTE_REF_HOSTS_SETTING,\n ...GENERATOR_FLAGS,\n ...IGNORED_SETTINGS,\n];\n\nconst KNOWN_SETTINGS = new Set<string>([\n ...CAMEL_CASE_SETTINGS,\n ...CAMEL_CASE_SETTINGS.map((name) => kebabCase(name)),\n]);\n\n/** The warning for each setting of an API that no code reads. */\nexport function unknownSettingWarnings(apiName: string, settings: ApiSettings): string[] {\n return Object.keys(settings)\n .filter((key) => !KNOWN_SETTINGS.has(key))\n .map((key) =>\n warningText(\n `API ${apiName}: the setting \\`${key}\\` is not an openapi-typesafe option and is ignored`,\n WARNING_CODES.CONFIG_SETTING_UNKNOWN,\n ),\n );\n}\n\n/** The key a setting is written with: camelCase, else kebab-case; undefined when it is absent. */\nfunction settingKey(settings: ApiSettings, name: string): string | undefined {\n if (name in settings) {\n return name;\n }\n const kebabName = kebabCase(name);\n return kebabName in settings ? kebabName : undefined;\n}\n\n/** The value of a setting in camelCase, else in kebab-case; `undefined` when it is absent. */\nfunction settingValue(settings: ApiSettings, name: string): unknown {\n const key = settingKey(settings, name);\n return key === undefined ? undefined : settings[key];\n}\n\nfunction hasSetting(settings: ApiSettings, name: string): boolean {\n return settingKey(settings, name) !== undefined;\n}\n\n/** `CLI_CONFIG_INVALID` for the setting `name` of an API, named as the user wrote it. */\nfunction invalidSetting(apiName: string, settings: ApiSettings, name: string, expected: string) {\n const key = settingKey(settings, name) ?? kebabCase(name);\n return cliError(\n \"CLI_CONFIG_INVALID\",\n `API ${apiName}: \\`${key}\\` in x-openapi-ts must be ${expected}`,\n );\n}\n\n/**\n * The boolean flags an API sets, in camelCase or kebab-case; they win over the CLI's flags. A\n * value of another type (`root-types: \"true\"`) fails with `CLI_CONFIG_INVALID`: ignoring it\n * would generate other types than the config asks for, without a word.\n */\nexport function apiFlags(apiName: string, settings: ApiSettings): GeneratorFlags {\n const flags: Partial<Record<(typeof GENERATOR_FLAGS)[number], boolean>> = {};\n for (const name of GENERATOR_FLAGS) {\n const value = settingValue(settings, name);\n if (typeof value === \"boolean\") {\n flags[name] = value;\n } else if (hasSetting(settings, name)) {\n throw invalidSetting(apiName, settings, name, \"true or false\");\n }\n }\n return flags;\n}\n\n/** The API's `output` file as written; fails with `CLI_CONFIG_INVALID` when it is not text. */\nexport function apiOutputOf(apiName: string, settings: ApiSettings): string {\n const output = settings[OUTPUT_SETTING];\n if (typeof output !== \"string\") {\n throw invalidSetting(apiName, settings, OUTPUT_SETTING, \"a file path\");\n }\n return output;\n}\n\n/**\n * The API's `fix` names, which replace the CLI's `--fix` (ADR-021). An entry that is not text\n * fails with `CLI_CONFIG_INVALID`; an unknown name with `OPTION_FIX_UNKNOWN`, naming the API.\n */\nexport function apiFixNames(\n apiName: string,\n settings: ApiSettings,\n): readonly OutputFixName[] | undefined {\n if (!hasSetting(settings, FIX_SETTING)) {\n return undefined;\n }\n const entries = [settingValue(settings, FIX_SETTING)].flat();\n if (entries.some((entry) => typeof entry !== \"string\")) {\n throw invalidSetting(apiName, settings, FIX_SETTING, \"a list of fix names or a comma list\");\n }\n try {\n return fixNamesOf(entries);\n } catch (error) {\n throw new ApiFailure(apiName, error);\n }\n}\n\n/**\n * `local-ref-root: dir`, relative to the config file; empty means the config file's directory. A\n * value that is no text or a URL of another protocol fails with `CLI_CONFIG_INVALID`.\n */\nfunction localRefRootOf(apiName: string, settings: ApiSettings, configRoot: URL): RefLimitOptions {\n if (!hasSetting(settings, LOCAL_REF_ROOT_SETTING)) {\n return {};\n }\n const value = settingValue(settings, LOCAL_REF_ROOT_SETTING) ?? \"\";\n const localRoot = typeof value === \"string\" ? localRootUrl(value, configRoot) : undefined;\n if (localRoot === undefined) {\n throw invalidSetting(apiName, settings, LOCAL_REF_ROOT_SETTING, LOCAL_ROOT_EXPECTED);\n }\n return { localRefRoot: localRoot };\n}\n\n/** `remote-ref-hosts: [a, b]` or `a,b`; an empty list or value allows no host. */\nfunction remoteRefHostsOf(apiName: string, settings: ApiSettings): RefLimitOptions {\n if (!hasSetting(settings, REMOTE_REF_HOSTS_SETTING)) {\n return {};\n }\n const value = settingValue(settings, REMOTE_REF_HOSTS_SETTING) ?? [];\n const entries = [value].flat();\n if (entries.some((entry) => typeof entry !== \"string\")) {\n throw invalidSetting(apiName, settings, REMOTE_REF_HOSTS_SETTING, \"a host list\");\n }\n return { remoteRefHosts: hostList(entries) ?? [] };\n}\n\n/**\n * The `$ref` limits an API sets (threat model R1, R2). Each one replaces the CLI flag of the same\n * name for this API, as its boolean settings and `fix` do; fails with `CLI_CONFIG_INVALID` for a\n * value of another type.\n */\nexport function apiRefLimitOptions(\n apiName: string,\n settings: ApiSettings,\n configRoot: URL,\n): RefLimitOptions {\n return {\n ...localRefRootOf(apiName, settings, configRoot),\n ...remoteRefHostsOf(apiName, settings),\n };\n}\n"],"names":[],"mappings":";;;;;;;;AAiBO,MAAM,cAAA,GAAiB;AAGvB,MAAM,WAAA,GAAc;AAE3B,MAAM,sBAAA,GAAyB,cAAA;AAC/B,MAAM,mBAAA,GAAsB,iCAAA;AAC5B,MAAM,wBAAA,GAA2B,gBAAA;AAGjC,MAAM,gBAAA,GAAmB,CAAC,cAAc,CAAA;AAExC,MAAM,mBAAA,GAAsB;AAAA,EAC1B,cAAA;AAAA,EACA,WAAA;AAAA,EACA,sBAAA;AAAA,EACA,wBAAA;AAAA,EACA,GAAG,eAAA;AAAA,EACH,GAAG;AACL,CAAA;AAEA,MAAM,cAAA,uBAAqB,GAAA,CAAY;AAAA,EACrC,GAAG,mBAAA;AAAA,EACH,GAAG,mBAAA,CAAoB,GAAA,CAAI,CAAC,IAAA,KAAS,SAAA,CAAU,IAAI,CAAC;AACtD,CAAC,CAAA;AAGM,SAAS,sBAAA,CAAuB,SAAiB,QAAA,EAAiC;AACvF,EAAA,OAAO,MAAA,CAAO,IAAA,CAAK,QAAQ,CAAA,CACxB,MAAA,CAAO,CAAC,GAAA,KAAQ,CAAC,cAAA,CAAe,GAAA,CAAI,GAAG,CAAC,CAAA,CACxC,GAAA;AAAA,IAAI,CAAC,GAAA,KACJ,WAAA;AAAA,MACE,CAAA,IAAA,EAAO,OAAO,CAAA,gBAAA,EAAmB,GAAG,CAAA,mDAAA,CAAA;AAAA,MACpC,aAAA,CAAc;AAAA;AAChB,GACF;AACJ;AAGA,SAAS,UAAA,CAAW,UAAuB,IAAA,EAAkC;AAC3E,EAAA,IAAI,QAAQ,QAAA,EAAU;AACpB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,SAAA,GAAY,UAAU,IAAI,CAAA;AAChC,EAAA,OAAO,SAAA,IAAa,WAAW,SAAA,GAAY,MAAA;AAC7C;AAGA,SAAS,YAAA,CAAa,UAAuB,IAAA,EAAuB;AAClE,EAAA,MAAM,GAAA,GAAM,UAAA,CAAW,QAAA,EAAU,IAAI,CAAA;AACrC,EAAA,OAAO,GAAA,KAAQ,MAAA,GAAY,MAAA,GAAY,QAAA,CAAS,GAAG,CAAA;AACrD;AAEA,SAAS,UAAA,CAAW,UAAuB,IAAA,EAAuB;AAChE,EAAA,OAAO,UAAA,CAAW,QAAA,EAAU,IAAI,CAAA,KAAM,MAAA;AACxC;AAGA,SAAS,cAAA,CAAe,OAAA,EAAiB,QAAA,EAAuB,IAAA,EAAc,QAAA,EAAkB;AAC9F,EAAA,MAAM,MAAM,UAAA,CAAW,QAAA,EAAU,IAAI,CAAA,IAAK,UAAU,IAAI,CAAA;AACxD,EAAA,OAAO,QAAA;AAAA,IACL,oBAAA;AAAA,IACA,CAAA,IAAA,EAAO,OAAO,CAAA,IAAA,EAAO,GAAG,8BAA8B,QAAQ,CAAA;AAAA,GAChE;AACF;AAOO,SAAS,QAAA,CAAS,SAAiB,QAAA,EAAuC;AAC/E,EAAA,MAAM,QAAoE,EAAC;AAC3E,EAAA,KAAA,MAAW,QAAQ,eAAA,EAAiB;AAClC,IAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,QAAA,EAAU,IAAI,CAAA;AACzC,IAAA,IAAI,OAAO,UAAU,SAAA,EAAW;AAC9B,MAAA,KAAA,CAAM,IAAI,CAAA,GAAI,KAAA;AAAA,IAChB,CAAA,MAAA,IAAW,UAAA,CAAW,QAAA,EAAU,IAAI,CAAA,EAAG;AACrC,MAAA,MAAM,cAAA,CAAe,OAAA,EAAS,QAAA,EAAU,IAAA,EAAM,eAAe,CAAA;AAAA,IAC/D;AAAA,EACF;AACA,EAAA,OAAO,KAAA;AACT;AAGO,SAAS,WAAA,CAAY,SAAiB,QAAA,EAA+B;AAC1E,EAAA,MAAM,MAAA,GAAS,SAAS,cAAc,CAAA;AACtC,EAAA,IAAI,OAAO,WAAW,QAAA,EAAU;AAC9B,IAAA,MAAM,cAAA,CAAe,OAAA,EAAS,QAAA,EAAU,cAAA,EAAgB,aAAa,CAAA;AAAA,EACvE;AACA,EAAA,OAAO,MAAA;AACT;AAMO,SAAS,WAAA,CACd,SACA,QAAA,EACsC;AACtC,EAAA,IAAI,CAAC,UAAA,CAAW,QAAA,EAAU,WAAW,CAAA,EAAG;AACtC,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,MAAM,UAAU,CAAC,YAAA,CAAa,UAAU,WAAW,CAAC,EAAE,IAAA,EAAK;AAC3D,EAAA,IAAI,QAAQ,IAAA,CAAK,CAAC,UAAU,OAAO,KAAA,KAAU,QAAQ,CAAA,EAAG;AACtD,IAAA,MAAM,cAAA,CAAe,OAAA,EAAS,QAAA,EAAU,WAAA,EAAa,qCAAqC,CAAA;AAAA,EAC5F;AACA,EAAA,IAAI;AACF,IAAA,OAAO,WAAW,OAAO,CAAA;AAAA,EAC3B,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,IAAI,UAAA,CAAW,OAAA,EAAS,KAAK,CAAA;AAAA,EACrC;AACF;AAMA,SAAS,cAAA,CAAe,OAAA,EAAiB,QAAA,EAAuB,UAAA,EAAkC;AAChG,EAAA,IAAI,CAAC,UAAA,CAAW,QAAA,EAAU,sBAAsB,CAAA,EAAG;AACjD,IAAA,OAAO,EAAC;AAAA,EACV;AACA,EAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,QAAA,EAAU,sBAAsB,CAAA,IAAK,EAAA;AAChE,EAAA,MAAM,YAAY,OAAO,KAAA,KAAU,WAAW,YAAA,CAAa,KAAA,EAAO,UAAU,CAAA,GAAI,MAAA;AAChF,EAAA,IAAI,cAAc,MAAA,EAAW;AAC3B,IAAA,MAAM,cAAA,CAAe,OAAA,EAAS,QAAA,EAAU,sBAAA,EAAwB,mBAAmB,CAAA;AAAA,EACrF;AACA,EAAA,OAAO,EAAE,cAAc,SAAA,EAAU;AACnC;AAGA,SAAS,gBAAA,CAAiB,SAAiB,QAAA,EAAwC;AACjF,EAAA,IAAI,CAAC,UAAA,CAAW,QAAA,EAAU,wBAAwB,CAAA,EAAG;AACnD,IAAA,OAAO,EAAC;AAAA,EACV;AACA,EAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,QAAA,EAAU,wBAAwB,KAAK,EAAC;AACnE,EAAA,MAAM,OAAA,GAAU,CAAC,KAAK,CAAA,CAAE,IAAA,EAAK;AAC7B,EAAA,IAAI,QAAQ,IAAA,CAAK,CAAC,UAAU,OAAO,KAAA,KAAU,QAAQ,CAAA,EAAG;AACtD,IAAA,MAAM,cAAA,CAAe,OAAA,EAAS,QAAA,EAAU,wBAAA,EAA0B,aAAa,CAAA;AAAA,EACjF;AACA,EAAA,OAAO,EAAE,cAAA,EAAgB,QAAA,CAAS,OAAO,CAAA,IAAK,EAAC,EAAE;AACnD;AAOO,SAAS,kBAAA,CACd,OAAA,EACA,QAAA,EACA,UAAA,EACiB;AACjB,EAAA,OAAO;AAAA,IACL,GAAG,cAAA,CAAe,OAAA,EAAS,QAAA,EAAU,UAAU,CAAA;AAAA,IAC/C,GAAG,gBAAA,CAAiB,OAAA,EAAS,QAAQ;AAAA,GACvC;AACF;;"}
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ const cliErrors = require('./cli-errors.cjs');
3
4
  const cliOutput = require('./cli-output.cjs');
4
5
 
5
6
  function failuresOf(step) {
@@ -44,6 +45,11 @@ function writeClaimed(run, { api, claim }) {
44
45
  const failures = failuresOf(() => cliOutput.emitOutput(run, api.outputFile, api.types.contents));
45
46
  return failures.length > 0 && claim ? [...failures, ...failuresOf(() => claim.release())] : failures;
46
47
  }
48
+ function namedFailures(failures) {
49
+ return new Map(
50
+ [...failures].map(([name, list]) => [name, list.map((cause) => new cliErrors.ApiFailure(name, cause))])
51
+ );
52
+ }
47
53
  function writeGeneratedApis(run, apis, readFiles) {
48
54
  const failures = /* @__PURE__ */ new Map();
49
55
  const ownOutputs = apis.filter((api) => {
@@ -64,7 +70,7 @@ function writeGeneratedApis(run, apis, readFiles) {
64
70
  for (const entry of claimed.filter(({ api }) => !shared.has(api.name))) {
65
71
  failures.set(entry.api.name, writeClaimed(run, entry));
66
72
  }
67
- return failures;
73
+ return namedFailures(failures);
68
74
  }
69
75
 
70
76
  exports.failuresOf = failuresOf;
@@ -1 +1 @@
1
- {"version":3,"file":"api-writes.cjs","sources":["../../src/cli/api-writes.ts"],"sourcesContent":["import type { ClaimedFile } from \"../application/ports/file-system.js\";\nimport type { GeneratedTypes } from \"./cli-dependencies.js\";\nimport {\n type CliRun,\n duplicateOutputError,\n emitOutput,\n ensureOutputIsNotSchema,\n type NamedFile,\n type OutputFile,\n} from \"./cli-output.js\";\n\n/**\n * Writing the generated APIs of a Redocly config. Before the first byte is written, every output\n * is claimed: a missing one is created empty, so the file system gives it its own identity. Two\n * APIs whose files then have one identity fail with `CLI_OUTPUT_DUPLICATE` and write nothing,\n * also when their names looked different (ADR-043, decision 1).\n */\n\n/** An API whose types are generated and not written yet. */\nexport interface GeneratedApi {\n readonly name: string;\n readonly outputFile: OutputFile;\n readonly types: GeneratedTypes;\n}\n\n/** An API whose output is claimed; `claim` is undefined with `--check`, which writes nothing. */\ninterface ClaimedApi {\n readonly api: GeneratedApi;\n readonly claim: ClaimedFile | undefined;\n}\n\n/** The failures of the API an API name maps to; an API without failures was written. */\ntype ApiFailures = Map<string, unknown[]>;\n\n/** The failure of a step, as a list: empty when it succeeded. */\nexport function failuresOf(step: () => void): unknown[] {\n try {\n step();\n return [];\n } catch (failure) {\n return [failure];\n }\n}\n\n/** Claim the output of each API; an API whose claim fails gets that failure instead. */\nfunction claimOutputs(run: CliRun, apis: readonly GeneratedApi[], failures: ApiFailures) {\n const claimed: ClaimedApi[] = [];\n for (const api of apis) {\n try {\n const claim = run.args.isCheck ? undefined : run.deps.files.claimFile(api.outputFile.file);\n claimed.push({ api, claim });\n } catch (failure) {\n failures.set(api.name, [failure]);\n }\n }\n return claimed;\n}\n\n/** The APIs that share their claimed file with another, by API name, with the other names. */\nfunction sharedOutputs(claimed: readonly ClaimedApi[]): Map<string, string[]> {\n const byIdentity = new Map<string, string[]>();\n for (const { api, claim } of claimed) {\n if (claim) {\n byIdentity.set(claim.identity, [...(byIdentity.get(claim.identity) ?? []), api.name]);\n }\n }\n const shared = new Map<string, string[]>();\n for (const names of byIdentity.values()) {\n for (const name of names.length > 1 ? names : []) {\n shared.set(\n name,\n names.filter((other) => other !== name).map((other) => `API ${other}`),\n );\n }\n }\n return shared;\n}\n\n/** Write one claimed API; a failed write releases the claim, so no empty file is left. */\nfunction writeClaimed(run: CliRun, { api, claim }: ClaimedApi): unknown[] {\n const failures = failuresOf(() => emitOutput(run, api.outputFile, api.types.contents));\n return failures.length > 0 && claim\n ? [...failures, ...failuresOf(() => claim.release())]\n : failures;\n}\n\n/**\n * Write (or `--check`) every API unless its output is a file the run read or the file of another\n * API. Returns the failures by API name. Claims are released in reverse order, so a directory\n * one claim created is empty by the time it is removed.\n */\nexport function writeGeneratedApis(\n run: CliRun,\n apis: readonly GeneratedApi[],\n readFiles: readonly NamedFile[],\n): ApiFailures {\n const failures: ApiFailures = new Map();\n const ownOutputs = apis.filter((api) => {\n const failure = failuresOf(() => ensureOutputIsNotSchema(run, api.outputFile, readFiles));\n failures.set(api.name, failure);\n return failure.length === 0;\n });\n const claimed = claimOutputs(run, ownOutputs, failures);\n const shared = sharedOutputs(claimed);\n for (const entry of [...claimed].reverse()) {\n const { api, claim } = entry;\n const others = shared.get(api.name);\n if (others) {\n const release = claim ? failuresOf(() => claim.release()) : [];\n failures.set(api.name, [duplicateOutputError(api.outputFile, others), ...release]);\n }\n }\n for (const entry of claimed.filter(({ api }) => !shared.has(api.name))) {\n failures.set(entry.api.name, writeClaimed(run, entry));\n }\n return failures;\n}\n"],"names":["emitOutput","ensureOutputIsNotSchema","duplicateOutputError"],"mappings":"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"}
1
+ {"version":3,"file":"api-writes.cjs","sources":["../../src/cli/api-writes.ts"],"sourcesContent":["import type { ClaimedFile } from \"../application/ports/file-system.js\";\nimport type { GeneratedTypes } from \"./cli-dependencies.js\";\nimport { ApiFailure } from \"./cli-errors.js\";\nimport {\n type CliRun,\n duplicateOutputError,\n emitOutput,\n ensureOutputIsNotSchema,\n type NamedFile,\n type OutputFile,\n} from \"./cli-output.js\";\n\n/**\n * Writing the generated APIs of a Redocly config. Before the first byte is written, every output\n * is claimed: a missing one is created empty, so the file system gives it its own identity. Two\n * APIs whose files then have one identity fail with `CLI_OUTPUT_DUPLICATE` and write nothing,\n * also when their names looked different (ADR-043, decision 1).\n */\n\n/** An API whose types are generated and not written yet. */\nexport interface GeneratedApi {\n readonly name: string;\n readonly outputFile: OutputFile;\n readonly types: GeneratedTypes;\n}\n\n/** An API whose output is claimed; `claim` is undefined with `--check`, which writes nothing. */\ninterface ClaimedApi {\n readonly api: GeneratedApi;\n readonly claim: ClaimedFile | undefined;\n}\n\n/** The failures of the API an API name maps to; an API without failures was written. */\ntype ApiFailures = Map<string, unknown[]>;\n\n/** The failure of a step, as a list: empty when it succeeded. */\nexport function failuresOf(step: () => void): unknown[] {\n try {\n step();\n return [];\n } catch (failure) {\n return [failure];\n }\n}\n\n/** Claim the output of each API; an API whose claim fails gets that failure instead. */\nfunction claimOutputs(run: CliRun, apis: readonly GeneratedApi[], failures: ApiFailures) {\n const claimed: ClaimedApi[] = [];\n for (const api of apis) {\n try {\n const claim = run.args.isCheck ? undefined : run.deps.files.claimFile(api.outputFile.file);\n claimed.push({ api, claim });\n } catch (failure) {\n failures.set(api.name, [failure]);\n }\n }\n return claimed;\n}\n\n/** The APIs that share their claimed file with another, by API name, with the other names. */\nfunction sharedOutputs(claimed: readonly ClaimedApi[]): Map<string, string[]> {\n const byIdentity = new Map<string, string[]>();\n for (const { api, claim } of claimed) {\n if (claim) {\n byIdentity.set(claim.identity, [...(byIdentity.get(claim.identity) ?? []), api.name]);\n }\n }\n const shared = new Map<string, string[]>();\n for (const names of byIdentity.values()) {\n for (const name of names.length > 1 ? names : []) {\n shared.set(\n name,\n names.filter((other) => other !== name).map((other) => `API ${other}`),\n );\n }\n }\n return shared;\n}\n\n/** Write one claimed API; a failed write releases the claim, so no empty file is left. */\nfunction writeClaimed(run: CliRun, { api, claim }: ClaimedApi): unknown[] {\n const failures = failuresOf(() => emitOutput(run, api.outputFile, api.types.contents));\n return failures.length > 0 && claim\n ? [...failures, ...failuresOf(() => claim.release())]\n : failures;\n}\n\n/** The failures with the name of their API, which the CLI prints before each message. */\nfunction namedFailures(failures: ApiFailures): ApiFailures {\n return new Map(\n [...failures].map(([name, list]) => [name, list.map((cause) => new ApiFailure(name, cause))]),\n );\n}\n\n/**\n * Write (or `--check`) every API unless its output is a file the run read or the file of another\n * API. Returns the failures by API name, each an `ApiFailure`. Claims are released in reverse\n * order, so a directory one claim created is empty by the time it is removed.\n */\nexport function writeGeneratedApis(\n run: CliRun,\n apis: readonly GeneratedApi[],\n readFiles: readonly NamedFile[],\n): ApiFailures {\n const failures: ApiFailures = new Map();\n const ownOutputs = apis.filter((api) => {\n const failure = failuresOf(() => ensureOutputIsNotSchema(run, api.outputFile, readFiles));\n failures.set(api.name, failure);\n return failure.length === 0;\n });\n const claimed = claimOutputs(run, ownOutputs, failures);\n const shared = sharedOutputs(claimed);\n for (const entry of [...claimed].reverse()) {\n const { api, claim } = entry;\n const others = shared.get(api.name);\n if (others) {\n const release = claim ? failuresOf(() => claim.release()) : [];\n failures.set(api.name, [duplicateOutputError(api.outputFile, others), ...release]);\n }\n }\n for (const entry of claimed.filter(({ api }) => !shared.has(api.name))) {\n failures.set(entry.api.name, writeClaimed(run, entry));\n }\n return namedFailures(failures);\n}\n"],"names":["emitOutput","ApiFailure","ensureOutputIsNotSchema","duplicateOutputError"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { ApiFailure } from './cli-errors.mjs';
1
2
  import { duplicateOutputError, ensureOutputIsNotSchema, emitOutput } from './cli-output.mjs';
2
3
 
3
4
  function failuresOf(step) {
@@ -42,6 +43,11 @@ function writeClaimed(run, { api, claim }) {
42
43
  const failures = failuresOf(() => emitOutput(run, api.outputFile, api.types.contents));
43
44
  return failures.length > 0 && claim ? [...failures, ...failuresOf(() => claim.release())] : failures;
44
45
  }
46
+ function namedFailures(failures) {
47
+ return new Map(
48
+ [...failures].map(([name, list]) => [name, list.map((cause) => new ApiFailure(name, cause))])
49
+ );
50
+ }
45
51
  function writeGeneratedApis(run, apis, readFiles) {
46
52
  const failures = /* @__PURE__ */ new Map();
47
53
  const ownOutputs = apis.filter((api) => {
@@ -62,7 +68,7 @@ function writeGeneratedApis(run, apis, readFiles) {
62
68
  for (const entry of claimed.filter(({ api }) => !shared.has(api.name))) {
63
69
  failures.set(entry.api.name, writeClaimed(run, entry));
64
70
  }
65
- return failures;
71
+ return namedFailures(failures);
66
72
  }
67
73
 
68
74
  export { failuresOf, writeGeneratedApis };
@@ -1 +1 @@
1
- {"version":3,"file":"api-writes.mjs","sources":["../../src/cli/api-writes.ts"],"sourcesContent":["import type { ClaimedFile } from \"../application/ports/file-system.js\";\nimport type { GeneratedTypes } from \"./cli-dependencies.js\";\nimport {\n type CliRun,\n duplicateOutputError,\n emitOutput,\n ensureOutputIsNotSchema,\n type NamedFile,\n type OutputFile,\n} from \"./cli-output.js\";\n\n/**\n * Writing the generated APIs of a Redocly config. Before the first byte is written, every output\n * is claimed: a missing one is created empty, so the file system gives it its own identity. Two\n * APIs whose files then have one identity fail with `CLI_OUTPUT_DUPLICATE` and write nothing,\n * also when their names looked different (ADR-043, decision 1).\n */\n\n/** An API whose types are generated and not written yet. */\nexport interface GeneratedApi {\n readonly name: string;\n readonly outputFile: OutputFile;\n readonly types: GeneratedTypes;\n}\n\n/** An API whose output is claimed; `claim` is undefined with `--check`, which writes nothing. */\ninterface ClaimedApi {\n readonly api: GeneratedApi;\n readonly claim: ClaimedFile | undefined;\n}\n\n/** The failures of the API an API name maps to; an API without failures was written. */\ntype ApiFailures = Map<string, unknown[]>;\n\n/** The failure of a step, as a list: empty when it succeeded. */\nexport function failuresOf(step: () => void): unknown[] {\n try {\n step();\n return [];\n } catch (failure) {\n return [failure];\n }\n}\n\n/** Claim the output of each API; an API whose claim fails gets that failure instead. */\nfunction claimOutputs(run: CliRun, apis: readonly GeneratedApi[], failures: ApiFailures) {\n const claimed: ClaimedApi[] = [];\n for (const api of apis) {\n try {\n const claim = run.args.isCheck ? undefined : run.deps.files.claimFile(api.outputFile.file);\n claimed.push({ api, claim });\n } catch (failure) {\n failures.set(api.name, [failure]);\n }\n }\n return claimed;\n}\n\n/** The APIs that share their claimed file with another, by API name, with the other names. */\nfunction sharedOutputs(claimed: readonly ClaimedApi[]): Map<string, string[]> {\n const byIdentity = new Map<string, string[]>();\n for (const { api, claim } of claimed) {\n if (claim) {\n byIdentity.set(claim.identity, [...(byIdentity.get(claim.identity) ?? []), api.name]);\n }\n }\n const shared = new Map<string, string[]>();\n for (const names of byIdentity.values()) {\n for (const name of names.length > 1 ? names : []) {\n shared.set(\n name,\n names.filter((other) => other !== name).map((other) => `API ${other}`),\n );\n }\n }\n return shared;\n}\n\n/** Write one claimed API; a failed write releases the claim, so no empty file is left. */\nfunction writeClaimed(run: CliRun, { api, claim }: ClaimedApi): unknown[] {\n const failures = failuresOf(() => emitOutput(run, api.outputFile, api.types.contents));\n return failures.length > 0 && claim\n ? [...failures, ...failuresOf(() => claim.release())]\n : failures;\n}\n\n/**\n * Write (or `--check`) every API unless its output is a file the run read or the file of another\n * API. Returns the failures by API name. Claims are released in reverse order, so a directory\n * one claim created is empty by the time it is removed.\n */\nexport function writeGeneratedApis(\n run: CliRun,\n apis: readonly GeneratedApi[],\n readFiles: readonly NamedFile[],\n): ApiFailures {\n const failures: ApiFailures = new Map();\n const ownOutputs = apis.filter((api) => {\n const failure = failuresOf(() => ensureOutputIsNotSchema(run, api.outputFile, readFiles));\n failures.set(api.name, failure);\n return failure.length === 0;\n });\n const claimed = claimOutputs(run, ownOutputs, failures);\n const shared = sharedOutputs(claimed);\n for (const entry of [...claimed].reverse()) {\n const { api, claim } = entry;\n const others = shared.get(api.name);\n if (others) {\n const release = claim ? failuresOf(() => claim.release()) : [];\n failures.set(api.name, [duplicateOutputError(api.outputFile, others), ...release]);\n }\n }\n for (const entry of claimed.filter(({ api }) => !shared.has(api.name))) {\n failures.set(entry.api.name, writeClaimed(run, entry));\n }\n return failures;\n}\n"],"names":[],"mappings":";;AAmCO,SAAS,WAAW,IAAA,EAA6B;AACtD,EAAA,IAAI;AACF,IAAA,IAAA,EAAK;AACL,IAAA,OAAO,EAAC;AAAA,EACV,SAAS,OAAA,EAAS;AAChB,IAAA,OAAO,CAAC,OAAO,CAAA;AAAA,EACjB;AACF;AAGA,SAAS,YAAA,CAAa,GAAA,EAAa,IAAA,EAA+B,QAAA,EAAuB;AACvF,EAAA,MAAM,UAAwB,EAAC;AAC/B,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,IAAA,IAAI;AACF,MAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,IAAA,CAAK,OAAA,GAAU,KAAA,CAAA,GAAY,GAAA,CAAI,IAAA,CAAK,KAAA,CAAM,SAAA,CAAU,GAAA,CAAI,UAAA,CAAW,IAAI,CAAA;AACzF,MAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,GAAA,EAAK,KAAA,EAAO,CAAA;AAAA,IAC7B,SAAS,OAAA,EAAS;AAChB,MAAA,QAAA,CAAS,GAAA,CAAI,GAAA,CAAI,IAAA,EAAM,CAAC,OAAO,CAAC,CAAA;AAAA,IAClC;AAAA,EACF;AACA,EAAA,OAAO,OAAA;AACT;AAGA,SAAS,cAAc,OAAA,EAAuD;AAC5E,EAAA,MAAM,UAAA,uBAAiB,GAAA,EAAsB;AAC7C,EAAA,KAAA,MAAW,EAAE,GAAA,EAAK,KAAA,EAAM,IAAK,OAAA,EAAS;AACpC,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,UAAA,CAAW,GAAA,CAAI,KAAA,CAAM,QAAA,EAAU,CAAC,GAAI,UAAA,CAAW,GAAA,CAAI,KAAA,CAAM,QAAQ,CAAA,IAAK,EAAC,EAAI,GAAA,CAAI,IAAI,CAAC,CAAA;AAAA,IACtF;AAAA,EACF;AACA,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAsB;AACzC,EAAA,KAAA,MAAW,KAAA,IAAS,UAAA,CAAW,MAAA,EAAO,EAAG;AACvC,IAAA,KAAA,MAAW,QAAQ,KAAA,CAAM,MAAA,GAAS,CAAA,GAAI,KAAA,GAAQ,EAAC,EAAG;AAChD,MAAA,MAAA,CAAO,GAAA;AAAA,QACL,IAAA;AAAA,QACA,KAAA,CAAM,MAAA,CAAO,CAAC,KAAA,KAAU,KAAA,KAAU,IAAI,CAAA,CAAE,GAAA,CAAI,CAAC,KAAA,KAAU,CAAA,IAAA,EAAO,KAAK,CAAA,CAAE;AAAA,OACvE;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;AAGA,SAAS,YAAA,CAAa,GAAA,EAAa,EAAE,GAAA,EAAK,OAAM,EAA0B;AACxE,EAAA,MAAM,QAAA,GAAW,UAAA,CAAW,MAAM,UAAA,CAAW,GAAA,EAAK,IAAI,UAAA,EAAY,GAAA,CAAI,KAAA,CAAM,QAAQ,CAAC,CAAA;AACrF,EAAA,OAAO,QAAA,CAAS,MAAA,GAAS,CAAA,IAAK,KAAA,GAC1B,CAAC,GAAG,QAAA,EAAU,GAAG,UAAA,CAAW,MAAM,KAAA,CAAM,OAAA,EAAS,CAAC,CAAA,GAClD,QAAA;AACN;AAOO,SAAS,kBAAA,CACd,GAAA,EACA,IAAA,EACA,SAAA,EACa;AACb,EAAA,MAAM,QAAA,uBAA4B,GAAA,EAAI;AACtC,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,MAAA,CAAO,CAAC,GAAA,KAAQ;AACtC,IAAA,MAAM,OAAA,GAAU,WAAW,MAAM,uBAAA,CAAwB,KAAK,GAAA,CAAI,UAAA,EAAY,SAAS,CAAC,CAAA;AACxF,IAAA,QAAA,CAAS,GAAA,CAAI,GAAA,CAAI,IAAA,EAAM,OAAO,CAAA;AAC9B,IAAA,OAAO,QAAQ,MAAA,KAAW,CAAA;AAAA,EAC5B,CAAC,CAAA;AACD,EAAA,MAAM,OAAA,GAAU,YAAA,CAAa,GAAA,EAAK,UAAA,EAAY,QAAQ,CAAA;AACtD,EAAA,MAAM,MAAA,GAAS,cAAc,OAAO,CAAA;AACpC,EAAA,KAAA,MAAW,SAAS,CAAC,GAAG,OAAO,CAAA,CAAE,SAAQ,EAAG;AAC1C,IAAA,MAAM,EAAE,GAAA,EAAK,KAAA,EAAM,GAAI,KAAA;AACvB,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,GAAA,CAAI,GAAA,CAAI,IAAI,CAAA;AAClC,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,MAAM,OAAA,GAAU,QAAQ,UAAA,CAAW,MAAM,MAAM,OAAA,EAAS,IAAI,EAAC;AAC7D,MAAA,QAAA,CAAS,GAAA,CAAI,GAAA,CAAI,IAAA,EAAM,CAAC,oBAAA,CAAqB,GAAA,CAAI,UAAA,EAAY,MAAM,CAAA,EAAG,GAAG,OAAO,CAAC,CAAA;AAAA,IACnF;AAAA,EACF;AACA,EAAA,KAAA,MAAW,KAAA,IAAS,OAAA,CAAQ,MAAA,CAAO,CAAC,EAAE,GAAA,EAAI,KAAM,CAAC,MAAA,CAAO,GAAA,CAAI,GAAA,CAAI,IAAI,CAAC,CAAA,EAAG;AACtE,IAAA,QAAA,CAAS,IAAI,KAAA,CAAM,GAAA,CAAI,MAAM,YAAA,CAAa,GAAA,EAAK,KAAK,CAAC,CAAA;AAAA,EACvD;AACA,EAAA,OAAO,QAAA;AACT;;"}
1
+ {"version":3,"file":"api-writes.mjs","sources":["../../src/cli/api-writes.ts"],"sourcesContent":["import type { ClaimedFile } from \"../application/ports/file-system.js\";\nimport type { GeneratedTypes } from \"./cli-dependencies.js\";\nimport { ApiFailure } from \"./cli-errors.js\";\nimport {\n type CliRun,\n duplicateOutputError,\n emitOutput,\n ensureOutputIsNotSchema,\n type NamedFile,\n type OutputFile,\n} from \"./cli-output.js\";\n\n/**\n * Writing the generated APIs of a Redocly config. Before the first byte is written, every output\n * is claimed: a missing one is created empty, so the file system gives it its own identity. Two\n * APIs whose files then have one identity fail with `CLI_OUTPUT_DUPLICATE` and write nothing,\n * also when their names looked different (ADR-043, decision 1).\n */\n\n/** An API whose types are generated and not written yet. */\nexport interface GeneratedApi {\n readonly name: string;\n readonly outputFile: OutputFile;\n readonly types: GeneratedTypes;\n}\n\n/** An API whose output is claimed; `claim` is undefined with `--check`, which writes nothing. */\ninterface ClaimedApi {\n readonly api: GeneratedApi;\n readonly claim: ClaimedFile | undefined;\n}\n\n/** The failures of the API an API name maps to; an API without failures was written. */\ntype ApiFailures = Map<string, unknown[]>;\n\n/** The failure of a step, as a list: empty when it succeeded. */\nexport function failuresOf(step: () => void): unknown[] {\n try {\n step();\n return [];\n } catch (failure) {\n return [failure];\n }\n}\n\n/** Claim the output of each API; an API whose claim fails gets that failure instead. */\nfunction claimOutputs(run: CliRun, apis: readonly GeneratedApi[], failures: ApiFailures) {\n const claimed: ClaimedApi[] = [];\n for (const api of apis) {\n try {\n const claim = run.args.isCheck ? undefined : run.deps.files.claimFile(api.outputFile.file);\n claimed.push({ api, claim });\n } catch (failure) {\n failures.set(api.name, [failure]);\n }\n }\n return claimed;\n}\n\n/** The APIs that share their claimed file with another, by API name, with the other names. */\nfunction sharedOutputs(claimed: readonly ClaimedApi[]): Map<string, string[]> {\n const byIdentity = new Map<string, string[]>();\n for (const { api, claim } of claimed) {\n if (claim) {\n byIdentity.set(claim.identity, [...(byIdentity.get(claim.identity) ?? []), api.name]);\n }\n }\n const shared = new Map<string, string[]>();\n for (const names of byIdentity.values()) {\n for (const name of names.length > 1 ? names : []) {\n shared.set(\n name,\n names.filter((other) => other !== name).map((other) => `API ${other}`),\n );\n }\n }\n return shared;\n}\n\n/** Write one claimed API; a failed write releases the claim, so no empty file is left. */\nfunction writeClaimed(run: CliRun, { api, claim }: ClaimedApi): unknown[] {\n const failures = failuresOf(() => emitOutput(run, api.outputFile, api.types.contents));\n return failures.length > 0 && claim\n ? [...failures, ...failuresOf(() => claim.release())]\n : failures;\n}\n\n/** The failures with the name of their API, which the CLI prints before each message. */\nfunction namedFailures(failures: ApiFailures): ApiFailures {\n return new Map(\n [...failures].map(([name, list]) => [name, list.map((cause) => new ApiFailure(name, cause))]),\n );\n}\n\n/**\n * Write (or `--check`) every API unless its output is a file the run read or the file of another\n * API. Returns the failures by API name, each an `ApiFailure`. Claims are released in reverse\n * order, so a directory one claim created is empty by the time it is removed.\n */\nexport function writeGeneratedApis(\n run: CliRun,\n apis: readonly GeneratedApi[],\n readFiles: readonly NamedFile[],\n): ApiFailures {\n const failures: ApiFailures = new Map();\n const ownOutputs = apis.filter((api) => {\n const failure = failuresOf(() => ensureOutputIsNotSchema(run, api.outputFile, readFiles));\n failures.set(api.name, failure);\n return failure.length === 0;\n });\n const claimed = claimOutputs(run, ownOutputs, failures);\n const shared = sharedOutputs(claimed);\n for (const entry of [...claimed].reverse()) {\n const { api, claim } = entry;\n const others = shared.get(api.name);\n if (others) {\n const release = claim ? failuresOf(() => claim.release()) : [];\n failures.set(api.name, [duplicateOutputError(api.outputFile, others), ...release]);\n }\n }\n for (const entry of claimed.filter(({ api }) => !shared.has(api.name))) {\n failures.set(entry.api.name, writeClaimed(run, entry));\n }\n return namedFailures(failures);\n}\n"],"names":[],"mappings":"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"}