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.
- package/CHANGELOG.md +214 -0
- package/dist/adapters/node-file-system/node-file-system.cjs +7 -0
- package/dist/adapters/node-file-system/node-file-system.cjs.map +1 -1
- package/dist/adapters/node-file-system/node-file-system.mjs +7 -0
- package/dist/adapters/node-file-system/node-file-system.mjs.map +1 -1
- package/dist/adapters/pipe-safe-writer/pipe-safe-writer.cjs +19 -0
- package/dist/adapters/pipe-safe-writer/pipe-safe-writer.cjs.map +1 -0
- package/dist/adapters/pipe-safe-writer/pipe-safe-writer.mjs +17 -0
- package/dist/adapters/pipe-safe-writer/pipe-safe-writer.mjs.map +1 -0
- package/dist/adapters/redocly-loader/bundled-mapping-copies.cjs +5 -32
- package/dist/adapters/redocly-loader/bundled-mapping-copies.cjs.map +1 -1
- package/dist/adapters/redocly-loader/bundled-mapping-copies.mjs +6 -33
- package/dist/adapters/redocly-loader/bundled-mapping-copies.mjs.map +1 -1
- package/dist/adapters/redocly-loader/component-schemas.cjs +17 -0
- package/dist/adapters/redocly-loader/component-schemas.cjs.map +1 -0
- package/dist/adapters/redocly-loader/component-schemas.mjs +14 -0
- package/dist/adapters/redocly-loader/component-schemas.mjs.map +1 -0
- package/dist/adapters/redocly-loader/mapping-schema-names.cjs +22 -0
- package/dist/adapters/redocly-loader/mapping-schema-names.cjs.map +1 -0
- package/dist/adapters/redocly-loader/mapping-schema-names.mjs +20 -0
- package/dist/adapters/redocly-loader/mapping-schema-names.mjs.map +1 -0
- package/dist/adapters/redocly-loader/query-document-names.cjs +50 -0
- package/dist/adapters/redocly-loader/query-document-names.cjs.map +1 -0
- package/dist/adapters/redocly-loader/query-document-names.mjs +48 -0
- package/dist/adapters/redocly-loader/query-document-names.mjs.map +1 -0
- package/dist/adapters/redocly-loader/query-named-components.cjs +129 -0
- package/dist/adapters/redocly-loader/query-named-components.cjs.map +1 -0
- package/dist/adapters/redocly-loader/query-named-components.mjs +126 -0
- package/dist/adapters/redocly-loader/query-named-components.mjs.map +1 -0
- package/dist/adapters/redocly-loader/redocly-config-source.cjs +3 -0
- package/dist/adapters/redocly-loader/redocly-config-source.cjs.map +1 -1
- package/dist/adapters/redocly-loader/redocly-config-source.mjs +4 -1
- package/dist/adapters/redocly-loader/redocly-config-source.mjs.map +1 -1
- package/dist/adapters/redocly-loader/redocly-schema-loader.cjs +39 -18
- package/dist/adapters/redocly-loader/redocly-schema-loader.cjs.map +1 -1
- package/dist/adapters/redocly-loader/redocly-schema-loader.mjs +40 -19
- package/dist/adapters/redocly-loader/redocly-schema-loader.mjs.map +1 -1
- package/dist/adapters/redocly-loader/ref-access.cjs +25 -4
- package/dist/adapters/redocly-loader/ref-access.cjs.map +1 -1
- package/dist/adapters/redocly-loader/ref-access.mjs +26 -5
- package/dist/adapters/redocly-loader/ref-access.mjs.map +1 -1
- package/dist/adapters/redocly-loader/ref-holders.cjs +52 -10
- package/dist/adapters/redocly-loader/ref-holders.cjs.map +1 -1
- package/dist/adapters/redocly-loader/ref-holders.mjs +52 -11
- package/dist/adapters/redocly-loader/ref-holders.mjs.map +1 -1
- package/dist/adapters/redocly-loader/remote-fetch.cjs +20 -3
- package/dist/adapters/redocly-loader/remote-fetch.cjs.map +1 -1
- package/dist/adapters/redocly-loader/remote-fetch.mjs +20 -4
- package/dist/adapters/redocly-loader/remote-fetch.mjs.map +1 -1
- package/dist/adapters/redocly-loader/remote-node-limit.cjs +17 -3
- package/dist/adapters/redocly-loader/remote-node-limit.cjs.map +1 -1
- package/dist/adapters/redocly-loader/remote-node-limit.mjs +17 -3
- package/dist/adapters/redocly-loader/remote-node-limit.mjs.map +1 -1
- package/dist/adapters/redocly-loader/schema-source.cjs +7 -2
- package/dist/adapters/redocly-loader/schema-source.cjs.map +1 -1
- package/dist/adapters/redocly-loader/schema-source.mjs +8 -3
- package/dist/adapters/redocly-loader/schema-source.mjs.map +1 -1
- package/dist/adapters/terminal-logger/terminal-logger.cjs +7 -3
- package/dist/adapters/terminal-logger/terminal-logger.cjs.map +1 -1
- package/dist/adapters/terminal-logger/terminal-logger.mjs +7 -3
- package/dist/adapters/terminal-logger/terminal-logger.mjs.map +1 -1
- package/dist/api/cwd-option.cjs +58 -0
- package/dist/api/cwd-option.cjs.map +1 -0
- package/dist/api/cwd-option.mjs +52 -0
- package/dist/api/cwd-option.mjs.map +1 -0
- package/dist/api/default-ports.cjs +15 -7
- package/dist/api/default-ports.cjs.map +1 -1
- package/dist/api/default-ports.mjs +14 -8
- package/dist/api/default-ports.mjs.map +1 -1
- package/dist/api/document-refs.cjs +16 -1
- package/dist/api/document-refs.cjs.map +1 -1
- package/dist/api/document-refs.mjs +16 -1
- package/dist/api/document-refs.mjs.map +1 -1
- package/dist/api/document-run.cjs +6 -26
- package/dist/api/document-run.cjs.map +1 -1
- package/dist/api/document-run.mjs +5 -21
- package/dist/api/document-run.mjs.map +1 -1
- package/dist/api/legacy-utils.cjs +1 -1
- package/dist/api/legacy-utils.cjs.map +1 -1
- package/dist/api/legacy-utils.mjs +1 -1
- package/dist/api/legacy-utils.mjs.map +1 -1
- package/dist/api/openapi-ts.cjs +1 -2
- package/dist/api/openapi-ts.cjs.map +1 -1
- package/dist/api/openapi-ts.mjs +2 -3
- package/dist/api/openapi-ts.mjs.map +1 -1
- package/dist/api/option-errors.cjs +24 -0
- package/dist/api/option-errors.cjs.map +1 -0
- package/dist/api/option-errors.mjs +21 -0
- package/dist/api/option-errors.mjs.map +1 -0
- package/dist/api/ref-limit-options.cjs +58 -0
- package/dist/api/ref-limit-options.cjs.map +1 -0
- package/dist/api/ref-limit-options.mjs +52 -0
- package/dist/api/ref-limit-options.mjs.map +1 -0
- package/dist/api/transform-schema.cjs +12 -5
- package/dist/api/transform-schema.cjs.map +1 -1
- package/dist/api/transform-schema.mjs +12 -5
- package/dist/api/transform-schema.mjs.map +1 -1
- package/dist/application/transform/declared-value-types.cjs +36 -0
- package/dist/application/transform/declared-value-types.cjs.map +1 -0
- package/dist/application/transform/declared-value-types.mjs +34 -0
- package/dist/application/transform/declared-value-types.mjs.map +1 -0
- package/dist/application/transform/document/document.cjs +3 -1
- package/dist/application/transform/document/document.cjs.map +1 -1
- package/dist/application/transform/document/document.mjs +3 -1
- package/dist/application/transform/document/document.mjs.map +1 -1
- package/dist/application/transform/document/exploded-query-values.cjs +63 -0
- package/dist/application/transform/document/exploded-query-values.cjs.map +1 -0
- package/dist/application/transform/document/exploded-query-values.mjs +59 -0
- package/dist/application/transform/document/exploded-query-values.mjs.map +1 -0
- package/dist/application/transform/document/header.cjs +11 -3
- package/dist/application/transform/document/header.cjs.map +1 -1
- package/dist/application/transform/document/header.mjs +10 -2
- package/dist/application/transform/document/header.mjs.map +1 -1
- package/dist/application/transform/document/parameter.cjs +1 -1
- package/dist/application/transform/document/parameter.cjs.map +1 -1
- package/dist/application/transform/document/parameter.mjs +1 -1
- package/dist/application/transform/document/parameter.mjs.map +1 -1
- package/dist/application/transform/document/parameters.cjs +23 -5
- package/dist/application/transform/document/parameters.cjs.map +1 -1
- package/dist/application/transform/document/parameters.mjs +23 -5
- package/dist/application/transform/document/parameters.mjs.map +1 -1
- package/dist/application/transform/document/path-item.cjs +4 -3
- package/dist/application/transform/document/path-item.cjs.map +1 -1
- package/dist/application/transform/document/path-item.mjs +4 -4
- package/dist/application/transform/document/path-item.mjs.map +1 -1
- package/dist/application/transform/document/path-template-key.cjs +84 -0
- package/dist/application/transform/document/path-template-key.cjs.map +1 -0
- package/dist/application/transform/document/path-template-key.mjs +79 -0
- package/dist/application/transform/document/path-template-key.mjs.map +1 -0
- package/dist/application/transform/document/path-template-refs.cjs +80 -0
- package/dist/application/transform/document/path-template-refs.cjs.map +1 -0
- package/dist/application/transform/document/path-template-refs.mjs +77 -0
- package/dist/application/transform/document/path-template-refs.mjs.map +1 -0
- package/dist/application/transform/document/paths-enum.cjs +7 -6
- package/dist/application/transform/document/paths-enum.cjs.map +1 -1
- package/dist/application/transform/document/paths-enum.mjs +7 -6
- package/dist/application/transform/document/paths-enum.mjs.map +1 -1
- package/dist/application/transform/document/paths.cjs +38 -66
- package/dist/application/transform/document/paths.cjs.map +1 -1
- package/dist/application/transform/document/paths.mjs +36 -66
- package/dist/application/transform/document/paths.mjs.map +1 -1
- package/dist/application/transform/document/webhooks.cjs +10 -3
- package/dist/application/transform/document/webhooks.cjs.map +1 -1
- package/dist/application/transform/document/webhooks.mjs +9 -2
- package/dist/application/transform/document/webhooks.mjs.map +1 -1
- package/dist/application/transform/footer/document-footer.cjs +6 -3
- package/dist/application/transform/footer/document-footer.cjs.map +1 -1
- package/dist/application/transform/footer/document-footer.mjs +6 -3
- package/dist/application/transform/footer/document-footer.mjs.map +1 -1
- package/dist/application/transform/helper-types.cjs +3 -3
- package/dist/application/transform/helper-types.cjs.map +1 -1
- package/dist/application/transform/helper-types.mjs +3 -3
- package/dist/application/transform/helper-types.mjs.map +1 -1
- package/dist/application/transform/ref-pointer/generated-location.cjs +4 -4
- package/dist/application/transform/ref-pointer/generated-location.cjs.map +1 -1
- package/dist/application/transform/ref-pointer/generated-location.mjs +1 -1
- package/dist/application/transform/ref-pointer/generated-location.mjs.map +1 -1
- package/dist/application/transform/ref-pointer/generated-shape.cjs +63 -64
- package/dist/application/transform/ref-pointer/generated-shape.cjs.map +1 -1
- package/dist/application/transform/ref-pointer/generated-shape.mjs +57 -53
- package/dist/application/transform/ref-pointer/generated-shape.mjs.map +1 -1
- package/dist/application/transform/ref-pointer/inline-cycles.cjs +2 -2
- package/dist/application/transform/ref-pointer/inline-cycles.cjs.map +1 -1
- package/dist/application/transform/ref-pointer/inline-cycles.mjs +1 -1
- package/dist/application/transform/ref-pointer/inline-cycles.mjs.map +1 -1
- package/dist/application/transform/ref-pointer/located-node.cjs +23 -0
- package/dist/application/transform/ref-pointer/located-node.cjs.map +1 -0
- package/dist/application/transform/ref-pointer/located-node.mjs +18 -0
- package/dist/application/transform/ref-pointer/located-node.mjs.map +1 -0
- package/dist/application/transform/ref-pointer/original-index.cjs +69 -14
- package/dist/application/transform/ref-pointer/original-index.cjs.map +1 -1
- package/dist/application/transform/ref-pointer/original-index.mjs +71 -16
- package/dist/application/transform/ref-pointer/original-index.mjs.map +1 -1
- package/dist/application/transform/ref-pointer/pointer-type.cjs +2 -2
- package/dist/application/transform/ref-pointer/pointer-type.cjs.map +1 -1
- package/dist/application/transform/ref-pointer/pointer-type.mjs +1 -1
- package/dist/application/transform/ref-pointer/pointer-type.mjs.map +1 -1
- package/dist/application/transform/ref-pointer/pointer-walk.cjs +54 -13
- package/dist/application/transform/ref-pointer/pointer-walk.cjs.map +1 -1
- package/dist/application/transform/ref-pointer/pointer-walk.mjs +46 -7
- package/dist/application/transform/ref-pointer/pointer-walk.mjs.map +1 -1
- package/dist/application/transform/ref-pointer/property-shape.cjs +57 -0
- package/dist/application/transform/ref-pointer/property-shape.cjs.map +1 -0
- package/dist/application/transform/ref-pointer/property-shape.mjs +49 -0
- package/dist/application/transform/ref-pointer/property-shape.mjs.map +1 -0
- package/dist/application/transform/ref-pointer/typed-walk.cjs +90 -22
- package/dist/application/transform/ref-pointer/typed-walk.cjs.map +1 -1
- package/dist/application/transform/ref-pointer/typed-walk.mjs +87 -19
- package/dist/application/transform/ref-pointer/typed-walk.mjs.map +1 -1
- package/dist/application/transform/schema/access-flags.cjs.map +1 -1
- package/dist/application/transform/schema/access-flags.mjs.map +1 -1
- package/dist/application/transform/schema/index-signature-type.cjs +21 -0
- package/dist/application/transform/schema/index-signature-type.cjs.map +1 -0
- package/dist/application/transform/schema/index-signature-type.mjs +19 -0
- package/dist/application/transform/schema/index-signature-type.mjs.map +1 -0
- package/dist/application/transform/schema/input-location.cjs +23 -0
- package/dist/application/transform/schema/input-location.cjs.map +1 -0
- package/dist/application/transform/schema/input-location.mjs +21 -0
- package/dist/application/transform/schema/input-location.mjs.map +1 -0
- package/dist/application/transform/schema/object-type.cjs +15 -5
- package/dist/application/transform/schema/object-type.cjs.map +1 -1
- package/dist/application/transform/schema/object-type.mjs +15 -5
- package/dist/application/transform/schema/object-type.mjs.map +1 -1
- package/dist/application/transform/schema/schema-transform.cjs +2 -1
- package/dist/application/transform/schema/schema-transform.cjs.map +1 -1
- package/dist/application/transform/schema/schema-transform.mjs +2 -1
- package/dist/application/transform/schema/schema-transform.mjs.map +1 -1
- package/dist/application/transform/schema/unevaluated-properties.cjs +2 -30
- package/dist/application/transform/schema/unevaluated-properties.cjs.map +1 -1
- package/dist/application/transform/schema/unevaluated-properties.mjs +3 -31
- package/dist/application/transform/schema/unevaluated-properties.mjs.map +1 -1
- package/dist/cli/api-logger.cjs +13 -0
- package/dist/cli/api-logger.cjs.map +1 -0
- package/dist/cli/api-logger.mjs +11 -0
- package/dist/cli/api-logger.mjs.map +1 -0
- package/dist/cli/api-settings.cjs +10 -17
- package/dist/cli/api-settings.cjs.map +1 -1
- package/dist/cli/api-settings.mjs +10 -17
- package/dist/cli/api-settings.mjs.map +1 -1
- package/dist/cli/api-writes.cjs +7 -1
- package/dist/cli/api-writes.cjs.map +1 -1
- package/dist/cli/api-writes.mjs +7 -1
- package/dist/cli/api-writes.mjs.map +1 -1
- package/dist/cli/cli-arguments.cjs +32 -74
- package/dist/cli/cli-arguments.cjs.map +1 -1
- package/dist/cli/cli-arguments.mjs +28 -70
- package/dist/cli/cli-arguments.mjs.map +1 -1
- package/dist/cli/cli-errors.cjs +18 -0
- package/dist/cli/cli-errors.cjs.map +1 -1
- package/dist/cli/cli-errors.mjs +18 -1
- package/dist/cli/cli-errors.mjs.map +1 -1
- package/dist/cli/cli-flag-names.cjs +77 -0
- package/dist/cli/cli-flag-names.cjs.map +1 -0
- package/dist/cli/cli-flag-names.mjs +64 -0
- package/dist/cli/cli-flag-names.mjs.map +1 -0
- package/dist/cli/cli-output.cjs +13 -6
- package/dist/cli/cli-output.cjs.map +1 -1
- package/dist/cli/cli-output.mjs +14 -7
- package/dist/cli/cli-output.mjs.map +1 -1
- package/dist/cli/main.cjs +11 -5
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.mjs +11 -5
- package/dist/cli/main.mjs.map +1 -1
- package/dist/cli/redocly-apis.cjs +33 -12
- package/dist/cli/redocly-apis.cjs.map +1 -1
- package/dist/cli/redocly-apis.mjs +35 -14
- package/dist/cli/redocly-apis.mjs.map +1 -1
- package/dist/cli/ref-limits.cjs +15 -1
- package/dist/cli/ref-limits.cjs.map +1 -1
- package/dist/cli/ref-limits.mjs +15 -2
- package/dist/cli/ref-limits.mjs.map +1 -1
- package/dist/cli/run-cli.cjs +24 -7
- package/dist/cli/run-cli.cjs.map +1 -1
- package/dist/cli/run-cli.mjs +25 -8
- package/dist/cli/run-cli.mjs.map +1 -1
- package/dist/cli/written-flags.cjs +83 -0
- package/dist/cli/written-flags.cjs.map +1 -0
- package/dist/cli/written-flags.mjs +77 -0
- package/dist/cli/written-flags.mjs.map +1 -0
- package/dist/domain/cause-secrets.cjs +31 -16
- package/dist/domain/cause-secrets.cjs.map +1 -1
- package/dist/domain/cause-secrets.mjs +31 -16
- package/dist/domain/cause-secrets.mjs.map +1 -1
- package/dist/domain/errors.cjs +3 -0
- package/dist/domain/errors.cjs.map +1 -1
- package/dist/domain/errors.mjs +3 -0
- package/dist/domain/errors.mjs.map +1 -1
- package/dist/domain/location-text.cjs +15 -0
- package/dist/domain/location-text.cjs.map +1 -0
- package/dist/domain/location-text.mjs +13 -0
- package/dist/domain/location-text.mjs.map +1 -0
- package/dist/domain/openapi/document-places.cjs +55 -0
- package/dist/domain/openapi/document-places.cjs.map +1 -0
- package/dist/domain/openapi/document-places.mjs +53 -0
- package/dist/domain/openapi/document-places.mjs.map +1 -0
- package/dist/domain/output-fixes.cjs +8 -2
- package/dist/domain/output-fixes.cjs.map +1 -1
- package/dist/domain/output-fixes.mjs +8 -2
- package/dist/domain/output-fixes.mjs.map +1 -1
- package/dist/domain/terminal-text.cjs +31 -0
- package/dist/domain/terminal-text.cjs.map +1 -0
- package/dist/domain/terminal-text.mjs +29 -0
- package/dist/domain/terminal-text.mjs.map +1 -0
- package/dist/domain/warnings.cjs +1 -0
- package/dist/domain/warnings.cjs.map +1 -1
- package/dist/domain/warnings.mjs +1 -0
- package/dist/domain/warnings.mjs.map +1 -1
- package/dist/index.d.cts +29 -18
- package/dist/index.d.mts +29 -18
- package/dist/index.d.ts +29 -18
- package/package.json +1 -1
- package/src/adapters/node-file-system/node-file-system.ts +14 -1
- package/src/adapters/pipe-safe-writer/pipe-safe-writer.ts +29 -0
- package/src/adapters/redocly-loader/bundled-mapping-copies.ts +7 -42
- package/src/adapters/redocly-loader/component-schemas.ts +19 -0
- package/src/adapters/redocly-loader/mapping-schema-names.ts +25 -0
- package/src/adapters/redocly-loader/query-document-names.ts +79 -0
- package/src/adapters/redocly-loader/query-named-components.ts +200 -0
- package/src/adapters/redocly-loader/redocly-config-source.ts +11 -1
- package/src/adapters/redocly-loader/redocly-schema-loader.ts +63 -17
- package/src/adapters/redocly-loader/ref-access.ts +32 -5
- package/src/adapters/redocly-loader/ref-holders.ts +75 -14
- package/src/adapters/redocly-loader/remote-fetch.ts +37 -2
- package/src/adapters/redocly-loader/remote-node-limit.ts +44 -4
- package/src/adapters/redocly-loader/schema-source.ts +15 -3
- package/src/adapters/terminal-logger/terminal-logger.ts +10 -4
- package/src/api/cwd-option.ts +76 -0
- package/src/api/default-ports.ts +33 -10
- package/src/api/document-refs.ts +29 -1
- package/src/api/document-run.ts +7 -32
- package/src/api/legacy-utils.ts +1 -1
- package/src/api/openapi-ts.ts +20 -4
- package/src/api/option-errors.ts +22 -0
- package/src/api/ref-limit-options.ts +69 -0
- package/src/api/transform-schema.ts +20 -5
- package/src/application/ports/file-system.ts +8 -0
- package/src/application/ports/redocly-config-source.ts +5 -0
- package/src/application/transform/declared-value-types.ts +42 -0
- package/src/application/transform/document/document.ts +4 -2
- package/src/application/transform/document/exploded-query-values.ts +88 -0
- package/src/application/transform/document/header.ts +25 -5
- package/src/application/transform/document/parameter.ts +4 -4
- package/src/application/transform/document/parameters.ts +45 -10
- package/src/application/transform/document/path-item.ts +3 -3
- package/src/application/transform/document/path-template-key.ts +152 -0
- package/src/application/transform/document/path-template-refs.ts +127 -0
- package/src/application/transform/document/paths-enum.ts +23 -9
- package/src/application/transform/document/paths.ts +53 -123
- package/src/application/transform/document/webhooks.ts +18 -5
- package/src/application/transform/footer/document-footer.ts +18 -8
- package/src/application/transform/helper-types.ts +4 -4
- package/src/application/transform/ref-pointer/generated-location.ts +1 -1
- package/src/application/transform/ref-pointer/generated-shape.ts +115 -83
- package/src/application/transform/ref-pointer/inline-cycles.ts +1 -1
- package/src/application/transform/ref-pointer/located-node.ts +38 -0
- package/src/application/transform/ref-pointer/original-index.ts +106 -20
- package/src/application/transform/ref-pointer/pointer-type.ts +1 -1
- package/src/application/transform/ref-pointer/pointer-walk.ts +82 -8
- package/src/application/transform/ref-pointer/property-shape.ts +106 -0
- package/src/application/transform/ref-pointer/typed-walk.ts +143 -29
- package/src/application/transform/schema/access-flags.ts +5 -2
- package/src/application/transform/schema/index-signature-type.ts +31 -0
- package/src/application/transform/schema/input-location.ts +35 -0
- package/src/application/transform/schema/object-type.ts +18 -8
- package/src/application/transform/schema/schema-transform.ts +2 -1
- package/src/application/transform/schema/unevaluated-properties.ts +4 -44
- package/src/cli/api-logger.ts +17 -0
- package/src/cli/api-settings.ts +12 -20
- package/src/cli/api-writes.ts +11 -3
- package/src/cli/cli-arguments.ts +57 -92
- package/src/cli/cli-dependencies.ts +7 -2
- package/src/cli/cli-errors.ts +23 -0
- package/src/cli/cli-flag-names.ts +99 -0
- package/src/cli/cli-output.ts +31 -16
- package/src/cli/main.ts +12 -5
- package/src/cli/redocly-apis.ts +56 -20
- package/src/cli/ref-limits.ts +21 -2
- package/src/cli/run-cli.ts +39 -7
- package/src/cli/written-flags.ts +131 -0
- package/src/domain/cause-secrets.ts +59 -25
- package/src/domain/errors.ts +3 -0
- package/src/domain/location-text.ts +27 -0
- package/src/domain/openapi/document-places.ts +78 -0
- package/src/domain/output-fixes.ts +9 -2
- package/src/domain/terminal-text.ts +44 -0
- package/src/domain/warnings.ts +1 -0
package/src/cli/redocly-apis.ts
CHANGED
|
@@ -10,7 +10,8 @@ import {
|
|
|
10
10
|
unknownSettingWarnings,
|
|
11
11
|
} from "./api-settings.js";
|
|
12
12
|
import { type GeneratedApi, writeGeneratedApis } from "./api-writes.js";
|
|
13
|
-
import {
|
|
13
|
+
import { ineffectiveFlagNotices } from "./cli-arguments.js";
|
|
14
|
+
import { ApiFailure, cliError } from "./cli-errors.js";
|
|
14
15
|
import {
|
|
15
16
|
type CliRun,
|
|
16
17
|
ensureOutputIsNotSchema,
|
|
@@ -24,7 +25,7 @@ import {
|
|
|
24
25
|
} from "./cli-output.js";
|
|
25
26
|
import { MULTIPLE_SCHEMAS_DOCS_URL } from "./docs-links.js";
|
|
26
27
|
import { fixOption } from "./fix-option.js";
|
|
27
|
-
import { refLimitOptions } from "./ref-limits.js";
|
|
28
|
+
import { type RefLimitOptions, refLimitOptions } from "./ref-limits.js";
|
|
28
29
|
|
|
29
30
|
/** The `apis` of a Redocly config: each API is generated into its `x-openapi-ts.output`. */
|
|
30
31
|
|
|
@@ -92,16 +93,34 @@ function apiTarget(api: RedoclyApi, configRoot: URL): ApiTarget {
|
|
|
92
93
|
return { name, root, settings, configRoot };
|
|
93
94
|
}
|
|
94
95
|
|
|
95
|
-
/**
|
|
96
|
-
|
|
96
|
+
/**
|
|
97
|
+
* What every API of a run shares: the config, the files of all APIs, and the reference limits of
|
|
98
|
+
* the command line, which are checked once before any API, so an invalid flag fails the run once.
|
|
99
|
+
*/
|
|
100
|
+
interface ApiRun {
|
|
101
|
+
readonly redocly: RedoclyConfig;
|
|
102
|
+
readonly files: ConfigFiles;
|
|
103
|
+
readonly refLimits: RefLimitOptions;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* The generator options of one API: its own settings win over the CLI's flags, and its own lint
|
|
108
|
+
* rules in `redocly.yaml` over the root's (upstream used the root's only). A flag that has
|
|
109
|
+
* no effect with the merged flags is named for this API, since its settings may turn on the flag
|
|
110
|
+
* that the command line lacks, or set one that has no effect themselves.
|
|
111
|
+
*/
|
|
112
|
+
function apiOptions(run: CliRun, apiRun: ApiRun, target: ApiTarget): GeneratorOptions {
|
|
97
113
|
const { name, settings, configRoot } = target;
|
|
114
|
+
const flags = { ...run.args.generatorFlags, ...apiFlags(name, settings) };
|
|
115
|
+
for (const notice of ineffectiveFlagNotices(flags)) {
|
|
116
|
+
run.deps.console.notice(`API ${name}: ${notice}`);
|
|
117
|
+
}
|
|
98
118
|
return {
|
|
99
|
-
...
|
|
100
|
-
...
|
|
101
|
-
...refLimitOptions(run.args, run.deps.cwd),
|
|
119
|
+
...flags,
|
|
120
|
+
...apiRun.refLimits,
|
|
102
121
|
...apiRefLimitOptions(name, settings, configRoot),
|
|
103
122
|
...fixOption(apiFixNames(name, settings) ?? run.args.fix),
|
|
104
|
-
redocly,
|
|
123
|
+
redocly: run.deps.redoclyConfigs.forApi(apiRun.redocly, name),
|
|
105
124
|
};
|
|
106
125
|
}
|
|
107
126
|
|
|
@@ -122,22 +141,38 @@ function otherOutputs(files: ConfigFiles, apiName: string): NamedFile[] {
|
|
|
122
141
|
* Generate the types of one API. Its output must not be a file the run reads before any API is
|
|
123
142
|
* loaded (the root of any API, the Redocly config) nor another API's output.
|
|
124
143
|
*/
|
|
125
|
-
async function generateApi(
|
|
126
|
-
|
|
127
|
-
redocly: RedoclyConfig,
|
|
128
|
-
target: ApiTarget,
|
|
129
|
-
files: ConfigFiles,
|
|
130
|
-
): Promise<GeneratedApi> {
|
|
144
|
+
async function generateApi(run: CliRun, apiRun: ApiRun, target: ApiTarget): Promise<GeneratedApi> {
|
|
145
|
+
const { files } = apiRun;
|
|
131
146
|
for (const warning of unknownSettingWarnings(target.name, target.settings)) {
|
|
132
147
|
run.deps.logger.warn(warning);
|
|
133
148
|
}
|
|
134
149
|
const output = apiOutputOf(target.name, target.settings);
|
|
135
|
-
const outputFile =
|
|
136
|
-
|
|
137
|
-
|
|
150
|
+
const outputFile = failingAsApi(target.name, () => {
|
|
151
|
+
const file = outputFileOf(run, { source: target.name, output }, target.configRoot);
|
|
152
|
+
ensureOutputIsNotSchema(run, file, files.schemas);
|
|
153
|
+
ensureOutputIsOwn(run, file, otherOutputs(files, target.name));
|
|
154
|
+
return file;
|
|
155
|
+
});
|
|
138
156
|
const source = resolveLocationUrl(target.root, target.configRoot);
|
|
139
|
-
const
|
|
140
|
-
|
|
157
|
+
const options = apiOptions(run, apiRun, target);
|
|
158
|
+
try {
|
|
159
|
+
const types = await run.deps.generate(source, options, target.name);
|
|
160
|
+
return { name: target.name, outputFile, types };
|
|
161
|
+
} catch (error) {
|
|
162
|
+
throw new ApiFailure(target.name, error);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* The result of a step of one API, whose failure is reported with the API's name. Errors of an
|
|
168
|
+
* API's settings name the API in their own message and are not wrapped.
|
|
169
|
+
*/
|
|
170
|
+
function failingAsApi<T>(apiName: string, step: () => T): T {
|
|
171
|
+
try {
|
|
172
|
+
return step();
|
|
173
|
+
} catch (error) {
|
|
174
|
+
throw new ApiFailure(apiName, error);
|
|
175
|
+
}
|
|
141
176
|
}
|
|
142
177
|
|
|
143
178
|
/**
|
|
@@ -192,8 +227,9 @@ async function settledInTurn<T, R>(
|
|
|
192
227
|
export async function generateRedoclyApis(run: CliRun, redocly: RedoclyConfig): Promise<unknown[]> {
|
|
193
228
|
const apis = redoclyApisOf(redocly);
|
|
194
229
|
const { configRoot, files } = configFilesOf(run, redocly, apis);
|
|
230
|
+
const apiRun = { redocly, files, refLimits: refLimitOptions(run.args, run.deps.cwd) };
|
|
195
231
|
const results = await settledInTurn(apis, (api) =>
|
|
196
|
-
generateApi(run,
|
|
232
|
+
generateApi(run, apiRun, apiTarget(api, configRoot)),
|
|
197
233
|
);
|
|
198
234
|
const generated = results.flatMap((result) =>
|
|
199
235
|
result.status === "fulfilled" ? [result.value] : [],
|
package/src/cli/ref-limits.ts
CHANGED
|
@@ -1,16 +1,35 @@
|
|
|
1
1
|
import type { GeneratorOptions } from "../types.js";
|
|
2
2
|
import type { CliArguments } from "./cli-arguments.js";
|
|
3
|
+
import { cliError } from "./cli-errors.js";
|
|
3
4
|
import { resolveLocationUrl } from "./cli-output.js";
|
|
4
5
|
|
|
5
6
|
/** The `$ref` limits of the CLI flags as generator options (threat model R1, R2, ADR-017). */
|
|
6
7
|
|
|
7
8
|
export type RefLimitOptions = Pick<GeneratorOptions, "localRefRoot" | "remoteRefHosts">;
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
const FILE_PROTOCOL = "file:";
|
|
11
|
+
|
|
12
|
+
/** A local `$ref` root as a URL; undefined for a URL of another protocol, which names no folder. */
|
|
13
|
+
export function localRootUrl(location: string, base: URL): URL | undefined {
|
|
14
|
+
const url = resolveLocationUrl(location, base);
|
|
15
|
+
return url.protocol === FILE_PROTOCOL ? url : undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* `--local-ref-root` resolves against the working directory, like every other CLI path. A URL of
|
|
20
|
+
* another protocol (`https://…`) fails with `CLI_FLAG_INVALID`.
|
|
21
|
+
*/
|
|
10
22
|
export function refLimitOptions(args: CliArguments, cwd: URL): RefLimitOptions {
|
|
11
23
|
const { localRefRoot, remoteRefHosts } = args.refLimits;
|
|
24
|
+
const localRoot = localRefRoot === undefined ? undefined : localRootUrl(localRefRoot, cwd);
|
|
25
|
+
if (localRefRoot !== undefined && localRoot === undefined) {
|
|
26
|
+
throw cliError(
|
|
27
|
+
"CLI_FLAG_INVALID",
|
|
28
|
+
`--local-ref-root ${localRefRoot}: a directory path or a file: URL.`,
|
|
29
|
+
);
|
|
30
|
+
}
|
|
12
31
|
return {
|
|
13
|
-
...(
|
|
32
|
+
...(localRoot === undefined ? {} : { localRefRoot: localRoot }),
|
|
14
33
|
...(remoteRefHosts === undefined ? {} : { remoteRefHosts }),
|
|
15
34
|
};
|
|
16
35
|
}
|
package/src/cli/run-cli.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Logger } from "../application/ports/logger.js";
|
|
2
2
|
import type { RedoclyConfig } from "../application/ports/redocly-config-source.js";
|
|
3
|
+
import { hasUrlScheme } from "../domain/location-text.js";
|
|
3
4
|
import { WARNING_CODES, warningText } from "../domain/warnings.js";
|
|
4
5
|
import type { SchemaSource } from "../types.js";
|
|
5
6
|
import { ineffectiveFlagNotices, parseCliArguments } from "./cli-arguments.js";
|
|
@@ -52,13 +53,29 @@ function schemaSource(run: CliRun): SchemaSource {
|
|
|
52
53
|
return run.deps.stdin();
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
/** The character that made the original CLI read a schema argument as a glob pattern. */
|
|
57
|
+
const GLOB_WILDCARD = "*";
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Whether the schema argument is a glob pattern, which the CLI no longer expands: a path with a
|
|
61
|
+
* `*` that names no file. A URL is no pattern (`?fields=*` is its query), nor a file whose name
|
|
62
|
+
* has a `*`, which the CLI reads as any other file.
|
|
63
|
+
*/
|
|
64
|
+
function isGlobPattern(run: CliRun, input: string): boolean {
|
|
65
|
+
return (
|
|
66
|
+
input.includes(GLOB_WILDCARD) &&
|
|
67
|
+
!hasUrlScheme(input) &&
|
|
68
|
+
!run.deps.files.isFile(resolveLocationUrl(input, run.deps.cwd))
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
55
72
|
/**
|
|
56
73
|
* One schema from a path, a URL or stdin; without `--output`, the types go to stdout. Warnings and
|
|
57
74
|
* errors go to stderr either way, so they never mix with the types (upstream dropped warnings).
|
|
58
75
|
*/
|
|
59
76
|
async function generateSingleSchema(run: CliRun, redocly: RedoclyConfig): Promise<void> {
|
|
60
77
|
const { input, output } = run.args;
|
|
61
|
-
if (input
|
|
78
|
+
if (input !== undefined && isGlobPattern(run, input)) {
|
|
62
79
|
throw cliError(
|
|
63
80
|
"CLI_GLOB_UNSUPPORTED",
|
|
64
81
|
"Globbing has been deprecated in favor of redocly.yaml’s `apis` keys. " +
|
|
@@ -72,6 +89,9 @@ async function generateSingleSchema(run: CliRun, redocly: RedoclyConfig): Promis
|
|
|
72
89
|
"--check needs the generated file to compare with: add --output <file>.",
|
|
73
90
|
);
|
|
74
91
|
}
|
|
92
|
+
for (const notice of ineffectiveFlagNotices(run.args.generatorFlags)) {
|
|
93
|
+
run.deps.console.notice(notice);
|
|
94
|
+
}
|
|
75
95
|
const source = schemaSource(run);
|
|
76
96
|
const outputFile = output ? singleOutputFile(run, output, source, redocly) : undefined;
|
|
77
97
|
const options = {
|
|
@@ -112,23 +132,35 @@ async function generate(run: CliRun): Promise<unknown[]> {
|
|
|
112
132
|
await generateSingleSchema(run, redocly);
|
|
113
133
|
return [];
|
|
114
134
|
}
|
|
115
|
-
|
|
116
|
-
|
|
135
|
+
warnAboutIgnoredArguments(run);
|
|
136
|
+
return generateRedoclyApis(run, redocly);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** With the APIs of a Redocly config, the input and the output of the command line are unused. */
|
|
140
|
+
function warnAboutIgnoredArguments(run: CliRun): void {
|
|
141
|
+
const { args, deps } = run;
|
|
142
|
+
if (args.input) {
|
|
143
|
+
deps.logger.warn(
|
|
117
144
|
warningText(
|
|
118
145
|
"APIs are specified both in Redocly Config and CLI argument. Only using Redocly config.",
|
|
119
146
|
WARNING_CODES.CLI_INPUT_IGNORED,
|
|
120
147
|
),
|
|
121
148
|
);
|
|
122
149
|
}
|
|
123
|
-
|
|
150
|
+
if (args.output) {
|
|
151
|
+
deps.logger.warn(
|
|
152
|
+
warningText(
|
|
153
|
+
`APIs are specified in Redocly Config, so --output ${args.output} is ignored: ` +
|
|
154
|
+
"each API is written to its x-openapi-ts.output.",
|
|
155
|
+
WARNING_CODES.CLI_OUTPUT_IGNORED,
|
|
156
|
+
),
|
|
157
|
+
);
|
|
158
|
+
}
|
|
124
159
|
}
|
|
125
160
|
|
|
126
161
|
/** Run the command; the failures it returns did not stop the other outputs. */
|
|
127
162
|
async function runCommand(argv: readonly string[], deps: CliDependencies): Promise<unknown[]> {
|
|
128
163
|
const startedAt = deps.now();
|
|
129
|
-
for (const notice of ineffectiveFlagNotices(argv)) {
|
|
130
|
-
deps.console.notice(notice);
|
|
131
|
-
}
|
|
132
164
|
const args = parseCliArguments(argv);
|
|
133
165
|
for (const flag of args.unknownFlags) {
|
|
134
166
|
deps.console.notice(`Unknown flag ${flag} is ignored (see --help)`);
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { kebabCase } from "scule";
|
|
2
|
+
import { cliError } from "./cli-errors.js";
|
|
3
|
+
import {
|
|
4
|
+
BOOLEAN_FLAG_NAMES,
|
|
5
|
+
KNOWN_LONG_FLAG_NAMES,
|
|
6
|
+
KNOWN_SHORT_FLAGS,
|
|
7
|
+
LONG_PREFIX,
|
|
8
|
+
NEGATION_PREFIX,
|
|
9
|
+
SHORT_PREFIX,
|
|
10
|
+
VALUE_FLAG_NAMES,
|
|
11
|
+
} from "./cli-flag-names.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Checks of the flags as the user wrote them, before yargs-parser reads them: yargs-parser accepts
|
|
15
|
+
* any spelling and value, so what it cannot tell apart is checked here.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** Flags of older versions that were removed or renamed, with the message for each. */
|
|
19
|
+
const REMOVED_FLAGS: readonly (readonly [string, string])[] = [
|
|
20
|
+
["-ap", `The -ap alias has been deprecated. Use "--additional-properties" instead.`],
|
|
21
|
+
["--immutable-types", `The --immutable-types flag has been renamed to "--immutable".`],
|
|
22
|
+
[
|
|
23
|
+
"--support-array-length",
|
|
24
|
+
`The --support-array-length flag has been renamed to "--array-length".`,
|
|
25
|
+
],
|
|
26
|
+
["-it", `The -it alias has been deprecated. Use "--immutable" instead.`],
|
|
27
|
+
["--redoc", `The --redoc config flag has been renamed to "--redocly" (or -c as shorthand).`],
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
const OPTIONS_END = "--";
|
|
31
|
+
const VALUE_SEPARATOR = "=";
|
|
32
|
+
const BOOLEAN_VALUES: ReadonlySet<string> = new Set(["true", "false"]);
|
|
33
|
+
const LETTER = /^[a-z]$/i;
|
|
34
|
+
|
|
35
|
+
/** A flag as written before `--`: its name (`--redoc`, `-o`) and the text after `=`, if any. */
|
|
36
|
+
export interface WrittenFlag {
|
|
37
|
+
readonly name: string;
|
|
38
|
+
readonly value: string | undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function writtenFlags(argv: readonly string[]): WrittenFlag[] {
|
|
42
|
+
const end = argv.indexOf(OPTIONS_END);
|
|
43
|
+
return (end === -1 ? argv : argv.slice(0, end))
|
|
44
|
+
.filter((arg) => arg.startsWith(SHORT_PREFIX) && arg !== SHORT_PREFIX)
|
|
45
|
+
.map((arg) => {
|
|
46
|
+
const at = arg.indexOf(VALUE_SEPARATOR);
|
|
47
|
+
return at === -1
|
|
48
|
+
? { name: arg, value: undefined }
|
|
49
|
+
: { name: arg.slice(0, at), value: arg.slice(at + 1) };
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* A long flag as yargs-parser reads it: in kebab-case and without `--no-`, so `--immutableTypes`
|
|
55
|
+
* and `--no-immutable-types` are `--immutable-types`. A short flag stays as written.
|
|
56
|
+
*/
|
|
57
|
+
function canonicalFlagName(name: string): string {
|
|
58
|
+
if (!name.startsWith(LONG_PREFIX)) {
|
|
59
|
+
return name;
|
|
60
|
+
}
|
|
61
|
+
const bare = name.startsWith(NEGATION_PREFIX)
|
|
62
|
+
? name.slice(NEGATION_PREFIX.length)
|
|
63
|
+
: name.slice(LONG_PREFIX.length);
|
|
64
|
+
return `${LONG_PREFIX}${kebabCase(bare)}`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** An old flag fails by its name in any spelling, also with a value (`--redoc=redocly.yaml`). */
|
|
68
|
+
export function rejectRemovedFlags(flags: readonly WrittenFlag[]): void {
|
|
69
|
+
const names = new Set(flags.map(({ name }) => canonicalFlagName(name)));
|
|
70
|
+
for (const [flag, message] of REMOVED_FLAGS) {
|
|
71
|
+
if (names.has(flag)) {
|
|
72
|
+
throw cliError("CLI_FLAG_REMOVED", message);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* A boolean flag takes `=true` or `=false`, and its `--no-` form takes no value. yargs-parser read
|
|
79
|
+
* any other value as false (`--enum=1`, `--alphabetize=yes`), which turned the option off.
|
|
80
|
+
*/
|
|
81
|
+
export function rejectInvalidBooleans(flags: readonly WrittenFlag[]): void {
|
|
82
|
+
for (const { name, value } of flags) {
|
|
83
|
+
const negated = name.startsWith(NEGATION_PREFIX)
|
|
84
|
+
? `${LONG_PREFIX}${name.slice(NEGATION_PREFIX.length)}`
|
|
85
|
+
: undefined;
|
|
86
|
+
const isNegatedWithValue = negated !== undefined && BOOLEAN_FLAG_NAMES.has(negated);
|
|
87
|
+
const isInvalid = BOOLEAN_FLAG_NAMES.has(name) && !BOOLEAN_VALUES.has(value ?? "true");
|
|
88
|
+
if (value !== undefined && (isNegatedWithValue || isInvalid)) {
|
|
89
|
+
throw cliError(
|
|
90
|
+
"CLI_FLAG_INVALID",
|
|
91
|
+
`${name}=${value}: a boolean flag takes no value, or =true or =false.`,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* A flag that takes a value has no `--no-` form: yargs-parser gave it the value false, which the
|
|
99
|
+
* CLI read as the text "false" (`--no-output` wrote a file named `false`).
|
|
100
|
+
*/
|
|
101
|
+
export function rejectNegatedValueFlags(flags: readonly WrittenFlag[]): void {
|
|
102
|
+
for (const { name } of flags) {
|
|
103
|
+
if (name.startsWith(NEGATION_PREFIX) && VALUE_FLAG_NAMES.has(canonicalFlagName(name))) {
|
|
104
|
+
throw cliError(
|
|
105
|
+
"CLI_FLAG_INVALID",
|
|
106
|
+
`${name}: a flag that takes a value has no --no- form. Leave the flag out instead.`,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** The bare names of the unknown flags in a written long flag or a group of short flags. */
|
|
113
|
+
function unknownNamesOf({ name }: WrittenFlag): string[] {
|
|
114
|
+
if (name.startsWith(LONG_PREFIX)) {
|
|
115
|
+
return KNOWN_LONG_FLAG_NAMES.has(canonicalFlagName(name))
|
|
116
|
+
? []
|
|
117
|
+
: [name.slice(LONG_PREFIX.length)];
|
|
118
|
+
}
|
|
119
|
+
return [...name.slice(SHORT_PREFIX.length)].filter(
|
|
120
|
+
(letter) => LETTER.test(letter) && !KNOWN_SHORT_FLAGS.has(letter),
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* The unknown flags, to declare as boolean: yargs-parser gives an undeclared flag the next
|
|
126
|
+
* argument as its value, so `--alphabetise api.yaml` took the schema path and read stdin. An
|
|
127
|
+
* unknown flag is ignored, so it takes a value only as `--flag=value`.
|
|
128
|
+
*/
|
|
129
|
+
export function unknownFlagNames(flags: readonly WrittenFlag[]): string[] {
|
|
130
|
+
return [...new Set(flags.flatMap(unknownNamesOf))];
|
|
131
|
+
}
|
|
@@ -3,31 +3,55 @@ import { redactUrlSecrets } from "./url-secrets.js";
|
|
|
3
3
|
/**
|
|
4
4
|
* The `cause` of a typed error is shown wherever the error is: `console.error(error)` and
|
|
5
5
|
* `util.inspect` print the whole chain, and error trackers send it. A lower-level error names the
|
|
6
|
-
* URL it failed on (fetch refuses `https://user:token@host/…` and quotes it),
|
|
7
|
-
*
|
|
6
|
+
* URL it failed on (fetch refuses `https://user:token@host/…` and quotes it), and may keep it in
|
|
7
|
+
* nested objects too (Redocly's parse error holds `originalError.mark.name` and
|
|
8
|
+
* `source.absoluteRef`), so the chain must hide the same secrets as the message (url-secrets.ts)
|
|
9
|
+
* at every depth.
|
|
8
10
|
*/
|
|
9
11
|
|
|
10
|
-
/**
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* How deep the walk copies a cause. The data of a cause is shallow (Redocly's deepest URL is three
|
|
14
|
+
* levels below the error); a value below this depth is dropped, so no secret is kept unread.
|
|
15
|
+
*/
|
|
16
|
+
const MAX_CAUSE_DEPTH = 8;
|
|
17
|
+
|
|
18
|
+
interface Walk {
|
|
19
|
+
/** The objects on the way from the cause to the value, so a cycle is cut where it closes. */
|
|
20
|
+
readonly path: ReadonlySet<object>;
|
|
21
|
+
readonly depth: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function deeper(walk: Walk, value: object): Walk {
|
|
25
|
+
return { path: new Set([...walk.path, value]), depth: walk.depth + 1 };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** An array with each item hidden, or the array itself when no item holds a secret. */
|
|
29
|
+
function redactedArray(array: readonly unknown[], walk: Walk): readonly unknown[] {
|
|
30
|
+
const inner = deeper(walk, array);
|
|
31
|
+
const items = array.map((item) => redactedValue(item, inner));
|
|
32
|
+
return items.every((item, index) => item === array[index]) ? array : items;
|
|
13
33
|
}
|
|
14
34
|
|
|
15
35
|
/**
|
|
16
|
-
* A copy of `
|
|
17
|
-
* nested `cause`) with URL secrets hidden, or `
|
|
18
|
-
* property is read through its getter (V8 keeps `stack` behind one) and
|
|
36
|
+
* A copy of `value` with the same prototype, its own properties (`message`, `stack`, `code`,
|
|
37
|
+
* `input`, a nested `cause` or object) with URL secrets hidden, or `value` itself when none of
|
|
38
|
+
* them holds one. Each property is read through its getter (V8 keeps `stack` behind one) and
|
|
39
|
+
* copied as a value.
|
|
19
40
|
*/
|
|
20
|
-
function
|
|
21
|
-
const inner =
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
const copy =
|
|
41
|
+
function redactedObject(value: object, walk: Walk): object {
|
|
42
|
+
const inner = deeper(walk, value);
|
|
43
|
+
// An error is copied as a real error, so `util.inspect` and `util.types.isNativeError` treat
|
|
44
|
+
// the copy as one.
|
|
45
|
+
const copy: object =
|
|
46
|
+
value instanceof Error
|
|
47
|
+
? Object.setPrototypeOf(new Error(), Object.getPrototypeOf(value))
|
|
48
|
+
: Object.create(Object.getPrototypeOf(value) as object | null);
|
|
25
49
|
let isChanged = false;
|
|
26
|
-
for (const key of Reflect.ownKeys(
|
|
27
|
-
const
|
|
28
|
-
const shown =
|
|
29
|
-
isChanged ||= shown !==
|
|
30
|
-
const enumerable = Object.getOwnPropertyDescriptor(
|
|
50
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
51
|
+
const property: unknown = Reflect.get(value, key);
|
|
52
|
+
const shown = redactedValue(property, inner);
|
|
53
|
+
isChanged ||= shown !== property;
|
|
54
|
+
const enumerable = Object.getOwnPropertyDescriptor(value, key)?.enumerable === true;
|
|
31
55
|
Object.defineProperty(copy, key, {
|
|
32
56
|
value: shown,
|
|
33
57
|
enumerable,
|
|
@@ -35,18 +59,28 @@ function redactedError(error: Error, seen: ReadonlySet<Error>): Error {
|
|
|
35
59
|
configurable: true,
|
|
36
60
|
});
|
|
37
61
|
}
|
|
38
|
-
return isChanged ? copy :
|
|
62
|
+
return isChanged ? copy : value;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Binary data and functions hold no text to hide, so they are kept as they are. */
|
|
66
|
+
function isOpaque(value: object): boolean {
|
|
67
|
+
return typeof value === "function" || ArrayBuffer.isView(value) || value instanceof ArrayBuffer;
|
|
39
68
|
}
|
|
40
69
|
|
|
41
|
-
function
|
|
42
|
-
if (
|
|
43
|
-
return
|
|
70
|
+
function redactedValue(value: unknown, walk: Walk): unknown {
|
|
71
|
+
if (typeof value === "string") {
|
|
72
|
+
return redactUrlSecrets(value);
|
|
73
|
+
}
|
|
74
|
+
if (typeof value !== "object" || value === null || isOpaque(value)) {
|
|
75
|
+
return value;
|
|
76
|
+
}
|
|
77
|
+
if (walk.path.has(value) || walk.depth >= MAX_CAUSE_DEPTH) {
|
|
78
|
+
return undefined;
|
|
44
79
|
}
|
|
45
|
-
|
|
46
|
-
return seen.has(cause) ? undefined : redactedError(cause, seen);
|
|
80
|
+
return Array.isArray(value) ? redactedArray(value, walk) : redactedObject(value, walk);
|
|
47
81
|
}
|
|
48
82
|
|
|
49
83
|
/** The cause of a typed error with the URL secrets of its whole chain hidden. */
|
|
50
84
|
export function redactCauseSecrets(cause: unknown): unknown {
|
|
51
|
-
return
|
|
85
|
+
return redactedValue(cause, { path: new Set(), depth: 0 });
|
|
52
86
|
}
|
package/src/domain/errors.ts
CHANGED
|
@@ -28,14 +28,17 @@ export const ERROR_CODES = {
|
|
|
28
28
|
ENUM_NAME_EMPTY: "ENUM_NAME_EMPTY",
|
|
29
29
|
CALLBACK_RESULT_UNREADABLE: "CALLBACK_RESULT_UNREADABLE",
|
|
30
30
|
OPTION_FIX_UNKNOWN: "OPTION_FIX_UNKNOWN",
|
|
31
|
+
OPTION_INVALID: "OPTION_INVALID",
|
|
31
32
|
TYPESCRIPT_NOT_FOUND: "TYPESCRIPT_NOT_FOUND",
|
|
32
33
|
CLI_FLAG_REMOVED: "CLI_FLAG_REMOVED",
|
|
34
|
+
CLI_FLAG_INVALID: "CLI_FLAG_INVALID",
|
|
33
35
|
CLI_GLOB_UNSUPPORTED: "CLI_GLOB_UNSUPPORTED",
|
|
34
36
|
CLI_CONFIG_NOT_FOUND: "CLI_CONFIG_NOT_FOUND",
|
|
35
37
|
CLI_CONFIG_INVALID: "CLI_CONFIG_INVALID",
|
|
36
38
|
CLI_CONFIG_OUTPUT_MISSING: "CLI_CONFIG_OUTPUT_MISSING",
|
|
37
39
|
CLI_CHECK_OUTPUT_MISSING: "CLI_CHECK_OUTPUT_MISSING",
|
|
38
40
|
CLI_INPUT_MISSING: "CLI_INPUT_MISSING",
|
|
41
|
+
CLI_INPUT_EXTRA: "CLI_INPUT_EXTRA",
|
|
39
42
|
CLI_OUTPUT_IS_INPUT: "CLI_OUTPUT_IS_INPUT",
|
|
40
43
|
CLI_OUTPUT_DUPLICATE: "CLI_OUTPUT_DUPLICATE",
|
|
41
44
|
CLI_OUTPUT_INVALID: "CLI_OUTPUT_INVALID",
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** How a location the user writes, as a CLI argument or an option string, is read. */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A scheme of two or more characters (`https:`, `file:`). One letter is a Windows drive (`C:`), so
|
|
5
|
+
* `C:\\specs\\api.yaml` stays a path.
|
|
6
|
+
*/
|
|
7
|
+
const URL_SCHEME = /^[a-z][a-z\d+.-]+:/i;
|
|
8
|
+
|
|
9
|
+
/** The schemes the generator reads, which mark a URL also without `//` (`file:api.yaml`). */
|
|
10
|
+
const READ_SCHEMES: ReadonlySet<string> = new Set(["file:", "http:", "https:"]);
|
|
11
|
+
|
|
12
|
+
const AUTHORITY_START = "//";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Whether the location is written as a URL, not as a file path: a scheme the generator reads, or
|
|
16
|
+
* any scheme followed by `//` (`s3://bucket/api.yaml`). Another text before a colon is part of a
|
|
17
|
+
* file name, as it is on POSIX file systems (`out:v2.ts`, `spec:v2.yaml`).
|
|
18
|
+
*/
|
|
19
|
+
export function hasUrlScheme(location: string): boolean {
|
|
20
|
+
const scheme = URL_SCHEME.exec(location)?.[0];
|
|
21
|
+
if (scheme === undefined) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return (
|
|
25
|
+
READ_SCHEMES.has(scheme.toLowerCase()) || location.startsWith(AUTHORITY_START, scheme.length)
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { ADDITIONAL_OPERATIONS_KEY, HTTP_METHODS, QUERY_METHOD } from "./path-item-object.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The places of an OpenAPI document that a JSON Pointer passes through, read from the document's
|
|
5
|
+
* structure rather than from the words of the pointer. `named*` places and `callback` are maps
|
|
6
|
+
* whose next segment is a name (a path, a component name, a callback expression). `outside` (a
|
|
7
|
+
* root key that is no document key), `input` (a parameter or a request body) and `other` end the
|
|
8
|
+
* walk.
|
|
9
|
+
*/
|
|
10
|
+
export type DocumentPlace =
|
|
11
|
+
| "root"
|
|
12
|
+
| "outside"
|
|
13
|
+
| "components"
|
|
14
|
+
| "namedPathItems"
|
|
15
|
+
| "namedCallbacks"
|
|
16
|
+
| "callback"
|
|
17
|
+
| "pathItem"
|
|
18
|
+
| "namedOperations"
|
|
19
|
+
| "operation"
|
|
20
|
+
| "input"
|
|
21
|
+
| "other";
|
|
22
|
+
|
|
23
|
+
const OPERATION_KEYS: ReadonlySet<string> = new Set([...HTTP_METHODS, QUERY_METHOD]);
|
|
24
|
+
|
|
25
|
+
/** The place each fixed field leads to; any other field leads to `other`. */
|
|
26
|
+
const FIELDS: Readonly<Partial<Record<DocumentPlace, Readonly<Record<string, DocumentPlace>>>>> = {
|
|
27
|
+
root: {
|
|
28
|
+
paths: "namedPathItems",
|
|
29
|
+
webhooks: "namedPathItems",
|
|
30
|
+
components: "components",
|
|
31
|
+
$defs: "other",
|
|
32
|
+
},
|
|
33
|
+
components: {
|
|
34
|
+
parameters: "input",
|
|
35
|
+
requestBodies: "input",
|
|
36
|
+
pathItems: "namedPathItems",
|
|
37
|
+
callbacks: "namedCallbacks",
|
|
38
|
+
},
|
|
39
|
+
pathItem: { parameters: "input", [ADDITIONAL_OPERATIONS_KEY]: "namedOperations" },
|
|
40
|
+
operation: { parameters: "input", requestBody: "input", callbacks: "namedCallbacks" },
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** Maps whose every key leads to the same place. */
|
|
44
|
+
const NAMED: Readonly<Partial<Record<DocumentPlace, DocumentPlace>>> = {
|
|
45
|
+
namedPathItems: "pathItem",
|
|
46
|
+
namedCallbacks: "callback",
|
|
47
|
+
callback: "pathItem",
|
|
48
|
+
namedOperations: "operation",
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
function nextPlace(place: DocumentPlace, segment: string): DocumentPlace {
|
|
52
|
+
const named = NAMED[place];
|
|
53
|
+
if (named !== undefined) {
|
|
54
|
+
return named;
|
|
55
|
+
}
|
|
56
|
+
if (place === "pathItem" && OPERATION_KEYS.has(segment)) {
|
|
57
|
+
return "operation";
|
|
58
|
+
}
|
|
59
|
+
const fields = FIELDS[place] ?? {};
|
|
60
|
+
if (Object.hasOwn(fields, segment)) {
|
|
61
|
+
return fields[segment] as DocumentPlace;
|
|
62
|
+
}
|
|
63
|
+
return place === "root" ? "outside" : "other";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const TERMINAL_PLACES: ReadonlySet<DocumentPlace> = new Set(["outside", "input", "other"]);
|
|
67
|
+
|
|
68
|
+
/** The place the segments of a pointer (after `#`) lead to; the walk stops at a terminal place. */
|
|
69
|
+
export function placeOf(segments: Iterable<string>): DocumentPlace {
|
|
70
|
+
let place: DocumentPlace = "root";
|
|
71
|
+
for (const segment of segments) {
|
|
72
|
+
place = nextPlace(place, segment);
|
|
73
|
+
if (TERMINAL_PLACES.has(place)) {
|
|
74
|
+
return place;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return place;
|
|
78
|
+
}
|
|
@@ -21,6 +21,11 @@ export const FIX = {
|
|
|
21
21
|
ARRAY_LENGTH_TUPLES: "array-length-tuples",
|
|
22
22
|
/** `--dedupe-enums` names a shared enum by all of its schemas, not by the first one. */
|
|
23
23
|
DEDUPE_ENUM_NAMES: "dedupe-enum-names",
|
|
24
|
+
/**
|
|
25
|
+
* `--default-non-nullable` finds parameters and request bodies by the document's structure, not
|
|
26
|
+
* by the words `parameters` and `requestBody` anywhere in a schema's location.
|
|
27
|
+
*/
|
|
28
|
+
DEFAULT_INPUT_LOCATIONS: "default-input-locations",
|
|
24
29
|
/** `required` next to an `allOf` `$ref` to a discriminator member still gives `WithRequired`. */
|
|
25
30
|
DISCRIMINATOR_MEMBER_REQUIRED: "discriminator-member-required",
|
|
26
31
|
/**
|
|
@@ -33,8 +38,8 @@ export const FIX = {
|
|
|
33
38
|
EXPLODED_QUERY_OBJECTS: "exploded-query-objects",
|
|
34
39
|
/** `--enum` declares an enum that lists `null` without it, and the type adds `| null`. */
|
|
35
40
|
NULLABLE_ENUMS: "nullable-enums",
|
|
36
|
-
/** A parameter with `content
|
|
37
|
-
|
|
41
|
+
/** A parameter or header with `content`, not `schema`, is typed by its media type's schema. */
|
|
42
|
+
PARAMETER_HEADER_CONTENT: "parameter-header-content",
|
|
38
43
|
/** `--path-params-as-types` gives each `{name}` its placeholder, `{number}` included. */
|
|
39
44
|
PATH_PARAM_TYPE_NAMES: "path-param-type-names",
|
|
40
45
|
/** A `prefixItems` tuple is open unless `items` or `unevaluatedItems` closes it (2020-12). */
|
|
@@ -111,6 +116,7 @@ export interface OutputFixRequirement {
|
|
|
111
116
|
readonly option:
|
|
112
117
|
| "arrayLength"
|
|
113
118
|
| "dedupeEnums"
|
|
119
|
+
| "defaultNonNullable"
|
|
114
120
|
| "enum"
|
|
115
121
|
| "pathParamsAsTypes"
|
|
116
122
|
| "rootTypes"
|
|
@@ -129,6 +135,7 @@ const NO_SCHEMA_PREFIX = {
|
|
|
129
135
|
const REQUIREMENTS: Readonly<Partial<Record<OutputFixName, readonly OutputFixRequirement[]>>> = {
|
|
130
136
|
[FIX.ARRAY_LENGTH_TUPLES]: [{ option: "arrayLength", flag: "--array-length" }],
|
|
131
137
|
[FIX.DEDUPE_ENUM_NAMES]: [ENUM, { option: "dedupeEnums", flag: "--dedupe-enums" }],
|
|
138
|
+
[FIX.DEFAULT_INPUT_LOCATIONS]: [{ option: "defaultNonNullable", flag: "--default-non-nullable" }],
|
|
132
139
|
[FIX.NULLABLE_ENUMS]: [ENUM],
|
|
133
140
|
[FIX.PATH_PARAM_TYPE_NAMES]: [{ option: "pathParamsAsTypes", flag: "--path-params-as-types" }],
|
|
134
141
|
[FIX.ROOT_TYPE_NUMBERING]: [ROOT_TYPES, NO_SCHEMA_PREFIX],
|