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
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import { isRawBinarySchema } from "../../../domain/openapi/binary-content.js";
|
|
2
2
|
import type { RefResolver, SchemaOptions } from "../schema/schema-context.js";
|
|
3
|
+
import {
|
|
4
|
+
childLocation,
|
|
5
|
+
followLocated,
|
|
6
|
+
isJsonObject,
|
|
7
|
+
type JsonObject,
|
|
8
|
+
type LocatedNode,
|
|
9
|
+
} from "./located-node.js";
|
|
10
|
+
import {
|
|
11
|
+
hasKeptProperties,
|
|
12
|
+
isExcludedProperty,
|
|
13
|
+
isMarkedProperty,
|
|
14
|
+
isNullableSchema,
|
|
15
|
+
isOptionalProperty,
|
|
16
|
+
} from "./property-shape.js";
|
|
3
17
|
|
|
4
18
|
/**
|
|
5
19
|
* What the generated type of a schema has under a key, read from the schema itself. It answers the
|
|
@@ -8,14 +22,27 @@ import type { RefResolver, SchemaOptions } from "../schema/schema-context.js";
|
|
|
8
22
|
*/
|
|
9
23
|
|
|
10
24
|
export type GeneratedMember =
|
|
11
|
-
| {
|
|
12
|
-
|
|
13
|
-
|
|
25
|
+
| {
|
|
26
|
+
readonly kind: "property";
|
|
27
|
+
readonly node: unknown;
|
|
28
|
+
readonly location: string | undefined;
|
|
29
|
+
readonly isOptional: boolean;
|
|
30
|
+
/** `$Read<T>` or `$Write<T>` (`isMarkedProperty`): no member but the marker's own. */
|
|
31
|
+
readonly isMarked: boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* An index signature; `node` is undefined when its value type is `unknown`. `isOtherType`: the
|
|
35
|
+
* type read is not the type of the node the key names (`indexMember`).
|
|
36
|
+
*/
|
|
37
|
+
| {
|
|
38
|
+
readonly kind: "index";
|
|
39
|
+
readonly node: unknown;
|
|
40
|
+
readonly location: string | undefined;
|
|
41
|
+
readonly isOtherType: boolean;
|
|
42
|
+
}
|
|
14
43
|
| { readonly kind: "missing" }
|
|
15
44
|
| { readonly kind: "opaque" };
|
|
16
45
|
|
|
17
|
-
type JsonObject = Readonly<Record<string, unknown>>;
|
|
18
|
-
|
|
19
46
|
const OPAQUE_KEYS = ["not", "enum", "const", "$ref"] as const;
|
|
20
47
|
/** How deep `allOf`/`anyOf`/`oneOf` members are read; deeper shapes count as opaque. */
|
|
21
48
|
const MAX_DEPTH = 8;
|
|
@@ -23,23 +50,6 @@ const INDEX_RE = /^\d+$/;
|
|
|
23
50
|
const MISSING: GeneratedMember = { kind: "missing" };
|
|
24
51
|
const OPAQUE: GeneratedMember = { kind: "opaque" };
|
|
25
52
|
|
|
26
|
-
export function isJsonObject(value: unknown): value is JsonObject {
|
|
27
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** The schema a node stands for: a `$ref` is followed to its target. */
|
|
31
|
-
export function followRefs(node: unknown, refs: RefResolver): unknown {
|
|
32
|
-
return isJsonObject(node) && typeof node.$ref === "string" ? refs.resolve(node.$ref) : node;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** `nullable: true` or a `type` list with `null`: the generated type includes `null`. */
|
|
36
|
-
export function isNullableSchema(node: unknown): boolean {
|
|
37
|
-
if (!isJsonObject(node)) {
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
return node.nullable === true || (Array.isArray(node.type) && node.type.includes("null"));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
53
|
function typeNames(node: JsonObject): readonly unknown[] {
|
|
44
54
|
return Array.isArray(node.type) ? node.type : [node.type];
|
|
45
55
|
}
|
|
@@ -90,39 +100,71 @@ function isBuiltInMember(key: string, prototype: object): boolean {
|
|
|
90
100
|
return key in prototype;
|
|
91
101
|
}
|
|
92
102
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
103
|
+
/** `additionalProperties: true` or `{}` (also as a pattern's schema): a value of `unknown`. */
|
|
104
|
+
function isUnknownValue(value: unknown): boolean {
|
|
105
|
+
return value === true || (isJsonObject(value) && Object.keys(value).length === 0);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** The value schemas of an index signature none of whose values is `unknown`, located. */
|
|
109
|
+
function typedIndexValues(owner: LocatedNode & { node: JsonObject }): LocatedNode[] {
|
|
110
|
+
const { additionalProperties: values, patternProperties: patterns } = owner.node;
|
|
111
|
+
const located: LocatedNode[] = [];
|
|
112
|
+
if (isJsonObject(values)) {
|
|
113
|
+
located.push({ node: values, location: childLocation(owner.location, "additionalProperties") });
|
|
97
114
|
}
|
|
98
|
-
|
|
99
|
-
|
|
115
|
+
for (const [pattern, node] of isJsonObject(patterns) ? Object.entries(patterns) : []) {
|
|
116
|
+
located.push({ node, location: childLocation(owner.location, "patternProperties", pattern) });
|
|
100
117
|
}
|
|
101
|
-
|
|
102
|
-
return isImplicit || (!values && options.additionalProperties)
|
|
103
|
-
? { kind: "index", node: undefined }
|
|
104
|
-
: null;
|
|
118
|
+
return located;
|
|
105
119
|
}
|
|
106
120
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
121
|
+
/**
|
|
122
|
+
* The index signature of an object schema, or null without one. Its type is the union of its
|
|
123
|
+
* value schemas' types (`unknown` if one is `unknown`); a union of several counts as opaque. It
|
|
124
|
+
* also holds the kept property types (`withPropertyTypes`), and a key that names a property
|
|
125
|
+
* `--exclude-deprecated` left out reads it instead of that property: both are `isOtherType`.
|
|
126
|
+
*/
|
|
127
|
+
function indexMember(
|
|
128
|
+
owner: LocatedNode & { node: JsonObject },
|
|
129
|
+
isExcludedKey: boolean,
|
|
130
|
+
input: MemberInput,
|
|
131
|
+
): GeneratedMember | null {
|
|
132
|
+
const { additionalProperties: values, patternProperties: patterns } = owner.node;
|
|
133
|
+
const patternValues = isJsonObject(patterns) ? Object.values(patterns) : [];
|
|
134
|
+
const isUnknown =
|
|
135
|
+
isUnknownValue(values) ||
|
|
136
|
+
patternValues.some(isUnknownValue) ||
|
|
137
|
+
(!values && input.options.additionalProperties);
|
|
138
|
+
if (isUnknown) {
|
|
139
|
+
return { kind: "index", node: undefined, location: undefined, isOtherType: isExcludedKey };
|
|
140
|
+
}
|
|
141
|
+
const typed = typedIndexValues(owner);
|
|
142
|
+
const [only] = typed;
|
|
143
|
+
if (only === undefined || typed.length > 1) {
|
|
144
|
+
return only === undefined ? null : OPAQUE;
|
|
145
|
+
}
|
|
146
|
+
const isOtherType = isExcludedKey || hasKeptProperties(owner.node, input.options, input.refs);
|
|
147
|
+
return { kind: "index", ...only, isOtherType };
|
|
116
148
|
}
|
|
117
149
|
|
|
118
|
-
function objectMember(
|
|
150
|
+
function objectMember(
|
|
151
|
+
owner: LocatedNode & { node: JsonObject },
|
|
152
|
+
key: string,
|
|
153
|
+
input: MemberInput,
|
|
154
|
+
): GeneratedMember {
|
|
155
|
+
const { options } = input;
|
|
156
|
+
const { node } = owner;
|
|
119
157
|
const properties = isJsonObject(node.properties) ? node.properties : {};
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
158
|
+
const isExcludedKey =
|
|
159
|
+
Object.hasOwn(properties, key) && isExcludedProperty(properties[key], options, input.refs);
|
|
160
|
+
if (Object.hasOwn(properties, key) && !isExcludedKey) {
|
|
161
|
+
if (isJsonObject(node.discriminator)) {
|
|
162
|
+
return OPAQUE;
|
|
163
|
+
}
|
|
164
|
+
const location = childLocation(owner.location, "properties", key);
|
|
165
|
+
const isOptional = isOptionalProperty(owner, key, options);
|
|
166
|
+
const isMarked = isMarkedProperty(properties[key], options, input.refs);
|
|
167
|
+
return { kind: "property", node: properties[key], location, isOptional, isMarked };
|
|
126
168
|
}
|
|
127
169
|
// `unevaluatedProperties` adds an index signature with its fix, so it counts as opaque too.
|
|
128
170
|
const isUnknownShape =
|
|
@@ -131,38 +173,23 @@ function objectMember(node: JsonObject, key: string, options: SchemaOptions): Ge
|
|
|
131
173
|
return OPAQUE;
|
|
132
174
|
}
|
|
133
175
|
return hasObjectKeywords(node)
|
|
134
|
-
? (indexMember(
|
|
176
|
+
? (indexMember(owner, isExcludedKey, input) ?? MISSING)
|
|
135
177
|
: emptyObjectMember(node, options);
|
|
136
178
|
}
|
|
137
179
|
|
|
138
|
-
/** Whether a value is there: `present`, `absent` (may be `undefined` or `null`) or `unknown`. */
|
|
139
|
-
export type Presence = "present" | "absent" | "unknown";
|
|
140
|
-
|
|
141
|
-
/** The presence of a value of `schema` itself: `absent` when its type includes `null`. */
|
|
142
|
-
export function schemaPresence(schema: unknown, refs: RefResolver): Presence {
|
|
143
|
-
return isNullableSchema(followRefs(schema, refs)) ? "absent" : "present";
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/** The presence of property `key` of `schema`: optional or nullable is `absent`. */
|
|
147
|
-
export function propertyPresence(
|
|
148
|
-
schema: unknown,
|
|
149
|
-
key: string,
|
|
150
|
-
options: SchemaOptions,
|
|
151
|
-
refs: RefResolver,
|
|
152
|
-
): Presence {
|
|
153
|
-
const node = followRefs(schema, refs);
|
|
154
|
-
const properties = isJsonObject(node) && isJsonObject(node.properties) ? node.properties : {};
|
|
155
|
-
if (!isJsonObject(node) || !Object.hasOwn(properties, key)) {
|
|
156
|
-
return "unknown";
|
|
157
|
-
}
|
|
158
|
-
return isOptionalProperty(node, key, options) ? "absent" : schemaPresence(properties[key], refs);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
180
|
function membersOf(node: JsonObject, keyword: string): readonly unknown[] {
|
|
162
181
|
const members = node[keyword];
|
|
163
182
|
return Array.isArray(members) ? members : [];
|
|
164
183
|
}
|
|
165
184
|
|
|
185
|
+
/** The members of a composition keyword with their locations. */
|
|
186
|
+
function locatedMembers(owner: LocatedNode & { node: JsonObject }, keyword: string): LocatedNode[] {
|
|
187
|
+
return membersOf(owner.node, keyword).map((node, index) => ({
|
|
188
|
+
node,
|
|
189
|
+
location: childLocation(owner.location, keyword, String(index)),
|
|
190
|
+
}));
|
|
191
|
+
}
|
|
192
|
+
|
|
166
193
|
function withoutComposition(node: JsonObject): JsonObject {
|
|
167
194
|
const { allOf: _allOf, anyOf: _anyOf, oneOf: _oneOf, ...own } = node;
|
|
168
195
|
return own;
|
|
@@ -178,8 +205,13 @@ function hasOwnObjectType(own: JsonObject): boolean {
|
|
|
178
205
|
* `anyOf` or `oneOf` alone is a union: a key is missing if one member misses it. A mix of both
|
|
179
206
|
* is written in more than one way (`anyof-properties`), so it counts as opaque.
|
|
180
207
|
*/
|
|
181
|
-
function composedMember(
|
|
182
|
-
|
|
208
|
+
function composedMember(
|
|
209
|
+
owner: LocatedNode & { node: JsonObject },
|
|
210
|
+
key: string,
|
|
211
|
+
input: MemberInput,
|
|
212
|
+
): GeneratedMember {
|
|
213
|
+
const { node } = owner;
|
|
214
|
+
const variants = [...locatedMembers(owner, "anyOf"), ...locatedMembers(owner, "oneOf")];
|
|
183
215
|
const own = withoutComposition(node);
|
|
184
216
|
const hasOwn = hasOwnObjectType(own);
|
|
185
217
|
if (variants.length > 0) {
|
|
@@ -187,7 +219,8 @@ function composedMember(node: JsonObject, key: string, input: MemberInput): Gene
|
|
|
187
219
|
const members = variants.map((variant) => memberAt(variant, key, input));
|
|
188
220
|
return isAlone && members.some((member) => member.kind === "missing") ? MISSING : OPAQUE;
|
|
189
221
|
}
|
|
190
|
-
const
|
|
222
|
+
const ownPart = { node: own, location: owner.location };
|
|
223
|
+
const parts = [...locatedMembers(owner, "allOf"), ...(hasOwn ? [ownPart] : [])];
|
|
191
224
|
return intersectionMember(parts.map((part) => memberAt(part, key, input)));
|
|
192
225
|
}
|
|
193
226
|
|
|
@@ -216,23 +249,22 @@ interface MemberInput {
|
|
|
216
249
|
readonly depth: number;
|
|
217
250
|
}
|
|
218
251
|
|
|
219
|
-
function memberAt(schema:
|
|
220
|
-
const
|
|
252
|
+
function memberAt(schema: LocatedNode, key: string, input: MemberInput): GeneratedMember {
|
|
253
|
+
const followed = followLocated(schema, input.refs);
|
|
254
|
+
const { node } = followed;
|
|
221
255
|
if (!isJsonObject(node) || OPAQUE_KEYS.some((name) => name in node) || input.depth > MAX_DEPTH) {
|
|
222
256
|
return OPAQUE;
|
|
223
257
|
}
|
|
258
|
+
const owner = { ...followed, node };
|
|
224
259
|
if (isNullableSchema(node)) {
|
|
225
260
|
// Every key of `T | null` is an error, unless `T` is unknown (then the type is `unknown`).
|
|
226
261
|
return isObjectShape(node) || isArrayShape(node) ? MISSING : OPAQUE;
|
|
227
262
|
}
|
|
228
|
-
if (input.options.readWriteMarkers) {
|
|
229
|
-
return OPAQUE;
|
|
230
|
-
}
|
|
231
263
|
if ("allOf" in node || "anyOf" in node || "oneOf" in node) {
|
|
232
|
-
return composedMember(
|
|
264
|
+
return composedMember(owner, key, { ...input, depth: input.depth + 1 });
|
|
233
265
|
}
|
|
234
266
|
if (isObjectShape(node)) {
|
|
235
|
-
return objectMember(
|
|
267
|
+
return objectMember(owner, key, input);
|
|
236
268
|
}
|
|
237
269
|
if (isArrayShape(node)) {
|
|
238
270
|
return INDEX_RE.test(key) || isBuiltInMember(key, []) ? OPAQUE : MISSING;
|
|
@@ -266,7 +298,7 @@ function primitiveMember(node: JsonObject, key: string): GeneratedMember {
|
|
|
266
298
|
|
|
267
299
|
/** The member `key` of the type generated for `schema` (a `$ref` is followed first). */
|
|
268
300
|
export function generatedMember(
|
|
269
|
-
schema:
|
|
301
|
+
schema: LocatedNode,
|
|
270
302
|
key: string,
|
|
271
303
|
options: SchemaOptions,
|
|
272
304
|
refs: RefResolver,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RefResolver, SchemaOptions } from "../schema/schema-context.js";
|
|
2
|
-
import { isJsonObject } from "./
|
|
2
|
+
import { isJsonObject } from "./located-node.js";
|
|
3
3
|
import { pointerNode, refPointerOf } from "./pointer-walk.js";
|
|
4
4
|
import { typedWalk } from "./typed-walk.js";
|
|
5
5
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { appendPointer } from "../../../domain/openapi/json-pointer.js";
|
|
2
|
+
import type { RefResolver } from "../schema/schema-context.js";
|
|
3
|
+
|
|
4
|
+
/** Document nodes as the `$ref` pointer walks read them: with their place in the document. */
|
|
5
|
+
|
|
6
|
+
export type JsonObject = Readonly<Record<string, unknown>>;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A schema node and its JSON Pointer in the document. The generator writes the type of a schema
|
|
10
|
+
* reached by a `$ref` at the target, and the location decides whether a property with a `default`
|
|
11
|
+
* is required (`isInputLocation`). Undefined for a node that is not in the document.
|
|
12
|
+
*/
|
|
13
|
+
export interface LocatedNode {
|
|
14
|
+
readonly node: unknown;
|
|
15
|
+
readonly location: string | undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function isJsonObject(value: unknown): value is JsonObject {
|
|
19
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** The schema a node stands for: a `$ref` is followed to its target. */
|
|
23
|
+
export function followRefs(node: unknown, refs: RefResolver): unknown {
|
|
24
|
+
return isJsonObject(node) && typeof node.$ref === "string" ? refs.resolve(node.$ref) : node;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** `followRefs` with the location: a `$ref` is followed to its target and the target's pointer. */
|
|
28
|
+
export function followLocated(located: LocatedNode, refs: RefResolver): LocatedNode {
|
|
29
|
+
const { node } = located;
|
|
30
|
+
return isJsonObject(node) && typeof node.$ref === "string"
|
|
31
|
+
? { node: refs.resolve(node.$ref), location: node.$ref }
|
|
32
|
+
: located;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** The location of a child of a node at `location`, or undefined outside the document. */
|
|
36
|
+
export function childLocation(location: string | undefined, ...segments: string[]) {
|
|
37
|
+
return location === undefined ? undefined : appendPointer(location, segments);
|
|
38
|
+
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import type { RefResolver, SchemaOptions } from "../schema/schema-context.js";
|
|
2
|
-
import {
|
|
2
|
+
import { generatedMember } from "./generated-shape.js";
|
|
3
|
+
import { childLocation, followLocated, isJsonObject } from "./located-node.js";
|
|
3
4
|
import {
|
|
5
|
+
type ContentForm,
|
|
6
|
+
headerParameterContentForm,
|
|
7
|
+
isExcludedOperation,
|
|
4
8
|
isOptionalHeader,
|
|
5
9
|
isOptionalRequestBody,
|
|
6
10
|
isParameterList,
|
|
7
11
|
isTypedAsSchema,
|
|
8
|
-
|
|
12
|
+
leadingLocated,
|
|
9
13
|
leadingSegmentsOf,
|
|
10
14
|
type RefPointer,
|
|
11
15
|
startsInSchema,
|
|
@@ -14,14 +18,18 @@ import {
|
|
|
14
18
|
/**
|
|
15
19
|
* Whether the type the original wrote for a `$ref` (`refType`: every segment indexed by name,
|
|
16
20
|
* `properties` skipped) surely fails to compile. It walks the document as TypeScript walks the
|
|
17
|
-
* generated types and answers true only where TypeScript reports an error for sure
|
|
18
|
-
*
|
|
21
|
+
* generated types and answers true only where TypeScript reports an error for sure, or where the
|
|
22
|
+
* type compiles but is read through an index signature that is not the target's type alone
|
|
23
|
+
* (`isOtherType`); where the answer depends on a shape it does not model, it answers false, so
|
|
24
|
+
* that output stays as it was.
|
|
19
25
|
*/
|
|
20
26
|
|
|
21
27
|
type Step = "fails" | "compiles" | "continue";
|
|
22
28
|
|
|
23
29
|
interface OriginalWalk {
|
|
24
30
|
readonly node: unknown;
|
|
31
|
+
/** The node's JSON Pointer (`LocatedNode`). */
|
|
32
|
+
readonly location: string | undefined;
|
|
25
33
|
readonly isSchema: boolean;
|
|
26
34
|
}
|
|
27
35
|
|
|
@@ -35,57 +43,135 @@ function schemaStep(walk: OriginalWalk, segment: string, isLast: boolean, input:
|
|
|
35
43
|
if (segment === "properties") {
|
|
36
44
|
return { step: "continue" as Step, walk };
|
|
37
45
|
}
|
|
38
|
-
const member = generatedMember(walk
|
|
39
|
-
|
|
46
|
+
const member = generatedMember(walk, segment, input.options, input.refs);
|
|
47
|
+
// Such an index signature compiles, but its type is not the target's alone.
|
|
48
|
+
if (member.kind === "missing" || (member.kind === "index" && member.isOtherType)) {
|
|
40
49
|
return { step: "fails" as Step, walk };
|
|
41
50
|
}
|
|
42
51
|
if (member.kind === "opaque") {
|
|
43
52
|
return { step: "compiles" as Step, walk };
|
|
44
53
|
}
|
|
45
54
|
const isAbsentValue = member.kind === "index" && member.node === undefined;
|
|
46
|
-
const isUnsafe =
|
|
55
|
+
const isUnsafe =
|
|
56
|
+
member.kind === "property" ? member.isOptional || member.isMarked : isAbsentValue;
|
|
47
57
|
return {
|
|
48
58
|
step: (isUnsafe && !isLast ? "fails" : "continue") as Step,
|
|
49
|
-
walk: { ...walk, node: member.node },
|
|
59
|
+
walk: { ...walk, node: member.node, location: member.location },
|
|
50
60
|
};
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
function containerStep(walk: OriginalWalk, index: number, input: WalkInput) {
|
|
54
64
|
const segment = input.pointer.segments[index] as string;
|
|
55
65
|
const isLast = index === input.pointer.segments.length - 1;
|
|
66
|
+
if (isExcludedOperation(input.pointer, index, walk.node, input)) {
|
|
67
|
+
return { step: "fails" as Step, walk };
|
|
68
|
+
}
|
|
56
69
|
const isOptional =
|
|
57
70
|
(segment === "requestBody" && isOptionalRequestBody(walk.node, input.refs)) ||
|
|
58
71
|
isOptionalHeader(input.pointer, index, walk.node);
|
|
59
72
|
if (isOptional && !isLast) {
|
|
60
73
|
return { step: "fails" as Step, walk };
|
|
61
74
|
}
|
|
62
|
-
const child =
|
|
75
|
+
const child = followLocated(
|
|
76
|
+
{
|
|
77
|
+
node: isJsonObject(walk.node) ? walk.node[segment] : undefined,
|
|
78
|
+
location: childLocation(walk.location, segment),
|
|
79
|
+
},
|
|
80
|
+
input.refs,
|
|
81
|
+
);
|
|
63
82
|
return {
|
|
64
|
-
step: (child === undefined ? "compiles" : "continue") as Step,
|
|
65
|
-
walk: { ...walk,
|
|
83
|
+
step: (child.node === undefined ? "compiles" : "continue") as Step,
|
|
84
|
+
walk: { ...walk, ...child },
|
|
66
85
|
};
|
|
67
86
|
}
|
|
68
87
|
|
|
88
|
+
/** The schema of the first media type of a `content` map, `$ref`s followed. */
|
|
89
|
+
function firstMediaTypeSchema(walk: OriginalWalk, refs: RefResolver): OriginalWalk | null {
|
|
90
|
+
const content = isJsonObject(walk.node) ? walk.node.content : undefined;
|
|
91
|
+
if (!isJsonObject(content)) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
const [mediaType] = Object.keys(content);
|
|
95
|
+
if (mediaType === undefined) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
const location = childLocation(childLocation(walk.location, "content"), mediaType);
|
|
99
|
+
const entry = followLocated({ node: content[mediaType], location }, refs);
|
|
100
|
+
return ownSchema({ ...entry, isSchema: false }, refs);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** The schema a header or parameter is typed by, `$ref`s followed. */
|
|
104
|
+
function ownSchema(walk: OriginalWalk, refs: RefResolver): OriginalWalk {
|
|
105
|
+
const schema = isJsonObject(walk.node) ? walk.node.schema : undefined;
|
|
106
|
+
const location = childLocation(walk.location, "schema");
|
|
107
|
+
return { ...followLocated({ node: schema, location }, refs), isSchema: true };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** The schema whose type a header or parameter is, when not its media type members. */
|
|
111
|
+
function contentSchema(
|
|
112
|
+
walk: OriginalWalk,
|
|
113
|
+
form: Exclude<ContentForm, "media-type-members">,
|
|
114
|
+
refs: RefResolver,
|
|
115
|
+
): OriginalWalk | null {
|
|
116
|
+
switch (form) {
|
|
117
|
+
case "first-media-type":
|
|
118
|
+
return firstMediaTypeSchema(walk, refs);
|
|
119
|
+
case "schema":
|
|
120
|
+
return ownSchema(walk, refs);
|
|
121
|
+
case "string":
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* The original indexes the `content` of a header or parameter by name. The media type members
|
|
128
|
+
* have no `content` unless a media type is named so, and `string` and `unknown` (no media type)
|
|
129
|
+
* have none; the schema of the first media type, or the `schema` next to `content`, is walked on.
|
|
130
|
+
*/
|
|
131
|
+
function contentStep(walk: OriginalWalk, form: ContentForm, isLast: boolean, input: WalkInput) {
|
|
132
|
+
const content = isJsonObject(walk.node) ? walk.node.content : undefined;
|
|
133
|
+
if (form === "media-type-members") {
|
|
134
|
+
const hasMember = isJsonObject(content) && Object.hasOwn(content, "content");
|
|
135
|
+
return { step: (hasMember ? "compiles" : "fails") as Step, walk };
|
|
136
|
+
}
|
|
137
|
+
const schema = contentSchema(walk, form, input.refs);
|
|
138
|
+
return schema === null
|
|
139
|
+
? { step: "fails" as Step, walk }
|
|
140
|
+
: schemaStep(schema, "content", isLast, input);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* A step outside a schema: a header's or parameter's `content`, a schema's container, or another.
|
|
145
|
+
*/
|
|
146
|
+
function documentStep(walk: OriginalWalk, index: number, input: WalkInput) {
|
|
147
|
+
const segment = input.pointer.segments[index] as string;
|
|
148
|
+
const isLast = index === input.pointer.segments.length - 1;
|
|
149
|
+
const form = headerParameterContentForm(input.pointer, index, walk.node, input.options);
|
|
150
|
+
if (form !== null) {
|
|
151
|
+
return contentStep(walk, form, isLast, input);
|
|
152
|
+
}
|
|
153
|
+
if (isTypedAsSchema(input.pointer, index) && isJsonObject(walk.node)) {
|
|
154
|
+
// The container's type is its schema's type: the segment indexes that type.
|
|
155
|
+
return schemaStep(ownSchema(walk, input.refs), segment, isLast, input);
|
|
156
|
+
}
|
|
157
|
+
return containerStep(walk, index, input);
|
|
158
|
+
}
|
|
159
|
+
|
|
69
160
|
/** True when the original type of the `$ref` does not compile for sure. */
|
|
70
161
|
export function originalIndexFails(input: WalkInput): boolean {
|
|
71
162
|
const { segments } = input.pointer;
|
|
72
163
|
let walk: OriginalWalk = {
|
|
73
|
-
|
|
164
|
+
...leadingLocated(input.pointer, input.refs),
|
|
74
165
|
isSchema: startsInSchema(input.pointer),
|
|
75
166
|
};
|
|
76
167
|
for (let index = leadingSegmentsOf(input.pointer); index < segments.length; index++) {
|
|
77
|
-
const segment = segments[index] as string;
|
|
78
|
-
const isLast = index === segments.length - 1;
|
|
79
168
|
if (!walk.isSchema && isParameterList(input.pointer, index)) {
|
|
80
169
|
return true;
|
|
81
170
|
}
|
|
82
|
-
|
|
83
|
-
// The container's type is its schema's type: the segment indexes that type.
|
|
84
|
-
walk = { node: followRefs(walk.node.schema, input.refs), isSchema: true };
|
|
85
|
-
}
|
|
171
|
+
const isLast = index === segments.length - 1;
|
|
86
172
|
const result = walk.isSchema
|
|
87
|
-
? schemaStep(walk,
|
|
88
|
-
:
|
|
173
|
+
? schemaStep(walk, segments[index] as string, isLast, input)
|
|
174
|
+
: documentStep(walk, index, input);
|
|
89
175
|
if (result.step !== "continue") {
|
|
90
176
|
return result.step === "fails";
|
|
91
177
|
}
|
|
@@ -4,8 +4,8 @@ import { FIX } from "../../../domain/output-fixes.js";
|
|
|
4
4
|
import { InvalidRefError, refType } from "../ref-type.js";
|
|
5
5
|
import type { SchemaRequest } from "../schema/schema-rule.js";
|
|
6
6
|
import { generatedLocationOf } from "./generated-location.js";
|
|
7
|
-
import { isJsonObject } from "./generated-shape.js";
|
|
8
7
|
import { hasInlineCycle } from "./inline-cycles.js";
|
|
8
|
+
import { isJsonObject } from "./located-node.js";
|
|
9
9
|
import { originalIndexFails } from "./original-index.js";
|
|
10
10
|
import { leadingSegmentsOf, pointerNode, type RefPointer, refPointerOf } from "./pointer-walk.js";
|
|
11
11
|
import { typedWalk } from "./typed-walk.js";
|
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
1
|
+
import { placeOf } from "../../../domain/openapi/document-places.js";
|
|
2
|
+
import { parseRefPointer, ROOT_POINTER } from "../../../domain/openapi/json-pointer.js";
|
|
3
|
+
import { QUERYSTRING_LOCATION } from "../../../domain/openapi/parameter-object.js";
|
|
4
|
+
import { FIX } from "../../../domain/output-fixes.js";
|
|
5
|
+
import type { RefResolver, SchemaOptions } from "../schema/schema-context.js";
|
|
6
|
+
import {
|
|
7
|
+
childLocation,
|
|
8
|
+
followLocated,
|
|
9
|
+
followRefs,
|
|
10
|
+
isJsonObject,
|
|
11
|
+
type LocatedNode,
|
|
12
|
+
} from "./located-node.js";
|
|
4
13
|
|
|
5
14
|
/** The parts of a `$ref` pointer that both the original and the new types walk. */
|
|
6
15
|
|
|
@@ -27,13 +36,18 @@ export function refPointerOf(ref: string): RefPointer | null {
|
|
|
27
36
|
return rootSegment === undefined ? null : { rootSegment, segments };
|
|
28
37
|
}
|
|
29
38
|
|
|
30
|
-
/** The document node at the end of the leading segments, `$ref`s followed. */
|
|
31
|
-
export function
|
|
32
|
-
let
|
|
39
|
+
/** The document node at the end of the leading segments, `$ref`s followed, with its location. */
|
|
40
|
+
export function leadingLocated(pointer: RefPointer, refs: RefResolver): LocatedNode {
|
|
41
|
+
let located: LocatedNode = {
|
|
42
|
+
node: refs.resolve(`#/${pointer.rootSegment}`),
|
|
43
|
+
location: childLocation(ROOT_POINTER, pointer.rootSegment),
|
|
44
|
+
};
|
|
33
45
|
for (const segment of pointer.segments.slice(0, leadingSegmentsOf(pointer))) {
|
|
34
|
-
|
|
46
|
+
const { node, location } = located;
|
|
47
|
+
const child = isJsonObject(node) ? node[segment] : undefined;
|
|
48
|
+
located = followLocated({ node: child, location: childLocation(location, segment) }, refs);
|
|
35
49
|
}
|
|
36
|
-
return
|
|
50
|
+
return located;
|
|
37
51
|
}
|
|
38
52
|
|
|
39
53
|
/** The node at the whole pointer, without following a `$ref` at its end. */
|
|
@@ -62,6 +76,47 @@ export function isTypedAsSchema(pointer: RefPointer, index: number): boolean {
|
|
|
62
76
|
return owner === "content" || owner === "headers" || isComponentParameter;
|
|
63
77
|
}
|
|
64
78
|
|
|
79
|
+
/**
|
|
80
|
+
* How the generated type of a header or component parameter holds its `content` (header.ts,
|
|
81
|
+
* parameter.ts): one member per media type, the type of the first media type, `string` (a
|
|
82
|
+
* parameter without the `parameter-header-content` fix), or not at all (a `schema` wins).
|
|
83
|
+
*/
|
|
84
|
+
export type ContentForm = "media-type-members" | "first-media-type" | "string" | "schema";
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The form of the `content` at `index` when it belongs to a header or a component parameter; null
|
|
88
|
+
* for any other segment. An `in: querystring` parameter is typed by its `content` even next to a
|
|
89
|
+
* `schema`.
|
|
90
|
+
*/
|
|
91
|
+
export function headerParameterContentForm(
|
|
92
|
+
pointer: RefPointer,
|
|
93
|
+
index: number,
|
|
94
|
+
owner: unknown,
|
|
95
|
+
options: SchemaOptions,
|
|
96
|
+
): ContentForm | null {
|
|
97
|
+
const isHeader = pointer.segments[index - 2] === "headers";
|
|
98
|
+
const isComponentParameter =
|
|
99
|
+
pointer.rootSegment === "components" && index === 2 && pointer.segments[0] === "parameters";
|
|
100
|
+
const isOwnContent = pointer.segments[index] === "content" && (isHeader || isComponentParameter);
|
|
101
|
+
if (!isOwnContent || !isJsonObject(owner)) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
const isFixed = options.fixes.has(FIX.PARAMETER_HEADER_CONTENT);
|
|
105
|
+
if (isHeader) {
|
|
106
|
+
if (owner.schema) {
|
|
107
|
+
return "schema";
|
|
108
|
+
}
|
|
109
|
+
return isFixed ? "first-media-type" : "media-type-members";
|
|
110
|
+
}
|
|
111
|
+
if (owner.in === QUERYSTRING_LOCATION) {
|
|
112
|
+
return "first-media-type";
|
|
113
|
+
}
|
|
114
|
+
if (owner.schema !== undefined) {
|
|
115
|
+
return "schema";
|
|
116
|
+
}
|
|
117
|
+
return isFixed ? "first-media-type" : "string";
|
|
118
|
+
}
|
|
119
|
+
|
|
65
120
|
/**
|
|
66
121
|
* Whether the segment at `index` is an operation's or path item's `parameters` list, indexed by
|
|
67
122
|
* position next. The generated type groups parameters by `in` (`query`, `path`), so it has no
|
|
@@ -86,6 +141,25 @@ export function isOptionalHeader(pointer: RefPointer, index: number, headers: un
|
|
|
86
141
|
return isJsonObject(header) && header.$ref === undefined && header.required !== true;
|
|
87
142
|
}
|
|
88
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Whether the segment at `index` names an operation that `--exclude-deprecated` leaves out: the
|
|
146
|
+
* path item types it `never`, which has no member to index (`isIncludedOperation`).
|
|
147
|
+
*/
|
|
148
|
+
export function isExcludedOperation(
|
|
149
|
+
pointer: RefPointer,
|
|
150
|
+
index: number,
|
|
151
|
+
pathItem: unknown,
|
|
152
|
+
input: { readonly options: SchemaOptions; readonly refs: RefResolver },
|
|
153
|
+
): boolean {
|
|
154
|
+
const segments = [pointer.rootSegment, ...pointer.segments.slice(0, index + 1)];
|
|
155
|
+
if (!input.options.excludeDeprecated || placeOf(segments) !== "operation") {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
const segment = pointer.segments[index] as string;
|
|
159
|
+
const operation = isJsonObject(pathItem) ? followRefs(pathItem[segment], input.refs) : undefined;
|
|
160
|
+
return isJsonObject(operation) && Boolean(operation.deprecated);
|
|
161
|
+
}
|
|
162
|
+
|
|
89
163
|
/** A `requestBody` the operation does not mark `required` is an optional member. */
|
|
90
164
|
export function isOptionalRequestBody(container: unknown, refs: RefResolver): boolean {
|
|
91
165
|
if (!isJsonObject(container) || container.requestBody === undefined) {
|