@geastack/compiler 1.0.15
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/LICENSE +202 -0
- package/README.md +149 -0
- package/dist/cli-analyze.d.ts +1 -0
- package/dist/cli-analyze.js +61 -0
- package/dist/cli-coverage.d.ts +1 -0
- package/dist/cli-coverage.js +329 -0
- package/dist/cli-emit.d.ts +10 -0
- package/dist/cli-emit.js +398 -0
- package/dist/cli-module-graph.d.ts +18 -0
- package/dist/cli-module-graph.js +123 -0
- package/dist/cli-package-source.d.ts +5 -0
- package/dist/cli-package-source.js +116 -0
- package/dist/cli-project.d.ts +2 -0
- package/dist/cli-project.js +60 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +199 -0
- package/dist/compiler.d.ts +228 -0
- package/dist/compiler.js +1029 -0
- package/dist/conversion/algebra.d.ts +218 -0
- package/dist/conversion/algebra.js +155 -0
- package/dist/conversion/build.d.ts +67 -0
- package/dist/conversion/build.js +1378 -0
- package/dist/conversion/derive.d.ts +37 -0
- package/dist/conversion/derive.js +260 -0
- package/dist/conversion/graph-validation.d.ts +8 -0
- package/dist/conversion/graph-validation.js +97 -0
- package/dist/conversion/native-callable-adapter.d.ts +13 -0
- package/dist/conversion/native-callable-adapter.js +53 -0
- package/dist/conversion/native-class-reference.d.ts +12 -0
- package/dist/conversion/native-class-reference.js +39 -0
- package/dist/conversion/native-payload-transport.d.ts +25 -0
- package/dist/conversion/native-payload-transport.js +33 -0
- package/dist/conversion/native-selection.d.ts +49 -0
- package/dist/conversion/native-selection.js +135 -0
- package/dist/conversion/native-sum.d.ts +42 -0
- package/dist/conversion/native-sum.js +115 -0
- package/dist/conversion/nodes.d.ts +55 -0
- package/dist/conversion/nodes.js +91 -0
- package/dist/conversion/operand-view.d.ts +14 -0
- package/dist/conversion/operand-view.js +20 -0
- package/dist/conversion/record-view.d.ts +157 -0
- package/dist/conversion/record-view.js +273 -0
- package/dist/conversion/registry.d.ts +217 -0
- package/dist/conversion/registry.js +1 -0
- package/dist/diagnostics/model.d.ts +76 -0
- package/dist/diagnostics/model.js +60 -0
- package/dist/diagnostics/sweep.d.ts +31 -0
- package/dist/diagnostics/sweep.js +112 -0
- package/dist/identity/ids.d.ts +179 -0
- package/dist/identity/ids.js +212 -0
- package/dist/ir/absent-class-arm.d.ts +48 -0
- package/dist/ir/absent-class-arm.js +157 -0
- package/dist/ir/borrow-effects.d.ts +23 -0
- package/dist/ir/borrow-effects.js +151 -0
- package/dist/ir/borrowed-call-arguments.d.ts +40 -0
- package/dist/ir/borrowed-call-arguments.js +117 -0
- package/dist/ir/build.d.ts +168 -0
- package/dist/ir/build.js +459 -0
- package/dist/ir/call-dispatch.d.ts +38 -0
- package/dist/ir/call-dispatch.js +502 -0
- package/dist/ir/call-entry.d.ts +142 -0
- package/dist/ir/call-entry.js +386 -0
- package/dist/ir/callable-class-flow.d.ts +27 -0
- package/dist/ir/callable-class-flow.js +1386 -0
- package/dist/ir/callable-field-slots.d.ts +22 -0
- package/dist/ir/callable-field-slots.js +166 -0
- package/dist/ir/callable-identity-demand.d.ts +52 -0
- package/dist/ir/callable-identity-demand.js +460 -0
- package/dist/ir/callable-member-candidates.d.ts +9 -0
- package/dist/ir/callable-member-candidates.js +39 -0
- package/dist/ir/callable-records.d.ts +21 -0
- package/dist/ir/callable-records.js +411 -0
- package/dist/ir/captures.d.ts +26 -0
- package/dist/ir/captures.js +335 -0
- package/dist/ir/certificate.d.ts +45 -0
- package/dist/ir/certificate.js +47 -0
- package/dist/ir/certify/carrier-keys.d.ts +73 -0
- package/dist/ir/certify/carrier-keys.js +221 -0
- package/dist/ir/certify/function-source.d.ts +4 -0
- package/dist/ir/certify/function-source.js +28 -0
- package/dist/ir/certify/has-property-key.d.ts +88 -0
- package/dist/ir/certify/has-property-key.js +116 -0
- package/dist/ir/certify/instanceof-key.d.ts +24 -0
- package/dist/ir/certify/instanceof-key.js +35 -0
- package/dist/ir/certify/property-access-keys.d.ts +172 -0
- package/dist/ir/certify/property-access-keys.js +291 -0
- package/dist/ir/certify/property-access.d.ts +3 -0
- package/dist/ir/certify/property-access.js +597 -0
- package/dist/ir/certify/runtime-helper.d.ts +3 -0
- package/dist/ir/certify/runtime-helper.js +326 -0
- package/dist/ir/certify/typeof-operand.d.ts +14 -0
- package/dist/ir/certify/typeof-operand.js +16 -0
- package/dist/ir/certify.d.ts +123 -0
- package/dist/ir/certify.js +481 -0
- package/dist/ir/class-evaluation.d.ts +26 -0
- package/dist/ir/class-evaluation.js +50 -0
- package/dist/ir/class-static-fields.d.ts +60 -0
- package/dist/ir/class-static-fields.js +108 -0
- package/dist/ir/construct-entry.d.ts +26 -0
- package/dist/ir/construct-entry.js +117 -0
- package/dist/ir/dead-values.d.ts +90 -0
- package/dist/ir/dead-values.js +184 -0
- package/dist/ir/deferral.d.ts +99 -0
- package/dist/ir/deferral.js +409 -0
- package/dist/ir/dense-loops.d.ts +230 -0
- package/dist/ir/dense-loops.js +697 -0
- package/dist/ir/dominance.d.ts +82 -0
- package/dist/ir/dominance.js +268 -0
- package/dist/ir/emission-representations.d.ts +71 -0
- package/dist/ir/emission-representations.js +350 -0
- package/dist/ir/facts.d.ts +218 -0
- package/dist/ir/facts.js +181 -0
- package/dist/ir/fixed-data-definition.d.ts +19 -0
- package/dist/ir/fixed-data-definition.js +49 -0
- package/dist/ir/generator-split.d.ts +38 -0
- package/dist/ir/generator-split.js +329 -0
- package/dist/ir/hoist.d.ts +55 -0
- package/dist/ir/hoist.js +375 -0
- package/dist/ir/instantiation.d.ts +61 -0
- package/dist/ir/instantiation.js +137 -0
- package/dist/ir/integer-storage.d.ts +170 -0
- package/dist/ir/integer-storage.js +822 -0
- package/dist/ir/integers.d.ts +161 -0
- package/dist/ir/integers.js +539 -0
- package/dist/ir/integrity-restrictions.d.ts +50 -0
- package/dist/ir/integrity-restrictions.js +118 -0
- package/dist/ir/local-iterators.d.ts +4 -0
- package/dist/ir/local-iterators.js +27 -0
- package/dist/ir/lower-allocation.d.ts +4 -0
- package/dist/ir/lower-allocation.js +325 -0
- package/dist/ir/lower-completion.d.ts +15 -0
- package/dist/ir/lower-completion.js +25 -0
- package/dist/ir/lower-destructuring.d.ts +5 -0
- package/dist/ir/lower-destructuring.js +693 -0
- package/dist/ir/lower-element.d.ts +29 -0
- package/dist/ir/lower-element.js +111 -0
- package/dist/ir/lower-exceptions.d.ts +47 -0
- package/dist/ir/lower-exceptions.js +92 -0
- package/dist/ir/lower-flow.d.ts +137 -0
- package/dist/ir/lower-flow.js +600 -0
- package/dist/ir/lower-graph.d.ts +218 -0
- package/dist/ir/lower-graph.js +687 -0
- package/dist/ir/lower-invocation.d.ts +4 -0
- package/dist/ir/lower-invocation.js +514 -0
- package/dist/ir/lower-narrow.d.ts +53 -0
- package/dist/ir/lower-narrow.js +320 -0
- package/dist/ir/lower-operands.d.ts +272 -0
- package/dist/ir/lower-operands.js +461 -0
- package/dist/ir/lower-property.d.ts +21 -0
- package/dist/ir/lower-property.js +132 -0
- package/dist/ir/lower-protocol.d.ts +11 -0
- package/dist/ir/lower-protocol.js +118 -0
- package/dist/ir/lower-short-circuit.d.ts +41 -0
- package/dist/ir/lower-short-circuit.js +63 -0
- package/dist/ir/lower.d.ts +82 -0
- package/dist/ir/lower.js +1346 -0
- package/dist/ir/model.d.ts +1474 -0
- package/dist/ir/model.js +6 -0
- package/dist/ir/native-absent-property.d.ts +3 -0
- package/dist/ir/native-absent-property.js +13 -0
- package/dist/ir/native-array-transport.d.ts +7 -0
- package/dist/ir/native-array-transport.js +46 -0
- package/dist/ir/native-callable-bind.d.ts +9 -0
- package/dist/ir/native-callable-bind.js +30 -0
- package/dist/ir/native-carrier-predicate.d.ts +34 -0
- package/dist/ir/native-carrier-predicate.js +49 -0
- package/dist/ir/native-class-accessor.d.ts +18 -0
- package/dist/ir/native-class-accessor.js +52 -0
- package/dist/ir/native-class-construction.d.ts +16 -0
- package/dist/ir/native-class-construction.js +71 -0
- package/dist/ir/native-class-initialization.d.ts +15 -0
- package/dist/ir/native-class-initialization.js +56 -0
- package/dist/ir/native-class-origins.d.ts +13 -0
- package/dist/ir/native-class-origins.js +237 -0
- package/dist/ir/native-dictionary-transport.d.ts +6 -0
- package/dist/ir/native-dictionary-transport.js +37 -0
- package/dist/ir/native-enumeration.d.ts +14 -0
- package/dist/ir/native-enumeration.js +26 -0
- package/dist/ir/native-equality.d.ts +10 -0
- package/dist/ir/native-equality.js +18 -0
- package/dist/ir/native-field-owner.d.ts +37 -0
- package/dist/ir/native-field-owner.js +183 -0
- package/dist/ir/native-fixed-layout.d.ts +41 -0
- package/dist/ir/native-fixed-layout.js +232 -0
- package/dist/ir/native-host-construction.d.ts +53 -0
- package/dist/ir/native-host-construction.js +62 -0
- package/dist/ir/native-key-query.d.ts +4 -0
- package/dist/ir/native-key-query.js +38 -0
- package/dist/ir/native-merge-transport.d.ts +25 -0
- package/dist/ir/native-merge-transport.js +71 -0
- package/dist/ir/native-record-index-transport.d.ts +11 -0
- package/dist/ir/native-record-index-transport.js +34 -0
- package/dist/ir/native-record-index.d.ts +12 -0
- package/dist/ir/native-record-index.js +27 -0
- package/dist/ir/native-reflect-field.d.ts +5 -0
- package/dist/ir/native-reflect-field.js +33 -0
- package/dist/ir/native-sequence-transport.d.ts +7 -0
- package/dist/ir/native-sequence-transport.js +53 -0
- package/dist/ir/numeric-intrinsics.d.ts +13 -0
- package/dist/ir/numeric-intrinsics.js +57 -0
- package/dist/ir/object-value-conversions.d.ts +20 -0
- package/dist/ir/object-value-conversions.js +50 -0
- package/dist/ir/physical-class-reflection.d.ts +9 -0
- package/dist/ir/physical-class-reflection.js +57 -0
- package/dist/ir/presence-proof.d.ts +42 -0
- package/dist/ir/presence-proof.js +490 -0
- package/dist/ir/program-facts.d.ts +106 -0
- package/dist/ir/program-facts.js +319 -0
- package/dist/ir/proven-branches.d.ts +16 -0
- package/dist/ir/proven-branches.js +219 -0
- package/dist/ir/queries.d.ts +41 -0
- package/dist/ir/queries.js +213 -0
- package/dist/ir/reflection-demand.d.ts +64 -0
- package/dist/ir/reflection-demand.js +1394 -0
- package/dist/ir/refusal.d.ts +43 -0
- package/dist/ir/refusal.js +28 -0
- package/dist/ir/shake.d.ts +37 -0
- package/dist/ir/shake.js +1078 -0
- package/dist/ir/static-callables.d.ts +11 -0
- package/dist/ir/static-callables.js +163 -0
- package/dist/ir/string-layout-reuse.d.ts +13 -0
- package/dist/ir/string-layout-reuse.js +39 -0
- package/dist/ir/string-length-reuse.d.ts +8 -0
- package/dist/ir/string-length-reuse.js +47 -0
- package/dist/ir/transfer.d.ts +78 -0
- package/dist/ir/transfer.js +270 -0
- package/dist/ir/type-query-results.d.ts +25 -0
- package/dist/ir/type-query-results.js +96 -0
- package/dist/ir/typed-property-access.d.ts +100 -0
- package/dist/ir/typed-property-access.js +161 -0
- package/dist/ir/verify.d.ts +19 -0
- package/dist/ir/verify.js +355 -0
- package/dist/plugins/apple/constructors.d.ts +112 -0
- package/dist/plugins/apple/constructors.js +217 -0
- package/dist/plugins/apple/host.d.ts +181 -0
- package/dist/plugins/apple/host.js +262 -0
- package/dist/plugins/apple/jsx.d.ts +2 -0
- package/dist/plugins/apple/jsx.js +293 -0
- package/dist/plugins/apple/members.d.ts +16 -0
- package/dist/plugins/apple/members.js +190 -0
- package/dist/plugins/apple/plugin.d.ts +2 -0
- package/dist/plugins/apple/plugin.js +156 -0
- package/dist/plugins/gea/component-classes.d.ts +25 -0
- package/dist/plugins/gea/component-classes.js +162 -0
- package/dist/plugins/gea/component-inline.d.ts +13 -0
- package/dist/plugins/gea/component-inline.js +532 -0
- package/dist/plugins/gea/constructors.d.ts +23 -0
- package/dist/plugins/gea/constructors.js +100 -0
- package/dist/plugins/gea/contract.d.ts +150 -0
- package/dist/plugins/gea/contract.js +195 -0
- package/dist/plugins/gea/element-ref.d.ts +31 -0
- package/dist/plugins/gea/element-ref.js +45 -0
- package/dist/plugins/gea/host.d.ts +520 -0
- package/dist/plugins/gea/host.js +762 -0
- package/dist/plugins/gea/lower.d.ts +6 -0
- package/dist/plugins/gea/lower.js +195 -0
- package/dist/plugins/gea/members.d.ts +22 -0
- package/dist/plugins/gea/members.js +221 -0
- package/dist/plugins/gea/plugin.d.ts +22 -0
- package/dist/plugins/gea/plugin.js +307 -0
- package/dist/plugins/gea/prelude.d.ts +78 -0
- package/dist/plugins/gea/prelude.js +153 -0
- package/dist/plugins/gea/producer.d.ts +5 -0
- package/dist/plugins/gea/producer.js +52 -0
- package/dist/plugins/gea/reactive-slots.d.ts +49 -0
- package/dist/plugins/gea/reactive-slots.js +578 -0
- package/dist/plugins/gea/render-bridge.d.ts +6 -0
- package/dist/plugins/gea/render-bridge.js +281 -0
- package/dist/plugins/gea/slots.d.ts +15 -0
- package/dist/plugins/gea/slots.js +36 -0
- package/dist/plugins/gea/template-analysis.d.ts +151 -0
- package/dist/plugins/gea/template-analysis.js +346 -0
- package/dist/plugins/gea/user-agent-styles.d.ts +9 -0
- package/dist/plugins/gea/user-agent-styles.js +94 -0
- package/dist/plugins/installed.d.ts +19 -0
- package/dist/plugins/installed.js +21 -0
- package/dist/plugins/load.d.ts +7 -0
- package/dist/plugins/load.js +207 -0
- package/dist/plugins/model.d.ts +735 -0
- package/dist/plugins/model.js +47 -0
- package/dist/plugins/webgl/host.d.ts +77 -0
- package/dist/plugins/webgl/host.js +162 -0
- package/dist/plugins/webgl/plugin.d.ts +40 -0
- package/dist/plugins/webgl/plugin.js +99 -0
- package/dist/preflight/obligations.d.ts +206 -0
- package/dist/preflight/obligations.js +36 -0
- package/dist/preflight/report.d.ts +20 -0
- package/dist/preflight/report.js +61 -0
- package/dist/preflight/run.d.ts +39 -0
- package/dist/preflight/run.js +403 -0
- package/dist/project-preparation.d.ts +33 -0
- package/dist/project-preparation.js +314 -0
- package/dist/projection/abi.d.ts +82 -0
- package/dist/projection/abi.js +349 -0
- package/dist/projection/apply-arguments.d.ts +12 -0
- package/dist/projection/apply-arguments.js +20 -0
- package/dist/projection/bindings.d.ts +250 -0
- package/dist/projection/bindings.js +340 -0
- package/dist/projection/callee.d.ts +196 -0
- package/dist/projection/callee.js +444 -0
- package/dist/projection/class-property-presence.d.ts +28 -0
- package/dist/projection/class-property-presence.js +58 -0
- package/dist/projection/class-prototype.d.ts +5 -0
- package/dist/projection/class-prototype.js +23 -0
- package/dist/projection/class-storage.d.ts +26 -0
- package/dist/projection/class-storage.js +236 -0
- package/dist/projection/classes.d.ts +283 -0
- package/dist/projection/classes.js +944 -0
- package/dist/projection/coercions.d.ts +20 -0
- package/dist/projection/coercions.js +33 -0
- package/dist/projection/dispatch.d.ts +167 -0
- package/dist/projection/dispatch.js +379 -0
- package/dist/projection/fields.d.ts +123 -0
- package/dist/projection/fields.js +383 -0
- package/dist/projection/instance-test.d.ts +78 -0
- package/dist/projection/instance-test.js +156 -0
- package/dist/projection/slots.d.ts +146 -0
- package/dist/projection/slots.js +663 -0
- package/dist/projection/synthesized-abi.d.ts +61 -0
- package/dist/projection/synthesized-abi.js +94 -0
- package/dist/representation/array-index.d.ts +14 -0
- package/dist/representation/array-index.js +17 -0
- package/dist/representation/callable-object.d.ts +3 -0
- package/dist/representation/callable-object.js +6 -0
- package/dist/representation/collections.d.ts +84 -0
- package/dist/representation/collections.js +139 -0
- package/dist/representation/derive.d.ts +159 -0
- package/dist/representation/derive.js +2546 -0
- package/dist/representation/difference.d.ts +30 -0
- package/dist/representation/difference.js +240 -0
- package/dist/representation/field-descriptor-policy.d.ts +19 -0
- package/dist/representation/field-descriptor-policy.js +39 -0
- package/dist/representation/function-constructor.d.ts +13 -0
- package/dist/representation/function-constructor.js +9 -0
- package/dist/representation/host-abi.d.ts +32 -0
- package/dist/representation/host-abi.js +97 -0
- package/dist/representation/host-templates.d.ts +67 -0
- package/dist/representation/host-templates.js +94 -0
- package/dist/representation/intersection.d.ts +84 -0
- package/dist/representation/intersection.js +149 -0
- package/dist/representation/literal-destination.d.ts +43 -0
- package/dist/representation/literal-destination.js +133 -0
- package/dist/representation/merge.d.ts +18 -0
- package/dist/representation/merge.js +83 -0
- package/dist/representation/model.d.ts +1160 -0
- package/dist/representation/model.js +1019 -0
- package/dist/representation/numeric-index.d.ts +13 -0
- package/dist/representation/numeric-index.js +29 -0
- package/dist/representation/object-shape.d.ts +109 -0
- package/dist/representation/object-shape.js +123 -0
- package/dist/representation/optional.d.ts +12 -0
- package/dist/representation/optional.js +87 -0
- package/dist/representation/plan.d.ts +60 -0
- package/dist/representation/plan.js +78 -0
- package/dist/representation/policies.d.ts +589 -0
- package/dist/representation/policies.js +107 -0
- package/dist/representation/primitive-domain.d.ts +1 -0
- package/dist/representation/primitive-domain.js +1 -0
- package/dist/representation/primitives.d.ts +44 -0
- package/dist/representation/primitives.js +78 -0
- package/dist/representation/publish.d.ts +49 -0
- package/dist/representation/publish.js +648 -0
- package/dist/representation/record-fields.d.ts +96 -0
- package/dist/representation/record-fields.js +116 -0
- package/dist/representation/template-object.d.ts +11 -0
- package/dist/representation/template-object.js +26 -0
- package/dist/representation/union.d.ts +30 -0
- package/dist/representation/union.js +324 -0
- package/dist/representation/value-records.d.ts +3 -0
- package/dist/representation/value-records.js +307 -0
- package/dist/representation/verify.d.ts +17 -0
- package/dist/representation/verify.js +221 -0
- package/dist/semantics/alias-this-field-declaration-transform.d.ts +4 -0
- package/dist/semantics/alias-this-field-declaration-transform.js +207 -0
- package/dist/semantics/ambient-type-realization-transform.d.ts +62 -0
- package/dist/semantics/ambient-type-realization-transform.js +168 -0
- package/dist/semantics/ambient.d.ts +24 -0
- package/dist/semantics/ambient.js +119 -0
- package/dist/semantics/borrowed-builtin-call-bind-source-transform.d.ts +4 -0
- package/dist/semantics/borrowed-builtin-call-bind-source-transform.js +341 -0
- package/dist/semantics/callable-origins.d.ts +46 -0
- package/dist/semantics/callable-origins.js +354 -0
- package/dist/semantics/class-alias.d.ts +7 -0
- package/dist/semantics/class-alias.js +37 -0
- package/dist/semantics/class-heritage.d.ts +34 -0
- package/dist/semantics/class-heritage.js +104 -0
- package/dist/semantics/commonjs-wrapper.d.ts +69 -0
- package/dist/semantics/commonjs-wrapper.js +231 -0
- package/dist/semantics/constructor-slot-subclasses.d.ts +28 -0
- package/dist/semantics/constructor-slot-subclasses.js +112 -0
- package/dist/semantics/declaration-overlay-transform.d.ts +35 -0
- package/dist/semantics/declaration-overlay-transform.js +2157 -0
- package/dist/semantics/define-property-source-transform.d.ts +4 -0
- package/dist/semantics/define-property-source-transform.js +437 -0
- package/dist/semantics/diagnostic-source-preparation.d.ts +24 -0
- package/dist/semantics/diagnostic-source-preparation.js +82 -0
- package/dist/semantics/documentation-ranges.d.ts +22 -0
- package/dist/semantics/documentation-ranges.js +36 -0
- package/dist/semantics/dynamic-fallback.d.ts +86 -0
- package/dist/semantics/dynamic-fallback.js +249 -0
- package/dist/semantics/frontend-timing.d.ts +6 -0
- package/dist/semantics/frontend-timing.js +35 -0
- package/dist/semantics/frontend.d.ts +504 -0
- package/dist/semantics/frontend.js +1157 -0
- package/dist/semantics/host-declaration-provenance.d.ts +11 -0
- package/dist/semantics/host-declaration-provenance.js +18 -0
- package/dist/semantics/host-methods.d.ts +24 -0
- package/dist/semantics/host-methods.js +74 -0
- package/dist/semantics/host-protocols.d.ts +429 -0
- package/dist/semantics/host-protocols.js +1501 -0
- package/dist/semantics/inherited-accessor.d.ts +7 -0
- package/dist/semantics/inherited-accessor.js +48 -0
- package/dist/semantics/interface-families.d.ts +70 -0
- package/dist/semantics/interface-families.js +180 -0
- package/dist/semantics/interface-implementors.d.ts +53 -0
- package/dist/semantics/interface-implementors.js +87 -0
- package/dist/semantics/jsdoc-namepath-transform.d.ts +4 -0
- package/dist/semantics/jsdoc-namepath-transform.js +85 -0
- package/dist/semantics/model/coverage.d.ts +68 -0
- package/dist/semantics/model/coverage.js +73 -0
- package/dist/semantics/model/edges.d.ts +103 -0
- package/dist/semantics/model/edges.js +20 -0
- package/dist/semantics/model/graph.d.ts +55 -0
- package/dist/semantics/model/graph.js +129 -0
- package/dist/semantics/model/operands.d.ts +159 -0
- package/dist/semantics/model/operands.js +26 -0
- package/dist/semantics/model/operations.d.ts +496 -0
- package/dist/semantics/model/operations.js +2 -0
- package/dist/semantics/model/primitive-domain.d.ts +26 -0
- package/dist/semantics/model/primitive-domain.js +38 -0
- package/dist/semantics/model/selected-signature.d.ts +261 -0
- package/dist/semantics/model/selected-signature.js +55 -0
- package/dist/semantics/model/structural-type-table.d.ts +93 -0
- package/dist/semantics/model/structural-type-table.js +237 -0
- package/dist/semantics/model/structural-types.d.ts +367 -0
- package/dist/semantics/model/structural-types.js +200 -0
- package/dist/semantics/module-resolution.d.ts +23 -0
- package/dist/semantics/module-resolution.js +227 -0
- package/dist/semantics/new-callee-class-tag-source-transform.d.ts +4 -0
- package/dist/semantics/new-callee-class-tag-source-transform.js +64 -0
- package/dist/semantics/node-project.d.ts +13 -0
- package/dist/semantics/node-project.js +107 -0
- package/dist/semantics/node-source-hooks.d.ts +1 -0
- package/dist/semantics/node-source-hooks.js +63 -0
- package/dist/semantics/normalize/absent-globals.d.ts +143 -0
- package/dist/semantics/normalize/absent-globals.js +191 -0
- package/dist/semantics/normalize/arguments-objects.d.ts +43 -0
- package/dist/semantics/normalize/arguments-objects.js +60 -0
- package/dist/semantics/normalize/asserted-arm-absence.d.ts +28 -0
- package/dist/semantics/normalize/asserted-arm-absence.js +61 -0
- package/dist/semantics/normalize/assignment-patterns.d.ts +70 -0
- package/dist/semantics/normalize/assignment-patterns.js +147 -0
- package/dist/semantics/normalize/bag-absence.d.ts +8 -0
- package/dist/semantics/normalize/bag-absence.js +42 -0
- package/dist/semantics/normalize/binding-fixpoint.d.ts +36 -0
- package/dist/semantics/normalize/binding-fixpoint.js +140 -0
- package/dist/semantics/normalize/callback-parameter-contracts.d.ts +16 -0
- package/dist/semantics/normalize/callback-parameter-contracts.js +91 -0
- package/dist/semantics/normalize/cells/agreement.d.ts +46 -0
- package/dist/semantics/normalize/cells/agreement.js +34 -0
- package/dist/semantics/normalize/cells/candidates.d.ts +17 -0
- package/dist/semantics/normalize/cells/candidates.js +35 -0
- package/dist/semantics/normalize/cells/facts.d.ts +19 -0
- package/dist/semantics/normalize/cells/facts.js +90 -0
- package/dist/semantics/normalize/cells/index.d.ts +10 -0
- package/dist/semantics/normalize/cells/index.js +6 -0
- package/dist/semantics/normalize/cells/model.d.ts +98 -0
- package/dist/semantics/normalize/cells/model.js +2 -0
- package/dist/semantics/normalize/cells/policies/bag.d.ts +44 -0
- package/dist/semantics/normalize/cells/policies/bag.js +114 -0
- package/dist/semantics/normalize/cells/policies/collection.d.ts +42 -0
- package/dist/semantics/normalize/cells/policies/collection.js +218 -0
- package/dist/semantics/normalize/cells/policies/field.d.ts +28 -0
- package/dist/semantics/normalize/cells/policies/field.js +40 -0
- package/dist/semantics/normalize/cells/policies/index.d.ts +49 -0
- package/dist/semantics/normalize/cells/policies/index.js +58 -0
- package/dist/semantics/normalize/cells/policies/local.d.ts +18 -0
- package/dist/semantics/normalize/cells/policies/local.js +37 -0
- package/dist/semantics/normalize/cells/policies/parameter.d.ts +28 -0
- package/dist/semantics/normalize/cells/policies/parameter.js +39 -0
- package/dist/semantics/normalize/cells/policies/return.d.ts +26 -0
- package/dist/semantics/normalize/cells/policies/return.js +45 -0
- package/dist/semantics/normalize/cells/policies/shared.d.ts +33 -0
- package/dist/semantics/normalize/cells/policies/shared.js +45 -0
- package/dist/semantics/normalize/cells/policy.d.ts +72 -0
- package/dist/semantics/normalize/cells/policy.js +18 -0
- package/dist/semantics/normalize/cells/registry.d.ts +14 -0
- package/dist/semantics/normalize/cells/registry.js +17 -0
- package/dist/semantics/normalize/census-refusal.d.ts +62 -0
- package/dist/semantics/normalize/census-refusal.js +27 -0
- package/dist/semantics/normalize/census.d.ts +109 -0
- package/dist/semantics/normalize/census.js +667 -0
- package/dist/semantics/normalize/collection-bindings.d.ts +278 -0
- package/dist/semantics/normalize/collection-bindings.js +677 -0
- package/dist/semantics/normalize/commonjs-module-record.d.ts +21 -0
- package/dist/semantics/normalize/commonjs-module-record.js +289 -0
- package/dist/semantics/normalize/commonjs-require.d.ts +13 -0
- package/dist/semantics/normalize/commonjs-require.js +1527 -0
- package/dist/semantics/normalize/contribution.d.ts +63 -0
- package/dist/semantics/normalize/contribution.js +172 -0
- package/dist/semantics/normalize/dead-typeof-guards.d.ts +64 -0
- package/dist/semantics/normalize/dead-typeof-guards.js +152 -0
- package/dist/semantics/normalize/deferred-intrinsic-protocols.d.ts +57 -0
- package/dist/semantics/normalize/deferred-intrinsic-protocols.js +109 -0
- package/dist/semantics/normalize/derived-expression-type.d.ts +1070 -0
- package/dist/semantics/normalize/derived-expression-type.js +3463 -0
- package/dist/semantics/normalize/evaluation-order.d.ts +16 -0
- package/dist/semantics/normalize/evaluation-order.js +37 -0
- package/dist/semantics/normalize/field-bindings.d.ts +167 -0
- package/dist/semantics/normalize/field-bindings.js +1125 -0
- package/dist/semantics/normalize/flow/array-element-continuation.d.ts +27 -0
- package/dist/semantics/normalize/flow/array-element-continuation.js +1452 -0
- package/dist/semantics/normalize/flow/callable-array-origins.d.ts +42 -0
- package/dist/semantics/normalize/flow/callable-array-origins.js +318 -0
- package/dist/semantics/normalize/flow/callable-completions.d.ts +45 -0
- package/dist/semantics/normalize/flow/callable-completions.js +82 -0
- package/dist/semantics/normalize/flow/callable-reach.d.ts +237 -0
- package/dist/semantics/normalize/flow/callable-reach.js +7174 -0
- package/dist/semantics/normalize/flow/class-family-member-read.d.ts +16 -0
- package/dist/semantics/normalize/flow/class-family-member-read.js +992 -0
- package/dist/semantics/normalize/flow/collection-value-continuation.d.ts +21 -0
- package/dist/semantics/normalize/flow/collection-value-continuation.js +192 -0
- package/dist/semantics/normalize/flow/component-solver.d.ts +199 -0
- package/dist/semantics/normalize/flow/component-solver.js +587 -0
- package/dist/semantics/normalize/flow/computed-key-set.d.ts +84 -0
- package/dist/semantics/normalize/flow/computed-key-set.js +660 -0
- package/dist/semantics/normalize/flow/export-importers.d.ts +24 -0
- package/dist/semantics/normalize/flow/export-importers.js +269 -0
- package/dist/semantics/normalize/flow/host-text-sink.d.ts +25 -0
- package/dist/semantics/normalize/flow/host-text-sink.js +87 -0
- package/dist/semantics/normalize/flow/intrinsic-array-callback-frames.d.ts +84 -0
- package/dist/semantics/normalize/flow/intrinsic-array-callback-frames.js +180 -0
- package/dist/semantics/normalize/flow/intrinsic-data-definition.d.ts +35 -0
- package/dist/semantics/normalize/flow/intrinsic-data-definition.js +140 -0
- package/dist/semantics/normalize/flow/invocation-facts.d.ts +98 -0
- package/dist/semantics/normalize/flow/invocation-facts.js +257 -0
- package/dist/semantics/normalize/flow/member-call-forwarding.d.ts +122 -0
- package/dist/semantics/normalize/flow/member-call-forwarding.js +835 -0
- package/dist/semantics/normalize/flow/model.d.ts +357 -0
- package/dist/semantics/normalize/flow/model.js +177 -0
- package/dist/semantics/normalize/flow/native-collection-protocol.d.ts +24 -0
- package/dist/semantics/normalize/flow/native-collection-protocol.js +252 -0
- package/dist/semantics/normalize/flow/node-path-token.d.ts +3 -0
- package/dist/semantics/normalize/flow/node-path-token.js +53 -0
- package/dist/semantics/normalize/flow/object-binding-continuation.d.ts +11 -0
- package/dist/semantics/normalize/flow/object-binding-continuation.js +42 -0
- package/dist/semantics/normalize/flow/origin-authority.d.ts +56 -0
- package/dist/semantics/normalize/flow/origin-authority.js +2 -0
- package/dist/semantics/normalize/flow/owned-class-receivers.d.ts +35 -0
- package/dist/semantics/normalize/flow/owned-class-receivers.js +191 -0
- package/dist/semantics/normalize/flow/parameter-values.d.ts +27 -0
- package/dist/semantics/normalize/flow/parameter-values.js +251 -0
- package/dist/semantics/normalize/flow/proof-hypotheses.d.ts +66 -0
- package/dist/semantics/normalize/flow/proof-hypotheses.js +162 -0
- package/dist/semantics/normalize/flow/record-alias-closure.d.ts +27 -0
- package/dist/semantics/normalize/flow/record-alias-closure.js +298 -0
- package/dist/semantics/normalize/flow/seeded-origins.d.ts +43 -0
- package/dist/semantics/normalize/flow/seeded-origins.js +54 -0
- package/dist/semantics/normalize/flow/source-class-data.d.ts +132 -0
- package/dist/semantics/normalize/flow/source-class-data.js +838 -0
- package/dist/semantics/normalize/flow/source-class-instanceof.d.ts +13 -0
- package/dist/semantics/normalize/flow/source-class-instanceof.js +37 -0
- package/dist/semantics/normalize/flow/source-class-static-data.d.ts +16 -0
- package/dist/semantics/normalize/flow/source-class-static-data.js +47 -0
- package/dist/semantics/normalize/flow/source-construction-frames.d.ts +12 -0
- package/dist/semantics/normalize/flow/source-construction-frames.js +118 -0
- package/dist/semantics/normalize/flow/source-invocation-frame-layout.d.ts +34 -0
- package/dist/semantics/normalize/flow/source-invocation-frame-layout.js +78 -0
- package/dist/semantics/normalize/flow/source-invocation-receiver.d.ts +37 -0
- package/dist/semantics/normalize/flow/source-invocation-receiver.js +95 -0
- package/dist/semantics/normalize/flow/source-prototype-method-identity.d.ts +23 -0
- package/dist/semantics/normalize/flow/source-prototype-method-identity.js +81 -0
- package/dist/semantics/normalize/flow/source-record-data.d.ts +29 -0
- package/dist/semantics/normalize/flow/source-record-data.js +626 -0
- package/dist/semantics/normalize/flow/source-value-session.d.ts +77 -0
- package/dist/semantics/normalize/flow/source-value-session.js +3089 -0
- package/dist/semantics/normalize/flow/targets.d.ts +118 -0
- package/dist/semantics/normalize/flow/targets.js +405 -0
- package/dist/semantics/normalize/flow/value-flow.d.ts +36 -0
- package/dist/semantics/normalize/flow/value-flow.js +823 -0
- package/dist/semantics/normalize/flow/value-provenance.d.ts +31 -0
- package/dist/semantics/normalize/flow/value-provenance.js +112 -0
- package/dist/semantics/normalize/gating.d.ts +51 -0
- package/dist/semantics/normalize/gating.js +560 -0
- package/dist/semantics/normalize/generic-function-choice.d.ts +31 -0
- package/dist/semantics/normalize/generic-function-choice.js +115 -0
- package/dist/semantics/normalize/global-host-mutations.d.ts +51 -0
- package/dist/semantics/normalize/global-host-mutations.js +5989 -0
- package/dist/semantics/normalize/host-effect-contracts.d.ts +77 -0
- package/dist/semantics/normalize/host-effect-contracts.js +143 -0
- package/dist/semantics/normalize/host-mutation-computed-keys.d.ts +38 -0
- package/dist/semantics/normalize/host-mutation-computed-keys.js +26 -0
- package/dist/semantics/normalize/host-mutation-key-reader.d.ts +66 -0
- package/dist/semantics/normalize/host-mutation-key-reader.js +192 -0
- package/dist/semantics/normalize/host-mutation-keys.d.ts +114 -0
- package/dist/semantics/normalize/host-mutation-keys.js +183 -0
- package/dist/semantics/normalize/identities.d.ts +172 -0
- package/dist/semantics/normalize/identities.js +426 -0
- package/dist/semantics/normalize/implicit-arguments-tuple.d.ts +97 -0
- package/dist/semantics/normalize/implicit-arguments-tuple.js +197 -0
- package/dist/semantics/normalize/implicit-arguments.d.ts +11 -0
- package/dist/semantics/normalize/implicit-arguments.js +39 -0
- package/dist/semantics/normalize/instantiation.d.ts +73 -0
- package/dist/semantics/normalize/instantiation.js +399 -0
- package/dist/semantics/normalize/intrinsic-property-call.d.ts +18 -0
- package/dist/semantics/normalize/intrinsic-property-call.js +69 -0
- package/dist/semantics/normalize/intrinsic-prototype.d.ts +41 -0
- package/dist/semantics/normalize/intrinsic-prototype.js +87 -0
- package/dist/semantics/normalize/intrinsic-static-member.d.ts +14 -0
- package/dist/semantics/normalize/intrinsic-static-member.js +23 -0
- package/dist/semantics/normalize/jsdoc-type-names.d.ts +32 -0
- package/dist/semantics/normalize/jsdoc-type-names.js +512 -0
- package/dist/semantics/normalize/keyof.d.ts +32 -0
- package/dist/semantics/normalize/keyof.js +110 -0
- package/dist/semantics/normalize/local-bindings.d.ts +176 -0
- package/dist/semantics/normalize/local-bindings.js +1826 -0
- package/dist/semantics/normalize/logical-result-type.d.ts +16 -0
- package/dist/semantics/normalize/logical-result-type.js +102 -0
- package/dist/semantics/normalize/namespace-paths.d.ts +57 -0
- package/dist/semantics/normalize/namespace-paths.js +108 -0
- package/dist/semantics/normalize/normalize.d.ts +57 -0
- package/dist/semantics/normalize/normalize.js +68 -0
- package/dist/semantics/normalize/object-bag-bindings.d.ts +305 -0
- package/dist/semantics/normalize/object-bag-bindings.js +1290 -0
- package/dist/semantics/normalize/omitted-stated-parameter.d.ts +53 -0
- package/dist/semantics/normalize/omitted-stated-parameter.js +59 -0
- package/dist/semantics/normalize/open-type-form.d.ts +10 -0
- package/dist/semantics/normalize/open-type-form.js +32 -0
- package/dist/semantics/normalize/parameter-bindings.d.ts +361 -0
- package/dist/semantics/normalize/parameter-bindings.js +3339 -0
- package/dist/semantics/normalize/parameter-slot.d.ts +264 -0
- package/dist/semantics/normalize/parameter-slot.js +491 -0
- package/dist/semantics/normalize/physical-overload-result.d.ts +77 -0
- package/dist/semantics/normalize/physical-overload-result.js +99 -0
- package/dist/semantics/normalize/primitive-property-absence.d.ts +12 -0
- package/dist/semantics/normalize/primitive-property-absence.js +60 -0
- package/dist/semantics/normalize/producer-context.d.ts +376 -0
- package/dist/semantics/normalize/producer-context.js +1 -0
- package/dist/semantics/normalize/producers/allocations.d.ts +3 -0
- package/dist/semantics/normalize/producers/allocations.js +863 -0
- package/dist/semantics/normalize/producers/binding-kind.d.ts +37 -0
- package/dist/semantics/normalize/producers/binding-kind.js +36 -0
- package/dist/semantics/normalize/producers/bindings.d.ts +85 -0
- package/dist/semantics/normalize/producers/bindings.js +710 -0
- package/dist/semantics/normalize/producers/boundary.d.ts +34 -0
- package/dist/semantics/normalize/producers/boundary.js +123 -0
- package/dist/semantics/normalize/producers/class-lifecycle.d.ts +3 -0
- package/dist/semantics/normalize/producers/class-lifecycle.js +902 -0
- package/dist/semantics/normalize/producers/computations.d.ts +3 -0
- package/dist/semantics/normalize/producers/computations.js +613 -0
- package/dist/semantics/normalize/producers/control-loops.d.ts +30 -0
- package/dist/semantics/normalize/producers/control-loops.js +91 -0
- package/dist/semantics/normalize/producers/control.d.ts +30 -0
- package/dist/semantics/normalize/producers/control.js +923 -0
- package/dist/semantics/normalize/producers/declaration-lifecycle.d.ts +3 -0
- package/dist/semantics/normalize/producers/declaration-lifecycle.js +390 -0
- package/dist/semantics/normalize/producers/destructuring.d.ts +45 -0
- package/dist/semantics/normalize/producers/destructuring.js +1180 -0
- package/dist/semantics/normalize/producers/dynamic-language.d.ts +3 -0
- package/dist/semantics/normalize/producers/dynamic-language.js +70 -0
- package/dist/semantics/normalize/producers/erasure.d.ts +51 -0
- package/dist/semantics/normalize/producers/erasure.js +90 -0
- package/dist/semantics/normalize/producers/installed.d.ts +3 -0
- package/dist/semantics/normalize/producers/installed.js +55 -0
- package/dist/semantics/normalize/producers/invocations.d.ts +35 -0
- package/dist/semantics/normalize/producers/invocations.js +1796 -0
- package/dist/semantics/normalize/producers/iteration-yield.d.ts +59 -0
- package/dist/semantics/normalize/producers/iteration-yield.js +235 -0
- package/dist/semantics/normalize/producers/jsx.d.ts +3 -0
- package/dist/semantics/normalize/producers/jsx.js +360 -0
- package/dist/semantics/normalize/producers/mint.d.ts +39 -0
- package/dist/semantics/normalize/producers/mint.js +44 -0
- package/dist/semantics/normalize/producers/nullish.d.ts +16 -0
- package/dist/semantics/normalize/producers/nullish.js +27 -0
- package/dist/semantics/normalize/producers/object-assignment.d.ts +8 -0
- package/dist/semantics/normalize/producers/object-assignment.js +204 -0
- package/dist/semantics/normalize/producers/object-tag.d.ts +9 -0
- package/dist/semantics/normalize/producers/object-tag.js +119 -0
- package/dist/semantics/normalize/producers/optional-chain.d.ts +44 -0
- package/dist/semantics/normalize/producers/optional-chain.js +75 -0
- package/dist/semantics/normalize/producers/properties.d.ts +21 -0
- package/dist/semantics/normalize/producers/properties.js +1053 -0
- package/dist/semantics/normalize/producers/protocol.d.ts +67 -0
- package/dist/semantics/normalize/producers/protocol.js +695 -0
- package/dist/semantics/normalize/producers/references.d.ts +53 -0
- package/dist/semantics/normalize/producers/references.js +1027 -0
- package/dist/semantics/normalize/producers/shared.d.ts +561 -0
- package/dist/semantics/normalize/producers/shared.js +1683 -0
- package/dist/semantics/normalize/producers/spread-arguments.d.ts +72 -0
- package/dist/semantics/normalize/producers/spread-arguments.js +375 -0
- package/dist/semantics/normalize/producers/tagged-template.d.ts +5 -0
- package/dist/semantics/normalize/producers/tagged-template.js +307 -0
- package/dist/semantics/normalize/producers/tuple-spread.d.ts +189 -0
- package/dist/semantics/normalize/producers/tuple-spread.js +279 -0
- package/dist/semantics/normalize/property-key-domain.d.ts +36 -0
- package/dist/semantics/normalize/property-key-domain.js +150 -0
- package/dist/semantics/normalize/reachability.d.ts +189 -0
- package/dist/semantics/normalize/reachability.js +1057 -0
- package/dist/semantics/normalize/reassigned-bindings.d.ts +13 -0
- package/dist/semantics/normalize/reassigned-bindings.js +41 -0
- package/dist/semantics/normalize/record-storage-families.d.ts +11 -0
- package/dist/semantics/normalize/record-storage-families.js +109 -0
- package/dist/semantics/normalize/return-bindings.d.ts +260 -0
- package/dist/semantics/normalize/return-bindings.js +1311 -0
- package/dist/semantics/normalize/return-paths.d.ts +2 -0
- package/dist/semantics/normalize/return-paths.js +28 -0
- package/dist/semantics/normalize/script-global-redefinition.d.ts +44 -0
- package/dist/semantics/normalize/script-global-redefinition.js +75 -0
- package/dist/semantics/normalize/specialization.d.ts +201 -0
- package/dist/semantics/normalize/specialization.js +1824 -0
- package/dist/semantics/normalize/structural-array-element.d.ts +176 -0
- package/dist/semantics/normalize/structural-array-element.js +700 -0
- package/dist/semantics/normalize/structural-array-read.d.ts +13 -0
- package/dist/semantics/normalize/structural-array-read.js +124 -0
- package/dist/semantics/normalize/structural-callable.d.ts +12 -0
- package/dist/semantics/normalize/structural-callable.js +82 -0
- package/dist/semantics/normalize/structural-creation-order.d.ts +32 -0
- package/dist/semantics/normalize/structural-creation-order.js +111 -0
- package/dist/semantics/normalize/structural-declarations.d.ts +395 -0
- package/dist/semantics/normalize/structural-declarations.js +968 -0
- package/dist/semantics/normalize/structural-declared-body.d.ts +25 -0
- package/dist/semantics/normalize/structural-declared-body.js +147 -0
- package/dist/semantics/normalize/structural-generics.d.ts +56 -0
- package/dist/semantics/normalize/structural-generics.js +120 -0
- package/dist/semantics/normalize/structural-indexed-access.d.ts +11 -0
- package/dist/semantics/normalize/structural-indexed-access.js +126 -0
- package/dist/semantics/normalize/structural-instantiated-member.d.ts +64 -0
- package/dist/semantics/normalize/structural-instantiated-member.js +407 -0
- package/dist/semantics/normalize/structural-joins.d.ts +44 -0
- package/dist/semantics/normalize/structural-joins.js +143 -0
- package/dist/semantics/normalize/structural-layout-relevance.d.ts +29 -0
- package/dist/semantics/normalize/structural-layout-relevance.js +391 -0
- package/dist/semantics/normalize/structural-layout-type.d.ts +11 -0
- package/dist/semantics/normalize/structural-layout-type.js +1468 -0
- package/dist/semantics/normalize/structural-leaves.d.ts +49 -0
- package/dist/semantics/normalize/structural-leaves.js +125 -0
- package/dist/semantics/normalize/structural-local-union.d.ts +13 -0
- package/dist/semantics/normalize/structural-local-union.js +133 -0
- package/dist/semantics/normalize/structural-members.d.ts +26 -0
- package/dist/semantics/normalize/structural-members.js +84 -0
- package/dist/semantics/normalize/structural-mutable-method.d.ts +15 -0
- package/dist/semantics/normalize/structural-mutable-method.js +109 -0
- package/dist/semantics/normalize/structural-parts.d.ts +131 -0
- package/dist/semantics/normalize/structural-parts.js +737 -0
- package/dist/semantics/normalize/structural-receiver.d.ts +66 -0
- package/dist/semantics/normalize/structural-receiver.js +551 -0
- package/dist/semantics/normalize/structural-rules.d.ts +112 -0
- package/dist/semantics/normalize/structural-rules.js +93 -0
- package/dist/semantics/normalize/structural-self-reference.d.ts +150 -0
- package/dist/semantics/normalize/structural-self-reference.js +494 -0
- package/dist/semantics/normalize/structural.d.ts +202 -0
- package/dist/semantics/normalize/structural.js +4218 -0
- package/dist/semantics/normalize/unreduced-type-form.d.ts +41 -0
- package/dist/semantics/normalize/unreduced-type-form.js +53 -0
- package/dist/semantics/normalize/unresolvable-names.d.ts +56 -0
- package/dist/semantics/normalize/unresolvable-names.js +140 -0
- package/dist/semantics/package-sources.d.ts +16 -0
- package/dist/semantics/package-sources.js +365 -0
- package/dist/semantics/program.d.ts +151 -0
- package/dist/semantics/program.js +667 -0
- package/dist/semantics/prototype-install-source-transform.d.ts +4 -0
- package/dist/semantics/prototype-install-source-transform.js +341 -0
- package/dist/semantics/prototype-object-class-source-transform.d.ts +4 -0
- package/dist/semantics/prototype-object-class-source-transform.js +525 -0
- package/dist/semantics/prototype-reparenting.d.ts +50 -0
- package/dist/semantics/prototype-reparenting.js +317 -0
- package/dist/semantics/stable-checker.d.ts +10 -0
- package/dist/semantics/stable-checker.js +148 -0
- package/dist/semantics/subclass-member-overlay-transform.d.ts +35 -0
- package/dist/semantics/subclass-member-overlay-transform.js +1418 -0
- package/dist/semantics/symbol-keyed-expando-source-transform.d.ts +4 -0
- package/dist/semantics/symbol-keyed-expando-source-transform.js +66 -0
- package/dist/semantics/this-constructor-source-transform.d.ts +4 -0
- package/dist/semantics/this-constructor-source-transform.js +122 -0
- package/dist/semantics/uninstantiable-classes.d.ts +22 -0
- package/dist/semantics/uninstantiable-classes.js +75 -0
- package/dist/targets/cpp/balanced-units.d.ts +3 -0
- package/dist/targets/cpp/balanced-units.js +58 -0
- package/dist/targets/cpp/borrowed-call-entry.d.ts +30 -0
- package/dist/targets/cpp/borrowed-call-entry.js +68 -0
- package/dist/targets/cpp/captures.d.ts +68 -0
- package/dist/targets/cpp/captures.js +269 -0
- package/dist/targets/cpp/class-layout.d.ts +313 -0
- package/dist/targets/cpp/class-layout.js +483 -0
- package/dist/targets/cpp/class-properties/computed-method-value.d.ts +25 -0
- package/dist/targets/cpp/class-properties/computed-method-value.js +22 -0
- package/dist/targets/cpp/class-properties/emit-class-properties.d.ts +216 -0
- package/dist/targets/cpp/class-properties/emit-class-properties.js +917 -0
- package/dist/targets/cpp/class-properties/native-prototype.d.ts +11 -0
- package/dist/targets/cpp/class-properties/native-prototype.js +101 -0
- package/dist/targets/cpp/class-ref-transport.d.ts +12 -0
- package/dist/targets/cpp/class-ref-transport.js +32 -0
- package/dist/targets/cpp/conversions.d.ts +3 -0
- package/dist/targets/cpp/conversions.js +2027 -0
- package/dist/targets/cpp/deferral-safety.d.ts +82 -0
- package/dist/targets/cpp/deferral-safety.js +86 -0
- package/dist/targets/cpp/direct-call-receivers.d.ts +37 -0
- package/dist/targets/cpp/direct-call-receivers.js +79 -0
- package/dist/targets/cpp/document.d.ts +74 -0
- package/dist/targets/cpp/document.js +106 -0
- package/dist/targets/cpp/emit-allocation.d.ts +60 -0
- package/dist/targets/cpp/emit-allocation.js +573 -0
- package/dist/targets/cpp/emit-arrays.d.ts +119 -0
- package/dist/targets/cpp/emit-arrays.js +1047 -0
- package/dist/targets/cpp/emit-binding-reference.d.ts +17 -0
- package/dist/targets/cpp/emit-binding-reference.js +120 -0
- package/dist/targets/cpp/emit-bindings.d.ts +158 -0
- package/dist/targets/cpp/emit-bindings.js +769 -0
- package/dist/targets/cpp/emit-buffers.d.ts +156 -0
- package/dist/targets/cpp/emit-buffers.js +573 -0
- package/dist/targets/cpp/emit-callable.d.ts +230 -0
- package/dist/targets/cpp/emit-callable.js +2154 -0
- package/dist/targets/cpp/emit-carrier-members.d.ts +406 -0
- package/dist/targets/cpp/emit-carrier-members.js +1224 -0
- package/dist/targets/cpp/emit-coercion.d.ts +26 -0
- package/dist/targets/cpp/emit-coercion.js +39 -0
- package/dist/targets/cpp/emit-context.d.ts +1882 -0
- package/dist/targets/cpp/emit-context.js +904 -0
- package/dist/targets/cpp/emit-dynamic-properties.d.ts +174 -0
- package/dist/targets/cpp/emit-dynamic-properties.js +1249 -0
- package/dist/targets/cpp/emit-equality.d.ts +39 -0
- package/dist/targets/cpp/emit-equality.js +472 -0
- package/dist/targets/cpp/emit-exceptions.d.ts +104 -0
- package/dist/targets/cpp/emit-exceptions.js +513 -0
- package/dist/targets/cpp/emit-field-owner.d.ts +4 -0
- package/dist/targets/cpp/emit-field-owner.js +27 -0
- package/dist/targets/cpp/emit-in.d.ts +31 -0
- package/dist/targets/cpp/emit-in.js +426 -0
- package/dist/targets/cpp/emit-instanceof.d.ts +19 -0
- package/dist/targets/cpp/emit-instanceof.js +601 -0
- package/dist/targets/cpp/emit-integers.d.ts +68 -0
- package/dist/targets/cpp/emit-integers.js +184 -0
- package/dist/targets/cpp/emit-iterator.d.ts +100 -0
- package/dist/targets/cpp/emit-iterator.js +1137 -0
- package/dist/targets/cpp/emit-json.d.ts +73 -0
- package/dist/targets/cpp/emit-json.js +823 -0
- package/dist/targets/cpp/emit-jsx.d.ts +74 -0
- package/dist/targets/cpp/emit-jsx.js +806 -0
- package/dist/targets/cpp/emit-mixed-binary.d.ts +51 -0
- package/dist/targets/cpp/emit-mixed-binary.js +60 -0
- package/dist/targets/cpp/emit-namespaces.d.ts +101 -0
- package/dist/targets/cpp/emit-namespaces.js +133 -0
- package/dist/targets/cpp/emit-narrowing.d.ts +738 -0
- package/dist/targets/cpp/emit-narrowing.js +3967 -0
- package/dist/targets/cpp/emit-native-equality.d.ts +3 -0
- package/dist/targets/cpp/emit-native-equality.js +14 -0
- package/dist/targets/cpp/emit-native-selection.d.ts +5 -0
- package/dist/targets/cpp/emit-native-selection.js +37 -0
- package/dist/targets/cpp/emit-object-tag.d.ts +4 -0
- package/dist/targets/cpp/emit-object-tag.js +108 -0
- package/dist/targets/cpp/emit-owned-record.d.ts +2 -0
- package/dist/targets/cpp/emit-owned-record.js +15 -0
- package/dist/targets/cpp/emit-presence.d.ts +78 -0
- package/dist/targets/cpp/emit-presence.js +376 -0
- package/dist/targets/cpp/emit-properties.d.ts +105 -0
- package/dist/targets/cpp/emit-properties.js +1640 -0
- package/dist/targets/cpp/emit-record-view.d.ts +20 -0
- package/dist/targets/cpp/emit-record-view.js +354 -0
- package/dist/targets/cpp/emit-return.d.ts +5 -0
- package/dist/targets/cpp/emit-return.js +237 -0
- package/dist/targets/cpp/emit-sum-widening.d.ts +10 -0
- package/dist/targets/cpp/emit-sum-widening.js +69 -0
- package/dist/targets/cpp/emit-tonumber.d.ts +38 -0
- package/dist/targets/cpp/emit-tonumber.js +177 -0
- package/dist/targets/cpp/emit-tostring.d.ts +92 -0
- package/dist/targets/cpp/emit-tostring.js +556 -0
- package/dist/targets/cpp/emit-typeof.d.ts +49 -0
- package/dist/targets/cpp/emit-typeof.js +317 -0
- package/dist/targets/cpp/emit-union-properties.d.ts +181 -0
- package/dist/targets/cpp/emit-union-properties.js +1281 -0
- package/dist/targets/cpp/emit.d.ts +45 -0
- package/dist/targets/cpp/emit.js +2225 -0
- package/dist/targets/cpp/error-types.d.ts +4 -0
- package/dist/targets/cpp/error-types.js +11 -0
- package/dist/targets/cpp/function-source-reads.d.ts +72 -0
- package/dist/targets/cpp/function-source-reads.js +148 -0
- package/dist/targets/cpp/host/atomics.d.ts +25 -0
- package/dist/targets/cpp/host/atomics.js +63 -0
- package/dist/targets/cpp/host/core-globals.d.ts +108 -0
- package/dist/targets/cpp/host/core-globals.js +158 -0
- package/dist/targets/cpp/host/dynamic-argument-members.d.ts +42 -0
- package/dist/targets/cpp/host/dynamic-argument-members.js +61 -0
- package/dist/targets/cpp/host/emit-host-arity.d.ts +139 -0
- package/dist/targets/cpp/host/emit-host-arity.js +232 -0
- package/dist/targets/cpp/host/emit-host-invoke.d.ts +91 -0
- package/dist/targets/cpp/host/emit-host-invoke.js +1105 -0
- package/dist/targets/cpp/host/emit-host-object.d.ts +55 -0
- package/dist/targets/cpp/host/emit-host-object.js +2206 -0
- package/dist/targets/cpp/host/emit-host-properties.d.ts +69 -0
- package/dist/targets/cpp/host/emit-host-properties.js +533 -0
- package/dist/targets/cpp/host/emit-host-reflect.d.ts +4 -0
- package/dist/targets/cpp/host/emit-host-reflect.js +180 -0
- package/dist/targets/cpp/host/emit-host-value.d.ts +120 -0
- package/dist/targets/cpp/host/emit-host-value.js +392 -0
- package/dist/targets/cpp/host/host-members.d.ts +505 -0
- package/dist/targets/cpp/host/host-members.js +819 -0
- package/dist/targets/cpp/host/host-method-aliases.d.ts +30 -0
- package/dist/targets/cpp/host/host-method-aliases.js +76 -0
- package/dist/targets/cpp/host/native-protocols.d.ts +47 -0
- package/dist/targets/cpp/host/native-protocols.js +183 -0
- package/dist/targets/cpp/host/object-protocol.d.ts +351 -0
- package/dist/targets/cpp/host/object-protocol.js +671 -0
- package/dist/targets/cpp/host-namespace-reads.d.ts +83 -0
- package/dist/targets/cpp/host-namespace-reads.js +113 -0
- package/dist/targets/cpp/manifest/capabilities.d.ts +39 -0
- package/dist/targets/cpp/manifest/capabilities.js +1484 -0
- package/dist/targets/cpp/manifest.d.ts +23 -0
- package/dist/targets/cpp/manifest.js +113 -0
- package/dist/targets/cpp/native-error-base.d.ts +38 -0
- package/dist/targets/cpp/native-error-base.js +74 -0
- package/dist/targets/cpp/native-narrowing-transport.d.ts +12 -0
- package/dist/targets/cpp/native-narrowing-transport.js +151 -0
- package/dist/targets/cpp/native-selection-helpers.d.ts +11 -0
- package/dist/targets/cpp/native-selection-helpers.js +46 -0
- package/dist/targets/cpp/native-symbol-keys.d.ts +8 -0
- package/dist/targets/cpp/native-symbol-keys.js +34 -0
- package/dist/targets/cpp/ownership.d.ts +43 -0
- package/dist/targets/cpp/ownership.js +38 -0
- package/dist/targets/cpp/owning-conversion-input.d.ts +14 -0
- package/dist/targets/cpp/owning-conversion-input.js +12 -0
- package/dist/targets/cpp/property-read-claims.d.ts +62 -0
- package/dist/targets/cpp/property-read-claims.js +23 -0
- package/dist/targets/cpp/property-store-claims.d.ts +62 -0
- package/dist/targets/cpp/property-store-claims.js +26 -0
- package/dist/targets/cpp/prototype/emit-prototype-array.d.ts +111 -0
- package/dist/targets/cpp/prototype/emit-prototype-array.js +602 -0
- package/dist/targets/cpp/prototype/emit-prototype-date.d.ts +133 -0
- package/dist/targets/cpp/prototype/emit-prototype-date.js +515 -0
- package/dist/targets/cpp/prototype/emit-prototype-error.d.ts +13 -0
- package/dist/targets/cpp/prototype/emit-prototype-error.js +54 -0
- package/dist/targets/cpp/prototype/emit-prototype-invoke.d.ts +34 -0
- package/dist/targets/cpp/prototype/emit-prototype-invoke.js +1003 -0
- package/dist/targets/cpp/prototype/emit-prototype-iterator.d.ts +47 -0
- package/dist/targets/cpp/prototype/emit-prototype-iterator.js +250 -0
- package/dist/targets/cpp/prototype/emit-prototype-promise.d.ts +46 -0
- package/dist/targets/cpp/prototype/emit-prototype-promise.js +143 -0
- package/dist/targets/cpp/prototype/emit-prototype-regexp.d.ts +335 -0
- package/dist/targets/cpp/prototype/emit-prototype-regexp.js +853 -0
- package/dist/targets/cpp/prototype/emit-prototype-string.d.ts +42 -0
- package/dist/targets/cpp/prototype/emit-prototype-string.js +252 -0
- package/dist/targets/cpp/prototype/prototype-method-reads.d.ts +25 -0
- package/dist/targets/cpp/prototype/prototype-method-reads.js +182 -0
- package/dist/targets/cpp/reactive-dependencies.d.ts +140 -0
- package/dist/targets/cpp/reactive-dependencies.js +432 -0
- package/dist/targets/cpp/reactive-origins.d.ts +44 -0
- package/dist/targets/cpp/reactive-origins.js +82 -0
- package/dist/targets/cpp/records.d.ts +277 -0
- package/dist/targets/cpp/records.js +2427 -0
- package/dist/targets/cpp/recursive-containers.d.ts +43 -0
- package/dist/targets/cpp/recursive-containers.js +144 -0
- package/dist/targets/cpp/regexp-types.d.ts +56 -0
- package/dist/targets/cpp/regexp-types.js +59 -0
- package/dist/targets/cpp/substrate.d.ts +125 -0
- package/dist/targets/cpp/substrate.js +12 -0
- package/dist/targets/cpp/translation-unit.d.ts +219 -0
- package/dist/targets/cpp/translation-unit.js +2063 -0
- package/dist/targets/cpp/types.d.ts +280 -0
- package/dist/targets/cpp/types.js +1135 -0
- package/dist/targets/cpp/virtual-methods.d.ts +95 -0
- package/dist/targets/cpp/virtual-methods.js +264 -0
- package/package.json +95 -0
- package/src/targets/cpp/runtime/gea_dynamic_proxy.h +824 -0
- package/src/targets/cpp/runtime/gea_eval.h +1376 -0
- package/src/targets/cpp/runtime/gea_native_class_prototype.h +44 -0
- package/src/targets/cpp/runtime/gea_runtime.h +29222 -0
- package/src/targets/cpp/runtime/gea_runtime_builtins.cpp +55 -0
|
@@ -0,0 +1,2157 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import { existsSync, readFileSync } from 'fs';
|
|
3
|
+
import { basename, dirname, join, relative, resolve, sep } from 'path';
|
|
4
|
+
/**
|
|
5
|
+
* Names a JSDoc type may use without anything having to bring them into
|
|
6
|
+
* scope. Everything else must be traceable to an import this overlay emits,
|
|
7
|
+
* or the field is refused -- a `@type` naming something unresolvable is worse
|
|
8
|
+
* than no annotation at all, because `withJsDocTypeNames` sits OUTERMOST in
|
|
9
|
+
* the composed census and a stated type outranks the one the census would
|
|
10
|
+
* otherwise have derived from the call site.
|
|
11
|
+
*/
|
|
12
|
+
const AMBIENT_TYPE_NAMES = new Set([
|
|
13
|
+
'any',
|
|
14
|
+
'bigint',
|
|
15
|
+
'boolean',
|
|
16
|
+
'false',
|
|
17
|
+
'never',
|
|
18
|
+
'null',
|
|
19
|
+
'number',
|
|
20
|
+
'object',
|
|
21
|
+
'string',
|
|
22
|
+
'symbol',
|
|
23
|
+
'true',
|
|
24
|
+
'undefined',
|
|
25
|
+
'unknown',
|
|
26
|
+
'void',
|
|
27
|
+
'this',
|
|
28
|
+
'Array',
|
|
29
|
+
'ArrayBuffer',
|
|
30
|
+
'ArrayBufferLike',
|
|
31
|
+
'ArrayBufferView',
|
|
32
|
+
'ArrayLike',
|
|
33
|
+
'Date',
|
|
34
|
+
'Error',
|
|
35
|
+
'Exclude',
|
|
36
|
+
'Extract',
|
|
37
|
+
'Function',
|
|
38
|
+
'Iterable',
|
|
39
|
+
'IterableIterator',
|
|
40
|
+
'Map',
|
|
41
|
+
'NonNullable',
|
|
42
|
+
'Object',
|
|
43
|
+
'Omit',
|
|
44
|
+
'Partial',
|
|
45
|
+
'Pick',
|
|
46
|
+
'Promise',
|
|
47
|
+
'Readonly',
|
|
48
|
+
'ReadonlyArray',
|
|
49
|
+
'ReadonlyMap',
|
|
50
|
+
'ReadonlySet',
|
|
51
|
+
'Record',
|
|
52
|
+
'RegExp',
|
|
53
|
+
'Required',
|
|
54
|
+
'Set',
|
|
55
|
+
'WeakMap',
|
|
56
|
+
'WeakSet',
|
|
57
|
+
'Int8Array',
|
|
58
|
+
'Uint8Array',
|
|
59
|
+
'Uint8ClampedArray',
|
|
60
|
+
'Int16Array',
|
|
61
|
+
'Uint16Array',
|
|
62
|
+
'Int32Array',
|
|
63
|
+
'Uint32Array',
|
|
64
|
+
'Float32Array',
|
|
65
|
+
'Float64Array',
|
|
66
|
+
'BigInt64Array',
|
|
67
|
+
'BigUint64Array'
|
|
68
|
+
]);
|
|
69
|
+
/** Every type name a type's text refers to, by parsing it rather than scanning it. */
|
|
70
|
+
const typeNamesIn = (text) => {
|
|
71
|
+
const probe = ts.createSourceFile('__type.ts', `type __Probe = ${text};`, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
72
|
+
if (probe.statements.length !== 1)
|
|
73
|
+
return null;
|
|
74
|
+
const names = [];
|
|
75
|
+
const leftmost = (name) => (ts.isIdentifier(name) ? name : leftmost(name.left));
|
|
76
|
+
const walk = (node) => {
|
|
77
|
+
if (ts.isTypeReferenceNode(node))
|
|
78
|
+
names.push(leftmost(node.typeName).text);
|
|
79
|
+
// `typeof AlphaFormat` names a VALUE, and a value needs bringing into
|
|
80
|
+
// scope exactly as a type does -- three's `PixelFormat` is a union of
|
|
81
|
+
// eleven of them.
|
|
82
|
+
if (ts.isTypeQueryNode(node))
|
|
83
|
+
names.push(leftmost(node.exprName).text);
|
|
84
|
+
if (ts.isImportTypeNode(node))
|
|
85
|
+
return;
|
|
86
|
+
ts.forEachChild(node, walk);
|
|
87
|
+
};
|
|
88
|
+
walk(probe.statements[0]);
|
|
89
|
+
return names;
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* A class's type arguments as the JS class itself means them.
|
|
93
|
+
*
|
|
94
|
+
* `class BufferGeometry<Attributes extends NormalOrGLBufferAttributes =
|
|
95
|
+
* NormalBufferAttributes>` describes a JS class that has no type parameters at
|
|
96
|
+
* all, so the only faithful reading of `attributes: Attributes` for that JS is
|
|
97
|
+
* the declaration file's OWN stated default. Substituting it is transferring
|
|
98
|
+
* shipped data, not inventing a type. A parameter with no default has no such
|
|
99
|
+
* reading, and every field mentioning it is refused.
|
|
100
|
+
*/
|
|
101
|
+
const typeArgumentDefaults = (owner, file) => {
|
|
102
|
+
const defaults = new Map();
|
|
103
|
+
for (const parameter of owner.typeParameters ?? []) {
|
|
104
|
+
defaults.set(parameter.name.text, parameter.default ? parameter.default.getText(file).replace(/\s+/g, ' ') : null);
|
|
105
|
+
}
|
|
106
|
+
return defaults;
|
|
107
|
+
};
|
|
108
|
+
const overlayCache = new Map();
|
|
109
|
+
/**
|
|
110
|
+
* The modules a JS file imports at RUNTIME, as absolute paths.
|
|
111
|
+
*
|
|
112
|
+
* Only relative specifiers are followed: a bare specifier leaves the package,
|
|
113
|
+
* and nothing this module reasons about crosses that line.
|
|
114
|
+
*/
|
|
115
|
+
const runtimeImportCache = new Map();
|
|
116
|
+
const runtimeImportsOf = (fileName) => {
|
|
117
|
+
const cached = runtimeImportCache.get(fileName);
|
|
118
|
+
if (cached)
|
|
119
|
+
return cached;
|
|
120
|
+
let targets = [];
|
|
121
|
+
try {
|
|
122
|
+
const info = ts.preProcessFile(readFileSync(fileName, 'utf8'), true, true);
|
|
123
|
+
targets = info.importedFiles
|
|
124
|
+
.map((imported) => imported.fileName)
|
|
125
|
+
.filter((specifier) => specifier.startsWith('.'))
|
|
126
|
+
.map((specifier) => resolve(dirname(fileName), specifier))
|
|
127
|
+
.filter((path) => existsSync(path));
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
targets = [];
|
|
131
|
+
}
|
|
132
|
+
runtimeImportCache.set(fileName, targets);
|
|
133
|
+
return targets;
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* The names a JS module exports as a FACTORY: a plain function that builds and
|
|
137
|
+
* RETURNS an object, rather than a class or a constructor assigning to `this`.
|
|
138
|
+
*
|
|
139
|
+
* three's renderer modules are written this way -- `function WebGLState( gl,
|
|
140
|
+
* extensions ) { ...; return { buffers, ... } }` -- while `@types/three`
|
|
141
|
+
* declares each as a CLASS. So the declaration file's `state: WebGLState` and
|
|
142
|
+
* the JS module's `WebGLState` do not denote the same thing: transferred
|
|
143
|
+
* verbatim, the tag resolves to the FACTORY'S OWN SIGNATURE, and a parameter
|
|
144
|
+
* holding a state object is typed as the function that makes one. 31
|
|
145
|
+
* parameters land this way in the three.js app, 462 boxed carriers behind them, and
|
|
146
|
+
* `WebGLState` alone is 216.
|
|
147
|
+
*
|
|
148
|
+
* What the JS means by "a WebGLState" is what calling `WebGLState` yields, and
|
|
149
|
+
* that is `ReturnType<WebGLState>` -- the tag already denotes the function
|
|
150
|
+
* type, so no `typeof` is needed, which matters because `@import` binds a
|
|
151
|
+
* type, not a value.
|
|
152
|
+
*
|
|
153
|
+
* ⛔ Only the pure `return` shape qualifies. A function that assigns to `this`
|
|
154
|
+
* is one TypeScript already reads as a constructor, and its instance type is
|
|
155
|
+
* NOT its return type; 30 of the 31 measured are pure, and the rule refuses
|
|
156
|
+
* the rest rather than guessing between the two.
|
|
157
|
+
*/
|
|
158
|
+
const factoryCache = new Map();
|
|
159
|
+
const factoryExportsOf = (fileName) => {
|
|
160
|
+
const cached = factoryCache.get(fileName);
|
|
161
|
+
if (cached)
|
|
162
|
+
return cached;
|
|
163
|
+
const names = new Set();
|
|
164
|
+
try {
|
|
165
|
+
const file = ts.createSourceFile(fileName, readFileSync(fileName, 'utf8'), ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
|
|
166
|
+
for (const statement of file.statements) {
|
|
167
|
+
if (!ts.isFunctionDeclaration(statement) || !statement.name || !statement.body)
|
|
168
|
+
continue;
|
|
169
|
+
let assignsThis = false;
|
|
170
|
+
const seek = (node) => {
|
|
171
|
+
if (assignsThis)
|
|
172
|
+
return;
|
|
173
|
+
if (ts.isBinaryExpression(node) &&
|
|
174
|
+
node.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
175
|
+
ts.isPropertyAccessExpression(node.left) &&
|
|
176
|
+
node.left.expression.kind === ts.SyntaxKind.ThisKeyword) {
|
|
177
|
+
assignsThis = true;
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
ts.forEachChild(node, seek);
|
|
181
|
+
};
|
|
182
|
+
seek(statement.body);
|
|
183
|
+
if (assignsThis)
|
|
184
|
+
continue;
|
|
185
|
+
if (!statement.body.statements.some((inner) => ts.isReturnStatement(inner) && inner.expression !== undefined))
|
|
186
|
+
continue;
|
|
187
|
+
names.add(statement.name.text);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
/* an unreadable module exports nothing this rule can use */
|
|
192
|
+
}
|
|
193
|
+
factoryCache.set(fileName, names);
|
|
194
|
+
return names;
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* The names a JS module actually exports.
|
|
198
|
+
*
|
|
199
|
+
* A declaration file's import is not evidence that the mirrored JS module has
|
|
200
|
+
* anything by that name: `WebGLUtils.d.ts` reaches `PixelFormat` through
|
|
201
|
+
* `"../../constants.js"`, and `three/src/constants.js` exports two hundred
|
|
202
|
+
* numeric constants and no types at all, because `PixelFormat` exists only in
|
|
203
|
+
* the declaration tree. Writing `@import { PixelFormat } from
|
|
204
|
+
* "../../constants.js"` into the JS therefore imports NOTHING, and every
|
|
205
|
+
* annotation naming it resolves to `any` -- measured, 47 of the 307 names this
|
|
206
|
+
* overlay was importing were of that kind.
|
|
207
|
+
*/
|
|
208
|
+
const jsExportCache = new Map();
|
|
209
|
+
const jsExportsOf = (fileName, depth = 0) => {
|
|
210
|
+
const cached = jsExportCache.get(fileName);
|
|
211
|
+
if (cached)
|
|
212
|
+
return cached;
|
|
213
|
+
const names = new Set();
|
|
214
|
+
jsExportCache.set(fileName, names);
|
|
215
|
+
if (depth > 4 || !existsSync(fileName))
|
|
216
|
+
return names;
|
|
217
|
+
let file;
|
|
218
|
+
try {
|
|
219
|
+
file = ts.createSourceFile(fileName, readFileSync(fileName, 'utf8'), ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
return names;
|
|
223
|
+
}
|
|
224
|
+
const exported = (node) => ts.canHaveModifiers(node) && (ts.getModifiers(node) ?? []).some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword);
|
|
225
|
+
for (const statement of file.statements) {
|
|
226
|
+
if (ts.isVariableStatement(statement) && exported(statement)) {
|
|
227
|
+
for (const declaration of statement.declarationList.declarations)
|
|
228
|
+
if (ts.isIdentifier(declaration.name))
|
|
229
|
+
names.add(declaration.name.text);
|
|
230
|
+
}
|
|
231
|
+
else if ((ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) && exported(statement)) {
|
|
232
|
+
if (statement.name)
|
|
233
|
+
names.add(statement.name.text);
|
|
234
|
+
}
|
|
235
|
+
else if (ts.isExportDeclaration(statement)) {
|
|
236
|
+
const clause = statement.exportClause;
|
|
237
|
+
if (clause && ts.isNamedExports(clause)) {
|
|
238
|
+
for (const element of clause.elements)
|
|
239
|
+
names.add(element.name.text);
|
|
240
|
+
}
|
|
241
|
+
else if (!clause && statement.moduleSpecifier && ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
242
|
+
// `export * from './Three.Core.js'` -- the names are the target's.
|
|
243
|
+
const text = statement.moduleSpecifier.text;
|
|
244
|
+
if (text.startsWith('.'))
|
|
245
|
+
for (const name of jsExportsOf(resolve(dirname(fileName), text), depth + 1))
|
|
246
|
+
names.add(name);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return names;
|
|
251
|
+
};
|
|
252
|
+
/**
|
|
253
|
+
* Whether `from` reaches `target` through runtime imports.
|
|
254
|
+
*
|
|
255
|
+
* ⛔ THE guard on every `@import` this module writes. An `@import` is a real
|
|
256
|
+
* module EDGE, and three's runtime graph is carefully acyclic. Adding an edge
|
|
257
|
+
* that points back at the file adding it closes a cycle -- `WebXRManager.js`
|
|
258
|
+
* naming `../WebGLRenderer.js` closes one through the renderer hub -- and the
|
|
259
|
+
* checker then answers `any` for every symbol caught in it. Measured on
|
|
260
|
+
* the three.js app: unguarded, boxes fall by 2099 and OPERATIONS by 2294, nearly one
|
|
261
|
+
* for one, because the code stopped being censused rather than started being
|
|
262
|
+
* typed, and withheld producers go 8 -> 21.
|
|
263
|
+
*
|
|
264
|
+
* Fail-closed: an unreadable file contributes no edges, so a specifier whose
|
|
265
|
+
* module cannot be read is refused by the caller rather than assumed safe.
|
|
266
|
+
*/
|
|
267
|
+
const reachabilityCache = new Map();
|
|
268
|
+
const modulesReachableFrom = (start) => {
|
|
269
|
+
const cached = reachabilityCache.get(start);
|
|
270
|
+
if (cached)
|
|
271
|
+
return cached;
|
|
272
|
+
const seen = new Set();
|
|
273
|
+
const queue = [start];
|
|
274
|
+
while (queue.length > 0) {
|
|
275
|
+
const current = queue.shift();
|
|
276
|
+
if (current === undefined)
|
|
277
|
+
break;
|
|
278
|
+
for (const next of runtimeImportsOf(current)) {
|
|
279
|
+
if (seen.has(next))
|
|
280
|
+
continue;
|
|
281
|
+
seen.add(next);
|
|
282
|
+
queue.push(next);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
reachabilityCache.set(start, seen);
|
|
286
|
+
return seen;
|
|
287
|
+
};
|
|
288
|
+
/** The declaration file mirroring this source file, or `null`. */
|
|
289
|
+
const declarationPathFor = (fileName) => {
|
|
290
|
+
const marker = '/node_modules/';
|
|
291
|
+
const at = fileName.lastIndexOf(marker);
|
|
292
|
+
if (at < 0)
|
|
293
|
+
return null;
|
|
294
|
+
const modules = fileName.slice(0, at + marker.length);
|
|
295
|
+
const rest = fileName.slice(at + marker.length);
|
|
296
|
+
const scoped = rest.startsWith('@');
|
|
297
|
+
const parts = rest.split('/');
|
|
298
|
+
const packageName = scoped ? `${parts[0] ?? ''}/${parts[1] ?? ''}` : (parts[0] ?? '');
|
|
299
|
+
if (!packageName || packageName.startsWith('@types/'))
|
|
300
|
+
return null;
|
|
301
|
+
const relative = rest.slice(packageName.length + 1);
|
|
302
|
+
const typesName = scoped ? `@types/${packageName.slice(1).replace('/', '__')}` : `@types/${packageName}`;
|
|
303
|
+
const candidate = join(modules, typesName, relative.replace(/\.m?js$/, '.d.ts'));
|
|
304
|
+
return existsSync(candidate) ? candidate : null;
|
|
305
|
+
};
|
|
306
|
+
const nameOf = (node) => {
|
|
307
|
+
const named = node;
|
|
308
|
+
const name = named.name;
|
|
309
|
+
if (!name)
|
|
310
|
+
return null;
|
|
311
|
+
if (ts.isIdentifier(name) || ts.isStringLiteral(name))
|
|
312
|
+
return name.text;
|
|
313
|
+
return null;
|
|
314
|
+
};
|
|
315
|
+
/** Accessors need both their owner and side: a getter and setter may declare different types. */
|
|
316
|
+
const accessorKey = (node) => {
|
|
317
|
+
const owner = node.parent;
|
|
318
|
+
if (!ts.isClassDeclaration(owner) || !owner.name || !ts.isSourceFile(owner.parent))
|
|
319
|
+
return null;
|
|
320
|
+
// A generic declaration needs its type arguments instantiated before it can
|
|
321
|
+
// annotate a JS body. Do not publish an unbound type parameter as evidence.
|
|
322
|
+
if (owner.typeParameters?.length)
|
|
323
|
+
return null;
|
|
324
|
+
const name = nameOf(node);
|
|
325
|
+
if (name === null)
|
|
326
|
+
return null;
|
|
327
|
+
const placement = node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.StaticKeyword) ? 'static' : 'instance';
|
|
328
|
+
return JSON.stringify([owner.name.text, placement, name, ts.isGetAccessorDeclaration(node) ? 'get' : 'set']);
|
|
329
|
+
};
|
|
330
|
+
const declaredNamesIn = (file) => {
|
|
331
|
+
const names = new Set();
|
|
332
|
+
for (const statement of file.statements) {
|
|
333
|
+
if ((ts.isClassDeclaration(statement) ||
|
|
334
|
+
ts.isInterfaceDeclaration(statement) ||
|
|
335
|
+
ts.isTypeAliasDeclaration(statement) ||
|
|
336
|
+
ts.isEnumDeclaration(statement)) &&
|
|
337
|
+
statement.name)
|
|
338
|
+
names.add(statement.name.text);
|
|
339
|
+
}
|
|
340
|
+
return names;
|
|
341
|
+
};
|
|
342
|
+
const recordSurfaceIn = (file) => {
|
|
343
|
+
const ownerCounts = new Map();
|
|
344
|
+
const generic = new Set();
|
|
345
|
+
const memberCounts = new Map();
|
|
346
|
+
const signatures = new Map();
|
|
347
|
+
const types = new Map();
|
|
348
|
+
const constantCounts = new Map();
|
|
349
|
+
const constants = new Map();
|
|
350
|
+
for (const statement of file.statements) {
|
|
351
|
+
if (ts.isVariableStatement(statement) && statement.declarationList.flags & ts.NodeFlags.Const) {
|
|
352
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
353
|
+
if (!ts.isIdentifier(declaration.name))
|
|
354
|
+
continue;
|
|
355
|
+
const name = declaration.name.text;
|
|
356
|
+
constantCounts.set(name, (constantCounts.get(name) ?? 0) + 1);
|
|
357
|
+
if (declaration.type)
|
|
358
|
+
constants.set(name, declaration.type);
|
|
359
|
+
}
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
if (!(ts.isClassDeclaration(statement) || ts.isInterfaceDeclaration(statement)) || !statement.name)
|
|
363
|
+
continue;
|
|
364
|
+
const owner = statement.name.text;
|
|
365
|
+
ownerCounts.set(owner, (ownerCounts.get(owner) ?? 0) + 1);
|
|
366
|
+
if (statement.typeParameters?.length)
|
|
367
|
+
generic.add(owner);
|
|
368
|
+
for (const member of statement.members) {
|
|
369
|
+
const name = ts.isConstructorDeclaration(member) ? null : nameOf(member);
|
|
370
|
+
if (name === null)
|
|
371
|
+
continue;
|
|
372
|
+
if (ts.canHaveModifiers(member) && ts.getModifiers(member)?.some((modifier) => modifier.kind === ts.SyntaxKind.StaticKeyword))
|
|
373
|
+
continue;
|
|
374
|
+
const key = `${owner}.${name}`;
|
|
375
|
+
memberCounts.set(key, (memberCounts.get(key) ?? 0) + 1);
|
|
376
|
+
if (ts.isMethodDeclaration(member) || ts.isMethodSignature(member))
|
|
377
|
+
signatures.set(key, member);
|
|
378
|
+
else if ((ts.isPropertyDeclaration(member) || ts.isPropertySignature(member)) && member.type) {
|
|
379
|
+
if (ts.isFunctionTypeNode(member.type))
|
|
380
|
+
signatures.set(key, member.type);
|
|
381
|
+
else
|
|
382
|
+
types.set(key, member.type);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
for (const [key, count] of memberCounts) {
|
|
387
|
+
if (count === 1)
|
|
388
|
+
continue;
|
|
389
|
+
signatures.delete(key);
|
|
390
|
+
types.delete(key);
|
|
391
|
+
}
|
|
392
|
+
for (const [name, count] of constantCounts)
|
|
393
|
+
if (count > 1)
|
|
394
|
+
constants.delete(name);
|
|
395
|
+
const owners = new Set([...ownerCounts].filter(([name, count]) => count === 1 && !generic.has(name)).map(([name]) => name));
|
|
396
|
+
return { owners, signatures, types, constants };
|
|
397
|
+
};
|
|
398
|
+
/**
|
|
399
|
+
* `node`'s own surface as an `InterfaceShape`, or `null` if anything about it
|
|
400
|
+
* is not representable as a JSDoc object-literal type.
|
|
401
|
+
*
|
|
402
|
+
* Refused, per measurement rather than taste: a type parameter (the JS module
|
|
403
|
+
* has no way to supply one), an index signature, and a call/method/construct
|
|
404
|
+
* signature (a JSDoc object type has no way to state a call surface). A
|
|
405
|
+
* member with no explicit type, or whose name is not a plain identifier
|
|
406
|
+
* (a computed or string-literal key), refuses the whole interface -- a
|
|
407
|
+
* partial member list would silently understate the shape.
|
|
408
|
+
*/
|
|
409
|
+
const interfaceShapeOf = (node, file) => {
|
|
410
|
+
if (node.typeParameters && node.typeParameters.length > 0)
|
|
411
|
+
return null;
|
|
412
|
+
const members = [];
|
|
413
|
+
for (const member of node.members) {
|
|
414
|
+
if (ts.isIndexSignatureDeclaration(member) || ts.isCallSignatureDeclaration(member) || ts.isConstructSignatureDeclaration(member))
|
|
415
|
+
return null;
|
|
416
|
+
if (ts.isMethodSignature(member))
|
|
417
|
+
return null;
|
|
418
|
+
if (!ts.isPropertySignature(member) || !member.type || !member.name || !ts.isIdentifier(member.name))
|
|
419
|
+
return null;
|
|
420
|
+
const type = statedTypeTextOf(member.type, file);
|
|
421
|
+
if (type.includes('*/'))
|
|
422
|
+
return null;
|
|
423
|
+
members.push({ name: member.name.text, optional: member.questionToken !== undefined, type });
|
|
424
|
+
}
|
|
425
|
+
const extended = [];
|
|
426
|
+
for (const clause of node.heritageClauses ?? []) {
|
|
427
|
+
if (clause.token !== ts.SyntaxKind.ExtendsKeyword)
|
|
428
|
+
continue;
|
|
429
|
+
for (const type of clause.types) {
|
|
430
|
+
// A base named with type arguments (`extends Base<Foo>`) is refused --
|
|
431
|
+
// exactly the same call `typeArgumentDefaults` makes for a class, but an
|
|
432
|
+
// interface's own defaults are not tracked here, and none of the
|
|
433
|
+
// measured targets need it.
|
|
434
|
+
if (!ts.isIdentifier(type.expression) || type.typeArguments)
|
|
435
|
+
return null;
|
|
436
|
+
extended.push(type.expression.text);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
return { members, extends: extended };
|
|
440
|
+
};
|
|
441
|
+
/**
|
|
442
|
+
* A CLASS's own surface, as an `InterfaceShape`, when the class states
|
|
443
|
+
* nothing but plain data.
|
|
444
|
+
*
|
|
445
|
+
* `@types/three` sometimes states a JSON shape as a `class` rather than an
|
|
446
|
+
* `interface` -- `SourceJSON` is two properties and nothing else, even
|
|
447
|
+
* though nothing in three's own JS ever constructs or extends one:
|
|
448
|
+
* `textures/Source.js` exports `Source`, never `SourceJSON`, so no import
|
|
449
|
+
* can reach it, and TypeScript's structural typing means a class used only
|
|
450
|
+
* as an annotation -- never `new`'d, never the target of `instanceof` --
|
|
451
|
+
* means exactly what an interface with the same members would mean. The
|
|
452
|
+
* general rule that "a class is never inlined" still holds for a class that
|
|
453
|
+
* states behavior: a constructor, a method, a static member, or a heritage
|
|
454
|
+
* clause is exactly what turns a name into an IDENTITY rather than a shape,
|
|
455
|
+
* and any of those refuses the whole class here, the same way a disqualifying
|
|
456
|
+
* member refuses an interface in `interfaceShapeOf`.
|
|
457
|
+
*/
|
|
458
|
+
const dataOnlyClassShapeOf = (node, file) => {
|
|
459
|
+
if (!node.name)
|
|
460
|
+
return null;
|
|
461
|
+
if (node.typeParameters && node.typeParameters.length > 0)
|
|
462
|
+
return null;
|
|
463
|
+
if (node.heritageClauses && node.heritageClauses.length > 0)
|
|
464
|
+
return null;
|
|
465
|
+
const members = [];
|
|
466
|
+
for (const member of node.members) {
|
|
467
|
+
if (ts.isConstructorDeclaration(member) ||
|
|
468
|
+
ts.isMethodDeclaration(member) ||
|
|
469
|
+
ts.isGetAccessorDeclaration(member) ||
|
|
470
|
+
ts.isSetAccessorDeclaration(member) ||
|
|
471
|
+
ts.isIndexSignatureDeclaration(member))
|
|
472
|
+
return null;
|
|
473
|
+
if (!ts.isPropertyDeclaration(member) || !member.type || !member.name || !ts.isIdentifier(member.name))
|
|
474
|
+
return null;
|
|
475
|
+
if (member.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.StaticKeyword ||
|
|
476
|
+
modifier.kind === ts.SyntaxKind.PrivateKeyword ||
|
|
477
|
+
modifier.kind === ts.SyntaxKind.ProtectedKeyword))
|
|
478
|
+
return null;
|
|
479
|
+
const type = statedTypeTextOf(member.type, file);
|
|
480
|
+
if (type.includes('*/'))
|
|
481
|
+
return null;
|
|
482
|
+
members.push({ name: member.name.text, optional: member.questionToken !== undefined, type });
|
|
483
|
+
}
|
|
484
|
+
if (members.length === 0)
|
|
485
|
+
return null;
|
|
486
|
+
return { members, extends: [] };
|
|
487
|
+
};
|
|
488
|
+
const declarationFileCache = new Map();
|
|
489
|
+
const readDeclarationFile = (path) => {
|
|
490
|
+
const cached = declarationFileCache.get(path);
|
|
491
|
+
if (cached !== undefined)
|
|
492
|
+
return cached;
|
|
493
|
+
if (!existsSync(path)) {
|
|
494
|
+
declarationFileCache.set(path, null);
|
|
495
|
+
return null;
|
|
496
|
+
}
|
|
497
|
+
const file = ts.createSourceFile(path, readFileSync(path, 'utf8'), ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
498
|
+
const byName = new Map();
|
|
499
|
+
const accessors = new Map();
|
|
500
|
+
const duplicateAccessors = new Set();
|
|
501
|
+
const duplicated = new Set();
|
|
502
|
+
const extended = [];
|
|
503
|
+
const aliases = new Map();
|
|
504
|
+
const interfaces = new Map();
|
|
505
|
+
const add = (key, node) => {
|
|
506
|
+
if (!key)
|
|
507
|
+
return;
|
|
508
|
+
if (byName.has(key)) {
|
|
509
|
+
duplicated.add(key);
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
byName.set(key, node);
|
|
513
|
+
};
|
|
514
|
+
const walk = (node) => {
|
|
515
|
+
if (ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node)) {
|
|
516
|
+
const key = accessorKey(node);
|
|
517
|
+
if (key !== null) {
|
|
518
|
+
if (accessors.has(key))
|
|
519
|
+
duplicateAccessors.add(key);
|
|
520
|
+
else
|
|
521
|
+
accessors.set(key, node);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
if (ts.isFunctionDeclaration(node))
|
|
525
|
+
add(nameOf(node), node);
|
|
526
|
+
else if (ts.isMethodDeclaration(node) || ts.isMethodSignature(node))
|
|
527
|
+
add(nameOf(node), node);
|
|
528
|
+
// A PROPERTY whose declared type is a function type is a signature too.
|
|
529
|
+
// `@types/three` publishes a factory's members that way --
|
|
530
|
+
// `renderMultiDraw: ( starts: Int32Array, counts: Int32Array, drawCount:
|
|
531
|
+
// number ) => void` on `WebGLBufferRenderer` -- because the JS assigns
|
|
532
|
+
// them rather than declaring methods. Reading only `MethodSignature`
|
|
533
|
+
// missed every one, and those are exactly the functions the parameter
|
|
534
|
+
// census then refuses as `function-escapes:BinaryExpression`: their name
|
|
535
|
+
// is referenced once more, by the `this.renderMultiDraw = renderMultiDraw`
|
|
536
|
+
// that publishes them.
|
|
537
|
+
else if ((ts.isPropertySignature(node) || ts.isPropertyDeclaration(node)) && node.type && ts.isFunctionTypeNode(node.type)) {
|
|
538
|
+
add(nameOf(node), node.type);
|
|
539
|
+
}
|
|
540
|
+
else if (ts.isConstructorDeclaration(node) || ts.isConstructSignatureDeclaration(node)) {
|
|
541
|
+
const owner = node.parent;
|
|
542
|
+
add(ts.isClassDeclaration(owner) || ts.isInterfaceDeclaration(owner) ? (owner.name?.text ?? null) : null, node);
|
|
543
|
+
}
|
|
544
|
+
if (ts.isTypeAliasDeclaration(node) && node.typeParameters === undefined) {
|
|
545
|
+
aliases.set(node.name.text, statedTypeTextOf(node.type, file));
|
|
546
|
+
}
|
|
547
|
+
if (ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node)) {
|
|
548
|
+
for (const clause of node.heritageClauses ?? []) {
|
|
549
|
+
if (clause.token !== ts.SyntaxKind.ExtendsKeyword)
|
|
550
|
+
continue;
|
|
551
|
+
for (const type of clause.types)
|
|
552
|
+
if (ts.isIdentifier(type.expression))
|
|
553
|
+
extended.push(type.expression.text);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
if (ts.isInterfaceDeclaration(node) && node.name) {
|
|
557
|
+
const shape = interfaceShapeOf(node, file);
|
|
558
|
+
if (shape)
|
|
559
|
+
interfaces.set(node.name.text, shape);
|
|
560
|
+
}
|
|
561
|
+
if (ts.isClassDeclaration(node) && node.name) {
|
|
562
|
+
const shape = dataOnlyClassShapeOf(node, file);
|
|
563
|
+
if (shape)
|
|
564
|
+
interfaces.set(node.name.text, shape);
|
|
565
|
+
}
|
|
566
|
+
ts.forEachChild(node, walk);
|
|
567
|
+
};
|
|
568
|
+
walk(file);
|
|
569
|
+
for (const key of duplicated)
|
|
570
|
+
byName.delete(key);
|
|
571
|
+
const importedFrom = new Map();
|
|
572
|
+
for (const statement of file.statements) {
|
|
573
|
+
if (!ts.isImportDeclaration(statement) || !statement.importClause)
|
|
574
|
+
continue;
|
|
575
|
+
const bindings = statement.importClause.namedBindings;
|
|
576
|
+
if (!bindings || !ts.isNamedImports(bindings))
|
|
577
|
+
continue;
|
|
578
|
+
const specifier = statement.moduleSpecifier.getText(file);
|
|
579
|
+
for (const element of bindings.elements)
|
|
580
|
+
importedFrom.set(element.name.text, specifier);
|
|
581
|
+
}
|
|
582
|
+
for (const key of duplicateAccessors)
|
|
583
|
+
accessors.delete(key);
|
|
584
|
+
const result = {
|
|
585
|
+
signatures: byName,
|
|
586
|
+
accessors,
|
|
587
|
+
importedFrom,
|
|
588
|
+
fields: fieldsIn(file),
|
|
589
|
+
aliases,
|
|
590
|
+
interfaces,
|
|
591
|
+
extended,
|
|
592
|
+
records: recordSurfaceIn(file),
|
|
593
|
+
declared: declaredNamesIn(file)
|
|
594
|
+
};
|
|
595
|
+
declarationFileCache.set(path, result);
|
|
596
|
+
return result;
|
|
597
|
+
};
|
|
598
|
+
/**
|
|
599
|
+
* `specifier`, written relative to `from`, re-expressed relative to `to`.
|
|
600
|
+
*
|
|
601
|
+
* A base class's annotations name types the BASE declaration file imports,
|
|
602
|
+
* over specifiers relative to ITS OWN directory: `Object3D.d.ts` reaches
|
|
603
|
+
* `Vector3` as `"../math/Vector3.js"`, which from `cameras/Camera.js` means a
|
|
604
|
+
* different module or none at all. The two trees mirror each other, so a
|
|
605
|
+
* specifier rebased onto the derived file's directory resolves from the JS
|
|
606
|
+
* module at that same path -- which is the whole premise this overlay rests
|
|
607
|
+
* on, applied one level further out.
|
|
608
|
+
*/
|
|
609
|
+
const rebased = (specifier, from, to) => {
|
|
610
|
+
if (from === to)
|
|
611
|
+
return specifier;
|
|
612
|
+
const text = specifier.slice(1, -1);
|
|
613
|
+
if (!text.startsWith('.'))
|
|
614
|
+
return specifier;
|
|
615
|
+
const path = relative(to, resolve(from, text)).split(sep).join('/');
|
|
616
|
+
return `"${path.startsWith('.') ? path : `./${path}`}"`;
|
|
617
|
+
};
|
|
618
|
+
/**
|
|
619
|
+
* The declaration surface a JS module compiles against, INCLUDING what it
|
|
620
|
+
* inherits.
|
|
621
|
+
*
|
|
622
|
+
* `Camera.js` writes `updateMatrixWorld( force )` and `Camera.d.ts` says
|
|
623
|
+
* nothing about it, because the method is declared once, on `Object3D`, and
|
|
624
|
+
* `Camera extends Object3D`. Reading only the file beside the module misses
|
|
625
|
+
* every inherited member: measured on the three.js app, 351 of the parameters still
|
|
626
|
+
* boxed after everything else -- 3925 boxed carriers -- are refused for
|
|
627
|
+
* exactly this reason, more than every other cause combined.
|
|
628
|
+
*
|
|
629
|
+
* Depth decides collisions, which is what overriding means: a name the
|
|
630
|
+
* derived file declares is the answer, and a base's is consulted only where
|
|
631
|
+
* the derived file is silent. Within ONE depth two bases declaring the same
|
|
632
|
+
* name have no single answer, so that name is dropped -- the same rule an
|
|
633
|
+
* overload set already gets.
|
|
634
|
+
*/
|
|
635
|
+
const overlayFor = (fileName, declaredPath) => {
|
|
636
|
+
const cacheKey = `${fileName}\0${declaredPath ?? ''}`;
|
|
637
|
+
const cached = overlayCache.get(cacheKey);
|
|
638
|
+
if (cached !== undefined)
|
|
639
|
+
return cached;
|
|
640
|
+
const path = declaredPath ?? declarationPathFor(fileName);
|
|
641
|
+
if (!path) {
|
|
642
|
+
overlayCache.set(cacheKey, null);
|
|
643
|
+
return null;
|
|
644
|
+
}
|
|
645
|
+
const own = readDeclarationFile(path);
|
|
646
|
+
if (!own) {
|
|
647
|
+
overlayCache.set(cacheKey, null);
|
|
648
|
+
return null;
|
|
649
|
+
}
|
|
650
|
+
const signatures = new Map(own.signatures);
|
|
651
|
+
const importedFrom = new Map(own.importedFrom);
|
|
652
|
+
const aliases = new Map(own.aliases);
|
|
653
|
+
const interfaces = new Map(own.interfaces);
|
|
654
|
+
const declared = new Set(own.declared);
|
|
655
|
+
const here = dirname(path);
|
|
656
|
+
const seen = new Set([path]);
|
|
657
|
+
let frontier = [{ path, declarations: own }];
|
|
658
|
+
for (let depth = 0; depth < 8 && frontier.length > 0; depth++) {
|
|
659
|
+
const next = [];
|
|
660
|
+
for (const current of frontier) {
|
|
661
|
+
for (const name of current.declarations.extended) {
|
|
662
|
+
const specifier = current.declarations.importedFrom.get(name);
|
|
663
|
+
if (specifier === undefined)
|
|
664
|
+
continue;
|
|
665
|
+
const text = specifier.slice(1, -1);
|
|
666
|
+
if (!text.startsWith('.'))
|
|
667
|
+
continue;
|
|
668
|
+
const target = resolve(dirname(current.path), text).replace(/\.m?js$/, '.d.ts');
|
|
669
|
+
if (seen.has(target))
|
|
670
|
+
continue;
|
|
671
|
+
const declarations = readDeclarationFile(target);
|
|
672
|
+
if (!declarations)
|
|
673
|
+
continue;
|
|
674
|
+
seen.add(target);
|
|
675
|
+
next.push({ path: target, declarations });
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
const arriving = new Map();
|
|
679
|
+
const ambiguous = new Set();
|
|
680
|
+
for (const { declarations } of next) {
|
|
681
|
+
for (const [key, node] of declarations.signatures) {
|
|
682
|
+
if (signatures.has(key))
|
|
683
|
+
continue;
|
|
684
|
+
if (arriving.has(key)) {
|
|
685
|
+
ambiguous.add(key);
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
688
|
+
arriving.set(key, node);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
for (const key of ambiguous)
|
|
692
|
+
arriving.delete(key);
|
|
693
|
+
for (const [key, node] of arriving)
|
|
694
|
+
signatures.set(key, node);
|
|
695
|
+
for (const { path: from, declarations } of next) {
|
|
696
|
+
for (const [name, specifier] of declarations.importedFrom) {
|
|
697
|
+
if (importedFrom.has(name))
|
|
698
|
+
continue;
|
|
699
|
+
importedFrom.set(name, rebased(specifier, dirname(from), here));
|
|
700
|
+
}
|
|
701
|
+
for (const [name, definition] of declarations.aliases)
|
|
702
|
+
if (!aliases.has(name))
|
|
703
|
+
aliases.set(name, definition);
|
|
704
|
+
for (const [name, shape] of declarations.interfaces)
|
|
705
|
+
if (!interfaces.has(name))
|
|
706
|
+
interfaces.set(name, shape);
|
|
707
|
+
for (const name of declarations.declared)
|
|
708
|
+
declared.add(name);
|
|
709
|
+
}
|
|
710
|
+
frontier = next;
|
|
711
|
+
}
|
|
712
|
+
const overlay = {
|
|
713
|
+
importedFrom,
|
|
714
|
+
signatures,
|
|
715
|
+
accessors: own.accessors,
|
|
716
|
+
fields: own.fields,
|
|
717
|
+
aliases,
|
|
718
|
+
interfaces,
|
|
719
|
+
records: own.records,
|
|
720
|
+
declared
|
|
721
|
+
};
|
|
722
|
+
overlayCache.set(cacheKey, overlay);
|
|
723
|
+
return overlay;
|
|
724
|
+
};
|
|
725
|
+
/**
|
|
726
|
+
* `Class.property` -> the type the declaration file states, with the class's
|
|
727
|
+
* own type arguments resolved to their declared defaults.
|
|
728
|
+
*
|
|
729
|
+
* A property declared more than once for one class is dropped for the same
|
|
730
|
+
* reason an overload set is: there is no single answer.
|
|
731
|
+
*/
|
|
732
|
+
const fieldsIn = (file) => {
|
|
733
|
+
const fields = new Map();
|
|
734
|
+
const duplicated = new Set();
|
|
735
|
+
const walk = (node) => {
|
|
736
|
+
if ((ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node)) && node.name) {
|
|
737
|
+
const defaults = typeArgumentDefaults(node, file);
|
|
738
|
+
for (const member of node.members) {
|
|
739
|
+
if (!ts.isPropertyDeclaration(member) && !ts.isPropertySignature(member))
|
|
740
|
+
continue;
|
|
741
|
+
if (!member.type || !member.name || !ts.isIdentifier(member.name))
|
|
742
|
+
continue;
|
|
743
|
+
if (member.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.StaticKeyword))
|
|
744
|
+
continue;
|
|
745
|
+
if (member.questionToken)
|
|
746
|
+
continue;
|
|
747
|
+
const key = `${node.name.text}.${member.name.text}`;
|
|
748
|
+
if (fields.has(key)) {
|
|
749
|
+
duplicated.add(key);
|
|
750
|
+
continue;
|
|
751
|
+
}
|
|
752
|
+
const resolved = withTypeArguments(statedTypeTextOf(member.type, file), defaults);
|
|
753
|
+
if (resolved !== null)
|
|
754
|
+
fields.set(key, resolved);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
ts.forEachChild(node, walk);
|
|
758
|
+
};
|
|
759
|
+
walk(file);
|
|
760
|
+
for (const key of duplicated)
|
|
761
|
+
fields.delete(key);
|
|
762
|
+
return fields;
|
|
763
|
+
};
|
|
764
|
+
/**
|
|
765
|
+
* A declared type node's text, as one line, in a spelling JSDoc can parse.
|
|
766
|
+
*
|
|
767
|
+
* ⛔ The leading-operator strip is the whole reason this exists. TypeScript
|
|
768
|
+
* lets a union or intersection ANNOTATION open with its own operator, and
|
|
769
|
+
* `@types/three` writes `TypedArray` exactly that way:
|
|
770
|
+
*
|
|
771
|
+
* export type TypedArray =
|
|
772
|
+
* | Int8Array
|
|
773
|
+
* | Uint8Array
|
|
774
|
+
* ...
|
|
775
|
+
*
|
|
776
|
+
* `getText()` hands that back verbatim, and every consumer here puts the text
|
|
777
|
+
* into a JSDoc type position -- where `{(| Int8Array | Uint8Array)}` is a
|
|
778
|
+
* PARSE ERROR (`'}' expected.`), because JSDoc's parenthesized union has no
|
|
779
|
+
* leading-operator form. Two of three's `animation/` modules came out
|
|
780
|
+
* unparseable from that alone, and a file the checker cannot parse answers
|
|
781
|
+
* every question about itself wrongly rather than refusing.
|
|
782
|
+
*
|
|
783
|
+
* Whitespace to single spaces for the same reason: these texts are spliced
|
|
784
|
+
* into a one-line JSDoc tag, and a multi-line alias body would end the comment
|
|
785
|
+
* where its own newline falls.
|
|
786
|
+
*/
|
|
787
|
+
const statedTypeTextOf = (node, file) => node
|
|
788
|
+
.getText(file)
|
|
789
|
+
.replace(/\s+/g, ' ')
|
|
790
|
+
.replace(/^\s*[|&]\s*/, '')
|
|
791
|
+
.trim();
|
|
792
|
+
/** `text` with every type argument replaced by its default, or `null` if one has none. */
|
|
793
|
+
const withTypeArguments = (text, defaults) => {
|
|
794
|
+
if (defaults.size === 0)
|
|
795
|
+
return text;
|
|
796
|
+
const names = typeNamesIn(text);
|
|
797
|
+
if (!names)
|
|
798
|
+
return null;
|
|
799
|
+
if (!names.some((name) => defaults.has(name)))
|
|
800
|
+
return text;
|
|
801
|
+
let substituted = text;
|
|
802
|
+
for (const [name, value] of defaults) {
|
|
803
|
+
if (!names.includes(name))
|
|
804
|
+
continue;
|
|
805
|
+
if (value === null)
|
|
806
|
+
return null;
|
|
807
|
+
substituted = substituted.replace(new RegExp(`\\b${name}\\b`, 'g'), value);
|
|
808
|
+
}
|
|
809
|
+
// The default may itself name a parameter; one pass is enough only if none
|
|
810
|
+
// survives, and a survivor is refused rather than guessed at.
|
|
811
|
+
const after = typeNamesIn(substituted);
|
|
812
|
+
if (!after || after.some((name) => defaults.has(name)))
|
|
813
|
+
return null;
|
|
814
|
+
return substituted;
|
|
815
|
+
};
|
|
816
|
+
/**
|
|
817
|
+
* The declared parameter that describes the JS parameter at `index`, or
|
|
818
|
+
* `null` when position alone cannot say so.
|
|
819
|
+
*
|
|
820
|
+
* Position is the only link between a JS signature and its declaration, and a
|
|
821
|
+
* declaration file drifts from the source it describes. three's
|
|
822
|
+
* `WebGLState.js` writes `setBlending( blending, ..., blendDstAlpha,
|
|
823
|
+
* blendColor, blendAlpha, premultipliedAlpha )` -- ten parameters -- while
|
|
824
|
+
* `WebGLState.d.ts` still states eight, ending in `premultiplyAlpha?:
|
|
825
|
+
* boolean`. Read by position, `blendColor` (a `Color`) is stated `boolean`,
|
|
826
|
+
* a type the declaration never gave it. So:
|
|
827
|
+
*
|
|
828
|
+
* - equal arity, equal names: the declared parameter.
|
|
829
|
+
* - equal arity, different names: the declared parameter, unless the JS name
|
|
830
|
+
* is declared at ANOTHER position -- a swapped pair is not a rename.
|
|
831
|
+
* `setReversed( reversed )` against `setReversed(value: boolean)` is a
|
|
832
|
+
* rename and keeps its type.
|
|
833
|
+
* - the JS longer than the declaration: only a slot whose names agree; the
|
|
834
|
+
* declaration has plainly lost track of where each parameter sits.
|
|
835
|
+
* - the JS shorter (it ignores trailing arguments the declaration states):
|
|
836
|
+
* the equal-arity rule, which already refuses a swapped pair.
|
|
837
|
+
*/
|
|
838
|
+
const counterpartOf = (jsSignature, declared, index) => {
|
|
839
|
+
const parameter = jsSignature.parameters[index];
|
|
840
|
+
const counterpart = declared.parameters[index];
|
|
841
|
+
if (!parameter || !counterpart || !ts.isIdentifier(parameter.name) || !ts.isIdentifier(counterpart.name))
|
|
842
|
+
return null;
|
|
843
|
+
const name = parameter.name.text;
|
|
844
|
+
if (counterpart.name.text === name)
|
|
845
|
+
return counterpart;
|
|
846
|
+
if (jsSignature.parameters.length > declared.parameters.length)
|
|
847
|
+
return null;
|
|
848
|
+
const declaredElsewhere = declared.parameters.some((other, position) => position !== index && ts.isIdentifier(other.name) && other.name.text === name);
|
|
849
|
+
return declaredElsewhere ? null : counterpart;
|
|
850
|
+
};
|
|
851
|
+
/**
|
|
852
|
+
* A declared parameter type that states nothing. `WebGLProperties.d.ts` writes
|
|
853
|
+
* `get: (object: unknown) => unknown`; transferred, `@param {unknown} object`
|
|
854
|
+
* would be a STATEMENT, and `withJsDocTypeNames` sits OUTERMOST in the composed
|
|
855
|
+
* census, so it would outrank the carrier the census derives from the call
|
|
856
|
+
* sites -- turning a parameter the census could type into one it must box. The
|
|
857
|
+
* package said nothing about that position, so neither does this.
|
|
858
|
+
*/
|
|
859
|
+
const STATES_NOTHING = new Set(['any', 'unknown']);
|
|
860
|
+
/**
|
|
861
|
+
* Whether a declared parameter type leaves a position INSIDE it unstated -- an
|
|
862
|
+
* `any`/`unknown` array element, type argument, or member.
|
|
863
|
+
*
|
|
864
|
+
* `STATES_NOTHING` catches the bare spelling; this catches the same silence one
|
|
865
|
+
* level down, and it matters for the same reason. `WebGLPrograms.d.ts` states
|
|
866
|
+
* `getParameters( ..., lights: WebGLLightsState, ..., lightProbeGrids:
|
|
867
|
+
* unknown[] )`, and `WebGLLightsState` states `probe: unknown[]`,
|
|
868
|
+
* `directional: unknown[]`. Transferred, each is a STATEMENT, so the census
|
|
869
|
+
* never derives the parameter from its call site -- yet the one call site
|
|
870
|
+
* passes `lights.state` and `lightProbeGridArray` whose elements the program
|
|
871
|
+
* DOES type (`Vector3`, the uniform classes, `NativeLightProbeGrid`). The
|
|
872
|
+
* argument is then a typed array and the parameter an array of dynamic
|
|
873
|
+
* elements, the element layouts differ, and no conversion exists or should:
|
|
874
|
+
* measured on the three.js app, those two parameters were two of the three certificate
|
|
875
|
+
* refusals. The package said nothing about those elements, so the overlay says
|
|
876
|
+
* nothing about the parameter, and the census derives it from what callers
|
|
877
|
+
* actually pass.
|
|
878
|
+
*
|
|
879
|
+
* ⛔ Only DATA positions count: an array/tuple element, a type argument, a
|
|
880
|
+
* record member's value. A function type is a different statement entirely --
|
|
881
|
+
* `traverse( callback: ( object: Object3D ) => any )` states the callback's
|
|
882
|
+
* parameter, which is the CONTEXTUAL type an app's arrow function has no
|
|
883
|
+
* other source for, and its `any` return says nothing a caller supplies. The
|
|
884
|
+
* census cannot re-derive a callback's signature from call sites, so dropping
|
|
885
|
+
* such a statement strips the app's parameter to an implicit `any` (measured:
|
|
886
|
+
* one app module's `part` parameter became a checker error). Function types,
|
|
887
|
+
* method members and call/construct signatures are therefore never walked.
|
|
888
|
+
*/
|
|
889
|
+
export const statesNothingWithin = (text) => {
|
|
890
|
+
const probe = ts.createSourceFile('__type.ts', `type __Probe = ${text};`, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
891
|
+
const alias = probe.statements[0];
|
|
892
|
+
if (!alias || !ts.isTypeAliasDeclaration(alias))
|
|
893
|
+
return true;
|
|
894
|
+
let found = false;
|
|
895
|
+
const walk = (node) => {
|
|
896
|
+
if (found)
|
|
897
|
+
return;
|
|
898
|
+
if (ts.isFunctionTypeNode(node) ||
|
|
899
|
+
ts.isConstructorTypeNode(node) ||
|
|
900
|
+
ts.isMethodSignature(node) ||
|
|
901
|
+
ts.isCallSignatureDeclaration(node) ||
|
|
902
|
+
ts.isConstructSignatureDeclaration(node))
|
|
903
|
+
return;
|
|
904
|
+
if (node.kind === ts.SyntaxKind.AnyKeyword || node.kind === ts.SyntaxKind.UnknownKeyword) {
|
|
905
|
+
found = true;
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
ts.forEachChild(node, walk);
|
|
909
|
+
};
|
|
910
|
+
walk(alias.type);
|
|
911
|
+
return found;
|
|
912
|
+
};
|
|
913
|
+
/**
|
|
914
|
+
* Whether a parameter type holds an object-literal type INSIDE a container --
|
|
915
|
+
* a type argument, an array or a tuple element.
|
|
916
|
+
*
|
|
917
|
+
* `ColorManagement.d.ts` states `define: (colorSpaces: Record<string,
|
|
918
|
+
* ColorSpaceDefinition>) => void`, and `ColorSpaceDefinition` is plain data
|
|
919
|
+
* the overlay spells inline. Stated, it makes the parameter a dictionary of
|
|
920
|
+
* THAT record, while `createColorManagement`'s own `ColorManagement.define( {
|
|
921
|
+
* [ LinearSRGBColorSpace ]: { primaries: REC709_PRIMARIES, ... }, ... } )`
|
|
922
|
+
* builds a dictionary of the literals' own record type. The two element
|
|
923
|
+
* layouts differ, every element would need a structural conversion inside the
|
|
924
|
+
* container, and none is installed: measured on the three.js app, that one parameter
|
|
925
|
+
* is the whole of the certificate refusal ("no runtime conversion is installed
|
|
926
|
+
* from dictionary(string,native-record-ref(...)) to
|
|
927
|
+
* dictionary(string,record#...)"). Unannotated, the census derives the
|
|
928
|
+
* argument's own type and certifies. A record at the TOP of a parameter
|
|
929
|
+
* (`WebGLProgramParameters`, `GeometryGroup`, the `toJSON( meta )` bag with
|
|
930
|
+
* its own `geometries: Record<string, ...>` inside) converts as a record,
|
|
931
|
+
* certified before this rule existed, and keeps its statement -- so the walk
|
|
932
|
+
* stops at the first record it meets outside a container.
|
|
933
|
+
*/
|
|
934
|
+
const recordInsideContainer = (text) => {
|
|
935
|
+
const probe = ts.createSourceFile('__type.ts', `type __Probe = ${text};`, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
936
|
+
const alias = probe.statements[0];
|
|
937
|
+
if (!alias || !ts.isTypeAliasDeclaration(alias))
|
|
938
|
+
return true;
|
|
939
|
+
let found = false;
|
|
940
|
+
const walk = (node, contained) => {
|
|
941
|
+
if (found)
|
|
942
|
+
return;
|
|
943
|
+
if (ts.isTypeLiteralNode(node) || ts.isMappedTypeNode(node)) {
|
|
944
|
+
found = contained;
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
if (ts.isTypeReferenceNode(node)) {
|
|
948
|
+
for (const argument of node.typeArguments ?? [])
|
|
949
|
+
walk(argument, true);
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
if (ts.isArrayTypeNode(node))
|
|
953
|
+
return walk(node.elementType, true);
|
|
954
|
+
if (ts.isTupleTypeNode(node)) {
|
|
955
|
+
for (const element of node.elements)
|
|
956
|
+
walk(element, true);
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
ts.forEachChild(node, (child) => walk(child, contained));
|
|
960
|
+
};
|
|
961
|
+
walk(alias.type, false);
|
|
962
|
+
return found;
|
|
963
|
+
};
|
|
964
|
+
/**
|
|
965
|
+
* The `@param` lines a JS signature is missing, from its declared counterpart,
|
|
966
|
+
* and every type name those lines refer to.
|
|
967
|
+
*
|
|
968
|
+
* The names come back with the lines because an annotation is only worth
|
|
969
|
+
* writing if what it names is in scope: `@param {Texture}` in a file that
|
|
970
|
+
* never imports `Texture` resolves to `any`, and `withJsDocTypeNames` sits
|
|
971
|
+
* OUTERMOST in the composed census, so that `any` OUTRANKS the type the census
|
|
972
|
+
* would otherwise have derived from the call site. The caller turns these
|
|
973
|
+
* names into the `@import` lines that make them mean what they say.
|
|
974
|
+
*/
|
|
975
|
+
const paramLinesFor = (jsSignature, declared, respell) => {
|
|
976
|
+
const lines = [];
|
|
977
|
+
const names = [];
|
|
978
|
+
jsSignature.parameters.forEach((parameter, index) => {
|
|
979
|
+
if (parameter.type || !ts.isIdentifier(parameter.name))
|
|
980
|
+
return;
|
|
981
|
+
if (ts.getJSDocParameterTags(parameter).length > 0)
|
|
982
|
+
return;
|
|
983
|
+
const counterpart = counterpartOf(jsSignature, declared, index);
|
|
984
|
+
if (!counterpart || !counterpart.type || !ts.isIdentifier(counterpart.name))
|
|
985
|
+
return;
|
|
986
|
+
const stated = statedTypeTextOf(counterpart.type, counterpart.getSourceFile());
|
|
987
|
+
if (STATES_NOTHING.has(stated))
|
|
988
|
+
return;
|
|
989
|
+
const text = respell(stated);
|
|
990
|
+
if (text === null || text.length === 0 || text.includes('*/') || recordInsideContainer(text) || statesNothingWithin(text))
|
|
991
|
+
return;
|
|
992
|
+
const optional = counterpart.questionToken !== undefined || parameter.initializer !== undefined;
|
|
993
|
+
for (const name of typeNamesIn(text) ?? [])
|
|
994
|
+
names.push(name);
|
|
995
|
+
lines.push(` * @param {${text}} ${optional ? `[${parameter.name.text}]` : parameter.name.text}`);
|
|
996
|
+
});
|
|
997
|
+
return { lines, names };
|
|
998
|
+
};
|
|
999
|
+
/**
|
|
1000
|
+
* How many bindings, factory calls and nested properties a record may be
|
|
1001
|
+
* reached through. three's deepest is two (`WebGLState`'s record ->
|
|
1002
|
+
* `buffers` -> `colorBuffer` -> `new ColorBuffer()`'s record); the bound is
|
|
1003
|
+
* a guard, not a tuning knob.
|
|
1004
|
+
*/
|
|
1005
|
+
const MAX_RECORD_DEPTH = 8;
|
|
1006
|
+
const bindsName = (name, wanted) => ts.isIdentifier(name)
|
|
1007
|
+
? name.text === wanted
|
|
1008
|
+
: name.elements.some((element) => !ts.isOmittedExpression(element) && bindsName(element.name, wanted));
|
|
1009
|
+
/** Whether `container` hoists a `var` named `wanted`. A nested function's `var` is its own. */
|
|
1010
|
+
const hoistsVar = (container, wanted) => {
|
|
1011
|
+
let found = false;
|
|
1012
|
+
const seek = (node) => {
|
|
1013
|
+
if (found || ts.isFunctionLike(node))
|
|
1014
|
+
return;
|
|
1015
|
+
if (ts.isVariableDeclarationList(node) &&
|
|
1016
|
+
(node.flags & ts.NodeFlags.BlockScoped) === 0 &&
|
|
1017
|
+
node.declarations.some((declaration) => bindsName(declaration.name, wanted))) {
|
|
1018
|
+
found = true;
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
ts.forEachChild(node, seek);
|
|
1022
|
+
};
|
|
1023
|
+
if (ts.isFunctionLike(container)) {
|
|
1024
|
+
const body = container.body;
|
|
1025
|
+
if (body)
|
|
1026
|
+
ts.forEachChild(body, seek);
|
|
1027
|
+
}
|
|
1028
|
+
else
|
|
1029
|
+
ts.forEachChild(container, seek);
|
|
1030
|
+
return found;
|
|
1031
|
+
};
|
|
1032
|
+
const importBinds = (statement, wanted) => {
|
|
1033
|
+
const clause = statement.importClause;
|
|
1034
|
+
if (!clause)
|
|
1035
|
+
return false;
|
|
1036
|
+
if (clause.name?.text === wanted)
|
|
1037
|
+
return true;
|
|
1038
|
+
const bindings = clause.namedBindings;
|
|
1039
|
+
if (!bindings)
|
|
1040
|
+
return false;
|
|
1041
|
+
return ts.isNamespaceImport(bindings) ? bindings.name.text === wanted : bindings.elements.some((element) => element.name.text === wanted);
|
|
1042
|
+
};
|
|
1043
|
+
/**
|
|
1044
|
+
* The declaration `reference` resolves to, by the language's own scoping,
|
|
1045
|
+
* when that declaration is a function declaration or a `const` -- the only
|
|
1046
|
+
* two whose value a reader can know without following the program's flow.
|
|
1047
|
+
*
|
|
1048
|
+
* `WebGLState` returns `{ buffers: { color: colorBuffer } }`, and the
|
|
1049
|
+
* `colorBuffer` there is the `const colorBuffer = new ColorBuffer()` two
|
|
1050
|
+
* hundred lines up in the same body; `ColorManagement.js`'s factory returns
|
|
1051
|
+
* `ColorManagement`, which is its OWN `const ColorManagement = { ... }` and
|
|
1052
|
+
* not the module's exported binding of the same name. So this walks scopes
|
|
1053
|
+
* outward rather than matching names file-wide.
|
|
1054
|
+
*
|
|
1055
|
+
* Fail-closed at every shadow it cannot see through: a parameter, a catch or
|
|
1056
|
+
* loop binding, a hoisted `var`, a `let`, an import, a class, or two
|
|
1057
|
+
* declarations in one scope all answer `null`.
|
|
1058
|
+
*/
|
|
1059
|
+
const bindingOf = (reference) => {
|
|
1060
|
+
const wanted = reference.text;
|
|
1061
|
+
for (let scope = reference.parent; scope; scope = scope.parent) {
|
|
1062
|
+
if (ts.isFunctionLike(scope)) {
|
|
1063
|
+
if (scope.parameters.some((parameter) => bindsName(parameter.name, wanted)))
|
|
1064
|
+
return null;
|
|
1065
|
+
if (ts.isFunctionExpression(scope) && scope.name?.text === wanted)
|
|
1066
|
+
return null;
|
|
1067
|
+
if (hoistsVar(scope, wanted))
|
|
1068
|
+
return null;
|
|
1069
|
+
}
|
|
1070
|
+
if (ts.isCatchClause(scope) && scope.variableDeclaration && bindsName(scope.variableDeclaration.name, wanted))
|
|
1071
|
+
return null;
|
|
1072
|
+
if ((ts.isForStatement(scope) || ts.isForInStatement(scope) || ts.isForOfStatement(scope)) &&
|
|
1073
|
+
scope.initializer &&
|
|
1074
|
+
ts.isVariableDeclarationList(scope.initializer) &&
|
|
1075
|
+
scope.initializer.declarations.some((declaration) => bindsName(declaration.name, wanted)))
|
|
1076
|
+
return null;
|
|
1077
|
+
if ((ts.isClassDeclaration(scope) || ts.isClassExpression(scope)) && scope.name?.text === wanted)
|
|
1078
|
+
return null;
|
|
1079
|
+
const statements = ts.isBlock(scope) || ts.isSourceFile(scope) || ts.isModuleBlock(scope)
|
|
1080
|
+
? scope.statements
|
|
1081
|
+
: ts.isCaseBlock(scope)
|
|
1082
|
+
? scope.clauses.flatMap((clause) => [...clause.statements])
|
|
1083
|
+
: null;
|
|
1084
|
+
if (!statements)
|
|
1085
|
+
continue;
|
|
1086
|
+
if (ts.isSourceFile(scope) && hoistsVar(scope, wanted))
|
|
1087
|
+
return null;
|
|
1088
|
+
const found = [];
|
|
1089
|
+
for (const statement of statements) {
|
|
1090
|
+
if (ts.isFunctionDeclaration(statement) && statement.name?.text === wanted)
|
|
1091
|
+
found.push(statement);
|
|
1092
|
+
else if (ts.isClassDeclaration(statement) && statement.name?.text === wanted)
|
|
1093
|
+
return null;
|
|
1094
|
+
else if (ts.isImportDeclaration(statement) && importBinds(statement, wanted))
|
|
1095
|
+
return null;
|
|
1096
|
+
else if (ts.isVariableStatement(statement)) {
|
|
1097
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
1098
|
+
if (!bindsName(declaration.name, wanted))
|
|
1099
|
+
continue;
|
|
1100
|
+
if (!(statement.declarationList.flags & ts.NodeFlags.Const) || !ts.isIdentifier(declaration.name))
|
|
1101
|
+
return null;
|
|
1102
|
+
found.push(declaration);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
if (found.length > 1)
|
|
1107
|
+
return null;
|
|
1108
|
+
if (found.length === 1)
|
|
1109
|
+
return found[0] ?? null;
|
|
1110
|
+
}
|
|
1111
|
+
return null;
|
|
1112
|
+
};
|
|
1113
|
+
/**
|
|
1114
|
+
* The one expression a plain function returns, when it is a FACTORY in
|
|
1115
|
+
* `factoryExportsOf`'s sense: no `this.x =` of its own (a nested non-arrow
|
|
1116
|
+
* function's `this` is that function's), exactly one `return` of its own,
|
|
1117
|
+
* with a value, and not a generator or async function, whose callers
|
|
1118
|
+
* receive something else. Under `new` a returned object REPLACES the
|
|
1119
|
+
* instance, so `new ColorBuffer()` and `ColorBuffer()` denote the same record.
|
|
1120
|
+
*/
|
|
1121
|
+
const soleReturnOf = (fn) => {
|
|
1122
|
+
if (!fn.body || fn.asteriskToken)
|
|
1123
|
+
return null;
|
|
1124
|
+
if (ts.getModifiers(fn)?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword))
|
|
1125
|
+
return null;
|
|
1126
|
+
const returns = [];
|
|
1127
|
+
let assignsThis = false;
|
|
1128
|
+
const seek = (node, nested, foreignThis) => {
|
|
1129
|
+
if (!nested && ts.isReturnStatement(node))
|
|
1130
|
+
returns.push(node);
|
|
1131
|
+
if (!foreignThis &&
|
|
1132
|
+
ts.isBinaryExpression(node) &&
|
|
1133
|
+
node.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
1134
|
+
(ts.isPropertyAccessExpression(node.left) || ts.isElementAccessExpression(node.left)) &&
|
|
1135
|
+
node.left.expression.kind === ts.SyntaxKind.ThisKeyword)
|
|
1136
|
+
assignsThis = true;
|
|
1137
|
+
const entersFunction = ts.isFunctionLike(node) || ts.isClassLike(node);
|
|
1138
|
+
const entersThis = (ts.isFunctionLike(node) && !ts.isArrowFunction(node)) || ts.isClassLike(node);
|
|
1139
|
+
ts.forEachChild(node, (child) => seek(child, nested || entersFunction, foreignThis || entersThis));
|
|
1140
|
+
};
|
|
1141
|
+
ts.forEachChild(fn.body, (child) => seek(child, false, false));
|
|
1142
|
+
if (assignsThis || returns.length !== 1)
|
|
1143
|
+
return null;
|
|
1144
|
+
return returns[0]?.expression ?? null;
|
|
1145
|
+
};
|
|
1146
|
+
/**
|
|
1147
|
+
* The object literal `expression` evaluates to, followed through `const`
|
|
1148
|
+
* bindings and factory calls, or `null`.
|
|
1149
|
+
*
|
|
1150
|
+
* Wherever the PROGRAM states the record's type itself -- `@type` on the
|
|
1151
|
+
* binding or a cast, `@returns`/`@type` on the factory -- the answer is
|
|
1152
|
+
* `null`: the program said something, and a declared member contract laid
|
|
1153
|
+
* over its methods would contradict it rather than fill a silence.
|
|
1154
|
+
*/
|
|
1155
|
+
const recordOf = (expression, depth) => {
|
|
1156
|
+
if (depth > MAX_RECORD_DEPTH)
|
|
1157
|
+
return null;
|
|
1158
|
+
let bare = expression;
|
|
1159
|
+
while (ts.isParenthesizedExpression(bare)) {
|
|
1160
|
+
if (ts.getJSDocTypeTag(bare))
|
|
1161
|
+
return null;
|
|
1162
|
+
bare = bare.expression;
|
|
1163
|
+
}
|
|
1164
|
+
if (ts.isObjectLiteralExpression(bare))
|
|
1165
|
+
return bare;
|
|
1166
|
+
if (ts.isIdentifier(bare)) {
|
|
1167
|
+
const binding = bindingOf(bare);
|
|
1168
|
+
if (!binding || !ts.isVariableDeclaration(binding) || !binding.initializer || ts.getJSDocTypeTag(binding))
|
|
1169
|
+
return null;
|
|
1170
|
+
return recordOf(binding.initializer, depth + 1);
|
|
1171
|
+
}
|
|
1172
|
+
if ((ts.isNewExpression(bare) || ts.isCallExpression(bare)) && ts.isIdentifier(bare.expression)) {
|
|
1173
|
+
const binding = bindingOf(bare.expression);
|
|
1174
|
+
if (!binding || !ts.isFunctionDeclaration(binding))
|
|
1175
|
+
return null;
|
|
1176
|
+
if (ts.getJSDocReturnTag(binding) || ts.getJSDocTypeTag(binding))
|
|
1177
|
+
return null;
|
|
1178
|
+
const returned = soleReturnOf(binding);
|
|
1179
|
+
return returned ? recordOf(returned, depth + 1) : null;
|
|
1180
|
+
}
|
|
1181
|
+
return null;
|
|
1182
|
+
};
|
|
1183
|
+
/** A record's plainly named properties. A spread may overwrite any of them, so a record with one has none. */
|
|
1184
|
+
const recordPropertiesOf = (record) => {
|
|
1185
|
+
const properties = new Map();
|
|
1186
|
+
const repeated = new Set();
|
|
1187
|
+
for (const property of record.properties) {
|
|
1188
|
+
if (ts.isSpreadAssignment(property))
|
|
1189
|
+
return new Map();
|
|
1190
|
+
const name = ts.isIdentifier(property.name) || ts.isStringLiteral(property.name) ? property.name.text : null;
|
|
1191
|
+
if (name === null)
|
|
1192
|
+
continue;
|
|
1193
|
+
if (properties.has(name))
|
|
1194
|
+
repeated.add(name);
|
|
1195
|
+
properties.set(name, property);
|
|
1196
|
+
}
|
|
1197
|
+
for (const name of repeated)
|
|
1198
|
+
properties.delete(name);
|
|
1199
|
+
return properties;
|
|
1200
|
+
};
|
|
1201
|
+
/** `enable: enable` / `{ enable }` -- the function a record publishes by name. */
|
|
1202
|
+
const boundFunctionOf = (reference) => {
|
|
1203
|
+
const binding = bindingOf(reference);
|
|
1204
|
+
if (!binding)
|
|
1205
|
+
return null;
|
|
1206
|
+
if (ts.isFunctionDeclaration(binding))
|
|
1207
|
+
return binding.body ? { fn: binding, anchor: binding } : null;
|
|
1208
|
+
const value = binding.initializer;
|
|
1209
|
+
const list = binding.parent;
|
|
1210
|
+
if (!value || !(ts.isFunctionExpression(value) || ts.isArrowFunction(value)))
|
|
1211
|
+
return null;
|
|
1212
|
+
if (!ts.isVariableDeclarationList(list) || list.declarations.length !== 1 || !ts.isVariableStatement(list.parent))
|
|
1213
|
+
return null;
|
|
1214
|
+
return { fn: value, anchor: list.parent };
|
|
1215
|
+
};
|
|
1216
|
+
/**
|
|
1217
|
+
* The function `property` holds, anchored where the checker reads its tags:
|
|
1218
|
+
* the PROPERTY for `setClear: function ( ... ) {...}` (a function
|
|
1219
|
+
* expression's JSDoc host is the assignment it is the value of), the method
|
|
1220
|
+
* itself for `setClear( ... ) {...}`, and the declaration for a function the
|
|
1221
|
+
* record publishes by name.
|
|
1222
|
+
*/
|
|
1223
|
+
const recordFunctionOf = (property) => {
|
|
1224
|
+
if (ts.isMethodDeclaration(property))
|
|
1225
|
+
return property.body ? { fn: property, anchor: property } : null;
|
|
1226
|
+
if (ts.isPropertyAssignment(property)) {
|
|
1227
|
+
const value = property.initializer;
|
|
1228
|
+
if (ts.isFunctionExpression(value) || ts.isArrowFunction(value))
|
|
1229
|
+
return { fn: value, anchor: property };
|
|
1230
|
+
return ts.isIdentifier(value) ? boundFunctionOf(value) : null;
|
|
1231
|
+
}
|
|
1232
|
+
return ts.isShorthandPropertyAssignment(property) ? boundFunctionOf(property.name) : null;
|
|
1233
|
+
};
|
|
1234
|
+
/** The names a JS module exports under their own local name. */
|
|
1235
|
+
const exportedNamesOf = (file) => {
|
|
1236
|
+
const names = new Set();
|
|
1237
|
+
const exported = (node) => ts.canHaveModifiers(node) && (ts.getModifiers(node) ?? []).some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword);
|
|
1238
|
+
for (const statement of file.statements) {
|
|
1239
|
+
if (ts.isVariableStatement(statement) && exported(statement)) {
|
|
1240
|
+
for (const declaration of statement.declarationList.declarations)
|
|
1241
|
+
if (ts.isIdentifier(declaration.name))
|
|
1242
|
+
names.add(declaration.name.text);
|
|
1243
|
+
}
|
|
1244
|
+
else if ((ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) && statement.name && exported(statement)) {
|
|
1245
|
+
names.add(statement.name.text);
|
|
1246
|
+
}
|
|
1247
|
+
else if (ts.isExportDeclaration(statement) && !statement.moduleSpecifier && !statement.isTypeOnly) {
|
|
1248
|
+
const clause = statement.exportClause;
|
|
1249
|
+
if (clause && ts.isNamedExports(clause))
|
|
1250
|
+
for (const element of clause.elements)
|
|
1251
|
+
if (!element.propertyName)
|
|
1252
|
+
names.add(element.name.text);
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
return names;
|
|
1256
|
+
};
|
|
1257
|
+
/**
|
|
1258
|
+
* Every function a record in `file` publishes under a name its declared
|
|
1259
|
+
* owner states a signature for -- `null` for one two owners disagree about.
|
|
1260
|
+
*
|
|
1261
|
+
* ## Where an owner comes from
|
|
1262
|
+
*
|
|
1263
|
+
* - An exported factory named like a class or interface of its own
|
|
1264
|
+
* declaration file: `function WebGLState( gl, extensions ) { ...; return
|
|
1265
|
+
* { enable, useProgram, ... } }` is `declare class WebGLState`. This is
|
|
1266
|
+
* the identification `factoryExportsOf` already makes when it spells
|
|
1267
|
+
* `WebGLState` as `ReturnType<WebGLState>` across an import.
|
|
1268
|
+
* - An exported `const` the declaration file states a type for: `export
|
|
1269
|
+
* const ColorManagement = createColorManagement()` is `export const
|
|
1270
|
+
* ColorManagement: ColorManagement`, and the record is what
|
|
1271
|
+
* `createColorManagement` returns.
|
|
1272
|
+
* - A property of a record that already has an owner, through the type the
|
|
1273
|
+
* owner states for it: `buffers: { color: colorBuffer, ... }` is
|
|
1274
|
+
* `buffers: { color: WebGLColorBuffer; ... }`, so the literal is that
|
|
1275
|
+
* inline type and `colorBuffer`'s record is a `WebGLColorBuffer`. Only a
|
|
1276
|
+
* type literal or a bare reference to one of the file's own owners is
|
|
1277
|
+
* followed -- a union, a generic, an imported class is not a record this
|
|
1278
|
+
* file writes.
|
|
1279
|
+
*
|
|
1280
|
+
* ## What it refuses
|
|
1281
|
+
*
|
|
1282
|
+
* - A record reached as two different owners: which contract it keeps is
|
|
1283
|
+
* not one answer.
|
|
1284
|
+
* - A function reached through two owners' members with different
|
|
1285
|
+
* declarations (`reset` published by two records): `null`, which also
|
|
1286
|
+
* withholds the flat by-name guess.
|
|
1287
|
+
* - Everything `recordOf`, `bindingOf` and `recordPropertiesOf` refuse.
|
|
1288
|
+
*/
|
|
1289
|
+
const recordMethodsIn = (file, records) => {
|
|
1290
|
+
const methods = new Map();
|
|
1291
|
+
if (records.signatures.size === 0)
|
|
1292
|
+
return methods;
|
|
1293
|
+
const targetOfType = (stated) => {
|
|
1294
|
+
let type = stated;
|
|
1295
|
+
while (ts.isParenthesizedTypeNode(type))
|
|
1296
|
+
type = type.type;
|
|
1297
|
+
if (ts.isTypeLiteralNode(type))
|
|
1298
|
+
return { kind: 'literal', node: type };
|
|
1299
|
+
if (ts.isTypeReferenceNode(type) && !type.typeArguments && ts.isIdentifier(type.typeName) && records.owners.has(type.typeName.text))
|
|
1300
|
+
return { kind: 'owner', name: type.typeName.text };
|
|
1301
|
+
return null;
|
|
1302
|
+
};
|
|
1303
|
+
const memberOf = (target, name) => {
|
|
1304
|
+
if (target.kind === 'owner') {
|
|
1305
|
+
const signature = records.signatures.get(`${target.name}.${name}`);
|
|
1306
|
+
if (signature)
|
|
1307
|
+
return { signature };
|
|
1308
|
+
const type = records.types.get(`${target.name}.${name}`);
|
|
1309
|
+
return type ? { type } : null;
|
|
1310
|
+
}
|
|
1311
|
+
const matching = target.node.members.filter((member) => nameOf(member) === name);
|
|
1312
|
+
const member = matching.length === 1 ? matching[0] : undefined;
|
|
1313
|
+
if (!member)
|
|
1314
|
+
return null;
|
|
1315
|
+
if (ts.isMethodSignature(member))
|
|
1316
|
+
return { signature: member };
|
|
1317
|
+
if (ts.isPropertySignature(member) && member.type)
|
|
1318
|
+
return ts.isFunctionTypeNode(member.type) ? { signature: member.type } : { type: member.type };
|
|
1319
|
+
return null;
|
|
1320
|
+
};
|
|
1321
|
+
const keyOf = (target) => (target.kind === 'owner' ? target.name : `{}@${target.node.pos}`);
|
|
1322
|
+
const reached = new Map();
|
|
1323
|
+
const reach = (record, target, depth) => {
|
|
1324
|
+
if (depth > MAX_RECORD_DEPTH)
|
|
1325
|
+
return;
|
|
1326
|
+
let known = reached.get(record);
|
|
1327
|
+
if (!known)
|
|
1328
|
+
reached.set(record, (known = new Map()));
|
|
1329
|
+
if (known.has(keyOf(target)))
|
|
1330
|
+
return;
|
|
1331
|
+
known.set(keyOf(target), target);
|
|
1332
|
+
for (const [name, property] of recordPropertiesOf(record)) {
|
|
1333
|
+
const member = memberOf(target, name);
|
|
1334
|
+
if (!member || !('type' in member))
|
|
1335
|
+
continue;
|
|
1336
|
+
const nested = targetOfType(member.type);
|
|
1337
|
+
const value = ts.isPropertyAssignment(property)
|
|
1338
|
+
? property.initializer
|
|
1339
|
+
: ts.isShorthandPropertyAssignment(property)
|
|
1340
|
+
? property.name
|
|
1341
|
+
: null;
|
|
1342
|
+
const inner = nested && value ? recordOf(value, depth + 1) : null;
|
|
1343
|
+
if (nested && inner)
|
|
1344
|
+
reach(inner, nested, depth + 1);
|
|
1345
|
+
}
|
|
1346
|
+
};
|
|
1347
|
+
const exported = exportedNamesOf(file);
|
|
1348
|
+
for (const statement of file.statements) {
|
|
1349
|
+
if (ts.isFunctionDeclaration(statement) && statement.name && exported.has(statement.name.text)) {
|
|
1350
|
+
const name = statement.name.text;
|
|
1351
|
+
if (!records.owners.has(name) || ts.getJSDocReturnTag(statement) || ts.getJSDocTypeTag(statement))
|
|
1352
|
+
continue;
|
|
1353
|
+
const returned = soleReturnOf(statement);
|
|
1354
|
+
const record = returned ? recordOf(returned, 0) : null;
|
|
1355
|
+
if (record)
|
|
1356
|
+
reach(record, { kind: 'owner', name }, 0);
|
|
1357
|
+
}
|
|
1358
|
+
else if (ts.isVariableStatement(statement) && statement.declarationList.flags & ts.NodeFlags.Const) {
|
|
1359
|
+
if (ts.getJSDocTypeTag(statement))
|
|
1360
|
+
continue;
|
|
1361
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
1362
|
+
if (!ts.isIdentifier(declaration.name) || !declaration.initializer || !exported.has(declaration.name.text))
|
|
1363
|
+
continue;
|
|
1364
|
+
const stated = records.constants.get(declaration.name.text);
|
|
1365
|
+
const target = stated ? targetOfType(stated) : null;
|
|
1366
|
+
const record = target ? recordOf(declaration.initializer, 0) : null;
|
|
1367
|
+
if (target && record)
|
|
1368
|
+
reach(record, target, 0);
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
const candidates = new Map();
|
|
1373
|
+
for (const [record, known] of reached) {
|
|
1374
|
+
if (known.size !== 1)
|
|
1375
|
+
continue;
|
|
1376
|
+
const target = [...known.values()][0];
|
|
1377
|
+
if (!target)
|
|
1378
|
+
continue;
|
|
1379
|
+
for (const [name, property] of recordPropertiesOf(record)) {
|
|
1380
|
+
const member = memberOf(target, name);
|
|
1381
|
+
if (!member || !('signature' in member))
|
|
1382
|
+
continue;
|
|
1383
|
+
const held = recordFunctionOf(property);
|
|
1384
|
+
if (!held)
|
|
1385
|
+
continue;
|
|
1386
|
+
const list = candidates.get(held.fn) ?? [];
|
|
1387
|
+
list.push({ ...held, declared: member.signature });
|
|
1388
|
+
candidates.set(held.fn, list);
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
for (const [fn, list] of candidates) {
|
|
1392
|
+
const first = list[0];
|
|
1393
|
+
methods.set(fn, first && list.every((candidate) => candidate.declared === first.declared) ? first : null);
|
|
1394
|
+
}
|
|
1395
|
+
return methods;
|
|
1396
|
+
};
|
|
1397
|
+
export const declarationOverlayTransform = (input) => {
|
|
1398
|
+
if (!/\.(?:js|mjs|cjs)$/.test(input.fileName))
|
|
1399
|
+
return null;
|
|
1400
|
+
const overlay = overlayFor(input.fileName, input.declarationFileName);
|
|
1401
|
+
if (!overlay || (overlay.signatures.size === 0 && overlay.accessors.size === 0 && overlay.records.signatures.size === 0))
|
|
1402
|
+
return null;
|
|
1403
|
+
const declaredPath = input.declarationFileName ?? declarationPathFor(input.fileName);
|
|
1404
|
+
if (!declaredPath)
|
|
1405
|
+
return null;
|
|
1406
|
+
const file = ts.createSourceFile(input.fileName, input.text, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
|
|
1407
|
+
/** The JS file's own directory, in the frame every specifier this module writes is expressed in -- see `rebased`. */
|
|
1408
|
+
const here = dirname(declaredPath);
|
|
1409
|
+
const edits = [];
|
|
1410
|
+
const declaredAccessorTypes = new Set();
|
|
1411
|
+
// Every name the JS module itself binds at top level. A `@import` of a name
|
|
1412
|
+
// the source already declares would be a duplicate binding AND a second
|
|
1413
|
+
// identity for one class -- `Object3D.d.ts` states `parent: Object3D`, and
|
|
1414
|
+
// importing that INTO `Object3D.js` would give the file two `Object3D`s. So
|
|
1415
|
+
// a field whose type needs such a name is refused.
|
|
1416
|
+
const boundHere = new Set();
|
|
1417
|
+
for (const statement of file.statements) {
|
|
1418
|
+
// EVERY block, not `ts.getJSDocTags`: that keeps only the block nearest the
|
|
1419
|
+
// node, while the binder binds an `@import` or `@typedef` from any of them
|
|
1420
|
+
// -- and this overlay's own `@import` header lands in an earlier block
|
|
1421
|
+
// whenever the file's first statement also earns a `@param` block, so a
|
|
1422
|
+
// second pass would not see it and would import the same name again.
|
|
1423
|
+
const blocks = statement.jsDoc ?? [];
|
|
1424
|
+
for (const tag of blocks.flatMap((block) => [...(block.tags ?? [])])) {
|
|
1425
|
+
if ((ts.isJSDocTypedefTag(tag) || ts.isJSDocCallbackTag(tag)) && tag.name)
|
|
1426
|
+
boundHere.add(tag.name.text);
|
|
1427
|
+
if (!ts.isJSDocImportTag(tag))
|
|
1428
|
+
continue;
|
|
1429
|
+
const bindings = tag.importClause?.namedBindings;
|
|
1430
|
+
if (bindings && ts.isNamedImports(bindings))
|
|
1431
|
+
for (const element of bindings.elements)
|
|
1432
|
+
boundHere.add(element.name.text);
|
|
1433
|
+
if (bindings && ts.isNamespaceImport(bindings))
|
|
1434
|
+
boundHere.add(bindings.name.text);
|
|
1435
|
+
if (tag.importClause?.name)
|
|
1436
|
+
boundHere.add(tag.importClause.name.text);
|
|
1437
|
+
}
|
|
1438
|
+
if (ts.isClassDeclaration(statement) || ts.isFunctionDeclaration(statement)) {
|
|
1439
|
+
if (statement.name)
|
|
1440
|
+
boundHere.add(statement.name.text);
|
|
1441
|
+
}
|
|
1442
|
+
else if (ts.isVariableStatement(statement)) {
|
|
1443
|
+
for (const declaration of statement.declarationList.declarations)
|
|
1444
|
+
if (ts.isIdentifier(declaration.name))
|
|
1445
|
+
boundHere.add(declaration.name.text);
|
|
1446
|
+
}
|
|
1447
|
+
else if (ts.isImportDeclaration(statement) && statement.importClause) {
|
|
1448
|
+
const bindings = statement.importClause.namedBindings;
|
|
1449
|
+
if (bindings && ts.isNamedImports(bindings))
|
|
1450
|
+
for (const element of bindings.elements)
|
|
1451
|
+
boundHere.add(element.name.text);
|
|
1452
|
+
if (statement.importClause.name)
|
|
1453
|
+
boundHere.add(statement.importClause.name.text);
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
// Every type name this file needs brought into scope, whether for an
|
|
1457
|
+
// annotation this overlay adds or for one the source already wrote.
|
|
1458
|
+
const required = new Set();
|
|
1459
|
+
/** A name reached by inlining an alias or interface, and the specifier that supplies it. */
|
|
1460
|
+
const alsoFrom = new Map();
|
|
1461
|
+
/**
|
|
1462
|
+
* Whether this overlay can bring `name` into scope here, recording it if so.
|
|
1463
|
+
*
|
|
1464
|
+
* ⛔ Only a specifier the declaration file itself wrote may be used, because
|
|
1465
|
+
* those are RELATIVE and the two trees mirror each other, so they resolve
|
|
1466
|
+
* from the JS file to the real JS module. Naming the declaration tree
|
|
1467
|
+
* directly -- `../../@types/three/src/.../X.js`, to reach a type the
|
|
1468
|
+
* declaration file declares rather than imports -- looks like the same idea
|
|
1469
|
+
* and is not: it pulls `@types/three` into the program, and a `.d.ts`
|
|
1470
|
+
* REPLACES a `.js` for the checker. Every three module with no declaration
|
|
1471
|
+
* beside it (`WebGLShaderCache`, `WebXRDepthSensing`) then resolves to
|
|
1472
|
+
* nothing at all, so `new WebGLShaderCache()` becomes `any` and its whole
|
|
1473
|
+
* invocation is withheld. Measured: 13 new withheld operations and +94
|
|
1474
|
+
* unmet obligations, for types the census was already deriving correctly.
|
|
1475
|
+
*/
|
|
1476
|
+
/**
|
|
1477
|
+
* How this file must SPELL the type a declaration file calls `Name`, or
|
|
1478
|
+
* `null` if it CANNOT be spelled at all.
|
|
1479
|
+
*
|
|
1480
|
+
* `ReturnType<Name>` where the JS module exports `Name` as a factory (see
|
|
1481
|
+
* `factoryExportsOf`), and `Name` everywhere else this transform recognizes
|
|
1482
|
+
* it. A name this transform does NOT recognize -- not ambient, not bound
|
|
1483
|
+
* here, not an alias or interface this overlay knows -- is left exactly as
|
|
1484
|
+
* the program wrote it: something else (`withJsDocTypeNames`) may still
|
|
1485
|
+
* resolve it one scope wider.
|
|
1486
|
+
*
|
|
1487
|
+
* ⛔ A name this overlay DOES recognize as alias- or interface-ONLY (no JS
|
|
1488
|
+
* value exists to import) but fails to inline is different: reusing the
|
|
1489
|
+
* bare name here would leave a reference to nothing at all in the JSDoc --
|
|
1490
|
+
* worse than not touching it, since an unimported, undeclared name resolves
|
|
1491
|
+
* to `any` with no fallback. `null` propagates that refusal to the caller
|
|
1492
|
+
* rather than silently emitting a dangling reference.
|
|
1493
|
+
*/
|
|
1494
|
+
const spellingOf = (name) => {
|
|
1495
|
+
const resolved = resolveNameFrom(name, ownHome, 0, new Set());
|
|
1496
|
+
if (resolved !== null)
|
|
1497
|
+
return resolved;
|
|
1498
|
+
return overlay.aliases.has(name) || overlay.interfaces.has(name) || declarationOnly(name) ? null : name;
|
|
1499
|
+
};
|
|
1500
|
+
/**
|
|
1501
|
+
* Whether the declaration tree says exactly where `name` lives and that
|
|
1502
|
+
* place has no JS value by it -- so a bare `name` in this file names
|
|
1503
|
+
* NOTHING the declaration meant.
|
|
1504
|
+
*
|
|
1505
|
+
* Two shapes: a class or interface the declaration file declares itself
|
|
1506
|
+
* (`WebGLState.d.ts`'s `declare class WebGLColorBuffer`, which no JS module
|
|
1507
|
+
* exports), and a name it imports from a module whose JS does not export it
|
|
1508
|
+
* (`PixelFormat` from `"../../constants.js"`, see `jsExportsOf`). Neither
|
|
1509
|
+
* is the "unrecognized" name `spellingOf` leaves for a wider scope: a bare
|
|
1510
|
+
* spelling reaches `withJsDocTypeNames`, which binds it to whatever ONE type
|
|
1511
|
+
* the PROGRAM declares by that name -- a JS class elsewhere that merely
|
|
1512
|
+
* shares the name, which is not what the declaration meant, or nothing at
|
|
1513
|
+
* all. So the one parameter is left out, and its siblings still get theirs. A name whose import is refused only because the edge would close
|
|
1514
|
+
* a cycle IS exported by its module, and keeps the bare spelling.
|
|
1515
|
+
*/
|
|
1516
|
+
const declarationOnly = (name) => {
|
|
1517
|
+
const specifier = overlay.importedFrom.get(name);
|
|
1518
|
+
if (specifier === undefined)
|
|
1519
|
+
return overlay.declared.has(name);
|
|
1520
|
+
const text = specifier.slice(1, -1);
|
|
1521
|
+
if (!text.startsWith('.'))
|
|
1522
|
+
return false;
|
|
1523
|
+
const target = resolve(dirname(input.fileName), text);
|
|
1524
|
+
return existsSync(target) && !jsExportsOf(target).has(name);
|
|
1525
|
+
};
|
|
1526
|
+
/**
|
|
1527
|
+
* The merged view `overlay` already built for THIS JS file's own
|
|
1528
|
+
* declaration -- including everything its class-inheritance chain folded
|
|
1529
|
+
* in -- reused as a `Home` so the general resolver below needs no special
|
|
1530
|
+
* case for "the declaration beside this very file".
|
|
1531
|
+
*/
|
|
1532
|
+
const ownHome = {
|
|
1533
|
+
path: declaredPath,
|
|
1534
|
+
file: {
|
|
1535
|
+
signatures: overlay.signatures,
|
|
1536
|
+
accessors: overlay.accessors,
|
|
1537
|
+
importedFrom: overlay.importedFrom,
|
|
1538
|
+
fields: overlay.fields,
|
|
1539
|
+
aliases: overlay.aliases,
|
|
1540
|
+
interfaces: overlay.interfaces,
|
|
1541
|
+
extended: [],
|
|
1542
|
+
records: overlay.records,
|
|
1543
|
+
declared: overlay.declared
|
|
1544
|
+
},
|
|
1545
|
+
reach: null
|
|
1546
|
+
};
|
|
1547
|
+
/** The specifier, relative to `here`, that imports a value from the module `declPath` mirrors. */
|
|
1548
|
+
const reachSpecifierFor = (declPath) => {
|
|
1549
|
+
const dir = relative(here, dirname(declPath)).split(sep).join('/');
|
|
1550
|
+
const dirText = dir.length === 0 ? '.' : dir.startsWith('.') ? dir : `./${dir}`;
|
|
1551
|
+
return `"${dirText}/${basename(declPath).replace(/\.d\.ts$/, '.js')}"`;
|
|
1552
|
+
};
|
|
1553
|
+
const homeCache = new Map();
|
|
1554
|
+
const homeAt = (path) => {
|
|
1555
|
+
const cached = homeCache.get(path);
|
|
1556
|
+
if (cached !== undefined)
|
|
1557
|
+
return cached;
|
|
1558
|
+
const file = readDeclarationFile(path);
|
|
1559
|
+
const home = file ? { path, file, reach: reachSpecifierFor(path) } : null;
|
|
1560
|
+
homeCache.set(path, home);
|
|
1561
|
+
return home;
|
|
1562
|
+
};
|
|
1563
|
+
/**
|
|
1564
|
+
* Whether an edge from the JS file being rewritten to `target` may be
|
|
1565
|
+
* added at all: `target` must exist, must not be the file itself, and must
|
|
1566
|
+
* not be able to reach BACK to it -- see `modulesReachableFrom`.
|
|
1567
|
+
*/
|
|
1568
|
+
const validEdge = (target) => existsSync(target) && target !== input.fileName && !modulesReachableFrom(target).has(input.fileName);
|
|
1569
|
+
const MAX_INLINE_DEPTH = 6;
|
|
1570
|
+
/**
|
|
1571
|
+
* What a name means when the JS module has nothing by that name.
|
|
1572
|
+
*
|
|
1573
|
+
* `PixelFormat` and `TypedArray` live only in the declaration tree, so no
|
|
1574
|
+
* import can reach them and every annotation naming one resolves to `any`.
|
|
1575
|
+
* But an ALIAS is just a spelling, and an INTERFACE with no method, index
|
|
1576
|
+
* signature or type parameter is exactly a JSDoc object-literal type: both
|
|
1577
|
+
* say the same thing without needing the name in scope at all. `TypedArray`
|
|
1578
|
+
* becomes the union of nine ambient array types; `WebGLProgramParameters`
|
|
1579
|
+
* becomes `{ shaderID: string, ... }`.
|
|
1580
|
+
*
|
|
1581
|
+
* Every name the definition (or, for an interface, every member's type)
|
|
1582
|
+
* refers to must itself be reachable -- ambient, bound in this file
|
|
1583
|
+
* already, genuinely exported by the module that name's OWN home reaches
|
|
1584
|
+
* it through, or itself inlinable the same way -- or the whole thing is
|
|
1585
|
+
* refused: a partially-resolved definition buys nothing and costs the
|
|
1586
|
+
* census the answer it had. A class that states behavior is never
|
|
1587
|
+
* inlined -- its meaning is identity, not a piece of type text -- but a
|
|
1588
|
+
* class stating nothing but plain data (`SourceJSON`, see
|
|
1589
|
+
* `dataOnlyClassShapeOf`) is captured into `interfaces` the same as an
|
|
1590
|
+
* interface and inlines through this same path.
|
|
1591
|
+
*/
|
|
1592
|
+
const inlineAt = (name, home, depth, visiting) => {
|
|
1593
|
+
if (depth > MAX_INLINE_DEPTH)
|
|
1594
|
+
return null;
|
|
1595
|
+
const key = `${home.path}::${name}`;
|
|
1596
|
+
if (visiting.has(key))
|
|
1597
|
+
return null;
|
|
1598
|
+
if (home.file.interfaces.has(name))
|
|
1599
|
+
return inlineInterfaceAt(name, home, depth, visiting);
|
|
1600
|
+
if (home.file.aliases.has(name))
|
|
1601
|
+
return inlineAliasAt(name, home, depth, visiting);
|
|
1602
|
+
return null;
|
|
1603
|
+
};
|
|
1604
|
+
const inlineAliasAt = (name, home, depth, visiting) => {
|
|
1605
|
+
const definition = home.file.aliases.get(name);
|
|
1606
|
+
if (definition === undefined || definition.includes('*/'))
|
|
1607
|
+
return null;
|
|
1608
|
+
const nextVisiting = new Set(visiting);
|
|
1609
|
+
nextVisiting.add(`${home.path}::${name}`);
|
|
1610
|
+
const spelled = respellUsing(definition, home, depth + 1, nextVisiting);
|
|
1611
|
+
return spelled === null ? null : `(${spelled})`;
|
|
1612
|
+
};
|
|
1613
|
+
/** One interface's own + inherited members, each still tagged with the file it was declared in. */
|
|
1614
|
+
const mergedInterfaceMembers = (name, home, depth, visiting) => {
|
|
1615
|
+
if (depth > MAX_INLINE_DEPTH)
|
|
1616
|
+
return null;
|
|
1617
|
+
const shape = home.file.interfaces.get(name);
|
|
1618
|
+
if (!shape)
|
|
1619
|
+
return null;
|
|
1620
|
+
const key = `${home.path}::${name}`;
|
|
1621
|
+
if (visiting.has(key))
|
|
1622
|
+
return null;
|
|
1623
|
+
const nextVisiting = new Set(visiting);
|
|
1624
|
+
nextVisiting.add(key);
|
|
1625
|
+
const merged = new Map();
|
|
1626
|
+
for (const baseName of shape.extends) {
|
|
1627
|
+
const baseHome = homeFor(baseName, home);
|
|
1628
|
+
if (!baseHome)
|
|
1629
|
+
return null;
|
|
1630
|
+
const baseMembers = mergedInterfaceMembers(baseName, baseHome, depth + 1, nextVisiting);
|
|
1631
|
+
if (!baseMembers)
|
|
1632
|
+
return null;
|
|
1633
|
+
for (const [memberName, member] of baseMembers)
|
|
1634
|
+
merged.set(memberName, member);
|
|
1635
|
+
}
|
|
1636
|
+
for (const member of shape.members)
|
|
1637
|
+
merged.set(member.name, { optional: member.optional, type: member.type, home });
|
|
1638
|
+
return merged;
|
|
1639
|
+
};
|
|
1640
|
+
const inlineInterfaceAt = (name, home, depth, visiting) => {
|
|
1641
|
+
const members = mergedInterfaceMembers(name, home, depth, visiting);
|
|
1642
|
+
if (!members || members.size === 0)
|
|
1643
|
+
return null;
|
|
1644
|
+
const nextVisiting = new Set(visiting);
|
|
1645
|
+
nextVisiting.add(`${home.path}::${name}`);
|
|
1646
|
+
const parts = [];
|
|
1647
|
+
for (const [memberName, member] of members) {
|
|
1648
|
+
const spelled = respellUsing(member.type, member.home, depth + 1, nextVisiting);
|
|
1649
|
+
if (spelled === null)
|
|
1650
|
+
return null;
|
|
1651
|
+
parts.push(`${memberName}${member.optional ? '?' : ''}: ${spelled}`);
|
|
1652
|
+
}
|
|
1653
|
+
return `{ ${parts.join(', ')} }`;
|
|
1654
|
+
};
|
|
1655
|
+
/**
|
|
1656
|
+
* Where `name` lives, seen from `from`: an import `from` itself wrote --
|
|
1657
|
+
* rebased onto `here` and validated as a real, acyclic edge -- or, absent
|
|
1658
|
+
* one, `from` itself (so a name `from`'s own file declares needs nothing
|
|
1659
|
+
* further).
|
|
1660
|
+
*/
|
|
1661
|
+
const homeFor = (name, from) => {
|
|
1662
|
+
const specifier = from.file.importedFrom.get(name);
|
|
1663
|
+
if (specifier === undefined)
|
|
1664
|
+
return from;
|
|
1665
|
+
const text = specifier.slice(1, -1);
|
|
1666
|
+
if (!text.startsWith('.'))
|
|
1667
|
+
return null;
|
|
1668
|
+
const declPath = resolve(dirname(from.path), text).replace(/\.m?js$/, '.d.ts');
|
|
1669
|
+
const home = homeAt(declPath);
|
|
1670
|
+
if (!home || home.reach === null)
|
|
1671
|
+
return null;
|
|
1672
|
+
if (!validEdge(resolve(dirname(input.fileName), home.reach.slice(1, -1))))
|
|
1673
|
+
return null;
|
|
1674
|
+
return home;
|
|
1675
|
+
};
|
|
1676
|
+
/**
|
|
1677
|
+
* How `name`, used inside `home`'s own text, must be spelled in the JS file
|
|
1678
|
+
* this overlay is rewriting: itself, if `home`'s module genuinely exports
|
|
1679
|
+
* it (an import is recorded as a side effect), or an inlined definition if
|
|
1680
|
+
* it does not -- exactly `spellingOf`'s own decision, generalized to any
|
|
1681
|
+
* `home` a nested reference has walked to.
|
|
1682
|
+
*/
|
|
1683
|
+
const resolveNameFrom = (name, home, depth, visiting) => {
|
|
1684
|
+
if (AMBIENT_TYPE_NAMES.has(name) || boundHere.has(name))
|
|
1685
|
+
return name;
|
|
1686
|
+
const target = homeFor(name, home);
|
|
1687
|
+
if (!target)
|
|
1688
|
+
return null;
|
|
1689
|
+
if (target.reach !== null) {
|
|
1690
|
+
const jsTarget = resolve(dirname(input.fileName), target.reach.slice(1, -1));
|
|
1691
|
+
if (jsExportsOf(jsTarget).has(name)) {
|
|
1692
|
+
alsoFrom.set(name, target.reach);
|
|
1693
|
+
required.add(name);
|
|
1694
|
+
return factoryExportsOf(jsTarget).has(name) ? `ReturnType<${name}>` : name;
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
return inlineAt(name, target, depth, visiting);
|
|
1698
|
+
};
|
|
1699
|
+
/**
|
|
1700
|
+
* `text` with every occurrence of `name` respelled as `spelling`, or `null`
|
|
1701
|
+
* when one of them cannot be.
|
|
1702
|
+
*
|
|
1703
|
+
* ⛔ A JSDoc NAMEPATH's head must be a NAME. `{TypedArray.constructor}` is a
|
|
1704
|
+
* type this compiler cannot read, so the overlay reaches for the alias body --
|
|
1705
|
+
* and `@types/three` spells `TypedArray` as a nine-arm union, which turns the
|
|
1706
|
+
* tag into `{(Int8Array | ... | Float64Array).constructor}`: a parenthesized
|
|
1707
|
+
* union with a property access on it, which JSDoc has no grammar for. The
|
|
1708
|
+
* file stops parsing (`'}' expected.`), and a file the checker cannot parse
|
|
1709
|
+
* answers every question about itself from a broken tree rather than
|
|
1710
|
+
* refusing.
|
|
1711
|
+
*
|
|
1712
|
+
* So refuse: the tag keeps the spelling three wrote, the parameter stays
|
|
1713
|
+
* whatever the checker already made of it, and nothing downstream is told a
|
|
1714
|
+
* type that is not there. A box is a worse answer than a real carrier and a
|
|
1715
|
+
* far better one than an unparseable module.
|
|
1716
|
+
*
|
|
1717
|
+
* Only the namepath HEAD is affected. A union substituted into an ordinary
|
|
1718
|
+
* position (`{TypedArray|Array}`) or a type argument (`{Array<TypedArray>}`)
|
|
1719
|
+
* is valid JSDoc and is respelled as before.
|
|
1720
|
+
*/
|
|
1721
|
+
const respelledName = (text, name, spelling) => {
|
|
1722
|
+
const isName = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*$/.test(spelling);
|
|
1723
|
+
if (!isName && new RegExp(`\\b${name}\\b\\s*\\.`).test(text))
|
|
1724
|
+
return null;
|
|
1725
|
+
return text.replace(new RegExp(`\\b${name}\\b`, 'g'), spelling);
|
|
1726
|
+
};
|
|
1727
|
+
/** `text`, as declared inside `home`, with every name it refers to resolved from `home`'s own scope. */
|
|
1728
|
+
const respellUsing = (text, home, depth, visiting) => {
|
|
1729
|
+
const names = typeNamesIn(text);
|
|
1730
|
+
if (!names)
|
|
1731
|
+
return null;
|
|
1732
|
+
let spelled = text;
|
|
1733
|
+
for (const rawName of [...new Set(names)]) {
|
|
1734
|
+
const resolved = resolveNameFrom(rawName, home, depth, visiting);
|
|
1735
|
+
if (resolved === null)
|
|
1736
|
+
return null;
|
|
1737
|
+
if (resolved === rawName)
|
|
1738
|
+
continue;
|
|
1739
|
+
const next = respelledName(spelled, rawName, resolved);
|
|
1740
|
+
if (next === null)
|
|
1741
|
+
return null;
|
|
1742
|
+
spelled = next;
|
|
1743
|
+
}
|
|
1744
|
+
return spelled;
|
|
1745
|
+
};
|
|
1746
|
+
/**
|
|
1747
|
+
* `text` with every type name it refers to spelled as this file must spell
|
|
1748
|
+
* it, or `null` if `spellingOf` refuses one of them -- see `spellingOf`.
|
|
1749
|
+
*/
|
|
1750
|
+
const respell = (text) => {
|
|
1751
|
+
const names = typeNamesIn(text);
|
|
1752
|
+
if (!names)
|
|
1753
|
+
return text;
|
|
1754
|
+
let spelled = text;
|
|
1755
|
+
for (const name of [...new Set(names)]) {
|
|
1756
|
+
const spelling = spellingOf(name);
|
|
1757
|
+
if (spelling === null)
|
|
1758
|
+
return null;
|
|
1759
|
+
if (spelling === name)
|
|
1760
|
+
continue;
|
|
1761
|
+
const next = respelledName(spelled, name, spelling);
|
|
1762
|
+
if (next === null)
|
|
1763
|
+
return null;
|
|
1764
|
+
spelled = next;
|
|
1765
|
+
}
|
|
1766
|
+
return spelled;
|
|
1767
|
+
};
|
|
1768
|
+
const canSupply = (name) => {
|
|
1769
|
+
if (AMBIENT_TYPE_NAMES.has(name) || boundHere.has(name))
|
|
1770
|
+
return false;
|
|
1771
|
+
// A leaf name `respell` already reached through an inlined interface or
|
|
1772
|
+
// alias -- possibly over an edge rebased from a nested declaration file,
|
|
1773
|
+
// which `overlay.importedFrom` alone does not know about. It is already
|
|
1774
|
+
// registered; this is just recognizing that.
|
|
1775
|
+
if (alsoFrom.has(name)) {
|
|
1776
|
+
required.add(name);
|
|
1777
|
+
return true;
|
|
1778
|
+
}
|
|
1779
|
+
let specifier = overlay.importedFrom.get(name);
|
|
1780
|
+
if (specifier === undefined) {
|
|
1781
|
+
// A declaration may import a union alias while the source's JSDoc
|
|
1782
|
+
// spells its constituent constants. Those names must come from one
|
|
1783
|
+
// unambiguous, already-declared module edge, not a program-wide guess.
|
|
1784
|
+
const candidates = new Map();
|
|
1785
|
+
for (const imported of new Set(overlay.importedFrom.values())) {
|
|
1786
|
+
const text = imported.slice(1, -1);
|
|
1787
|
+
if (!text.startsWith('.'))
|
|
1788
|
+
continue;
|
|
1789
|
+
const target = resolve(dirname(input.fileName), text);
|
|
1790
|
+
if (validEdge(target) && jsExportsOf(target).has(name))
|
|
1791
|
+
candidates.set(target, imported);
|
|
1792
|
+
}
|
|
1793
|
+
if (candidates.size !== 1)
|
|
1794
|
+
return false;
|
|
1795
|
+
specifier = [...candidates.values()][0];
|
|
1796
|
+
alsoFrom.set(name, specifier);
|
|
1797
|
+
}
|
|
1798
|
+
const text = specifier.slice(1, -1);
|
|
1799
|
+
if (!text.startsWith('.'))
|
|
1800
|
+
return false;
|
|
1801
|
+
const target = resolve(dirname(input.fileName), text);
|
|
1802
|
+
if (!existsSync(target))
|
|
1803
|
+
return false;
|
|
1804
|
+
// The edge must not point back at this file: see `modulesReachableFrom`.
|
|
1805
|
+
if (target === input.fileName || modulesReachableFrom(target).has(input.fileName))
|
|
1806
|
+
return false;
|
|
1807
|
+
if (!jsExportsOf(target).has(name))
|
|
1808
|
+
return false;
|
|
1809
|
+
required.add(name);
|
|
1810
|
+
return true;
|
|
1811
|
+
};
|
|
1812
|
+
/** The `@type` line this field earns, or `null` where anything is unclear. */
|
|
1813
|
+
const fieldTypeFor = (className, property) => {
|
|
1814
|
+
const stated = overlay.fields.get(`${className}.${property}`);
|
|
1815
|
+
if (stated === undefined)
|
|
1816
|
+
return null;
|
|
1817
|
+
const text = respell(stated);
|
|
1818
|
+
if (text === null || text.length === 0 || text.includes('*/'))
|
|
1819
|
+
return null;
|
|
1820
|
+
const names = typeNamesIn(text);
|
|
1821
|
+
if (!names)
|
|
1822
|
+
return null;
|
|
1823
|
+
const needed = [];
|
|
1824
|
+
for (const name of names) {
|
|
1825
|
+
if (AMBIENT_TYPE_NAMES.has(name))
|
|
1826
|
+
continue;
|
|
1827
|
+
if (!canSupply(name))
|
|
1828
|
+
return null;
|
|
1829
|
+
needed.push(name);
|
|
1830
|
+
}
|
|
1831
|
+
void needed;
|
|
1832
|
+
return text;
|
|
1833
|
+
};
|
|
1834
|
+
const considerFields = (node) => {
|
|
1835
|
+
const className = node.name?.text;
|
|
1836
|
+
if (!className)
|
|
1837
|
+
return;
|
|
1838
|
+
const constructor = node.members.find(ts.isConstructorDeclaration);
|
|
1839
|
+
if (!constructor?.body)
|
|
1840
|
+
return;
|
|
1841
|
+
const annotated = new Set();
|
|
1842
|
+
for (const statement of constructor.body.statements) {
|
|
1843
|
+
if (!ts.isExpressionStatement(statement))
|
|
1844
|
+
continue;
|
|
1845
|
+
const expression = statement.expression;
|
|
1846
|
+
if (!ts.isBinaryExpression(expression) || expression.operatorToken.kind !== ts.SyntaxKind.EqualsToken)
|
|
1847
|
+
continue;
|
|
1848
|
+
const target = expression.left;
|
|
1849
|
+
if (!ts.isPropertyAccessExpression(target) || target.expression.kind !== ts.SyntaxKind.ThisKeyword)
|
|
1850
|
+
continue;
|
|
1851
|
+
const property = target.name.text;
|
|
1852
|
+
if (annotated.has(property))
|
|
1853
|
+
continue;
|
|
1854
|
+
if (ts.getJSDocTags(statement).length > 0 || ts.getJSDocCommentsAndTags(statement).length > 0)
|
|
1855
|
+
continue;
|
|
1856
|
+
const text = fieldTypeFor(className, property);
|
|
1857
|
+
if (text === null)
|
|
1858
|
+
continue;
|
|
1859
|
+
annotated.add(property);
|
|
1860
|
+
const start = statement.getStart(file);
|
|
1861
|
+
const lineStart = file.getLineStarts()[file.getLineAndCharacterOfPosition(start).line] ?? start;
|
|
1862
|
+
const indent = input.text.slice(lineStart, start).replace(/[^\t ]/g, '');
|
|
1863
|
+
edits.push({ at: start, end: start, text: `/** @type {${text}} */\n${indent}` });
|
|
1864
|
+
}
|
|
1865
|
+
};
|
|
1866
|
+
/**
|
|
1867
|
+
* A `@param` tag whose STATED type says nothing -- three writes
|
|
1868
|
+
* `@param {Object} json` for `fromJSON( json )` and `@param {object}
|
|
1869
|
+
* parameters` for a parameters bag, while the declaration file states
|
|
1870
|
+
* `MaterialJSON` and `WebGLProgramParameters` for the very same positions.
|
|
1871
|
+
* A vague tag is a program stating strictly LESS than the package's own
|
|
1872
|
+
* declaration file already ships, so the declared type wins -- as a
|
|
1873
|
+
* REPLACEMENT over the existing tag's type-expression span, never a second
|
|
1874
|
+
* `@param` line.
|
|
1875
|
+
*/
|
|
1876
|
+
const VAGUE_PARAM_TYPES = new Set(['Object', 'object', 'any', '*', 'Array', 'Function']);
|
|
1877
|
+
const jsDocParameterTagsOf = (owner) => ts.getJSDocTags(owner).filter(ts.isJSDocParameterTag);
|
|
1878
|
+
/**
|
|
1879
|
+
* Replace every VAGUE existing `@param` tag's type span with what the
|
|
1880
|
+
* declaration file states for that same position, respelled for this file.
|
|
1881
|
+
*
|
|
1882
|
+
* Matched by NAME rather than position: an assigned method's JSDoc may list
|
|
1883
|
+
* parameters in the JS's own order, which is what `getJSDocParameterTags`
|
|
1884
|
+
* already keys off, so following the same key keeps this aligned with how
|
|
1885
|
+
* the checker itself reads the tag.
|
|
1886
|
+
*/
|
|
1887
|
+
const replaceVagueParamTags = (jsSignature, declared, tags) => {
|
|
1888
|
+
const indexOfParam = new Map();
|
|
1889
|
+
jsSignature.parameters.forEach((parameter, index) => {
|
|
1890
|
+
if (ts.isIdentifier(parameter.name))
|
|
1891
|
+
indexOfParam.set(parameter.name.text, index);
|
|
1892
|
+
});
|
|
1893
|
+
for (const tag of tags) {
|
|
1894
|
+
if (!tag.typeExpression || !ts.isIdentifier(tag.name))
|
|
1895
|
+
continue;
|
|
1896
|
+
const typeNode = tag.typeExpression.type;
|
|
1897
|
+
const stated = statedTypeTextOf(typeNode, file);
|
|
1898
|
+
if (!VAGUE_PARAM_TYPES.has(stated))
|
|
1899
|
+
continue;
|
|
1900
|
+
const index = indexOfParam.get(tag.name.text);
|
|
1901
|
+
if (index === undefined)
|
|
1902
|
+
continue;
|
|
1903
|
+
const counterpart = counterpartOf(jsSignature, declared, index);
|
|
1904
|
+
if (!counterpart || !counterpart.type || !ts.isIdentifier(counterpart.name))
|
|
1905
|
+
continue;
|
|
1906
|
+
// ⛔ Against the DECLARED parameter's own source file, never `file` --
|
|
1907
|
+
// reading its text through the JS file being rewritten silently yields
|
|
1908
|
+
// the wrong span.
|
|
1909
|
+
const declaredText = statedTypeTextOf(counterpart.type, counterpart.getSourceFile());
|
|
1910
|
+
if (STATES_NOTHING.has(declaredText))
|
|
1911
|
+
continue;
|
|
1912
|
+
const text = respell(declaredText);
|
|
1913
|
+
if (text === null ||
|
|
1914
|
+
text.length === 0 ||
|
|
1915
|
+
text === stated ||
|
|
1916
|
+
text.includes('*/') ||
|
|
1917
|
+
recordInsideContainer(text) ||
|
|
1918
|
+
statesNothingWithin(text))
|
|
1919
|
+
continue;
|
|
1920
|
+
for (const name of typeNamesIn(text) ?? [])
|
|
1921
|
+
canSupply(name);
|
|
1922
|
+
edits.push({ at: typeNode.getStart(file), end: typeNode.getEnd(), text });
|
|
1923
|
+
}
|
|
1924
|
+
};
|
|
1925
|
+
const consider = (node, key, anchor = node) => {
|
|
1926
|
+
if (!key)
|
|
1927
|
+
return;
|
|
1928
|
+
const declared = overlay.signatures.get(key);
|
|
1929
|
+
if (declared)
|
|
1930
|
+
considerDeclared(node, declared, anchor);
|
|
1931
|
+
};
|
|
1932
|
+
/** `node`'s missing `@param` lines from `declared`, anchored where the checker reads them -- see `consider`. */
|
|
1933
|
+
const considerDeclared = (node, declared, anchor) => {
|
|
1934
|
+
const existingTags = [...jsDocParameterTagsOf(node), ...(anchor !== node ? jsDocParameterTagsOf(anchor) : [])];
|
|
1935
|
+
if (existingTags.length > 0) {
|
|
1936
|
+
replaceVagueParamTags(node, declared, existingTags);
|
|
1937
|
+
return;
|
|
1938
|
+
}
|
|
1939
|
+
const { lines, names } = paramLinesFor(node, declared, respell);
|
|
1940
|
+
if (lines.length === 0)
|
|
1941
|
+
return;
|
|
1942
|
+
for (const name of names)
|
|
1943
|
+
canSupply(name);
|
|
1944
|
+
const start = anchor.getStart(file);
|
|
1945
|
+
const lineStart = file.getLineStarts()[file.getLineAndCharacterOfPosition(start).line] ?? start;
|
|
1946
|
+
const column = start - lineStart;
|
|
1947
|
+
const indent = input.text.slice(start - column, start).replace(/[^\t ]/g, '');
|
|
1948
|
+
edits.push({ at: start, end: start, text: `/**\n${lines.map((l) => indent + l).join('\n')}\n${indent} */\n${indent}` });
|
|
1949
|
+
};
|
|
1950
|
+
/**
|
|
1951
|
+
* `this.copyTextureToTexture = function ( ... ) { ... }` -- a member the
|
|
1952
|
+
* declaration file states as a METHOD and the source writes as an
|
|
1953
|
+
* assignment.
|
|
1954
|
+
*
|
|
1955
|
+
* three's renderer modules are factories, not classes: `WebGLTextures.js`
|
|
1956
|
+
* declares its functions locally and publishes them by assignment, and
|
|
1957
|
+
* `WebGLRenderer` writes a large part of its own surface the same way. The
|
|
1958
|
+
* declaration file describes every one of them as a method, so the types are
|
|
1959
|
+
* already shipped -- the walk simply never reached them, because a
|
|
1960
|
+
* `FunctionExpression` on the right of an `=` is not a `MethodDeclaration`.
|
|
1961
|
+
* `copyTextureToTexture` alone accounts for 418 boxed carriers and 72 of
|
|
1962
|
+
* the three.js app's unmet obligations.
|
|
1963
|
+
*
|
|
1964
|
+
* The JSDoc is anchored on the STATEMENT rather than the function, because
|
|
1965
|
+
* that is where the checker looks for an assignment's tags.
|
|
1966
|
+
*/
|
|
1967
|
+
const considerAssignedMethod = (node) => {
|
|
1968
|
+
if (!ts.isExpressionStatement(node))
|
|
1969
|
+
return;
|
|
1970
|
+
const expression = node.expression;
|
|
1971
|
+
if (!ts.isBinaryExpression(expression) || expression.operatorToken.kind !== ts.SyntaxKind.EqualsToken)
|
|
1972
|
+
return;
|
|
1973
|
+
const target = expression.left;
|
|
1974
|
+
if (!ts.isPropertyAccessExpression(target) || target.expression.kind !== ts.SyntaxKind.ThisKeyword)
|
|
1975
|
+
return;
|
|
1976
|
+
const value = expression.right;
|
|
1977
|
+
if (!ts.isFunctionExpression(value) && !ts.isArrowFunction(value))
|
|
1978
|
+
return;
|
|
1979
|
+
consider(value, target.name.text, node);
|
|
1980
|
+
};
|
|
1981
|
+
/**
|
|
1982
|
+
* A matched declaration owns this accessor's signature. In JS, a getter's
|
|
1983
|
+
* @type also supplies an unannotated setter's parameter type, even when the
|
|
1984
|
+
* declaration explicitly states a different write type. Publish each side
|
|
1985
|
+
* before the checker runs so no downstream census has to undo that inference.
|
|
1986
|
+
* This policy is limited to exact, own declarations, never a name inherited
|
|
1987
|
+
* through the method overlay's file-wide signature merge.
|
|
1988
|
+
*/
|
|
1989
|
+
const considerAccessor = (node) => {
|
|
1990
|
+
const key = accessorKey(node);
|
|
1991
|
+
if (key === null)
|
|
1992
|
+
return;
|
|
1993
|
+
const declared = overlay.accessors.get(key);
|
|
1994
|
+
if (declared === undefined)
|
|
1995
|
+
return;
|
|
1996
|
+
const getter = ts.isGetAccessorDeclaration(node);
|
|
1997
|
+
const parameter = node.parameters[0];
|
|
1998
|
+
if (!getter && (!parameter || !ts.isIdentifier(parameter.name) || parameter.type))
|
|
1999
|
+
return;
|
|
2000
|
+
if (getter && node.type)
|
|
2001
|
+
return;
|
|
2002
|
+
const type = ts.isGetAccessorDeclaration(declared) ? declared.type : declared.parameters[0]?.type;
|
|
2003
|
+
if (type === undefined)
|
|
2004
|
+
return;
|
|
2005
|
+
const text = respell(statedTypeTextOf(type, declared.getSourceFile()));
|
|
2006
|
+
if (text === null || text.length === 0 || text.includes('*/'))
|
|
2007
|
+
return;
|
|
2008
|
+
const tags = ts.getJSDocTags(node);
|
|
2009
|
+
// A setter annotated with a whole callable type is a different contract;
|
|
2010
|
+
// do not add a competing @param alongside it.
|
|
2011
|
+
if (!getter && tags.some(ts.isJSDocTypeTag))
|
|
2012
|
+
return;
|
|
2013
|
+
for (const name of typeNamesIn(text) ?? []) {
|
|
2014
|
+
if (!AMBIENT_TYPE_NAMES.has(name) && !boundHere.has(name) && !canSupply(name))
|
|
2015
|
+
return;
|
|
2016
|
+
}
|
|
2017
|
+
const existing = tags.filter((tag) => getter
|
|
2018
|
+
? ts.isJSDocTypeTag(tag) || ts.isJSDocReturnTag(tag)
|
|
2019
|
+
: ts.isJSDocParameterTag(tag) && ts.isIdentifier(tag.name) && tag.name.text === parameter?.name.getText(file));
|
|
2020
|
+
if (existing.length > 0) {
|
|
2021
|
+
for (const tag of existing) {
|
|
2022
|
+
if (!tag.typeExpression)
|
|
2023
|
+
return;
|
|
2024
|
+
}
|
|
2025
|
+
for (const tag of existing) {
|
|
2026
|
+
if (tag.typeExpression) {
|
|
2027
|
+
declaredAccessorTypes.add(tag.typeExpression.type);
|
|
2028
|
+
edits.push({ at: tag.typeExpression.type.getStart(file), end: tag.typeExpression.type.getEnd(), text });
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
return;
|
|
2032
|
+
}
|
|
2033
|
+
const start = node.getStart(file);
|
|
2034
|
+
const lineStart = file.getLineStarts()[file.getLineAndCharacterOfPosition(start).line] ?? start;
|
|
2035
|
+
const indent = input.text.slice(lineStart, start).replace(/[^\t ]/g, '');
|
|
2036
|
+
const tag = getter ? `@returns {${text}}` : `@param {${text}} ${parameter?.name.getText(file)}`;
|
|
2037
|
+
edits.push({ at: start, end: start, text: `/** ${tag} */\n${indent}` });
|
|
2038
|
+
};
|
|
2039
|
+
// A function a record's owner states a member for answers to THAT member,
|
|
2040
|
+
// ahead of the flat by-name lookup -- which, for `setClear`, has no answer
|
|
2041
|
+
// at all. A function two owners claim with different declarations is
|
|
2042
|
+
// `null`: neither, and not the flat guess either.
|
|
2043
|
+
const recordMethods = recordMethodsIn(file, overlay.records);
|
|
2044
|
+
const walk = (node) => {
|
|
2045
|
+
const scoped = recordMethods.get(node);
|
|
2046
|
+
if (scoped !== undefined) {
|
|
2047
|
+
if (scoped !== null)
|
|
2048
|
+
considerDeclared(scoped.fn, scoped.declared, scoped.anchor);
|
|
2049
|
+
}
|
|
2050
|
+
else if (ts.isFunctionDeclaration(node))
|
|
2051
|
+
consider(node, nameOf(node));
|
|
2052
|
+
else if (ts.isMethodDeclaration(node))
|
|
2053
|
+
consider(node, nameOf(node));
|
|
2054
|
+
else if (ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node))
|
|
2055
|
+
considerAccessor(node);
|
|
2056
|
+
else if (ts.isConstructorDeclaration(node)) {
|
|
2057
|
+
const owner = node.parent;
|
|
2058
|
+
consider(node, ts.isClassDeclaration(owner) ? (owner.name?.text ?? null) : null);
|
|
2059
|
+
}
|
|
2060
|
+
else if (ts.isClassDeclaration(node))
|
|
2061
|
+
considerFields(node);
|
|
2062
|
+
else
|
|
2063
|
+
considerAssignedMethod(node);
|
|
2064
|
+
ts.forEachChild(node, walk);
|
|
2065
|
+
};
|
|
2066
|
+
walk(file);
|
|
2067
|
+
// The type names the SOURCE'S OWN JSDoc already uses. three writes
|
|
2068
|
+
// `@type {?Texture}` in files that never import `Texture` at runtime, and
|
|
2069
|
+
// memory of the earlier attempt records the consequence: the tag resolves to
|
|
2070
|
+
// `any`, so a field the program plainly stated is boxed anyway. The package's
|
|
2071
|
+
// own declaration tree knows where every one of those names lives, so this
|
|
2072
|
+
// brings them into scope and the tag starts meaning what it says. Nothing is
|
|
2073
|
+
// annotated here -- only the names the program ALREADY wrote are resolved.
|
|
2074
|
+
// The type names the SOURCE'S OWN JSDoc already uses. three writes
|
|
2075
|
+
// `@type {?Texture}` in files that never import `Texture` at runtime, and
|
|
2076
|
+
// the tag then resolves to `any` -- which, because `withJsDocTypeNames` is
|
|
2077
|
+
// OUTERMOST in the composed census, OUTRANKS the type the census would have
|
|
2078
|
+
// derived from the call site. Nothing is annotated here: only names the
|
|
2079
|
+
// program already wrote are brought into scope, and only over an edge
|
|
2080
|
+
// `canSupply` has proved does not point back at this file.
|
|
2081
|
+
/**
|
|
2082
|
+
* Resolve the names ONE tag the program already wrote refers to, and where
|
|
2083
|
+
* a name means something only the declaration tree can say, rewrite the tag
|
|
2084
|
+
* to say it directly.
|
|
2085
|
+
*
|
|
2086
|
+
* `WebGLState.js` writes `@param {BlendingSrcFactor} blendSrc` and
|
|
2087
|
+
* `BufferAttribute.js` writes `@param {TypedArray} array`. Both name pure
|
|
2088
|
+
* declaration-tree aliases, so no import can reach them and the tags have
|
|
2089
|
+
* always resolved to `any` -- which, `withJsDocTypeNames` being OUTERMOST,
|
|
2090
|
+
* OUTRANKS whatever the census derived. `respell` already knows how to say
|
|
2091
|
+
* such a name as the definition it stands for; this applies it to the tags
|
|
2092
|
+
* the program wrote, not only to the ones this overlay adds.
|
|
2093
|
+
*/
|
|
2094
|
+
const considerStatedType = (typeNode) => {
|
|
2095
|
+
if (declaredAccessorTypes.has(typeNode))
|
|
2096
|
+
return;
|
|
2097
|
+
const stated = statedTypeTextOf(typeNode, file);
|
|
2098
|
+
for (const name of typeNamesIn(stated) ?? [])
|
|
2099
|
+
canSupply(name);
|
|
2100
|
+
const spelled = respell(stated);
|
|
2101
|
+
if (spelled === null || spelled === stated || spelled.includes('*/'))
|
|
2102
|
+
return;
|
|
2103
|
+
edits.push({ at: typeNode.getStart(file), end: typeNode.getEnd(), text: spelled });
|
|
2104
|
+
};
|
|
2105
|
+
const scanJsDoc = (node) => {
|
|
2106
|
+
for (const tag of ts.getJSDocTags(node)) {
|
|
2107
|
+
const typeExpression = tag.typeExpression;
|
|
2108
|
+
if (typeExpression && ts.isJSDocTypeExpression(typeExpression))
|
|
2109
|
+
considerStatedType(typeExpression.type);
|
|
2110
|
+
}
|
|
2111
|
+
ts.forEachChild(node, scanJsDoc);
|
|
2112
|
+
};
|
|
2113
|
+
scanJsDoc(file);
|
|
2114
|
+
const bySpecifier = new Map();
|
|
2115
|
+
for (const name of [...required].sort()) {
|
|
2116
|
+
const specifier = overlay.importedFrom.get(name) ?? alsoFrom.get(name) ?? '""';
|
|
2117
|
+
const names = bySpecifier.get(specifier);
|
|
2118
|
+
if (names)
|
|
2119
|
+
names.push(name);
|
|
2120
|
+
else
|
|
2121
|
+
bySpecifier.set(specifier, [name]);
|
|
2122
|
+
}
|
|
2123
|
+
const header = [...bySpecifier].map(([specifier, names]) => `/** @import { ${names.join(', ')} } from ${specifier} */`);
|
|
2124
|
+
if (edits.length === 0 && header.length === 0)
|
|
2125
|
+
return null;
|
|
2126
|
+
// ⛔ NON-OVERLAPPING, and that is not a tidiness rule -- two edits over the
|
|
2127
|
+
// same text corrupt the file.
|
|
2128
|
+
//
|
|
2129
|
+
// Applying descending by `at` is what makes each edit's offsets still valid
|
|
2130
|
+
// in the text the previous ones already rewrote, and it holds for edits that
|
|
2131
|
+
// do not overlap. Two that DO overlap break it: the second's `end` lands
|
|
2132
|
+
// inside the first's inserted text, so the splice keeps a fragment of the
|
|
2133
|
+
// insertion and drops real source. Three's `AnimationUtils.js` is the
|
|
2134
|
+
// measured case -- `@param {TypedArray.constructor}` collected an edit for
|
|
2135
|
+
// the namepath AND one for the `TypedArray` inside it, both starting at the
|
|
2136
|
+
// same offset, and came out as
|
|
2137
|
+
// `{(| Int8Array | ... ).constructorray | Uint8ClampedArray | ... }`:
|
|
2138
|
+
// syntactically invalid JavaScript. 58 `'}' expected.` diagnostics across
|
|
2139
|
+
// three's `animation/` modules, every one of them a file whose whole
|
|
2140
|
+
// semantics the checker then answered from a broken parse.
|
|
2141
|
+
//
|
|
2142
|
+
// The OUTERMOST edit wins, which is why the accept order is by `at`
|
|
2143
|
+
// ascending and `end` descending: an edit that spells a whole namepath
|
|
2144
|
+
// states more than one that respells a name inside it, and dropping the
|
|
2145
|
+
// wider one to keep the narrower would leave the namepath half-rewritten.
|
|
2146
|
+
const accepted = [];
|
|
2147
|
+
for (const edit of [...edits].sort((a, b) => a.at - b.at || b.end - a.end)) {
|
|
2148
|
+
const last = accepted[accepted.length - 1];
|
|
2149
|
+
if (last && edit.at < last.end)
|
|
2150
|
+
continue;
|
|
2151
|
+
accepted.push(edit);
|
|
2152
|
+
}
|
|
2153
|
+
let text = input.text;
|
|
2154
|
+
for (const edit of [...accepted].sort((a, b) => b.at - a.at))
|
|
2155
|
+
text = text.slice(0, edit.at) + edit.text + text.slice(edit.end);
|
|
2156
|
+
return header.length > 0 ? `${header.join('\n')}\n${text}` : text;
|
|
2157
|
+
};
|