openapi-typesafe 1.0.0-rc.1 → 1.0.0-rc.3
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/README.md +12 -5
- package/dist/adapters/node-deprecations/node-deprecations.cjs +14 -0
- package/dist/adapters/node-deprecations/node-deprecations.cjs.map +1 -0
- package/dist/adapters/node-deprecations/node-deprecations.mjs +12 -0
- package/dist/adapters/node-deprecations/node-deprecations.mjs.map +1 -0
- package/dist/adapters/redocly-loader/configured-headers.cjs +32 -0
- package/dist/adapters/redocly-loader/configured-headers.cjs.map +1 -0
- package/dist/adapters/redocly-loader/configured-headers.mjs +30 -0
- package/dist/adapters/redocly-loader/configured-headers.mjs.map +1 -0
- package/dist/adapters/redocly-loader/redocly-schema-loader.cjs +19 -6
- package/dist/adapters/redocly-loader/redocly-schema-loader.cjs.map +1 -1
- package/dist/adapters/redocly-loader/redocly-schema-loader.mjs +18 -5
- package/dist/adapters/redocly-loader/redocly-schema-loader.mjs.map +1 -1
- package/dist/adapters/redocly-loader/ref-access.cjs +37 -4
- package/dist/adapters/redocly-loader/ref-access.cjs.map +1 -1
- package/dist/adapters/redocly-loader/ref-access.mjs +37 -4
- package/dist/adapters/redocly-loader/ref-access.mjs.map +1 -1
- package/dist/adapters/redocly-loader/ref-resolution-check.cjs +191 -0
- package/dist/adapters/redocly-loader/ref-resolution-check.cjs.map +1 -0
- package/dist/adapters/redocly-loader/ref-resolution-check.mjs +189 -0
- package/dist/adapters/redocly-loader/ref-resolution-check.mjs.map +1 -0
- package/dist/adapters/redocly-loader/ref-resolution-steps.cjs +73 -0
- package/dist/adapters/redocly-loader/ref-resolution-steps.cjs.map +1 -0
- package/dist/adapters/redocly-loader/ref-resolution-steps.mjs +60 -0
- package/dist/adapters/redocly-loader/ref-resolution-steps.mjs.map +1 -0
- package/dist/adapters/redocly-loader/remote-fetch.cjs +41 -14
- package/dist/adapters/redocly-loader/remote-fetch.cjs.map +1 -1
- package/dist/adapters/redocly-loader/remote-fetch.mjs +40 -14
- package/dist/adapters/redocly-loader/remote-fetch.mjs.map +1 -1
- package/dist/adapters/redocly-loader/schema-load-errors.cjs +23 -5
- package/dist/adapters/redocly-loader/schema-load-errors.cjs.map +1 -1
- package/dist/adapters/redocly-loader/schema-load-errors.mjs +23 -5
- package/dist/adapters/redocly-loader/schema-load-errors.mjs.map +1 -1
- package/dist/adapters/redocly-loader/unsupported-keys.cjs +9 -1
- package/dist/adapters/redocly-loader/unsupported-keys.cjs.map +1 -1
- package/dist/adapters/redocly-loader/unsupported-keys.mjs +9 -1
- package/dist/adapters/redocly-loader/unsupported-keys.mjs.map +1 -1
- package/dist/adapters/terminal-logger/terminal-logger.cjs +6 -4
- package/dist/adapters/terminal-logger/terminal-logger.cjs.map +1 -1
- package/dist/adapters/terminal-logger/terminal-logger.mjs +6 -4
- package/dist/adapters/terminal-logger/terminal-logger.mjs.map +1 -1
- package/dist/adapters/type-ast-bridge/ir-to-typescript.cjs +2 -1
- package/dist/adapters/type-ast-bridge/ir-to-typescript.cjs.map +1 -1
- package/dist/adapters/type-ast-bridge/ir-to-typescript.mjs +2 -1
- package/dist/adapters/type-ast-bridge/ir-to-typescript.mjs.map +1 -1
- package/dist/adapters/type-ast-bridge/print-typescript.cjs.map +1 -1
- package/dist/adapters/type-ast-bridge/print-typescript.mjs.map +1 -1
- package/dist/api/default-ports.cjs +14 -0
- package/dist/api/default-ports.cjs.map +1 -1
- package/dist/api/default-ports.mjs +12 -1
- package/dist/api/default-ports.mjs.map +1 -1
- package/dist/api/discriminator-conflict-warnings.cjs +1 -1
- package/dist/api/discriminator-conflict-warnings.cjs.map +1 -1
- package/dist/api/discriminator-conflict-warnings.mjs +2 -2
- package/dist/api/discriminator-conflict-warnings.mjs.map +1 -1
- package/dist/api/discriminator-patch.cjs +8 -4
- package/dist/api/discriminator-patch.cjs.map +1 -1
- package/dist/api/discriminator-patch.mjs +9 -5
- package/dist/api/discriminator-patch.mjs.map +1 -1
- package/dist/api/discriminator-scan.cjs +2 -2
- package/dist/api/discriminator-scan.cjs.map +1 -1
- package/dist/api/discriminator-scan.mjs +3 -3
- package/dist/api/discriminator-scan.mjs.map +1 -1
- package/dist/api/document-refs.cjs +15 -12
- package/dist/api/document-refs.cjs.map +1 -1
- package/dist/api/document-refs.mjs +15 -12
- package/dist/api/document-refs.mjs.map +1 -1
- package/dist/api/document-run.cjs +6 -3
- package/dist/api/document-run.cjs.map +1 -1
- package/dist/api/document-run.mjs +6 -3
- package/dist/api/document-run.mjs.map +1 -1
- package/dist/api/footer-sink.cjs +25 -2
- package/dist/api/footer-sink.cjs.map +1 -1
- package/dist/api/footer-sink.mjs +25 -2
- package/dist/api/footer-sink.mjs.map +1 -1
- package/dist/api/legacy-callback-warning.cjs +7 -1
- package/dist/api/legacy-callback-warning.cjs.map +1 -1
- package/dist/api/legacy-callback-warning.mjs +8 -2
- package/dist/api/legacy-callback-warning.mjs.map +1 -1
- package/dist/api/legacy-ts-helpers.cjs.map +1 -1
- package/dist/api/legacy-ts-helpers.mjs.map +1 -1
- package/dist/api/legacy-utils.cjs.map +1 -1
- package/dist/api/legacy-utils.mjs.map +1 -1
- package/dist/api/openapi-ts.cjs +3 -2
- package/dist/api/openapi-ts.cjs.map +1 -1
- package/dist/api/openapi-ts.mjs +4 -3
- package/dist/api/openapi-ts.mjs.map +1 -1
- package/dist/api/string-to-ast.cjs +7 -9
- package/dist/api/string-to-ast.cjs.map +1 -1
- package/dist/api/string-to-ast.mjs +8 -9
- package/dist/api/string-to-ast.mjs.map +1 -1
- package/dist/api/transform-context.cjs +1 -1
- package/dist/api/transform-context.cjs.map +1 -1
- package/dist/api/transform-context.mjs +1 -1
- package/dist/api/transform-context.mjs.map +1 -1
- package/dist/api/transform-schema.cjs +2 -2
- package/dist/api/transform-schema.cjs.map +1 -1
- package/dist/api/transform-schema.mjs +3 -3
- package/dist/api/transform-schema.mjs.map +1 -1
- package/dist/application/print/type-printer.cjs +2 -1
- package/dist/application/print/type-printer.cjs.map +1 -1
- package/dist/application/print/type-printer.mjs +2 -1
- package/dist/application/print/type-printer.mjs.map +1 -1
- package/dist/application/transform/document/components.cjs +1 -1
- package/dist/application/transform/document/components.cjs.map +1 -1
- package/dist/application/transform/document/components.mjs +2 -2
- package/dist/application/transform/document/components.mjs.map +1 -1
- package/dist/application/transform/document/parameters.cjs +2 -2
- package/dist/application/transform/document/parameters.cjs.map +1 -1
- package/dist/application/transform/document/parameters.mjs +3 -3
- package/dist/application/transform/document/parameters.mjs.map +1 -1
- package/dist/application/transform/document/paths.cjs +2 -2
- package/dist/application/transform/document/paths.cjs.map +1 -1
- package/dist/application/transform/document/paths.mjs +3 -3
- package/dist/application/transform/document/paths.mjs.map +1 -1
- package/dist/application/transform/footer/evaluation.cjs +9 -0
- package/dist/application/transform/footer/evaluation.cjs.map +1 -1
- package/dist/application/transform/footer/evaluation.mjs +8 -1
- package/dist/application/transform/footer/evaluation.mjs.map +1 -1
- package/dist/application/transform/footer/type-evaluation.cjs +4 -112
- package/dist/application/transform/footer/type-evaluation.cjs.map +1 -1
- package/dist/application/transform/footer/type-evaluation.mjs +4 -112
- package/dist/application/transform/footer/type-evaluation.mjs.map +1 -1
- package/dist/application/transform/footer/type-indexing.cjs +107 -0
- package/dist/application/transform/footer/type-indexing.cjs.map +1 -0
- package/dist/application/transform/footer/type-indexing.mjs +105 -0
- package/dist/application/transform/footer/type-indexing.mjs.map +1 -0
- package/dist/application/transform/ref-pointer/pointer-type.cjs +1 -1
- package/dist/application/transform/ref-pointer/pointer-type.cjs.map +1 -1
- package/dist/application/transform/ref-pointer/pointer-type.mjs +2 -2
- package/dist/application/transform/ref-pointer/pointer-type.mjs.map +1 -1
- package/dist/application/transform/schema/access-flags.cjs +1 -1
- package/dist/application/transform/schema/access-flags.cjs.map +1 -1
- package/dist/application/transform/schema/access-flags.mjs +2 -2
- package/dist/application/transform/schema/access-flags.mjs.map +1 -1
- package/dist/application/transform/schema/array-type.cjs +2 -2
- package/dist/application/transform/schema/array-type.cjs.map +1 -1
- package/dist/application/transform/schema/array-type.mjs +3 -3
- package/dist/application/transform/schema/array-type.mjs.map +1 -1
- package/dist/application/transform/schema/composition-type.cjs +3 -3
- package/dist/application/transform/schema/composition-type.cjs.map +1 -1
- package/dist/application/transform/schema/composition-type.mjs +4 -4
- package/dist/application/transform/schema/composition-type.mjs.map +1 -1
- package/dist/application/transform/schema/enum-rule.cjs +3 -5
- package/dist/application/transform/schema/enum-rule.cjs.map +1 -1
- package/dist/application/transform/schema/enum-rule.mjs +4 -6
- package/dist/application/transform/schema/enum-rule.mjs.map +1 -1
- package/dist/application/transform/schema/presence-members.cjs +1 -1
- package/dist/application/transform/schema/presence-members.cjs.map +1 -1
- package/dist/application/transform/schema/presence-members.mjs +2 -2
- package/dist/application/transform/schema/presence-members.mjs.map +1 -1
- package/dist/application/transform/schema/required-variants.cjs +2 -2
- package/dist/application/transform/schema/required-variants.cjs.map +1 -1
- package/dist/application/transform/schema/required-variants.mjs +3 -3
- package/dist/application/transform/schema/required-variants.mjs.map +1 -1
- package/dist/application/transform/schema/unevaluated-properties.cjs +1 -1
- package/dist/application/transform/schema/unevaluated-properties.cjs.map +1 -1
- package/dist/application/transform/schema/unevaluated-properties.mjs +2 -2
- package/dist/application/transform/schema/unevaluated-properties.mjs.map +1 -1
- package/dist/application/transform/schema-comment.cjs +1 -1
- package/dist/application/transform/schema-comment.cjs.map +1 -1
- package/dist/application/transform/schema-comment.mjs +2 -2
- package/dist/application/transform/schema-comment.mjs.map +1 -1
- package/dist/cli/api-settings.cjs +78 -0
- package/dist/cli/api-settings.cjs.map +1 -0
- package/dist/cli/api-settings.mjs +73 -0
- package/dist/cli/api-settings.mjs.map +1 -0
- package/dist/cli/cli-arguments.cjs +1 -0
- package/dist/cli/cli-arguments.cjs.map +1 -1
- package/dist/cli/cli-arguments.mjs +1 -1
- package/dist/cli/cli-arguments.mjs.map +1 -1
- package/dist/cli/help-text.cjs +3 -3
- package/dist/cli/help-text.cjs.map +1 -1
- package/dist/cli/help-text.mjs +3 -3
- package/dist/cli/help-text.mjs.map +1 -1
- package/dist/cli/redocly-apis.cjs +8 -4
- package/dist/cli/redocly-apis.cjs.map +1 -1
- package/dist/cli/redocly-apis.mjs +7 -3
- package/dist/cli/redocly-apis.mjs.map +1 -1
- package/dist/cli/run-cli.cjs +5 -1
- package/dist/cli/run-cli.cjs.map +1 -1
- package/dist/cli/run-cli.mjs +5 -1
- package/dist/cli/run-cli.mjs.map +1 -1
- package/dist/domain/deprecations.cjs +11 -0
- package/dist/domain/deprecations.cjs.map +1 -0
- package/dist/domain/deprecations.mjs +9 -0
- package/dist/domain/deprecations.mjs.map +1 -0
- package/dist/domain/errors.cjs +4 -1
- package/dist/domain/errors.cjs.map +1 -1
- package/dist/domain/errors.mjs +4 -1
- package/dist/domain/errors.mjs.map +1 -1
- package/dist/domain/ir/constructors.cjs +2 -0
- package/dist/domain/ir/constructors.cjs.map +1 -1
- package/dist/domain/ir/constructors.mjs +2 -1
- package/dist/domain/ir/constructors.mjs.map +1 -1
- package/dist/domain/openapi/path-templates.cjs +1 -1
- package/dist/domain/openapi/path-templates.cjs.map +1 -1
- package/dist/domain/openapi/path-templates.mjs +1 -1
- package/dist/domain/openapi/path-templates.mjs.map +1 -1
- package/dist/domain/output-fixes.cjs +11 -14
- package/dist/domain/output-fixes.cjs.map +1 -1
- package/dist/domain/output-fixes.mjs +11 -13
- package/dist/domain/output-fixes.mjs.map +1 -1
- package/dist/domain/url-credentials.cjs +10 -0
- package/dist/domain/url-credentials.cjs.map +1 -0
- package/dist/domain/url-credentials.mjs +8 -0
- package/dist/domain/url-credentials.mjs.map +1 -0
- package/dist/domain/warnings.cjs +8 -1
- package/dist/domain/warnings.cjs.map +1 -1
- package/dist/domain/warnings.mjs +8 -1
- package/dist/domain/warnings.mjs.map +1 -1
- package/dist/index.cjs +4 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1185 -59
- package/dist/index.d.mts +1185 -59
- package/dist/index.d.ts +1185 -59
- package/dist/index.mjs +4 -2
- package/dist/index.mjs.map +1 -1
- package/dist/transform/path-item-object.cjs.map +1 -1
- package/dist/transform/path-item-object.mjs.map +1 -1
- package/package.json +5 -4
- package/src/adapters/node-deprecations/node-deprecations.ts +14 -0
- package/src/adapters/redocly-loader/configured-headers.ts +65 -0
- package/src/adapters/redocly-loader/redocly-schema-loader.ts +22 -7
- package/src/adapters/redocly-loader/ref-access.ts +60 -5
- package/src/adapters/redocly-loader/ref-resolution-check.ts +257 -0
- package/src/adapters/redocly-loader/ref-resolution-steps.ts +113 -0
- package/src/adapters/redocly-loader/remote-fetch.ts +77 -21
- package/src/adapters/redocly-loader/schema-load-errors.ts +33 -11
- package/src/adapters/redocly-loader/unsupported-keys.ts +17 -2
- package/src/adapters/terminal-logger/terminal-logger.ts +9 -5
- package/src/adapters/type-ast-bridge/ir-to-typescript.ts +2 -1
- package/src/adapters/type-ast-bridge/print-typescript.ts +3 -1
- package/src/adapters/type-ast-bridge/typescript-types.ts +57 -5
- package/src/api/default-ports.ts +23 -0
- package/src/api/discriminator-conflict-warnings.ts +2 -2
- package/src/api/discriminator-patch.ts +11 -7
- package/src/api/discriminator-scan.ts +3 -3
- package/src/api/document-refs.ts +19 -15
- package/src/api/document-run.ts +14 -6
- package/src/api/footer-sink.ts +34 -2
- package/src/api/legacy-callback-warning.ts +16 -5
- package/src/api/legacy-ts-helpers.ts +7 -5
- package/src/api/legacy-utils.ts +1 -1
- package/src/api/openapi-ts.ts +8 -2
- package/src/api/run-context.ts +37 -0
- package/src/api/string-to-ast.ts +11 -15
- package/src/api/transform-context.ts +10 -8
- package/src/api/transform-schema.ts +9 -8
- package/src/application/ports/deprecation-reporter.ts +9 -0
- package/src/application/print/type-printer.ts +2 -1
- package/src/application/transform/document/components.ts +2 -2
- package/src/application/transform/document/parameters.ts +4 -3
- package/src/application/transform/document/paths.ts +4 -3
- package/src/application/transform/footer/evaluation.ts +10 -0
- package/src/application/transform/footer/type-evaluation.ts +6 -133
- package/src/application/transform/footer/type-indexing.ts +152 -0
- package/src/application/transform/ref-pointer/pointer-type.ts +2 -4
- package/src/application/transform/schema/access-flags.ts +2 -2
- package/src/application/transform/schema/array-type.ts +3 -5
- package/src/application/transform/schema/composition-type.ts +4 -4
- package/src/application/transform/schema/enum-rule.ts +4 -6
- package/src/application/transform/schema/presence-members.ts +2 -2
- package/src/application/transform/schema/required-variants.ts +3 -3
- package/src/application/transform/schema/unevaluated-properties.ts +2 -2
- package/src/application/transform/schema-comment.ts +2 -2
- package/src/cli/api-settings.ts +109 -0
- package/src/cli/cli-arguments.ts +5 -2
- package/src/cli/help-text.ts +4 -4
- package/src/cli/redocly-apis.ts +13 -7
- package/src/cli/run-cli.ts +5 -1
- package/src/domain/deprecations.ts +15 -0
- package/src/domain/errors.ts +16 -4
- package/src/domain/ir/constructors.ts +3 -0
- package/src/domain/ir/nodes.ts +9 -6
- package/src/domain/openapi/path-templates.ts +2 -1
- package/src/domain/output-fixes.ts +16 -16
- package/src/domain/url-credentials.ts +18 -0
- package/src/domain/warnings.ts +7 -0
- package/src/index.ts +3 -6
- package/src/transform/path-item-object.ts +6 -2
- package/src/types/generator-options.ts +12 -32
- package/src/types/openapi-common.ts +1 -0
- package/src/types/openapi-request.ts +3 -0
- package/src/types/openapi-schema.ts +2 -0
- package/src/types/openapi-security.ts +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.mjs","sources":["../../../../src/application/transform/document/paths.ts"],"sourcesContent":["import { irIntersection, irObject, irProperty, irRaw } from \"../../../domain/ir/constructors.js\";\nimport type { IrMember, IrType } from \"../../../domain/ir/nodes.js\";\nimport { toPropertyName } from \"../../../domain/ir/property-name.js\";\nimport { escapeTemplateText } from \"../../../domain/ir/raw-text-escapes.js\";\nimport { createRef } from \"../../../domain/openapi/json-pointer.js\";\nimport type { OperationObject } from \"../../../domain/openapi/operation-object.js\";\nimport type {\n ParameterObject,\n ParameterOrReference,\n} from \"../../../domain/openapi/parameter-object.js\";\nimport {\n type PathItemObject,\n type PathsObject,\n pathItemOperations,\n} from \"../../../domain/openapi/path-item-object.js\";\nimport type { ReferenceSchema, SchemaObject } from \"../../../domain/openapi/schema-object.js\";\nimport { OutputFix } from \"../../../domain/output-fixes.js\";\nimport { documentEntries } from \"../document-entries.js\";\nimport { refType } from \"../ref-type.js\";\nimport type { TransformContext } from \"../transform-context.js\";\nimport { type DeclaredTypeLookup, NO_DECLARED_TYPES } from \"./declared-types.js\";\nimport { documentMember } from \"./document-member.js\";\nimport { pathItemType } from \"./path-item.js\";\nimport {\n type CoverRejection,\n coveringTemplateKeys,\n type PathKey,\n type PathKeyPart,\n type PathPlaceholder,\n} from \"./path-key-overlaps.js\";\nimport {\n type PathParameterMatch,\n placeholderText,\n replacedTemplateParts,\n} from \"./path-template-replace.js\";\nimport { assignabilityProof } from \"./type-assignability.js\";\n\nconst PATH_PARAMETER_RE = /\\{[^}]+\\}/g;\n\n/** Placeholders by parameter schema type; anything else is a string placeholder. */\nconst PLACEHOLDERS: ReadonlyMap<unknown, PathPlaceholder> = new Map([\n [\"number\", \"number\"],\n [\"integer\", \"number\"],\n [\"boolean\", \"boolean\"],\n]);\nconst STRING_PLACEHOLDER: PathPlaceholder = \"string\";\n\nfunction resolvedParameter(\n parameter: ParameterOrReference,\n context: TransformContext,\n): ParameterObject | undefined {\n return \"$ref\" in parameter && parameter.$ref\n ? (context.refs.resolve(parameter.$ref) as ParameterObject | undefined)\n : (parameter as ParameterObject);\n}\n\nfunction addPathParameters(\n parameters: readonly ParameterOrReference[],\n byName: Map<string, ParameterObject>,\n context: TransformContext,\n): void {\n for (const parameter of parameters) {\n const resolved = resolvedParameter(parameter, context);\n if (resolved && resolved.in === \"path\") {\n byName.set(resolved.name, resolved);\n }\n }\n}\n\n/** Path parameters of the path item and of its operations; later definitions win. */\nfunction pathParameters(\n pathItem: PathItemObject,\n context: TransformContext,\n): Map<string, ParameterObject> {\n const byName = new Map<string, ParameterObject>();\n addPathParameters(pathItem.parameters ?? [], byName, context);\n for (const { operation: entry } of pathItemOperations(pathItem)) {\n const operation = (entry as ReferenceSchema).$ref\n ? (context.refs.resolve((entry as ReferenceSchema).$ref) as OperationObject | undefined)\n : (entry as OperationObject);\n addPathParameters(operation?.parameters ?? [], byName, context);\n }\n return byName;\n}\n\n/** Each `{name}` of the URL and its own placeholder, from the URL split at the matches. */\nfunction splitTemplateParts(url: string, matches: readonly PathParameterMatch[]): PathKeyPart[] {\n return url.split(PATH_PARAMETER_RE).flatMap((text, index): PathKeyPart[] => {\n const type = matches[index]?.type;\n const textPart: PathKeyPart = { kind: \"text\", text };\n return type === undefined ? [textPart] : [textPart, { kind: \"placeholder\", type }];\n });\n}\n\n/**\n * `--path-params-as-types`: the URL as template parts, each `{name}` replaced by a placeholder for\n * its parameter's type, the way the original replaces them unless the `path-param-type-names` fix\n * is on (see `replacedTemplateParts`). Null when the URL has no complete `{…}` placeholder.\n */\nfunction pathTemplateParts(\n url: string,\n pathItem: PathItemObject,\n context: TransformContext,\n): PathKeyPart[] | null {\n const found = url.match(PATH_PARAMETER_RE);\n if (!found) {\n return null;\n }\n const parameters = pathParameters(pathItem, context);\n const matches = found.map((match): PathParameterMatch => {\n const schema = parameters.get(match.slice(1, -1))?.schema as SchemaObject | undefined;\n return { match, type: PLACEHOLDERS.get(schema?.type) ?? STRING_PLACEHOLDER };\n });\n return context.options.fixes.has(OutputFix.PATH_PARAM_TYPE_NAMES)\n ? splitTemplateParts(url, matches)\n : replacedTemplateParts(url, matches);\n}\n\n/**\n * The template literal type of the parts. The original escaped only backticks: a backslash or\n * `${` in the URL could end the literal or open a placeholder, and add code to the generated file\n * (intentional fix). So the text parts are escaped.\n */\nfunction templateText(parts: readonly PathKeyPart[]): string {\n const text = parts\n .map((part) =>\n part.kind === \"text\" ? escapeTemplateText(part.text) : placeholderText(part.type),\n )\n .join(\"\");\n return `\\`${text}\\``;\n}\n\n/** A path's member, its key and its path item type for the overlap check. */\nexport interface PathMember {\n readonly url: string;\n readonly member: IrMember;\n readonly key: PathKey;\n readonly type: IrType;\n}\n\nfunction pathItemMember(\n url: string,\n pathItem: PathItemObject,\n context: TransformContext,\n): PathMember {\n const isReadonly = context.options.immutable;\n const type = pathItemType(pathItem, { path: createRef([\"paths\", url]) }, context);\n const parts =\n context.options.pathParamsAsTypes && url.includes(\"{\")\n ? pathTemplateParts(url, pathItem, context)\n : null;\n if (parts === null) {\n const member = irProperty(toPropertyName(url), type, { isReadonly });\n return { url, member, key: literalKey(url), type };\n }\n const member: IrMember = {\n kind: \"indexSignature\",\n parameterName: \"path\",\n parameterType: irRaw(templateText(parts)),\n type,\n isReadonly,\n comments: [],\n };\n return { url, member, key: { kind: \"template\", parts }, type };\n}\n\nfunction literalKey(url: string): PathKey {\n return { kind: \"literal\", url };\n}\n\nconst PATHS_TYPE_NAME = \"paths\";\n\n/** The URL of `paths[\"/apps/{id}\"]`, or null for any other type. */\nfunction pathsIndexOf(type: IrType): string | null {\n if (type.kind !== \"indexedAccess\" || type.index.kind !== \"stringLiteral\") {\n return null;\n }\n const { object } = type;\n const isPaths =\n object.kind === \"reference\" &&\n object.name === PATHS_TYPE_NAME &&\n object.typeArguments.length === 0;\n return isPaths ? type.index.value : null;\n}\n\n/**\n * The lookup, and `paths[\"/apps/{id}\"]` as that path's item. The declarations cannot read it: a\n * templated path is no property of `paths`, and TypeScript finds it through the signature.\n */\nfunction withPathItems(\n paths: readonly PathMember[],\n lookup: DeclaredTypeLookup,\n): DeclaredTypeLookup {\n const byUrl = new Map(paths.map((path) => [path.url, path.type]));\n return (type) => {\n const url = pathsIndexOf(type);\n return (url === null ? undefined : byUrl.get(url)) ?? lookup(type);\n };\n}\n\n/**\n * The rejection of a covered path item: only one proven not assignable to the signature's type\n * counts (ADR-028). A pair the proof cannot decide keeps the original output, which may well\n * compile (`Record<string, never>` fits `{ [key: string]: unknown }`).\n */\nfunction rejectionOf(paths: readonly PathMember[], lookup: DeclaredTypeLookup): CoverRejection {\n const relate = assignabilityProof(withPathItems(paths, lookup));\n return (coveringIndex, coveredIndex) => {\n const coveringPath = paths[coveringIndex];\n const coveredPath = paths[coveredIndex];\n return (\n coveringPath !== undefined &&\n coveredPath !== undefined &&\n relate(coveredPath.type, coveringPath.type) === \"rejected\"\n );\n };\n}\n\n/**\n * The members as one object type. When an index signature covers another key, TypeScript checks\n * the covered key's type against it. Where that check surely fails (TS2411, TS2413), each such\n * signature gets an object of its own in an intersection: an intersection does not check its parts\n * against each other, and every key has the type it had in the one object. Output that compiles\n * keeps the one object. The lookup reads the types that path items reference; without it, a\n * reference decides nothing.\n */\nexport function pathsObjectType(\n paths: readonly PathMember[],\n lookup: DeclaredTypeLookup = NO_DECLARED_TYPES,\n): IrType {\n const keys = paths.map(({ key }) => key);\n const covering = coveringTemplateKeys(keys, rejectionOf(paths, lookup));\n if (covering.size === 0) {\n return irObject(paths.map(({ member }) => member));\n }\n const rest = paths.filter((_, index) => !covering.has(index)).map(({ member }) => member);\n const own = paths\n .filter((_, index) => covering.has(index))\n .map(({ member }) => irObject([member]));\n return irIntersection([irObject(rest), ...own]);\n}\n\n/** The members of the `paths` interface (OpenAPI 3.1 §4.8.8): one per path, by URL. */\nexport function pathMembers(paths: PathsObject, context: TransformContext): PathMember[] {\n const members: PathMember[] = [];\n for (const [url, pathItem] of documentEntries(paths, context.options)) {\n if (!pathItem || typeof pathItem !== \"object\") {\n continue;\n }\n if (\"$ref\" in pathItem) {\n const options = { isReadonly: context.options.immutable };\n const member = documentMember(url, refType(pathItem.$ref), pathItem, options);\n members.push({ url, member, key: literalKey(url), type: member.type });\n continue;\n }\n const startedAt = context.diagnostics.now();\n const path = pathItemMember(url, pathItem, context);\n members.push(path);\n // The original reports only paths written as properties.\n if (path.member.kind === \"property\") {\n context.diagnostics.debug(`Transformed path \"${url}\"`, context.diagnostics.now() - startedAt);\n }\n }\n return members;\n}\n\n/**\n * The `paths` interface body, with only the path items' own types for the overlap check. The\n * document transform checks the overlaps again once the referenced types are declared.\n */\nexport function pathsType(paths: PathsObject, context: TransformContext): IrType {\n return pathsObjectType(pathMembers(paths, context));\n}\n"],"names":["member"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"paths.mjs","sources":["../../../../src/application/transform/document/paths.ts"],"sourcesContent":["import { irIntersection, irObject, irProperty, irRaw } from \"../../../domain/ir/constructors.js\";\nimport type { IrMember, IrType } from \"../../../domain/ir/nodes.js\";\nimport { toPropertyName } from \"../../../domain/ir/property-name.js\";\nimport { escapeTemplateText } from \"../../../domain/ir/raw-text-escapes.js\";\nimport { createRef } from \"../../../domain/openapi/json-pointer.js\";\nimport type { OperationObject } from \"../../../domain/openapi/operation-object.js\";\nimport type {\n ParameterObject,\n ParameterOrReference,\n} from \"../../../domain/openapi/parameter-object.js\";\nimport {\n type PathItemObject,\n type PathsObject,\n pathItemOperations,\n} from \"../../../domain/openapi/path-item-object.js\";\nimport type { ReferenceSchema, SchemaObject } from \"../../../domain/openapi/schema-object.js\";\nimport { FIX } from \"../../../domain/output-fixes.js\";\nimport { documentEntries } from \"../document-entries.js\";\nimport { refType } from \"../ref-type.js\";\nimport type { TransformContext } from \"../transform-context.js\";\nimport { type DeclaredTypeLookup, NO_DECLARED_TYPES } from \"./declared-types.js\";\nimport { documentMember } from \"./document-member.js\";\nimport { pathItemType } from \"./path-item.js\";\nimport {\n type CoverRejection,\n coveringTemplateKeys,\n type PathKey,\n type PathKeyPart,\n type PathPlaceholder,\n} from \"./path-key-overlaps.js\";\nimport {\n type PathParameterMatch,\n placeholderText,\n replacedTemplateParts,\n} from \"./path-template-replace.js\";\nimport { assignabilityProof } from \"./type-assignability.js\";\n\n/** `[^{}]` keeps the scan linear: `[^}]` retried from every `{` of a long run of them. */\nconst PATH_PARAMETER_RE = /\\{[^{}]+\\}/g;\n\n/** Placeholders by parameter schema type; anything else is a string placeholder. */\nconst PLACEHOLDERS: ReadonlyMap<unknown, PathPlaceholder> = new Map([\n [\"number\", \"number\"],\n [\"integer\", \"number\"],\n [\"boolean\", \"boolean\"],\n]);\nconst STRING_PLACEHOLDER: PathPlaceholder = \"string\";\n\nfunction resolvedParameter(\n parameter: ParameterOrReference,\n context: TransformContext,\n): ParameterObject | undefined {\n return \"$ref\" in parameter && parameter.$ref\n ? (context.refs.resolve(parameter.$ref) as ParameterObject | undefined)\n : (parameter as ParameterObject);\n}\n\nfunction addPathParameters(\n parameters: readonly ParameterOrReference[],\n byName: Map<string, ParameterObject>,\n context: TransformContext,\n): void {\n for (const parameter of parameters) {\n const resolved = resolvedParameter(parameter, context);\n if (resolved && resolved.in === \"path\") {\n byName.set(resolved.name, resolved);\n }\n }\n}\n\n/** Path parameters of the path item and of its operations; later definitions win. */\nfunction pathParameters(\n pathItem: PathItemObject,\n context: TransformContext,\n): Map<string, ParameterObject> {\n const byName = new Map<string, ParameterObject>();\n addPathParameters(pathItem.parameters ?? [], byName, context);\n for (const { operation: entry } of pathItemOperations(pathItem)) {\n const operation = (entry as ReferenceSchema).$ref\n ? (context.refs.resolve((entry as ReferenceSchema).$ref) as OperationObject | undefined)\n : (entry as OperationObject);\n addPathParameters(operation?.parameters ?? [], byName, context);\n }\n return byName;\n}\n\n/** Each `{name}` of the URL and its own placeholder, from the URL split at the matches. */\nfunction splitTemplateParts(url: string, matches: readonly PathParameterMatch[]): PathKeyPart[] {\n return url.split(PATH_PARAMETER_RE).flatMap((text, index): PathKeyPart[] => {\n const type = matches[index]?.type;\n const textPart: PathKeyPart = { kind: \"text\", text };\n return type === undefined ? [textPart] : [textPart, { kind: \"placeholder\", type }];\n });\n}\n\n/**\n * `--path-params-as-types`: the URL as template parts, each `{name}` replaced by a placeholder for\n * its parameter's type, the way the original replaces them unless the `path-param-type-names` fix\n * is on (see `replacedTemplateParts`). Null when the URL has no complete `{…}` placeholder.\n */\nfunction pathTemplateParts(\n url: string,\n pathItem: PathItemObject,\n context: TransformContext,\n): PathKeyPart[] | null {\n const found = url.match(PATH_PARAMETER_RE);\n if (!found) {\n return null;\n }\n const parameters = pathParameters(pathItem, context);\n const matches = found.map((match): PathParameterMatch => {\n const schema = parameters.get(match.slice(1, -1))?.schema as SchemaObject | undefined;\n return { match, type: PLACEHOLDERS.get(schema?.type) ?? STRING_PLACEHOLDER };\n });\n return context.options.fixes.has(FIX.PATH_PARAM_TYPE_NAMES)\n ? splitTemplateParts(url, matches)\n : replacedTemplateParts(url, matches);\n}\n\n/**\n * The template literal type of the parts. The original escaped only backticks: a backslash or\n * `${` in the URL could end the literal or open a placeholder, and add code to the generated file\n * (intentional fix). So the text parts are escaped.\n */\nfunction templateText(parts: readonly PathKeyPart[]): string {\n const text = parts\n .map((part) =>\n part.kind === \"text\" ? escapeTemplateText(part.text) : placeholderText(part.type),\n )\n .join(\"\");\n return `\\`${text}\\``;\n}\n\n/** A path's member, its key and its path item type for the overlap check. */\nexport interface PathMember {\n readonly url: string;\n readonly member: IrMember;\n readonly key: PathKey;\n readonly type: IrType;\n}\n\nfunction pathItemMember(\n url: string,\n pathItem: PathItemObject,\n context: TransformContext,\n): PathMember {\n const isReadonly = context.options.immutable;\n const type = pathItemType(pathItem, { path: createRef([\"paths\", url]) }, context);\n const parts =\n context.options.pathParamsAsTypes && url.includes(\"{\")\n ? pathTemplateParts(url, pathItem, context)\n : null;\n if (parts === null) {\n const member = irProperty(toPropertyName(url), type, { isReadonly });\n return { url, member, key: literalKey(url), type };\n }\n const member: IrMember = {\n kind: \"indexSignature\",\n parameterName: \"path\",\n parameterType: irRaw(templateText(parts)),\n type,\n isReadonly,\n comments: [],\n };\n return { url, member, key: { kind: \"template\", parts }, type };\n}\n\nfunction literalKey(url: string): PathKey {\n return { kind: \"literal\", url };\n}\n\nconst PATHS_TYPE_NAME = \"paths\";\n\n/** The URL of `paths[\"/apps/{id}\"]`, or null for any other type. */\nfunction pathsIndexOf(type: IrType): string | null {\n if (type.kind !== \"indexedAccess\" || type.index.kind !== \"stringLiteral\") {\n return null;\n }\n const { object } = type;\n const isPaths =\n object.kind === \"reference\" &&\n object.name === PATHS_TYPE_NAME &&\n object.typeArguments.length === 0;\n return isPaths ? type.index.value : null;\n}\n\n/**\n * The lookup, and `paths[\"/apps/{id}\"]` as that path's item. The declarations cannot read it: a\n * templated path is no property of `paths`, and TypeScript finds it through the signature.\n */\nfunction withPathItems(\n paths: readonly PathMember[],\n lookup: DeclaredTypeLookup,\n): DeclaredTypeLookup {\n const byUrl = new Map(paths.map((path) => [path.url, path.type]));\n return (type) => {\n const url = pathsIndexOf(type);\n return (url === null ? undefined : byUrl.get(url)) ?? lookup(type);\n };\n}\n\n/**\n * The rejection of a covered path item: only one proven not assignable to the signature's type\n * counts (ADR-028). A pair the proof cannot decide keeps the original output, which may well\n * compile (`Record<string, never>` fits `{ [key: string]: unknown }`).\n */\nfunction rejectionOf(paths: readonly PathMember[], lookup: DeclaredTypeLookup): CoverRejection {\n const relate = assignabilityProof(withPathItems(paths, lookup));\n return (coveringIndex, coveredIndex) => {\n const coveringPath = paths[coveringIndex];\n const coveredPath = paths[coveredIndex];\n return (\n coveringPath !== undefined &&\n coveredPath !== undefined &&\n relate(coveredPath.type, coveringPath.type) === \"rejected\"\n );\n };\n}\n\n/**\n * The members as one object type. When an index signature covers another key, TypeScript checks\n * the covered key's type against it. Where that check surely fails (TS2411, TS2413), each such\n * signature gets an object of its own in an intersection: an intersection does not check its parts\n * against each other, and every key has the type it had in the one object. Output that compiles\n * keeps the one object. The lookup reads the types that path items reference; without it, a\n * reference decides nothing.\n */\nexport function pathsObjectType(\n paths: readonly PathMember[],\n lookup: DeclaredTypeLookup = NO_DECLARED_TYPES,\n): IrType {\n const keys = paths.map(({ key }) => key);\n const covering = coveringTemplateKeys(keys, rejectionOf(paths, lookup));\n if (covering.size === 0) {\n return irObject(paths.map(({ member }) => member));\n }\n const rest = paths.filter((_, index) => !covering.has(index)).map(({ member }) => member);\n const own = paths\n .filter((_, index) => covering.has(index))\n .map(({ member }) => irObject([member]));\n return irIntersection([irObject(rest), ...own]);\n}\n\n/** The members of the `paths` interface (OpenAPI 3.1 §4.8.8): one per path, by URL. */\nexport function pathMembers(paths: PathsObject, context: TransformContext): PathMember[] {\n const members: PathMember[] = [];\n for (const [url, pathItem] of documentEntries(paths, context.options)) {\n if (!pathItem || typeof pathItem !== \"object\") {\n continue;\n }\n if (\"$ref\" in pathItem) {\n const options = { isReadonly: context.options.immutable };\n const member = documentMember(url, refType(pathItem.$ref), pathItem, options);\n members.push({ url, member, key: literalKey(url), type: member.type });\n continue;\n }\n const startedAt = context.diagnostics.now();\n const path = pathItemMember(url, pathItem, context);\n members.push(path);\n // The original reports only paths written as properties.\n if (path.member.kind === \"property\") {\n context.diagnostics.debug(`Transformed path \"${url}\"`, context.diagnostics.now() - startedAt);\n }\n }\n return members;\n}\n\n/**\n * The `paths` interface body, with only the path items' own types for the overlap check. The\n * document transform checks the overlaps again once the referenced types are declared.\n */\nexport function pathsType(paths: PathsObject, context: TransformContext): IrType {\n return pathsObjectType(pathMembers(paths, context));\n}\n"],"names":["member"],"mappings":";;;;;;;;;;;;;;;AAsCA,MAAM,iBAAA,GAAoB,aAAA;AAG1B,MAAM,YAAA,uBAA0D,GAAA,CAAI;AAAA,EAClE,CAAC,UAAU,QAAQ,CAAA;AAAA,EACnB,CAAC,WAAW,QAAQ,CAAA;AAAA,EACpB,CAAC,WAAW,SAAS;AACvB,CAAC,CAAA;AACD,MAAM,kBAAA,GAAsC,QAAA;AAE5C,SAAS,iBAAA,CACP,WACA,OAAA,EAC6B;AAC7B,EAAA,OAAO,MAAA,IAAU,aAAa,SAAA,CAAU,IAAA,GACnC,QAAQ,IAAA,CAAK,OAAA,CAAQ,SAAA,CAAU,IAAI,CAAA,GACnC,SAAA;AACP;AAEA,SAAS,iBAAA,CACP,UAAA,EACA,MAAA,EACA,OAAA,EACM;AACN,EAAA,KAAA,MAAW,aAAa,UAAA,EAAY;AAClC,IAAA,MAAM,QAAA,GAAW,iBAAA,CAAkB,SAAA,EAAW,OAAO,CAAA;AACrD,IAAA,IAAI,QAAA,IAAY,QAAA,CAAS,EAAA,KAAO,MAAA,EAAQ;AACtC,MAAA,MAAA,CAAO,GAAA,CAAI,QAAA,CAAS,IAAA,EAAM,QAAQ,CAAA;AAAA,IACpC;AAAA,EACF;AACF;AAGA,SAAS,cAAA,CACP,UACA,OAAA,EAC8B;AAC9B,EAAA,MAAM,MAAA,uBAAa,GAAA,EAA6B;AAChD,EAAA,iBAAA,CAAkB,QAAA,CAAS,UAAA,IAAc,EAAC,EAAG,QAAQ,OAAO,CAAA;AAC5D,EAAA,KAAA,MAAW,EAAE,SAAA,EAAW,KAAA,EAAM,IAAK,kBAAA,CAAmB,QAAQ,CAAA,EAAG;AAC/D,IAAA,MAAM,SAAA,GAAa,MAA0B,IAAA,GACxC,OAAA,CAAQ,KAAK,OAAA,CAAS,KAAA,CAA0B,IAAI,CAAA,GACpD,KAAA;AACL,IAAA,iBAAA,CAAkB,SAAA,EAAW,UAAA,IAAc,EAAC,EAAG,QAAQ,OAAO,CAAA;AAAA,EAChE;AACA,EAAA,OAAO,MAAA;AACT;AAGA,SAAS,kBAAA,CAAmB,KAAa,OAAA,EAAuD;AAC9F,EAAA,OAAO,IAAI,KAAA,CAAM,iBAAiB,EAAE,OAAA,CAAQ,CAAC,MAAM,KAAA,KAAyB;AAC1E,IAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,KAAK,CAAA,EAAG,IAAA;AAC7B,IAAA,MAAM,QAAA,GAAwB,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAK;AACnD,IAAA,OAAO,IAAA,KAAS,MAAA,GAAY,CAAC,QAAQ,CAAA,GAAI,CAAC,QAAA,EAAU,EAAE,IAAA,EAAM,aAAA,EAAe,IAAA,EAAM,CAAA;AAAA,EACnF,CAAC,CAAA;AACH;AAOA,SAAS,iBAAA,CACP,GAAA,EACA,QAAA,EACA,OAAA,EACsB;AACtB,EAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,KAAA,CAAM,iBAAiB,CAAA;AACzC,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,UAAA,GAAa,cAAA,CAAe,QAAA,EAAU,OAAO,CAAA;AACnD,EAAA,MAAM,OAAA,GAAU,KAAA,CAAM,GAAA,CAAI,CAAC,KAAA,KAA8B;AACvD,IAAA,MAAM,MAAA,GAAS,WAAW,GAAA,CAAI,KAAA,CAAM,MAAM,CAAA,EAAG,EAAE,CAAC,CAAA,EAAG,MAAA;AACnD,IAAA,OAAO,EAAE,OAAO,IAAA,EAAM,YAAA,CAAa,IAAI,MAAA,EAAQ,IAAI,KAAK,kBAAA,EAAmB;AAAA,EAC7E,CAAC,CAAA;AACD,EAAA,OAAO,OAAA,CAAQ,OAAA,CAAQ,KAAA,CAAM,GAAA,CAAI,GAAA,CAAI,qBAAqB,CAAA,GACtD,kBAAA,CAAmB,GAAA,EAAK,OAAO,CAAA,GAC/B,qBAAA,CAAsB,KAAK,OAAO,CAAA;AACxC;AAOA,SAAS,aAAa,KAAA,EAAuC;AAC3D,EAAA,MAAM,OAAO,KAAA,CACV,GAAA;AAAA,IAAI,CAAC,IAAA,KACJ,IAAA,CAAK,IAAA,KAAS,MAAA,GAAS,kBAAA,CAAmB,IAAA,CAAK,IAAI,CAAA,GAAI,eAAA,CAAgB,IAAA,CAAK,IAAI;AAAA,GAClF,CACC,KAAK,EAAE,CAAA;AACV,EAAA,OAAO,KAAK,IAAI,CAAA,EAAA,CAAA;AAClB;AAUA,SAAS,cAAA,CACP,GAAA,EACA,QAAA,EACA,OAAA,EACY;AACZ,EAAA,MAAM,UAAA,GAAa,QAAQ,OAAA,CAAQ,SAAA;AACnC,EAAA,MAAM,IAAA,GAAO,YAAA,CAAa,QAAA,EAAU,EAAE,IAAA,EAAM,SAAA,CAAU,CAAC,OAAA,EAAS,GAAG,CAAC,CAAA,EAAE,EAAG,OAAO,CAAA;AAChF,EAAA,MAAM,KAAA,GACJ,OAAA,CAAQ,OAAA,CAAQ,iBAAA,IAAqB,GAAA,CAAI,QAAA,CAAS,GAAG,CAAA,GACjD,iBAAA,CAAkB,GAAA,EAAK,QAAA,EAAU,OAAO,CAAA,GACxC,IAAA;AACN,EAAA,IAAI,UAAU,IAAA,EAAM;AAClB,IAAA,MAAMA,OAAAA,GAAS,WAAW,cAAA,CAAe,GAAG,GAAG,IAAA,EAAM,EAAE,YAAY,CAAA;AACnE,IAAA,OAAO,EAAE,KAAK,MAAA,EAAAA,OAAAA,EAAQ,KAAK,UAAA,CAAW,GAAG,GAAG,IAAA,EAAK;AAAA,EACnD;AACA,EAAA,MAAM,MAAA,GAAmB;AAAA,IACvB,IAAA,EAAM,gBAAA;AAAA,IACN,aAAA,EAAe,MAAA;AAAA,IACf,aAAA,EAAe,KAAA,CAAM,YAAA,CAAa,KAAK,CAAC,CAAA;AAAA,IACxC,IAAA;AAAA,IACA,UAAA;AAAA,IACA,UAAU;AAAC,GACb;AACA,EAAA,OAAO,EAAE,KAAK,MAAA,EAAQ,GAAA,EAAK,EAAE,IAAA,EAAM,UAAA,EAAY,KAAA,EAAM,EAAG,IAAA,EAAK;AAC/D;AAEA,SAAS,WAAW,GAAA,EAAsB;AACxC,EAAA,OAAO,EAAE,IAAA,EAAM,SAAA,EAAW,GAAA,EAAI;AAChC;AAEA,MAAM,eAAA,GAAkB,OAAA;AAGxB,SAAS,aAAa,IAAA,EAA6B;AACjD,EAAA,IAAI,KAAK,IAAA,KAAS,eAAA,IAAmB,IAAA,CAAK,KAAA,CAAM,SAAS,eAAA,EAAiB;AACxE,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,EAAE,QAAO,GAAI,IAAA;AACnB,EAAA,MAAM,OAAA,GACJ,OAAO,IAAA,KAAS,WAAA,IAChB,OAAO,IAAA,KAAS,eAAA,IAChB,MAAA,CAAO,aAAA,CAAc,MAAA,KAAW,CAAA;AAClC,EAAA,OAAO,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,KAAA,GAAQ,IAAA;AACtC;AAMA,SAAS,aAAA,CACP,OACA,MAAA,EACoB;AACpB,EAAA,MAAM,KAAA,GAAQ,IAAI,GAAA,CAAI,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,KAAS,CAAC,IAAA,CAAK,GAAA,EAAK,IAAA,CAAK,IAAI,CAAC,CAAC,CAAA;AAChE,EAAA,OAAO,CAAC,IAAA,KAAS;AACf,IAAA,MAAM,GAAA,GAAM,aAAa,IAAI,CAAA;AAC7B,IAAA,OAAA,CAAQ,GAAA,KAAQ,OAAO,MAAA,GAAY,KAAA,CAAM,IAAI,GAAG,CAAA,KAAM,OAAO,IAAI,CAAA;AAAA,EACnE,CAAA;AACF;AAOA,SAAS,WAAA,CAAY,OAA8B,MAAA,EAA4C;AAC7F,EAAA,MAAM,MAAA,GAAS,kBAAA,CAAmB,aAAA,CAAc,KAAA,EAAO,MAAM,CAAC,CAAA;AAC9D,EAAA,OAAO,CAAC,eAAe,YAAA,KAAiB;AACtC,IAAA,MAAM,YAAA,GAAe,MAAM,aAAa,CAAA;AACxC,IAAA,MAAM,WAAA,GAAc,MAAM,YAAY,CAAA;AACtC,IAAA,OACE,YAAA,KAAiB,UACjB,WAAA,KAAgB,MAAA,IAChB,OAAO,WAAA,CAAY,IAAA,EAAM,YAAA,CAAa,IAAI,CAAA,KAAM,UAAA;AAAA,EAEpD,CAAA;AACF;AAUO,SAAS,eAAA,CACd,KAAA,EACA,MAAA,GAA6B,iBAAA,EACrB;AACR,EAAA,MAAM,OAAO,KAAA,CAAM,GAAA,CAAI,CAAC,EAAE,GAAA,OAAU,GAAG,CAAA;AACvC,EAAA,MAAM,WAAW,oBAAA,CAAqB,IAAA,EAAM,WAAA,CAAY,KAAA,EAAO,MAAM,CAAC,CAAA;AACtE,EAAA,IAAI,QAAA,CAAS,SAAS,CAAA,EAAG;AACvB,IAAA,OAAO,QAAA,CAAS,MAAM,GAAA,CAAI,CAAC,EAAE,MAAA,EAAO,KAAM,MAAM,CAAC,CAAA;AAAA,EACnD;AACA,EAAA,MAAM,OAAO,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,EAAG,UAAU,CAAC,QAAA,CAAS,GAAA,CAAI,KAAK,CAAC,CAAA,CAAE,GAAA,CAAI,CAAC,EAAE,MAAA,OAAa,MAAM,CAAA;AACxF,EAAA,MAAM,GAAA,GAAM,MACT,MAAA,CAAO,CAAC,GAAG,KAAA,KAAU,QAAA,CAAS,IAAI,KAAK,CAAC,EACxC,GAAA,CAAI,CAAC,EAAE,MAAA,EAAO,KAAM,SAAS,CAAC,MAAM,CAAC,CAAC,CAAA;AACzC,EAAA,OAAO,eAAe,CAAC,QAAA,CAAS,IAAI,CAAA,EAAG,GAAG,GAAG,CAAC,CAAA;AAChD;AAGO,SAAS,WAAA,CAAY,OAAoB,OAAA,EAAyC;AACvF,EAAA,MAAM,UAAwB,EAAC;AAC/B,EAAA,KAAA,MAAW,CAAC,KAAK,QAAQ,CAAA,IAAK,gBAAgB,KAAA,EAAO,OAAA,CAAQ,OAAO,CAAA,EAAG;AACrE,IAAA,IAAI,CAAC,QAAA,IAAY,OAAO,QAAA,KAAa,QAAA,EAAU;AAC7C,MAAA;AAAA,IACF;AACA,IAAA,IAAI,UAAU,QAAA,EAAU;AACtB,MAAA,MAAM,OAAA,GAAU,EAAE,UAAA,EAAY,OAAA,CAAQ,QAAQ,SAAA,EAAU;AACxD,MAAA,MAAM,MAAA,GAAS,eAAe,GAAA,EAAK,OAAA,CAAQ,SAAS,IAAI,CAAA,EAAG,UAAU,OAAO,CAAA;AAC5E,MAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,GAAA,EAAK,MAAA,EAAQ,GAAA,EAAK,UAAA,CAAW,GAAG,CAAA,EAAG,IAAA,EAAM,MAAA,CAAO,IAAA,EAAM,CAAA;AACrE,MAAA;AAAA,IACF;AACA,IAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,WAAA,CAAY,GAAA,EAAI;AAC1C,IAAA,MAAM,IAAA,GAAO,cAAA,CAAe,GAAA,EAAK,QAAA,EAAU,OAAO,CAAA;AAClD,IAAA,OAAA,CAAQ,KAAK,IAAI,CAAA;AAEjB,IAAA,IAAI,IAAA,CAAK,MAAA,CAAO,IAAA,KAAS,UAAA,EAAY;AACnC,MAAA,OAAA,CAAQ,WAAA,CAAY,MAAM,CAAA,kBAAA,EAAqB,GAAG,KAAK,OAAA,CAAQ,WAAA,CAAY,GAAA,EAAI,GAAI,SAAS,CAAA;AAAA,IAC9F;AAAA,EACF;AACA,EAAA,OAAO,OAAA;AACT;AAMO,SAAS,SAAA,CAAU,OAAoB,OAAA,EAAmC;AAC/E,EAAA,OAAO,eAAA,CAAgB,WAAA,CAAY,KAAA,EAAO,OAAO,CAAC,CAAA;AACpD;;"}
|
|
@@ -9,6 +9,13 @@ function unionType(types) {
|
|
|
9
9
|
}
|
|
10
10
|
return types.length === 0 ? NEVER : { kind: "union", types };
|
|
11
11
|
}
|
|
12
|
+
function intersectionType(types) {
|
|
13
|
+
return types.length === 1 ? types[0] : { kind: "intersection", types };
|
|
14
|
+
}
|
|
15
|
+
const NULLISH = /* @__PURE__ */ new Set(["null", "undefined"]);
|
|
16
|
+
function isNullish(type) {
|
|
17
|
+
return type.kind === "keyword" && NULLISH.has(type.keyword);
|
|
18
|
+
}
|
|
12
19
|
function propertyKey(name) {
|
|
13
20
|
return name.kind === "string" ? name.value : name.text;
|
|
14
21
|
}
|
|
@@ -28,6 +35,8 @@ exports.MISSING = MISSING;
|
|
|
28
35
|
exports.NEVER = NEVER;
|
|
29
36
|
exports.OPAQUE = OPAQUE;
|
|
30
37
|
exports.absorbed = absorbed;
|
|
38
|
+
exports.intersectionType = intersectionType;
|
|
39
|
+
exports.isNullish = isNullish;
|
|
31
40
|
exports.propertyKey = propertyKey;
|
|
32
41
|
exports.unionType = unionType;
|
|
33
42
|
//# sourceMappingURL=evaluation.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evaluation.cjs","sources":["../../../../src/application/transform/footer/evaluation.ts"],"sourcesContent":["import type { IrPropertyName, IrType } from \"../../../domain/ir/nodes.js\";\n\n/** The values the evaluator of the `--enum-values` check works with (ADR-027). */\n\n/** A type as evaluated: `deep` is set inside `FlattenedDeepRequired`. */\nexport interface Evaluated {\n readonly kind: \"type\";\n readonly type: IrType;\n readonly deep: boolean;\n}\n\nexport type Evaluation = Evaluated | { readonly kind: \"missing\" } | { readonly kind: \"opaque\" };\n\nexport const MISSING: Evaluation = { kind: \"missing\" };\nexport const OPAQUE: Evaluation = { kind: \"opaque\" };\n\nexport const NEVER: IrType = { kind: \"keyword\", keyword: \"never\" };\n\nexport function unionType(types: readonly IrType[]): IrType {\n if (types.length === 1) {\n return types[0] as IrType;\n }\n return types.length === 0 ? NEVER : { kind: \"union\", types };\n}\n\nexport function propertyKey(name: IrPropertyName): string {\n return name.kind === \"string\" ? name.value : name.text;\n}\n\nfunction isKeyword(member: Evaluation, keyword: string): boolean {\n return (\n member.kind === \"type\" && member.type.kind === \"keyword\" && member.type.keyword === keyword\n );\n}\n\n/**\n * Union members as TypeScript reduces them: `any` absorbs every member, `unknown` every member\n * but `any`, so `{ a: X } | unknown` is `unknown`. An opaque member may be `any`.\n */\nexport function absorbed(members: readonly Evaluation[]): readonly Evaluation[] {\n const any = members.find((member) => isKeyword(member, \"any\"));\n const unknown = members.find((member) => isKeyword(member, \"unknown\"));\n if (any !== undefined || unknown === undefined) {\n return any === undefined ? members : [any];\n }\n return members.some((member) => member.kind !== \"type\") ? [OPAQUE] : [unknown];\n}\n"],"names":[],"mappings":";;AAaO,MAAM,OAAA,GAAsB,EAAE,IAAA,EAAM,SAAA;AACpC,MAAM,MAAA,GAAqB,EAAE,IAAA,EAAM,QAAA;AAEnC,MAAM,KAAA,GAAgB,EAAE,IAAA,EAAM,SAAA,EAAW,SAAS,OAAA;AAElD,SAAS,UAAU,KAAA,EAAkC;AAC1D,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,IAAA,OAAO,MAAM,CAAC,CAAA;AAAA,EAChB;AACA,EAAA,OAAO,MAAM,MAAA,KAAW,CAAA,GAAI,QAAQ,EAAE,IAAA,EAAM,SAAS,KAAA,EAAM;AAC7D;AAEO,SAAS,YAAY,IAAA,EAA8B;AACxD,EAAA,OAAO,IAAA,CAAK,IAAA,KAAS,QAAA,GAAW,IAAA,CAAK,QAAQ,IAAA,CAAK,IAAA;AACpD;AAEA,SAAS,SAAA,CAAU,QAAoB,OAAA,EAA0B;AAC/D,EAAA,OACE,MAAA,CAAO,SAAS,MAAA,IAAU,MAAA,CAAO,KAAK,IAAA,KAAS,SAAA,IAAa,MAAA,CAAO,IAAA,CAAK,OAAA,KAAY,OAAA;AAExF;AAMO,SAAS,SAAS,OAAA,EAAuD;AAC9E,EAAA,MAAM,GAAA,GAAM,QAAQ,IAAA,CAAK,CAAC,WAAW,SAAA,CAAU,MAAA,EAAQ,KAAK,CAAC,CAAA;AAC7D,EAAA,MAAM,OAAA,GAAU,QAAQ,IAAA,CAAK,CAAC,WAAW,SAAA,CAAU,MAAA,EAAQ,SAAS,CAAC,CAAA;AACrE,EAAA,IAAI,GAAA,KAAQ,MAAA,IAAa,OAAA,KAAY,MAAA,EAAW;AAC9C,IAAA,OAAO,GAAA,KAAQ,MAAA,GAAY,OAAA,GAAU,CAAC,GAAG,CAAA;AAAA,EAC3C;AACA,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,CAAC,MAAA,KAAW,MAAA,CAAO,IAAA,KAAS,MAAM,CAAA,GAAI,CAAC,MAAM,CAAA,GAAI,CAAC,OAAO,CAAA;AAC/E
|
|
1
|
+
{"version":3,"file":"evaluation.cjs","sources":["../../../../src/application/transform/footer/evaluation.ts"],"sourcesContent":["import type { IrPropertyName, IrType } from \"../../../domain/ir/nodes.js\";\n\n/** The values the evaluator of the `--enum-values` check works with (ADR-027). */\n\n/** A type as evaluated: `deep` is set inside `FlattenedDeepRequired`. */\nexport interface Evaluated {\n readonly kind: \"type\";\n readonly type: IrType;\n readonly deep: boolean;\n}\n\nexport type Evaluation = Evaluated | { readonly kind: \"missing\" } | { readonly kind: \"opaque\" };\n\nexport const MISSING: Evaluation = { kind: \"missing\" };\nexport const OPAQUE: Evaluation = { kind: \"opaque\" };\n\nexport const NEVER: IrType = { kind: \"keyword\", keyword: \"never\" };\n\nexport function unionType(types: readonly IrType[]): IrType {\n if (types.length === 1) {\n return types[0] as IrType;\n }\n return types.length === 0 ? NEVER : { kind: \"union\", types };\n}\n\nexport function intersectionType(types: readonly IrType[]): IrType {\n return types.length === 1 ? (types[0] as IrType) : { kind: \"intersection\", types };\n}\n\nconst NULLISH: ReadonlySet<string> = new Set([\"null\", \"undefined\"]);\n\nexport function isNullish(type: IrType): boolean {\n return type.kind === \"keyword\" && NULLISH.has(type.keyword);\n}\n\nexport function propertyKey(name: IrPropertyName): string {\n return name.kind === \"string\" ? name.value : name.text;\n}\n\nfunction isKeyword(member: Evaluation, keyword: string): boolean {\n return (\n member.kind === \"type\" && member.type.kind === \"keyword\" && member.type.keyword === keyword\n );\n}\n\n/**\n * Union members as TypeScript reduces them: `any` absorbs every member, `unknown` every member\n * but `any`, so `{ a: X } | unknown` is `unknown`. An opaque member may be `any`.\n */\nexport function absorbed(members: readonly Evaluation[]): readonly Evaluation[] {\n const any = members.find((member) => isKeyword(member, \"any\"));\n const unknown = members.find((member) => isKeyword(member, \"unknown\"));\n if (any !== undefined || unknown === undefined) {\n return any === undefined ? members : [any];\n }\n return members.some((member) => member.kind !== \"type\") ? [OPAQUE] : [unknown];\n}\n"],"names":[],"mappings":";;AAaO,MAAM,OAAA,GAAsB,EAAE,IAAA,EAAM,SAAA;AACpC,MAAM,MAAA,GAAqB,EAAE,IAAA,EAAM,QAAA;AAEnC,MAAM,KAAA,GAAgB,EAAE,IAAA,EAAM,SAAA,EAAW,SAAS,OAAA;AAElD,SAAS,UAAU,KAAA,EAAkC;AAC1D,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,IAAA,OAAO,MAAM,CAAC,CAAA;AAAA,EAChB;AACA,EAAA,OAAO,MAAM,MAAA,KAAW,CAAA,GAAI,QAAQ,EAAE,IAAA,EAAM,SAAS,KAAA,EAAM;AAC7D;AAEO,SAAS,iBAAiB,KAAA,EAAkC;AACjE,EAAA,OAAO,KAAA,CAAM,WAAW,CAAA,GAAK,KAAA,CAAM,CAAC,CAAA,GAAe,EAAE,IAAA,EAAM,cAAA,EAAgB,KAAA,EAAM;AACnF;AAEA,MAAM,0BAA+B,IAAI,GAAA,CAAI,CAAC,MAAA,EAAQ,WAAW,CAAC,CAAA;AAE3D,SAAS,UAAU,IAAA,EAAuB;AAC/C,EAAA,OAAO,KAAK,IAAA,KAAS,SAAA,IAAa,OAAA,CAAQ,GAAA,CAAI,KAAK,OAAO,CAAA;AAC5D;AAEO,SAAS,YAAY,IAAA,EAA8B;AACxD,EAAA,OAAO,IAAA,CAAK,IAAA,KAAS,QAAA,GAAW,IAAA,CAAK,QAAQ,IAAA,CAAK,IAAA;AACpD;AAEA,SAAS,SAAA,CAAU,QAAoB,OAAA,EAA0B;AAC/D,EAAA,OACE,MAAA,CAAO,SAAS,MAAA,IAAU,MAAA,CAAO,KAAK,IAAA,KAAS,SAAA,IAAa,MAAA,CAAO,IAAA,CAAK,OAAA,KAAY,OAAA;AAExF;AAMO,SAAS,SAAS,OAAA,EAAuD;AAC9E,EAAA,MAAM,GAAA,GAAM,QAAQ,IAAA,CAAK,CAAC,WAAW,SAAA,CAAU,MAAA,EAAQ,KAAK,CAAC,CAAA;AAC7D,EAAA,MAAM,OAAA,GAAU,QAAQ,IAAA,CAAK,CAAC,WAAW,SAAA,CAAU,MAAA,EAAQ,SAAS,CAAC,CAAA;AACrE,EAAA,IAAI,GAAA,KAAQ,MAAA,IAAa,OAAA,KAAY,MAAA,EAAW;AAC9C,IAAA,OAAO,GAAA,KAAQ,MAAA,GAAY,OAAA,GAAU,CAAC,GAAG,CAAA;AAAA,EAC3C;AACA,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,CAAC,MAAA,KAAW,MAAA,CAAO,IAAA,KAAS,MAAM,CAAA,GAAI,CAAC,MAAM,CAAA,GAAI,CAAC,OAAO,CAAA;AAC/E;;;;;;;;;"}
|
|
@@ -7,6 +7,13 @@ function unionType(types) {
|
|
|
7
7
|
}
|
|
8
8
|
return types.length === 0 ? NEVER : { kind: "union", types };
|
|
9
9
|
}
|
|
10
|
+
function intersectionType(types) {
|
|
11
|
+
return types.length === 1 ? types[0] : { kind: "intersection", types };
|
|
12
|
+
}
|
|
13
|
+
const NULLISH = /* @__PURE__ */ new Set(["null", "undefined"]);
|
|
14
|
+
function isNullish(type) {
|
|
15
|
+
return type.kind === "keyword" && NULLISH.has(type.keyword);
|
|
16
|
+
}
|
|
10
17
|
function propertyKey(name) {
|
|
11
18
|
return name.kind === "string" ? name.value : name.text;
|
|
12
19
|
}
|
|
@@ -22,5 +29,5 @@ function absorbed(members) {
|
|
|
22
29
|
return members.some((member) => member.kind !== "type") ? [OPAQUE] : [unknown];
|
|
23
30
|
}
|
|
24
31
|
|
|
25
|
-
export { MISSING, NEVER, OPAQUE, absorbed, propertyKey, unionType };
|
|
32
|
+
export { MISSING, NEVER, OPAQUE, absorbed, intersectionType, isNullish, propertyKey, unionType };
|
|
26
33
|
//# sourceMappingURL=evaluation.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evaluation.mjs","sources":["../../../../src/application/transform/footer/evaluation.ts"],"sourcesContent":["import type { IrPropertyName, IrType } from \"../../../domain/ir/nodes.js\";\n\n/** The values the evaluator of the `--enum-values` check works with (ADR-027). */\n\n/** A type as evaluated: `deep` is set inside `FlattenedDeepRequired`. */\nexport interface Evaluated {\n readonly kind: \"type\";\n readonly type: IrType;\n readonly deep: boolean;\n}\n\nexport type Evaluation = Evaluated | { readonly kind: \"missing\" } | { readonly kind: \"opaque\" };\n\nexport const MISSING: Evaluation = { kind: \"missing\" };\nexport const OPAQUE: Evaluation = { kind: \"opaque\" };\n\nexport const NEVER: IrType = { kind: \"keyword\", keyword: \"never\" };\n\nexport function unionType(types: readonly IrType[]): IrType {\n if (types.length === 1) {\n return types[0] as IrType;\n }\n return types.length === 0 ? NEVER : { kind: \"union\", types };\n}\n\nexport function propertyKey(name: IrPropertyName): string {\n return name.kind === \"string\" ? name.value : name.text;\n}\n\nfunction isKeyword(member: Evaluation, keyword: string): boolean {\n return (\n member.kind === \"type\" && member.type.kind === \"keyword\" && member.type.keyword === keyword\n );\n}\n\n/**\n * Union members as TypeScript reduces them: `any` absorbs every member, `unknown` every member\n * but `any`, so `{ a: X } | unknown` is `unknown`. An opaque member may be `any`.\n */\nexport function absorbed(members: readonly Evaluation[]): readonly Evaluation[] {\n const any = members.find((member) => isKeyword(member, \"any\"));\n const unknown = members.find((member) => isKeyword(member, \"unknown\"));\n if (any !== undefined || unknown === undefined) {\n return any === undefined ? members : [any];\n }\n return members.some((member) => member.kind !== \"type\") ? [OPAQUE] : [unknown];\n}\n"],"names":[],"mappings":"AAaO,MAAM,OAAA,GAAsB,EAAE,IAAA,EAAM,SAAA;AACpC,MAAM,MAAA,GAAqB,EAAE,IAAA,EAAM,QAAA;AAEnC,MAAM,KAAA,GAAgB,EAAE,IAAA,EAAM,SAAA,EAAW,SAAS,OAAA;AAElD,SAAS,UAAU,KAAA,EAAkC;AAC1D,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,IAAA,OAAO,MAAM,CAAC,CAAA;AAAA,EAChB;AACA,EAAA,OAAO,MAAM,MAAA,KAAW,CAAA,GAAI,QAAQ,EAAE,IAAA,EAAM,SAAS,KAAA,EAAM;AAC7D;AAEO,SAAS,YAAY,IAAA,EAA8B;AACxD,EAAA,OAAO,IAAA,CAAK,IAAA,KAAS,QAAA,GAAW,IAAA,CAAK,QAAQ,IAAA,CAAK,IAAA;AACpD;AAEA,SAAS,SAAA,CAAU,QAAoB,OAAA,EAA0B;AAC/D,EAAA,OACE,MAAA,CAAO,SAAS,MAAA,IAAU,MAAA,CAAO,KAAK,IAAA,KAAS,SAAA,IAAa,MAAA,CAAO,IAAA,CAAK,OAAA,KAAY,OAAA;AAExF;AAMO,SAAS,SAAS,OAAA,EAAuD;AAC9E,EAAA,MAAM,GAAA,GAAM,QAAQ,IAAA,CAAK,CAAC,WAAW,SAAA,CAAU,MAAA,EAAQ,KAAK,CAAC,CAAA;AAC7D,EAAA,MAAM,OAAA,GAAU,QAAQ,IAAA,CAAK,CAAC,WAAW,SAAA,CAAU,MAAA,EAAQ,SAAS,CAAC,CAAA;AACrE,EAAA,IAAI,GAAA,KAAQ,MAAA,IAAa,OAAA,KAAY,MAAA,EAAW;AAC9C,IAAA,OAAO,GAAA,KAAQ,MAAA,GAAY,OAAA,GAAU,CAAC,GAAG,CAAA;AAAA,EAC3C;AACA,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,CAAC,MAAA,KAAW,MAAA,CAAO,IAAA,KAAS,MAAM,CAAA,GAAI,CAAC,MAAM,CAAA,GAAI,CAAC,OAAO,CAAA;AAC/E;;"}
|
|
1
|
+
{"version":3,"file":"evaluation.mjs","sources":["../../../../src/application/transform/footer/evaluation.ts"],"sourcesContent":["import type { IrPropertyName, IrType } from \"../../../domain/ir/nodes.js\";\n\n/** The values the evaluator of the `--enum-values` check works with (ADR-027). */\n\n/** A type as evaluated: `deep` is set inside `FlattenedDeepRequired`. */\nexport interface Evaluated {\n readonly kind: \"type\";\n readonly type: IrType;\n readonly deep: boolean;\n}\n\nexport type Evaluation = Evaluated | { readonly kind: \"missing\" } | { readonly kind: \"opaque\" };\n\nexport const MISSING: Evaluation = { kind: \"missing\" };\nexport const OPAQUE: Evaluation = { kind: \"opaque\" };\n\nexport const NEVER: IrType = { kind: \"keyword\", keyword: \"never\" };\n\nexport function unionType(types: readonly IrType[]): IrType {\n if (types.length === 1) {\n return types[0] as IrType;\n }\n return types.length === 0 ? NEVER : { kind: \"union\", types };\n}\n\nexport function intersectionType(types: readonly IrType[]): IrType {\n return types.length === 1 ? (types[0] as IrType) : { kind: \"intersection\", types };\n}\n\nconst NULLISH: ReadonlySet<string> = new Set([\"null\", \"undefined\"]);\n\nexport function isNullish(type: IrType): boolean {\n return type.kind === \"keyword\" && NULLISH.has(type.keyword);\n}\n\nexport function propertyKey(name: IrPropertyName): string {\n return name.kind === \"string\" ? name.value : name.text;\n}\n\nfunction isKeyword(member: Evaluation, keyword: string): boolean {\n return (\n member.kind === \"type\" && member.type.kind === \"keyword\" && member.type.keyword === keyword\n );\n}\n\n/**\n * Union members as TypeScript reduces them: `any` absorbs every member, `unknown` every member\n * but `any`, so `{ a: X } | unknown` is `unknown`. An opaque member may be `any`.\n */\nexport function absorbed(members: readonly Evaluation[]): readonly Evaluation[] {\n const any = members.find((member) => isKeyword(member, \"any\"));\n const unknown = members.find((member) => isKeyword(member, \"unknown\"));\n if (any !== undefined || unknown === undefined) {\n return any === undefined ? members : [any];\n }\n return members.some((member) => member.kind !== \"type\") ? [OPAQUE] : [unknown];\n}\n"],"names":[],"mappings":"AAaO,MAAM,OAAA,GAAsB,EAAE,IAAA,EAAM,SAAA;AACpC,MAAM,MAAA,GAAqB,EAAE,IAAA,EAAM,QAAA;AAEnC,MAAM,KAAA,GAAgB,EAAE,IAAA,EAAM,SAAA,EAAW,SAAS,OAAA;AAElD,SAAS,UAAU,KAAA,EAAkC;AAC1D,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,IAAA,OAAO,MAAM,CAAC,CAAA;AAAA,EAChB;AACA,EAAA,OAAO,MAAM,MAAA,KAAW,CAAA,GAAI,QAAQ,EAAE,IAAA,EAAM,SAAS,KAAA,EAAM;AAC7D;AAEO,SAAS,iBAAiB,KAAA,EAAkC;AACjE,EAAA,OAAO,KAAA,CAAM,WAAW,CAAA,GAAK,KAAA,CAAM,CAAC,CAAA,GAAe,EAAE,IAAA,EAAM,cAAA,EAAgB,KAAA,EAAM;AACnF;AAEA,MAAM,0BAA+B,IAAI,GAAA,CAAI,CAAC,MAAA,EAAQ,WAAW,CAAC,CAAA;AAE3D,SAAS,UAAU,IAAA,EAAuB;AAC/C,EAAA,OAAO,KAAK,IAAA,KAAS,SAAA,IAAa,OAAA,CAAQ,GAAA,CAAI,KAAK,OAAO,CAAA;AAC5D;AAEO,SAAS,YAAY,IAAA,EAA8B;AACxD,EAAA,OAAO,IAAA,CAAK,IAAA,KAAS,QAAA,GAAW,IAAA,CAAK,QAAQ,IAAA,CAAK,IAAA;AACpD;AAEA,SAAS,SAAA,CAAU,QAAoB,OAAA,EAA0B;AAC/D,EAAA,OACE,MAAA,CAAO,SAAS,MAAA,IAAU,MAAA,CAAO,KAAK,IAAA,KAAS,SAAA,IAAa,MAAA,CAAO,IAAA,CAAK,OAAA,KAAY,OAAA;AAExF;AAMO,SAAS,SAAS,OAAA,EAAuD;AAC9E,EAAA,MAAM,GAAA,GAAM,QAAQ,IAAA,CAAK,CAAC,WAAW,SAAA,CAAU,MAAA,EAAQ,KAAK,CAAC,CAAA;AAC7D,EAAA,MAAM,OAAA,GAAU,QAAQ,IAAA,CAAK,CAAC,WAAW,SAAA,CAAU,MAAA,EAAQ,SAAS,CAAC,CAAA;AACrE,EAAA,IAAI,GAAA,KAAQ,MAAA,IAAa,OAAA,KAAY,MAAA,EAAW;AAC9C,IAAA,OAAO,GAAA,KAAQ,MAAA,GAAY,OAAA,GAAU,CAAC,GAAG,CAAA;AAAA,EAC3C;AACA,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,CAAC,MAAA,KAAW,MAAA,CAAO,IAAA,KAAS,MAAM,CAAA,GAAI,CAAC,MAAM,CAAA,GAAI,CAAC,OAAO,CAAA;AAC/E;;"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const evaluation = require('./evaluation.cjs');
|
|
4
|
+
const typeIndexing = require('./type-indexing.cjs');
|
|
4
5
|
const typeRules = require('./type-rules.cjs');
|
|
5
6
|
|
|
6
7
|
const MAX_EXPANSIONS = 200;
|
|
7
8
|
const DEEP_PREFIX = "FlattenedDeepRequired<";
|
|
8
9
|
const MAX_DISTRIBUTED = 64;
|
|
9
|
-
const NULLISH = /* @__PURE__ */ new Set(["null", "undefined"]);
|
|
10
10
|
class TypeEvaluator {
|
|
11
11
|
declared = /* @__PURE__ */ new Map();
|
|
12
12
|
expansions = 0;
|
|
@@ -110,14 +110,14 @@ class TypeEvaluator {
|
|
|
110
110
|
for (const list of memberLists) {
|
|
111
111
|
combinations = combinations.flatMap((done) => list.map((member) => [...done, member.type]));
|
|
112
112
|
}
|
|
113
|
-
return combinations.map((types) => ({ ...value, type: intersectionType(types) }));
|
|
113
|
+
return combinations.map((types) => ({ ...value, type: evaluation.intersectionType(types) }));
|
|
114
114
|
}
|
|
115
115
|
withoutNullish(value) {
|
|
116
116
|
const members = this.membersOf(value);
|
|
117
117
|
if (members.some((member) => member.kind !== "type")) {
|
|
118
118
|
return evaluation.OPAQUE;
|
|
119
119
|
}
|
|
120
|
-
const kept = members.filter((member) => !isNullish(member.type));
|
|
120
|
+
const kept = members.filter((member) => !evaluation.isNullish(member.type));
|
|
121
121
|
return { ...value, type: evaluation.unionType(kept.map((member) => member.type)) };
|
|
122
122
|
}
|
|
123
123
|
/** `Extract<T, { key: unknown }>` keeps the members that have `key`; other probes are opaque. */
|
|
@@ -130,116 +130,8 @@ class TypeEvaluator {
|
|
|
130
130
|
}
|
|
131
131
|
/** `value[index]` for a string literal, `string` or `number` index. */
|
|
132
132
|
index(value, index) {
|
|
133
|
-
|
|
134
|
-
if (owner.kind !== "type") {
|
|
135
|
-
return owner;
|
|
136
|
-
}
|
|
137
|
-
if (this.membersOf(owner).length > 1) {
|
|
138
|
-
return this.unionIndex(owner, index);
|
|
139
|
-
}
|
|
140
|
-
const { type } = owner;
|
|
141
|
-
switch (type.kind) {
|
|
142
|
-
case "object":
|
|
143
|
-
return this.memberType(owner, type.members, index);
|
|
144
|
-
case "intersection":
|
|
145
|
-
return this.partsIndex(owner, type.types, index);
|
|
146
|
-
case "union":
|
|
147
|
-
return this.unionIndex(owner, index);
|
|
148
|
-
case "array":
|
|
149
|
-
return isNumberIndex(index) ? this.flattened(owner, type.element) : builtInIndex(index);
|
|
150
|
-
case "keyword":
|
|
151
|
-
return type.keyword === "never" ? owner : builtInIndex(index);
|
|
152
|
-
default:
|
|
153
|
-
return builtInIndex(index);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
memberType(owner, members, index) {
|
|
157
|
-
const key = indexKey(index);
|
|
158
|
-
const property = members.find(
|
|
159
|
-
(member) => member.kind === "property" && key !== null && evaluation.propertyKey(member.name) === key
|
|
160
|
-
);
|
|
161
|
-
if (property !== void 0) {
|
|
162
|
-
return this.flattened(owner, property.type);
|
|
163
|
-
}
|
|
164
|
-
const signature = members.find((member) => member.kind === "indexSignature");
|
|
165
|
-
if (signature !== void 0) {
|
|
166
|
-
return this.flattened(owner, signature.type);
|
|
167
|
-
}
|
|
168
|
-
return key === null || isObjectBuiltIn(key) ? evaluation.OPAQUE : evaluation.MISSING;
|
|
169
|
-
}
|
|
170
|
-
partsIndex(owner, parts, index) {
|
|
171
|
-
if (typeRules.isNeverIntersection(this, owner, parts)) {
|
|
172
|
-
return { ...owner, type: evaluation.NEVER };
|
|
173
|
-
}
|
|
174
|
-
const found = parts.map((type) => this.index({ ...owner, type }, index));
|
|
175
|
-
if (found.some((part) => part.kind === "opaque")) {
|
|
176
|
-
return evaluation.OPAQUE;
|
|
177
|
-
}
|
|
178
|
-
const read = parts.map((type, at) => ({ type, found: found[at] }));
|
|
179
|
-
const types = typeRules.declaredFirst(this, owner, indexKey(index), read).flatMap(
|
|
180
|
-
(part) => part.kind === "type" ? [part.type] : []
|
|
181
|
-
);
|
|
182
|
-
return types.length === 0 ? evaluation.MISSING : { ...owner, type: intersectionType(types) };
|
|
183
|
-
}
|
|
184
|
-
unionIndex(owner, index) {
|
|
185
|
-
const found = this.membersOf(owner).map(
|
|
186
|
-
(member) => member.kind === "type" ? this.index(member, index) : member
|
|
187
|
-
);
|
|
188
|
-
if (found.some((member) => member.kind === "missing")) {
|
|
189
|
-
return evaluation.MISSING;
|
|
190
|
-
}
|
|
191
|
-
if (found.some((member) => member.kind === "opaque")) {
|
|
192
|
-
return evaluation.OPAQUE;
|
|
193
|
-
}
|
|
194
|
-
return { ...owner, type: evaluation.unionType(found.map((member) => member.type)) };
|
|
133
|
+
return typeIndexing.indexType(this, value, index);
|
|
195
134
|
}
|
|
196
|
-
/**
|
|
197
|
-
* A member read through `FlattenedDeepRequired`: a value that is only arrays (and `undefined` or
|
|
198
|
-
* `null`) is replaced by its elements, anything else loses `undefined` and `null`.
|
|
199
|
-
*/
|
|
200
|
-
flattened(owner, type) {
|
|
201
|
-
const member = { ...owner, type };
|
|
202
|
-
if (!owner.deep) {
|
|
203
|
-
return this.expand(member);
|
|
204
|
-
}
|
|
205
|
-
const members = this.membersOf(member);
|
|
206
|
-
if (members.some((candidate) => candidate.kind !== "type")) {
|
|
207
|
-
return evaluation.OPAQUE;
|
|
208
|
-
}
|
|
209
|
-
const present = members.filter((candidate) => !isNullish(candidate.type));
|
|
210
|
-
const elements = present.map((candidate) => arrayElement(candidate.type));
|
|
211
|
-
if (present.length > 0 && elements.every((element) => element !== null)) {
|
|
212
|
-
return this.expand({ ...owner, type: evaluation.unionType(elements) });
|
|
213
|
-
}
|
|
214
|
-
return { ...owner, type: evaluation.unionType(present.map((candidate) => candidate.type)) };
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
function isNullish(type) {
|
|
218
|
-
return type.kind === "keyword" && NULLISH.has(type.keyword);
|
|
219
|
-
}
|
|
220
|
-
function arrayElement(type) {
|
|
221
|
-
return type.kind === "array" ? type.element : null;
|
|
222
|
-
}
|
|
223
|
-
function intersectionType(types) {
|
|
224
|
-
return types.length === 1 ? types[0] : { kind: "intersection", types };
|
|
225
|
-
}
|
|
226
|
-
function indexKey(index) {
|
|
227
|
-
if (index.kind === "stringLiteral") {
|
|
228
|
-
return index.value;
|
|
229
|
-
}
|
|
230
|
-
return index.kind === "numberLiteral" ? String(index.value) : null;
|
|
231
|
-
}
|
|
232
|
-
function isNumberIndex(index) {
|
|
233
|
-
const key = indexKey(index);
|
|
234
|
-
return index.kind === "keyword" && index.keyword === "number" || /^\d+$/.test(key ?? "");
|
|
235
|
-
}
|
|
236
|
-
function isObjectBuiltIn(key) {
|
|
237
|
-
return key in {};
|
|
238
|
-
}
|
|
239
|
-
function builtInIndex(index) {
|
|
240
|
-
const key = indexKey(index);
|
|
241
|
-
const isBuiltIn = key === null || key in String.prototype || key in Array.prototype;
|
|
242
|
-
return isBuiltIn || key in Number.prototype ? evaluation.OPAQUE : evaluation.MISSING;
|
|
243
135
|
}
|
|
244
136
|
|
|
245
137
|
exports.TypeEvaluator = TypeEvaluator;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"type-evaluation.cjs","sources":["../../../../src/application/transform/footer/type-evaluation.ts"],"sourcesContent":["import type { IrDeclaration, IrMember, IrType } from \"../../../domain/ir/nodes.js\";\nimport {\n absorbed,\n type Evaluated,\n type Evaluation,\n MISSING,\n NEVER,\n OPAQUE,\n propertyKey,\n unionType,\n} from \"./evaluation.js\";\nimport {\n declaredFirst,\n extracted,\n isNeverIntersection,\n markerObject,\n omitted,\n} from \"./type-rules.js\";\n\n/**\n * A small evaluator of the generated types, as TypeScript reads them, for the `--enum-values`\n * check (ADR-027). It follows the declarations of the document and the helper types the generator\n * writes (`NonNullable`, `Extract`, `WithRequired`, `Omit`, `Record`, `FlattenedDeepRequired`). Its\n * answers are sure: a key is `missing` only where TypeScript reports it, and every type it does\n * not model is `opaque`, which never counts as an error.\n */\n\n/** How many references one evaluation expands; a deeper one is opaque. */\nconst MAX_EXPANSIONS = 200;\nconst DEEP_PREFIX = \"FlattenedDeepRequired<\";\n/** How many members distributing an intersection may give; more is opaque. */\nconst MAX_DISTRIBUTED = 64;\nconst NULLISH: ReadonlySet<string> = new Set([\"null\", \"undefined\"]);\n\nexport class TypeEvaluator {\n private readonly declared = new Map<string, IrType>();\n private expansions = 0;\n\n constructor(declarations: readonly IrDeclaration[]) {\n for (const declaration of declarations) {\n if (declaration.kind === \"interface\") {\n this.declared.set(declaration.name, { kind: \"object\", members: declaration.members });\n } else if (declaration.kind === \"typeAlias\") {\n this.declared.set(declaration.name, declaration.type);\n }\n }\n }\n\n /** Evaluate a type written in the footer; the expansion budget starts again. */\n evaluate(type: IrType): Evaluation {\n this.expansions = 0;\n return this.expand({ kind: \"type\", type, deep: false });\n }\n\n /** The type with references, `readonly` and indexed access resolved at the top. */\n expand(value: Evaluated): Evaluation {\n const { type } = value;\n switch (type.kind) {\n case \"readonly\":\n return this.expand({ ...value, type: type.type });\n case \"indexedAccess\":\n return this.indexedAccess(value, type.object, type.index);\n case \"reference\":\n return this.reference(value, type.name, type.typeArguments);\n case \"raw\":\n case \"tuple\":\n return OPAQUE;\n default:\n return value;\n }\n }\n\n private indexedAccess(value: Evaluated, object: IrType, index: IrType): Evaluation {\n const owner = this.expand({ ...value, type: object });\n return owner.kind === \"type\" ? this.index(owner, index) : owner;\n }\n\n private reference(value: Evaluated, name: string, args: readonly IrType[]): Evaluation {\n // Only references cost budget: re-expanding an already expanded value (as the checks after\n // `evaluate` do) is free, so a large evaluation does not leave its checks opaque.\n if (this.expansions++ > MAX_EXPANSIONS) {\n return OPAQUE;\n }\n if (name.startsWith(DEEP_PREFIX) && name.endsWith(\">\")) {\n const root = this.declared.get(name.slice(DEEP_PREFIX.length, -1));\n return root === undefined ? OPAQUE : this.expand({ kind: \"type\", type: root, deep: true });\n }\n const declared = args.length === 0 ? this.declared.get(name) : undefined;\n if (declared !== undefined) {\n return this.expand({ ...value, type: declared });\n }\n const [first, second] = args;\n if (first === undefined) {\n return OPAQUE;\n }\n const argument = this.expand({ ...value, type: first });\n if (argument.kind !== \"type\") {\n return argument;\n }\n return this.helper(name, argument, second);\n }\n\n private helper(name: string, argument: Evaluated, second: IrType | undefined): Evaluation {\n switch (name) {\n case \"NonNullable\":\n return this.withoutNullish(argument);\n case \"WithRequired\":\n case \"Readonly\":\n return argument;\n case \"Extract\":\n return second === undefined ? OPAQUE : this.extract(argument, second);\n case \"Omit\":\n return second === undefined ? OPAQUE : omitted(this, argument, second);\n default:\n return markerObject(name, argument) ?? OPAQUE;\n }\n }\n\n /**\n * The members of a union, each expanded; an intersection with unions in it is distributed over\n * them (`A & (B | C)` is `(A & B) | (A & C)`), as TypeScript normalizes it. A type that is not a\n * union is its only member. A union with an `any` or `unknown` member is that keyword alone.\n */\n membersOf(value: Evaluated): readonly Evaluation[] {\n const expanded = this.expand(value);\n if (expanded.kind !== \"type\") {\n return [expanded];\n }\n const { type } = expanded;\n if (type.kind === \"union\") {\n return absorbed(\n type.types.flatMap((member) => this.membersOf({ ...expanded, type: member })),\n );\n }\n return type.kind === \"intersection\" ? this.distributed(expanded, type.types) : [expanded];\n }\n\n private distributed(value: Evaluated, parts: readonly IrType[]): readonly Evaluation[] {\n const memberLists = parts.map((part) => this.membersOf({ ...value, type: part }));\n const size = memberLists.reduce((product, list) => product * list.length, 1);\n if (size > MAX_DISTRIBUTED || memberLists.some((list) => list.some((m) => m.kind !== \"type\"))) {\n return [OPAQUE];\n }\n let combinations: IrType[][] = [[]];\n for (const list of memberLists as Evaluated[][]) {\n combinations = combinations.flatMap((done) => list.map((member) => [...done, member.type]));\n }\n return combinations.map((types) => ({ ...value, type: intersectionType(types) }));\n }\n\n private withoutNullish(value: Evaluated): Evaluation {\n const members = this.membersOf(value);\n if (members.some((member) => member.kind !== \"type\")) {\n return OPAQUE;\n }\n const kept = (members as Evaluated[]).filter((member) => !isNullish(member.type));\n return { ...value, type: unionType(kept.map((member) => member.type)) };\n }\n\n /** `Extract<T, { key: unknown }>` keeps the members that have `key`; other probes are opaque. */\n private extract(value: Evaluated, probe: IrType): Evaluation {\n const [member] = probe.kind === \"object\" ? probe.members : [];\n if (probe.kind !== \"object\" || probe.members.length !== 1 || member?.kind !== \"property\") {\n return OPAQUE;\n }\n return extracted(this, value, propertyKey(member.name));\n }\n\n /** `value[index]` for a string literal, `string` or `number` index. */\n index(value: Evaluated, index: IrType): Evaluation {\n const owner = this.expand(value);\n if (owner.kind !== \"type\") {\n return owner;\n }\n if (this.membersOf(owner).length > 1) {\n return this.unionIndex(owner, index);\n }\n const { type } = owner;\n switch (type.kind) {\n case \"object\":\n return this.memberType(owner, type.members, index);\n case \"intersection\":\n return this.partsIndex(owner, type.types, index);\n case \"union\":\n return this.unionIndex(owner, index);\n case \"array\":\n return isNumberIndex(index) ? this.flattened(owner, type.element) : builtInIndex(index);\n case \"keyword\":\n return type.keyword === \"never\" ? owner : builtInIndex(index);\n default:\n return builtInIndex(index);\n }\n }\n\n private memberType(owner: Evaluated, members: readonly IrMember[], index: IrType): Evaluation {\n const key = indexKey(index);\n const property = members.find(\n (member) => member.kind === \"property\" && key !== null && propertyKey(member.name) === key,\n );\n if (property !== undefined) {\n return this.flattened(owner, property.type);\n }\n const signature = members.find((member) => member.kind === \"indexSignature\");\n if (signature !== undefined) {\n return this.flattened(owner, signature.type);\n }\n return key === null || isObjectBuiltIn(key) ? OPAQUE : MISSING;\n }\n\n private partsIndex(owner: Evaluated, parts: readonly IrType[], index: IrType): Evaluation {\n if (isNeverIntersection(this, owner, parts)) {\n return { ...owner, type: NEVER };\n }\n const found = parts.map((type) => this.index({ ...owner, type }, index));\n if (found.some((part) => part.kind === \"opaque\")) {\n return OPAQUE;\n }\n const read = parts.map((type, at) => ({ type, found: found[at] as Evaluation }));\n const types = declaredFirst(this, owner, indexKey(index), read).flatMap((part) =>\n part.kind === \"type\" ? [part.type] : [],\n );\n return types.length === 0 ? MISSING : { ...owner, type: intersectionType(types) };\n }\n\n private unionIndex(owner: Evaluated, index: IrType): Evaluation {\n const found = this.membersOf(owner).map((member) =>\n member.kind === \"type\" ? this.index(member, index) : member,\n );\n if (found.some((member) => member.kind === \"missing\")) {\n return MISSING;\n }\n if (found.some((member) => member.kind === \"opaque\")) {\n return OPAQUE;\n }\n return { ...owner, type: unionType((found as Evaluated[]).map((member) => member.type)) };\n }\n\n /**\n * A member read through `FlattenedDeepRequired`: a value that is only arrays (and `undefined` or\n * `null`) is replaced by its elements, anything else loses `undefined` and `null`.\n */\n private flattened(owner: Evaluated, type: IrType): Evaluation {\n const member: Evaluated = { ...owner, type };\n if (!owner.deep) {\n return this.expand(member);\n }\n const members = this.membersOf(member);\n if (members.some((candidate) => candidate.kind !== \"type\")) {\n return OPAQUE;\n }\n const present = (members as Evaluated[]).filter((candidate) => !isNullish(candidate.type));\n const elements = present.map((candidate) => arrayElement(candidate.type));\n if (present.length > 0 && elements.every((element) => element !== null)) {\n return this.expand({ ...owner, type: unionType(elements as IrType[]) });\n }\n return { ...owner, type: unionType(present.map((candidate) => candidate.type)) };\n }\n}\n\nfunction isNullish(type: IrType): boolean {\n return type.kind === \"keyword\" && NULLISH.has(type.keyword);\n}\n\n/** The element of an expanded member; expanding already dropped `readonly`. */\nfunction arrayElement(type: IrType): IrType | null {\n return type.kind === \"array\" ? type.element : null;\n}\n\nfunction intersectionType(types: readonly IrType[]): IrType {\n return types.length === 1 ? (types[0] as IrType) : { kind: \"intersection\", types };\n}\n\nfunction indexKey(index: IrType): string | null {\n if (index.kind === \"stringLiteral\") {\n return index.value;\n }\n return index.kind === \"numberLiteral\" ? String(index.value) : null;\n}\n\nfunction isNumberIndex(index: IrType): boolean {\n const key = indexKey(index);\n return (index.kind === \"keyword\" && index.keyword === \"number\") || /^\\d+$/.test(key ?? \"\");\n}\n\nfunction isObjectBuiltIn(key: string): boolean {\n return key in {};\n}\n\n/** A key of a primitive or an array: a built-in member is opaque, any other key is missing. */\nfunction builtInIndex(index: IrType): Evaluation {\n const key = indexKey(index);\n const isBuiltIn = key === null || key in String.prototype || key in Array.prototype;\n return isBuiltIn || key in Number.prototype ? OPAQUE : MISSING;\n}\n"],"names":["OPAQUE","omitted","markerObject","absorbed","unionType","extracted","propertyKey","MISSING","isNeverIntersection","NEVER","declaredFirst"],"mappings":";;;;;AA4BA,MAAM,cAAA,GAAiB,GAAA;AACvB,MAAM,WAAA,GAAc,wBAAA;AAEpB,MAAM,eAAA,GAAkB,EAAA;AACxB,MAAM,0BAA+B,IAAI,GAAA,CAAI,CAAC,MAAA,EAAQ,WAAW,CAAC,CAAA;AAE3D,MAAM,aAAA,CAAc;AAAA,EACR,QAAA,uBAAe,GAAA,EAAoB;AAAA,EAC5C,UAAA,GAAa,CAAA;AAAA,EAErB,YAAY,YAAA,EAAwC;AAClD,IAAA,KAAA,MAAW,eAAe,YAAA,EAAc;AACtC,MAAA,IAAI,WAAA,CAAY,SAAS,WAAA,EAAa;AACpC,QAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,WAAA,CAAY,IAAA,EAAM,EAAE,MAAM,QAAA,EAAU,OAAA,EAAS,WAAA,CAAY,OAAA,EAAS,CAAA;AAAA,MACtF,CAAA,MAAA,IAAW,WAAA,CAAY,IAAA,KAAS,WAAA,EAAa;AAC3C,QAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,WAAA,CAAY,IAAA,EAAM,YAAY,IAAI,CAAA;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,SAAS,IAAA,EAA0B;AACjC,IAAA,IAAA,CAAK,UAAA,GAAa,CAAA;AAClB,IAAA,OAAO,IAAA,CAAK,OAAO,EAAE,IAAA,EAAM,QAAQ,IAAA,EAAM,IAAA,EAAM,OAAO,CAAA;AAAA,EACxD;AAAA;AAAA,EAGA,OAAO,KAAA,EAA8B;AACnC,IAAA,MAAM,EAAE,MAAK,GAAI,KAAA;AACjB,IAAA,QAAQ,KAAK,IAAA;AAAM,MACjB,KAAK,UAAA;AACH,QAAA,OAAO,IAAA,CAAK,OAAO,EAAE,GAAG,OAAO,IAAA,EAAM,IAAA,CAAK,MAAM,CAAA;AAAA,MAClD,KAAK,eAAA;AACH,QAAA,OAAO,KAAK,aAAA,CAAc,KAAA,EAAO,IAAA,CAAK,MAAA,EAAQ,KAAK,KAAK,CAAA;AAAA,MAC1D,KAAK,WAAA;AACH,QAAA,OAAO,KAAK,SAAA,CAAU,KAAA,EAAO,IAAA,CAAK,IAAA,EAAM,KAAK,aAAa,CAAA;AAAA,MAC5D,KAAK,KAAA;AAAA,MACL,KAAK,OAAA;AACH,QAAA,OAAOA,iBAAA;AAAA,MACT;AACE,QAAA,OAAO,KAAA;AAAA;AACX,EACF;AAAA,EAEQ,aAAA,CAAc,KAAA,EAAkB,MAAA,EAAgB,KAAA,EAA2B;AACjF,IAAA,MAAM,KAAA,GAAQ,KAAK,MAAA,CAAO,EAAE,GAAG,KAAA,EAAO,IAAA,EAAM,QAAQ,CAAA;AACpD,IAAA,OAAO,MAAM,IAAA,KAAS,MAAA,GAAS,KAAK,KAAA,CAAM,KAAA,EAAO,KAAK,CAAA,GAAI,KAAA;AAAA,EAC5D;AAAA,EAEQ,SAAA,CAAU,KAAA,EAAkB,IAAA,EAAc,IAAA,EAAqC;AAGrF,IAAA,IAAI,IAAA,CAAK,eAAe,cAAA,EAAgB;AACtC,MAAA,OAAOA,iBAAA;AAAA,IACT;AACA,IAAA,IAAI,KAAK,UAAA,CAAW,WAAW,KAAK,IAAA,CAAK,QAAA,CAAS,GAAG,CAAA,EAAG;AACtD,MAAA,MAAM,IAAA,GAAO,KAAK,QAAA,CAAS,GAAA,CAAI,KAAK,KAAA,CAAM,WAAA,CAAY,MAAA,EAAQ,EAAE,CAAC,CAAA;AACjE,MAAA,OAAO,IAAA,KAAS,MAAA,GAAYA,iBAAA,GAAS,IAAA,CAAK,MAAA,CAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,CAAA;AAAA,IAC3F;AACA,IAAA,MAAM,QAAA,GAAW,KAAK,MAAA,KAAW,CAAA,GAAI,KAAK,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA,GAAI,MAAA;AAC/D,IAAA,IAAI,aAAa,MAAA,EAAW;AAC1B,MAAA,OAAO,KAAK,MAAA,CAAO,EAAE,GAAG,KAAA,EAAO,IAAA,EAAM,UAAU,CAAA;AAAA,IACjD;AACA,IAAA,MAAM,CAAC,KAAA,EAAO,MAAM,CAAA,GAAI,IAAA;AACxB,IAAA,IAAI,UAAU,MAAA,EAAW;AACvB,MAAA,OAAOA,iBAAA;AAAA,IACT;AACA,IAAA,MAAM,QAAA,GAAW,KAAK,MAAA,CAAO,EAAE,GAAG,KAAA,EAAO,IAAA,EAAM,OAAO,CAAA;AACtD,IAAA,IAAI,QAAA,CAAS,SAAS,MAAA,EAAQ;AAC5B,MAAA,OAAO,QAAA;AAAA,IACT;AACA,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,IAAA,EAAM,QAAA,EAAU,MAAM,CAAA;AAAA,EAC3C;AAAA,EAEQ,MAAA,CAAO,IAAA,EAAc,QAAA,EAAqB,MAAA,EAAwC;AACxF,IAAA,QAAQ,IAAA;AAAM,MACZ,KAAK,aAAA;AACH,QAAA,OAAO,IAAA,CAAK,eAAe,QAAQ,CAAA;AAAA,MACrC,KAAK,cAAA;AAAA,MACL,KAAK,UAAA;AACH,QAAA,OAAO,QAAA;AAAA,MACT,KAAK,SAAA;AACH,QAAA,OAAO,WAAW,MAAA,GAAYA,iBAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,UAAU,MAAM,CAAA;AAAA,MACtE,KAAK,MAAA;AACH,QAAA,OAAO,WAAW,MAAA,GAAYA,iBAAA,GAASC,iBAAA,CAAQ,IAAA,EAAM,UAAU,MAAM,CAAA;AAAA,MACvE;AACE,QAAA,OAAOC,sBAAA,CAAa,IAAA,EAAM,QAAQ,CAAA,IAAKF,iBAAA;AAAA;AAC3C,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAU,KAAA,EAAyC;AACjD,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,MAAA,CAAO,KAAK,CAAA;AAClC,IAAA,IAAI,QAAA,CAAS,SAAS,MAAA,EAAQ;AAC5B,MAAA,OAAO,CAAC,QAAQ,CAAA;AAAA,IAClB;AACA,IAAA,MAAM,EAAE,MAAK,GAAI,QAAA;AACjB,IAAA,IAAI,IAAA,CAAK,SAAS,OAAA,EAAS;AACzB,MAAA,OAAOG,mBAAA;AAAA,QACL,IAAA,CAAK,KAAA,CAAM,OAAA,CAAQ,CAAC,MAAA,KAAW,IAAA,CAAK,SAAA,CAAU,EAAE,GAAG,QAAA,EAAU,IAAA,EAAM,MAAA,EAAQ,CAAC;AAAA,OAC9E;AAAA,IACF;AACA,IAAA,OAAO,IAAA,CAAK,IAAA,KAAS,cAAA,GAAiB,IAAA,CAAK,WAAA,CAAY,UAAU,IAAA,CAAK,KAAK,CAAA,GAAI,CAAC,QAAQ,CAAA;AAAA,EAC1F;AAAA,EAEQ,WAAA,CAAY,OAAkB,KAAA,EAAiD;AACrF,IAAA,MAAM,WAAA,GAAc,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,SAAA,CAAU,EAAE,GAAG,KAAA,EAAO,IAAA,EAAM,IAAA,EAAM,CAAC,CAAA;AAChF,IAAA,MAAM,IAAA,GAAO,YAAY,MAAA,CAAO,CAAC,SAAS,IAAA,KAAS,OAAA,GAAU,IAAA,CAAK,MAAA,EAAQ,CAAC,CAAA;AAC3E,IAAA,IAAI,IAAA,GAAO,eAAA,IAAmB,WAAA,CAAY,IAAA,CAAK,CAAC,IAAA,KAAS,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,KAAS,MAAM,CAAC,CAAA,EAAG;AAC7F,MAAA,OAAO,CAACH,iBAAM,CAAA;AAAA,IAChB;AACA,IAAA,IAAI,YAAA,GAA2B,CAAC,EAAE,CAAA;AAClC,IAAA,KAAA,MAAW,QAAQ,WAAA,EAA8B;AAC/C,MAAA,YAAA,GAAe,YAAA,CAAa,OAAA,CAAQ,CAAC,IAAA,KAAS,KAAK,GAAA,CAAI,CAAC,MAAA,KAAW,CAAC,GAAG,IAAA,EAAM,MAAA,CAAO,IAAI,CAAC,CAAC,CAAA;AAAA,IAC5F;AACA,IAAA,OAAO,YAAA,CAAa,GAAA,CAAI,CAAC,KAAA,MAAW,EAAE,GAAG,KAAA,EAAO,IAAA,EAAM,gBAAA,CAAiB,KAAK,CAAA,EAAE,CAAE,CAAA;AAAA,EAClF;AAAA,EAEQ,eAAe,KAAA,EAA8B;AACnD,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA;AACpC,IAAA,IAAI,QAAQ,IAAA,CAAK,CAAC,WAAW,MAAA,CAAO,IAAA,KAAS,MAAM,CAAA,EAAG;AACpD,MAAA,OAAOA,iBAAA;AAAA,IACT;AACA,IAAA,MAAM,IAAA,GAAQ,QAAwB,MAAA,CAAO,CAAC,WAAW,CAAC,SAAA,CAAU,MAAA,CAAO,IAAI,CAAC,CAAA;AAChF,IAAA,OAAO,EAAE,GAAG,KAAA,EAAO,IAAA,EAAMI,oBAAA,CAAU,IAAA,CAAK,GAAA,CAAI,CAAC,MAAA,KAAW,MAAA,CAAO,IAAI,CAAC,CAAA,EAAE;AAAA,EACxE;AAAA;AAAA,EAGQ,OAAA,CAAQ,OAAkB,KAAA,EAA2B;AAC3D,IAAA,MAAM,CAAC,MAAM,CAAA,GAAI,KAAA,CAAM,SAAS,QAAA,GAAW,KAAA,CAAM,UAAU,EAAC;AAC5D,IAAA,IAAI,KAAA,CAAM,SAAS,QAAA,IAAY,KAAA,CAAM,QAAQ,MAAA,KAAW,CAAA,IAAK,MAAA,EAAQ,IAAA,KAAS,UAAA,EAAY;AACxF,MAAA,OAAOJ,iBAAA;AAAA,IACT;AACA,IAAA,OAAOK,oBAAU,IAAA,EAAM,KAAA,EAAOC,sBAAA,CAAY,MAAA,CAAO,IAAI,CAAC,CAAA;AAAA,EACxD;AAAA;AAAA,EAGA,KAAA,CAAM,OAAkB,KAAA,EAA2B;AACjD,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,MAAA,CAAO,KAAK,CAAA;AAC/B,IAAA,IAAI,KAAA,CAAM,SAAS,MAAA,EAAQ;AACzB,MAAA,OAAO,KAAA;AAAA,IACT;AACA,IAAA,IAAI,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,CAAE,SAAS,CAAA,EAAG;AACpC,MAAA,OAAO,IAAA,CAAK,UAAA,CAAW,KAAA,EAAO,KAAK,CAAA;AAAA,IACrC;AACA,IAAA,MAAM,EAAE,MAAK,GAAI,KAAA;AACjB,IAAA,QAAQ,KAAK,IAAA;AAAM,MACjB,KAAK,QAAA;AACH,QAAA,OAAO,IAAA,CAAK,UAAA,CAAW,KAAA,EAAO,IAAA,CAAK,SAAS,KAAK,CAAA;AAAA,MACnD,KAAK,cAAA;AACH,QAAA,OAAO,IAAA,CAAK,UAAA,CAAW,KAAA,EAAO,IAAA,CAAK,OAAO,KAAK,CAAA;AAAA,MACjD,KAAK,OAAA;AACH,QAAA,OAAO,IAAA,CAAK,UAAA,CAAW,KAAA,EAAO,KAAK,CAAA;AAAA,MACrC,KAAK,OAAA;AACH,QAAA,OAAO,aAAA,CAAc,KAAK,CAAA,GAAI,IAAA,CAAK,SAAA,CAAU,OAAO,IAAA,CAAK,OAAO,CAAA,GAAI,YAAA,CAAa,KAAK,CAAA;AAAA,MACxF,KAAK,SAAA;AACH,QAAA,OAAO,IAAA,CAAK,OAAA,KAAY,OAAA,GAAU,KAAA,GAAQ,aAAa,KAAK,CAAA;AAAA,MAC9D;AACE,QAAA,OAAO,aAAa,KAAK,CAAA;AAAA;AAC7B,EACF;AAAA,EAEQ,UAAA,CAAW,KAAA,EAAkB,OAAA,EAA8B,KAAA,EAA2B;AAC5F,IAAA,MAAM,GAAA,GAAM,SAAS,KAAK,CAAA;AAC1B,IAAA,MAAM,WAAW,OAAA,CAAQ,IAAA;AAAA,MACvB,CAAC,MAAA,KAAW,MAAA,CAAO,IAAA,KAAS,UAAA,IAAc,QAAQ,IAAA,IAAQA,sBAAA,CAAY,MAAA,CAAO,IAAI,CAAA,KAAM;AAAA,KACzF;AACA,IAAA,IAAI,aAAa,MAAA,EAAW;AAC1B,MAAA,OAAO,IAAA,CAAK,SAAA,CAAU,KAAA,EAAO,QAAA,CAAS,IAAI,CAAA;AAAA,IAC5C;AACA,IAAA,MAAM,YAAY,OAAA,CAAQ,IAAA,CAAK,CAAC,MAAA,KAAW,MAAA,CAAO,SAAS,gBAAgB,CAAA;AAC3E,IAAA,IAAI,cAAc,MAAA,EAAW;AAC3B,MAAA,OAAO,IAAA,CAAK,SAAA,CAAU,KAAA,EAAO,SAAA,CAAU,IAAI,CAAA;AAAA,IAC7C;AACA,IAAA,OAAO,GAAA,KAAQ,IAAA,IAAQ,eAAA,CAAgB,GAAG,IAAIN,iBAAA,GAASO,kBAAA;AAAA,EACzD;AAAA,EAEQ,UAAA,CAAW,KAAA,EAAkB,KAAA,EAA0B,KAAA,EAA2B;AACxF,IAAA,IAAIC,6BAAA,CAAoB,IAAA,EAAM,KAAA,EAAO,KAAK,CAAA,EAAG;AAC3C,MAAA,OAAO,EAAE,GAAG,KAAA,EAAO,IAAA,EAAMC,gBAAA,EAAM;AAAA,IACjC;AACA,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,KAAA,CAAM,EAAE,GAAG,KAAA,EAAO,IAAA,EAAK,EAAG,KAAK,CAAC,CAAA;AACvE,IAAA,IAAI,MAAM,IAAA,CAAK,CAAC,SAAS,IAAA,CAAK,IAAA,KAAS,QAAQ,CAAA,EAAG;AAChD,MAAA,OAAOT,iBAAA;AAAA,IACT;AACA,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,EAAM,EAAA,MAAQ,EAAE,IAAA,EAAM,KAAA,EAAO,KAAA,CAAM,EAAE,CAAA,EAAgB,CAAE,CAAA;AAC/E,IAAA,MAAM,KAAA,GAAQU,wBAAc,IAAA,EAAM,KAAA,EAAO,SAAS,KAAK,CAAA,EAAG,IAAI,CAAA,CAAE,OAAA;AAAA,MAAQ,CAAC,SACvE,IAAA,CAAK,IAAA,KAAS,SAAS,CAAC,IAAA,CAAK,IAAI,CAAA,GAAI;AAAC,KACxC;AACA,IAAA,OAAO,KAAA,CAAM,MAAA,KAAW,CAAA,GAAIH,kBAAA,GAAU,EAAE,GAAG,KAAA,EAAO,IAAA,EAAM,gBAAA,CAAiB,KAAK,CAAA,EAAE;AAAA,EAClF;AAAA,EAEQ,UAAA,CAAW,OAAkB,KAAA,EAA2B;AAC9D,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,CAAE,GAAA;AAAA,MAAI,CAAC,WACvC,MAAA,CAAO,IAAA,KAAS,SAAS,IAAA,CAAK,KAAA,CAAM,MAAA,EAAQ,KAAK,CAAA,GAAI;AAAA,KACvD;AACA,IAAA,IAAI,MAAM,IAAA,CAAK,CAAC,WAAW,MAAA,CAAO,IAAA,KAAS,SAAS,CAAA,EAAG;AACrD,MAAA,OAAOA,kBAAA;AAAA,IACT;AACA,IAAA,IAAI,MAAM,IAAA,CAAK,CAAC,WAAW,MAAA,CAAO,IAAA,KAAS,QAAQ,CAAA,EAAG;AACpD,MAAA,OAAOP,iBAAA;AAAA,IACT;AACA,IAAA,OAAO,EAAE,GAAG,KAAA,EAAO,IAAA,EAAMI,oBAAA,CAAW,KAAA,CAAsB,GAAA,CAAI,CAAC,MAAA,KAAW,MAAA,CAAO,IAAI,CAAC,CAAA,EAAE;AAAA,EAC1F;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,SAAA,CAAU,OAAkB,IAAA,EAA0B;AAC5D,IAAA,MAAM,MAAA,GAAoB,EAAE,GAAG,KAAA,EAAO,IAAA,EAAK;AAC3C,IAAA,IAAI,CAAC,MAAM,IAAA,EAAM;AACf,MAAA,OAAO,IAAA,CAAK,OAAO,MAAM,CAAA;AAAA,IAC3B;AACA,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,SAAA,CAAU,MAAM,CAAA;AACrC,IAAA,IAAI,QAAQ,IAAA,CAAK,CAAC,cAAc,SAAA,CAAU,IAAA,KAAS,MAAM,CAAA,EAAG;AAC1D,MAAA,OAAOJ,iBAAA;AAAA,IACT;AACA,IAAA,MAAM,OAAA,GAAW,QAAwB,MAAA,CAAO,CAAC,cAAc,CAAC,SAAA,CAAU,SAAA,CAAU,IAAI,CAAC,CAAA;AACzF,IAAA,MAAM,QAAA,GAAW,QAAQ,GAAA,CAAI,CAAC,cAAc,YAAA,CAAa,SAAA,CAAU,IAAI,CAAC,CAAA;AACxE,IAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,IAAK,QAAA,CAAS,MAAM,CAAC,OAAA,KAAY,OAAA,KAAY,IAAI,CAAA,EAAG;AACvE,MAAA,OAAO,IAAA,CAAK,OAAO,EAAE,GAAG,OAAO,IAAA,EAAMI,oBAAA,CAAU,QAAoB,CAAA,EAAG,CAAA;AAAA,IACxE;AACA,IAAA,OAAO,EAAE,GAAG,KAAA,EAAO,IAAA,EAAMA,oBAAA,CAAU,OAAA,CAAQ,GAAA,CAAI,CAAC,SAAA,KAAc,SAAA,CAAU,IAAI,CAAC,CAAA,EAAE;AAAA,EACjF;AACF;AAEA,SAAS,UAAU,IAAA,EAAuB;AACxC,EAAA,OAAO,KAAK,IAAA,KAAS,SAAA,IAAa,OAAA,CAAQ,GAAA,CAAI,KAAK,OAAO,CAAA;AAC5D;AAGA,SAAS,aAAa,IAAA,EAA6B;AACjD,EAAA,OAAO,IAAA,CAAK,IAAA,KAAS,OAAA,GAAU,IAAA,CAAK,OAAA,GAAU,IAAA;AAChD;AAEA,SAAS,iBAAiB,KAAA,EAAkC;AAC1D,EAAA,OAAO,KAAA,CAAM,WAAW,CAAA,GAAK,KAAA,CAAM,CAAC,CAAA,GAAe,EAAE,IAAA,EAAM,cAAA,EAAgB,KAAA,EAAM;AACnF;AAEA,SAAS,SAAS,KAAA,EAA8B;AAC9C,EAAA,IAAI,KAAA,CAAM,SAAS,eAAA,EAAiB;AAClC,IAAA,OAAO,KAAA,CAAM,KAAA;AAAA,EACf;AACA,EAAA,OAAO,MAAM,IAAA,KAAS,eAAA,GAAkB,MAAA,CAAO,KAAA,CAAM,KAAK,CAAA,GAAI,IAAA;AAChE;AAEA,SAAS,cAAc,KAAA,EAAwB;AAC7C,EAAA,MAAM,GAAA,GAAM,SAAS,KAAK,CAAA;AAC1B,EAAA,OAAQ,KAAA,CAAM,SAAS,SAAA,IAAa,KAAA,CAAM,YAAY,QAAA,IAAa,OAAA,CAAQ,IAAA,CAAK,GAAA,IAAO,EAAE,CAAA;AAC3F;AAEA,SAAS,gBAAgB,GAAA,EAAsB;AAC7C,EAAA,OAAO,OAAO,EAAC;AACjB;AAGA,SAAS,aAAa,KAAA,EAA2B;AAC/C,EAAA,MAAM,GAAA,GAAM,SAAS,KAAK,CAAA;AAC1B,EAAA,MAAM,YAAY,GAAA,KAAQ,IAAA,IAAQ,OAAO,MAAA,CAAO,SAAA,IAAa,OAAO,KAAA,CAAM,SAAA;AAC1E,EAAA,OAAO,SAAA,IAAa,GAAA,IAAO,MAAA,CAAO,SAAA,GAAYJ,iBAAA,GAASO,kBAAA;AACzD;;"}
|
|
1
|
+
{"version":3,"file":"type-evaluation.cjs","sources":["../../../../src/application/transform/footer/type-evaluation.ts"],"sourcesContent":["import type { IrDeclaration, IrType } from \"../../../domain/ir/nodes.js\";\nimport {\n absorbed,\n type Evaluated,\n type Evaluation,\n intersectionType,\n isNullish,\n OPAQUE,\n propertyKey,\n unionType,\n} from \"./evaluation.js\";\nimport { indexType } from \"./type-indexing.js\";\nimport { extracted, markerObject, omitted } from \"./type-rules.js\";\n\n/**\n * A small evaluator of the generated types, as TypeScript reads them, for the `--enum-values`\n * check (ADR-027). It follows the declarations of the document and the helper types the generator\n * writes (`NonNullable`, `Extract`, `WithRequired`, `Omit`, `Record`, `FlattenedDeepRequired`). Its\n * answers are sure: a key is `missing` only where TypeScript reports it, and every type it does\n * not model is `opaque`, which never counts as an error.\n */\n\n/** How many references one evaluation expands; a deeper one is opaque. */\nconst MAX_EXPANSIONS = 200;\nconst DEEP_PREFIX = \"FlattenedDeepRequired<\";\n/** How many members distributing an intersection may give; more is opaque. */\nconst MAX_DISTRIBUTED = 64;\n\nexport class TypeEvaluator {\n private readonly declared = new Map<string, IrType>();\n private expansions = 0;\n\n constructor(declarations: readonly IrDeclaration[]) {\n for (const declaration of declarations) {\n if (declaration.kind === \"interface\") {\n this.declared.set(declaration.name, { kind: \"object\", members: declaration.members });\n } else if (declaration.kind === \"typeAlias\") {\n this.declared.set(declaration.name, declaration.type);\n }\n }\n }\n\n /** Evaluate a type written in the footer; the expansion budget starts again. */\n evaluate(type: IrType): Evaluation {\n this.expansions = 0;\n return this.expand({ kind: \"type\", type, deep: false });\n }\n\n /** The type with references, `readonly` and indexed access resolved at the top. */\n expand(value: Evaluated): Evaluation {\n const { type } = value;\n switch (type.kind) {\n case \"readonly\":\n return this.expand({ ...value, type: type.type });\n case \"indexedAccess\":\n return this.indexedAccess(value, type.object, type.index);\n case \"reference\":\n return this.reference(value, type.name, type.typeArguments);\n case \"raw\":\n case \"tuple\":\n return OPAQUE;\n default:\n return value;\n }\n }\n\n private indexedAccess(value: Evaluated, object: IrType, index: IrType): Evaluation {\n const owner = this.expand({ ...value, type: object });\n return owner.kind === \"type\" ? this.index(owner, index) : owner;\n }\n\n private reference(value: Evaluated, name: string, args: readonly IrType[]): Evaluation {\n // Only references cost budget: re-expanding an already expanded value (as the checks after\n // `evaluate` do) is free, so a large evaluation does not leave its checks opaque.\n if (this.expansions++ > MAX_EXPANSIONS) {\n return OPAQUE;\n }\n if (name.startsWith(DEEP_PREFIX) && name.endsWith(\">\")) {\n const root = this.declared.get(name.slice(DEEP_PREFIX.length, -1));\n return root === undefined ? OPAQUE : this.expand({ kind: \"type\", type: root, deep: true });\n }\n const declared = args.length === 0 ? this.declared.get(name) : undefined;\n if (declared !== undefined) {\n return this.expand({ ...value, type: declared });\n }\n const [first, second] = args;\n if (first === undefined) {\n return OPAQUE;\n }\n const argument = this.expand({ ...value, type: first });\n if (argument.kind !== \"type\") {\n return argument;\n }\n return this.helper(name, argument, second);\n }\n\n private helper(name: string, argument: Evaluated, second: IrType | undefined): Evaluation {\n switch (name) {\n case \"NonNullable\":\n return this.withoutNullish(argument);\n case \"WithRequired\":\n case \"Readonly\":\n return argument;\n case \"Extract\":\n return second === undefined ? OPAQUE : this.extract(argument, second);\n case \"Omit\":\n return second === undefined ? OPAQUE : omitted(this, argument, second);\n default:\n return markerObject(name, argument) ?? OPAQUE;\n }\n }\n\n /**\n * The members of a union, each expanded; an intersection with unions in it is distributed over\n * them (`A & (B | C)` is `(A & B) | (A & C)`), as TypeScript normalizes it. A type that is not a\n * union is its only member. A union with an `any` or `unknown` member is that keyword alone.\n */\n membersOf(value: Evaluated): readonly Evaluation[] {\n const expanded = this.expand(value);\n if (expanded.kind !== \"type\") {\n return [expanded];\n }\n const { type } = expanded;\n if (type.kind === \"union\") {\n return absorbed(\n type.types.flatMap((member) => this.membersOf({ ...expanded, type: member })),\n );\n }\n return type.kind === \"intersection\" ? this.distributed(expanded, type.types) : [expanded];\n }\n\n private distributed(value: Evaluated, parts: readonly IrType[]): readonly Evaluation[] {\n const memberLists = parts.map((part) => this.membersOf({ ...value, type: part }));\n const size = memberLists.reduce((product, list) => product * list.length, 1);\n if (size > MAX_DISTRIBUTED || memberLists.some((list) => list.some((m) => m.kind !== \"type\"))) {\n return [OPAQUE];\n }\n let combinations: IrType[][] = [[]];\n for (const list of memberLists as Evaluated[][]) {\n combinations = combinations.flatMap((done) => list.map((member) => [...done, member.type]));\n }\n return combinations.map((types) => ({ ...value, type: intersectionType(types) }));\n }\n\n private withoutNullish(value: Evaluated): Evaluation {\n const members = this.membersOf(value);\n if (members.some((member) => member.kind !== \"type\")) {\n return OPAQUE;\n }\n const kept = (members as Evaluated[]).filter((member) => !isNullish(member.type));\n return { ...value, type: unionType(kept.map((member) => member.type)) };\n }\n\n /** `Extract<T, { key: unknown }>` keeps the members that have `key`; other probes are opaque. */\n private extract(value: Evaluated, probe: IrType): Evaluation {\n const [member] = probe.kind === \"object\" ? probe.members : [];\n if (probe.kind !== \"object\" || probe.members.length !== 1 || member?.kind !== \"property\") {\n return OPAQUE;\n }\n return extracted(this, value, propertyKey(member.name));\n }\n\n /** `value[index]` for a string literal, `string` or `number` index. */\n index(value: Evaluated, index: IrType): Evaluation {\n return indexType(this, value, index);\n }\n}\n"],"names":["OPAQUE","omitted","markerObject","absorbed","intersectionType","isNullish","unionType","extracted","propertyKey","indexType"],"mappings":"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"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { OPAQUE, absorbed,
|
|
2
|
-
import {
|
|
1
|
+
import { OPAQUE, absorbed, intersectionType, isNullish, unionType, propertyKey } from './evaluation.mjs';
|
|
2
|
+
import { indexType } from './type-indexing.mjs';
|
|
3
|
+
import { markerObject, omitted, extracted } from './type-rules.mjs';
|
|
3
4
|
|
|
4
5
|
const MAX_EXPANSIONS = 200;
|
|
5
6
|
const DEEP_PREFIX = "FlattenedDeepRequired<";
|
|
6
7
|
const MAX_DISTRIBUTED = 64;
|
|
7
|
-
const NULLISH = /* @__PURE__ */ new Set(["null", "undefined"]);
|
|
8
8
|
class TypeEvaluator {
|
|
9
9
|
declared = /* @__PURE__ */ new Map();
|
|
10
10
|
expansions = 0;
|
|
@@ -128,116 +128,8 @@ class TypeEvaluator {
|
|
|
128
128
|
}
|
|
129
129
|
/** `value[index]` for a string literal, `string` or `number` index. */
|
|
130
130
|
index(value, index) {
|
|
131
|
-
|
|
132
|
-
if (owner.kind !== "type") {
|
|
133
|
-
return owner;
|
|
134
|
-
}
|
|
135
|
-
if (this.membersOf(owner).length > 1) {
|
|
136
|
-
return this.unionIndex(owner, index);
|
|
137
|
-
}
|
|
138
|
-
const { type } = owner;
|
|
139
|
-
switch (type.kind) {
|
|
140
|
-
case "object":
|
|
141
|
-
return this.memberType(owner, type.members, index);
|
|
142
|
-
case "intersection":
|
|
143
|
-
return this.partsIndex(owner, type.types, index);
|
|
144
|
-
case "union":
|
|
145
|
-
return this.unionIndex(owner, index);
|
|
146
|
-
case "array":
|
|
147
|
-
return isNumberIndex(index) ? this.flattened(owner, type.element) : builtInIndex(index);
|
|
148
|
-
case "keyword":
|
|
149
|
-
return type.keyword === "never" ? owner : builtInIndex(index);
|
|
150
|
-
default:
|
|
151
|
-
return builtInIndex(index);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
memberType(owner, members, index) {
|
|
155
|
-
const key = indexKey(index);
|
|
156
|
-
const property = members.find(
|
|
157
|
-
(member) => member.kind === "property" && key !== null && propertyKey(member.name) === key
|
|
158
|
-
);
|
|
159
|
-
if (property !== void 0) {
|
|
160
|
-
return this.flattened(owner, property.type);
|
|
161
|
-
}
|
|
162
|
-
const signature = members.find((member) => member.kind === "indexSignature");
|
|
163
|
-
if (signature !== void 0) {
|
|
164
|
-
return this.flattened(owner, signature.type);
|
|
165
|
-
}
|
|
166
|
-
return key === null || isObjectBuiltIn(key) ? OPAQUE : MISSING;
|
|
167
|
-
}
|
|
168
|
-
partsIndex(owner, parts, index) {
|
|
169
|
-
if (isNeverIntersection(this, owner, parts)) {
|
|
170
|
-
return { ...owner, type: NEVER };
|
|
171
|
-
}
|
|
172
|
-
const found = parts.map((type) => this.index({ ...owner, type }, index));
|
|
173
|
-
if (found.some((part) => part.kind === "opaque")) {
|
|
174
|
-
return OPAQUE;
|
|
175
|
-
}
|
|
176
|
-
const read = parts.map((type, at) => ({ type, found: found[at] }));
|
|
177
|
-
const types = declaredFirst(this, owner, indexKey(index), read).flatMap(
|
|
178
|
-
(part) => part.kind === "type" ? [part.type] : []
|
|
179
|
-
);
|
|
180
|
-
return types.length === 0 ? MISSING : { ...owner, type: intersectionType(types) };
|
|
181
|
-
}
|
|
182
|
-
unionIndex(owner, index) {
|
|
183
|
-
const found = this.membersOf(owner).map(
|
|
184
|
-
(member) => member.kind === "type" ? this.index(member, index) : member
|
|
185
|
-
);
|
|
186
|
-
if (found.some((member) => member.kind === "missing")) {
|
|
187
|
-
return MISSING;
|
|
188
|
-
}
|
|
189
|
-
if (found.some((member) => member.kind === "opaque")) {
|
|
190
|
-
return OPAQUE;
|
|
191
|
-
}
|
|
192
|
-
return { ...owner, type: unionType(found.map((member) => member.type)) };
|
|
131
|
+
return indexType(this, value, index);
|
|
193
132
|
}
|
|
194
|
-
/**
|
|
195
|
-
* A member read through `FlattenedDeepRequired`: a value that is only arrays (and `undefined` or
|
|
196
|
-
* `null`) is replaced by its elements, anything else loses `undefined` and `null`.
|
|
197
|
-
*/
|
|
198
|
-
flattened(owner, type) {
|
|
199
|
-
const member = { ...owner, type };
|
|
200
|
-
if (!owner.deep) {
|
|
201
|
-
return this.expand(member);
|
|
202
|
-
}
|
|
203
|
-
const members = this.membersOf(member);
|
|
204
|
-
if (members.some((candidate) => candidate.kind !== "type")) {
|
|
205
|
-
return OPAQUE;
|
|
206
|
-
}
|
|
207
|
-
const present = members.filter((candidate) => !isNullish(candidate.type));
|
|
208
|
-
const elements = present.map((candidate) => arrayElement(candidate.type));
|
|
209
|
-
if (present.length > 0 && elements.every((element) => element !== null)) {
|
|
210
|
-
return this.expand({ ...owner, type: unionType(elements) });
|
|
211
|
-
}
|
|
212
|
-
return { ...owner, type: unionType(present.map((candidate) => candidate.type)) };
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
function isNullish(type) {
|
|
216
|
-
return type.kind === "keyword" && NULLISH.has(type.keyword);
|
|
217
|
-
}
|
|
218
|
-
function arrayElement(type) {
|
|
219
|
-
return type.kind === "array" ? type.element : null;
|
|
220
|
-
}
|
|
221
|
-
function intersectionType(types) {
|
|
222
|
-
return types.length === 1 ? types[0] : { kind: "intersection", types };
|
|
223
|
-
}
|
|
224
|
-
function indexKey(index) {
|
|
225
|
-
if (index.kind === "stringLiteral") {
|
|
226
|
-
return index.value;
|
|
227
|
-
}
|
|
228
|
-
return index.kind === "numberLiteral" ? String(index.value) : null;
|
|
229
|
-
}
|
|
230
|
-
function isNumberIndex(index) {
|
|
231
|
-
const key = indexKey(index);
|
|
232
|
-
return index.kind === "keyword" && index.keyword === "number" || /^\d+$/.test(key ?? "");
|
|
233
|
-
}
|
|
234
|
-
function isObjectBuiltIn(key) {
|
|
235
|
-
return key in {};
|
|
236
|
-
}
|
|
237
|
-
function builtInIndex(index) {
|
|
238
|
-
const key = indexKey(index);
|
|
239
|
-
const isBuiltIn = key === null || key in String.prototype || key in Array.prototype;
|
|
240
|
-
return isBuiltIn || key in Number.prototype ? OPAQUE : MISSING;
|
|
241
133
|
}
|
|
242
134
|
|
|
243
135
|
export { TypeEvaluator };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"type-evaluation.mjs","sources":["../../../../src/application/transform/footer/type-evaluation.ts"],"sourcesContent":["import type { IrDeclaration, IrMember, IrType } from \"../../../domain/ir/nodes.js\";\nimport {\n absorbed,\n type Evaluated,\n type Evaluation,\n MISSING,\n NEVER,\n OPAQUE,\n propertyKey,\n unionType,\n} from \"./evaluation.js\";\nimport {\n declaredFirst,\n extracted,\n isNeverIntersection,\n markerObject,\n omitted,\n} from \"./type-rules.js\";\n\n/**\n * A small evaluator of the generated types, as TypeScript reads them, for the `--enum-values`\n * check (ADR-027). It follows the declarations of the document and the helper types the generator\n * writes (`NonNullable`, `Extract`, `WithRequired`, `Omit`, `Record`, `FlattenedDeepRequired`). Its\n * answers are sure: a key is `missing` only where TypeScript reports it, and every type it does\n * not model is `opaque`, which never counts as an error.\n */\n\n/** How many references one evaluation expands; a deeper one is opaque. */\nconst MAX_EXPANSIONS = 200;\nconst DEEP_PREFIX = \"FlattenedDeepRequired<\";\n/** How many members distributing an intersection may give; more is opaque. */\nconst MAX_DISTRIBUTED = 64;\nconst NULLISH: ReadonlySet<string> = new Set([\"null\", \"undefined\"]);\n\nexport class TypeEvaluator {\n private readonly declared = new Map<string, IrType>();\n private expansions = 0;\n\n constructor(declarations: readonly IrDeclaration[]) {\n for (const declaration of declarations) {\n if (declaration.kind === \"interface\") {\n this.declared.set(declaration.name, { kind: \"object\", members: declaration.members });\n } else if (declaration.kind === \"typeAlias\") {\n this.declared.set(declaration.name, declaration.type);\n }\n }\n }\n\n /** Evaluate a type written in the footer; the expansion budget starts again. */\n evaluate(type: IrType): Evaluation {\n this.expansions = 0;\n return this.expand({ kind: \"type\", type, deep: false });\n }\n\n /** The type with references, `readonly` and indexed access resolved at the top. */\n expand(value: Evaluated): Evaluation {\n const { type } = value;\n switch (type.kind) {\n case \"readonly\":\n return this.expand({ ...value, type: type.type });\n case \"indexedAccess\":\n return this.indexedAccess(value, type.object, type.index);\n case \"reference\":\n return this.reference(value, type.name, type.typeArguments);\n case \"raw\":\n case \"tuple\":\n return OPAQUE;\n default:\n return value;\n }\n }\n\n private indexedAccess(value: Evaluated, object: IrType, index: IrType): Evaluation {\n const owner = this.expand({ ...value, type: object });\n return owner.kind === \"type\" ? this.index(owner, index) : owner;\n }\n\n private reference(value: Evaluated, name: string, args: readonly IrType[]): Evaluation {\n // Only references cost budget: re-expanding an already expanded value (as the checks after\n // `evaluate` do) is free, so a large evaluation does not leave its checks opaque.\n if (this.expansions++ > MAX_EXPANSIONS) {\n return OPAQUE;\n }\n if (name.startsWith(DEEP_PREFIX) && name.endsWith(\">\")) {\n const root = this.declared.get(name.slice(DEEP_PREFIX.length, -1));\n return root === undefined ? OPAQUE : this.expand({ kind: \"type\", type: root, deep: true });\n }\n const declared = args.length === 0 ? this.declared.get(name) : undefined;\n if (declared !== undefined) {\n return this.expand({ ...value, type: declared });\n }\n const [first, second] = args;\n if (first === undefined) {\n return OPAQUE;\n }\n const argument = this.expand({ ...value, type: first });\n if (argument.kind !== \"type\") {\n return argument;\n }\n return this.helper(name, argument, second);\n }\n\n private helper(name: string, argument: Evaluated, second: IrType | undefined): Evaluation {\n switch (name) {\n case \"NonNullable\":\n return this.withoutNullish(argument);\n case \"WithRequired\":\n case \"Readonly\":\n return argument;\n case \"Extract\":\n return second === undefined ? OPAQUE : this.extract(argument, second);\n case \"Omit\":\n return second === undefined ? OPAQUE : omitted(this, argument, second);\n default:\n return markerObject(name, argument) ?? OPAQUE;\n }\n }\n\n /**\n * The members of a union, each expanded; an intersection with unions in it is distributed over\n * them (`A & (B | C)` is `(A & B) | (A & C)`), as TypeScript normalizes it. A type that is not a\n * union is its only member. A union with an `any` or `unknown` member is that keyword alone.\n */\n membersOf(value: Evaluated): readonly Evaluation[] {\n const expanded = this.expand(value);\n if (expanded.kind !== \"type\") {\n return [expanded];\n }\n const { type } = expanded;\n if (type.kind === \"union\") {\n return absorbed(\n type.types.flatMap((member) => this.membersOf({ ...expanded, type: member })),\n );\n }\n return type.kind === \"intersection\" ? this.distributed(expanded, type.types) : [expanded];\n }\n\n private distributed(value: Evaluated, parts: readonly IrType[]): readonly Evaluation[] {\n const memberLists = parts.map((part) => this.membersOf({ ...value, type: part }));\n const size = memberLists.reduce((product, list) => product * list.length, 1);\n if (size > MAX_DISTRIBUTED || memberLists.some((list) => list.some((m) => m.kind !== \"type\"))) {\n return [OPAQUE];\n }\n let combinations: IrType[][] = [[]];\n for (const list of memberLists as Evaluated[][]) {\n combinations = combinations.flatMap((done) => list.map((member) => [...done, member.type]));\n }\n return combinations.map((types) => ({ ...value, type: intersectionType(types) }));\n }\n\n private withoutNullish(value: Evaluated): Evaluation {\n const members = this.membersOf(value);\n if (members.some((member) => member.kind !== \"type\")) {\n return OPAQUE;\n }\n const kept = (members as Evaluated[]).filter((member) => !isNullish(member.type));\n return { ...value, type: unionType(kept.map((member) => member.type)) };\n }\n\n /** `Extract<T, { key: unknown }>` keeps the members that have `key`; other probes are opaque. */\n private extract(value: Evaluated, probe: IrType): Evaluation {\n const [member] = probe.kind === \"object\" ? probe.members : [];\n if (probe.kind !== \"object\" || probe.members.length !== 1 || member?.kind !== \"property\") {\n return OPAQUE;\n }\n return extracted(this, value, propertyKey(member.name));\n }\n\n /** `value[index]` for a string literal, `string` or `number` index. */\n index(value: Evaluated, index: IrType): Evaluation {\n const owner = this.expand(value);\n if (owner.kind !== \"type\") {\n return owner;\n }\n if (this.membersOf(owner).length > 1) {\n return this.unionIndex(owner, index);\n }\n const { type } = owner;\n switch (type.kind) {\n case \"object\":\n return this.memberType(owner, type.members, index);\n case \"intersection\":\n return this.partsIndex(owner, type.types, index);\n case \"union\":\n return this.unionIndex(owner, index);\n case \"array\":\n return isNumberIndex(index) ? this.flattened(owner, type.element) : builtInIndex(index);\n case \"keyword\":\n return type.keyword === \"never\" ? owner : builtInIndex(index);\n default:\n return builtInIndex(index);\n }\n }\n\n private memberType(owner: Evaluated, members: readonly IrMember[], index: IrType): Evaluation {\n const key = indexKey(index);\n const property = members.find(\n (member) => member.kind === \"property\" && key !== null && propertyKey(member.name) === key,\n );\n if (property !== undefined) {\n return this.flattened(owner, property.type);\n }\n const signature = members.find((member) => member.kind === \"indexSignature\");\n if (signature !== undefined) {\n return this.flattened(owner, signature.type);\n }\n return key === null || isObjectBuiltIn(key) ? OPAQUE : MISSING;\n }\n\n private partsIndex(owner: Evaluated, parts: readonly IrType[], index: IrType): Evaluation {\n if (isNeverIntersection(this, owner, parts)) {\n return { ...owner, type: NEVER };\n }\n const found = parts.map((type) => this.index({ ...owner, type }, index));\n if (found.some((part) => part.kind === \"opaque\")) {\n return OPAQUE;\n }\n const read = parts.map((type, at) => ({ type, found: found[at] as Evaluation }));\n const types = declaredFirst(this, owner, indexKey(index), read).flatMap((part) =>\n part.kind === \"type\" ? [part.type] : [],\n );\n return types.length === 0 ? MISSING : { ...owner, type: intersectionType(types) };\n }\n\n private unionIndex(owner: Evaluated, index: IrType): Evaluation {\n const found = this.membersOf(owner).map((member) =>\n member.kind === \"type\" ? this.index(member, index) : member,\n );\n if (found.some((member) => member.kind === \"missing\")) {\n return MISSING;\n }\n if (found.some((member) => member.kind === \"opaque\")) {\n return OPAQUE;\n }\n return { ...owner, type: unionType((found as Evaluated[]).map((member) => member.type)) };\n }\n\n /**\n * A member read through `FlattenedDeepRequired`: a value that is only arrays (and `undefined` or\n * `null`) is replaced by its elements, anything else loses `undefined` and `null`.\n */\n private flattened(owner: Evaluated, type: IrType): Evaluation {\n const member: Evaluated = { ...owner, type };\n if (!owner.deep) {\n return this.expand(member);\n }\n const members = this.membersOf(member);\n if (members.some((candidate) => candidate.kind !== \"type\")) {\n return OPAQUE;\n }\n const present = (members as Evaluated[]).filter((candidate) => !isNullish(candidate.type));\n const elements = present.map((candidate) => arrayElement(candidate.type));\n if (present.length > 0 && elements.every((element) => element !== null)) {\n return this.expand({ ...owner, type: unionType(elements as IrType[]) });\n }\n return { ...owner, type: unionType(present.map((candidate) => candidate.type)) };\n }\n}\n\nfunction isNullish(type: IrType): boolean {\n return type.kind === \"keyword\" && NULLISH.has(type.keyword);\n}\n\n/** The element of an expanded member; expanding already dropped `readonly`. */\nfunction arrayElement(type: IrType): IrType | null {\n return type.kind === \"array\" ? type.element : null;\n}\n\nfunction intersectionType(types: readonly IrType[]): IrType {\n return types.length === 1 ? (types[0] as IrType) : { kind: \"intersection\", types };\n}\n\nfunction indexKey(index: IrType): string | null {\n if (index.kind === \"stringLiteral\") {\n return index.value;\n }\n return index.kind === \"numberLiteral\" ? String(index.value) : null;\n}\n\nfunction isNumberIndex(index: IrType): boolean {\n const key = indexKey(index);\n return (index.kind === \"keyword\" && index.keyword === \"number\") || /^\\d+$/.test(key ?? \"\");\n}\n\nfunction isObjectBuiltIn(key: string): boolean {\n return key in {};\n}\n\n/** A key of a primitive or an array: a built-in member is opaque, any other key is missing. */\nfunction builtInIndex(index: IrType): Evaluation {\n const key = indexKey(index);\n const isBuiltIn = key === null || key in String.prototype || key in Array.prototype;\n return isBuiltIn || key in Number.prototype ? OPAQUE : MISSING;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"type-evaluation.mjs","sources":["../../../../src/application/transform/footer/type-evaluation.ts"],"sourcesContent":["import type { IrDeclaration, IrType } from \"../../../domain/ir/nodes.js\";\nimport {\n absorbed,\n type Evaluated,\n type Evaluation,\n intersectionType,\n isNullish,\n OPAQUE,\n propertyKey,\n unionType,\n} from \"./evaluation.js\";\nimport { indexType } from \"./type-indexing.js\";\nimport { extracted, markerObject, omitted } from \"./type-rules.js\";\n\n/**\n * A small evaluator of the generated types, as TypeScript reads them, for the `--enum-values`\n * check (ADR-027). It follows the declarations of the document and the helper types the generator\n * writes (`NonNullable`, `Extract`, `WithRequired`, `Omit`, `Record`, `FlattenedDeepRequired`). Its\n * answers are sure: a key is `missing` only where TypeScript reports it, and every type it does\n * not model is `opaque`, which never counts as an error.\n */\n\n/** How many references one evaluation expands; a deeper one is opaque. */\nconst MAX_EXPANSIONS = 200;\nconst DEEP_PREFIX = \"FlattenedDeepRequired<\";\n/** How many members distributing an intersection may give; more is opaque. */\nconst MAX_DISTRIBUTED = 64;\n\nexport class TypeEvaluator {\n private readonly declared = new Map<string, IrType>();\n private expansions = 0;\n\n constructor(declarations: readonly IrDeclaration[]) {\n for (const declaration of declarations) {\n if (declaration.kind === \"interface\") {\n this.declared.set(declaration.name, { kind: \"object\", members: declaration.members });\n } else if (declaration.kind === \"typeAlias\") {\n this.declared.set(declaration.name, declaration.type);\n }\n }\n }\n\n /** Evaluate a type written in the footer; the expansion budget starts again. */\n evaluate(type: IrType): Evaluation {\n this.expansions = 0;\n return this.expand({ kind: \"type\", type, deep: false });\n }\n\n /** The type with references, `readonly` and indexed access resolved at the top. */\n expand(value: Evaluated): Evaluation {\n const { type } = value;\n switch (type.kind) {\n case \"readonly\":\n return this.expand({ ...value, type: type.type });\n case \"indexedAccess\":\n return this.indexedAccess(value, type.object, type.index);\n case \"reference\":\n return this.reference(value, type.name, type.typeArguments);\n case \"raw\":\n case \"tuple\":\n return OPAQUE;\n default:\n return value;\n }\n }\n\n private indexedAccess(value: Evaluated, object: IrType, index: IrType): Evaluation {\n const owner = this.expand({ ...value, type: object });\n return owner.kind === \"type\" ? this.index(owner, index) : owner;\n }\n\n private reference(value: Evaluated, name: string, args: readonly IrType[]): Evaluation {\n // Only references cost budget: re-expanding an already expanded value (as the checks after\n // `evaluate` do) is free, so a large evaluation does not leave its checks opaque.\n if (this.expansions++ > MAX_EXPANSIONS) {\n return OPAQUE;\n }\n if (name.startsWith(DEEP_PREFIX) && name.endsWith(\">\")) {\n const root = this.declared.get(name.slice(DEEP_PREFIX.length, -1));\n return root === undefined ? OPAQUE : this.expand({ kind: \"type\", type: root, deep: true });\n }\n const declared = args.length === 0 ? this.declared.get(name) : undefined;\n if (declared !== undefined) {\n return this.expand({ ...value, type: declared });\n }\n const [first, second] = args;\n if (first === undefined) {\n return OPAQUE;\n }\n const argument = this.expand({ ...value, type: first });\n if (argument.kind !== \"type\") {\n return argument;\n }\n return this.helper(name, argument, second);\n }\n\n private helper(name: string, argument: Evaluated, second: IrType | undefined): Evaluation {\n switch (name) {\n case \"NonNullable\":\n return this.withoutNullish(argument);\n case \"WithRequired\":\n case \"Readonly\":\n return argument;\n case \"Extract\":\n return second === undefined ? OPAQUE : this.extract(argument, second);\n case \"Omit\":\n return second === undefined ? OPAQUE : omitted(this, argument, second);\n default:\n return markerObject(name, argument) ?? OPAQUE;\n }\n }\n\n /**\n * The members of a union, each expanded; an intersection with unions in it is distributed over\n * them (`A & (B | C)` is `(A & B) | (A & C)`), as TypeScript normalizes it. A type that is not a\n * union is its only member. A union with an `any` or `unknown` member is that keyword alone.\n */\n membersOf(value: Evaluated): readonly Evaluation[] {\n const expanded = this.expand(value);\n if (expanded.kind !== \"type\") {\n return [expanded];\n }\n const { type } = expanded;\n if (type.kind === \"union\") {\n return absorbed(\n type.types.flatMap((member) => this.membersOf({ ...expanded, type: member })),\n );\n }\n return type.kind === \"intersection\" ? this.distributed(expanded, type.types) : [expanded];\n }\n\n private distributed(value: Evaluated, parts: readonly IrType[]): readonly Evaluation[] {\n const memberLists = parts.map((part) => this.membersOf({ ...value, type: part }));\n const size = memberLists.reduce((product, list) => product * list.length, 1);\n if (size > MAX_DISTRIBUTED || memberLists.some((list) => list.some((m) => m.kind !== \"type\"))) {\n return [OPAQUE];\n }\n let combinations: IrType[][] = [[]];\n for (const list of memberLists as Evaluated[][]) {\n combinations = combinations.flatMap((done) => list.map((member) => [...done, member.type]));\n }\n return combinations.map((types) => ({ ...value, type: intersectionType(types) }));\n }\n\n private withoutNullish(value: Evaluated): Evaluation {\n const members = this.membersOf(value);\n if (members.some((member) => member.kind !== \"type\")) {\n return OPAQUE;\n }\n const kept = (members as Evaluated[]).filter((member) => !isNullish(member.type));\n return { ...value, type: unionType(kept.map((member) => member.type)) };\n }\n\n /** `Extract<T, { key: unknown }>` keeps the members that have `key`; other probes are opaque. */\n private extract(value: Evaluated, probe: IrType): Evaluation {\n const [member] = probe.kind === \"object\" ? probe.members : [];\n if (probe.kind !== \"object\" || probe.members.length !== 1 || member?.kind !== \"property\") {\n return OPAQUE;\n }\n return extracted(this, value, propertyKey(member.name));\n }\n\n /** `value[index]` for a string literal, `string` or `number` index. */\n index(value: Evaluated, index: IrType): Evaluation {\n return indexType(this, value, index);\n }\n}\n"],"names":[],"mappings":"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"}
|