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
|
@@ -14,18 +14,26 @@ import {
|
|
|
14
14
|
pathItemOperations,
|
|
15
15
|
} from "../../../domain/openapi/path-item-object.js";
|
|
16
16
|
import type { ReferenceSchema, SchemaObject } from "../../../domain/openapi/schema-object.js";
|
|
17
|
+
import { OutputFix } from "../../../domain/output-fixes.js";
|
|
17
18
|
import { documentEntries } from "../document-entries.js";
|
|
18
19
|
import { refType } from "../ref-type.js";
|
|
19
20
|
import type { TransformContext } from "../transform-context.js";
|
|
21
|
+
import { type DeclaredTypeLookup, NO_DECLARED_TYPES } from "./declared-types.js";
|
|
20
22
|
import { documentMember } from "./document-member.js";
|
|
21
23
|
import { pathItemType } from "./path-item.js";
|
|
22
|
-
import { isCoveredPathItemRejected } from "./path-item-conflicts.js";
|
|
23
24
|
import {
|
|
25
|
+
type CoverRejection,
|
|
24
26
|
coveringTemplateKeys,
|
|
25
27
|
type PathKey,
|
|
26
28
|
type PathKeyPart,
|
|
27
29
|
type PathPlaceholder,
|
|
28
30
|
} from "./path-key-overlaps.js";
|
|
31
|
+
import {
|
|
32
|
+
type PathParameterMatch,
|
|
33
|
+
placeholderText,
|
|
34
|
+
replacedTemplateParts,
|
|
35
|
+
} from "./path-template-replace.js";
|
|
36
|
+
import { assignabilityProof } from "./type-assignability.js";
|
|
29
37
|
|
|
30
38
|
const PATH_PARAMETER_RE = /\{[^}]+\}/g;
|
|
31
39
|
|
|
@@ -37,11 +45,6 @@ const PLACEHOLDERS: ReadonlyMap<unknown, PathPlaceholder> = new Map([
|
|
|
37
45
|
]);
|
|
38
46
|
const STRING_PLACEHOLDER: PathPlaceholder = "string";
|
|
39
47
|
|
|
40
|
-
/** `${type}`: the text of a template literal type placeholder. */
|
|
41
|
-
function placeholderText(type: PathPlaceholder): string {
|
|
42
|
-
return `\${${type}}`;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
48
|
function resolvedParameter(
|
|
46
49
|
parameter: ParameterOrReference,
|
|
47
50
|
context: TransformContext,
|
|
@@ -80,29 +83,37 @@ function pathParameters(
|
|
|
80
83
|
return byName;
|
|
81
84
|
}
|
|
82
85
|
|
|
86
|
+
/** Each `{name}` of the URL and its own placeholder, from the URL split at the matches. */
|
|
87
|
+
function splitTemplateParts(url: string, matches: readonly PathParameterMatch[]): PathKeyPart[] {
|
|
88
|
+
return url.split(PATH_PARAMETER_RE).flatMap((text, index): PathKeyPart[] => {
|
|
89
|
+
const type = matches[index]?.type;
|
|
90
|
+
const textPart: PathKeyPart = { kind: "text", text };
|
|
91
|
+
return type === undefined ? [textPart] : [textPart, { kind: "placeholder", type }];
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
83
95
|
/**
|
|
84
96
|
* `--path-params-as-types`: the URL as template parts, each `{name}` replaced by a placeholder for
|
|
85
|
-
* its parameter's type
|
|
97
|
+
* its parameter's type, the way the original replaces them unless the `path-param-type-names` fix
|
|
98
|
+
* is on (see `replacedTemplateParts`). Null when the URL has no complete `{…}` placeholder.
|
|
86
99
|
*/
|
|
87
100
|
function pathTemplateParts(
|
|
88
101
|
url: string,
|
|
89
102
|
pathItem: PathItemObject,
|
|
90
103
|
context: TransformContext,
|
|
91
104
|
): PathKeyPart[] | null {
|
|
92
|
-
const
|
|
93
|
-
if (!
|
|
105
|
+
const found = url.match(PATH_PARAMETER_RE);
|
|
106
|
+
if (!found) {
|
|
94
107
|
return null;
|
|
95
108
|
}
|
|
96
109
|
const parameters = pathParameters(pathItem, context);
|
|
97
|
-
const
|
|
110
|
+
const matches = found.map((match): PathParameterMatch => {
|
|
98
111
|
const schema = parameters.get(match.slice(1, -1))?.schema as SchemaObject | undefined;
|
|
99
|
-
return PLACEHOLDERS.get(schema?.type) ?? STRING_PLACEHOLDER;
|
|
100
|
-
});
|
|
101
|
-
return url.split(PATH_PARAMETER_RE).flatMap((text, index): PathKeyPart[] => {
|
|
102
|
-
const type = placeholders[index];
|
|
103
|
-
const textPart: PathKeyPart = { kind: "text", text };
|
|
104
|
-
return type === undefined ? [textPart] : [textPart, { kind: "placeholder", type }];
|
|
112
|
+
return { match, type: PLACEHOLDERS.get(schema?.type) ?? STRING_PLACEHOLDER };
|
|
105
113
|
});
|
|
114
|
+
return context.options.fixes.has(OutputFix.PATH_PARAM_TYPE_NAMES)
|
|
115
|
+
? splitTemplateParts(url, matches)
|
|
116
|
+
: replacedTemplateParts(url, matches);
|
|
106
117
|
}
|
|
107
118
|
|
|
108
119
|
/**
|
|
@@ -120,7 +131,8 @@ function templateText(parts: readonly PathKeyPart[]): string {
|
|
|
120
131
|
}
|
|
121
132
|
|
|
122
133
|
/** A path's member, its key and its path item type for the overlap check. */
|
|
123
|
-
interface PathMember {
|
|
134
|
+
export interface PathMember {
|
|
135
|
+
readonly url: string;
|
|
124
136
|
readonly member: IrMember;
|
|
125
137
|
readonly key: PathKey;
|
|
126
138
|
readonly type: IrType;
|
|
@@ -139,7 +151,7 @@ function pathItemMember(
|
|
|
139
151
|
: null;
|
|
140
152
|
if (parts === null) {
|
|
141
153
|
const member = irProperty(toPropertyName(url), type, { isReadonly });
|
|
142
|
-
return { member, key: literalKey(url), type };
|
|
154
|
+
return { url, member, key: literalKey(url), type };
|
|
143
155
|
}
|
|
144
156
|
const member: IrMember = {
|
|
145
157
|
kind: "indexSignature",
|
|
@@ -149,33 +161,75 @@ function pathItemMember(
|
|
|
149
161
|
isReadonly,
|
|
150
162
|
comments: [],
|
|
151
163
|
};
|
|
152
|
-
return { member, key: { kind: "template", parts }, type };
|
|
164
|
+
return { url, member, key: { kind: "template", parts }, type };
|
|
153
165
|
}
|
|
154
166
|
|
|
155
167
|
function literalKey(url: string): PathKey {
|
|
156
168
|
return { kind: "literal", url };
|
|
157
169
|
}
|
|
158
170
|
|
|
171
|
+
const PATHS_TYPE_NAME = "paths";
|
|
172
|
+
|
|
173
|
+
/** The URL of `paths["/apps/{id}"]`, or null for any other type. */
|
|
174
|
+
function pathsIndexOf(type: IrType): string | null {
|
|
175
|
+
if (type.kind !== "indexedAccess" || type.index.kind !== "stringLiteral") {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
const { object } = type;
|
|
179
|
+
const isPaths =
|
|
180
|
+
object.kind === "reference" &&
|
|
181
|
+
object.name === PATHS_TYPE_NAME &&
|
|
182
|
+
object.typeArguments.length === 0;
|
|
183
|
+
return isPaths ? type.index.value : null;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* The lookup, and `paths["/apps/{id}"]` as that path's item. The declarations cannot read it: a
|
|
188
|
+
* templated path is no property of `paths`, and TypeScript finds it through the signature.
|
|
189
|
+
*/
|
|
190
|
+
function withPathItems(
|
|
191
|
+
paths: readonly PathMember[],
|
|
192
|
+
lookup: DeclaredTypeLookup,
|
|
193
|
+
): DeclaredTypeLookup {
|
|
194
|
+
const byUrl = new Map(paths.map((path) => [path.url, path.type]));
|
|
195
|
+
return (type) => {
|
|
196
|
+
const url = pathsIndexOf(type);
|
|
197
|
+
return (url === null ? undefined : byUrl.get(url)) ?? lookup(type);
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* The rejection of a covered path item: only one proven not assignable to the signature's type
|
|
203
|
+
* counts (ADR-028). A pair the proof cannot decide keeps the original output, which may well
|
|
204
|
+
* compile (`Record<string, never>` fits `{ [key: string]: unknown }`).
|
|
205
|
+
*/
|
|
206
|
+
function rejectionOf(paths: readonly PathMember[], lookup: DeclaredTypeLookup): CoverRejection {
|
|
207
|
+
const relate = assignabilityProof(withPathItems(paths, lookup));
|
|
208
|
+
return (coveringIndex, coveredIndex) => {
|
|
209
|
+
const coveringPath = paths[coveringIndex];
|
|
210
|
+
const coveredPath = paths[coveredIndex];
|
|
211
|
+
return (
|
|
212
|
+
coveringPath !== undefined &&
|
|
213
|
+
coveredPath !== undefined &&
|
|
214
|
+
relate(coveredPath.type, coveringPath.type) === "rejected"
|
|
215
|
+
);
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
159
219
|
/**
|
|
160
220
|
* The members as one object type. When an index signature covers another key, TypeScript checks
|
|
161
221
|
* the covered key's type against it. Where that check surely fails (TS2411, TS2413), each such
|
|
162
222
|
* signature gets an object of its own in an intersection: an intersection does not check its parts
|
|
163
223
|
* against each other, and every key has the type it had in the one object. Output that compiles
|
|
164
|
-
* keeps the one object.
|
|
224
|
+
* keeps the one object. The lookup reads the types that path items reference; without it, a
|
|
225
|
+
* reference decides nothing.
|
|
165
226
|
*/
|
|
166
|
-
function pathsObjectType(
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return (
|
|
173
|
-
coveringPath !== undefined &&
|
|
174
|
-
coveredPath !== undefined &&
|
|
175
|
-
isCoveredPathItemRejected(coveredPath.type, coveringPath.type)
|
|
176
|
-
);
|
|
177
|
-
},
|
|
178
|
-
);
|
|
227
|
+
export function pathsObjectType(
|
|
228
|
+
paths: readonly PathMember[],
|
|
229
|
+
lookup: DeclaredTypeLookup = NO_DECLARED_TYPES,
|
|
230
|
+
): IrType {
|
|
231
|
+
const keys = paths.map(({ key }) => key);
|
|
232
|
+
const covering = coveringTemplateKeys(keys, rejectionOf(paths, lookup));
|
|
179
233
|
if (covering.size === 0) {
|
|
180
234
|
return irObject(paths.map(({ member }) => member));
|
|
181
235
|
}
|
|
@@ -186,8 +240,8 @@ function pathsObjectType(paths: readonly PathMember[]): IrType {
|
|
|
186
240
|
return irIntersection([irObject(rest), ...own]);
|
|
187
241
|
}
|
|
188
242
|
|
|
189
|
-
/** The `paths` interface
|
|
190
|
-
export function
|
|
243
|
+
/** The members of the `paths` interface (OpenAPI 3.1 §4.8.8): one per path, by URL. */
|
|
244
|
+
export function pathMembers(paths: PathsObject, context: TransformContext): PathMember[] {
|
|
191
245
|
const members: PathMember[] = [];
|
|
192
246
|
for (const [url, pathItem] of documentEntries(paths, context.options)) {
|
|
193
247
|
if (!pathItem || typeof pathItem !== "object") {
|
|
@@ -196,7 +250,7 @@ export function pathsType(paths: PathsObject, context: TransformContext): IrType
|
|
|
196
250
|
if ("$ref" in pathItem) {
|
|
197
251
|
const options = { isReadonly: context.options.immutable };
|
|
198
252
|
const member = documentMember(url, refType(pathItem.$ref), pathItem, options);
|
|
199
|
-
members.push({ member, key: literalKey(url), type: member.type });
|
|
253
|
+
members.push({ url, member, key: literalKey(url), type: member.type });
|
|
200
254
|
continue;
|
|
201
255
|
}
|
|
202
256
|
const startedAt = context.diagnostics.now();
|
|
@@ -207,5 +261,13 @@ export function pathsType(paths: PathsObject, context: TransformContext): IrType
|
|
|
207
261
|
context.diagnostics.debug(`Transformed path "${url}"`, context.diagnostics.now() - startedAt);
|
|
208
262
|
}
|
|
209
263
|
}
|
|
210
|
-
return
|
|
264
|
+
return members;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* The `paths` interface body, with only the path items' own types for the overlap check. The
|
|
269
|
+
* document transform checks the overlaps again once the referenced types are declared.
|
|
270
|
+
*/
|
|
271
|
+
export function pathsType(paths: PathsObject, context: TransformContext): IrType {
|
|
272
|
+
return pathsObjectType(pathMembers(paths, context));
|
|
211
273
|
}
|
|
@@ -2,6 +2,7 @@ import { irRaw } from "../../../domain/ir/constructors.js";
|
|
|
2
2
|
import type { IrDeclaration, IrTypeAliasDeclaration } from "../../../domain/ir/nodes.js";
|
|
3
3
|
import { escapeSingleQuotedText } from "../../../domain/ir/raw-text-escapes.js";
|
|
4
4
|
import type { ComponentKind } from "../../../domain/openapi/components-object.js";
|
|
5
|
+
import { globalTypeReferences } from "./global-type-references.js";
|
|
5
6
|
|
|
6
7
|
/** The `--root-types` aliases: `export type Pet = components['schemas']['Pet'];`. */
|
|
7
8
|
|
|
@@ -66,37 +67,37 @@ function freeName(name: string, taken: ReadonlySet<string>): string {
|
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
/**
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
70
|
+
* Rename each root alias whose name an enum or a helper type of the footer also declares, or that
|
|
71
|
+
* shadows a TypeScript global type the output refers to (`Record` in `Record<string, never>`), to
|
|
72
|
+
* the next free `Name_2`, `Name_3`, … (the suffix `--root-types` uses for its own conflicts). The
|
|
73
|
+
* footer and the globals keep their names, because the generated types refer to them. Before, the
|
|
74
|
+
* output did not compile (enums: upstream #2099, #2341, #2206; helpers: a schema named
|
|
75
|
+
* `WithRequired`, roadmap R11; globals: TS2315). Other declarations are returned unchanged.
|
|
76
|
+
*
|
|
77
|
+
* With the `root-type-numbering` fix (ADR-021, roadmap R13, backlog 30) the body also holds the
|
|
78
|
+
* aliases a later schema of one exported name took the name from, after the other aliases and
|
|
79
|
+
* under that same name. Each gets the next free number in body order, after the alias that kept
|
|
80
|
+
* the name got its own: so the fix only adds exports, and every other alias keeps the name it has
|
|
81
|
+
* without the fix.
|
|
72
82
|
*/
|
|
73
|
-
export function
|
|
74
|
-
|
|
75
|
-
kept: readonly IrTypeAliasDeclaration[],
|
|
76
|
-
): IrTypeAliasDeclaration[] {
|
|
77
|
-
const taken = new Set(kept.map((alias) => alias.name));
|
|
78
|
-
return displaced.map((alias) => {
|
|
79
|
-
const name = freeName(alias.name, taken);
|
|
80
|
-
taken.add(name);
|
|
81
|
-
return { ...alias, name };
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Rename each root alias whose name an enum or a helper type of the footer also declares, to the
|
|
87
|
-
* next free `Name_2`, `Name_3`, … (the suffix `--root-types` uses for its own conflicts). The
|
|
88
|
-
* footer keeps its names, because the generated types refer to them. Before, both were declared
|
|
89
|
-
* under one name, which does not compile (enums: upstream #2099, #2341, #2206; helpers: a schema
|
|
90
|
-
* named `WithRequired`, roadmap R11). Other declarations are returned unchanged.
|
|
91
|
-
*/
|
|
92
|
-
export function renameAliasesTakenByFooter(
|
|
93
|
-
body: readonly IrDeclaration[],
|
|
83
|
+
export function renameTakenAliases<T extends IrDeclaration>(
|
|
84
|
+
body: readonly T[],
|
|
94
85
|
footer: readonly IrDeclaration[],
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const
|
|
86
|
+
closing: readonly IrDeclaration[] = [],
|
|
87
|
+
): T[] {
|
|
88
|
+
const reserved = footerTypeNames(footer);
|
|
89
|
+
for (const name of globalTypeReferences([...body, ...footer, ...closing])) {
|
|
90
|
+
reserved.add(name);
|
|
91
|
+
}
|
|
92
|
+
const taken = declaredNames([...body, ...footer, ...closing]);
|
|
93
|
+
const aliasNames = new Set<string>();
|
|
98
94
|
return body.map((declaration) => {
|
|
99
|
-
if (!isRootTypeAlias(declaration)
|
|
95
|
+
if (!isRootTypeAlias(declaration)) {
|
|
96
|
+
return declaration;
|
|
97
|
+
}
|
|
98
|
+
const isRepeated = aliasNames.has(declaration.name);
|
|
99
|
+
aliasNames.add(declaration.name);
|
|
100
|
+
if (!isRepeated && !reserved.has(declaration.name)) {
|
|
100
101
|
return declaration;
|
|
101
102
|
}
|
|
102
103
|
const name = freeName(declaration.name, taken);
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a key type is assignable to a template literal key type, decided the way TypeScript's
|
|
3
|
+
* checker decides it (`inferFromLiteralPartsToTemplateLiteral` and
|
|
4
|
+
* `isValidTypeForTemplateLiteralPlaceholder` in TypeScript 5 and 6). An index signature checks
|
|
5
|
+
* exactly the keys that are assignable to its key type, so the overlap check must match the
|
|
6
|
+
* checker, not the strings a template stands for: the checker matches each text of the target at
|
|
7
|
+
* its first occurrence, so it misses some keys a regular expression would match, and a key it
|
|
8
|
+
* misses is never checked against the signature.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** A placeholder type of a template, after `${boolean}` became the texts `true` and `false`. */
|
|
12
|
+
export type TemplatePlaceholder = "string" | "number";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A key type as TypeScript stores a template literal: texts around placeholders, one more text
|
|
16
|
+
* than placeholders. A string literal is one text and no placeholder.
|
|
17
|
+
*/
|
|
18
|
+
export interface TemplateShape {
|
|
19
|
+
readonly texts: readonly string[];
|
|
20
|
+
readonly types: readonly TemplatePlaceholder[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** The text at an index of the shape; every caller passes one of `0 .. types.length`. */
|
|
24
|
+
function textAt(shape: TemplateShape, index: number): string {
|
|
25
|
+
return shape.texts[index] as string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The type the checker infers for one target placeholder: a text, or a slice of the source. */
|
|
29
|
+
type InferredMatch =
|
|
30
|
+
| { readonly kind: "text"; readonly text: string }
|
|
31
|
+
| { readonly kind: "template"; readonly shape: TemplateShape };
|
|
32
|
+
|
|
33
|
+
/** TypeScript's `isValidNumberString(text, false)`: a text that converts to a finite number. */
|
|
34
|
+
export function isNumberText(text: string): boolean {
|
|
35
|
+
return text !== "" && Number.isFinite(Number(text));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Whether the inferred type fits a placeholder: any string for `string`, a number for `number`. */
|
|
39
|
+
function isValidMatch(match: InferredMatch, placeholder: TemplatePlaceholder): boolean {
|
|
40
|
+
if (placeholder === "string") {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
if (match.kind === "text") {
|
|
44
|
+
return isNumberText(match.text);
|
|
45
|
+
}
|
|
46
|
+
const { texts, types } = match.shape;
|
|
47
|
+
return texts.length === 2 && texts[0] === "" && texts[1] === "" && types[0] === "number";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** The state of the scan through the source: the current text and the position in it. */
|
|
51
|
+
interface Cursor {
|
|
52
|
+
readonly segment: number;
|
|
53
|
+
readonly position: number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The scan of `inferFromLiteralPartsToTemplateLiteral`, over one source and one target. */
|
|
57
|
+
class LiteralPartsScan {
|
|
58
|
+
private readonly matches: InferredMatch[] = [];
|
|
59
|
+
private cursor: Cursor;
|
|
60
|
+
private readonly source: TemplateShape;
|
|
61
|
+
private readonly lastSourceIndex: number;
|
|
62
|
+
private readonly remainingEndText: string;
|
|
63
|
+
|
|
64
|
+
constructor(source: TemplateShape, startPosition: number, endTextLength: number) {
|
|
65
|
+
this.source = source;
|
|
66
|
+
this.lastSourceIndex = source.texts.length - 1;
|
|
67
|
+
const endText = textAt(source, this.lastSourceIndex);
|
|
68
|
+
this.remainingEndText = endText.slice(0, endText.length - endTextLength);
|
|
69
|
+
this.cursor = { segment: 0, position: startPosition };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** The matches for the target's texts between its first and last; null when one is missing. */
|
|
73
|
+
run(delimiters: readonly string[]): readonly InferredMatch[] | null {
|
|
74
|
+
for (const delimiter of delimiters) {
|
|
75
|
+
if (!this.matchDelimiter(delimiter)) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
this.addMatch(this.lastSourceIndex, this.sourceText(this.lastSourceIndex).length);
|
|
80
|
+
return this.matches;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private matchDelimiter(delimiter: string): boolean {
|
|
84
|
+
const { segment, position } = this.cursor;
|
|
85
|
+
if (delimiter.length > 0) {
|
|
86
|
+
const found = this.find(delimiter);
|
|
87
|
+
if (found === null) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
this.addMatch(found.segment, found.position);
|
|
91
|
+
this.cursor = { ...this.cursor, position: this.cursor.position + delimiter.length };
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
if (position < this.sourceText(segment).length) {
|
|
95
|
+
this.addMatch(segment, position + 1);
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
if (segment < this.lastSourceIndex) {
|
|
99
|
+
this.addMatch(segment + 1, 0);
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** The first occurrence of the delimiter at or after the cursor, in this or a later text. */
|
|
106
|
+
private find(delimiter: string): Cursor | null {
|
|
107
|
+
let { segment, position } = this.cursor;
|
|
108
|
+
while (segment < this.source.texts.length) {
|
|
109
|
+
const index = this.sourceText(segment).indexOf(delimiter, position);
|
|
110
|
+
if (index >= 0) {
|
|
111
|
+
return { segment, position: index };
|
|
112
|
+
}
|
|
113
|
+
segment += 1;
|
|
114
|
+
position = 0;
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private sourceText(index: number): string {
|
|
120
|
+
return index < this.lastSourceIndex ? textAt(this.source, index) : this.remainingEndText;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private addMatch(segment: number, position: number): void {
|
|
124
|
+
const start = this.cursor;
|
|
125
|
+
if (segment === start.segment) {
|
|
126
|
+
const text = this.sourceText(segment).slice(start.position, position);
|
|
127
|
+
this.matches.push({ kind: "text", text });
|
|
128
|
+
} else {
|
|
129
|
+
const texts = [
|
|
130
|
+
textAt(this.source, start.segment).slice(start.position),
|
|
131
|
+
...this.source.texts.slice(start.segment + 1, segment),
|
|
132
|
+
this.sourceText(segment).slice(0, position),
|
|
133
|
+
];
|
|
134
|
+
const types = this.source.types.slice(start.segment, segment);
|
|
135
|
+
this.matches.push({ kind: "template", shape: { texts, types } });
|
|
136
|
+
}
|
|
137
|
+
this.cursor = { segment, position };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** The checker's inferences for the target's placeholders; null when the texts do not fit. */
|
|
142
|
+
function inferMatches(
|
|
143
|
+
source: TemplateShape,
|
|
144
|
+
target: TemplateShape,
|
|
145
|
+
): readonly InferredMatch[] | null {
|
|
146
|
+
const sourceStart = textAt(source, 0);
|
|
147
|
+
const sourceEnd = textAt(source, source.texts.length - 1);
|
|
148
|
+
const targetStart = textAt(target, 0);
|
|
149
|
+
const targetEnd = textAt(target, target.texts.length - 1);
|
|
150
|
+
const isTooShort =
|
|
151
|
+
source.texts.length === 1 && sourceStart.length < targetStart.length + targetEnd.length;
|
|
152
|
+
if (isTooShort || !sourceStart.startsWith(targetStart) || !sourceEnd.endsWith(targetEnd)) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
const scan = new LiteralPartsScan(source, targetStart.length, targetEnd.length);
|
|
156
|
+
return scan.run(target.texts.slice(1, -1));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function haveSameTexts(source: TemplateShape, target: TemplateShape): boolean {
|
|
160
|
+
return (
|
|
161
|
+
source.texts.length === target.texts.length &&
|
|
162
|
+
source.texts.every((text, index) => text === target.texts[index])
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Whether the source key type is assignable to the target template. Templates with the same texts
|
|
168
|
+
* compare placeholder by placeholder (`inferTypesFromTemplateLiteralType`).
|
|
169
|
+
*/
|
|
170
|
+
export function isAssignableToTemplate(source: TemplateShape, target: TemplateShape): boolean {
|
|
171
|
+
if (source.types.length > 0 && haveSameTexts(source, target)) {
|
|
172
|
+
return source.types.every((type, index) => {
|
|
173
|
+
const placeholder = target.types[index];
|
|
174
|
+
return placeholder === "string" || type === placeholder;
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
const matches = inferMatches(source, target);
|
|
178
|
+
const isEveryMatchValid = matches?.every((match, index) => {
|
|
179
|
+
const placeholder = target.types[index];
|
|
180
|
+
return placeholder !== undefined && isValidMatch(match, placeholder);
|
|
181
|
+
});
|
|
182
|
+
return isEveryMatchValid === true;
|
|
183
|
+
}
|