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
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { Schema } from "../../../domain/openapi/schema-object.js";
|
|
2
|
+
import { propertyAccessFlags } from "../schema/access-flags.js";
|
|
3
|
+
import { isInputLocation } from "../schema/input-location.js";
|
|
4
|
+
import type { RefResolver, SchemaOptions } from "../schema/schema-context.js";
|
|
5
|
+
import {
|
|
6
|
+
followLocated,
|
|
7
|
+
followRefs,
|
|
8
|
+
isJsonObject,
|
|
9
|
+
type JsonObject,
|
|
10
|
+
type LocatedNode,
|
|
11
|
+
} from "./located-node.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* What the generated type of an object schema makes of one of its properties: optional, left
|
|
15
|
+
* out, wrapped in a read or write marker, or a value that may be `undefined` or `null`.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** `nullable: true` or a `type` list with `null`: the generated type includes `null`. */
|
|
19
|
+
export function isNullableSchema(node: unknown): boolean {
|
|
20
|
+
if (!isJsonObject(node)) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
return node.nullable === true || (Array.isArray(node.type) && node.type.includes("null"));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Whether the generated type has the property as optional, as `objectType` decides: a `default`
|
|
28
|
+
* makes a property required except in an input location, where the client may leave it out.
|
|
29
|
+
*/
|
|
30
|
+
export function isOptionalProperty(
|
|
31
|
+
owner: LocatedNode & { node: JsonObject },
|
|
32
|
+
key: string,
|
|
33
|
+
options: SchemaOptions,
|
|
34
|
+
): boolean {
|
|
35
|
+
const { node } = owner;
|
|
36
|
+
const required = Array.isArray(node.required) ? node.required : undefined;
|
|
37
|
+
const property = (node.properties as JsonObject)[key];
|
|
38
|
+
const hasDefault = isJsonObject(property) && property.default !== undefined;
|
|
39
|
+
const isDefaultRequired =
|
|
40
|
+
hasDefault && options.defaultNonNullable && !isInputLocation(owner.location, options.fixes);
|
|
41
|
+
const isRequired =
|
|
42
|
+
required?.includes(key) === true ||
|
|
43
|
+
(required === undefined && options.propertiesRequiredByDefault) ||
|
|
44
|
+
isDefaultRequired;
|
|
45
|
+
return !isRequired;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Whether `--exclude-deprecated` leaves the property out: its object, or the one its `$ref`
|
|
50
|
+
* names, is deprecated (`objectType`). The key is then not in the generated type at all.
|
|
51
|
+
*/
|
|
52
|
+
export function isExcludedProperty(
|
|
53
|
+
property: unknown,
|
|
54
|
+
options: SchemaOptions,
|
|
55
|
+
refs: RefResolver,
|
|
56
|
+
): boolean {
|
|
57
|
+
const resolved = followRefs(property, refs);
|
|
58
|
+
return options.excludeDeprecated && isJsonObject(resolved) && Boolean(resolved.deprecated);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Whether the generated type keeps one of the schema's properties. The index signature next to
|
|
63
|
+
* them then holds their types too (`withPropertyTypes`), so it is not its value schema's type.
|
|
64
|
+
*/
|
|
65
|
+
export function hasKeptProperties(node: JsonObject, options: SchemaOptions, refs: RefResolver) {
|
|
66
|
+
const properties = isJsonObject(node.properties) ? node.properties : {};
|
|
67
|
+
return Object.values(properties).some((value) => !isExcludedProperty(value, options, refs));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Whether `--read-write-markers` wraps the type of a property or `$defs` member: one that is only
|
|
72
|
+
* `readOnly` or only `writeOnly` is `$Read<T>` or `$Write<T>` (object-type.ts).
|
|
73
|
+
*/
|
|
74
|
+
export function isMarkedProperty(value: unknown, options: SchemaOptions, refs: RefResolver) {
|
|
75
|
+
if (!options.readWriteMarkers || !isJsonObject(value)) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
const flags = propertyAccessFlags(value as Schema, { options, refs });
|
|
79
|
+
return flags.isReadOnly !== flags.isWriteOnly;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Whether a value is there: `present`, `absent` (may be `undefined` or `null`) or `unknown`. */
|
|
83
|
+
export type Presence = "present" | "absent" | "unknown";
|
|
84
|
+
|
|
85
|
+
/** The presence of a value of `schema` itself: `absent` when its type includes `null`. */
|
|
86
|
+
export function schemaPresence(schema: unknown, refs: RefResolver): Presence {
|
|
87
|
+
return isNullableSchema(followRefs(schema, refs)) ? "absent" : "present";
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** The presence of property `key` of `schema`: optional or nullable is `absent`. */
|
|
91
|
+
export function propertyPresence(
|
|
92
|
+
schema: LocatedNode,
|
|
93
|
+
key: string,
|
|
94
|
+
options: SchemaOptions,
|
|
95
|
+
refs: RefResolver,
|
|
96
|
+
): Presence {
|
|
97
|
+
const owner = followLocated(schema, refs);
|
|
98
|
+
const { node } = owner;
|
|
99
|
+
const properties = isJsonObject(node) && isJsonObject(node.properties) ? node.properties : {};
|
|
100
|
+
if (!isJsonObject(node) || !Object.hasOwn(properties, key)) {
|
|
101
|
+
return "unknown";
|
|
102
|
+
}
|
|
103
|
+
return isOptionalProperty({ ...owner, node }, key, options)
|
|
104
|
+
? "absent"
|
|
105
|
+
: schemaPresence(properties[key], refs);
|
|
106
|
+
}
|
|
@@ -2,32 +2,43 @@ import { irIndexedAccess, irKeyword, irReference } from "../../../domain/ir/cons
|
|
|
2
2
|
import type { IrKeyword, IrType } from "../../../domain/ir/nodes.js";
|
|
3
3
|
import { indexBy, indexKeyword, rootType } from "../ref-type.js";
|
|
4
4
|
import type { RefResolver, SchemaOptions } from "../schema/schema-context.js";
|
|
5
|
+
import { isArrayShape, isObjectShape } from "./generated-shape.js";
|
|
5
6
|
import {
|
|
7
|
+
childLocation,
|
|
8
|
+
followLocated,
|
|
6
9
|
followRefs,
|
|
7
|
-
isArrayShape,
|
|
8
10
|
isJsonObject,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
propertyPresence,
|
|
12
|
-
schemaPresence,
|
|
13
|
-
} from "./generated-shape.js";
|
|
11
|
+
type LocatedNode,
|
|
12
|
+
} from "./located-node.js";
|
|
14
13
|
import {
|
|
14
|
+
type ContentForm,
|
|
15
|
+
headerParameterContentForm,
|
|
16
|
+
isExcludedOperation,
|
|
15
17
|
isOptionalHeader,
|
|
16
18
|
isOptionalRequestBody,
|
|
17
19
|
isParameterList,
|
|
18
20
|
isTypedAsSchema,
|
|
19
|
-
|
|
21
|
+
leadingLocated,
|
|
20
22
|
leadingSegmentsOf,
|
|
21
23
|
type RefPointer,
|
|
22
24
|
startsInSchema,
|
|
23
25
|
} from "./pointer-walk.js";
|
|
26
|
+
import {
|
|
27
|
+
hasKeptProperties,
|
|
28
|
+
isExcludedProperty,
|
|
29
|
+
isMarkedProperty,
|
|
30
|
+
type Presence,
|
|
31
|
+
propertyPresence,
|
|
32
|
+
schemaPresence,
|
|
33
|
+
} from "./property-shape.js";
|
|
24
34
|
|
|
25
35
|
/**
|
|
26
36
|
* The type of a `$ref` pointer as the generated types have it: the `schema` of a media type,
|
|
27
37
|
* header or component parameter is its type, `items` is indexed by `number`,
|
|
28
|
-
* `additionalProperties` by `string
|
|
29
|
-
* `NonNullable` before it is indexed. The walk
|
|
30
|
-
* (`allOf/0`, `definitions/A`, operation
|
|
38
|
+
* `additionalProperties` by `string` where the index signature is its type alone, and a value
|
|
39
|
+
* that may be `undefined` or `null` is wrapped in `NonNullable` before it is indexed. The walk
|
|
40
|
+
* stops at a segment with no type of its own (`allOf/0`, `definitions/A`, operation
|
|
41
|
+
* `parameters/0`): the caller types the target itself.
|
|
31
42
|
*/
|
|
32
43
|
|
|
33
44
|
const DEFS_KEYWORD = "$defs";
|
|
@@ -36,9 +47,18 @@ export interface TypedWalk {
|
|
|
36
47
|
readonly type: IrType;
|
|
37
48
|
/** The document node the type stands for (not followed through a `$ref`). */
|
|
38
49
|
readonly node: unknown;
|
|
50
|
+
/** The node's JSON Pointer, where the generator writes its type (`LocatedNode`). */
|
|
51
|
+
readonly location: string | undefined;
|
|
39
52
|
readonly isSchema: boolean;
|
|
40
53
|
/** The segment is a property or `$defs` name, not a keyword. */
|
|
41
54
|
readonly isName: boolean;
|
|
55
|
+
/** The location of the map of names (`properties` or `$defs`) when `isName`. */
|
|
56
|
+
readonly namesLocation?: string | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* The node is the `content` of a header or parameter typed as its first media type, so the
|
|
59
|
+
* next segment must name that media type and adds no member.
|
|
60
|
+
*/
|
|
61
|
+
readonly isFirstMediaType?: boolean;
|
|
42
62
|
readonly presence: Presence;
|
|
43
63
|
}
|
|
44
64
|
|
|
@@ -58,19 +78,32 @@ function present(walk: TypedWalk): IrType {
|
|
|
58
78
|
}
|
|
59
79
|
|
|
60
80
|
function indexEntries(walk: TypedWalk, key: IrKeyword, keyword: string, refs: RefResolver) {
|
|
61
|
-
const owner =
|
|
62
|
-
const child = isJsonObject(owner) ? owner[keyword] : undefined;
|
|
81
|
+
const owner = followLocated(walk, refs);
|
|
82
|
+
const child = isJsonObject(owner.node) ? owner.node[keyword] : undefined;
|
|
63
83
|
return {
|
|
64
84
|
...walk,
|
|
65
85
|
type: irIndexedAccess(present(walk), irKeyword(key)),
|
|
66
86
|
node: child,
|
|
87
|
+
location: childLocation(owner.location, keyword),
|
|
67
88
|
presence: schemaPresence(child, refs),
|
|
68
89
|
};
|
|
69
90
|
}
|
|
70
91
|
|
|
92
|
+
/**
|
|
93
|
+
* A property `--exclude-deprecated` left out has no member to index, and the `$Read<T>` or
|
|
94
|
+
* `$Write<T>` of a marked property has no member but the marker's: such a pointer is typed in
|
|
95
|
+
* place.
|
|
96
|
+
*/
|
|
71
97
|
function nameStep(walk: TypedWalk, name: string, isLast: boolean, input: TypedWalkInput) {
|
|
72
|
-
const owner =
|
|
73
|
-
const
|
|
98
|
+
const owner = followLocated(walk, input.refs);
|
|
99
|
+
const { node } = owner;
|
|
100
|
+
const properties = isJsonObject(node) && isJsonObject(node.properties) ? node.properties : {};
|
|
101
|
+
const value = properties[name];
|
|
102
|
+
const { options, refs } = input;
|
|
103
|
+
const isMarkedOnTheWay = !isLast && isMarkedProperty(value, options, refs);
|
|
104
|
+
if (isExcludedProperty(value, options, refs) || isMarkedOnTheWay) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
74
107
|
const type =
|
|
75
108
|
walk.presence === "present"
|
|
76
109
|
? indexKeyword(walk.type, name, isLast)
|
|
@@ -78,24 +111,32 @@ function nameStep(walk: TypedWalk, name: string, isLast: boolean, input: TypedWa
|
|
|
78
111
|
return {
|
|
79
112
|
...walk,
|
|
80
113
|
type,
|
|
81
|
-
node:
|
|
114
|
+
node: value,
|
|
115
|
+
location: childLocation(walk.namesLocation, name),
|
|
82
116
|
isName: false,
|
|
83
|
-
presence: propertyPresence(walk
|
|
117
|
+
presence: propertyPresence(walk, name, input.options, input.refs),
|
|
84
118
|
};
|
|
85
119
|
}
|
|
86
120
|
|
|
87
121
|
/** `$defs` is optional (`NonNullable` when more follows); its members are present. */
|
|
88
|
-
function defsStep(walk: TypedWalk, owner:
|
|
89
|
-
const
|
|
122
|
+
function defsStep(walk: TypedWalk, owner: LocatedNode, isLast: boolean): TypedWalk {
|
|
123
|
+
const { node } = owner;
|
|
124
|
+
const defs = isJsonObject(node) && isJsonObject(node[DEFS_KEYWORD]) ? node[DEFS_KEYWORD] : {};
|
|
125
|
+
const namesLocation = childLocation(owner.location, DEFS_KEYWORD);
|
|
90
126
|
return {
|
|
91
127
|
...walk,
|
|
92
128
|
type: indexKeyword(present(walk), DEFS_KEYWORD, isLast),
|
|
129
|
+
// A node of its own, not in the document: its properties are the definitions.
|
|
93
130
|
node: { properties: defs, required: Object.keys(defs) },
|
|
131
|
+
location: namesLocation,
|
|
132
|
+
namesLocation,
|
|
94
133
|
isName: true,
|
|
95
134
|
presence: "present",
|
|
96
135
|
};
|
|
97
136
|
}
|
|
98
137
|
|
|
138
|
+
const COMPOSITION_KEYWORDS = ["allOf", "anyOf", "oneOf"] as const;
|
|
139
|
+
|
|
99
140
|
const SHAPED_KEYWORDS: ReadonlySet<string> = new Set([
|
|
100
141
|
"properties",
|
|
101
142
|
"items",
|
|
@@ -114,18 +155,36 @@ function hasKeywordMember(owner: unknown, segment: string): boolean {
|
|
|
114
155
|
return segment === "items" ? isArrayShape(owner) : isObjectShape(owner);
|
|
115
156
|
}
|
|
116
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Whether `[string]` of the owner's type is its `additionalProperties` type. Not where the index
|
|
160
|
+
* signature also holds pattern or property types (`withPropertyTypes`), nor next to `allOf` /
|
|
161
|
+
* `anyOf` / `oneOf`, whose members may add an index signature or an inherited discriminator.
|
|
162
|
+
*/
|
|
163
|
+
function isIndexedByValue(owner: unknown, input: TypedWalkInput): boolean {
|
|
164
|
+
if (!isJsonObject(owner)) {
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
const patterns = owner.patternProperties;
|
|
168
|
+
const hasPatterns = isJsonObject(patterns) && Object.keys(patterns).length > 0;
|
|
169
|
+
const isComposed = COMPOSITION_KEYWORDS.some((keyword) => keyword in owner);
|
|
170
|
+
return !hasPatterns && !isComposed && !hasKeptProperties(owner, input.options, input.refs);
|
|
171
|
+
}
|
|
172
|
+
|
|
117
173
|
function keywordStep(walk: TypedWalk, segment: string, isLast: boolean, input: TypedWalkInput) {
|
|
118
|
-
const owner =
|
|
119
|
-
if (!hasKeywordMember(owner, segment)) {
|
|
174
|
+
const owner = followLocated(walk, input.refs);
|
|
175
|
+
if (!hasKeywordMember(owner.node, segment)) {
|
|
120
176
|
return null;
|
|
121
177
|
}
|
|
122
178
|
switch (segment) {
|
|
123
179
|
case "properties":
|
|
124
|
-
return { ...walk, isName: true };
|
|
180
|
+
return { ...walk, isName: true, namesLocation: childLocation(owner.location, segment) };
|
|
125
181
|
case "items":
|
|
126
182
|
return indexEntries(walk, "number", "items", input.refs);
|
|
127
183
|
case "additionalProperties":
|
|
128
|
-
|
|
184
|
+
// Otherwise the walk stops, and the target is typed in place.
|
|
185
|
+
return isIndexedByValue(owner.node, input)
|
|
186
|
+
? indexEntries(walk, "string", "additionalProperties", input.refs)
|
|
187
|
+
: null;
|
|
129
188
|
case DEFS_KEYWORD:
|
|
130
189
|
return defsStep(walk, owner, isLast);
|
|
131
190
|
default:
|
|
@@ -143,10 +202,65 @@ function containerStep(walk: TypedWalk, index: number, input: TypedWalkInput): T
|
|
|
143
202
|
...walk,
|
|
144
203
|
type: indexBy(present(walk), segment),
|
|
145
204
|
node: isJsonObject(owner) ? owner[segment] : undefined,
|
|
205
|
+
location: childLocation(followLocated(walk, input.refs).location, segment),
|
|
146
206
|
presence: isOptional ? "absent" : "present",
|
|
147
207
|
};
|
|
148
208
|
}
|
|
149
209
|
|
|
210
|
+
/**
|
|
211
|
+
* The `content` of a header or parameter: no member of its own, since the type holds its media
|
|
212
|
+
* types (or the first one's type). Untyped where the type is `string` or a `schema`'s, and as the
|
|
213
|
+
* last segment of the first media type form, whose type is not the map's.
|
|
214
|
+
*/
|
|
215
|
+
function contentStep(walk: TypedWalk, form: ContentForm, isLast: boolean, refs: RefResolver) {
|
|
216
|
+
const isMapTyped = form === "media-type-members" || (form === "first-media-type" && !isLast);
|
|
217
|
+
if (!isMapTyped) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
const owner = followLocated(walk, refs);
|
|
221
|
+
return {
|
|
222
|
+
...walk,
|
|
223
|
+
node: isJsonObject(owner.node) ? owner.node.content : undefined,
|
|
224
|
+
location: childLocation(owner.location, "content"),
|
|
225
|
+
isFirstMediaType: form === "first-media-type",
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** The first media type of such a `content` is the type itself; another one has no type. */
|
|
230
|
+
function firstMediaTypeStep(walk: TypedWalk, segment: string): TypedWalk | null {
|
|
231
|
+
const content = isJsonObject(walk.node) ? walk.node : {};
|
|
232
|
+
if (Object.keys(content)[0] !== segment) {
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
const location = childLocation(walk.location, segment);
|
|
236
|
+
return { ...walk, node: content[segment], location, isFirstMediaType: false };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function schemaStep(walk: TypedWalk, refs: RefResolver): TypedWalk {
|
|
240
|
+
const owner = followLocated(walk, refs);
|
|
241
|
+
const schema = isJsonObject(owner.node) ? owner.node.schema : undefined;
|
|
242
|
+
const location = childLocation(owner.location, "schema");
|
|
243
|
+
// The container's type is its schema's type: an optional header stays optional.
|
|
244
|
+
const presence = walk.presence === "absent" ? "absent" : schemaPresence(schema, refs);
|
|
245
|
+
return { ...walk, node: schema, location, isSchema: true, presence };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function documentStep(walk: TypedWalk, index: number, input: TypedWalkInput): TypedWalk | null {
|
|
249
|
+
const owner = followRefs(walk.node, input.refs);
|
|
250
|
+
const form = headerParameterContentForm(input.pointer, index, owner, input.options);
|
|
251
|
+
if (form !== null) {
|
|
252
|
+
const isLast = index === input.pointer.segments.length - 1;
|
|
253
|
+
return contentStep(walk, form, isLast, input.refs);
|
|
254
|
+
}
|
|
255
|
+
if (
|
|
256
|
+
isParameterList(input.pointer, index) ||
|
|
257
|
+
isExcludedOperation(input.pointer, index, owner, input)
|
|
258
|
+
) {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
return containerStep(walk, index, input);
|
|
262
|
+
}
|
|
263
|
+
|
|
150
264
|
function step(walk: TypedWalk, index: number, input: TypedWalkInput): TypedWalk | null {
|
|
151
265
|
const { segments } = input.pointer;
|
|
152
266
|
const segment = segments[index] as string;
|
|
@@ -156,20 +270,19 @@ function step(walk: TypedWalk, index: number, input: TypedWalkInput): TypedWalk
|
|
|
156
270
|
? nameStep(walk, segment, isLast, input)
|
|
157
271
|
: keywordStep(walk, segment, isLast, input);
|
|
158
272
|
}
|
|
273
|
+
if (walk.isFirstMediaType) {
|
|
274
|
+
return firstMediaTypeStep(walk, segment);
|
|
275
|
+
}
|
|
159
276
|
if (segment === "schema" && isTypedAsSchema(input.pointer, index)) {
|
|
160
|
-
|
|
161
|
-
const schema = isJsonObject(owner) ? owner.schema : undefined;
|
|
162
|
-
// The container's type is its schema's type: an optional header stays optional.
|
|
163
|
-
const presence = walk.presence === "absent" ? "absent" : schemaPresence(schema, input.refs);
|
|
164
|
-
return { ...walk, node: schema, isSchema: true, presence };
|
|
277
|
+
return schemaStep(walk, input.refs);
|
|
165
278
|
}
|
|
166
|
-
return
|
|
279
|
+
return documentStep(walk, index, input);
|
|
167
280
|
}
|
|
168
281
|
|
|
169
282
|
/** Walk the whole pointer; see the module comment. */
|
|
170
283
|
export function typedWalk(input: TypedWalkInput): TypedWalkResult {
|
|
171
284
|
const { pointer } = input;
|
|
172
|
-
const node =
|
|
285
|
+
const { node, location } = leadingLocated(pointer, input.refs);
|
|
173
286
|
const isSchema = startsInSchema(pointer);
|
|
174
287
|
let walk: TypedWalk = {
|
|
175
288
|
type: indexBy(
|
|
@@ -177,6 +290,7 @@ export function typedWalk(input: TypedWalkInput): TypedWalkResult {
|
|
|
177
290
|
...pointer.segments.slice(0, leadingSegmentsOf(pointer)),
|
|
178
291
|
),
|
|
179
292
|
node,
|
|
293
|
+
location,
|
|
180
294
|
isSchema,
|
|
181
295
|
isName: false,
|
|
182
296
|
presence: isSchema ? schemaPresence(node, input.refs) : "present",
|
|
@@ -30,7 +30,7 @@ function merged(left: AccessFlags, right: AccessFlags): AccessFlags {
|
|
|
30
30
|
*/
|
|
31
31
|
function appliedFlags(
|
|
32
32
|
schema: Schema | undefined,
|
|
33
|
-
context: SchemaContext,
|
|
33
|
+
context: Pick<SchemaContext, "refs">,
|
|
34
34
|
seen: ReadonlySet<Schema>,
|
|
35
35
|
): AccessFlags {
|
|
36
36
|
if (typeof schema !== "object" || schema === null || seen.has(schema)) {
|
|
@@ -52,7 +52,10 @@ function appliedFlags(
|
|
|
52
52
|
* it count, as in openapi-typescript; with it, also those of the schemas its `$ref` and `allOf`
|
|
53
53
|
* apply (upstream #1938).
|
|
54
54
|
*/
|
|
55
|
-
export function propertyAccessFlags(
|
|
55
|
+
export function propertyAccessFlags(
|
|
56
|
+
value: Schema,
|
|
57
|
+
context: Pick<SchemaContext, "options" | "refs">,
|
|
58
|
+
): AccessFlags {
|
|
56
59
|
if (typeof value !== "object") {
|
|
57
60
|
return NO_FLAGS;
|
|
58
61
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { IrType } from "../../../domain/ir/nodes.js";
|
|
2
|
+
import { NO_DECLARED_TYPES } from "../document/declared-types.js";
|
|
3
|
+
import { assignabilityProof } from "../document/type-assignability.js";
|
|
4
|
+
import { unionOf } from "../type-combinators.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The index signature type with the property types it does not admit. TypeScript checks an index
|
|
8
|
+
* signature against every key of a value, declared ones too, so `{ total: number } & { [key:
|
|
9
|
+
* string]: string }` admits no value with `total` (with a required `total`, none at all). The
|
|
10
|
+
* signature takes those property types too, as `unevaluated-properties` does. A property type
|
|
11
|
+
* proven assignable adds nothing, so output that admitted its values stays; one the proof cannot
|
|
12
|
+
* decide (a `$ref`) is added, member by member, so the union stays flat. `$defs` is a keyword, not
|
|
13
|
+
* data, so it is not read.
|
|
14
|
+
*/
|
|
15
|
+
export function withPropertyTypes(indexType: IrType, propertyTypes: readonly IrType[]): IrType {
|
|
16
|
+
const relate = assignabilityProof(NO_DECLARED_TYPES);
|
|
17
|
+
const members = unionMembers(indexType);
|
|
18
|
+
const added: IrType[] = [];
|
|
19
|
+
// Each member of a property type joins the union on its own, unless the union admits it
|
|
20
|
+
// already: `(string | null) | (string | null)` is written `string | null`.
|
|
21
|
+
for (const member of propertyTypes.flatMap(unionMembers)) {
|
|
22
|
+
if (relate(member, unionOf([...members, ...added])) !== "assignable") {
|
|
23
|
+
added.push(member);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// Without an added member the index type stays as printed before, repeats and all.
|
|
27
|
+
return added.length === 0 ? indexType : unionOf([...members, ...added]);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const unionMembers = (type: IrType): readonly IrType[] =>
|
|
31
|
+
type.kind === "union" ? type.types : [type];
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { placeOf } from "../../../domain/openapi/document-places.js";
|
|
2
|
+
import { parseRefPointer } from "../../../domain/openapi/json-pointer.js";
|
|
3
|
+
import { FIX, type OutputFix } from "../../../domain/output-fixes.js";
|
|
4
|
+
|
|
5
|
+
/** The words that mark an input anywhere in a location, as the original reads them. */
|
|
6
|
+
const ORIGINAL_INPUT_WORDS = ["parameters", "requestBody", "requestBodies"] as const;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Whether a schema location describes an input: a parameter or a request body. A client may
|
|
10
|
+
* leave out an input property that has a `default`, so the default makes no such property
|
|
11
|
+
* required. The original tests the location text for a word, so a schema or path that is only
|
|
12
|
+
* named so (`#/components/schemas/Job/properties/parameters`, `/system-parameters`) counts as an
|
|
13
|
+
* input too. The `default-input-locations` fix reads a pointer into the document by the
|
|
14
|
+
* document's structure instead (ADR-021).
|
|
15
|
+
*/
|
|
16
|
+
export function isInputLocation(path: string | undefined, fixes: ReadonlySet<OutputFix>): boolean {
|
|
17
|
+
if (path === undefined) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
return fixes.has(FIX.DEFAULT_INPUT_LOCATIONS) ? isStructuralInput(path) : namesInput(path);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function namesInput(path: string): boolean {
|
|
24
|
+
return ORIGINAL_INPUT_WORDS.some((word) => path.includes(word));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Whether the document's structure makes the pointer an input. A path an exported transformer was
|
|
29
|
+
* given that is no pointer into the document (`/items/{id}`) has no known structure, so the
|
|
30
|
+
* original's words still mark an input there.
|
|
31
|
+
*/
|
|
32
|
+
function isStructuralInput(path: string): boolean {
|
|
33
|
+
const place = placeOf(parseRefPointer(path));
|
|
34
|
+
return place === "outside" ? namesInput(path) : place === "input";
|
|
35
|
+
}
|
|
@@ -15,13 +15,13 @@ import { schemaCommentOptionsOf, withSchemaComment } from "../schema-comment.js"
|
|
|
15
15
|
import { UNKNOWN_TYPE } from "../shared-types.js";
|
|
16
16
|
import { intersectionOf, unionOf } from "../type-combinators.js";
|
|
17
17
|
import { type AccessFlags, propertyAccessFlags } from "./access-flags.js";
|
|
18
|
+
import { withPropertyTypes } from "./index-signature-type.js";
|
|
18
19
|
import { discriminatorMember, inheritedDiscriminator } from "./inherited-discriminator.js";
|
|
20
|
+
import { isInputLocation } from "./input-location.js";
|
|
21
|
+
import { refWithSiblingsAsAllOf } from "./ref-siblings.js";
|
|
19
22
|
import type { SchemaOptions } from "./schema-context.js";
|
|
20
23
|
import type { SchemaRequest } from "./schema-rule.js";
|
|
21
24
|
|
|
22
|
-
/** Path parts where a default value cannot make a property required (inputs may omit it). */
|
|
23
|
-
const INPUT_PATH_PARTS = ["parameters", "requestBody", "requestBodies"] as const;
|
|
24
|
-
|
|
25
25
|
export class InvalidPropertyError extends OpenAPITypesafeError {
|
|
26
26
|
constructor(path: string | undefined, key: string, value: unknown) {
|
|
27
27
|
const received = Array.isArray(value) ? "Array" : typeof value;
|
|
@@ -85,11 +85,10 @@ function isOptionalProperty(
|
|
|
85
85
|
request: SchemaRequest,
|
|
86
86
|
): boolean {
|
|
87
87
|
const { options } = request.context;
|
|
88
|
-
const path = request.location.path;
|
|
89
88
|
const isDefaultRequired =
|
|
90
89
|
facts.hasDefault &&
|
|
91
90
|
options.defaultNonNullable &&
|
|
92
|
-
!
|
|
91
|
+
!isInputLocation(request.location.path, options.fixes);
|
|
93
92
|
const isRequired =
|
|
94
93
|
schema.required?.includes(key) ||
|
|
95
94
|
(schema.required === undefined && options.propertiesRequiredByDefault) ||
|
|
@@ -111,6 +110,12 @@ interface CustomResult {
|
|
|
111
110
|
readonly isOptional: true | null;
|
|
112
111
|
}
|
|
113
112
|
|
|
113
|
+
/** A `$ref` with siblings that `ref-siblings` types as an `allOf` is typed as a schema. */
|
|
114
|
+
function plainRef({ ref }: PropertyFacts, value: Schema, request: SchemaRequest) {
|
|
115
|
+
const isAllOf = ref && refWithSiblingsAsAllOf(value as SchemaObject, request.context.options);
|
|
116
|
+
return isAllOf ? undefined : ref;
|
|
117
|
+
}
|
|
118
|
+
|
|
114
119
|
function propertyType(
|
|
115
120
|
key: string,
|
|
116
121
|
value: Schema,
|
|
@@ -118,8 +123,9 @@ function propertyType(
|
|
|
118
123
|
request: SchemaRequest,
|
|
119
124
|
): CustomResult {
|
|
120
125
|
const path = appendPointer(request.location.path, [key]);
|
|
121
|
-
const
|
|
122
|
-
|
|
126
|
+
const ref = plainRef(facts, value, request);
|
|
127
|
+
const type = ref
|
|
128
|
+
? schemaRefType(ref, request)
|
|
123
129
|
: request.transformNested(value, { ...request.location, path });
|
|
124
130
|
const custom = request.context.callbacks.transform(value, request.location);
|
|
125
131
|
return custom === null
|
|
@@ -270,6 +276,9 @@ export function objectType(schema: SchemaObject, request: SchemaRequest): IrType
|
|
|
270
276
|
return inherited ? irObject([discriminatorMember(inherited, request)]) : null;
|
|
271
277
|
}
|
|
272
278
|
const members = discriminatorAndPropertyMembers(schema, request);
|
|
279
|
+
const propertyTypes = members.flatMap((member) =>
|
|
280
|
+
member.kind === "property" ? [member.type] : [],
|
|
281
|
+
);
|
|
273
282
|
// As in the original, a null `$defs` throws here (Object.keys) instead of being skipped.
|
|
274
283
|
if (
|
|
275
284
|
"$defs" in schema &&
|
|
@@ -282,8 +291,9 @@ export function objectType(schema: SchemaObject, request: SchemaRequest): IrType
|
|
|
282
291
|
if (valueTypes.length === 0) {
|
|
283
292
|
return members.length > 0 ? irObject(members) : null;
|
|
284
293
|
}
|
|
294
|
+
const indexType = withPropertyTypes(unionOf(valueTypes), propertyTypes);
|
|
285
295
|
const index = irObject([
|
|
286
|
-
irStringIndexSignature("key",
|
|
296
|
+
irStringIndexSignature("key", indexType, request.context.options.immutable),
|
|
287
297
|
]);
|
|
288
298
|
return intersectionOf([...(members.length > 0 ? [irObject(members)] : []), index]);
|
|
289
299
|
}
|
|
@@ -32,7 +32,8 @@ const SHAPE_RULES: readonly SchemaRule[] = [
|
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
name: "const",
|
|
35
|
-
|
|
35
|
+
// `const: null` is the value null (JSON Schema §6.1.3); the original read it as no `const`.
|
|
36
|
+
matches: (schema) => schema.const !== undefined,
|
|
36
37
|
transform: (schema) => literalType(schema.const),
|
|
37
38
|
},
|
|
38
39
|
enumRule,
|
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
irObject,
|
|
4
|
-
irReference,
|
|
5
|
-
irStringIndexSignature,
|
|
6
|
-
} from "../../../domain/ir/constructors.js";
|
|
7
|
-
import type { IrMember, IrType } from "../../../domain/ir/nodes.js";
|
|
1
|
+
import { irObject, irStringIndexSignature } from "../../../domain/ir/constructors.js";
|
|
2
|
+
import type { IrType } from "../../../domain/ir/nodes.js";
|
|
8
3
|
import type { Schema, SchemaObject } from "../../../domain/openapi/schema-object.js";
|
|
9
4
|
import { FIX } from "../../../domain/output-fixes.js";
|
|
10
|
-
import {
|
|
5
|
+
import { declaredValueTypes } from "../declared-value-types.js";
|
|
11
6
|
import { UNKNOWN_TYPE } from "../shared-types.js";
|
|
12
7
|
import { unionOf } from "../type-combinators.js";
|
|
13
8
|
import type { SchemaRequest } from "./schema-rule.js";
|
|
@@ -46,41 +41,6 @@ function isAnySchema(schema: Schema): boolean {
|
|
|
46
41
|
return schema === true || (typeof schema === "object" && Object.keys(schema).length === 0);
|
|
47
42
|
}
|
|
48
43
|
|
|
49
|
-
function memberValueTypes(member: IrMember): IrType[] {
|
|
50
|
-
if (member.kind === "indexSignature") {
|
|
51
|
-
return [member.type];
|
|
52
|
-
}
|
|
53
|
-
return member.isOptional ? [member.type, irKeyword("undefined")] : [member.type];
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* The value types a key of the composed type can have, read from its IR: the members of object
|
|
58
|
-
* types, through unions and intersections. A reference (a `$ref`, `Omit`, `WithRequired`) or a raw
|
|
59
|
-
* type is read with `PropertyValues`. Primitives, literals and arrays declare no keys.
|
|
60
|
-
*/
|
|
61
|
-
function declaredValueTypes(type: IrType, request: SchemaRequest): IrType[] {
|
|
62
|
-
switch (type.kind) {
|
|
63
|
-
case "object":
|
|
64
|
-
return type.members.flatMap(memberValueTypes);
|
|
65
|
-
case "union":
|
|
66
|
-
case "intersection":
|
|
67
|
-
return type.types.flatMap((member) => declaredValueTypes(member, request));
|
|
68
|
-
case "reference":
|
|
69
|
-
case "indexedAccess":
|
|
70
|
-
case "raw":
|
|
71
|
-
request.context.footer.requirePropertyValues();
|
|
72
|
-
return [irReference(HELPER_TYPES.propertyValues.name, [type])];
|
|
73
|
-
case "keyword":
|
|
74
|
-
case "stringLiteral":
|
|
75
|
-
case "numberLiteral":
|
|
76
|
-
case "booleanLiteral":
|
|
77
|
-
case "array":
|
|
78
|
-
case "tuple":
|
|
79
|
-
case "readonly":
|
|
80
|
-
return [];
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
44
|
/**
|
|
85
45
|
* The index signature object for `unevaluatedProperties`, given the composed type of the other
|
|
86
46
|
* keywords (null when there is none). Null when the fix is off or the keyword does not apply.
|
|
@@ -98,7 +58,7 @@ export function unevaluatedPropertiesType(
|
|
|
98
58
|
? [UNKNOWN_TYPE]
|
|
99
59
|
: [
|
|
100
60
|
request.transformNested(unevaluated, request.location, true),
|
|
101
|
-
...(composed === null ? [] : declaredValueTypes(composed, request)),
|
|
61
|
+
...(composed === null ? [] : declaredValueTypes(composed, request.context.footer)),
|
|
102
62
|
];
|
|
103
63
|
const { immutable } = request.context.options;
|
|
104
64
|
return irObject([irStringIndexSignature("key", unionOf(valueTypes), immutable)]);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { DebugGroup, Logger } from "../application/ports/logger.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A logger whose lines name the API they are about. With several APIs in `redocly.yaml`, each is
|
|
5
|
+
* loaded and linted in turn, and a problem line such as "Can't resolve $ref" is the same for
|
|
6
|
+
* each, so without the name the user cannot tell which API it belongs to. The summary of a
|
|
7
|
+
* failed API names it the same way (`API a: …`).
|
|
8
|
+
*/
|
|
9
|
+
export function apiLogger(logger: Logger, apiName: string): Logger {
|
|
10
|
+
const prefix = `API ${apiName}: `;
|
|
11
|
+
return {
|
|
12
|
+
debug: (message: string, group?: DebugGroup, durationMs?: number) =>
|
|
13
|
+
logger.debug(`${prefix}${message}`, group, durationMs),
|
|
14
|
+
warn: (message: string) => logger.warn(`${prefix}${message}`),
|
|
15
|
+
error: (message: string) => logger.error(`${prefix}${message}`),
|
|
16
|
+
};
|
|
17
|
+
}
|