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,147 @@
|
|
|
1
|
+
import type { Logger } from "../application/ports/logger.js";
|
|
2
|
+
import { OutputFix } from "../domain/output-fixes.js";
|
|
3
|
+
import type { DiscriminatorObject, OpenAPI3, SchemaObject } from "../types.js";
|
|
4
|
+
import { addEnumProperty, declaresValues, type EnumPatch } from "./discriminator-enum.js";
|
|
5
|
+
import {
|
|
6
|
+
type DiscriminatorOwner,
|
|
7
|
+
type EnumParent,
|
|
8
|
+
enumParentOf,
|
|
9
|
+
} from "./discriminator-enum-parent.js";
|
|
10
|
+
import { resolveDocumentRef } from "./document-refs.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The state of the discriminator pre-pass and the in-place patch of a mapped schema: the enum
|
|
14
|
+
* property that the generated union narrows by. Two discriminators of one property may patch one
|
|
15
|
+
* schema; how they combine is the `discriminator-values` fix (ADR-021, roadmap R12).
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** How to scan: the warnings, and the output fixes of the run (ADR-021). */
|
|
19
|
+
export interface DiscriminatorScanOptions {
|
|
20
|
+
readonly silent: boolean;
|
|
21
|
+
readonly logger: Logger;
|
|
22
|
+
readonly fixes: ReadonlySet<OutputFix>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** What the two passes share: the document they patch and what they found so far. */
|
|
26
|
+
export interface ScanState extends DiscriminatorScanOptions {
|
|
27
|
+
readonly schema: OpenAPI3;
|
|
28
|
+
readonly objects: Record<string, DiscriminatorObject>;
|
|
29
|
+
/** The schemas that define a discriminator themselves (pass 1), not by inheritance. */
|
|
30
|
+
readonly owners: Set<string>;
|
|
31
|
+
readonly refsHandled: string[];
|
|
32
|
+
/** With the fix: the enum added to each schema, by schema and property, so values merge. */
|
|
33
|
+
readonly patchedEnums: Map<string, SchemaObject>;
|
|
34
|
+
/** With the fix: schema-name values, applied after both passes where no mapping names one. */
|
|
35
|
+
readonly inferredPatches: EnumPatch[];
|
|
36
|
+
/** With the fix: schema-name values of other properties (`inheritOtherOwners`). */
|
|
37
|
+
readonly otherInferredPatches: EnumPatch[];
|
|
38
|
+
/** With the fix: the other properties each schema got a value of (`inheritOtherOwners`). */
|
|
39
|
+
readonly otherProperties: Record<string, string[]>;
|
|
40
|
+
/** With `discriminator-values`: the enum keys that a schema declares itself. */
|
|
41
|
+
readonly declaredKeys: Set<string>;
|
|
42
|
+
/** With `discriminator-values`: the owner's enum of each added enum, by that enum. */
|
|
43
|
+
readonly enumParents: Map<object, EnumParent>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Whether `discriminator-values` is on: values of two discriminators merge into one enum. */
|
|
47
|
+
export function mergesValues(state: ScanState): boolean {
|
|
48
|
+
return state.fixes.has(OutputFix.DISCRIMINATOR_VALUES);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function patchedSchema(state: ScanState, patch: EnumPatch): SchemaObject | undefined {
|
|
52
|
+
const { silent, logger } = state;
|
|
53
|
+
return resolveDocumentRef<SchemaObject>(state.schema, patch.ref, { silent, logger });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* With `discriminator-values`: the schema at `patch.ref` requires the property with
|
|
58
|
+
* exactly these values already, so a patch would only repeat it (#2124).
|
|
59
|
+
*/
|
|
60
|
+
function isDeclared(state: ScanState, patch: EnumPatch): boolean {
|
|
61
|
+
return (
|
|
62
|
+
state.fixes.has(OutputFix.DISCRIMINATOR_VALUES) &&
|
|
63
|
+
declaresValues(patchedSchema(state, patch), patch)
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* With `discriminator-values`: the enum of the owner's property, for `key`: an enum the scan
|
|
69
|
+
* added, or a discriminator object that a schema inherited.
|
|
70
|
+
*/
|
|
71
|
+
export function recordEnumParent(state: ScanState, owner: DiscriminatorOwner, key: object): void {
|
|
72
|
+
if (!state.fixes.has(OutputFix.DISCRIMINATOR_VALUES)) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const { silent, logger } = state;
|
|
76
|
+
const parent = enumParentOf(owner, (ref) =>
|
|
77
|
+
resolveDocumentRef(state.schema, ref, { silent, logger }),
|
|
78
|
+
);
|
|
79
|
+
if (parent !== undefined) {
|
|
80
|
+
state.enumParents.set(key, parent);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** The enum the schema at `patch.ref` gets, or null (with a warning) for another kind of schema. */
|
|
85
|
+
function addDiscriminatorEnum(state: ScanState, patch: EnumPatch): SchemaObject | null {
|
|
86
|
+
const added = addEnumProperty(patchedSchema(state, patch), patch);
|
|
87
|
+
if (added === null) {
|
|
88
|
+
warnInvalidMapping(patch, state.logger);
|
|
89
|
+
} else {
|
|
90
|
+
recordEnumParent(state, patch, added);
|
|
91
|
+
}
|
|
92
|
+
return added;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** One schema and discriminator property; two discriminators of one property share an enum. */
|
|
96
|
+
export function enumKey(patch: EnumPatch): string {
|
|
97
|
+
return `${patch.ref}\n${patch.discriminator.propertyName}`;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** With the fix, a second discriminator of the same property adds its values to the first enum. */
|
|
101
|
+
function mergeIntoPatchedEnum(state: ScanState, key: string, values: readonly string[]): boolean {
|
|
102
|
+
const patched = state.patchedEnums.get(key);
|
|
103
|
+
if (patched === undefined) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
const merged = patched.enum as unknown[];
|
|
107
|
+
merged.push(...values.filter((value) => !merged.includes(value)));
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Add or replace the discriminator enum in the schema at `patch.ref`. Returns false, with a
|
|
113
|
+
* warning, when that schema is neither an `allOf` nor an object schema. Without the fix every
|
|
114
|
+
* patch adds a property, so two discriminators with different values intersect to `never`.
|
|
115
|
+
*/
|
|
116
|
+
export function patchDiscriminatorEnum(state: ScanState, patch: EnumPatch): boolean {
|
|
117
|
+
if (isDeclared(state, patch)) {
|
|
118
|
+
state.declaredKeys.add(enumKey(patch));
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
if (!mergesValues(state)) {
|
|
122
|
+
return addDiscriminatorEnum(state, patch) !== null;
|
|
123
|
+
}
|
|
124
|
+
const key = enumKey(patch);
|
|
125
|
+
if (mergeIntoPatchedEnum(state, key, patch.values)) {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
const added = addDiscriminatorEnum(state, patch);
|
|
129
|
+
if (added !== null) {
|
|
130
|
+
state.patchedEnums.set(key, added);
|
|
131
|
+
}
|
|
132
|
+
return added !== null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function markHandled(state: ScanState, ref: string): void {
|
|
136
|
+
if (!state.refsHandled.includes(ref)) {
|
|
137
|
+
state.refsHandled.push(ref);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function warnInvalidMapping(patch: EnumPatch, logger: Logger): void {
|
|
142
|
+
const mapped = `${patch.ref} => ${patch.values.join(", ")}`;
|
|
143
|
+
logger.warn(
|
|
144
|
+
"Discriminator mapping has an invalid schema (neither an object schema nor an allOf array): " +
|
|
145
|
+
`${mapped} (Discriminator: ${patch.discriminatorRef})`,
|
|
146
|
+
);
|
|
147
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { Logger } from "../application/ports/logger.js";
|
|
2
|
+
import { isUnionMember, unionAt } from "../domain/openapi/discriminated-union.js";
|
|
3
|
+
import { OutputFix } from "../domain/output-fixes.js";
|
|
2
4
|
import type {
|
|
3
5
|
DiscriminatorObject,
|
|
4
6
|
GeneratorOptions,
|
|
@@ -7,7 +9,18 @@ import type {
|
|
|
7
9
|
SchemaObject,
|
|
8
10
|
} from "../types.js";
|
|
9
11
|
import { defaultLogger } from "./default-ports.js";
|
|
10
|
-
import {
|
|
12
|
+
import type { EnumPatch } from "./discriminator-enum.js";
|
|
13
|
+
import type { EnumParent } from "./discriminator-enum-parent.js";
|
|
14
|
+
import { applyOtherInferredPatches, inheritOtherOwners } from "./discriminator-other-owners.js";
|
|
15
|
+
import {
|
|
16
|
+
type DiscriminatorScanOptions,
|
|
17
|
+
enumKey,
|
|
18
|
+
markHandled,
|
|
19
|
+
mergesValues,
|
|
20
|
+
patchDiscriminatorEnum,
|
|
21
|
+
recordEnumParent,
|
|
22
|
+
type ScanState,
|
|
23
|
+
} from "./discriminator-patch.js";
|
|
11
24
|
import { resolveDocumentRef, walkDocument } from "./document-refs.js";
|
|
12
25
|
import { createRef } from "./legacy-utils.js";
|
|
13
26
|
|
|
@@ -19,85 +32,6 @@ import { createRef } from "./legacy-utils.js";
|
|
|
19
32
|
|
|
20
33
|
type DiscriminatorMapping = Record<string, { inferred?: string; defined?: string[] }>;
|
|
21
34
|
|
|
22
|
-
/** How to scan; `fixesValueConflicts` is the `discriminator-values` fix (ADR-021, roadmap R12). */
|
|
23
|
-
export interface DiscriminatorScanOptions {
|
|
24
|
-
readonly silent: boolean;
|
|
25
|
-
readonly logger: Logger;
|
|
26
|
-
readonly fixesValueConflicts: boolean;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/** What the two passes share: the document they patch and what they found so far. */
|
|
30
|
-
interface ScanState extends DiscriminatorScanOptions {
|
|
31
|
-
readonly schema: OpenAPI3;
|
|
32
|
-
readonly objects: Record<string, DiscriminatorObject>;
|
|
33
|
-
readonly refsHandled: string[];
|
|
34
|
-
/** With the fix: the enum added to each schema, by schema and property, so values merge. */
|
|
35
|
-
readonly patchedEnums: Map<string, SchemaObject>;
|
|
36
|
-
/** With the fix: schema-name values, applied after both passes where no mapping names one. */
|
|
37
|
-
readonly inferredPatches: EnumPatch[];
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** The enum the schema at `patch.ref` gets, or null (with a warning) for another kind of schema. */
|
|
41
|
-
function addDiscriminatorEnum(state: ScanState, patch: EnumPatch): SchemaObject | null {
|
|
42
|
-
const { silent, logger } = state;
|
|
43
|
-
const resolved = resolveDocumentRef<SchemaObject>(state.schema, patch.ref, { silent, logger });
|
|
44
|
-
const added = addEnumProperty(resolved, patch);
|
|
45
|
-
if (added === null) {
|
|
46
|
-
warnInvalidMapping(patch, state.logger);
|
|
47
|
-
}
|
|
48
|
-
return added;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/** One schema and discriminator property; two discriminators of one property share an enum. */
|
|
52
|
-
function enumKey(patch: EnumPatch): string {
|
|
53
|
-
return `${patch.ref}\n${patch.discriminator.propertyName}`;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** With the fix, a second discriminator of the same property adds its values to the first enum. */
|
|
57
|
-
function mergeIntoPatchedEnum(state: ScanState, key: string, values: readonly string[]): boolean {
|
|
58
|
-
const patched = state.patchedEnums.get(key);
|
|
59
|
-
if (patched === undefined) {
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
62
|
-
const merged = patched.enum as unknown[];
|
|
63
|
-
merged.push(...values.filter((value) => !merged.includes(value)));
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Add or replace the discriminator enum in the schema at `patch.ref`. Returns false, with a
|
|
69
|
-
* warning, when that schema is neither an `allOf` nor an object schema. Without the fix every
|
|
70
|
-
* patch adds a property, so two discriminators with different values intersect to `never`.
|
|
71
|
-
*/
|
|
72
|
-
function patchDiscriminatorEnum(state: ScanState, patch: EnumPatch): boolean {
|
|
73
|
-
if (!state.fixesValueConflicts) {
|
|
74
|
-
return addDiscriminatorEnum(state, patch) !== null;
|
|
75
|
-
}
|
|
76
|
-
const key = enumKey(patch);
|
|
77
|
-
if (mergeIntoPatchedEnum(state, key, patch.values)) {
|
|
78
|
-
return true;
|
|
79
|
-
}
|
|
80
|
-
const added = addDiscriminatorEnum(state, patch);
|
|
81
|
-
if (added !== null) {
|
|
82
|
-
state.patchedEnums.set(key, added);
|
|
83
|
-
}
|
|
84
|
-
return added !== null;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function markHandled(state: ScanState, ref: string): void {
|
|
88
|
-
if (!state.refsHandled.includes(ref)) {
|
|
89
|
-
state.refsHandled.push(ref);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function warnInvalidMapping(patch: EnumPatch, logger: Logger): void {
|
|
94
|
-
const mapped = `${patch.ref} => ${patch.values.join(", ")}`;
|
|
95
|
-
logger.warn(
|
|
96
|
-
"Discriminator mapping has an invalid schema (neither an object schema nor an allOf array): " +
|
|
97
|
-
`${mapped} (Discriminator: ${patch.discriminatorRef})`,
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
35
|
/** The schema name at the end of each `oneOf` `$ref` is the inferred discriminator value. */
|
|
102
36
|
function inferredMapping(oneOf: (SchemaObject | ReferenceObject)[]): DiscriminatorMapping {
|
|
103
37
|
const mapping: DiscriminatorMapping = {};
|
|
@@ -116,9 +50,9 @@ function inferredMapping(oneOf: (SchemaObject | ReferenceObject)[]): Discriminat
|
|
|
116
50
|
/** Values defined in `discriminator.mapping` replace inferred ones for the same schema. */
|
|
117
51
|
function addDefinedMapping(
|
|
118
52
|
mapping: DiscriminatorMapping,
|
|
119
|
-
|
|
53
|
+
defined: Readonly<Record<string, string>>,
|
|
120
54
|
): void {
|
|
121
|
-
for (const [mappedValue, mappedRef] of Object.entries(
|
|
55
|
+
for (const [mappedValue, mappedRef] of Object.entries(defined)) {
|
|
122
56
|
if (!mappedRef) {
|
|
123
57
|
continue;
|
|
124
58
|
}
|
|
@@ -135,13 +69,13 @@ function patchMappedSchemas(
|
|
|
135
69
|
discriminator: Omit<EnumPatch, "ref" | "values">,
|
|
136
70
|
): void {
|
|
137
71
|
for (const [ref, { inferred, defined }] of Object.entries(mapping)) {
|
|
138
|
-
const isSkipped = !state
|
|
72
|
+
const isSkipped = !mergesValues(state) && state.refsHandled.includes(ref);
|
|
139
73
|
if (isSkipped || (!inferred && !defined)) {
|
|
140
74
|
continue;
|
|
141
75
|
}
|
|
142
76
|
// A defined value wins: the schema name may not be the value the API sends.
|
|
143
77
|
const values = defined ?? [inferred as string];
|
|
144
|
-
if (state
|
|
78
|
+
if (mergesValues(state) && defined === undefined) {
|
|
145
79
|
// A mapping found later, in this pass or the next, may name the schema.
|
|
146
80
|
state.inferredPatches.push({ ...discriminator, ref, values });
|
|
147
81
|
} else if (patchDiscriminatorEnum(state, { ...discriminator, ref, values })) {
|
|
@@ -162,12 +96,13 @@ function collectDiscriminator(
|
|
|
162
96
|
}
|
|
163
97
|
const discriminatorRef = createRef(path);
|
|
164
98
|
state.objects[discriminatorRef] = discriminator;
|
|
99
|
+
state.owners.add(discriminatorRef);
|
|
165
100
|
if (!Array.isArray(value.oneOf)) {
|
|
166
101
|
return;
|
|
167
102
|
}
|
|
168
103
|
const mapping = inferredMapping(value.oneOf);
|
|
169
104
|
if (discriminator.mapping) {
|
|
170
|
-
addDefinedMapping(mapping, discriminator);
|
|
105
|
+
addDefinedMapping(mapping, discriminator.mapping);
|
|
171
106
|
}
|
|
172
107
|
patchMappedSchemas(state, mapping, { discriminator, discriminatorRef });
|
|
173
108
|
}
|
|
@@ -179,6 +114,41 @@ function valuesMappedTo(discriminator: DiscriminatorObject, ref: string): string
|
|
|
179
114
|
.map(([mappedValue]) => mappedValue);
|
|
180
115
|
}
|
|
181
116
|
|
|
117
|
+
/**
|
|
118
|
+
* Whether the schema at `ref` takes the discriminator of its `allOf` parent at `parentRef`. With
|
|
119
|
+
* `allof-discriminated-union`, a schema that `allOf`s a discriminated union that does not contain
|
|
120
|
+
* it is that union, not one of its members, so it gets no value of its own (#1464, #1690). A
|
|
121
|
+
* schema that the union's mapping names is a member.
|
|
122
|
+
*/
|
|
123
|
+
function inheritsDiscriminator(state: ScanState, parentRef: string, ref: string): boolean {
|
|
124
|
+
if (!state.fixes.has(OutputFix.ALLOF_DISCRIMINATED_UNION)) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
const resolve = (target: string) => resolveDocumentRef(state.schema, target, state);
|
|
128
|
+
const union = unionAt(parentRef, resolve);
|
|
129
|
+
return union === undefined || isUnionMember(union, ref, resolve);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* The schema at `ref` inherits `discriminator`. With `discriminator-values`, a schema that
|
|
134
|
+
* defines a discriminator keeps it: the inherited one replaced its mapping, so the members walked
|
|
135
|
+
* after this schema got their schema name instead of the mapped value (#2200). `ownerRef` is the
|
|
136
|
+
* schema that declares the discriminator property, whose enum `--enum` values use (#1700).
|
|
137
|
+
*/
|
|
138
|
+
function recordInherited(
|
|
139
|
+
state: ScanState,
|
|
140
|
+
ref: string,
|
|
141
|
+
discriminator: DiscriminatorObject,
|
|
142
|
+
ownerRef: string,
|
|
143
|
+
): void {
|
|
144
|
+
if (state.fixes.has(OutputFix.DISCRIMINATOR_VALUES) && state.owners.has(ref)) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const inherited = { ...discriminator };
|
|
148
|
+
state.objects[ref] = inherited;
|
|
149
|
+
recordEnumParent(state, { discriminator, discriminatorRef: ownerRef }, inherited);
|
|
150
|
+
}
|
|
151
|
+
|
|
182
152
|
/**
|
|
183
153
|
* An `allOf` item that is a `$ref` to a discriminator owner: the schema at `ref` inherits the
|
|
184
154
|
* discriminator, and gets its enum when the parent's mapping names it. Returns false when the
|
|
@@ -194,7 +164,12 @@ function inheritFromRef(state: ScanState, parentRef: string, ref: string): boole
|
|
|
194
164
|
if (values.length > 0 && patchDiscriminatorEnum(state, patch)) {
|
|
195
165
|
markHandled(state, ref);
|
|
196
166
|
}
|
|
197
|
-
state
|
|
167
|
+
if (inheritsDiscriminator(state, parentRef, ref)) {
|
|
168
|
+
recordInherited(state, ref, discriminator, parentRef);
|
|
169
|
+
if (mergesValues(state)) {
|
|
170
|
+
inheritOtherOwners(state, parentRef, ref);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
198
173
|
return true;
|
|
199
174
|
}
|
|
200
175
|
|
|
@@ -213,7 +188,8 @@ function inheritDiscriminators(
|
|
|
213
188
|
return;
|
|
214
189
|
}
|
|
215
190
|
} else if (item.discriminator?.propertyName) {
|
|
216
|
-
|
|
191
|
+
// The inline item is typed at the schema's own location.
|
|
192
|
+
recordInherited(state, createRef(path), item.discriminator, createRef(path));
|
|
217
193
|
}
|
|
218
194
|
}
|
|
219
195
|
}
|
|
@@ -222,6 +198,10 @@ function inheritDiscriminators(
|
|
|
222
198
|
export interface DiscriminatorScan {
|
|
223
199
|
objects: Record<string, DiscriminatorObject>;
|
|
224
200
|
refsHandled: string[];
|
|
201
|
+
/** With `discriminator-values`: the owner's enum of each enum the scan added. */
|
|
202
|
+
enumParents: ReadonlyMap<object, EnumParent>;
|
|
203
|
+
/** With `discriminator-values`: the properties of the other discriminators a schema inherits. */
|
|
204
|
+
otherProperties: Readonly<Record<string, readonly string[]>>;
|
|
225
205
|
}
|
|
226
206
|
|
|
227
207
|
/**
|
|
@@ -229,12 +209,14 @@ export interface DiscriminatorScan {
|
|
|
229
209
|
* Every enum patched so far came from a mapping, since schema-name values wait for this step.
|
|
230
210
|
*/
|
|
231
211
|
function applyInferredPatches(state: ScanState): void {
|
|
232
|
-
|
|
212
|
+
// A value that a schema declares itself came from a mapping as well.
|
|
213
|
+
const mapped = new Set([...state.patchedEnums.keys(), ...state.declaredKeys]);
|
|
233
214
|
for (const patch of state.inferredPatches) {
|
|
234
215
|
if (!mapped.has(enumKey(patch)) && patchDiscriminatorEnum(state, patch)) {
|
|
235
216
|
markHandled(state, patch.ref);
|
|
236
217
|
}
|
|
237
218
|
}
|
|
219
|
+
applyOtherInferredPatches(state, mapped);
|
|
238
220
|
}
|
|
239
221
|
|
|
240
222
|
/** Find every discriminator in `schema`; warnings go to `logger` unless `silent`. */
|
|
@@ -246,15 +228,21 @@ export function findDiscriminators(
|
|
|
246
228
|
...options,
|
|
247
229
|
schema,
|
|
248
230
|
objects: {},
|
|
231
|
+
owners: new Set(),
|
|
249
232
|
refsHandled: [],
|
|
250
233
|
patchedEnums: new Map(),
|
|
251
234
|
inferredPatches: [],
|
|
235
|
+
otherInferredPatches: [],
|
|
236
|
+
otherProperties: {},
|
|
237
|
+
declaredKeys: new Set(),
|
|
238
|
+
enumParents: new Map(),
|
|
252
239
|
};
|
|
253
240
|
walkDocument(schema, (value, path) => collectDiscriminator(state, value, path));
|
|
254
241
|
// A second pass, because an `allOf` may name a discriminator that is defined later.
|
|
255
242
|
walkDocument(schema, (value, path) => inheritDiscriminators(state, value, path));
|
|
256
243
|
applyInferredPatches(state);
|
|
257
|
-
|
|
244
|
+
const { objects, refsHandled, enumParents, otherProperties } = state;
|
|
245
|
+
return { objects, refsHandled, enumParents, otherProperties };
|
|
258
246
|
}
|
|
259
247
|
|
|
260
248
|
/**
|
|
@@ -268,5 +256,5 @@ export function scanDiscriminators(
|
|
|
268
256
|
logger: Logger = defaultLogger(options.silent ?? false),
|
|
269
257
|
): DiscriminatorScan {
|
|
270
258
|
const silent = options.silent ?? false;
|
|
271
|
-
return findDiscriminators(schema, { silent, logger,
|
|
259
|
+
return findDiscriminators(schema, { silent, logger, fixes: new Set() });
|
|
272
260
|
}
|
package/src/api/document-run.ts
CHANGED
|
@@ -7,13 +7,15 @@ import type { RefAccess, SchemaLoader } from "../application/ports/schema-loader
|
|
|
7
7
|
import { withStackOverflowReported } from "../application/stack-overflow.js";
|
|
8
8
|
import {
|
|
9
9
|
ineffectiveFixNotices,
|
|
10
|
-
OutputFix,
|
|
10
|
+
type OutputFix,
|
|
11
11
|
outputFixNamesOf,
|
|
12
12
|
resolveOutputFixes,
|
|
13
13
|
} from "../domain/output-fixes.js";
|
|
14
14
|
import type { GeneratorOptions, GlobalContext, OpenAPI3, SchemaSource } from "../types.js";
|
|
15
|
+
import { warnDiscriminatorValueConflicts } from "./discriminator-conflict-warnings.js";
|
|
15
16
|
import { findDiscriminators } from "./discriminator-scan.js";
|
|
16
17
|
import { resolveDocumentRef } from "./document-refs.js";
|
|
18
|
+
import { warnIdenticalPathTemplates } from "./path-template-warnings.js";
|
|
17
19
|
import { warnUnsupportedFeatures } from "./unsupported-feature-warnings.js";
|
|
18
20
|
|
|
19
21
|
/** The ports of one generator run, wired by the Node API or the CLI (ENGINEERING_PLAN 4.5). */
|
|
@@ -45,10 +47,17 @@ type ContextFlags = Omit<
|
|
|
45
47
|
| "fix"
|
|
46
48
|
>;
|
|
47
49
|
|
|
50
|
+
/**
|
|
51
|
+
* The directory that relative `$ref`s of an inline source resolve against, as a URL that ends in
|
|
52
|
+
* a slash. A path is resolved and encoded (`#`, `%`, spaces); a URL without the slash gets one.
|
|
53
|
+
*/
|
|
48
54
|
function sourceCwd(options: GeneratorOptions): URL {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
: new URL(
|
|
55
|
+
const { cwd } = options;
|
|
56
|
+
if (cwd instanceof URL) {
|
|
57
|
+
return cwd.pathname.endsWith("/") ? cwd : new URL(`${cwd.pathname}/`, cwd);
|
|
58
|
+
}
|
|
59
|
+
const directory = path.resolve(cwd === undefined ? process.cwd() : cwd.toString());
|
|
60
|
+
return pathToFileURL(path.join(directory, path.sep));
|
|
52
61
|
}
|
|
53
62
|
|
|
54
63
|
/** The `$ref` limits of the options; a relative local root resolves against the cwd. */
|
|
@@ -115,6 +124,15 @@ function outputFixesOf(options: GeneratorOptions, logger: Logger): readonly Outp
|
|
|
115
124
|
return [...resolveOutputFixes(names)];
|
|
116
125
|
}
|
|
117
126
|
|
|
127
|
+
/** The warnings about the loaded document itself, before it is transformed. */
|
|
128
|
+
function warnAboutDocument(schema: OpenAPI3, fix: readonly OutputFix[], logger: Logger): void {
|
|
129
|
+
withStackOverflowReported("transform", () => warnUnsupportedFeatures(schema, logger));
|
|
130
|
+
withStackOverflowReported("transform", () =>
|
|
131
|
+
warnDiscriminatorValueConflicts(schema, fix, logger),
|
|
132
|
+
);
|
|
133
|
+
warnIdenticalPathTemplates(schema, logger);
|
|
134
|
+
}
|
|
135
|
+
|
|
118
136
|
/**
|
|
119
137
|
* Load the source through the ports, then build the run's context from the options. The fix names
|
|
120
138
|
* are checked first, so a typo fails before the document is read.
|
|
@@ -137,7 +155,7 @@ export async function createDocumentRun(
|
|
|
137
155
|
shouldLint: options.lint ?? true,
|
|
138
156
|
refAccess: refAccessOf(options, cwd),
|
|
139
157
|
});
|
|
140
|
-
|
|
158
|
+
warnAboutDocument(schema, fix, logger);
|
|
141
159
|
const ctx: GlobalContext = {
|
|
142
160
|
...contextFlags(options),
|
|
143
161
|
fix,
|
|
@@ -147,7 +165,7 @@ export async function createDocumentRun(
|
|
|
147
165
|
findDiscriminators(schema, {
|
|
148
166
|
silent,
|
|
149
167
|
logger,
|
|
150
|
-
|
|
168
|
+
fixes: new Set(fix),
|
|
151
169
|
}),
|
|
152
170
|
),
|
|
153
171
|
injectFooter: [],
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { WARNING_CODES, warningText } from "../domain/warnings.js";
|
|
2
|
+
|
|
3
|
+
const DOCS_BASE_URL = "https://github.com/openapi-typesafe/openapi-typesafe/blob/main/docs";
|
|
4
|
+
const DOCS_URL = `${DOCS_BASE_URL}/advanced.md#enum-values-arrays`;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The warning for an `--enum-values` array whose schema's location in the generated types admits
|
|
8
|
+
* none or only some of its values (ADR-027): the schema contradicts itself, for example an `allOf`
|
|
9
|
+
* of enums with different values or a discriminator value that the property enum does not list.
|
|
10
|
+
*/
|
|
11
|
+
export function excludedValuesWarning(name: string, excluded: readonly unknown[]): string {
|
|
12
|
+
const values = excluded.map((value) => JSON.stringify(value)).join(", ");
|
|
13
|
+
return warningText(
|
|
14
|
+
`${name}: the generated type at the location of this enum does not admit ${values}; ` +
|
|
15
|
+
"other keywords of the document exclude these values (an allOf of enums with other " +
|
|
16
|
+
"values, or a discriminator value the enum does not list). The array is typed by its own " +
|
|
17
|
+
"values. " +
|
|
18
|
+
`See ${DOCS_URL}`,
|
|
19
|
+
WARNING_CODES.ENUM_VALUES_EXCLUDED,
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Logger } from "../application/ports/logger.js";
|
|
2
|
+
import { findIdenticalPathTemplates } from "../domain/openapi/path-templates.js";
|
|
3
|
+
import { WARNING_CODES, warningText } from "../domain/warnings.js";
|
|
4
|
+
|
|
5
|
+
const DOCS_URL =
|
|
6
|
+
"https://github.com/openapi-typesafe/openapi-typesafe/blob/main/docs/cli.md#pathparamsastypes";
|
|
7
|
+
const SPEC_RULE =
|
|
8
|
+
"OpenAPI does not allow this (Paths Object): templated paths with the same hierarchy but " +
|
|
9
|
+
"different templated names MUST NOT exist as they are identical";
|
|
10
|
+
|
|
11
|
+
/** `"/a"`, `"/a" and "/b"`, `"/a", "/b" and "/c"`. */
|
|
12
|
+
function quotedList(urls: readonly string[]): string {
|
|
13
|
+
const quoted = urls.map((url) => `"${url}"`);
|
|
14
|
+
const last = quoted.pop();
|
|
15
|
+
return quoted.length === 0 ? (last ?? "") : `${quoted.join(", ")} and ${last}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Warn once per group of paths that differ only in parameter names, which the spec forbids: a URL
|
|
20
|
+
* cannot tell them apart, and `--path-params-as-types` gives them the same key type.
|
|
21
|
+
*/
|
|
22
|
+
export function warnIdenticalPathTemplates(document: unknown, logger: Logger): void {
|
|
23
|
+
for (const urls of findIdenticalPathTemplates(document)) {
|
|
24
|
+
const message = `Paths ${quotedList(urls)} differ only in their parameter names. ${SPEC_RULE}`;
|
|
25
|
+
logger.warn(warningText(`${message}. See ${DOCS_URL}`, WARNING_CODES.PATH_TEMPLATES_IDENTICAL));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import * as changeCase from "change-case";
|
|
2
2
|
import { RunFooter } from "../application/transform/footer/document-footer.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
DiscriminatorEnumParent,
|
|
5
|
+
SchemaLocation,
|
|
6
|
+
} from "../application/transform/schema/schema-context.js";
|
|
4
7
|
import type {
|
|
5
8
|
DocumentFooter,
|
|
6
9
|
NameCasing,
|
|
@@ -73,6 +76,9 @@ export function createTransformContext(ctx: GlobalContext): TransformContext {
|
|
|
73
76
|
discriminators: {
|
|
74
77
|
objectAt: (ref) => ctx.discriminators.objects[ref],
|
|
75
78
|
isHandled: (ref) => ctx.discriminators.refsHandled.includes(ref),
|
|
79
|
+
otherPropertiesAt: (ref) => ctx.discriminators.otherProperties?.[ref] ?? [],
|
|
80
|
+
enumParentOf: (schema) =>
|
|
81
|
+
ctx.discriminators.enumParents?.get(schema) as DiscriminatorEnumParent | undefined,
|
|
76
82
|
},
|
|
77
83
|
footer: runFooter(ctx),
|
|
78
84
|
callbacks: schemaCallbacks(ctx),
|
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
import type { ts } from "../adapters/type-ast-bridge/typescript-types.js";
|
|
2
2
|
import { documentBody, documentClosing } from "../application/transform/document/document.js";
|
|
3
|
-
import {
|
|
3
|
+
import { renameTakenAliases } from "../application/transform/document/root-type-aliases.js";
|
|
4
|
+
import { RunFooter } from "../application/transform/footer/document-footer.js";
|
|
5
|
+
import { checkedEnumValues } from "../application/transform/footer/enum-values-check.js";
|
|
6
|
+
import {
|
|
7
|
+
SharedEnumNameRecorder,
|
|
8
|
+
type SharedEnumNames,
|
|
9
|
+
} from "../application/transform/footer/shared-enum-names.js";
|
|
4
10
|
import type { IrDeclaration } from "../domain/ir/nodes.js";
|
|
5
11
|
import type { DocumentObject } from "../domain/openapi/document-object.js";
|
|
12
|
+
import { OutputFix } from "../domain/output-fixes.js";
|
|
6
13
|
import type { GlobalContext, OpenAPI3 } from "../types.js";
|
|
14
|
+
import { FirstSchemaNameRecorder } from "./discriminator-enum-names.js";
|
|
7
15
|
import { documentDeclarations, type TransformedDocument } from "./document-declarations.js";
|
|
16
|
+
import { excludedValuesWarning } from "./enum-values-warnings.js";
|
|
8
17
|
import { type FooterEntry, isIrDeclaration } from "./footer-entry.js";
|
|
18
|
+
import { ContextFooterSink } from "./footer-sink.js";
|
|
9
19
|
import { createTransformContext } from "./transform-context.js";
|
|
10
20
|
|
|
11
21
|
const OPERATIONS_NAME = "operations";
|
|
@@ -18,15 +28,89 @@ function isOperations(entry: FooterEntry): boolean {
|
|
|
18
28
|
return name === OPERATIONS_NAME;
|
|
19
29
|
}
|
|
20
30
|
|
|
31
|
+
/** Drops a message: the first pass must not repeat the run's warnings or debug lines. */
|
|
32
|
+
const dropMessage = (): void => undefined;
|
|
33
|
+
const DROPPED_MESSAGES = { debug: dropMessage, warn: dropMessage, error: dropMessage };
|
|
34
|
+
|
|
35
|
+
/** A shared enum name recorder of a first pass, and the names it gives the second. */
|
|
36
|
+
interface EnumNameRecorder extends SharedEnumNames {
|
|
37
|
+
chosenNames(): SharedEnumNames;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The names of shared enums, known only at the end: a first pass transforms the document into a
|
|
42
|
+
* scratch footer that `recorder` watches; its output is dropped. User callbacks run in both
|
|
43
|
+
* passes. The `dedupe-enum-names` fix (ADR-021, upstream #1683) names an enum by all of its
|
|
44
|
+
* schemas; `discriminator-values` keeps the first declaring schema's name
|
|
45
|
+
* (`FirstSchemaNameRecorder`).
|
|
46
|
+
*/
|
|
47
|
+
function sharedEnumNamesOf(
|
|
48
|
+
document: DocumentObject,
|
|
49
|
+
ctx: GlobalContext,
|
|
50
|
+
recorder: EnumNameRecorder,
|
|
51
|
+
): SharedEnumNames {
|
|
52
|
+
const injectFooter: FooterEntry[] = [];
|
|
53
|
+
const scratch: GlobalContext = {
|
|
54
|
+
...ctx,
|
|
55
|
+
injectFooter,
|
|
56
|
+
runFooter: new RunFooter(new ContextFooterSink(injectFooter), true, recorder),
|
|
57
|
+
logger: DROPPED_MESSAGES,
|
|
58
|
+
legacyCallbackWarnings: new Set(),
|
|
59
|
+
};
|
|
60
|
+
const scratchContext = createTransformContext(scratch);
|
|
61
|
+
documentBody(document, scratchContext, () => injectFooter.filter(isIrDeclaration));
|
|
62
|
+
return recorder.chosenNames();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** The recorder of the run's fixes, or null where the first schema's name needs no first pass. */
|
|
66
|
+
function enumNameRecorderOf(ctx: GlobalContext): EnumNameRecorder | null {
|
|
67
|
+
if (ctx.fix?.includes(OutputFix.DEDUPE_ENUM_NAMES)) {
|
|
68
|
+
return new SharedEnumNameRecorder();
|
|
69
|
+
}
|
|
70
|
+
return ctx.fix?.includes(OutputFix.DISCRIMINATOR_VALUES) ? new FirstSchemaNameRecorder() : null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** With a naming fix, `--enum` and `--dedupe-enums`, the run's footer names shared enums. */
|
|
74
|
+
function withSharedEnumNames(document: DocumentObject, ctx: GlobalContext): void {
|
|
75
|
+
const recorder = ctx.runFooter === undefined ? enumNameRecorderOf(ctx) : null;
|
|
76
|
+
if (recorder === null || !ctx.enum || !ctx.dedupeEnums) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const names = sharedEnumNamesOf(document, ctx, recorder);
|
|
80
|
+
ctx.runFooter = new RunFooter(new ContextFooterSink(ctx.injectFooter), true, names);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* With `--enum-values`, arrays whose location type does not hold their values are typed by their
|
|
85
|
+
* values (ADR-027); a location that excludes listed values is a contradiction of the document.
|
|
86
|
+
*/
|
|
87
|
+
function enumValuesChecked(
|
|
88
|
+
body: readonly IrDeclaration[],
|
|
89
|
+
footer: FooterEntry[],
|
|
90
|
+
ctx: GlobalContext,
|
|
91
|
+
): FooterEntry[] {
|
|
92
|
+
if (!ctx.enumValues) {
|
|
93
|
+
return footer;
|
|
94
|
+
}
|
|
95
|
+
const checked = checkedEnumValues(footer, body, isIrDeclaration);
|
|
96
|
+
for (const retype of checked.retyped) {
|
|
97
|
+
if (retype.kind === "excluded") {
|
|
98
|
+
ctx.logger?.warn(excludedValuesWarning(retype.name, retype.excluded));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return checked.footer;
|
|
102
|
+
}
|
|
103
|
+
|
|
21
104
|
/** @internal Root types, the footer, then the closing declarations (Phase 5, step 6). */
|
|
22
105
|
export function transformDocument(schema: OpenAPI3, ctx: GlobalContext): TransformedDocument {
|
|
23
106
|
const document = schema as DocumentObject;
|
|
107
|
+
withSharedEnumNames(document, ctx);
|
|
24
108
|
const context = createTransformContext(ctx);
|
|
25
109
|
// documentBody registers the enums in the footer, so the footer is read after it.
|
|
26
|
-
const rawBody = documentBody(document, context);
|
|
27
|
-
const footer
|
|
28
|
-
const body = renameAliasesTakenByFooter(rawBody, footer.filter(isIrDeclaration));
|
|
110
|
+
const rawBody = documentBody(document, context, () => ctx.injectFooter.filter(isIrDeclaration));
|
|
111
|
+
const footer = enumValuesChecked(rawBody, [...ctx.injectFooter], ctx);
|
|
29
112
|
const closing = documentClosing(document, context, footer.some(isOperations));
|
|
113
|
+
const body = renameTakenAliases(rawBody, footer.filter(isIrDeclaration), closing);
|
|
30
114
|
return { body, footer, closing };
|
|
31
115
|
}
|
|
32
116
|
|