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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components-object.mjs","sources":["../../src/transform/components-object.ts"],"sourcesContent":["import { createTransformContext } from \"../api/transform-context.js\";\nimport { componentsType } from \"../application/transform/document/components.js\";\nimport type { IrType, IrTypeAliasDeclaration } from \"../domain/ir/nodes.js\";\nimport { isEnumSchema, singularizeComponentKind } from \"../domain/openapi/components-object.js\";\nimport type { ComponentsObject, GlobalContext } from \"../types.js\";\n\nexport { isEnumSchema };\n\n/** `requestBodies` → `requestBody`; other keys drop the final `s`. */\nexport const singularizeComponentKey = singularizeComponentKind;\n\n/**\n * Transform the ComponentsObject (4.8.7)\n * @see https://spec.openapis.org/oas/latest.html#components-object\n *\n * Ported to IR (ENGINEERING_PLAN Phase 5, step 6). Same name and parameters as the original;\n * returns IR (task 6.2). For the public API: the `components` type, then the root type aliases.\n */\nexport default function transformComponentsObject(\n componentsObject: ComponentsObject,\n ctx: GlobalContext,\n): (IrType | IrTypeAliasDeclaration)[] {\n const { type, rootTypes } = componentsType(componentsObject, createTransformContext(ctx));\n return [type, ...rootTypes];\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"components-object.mjs","sources":["../../src/transform/components-object.ts"],"sourcesContent":["import { createTransformContext } from \"../api/transform-context.js\";\nimport { componentsType } from \"../application/transform/document/components.js\";\nimport { renameTakenAliases } from \"../application/transform/document/root-type-aliases.js\";\nimport type { IrType, IrTypeAliasDeclaration } from \"../domain/ir/nodes.js\";\nimport { isEnumSchema, singularizeComponentKind } from \"../domain/openapi/components-object.js\";\nimport type { ComponentsObject, GlobalContext } from \"../types.js\";\n\nexport { isEnumSchema };\n\n/** `requestBodies` → `requestBody`; other keys drop the final `s`. */\nexport const singularizeComponentKey = singularizeComponentKind;\n\n/**\n * Transform the ComponentsObject (4.8.7)\n * @see https://spec.openapis.org/oas/latest.html#components-object\n *\n * Ported to IR (ENGINEERING_PLAN Phase 5, step 6). Same name and parameters as the original;\n * returns IR (task 6.2). For the public API: the `components` type, then the root type aliases.\n */\nexport default function transformComponentsObject(\n componentsObject: ComponentsObject,\n ctx: GlobalContext,\n): (IrType | IrTypeAliasDeclaration)[] {\n const { type, rootTypes } = componentsType(componentsObject, createTransformContext(ctx));\n // No footer here: only the aliases the `root-type-numbering` fix keeps get numbers.\n return [type, ...renameTakenAliases(rootTypes, [])];\n}\n"],"names":[],"mappings":";;;;AAmBA,SAAwB,yBAAA,CACtB,kBACA,GAAA,EACqC;AACrC,EAAA,MAAM,EAAE,MAAM,SAAA,EAAU,GAAI,eAAe,gBAAA,EAAkB,sBAAA,CAAuB,GAAG,CAAC,CAAA;AAExF,EAAA,OAAO,CAAC,IAAA,EAAM,GAAG,mBAAmB,SAAA,EAAW,EAAE,CAAC,CAAA;AACpD;;"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,43 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { createConfig, findConfig, loadConfig } from "@redocly/openapi-core";
|
|
3
|
+
import { createConfig, findConfig, IGNORE_FILE, loadConfig } from "@redocly/openapi-core";
|
|
4
4
|
import type {
|
|
5
5
|
RedoclyConfig,
|
|
6
6
|
RedoclyConfigSource,
|
|
7
7
|
} from "../../application/ports/redocly-config-source.js";
|
|
8
|
+
import { ERROR_CODES, OpenAPITypesafeError } from "../../domain/errors.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The first line of a failure, with the error's name: a YAML error goes on with a snippet of the
|
|
12
|
+
* file, and the name tells a YAML error from a file system one.
|
|
13
|
+
*/
|
|
14
|
+
function reasonOf(error: unknown): string {
|
|
15
|
+
return String(error).replace(/\n[\s\S]*$/, "");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The config, or `CLI_CONFIG_INVALID`. Redocly reads the config file and the lint-ignore file
|
|
20
|
+
* next to it (or in the working directory); either can be malformed, and its error does not
|
|
21
|
+
* always name the file, so the message names both.
|
|
22
|
+
*/
|
|
23
|
+
async function loadedConfig(
|
|
24
|
+
load: () => Promise<RedoclyConfig>,
|
|
25
|
+
configPath: string | undefined,
|
|
26
|
+
): Promise<RedoclyConfig> {
|
|
27
|
+
try {
|
|
28
|
+
return await load();
|
|
29
|
+
} catch (error) {
|
|
30
|
+
const config =
|
|
31
|
+
configPath === undefined ? "the default Redocly config" : `the Redocly config ${configPath}`;
|
|
32
|
+
const where = configPath === undefined ? "in the working directory" : "next to it";
|
|
33
|
+
throw new OpenAPITypesafeError({
|
|
34
|
+
code: ERROR_CODES.CLI_CONFIG_INVALID,
|
|
35
|
+
message: `Cannot load ${config} or the ${IGNORE_FILE} ${where}: ${reasonOf(error)}`,
|
|
36
|
+
details: { configPath },
|
|
37
|
+
cause: error,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
8
41
|
|
|
9
42
|
/** The Redocly config port on `@redocly/openapi-core`, resolving paths from `cwd`. */
|
|
10
43
|
class RedoclyConfigFiles implements RedoclyConfigSource {
|
|
@@ -26,14 +59,16 @@ class RedoclyConfigFiles implements RedoclyConfigSource {
|
|
|
26
59
|
}
|
|
27
60
|
|
|
28
61
|
load(configPath: string): Promise<RedoclyConfig> {
|
|
29
|
-
return loadConfig({ configPath });
|
|
62
|
+
return loadedConfig(() => loadConfig({ configPath }), configPath);
|
|
30
63
|
}
|
|
31
64
|
|
|
32
65
|
createDefault(): Promise<RedoclyConfig> {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
66
|
+
const create = () =>
|
|
67
|
+
createConfig(
|
|
68
|
+
{ rules: { "operation-operationId-unique": { severity: "warn" } } },
|
|
69
|
+
{ extends: ["minimal"] },
|
|
70
|
+
);
|
|
71
|
+
return loadedConfig(create, undefined);
|
|
37
72
|
}
|
|
38
73
|
}
|
|
39
74
|
|
|
@@ -74,12 +74,17 @@ function assertOpenAPI3(document: unknown): void {
|
|
|
74
74
|
throw versionUnsupportedError(UNSUPPORTED_FORMAT_MESSAGE, parsed);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
/**
|
|
77
|
+
/**
|
|
78
|
+
* The name an inline source (a string, object, buffer or stream) gets inside the working
|
|
79
|
+
* directory. Redocly resolves relative `$ref`s against the directory of the document, so the
|
|
80
|
+
* document must be named as a file in the working directory, not as the directory itself.
|
|
81
|
+
*/
|
|
82
|
+
const INLINE_SOURCE_NAME = "inline-source";
|
|
83
|
+
|
|
84
|
+
/** The base for relative `$ref`s: the source file or URL itself, else a file in the cwd. */
|
|
78
85
|
function sourceAbsoluteRef(source: unknown, cwd: URL): string {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
return fileURLToPath(cwd);
|
|
86
|
+
const document = source instanceof URL ? source : new URL(INLINE_SOURCE_NAME, cwd);
|
|
87
|
+
return document.protocol === "file:" ? sourceFilePath(document) : document.href;
|
|
83
88
|
}
|
|
84
89
|
|
|
85
90
|
/**
|
|
@@ -217,10 +222,21 @@ class RedoclySchemaLoader implements SchemaLoader {
|
|
|
217
222
|
return bundled.bundle.parsed;
|
|
218
223
|
}
|
|
219
224
|
|
|
220
|
-
/**
|
|
225
|
+
/**
|
|
226
|
+
* Report every problem; then throw if any of them is an error. A problem that the Redocly
|
|
227
|
+
* config's `.redocly.lint-ignore.yaml` lists is left out, as `redocly lint` leaves it out
|
|
228
|
+
* (upstream #2189).
|
|
229
|
+
*/
|
|
221
230
|
#report(problems: readonly NormalizedProblem[]): void {
|
|
222
231
|
const errorMessages: string[] = [];
|
|
223
232
|
for (const problem of problems) {
|
|
233
|
+
if (problem.ignored === true) {
|
|
234
|
+
this.#options.logger.debug(
|
|
235
|
+
`Ignored by the lint ignore file: ${problemMessage(problem)}`,
|
|
236
|
+
"lint",
|
|
237
|
+
);
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
224
240
|
const message = problemMessage(problem);
|
|
225
241
|
if (problem.severity === "error") {
|
|
226
242
|
errorMessages.push(message);
|
|
@@ -74,6 +74,9 @@ function toStringLiteralType(
|
|
|
74
74
|
|
|
75
75
|
function toTupleElement(ts: TypeScriptModule, element: IrTupleElement): ts.TypeNode {
|
|
76
76
|
const type = toTypeNode(ts, element.type);
|
|
77
|
+
if (element.isOptional) {
|
|
78
|
+
return ts.factory.createOptionalTypeNode(type);
|
|
79
|
+
}
|
|
77
80
|
return element.isRest ? ts.factory.createRestTypeNode(type) : type;
|
|
78
81
|
}
|
|
79
82
|
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
IrMember,
|
|
7
7
|
IrPropertyName,
|
|
8
8
|
IrPropertySignature,
|
|
9
|
+
IrTupleElement,
|
|
9
10
|
IrType,
|
|
10
11
|
} from "../../domain/ir/nodes.js";
|
|
11
12
|
import type { TypeScriptModule } from "./load-typescript.js";
|
|
@@ -83,20 +84,31 @@ function fromReference(ts: TypeScriptModule, node: ts.TypeReferenceNode): IrType
|
|
|
83
84
|
return { kind: "reference", name: ts.idText(node.typeName), typeArguments };
|
|
84
85
|
}
|
|
85
86
|
|
|
87
|
+
function fromTupleElement(
|
|
88
|
+
ts: TypeScriptModule,
|
|
89
|
+
element: ts.TypeNode,
|
|
90
|
+
convert: (node: ts.TypeNode) => IrType,
|
|
91
|
+
): IrTupleElement {
|
|
92
|
+
if (ts.isRestTypeNode(element)) {
|
|
93
|
+
return { type: convert(element.type), isRest: true, isOptional: false };
|
|
94
|
+
}
|
|
95
|
+
if (ts.isOptionalTypeNode(element)) {
|
|
96
|
+
// The `?` is the parent of the type: it decides which parentheses the factory put in.
|
|
97
|
+
return { type: fromTypeNode(ts, element.type, element), isRest: false, isOptional: true };
|
|
98
|
+
}
|
|
99
|
+
return { type: convert(element), isRest: false, isOptional: false };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** A tuple of plain, rest and optional elements; one with named members stays text. */
|
|
86
103
|
function fromTuple(ts: TypeScriptModule, node: ts.TupleTypeNode): IrType | null {
|
|
87
|
-
|
|
88
|
-
(element) => !ts.isNamedTupleMember(element) && !ts.isOptionalTypeNode(element),
|
|
89
|
-
);
|
|
90
|
-
if (!isPlain) {
|
|
104
|
+
if (node.elements.some((element) => ts.isNamedTupleMember(element))) {
|
|
91
105
|
return null;
|
|
92
106
|
}
|
|
93
107
|
const convert = childrenOf(ts, node);
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
);
|
|
99
|
-
return { kind: "tuple", elements };
|
|
108
|
+
return {
|
|
109
|
+
kind: "tuple",
|
|
110
|
+
elements: node.elements.map((element) => fromTupleElement(ts, element, convert)),
|
|
111
|
+
};
|
|
100
112
|
}
|
|
101
113
|
|
|
102
114
|
/**
|
|
@@ -237,8 +249,9 @@ function fromStructure(ts: TypeScriptModule, node: ts.TypeNode): IrType | null {
|
|
|
237
249
|
|
|
238
250
|
/**
|
|
239
251
|
* Whether the factory's parenthesizer put these parentheses in (same rules as the IR printer):
|
|
240
|
-
* unions, intersections and `readonly` types as array elements, indexed objects
|
|
241
|
-
* operands; unions and intersections as members of other unions or
|
|
252
|
+
* unions, intersections and `readonly` types as array elements, indexed objects, optional tuple
|
|
253
|
+
* elements and `readonly` operands; unions and intersections as members of other unions or
|
|
254
|
+
* intersections.
|
|
242
255
|
*/
|
|
243
256
|
function isFactoryParenthesis(
|
|
244
257
|
ts: TypeScriptModule,
|
|
@@ -252,6 +265,7 @@ function isFactoryParenthesis(
|
|
|
252
265
|
const isPostfixOrReadonlyParent =
|
|
253
266
|
ts.isArrayTypeNode(parent) ||
|
|
254
267
|
ts.isIndexedAccessTypeNode(parent) ||
|
|
268
|
+
ts.isOptionalTypeNode(parent) ||
|
|
255
269
|
ts.isTypeOperatorNode(parent);
|
|
256
270
|
if (isPostfixOrReadonlyParent) {
|
|
257
271
|
return isComposite || ts.isTypeOperatorNode(inner);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Logger } from "../application/ports/logger.js";
|
|
2
|
+
import {
|
|
3
|
+
type DiscriminatorValueConflict,
|
|
4
|
+
findDiscriminatorValueConflicts,
|
|
5
|
+
} from "../domain/openapi/discriminator-conflicts.js";
|
|
6
|
+
import { OutputFix } from "../domain/output-fixes.js";
|
|
7
|
+
import { WARNING_CODES, warningText } from "../domain/warnings.js";
|
|
8
|
+
|
|
9
|
+
const DOCS_BASE_URL = "https://github.com/openapi-typesafe/openapi-typesafe/blob/main/docs";
|
|
10
|
+
const DOCS_URL = `${DOCS_BASE_URL}/advanced.md#discriminator-values`;
|
|
11
|
+
|
|
12
|
+
function listed(values: readonly unknown[]): string {
|
|
13
|
+
return values.map((value) => JSON.stringify(value)).join(", ");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function warningOf(conflict: DiscriminatorValueConflict): string {
|
|
17
|
+
const { member, owner, propertyName, values, allowed, isImplicit } = conflict;
|
|
18
|
+
const rule = isImplicit
|
|
19
|
+
? "A Discriminator Object without a mapping entry for a schema gives it its schema name as " +
|
|
20
|
+
`the value; add a mapping entry such as ${JSON.stringify(allowed[0])}: "${member}".`
|
|
21
|
+
: "The Discriminator Object maps these values to the schema; map the values it allows.";
|
|
22
|
+
return (
|
|
23
|
+
`${member}: the discriminator "${propertyName}" of ${owner} gives this schema the value ` +
|
|
24
|
+
`${listed(values)}, which its "${propertyName}" property does not allow ` +
|
|
25
|
+
`(${listed(allowed)}), so no value of the schema matches the discriminator. ${rule} ` +
|
|
26
|
+
`See ${DOCS_URL}`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Warn once per discriminator member whose value its own property does not allow. The members
|
|
32
|
+
* depend on the run's fixes (`allof-discriminated-union`).
|
|
33
|
+
*/
|
|
34
|
+
export function warnDiscriminatorValueConflicts(
|
|
35
|
+
document: unknown,
|
|
36
|
+
fixes: readonly OutputFix[],
|
|
37
|
+
logger: Logger,
|
|
38
|
+
): void {
|
|
39
|
+
const isUnionReused = fixes.includes(OutputFix.ALLOF_DISCRIMINATED_UNION);
|
|
40
|
+
for (const conflict of findDiscriminatorValueConflicts(document, { isUnionReused })) {
|
|
41
|
+
logger.warn(warningText(warningOf(conflict), WARNING_CODES.DISCRIMINATOR_VALUE_NOT_ALLOWED));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { SharedEnumNames } from "../application/transform/footer/shared-enum-names.js";
|
|
2
|
+
import type { EnumDeclarationRequest } from "../application/transform/schema/schema-context.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `--dedupe-enums` names a shared enum after the first schema that declares it. With
|
|
6
|
+
* `discriminator-values` and `--enum`, a member's value refers to the owner's enum, which is then
|
|
7
|
+
* declared when the member is typed, maybe before that first schema; the shared enum would take
|
|
8
|
+
* the owner's name. A first pass records the names of the declaring schemas only, so the second
|
|
9
|
+
* pass names each shared enum as the document order does (`OtherKind`, not `PetPetType`).
|
|
10
|
+
*/
|
|
11
|
+
export class FirstSchemaNameRecorder implements SharedEnumNames {
|
|
12
|
+
private readonly names = new Map<string, string>();
|
|
13
|
+
|
|
14
|
+
nameOf(key: string, name: string, request: EnumDeclarationRequest): string {
|
|
15
|
+
if (!request.isOwnerReference && !this.names.has(key)) {
|
|
16
|
+
this.names.set(key, name);
|
|
17
|
+
}
|
|
18
|
+
return name;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** The recorded name of each shared enum, for the second pass. */
|
|
22
|
+
chosenNames(): SharedEnumNames {
|
|
23
|
+
const chosen = new Map(this.names);
|
|
24
|
+
return { nameOf: (key, name) => chosen.get(key) ?? name };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { createRef, parseRefPointer } from "../domain/openapi/json-pointer.js";
|
|
2
|
+
import type { SchemaObject } from "../types.js";
|
|
3
|
+
import type { EnumPatch } from "./discriminator-enum.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The `discriminator-values` fix (#1700). With `--enum`, the enum the scan adds to a member
|
|
7
|
+
* (`petType: "Cat"`) is declared as an enum of its own (`CatPetType`), which is not assignable to
|
|
8
|
+
* the parent's enum (`PetType`). The parent's enum is found here, so the member's property can be
|
|
9
|
+
* typed with its members (`PetType.Cat`).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/** The parent's enum schema and the location it is typed at, which gives the enum its name. */
|
|
13
|
+
export interface EnumParent {
|
|
14
|
+
readonly schema: SchemaObject;
|
|
15
|
+
readonly path: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type ResolveSchemaRef = (ref: string) => unknown;
|
|
19
|
+
|
|
20
|
+
/** A declared property schema and the location the transformer types it at. */
|
|
21
|
+
interface DeclaredProperty {
|
|
22
|
+
readonly property: unknown;
|
|
23
|
+
readonly path: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const PROPERTIES_KEYWORD = "properties";
|
|
27
|
+
/** `components`, `schemas` and the schema name: the segments before the schema's own keywords. */
|
|
28
|
+
const ROOT_SEGMENTS = 3;
|
|
29
|
+
|
|
30
|
+
/** The location a `$ref` is typed at: object properties are nested without `properties`. */
|
|
31
|
+
function typedAt(ref: string): string {
|
|
32
|
+
const segments = parseRefPointer(ref);
|
|
33
|
+
const nested = segments.slice(ROOT_SEGMENTS).filter((segment) => segment !== PROPERTIES_KEYWORD);
|
|
34
|
+
return createRef([...segments.slice(0, ROOT_SEGMENTS), ...nested]);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isSchemaObject(value: unknown): value is SchemaObject {
|
|
38
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** The property `name` of a schema object typed at `ref`. */
|
|
42
|
+
function ownProperty(item: SchemaObject, ref: string, name: string): DeclaredProperty | undefined {
|
|
43
|
+
const property = ("properties" in item ? item.properties : undefined)?.[name];
|
|
44
|
+
return property === undefined ? undefined : { property, path: createRef([ref, name]) };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** The property `name` of the schema at `ref`, its own or from an `allOf` item, depth first. */
|
|
48
|
+
function declaredProperty(
|
|
49
|
+
ref: string,
|
|
50
|
+
name: string,
|
|
51
|
+
resolve: ResolveSchemaRef,
|
|
52
|
+
visited: Set<string>,
|
|
53
|
+
): DeclaredProperty | undefined {
|
|
54
|
+
const schema = resolve(ref);
|
|
55
|
+
if (visited.has(ref) || !isSchemaObject(schema)) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
visited.add(ref);
|
|
59
|
+
// An inline `allOf` item is typed at its parent's location, so both share the path.
|
|
60
|
+
for (const item of [schema, ...(schema.allOf ?? [])]) {
|
|
61
|
+
if (!isSchemaObject(item)) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const found =
|
|
65
|
+
"$ref" in item
|
|
66
|
+
? declaredProperty(item.$ref as string, name, resolve, visited)
|
|
67
|
+
: ownProperty(item, ref, name);
|
|
68
|
+
if (found !== undefined) {
|
|
69
|
+
return found;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* A discriminator and the `$ref` of the schema that declares its property; `ref` is the member
|
|
77
|
+
* whose value the discriminator gives, where there is one.
|
|
78
|
+
*/
|
|
79
|
+
export type DiscriminatorOwner = Pick<EnumPatch, "discriminator" | "discriminatorRef"> &
|
|
80
|
+
Partial<Pick<EnumPatch, "ref">>;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The property `name` that the member at `ref` inherits through its `allOf` `$ref`s. Its own
|
|
84
|
+
* keywords and inline items are left out: the scan writes the added value there.
|
|
85
|
+
*/
|
|
86
|
+
function inheritedProperty(
|
|
87
|
+
ref: string,
|
|
88
|
+
name: string,
|
|
89
|
+
resolve: ResolveSchemaRef,
|
|
90
|
+
): DeclaredProperty | undefined {
|
|
91
|
+
const schema = resolve(ref);
|
|
92
|
+
const visited = new Set([ref]);
|
|
93
|
+
for (const item of isSchemaObject(schema) ? (schema.allOf ?? []) : []) {
|
|
94
|
+
const found =
|
|
95
|
+
isSchemaObject(item) && "$ref" in item
|
|
96
|
+
? declaredProperty(item.$ref as string, name, resolve, visited)
|
|
97
|
+
: undefined;
|
|
98
|
+
if (found !== undefined) {
|
|
99
|
+
return found;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* The enum of the property that the discriminator owner declares, if it is one. An owner that
|
|
107
|
+
* declares no such property (a `oneOf` with a mapping) leaves the member's type to the property
|
|
108
|
+
* the member inherits, so that property's enum is the one.
|
|
109
|
+
*/
|
|
110
|
+
export function enumParentOf(
|
|
111
|
+
patch: DiscriminatorOwner,
|
|
112
|
+
resolve: ResolveSchemaRef,
|
|
113
|
+
): EnumParent | undefined {
|
|
114
|
+
const name = patch.discriminator.propertyName;
|
|
115
|
+
const declared =
|
|
116
|
+
declaredProperty(patch.discriminatorRef, name, resolve, new Set()) ??
|
|
117
|
+
(patch.ref === undefined ? undefined : inheritedProperty(patch.ref, name, resolve));
|
|
118
|
+
if (declared === undefined || !isSchemaObject(declared.property)) {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
const ref = (declared.property as { readonly $ref?: unknown }).$ref;
|
|
122
|
+
const parent =
|
|
123
|
+
typeof ref === "string"
|
|
124
|
+
? { schema: resolve(ref), path: typedAt(ref) }
|
|
125
|
+
: { schema: declared.property, path: declared.path };
|
|
126
|
+
return isSchemaObject(parent.schema) && Array.isArray(parent.schema.enum)
|
|
127
|
+
? { schema: parent.schema, path: parent.path }
|
|
128
|
+
: undefined;
|
|
129
|
+
}
|
|
@@ -61,6 +61,45 @@ function isObjectSchema(schema: unknown): schema is SchemaObject & ObjectSubtype
|
|
|
61
61
|
);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
/** The values a property schema allows, from `const` or `enum`; null when it lists none. */
|
|
65
|
+
function listedValues(property: unknown): readonly unknown[] | null {
|
|
66
|
+
if (typeof property !== "object" || property === null) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
const { const: constant, enum: values } = property as SchemaObject;
|
|
70
|
+
if (constant !== undefined) {
|
|
71
|
+
return [constant];
|
|
72
|
+
}
|
|
73
|
+
return Array.isArray(values) ? values : null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Whether one schema object requires the property and allows exactly the values. */
|
|
77
|
+
function requiresValues(schema: unknown, name: string, values: readonly string[]): boolean {
|
|
78
|
+
if (typeof schema !== "object" || schema === null || "$ref" in schema) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
const { required, properties } = schema as SchemaObject & ObjectSubtype;
|
|
82
|
+
const listed = listedValues(properties?.[name]);
|
|
83
|
+
return (
|
|
84
|
+
Boolean(required?.includes(name)) &&
|
|
85
|
+
listed !== null &&
|
|
86
|
+
listed.length === values.length &&
|
|
87
|
+
values.every((value) => listed.includes(value))
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Whether `schema`, or an inline `allOf` item of it, already requires the discriminator property
|
|
93
|
+
* with exactly the patch's values (the `discriminator-values` fix). Then a patch would
|
|
94
|
+
* only repeat it (#2124).
|
|
95
|
+
*/
|
|
96
|
+
export function declaresValues(schema: SchemaObject | undefined, patch: EnumPatch): boolean {
|
|
97
|
+
const name = patch.discriminator.propertyName;
|
|
98
|
+
return [schema, ...(schema?.allOf ?? [])].some((item) =>
|
|
99
|
+
requiresValues(item, name, patch.values),
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
64
103
|
/**
|
|
65
104
|
* Add or replace the enum property in `schema`, an `allOf` or object schema. Returns the added
|
|
66
105
|
* enum schema, or null for another kind of schema, which is left as it is.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { DiscriminatorObject, ReferenceObject, SchemaObject } from "../types.js";
|
|
2
|
+
import type { EnumPatch } from "./discriminator-enum.js";
|
|
3
|
+
import { enumKey, patchDiscriminatorEnum, type ScanState } from "./discriminator-patch.js";
|
|
4
|
+
import { resolveDocumentRef } from "./document-refs.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The `discriminator-values` fix: a schema inherits one discriminator per property. A schema that
|
|
8
|
+
* owns a discriminator keeps its own (#2200), so the scan does not record the one it inherits for
|
|
9
|
+
* another property (`Content` owns `subtype` and `allOf`s `Element`, which owns `contentType`).
|
|
10
|
+
* Its members (`Video`) still get a value of that property, found here from the owners above.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** A discriminator and the schema that defines it. */
|
|
14
|
+
interface OtherOwner {
|
|
15
|
+
readonly discriminator: DiscriminatorObject;
|
|
16
|
+
readonly ownerRef: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** The `$ref`s of a schema's `allOf` items. */
|
|
20
|
+
function allOfRefs(state: ScanState, ref: string): string[] {
|
|
21
|
+
const { silent, logger } = state;
|
|
22
|
+
const schema = resolveDocumentRef<SchemaObject>(state.schema, ref, { silent, logger });
|
|
23
|
+
const items = (schema?.allOf ?? []) as (SchemaObject | ReferenceObject)[];
|
|
24
|
+
return items.flatMap((item) =>
|
|
25
|
+
"$ref" in item && typeof item.$ref === "string" ? [item.$ref] : [],
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The owners' discriminators that the schema at `parentRef` and its `allOf` parents define, the
|
|
31
|
+
* nearest one per property, except the property of `parentRef`'s own discriminator.
|
|
32
|
+
*/
|
|
33
|
+
function otherOwners(state: ScanState, parentRef: string): OtherOwner[] {
|
|
34
|
+
const own = state.objects[parentRef]?.propertyName;
|
|
35
|
+
const found = new Map<string, OtherOwner>();
|
|
36
|
+
const visited = new Set<string>();
|
|
37
|
+
const queue = [parentRef];
|
|
38
|
+
for (let ref = queue.shift(); ref !== undefined; ref = queue.shift()) {
|
|
39
|
+
if (visited.has(ref)) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
visited.add(ref);
|
|
43
|
+
const discriminator = state.owners.has(ref) ? state.objects[ref] : undefined;
|
|
44
|
+
const name = discriminator?.propertyName;
|
|
45
|
+
if (discriminator && name !== undefined && name !== own && !found.has(name)) {
|
|
46
|
+
found.set(name, { discriminator, ownerRef: ref });
|
|
47
|
+
}
|
|
48
|
+
queue.push(...allOfRefs(state, ref));
|
|
49
|
+
}
|
|
50
|
+
return [...found.values()];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The child redefines this property, so its `allOf` items omit it: a parent may have a value of
|
|
55
|
+
* its own, as `Content` has when `Element`'s mapping names it.
|
|
56
|
+
*/
|
|
57
|
+
function recordOtherProperty(state: ScanState, ref: string, propertyName: string): void {
|
|
58
|
+
const names = state.otherProperties[ref] ?? [];
|
|
59
|
+
if (!names.includes(propertyName)) {
|
|
60
|
+
names.push(propertyName);
|
|
61
|
+
}
|
|
62
|
+
state.otherProperties[ref] = names;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The child at `ref` of the schema at `parentRef` gets a value of each other property: a mapped
|
|
67
|
+
* one at once, else its schema name after both passes, where no mapping gives one. The schema's
|
|
68
|
+
* own discriminator property is still added, so these patches do not mark it handled.
|
|
69
|
+
*/
|
|
70
|
+
export function inheritOtherOwners(state: ScanState, parentRef: string, ref: string): void {
|
|
71
|
+
const childProperty = state.objects[ref]?.propertyName;
|
|
72
|
+
for (const { discriminator, ownerRef } of otherOwners(state, parentRef)) {
|
|
73
|
+
if (discriminator.propertyName === childProperty) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
recordOtherProperty(state, ref, discriminator.propertyName);
|
|
77
|
+
const mapped = Object.entries(discriminator.mapping ?? {})
|
|
78
|
+
.filter(([, target]) => target === ref)
|
|
79
|
+
.map(([value]) => value);
|
|
80
|
+
const name = ref.slice(ref.lastIndexOf("/") + 1);
|
|
81
|
+
const patch: EnumPatch = { ref, values: mapped, discriminator, discriminatorRef: ownerRef };
|
|
82
|
+
if (mapped.length > 0) {
|
|
83
|
+
patchDiscriminatorEnum(state, patch);
|
|
84
|
+
} else {
|
|
85
|
+
state.otherInferredPatches.push({ ...patch, values: [name] });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** The deferred schema-name values of other properties; see `inheritOtherOwners`. */
|
|
91
|
+
export function applyOtherInferredPatches(state: ScanState, mapped: ReadonlySet<string>): void {
|
|
92
|
+
for (const patch of state.otherInferredPatches) {
|
|
93
|
+
if (!mapped.has(enumKey(patch))) {
|
|
94
|
+
patchDiscriminatorEnum(state, patch);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|