openapi-typesafe 1.0.0-rc.0 → 1.0.0-rc.1
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/dist/adapters/redocly-loader/redocly-config-source.cjs +21 -2
- package/dist/adapters/redocly-loader/redocly-config-source.cjs.map +1 -1
- package/dist/adapters/redocly-loader/redocly-config-source.mjs +22 -3
- package/dist/adapters/redocly-loader/redocly-config-source.mjs.map +1 -1
- package/dist/adapters/redocly-loader/redocly-schema-loader.cjs +15 -5
- package/dist/adapters/redocly-loader/redocly-schema-loader.cjs.map +1 -1
- package/dist/adapters/redocly-loader/redocly-schema-loader.mjs +15 -5
- package/dist/adapters/redocly-loader/redocly-schema-loader.mjs.map +1 -1
- package/dist/adapters/type-ast-bridge/ir-to-typescript.cjs +3 -0
- package/dist/adapters/type-ast-bridge/ir-to-typescript.cjs.map +1 -1
- package/dist/adapters/type-ast-bridge/ir-to-typescript.mjs +3 -0
- package/dist/adapters/type-ast-bridge/ir-to-typescript.mjs.map +1 -1
- package/dist/adapters/type-ast-bridge/typescript-to-ir.cjs +15 -9
- package/dist/adapters/type-ast-bridge/typescript-to-ir.cjs.map +1 -1
- package/dist/adapters/type-ast-bridge/typescript-to-ir.mjs +15 -9
- package/dist/adapters/type-ast-bridge/typescript-to-ir.mjs.map +1 -1
- package/dist/api/discriminator-conflict-warnings.cjs +25 -0
- package/dist/api/discriminator-conflict-warnings.cjs.map +1 -0
- package/dist/api/discriminator-conflict-warnings.mjs +23 -0
- package/dist/api/discriminator-conflict-warnings.mjs.map +1 -0
- package/dist/api/discriminator-enum-names.cjs +19 -0
- package/dist/api/discriminator-enum-names.cjs.map +1 -0
- package/dist/api/discriminator-enum-names.mjs +17 -0
- package/dist/api/discriminator-enum-names.mjs.map +1 -0
- package/dist/api/discriminator-enum-parent.cjs +59 -0
- package/dist/api/discriminator-enum-parent.cjs.map +1 -0
- package/dist/api/discriminator-enum-parent.mjs +57 -0
- package/dist/api/discriminator-enum-parent.mjs.map +1 -0
- package/dist/api/discriminator-enum.cjs +25 -0
- package/dist/api/discriminator-enum.cjs.map +1 -1
- package/dist/api/discriminator-enum.mjs +25 -1
- package/dist/api/discriminator-enum.mjs.map +1 -1
- package/dist/api/discriminator-other-owners.cjs +67 -0
- package/dist/api/discriminator-other-owners.cjs.map +1 -0
- package/dist/api/discriminator-other-owners.mjs +64 -0
- package/dist/api/discriminator-other-owners.mjs.map +1 -0
- package/dist/api/discriminator-patch.cjs +88 -0
- package/dist/api/discriminator-patch.cjs.map +1 -0
- package/dist/api/discriminator-patch.mjs +82 -0
- package/dist/api/discriminator-patch.mjs.map +1 -0
- package/dist/api/discriminator-scan.cjs +50 -65
- package/dist/api/discriminator-scan.cjs.map +1 -1
- package/dist/api/discriminator-scan.mjs +44 -59
- package/dist/api/discriminator-scan.mjs.map +1 -1
- package/dist/api/document-run.cjs +18 -3
- package/dist/api/document-run.cjs.map +1 -1
- package/dist/api/document-run.mjs +19 -4
- package/dist/api/document-run.mjs.map +1 -1
- package/dist/api/enum-values-warnings.cjs +16 -0
- package/dist/api/enum-values-warnings.cjs.map +1 -0
- package/dist/api/enum-values-warnings.mjs +14 -0
- package/dist/api/enum-values-warnings.mjs.map +1 -0
- package/dist/api/path-template-warnings.cjs +21 -0
- package/dist/api/path-template-warnings.cjs.map +1 -0
- package/dist/api/path-template-warnings.mjs +19 -0
- package/dist/api/path-template-warnings.mjs.map +1 -0
- package/dist/api/transform-context.cjs +3 -1
- package/dist/api/transform-context.cjs.map +1 -1
- package/dist/api/transform-context.mjs +3 -1
- package/dist/api/transform-context.mjs.map +1 -1
- package/dist/api/transform-schema.cjs +52 -3
- package/dist/api/transform-schema.cjs.map +1 -1
- package/dist/api/transform-schema.mjs +53 -4
- package/dist/api/transform-schema.mjs.map +1 -1
- package/dist/api/unsupported-feature-warnings.cjs +6 -1
- package/dist/api/unsupported-feature-warnings.cjs.map +1 -1
- package/dist/api/unsupported-feature-warnings.mjs +6 -1
- package/dist/api/unsupported-feature-warnings.mjs.map +1 -1
- package/dist/application/print/type-printer.cjs +5 -0
- package/dist/application/print/type-printer.cjs.map +1 -1
- package/dist/application/print/type-printer.mjs +5 -0
- package/dist/application/print/type-printer.mjs.map +1 -1
- package/dist/application/transform/document/assignability.cjs +144 -0
- package/dist/application/transform/document/assignability.cjs.map +1 -0
- package/dist/application/transform/document/assignability.mjs +138 -0
- package/dist/application/transform/document/assignability.mjs.map +1 -0
- package/dist/application/transform/document/components.cjs +2 -2
- package/dist/application/transform/document/components.cjs.map +1 -1
- package/dist/application/transform/document/components.mjs +4 -4
- package/dist/application/transform/document/components.mjs.map +1 -1
- package/dist/application/transform/document/declared-types.cjs +66 -0
- package/dist/application/transform/document/declared-types.cjs.map +1 -0
- package/dist/application/transform/document/declared-types.mjs +63 -0
- package/dist/application/transform/document/declared-types.mjs.map +1 -0
- package/dist/application/transform/document/document.cjs +32 -9
- package/dist/application/transform/document/document.cjs.map +1 -1
- package/dist/application/transform/document/document.mjs +34 -11
- package/dist/application/transform/document/document.mjs.map +1 -1
- package/dist/application/transform/document/exploded-query.cjs +46 -0
- package/dist/application/transform/document/exploded-query.cjs.map +1 -0
- package/dist/application/transform/document/exploded-query.mjs +43 -0
- package/dist/application/transform/document/exploded-query.mjs.map +1 -0
- package/dist/application/transform/document/global-type-references.cjs +63 -0
- package/dist/application/transform/document/global-type-references.cjs.map +1 -0
- package/dist/application/transform/document/global-type-references.mjs +61 -0
- package/dist/application/transform/document/global-type-references.mjs.map +1 -0
- package/dist/application/transform/document/list-assignability.cjs +54 -0
- package/dist/application/transform/document/list-assignability.cjs.map +1 -0
- package/dist/application/transform/document/list-assignability.mjs +52 -0
- package/dist/application/transform/document/list-assignability.mjs.map +1 -0
- package/dist/application/transform/document/parameters.cjs +40 -8
- package/dist/application/transform/document/parameters.cjs.map +1 -1
- package/dist/application/transform/document/parameters.mjs +41 -9
- package/dist/application/transform/document/parameters.mjs.map +1 -1
- package/dist/application/transform/document/path-key-overlaps.cjs +83 -33
- package/dist/application/transform/document/path-key-overlaps.cjs.map +1 -1
- package/dist/application/transform/document/path-key-overlaps.mjs +83 -33
- package/dist/application/transform/document/path-key-overlaps.mjs.map +1 -1
- package/dist/application/transform/document/path-template-replace.cjs +48 -0
- package/dist/application/transform/document/path-template-replace.cjs.map +1 -0
- package/dist/application/transform/document/path-template-replace.mjs +45 -0
- package/dist/application/transform/document/path-template-replace.mjs.map +1 -0
- package/dist/application/transform/document/paths.cjs +54 -28
- package/dist/application/transform/document/paths.cjs.map +1 -1
- package/dist/application/transform/document/paths.mjs +53 -29
- package/dist/application/transform/document/paths.mjs.map +1 -1
- package/dist/application/transform/document/root-type-aliases.cjs +15 -14
- package/dist/application/transform/document/root-type-aliases.cjs.map +1 -1
- package/dist/application/transform/document/root-type-aliases.mjs +15 -13
- package/dist/application/transform/document/root-type-aliases.mjs.map +1 -1
- package/dist/application/transform/document/template-key-match.cjs +128 -0
- package/dist/application/transform/document/template-key-match.cjs.map +1 -0
- package/dist/application/transform/document/template-key-match.mjs +125 -0
- package/dist/application/transform/document/template-key-match.mjs.map +1 -0
- package/dist/application/transform/document/type-assignability.cjs +192 -0
- package/dist/application/transform/document/type-assignability.cjs.map +1 -0
- package/dist/application/transform/document/type-assignability.mjs +190 -0
- package/dist/application/transform/document/type-assignability.mjs.map +1 -0
- package/dist/application/transform/document/type-key.cjs +70 -0
- package/dist/application/transform/document/type-key.cjs.map +1 -0
- package/dist/application/transform/document/type-key.mjs +68 -0
- package/dist/application/transform/document/type-key.mjs.map +1 -0
- package/dist/application/transform/document/type-resolution.cjs +131 -0
- package/dist/application/transform/document/type-resolution.cjs.map +1 -0
- package/dist/application/transform/document/type-resolution.mjs +125 -0
- package/dist/application/transform/document/type-resolution.mjs.map +1 -0
- package/dist/application/transform/footer/document-footer.cjs +66 -4
- package/dist/application/transform/footer/document-footer.cjs.map +1 -1
- package/dist/application/transform/footer/document-footer.mjs +67 -5
- package/dist/application/transform/footer/document-footer.mjs.map +1 -1
- package/dist/application/transform/footer/enum-naming.cjs +17 -0
- package/dist/application/transform/footer/enum-naming.cjs.map +1 -1
- package/dist/application/transform/footer/enum-naming.mjs +17 -1
- package/dist/application/transform/footer/enum-naming.mjs.map +1 -1
- package/dist/application/transform/footer/enum-values-check.cjs +129 -0
- package/dist/application/transform/footer/enum-values-check.cjs.map +1 -0
- package/dist/application/transform/footer/enum-values-check.mjs +127 -0
- package/dist/application/transform/footer/enum-values-check.mjs.map +1 -0
- package/dist/application/transform/footer/evaluation.cjs +33 -0
- package/dist/application/transform/footer/evaluation.cjs.map +1 -0
- package/dist/application/transform/footer/evaluation.mjs +26 -0
- package/dist/application/transform/footer/evaluation.mjs.map +1 -0
- package/dist/application/transform/footer/shared-enum-names.cjs +60 -0
- package/dist/application/transform/footer/shared-enum-names.cjs.map +1 -0
- package/dist/application/transform/footer/shared-enum-names.mjs +57 -0
- package/dist/application/transform/footer/shared-enum-names.mjs.map +1 -0
- package/dist/application/transform/footer/type-evaluation.cjs +246 -0
- package/dist/application/transform/footer/type-evaluation.cjs.map +1 -0
- package/dist/application/transform/footer/type-evaluation.mjs +244 -0
- package/dist/application/transform/footer/type-evaluation.mjs.map +1 -0
- package/dist/application/transform/footer/type-rules.cjs +172 -0
- package/dist/application/transform/footer/type-rules.cjs.map +1 -0
- package/dist/application/transform/footer/type-rules.mjs +166 -0
- package/dist/application/transform/footer/type-rules.mjs.map +1 -0
- package/dist/application/transform/ref-pointer/generated-location.cjs +138 -0
- package/dist/application/transform/ref-pointer/generated-location.cjs.map +1 -0
- package/dist/application/transform/ref-pointer/generated-location.mjs +136 -0
- package/dist/application/transform/ref-pointer/generated-location.mjs.map +1 -0
- package/dist/application/transform/ref-pointer/generated-shape.cjs +171 -0
- package/dist/application/transform/ref-pointer/generated-shape.cjs.map +1 -0
- package/dist/application/transform/ref-pointer/generated-shape.mjs +162 -0
- package/dist/application/transform/ref-pointer/generated-shape.mjs.map +1 -0
- package/dist/application/transform/ref-pointer/inline-cycles.cjs +44 -0
- package/dist/application/transform/ref-pointer/inline-cycles.cjs.map +1 -0
- package/dist/application/transform/ref-pointer/inline-cycles.mjs +42 -0
- package/dist/application/transform/ref-pointer/inline-cycles.mjs.map +1 -0
- package/dist/application/transform/ref-pointer/original-index.cjs +62 -0
- package/dist/application/transform/ref-pointer/original-index.cjs.map +1 -0
- package/dist/application/transform/ref-pointer/original-index.mjs +60 -0
- package/dist/application/transform/ref-pointer/original-index.mjs.map +1 -0
- package/dist/application/transform/ref-pointer/pointer-type.cjs +60 -0
- package/dist/application/transform/ref-pointer/pointer-type.cjs.map +1 -0
- package/dist/application/transform/ref-pointer/pointer-type.mjs +57 -0
- package/dist/application/transform/ref-pointer/pointer-type.mjs.map +1 -0
- package/dist/application/transform/ref-pointer/pointer-walk.cjs +66 -0
- package/dist/application/transform/ref-pointer/pointer-walk.cjs.map +1 -0
- package/dist/application/transform/ref-pointer/pointer-walk.mjs +56 -0
- package/dist/application/transform/ref-pointer/pointer-walk.mjs.map +1 -0
- package/dist/application/transform/ref-pointer/typed-walk.cjs +124 -0
- package/dist/application/transform/ref-pointer/typed-walk.cjs.map +1 -0
- package/dist/application/transform/ref-pointer/typed-walk.mjs +122 -0
- package/dist/application/transform/ref-pointer/typed-walk.mjs.map +1 -0
- package/dist/application/transform/ref-type.cjs +7 -2
- package/dist/application/transform/ref-type.cjs.map +1 -1
- package/dist/application/transform/ref-type.mjs +3 -2
- package/dist/application/transform/ref-type.mjs.map +1 -1
- package/dist/application/transform/schema/access-flags.cjs +38 -0
- package/dist/application/transform/schema/access-flags.cjs.map +1 -0
- package/dist/application/transform/schema/access-flags.mjs +36 -0
- package/dist/application/transform/schema/access-flags.mjs.map +1 -0
- package/dist/application/transform/schema/array-type.cjs +32 -1
- package/dist/application/transform/schema/array-type.cjs.map +1 -1
- package/dist/application/transform/schema/array-type.mjs +33 -2
- package/dist/application/transform/schema/array-type.mjs.map +1 -1
- package/dist/application/transform/schema/composition-type.cjs +50 -15
- package/dist/application/transform/schema/composition-type.cjs.map +1 -1
- package/dist/application/transform/schema/composition-type.mjs +50 -15
- package/dist/application/transform/schema/composition-type.mjs.map +1 -1
- package/dist/application/transform/schema/core-type.cjs +3 -1
- package/dist/application/transform/schema/core-type.cjs.map +1 -1
- package/dist/application/transform/schema/core-type.mjs +3 -1
- package/dist/application/transform/schema/core-type.mjs.map +1 -1
- package/dist/application/transform/schema/discriminated-union.cjs +30 -0
- package/dist/application/transform/schema/discriminated-union.cjs.map +1 -0
- package/dist/application/transform/schema/discriminated-union.mjs +27 -0
- package/dist/application/transform/schema/discriminated-union.mjs.map +1 -0
- package/dist/application/transform/schema/discriminator-property.cjs +3 -2
- package/dist/application/transform/schema/discriminator-property.cjs.map +1 -1
- package/dist/application/transform/schema/discriminator-property.mjs +3 -2
- package/dist/application/transform/schema/discriminator-property.mjs.map +1 -1
- package/dist/application/transform/schema/enum-rule.cjs +66 -10
- package/dist/application/transform/schema/enum-rule.cjs.map +1 -1
- package/dist/application/transform/schema/enum-rule.mjs +67 -12
- package/dist/application/transform/schema/enum-rule.mjs.map +1 -1
- package/dist/application/transform/schema/inherited-discriminator.cjs +29 -0
- package/dist/application/transform/schema/inherited-discriminator.cjs.map +1 -0
- package/dist/application/transform/schema/inherited-discriminator.mjs +26 -0
- package/dist/application/transform/schema/inherited-discriminator.mjs.map +1 -0
- package/dist/application/transform/schema/object-type.cjs +38 -25
- package/dist/application/transform/schema/object-type.cjs.map +1 -1
- package/dist/application/transform/schema/object-type.mjs +39 -27
- package/dist/application/transform/schema/object-type.mjs.map +1 -1
- package/dist/application/transform/schema/required-variants.cjs +45 -0
- package/dist/application/transform/schema/required-variants.cjs.map +1 -0
- package/dist/application/transform/schema/required-variants.mjs +42 -0
- package/dist/application/transform/schema/required-variants.mjs.map +1 -0
- package/dist/application/transform/schema/schema-transform.cjs +2 -2
- package/dist/application/transform/schema/schema-transform.cjs.map +1 -1
- package/dist/application/transform/schema/schema-transform.mjs +2 -2
- package/dist/application/transform/schema/schema-transform.mjs.map +1 -1
- package/dist/application/transform/schema-comment.cjs +51 -5
- package/dist/application/transform/schema-comment.cjs.map +1 -1
- package/dist/application/transform/schema-comment.mjs +50 -6
- package/dist/application/transform/schema-comment.mjs.map +1 -1
- package/dist/application/transform/type-combinators.mjs +1 -1
- package/dist/cli/cli-arguments.cjs +11 -3
- package/dist/cli/cli-arguments.cjs.map +1 -1
- package/dist/cli/cli-arguments.mjs +11 -3
- package/dist/cli/cli-arguments.mjs.map +1 -1
- package/dist/cli/cli-errors.cjs +3 -2
- package/dist/cli/cli-errors.cjs.map +1 -1
- package/dist/cli/cli-errors.mjs +3 -2
- package/dist/cli/cli-errors.mjs.map +1 -1
- package/dist/cli/cli-output.cjs +8 -3
- package/dist/cli/cli-output.cjs.map +1 -1
- package/dist/cli/cli-output.mjs +9 -4
- package/dist/cli/cli-output.mjs.map +1 -1
- package/dist/cli/main.cjs +5 -0
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.mjs +5 -0
- package/dist/cli/main.mjs.map +1 -1
- package/dist/cli/redocly-apis.cjs +7 -3
- package/dist/cli/redocly-apis.cjs.map +1 -1
- package/dist/cli/redocly-apis.mjs +8 -4
- package/dist/cli/redocly-apis.mjs.map +1 -1
- package/dist/cli/ref-limits.cjs +1 -1
- package/dist/cli/ref-limits.cjs.map +1 -1
- package/dist/cli/ref-limits.mjs +2 -2
- package/dist/cli/ref-limits.mjs.map +1 -1
- package/dist/cli/run-cli.cjs +15 -2
- package/dist/cli/run-cli.cjs.map +1 -1
- package/dist/cli/run-cli.mjs +16 -3
- package/dist/cli/run-cli.mjs.map +1 -1
- package/dist/domain/errors.cjs +2 -0
- package/dist/domain/errors.cjs.map +1 -1
- package/dist/domain/errors.mjs +2 -0
- package/dist/domain/errors.mjs.map +1 -1
- package/dist/domain/ir/constructors.cjs +5 -1
- package/dist/domain/ir/constructors.cjs.map +1 -1
- package/dist/domain/ir/constructors.mjs +5 -2
- package/dist/domain/ir/constructors.mjs.map +1 -1
- package/dist/domain/openapi/admitted-values.cjs +75 -0
- package/dist/domain/openapi/admitted-values.cjs.map +1 -0
- package/dist/domain/openapi/admitted-values.mjs +72 -0
- package/dist/domain/openapi/admitted-values.mjs.map +1 -0
- package/dist/domain/openapi/discriminated-union.cjs +68 -0
- package/dist/domain/openapi/discriminated-union.cjs.map +1 -0
- package/dist/domain/openapi/discriminated-union.mjs +62 -0
- package/dist/domain/openapi/discriminated-union.mjs.map +1 -0
- package/dist/domain/openapi/discriminator-conflicts.cjs +143 -0
- package/dist/domain/openapi/discriminator-conflicts.cjs.map +1 -0
- package/dist/domain/openapi/discriminator-conflicts.mjs +141 -0
- package/dist/domain/openapi/discriminator-conflicts.mjs.map +1 -0
- package/dist/domain/openapi/parameter-object.cjs.map +1 -1
- package/dist/domain/openapi/parameter-object.mjs.map +1 -1
- package/dist/domain/openapi/path-templates.cjs +23 -0
- package/dist/domain/openapi/path-templates.cjs.map +1 -0
- package/dist/domain/openapi/path-templates.mjs +21 -0
- package/dist/domain/openapi/path-templates.mjs.map +1 -0
- package/dist/domain/output-fixes.cjs +36 -1
- package/dist/domain/output-fixes.cjs.map +1 -1
- package/dist/domain/output-fixes.mjs +36 -1
- package/dist/domain/output-fixes.mjs.map +1 -1
- package/dist/domain/warnings.cjs +15 -0
- package/dist/domain/warnings.cjs.map +1 -0
- package/dist/domain/warnings.mjs +12 -0
- package/dist/domain/warnings.mjs.map +1 -0
- package/dist/index.d.cts +29 -0
- package/dist/index.d.mts +29 -0
- package/dist/index.d.ts +29 -0
- package/dist/transform/components-object.cjs +2 -1
- package/dist/transform/components-object.cjs.map +1 -1
- package/dist/transform/components-object.mjs +2 -1
- package/dist/transform/components-object.mjs.map +1 -1
- package/package.json +1 -1
- package/src/adapters/redocly-loader/redocly-config-source.ts +41 -6
- package/src/adapters/redocly-loader/redocly-schema-loader.ts +22 -6
- package/src/adapters/type-ast-bridge/ir-to-typescript.ts +3 -0
- package/src/adapters/type-ast-bridge/typescript-to-ir.ts +26 -12
- package/src/api/discriminator-conflict-warnings.ts +43 -0
- package/src/api/discriminator-enum-names.ts +26 -0
- package/src/api/discriminator-enum-parent.ts +129 -0
- package/src/api/discriminator-enum.ts +39 -0
- package/src/api/discriminator-other-owners.ts +97 -0
- package/src/api/discriminator-patch.ts +147 -0
- package/src/api/discriminator-scan.ts +78 -90
- package/src/api/document-run.ts +24 -6
- package/src/api/enum-values-warnings.ts +21 -0
- package/src/api/path-template-warnings.ts +27 -0
- package/src/api/transform-context.ts +7 -1
- package/src/api/transform-schema.ts +88 -4
- package/src/api/unsupported-feature-warnings.ts +8 -1
- package/src/application/ports/redocly-config-source.ts +5 -1
- package/src/application/print/type-printer.ts +6 -0
- package/src/application/transform/document/assignability.ts +203 -0
- package/src/application/transform/document/components.ts +6 -6
- package/src/application/transform/document/declared-types.ts +93 -0
- package/src/application/transform/document/document.ts +71 -13
- package/src/application/transform/document/exploded-query.ts +91 -0
- package/src/application/transform/document/global-type-references.ts +78 -0
- package/src/application/transform/document/list-assignability.ts +87 -0
- package/src/application/transform/document/parameters.ts +76 -11
- package/src/application/transform/document/path-key-overlaps.ts +148 -59
- package/src/application/transform/document/path-template-replace.ts +90 -0
- package/src/application/transform/document/paths.ts +99 -37
- package/src/application/transform/document/root-type-aliases.ts +29 -28
- package/src/application/transform/document/template-key-match.ts +183 -0
- package/src/application/transform/document/type-assignability.ts +268 -0
- package/src/application/transform/document/type-key.ts +80 -0
- package/src/application/transform/document/type-resolution.ts +163 -0
- package/src/application/transform/footer/document-footer.ts +91 -6
- package/src/application/transform/footer/enum-naming.ts +29 -0
- package/src/application/transform/footer/enum-values-check.ts +171 -0
- package/src/application/transform/footer/evaluation.ts +47 -0
- package/src/application/transform/footer/shared-enum-names.ts +86 -0
- package/src/application/transform/footer/type-evaluation.ts +294 -0
- package/src/application/transform/footer/type-rules.ts +269 -0
- package/src/application/transform/ref-pointer/generated-location.ts +211 -0
- package/src/application/transform/ref-pointer/generated-shape.ts +275 -0
- package/src/application/transform/ref-pointer/inline-cycles.ts +56 -0
- package/src/application/transform/ref-pointer/original-index.ts +95 -0
- package/src/application/transform/ref-pointer/pointer-type.ts +92 -0
- package/src/application/transform/ref-pointer/pointer-walk.ts +96 -0
- package/src/application/transform/ref-pointer/typed-walk.ts +192 -0
- package/src/application/transform/ref-type.ts +11 -6
- package/src/application/transform/schema/access-flags.ts +63 -0
- package/src/application/transform/schema/array-type.ts +66 -5
- package/src/application/transform/schema/composition-type.ts +96 -24
- package/src/application/transform/schema/core-type.ts +8 -4
- package/src/application/transform/schema/discriminated-union.ts +58 -0
- package/src/application/transform/schema/discriminator-property.ts +8 -3
- package/src/application/transform/schema/enum-rule.ts +136 -13
- package/src/application/transform/schema/inherited-discriminator.ts +54 -0
- package/src/application/transform/schema/object-type.ts +51 -33
- package/src/application/transform/schema/required-variants.ts +88 -0
- package/src/application/transform/schema/schema-context.ts +26 -0
- package/src/application/transform/schema/schema-transform.ts +2 -2
- package/src/application/transform/schema-comment.ts +84 -4
- package/src/cli/cli-arguments.ts +13 -3
- package/src/cli/cli-dependencies.ts +5 -0
- package/src/cli/cli-errors.ts +4 -2
- package/src/cli/cli-output.ts +18 -4
- package/src/cli/main.ts +6 -0
- package/src/cli/redocly-apis.ts +8 -4
- package/src/cli/ref-limits.ts +2 -2
- package/src/cli/run-cli.ts +20 -3
- package/src/domain/errors.ts +2 -0
- package/src/domain/ir/constructors.ts +6 -1
- package/src/domain/ir/nodes.ts +2 -1
- package/src/domain/openapi/admitted-values.ts +113 -0
- package/src/domain/openapi/discriminated-union.ts +109 -0
- package/src/domain/openapi/discriminator-conflicts.ts +251 -0
- package/src/domain/openapi/parameter-object.ts +4 -0
- package/src/domain/openapi/path-templates.ts +31 -0
- package/src/domain/openapi/schema-object.ts +2 -0
- package/src/domain/output-fixes.ts +43 -2
- package/src/domain/warnings.ts +20 -0
- package/src/transform/components-object.ts +3 -1
- package/src/types/generator-options.ts +11 -0
- package/dist/application/transform/document/path-item-conflicts.cjs +0 -51
- package/dist/application/transform/document/path-item-conflicts.cjs.map +0 -1
- package/dist/application/transform/document/path-item-conflicts.mjs +0 -49
- package/dist/application/transform/document/path-item-conflicts.mjs.map +0 -1
- package/src/application/transform/document/path-item-conflicts.ts +0 -79
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { irIndexedAccess, irKeyword, irReference } from "../../../domain/ir/constructors.js";
|
|
2
|
+
import type { IrKeyword, IrType } from "../../../domain/ir/nodes.js";
|
|
3
|
+
import { indexBy, indexKeyword, rootType } from "../ref-type.js";
|
|
4
|
+
import type { RefResolver, SchemaOptions } from "../schema/schema-context.js";
|
|
5
|
+
import {
|
|
6
|
+
followRefs,
|
|
7
|
+
isArrayShape,
|
|
8
|
+
isJsonObject,
|
|
9
|
+
isObjectShape,
|
|
10
|
+
type Presence,
|
|
11
|
+
propertyPresence,
|
|
12
|
+
schemaPresence,
|
|
13
|
+
} from "./generated-shape.js";
|
|
14
|
+
import {
|
|
15
|
+
isOptionalHeader,
|
|
16
|
+
isOptionalRequestBody,
|
|
17
|
+
isParameterList,
|
|
18
|
+
isTypedAsSchema,
|
|
19
|
+
leadingNode,
|
|
20
|
+
leadingSegmentsOf,
|
|
21
|
+
type RefPointer,
|
|
22
|
+
startsInSchema,
|
|
23
|
+
} from "./pointer-walk.js";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The type of a `$ref` pointer as the generated types have it: the `schema` of a media type,
|
|
27
|
+
* header or component parameter is its type, `items` is indexed by `number`,
|
|
28
|
+
* `additionalProperties` by `string`, and a value that may be `undefined` or `null` is wrapped in
|
|
29
|
+
* `NonNullable` before it is indexed. The walk stops at a segment with no type of its own
|
|
30
|
+
* (`allOf/0`, `definitions/A`, operation `parameters/0`): the caller types the target itself.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
const DEFS_KEYWORD = "$defs";
|
|
34
|
+
|
|
35
|
+
export interface TypedWalk {
|
|
36
|
+
readonly type: IrType;
|
|
37
|
+
/** The document node the type stands for (not followed through a `$ref`). */
|
|
38
|
+
readonly node: unknown;
|
|
39
|
+
readonly isSchema: boolean;
|
|
40
|
+
/** The segment is a property or `$defs` name, not a keyword. */
|
|
41
|
+
readonly isName: boolean;
|
|
42
|
+
readonly presence: Presence;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface TypedWalkInput {
|
|
46
|
+
readonly pointer: RefPointer;
|
|
47
|
+
readonly options: SchemaOptions;
|
|
48
|
+
readonly refs: RefResolver;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** The walk result: a type, or the index of the first segment that has no type. */
|
|
52
|
+
export type TypedWalkResult =
|
|
53
|
+
| { readonly kind: "typed"; readonly walk: TypedWalk }
|
|
54
|
+
| { readonly kind: "untyped"; readonly index: number };
|
|
55
|
+
|
|
56
|
+
function present(walk: TypedWalk): IrType {
|
|
57
|
+
return walk.presence === "present" ? walk.type : irReference("NonNullable", [walk.type]);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function indexEntries(walk: TypedWalk, key: IrKeyword, keyword: string, refs: RefResolver) {
|
|
61
|
+
const owner = followRefs(walk.node, refs);
|
|
62
|
+
const child = isJsonObject(owner) ? owner[keyword] : undefined;
|
|
63
|
+
return {
|
|
64
|
+
...walk,
|
|
65
|
+
type: irIndexedAccess(present(walk), irKeyword(key)),
|
|
66
|
+
node: child,
|
|
67
|
+
presence: schemaPresence(child, refs),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function nameStep(walk: TypedWalk, name: string, isLast: boolean, input: TypedWalkInput) {
|
|
72
|
+
const owner = followRefs(walk.node, input.refs);
|
|
73
|
+
const properties = isJsonObject(owner) && isJsonObject(owner.properties) ? owner.properties : {};
|
|
74
|
+
const type =
|
|
75
|
+
walk.presence === "present"
|
|
76
|
+
? indexKeyword(walk.type, name, isLast)
|
|
77
|
+
: indexBy(present(walk), name);
|
|
78
|
+
return {
|
|
79
|
+
...walk,
|
|
80
|
+
type,
|
|
81
|
+
node: properties[name],
|
|
82
|
+
isName: false,
|
|
83
|
+
presence: propertyPresence(walk.node, name, input.options, input.refs),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** `$defs` is optional (`NonNullable` when more follows); its members are present. */
|
|
88
|
+
function defsStep(walk: TypedWalk, owner: unknown, isLast: boolean): TypedWalk {
|
|
89
|
+
const defs = isJsonObject(owner) && isJsonObject(owner[DEFS_KEYWORD]) ? owner[DEFS_KEYWORD] : {};
|
|
90
|
+
return {
|
|
91
|
+
...walk,
|
|
92
|
+
type: indexKeyword(present(walk), DEFS_KEYWORD, isLast),
|
|
93
|
+
node: { properties: defs, required: Object.keys(defs) },
|
|
94
|
+
isName: true,
|
|
95
|
+
presence: "present",
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const SHAPED_KEYWORDS: ReadonlySet<string> = new Set([
|
|
100
|
+
"properties",
|
|
101
|
+
"items",
|
|
102
|
+
"additionalProperties",
|
|
103
|
+
]);
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Whether the keyword gives the owner's generated type a member: `items` only an array,
|
|
107
|
+
* `properties` and `additionalProperties` only an object (`type: string` ignores them). A node
|
|
108
|
+
* that is not in the document is indexed as the keyword says.
|
|
109
|
+
*/
|
|
110
|
+
function hasKeywordMember(owner: unknown, segment: string): boolean {
|
|
111
|
+
if (!SHAPED_KEYWORDS.has(segment) || !isJsonObject(owner)) {
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
return segment === "items" ? isArrayShape(owner) : isObjectShape(owner);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function keywordStep(walk: TypedWalk, segment: string, isLast: boolean, input: TypedWalkInput) {
|
|
118
|
+
const owner = followRefs(walk.node, input.refs);
|
|
119
|
+
if (!hasKeywordMember(owner, segment)) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
switch (segment) {
|
|
123
|
+
case "properties":
|
|
124
|
+
return { ...walk, isName: true };
|
|
125
|
+
case "items":
|
|
126
|
+
return indexEntries(walk, "number", "items", input.refs);
|
|
127
|
+
case "additionalProperties":
|
|
128
|
+
return indexEntries(walk, "string", "additionalProperties", input.refs);
|
|
129
|
+
case DEFS_KEYWORD:
|
|
130
|
+
return defsStep(walk, owner, isLast);
|
|
131
|
+
default:
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function containerStep(walk: TypedWalk, index: number, input: TypedWalkInput): TypedWalk {
|
|
137
|
+
const segment = input.pointer.segments[index] as string;
|
|
138
|
+
const owner = followRefs(walk.node, input.refs);
|
|
139
|
+
const isOptional =
|
|
140
|
+
(segment === "requestBody" && isOptionalRequestBody(owner, input.refs)) ||
|
|
141
|
+
isOptionalHeader(input.pointer, index, owner);
|
|
142
|
+
return {
|
|
143
|
+
...walk,
|
|
144
|
+
type: indexBy(present(walk), segment),
|
|
145
|
+
node: isJsonObject(owner) ? owner[segment] : undefined,
|
|
146
|
+
presence: isOptional ? "absent" : "present",
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function step(walk: TypedWalk, index: number, input: TypedWalkInput): TypedWalk | null {
|
|
151
|
+
const { segments } = input.pointer;
|
|
152
|
+
const segment = segments[index] as string;
|
|
153
|
+
const isLast = index === segments.length - 1;
|
|
154
|
+
if (walk.isSchema) {
|
|
155
|
+
return walk.isName
|
|
156
|
+
? nameStep(walk, segment, isLast, input)
|
|
157
|
+
: keywordStep(walk, segment, isLast, input);
|
|
158
|
+
}
|
|
159
|
+
if (segment === "schema" && isTypedAsSchema(input.pointer, index)) {
|
|
160
|
+
const owner = followRefs(walk.node, input.refs);
|
|
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 };
|
|
165
|
+
}
|
|
166
|
+
return isParameterList(input.pointer, index) ? null : containerStep(walk, index, input);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Walk the whole pointer; see the module comment. */
|
|
170
|
+
export function typedWalk(input: TypedWalkInput): TypedWalkResult {
|
|
171
|
+
const { pointer } = input;
|
|
172
|
+
const node = leadingNode(pointer, input.refs);
|
|
173
|
+
const isSchema = startsInSchema(pointer);
|
|
174
|
+
let walk: TypedWalk = {
|
|
175
|
+
type: indexBy(
|
|
176
|
+
rootType(pointer.rootSegment, false),
|
|
177
|
+
...pointer.segments.slice(0, leadingSegmentsOf(pointer)),
|
|
178
|
+
),
|
|
179
|
+
node,
|
|
180
|
+
isSchema,
|
|
181
|
+
isName: false,
|
|
182
|
+
presence: isSchema ? schemaPresence(node, input.refs) : "present",
|
|
183
|
+
};
|
|
184
|
+
for (let index = leadingSegmentsOf(pointer); index < pointer.segments.length; index++) {
|
|
185
|
+
const next = step(walk, index, input);
|
|
186
|
+
if (next === null) {
|
|
187
|
+
return { kind: "untyped", index };
|
|
188
|
+
}
|
|
189
|
+
walk = next;
|
|
190
|
+
}
|
|
191
|
+
return { kind: "typed", walk };
|
|
192
|
+
}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
irString,
|
|
9
9
|
} from "../../domain/ir/constructors.js";
|
|
10
10
|
import type { IrType } from "../../domain/ir/nodes.js";
|
|
11
|
+
import { toPropertyName } from "../../domain/ir/property-name.js";
|
|
11
12
|
import { parseRefPointer } from "../../domain/openapi/json-pointer.js";
|
|
12
13
|
|
|
13
14
|
/** Where a referenced parameter lives in the generated `parameters` type. */
|
|
@@ -37,16 +38,20 @@ export class InvalidRefError extends OpenAPITypesafeError {
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
/** Segments that index into the root type, always as escaped string literal types. */
|
|
40
|
-
function indexBy(type: IrType, ...segments: readonly string[]): IrType {
|
|
41
|
+
export function indexBy(type: IrType, ...segments: readonly string[]): IrType {
|
|
41
42
|
return segments.reduce<IrType>(
|
|
42
43
|
(object, segment) => irIndexedAccess(object, irString(segment, "escaped")),
|
|
43
44
|
type,
|
|
44
45
|
);
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
/**
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
/**
|
|
49
|
+
* `Extract<T, { name: unknown }>`. The original wrote the name as an identifier even when it is
|
|
50
|
+
* not one (`{ content-type: unknown }`), which is a syntax error; it is now quoted like any other
|
|
51
|
+
* property name, and an identifier stays as it was.
|
|
52
|
+
*/
|
|
53
|
+
export function extractVariantsWith(type: IrType, propertyName: string): IrType {
|
|
54
|
+
const probe = irProperty(toPropertyName(propertyName), irKeyword("unknown"));
|
|
50
55
|
return irReference("Extract", [type, irObject([probe])]);
|
|
51
56
|
}
|
|
52
57
|
|
|
@@ -57,12 +62,12 @@ const DEFS_KEYWORD = "$defs";
|
|
|
57
62
|
* segments follow it is wrapped in `NonNullable<…>` first; otherwise the next index fails on
|
|
58
63
|
* `undefined` (upstream #2664).
|
|
59
64
|
*/
|
|
60
|
-
function indexKeyword(type: IrType, segment: string, isLast: boolean): IrType {
|
|
65
|
+
export function indexKeyword(type: IrType, segment: string, isLast: boolean): IrType {
|
|
61
66
|
const indexed = indexBy(type, segment);
|
|
62
67
|
return segment === DEFS_KEYWORD && !isLast ? irReference("NonNullable", [indexed]) : indexed;
|
|
63
68
|
}
|
|
64
69
|
|
|
65
|
-
function rootType(rootSegment: string, isDeep: boolean): IrType {
|
|
70
|
+
export function rootType(rootSegment: string, isDeep: boolean): IrType {
|
|
66
71
|
return irReference(isDeep ? `FlattenedDeepRequired<${rootSegment}>` : rootSegment);
|
|
67
72
|
}
|
|
68
73
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { Schema, SchemaObject } from "../../../domain/openapi/schema-object.js";
|
|
2
|
+
import { OutputFix } from "../../../domain/output-fixes.js";
|
|
3
|
+
import type { SchemaContext } from "./schema-context.js";
|
|
4
|
+
|
|
5
|
+
/** Whether a property is `readOnly` or `writeOnly` (JSON Schema 2020-12 Validation §9.4). */
|
|
6
|
+
export interface AccessFlags {
|
|
7
|
+
readonly isReadOnly: boolean;
|
|
8
|
+
readonly isWriteOnly: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const NO_FLAGS: AccessFlags = { isReadOnly: false, isWriteOnly: false };
|
|
12
|
+
|
|
13
|
+
function ownFlags(schema: SchemaObject): AccessFlags {
|
|
14
|
+
return { isReadOnly: Boolean(schema.readOnly), isWriteOnly: Boolean(schema.writeOnly) };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function merged(left: AccessFlags, right: AccessFlags): AccessFlags {
|
|
18
|
+
return {
|
|
19
|
+
isReadOnly: left.isReadOnly || right.isReadOnly,
|
|
20
|
+
isWriteOnly: left.isWriteOnly || right.isWriteOnly,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The flags of a schema and of the schemas that always apply to the same value: the one its
|
|
26
|
+
* `$ref` names and its `allOf` members, followed until a schema repeats. `readOnly` is an
|
|
27
|
+
* annotation, and the annotations of those schemas are the value's (2020-12 Core §7.7.1); in
|
|
28
|
+
* OpenAPI 3.0 a referenced schema is the property's definition. `anyOf` and `oneOf` members apply
|
|
29
|
+
* only when they match, which the type cannot tell, so they are not read.
|
|
30
|
+
*/
|
|
31
|
+
function appliedFlags(
|
|
32
|
+
schema: Schema | undefined,
|
|
33
|
+
context: SchemaContext,
|
|
34
|
+
seen: ReadonlySet<Schema>,
|
|
35
|
+
): AccessFlags {
|
|
36
|
+
if (typeof schema !== "object" || schema === null || seen.has(schema)) {
|
|
37
|
+
return NO_FLAGS;
|
|
38
|
+
}
|
|
39
|
+
const inner = new Set([...seen, schema]);
|
|
40
|
+
// `readOnly` next to a `$ref` is read too, as the generator always has.
|
|
41
|
+
const object = schema as SchemaObject & { readonly $ref?: unknown };
|
|
42
|
+
const target =
|
|
43
|
+
typeof object.$ref === "string" ? (context.refs.resolve(object.$ref) as Schema) : undefined;
|
|
44
|
+
return (object.allOf ?? []).reduce<AccessFlags>(
|
|
45
|
+
(flags, member) => merged(flags, appliedFlags(member, context, inner)),
|
|
46
|
+
merged(ownFlags(object), appliedFlags(target, context, inner)),
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The flags of a property schema. Without the `read-write-refs` fix only the keywords written on
|
|
52
|
+
* it count, as in openapi-typescript; with it, also those of the schemas its `$ref` and `allOf`
|
|
53
|
+
* apply (upstream #1938).
|
|
54
|
+
*/
|
|
55
|
+
export function propertyAccessFlags(value: Schema, context: SchemaContext): AccessFlags {
|
|
56
|
+
if (typeof value !== "object") {
|
|
57
|
+
return NO_FLAGS;
|
|
58
|
+
}
|
|
59
|
+
if (!context.options.fixes.has(OutputFix.READ_WRITE_REFS)) {
|
|
60
|
+
return ownFlags(value as SchemaObject);
|
|
61
|
+
}
|
|
62
|
+
return appliedFlags(value, context, new Set());
|
|
63
|
+
}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
irArray,
|
|
3
|
+
irOptionalTupleElement,
|
|
4
|
+
irReadonly,
|
|
5
|
+
irTuple,
|
|
6
|
+
irTupleElement,
|
|
7
|
+
} from "../../../domain/ir/constructors.js";
|
|
8
|
+
import type { IrTupleElement, IrType } from "../../../domain/ir/nodes.js";
|
|
9
|
+
import type { Schema, SchemaObject } from "../../../domain/openapi/schema-object.js";
|
|
4
10
|
import { OutputFix } from "../../../domain/output-fixes.js";
|
|
5
11
|
import { UNKNOWN_TYPE } from "../shared-types.js";
|
|
6
12
|
import { unionOf } from "../type-combinators.js";
|
|
@@ -12,9 +18,15 @@ import type { SchemaRequest } from "./schema-rule.js";
|
|
|
12
18
|
*/
|
|
13
19
|
const MAX_LENGTH_TUPLE_ELEMENTS = 30;
|
|
14
20
|
|
|
15
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* The tuple of `prefixItems` (or of an `items` list); null without either. The original closes a
|
|
23
|
+
* `prefixItems` tuple and requires every element; the `prefix-items` fix does not.
|
|
24
|
+
*/
|
|
16
25
|
function prefixTupleType(schema: SchemaObject, request: SchemaRequest): IrType | null {
|
|
17
26
|
const { items } = schema;
|
|
27
|
+
if (schema.prefixItems && isPrefixItemsFixed(schema, request)) {
|
|
28
|
+
return prefixItemsTupleType(schema.prefixItems, schema, request);
|
|
29
|
+
}
|
|
18
30
|
if (!schema.prefixItems && !Array.isArray(items)) {
|
|
19
31
|
return null;
|
|
20
32
|
}
|
|
@@ -24,6 +36,54 @@ function prefixTupleType(schema: SchemaObject, request: SchemaRequest): IrType |
|
|
|
24
36
|
);
|
|
25
37
|
}
|
|
26
38
|
|
|
39
|
+
/** The type of the items after the prefix, or null when there may be none (`false`). */
|
|
40
|
+
function restItemType(schema: Schema, request: SchemaRequest): IrType | null {
|
|
41
|
+
return schema === false ? null : request.transformNested(schema, request.location);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The type of the items after a `prefixItems` tuple (JSON Schema 2020-12 §10.3.1): `items`, else
|
|
46
|
+
* `unevaluatedItems`, which does not apply to the items `contains` matches, else any item. Null
|
|
47
|
+
* when no item may follow. An `items` list is not a schema in 2020-12, so it allows any item.
|
|
48
|
+
*/
|
|
49
|
+
function prefixRestType(schema: SchemaObject, request: SchemaRequest): IrType | null {
|
|
50
|
+
const { items, unevaluatedItems, contains } = schema;
|
|
51
|
+
if (items !== undefined && !Array.isArray(items)) {
|
|
52
|
+
return restItemType(items as Schema, request);
|
|
53
|
+
}
|
|
54
|
+
if (unevaluatedItems === undefined || items !== undefined) {
|
|
55
|
+
return UNKNOWN_TYPE;
|
|
56
|
+
}
|
|
57
|
+
const unevaluated = restItemType(unevaluatedItems, request);
|
|
58
|
+
const matched = contains === undefined ? null : restItemType(contains, request);
|
|
59
|
+
const types = [unevaluated, matched].filter((type): type is IrType => type !== null);
|
|
60
|
+
return types.length === 0 ? null : unionOf(types);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The `prefix-items` tuple of `prefixItems`: an array may end before the prefix does, so the
|
|
65
|
+
* elements from `minItems` on are optional (`T?`), and a rest element types the items after it.
|
|
66
|
+
*/
|
|
67
|
+
function prefixItemsTupleType(
|
|
68
|
+
prefixItems: readonly Schema[],
|
|
69
|
+
schema: SchemaObject,
|
|
70
|
+
request: SchemaRequest,
|
|
71
|
+
): IrType {
|
|
72
|
+
const { min } = lengthBounds(schema);
|
|
73
|
+
const elements = prefixItems.map((item, index): IrTupleElement => {
|
|
74
|
+
const type = request.transformNested(item, request.location);
|
|
75
|
+
return index < min ? irTupleElement(type) : irOptionalTupleElement(type);
|
|
76
|
+
});
|
|
77
|
+
const rest = prefixRestType(schema, request);
|
|
78
|
+
return irTuple(rest === null ? elements : [...elements, irTupleElement(irArray(rest), true)]);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function isPrefixItemsFixed(schema: SchemaObject, request: SchemaRequest): boolean {
|
|
82
|
+
return (
|
|
83
|
+
schema.prefixItems !== undefined && request.context.options.fixes.has(OutputFix.PREFIX_ITEMS)
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
27
87
|
/** The type of one item; `unknown` without `items`. */
|
|
28
88
|
function singleItemType(schema: SchemaObject, request: SchemaRequest): IrType {
|
|
29
89
|
const { items } = schema;
|
|
@@ -143,7 +203,8 @@ export function arrayType(schema: SchemaObject, request: SchemaRequest): IrType
|
|
|
143
203
|
}
|
|
144
204
|
const item = itemType(schema, request);
|
|
145
205
|
const bounds = lengthBounds(schema);
|
|
146
|
-
|
|
206
|
+
// A `prefix-items` tuple has its own lengths, so `--array-length` adds no tuples around it.
|
|
207
|
+
if (!isPrefixItemsFixed(schema, request) && isLengthTupleWanted(bounds, request)) {
|
|
147
208
|
return lengthTupleType(schema, item, bounds);
|
|
148
209
|
}
|
|
149
210
|
// A tuple or an array item is used as the array type itself.
|
|
@@ -3,6 +3,7 @@ import type { IrType } from "../../../domain/ir/nodes.js";
|
|
|
3
3
|
import { createRef } from "../../../domain/openapi/json-pointer.js";
|
|
4
4
|
import type { Schema, SchemaObject } from "../../../domain/openapi/schema-object.js";
|
|
5
5
|
import { OutputFix } from "../../../domain/output-fixes.js";
|
|
6
|
+
import { requirableRefType } from "../ref-pointer/pointer-type.js";
|
|
6
7
|
import { UNKNOWN_TYPE } from "../shared-types.js";
|
|
7
8
|
import {
|
|
8
9
|
intersectionOf,
|
|
@@ -13,7 +14,9 @@ import {
|
|
|
13
14
|
withRequiredKeys,
|
|
14
15
|
} from "../type-combinators.js";
|
|
15
16
|
import { coreType } from "./core-type.js";
|
|
17
|
+
import { unionItemOf, unionOwnKeywords } from "./discriminated-union.js";
|
|
16
18
|
import { allOfMembers } from "./presence-members.js";
|
|
19
|
+
import { requiredVariantsType } from "./required-variants.js";
|
|
17
20
|
import type { SchemaRequest } from "./schema-rule.js";
|
|
18
21
|
import { unevaluatedPropertiesType } from "./unevaluated-properties.js";
|
|
19
22
|
|
|
@@ -39,6 +42,28 @@ function isRefItem(item: Schema): item is { readonly $ref: string } {
|
|
|
39
42
|
return "$ref" in (item as object);
|
|
40
43
|
}
|
|
41
44
|
|
|
45
|
+
/**
|
|
46
|
+
* The parent's `required` keys that the target at `ref` defines. A target that the discriminator
|
|
47
|
+
* scan gave its property got none: the scan made that property required, but the other keys were
|
|
48
|
+
* lost too. With `discriminator-member-required` only keys the target requires already are left
|
|
49
|
+
* out (#2162).
|
|
50
|
+
*/
|
|
51
|
+
function keysToRequire(
|
|
52
|
+
ref: string,
|
|
53
|
+
target: SchemaObject,
|
|
54
|
+
required: readonly string[],
|
|
55
|
+
request: SchemaRequest,
|
|
56
|
+
): readonly string[] {
|
|
57
|
+
const defined = required.filter((key) => Boolean(target.properties?.[key]));
|
|
58
|
+
if (!request.context.discriminators.isHandled(ref)) {
|
|
59
|
+
return defined;
|
|
60
|
+
}
|
|
61
|
+
if (!request.context.options.fixes.has(OutputFix.DISCRIMINATOR_MEMBER_REQUIRED)) {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
return defined.filter((key) => !target.required?.includes(key));
|
|
65
|
+
}
|
|
66
|
+
|
|
42
67
|
/** A `$ref` item gets the parent's `required` keys that its target defines (`WithRequired`). */
|
|
43
68
|
function refItemType(
|
|
44
69
|
item: { readonly $ref: string },
|
|
@@ -46,21 +71,16 @@ function refItemType(
|
|
|
46
71
|
request: SchemaRequest,
|
|
47
72
|
): IrType {
|
|
48
73
|
const type = request.transformNested(item, request.location);
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
const isEligible =
|
|
52
|
-
resolved &&
|
|
53
|
-
typeof resolved === "object" &&
|
|
54
|
-
"properties" in resolved &&
|
|
55
|
-
!discriminators.isHandled(item.$ref);
|
|
56
|
-
if (!isEligible) {
|
|
74
|
+
const resolved = request.context.refs.resolve(item.$ref) as SchemaObject | undefined;
|
|
75
|
+
if (!resolved || typeof resolved !== "object" || !("properties" in resolved)) {
|
|
57
76
|
return type;
|
|
58
77
|
}
|
|
59
|
-
const keys =
|
|
60
|
-
if (keys.length
|
|
61
|
-
|
|
78
|
+
const keys = keysToRequire(item.$ref, resolved, required, request);
|
|
79
|
+
if (keys.length === 0) {
|
|
80
|
+
return type;
|
|
62
81
|
}
|
|
63
|
-
|
|
82
|
+
request.context.footer.requireWithRequired();
|
|
83
|
+
return withRequiredKeys(requirableRefType(item.$ref, type, request), keys);
|
|
64
84
|
}
|
|
65
85
|
|
|
66
86
|
/** An inline item merges the parent's `required` keys with its own. */
|
|
@@ -75,22 +95,59 @@ function inlineItemType(item: Schema, required: readonly string[], request: Sche
|
|
|
75
95
|
);
|
|
76
96
|
}
|
|
77
97
|
|
|
78
|
-
/**
|
|
98
|
+
/**
|
|
99
|
+
* The union's own keywords at the union's location, so nested names (enums) stay the union's.
|
|
100
|
+
* Null when the union has none.
|
|
101
|
+
*/
|
|
102
|
+
function ownKeywordsType(own: SchemaObject, ref: string, request: SchemaRequest): IrType | null {
|
|
103
|
+
return combinedType(own, { ...request, location: { ...request.location, path: ref } });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* An `allOf` item; one with a discriminator omits that property (the parent redefines it). A
|
|
108
|
+
* `$ref` to a discriminated union is not such a parent: for a member of the union it is the
|
|
109
|
+
* union's own keywords, since the union contains the member (#1665); with
|
|
110
|
+
* `allof-discriminated-union` it is the union, since `Omit` on a union drops keys (#1464), unless
|
|
111
|
+
* the union's mapping names the schema: then it is a member, as the discriminator scan has it.
|
|
112
|
+
*/
|
|
113
|
+
function allOfItemType(
|
|
114
|
+
item: Schema,
|
|
115
|
+
required: readonly string[],
|
|
116
|
+
request: SchemaRequest,
|
|
117
|
+
): IrType | null {
|
|
118
|
+
const isRef = isRefItem(item);
|
|
119
|
+
const discriminator =
|
|
120
|
+
(isRef && request.context.discriminators.objectAt(item.$ref)) ||
|
|
121
|
+
(item as SchemaObject).discriminator;
|
|
122
|
+
const propertyName = discriminator?.propertyName;
|
|
123
|
+
const unionItem = isRef && propertyName ? unionItemOf(item.$ref, request) : undefined;
|
|
124
|
+
if (isRef && propertyName && unionItem?.isMember) {
|
|
125
|
+
const own = unionOwnKeywords(unionItem.union, propertyName, required);
|
|
126
|
+
return ownKeywordsType(own, item.$ref, request);
|
|
127
|
+
}
|
|
128
|
+
const type = isRef
|
|
129
|
+
? refItemType(item, required, request)
|
|
130
|
+
: inlineItemType(item, required, request);
|
|
131
|
+
const isUnion =
|
|
132
|
+
unionItem !== undefined &&
|
|
133
|
+
!unionItem.isMapped &&
|
|
134
|
+
request.context.options.fixes.has(OutputFix.ALLOF_DISCRIMINATED_UNION);
|
|
135
|
+
if (!propertyName || isUnion) {
|
|
136
|
+
return type;
|
|
137
|
+
}
|
|
138
|
+
// With `discriminator-values` the schema also redefines the properties of other owners above
|
|
139
|
+
// it, so no item may keep a value of its own for them (a parent mapped as `content`).
|
|
140
|
+
const { path } = request.location;
|
|
141
|
+
const others = path === undefined ? [] : request.context.discriminators.otherPropertiesAt(path);
|
|
142
|
+
return omitKeys(type, [propertyName, ...others]);
|
|
143
|
+
}
|
|
144
|
+
|
|
79
145
|
function allOfTypes(
|
|
80
146
|
items: readonly Schema[],
|
|
81
147
|
required: readonly string[],
|
|
82
148
|
request: SchemaRequest,
|
|
83
149
|
): IrType[] {
|
|
84
|
-
return items.
|
|
85
|
-
const isRef = isRefItem(item);
|
|
86
|
-
const type = isRef
|
|
87
|
-
? refItemType(item, required, request)
|
|
88
|
-
: inlineItemType(item, required, request);
|
|
89
|
-
const discriminator =
|
|
90
|
-
(isRef && request.context.discriminators.objectAt(item.$ref)) ||
|
|
91
|
-
(item as SchemaObject).discriminator;
|
|
92
|
-
return discriminator?.propertyName ? omitKeys(type, [discriminator.propertyName]) : type;
|
|
93
|
-
});
|
|
150
|
+
return items.flatMap((item) => allOfItemType(item, required, request) ?? []);
|
|
94
151
|
}
|
|
95
152
|
|
|
96
153
|
function oneOfType(previous: IrType | null, variants: readonly IrType[]): IrType {
|
|
@@ -147,7 +204,22 @@ function composedType(schema: SchemaObject, request: SchemaRequest): IrType | nu
|
|
|
147
204
|
const allOfType = allOf.length > 0 ? [intersectionOf(allOf)] : [];
|
|
148
205
|
type = intersectionOf([...(core === null ? [] : [core]), ...allOfType]);
|
|
149
206
|
}
|
|
150
|
-
|
|
207
|
+
return variantsType(type, schema, request);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** `anyOf`, then `oneOf`, applied to the core and `allOf` type (`anyof-oneof-required` first). */
|
|
211
|
+
function variantsType(
|
|
212
|
+
previous: IrType | null,
|
|
213
|
+
schema: SchemaObject,
|
|
214
|
+
request: SchemaRequest,
|
|
215
|
+
): IrType | null {
|
|
216
|
+
const type =
|
|
217
|
+
requiredVariantsType(previous, schema, schema.anyOf ?? [], request) ??
|
|
218
|
+
anyOfType(previous, schema, request);
|
|
219
|
+
const oneOfRequired = requiredVariantsType(type, schema, schema.oneOf ?? [], request);
|
|
220
|
+
if (oneOfRequired !== null) {
|
|
221
|
+
return oneOfRequired;
|
|
222
|
+
}
|
|
151
223
|
const oneOf = variantTypes(oneOfVariants(schema), "oneOf", request);
|
|
152
224
|
return oneOf.length > 0 ? oneOfType(type, oneOf) : type;
|
|
153
225
|
}
|
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
import { unionOf } from "../type-combinators.js";
|
|
10
10
|
import { arrayType } from "./array-type.js";
|
|
11
11
|
import { objectType } from "./object-type.js";
|
|
12
|
+
import { hasRequiredVariants } from "./required-variants.js";
|
|
12
13
|
import type { SchemaRequest, SchemaRule } from "./schema-rule.js";
|
|
13
14
|
|
|
14
15
|
const PRIMITIVE_TYPE_NAMES: ReadonlySet<SchemaTypeName | null> = new Set([
|
|
@@ -34,10 +35,13 @@ function multipleTypes(schema: SchemaObject, request: SchemaRequest): IrType {
|
|
|
34
35
|
if (isInOneOf) {
|
|
35
36
|
continue;
|
|
36
37
|
}
|
|
37
|
-
// With oneOf, the member drops it, so oneOf is not applied once per member.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
// With oneOf, the member drops it, so oneOf is not applied once per member. Variants that
|
|
39
|
+
// only require properties (`anyof-oneof-required`) belong to the object member.
|
|
40
|
+
const isKept = typeName === "object" && hasRequiredVariants(schema, oneOf ?? [], request);
|
|
41
|
+
const variant =
|
|
42
|
+
Array.isArray(oneOf) && !isKept
|
|
43
|
+
? { ...schema, type: typeName, oneOf: undefined }
|
|
44
|
+
: { ...schema, type: typeName };
|
|
41
45
|
members.push(
|
|
42
46
|
typeName === "null" || typeName === null
|
|
43
47
|
? irKeyword("null")
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { unionAt, unionMaps, unionReaches } from "../../../domain/openapi/discriminated-union.js";
|
|
2
|
+
import type { SchemaObject } from "../../../domain/openapi/schema-object.js";
|
|
3
|
+
import type { SchemaRequest } from "./schema-rule.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* `allOf` items that are a `$ref` to a discriminated union (`oneOf` / `anyOf` and a
|
|
7
|
+
* discriminator). Such an item cannot be typed as the parent of the inheritance pattern,
|
|
8
|
+
* `Omit<Union, "kind">`.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** The union an `allOf` item refers to, and whether the union's type contains this schema. */
|
|
12
|
+
export interface UnionItem {
|
|
13
|
+
readonly union: SchemaObject;
|
|
14
|
+
/**
|
|
15
|
+
* The schema is one of the union's members: intersecting the union would make it refer to
|
|
16
|
+
* itself, which does not compile (TS2502, upstream #1665).
|
|
17
|
+
*/
|
|
18
|
+
readonly isMember: boolean;
|
|
19
|
+
/** The union's mapping names the schema, so it is a member even where the type is not. */
|
|
20
|
+
readonly isMapped: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** The union at `ref`, if the schema there is one. */
|
|
24
|
+
export function unionItemOf(ref: string, request: SchemaRequest): UnionItem | undefined {
|
|
25
|
+
const path = request.location.path;
|
|
26
|
+
const resolve = (target: string) => request.context.refs.resolve(target);
|
|
27
|
+
const union = unionAt(ref, resolve);
|
|
28
|
+
if (union === undefined) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
const isMember = path !== undefined && unionReaches(union, path, resolve);
|
|
32
|
+
return { union, isMember, isMapped: path !== undefined && unionMaps(union, path) };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function withoutKey<T>(record: Readonly<Record<string, T>>, key: string): Record<string, T> {
|
|
36
|
+
return Object.fromEntries(Object.entries(record).filter(([name]) => name !== key));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The keywords of a union that its members inherit: everything but the members and the
|
|
41
|
+
* discriminator property, which each member redefines (as `Omit` does for a parent). The item's
|
|
42
|
+
* `required` keys are added, as for an inline `allOf` item.
|
|
43
|
+
*/
|
|
44
|
+
export function unionOwnKeywords(
|
|
45
|
+
union: SchemaObject,
|
|
46
|
+
propertyName: string,
|
|
47
|
+
required: readonly string[],
|
|
48
|
+
): SchemaObject {
|
|
49
|
+
const { oneOf: _oneOf, anyOf: _anyOf, ...own } = union;
|
|
50
|
+
const ownRequired = (union.required ?? []).filter((key) => key !== propertyName);
|
|
51
|
+
return {
|
|
52
|
+
...own,
|
|
53
|
+
...(union.properties === undefined
|
|
54
|
+
? {}
|
|
55
|
+
: { properties: withoutKey(union.properties, propertyName) }),
|
|
56
|
+
required: [...required, ...ownRequired],
|
|
57
|
+
};
|
|
58
|
+
}
|