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
|
@@ -3,12 +3,30 @@
|
|
|
3
3
|
const fs = require('node:fs');
|
|
4
4
|
const path = require('node:path');
|
|
5
5
|
const openapiCore = require('@redocly/openapi-core');
|
|
6
|
+
const errors = require('../../domain/errors.cjs');
|
|
6
7
|
|
|
7
8
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
8
9
|
|
|
9
10
|
const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
|
|
10
11
|
const path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
11
12
|
|
|
13
|
+
function reasonOf(error) {
|
|
14
|
+
return String(error).replace(/\n[\s\S]*$/, "");
|
|
15
|
+
}
|
|
16
|
+
async function loadedConfig(load, configPath) {
|
|
17
|
+
try {
|
|
18
|
+
return await load();
|
|
19
|
+
} catch (error) {
|
|
20
|
+
const config = configPath === void 0 ? "the default Redocly config" : `the Redocly config ${configPath}`;
|
|
21
|
+
const where = configPath === void 0 ? "in the working directory" : "next to it";
|
|
22
|
+
throw new errors.OpenAPITypesafeError({
|
|
23
|
+
code: errors.ERROR_CODES.CLI_CONFIG_INVALID,
|
|
24
|
+
message: `Cannot load ${config} or the ${openapiCore.IGNORE_FILE} ${where}: ${reasonOf(error)}`,
|
|
25
|
+
details: { configPath },
|
|
26
|
+
cause: error
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
12
30
|
class RedoclyConfigFiles {
|
|
13
31
|
#cwd;
|
|
14
32
|
constructor(cwd) {
|
|
@@ -25,13 +43,14 @@ class RedoclyConfigFiles {
|
|
|
25
43
|
return fs__default.statSync(resolved).isDirectory() ? openapiCore.findConfig(resolved) : resolved;
|
|
26
44
|
}
|
|
27
45
|
load(configPath) {
|
|
28
|
-
return openapiCore.loadConfig({ configPath });
|
|
46
|
+
return loadedConfig(() => openapiCore.loadConfig({ configPath }), configPath);
|
|
29
47
|
}
|
|
30
48
|
createDefault() {
|
|
31
|
-
|
|
49
|
+
const create = () => openapiCore.createConfig(
|
|
32
50
|
{ rules: { "operation-operationId-unique": { severity: "warn" } } },
|
|
33
51
|
{ extends: ["minimal"] }
|
|
34
52
|
);
|
|
53
|
+
return loadedConfig(create, void 0);
|
|
35
54
|
}
|
|
36
55
|
}
|
|
37
56
|
function createRedoclyConfigSource(cwd) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redocly-config-source.cjs","sources":["../../../src/adapters/redocly-loader/redocly-config-source.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { createConfig, findConfig, loadConfig } from \"@redocly/openapi-core\";\nimport type {\n RedoclyConfig,\n RedoclyConfigSource,\n} from \"../../application/ports/redocly-config-source.js\";\n\n/** The Redocly config port on `@redocly/openapi-core`, resolving paths from `cwd`. */\nclass RedoclyConfigFiles implements RedoclyConfigSource {\n readonly #cwd: string;\n\n constructor(cwd: string) {\n this.#cwd = cwd;\n }\n\n find(explicitPath: string | undefined): string | undefined {\n if (!explicitPath) {\n return findConfig(this.#cwd);\n }\n const resolved = path.resolve(this.#cwd, explicitPath);\n if (!fs.existsSync(resolved)) {\n return undefined;\n }\n return fs.statSync(resolved).isDirectory() ? findConfig(resolved) : resolved;\n }\n\n load(configPath: string): Promise<RedoclyConfig> {\n return loadConfig({ configPath });\n }\n\n createDefault(): Promise<RedoclyConfig> {\n
|
|
1
|
+
{"version":3,"file":"redocly-config-source.cjs","sources":["../../../src/adapters/redocly-loader/redocly-config-source.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { createConfig, findConfig, IGNORE_FILE, loadConfig } from \"@redocly/openapi-core\";\nimport type {\n RedoclyConfig,\n RedoclyConfigSource,\n} from \"../../application/ports/redocly-config-source.js\";\nimport { ERROR_CODES, OpenAPITypesafeError } from \"../../domain/errors.js\";\n\n/**\n * The first line of a failure, with the error's name: a YAML error goes on with a snippet of the\n * file, and the name tells a YAML error from a file system one.\n */\nfunction reasonOf(error: unknown): string {\n return String(error).replace(/\\n[\\s\\S]*$/, \"\");\n}\n\n/**\n * The config, or `CLI_CONFIG_INVALID`. Redocly reads the config file and the lint-ignore file\n * next to it (or in the working directory); either can be malformed, and its error does not\n * always name the file, so the message names both.\n */\nasync function loadedConfig(\n load: () => Promise<RedoclyConfig>,\n configPath: string | undefined,\n): Promise<RedoclyConfig> {\n try {\n return await load();\n } catch (error) {\n const config =\n configPath === undefined ? \"the default Redocly config\" : `the Redocly config ${configPath}`;\n const where = configPath === undefined ? \"in the working directory\" : \"next to it\";\n throw new OpenAPITypesafeError({\n code: ERROR_CODES.CLI_CONFIG_INVALID,\n message: `Cannot load ${config} or the ${IGNORE_FILE} ${where}: ${reasonOf(error)}`,\n details: { configPath },\n cause: error,\n });\n }\n}\n\n/** The Redocly config port on `@redocly/openapi-core`, resolving paths from `cwd`. */\nclass RedoclyConfigFiles implements RedoclyConfigSource {\n readonly #cwd: string;\n\n constructor(cwd: string) {\n this.#cwd = cwd;\n }\n\n find(explicitPath: string | undefined): string | undefined {\n if (!explicitPath) {\n return findConfig(this.#cwd);\n }\n const resolved = path.resolve(this.#cwd, explicitPath);\n if (!fs.existsSync(resolved)) {\n return undefined;\n }\n return fs.statSync(resolved).isDirectory() ? findConfig(resolved) : resolved;\n }\n\n load(configPath: string): Promise<RedoclyConfig> {\n return loadedConfig(() => loadConfig({ configPath }), configPath);\n }\n\n createDefault(): Promise<RedoclyConfig> {\n const create = () =>\n createConfig(\n { rules: { \"operation-operationId-unique\": { severity: \"warn\" } } },\n { extends: [\"minimal\"] },\n );\n return loadedConfig(create, undefined);\n }\n}\n\n/** Find and load `redocly.yaml` relative to the directory `cwd`. */\nexport function createRedoclyConfigSource(cwd: string): RedoclyConfigSource {\n return new RedoclyConfigFiles(cwd);\n}\n"],"names":["OpenAPITypesafeError","ERROR_CODES","IGNORE_FILE","findConfig","path","fs","loadConfig","createConfig"],"mappings":";;;;;;;;;;;;AAaA,SAAS,SAAS,KAAA,EAAwB;AACxC,EAAA,OAAO,MAAA,CAAO,KAAK,CAAA,CAAE,OAAA,CAAQ,cAAc,EAAE,CAAA;AAC/C;AAOA,eAAe,YAAA,CACb,MACA,UAAA,EACwB;AACxB,EAAA,IAAI;AACF,IAAA,OAAO,MAAM,IAAA,EAAK;AAAA,EACpB,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,MAAA,GACJ,UAAA,KAAe,MAAA,GAAY,4BAAA,GAA+B,sBAAsB,UAAU,CAAA,CAAA;AAC5F,IAAA,MAAM,KAAA,GAAQ,UAAA,KAAe,MAAA,GAAY,0BAAA,GAA6B,YAAA;AACtE,IAAA,MAAM,IAAIA,2BAAA,CAAqB;AAAA,MAC7B,MAAMC,kBAAA,CAAY,kBAAA;AAAA,MAClB,OAAA,EAAS,CAAA,YAAA,EAAe,MAAM,CAAA,QAAA,EAAWC,uBAAW,IAAI,KAAK,CAAA,EAAA,EAAK,QAAA,CAAS,KAAK,CAAC,CAAA,CAAA;AAAA,MACjF,OAAA,EAAS,EAAE,UAAA,EAAW;AAAA,MACtB,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AACF;AAGA,MAAM,kBAAA,CAAkD;AAAA,EAC7C,IAAA;AAAA,EAET,YAAY,GAAA,EAAa;AACvB,IAAA,IAAA,CAAK,IAAA,GAAO,GAAA;AAAA,EACd;AAAA,EAEA,KAAK,YAAA,EAAsD;AACzD,IAAA,IAAI,CAAC,YAAA,EAAc;AACjB,MAAA,OAAOC,sBAAA,CAAW,KAAK,IAAI,CAAA;AAAA,IAC7B;AACA,IAAA,MAAM,QAAA,GAAWC,aAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,MAAM,YAAY,CAAA;AACrD,IAAA,IAAI,CAACC,WAAA,CAAG,UAAA,CAAW,QAAQ,CAAA,EAAG;AAC5B,MAAA,OAAO,MAAA;AAAA,IACT;AACA,IAAA,OAAOA,WAAA,CAAG,SAAS,QAAQ,CAAA,CAAE,aAAY,GAAIF,sBAAA,CAAW,QAAQ,CAAA,GAAI,QAAA;AAAA,EACtE;AAAA,EAEA,KAAK,UAAA,EAA4C;AAC/C,IAAA,OAAO,aAAa,MAAMG,sBAAA,CAAW,EAAE,UAAA,EAAY,GAAG,UAAU,CAAA;AAAA,EAClE;AAAA,EAEA,aAAA,GAAwC;AACtC,IAAA,MAAM,SAAS,MACbC,wBAAA;AAAA,MACE,EAAE,OAAO,EAAE,8BAAA,EAAgC,EAAE,QAAA,EAAU,MAAA,IAAS,EAAE;AAAA,MAClE,EAAE,OAAA,EAAS,CAAC,SAAS,CAAA;AAAE,KACzB;AACF,IAAA,OAAO,YAAA,CAAa,QAAQ,MAAS,CAAA;AAAA,EACvC;AACF;AAGO,SAAS,0BAA0B,GAAA,EAAkC;AAC1E,EAAA,OAAO,IAAI,mBAAmB,GAAG,CAAA;AACnC;;"}
|
|
@@ -1,7 +1,25 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { findConfig, loadConfig, createConfig } from '@redocly/openapi-core';
|
|
3
|
+
import { findConfig, IGNORE_FILE, loadConfig, createConfig } from '@redocly/openapi-core';
|
|
4
|
+
import { OpenAPITypesafeError, ERROR_CODES } from '../../domain/errors.mjs';
|
|
4
5
|
|
|
6
|
+
function reasonOf(error) {
|
|
7
|
+
return String(error).replace(/\n[\s\S]*$/, "");
|
|
8
|
+
}
|
|
9
|
+
async function loadedConfig(load, configPath) {
|
|
10
|
+
try {
|
|
11
|
+
return await load();
|
|
12
|
+
} catch (error) {
|
|
13
|
+
const config = configPath === void 0 ? "the default Redocly config" : `the Redocly config ${configPath}`;
|
|
14
|
+
const where = configPath === void 0 ? "in the working directory" : "next to it";
|
|
15
|
+
throw new OpenAPITypesafeError({
|
|
16
|
+
code: ERROR_CODES.CLI_CONFIG_INVALID,
|
|
17
|
+
message: `Cannot load ${config} or the ${IGNORE_FILE} ${where}: ${reasonOf(error)}`,
|
|
18
|
+
details: { configPath },
|
|
19
|
+
cause: error
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
5
23
|
class RedoclyConfigFiles {
|
|
6
24
|
#cwd;
|
|
7
25
|
constructor(cwd) {
|
|
@@ -18,13 +36,14 @@ class RedoclyConfigFiles {
|
|
|
18
36
|
return fs.statSync(resolved).isDirectory() ? findConfig(resolved) : resolved;
|
|
19
37
|
}
|
|
20
38
|
load(configPath) {
|
|
21
|
-
return loadConfig({ configPath });
|
|
39
|
+
return loadedConfig(() => loadConfig({ configPath }), configPath);
|
|
22
40
|
}
|
|
23
41
|
createDefault() {
|
|
24
|
-
|
|
42
|
+
const create = () => createConfig(
|
|
25
43
|
{ rules: { "operation-operationId-unique": { severity: "warn" } } },
|
|
26
44
|
{ extends: ["minimal"] }
|
|
27
45
|
);
|
|
46
|
+
return loadedConfig(create, void 0);
|
|
28
47
|
}
|
|
29
48
|
}
|
|
30
49
|
function createRedoclyConfigSource(cwd) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redocly-config-source.mjs","sources":["../../../src/adapters/redocly-loader/redocly-config-source.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { createConfig, findConfig, loadConfig } from \"@redocly/openapi-core\";\nimport type {\n RedoclyConfig,\n RedoclyConfigSource,\n} from \"../../application/ports/redocly-config-source.js\";\n\n/** The Redocly config port on `@redocly/openapi-core`, resolving paths from `cwd`. */\nclass RedoclyConfigFiles implements RedoclyConfigSource {\n readonly #cwd: string;\n\n constructor(cwd: string) {\n this.#cwd = cwd;\n }\n\n find(explicitPath: string | undefined): string | undefined {\n if (!explicitPath) {\n return findConfig(this.#cwd);\n }\n const resolved = path.resolve(this.#cwd, explicitPath);\n if (!fs.existsSync(resolved)) {\n return undefined;\n }\n return fs.statSync(resolved).isDirectory() ? findConfig(resolved) : resolved;\n }\n\n load(configPath: string): Promise<RedoclyConfig> {\n return loadConfig({ configPath });\n }\n\n createDefault(): Promise<RedoclyConfig> {\n
|
|
1
|
+
{"version":3,"file":"redocly-config-source.mjs","sources":["../../../src/adapters/redocly-loader/redocly-config-source.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { createConfig, findConfig, IGNORE_FILE, loadConfig } from \"@redocly/openapi-core\";\nimport type {\n RedoclyConfig,\n RedoclyConfigSource,\n} from \"../../application/ports/redocly-config-source.js\";\nimport { ERROR_CODES, OpenAPITypesafeError } from \"../../domain/errors.js\";\n\n/**\n * The first line of a failure, with the error's name: a YAML error goes on with a snippet of the\n * file, and the name tells a YAML error from a file system one.\n */\nfunction reasonOf(error: unknown): string {\n return String(error).replace(/\\n[\\s\\S]*$/, \"\");\n}\n\n/**\n * The config, or `CLI_CONFIG_INVALID`. Redocly reads the config file and the lint-ignore file\n * next to it (or in the working directory); either can be malformed, and its error does not\n * always name the file, so the message names both.\n */\nasync function loadedConfig(\n load: () => Promise<RedoclyConfig>,\n configPath: string | undefined,\n): Promise<RedoclyConfig> {\n try {\n return await load();\n } catch (error) {\n const config =\n configPath === undefined ? \"the default Redocly config\" : `the Redocly config ${configPath}`;\n const where = configPath === undefined ? \"in the working directory\" : \"next to it\";\n throw new OpenAPITypesafeError({\n code: ERROR_CODES.CLI_CONFIG_INVALID,\n message: `Cannot load ${config} or the ${IGNORE_FILE} ${where}: ${reasonOf(error)}`,\n details: { configPath },\n cause: error,\n });\n }\n}\n\n/** The Redocly config port on `@redocly/openapi-core`, resolving paths from `cwd`. */\nclass RedoclyConfigFiles implements RedoclyConfigSource {\n readonly #cwd: string;\n\n constructor(cwd: string) {\n this.#cwd = cwd;\n }\n\n find(explicitPath: string | undefined): string | undefined {\n if (!explicitPath) {\n return findConfig(this.#cwd);\n }\n const resolved = path.resolve(this.#cwd, explicitPath);\n if (!fs.existsSync(resolved)) {\n return undefined;\n }\n return fs.statSync(resolved).isDirectory() ? findConfig(resolved) : resolved;\n }\n\n load(configPath: string): Promise<RedoclyConfig> {\n return loadedConfig(() => loadConfig({ configPath }), configPath);\n }\n\n createDefault(): Promise<RedoclyConfig> {\n const create = () =>\n createConfig(\n { rules: { \"operation-operationId-unique\": { severity: \"warn\" } } },\n { extends: [\"minimal\"] },\n );\n return loadedConfig(create, undefined);\n }\n}\n\n/** Find and load `redocly.yaml` relative to the directory `cwd`. */\nexport function createRedoclyConfigSource(cwd: string): RedoclyConfigSource {\n return new RedoclyConfigFiles(cwd);\n}\n"],"names":[],"mappings":";;;;;AAaA,SAAS,SAAS,KAAA,EAAwB;AACxC,EAAA,OAAO,MAAA,CAAO,KAAK,CAAA,CAAE,OAAA,CAAQ,cAAc,EAAE,CAAA;AAC/C;AAOA,eAAe,YAAA,CACb,MACA,UAAA,EACwB;AACxB,EAAA,IAAI;AACF,IAAA,OAAO,MAAM,IAAA,EAAK;AAAA,EACpB,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,MAAA,GACJ,UAAA,KAAe,MAAA,GAAY,4BAAA,GAA+B,sBAAsB,UAAU,CAAA,CAAA;AAC5F,IAAA,MAAM,KAAA,GAAQ,UAAA,KAAe,MAAA,GAAY,0BAAA,GAA6B,YAAA;AACtE,IAAA,MAAM,IAAI,oBAAA,CAAqB;AAAA,MAC7B,MAAM,WAAA,CAAY,kBAAA;AAAA,MAClB,OAAA,EAAS,CAAA,YAAA,EAAe,MAAM,CAAA,QAAA,EAAW,WAAW,IAAI,KAAK,CAAA,EAAA,EAAK,QAAA,CAAS,KAAK,CAAC,CAAA,CAAA;AAAA,MACjF,OAAA,EAAS,EAAE,UAAA,EAAW;AAAA,MACtB,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AACF;AAGA,MAAM,kBAAA,CAAkD;AAAA,EAC7C,IAAA;AAAA,EAET,YAAY,GAAA,EAAa;AACvB,IAAA,IAAA,CAAK,IAAA,GAAO,GAAA;AAAA,EACd;AAAA,EAEA,KAAK,YAAA,EAAsD;AACzD,IAAA,IAAI,CAAC,YAAA,EAAc;AACjB,MAAA,OAAO,UAAA,CAAW,KAAK,IAAI,CAAA;AAAA,IAC7B;AACA,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,MAAM,YAAY,CAAA;AACrD,IAAA,IAAI,CAAC,EAAA,CAAG,UAAA,CAAW,QAAQ,CAAA,EAAG;AAC5B,MAAA,OAAO,MAAA;AAAA,IACT;AACA,IAAA,OAAO,EAAA,CAAG,SAAS,QAAQ,CAAA,CAAE,aAAY,GAAI,UAAA,CAAW,QAAQ,CAAA,GAAI,QAAA;AAAA,EACtE;AAAA,EAEA,KAAK,UAAA,EAA4C;AAC/C,IAAA,OAAO,aAAa,MAAM,UAAA,CAAW,EAAE,UAAA,EAAY,GAAG,UAAU,CAAA;AAAA,EAClE;AAAA,EAEA,aAAA,GAAwC;AACtC,IAAA,MAAM,SAAS,MACb,YAAA;AAAA,MACE,EAAE,OAAO,EAAE,8BAAA,EAAgC,EAAE,QAAA,EAAU,MAAA,IAAS,EAAE;AAAA,MAClE,EAAE,OAAA,EAAS,CAAC,SAAS,CAAA;AAAE,KACzB;AACF,IAAA,OAAO,YAAA,CAAa,QAAQ,MAAS,CAAA;AAAA,EACvC;AACF;AAGO,SAAS,0BAA0B,GAAA,EAAkC;AAC1E,EAAA,OAAO,IAAI,mBAAmB,GAAG,CAAA;AACnC;;"}
|
|
@@ -33,11 +33,10 @@ function assertOpenAPI3(document) {
|
|
|
33
33
|
}
|
|
34
34
|
throw schemaLoadErrors.versionUnsupportedError(UNSUPPORTED_FORMAT_MESSAGE, parsed);
|
|
35
35
|
}
|
|
36
|
+
const INLINE_SOURCE_NAME = "inline-source";
|
|
36
37
|
function sourceAbsoluteRef(source, cwd) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
return node_url.fileURLToPath(cwd);
|
|
38
|
+
const document = source instanceof URL ? source : new URL(INLINE_SOURCE_NAME, cwd);
|
|
39
|
+
return document.protocol === "file:" ? sourceFilePath(document) : document.href;
|
|
41
40
|
}
|
|
42
41
|
function sourceFilePath(source) {
|
|
43
42
|
try {
|
|
@@ -140,10 +139,21 @@ class RedoclySchemaLoader {
|
|
|
140
139
|
this.#options.logger.debug("Bundled schema", "bundle", this.#options.now() - startedAt);
|
|
141
140
|
return bundled.bundle.parsed;
|
|
142
141
|
}
|
|
143
|
-
/**
|
|
142
|
+
/**
|
|
143
|
+
* Report every problem; then throw if any of them is an error. A problem that the Redocly
|
|
144
|
+
* config's `.redocly.lint-ignore.yaml` lists is left out, as `redocly lint` leaves it out
|
|
145
|
+
* (upstream #2189).
|
|
146
|
+
*/
|
|
144
147
|
#report(problems) {
|
|
145
148
|
const errorMessages = [];
|
|
146
149
|
for (const problem of problems) {
|
|
150
|
+
if (problem.ignored === true) {
|
|
151
|
+
this.#options.logger.debug(
|
|
152
|
+
`Ignored by the lint ignore file: ${problemMessage(problem)}`,
|
|
153
|
+
"lint"
|
|
154
|
+
);
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
147
157
|
const message = problemMessage(problem);
|
|
148
158
|
if (problem.severity === "error") {
|
|
149
159
|
errorMessages.push(message);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redocly-schema-loader.cjs","sources":["../../../src/adapters/redocly-loader/redocly-schema-loader.ts"],"sourcesContent":["import { fileURLToPath } from \"node:url\";\nimport {\n type BaseResolver,\n bundle,\n type Document,\n lintDocument,\n type NormalizedProblem,\n type Config as RedoclyConfig,\n} from \"@redocly/openapi-core\";\nimport type { Logger } from \"../../application/ports/logger.js\";\nimport type { SchemaLoader, SchemaLoadRequest } from \"../../application/ports/schema-loader.js\";\nimport { withStackOverflowReportedAsync } from \"../../application/stack-overflow.js\";\nimport type { OpenAPI3 } from \"../../types.js\";\nimport { repairBundledRefs } from \"./bundled-ref-repair.js\";\nimport { findMalformedRefs, malformedRefsError } from \"./malformed-refs.js\";\nimport { RefAccessResolver } from \"./ref-access.js\";\nimport { resolveConfigWithAccess } from \"./remote-fetch.js\";\nimport {\n loadFailedError,\n refCycleError,\n schemaInvalidError,\n versionUnsupportedError,\n} from \"./schema-load-errors.js\";\nimport { parseSchema } from \"./schema-source.js\";\nimport {\n findUnsupportedKeys,\n type LoadedDocument,\n unsupportedKeysError,\n} from \"./unsupported-keys.js\";\n\n/**\n * The SchemaLoader port on Redocly 1.34 (ADR-005): parse any inherited source type, then lint and\n * bundle with the given Redocly config. Problems go to the logger; errors fail the load.\n */\nexport interface RedoclySchemaLoaderOptions {\n readonly redoc: RedoclyConfig;\n readonly logger: Logger;\n /** A monotonic time in milliseconds, for the debug durations. */\n readonly now: () => number;\n /** Time limit of one remote fetch, unless the Redocly config brings its own `customFetch`. */\n readonly remoteRefTimeoutMs: number;\n}\n\nconst UNSUPPORTED_FORMAT_MESSAGE = \"Unsupported schema format, expected `openapi: 3.x`\";\n\n/**\n * Accept OpenAPI 3.x only; Swagger 2 and other formats get their own message. An empty file or a\n * `null` root parses to nothing, so it is checked before any field is read.\n */\nfunction assertOpenAPI3(document: unknown): void {\n if (typeof document !== \"object\" || document === null) {\n throw versionUnsupportedError(UNSUPPORTED_FORMAT_MESSAGE, {});\n }\n const parsed = document as Record<string, unknown>;\n const openapiVersion = Number.parseFloat(parsed.openapi as string);\n const isOpenAPI3 =\n !parsed.swagger &&\n Boolean(parsed.openapi) &&\n !Number.isNaN(openapiVersion) &&\n openapiVersion >= 3 &&\n openapiVersion < 4;\n if (isOpenAPI3) {\n return;\n }\n if (parsed.swagger) {\n throw versionUnsupportedError(\n \"Unsupported Swagger version: 2.x. Use OpenAPI 3.x instead.\",\n parsed,\n );\n }\n if (parsed.openapi || openapiVersion < 3 || openapiVersion >= 4) {\n throw versionUnsupportedError(`Unsupported OpenAPI version: ${parsed.openapi}`, parsed);\n }\n throw versionUnsupportedError(UNSUPPORTED_FORMAT_MESSAGE, parsed);\n}\n\n/** The base for relative `$ref`s: the source file or URL itself, else the working directory. */\nfunction sourceAbsoluteRef(source: unknown, cwd: URL): string {\n if (source instanceof URL) {\n return source.protocol === \"file:\" ? sourceFilePath(source) : source.href;\n }\n return fileURLToPath(cwd);\n}\n\n/**\n * The path of a `file:` source. A URL that names no path on this platform (an encoded slash, a\n * host on POSIX, no drive letter on Windows) cannot be read, so it fails as a read would.\n */\nfunction sourceFilePath(source: URL): string {\n try {\n return fileURLToPath(source);\n } catch (error) {\n // Node.js reports these as TypeErrors (ERR_INVALID_FILE_URL_PATH, ERR_INVALID_FILE_URL_HOST).\n if (!(error instanceof TypeError)) {\n throw error;\n }\n throw loadFailedError(source.href, error);\n }\n}\n\n/** Redocly throws a plain Error for a `$ref` chain that points back to itself. */\nconst REF_CYCLE_MESSAGE = \"Self-referencing circular pointer\";\n\n/**\n * The root document and every other document the resolver loaded, as far as they parsed. A root\n * read from a file or URL is in the resolver cache too, and is listed once.\n */\nasync function loadedDocuments(root: Document, resolver: BaseResolver): Promise<LoadedDocument[]> {\n const cached = await Promise.all(resolver.cache.values());\n const bySource = new Map<string, unknown>([[root.source.absoluteRef, root.parsed]]);\n for (const document of cached) {\n if (\"parsed\" in document && !bySource.has(document.source.absoluteRef)) {\n bySource.set(document.source.absoluteRef, document.parsed);\n }\n }\n return [...bySource].map(([source, parsed]) => ({ source, parsed }));\n}\n\n/** Report the document problems Redocly throws as typed errors; anything else passes through. */\nasync function rethrowDocumentError(\n error: unknown,\n root: Document,\n resolver: BaseResolver,\n): Promise<never> {\n if (error instanceof Error && error.message === REF_CYCLE_MESSAGE) {\n throw refCycleError(error);\n }\n if (error instanceof URIError) {\n throw malformedRefsError(findMalformedRefs(await loadedDocuments(root, resolver)), error);\n }\n if (error instanceof TypeError) {\n const keys = findUnsupportedKeys(await loadedDocuments(root, resolver));\n throw keys.length === 0 ? error : unsupportedKeysError(keys, error);\n }\n throw error;\n}\n\nclass RedoclySchemaLoader implements SchemaLoader {\n readonly #options: RedoclySchemaLoaderOptions;\n\n constructor(options: RedoclySchemaLoaderOptions) {\n this.#options = options;\n }\n\n async load(request: SchemaLoadRequest): Promise<OpenAPI3> {\n const resolver = this.#resolver(request);\n // Parsing is guarded too: `JSON.stringify` of a deep object source overflows the stack on\n // Node.js 22 and 24, before linting starts.\n const bundled = await withStackOverflowReportedAsync(\"load\", () =>\n this.#parseAndBundle(request, resolver),\n ).catch((error: unknown) => {\n throw resolver.firstRefusal ?? error;\n });\n // A refused `$ref` is an unresolved-`$ref` problem, which a Redocly config can turn off.\n if (resolver.firstRefusal !== undefined) {\n throw resolver.firstRefusal;\n }\n return bundled;\n }\n\n async #parseAndBundle(request: SchemaLoadRequest, resolver: BaseResolver): Promise<OpenAPI3> {\n const { logger, now } = this.#options;\n const configLoadedAt = now();\n logger.debug(\"Loaded Redoc config\", \"redoc\", now() - configLoadedAt);\n const parseStartedAt = now();\n const absoluteRef = sourceAbsoluteRef(request.source, request.cwd);\n const document = await parseSchema(request.source, { absoluteRef, resolver });\n logger.debug(\"Parsed schema\", \"redoc\", now() - parseStartedAt);\n assertOpenAPI3(document.parsed);\n return this.#lintAndBundle(document, resolver, request.shouldLint);\n }\n\n #resolver(request: SchemaLoadRequest): RefAccessResolver {\n const { redoc, remoteRefTimeoutMs } = this.#options;\n const config = resolveConfigWithAccess(redoc.resolve, {\n timeoutMs: remoteRefTimeoutMs,\n access: request.refAccess,\n });\n return new RefAccessResolver(config, request.refAccess);\n }\n\n async #lintAndBundle(\n document: Document,\n resolver: BaseResolver,\n shouldLint: boolean,\n ): Promise<OpenAPI3> {\n const rethrow = (error: unknown) => rethrowDocumentError(error, document, resolver);\n if (shouldLint) {\n await this.#lint(document, resolver).catch(rethrow);\n }\n return this.#bundle(document, resolver).catch(rethrow);\n }\n\n async #lint(document: Document, resolver: BaseResolver): Promise<void> {\n const startedAt = this.#options.now();\n const problems = await lintDocument({\n document,\n config: this.#options.redoc.styleguide,\n externalRefResolver: resolver,\n });\n this.#report(problems);\n this.#options.logger.debug(\"Linted schema\", \"lint\", this.#options.now() - startedAt);\n }\n\n async #bundle(document: Document, resolver: BaseResolver): Promise<OpenAPI3> {\n const startedAt = this.#options.now();\n // The lint resolver: documents it already loaded are not fetched again.\n const bundled = await bundle({\n config: this.#options.redoc,\n dereference: false,\n doc: document,\n externalRefResolver: resolver,\n });\n this.#report(bundled.problems);\n repairBundledRefs(bundled.bundle.parsed);\n this.#options.logger.debug(\"Bundled schema\", \"bundle\", this.#options.now() - startedAt);\n return bundled.bundle.parsed;\n }\n\n /** Report every problem; then throw if any of them is an error. */\n #report(problems: readonly NormalizedProblem[]): void {\n const errorMessages: string[] = [];\n for (const problem of problems) {\n const message = problemMessage(problem);\n if (problem.severity === \"error\") {\n errorMessages.push(message);\n this.#options.logger.error(message);\n } else {\n this.#options.logger.warn(message);\n }\n }\n if (errorMessages.length > 0) {\n throw schemaInvalidError(errorMessages);\n }\n }\n}\n\nfunction problemMessage(problem: NormalizedProblem): string {\n const location = problem.location?.[0]?.pointer;\n return location ? `${problem.message} at ${location}` : problem.message;\n}\n\n/** A schema loader with one Redocly config and logger, for one or more loads. */\nexport function createRedoclySchemaLoader(options: RedoclySchemaLoaderOptions): SchemaLoader {\n return new RedoclySchemaLoader(options);\n}\n"],"names":["versionUnsupportedError","fileURLToPath","loadFailedError","refCycleError","malformedRefsError","findMalformedRefs","findUnsupportedKeys","unsupportedKeysError","withStackOverflowReportedAsync","parseSchema","resolveConfigWithAccess","RefAccessResolver","lintDocument","bundle","repairBundledRefs","schemaInvalidError"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"redocly-schema-loader.cjs","sources":["../../../src/adapters/redocly-loader/redocly-schema-loader.ts"],"sourcesContent":["import { fileURLToPath } from \"node:url\";\nimport {\n type BaseResolver,\n bundle,\n type Document,\n lintDocument,\n type NormalizedProblem,\n type Config as RedoclyConfig,\n} from \"@redocly/openapi-core\";\nimport type { Logger } from \"../../application/ports/logger.js\";\nimport type { SchemaLoader, SchemaLoadRequest } from \"../../application/ports/schema-loader.js\";\nimport { withStackOverflowReportedAsync } from \"../../application/stack-overflow.js\";\nimport type { OpenAPI3 } from \"../../types.js\";\nimport { repairBundledRefs } from \"./bundled-ref-repair.js\";\nimport { findMalformedRefs, malformedRefsError } from \"./malformed-refs.js\";\nimport { RefAccessResolver } from \"./ref-access.js\";\nimport { resolveConfigWithAccess } from \"./remote-fetch.js\";\nimport {\n loadFailedError,\n refCycleError,\n schemaInvalidError,\n versionUnsupportedError,\n} from \"./schema-load-errors.js\";\nimport { parseSchema } from \"./schema-source.js\";\nimport {\n findUnsupportedKeys,\n type LoadedDocument,\n unsupportedKeysError,\n} from \"./unsupported-keys.js\";\n\n/**\n * The SchemaLoader port on Redocly 1.34 (ADR-005): parse any inherited source type, then lint and\n * bundle with the given Redocly config. Problems go to the logger; errors fail the load.\n */\nexport interface RedoclySchemaLoaderOptions {\n readonly redoc: RedoclyConfig;\n readonly logger: Logger;\n /** A monotonic time in milliseconds, for the debug durations. */\n readonly now: () => number;\n /** Time limit of one remote fetch, unless the Redocly config brings its own `customFetch`. */\n readonly remoteRefTimeoutMs: number;\n}\n\nconst UNSUPPORTED_FORMAT_MESSAGE = \"Unsupported schema format, expected `openapi: 3.x`\";\n\n/**\n * Accept OpenAPI 3.x only; Swagger 2 and other formats get their own message. An empty file or a\n * `null` root parses to nothing, so it is checked before any field is read.\n */\nfunction assertOpenAPI3(document: unknown): void {\n if (typeof document !== \"object\" || document === null) {\n throw versionUnsupportedError(UNSUPPORTED_FORMAT_MESSAGE, {});\n }\n const parsed = document as Record<string, unknown>;\n const openapiVersion = Number.parseFloat(parsed.openapi as string);\n const isOpenAPI3 =\n !parsed.swagger &&\n Boolean(parsed.openapi) &&\n !Number.isNaN(openapiVersion) &&\n openapiVersion >= 3 &&\n openapiVersion < 4;\n if (isOpenAPI3) {\n return;\n }\n if (parsed.swagger) {\n throw versionUnsupportedError(\n \"Unsupported Swagger version: 2.x. Use OpenAPI 3.x instead.\",\n parsed,\n );\n }\n if (parsed.openapi || openapiVersion < 3 || openapiVersion >= 4) {\n throw versionUnsupportedError(`Unsupported OpenAPI version: ${parsed.openapi}`, parsed);\n }\n throw versionUnsupportedError(UNSUPPORTED_FORMAT_MESSAGE, parsed);\n}\n\n/**\n * The name an inline source (a string, object, buffer or stream) gets inside the working\n * directory. Redocly resolves relative `$ref`s against the directory of the document, so the\n * document must be named as a file in the working directory, not as the directory itself.\n */\nconst INLINE_SOURCE_NAME = \"inline-source\";\n\n/** The base for relative `$ref`s: the source file or URL itself, else a file in the cwd. */\nfunction sourceAbsoluteRef(source: unknown, cwd: URL): string {\n const document = source instanceof URL ? source : new URL(INLINE_SOURCE_NAME, cwd);\n return document.protocol === \"file:\" ? sourceFilePath(document) : document.href;\n}\n\n/**\n * The path of a `file:` source. A URL that names no path on this platform (an encoded slash, a\n * host on POSIX, no drive letter on Windows) cannot be read, so it fails as a read would.\n */\nfunction sourceFilePath(source: URL): string {\n try {\n return fileURLToPath(source);\n } catch (error) {\n // Node.js reports these as TypeErrors (ERR_INVALID_FILE_URL_PATH, ERR_INVALID_FILE_URL_HOST).\n if (!(error instanceof TypeError)) {\n throw error;\n }\n throw loadFailedError(source.href, error);\n }\n}\n\n/** Redocly throws a plain Error for a `$ref` chain that points back to itself. */\nconst REF_CYCLE_MESSAGE = \"Self-referencing circular pointer\";\n\n/**\n * The root document and every other document the resolver loaded, as far as they parsed. A root\n * read from a file or URL is in the resolver cache too, and is listed once.\n */\nasync function loadedDocuments(root: Document, resolver: BaseResolver): Promise<LoadedDocument[]> {\n const cached = await Promise.all(resolver.cache.values());\n const bySource = new Map<string, unknown>([[root.source.absoluteRef, root.parsed]]);\n for (const document of cached) {\n if (\"parsed\" in document && !bySource.has(document.source.absoluteRef)) {\n bySource.set(document.source.absoluteRef, document.parsed);\n }\n }\n return [...bySource].map(([source, parsed]) => ({ source, parsed }));\n}\n\n/** Report the document problems Redocly throws as typed errors; anything else passes through. */\nasync function rethrowDocumentError(\n error: unknown,\n root: Document,\n resolver: BaseResolver,\n): Promise<never> {\n if (error instanceof Error && error.message === REF_CYCLE_MESSAGE) {\n throw refCycleError(error);\n }\n if (error instanceof URIError) {\n throw malformedRefsError(findMalformedRefs(await loadedDocuments(root, resolver)), error);\n }\n if (error instanceof TypeError) {\n const keys = findUnsupportedKeys(await loadedDocuments(root, resolver));\n throw keys.length === 0 ? error : unsupportedKeysError(keys, error);\n }\n throw error;\n}\n\nclass RedoclySchemaLoader implements SchemaLoader {\n readonly #options: RedoclySchemaLoaderOptions;\n\n constructor(options: RedoclySchemaLoaderOptions) {\n this.#options = options;\n }\n\n async load(request: SchemaLoadRequest): Promise<OpenAPI3> {\n const resolver = this.#resolver(request);\n // Parsing is guarded too: `JSON.stringify` of a deep object source overflows the stack on\n // Node.js 22 and 24, before linting starts.\n const bundled = await withStackOverflowReportedAsync(\"load\", () =>\n this.#parseAndBundle(request, resolver),\n ).catch((error: unknown) => {\n throw resolver.firstRefusal ?? error;\n });\n // A refused `$ref` is an unresolved-`$ref` problem, which a Redocly config can turn off.\n if (resolver.firstRefusal !== undefined) {\n throw resolver.firstRefusal;\n }\n return bundled;\n }\n\n async #parseAndBundle(request: SchemaLoadRequest, resolver: BaseResolver): Promise<OpenAPI3> {\n const { logger, now } = this.#options;\n const configLoadedAt = now();\n logger.debug(\"Loaded Redoc config\", \"redoc\", now() - configLoadedAt);\n const parseStartedAt = now();\n const absoluteRef = sourceAbsoluteRef(request.source, request.cwd);\n const document = await parseSchema(request.source, { absoluteRef, resolver });\n logger.debug(\"Parsed schema\", \"redoc\", now() - parseStartedAt);\n assertOpenAPI3(document.parsed);\n return this.#lintAndBundle(document, resolver, request.shouldLint);\n }\n\n #resolver(request: SchemaLoadRequest): RefAccessResolver {\n const { redoc, remoteRefTimeoutMs } = this.#options;\n const config = resolveConfigWithAccess(redoc.resolve, {\n timeoutMs: remoteRefTimeoutMs,\n access: request.refAccess,\n });\n return new RefAccessResolver(config, request.refAccess);\n }\n\n async #lintAndBundle(\n document: Document,\n resolver: BaseResolver,\n shouldLint: boolean,\n ): Promise<OpenAPI3> {\n const rethrow = (error: unknown) => rethrowDocumentError(error, document, resolver);\n if (shouldLint) {\n await this.#lint(document, resolver).catch(rethrow);\n }\n return this.#bundle(document, resolver).catch(rethrow);\n }\n\n async #lint(document: Document, resolver: BaseResolver): Promise<void> {\n const startedAt = this.#options.now();\n const problems = await lintDocument({\n document,\n config: this.#options.redoc.styleguide,\n externalRefResolver: resolver,\n });\n this.#report(problems);\n this.#options.logger.debug(\"Linted schema\", \"lint\", this.#options.now() - startedAt);\n }\n\n async #bundle(document: Document, resolver: BaseResolver): Promise<OpenAPI3> {\n const startedAt = this.#options.now();\n // The lint resolver: documents it already loaded are not fetched again.\n const bundled = await bundle({\n config: this.#options.redoc,\n dereference: false,\n doc: document,\n externalRefResolver: resolver,\n });\n this.#report(bundled.problems);\n repairBundledRefs(bundled.bundle.parsed);\n this.#options.logger.debug(\"Bundled schema\", \"bundle\", this.#options.now() - startedAt);\n return bundled.bundle.parsed;\n }\n\n /**\n * Report every problem; then throw if any of them is an error. A problem that the Redocly\n * config's `.redocly.lint-ignore.yaml` lists is left out, as `redocly lint` leaves it out\n * (upstream #2189).\n */\n #report(problems: readonly NormalizedProblem[]): void {\n const errorMessages: string[] = [];\n for (const problem of problems) {\n if (problem.ignored === true) {\n this.#options.logger.debug(\n `Ignored by the lint ignore file: ${problemMessage(problem)}`,\n \"lint\",\n );\n continue;\n }\n const message = problemMessage(problem);\n if (problem.severity === \"error\") {\n errorMessages.push(message);\n this.#options.logger.error(message);\n } else {\n this.#options.logger.warn(message);\n }\n }\n if (errorMessages.length > 0) {\n throw schemaInvalidError(errorMessages);\n }\n }\n}\n\nfunction problemMessage(problem: NormalizedProblem): string {\n const location = problem.location?.[0]?.pointer;\n return location ? `${problem.message} at ${location}` : problem.message;\n}\n\n/** A schema loader with one Redocly config and logger, for one or more loads. */\nexport function createRedoclySchemaLoader(options: RedoclySchemaLoaderOptions): SchemaLoader {\n return new RedoclySchemaLoader(options);\n}\n"],"names":["versionUnsupportedError","fileURLToPath","loadFailedError","refCycleError","malformedRefsError","findMalformedRefs","findUnsupportedKeys","unsupportedKeysError","withStackOverflowReportedAsync","parseSchema","resolveConfigWithAccess","RefAccessResolver","lintDocument","bundle","repairBundledRefs","schemaInvalidError"],"mappings":"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"}
|
|
@@ -31,11 +31,10 @@ function assertOpenAPI3(document) {
|
|
|
31
31
|
}
|
|
32
32
|
throw versionUnsupportedError(UNSUPPORTED_FORMAT_MESSAGE, parsed);
|
|
33
33
|
}
|
|
34
|
+
const INLINE_SOURCE_NAME = "inline-source";
|
|
34
35
|
function sourceAbsoluteRef(source, cwd) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
return fileURLToPath(cwd);
|
|
36
|
+
const document = source instanceof URL ? source : new URL(INLINE_SOURCE_NAME, cwd);
|
|
37
|
+
return document.protocol === "file:" ? sourceFilePath(document) : document.href;
|
|
39
38
|
}
|
|
40
39
|
function sourceFilePath(source) {
|
|
41
40
|
try {
|
|
@@ -138,10 +137,21 @@ class RedoclySchemaLoader {
|
|
|
138
137
|
this.#options.logger.debug("Bundled schema", "bundle", this.#options.now() - startedAt);
|
|
139
138
|
return bundled.bundle.parsed;
|
|
140
139
|
}
|
|
141
|
-
/**
|
|
140
|
+
/**
|
|
141
|
+
* Report every problem; then throw if any of them is an error. A problem that the Redocly
|
|
142
|
+
* config's `.redocly.lint-ignore.yaml` lists is left out, as `redocly lint` leaves it out
|
|
143
|
+
* (upstream #2189).
|
|
144
|
+
*/
|
|
142
145
|
#report(problems) {
|
|
143
146
|
const errorMessages = [];
|
|
144
147
|
for (const problem of problems) {
|
|
148
|
+
if (problem.ignored === true) {
|
|
149
|
+
this.#options.logger.debug(
|
|
150
|
+
`Ignored by the lint ignore file: ${problemMessage(problem)}`,
|
|
151
|
+
"lint"
|
|
152
|
+
);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
145
155
|
const message = problemMessage(problem);
|
|
146
156
|
if (problem.severity === "error") {
|
|
147
157
|
errorMessages.push(message);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redocly-schema-loader.mjs","sources":["../../../src/adapters/redocly-loader/redocly-schema-loader.ts"],"sourcesContent":["import { fileURLToPath } from \"node:url\";\nimport {\n type BaseResolver,\n bundle,\n type Document,\n lintDocument,\n type NormalizedProblem,\n type Config as RedoclyConfig,\n} from \"@redocly/openapi-core\";\nimport type { Logger } from \"../../application/ports/logger.js\";\nimport type { SchemaLoader, SchemaLoadRequest } from \"../../application/ports/schema-loader.js\";\nimport { withStackOverflowReportedAsync } from \"../../application/stack-overflow.js\";\nimport type { OpenAPI3 } from \"../../types.js\";\nimport { repairBundledRefs } from \"./bundled-ref-repair.js\";\nimport { findMalformedRefs, malformedRefsError } from \"./malformed-refs.js\";\nimport { RefAccessResolver } from \"./ref-access.js\";\nimport { resolveConfigWithAccess } from \"./remote-fetch.js\";\nimport {\n loadFailedError,\n refCycleError,\n schemaInvalidError,\n versionUnsupportedError,\n} from \"./schema-load-errors.js\";\nimport { parseSchema } from \"./schema-source.js\";\nimport {\n findUnsupportedKeys,\n type LoadedDocument,\n unsupportedKeysError,\n} from \"./unsupported-keys.js\";\n\n/**\n * The SchemaLoader port on Redocly 1.34 (ADR-005): parse any inherited source type, then lint and\n * bundle with the given Redocly config. Problems go to the logger; errors fail the load.\n */\nexport interface RedoclySchemaLoaderOptions {\n readonly redoc: RedoclyConfig;\n readonly logger: Logger;\n /** A monotonic time in milliseconds, for the debug durations. */\n readonly now: () => number;\n /** Time limit of one remote fetch, unless the Redocly config brings its own `customFetch`. */\n readonly remoteRefTimeoutMs: number;\n}\n\nconst UNSUPPORTED_FORMAT_MESSAGE = \"Unsupported schema format, expected `openapi: 3.x`\";\n\n/**\n * Accept OpenAPI 3.x only; Swagger 2 and other formats get their own message. An empty file or a\n * `null` root parses to nothing, so it is checked before any field is read.\n */\nfunction assertOpenAPI3(document: unknown): void {\n if (typeof document !== \"object\" || document === null) {\n throw versionUnsupportedError(UNSUPPORTED_FORMAT_MESSAGE, {});\n }\n const parsed = document as Record<string, unknown>;\n const openapiVersion = Number.parseFloat(parsed.openapi as string);\n const isOpenAPI3 =\n !parsed.swagger &&\n Boolean(parsed.openapi) &&\n !Number.isNaN(openapiVersion) &&\n openapiVersion >= 3 &&\n openapiVersion < 4;\n if (isOpenAPI3) {\n return;\n }\n if (parsed.swagger) {\n throw versionUnsupportedError(\n \"Unsupported Swagger version: 2.x. Use OpenAPI 3.x instead.\",\n parsed,\n );\n }\n if (parsed.openapi || openapiVersion < 3 || openapiVersion >= 4) {\n throw versionUnsupportedError(`Unsupported OpenAPI version: ${parsed.openapi}`, parsed);\n }\n throw versionUnsupportedError(UNSUPPORTED_FORMAT_MESSAGE, parsed);\n}\n\n/** The base for relative `$ref`s: the source file or URL itself, else the working directory. */\nfunction sourceAbsoluteRef(source: unknown, cwd: URL): string {\n if (source instanceof URL) {\n return source.protocol === \"file:\" ? sourceFilePath(source) : source.href;\n }\n return fileURLToPath(cwd);\n}\n\n/**\n * The path of a `file:` source. A URL that names no path on this platform (an encoded slash, a\n * host on POSIX, no drive letter on Windows) cannot be read, so it fails as a read would.\n */\nfunction sourceFilePath(source: URL): string {\n try {\n return fileURLToPath(source);\n } catch (error) {\n // Node.js reports these as TypeErrors (ERR_INVALID_FILE_URL_PATH, ERR_INVALID_FILE_URL_HOST).\n if (!(error instanceof TypeError)) {\n throw error;\n }\n throw loadFailedError(source.href, error);\n }\n}\n\n/** Redocly throws a plain Error for a `$ref` chain that points back to itself. */\nconst REF_CYCLE_MESSAGE = \"Self-referencing circular pointer\";\n\n/**\n * The root document and every other document the resolver loaded, as far as they parsed. A root\n * read from a file or URL is in the resolver cache too, and is listed once.\n */\nasync function loadedDocuments(root: Document, resolver: BaseResolver): Promise<LoadedDocument[]> {\n const cached = await Promise.all(resolver.cache.values());\n const bySource = new Map<string, unknown>([[root.source.absoluteRef, root.parsed]]);\n for (const document of cached) {\n if (\"parsed\" in document && !bySource.has(document.source.absoluteRef)) {\n bySource.set(document.source.absoluteRef, document.parsed);\n }\n }\n return [...bySource].map(([source, parsed]) => ({ source, parsed }));\n}\n\n/** Report the document problems Redocly throws as typed errors; anything else passes through. */\nasync function rethrowDocumentError(\n error: unknown,\n root: Document,\n resolver: BaseResolver,\n): Promise<never> {\n if (error instanceof Error && error.message === REF_CYCLE_MESSAGE) {\n throw refCycleError(error);\n }\n if (error instanceof URIError) {\n throw malformedRefsError(findMalformedRefs(await loadedDocuments(root, resolver)), error);\n }\n if (error instanceof TypeError) {\n const keys = findUnsupportedKeys(await loadedDocuments(root, resolver));\n throw keys.length === 0 ? error : unsupportedKeysError(keys, error);\n }\n throw error;\n}\n\nclass RedoclySchemaLoader implements SchemaLoader {\n readonly #options: RedoclySchemaLoaderOptions;\n\n constructor(options: RedoclySchemaLoaderOptions) {\n this.#options = options;\n }\n\n async load(request: SchemaLoadRequest): Promise<OpenAPI3> {\n const resolver = this.#resolver(request);\n // Parsing is guarded too: `JSON.stringify` of a deep object source overflows the stack on\n // Node.js 22 and 24, before linting starts.\n const bundled = await withStackOverflowReportedAsync(\"load\", () =>\n this.#parseAndBundle(request, resolver),\n ).catch((error: unknown) => {\n throw resolver.firstRefusal ?? error;\n });\n // A refused `$ref` is an unresolved-`$ref` problem, which a Redocly config can turn off.\n if (resolver.firstRefusal !== undefined) {\n throw resolver.firstRefusal;\n }\n return bundled;\n }\n\n async #parseAndBundle(request: SchemaLoadRequest, resolver: BaseResolver): Promise<OpenAPI3> {\n const { logger, now } = this.#options;\n const configLoadedAt = now();\n logger.debug(\"Loaded Redoc config\", \"redoc\", now() - configLoadedAt);\n const parseStartedAt = now();\n const absoluteRef = sourceAbsoluteRef(request.source, request.cwd);\n const document = await parseSchema(request.source, { absoluteRef, resolver });\n logger.debug(\"Parsed schema\", \"redoc\", now() - parseStartedAt);\n assertOpenAPI3(document.parsed);\n return this.#lintAndBundle(document, resolver, request.shouldLint);\n }\n\n #resolver(request: SchemaLoadRequest): RefAccessResolver {\n const { redoc, remoteRefTimeoutMs } = this.#options;\n const config = resolveConfigWithAccess(redoc.resolve, {\n timeoutMs: remoteRefTimeoutMs,\n access: request.refAccess,\n });\n return new RefAccessResolver(config, request.refAccess);\n }\n\n async #lintAndBundle(\n document: Document,\n resolver: BaseResolver,\n shouldLint: boolean,\n ): Promise<OpenAPI3> {\n const rethrow = (error: unknown) => rethrowDocumentError(error, document, resolver);\n if (shouldLint) {\n await this.#lint(document, resolver).catch(rethrow);\n }\n return this.#bundle(document, resolver).catch(rethrow);\n }\n\n async #lint(document: Document, resolver: BaseResolver): Promise<void> {\n const startedAt = this.#options.now();\n const problems = await lintDocument({\n document,\n config: this.#options.redoc.styleguide,\n externalRefResolver: resolver,\n });\n this.#report(problems);\n this.#options.logger.debug(\"Linted schema\", \"lint\", this.#options.now() - startedAt);\n }\n\n async #bundle(document: Document, resolver: BaseResolver): Promise<OpenAPI3> {\n const startedAt = this.#options.now();\n // The lint resolver: documents it already loaded are not fetched again.\n const bundled = await bundle({\n config: this.#options.redoc,\n dereference: false,\n doc: document,\n externalRefResolver: resolver,\n });\n this.#report(bundled.problems);\n repairBundledRefs(bundled.bundle.parsed);\n this.#options.logger.debug(\"Bundled schema\", \"bundle\", this.#options.now() - startedAt);\n return bundled.bundle.parsed;\n }\n\n /** Report every problem; then throw if any of them is an error. */\n #report(problems: readonly NormalizedProblem[]): void {\n const errorMessages: string[] = [];\n for (const problem of problems) {\n const message = problemMessage(problem);\n if (problem.severity === \"error\") {\n errorMessages.push(message);\n this.#options.logger.error(message);\n } else {\n this.#options.logger.warn(message);\n }\n }\n if (errorMessages.length > 0) {\n throw schemaInvalidError(errorMessages);\n }\n }\n}\n\nfunction problemMessage(problem: NormalizedProblem): string {\n const location = problem.location?.[0]?.pointer;\n return location ? `${problem.message} at ${location}` : problem.message;\n}\n\n/** A schema loader with one Redocly config and logger, for one or more loads. */\nexport function createRedoclySchemaLoader(options: RedoclySchemaLoaderOptions): SchemaLoader {\n return new RedoclySchemaLoader(options);\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"redocly-schema-loader.mjs","sources":["../../../src/adapters/redocly-loader/redocly-schema-loader.ts"],"sourcesContent":["import { fileURLToPath } from \"node:url\";\nimport {\n type BaseResolver,\n bundle,\n type Document,\n lintDocument,\n type NormalizedProblem,\n type Config as RedoclyConfig,\n} from \"@redocly/openapi-core\";\nimport type { Logger } from \"../../application/ports/logger.js\";\nimport type { SchemaLoader, SchemaLoadRequest } from \"../../application/ports/schema-loader.js\";\nimport { withStackOverflowReportedAsync } from \"../../application/stack-overflow.js\";\nimport type { OpenAPI3 } from \"../../types.js\";\nimport { repairBundledRefs } from \"./bundled-ref-repair.js\";\nimport { findMalformedRefs, malformedRefsError } from \"./malformed-refs.js\";\nimport { RefAccessResolver } from \"./ref-access.js\";\nimport { resolveConfigWithAccess } from \"./remote-fetch.js\";\nimport {\n loadFailedError,\n refCycleError,\n schemaInvalidError,\n versionUnsupportedError,\n} from \"./schema-load-errors.js\";\nimport { parseSchema } from \"./schema-source.js\";\nimport {\n findUnsupportedKeys,\n type LoadedDocument,\n unsupportedKeysError,\n} from \"./unsupported-keys.js\";\n\n/**\n * The SchemaLoader port on Redocly 1.34 (ADR-005): parse any inherited source type, then lint and\n * bundle with the given Redocly config. Problems go to the logger; errors fail the load.\n */\nexport interface RedoclySchemaLoaderOptions {\n readonly redoc: RedoclyConfig;\n readonly logger: Logger;\n /** A monotonic time in milliseconds, for the debug durations. */\n readonly now: () => number;\n /** Time limit of one remote fetch, unless the Redocly config brings its own `customFetch`. */\n readonly remoteRefTimeoutMs: number;\n}\n\nconst UNSUPPORTED_FORMAT_MESSAGE = \"Unsupported schema format, expected `openapi: 3.x`\";\n\n/**\n * Accept OpenAPI 3.x only; Swagger 2 and other formats get their own message. An empty file or a\n * `null` root parses to nothing, so it is checked before any field is read.\n */\nfunction assertOpenAPI3(document: unknown): void {\n if (typeof document !== \"object\" || document === null) {\n throw versionUnsupportedError(UNSUPPORTED_FORMAT_MESSAGE, {});\n }\n const parsed = document as Record<string, unknown>;\n const openapiVersion = Number.parseFloat(parsed.openapi as string);\n const isOpenAPI3 =\n !parsed.swagger &&\n Boolean(parsed.openapi) &&\n !Number.isNaN(openapiVersion) &&\n openapiVersion >= 3 &&\n openapiVersion < 4;\n if (isOpenAPI3) {\n return;\n }\n if (parsed.swagger) {\n throw versionUnsupportedError(\n \"Unsupported Swagger version: 2.x. Use OpenAPI 3.x instead.\",\n parsed,\n );\n }\n if (parsed.openapi || openapiVersion < 3 || openapiVersion >= 4) {\n throw versionUnsupportedError(`Unsupported OpenAPI version: ${parsed.openapi}`, parsed);\n }\n throw versionUnsupportedError(UNSUPPORTED_FORMAT_MESSAGE, parsed);\n}\n\n/**\n * The name an inline source (a string, object, buffer or stream) gets inside the working\n * directory. Redocly resolves relative `$ref`s against the directory of the document, so the\n * document must be named as a file in the working directory, not as the directory itself.\n */\nconst INLINE_SOURCE_NAME = \"inline-source\";\n\n/** The base for relative `$ref`s: the source file or URL itself, else a file in the cwd. */\nfunction sourceAbsoluteRef(source: unknown, cwd: URL): string {\n const document = source instanceof URL ? source : new URL(INLINE_SOURCE_NAME, cwd);\n return document.protocol === \"file:\" ? sourceFilePath(document) : document.href;\n}\n\n/**\n * The path of a `file:` source. A URL that names no path on this platform (an encoded slash, a\n * host on POSIX, no drive letter on Windows) cannot be read, so it fails as a read would.\n */\nfunction sourceFilePath(source: URL): string {\n try {\n return fileURLToPath(source);\n } catch (error) {\n // Node.js reports these as TypeErrors (ERR_INVALID_FILE_URL_PATH, ERR_INVALID_FILE_URL_HOST).\n if (!(error instanceof TypeError)) {\n throw error;\n }\n throw loadFailedError(source.href, error);\n }\n}\n\n/** Redocly throws a plain Error for a `$ref` chain that points back to itself. */\nconst REF_CYCLE_MESSAGE = \"Self-referencing circular pointer\";\n\n/**\n * The root document and every other document the resolver loaded, as far as they parsed. A root\n * read from a file or URL is in the resolver cache too, and is listed once.\n */\nasync function loadedDocuments(root: Document, resolver: BaseResolver): Promise<LoadedDocument[]> {\n const cached = await Promise.all(resolver.cache.values());\n const bySource = new Map<string, unknown>([[root.source.absoluteRef, root.parsed]]);\n for (const document of cached) {\n if (\"parsed\" in document && !bySource.has(document.source.absoluteRef)) {\n bySource.set(document.source.absoluteRef, document.parsed);\n }\n }\n return [...bySource].map(([source, parsed]) => ({ source, parsed }));\n}\n\n/** Report the document problems Redocly throws as typed errors; anything else passes through. */\nasync function rethrowDocumentError(\n error: unknown,\n root: Document,\n resolver: BaseResolver,\n): Promise<never> {\n if (error instanceof Error && error.message === REF_CYCLE_MESSAGE) {\n throw refCycleError(error);\n }\n if (error instanceof URIError) {\n throw malformedRefsError(findMalformedRefs(await loadedDocuments(root, resolver)), error);\n }\n if (error instanceof TypeError) {\n const keys = findUnsupportedKeys(await loadedDocuments(root, resolver));\n throw keys.length === 0 ? error : unsupportedKeysError(keys, error);\n }\n throw error;\n}\n\nclass RedoclySchemaLoader implements SchemaLoader {\n readonly #options: RedoclySchemaLoaderOptions;\n\n constructor(options: RedoclySchemaLoaderOptions) {\n this.#options = options;\n }\n\n async load(request: SchemaLoadRequest): Promise<OpenAPI3> {\n const resolver = this.#resolver(request);\n // Parsing is guarded too: `JSON.stringify` of a deep object source overflows the stack on\n // Node.js 22 and 24, before linting starts.\n const bundled = await withStackOverflowReportedAsync(\"load\", () =>\n this.#parseAndBundle(request, resolver),\n ).catch((error: unknown) => {\n throw resolver.firstRefusal ?? error;\n });\n // A refused `$ref` is an unresolved-`$ref` problem, which a Redocly config can turn off.\n if (resolver.firstRefusal !== undefined) {\n throw resolver.firstRefusal;\n }\n return bundled;\n }\n\n async #parseAndBundle(request: SchemaLoadRequest, resolver: BaseResolver): Promise<OpenAPI3> {\n const { logger, now } = this.#options;\n const configLoadedAt = now();\n logger.debug(\"Loaded Redoc config\", \"redoc\", now() - configLoadedAt);\n const parseStartedAt = now();\n const absoluteRef = sourceAbsoluteRef(request.source, request.cwd);\n const document = await parseSchema(request.source, { absoluteRef, resolver });\n logger.debug(\"Parsed schema\", \"redoc\", now() - parseStartedAt);\n assertOpenAPI3(document.parsed);\n return this.#lintAndBundle(document, resolver, request.shouldLint);\n }\n\n #resolver(request: SchemaLoadRequest): RefAccessResolver {\n const { redoc, remoteRefTimeoutMs } = this.#options;\n const config = resolveConfigWithAccess(redoc.resolve, {\n timeoutMs: remoteRefTimeoutMs,\n access: request.refAccess,\n });\n return new RefAccessResolver(config, request.refAccess);\n }\n\n async #lintAndBundle(\n document: Document,\n resolver: BaseResolver,\n shouldLint: boolean,\n ): Promise<OpenAPI3> {\n const rethrow = (error: unknown) => rethrowDocumentError(error, document, resolver);\n if (shouldLint) {\n await this.#lint(document, resolver).catch(rethrow);\n }\n return this.#bundle(document, resolver).catch(rethrow);\n }\n\n async #lint(document: Document, resolver: BaseResolver): Promise<void> {\n const startedAt = this.#options.now();\n const problems = await lintDocument({\n document,\n config: this.#options.redoc.styleguide,\n externalRefResolver: resolver,\n });\n this.#report(problems);\n this.#options.logger.debug(\"Linted schema\", \"lint\", this.#options.now() - startedAt);\n }\n\n async #bundle(document: Document, resolver: BaseResolver): Promise<OpenAPI3> {\n const startedAt = this.#options.now();\n // The lint resolver: documents it already loaded are not fetched again.\n const bundled = await bundle({\n config: this.#options.redoc,\n dereference: false,\n doc: document,\n externalRefResolver: resolver,\n });\n this.#report(bundled.problems);\n repairBundledRefs(bundled.bundle.parsed);\n this.#options.logger.debug(\"Bundled schema\", \"bundle\", this.#options.now() - startedAt);\n return bundled.bundle.parsed;\n }\n\n /**\n * Report every problem; then throw if any of them is an error. A problem that the Redocly\n * config's `.redocly.lint-ignore.yaml` lists is left out, as `redocly lint` leaves it out\n * (upstream #2189).\n */\n #report(problems: readonly NormalizedProblem[]): void {\n const errorMessages: string[] = [];\n for (const problem of problems) {\n if (problem.ignored === true) {\n this.#options.logger.debug(\n `Ignored by the lint ignore file: ${problemMessage(problem)}`,\n \"lint\",\n );\n continue;\n }\n const message = problemMessage(problem);\n if (problem.severity === \"error\") {\n errorMessages.push(message);\n this.#options.logger.error(message);\n } else {\n this.#options.logger.warn(message);\n }\n }\n if (errorMessages.length > 0) {\n throw schemaInvalidError(errorMessages);\n }\n }\n}\n\nfunction problemMessage(problem: NormalizedProblem): string {\n const location = problem.location?.[0]?.pointer;\n return location ? `${problem.message} at ${location}` : problem.message;\n}\n\n/** A schema loader with one Redocly config and logger, for one or more loads. */\nexport function createRedoclySchemaLoader(options: RedoclySchemaLoaderOptions): SchemaLoader {\n return new RedoclySchemaLoader(options);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -30,6 +30,9 @@ function toStringLiteralType(ts, value, encoding) {
|
|
|
30
30
|
}
|
|
31
31
|
function toTupleElement(ts, element) {
|
|
32
32
|
const type = toTypeNode(ts, element.type);
|
|
33
|
+
if (element.isOptional) {
|
|
34
|
+
return ts.factory.createOptionalTypeNode(type);
|
|
35
|
+
}
|
|
33
36
|
return element.isRest ? ts.factory.createRestTypeNode(type) : type;
|
|
34
37
|
}
|
|
35
38
|
function toLeafTypeNode(ts, type) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ir-to-typescript.cjs","sources":["../../../src/adapters/type-ast-bridge/ir-to-typescript.ts"],"sourcesContent":["import type ts from \"typescript\";\nimport { assertNever } from \"../../domain/assert-never.js\";\nimport type {\n IrComment,\n IrKeyword,\n IrMember,\n IrPropertyName,\n IrPropertySignature,\n IrTupleElement,\n IrType,\n} from \"../../domain/ir/nodes.js\";\nimport type { TypeScriptModule } from \"./load-typescript.js\";\n\n/**\n * Convert IR to TypeScript AST nodes with the same factory calls the original generator makes.\n * Printing the result with the TypeScript printer gives the original output, which is how the\n * printer parity tests (ENGINEERING_PLAN 4.3) define \"byte-identical\". Every function takes the\n * TypeScript module to build with (ADR-004, decision 4): the nodes must come from the same module\n * that later reads or prints them.\n */\n\ntype KeywordName = Exclude<IrKeyword, \"null\">;\n\nfunction keywordKind(ts: TypeScriptModule, keyword: KeywordName): ts.KeywordTypeSyntaxKind {\n const kinds: Readonly<Record<KeywordName, ts.KeywordTypeSyntaxKind>> = {\n string: ts.SyntaxKind.StringKeyword,\n number: ts.SyntaxKind.NumberKeyword,\n boolean: ts.SyntaxKind.BooleanKeyword,\n undefined: ts.SyntaxKind.UndefinedKeyword,\n unknown: ts.SyntaxKind.UnknownKeyword,\n never: ts.SyntaxKind.NeverKeyword,\n };\n return kinds[keyword];\n}\n\nfunction toKeywordType(ts: TypeScriptModule, keyword: IrKeyword): ts.TypeNode {\n return keyword === \"null\"\n ? ts.factory.createLiteralTypeNode(ts.factory.createNull())\n : ts.factory.createKeywordTypeNode(keywordKind(ts, keyword));\n}\n\n/**\n * Numbers as the original writes them: a negative value is a prefix minus on its absolute value.\n */\nfunction toNumberExpression(\n ts: TypeScriptModule,\n value: number,\n): ts.PrefixUnaryExpression | ts.NumericLiteral {\n return value < 0\n ? ts.factory.createPrefixUnaryExpression(\n ts.SyntaxKind.MinusToken,\n ts.factory.createNumericLiteral(Math.abs(value)),\n )\n : ts.factory.createNumericLiteral(value);\n}\n\n/** An enum member or array element value, written as the original writes it. */\nexport function toValueExpression(ts: TypeScriptModule, value: string | number): ts.Expression {\n return typeof value === \"number\"\n ? toNumberExpression(ts, value)\n : ts.factory.createStringLiteral(value);\n}\n\n/** The original writes JSON-encoded literal types as identifiers to keep UTF-8 readable. */\nfunction toStringLiteralType(\n ts: TypeScriptModule,\n value: string,\n encoding: \"json\" | \"escaped\",\n): ts.TypeNode {\n return encoding === \"json\"\n ? (ts.factory.createIdentifier(JSON.stringify(value)) as unknown as ts.TypeNode)\n : ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(value));\n}\n\nfunction toTupleElement(ts: TypeScriptModule, element: IrTupleElement): ts.TypeNode {\n const type = toTypeNode(ts, element.type);\n return element.isRest ? ts.factory.createRestTypeNode(type) : type;\n}\n\ntype LeafType = Extract<\n IrType,\n { kind: \"keyword\" | \"stringLiteral\" | \"numberLiteral\" | \"booleanLiteral\" | \"raw\" }\n>;\n\nfunction toLeafTypeNode(ts: TypeScriptModule, type: LeafType): ts.TypeNode {\n switch (type.kind) {\n case \"keyword\":\n return toKeywordType(ts, type.keyword);\n case \"stringLiteral\":\n return toStringLiteralType(ts, type.value, type.encoding);\n case \"numberLiteral\":\n return ts.factory.createLiteralTypeNode(toNumberExpression(ts, type.value));\n case \"booleanLiteral\":\n return ts.factory.createLiteralTypeNode(\n type.value ? ts.factory.createTrue() : ts.factory.createFalse(),\n );\n case \"raw\":\n // A node read from TypeScript goes back as it was, so the TypeScript printer indents it.\n return (\n (type.origin as ts.TypeNode | undefined) ??\n (ts.factory.createIdentifier(type.text) as unknown as ts.TypeNode)\n );\n default:\n return assertNever(type);\n }\n}\n\nfunction toReferenceNode(\n ts: TypeScriptModule,\n type: Extract<IrType, { kind: \"reference\" }>,\n): ts.TypeNode {\n const typeArguments =\n type.typeArguments.length > 0\n ? type.typeArguments.map((argument) => toTypeNode(ts, argument))\n : undefined;\n return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(type.name), typeArguments);\n}\n\n/** Convert one IR type. */\nexport function toTypeNode(ts: TypeScriptModule, type: IrType): ts.TypeNode {\n const convert = (inner: IrType) => toTypeNode(ts, inner);\n const { factory } = ts;\n switch (type.kind) {\n case \"keyword\":\n case \"stringLiteral\":\n case \"numberLiteral\":\n case \"booleanLiteral\":\n case \"raw\":\n return toLeafTypeNode(ts, type);\n case \"reference\":\n return toReferenceNode(ts, type);\n case \"array\":\n return factory.createArrayTypeNode(convert(type.element));\n case \"tuple\":\n return factory.createTupleTypeNode(\n type.elements.map((element) => toTupleElement(ts, element)),\n );\n case \"union\":\n return factory.createUnionTypeNode(type.types.map(convert));\n case \"intersection\":\n return factory.createIntersectionTypeNode(type.types.map(convert));\n case \"object\":\n return factory.createTypeLiteralNode(type.members.map((member) => toTypeElement(ts, member)));\n case \"indexedAccess\":\n return factory.createIndexedAccessTypeNode(convert(type.object), convert(type.index));\n case \"readonly\":\n return factory.createTypeOperatorNode(ts.SyntaxKind.ReadonlyKeyword, convert(type.type));\n default:\n return assertNever(type);\n }\n}\n\n/** Attach IR comments to a node as synthetic leading comments, as the original does. */\nexport function withComments<T extends ts.Node>(\n ts: TypeScriptModule,\n node: T,\n comments: readonly IrComment[],\n): T {\n for (const comment of comments) {\n const kind =\n comment.kind === \"block\"\n ? ts.SyntaxKind.MultiLineCommentTrivia\n : ts.SyntaxKind.SingleLineCommentTrivia;\n ts.addSyntheticLeadingComment(node, kind, comment.text, true);\n }\n return node;\n}\n\nfunction toPropertyName(ts: TypeScriptModule, name: IrPropertyName): ts.PropertyName {\n switch (name.kind) {\n case \"identifier\":\n return ts.factory.createIdentifier(name.text);\n case \"string\":\n return ts.factory.createStringLiteral(name.value);\n case \"number\":\n return ts.factory.createNumericLiteral(name.text);\n default:\n return assertNever(name);\n }\n}\n\nfunction readonlyModifiers(ts: TypeScriptModule, isReadonly: boolean): ts.Modifier[] | undefined {\n return isReadonly ? [ts.factory.createModifier(ts.SyntaxKind.ReadonlyKeyword)] : undefined;\n}\n\n/** Convert one property signature (for callbacks that receive a `ts.PropertySignature`). */\nexport function toPropertySignature(\n ts: TypeScriptModule,\n property: IrPropertySignature,\n): ts.PropertySignature {\n const questionToken = property.isOptional\n ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)\n : undefined;\n const signature = ts.factory.createPropertySignature(\n readonlyModifiers(ts, property.isReadonly),\n toPropertyName(ts, property.name),\n questionToken,\n toTypeNode(ts, property.type),\n );\n return withComments(ts, signature, property.comments);\n}\n\nexport function toTypeElement(ts: TypeScriptModule, member: IrMember): ts.TypeElement {\n if (member.kind === \"property\") {\n return toPropertySignature(ts, member);\n }\n const parameter = ts.factory.createParameterDeclaration(\n undefined,\n undefined,\n member.parameterName,\n undefined,\n toTypeNode(ts, member.parameterType),\n );\n const signature = ts.factory.createIndexSignature(\n readonlyModifiers(ts, member.isReadonly),\n [parameter],\n toTypeNode(ts, member.type),\n );\n return withComments(ts, signature, member.comments);\n}\n"],"names":["assertNever"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ir-to-typescript.cjs","sources":["../../../src/adapters/type-ast-bridge/ir-to-typescript.ts"],"sourcesContent":["import type ts from \"typescript\";\nimport { assertNever } from \"../../domain/assert-never.js\";\nimport type {\n IrComment,\n IrKeyword,\n IrMember,\n IrPropertyName,\n IrPropertySignature,\n IrTupleElement,\n IrType,\n} from \"../../domain/ir/nodes.js\";\nimport type { TypeScriptModule } from \"./load-typescript.js\";\n\n/**\n * Convert IR to TypeScript AST nodes with the same factory calls the original generator makes.\n * Printing the result with the TypeScript printer gives the original output, which is how the\n * printer parity tests (ENGINEERING_PLAN 4.3) define \"byte-identical\". Every function takes the\n * TypeScript module to build with (ADR-004, decision 4): the nodes must come from the same module\n * that later reads or prints them.\n */\n\ntype KeywordName = Exclude<IrKeyword, \"null\">;\n\nfunction keywordKind(ts: TypeScriptModule, keyword: KeywordName): ts.KeywordTypeSyntaxKind {\n const kinds: Readonly<Record<KeywordName, ts.KeywordTypeSyntaxKind>> = {\n string: ts.SyntaxKind.StringKeyword,\n number: ts.SyntaxKind.NumberKeyword,\n boolean: ts.SyntaxKind.BooleanKeyword,\n undefined: ts.SyntaxKind.UndefinedKeyword,\n unknown: ts.SyntaxKind.UnknownKeyword,\n never: ts.SyntaxKind.NeverKeyword,\n };\n return kinds[keyword];\n}\n\nfunction toKeywordType(ts: TypeScriptModule, keyword: IrKeyword): ts.TypeNode {\n return keyword === \"null\"\n ? ts.factory.createLiteralTypeNode(ts.factory.createNull())\n : ts.factory.createKeywordTypeNode(keywordKind(ts, keyword));\n}\n\n/**\n * Numbers as the original writes them: a negative value is a prefix minus on its absolute value.\n */\nfunction toNumberExpression(\n ts: TypeScriptModule,\n value: number,\n): ts.PrefixUnaryExpression | ts.NumericLiteral {\n return value < 0\n ? ts.factory.createPrefixUnaryExpression(\n ts.SyntaxKind.MinusToken,\n ts.factory.createNumericLiteral(Math.abs(value)),\n )\n : ts.factory.createNumericLiteral(value);\n}\n\n/** An enum member or array element value, written as the original writes it. */\nexport function toValueExpression(ts: TypeScriptModule, value: string | number): ts.Expression {\n return typeof value === \"number\"\n ? toNumberExpression(ts, value)\n : ts.factory.createStringLiteral(value);\n}\n\n/** The original writes JSON-encoded literal types as identifiers to keep UTF-8 readable. */\nfunction toStringLiteralType(\n ts: TypeScriptModule,\n value: string,\n encoding: \"json\" | \"escaped\",\n): ts.TypeNode {\n return encoding === \"json\"\n ? (ts.factory.createIdentifier(JSON.stringify(value)) as unknown as ts.TypeNode)\n : ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(value));\n}\n\nfunction toTupleElement(ts: TypeScriptModule, element: IrTupleElement): ts.TypeNode {\n const type = toTypeNode(ts, element.type);\n if (element.isOptional) {\n return ts.factory.createOptionalTypeNode(type);\n }\n return element.isRest ? ts.factory.createRestTypeNode(type) : type;\n}\n\ntype LeafType = Extract<\n IrType,\n { kind: \"keyword\" | \"stringLiteral\" | \"numberLiteral\" | \"booleanLiteral\" | \"raw\" }\n>;\n\nfunction toLeafTypeNode(ts: TypeScriptModule, type: LeafType): ts.TypeNode {\n switch (type.kind) {\n case \"keyword\":\n return toKeywordType(ts, type.keyword);\n case \"stringLiteral\":\n return toStringLiteralType(ts, type.value, type.encoding);\n case \"numberLiteral\":\n return ts.factory.createLiteralTypeNode(toNumberExpression(ts, type.value));\n case \"booleanLiteral\":\n return ts.factory.createLiteralTypeNode(\n type.value ? ts.factory.createTrue() : ts.factory.createFalse(),\n );\n case \"raw\":\n // A node read from TypeScript goes back as it was, so the TypeScript printer indents it.\n return (\n (type.origin as ts.TypeNode | undefined) ??\n (ts.factory.createIdentifier(type.text) as unknown as ts.TypeNode)\n );\n default:\n return assertNever(type);\n }\n}\n\nfunction toReferenceNode(\n ts: TypeScriptModule,\n type: Extract<IrType, { kind: \"reference\" }>,\n): ts.TypeNode {\n const typeArguments =\n type.typeArguments.length > 0\n ? type.typeArguments.map((argument) => toTypeNode(ts, argument))\n : undefined;\n return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(type.name), typeArguments);\n}\n\n/** Convert one IR type. */\nexport function toTypeNode(ts: TypeScriptModule, type: IrType): ts.TypeNode {\n const convert = (inner: IrType) => toTypeNode(ts, inner);\n const { factory } = ts;\n switch (type.kind) {\n case \"keyword\":\n case \"stringLiteral\":\n case \"numberLiteral\":\n case \"booleanLiteral\":\n case \"raw\":\n return toLeafTypeNode(ts, type);\n case \"reference\":\n return toReferenceNode(ts, type);\n case \"array\":\n return factory.createArrayTypeNode(convert(type.element));\n case \"tuple\":\n return factory.createTupleTypeNode(\n type.elements.map((element) => toTupleElement(ts, element)),\n );\n case \"union\":\n return factory.createUnionTypeNode(type.types.map(convert));\n case \"intersection\":\n return factory.createIntersectionTypeNode(type.types.map(convert));\n case \"object\":\n return factory.createTypeLiteralNode(type.members.map((member) => toTypeElement(ts, member)));\n case \"indexedAccess\":\n return factory.createIndexedAccessTypeNode(convert(type.object), convert(type.index));\n case \"readonly\":\n return factory.createTypeOperatorNode(ts.SyntaxKind.ReadonlyKeyword, convert(type.type));\n default:\n return assertNever(type);\n }\n}\n\n/** Attach IR comments to a node as synthetic leading comments, as the original does. */\nexport function withComments<T extends ts.Node>(\n ts: TypeScriptModule,\n node: T,\n comments: readonly IrComment[],\n): T {\n for (const comment of comments) {\n const kind =\n comment.kind === \"block\"\n ? ts.SyntaxKind.MultiLineCommentTrivia\n : ts.SyntaxKind.SingleLineCommentTrivia;\n ts.addSyntheticLeadingComment(node, kind, comment.text, true);\n }\n return node;\n}\n\nfunction toPropertyName(ts: TypeScriptModule, name: IrPropertyName): ts.PropertyName {\n switch (name.kind) {\n case \"identifier\":\n return ts.factory.createIdentifier(name.text);\n case \"string\":\n return ts.factory.createStringLiteral(name.value);\n case \"number\":\n return ts.factory.createNumericLiteral(name.text);\n default:\n return assertNever(name);\n }\n}\n\nfunction readonlyModifiers(ts: TypeScriptModule, isReadonly: boolean): ts.Modifier[] | undefined {\n return isReadonly ? [ts.factory.createModifier(ts.SyntaxKind.ReadonlyKeyword)] : undefined;\n}\n\n/** Convert one property signature (for callbacks that receive a `ts.PropertySignature`). */\nexport function toPropertySignature(\n ts: TypeScriptModule,\n property: IrPropertySignature,\n): ts.PropertySignature {\n const questionToken = property.isOptional\n ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)\n : undefined;\n const signature = ts.factory.createPropertySignature(\n readonlyModifiers(ts, property.isReadonly),\n toPropertyName(ts, property.name),\n questionToken,\n toTypeNode(ts, property.type),\n );\n return withComments(ts, signature, property.comments);\n}\n\nexport function toTypeElement(ts: TypeScriptModule, member: IrMember): ts.TypeElement {\n if (member.kind === \"property\") {\n return toPropertySignature(ts, member);\n }\n const parameter = ts.factory.createParameterDeclaration(\n undefined,\n undefined,\n member.parameterName,\n undefined,\n toTypeNode(ts, member.parameterType),\n );\n const signature = ts.factory.createIndexSignature(\n readonlyModifiers(ts, member.isReadonly),\n [parameter],\n toTypeNode(ts, member.type),\n );\n return withComments(ts, signature, member.comments);\n}\n"],"names":["assertNever"],"mappings":"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"}
|
|
@@ -28,6 +28,9 @@ function toStringLiteralType(ts, value, encoding) {
|
|
|
28
28
|
}
|
|
29
29
|
function toTupleElement(ts, element) {
|
|
30
30
|
const type = toTypeNode(ts, element.type);
|
|
31
|
+
if (element.isOptional) {
|
|
32
|
+
return ts.factory.createOptionalTypeNode(type);
|
|
33
|
+
}
|
|
31
34
|
return element.isRest ? ts.factory.createRestTypeNode(type) : type;
|
|
32
35
|
}
|
|
33
36
|
function toLeafTypeNode(ts, type) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ir-to-typescript.mjs","sources":["../../../src/adapters/type-ast-bridge/ir-to-typescript.ts"],"sourcesContent":["import type ts from \"typescript\";\nimport { assertNever } from \"../../domain/assert-never.js\";\nimport type {\n IrComment,\n IrKeyword,\n IrMember,\n IrPropertyName,\n IrPropertySignature,\n IrTupleElement,\n IrType,\n} from \"../../domain/ir/nodes.js\";\nimport type { TypeScriptModule } from \"./load-typescript.js\";\n\n/**\n * Convert IR to TypeScript AST nodes with the same factory calls the original generator makes.\n * Printing the result with the TypeScript printer gives the original output, which is how the\n * printer parity tests (ENGINEERING_PLAN 4.3) define \"byte-identical\". Every function takes the\n * TypeScript module to build with (ADR-004, decision 4): the nodes must come from the same module\n * that later reads or prints them.\n */\n\ntype KeywordName = Exclude<IrKeyword, \"null\">;\n\nfunction keywordKind(ts: TypeScriptModule, keyword: KeywordName): ts.KeywordTypeSyntaxKind {\n const kinds: Readonly<Record<KeywordName, ts.KeywordTypeSyntaxKind>> = {\n string: ts.SyntaxKind.StringKeyword,\n number: ts.SyntaxKind.NumberKeyword,\n boolean: ts.SyntaxKind.BooleanKeyword,\n undefined: ts.SyntaxKind.UndefinedKeyword,\n unknown: ts.SyntaxKind.UnknownKeyword,\n never: ts.SyntaxKind.NeverKeyword,\n };\n return kinds[keyword];\n}\n\nfunction toKeywordType(ts: TypeScriptModule, keyword: IrKeyword): ts.TypeNode {\n return keyword === \"null\"\n ? ts.factory.createLiteralTypeNode(ts.factory.createNull())\n : ts.factory.createKeywordTypeNode(keywordKind(ts, keyword));\n}\n\n/**\n * Numbers as the original writes them: a negative value is a prefix minus on its absolute value.\n */\nfunction toNumberExpression(\n ts: TypeScriptModule,\n value: number,\n): ts.PrefixUnaryExpression | ts.NumericLiteral {\n return value < 0\n ? ts.factory.createPrefixUnaryExpression(\n ts.SyntaxKind.MinusToken,\n ts.factory.createNumericLiteral(Math.abs(value)),\n )\n : ts.factory.createNumericLiteral(value);\n}\n\n/** An enum member or array element value, written as the original writes it. */\nexport function toValueExpression(ts: TypeScriptModule, value: string | number): ts.Expression {\n return typeof value === \"number\"\n ? toNumberExpression(ts, value)\n : ts.factory.createStringLiteral(value);\n}\n\n/** The original writes JSON-encoded literal types as identifiers to keep UTF-8 readable. */\nfunction toStringLiteralType(\n ts: TypeScriptModule,\n value: string,\n encoding: \"json\" | \"escaped\",\n): ts.TypeNode {\n return encoding === \"json\"\n ? (ts.factory.createIdentifier(JSON.stringify(value)) as unknown as ts.TypeNode)\n : ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(value));\n}\n\nfunction toTupleElement(ts: TypeScriptModule, element: IrTupleElement): ts.TypeNode {\n const type = toTypeNode(ts, element.type);\n return element.isRest ? ts.factory.createRestTypeNode(type) : type;\n}\n\ntype LeafType = Extract<\n IrType,\n { kind: \"keyword\" | \"stringLiteral\" | \"numberLiteral\" | \"booleanLiteral\" | \"raw\" }\n>;\n\nfunction toLeafTypeNode(ts: TypeScriptModule, type: LeafType): ts.TypeNode {\n switch (type.kind) {\n case \"keyword\":\n return toKeywordType(ts, type.keyword);\n case \"stringLiteral\":\n return toStringLiteralType(ts, type.value, type.encoding);\n case \"numberLiteral\":\n return ts.factory.createLiteralTypeNode(toNumberExpression(ts, type.value));\n case \"booleanLiteral\":\n return ts.factory.createLiteralTypeNode(\n type.value ? ts.factory.createTrue() : ts.factory.createFalse(),\n );\n case \"raw\":\n // A node read from TypeScript goes back as it was, so the TypeScript printer indents it.\n return (\n (type.origin as ts.TypeNode | undefined) ??\n (ts.factory.createIdentifier(type.text) as unknown as ts.TypeNode)\n );\n default:\n return assertNever(type);\n }\n}\n\nfunction toReferenceNode(\n ts: TypeScriptModule,\n type: Extract<IrType, { kind: \"reference\" }>,\n): ts.TypeNode {\n const typeArguments =\n type.typeArguments.length > 0\n ? type.typeArguments.map((argument) => toTypeNode(ts, argument))\n : undefined;\n return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(type.name), typeArguments);\n}\n\n/** Convert one IR type. */\nexport function toTypeNode(ts: TypeScriptModule, type: IrType): ts.TypeNode {\n const convert = (inner: IrType) => toTypeNode(ts, inner);\n const { factory } = ts;\n switch (type.kind) {\n case \"keyword\":\n case \"stringLiteral\":\n case \"numberLiteral\":\n case \"booleanLiteral\":\n case \"raw\":\n return toLeafTypeNode(ts, type);\n case \"reference\":\n return toReferenceNode(ts, type);\n case \"array\":\n return factory.createArrayTypeNode(convert(type.element));\n case \"tuple\":\n return factory.createTupleTypeNode(\n type.elements.map((element) => toTupleElement(ts, element)),\n );\n case \"union\":\n return factory.createUnionTypeNode(type.types.map(convert));\n case \"intersection\":\n return factory.createIntersectionTypeNode(type.types.map(convert));\n case \"object\":\n return factory.createTypeLiteralNode(type.members.map((member) => toTypeElement(ts, member)));\n case \"indexedAccess\":\n return factory.createIndexedAccessTypeNode(convert(type.object), convert(type.index));\n case \"readonly\":\n return factory.createTypeOperatorNode(ts.SyntaxKind.ReadonlyKeyword, convert(type.type));\n default:\n return assertNever(type);\n }\n}\n\n/** Attach IR comments to a node as synthetic leading comments, as the original does. */\nexport function withComments<T extends ts.Node>(\n ts: TypeScriptModule,\n node: T,\n comments: readonly IrComment[],\n): T {\n for (const comment of comments) {\n const kind =\n comment.kind === \"block\"\n ? ts.SyntaxKind.MultiLineCommentTrivia\n : ts.SyntaxKind.SingleLineCommentTrivia;\n ts.addSyntheticLeadingComment(node, kind, comment.text, true);\n }\n return node;\n}\n\nfunction toPropertyName(ts: TypeScriptModule, name: IrPropertyName): ts.PropertyName {\n switch (name.kind) {\n case \"identifier\":\n return ts.factory.createIdentifier(name.text);\n case \"string\":\n return ts.factory.createStringLiteral(name.value);\n case \"number\":\n return ts.factory.createNumericLiteral(name.text);\n default:\n return assertNever(name);\n }\n}\n\nfunction readonlyModifiers(ts: TypeScriptModule, isReadonly: boolean): ts.Modifier[] | undefined {\n return isReadonly ? [ts.factory.createModifier(ts.SyntaxKind.ReadonlyKeyword)] : undefined;\n}\n\n/** Convert one property signature (for callbacks that receive a `ts.PropertySignature`). */\nexport function toPropertySignature(\n ts: TypeScriptModule,\n property: IrPropertySignature,\n): ts.PropertySignature {\n const questionToken = property.isOptional\n ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)\n : undefined;\n const signature = ts.factory.createPropertySignature(\n readonlyModifiers(ts, property.isReadonly),\n toPropertyName(ts, property.name),\n questionToken,\n toTypeNode(ts, property.type),\n );\n return withComments(ts, signature, property.comments);\n}\n\nexport function toTypeElement(ts: TypeScriptModule, member: IrMember): ts.TypeElement {\n if (member.kind === \"property\") {\n return toPropertySignature(ts, member);\n }\n const parameter = ts.factory.createParameterDeclaration(\n undefined,\n undefined,\n member.parameterName,\n undefined,\n toTypeNode(ts, member.parameterType),\n );\n const signature = ts.factory.createIndexSignature(\n readonlyModifiers(ts, member.isReadonly),\n [parameter],\n toTypeNode(ts, member.type),\n );\n return withComments(ts, signature, member.comments);\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ir-to-typescript.mjs","sources":["../../../src/adapters/type-ast-bridge/ir-to-typescript.ts"],"sourcesContent":["import type ts from \"typescript\";\nimport { assertNever } from \"../../domain/assert-never.js\";\nimport type {\n IrComment,\n IrKeyword,\n IrMember,\n IrPropertyName,\n IrPropertySignature,\n IrTupleElement,\n IrType,\n} from \"../../domain/ir/nodes.js\";\nimport type { TypeScriptModule } from \"./load-typescript.js\";\n\n/**\n * Convert IR to TypeScript AST nodes with the same factory calls the original generator makes.\n * Printing the result with the TypeScript printer gives the original output, which is how the\n * printer parity tests (ENGINEERING_PLAN 4.3) define \"byte-identical\". Every function takes the\n * TypeScript module to build with (ADR-004, decision 4): the nodes must come from the same module\n * that later reads or prints them.\n */\n\ntype KeywordName = Exclude<IrKeyword, \"null\">;\n\nfunction keywordKind(ts: TypeScriptModule, keyword: KeywordName): ts.KeywordTypeSyntaxKind {\n const kinds: Readonly<Record<KeywordName, ts.KeywordTypeSyntaxKind>> = {\n string: ts.SyntaxKind.StringKeyword,\n number: ts.SyntaxKind.NumberKeyword,\n boolean: ts.SyntaxKind.BooleanKeyword,\n undefined: ts.SyntaxKind.UndefinedKeyword,\n unknown: ts.SyntaxKind.UnknownKeyword,\n never: ts.SyntaxKind.NeverKeyword,\n };\n return kinds[keyword];\n}\n\nfunction toKeywordType(ts: TypeScriptModule, keyword: IrKeyword): ts.TypeNode {\n return keyword === \"null\"\n ? ts.factory.createLiteralTypeNode(ts.factory.createNull())\n : ts.factory.createKeywordTypeNode(keywordKind(ts, keyword));\n}\n\n/**\n * Numbers as the original writes them: a negative value is a prefix minus on its absolute value.\n */\nfunction toNumberExpression(\n ts: TypeScriptModule,\n value: number,\n): ts.PrefixUnaryExpression | ts.NumericLiteral {\n return value < 0\n ? ts.factory.createPrefixUnaryExpression(\n ts.SyntaxKind.MinusToken,\n ts.factory.createNumericLiteral(Math.abs(value)),\n )\n : ts.factory.createNumericLiteral(value);\n}\n\n/** An enum member or array element value, written as the original writes it. */\nexport function toValueExpression(ts: TypeScriptModule, value: string | number): ts.Expression {\n return typeof value === \"number\"\n ? toNumberExpression(ts, value)\n : ts.factory.createStringLiteral(value);\n}\n\n/** The original writes JSON-encoded literal types as identifiers to keep UTF-8 readable. */\nfunction toStringLiteralType(\n ts: TypeScriptModule,\n value: string,\n encoding: \"json\" | \"escaped\",\n): ts.TypeNode {\n return encoding === \"json\"\n ? (ts.factory.createIdentifier(JSON.stringify(value)) as unknown as ts.TypeNode)\n : ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(value));\n}\n\nfunction toTupleElement(ts: TypeScriptModule, element: IrTupleElement): ts.TypeNode {\n const type = toTypeNode(ts, element.type);\n if (element.isOptional) {\n return ts.factory.createOptionalTypeNode(type);\n }\n return element.isRest ? ts.factory.createRestTypeNode(type) : type;\n}\n\ntype LeafType = Extract<\n IrType,\n { kind: \"keyword\" | \"stringLiteral\" | \"numberLiteral\" | \"booleanLiteral\" | \"raw\" }\n>;\n\nfunction toLeafTypeNode(ts: TypeScriptModule, type: LeafType): ts.TypeNode {\n switch (type.kind) {\n case \"keyword\":\n return toKeywordType(ts, type.keyword);\n case \"stringLiteral\":\n return toStringLiteralType(ts, type.value, type.encoding);\n case \"numberLiteral\":\n return ts.factory.createLiteralTypeNode(toNumberExpression(ts, type.value));\n case \"booleanLiteral\":\n return ts.factory.createLiteralTypeNode(\n type.value ? ts.factory.createTrue() : ts.factory.createFalse(),\n );\n case \"raw\":\n // A node read from TypeScript goes back as it was, so the TypeScript printer indents it.\n return (\n (type.origin as ts.TypeNode | undefined) ??\n (ts.factory.createIdentifier(type.text) as unknown as ts.TypeNode)\n );\n default:\n return assertNever(type);\n }\n}\n\nfunction toReferenceNode(\n ts: TypeScriptModule,\n type: Extract<IrType, { kind: \"reference\" }>,\n): ts.TypeNode {\n const typeArguments =\n type.typeArguments.length > 0\n ? type.typeArguments.map((argument) => toTypeNode(ts, argument))\n : undefined;\n return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(type.name), typeArguments);\n}\n\n/** Convert one IR type. */\nexport function toTypeNode(ts: TypeScriptModule, type: IrType): ts.TypeNode {\n const convert = (inner: IrType) => toTypeNode(ts, inner);\n const { factory } = ts;\n switch (type.kind) {\n case \"keyword\":\n case \"stringLiteral\":\n case \"numberLiteral\":\n case \"booleanLiteral\":\n case \"raw\":\n return toLeafTypeNode(ts, type);\n case \"reference\":\n return toReferenceNode(ts, type);\n case \"array\":\n return factory.createArrayTypeNode(convert(type.element));\n case \"tuple\":\n return factory.createTupleTypeNode(\n type.elements.map((element) => toTupleElement(ts, element)),\n );\n case \"union\":\n return factory.createUnionTypeNode(type.types.map(convert));\n case \"intersection\":\n return factory.createIntersectionTypeNode(type.types.map(convert));\n case \"object\":\n return factory.createTypeLiteralNode(type.members.map((member) => toTypeElement(ts, member)));\n case \"indexedAccess\":\n return factory.createIndexedAccessTypeNode(convert(type.object), convert(type.index));\n case \"readonly\":\n return factory.createTypeOperatorNode(ts.SyntaxKind.ReadonlyKeyword, convert(type.type));\n default:\n return assertNever(type);\n }\n}\n\n/** Attach IR comments to a node as synthetic leading comments, as the original does. */\nexport function withComments<T extends ts.Node>(\n ts: TypeScriptModule,\n node: T,\n comments: readonly IrComment[],\n): T {\n for (const comment of comments) {\n const kind =\n comment.kind === \"block\"\n ? ts.SyntaxKind.MultiLineCommentTrivia\n : ts.SyntaxKind.SingleLineCommentTrivia;\n ts.addSyntheticLeadingComment(node, kind, comment.text, true);\n }\n return node;\n}\n\nfunction toPropertyName(ts: TypeScriptModule, name: IrPropertyName): ts.PropertyName {\n switch (name.kind) {\n case \"identifier\":\n return ts.factory.createIdentifier(name.text);\n case \"string\":\n return ts.factory.createStringLiteral(name.value);\n case \"number\":\n return ts.factory.createNumericLiteral(name.text);\n default:\n return assertNever(name);\n }\n}\n\nfunction readonlyModifiers(ts: TypeScriptModule, isReadonly: boolean): ts.Modifier[] | undefined {\n return isReadonly ? [ts.factory.createModifier(ts.SyntaxKind.ReadonlyKeyword)] : undefined;\n}\n\n/** Convert one property signature (for callbacks that receive a `ts.PropertySignature`). */\nexport function toPropertySignature(\n ts: TypeScriptModule,\n property: IrPropertySignature,\n): ts.PropertySignature {\n const questionToken = property.isOptional\n ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)\n : undefined;\n const signature = ts.factory.createPropertySignature(\n readonlyModifiers(ts, property.isReadonly),\n toPropertyName(ts, property.name),\n questionToken,\n toTypeNode(ts, property.type),\n );\n return withComments(ts, signature, property.comments);\n}\n\nexport function toTypeElement(ts: TypeScriptModule, member: IrMember): ts.TypeElement {\n if (member.kind === \"property\") {\n return toPropertySignature(ts, member);\n }\n const parameter = ts.factory.createParameterDeclaration(\n undefined,\n undefined,\n member.parameterName,\n undefined,\n toTypeNode(ts, member.parameterType),\n );\n const signature = ts.factory.createIndexSignature(\n readonlyModifiers(ts, member.isReadonly),\n [parameter],\n toTypeNode(ts, member.type),\n );\n return withComments(ts, signature, member.comments);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -48,18 +48,24 @@ function fromReference(ts, node) {
|
|
|
48
48
|
const typeArguments = (node.typeArguments ?? []).map(childrenOf(ts, node));
|
|
49
49
|
return { kind: "reference", name: ts.idText(node.typeName), typeArguments };
|
|
50
50
|
}
|
|
51
|
+
function fromTupleElement(ts, element, convert) {
|
|
52
|
+
if (ts.isRestTypeNode(element)) {
|
|
53
|
+
return { type: convert(element.type), isRest: true, isOptional: false };
|
|
54
|
+
}
|
|
55
|
+
if (ts.isOptionalTypeNode(element)) {
|
|
56
|
+
return { type: fromTypeNode(ts, element.type, element), isRest: false, isOptional: true };
|
|
57
|
+
}
|
|
58
|
+
return { type: convert(element), isRest: false, isOptional: false };
|
|
59
|
+
}
|
|
51
60
|
function fromTuple(ts, node) {
|
|
52
|
-
|
|
53
|
-
(element) => !ts.isNamedTupleMember(element) && !ts.isOptionalTypeNode(element)
|
|
54
|
-
);
|
|
55
|
-
if (!isPlain) {
|
|
61
|
+
if (node.elements.some((element) => ts.isNamedTupleMember(element))) {
|
|
56
62
|
return null;
|
|
57
63
|
}
|
|
58
64
|
const convert = childrenOf(ts, node);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
65
|
+
return {
|
|
66
|
+
kind: "tuple",
|
|
67
|
+
elements: node.elements.map((element) => fromTupleElement(ts, element, convert))
|
|
68
|
+
};
|
|
63
69
|
}
|
|
64
70
|
function fromComments(ts, node) {
|
|
65
71
|
const comments = ts.getSyntheticLeadingComments(node) ?? [];
|
|
@@ -179,7 +185,7 @@ function isFactoryParenthesis(ts, inner, parent) {
|
|
|
179
185
|
return false;
|
|
180
186
|
}
|
|
181
187
|
const isComposite = ts.isUnionTypeNode(inner) || ts.isIntersectionTypeNode(inner);
|
|
182
|
-
const isPostfixOrReadonlyParent = ts.isArrayTypeNode(parent) || ts.isIndexedAccessTypeNode(parent) || ts.isTypeOperatorNode(parent);
|
|
188
|
+
const isPostfixOrReadonlyParent = ts.isArrayTypeNode(parent) || ts.isIndexedAccessTypeNode(parent) || ts.isOptionalTypeNode(parent) || ts.isTypeOperatorNode(parent);
|
|
183
189
|
if (isPostfixOrReadonlyParent) {
|
|
184
190
|
return isComposite || ts.isTypeOperatorNode(inner);
|
|
185
191
|
}
|