@scriptc/compiler 0.4.5 → 0.4.6
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/ambient/node-fallback/assert-strict.d.ts +47 -0
- package/ambient/node-fallback/assert.d.ts +86 -0
- package/ambient/node-fallback/async_hooks.d.ts +41 -0
- package/ambient/node-fallback/buffer.d.ts +23 -0
- package/ambient/node-fallback/child_process.d.ts +242 -0
- package/ambient/node-fallback/cluster.d.ts +17 -0
- package/ambient/node-fallback/constants.d.ts +15 -0
- package/ambient/node-fallback/crypto.d.ts +837 -0
- package/ambient/node-fallback/dgram.d.ts +58 -0
- package/ambient/node-fallback/diagnostics_channel.d.ts +87 -0
- package/ambient/node-fallback/dns-promises.d.ts +27 -0
- package/ambient/node-fallback/dns.d.ts +65 -0
- package/ambient/node-fallback/events.d.ts +60 -0
- package/ambient/node-fallback/fs-promises.d.ts +225 -0
- package/ambient/node-fallback/fs.d.ts +641 -0
- package/ambient/node-fallback/graceful-fs.d.ts +9 -0
- package/ambient/node-fallback/http.d.ts +326 -0
- package/ambient/node-fallback/http2.d.ts +816 -0
- package/ambient/node-fallback/https.d.ts +59 -0
- package/ambient/node-fallback/module.d.ts +10 -0
- package/ambient/node-fallback/net.d.ts +374 -0
- package/ambient/node-fallback/os.d.ts +288 -0
- package/ambient/node-fallback/path-posix.d.ts +22 -0
- package/ambient/node-fallback/path-win32.d.ts +22 -0
- package/ambient/node-fallback/path.d.ts +55 -0
- package/ambient/node-fallback/process.d.ts +11 -0
- package/ambient/node-fallback/punycode.d.ts +18 -0
- package/ambient/node-fallback/querystring.d.ts +55 -0
- package/ambient/node-fallback/stream-consumers.d.ts +21 -0
- package/ambient/node-fallback/stream-promises.d.ts +28 -0
- package/ambient/node-fallback/stream-web.d.ts +36 -0
- package/ambient/node-fallback/stream.d.ts +644 -0
- package/ambient/node-fallback/string_decoder.d.ts +20 -0
- package/ambient/node-fallback/test.d.ts +236 -0
- package/ambient/node-fallback/timers-promises.d.ts +31 -0
- package/ambient/node-fallback/timers.d.ts +28 -0
- package/ambient/node-fallback/tls.d.ts +169 -0
- package/ambient/node-fallback/url.d.ts +95 -0
- package/ambient/node-fallback/util-types.d.ts +50 -0
- package/ambient/node-fallback/util.d.ts +416 -0
- package/ambient/node-fallback/v8.d.ts +43 -0
- package/ambient/node-fallback/worker_threads.d.ts +113 -0
- package/ambient/node-fallback/zlib.d.ts +422 -0
- package/ambient/scriptc-node-fallback.d.ts +224 -6688
- package/dist/backend/cycle-analysis.js +4 -0
- package/dist/backend/cycle-analysis.js.map +1 -1
- package/dist/backend/executable-features.d.ts +1 -1
- package/dist/backend/executable-features.js +15 -2
- package/dist/backend/executable-features.js.map +1 -1
- package/dist/backend/huge-text.d.ts +16 -0
- package/dist/backend/huge-text.js +103 -0
- package/dist/backend/huge-text.js.map +1 -0
- package/dist/backend/huge-text.test.d.ts +1 -0
- package/dist/backend/huge-text.test.js +73 -0
- package/dist/backend/huge-text.test.js.map +1 -0
- package/dist/backend/library-pack.js +1 -1
- package/dist/backend/library-pack.js.map +1 -1
- package/dist/backend/link-plan-core.d.ts +10 -0
- package/dist/backend/link-plan-core.js +14 -2
- package/dist/backend/link-plan-core.js.map +1 -1
- package/dist/backend/link-plan-core.test.d.ts +1 -0
- package/dist/backend/link-plan-core.test.js +20 -0
- package/dist/backend/link-plan-core.test.js.map +1 -0
- package/dist/backend/link-plan.d.ts +8 -0
- package/dist/backend/link-plan.js +7 -0
- package/dist/backend/link-plan.js.map +1 -1
- package/dist/backend/linker.js +37 -14
- package/dist/backend/linker.js.map +1 -1
- package/dist/backend/lld.d.ts +13 -0
- package/dist/backend/lld.js +18 -1
- package/dist/backend/lld.js.map +1 -1
- package/dist/backend/lld.test.js +7 -1
- package/dist/backend/lld.test.js.map +1 -1
- package/dist/backend/llvm/alloc.d.ts +2 -0
- package/dist/backend/llvm/alloc.js +1 -1
- package/dist/backend/llvm/alloc.js.map +1 -1
- package/dist/backend/llvm/arenas.d.ts +78 -0
- package/dist/backend/llvm/arenas.js +313 -0
- package/dist/backend/llvm/arenas.js.map +1 -0
- package/dist/backend/llvm/arenas.test.d.ts +1 -0
- package/dist/backend/llvm/arenas.test.js +140 -0
- package/dist/backend/llvm/arenas.test.js.map +1 -0
- package/dist/backend/llvm/blocks.d.ts +11 -1
- package/dist/backend/llvm/blocks.js +23 -5
- package/dist/backend/llvm/blocks.js.map +1 -1
- package/dist/backend/llvm/bytes-headers.d.ts +19 -0
- package/dist/backend/llvm/bytes-headers.js +55 -0
- package/dist/backend/llvm/bytes-headers.js.map +1 -0
- package/dist/backend/llvm/bytes-loop-versions.d.ts +4 -3
- package/dist/backend/llvm/bytes-loop-versions.js +42 -7
- package/dist/backend/llvm/bytes-loop-versions.js.map +1 -1
- package/dist/backend/llvm/bytes-loop-versions.test.js +39 -4
- package/dist/backend/llvm/bytes-loop-versions.test.js.map +1 -1
- package/dist/backend/llvm/call-lifetimes.d.ts +5 -0
- package/dist/backend/llvm/call-lifetimes.js +43 -8
- package/dist/backend/llvm/call-lifetimes.js.map +1 -1
- package/dist/backend/llvm/call-lifetimes.test.js +26 -0
- package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/checked-narrows.d.ts +3 -0
- package/dist/backend/llvm/checked-narrows.js +8 -1
- package/dist/backend/llvm/checked-narrows.js.map +1 -1
- package/dist/backend/llvm/class-unions.d.ts +21 -0
- package/dist/backend/llvm/class-unions.js +141 -0
- package/dist/backend/llvm/class-unions.js.map +1 -0
- package/dist/backend/llvm/class-unions.test.d.ts +1 -0
- package/dist/backend/llvm/class-unions.test.js +137 -0
- package/dist/backend/llvm/class-unions.test.js.map +1 -0
- package/dist/backend/llvm/classes.d.ts +46 -8
- package/dist/backend/llvm/classes.js +259 -32
- package/dist/backend/llvm/classes.js.map +1 -1
- package/dist/backend/llvm/classes.test.js +4 -0
- package/dist/backend/llvm/classes.test.js.map +1 -1
- package/dist/backend/llvm/common.d.ts +23 -0
- package/dist/backend/llvm/common.js +34 -0
- package/dist/backend/llvm/common.js.map +1 -1
- package/dist/backend/llvm/constant-callbacks.test.js +39 -0
- package/dist/backend/llvm/constant-callbacks.test.js.map +1 -1
- package/dist/backend/llvm/constant-choices.d.ts +32 -0
- package/dist/backend/llvm/constant-choices.js +209 -0
- package/dist/backend/llvm/constant-choices.js.map +1 -0
- package/dist/backend/llvm/constant-choices.test.d.ts +1 -0
- package/dist/backend/llvm/constant-choices.test.js +94 -0
- package/dist/backend/llvm/constant-choices.test.js.map +1 -0
- package/dist/backend/llvm/counted-loops.d.ts +14 -2
- package/dist/backend/llvm/counted-loops.js +60 -7
- package/dist/backend/llvm/counted-loops.js.map +1 -1
- package/dist/backend/llvm/counted-loops.test.d.ts +1 -0
- package/dist/backend/llvm/counted-loops.test.js +34 -0
- package/dist/backend/llvm/counted-loops.test.js.map +1 -0
- package/dist/backend/llvm/cpu-dispatch.d.ts +26 -0
- package/dist/backend/llvm/cpu-dispatch.js +279 -0
- package/dist/backend/llvm/cpu-dispatch.js.map +1 -0
- package/dist/backend/llvm/dense-array-access.d.ts +13 -2
- package/dist/backend/llvm/dense-array-access.js +60 -6
- package/dist/backend/llvm/dense-array-access.js.map +1 -1
- package/dist/backend/llvm/dyn-handle-tags.test.js +40 -14
- package/dist/backend/llvm/dyn-handle-tags.test.js.map +1 -1
- package/dist/backend/llvm/dyn.d.ts +28 -2
- package/dist/backend/llvm/dyn.js +176 -27
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emit-function.js +25 -3
- package/dist/backend/llvm/emit-function.js.map +1 -1
- package/dist/backend/llvm/emit-journal.d.ts +1 -0
- package/dist/backend/llvm/emit-journal.js.map +1 -1
- package/dist/backend/llvm/emit-module.d.ts +5 -3
- package/dist/backend/llvm/emit-module.js +362 -74
- package/dist/backend/llvm/emit-module.js.map +1 -1
- package/dist/backend/llvm/emit-statements.js +327 -59
- package/dist/backend/llvm/emit-statements.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +223 -33
- package/dist/backend/llvm/emitter.js +713 -100
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/emitter.test.js +20 -1
- package/dist/backend/llvm/emitter.test.js.map +1 -1
- package/dist/backend/llvm/expr-async.js +32 -6
- package/dist/backend/llvm/expr-async.js.map +1 -1
- package/dist/backend/llvm/expr-bytes.d.ts +9 -1
- package/dist/backend/llvm/expr-bytes.js +105 -9
- package/dist/backend/llvm/expr-bytes.js.map +1 -1
- package/dist/backend/llvm/expr-callbacks.d.ts +1 -1
- package/dist/backend/llvm/expr-callbacks.js +29 -22
- package/dist/backend/llvm/expr-callbacks.js.map +1 -1
- package/dist/backend/llvm/expr-calls.d.ts +0 -4
- package/dist/backend/llvm/expr-calls.js +116 -14
- package/dist/backend/llvm/expr-calls.js.map +1 -1
- package/dist/backend/llvm/expr-containers.js +77 -12
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-context.d.ts +22 -0
- package/dist/backend/llvm/expr-control.d.ts +4 -0
- package/dist/backend/llvm/expr-control.js +485 -426
- package/dist/backend/llvm/expr-control.js.map +1 -1
- package/dist/backend/llvm/expr-dispatch.js +4 -0
- package/dist/backend/llvm/expr-dispatch.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +3 -3
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.d.ts +6 -0
- package/dist/backend/llvm/expr-primitives.js +119 -58
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.test.js +11 -2
- package/dist/backend/llvm/expr-primitives.test.js.map +1 -1
- package/dist/backend/llvm/expr-records.d.ts +36 -4
- package/dist/backend/llvm/expr-records.js +249 -37
- package/dist/backend/llvm/expr-records.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.js +124 -7
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.test.js +1 -1
- package/dist/backend/llvm/expr-stream-bridges.test.js.map +1 -1
- package/dist/backend/llvm/expr-stream-callbacks.js +13 -14
- package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
- package/dist/backend/llvm/frame-escapes.d.ts +11 -0
- package/dist/backend/llvm/frame-escapes.js +219 -0
- package/dist/backend/llvm/frame-escapes.js.map +1 -0
- package/dist/backend/llvm/function-layout.d.ts +15 -0
- package/dist/backend/llvm/function-layout.js +40 -0
- package/dist/backend/llvm/function-layout.js.map +1 -0
- package/dist/backend/llvm/heap-census.d.ts +34 -0
- package/dist/backend/llvm/heap-census.js +163 -0
- package/dist/backend/llvm/heap-census.js.map +1 -0
- package/dist/backend/llvm/inline-arrays.d.ts +41 -0
- package/dist/backend/llvm/inline-arrays.js +195 -0
- package/dist/backend/llvm/inline-arrays.js.map +1 -0
- package/dist/backend/llvm/int32-kind-loops.js +2 -0
- package/dist/backend/llvm/int32-kind-loops.js.map +1 -1
- package/dist/backend/llvm/integer-clones.d.ts +32 -5
- package/dist/backend/llvm/integer-clones.js +237 -44
- package/dist/backend/llvm/integer-clones.js.map +1 -1
- package/dist/backend/llvm/integer-clones.test.js +120 -0
- package/dist/backend/llvm/integer-clones.test.js.map +1 -1
- package/dist/backend/llvm/iterative-teardown.test.d.ts +1 -0
- package/dist/backend/llvm/iterative-teardown.test.js +62 -0
- package/dist/backend/llvm/iterative-teardown.test.js.map +1 -0
- package/dist/backend/llvm/js-ic.js +246 -62
- package/dist/backend/llvm/js-ic.js.map +1 -1
- package/dist/backend/llvm/lib-connect.js +1 -1
- package/dist/backend/llvm/lib-connect.js.map +1 -1
- package/dist/backend/llvm/lib-datagram.js +2 -2
- package/dist/backend/llvm/lib-datagram.js.map +1 -1
- package/dist/backend/llvm/lib-dispatch.js +153 -16
- package/dist/backend/llvm/lib-dispatch.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.d.ts +8 -0
- package/dist/backend/llvm/lib-filesystem.js +48 -4
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-http2.js +4 -3
- package/dist/backend/llvm/lib-http2.js.map +1 -1
- package/dist/backend/llvm/lib-lookup.js +1 -1
- package/dist/backend/llvm/lib-lookup.js.map +1 -1
- package/dist/backend/llvm/lib-network.js +15 -1
- package/dist/backend/llvm/lib-network.js.map +1 -1
- package/dist/backend/llvm/lib-process.js +32 -8
- package/dist/backend/llvm/lib-process.js.map +1 -1
- package/dist/backend/llvm/lib-shared.d.ts +3 -0
- package/dist/backend/llvm/lib-shared.js +191 -28
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/lib-stream.js +1 -1
- package/dist/backend/llvm/lib-stream.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.js +15 -1
- package/dist/backend/llvm/local-array-reads.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.test.js +1 -1
- package/dist/backend/llvm/local-array-reads.test.js.map +1 -1
- package/dist/backend/llvm/local-extents.d.ts +22 -0
- package/dist/backend/llvm/local-extents.js +102 -0
- package/dist/backend/llvm/local-extents.js.map +1 -1
- package/dist/backend/llvm/local-union-storage.js +15 -2
- package/dist/backend/llvm/local-union-storage.js.map +1 -1
- package/dist/backend/llvm/local-union-storage.test.js +1 -1
- package/dist/backend/llvm/local-union-storage.test.js.map +1 -1
- package/dist/backend/llvm/loop-callees.d.ts +21 -0
- package/dist/backend/llvm/loop-callees.js +119 -0
- package/dist/backend/llvm/loop-callees.js.map +1 -0
- package/dist/backend/llvm/loop-callees.test.d.ts +1 -0
- package/dist/backend/llvm/loop-callees.test.js +65 -0
- package/dist/backend/llvm/loop-callees.test.js.map +1 -0
- package/dist/backend/llvm/loop-entry-versions.d.ts +17 -0
- package/dist/backend/llvm/loop-entry-versions.js +185 -0
- package/dist/backend/llvm/loop-entry-versions.js.map +1 -0
- package/dist/backend/llvm/map-number-lookup.js.map +1 -1
- package/dist/backend/llvm/map-number-lookup.test.js +13 -4
- package/dist/backend/llvm/map-number-lookup.test.js.map +1 -1
- package/dist/backend/llvm/map-read-lifetimes.d.ts +11 -0
- package/dist/backend/llvm/map-read-lifetimes.js +51 -1
- package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
- package/dist/backend/llvm/map-read-lifetimes.test.js +6 -3
- package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/nullable-unions.d.ts +67 -10
- package/dist/backend/llvm/nullable-unions.js +218 -22
- package/dist/backend/llvm/nullable-unions.js.map +1 -1
- package/dist/backend/llvm/nullable-unions.test.js +124 -1
- package/dist/backend/llvm/nullable-unions.test.js.map +1 -1
- package/dist/backend/llvm/periodic-guards.d.ts +16 -0
- package/dist/backend/llvm/periodic-guards.js +91 -0
- package/dist/backend/llvm/periodic-guards.js.map +1 -0
- package/dist/backend/llvm/periodic-guards.test.d.ts +1 -0
- package/dist/backend/llvm/periodic-guards.test.js +64 -0
- package/dist/backend/llvm/periodic-guards.test.js.map +1 -0
- package/dist/backend/llvm/publish.d.ts +12 -2
- package/dist/backend/llvm/publish.js +15 -8
- package/dist/backend/llvm/publish.js.map +1 -1
- package/dist/backend/llvm/rebound-parameters.d.ts +4 -1
- package/dist/backend/llvm/rebound-parameters.js +17 -1
- package/dist/backend/llvm/rebound-parameters.js.map +1 -1
- package/dist/backend/llvm/receivers.d.ts +7 -0
- package/dist/backend/llvm/receivers.js +77 -10
- package/dist/backend/llvm/receivers.js.map +1 -1
- package/dist/backend/llvm/record-union-keys.test.js +29 -0
- package/dist/backend/llvm/record-union-keys.test.js.map +1 -1
- package/dist/backend/llvm/record-views.d.ts +29 -0
- package/dist/backend/llvm/record-views.js +249 -0
- package/dist/backend/llvm/record-views.js.map +1 -0
- package/dist/backend/llvm/record-views.test.d.ts +1 -0
- package/dist/backend/llvm/record-views.test.js +118 -0
- package/dist/backend/llvm/record-views.test.js.map +1 -0
- package/dist/backend/llvm/reference-writes.js +21 -0
- package/dist/backend/llvm/reference-writes.js.map +1 -1
- package/dist/backend/llvm/reference-writes.test.js +42 -0
- package/dist/backend/llvm/reference-writes.test.js.map +1 -1
- package/dist/backend/llvm/regex-matchers.d.ts +5 -1
- package/dist/backend/llvm/regex-matchers.js +173 -21
- package/dist/backend/llvm/regex-matchers.js.map +1 -1
- package/dist/backend/llvm/regex-matchers.test.js +39 -1
- package/dist/backend/llvm/regex-matchers.test.js.map +1 -1
- package/dist/backend/llvm/region-groups.d.ts +67 -0
- package/dist/backend/llvm/region-groups.js +1719 -0
- package/dist/backend/llvm/region-groups.js.map +1 -0
- package/dist/backend/llvm/region-groups.test.d.ts +1 -0
- package/dist/backend/llvm/region-groups.test.js +197 -0
- package/dist/backend/llvm/region-groups.test.js.map +1 -0
- package/dist/backend/llvm/region-ir.d.ts +31 -0
- package/dist/backend/llvm/region-ir.js +256 -0
- package/dist/backend/llvm/region-ir.js.map +1 -0
- package/dist/backend/llvm/region-sites.d.ts +20 -0
- package/dist/backend/llvm/region-sites.js +327 -0
- package/dist/backend/llvm/region-sites.js.map +1 -0
- package/dist/backend/llvm/region-sites.test.d.ts +1 -0
- package/dist/backend/llvm/region-sites.test.js +216 -0
- package/dist/backend/llvm/region-sites.test.js.map +1 -0
- package/dist/backend/llvm/repr-report.d.ts +9 -0
- package/dist/backend/llvm/repr-report.js +143 -0
- package/dist/backend/llvm/repr-report.js.map +1 -0
- package/dist/backend/llvm/repr-report.test.d.ts +1 -0
- package/dist/backend/llvm/repr-report.test.js +62 -0
- package/dist/backend/llvm/repr-report.test.js.map +1 -0
- package/dist/backend/llvm/runtime-registries.test.d.ts +1 -0
- package/dist/backend/llvm/runtime-registries.test.js +88 -0
- package/dist/backend/llvm/runtime-registries.test.js.map +1 -0
- package/dist/backend/llvm/serialized-ir-emission.test.js +1 -0
- package/dist/backend/llvm/serialized-ir-emission.test.js.map +1 -1
- package/dist/backend/llvm/shape-union-tags.test.d.ts +1 -0
- package/dist/backend/llvm/shape-union-tags.test.js +75 -0
- package/dist/backend/llvm/shape-union-tags.test.js.map +1 -0
- package/dist/backend/llvm/shapes.d.ts +60 -10
- package/dist/backend/llvm/shapes.js +233 -51
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/shapes.test.js +37 -18
- package/dist/backend/llvm/shapes.test.js.map +1 -1
- package/dist/backend/llvm/speculative-integers.d.ts +3 -0
- package/dist/backend/llvm/speculative-integers.js +20 -8
- package/dist/backend/llvm/speculative-integers.js.map +1 -1
- package/dist/backend/llvm/split.js +6 -1
- package/dist/backend/llvm/split.js.map +1 -1
- package/dist/backend/llvm/split.test.js +23 -0
- package/dist/backend/llvm/split.test.js.map +1 -1
- package/dist/backend/llvm/stack-callbacks.js +4 -2
- package/dist/backend/llvm/stack-callbacks.js.map +1 -1
- package/dist/backend/llvm/stack-objects.d.ts +12 -3
- package/dist/backend/llvm/stack-objects.js +110 -22
- package/dist/backend/llvm/stack-objects.js.map +1 -1
- package/dist/backend/llvm/stack-objects.test.js +144 -0
- package/dist/backend/llvm/stack-objects.test.js.map +1 -1
- package/dist/backend/llvm/stack-unions.test.js +24 -1
- package/dist/backend/llvm/stack-unions.test.js.map +1 -1
- package/dist/backend/llvm/string-lifetimes.js +2 -1
- package/dist/backend/llvm/string-lifetimes.js.map +1 -1
- package/dist/backend/llvm/string-lifetimes.test.js +1 -1
- package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/string-reads.d.ts +4 -0
- package/dist/backend/llvm/string-reads.js +27 -0
- package/dist/backend/llvm/string-reads.js.map +1 -1
- package/dist/backend/llvm/test-boxed-unions.d.ts +10 -8
- package/dist/backend/llvm/test-boxed-unions.js +20 -25
- package/dist/backend/llvm/test-boxed-unions.js.map +1 -1
- package/dist/backend/llvm/union-repr.js +9 -8
- package/dist/backend/llvm/union-repr.js.map +1 -1
- package/dist/backend/llvm/union-retype.test.js +45 -2
- package/dist/backend/llvm/union-retype.test.js.map +1 -1
- package/dist/backend/llvm/unwind-abi.d.ts +20 -8
- package/dist/backend/llvm/unwind-abi.js +177 -70
- package/dist/backend/llvm/unwind-abi.js.map +1 -1
- package/dist/backend/llvm/unwind-abi.test.js +90 -3
- package/dist/backend/llvm/unwind-abi.test.js.map +1 -1
- package/dist/backend/llvm/walk-borrows.d.ts +3 -2
- package/dist/backend/llvm/walk-borrows.js +2 -2
- package/dist/backend/llvm/walk-borrows.js.map +1 -1
- package/dist/backend/llvm/walk-borrows.test.js +18 -0
- package/dist/backend/llvm/walk-borrows.test.js.map +1 -1
- package/dist/backend/llvm/walkers.d.ts +14 -1
- package/dist/backend/llvm/walkers.js +103 -11
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/backend/llvm/wrapping-sums.d.ts +26 -6
- package/dist/backend/llvm/wrapping-sums.js +64 -12
- package/dist/backend/llvm/wrapping-sums.js.map +1 -1
- package/dist/backend/loop-polls.d.ts +4 -2
- package/dist/backend/loop-polls.js +11 -2
- package/dist/backend/loop-polls.js.map +1 -1
- package/dist/backend/mangle.d.ts +0 -5
- package/dist/backend/mangle.js +0 -9
- package/dist/backend/mangle.js.map +1 -1
- package/dist/backend/may-throw.d.ts +10 -9
- package/dist/backend/may-throw.js +189 -27
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/may-throw.test.js +44 -7
- package/dist/backend/may-throw.test.js.map +1 -1
- package/dist/backend/native/compiler-fingerprint.d.ts +5 -0
- package/dist/backend/native/compiler-fingerprint.js +62 -16
- package/dist/backend/native/compiler-fingerprint.js.map +1 -1
- package/dist/backend/native/contracts.d.ts +31 -8
- package/dist/backend/native/executable.js +56 -32
- package/dist/backend/native/executable.js.map +1 -1
- package/dist/backend/native/library.js +3 -4
- package/dist/backend/native/library.js.map +1 -1
- package/dist/backend/native/object-merge.d.ts +3 -1
- package/dist/backend/native/object-merge.js +24 -11
- package/dist/backend/native/object-merge.js.map +1 -1
- package/dist/backend/native/program-shards.js +6 -3
- package/dist/backend/native/program-shards.js.map +1 -1
- package/dist/backend/native/runtime-inputs.d.ts +1 -1
- package/dist/backend/native/runtime-inputs.js +3 -0
- package/dist/backend/native/runtime-inputs.js.map +1 -1
- package/dist/backend/native/vendor.d.ts +1 -1
- package/dist/backend/native-codegen-core.d.ts +15 -6
- package/dist/backend/native-codegen-core.js +20 -9
- package/dist/backend/native-codegen-core.js.map +1 -1
- package/dist/backend/native-codegen.js +51 -5
- package/dist/backend/native-codegen.js.map +1 -1
- package/dist/backend/native-codegen.test.js +82 -8
- package/dist/backend/native-codegen.test.js.map +1 -1
- package/dist/backend/native-link-info-core.d.ts +30 -0
- package/dist/backend/native-link-info-core.js.map +1 -1
- package/dist/backend/native-profile.d.ts +68 -4
- package/dist/backend/native-profile.js +86 -14
- package/dist/backend/native-profile.js.map +1 -1
- package/dist/backend/native-profile.test.js +127 -4
- package/dist/backend/native-profile.test.js.map +1 -1
- package/dist/backend/native-toolchain.d.ts +1 -1
- package/dist/backend/native-toolchain.js +1 -1
- package/dist/backend/native-toolchain.js.map +1 -1
- package/dist/backend/native-toolchain.test.js +58 -4
- package/dist/backend/native-toolchain.test.js.map +1 -1
- package/dist/backend/native-tools.d.ts +17 -3
- package/dist/backend/native-tools.js +12 -4
- package/dist/backend/native-tools.js.map +1 -1
- package/dist/backend/native-tools.test.d.ts +1 -0
- package/dist/backend/native-tools.test.js +76 -0
- package/dist/backend/native-tools.test.js.map +1 -0
- package/dist/backend/object-localize.js +69 -9
- package/dist/backend/object-localize.js.map +1 -1
- package/dist/backend/object-localize.test.js +99 -10
- package/dist/backend/object-localize.test.js.map +1 -1
- package/dist/backend/publication.d.ts +2 -0
- package/dist/backend/publication.js +4 -0
- package/dist/backend/publication.js.map +1 -1
- package/dist/backend/runtime-abi.d.ts +2 -2
- package/dist/backend/runtime-abi.js +2 -2
- package/dist/backend/runtime-pack-core.d.ts +19 -0
- package/dist/backend/runtime-pack-core.js +23 -3
- package/dist/backend/runtime-pack-core.js.map +1 -1
- package/dist/backend/runtime-pack-targets.test.js +1 -1
- package/dist/backend/runtime-pack.test.js +48 -2
- package/dist/backend/runtime-pack.test.js.map +1 -1
- package/dist/backend/target-cpu.d.ts +2 -0
- package/dist/backend/target-cpu.js +4 -0
- package/dist/backend/target-cpu.js.map +1 -1
- package/dist/backend/target-diagnostics.js +1 -19
- package/dist/backend/target-diagnostics.js.map +1 -1
- package/dist/backend/target-diagnostics.test.js +1 -1
- package/dist/backend/target-diagnostics.test.js.map +1 -1
- package/dist/backend/targets.d.ts +28 -0
- package/dist/backend/targets.js +70 -0
- package/dist/backend/targets.js.map +1 -1
- package/dist/backend/targets.test.js +75 -1
- package/dist/backend/targets.test.js.map +1 -1
- package/dist/backend/vendor-archives.d.ts +1 -1
- package/dist/backend/vendor-archives.js +25 -12
- package/dist/backend/vendor-archives.js.map +1 -1
- package/dist/backend/vendor-inputs.d.ts +15 -2
- package/dist/backend/vendor-inputs.js +59 -3
- package/dist/backend/vendor-inputs.js.map +1 -1
- package/dist/backend/vendor-inputs.test.d.ts +1 -0
- package/dist/backend/vendor-inputs.test.js +74 -0
- package/dist/backend/vendor-inputs.test.js.map +1 -0
- package/dist/cli/command.js +95 -5
- package/dist/cli/command.js.map +1 -1
- package/dist/cli/host.d.ts +3 -0
- package/dist/cli/output-options.d.ts +3 -0
- package/dist/cli/output-options.js +8 -2
- package/dist/cli/output-options.js.map +1 -1
- package/dist/cli/usage.d.ts +28 -1
- package/dist/cli/usage.js +56 -6
- package/dist/cli/usage.js.map +1 -1
- package/dist/compat/fetch-profile.d.ts +3 -0
- package/dist/compat/fetch-profile.js +23 -3
- package/dist/compat/fetch-profile.js.map +1 -1
- package/dist/compile-types.d.ts +45 -0
- package/dist/contracts/check.js +70 -2
- package/dist/contracts/check.js.map +1 -1
- package/dist/contracts/int32-elements.d.ts +2 -1
- package/dist/contracts/int32-elements.js.map +1 -1
- package/dist/coverage/report.d.ts +5 -1
- package/dist/coverage/report.js +83 -2
- package/dist/coverage/report.js.map +1 -1
- package/dist/coverage/verdict-cache.d.ts +2 -0
- package/dist/coverage/verdict-cache.js +5 -10
- package/dist/coverage/verdict-cache.js.map +1 -1
- package/dist/diagnostics/codes.d.ts +145 -0
- package/dist/diagnostics/codes.js +159 -0
- package/dist/diagnostics/codes.js.map +1 -0
- package/dist/diagnostics/codes.test.d.ts +1 -0
- package/dist/diagnostics/codes.test.js +78 -0
- package/dist/diagnostics/codes.test.js.map +1 -0
- package/dist/diagnostics/diagnostic.d.ts +101 -2
- package/dist/diagnostics/diagnostic.js +155 -0
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/diagnostics/dynamic-slots.d.ts +23 -0
- package/dist/diagnostics/dynamic-slots.js +29 -0
- package/dist/diagnostics/dynamic-slots.js.map +1 -0
- package/dist/diagnostics/dynamic-tier.d.ts +6 -0
- package/dist/diagnostics/dynamic-tier.js +8 -1
- package/dist/diagnostics/dynamic-tier.js.map +1 -1
- package/dist/diagnostics/envelope.d.ts +43 -1
- package/dist/diagnostics/envelope.js +19 -1
- package/dist/diagnostics/envelope.js.map +1 -1
- package/dist/diagnostics/envelope.test.js.map +1 -1
- package/dist/diagnostics/render.d.ts +3 -1
- package/dist/diagnostics/render.js +27 -6
- package/dist/diagnostics/render.js.map +1 -1
- package/dist/executable/executable-cache.d.ts +41 -0
- package/dist/executable/executable-cache.js +39 -1
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/executable/executable-cache.test.js +4 -1
- package/dist/executable/executable-cache.test.js.map +1 -1
- package/dist/executable/prepare.d.ts +2 -1
- package/dist/executable/prepare.js +421 -10
- package/dist/executable/prepare.js.map +1 -1
- package/dist/frontend/analysis.js +1 -0
- package/dist/frontend/analysis.js.map +1 -1
- package/dist/frontend/canon-map.d.ts +17 -0
- package/dist/frontend/canon-map.js +177 -0
- package/dist/frontend/canon-map.js.map +1 -0
- package/dist/frontend/canon.d.ts +122 -0
- package/dist/frontend/canon.js +462 -0
- package/dist/frontend/canon.js.map +1 -0
- package/dist/frontend/contract-types.d.ts +9 -1
- package/dist/frontend/contract-types.js +46 -4
- package/dist/frontend/contract-types.js.map +1 -1
- package/dist/frontend/decl-projection.d.ts +3 -0
- package/dist/frontend/decl-projection.js +121 -3
- package/dist/frontend/decl-projection.js.map +1 -1
- package/dist/frontend/dts-paths.d.ts +17 -4
- package/dist/frontend/dts-paths.js +149 -5
- package/dist/frontend/dts-paths.js.map +1 -1
- package/dist/frontend/fork-target.js +4 -4
- package/dist/frontend/fork-target.js.map +1 -1
- package/dist/frontend/fork-target.test.js +3 -3
- package/dist/frontend/fork-target.test.js.map +1 -1
- package/dist/frontend/heritage-elements.d.ts +15 -0
- package/dist/frontend/heritage-elements.js +18 -0
- package/dist/frontend/heritage-elements.js.map +1 -0
- package/dist/frontend/heritage-elements.test.d.ts +1 -0
- package/dist/frontend/heritage-elements.test.js +68 -0
- package/dist/frontend/heritage-elements.test.js.map +1 -0
- package/dist/frontend/input-tracker.d.ts +20 -0
- package/dist/frontend/input-tracker.js +74 -4
- package/dist/frontend/input-tracker.js.map +1 -1
- package/dist/frontend/input-tracker.test.js +66 -0
- package/dist/frontend/input-tracker.test.js.map +1 -1
- package/dist/frontend/lowering/any-collection-residue.d.ts +9 -0
- package/dist/frontend/lowering/any-collection-residue.js +42 -0
- package/dist/frontend/lowering/any-collection-residue.js.map +1 -0
- package/dist/frontend/lowering/array-values.d.ts +44 -2
- package/dist/frontend/lowering/array-values.js +193 -3
- package/dist/frontend/lowering/array-values.js.map +1 -1
- package/dist/frontend/lowering/builtin-namespaces.d.ts +6 -2
- package/dist/frontend/lowering/builtin-namespaces.js +28 -6
- package/dist/frontend/lowering/builtin-namespaces.js.map +1 -1
- package/dist/frontend/lowering/builtins/array-classes.d.ts +69 -0
- package/dist/frontend/lowering/builtins/array-classes.js +729 -0
- package/dist/frontend/lowering/builtins/array-classes.js.map +1 -0
- package/dist/frontend/lowering/builtins/callable-aliases.js +4 -0
- package/dist/frontend/lowering/builtins/callable-aliases.js.map +1 -1
- package/dist/frontend/lowering/builtins/child-process-methods.js +34 -0
- package/dist/frontend/lowering/builtins/child-process-methods.js.map +1 -1
- package/dist/frontend/lowering/builtins/disposable-stack.js +1 -3
- package/dist/frontend/lowering/builtins/disposable-stack.js.map +1 -1
- package/dist/frontend/lowering/builtins/errors.d.ts +13 -9
- package/dist/frontend/lowering/builtins/errors.js +136 -56
- package/dist/frontend/lowering/builtins/errors.js.map +1 -1
- package/dist/frontend/lowering/builtins/filesystem-calls.d.ts +1 -0
- package/dist/frontend/lowering/builtins/filesystem-calls.js +85 -4
- package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/filesystem.d.ts +11 -6
- package/dist/frontend/lowering/builtins/filesystem.js +270 -24
- package/dist/frontend/lowering/builtins/filesystem.js.map +1 -1
- package/dist/frontend/lowering/builtins/json.js +7 -1
- package/dist/frontend/lowering/builtins/json.js.map +1 -1
- package/dist/frontend/lowering/builtins/mime.d.ts +25 -0
- package/dist/frontend/lowering/builtins/mime.js +167 -0
- package/dist/frontend/lowering/builtins/mime.js.map +1 -0
- package/dist/frontend/lowering/builtins/module-bindings.d.ts +3 -0
- package/dist/frontend/lowering/builtins/module-bindings.js +6 -0
- package/dist/frontend/lowering/builtins/module-bindings.js.map +1 -1
- package/dist/frontend/lowering/builtins/module-calls.js +79 -12
- package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/module-resolution.d.ts +7 -4
- package/dist/frontend/lowering/builtins/module-resolution.js +115 -13
- package/dist/frontend/lowering/builtins/module-resolution.js.map +1 -1
- package/dist/frontend/lowering/builtins/navigator.d.ts +3 -1
- package/dist/frontend/lowering/builtins/navigator.js +22 -8
- package/dist/frontend/lowering/builtins/navigator.js.map +1 -1
- package/dist/frontend/lowering/builtins/process.js +49 -9
- package/dist/frontend/lowering/builtins/process.js.map +1 -1
- package/dist/frontend/lowering/builtins/promises.js +18 -3
- package/dist/frontend/lowering/builtins/promises.js.map +1 -1
- package/dist/frontend/lowering/builtins/promisify-callback.d.ts +6 -2
- package/dist/frontend/lowering/builtins/promisify-callback.js +19 -6
- package/dist/frontend/lowering/builtins/promisify-callback.js.map +1 -1
- package/dist/frontend/lowering/builtins/properties.js +23 -5
- package/dist/frontend/lowering/builtins/properties.js.map +1 -1
- package/dist/frontend/lowering/builtins/web-streams-dyn.d.ts +42 -0
- package/dist/frontend/lowering/builtins/web-streams-dyn.js +321 -0
- package/dist/frontend/lowering/builtins/web-streams-dyn.js.map +1 -0
- package/dist/frontend/lowering/builtins/x509.js +35 -5
- package/dist/frontend/lowering/builtins/x509.js.map +1 -1
- package/dist/frontend/lowering/call-arguments.d.ts +14 -1
- package/dist/frontend/lowering/call-arguments.js +84 -70
- package/dist/frontend/lowering/call-arguments.js.map +1 -1
- package/dist/frontend/lowering/call-signatures.js +108 -24
- package/dist/frontend/lowering/call-signatures.js.map +1 -1
- package/dist/frontend/lowering/class-attributes.js +6 -5
- package/dist/frontend/lowering/class-attributes.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.js +40 -19
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js +1 -0
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
- package/dist/frontend/lowering/class-protocol-dispatch.js +4 -0
- package/dist/frontend/lowering/class-protocol-dispatch.js.map +1 -1
- package/dist/frontend/lowering/class-protocols.d.ts +61 -1
- package/dist/frontend/lowering/class-protocols.js +297 -21
- package/dist/frontend/lowering/class-protocols.js.map +1 -1
- package/dist/frontend/lowering/class-to-primitive.d.ts +3 -2
- package/dist/frontend/lowering/class-to-primitive.js +15 -5
- package/dist/frontend/lowering/class-to-primitive.js.map +1 -1
- package/dist/frontend/lowering/coercions/asserted.d.ts +16 -0
- package/dist/frontend/lowering/coercions/asserted.js +79 -0
- package/dist/frontend/lowering/coercions/asserted.js.map +1 -0
- package/dist/frontend/lowering/coercions/function-adapters.d.ts +13 -0
- package/dist/frontend/lowering/coercions/function-adapters.js +70 -3
- package/dist/frontend/lowering/coercions/function-adapters.js.map +1 -1
- package/dist/frontend/lowering/coercions/state.d.ts +23 -0
- package/dist/frontend/lowering/coercions/state.js +9 -0
- package/dist/frontend/lowering/coercions/state.js.map +1 -1
- package/dist/frontend/lowering/coercions/structural-plans.js +67 -1
- package/dist/frontend/lowering/coercions/structural-plans.js.map +1 -1
- package/dist/frontend/lowering/coercions/structural.d.ts +10 -0
- package/dist/frontend/lowering/coercions/structural.js +134 -4
- package/dist/frontend/lowering/coercions/structural.js.map +1 -1
- package/dist/frontend/lowering/coercions/unions.d.ts +11 -0
- package/dist/frontend/lowering/coercions/unions.js +83 -4
- package/dist/frontend/lowering/coercions/unions.js.map +1 -1
- package/dist/frontend/lowering/completion-callbacks.js +3 -2
- package/dist/frontend/lowering/completion-callbacks.js.map +1 -1
- package/dist/frontend/lowering/containers/array-callbacks.d.ts +10 -0
- package/dist/frontend/lowering/containers/array-callbacks.js +224 -81
- package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
- package/dist/frontend/lowering/containers/array-concat.d.ts +5 -2
- package/dist/frontend/lowering/containers/array-concat.js +76 -7
- package/dist/frontend/lowering/containers/array-concat.js.map +1 -1
- package/dist/frontend/lowering/containers/array-construction.d.ts +9 -4
- package/dist/frontend/lowering/containers/array-construction.js +112 -100
- package/dist/frontend/lowering/containers/array-construction.js.map +1 -1
- package/dist/frontend/lowering/containers/array-methods.js +193 -45
- package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
- package/dist/frontend/lowering/containers/array-pipelines.d.ts +3 -0
- package/dist/frontend/lowering/containers/array-pipelines.js +81 -13
- package/dist/frontend/lowering/containers/array-pipelines.js.map +1 -1
- package/dist/frontend/lowering/containers/callback-arguments.d.ts +1 -0
- package/dist/frontend/lowering/containers/callback-arguments.js +28 -2
- package/dist/frontend/lowering/containers/callback-arguments.js.map +1 -1
- package/dist/frontend/lowering/containers/collection-methods.js +13 -3
- package/dist/frontend/lowering/containers/collection-methods.js.map +1 -1
- package/dist/frontend/lowering/containers/filter-predicates.js +34 -3
- package/dist/frontend/lowering/containers/filter-predicates.js.map +1 -1
- package/dist/frontend/lowering/containers/indexed-objects.d.ts +34 -1
- package/dist/frontend/lowering/containers/indexed-objects.js +131 -72
- package/dist/frontend/lowering/containers/indexed-objects.js.map +1 -1
- package/dist/frontend/lowering/cycle-initialization.js +43 -6
- package/dist/frontend/lowering/cycle-initialization.js.map +1 -1
- package/dist/frontend/lowering/decl-origin.d.ts +49 -0
- package/dist/frontend/lowering/decl-origin.js +402 -0
- package/dist/frontend/lowering/decl-origin.js.map +1 -0
- package/dist/frontend/lowering/deferred-module-initializers.d.ts +2 -0
- package/dist/frontend/lowering/deferred-module-initializers.js +7 -0
- package/dist/frontend/lowering/deferred-module-initializers.js.map +1 -1
- package/dist/frontend/lowering/divergences.js +5 -0
- package/dist/frontend/lowering/divergences.js.map +1 -1
- package/dist/frontend/lowering/dynamic-tier.d.ts +8 -2
- package/dist/frontend/lowering/dynamic-tier.js +111 -3
- package/dist/frontend/lowering/dynamic-tier.js.map +1 -1
- package/dist/frontend/lowering/expressions/array-literals.d.ts +14 -1
- package/dist/frontend/lowering/expressions/array-literals.js +43 -5
- package/dist/frontend/lowering/expressions/array-literals.js.map +1 -1
- package/dist/frontend/lowering/expressions/asserted-receiver.d.ts +48 -0
- package/dist/frontend/lowering/expressions/asserted-receiver.js +233 -0
- package/dist/frontend/lowering/expressions/asserted-receiver.js.map +1 -0
- package/dist/frontend/lowering/expressions/binary.js +136 -1
- package/dist/frontend/lowering/expressions/binary.js.map +1 -1
- package/dist/frontend/lowering/expressions/element-access.d.ts +7 -0
- package/dist/frontend/lowering/expressions/element-access.js +363 -12
- package/dist/frontend/lowering/expressions/element-access.js.map +1 -1
- package/dist/frontend/lowering/expressions/identifiers.d.ts +3 -0
- package/dist/frontend/lowering/expressions/identifiers.js +78 -62
- package/dist/frontend/lowering/expressions/identifiers.js.map +1 -1
- package/dist/frontend/lowering/expressions/message-listeners.d.ts +3 -0
- package/dist/frontend/lowering/expressions/message-listeners.js +19 -0
- package/dist/frontend/lowering/expressions/message-listeners.js.map +1 -0
- package/dist/frontend/lowering/expressions/narrowing.js +224 -6
- package/dist/frontend/lowering/expressions/narrowing.js.map +1 -1
- package/dist/frontend/lowering/expressions/nullish-assignment.js +5 -2
- package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -1
- package/dist/frontend/lowering/expressions/object-literals.d.ts +1 -1
- package/dist/frontend/lowering/expressions/object-literals.js +282 -24
- package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
- package/dist/frontend/lowering/expressions/property-access.d.ts +15 -3
- package/dist/frontend/lowering/expressions/property-access.js +397 -74
- package/dist/frontend/lowering/expressions/property-access.js.map +1 -1
- package/dist/frontend/lowering/expressions/relational.js +202 -70
- package/dist/frontend/lowering/expressions/relational.js.map +1 -1
- package/dist/frontend/lowering/expressions/typeof.js +9 -1
- package/dist/frontend/lowering/expressions/typeof.js.map +1 -1
- package/dist/frontend/lowering/expressions/union-fields.d.ts +28 -8
- package/dist/frontend/lowering/expressions/union-fields.js +168 -14
- package/dist/frontend/lowering/expressions/union-fields.js.map +1 -1
- package/dist/frontend/lowering/frozen-records.d.ts +8 -0
- package/dist/frontend/lowering/frozen-records.js +56 -9
- package/dist/frontend/lowering/frozen-records.js.map +1 -1
- package/dist/frontend/lowering/function-context.d.ts +3 -0
- package/dist/frontend/lowering/function-context.js +4 -1
- package/dist/frontend/lowering/function-context.js.map +1 -1
- package/dist/frontend/lowering/function-returns.d.ts +4 -0
- package/dist/frontend/lowering/function-returns.js +231 -2
- package/dist/frontend/lowering/function-returns.js.map +1 -1
- package/dist/frontend/lowering/generator-delegation.js +3 -2
- package/dist/frontend/lowering/generator-delegation.js.map +1 -1
- package/dist/frontend/lowering/generator-dynamic-dispatch.d.ts +26 -0
- package/dist/frontend/lowering/generator-dynamic-dispatch.js +294 -2
- package/dist/frontend/lowering/generator-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/generic-functions.d.ts +10 -0
- package/dist/frontend/lowering/generic-functions.js +67 -7
- package/dist/frontend/lowering/generic-functions.js.map +1 -1
- package/dist/frontend/lowering/global-values.d.ts +37 -0
- package/dist/frontend/lowering/global-values.js +395 -0
- package/dist/frontend/lowering/global-values.js.map +1 -0
- package/dist/frontend/lowering/handle-properties.js +3 -2
- package/dist/frontend/lowering/handle-properties.js.map +1 -1
- package/dist/frontend/lowering/handle-properties.test.d.ts +1 -0
- package/dist/frontend/lowering/handle-properties.test.js +25 -0
- package/dist/frontend/lowering/handle-properties.test.js.map +1 -0
- package/dist/frontend/lowering/import-meta.d.ts +3 -0
- package/dist/frontend/lowering/import-meta.js +8 -3
- package/dist/frontend/lowering/import-meta.js.map +1 -1
- package/dist/frontend/lowering/iterator-adapters.js +3 -3
- package/dist/frontend/lowering/iterator-adapters.js.map +1 -1
- package/dist/frontend/lowering/key-order-witness.d.ts +2 -0
- package/dist/frontend/lowering/key-order-witness.js +10 -0
- package/dist/frontend/lowering/key-order-witness.js.map +1 -1
- package/dist/frontend/lowering/lower-array-sort.d.ts +5 -1
- package/dist/frontend/lowering/lower-array-sort.js +16 -2
- package/dist/frontend/lowering/lower-array-sort.js.map +1 -1
- package/dist/frontend/lowering/lower-builtin-values.d.ts +7 -0
- package/dist/frontend/lowering/lower-builtin-values.js +65 -16
- package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.js +222 -24
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +6 -0
- package/dist/frontend/lowering/lower-classes.js +154 -20
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-console.js +25 -2
- package/dist/frontend/lowering/lower-console.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +29 -0
- package/dist/frontend/lowering/lower-exprs.js +544 -24
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-functions.js +93 -18
- package/dist/frontend/lowering/lower-functions.js.map +1 -1
- package/dist/frontend/lowering/lower-global-value.d.ts +4 -1
- package/dist/frontend/lowering/lower-global-value.js +10 -3
- package/dist/frontend/lowering/lower-global-value.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.d.ts +44 -4
- package/dist/frontend/lowering/lower-inspect.js +723 -26
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.d.ts +3 -1
- package/dist/frontend/lowering/lower-modules.js +189 -24
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-namespaces.d.ts +7 -0
- package/dist/frontend/lowering/lower-namespaces.js +23 -0
- package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
- package/dist/frontend/lowering/lower-node-island.d.ts +74 -0
- package/dist/frontend/lowering/lower-node-island.js +1931 -0
- package/dist/frontend/lowering/lower-node-island.js.map +1 -0
- package/dist/frontend/lowering/lower-server.js +44 -0
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-shared-modules.d.ts +27 -0
- package/dist/frontend/lowering/lower-shared-modules.js +611 -0
- package/dist/frontend/lowering/lower-shared-modules.js.map +1 -0
- package/dist/frontend/lowering/lower-stdlib.js +85 -9
- package/dist/frontend/lowering/lower-stdlib.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.d.ts +2 -6
- package/dist/frontend/lowering/lower-stmts.js +781 -143
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.js +548 -36
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lower-timers.js +9 -0
- package/dist/frontend/lowering/lower-timers.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +514 -10
- package/dist/frontend/lowering/lowerer.js +2667 -163
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/lowerer.test.js +44 -1
- package/dist/frontend/lowering/lowerer.test.js.map +1 -1
- package/dist/frontend/lowering/maybe-promise.d.ts +6 -0
- package/dist/frontend/lowering/maybe-promise.js +13 -0
- package/dist/frontend/lowering/maybe-promise.js.map +1 -1
- package/dist/frontend/lowering/module-namespace-elements.d.ts +12 -0
- package/dist/frontend/lowering/module-namespace-elements.js +114 -18
- package/dist/frontend/lowering/module-namespace-elements.js.map +1 -1
- package/dist/frontend/lowering/nan-coded-reads.d.ts +11 -0
- package/dist/frontend/lowering/nan-coded-reads.js +45 -2
- package/dist/frontend/lowering/nan-coded-reads.js.map +1 -1
- package/dist/frontend/lowering/narrowing-stability.d.ts +4 -0
- package/dist/frontend/lowering/narrowing-stability.js +14 -6
- package/dist/frontend/lowering/narrowing-stability.js.map +1 -1
- package/dist/frontend/lowering/receiver-returns.d.ts +3 -0
- package/dist/frontend/lowering/receiver-returns.js +134 -0
- package/dist/frontend/lowering/receiver-returns.js.map +1 -0
- package/dist/frontend/lowering/record-inherited.d.ts +26 -0
- package/dist/frontend/lowering/record-inherited.js +807 -0
- package/dist/frontend/lowering/record-inherited.js.map +1 -0
- package/dist/frontend/lowering/runtime-optional-elements.d.ts +31 -1
- package/dist/frontend/lowering/runtime-optional-elements.js +105 -13
- package/dist/frontend/lowering/runtime-optional-elements.js.map +1 -1
- package/dist/frontend/lowering/runtime-optional-guards.d.ts +3 -0
- package/dist/frontend/lowering/runtime-optional-guards.js +35 -7
- package/dist/frontend/lowering/runtime-optional-guards.js.map +1 -1
- package/dist/frontend/lowering/runtime-optional-guards.test.js +59 -1
- package/dist/frontend/lowering/runtime-optional-guards.test.js.map +1 -1
- package/dist/frontend/lowering/stable-names.d.ts +8 -0
- package/dist/frontend/lowering/stable-names.js +22 -0
- package/dist/frontend/lowering/stable-names.js.map +1 -1
- package/dist/frontend/lowering/stable-names.test.d.ts +1 -0
- package/dist/frontend/lowering/stable-names.test.js +16 -0
- package/dist/frontend/lowering/stable-names.test.js.map +1 -0
- package/dist/frontend/lowering/static-typeof.d.ts +5 -4
- package/dist/frontend/lowering/static-typeof.js +10 -4
- package/dist/frontend/lowering/static-typeof.js.map +1 -1
- package/dist/frontend/lowering/structural-instances.d.ts +22 -0
- package/dist/frontend/lowering/structural-instances.js +282 -0
- package/dist/frontend/lowering/structural-instances.js.map +1 -0
- package/dist/frontend/lowering/surfaces.d.ts +3 -0
- package/dist/frontend/lowering/surfaces.js +108 -12
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/lowering/symbol-fields.d.ts +7 -0
- package/dist/frontend/lowering/symbol-fields.js +32 -0
- package/dist/frontend/lowering/symbol-fields.js.map +1 -1
- package/dist/frontend/lowering/type-failure.d.ts +17 -0
- package/dist/frontend/lowering/type-failure.js +163 -0
- package/dist/frontend/lowering/type-failure.js.map +1 -0
- package/dist/frontend/lowering/typed-arguments.d.ts +5 -6
- package/dist/frontend/lowering/typed-arguments.js +10 -2
- package/dist/frontend/lowering/typed-arguments.js.map +1 -1
- package/dist/frontend/lowering/union-narrow.d.ts +9 -1
- package/dist/frontend/lowering/union-narrow.js +31 -2
- package/dist/frontend/lowering/union-narrow.js.map +1 -1
- package/dist/frontend/lowering/union-retag.test.js +42 -2
- package/dist/frontend/lowering/union-retag.test.js.map +1 -1
- package/dist/frontend/lowering/unit-journal.d.ts +194 -0
- package/dist/frontend/lowering/unit-journal.js +556 -0
- package/dist/frontend/lowering/unit-journal.js.map +1 -0
- package/dist/frontend/lowering/unit-journal.test.d.ts +1 -0
- package/dist/frontend/lowering/unit-journal.test.js +335 -0
- package/dist/frontend/lowering/unit-journal.test.js.map +1 -0
- package/dist/frontend/lowering/width-lift.d.ts +19 -0
- package/dist/frontend/node-api-import.d.ts +21 -0
- package/dist/frontend/node-api-import.js +88 -0
- package/dist/frontend/node-api-import.js.map +1 -0
- package/dist/frontend/npm-static-type-exports-host.js +4 -3
- package/dist/frontend/npm-static-type-exports-host.js.map +1 -1
- package/dist/frontend/npm-static.js +9 -2
- package/dist/frontend/npm-static.js.map +1 -1
- package/dist/frontend/package-shims.d.ts +6 -2
- package/dist/frontend/package-shims.js +13 -2
- package/dist/frontend/package-shims.js.map +1 -1
- package/dist/frontend/pipeline.d.ts +11 -4
- package/dist/frontend/pipeline.js +249 -26
- package/dist/frontend/pipeline.js.map +1 -1
- package/dist/frontend/process-fork.d.ts +3 -0
- package/dist/frontend/process-fork.js.map +1 -1
- package/dist/frontend/program-analysis.d.ts +6 -0
- package/dist/frontend/program-analysis.js +4 -0
- package/dist/frontend/program-analysis.js.map +1 -1
- package/dist/frontend/program.d.ts +12 -1
- package/dist/frontend/program.js +256 -36
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/resolve.js +8 -2
- package/dist/frontend/resolve.js.map +1 -1
- package/dist/frontend/shape-inference/analyze.d.ts +23 -1
- package/dist/frontend/shape-inference/analyze.js +982 -97
- package/dist/frontend/shape-inference/analyze.js.map +1 -1
- package/dist/frontend/shape-inference/constant-graphs.d.ts +2 -0
- package/dist/frontend/shape-inference/constant-graphs.js +39 -4
- package/dist/frontend/shape-inference/constant-graphs.js.map +1 -1
- package/dist/frontend/shape-inference/domain.d.ts +2 -0
- package/dist/frontend/shape-inference/domain.js.map +1 -1
- package/dist/frontend/shape-inference/fallback.d.ts +17 -0
- package/dist/frontend/shape-inference/fallback.js +303 -0
- package/dist/frontend/shape-inference/fallback.js.map +1 -0
- package/dist/frontend/shape-inference/index.d.ts +75 -1
- package/dist/frontend/shape-inference/index.js +531 -2
- package/dist/frontend/shape-inference/index.js.map +1 -1
- package/dist/frontend/shape-inference/inferred-checks.d.ts +2 -0
- package/dist/frontend/shape-inference/inferred-checks.js +90 -0
- package/dist/frontend/shape-inference/inferred-checks.js.map +1 -0
- package/dist/frontend/shape-inference/memo.d.ts +30 -0
- package/dist/frontend/shape-inference/memo.js +99 -0
- package/dist/frontend/shape-inference/memo.js.map +1 -0
- package/dist/frontend/shape-inference/overlay.d.ts +81 -0
- package/dist/frontend/shape-inference/overlay.js +1160 -0
- package/dist/frontend/shape-inference/overlay.js.map +1 -0
- package/dist/frontend/shape-inference/registry.test.d.ts +1 -0
- package/dist/frontend/shape-inference/registry.test.js +34 -0
- package/dist/frontend/shape-inference/registry.test.js.map +1 -0
- package/dist/frontend/shape-inference/report.js +42 -8
- package/dist/frontend/shape-inference/report.js.map +1 -1
- package/dist/frontend/shape-inference/static-objects.d.ts +29 -0
- package/dist/frontend/shape-inference/static-objects.js +1951 -0
- package/dist/frontend/shape-inference/static-objects.js.map +1 -0
- package/dist/frontend/tier-analysis.d.ts +53 -1
- package/dist/frontend/tier-analysis.js +133 -0
- package/dist/frontend/tier-analysis.js.map +1 -1
- package/dist/frontend/ts7/api.js +4 -2
- package/dist/frontend/ts7/api.js.map +1 -1
- package/dist/frontend/ts7/ast-node.d.ts +9 -0
- package/dist/frontend/ts7/ast-node.js +42 -10
- package/dist/frontend/ts7/ast-node.js.map +1 -1
- package/dist/frontend/ts7/ast-node.test.js +23 -0
- package/dist/frontend/ts7/ast-node.test.js.map +1 -1
- package/dist/frontend/ts7/ast-wire-protocols.test.d.ts +1 -0
- package/dist/frontend/ts7/ast-wire-protocols.test.js +93 -0
- package/dist/frontend/ts7/ast-wire-protocols.test.js.map +1 -0
- package/dist/frontend/ts7/ast-wire.d.ts +18 -0
- package/dist/frontend/ts7/ast-wire.js +66 -4
- package/dist/frontend/ts7/ast-wire.js.map +1 -1
- package/dist/frontend/ts7/checker-server.d.ts +12 -11
- package/dist/frontend/ts7/checker-server.js +28 -12
- package/dist/frontend/ts7/checker-server.js.map +1 -1
- package/dist/frontend/ts7/checker-server.test.js +8 -3
- package/dist/frontend/ts7/checker-server.test.js.map +1 -1
- package/dist/frontend/ts7/checker.d.ts +4 -0
- package/dist/frontend/ts7/checker.js +9 -0
- package/dist/frontend/ts7/checker.js.map +1 -1
- package/dist/frontend/ts7/checker.test.js +216 -205
- package/dist/frontend/ts7/checker.test.js.map +1 -1
- package/dist/frontend/ts7/lib-diagnostics.d.ts +71 -4
- package/dist/frontend/ts7/lib-diagnostics.js +337 -20
- package/dist/frontend/ts7/lib-diagnostics.js.map +1 -1
- package/dist/frontend/ts7/lib-diagnostics.test.js +268 -5
- package/dist/frontend/ts7/lib-diagnostics.test.js.map +1 -1
- package/dist/frontend/ts7/native-api.d.ts +4 -0
- package/dist/frontend/ts7/native-api.js +36 -1
- package/dist/frontend/ts7/native-api.js.map +1 -1
- package/dist/frontend/ts7/program-host.d.ts +19 -2
- package/dist/frontend/ts7/program-host.js +69 -9
- package/dist/frontend/ts7/program-host.js.map +1 -1
- package/dist/frontend/ts7/program-host.test.js +42 -1
- package/dist/frontend/ts7/program-host.test.js.map +1 -1
- package/dist/frontend/ts7/rpc-filesystem.d.ts +4 -2
- package/dist/frontend/ts7/rpc-filesystem.js +23 -2
- package/dist/frontend/ts7/rpc-filesystem.js.map +1 -1
- package/dist/frontend/ts7/rpc-filesystem.test.js +28 -2
- package/dist/frontend/ts7/rpc-filesystem.test.js.map +1 -1
- package/dist/frontend/ts7/semantic-checker.js +73 -5
- package/dist/frontend/ts7/semantic-checker.js.map +1 -1
- package/dist/frontend/ts7/semantic-checker.test.js +106 -74
- package/dist/frontend/ts7/semantic-checker.test.js.map +1 -1
- package/dist/frontend/ts7/semantic-json.d.ts +2 -6
- package/dist/frontend/ts7/semantic-model-71.test.d.ts +1 -0
- package/dist/frontend/ts7/semantic-model-71.test.js +131 -0
- package/dist/frontend/ts7/semantic-model-71.test.js.map +1 -0
- package/dist/frontend/ts7/semantic-model.d.ts +121 -3
- package/dist/frontend/ts7/semantic-model.js +245 -8
- package/dist/frontend/ts7/semantic-model.js.map +1 -1
- package/dist/frontend/ts7/session.d.ts +19 -1
- package/dist/frontend/ts7/session.js +111 -11
- package/dist/frontend/ts7/session.js.map +1 -1
- package/dist/frontend/ts7/session.test.js +259 -239
- package/dist/frontend/ts7/session.test.js.map +1 -1
- package/dist/frontend/ts7/test-servers.d.ts +12 -0
- package/dist/frontend/ts7/test-servers.js +16 -0
- package/dist/frontend/ts7/test-servers.js.map +1 -0
- package/dist/frontend/tsc-codes.js +6 -3
- package/dist/frontend/tsc-codes.js.map +1 -1
- package/dist/frontend/type-mapper.d.ts +61 -1
- package/dist/frontend/type-mapper.js +577 -28
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/frontend/type-patches/command.d.ts +19 -0
- package/dist/frontend/type-patches/command.js +352 -0
- package/dist/frontend/type-patches/command.js.map +1 -0
- package/dist/frontend/type-patches/layer.d.ts +45 -0
- package/dist/frontend/type-patches/layer.js +409 -0
- package/dist/frontend/type-patches/layer.js.map +1 -0
- package/dist/frontend/type-patches/locate.d.ts +41 -0
- package/dist/frontend/type-patches/locate.js +914 -0
- package/dist/frontend/type-patches/locate.js.map +1 -0
- package/dist/frontend/type-patches/locate.test.d.ts +1 -0
- package/dist/frontend/type-patches/locate.test.js +179 -0
- package/dist/frontend/type-patches/locate.test.js.map +1 -0
- package/dist/frontend/type-patches/selector.d.ts +43 -0
- package/dist/frontend/type-patches/selector.js +126 -0
- package/dist/frontend/type-patches/selector.js.map +1 -0
- package/dist/frontend/type-patches/selector.test.d.ts +1 -0
- package/dist/frontend/type-patches/selector.test.js +56 -0
- package/dist/frontend/type-patches/selector.test.js.map +1 -0
- package/dist/frontend/type-patches/semver.d.ts +19 -0
- package/dist/frontend/type-patches/semver.js +221 -0
- package/dist/frontend/type-patches/semver.js.map +1 -0
- package/dist/frontend/type-patches/semver.test.d.ts +1 -0
- package/dist/frontend/type-patches/semver.test.js +47 -0
- package/dist/frontend/type-patches/semver.test.js.map +1 -0
- package/dist/frontend/worker-target.test.js +2 -2
- package/dist/frontend/worker-target.test.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +292 -27
- package/dist/index.js.map +1 -1
- package/dist/ir/builtin-effects.js +51 -5
- package/dist/ir/builtin-effects.js.map +1 -1
- package/dist/ir/builtin-signatures.d.ts +4 -3
- package/dist/ir/builtin-signatures.js +277 -12
- package/dist/ir/builtin-signatures.js.map +1 -1
- package/dist/ir/callback-specialization.js +108 -67
- package/dist/ir/callback-specialization.js.map +1 -1
- package/dist/ir/capture-values.d.ts +7 -1
- package/dist/ir/capture-values.js +28 -5
- package/dist/ir/capture-values.js.map +1 -1
- package/dist/ir/char-unit-locals.js +38 -42
- package/dist/ir/char-unit-locals.js.map +1 -1
- package/dist/ir/expression-inlining.js +12 -6
- package/dist/ir/expression-inlining.js.map +1 -1
- package/dist/ir/fields.generated.d.ts +751 -0
- package/dist/ir/fields.generated.js +2071 -0
- package/dist/ir/fields.generated.js.map +1 -0
- package/dist/ir/fields.test.d.ts +1 -0
- package/dist/ir/fields.test.js +113 -0
- package/dist/ir/fields.test.js.map +1 -0
- package/dist/ir/function-references.js +4 -0
- package/dist/ir/function-references.js.map +1 -1
- package/dist/ir/function-references.test.js +25 -0
- package/dist/ir/function-references.test.js.map +1 -1
- package/dist/ir/inline-array-sources.d.ts +15 -0
- package/dist/ir/inline-array-sources.js +1825 -0
- package/dist/ir/inline-array-sources.js.map +1 -0
- package/dist/ir/inline-arrays.d.ts +41 -0
- package/dist/ir/inline-arrays.js +533 -0
- package/dist/ir/inline-arrays.js.map +1 -0
- package/dist/ir/inline-arrays.test.d.ts +1 -0
- package/dist/ir/inline-arrays.test.js +225 -0
- package/dist/ir/inline-arrays.test.js.map +1 -0
- package/dist/ir/int32-slots.d.ts +6 -0
- package/dist/ir/int32-slots.js +154 -16
- package/dist/ir/int32-slots.js.map +1 -1
- package/dist/ir/int32-slots.test.js +48 -0
- package/dist/ir/int32-slots.test.js.map +1 -1
- package/dist/ir/integer-loops.d.ts +12 -0
- package/dist/ir/integer-loops.js +23 -0
- package/dist/ir/integer-loops.js.map +1 -1
- package/dist/ir/integer-ranges.d.ts +7 -1
- package/dist/ir/integer-ranges.js +29 -2
- package/dist/ir/integer-ranges.js.map +1 -1
- package/dist/ir/intrinsic-signatures.js +2 -1
- package/dist/ir/intrinsic-signatures.js.map +1 -1
- package/dist/ir/ir.d.ts +103 -5
- package/dist/ir/ir.js +38 -4
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/ir.test.js +134 -1
- package/dist/ir/ir.test.js.map +1 -1
- package/dist/ir/jsval.js +211 -29
- package/dist/ir/jsval.js.map +1 -1
- package/dist/ir/jsval.test.js +120 -0
- package/dist/ir/jsval.test.js.map +1 -1
- package/dist/ir/loop-entry-ranges.d.ts +38 -0
- package/dist/ir/loop-entry-ranges.js +259 -0
- package/dist/ir/loop-entry-ranges.js.map +1 -0
- package/dist/ir/loop-entry-ranges.test.d.ts +1 -0
- package/dist/ir/loop-entry-ranges.test.js +191 -0
- package/dist/ir/loop-entry-ranges.test.js.map +1 -0
- package/dist/ir/node-index.d.ts +3 -0
- package/dist/ir/node-index.js +6 -0
- package/dist/ir/node-index.js.map +1 -1
- package/dist/ir/numeric-call-specialization.d.ts +9 -6
- package/dist/ir/numeric-call-specialization.js +164 -34
- package/dist/ir/numeric-call-specialization.js.map +1 -1
- package/dist/ir/paired-while-loops.js +23 -19
- package/dist/ir/paired-while-loops.js.map +1 -1
- package/dist/ir/parameter-versions.js +6 -3
- package/dist/ir/parameter-versions.js.map +1 -1
- package/dist/ir/receiver-readers.d.ts +10 -0
- package/dist/ir/receiver-readers.js +65 -28
- package/dist/ir/receiver-readers.js.map +1 -1
- package/dist/ir/row-pairs.d.ts +9 -1
- package/dist/ir/row-pairs.js +136 -43
- package/dist/ir/row-pairs.js.map +1 -1
- package/dist/ir/row-pairs.test.js +25 -5
- package/dist/ir/row-pairs.test.js.map +1 -1
- package/dist/ir/runtime-features.d.ts +33 -1
- package/dist/ir/runtime-features.js +104 -6
- package/dist/ir/runtime-features.js.map +1 -1
- package/dist/ir/runtime-features.test.js +13 -0
- package/dist/ir/runtime-features.test.js.map +1 -1
- package/dist/ir/saturating-loop-jams.d.ts +24 -0
- package/dist/ir/saturating-loop-jams.js +420 -0
- package/dist/ir/saturating-loop-jams.js.map +1 -0
- package/dist/ir/saturating-loop-jams.test.d.ts +1 -0
- package/dist/ir/saturating-loop-jams.test.js +196 -0
- package/dist/ir/saturating-loop-jams.test.js.map +1 -0
- package/dist/ir/scalar-records.js +9 -3
- package/dist/ir/scalar-records.js.map +1 -1
- package/dist/ir/self-captures.js +2 -1
- package/dist/ir/self-captures.js.map +1 -1
- package/dist/ir/serialize.d.ts +5 -1
- package/dist/ir/serialize.js +7 -1
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/traverse.js +3 -0
- package/dist/ir/traverse.js.map +1 -1
- package/dist/ir/validate.js +91 -9
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/ir-policy.js +1 -0
- package/dist/library/ir-policy.js.map +1 -1
- package/dist/native/cache.js +2 -0
- package/dist/native/cache.js.map +1 -1
- package/dist/native/cli.js +54 -7
- package/dist/native/cli.js.map +1 -1
- package/dist/native/compiler.d.ts +3 -0
- package/dist/native/compiler.js +173 -36
- package/dist/native/compiler.js.map +1 -1
- package/dist/native/compiler.test.js +86 -3
- package/dist/native/compiler.test.js.map +1 -1
- package/dist/native/executable-cache.d.ts +20 -2
- package/dist/native/executable-cache.js +17 -10
- package/dist/native/executable-cache.js.map +1 -1
- package/dist/native/executable-cache.test.js +38 -1
- package/dist/native/executable-cache.test.js.map +1 -1
- package/dist/native/linker-job.d.ts +71 -0
- package/dist/native/linker-job.js +242 -0
- package/dist/native/linker-job.js.map +1 -0
- package/dist/native/linker-job.test.d.ts +1 -0
- package/dist/native/linker-job.test.js +349 -0
- package/dist/native/linker-job.test.js.map +1 -0
- package/dist/native/prepare.js +15 -2
- package/dist/native/prepare.js.map +1 -1
- package/dist/native/sanitizer.js +10 -15
- package/dist/native/sanitizer.js.map +1 -1
- package/dist/native/sanitizer.test.js +152 -66
- package/dist/native/sanitizer.test.js.map +1 -1
- package/dist/native/toolchain.d.ts +11 -2
- package/dist/native/toolchain.js +43 -17
- package/dist/native/toolchain.js.map +1 -1
- package/dist/native/toolchain.test.js +75 -0
- package/dist/native/toolchain.test.js.map +1 -1
- package/dist/node-islands/boundary.d.ts +37 -0
- package/dist/node-islands/boundary.js +135 -0
- package/dist/node-islands/boundary.js.map +1 -0
- package/dist/node-islands/classify.js +1 -1
- package/dist/node-islands/classify.js.map +1 -1
- package/dist/node-islands/effect-gate.d.ts +11 -0
- package/dist/node-islands/effect-gate.js +746 -0
- package/dist/node-islands/effect-gate.js.map +1 -0
- package/dist/node-islands/effect-gate.test.d.ts +1 -0
- package/dist/node-islands/effect-gate.test.js +152 -0
- package/dist/node-islands/effect-gate.test.js.map +1 -0
- package/dist/node-islands/libnode-pack.d.ts +68 -0
- package/dist/node-islands/libnode-pack.js +199 -0
- package/dist/node-islands/libnode-pack.js.map +1 -0
- package/dist/node-islands/libnode-pack.test.d.ts +1 -0
- package/dist/node-islands/libnode-pack.test.js +258 -0
- package/dist/node-islands/libnode-pack.test.js.map +1 -0
- package/dist/node-islands/libnode.d.ts +32 -0
- package/dist/node-islands/libnode.js +212 -0
- package/dist/node-islands/libnode.js.map +1 -0
- package/dist/node-islands/libnode.test.d.ts +1 -0
- package/dist/node-islands/libnode.test.js +170 -0
- package/dist/node-islands/libnode.test.js.map +1 -0
- package/dist/node-islands/modules.d.ts +96 -0
- package/dist/node-islands/modules.js +803 -0
- package/dist/node-islands/modules.js.map +1 -0
- package/dist/node-islands/modules.test.d.ts +1 -0
- package/dist/node-islands/modules.test.js +276 -0
- package/dist/node-islands/modules.test.js.map +1 -0
- package/dist/node-islands/resolve.d.ts +8 -0
- package/dist/node-islands/resolve.js +10 -0
- package/dist/node-islands/resolve.js.map +1 -0
- package/dist/node-islands/snapshot.d.ts +16 -0
- package/dist/node-islands/snapshot.js +486 -0
- package/dist/node-islands/snapshot.js.map +1 -0
- package/dist/node-islands/snapshot.test.d.ts +1 -0
- package/dist/node-islands/snapshot.test.js +56 -0
- package/dist/node-islands/snapshot.test.js.map +1 -0
- package/dist/project-config.d.ts +37 -1
- package/dist/project-config.js +159 -7
- package/dist/project-config.js.map +1 -1
- package/dist/project-config.test.js +153 -0
- package/dist/project-config.test.js.map +1 -1
- package/dist/startup-cache.d.ts +1 -0
- package/dist/startup-cache.js +1 -0
- package/dist/startup-cache.js.map +1 -1
- package/package.json +24 -21
- package/surface-manifest.json +47 -7
|
@@ -0,0 +1,1951 @@
|
|
|
1
|
+
/* Static-object specialization, stage 2b (DESIGN-constant-objects.md):
|
|
2
|
+
* structural rewrites of pre-module JavaScript the constant object graphs
|
|
3
|
+
* prove indistinguishable.
|
|
4
|
+
*
|
|
5
|
+
* 1. ES5 constructors become classes. `ns.Vec = function (x, y) { … };`
|
|
6
|
+
* followed by `ns.Vec.prototype.m = function (…) { … };` statements is
|
|
7
|
+
* respelled `ns.Vec = class { constructor(x, y) { … } m(…) { … } };`.
|
|
8
|
+
* The program cannot tell the difference when:
|
|
9
|
+
* - the function is only ever constructed (every call edge is a `new`),
|
|
10
|
+
* never escapes, and its prototype is never replaced;
|
|
11
|
+
* - its prototype object is a constant object (stage 1) whose members
|
|
12
|
+
* are the function expressions those statements store, and nothing
|
|
13
|
+
* enumerates or reflects on the prototype or the instances (class
|
|
14
|
+
* methods are not enumerable, prototype assignments are);
|
|
15
|
+
* - no code reads the function's or the methods' `name` or `toString`;
|
|
16
|
+
* - the bodies behave the same in strict mode (class bodies are strict):
|
|
17
|
+
* no `arguments`, `eval` or strict-mode reserved word, no `this` in a
|
|
18
|
+
* nested non-arrow function, no `with`, no `delete` of a name, no write
|
|
19
|
+
* to an undeclared name or to `undefined`, `NaN` or `Infinity`, no
|
|
20
|
+
* repeated parameter name, no octal literal or escape, and property
|
|
21
|
+
* writes and deletes only through `this` (a write that sloppy mode
|
|
22
|
+
* ignores, into a primitive or a frozen object, throws in strict mode);
|
|
23
|
+
* - nothing freezes, seals or redefines the instances, so their own
|
|
24
|
+
* properties stay writable;
|
|
25
|
+
* - each method is only called as a method (`x.m(…)`): never constructed,
|
|
26
|
+
* read as a value or for its `prototype`, so it is never called with a
|
|
27
|
+
* primitive or missing `this` (which sloppy mode would replace) and
|
|
28
|
+
* never needs to be constructible (class methods are not);
|
|
29
|
+
* - a named constructor expression does not refer to its own name, which
|
|
30
|
+
* the class would not bind;
|
|
31
|
+
* - the statements between the constructor and its last method only
|
|
32
|
+
* define more functions or data (nothing runs that could observe the
|
|
33
|
+
* prototype half built): their stores go to constant objects, which
|
|
34
|
+
* have no setters;
|
|
35
|
+
* - nothing asks the prototype whether its members are enumerable
|
|
36
|
+
* (`propertyIsEnumerable`).
|
|
37
|
+
* 2. Namespace functions become direct functions. A constant field holding
|
|
38
|
+
* a function expression that does not use `this`, stored by a top-level
|
|
39
|
+
* statement, is hoisted to a function declaration, and calls through
|
|
40
|
+
* the namespace in the same file whose receiver is exactly that
|
|
41
|
+
* constant object call it directly. A member read is replaced only when
|
|
42
|
+
* its receiver is an initialized name or a chain of constant-object reads
|
|
43
|
+
* from one (nothing to evaluate, nothing to throw), and it runs after the
|
|
44
|
+
* store: in a top-level statement after it, or inside the stored
|
|
45
|
+
* function, and not inside a function declaration (which hoisting lets
|
|
46
|
+
* run earlier). A name is initialized when it is a parameter, a function
|
|
47
|
+
* declaration, or a variable declared with an initializer by an earlier
|
|
48
|
+
* top-level statement and never assigned again.
|
|
49
|
+
*
|
|
50
|
+
* Each rewrite keeps the original text unless every condition holds. */
|
|
51
|
+
import * as ts from "../ts7/adapter.js";
|
|
52
|
+
import { computeConstantGraphs } from "./constant-graphs.js";
|
|
53
|
+
import { resolveCjsRuntime } from "../cjs-resolve.js";
|
|
54
|
+
/** The replacement text of the read `node`: `text`, or, when the receiver
|
|
55
|
+
* may be nullish, the read as written followed by `text` in a comma
|
|
56
|
+
* expression, so a nullish receiver still throws Node's TypeError and any
|
|
57
|
+
* other receiver yields `text`'s value. */
|
|
58
|
+
function keepRead(node, text, nullish) {
|
|
59
|
+
if (!nullish)
|
|
60
|
+
return text;
|
|
61
|
+
const sf = node.getSourceFile();
|
|
62
|
+
return `(${sf.text.slice(ts.tokenStartOfNode(node), node.end)}, ${text})`;
|
|
63
|
+
}
|
|
64
|
+
const REFLECTIVE_CALLS = new Set([
|
|
65
|
+
"keys",
|
|
66
|
+
"values",
|
|
67
|
+
"entries",
|
|
68
|
+
"getOwnPropertyNames",
|
|
69
|
+
"getOwnPropertyDescriptor",
|
|
70
|
+
"getOwnPropertyDescriptors",
|
|
71
|
+
"getOwnPropertySymbols",
|
|
72
|
+
"assign",
|
|
73
|
+
"defineProperty",
|
|
74
|
+
"defineProperties",
|
|
75
|
+
"getPrototypeOf",
|
|
76
|
+
"setPrototypeOf",
|
|
77
|
+
"freeze",
|
|
78
|
+
"seal",
|
|
79
|
+
"preventExtensions",
|
|
80
|
+
"ownKeys",
|
|
81
|
+
]);
|
|
82
|
+
/** The most members a dispatched function table may have. */
|
|
83
|
+
const MAX_TABLE_ARMS = 16;
|
|
84
|
+
/** Words that are reserved only in strict mode. */
|
|
85
|
+
const STRICT_RESERVED = new Set([
|
|
86
|
+
"implements",
|
|
87
|
+
"interface",
|
|
88
|
+
"let",
|
|
89
|
+
"package",
|
|
90
|
+
"private",
|
|
91
|
+
"protected",
|
|
92
|
+
"public",
|
|
93
|
+
"static",
|
|
94
|
+
"yield",
|
|
95
|
+
"eval",
|
|
96
|
+
]);
|
|
97
|
+
/** The reflective calls that freeze, seal or redefine an object. */
|
|
98
|
+
const RESHAPING_CALLS = new Set([
|
|
99
|
+
"freeze",
|
|
100
|
+
"seal",
|
|
101
|
+
"preventExtensions",
|
|
102
|
+
"defineProperty",
|
|
103
|
+
"defineProperties",
|
|
104
|
+
"setPrototypeOf",
|
|
105
|
+
]);
|
|
106
|
+
/** Globals that sloppy mode lets a write to fail silently. */
|
|
107
|
+
const READ_ONLY_GLOBALS = new Set(["undefined", "NaN", "Infinity"]);
|
|
108
|
+
function topStatement(n) {
|
|
109
|
+
let p = n;
|
|
110
|
+
while (p.parent !== undefined && !ts.isSourceFile(p.parent))
|
|
111
|
+
p = p.parent;
|
|
112
|
+
return p.parent !== undefined && ts.isStatement(p) ? p : null;
|
|
113
|
+
}
|
|
114
|
+
/** `<lhs> = function (…) { … };` as a top-level statement: the assignment. */
|
|
115
|
+
function assignedFunction(fn) {
|
|
116
|
+
if (!ts.isFunctionExpression(fn) || fn.asteriskToken !== undefined)
|
|
117
|
+
return null;
|
|
118
|
+
if (fn.modifiers?.nodes.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword))
|
|
119
|
+
return null;
|
|
120
|
+
const assign = fn.parent;
|
|
121
|
+
if (assign === undefined ||
|
|
122
|
+
!ts.isBinaryExpression(assign) ||
|
|
123
|
+
assign.operatorToken.kind !== ts.SyntaxKind.EqualsToken ||
|
|
124
|
+
assign.right !== fn)
|
|
125
|
+
return null;
|
|
126
|
+
const stmt = assign.parent;
|
|
127
|
+
if (stmt === undefined || !ts.isExpressionStatement(stmt) || !ts.isSourceFile(stmt.parent))
|
|
128
|
+
return null;
|
|
129
|
+
return { stmt, lhs: assign.left };
|
|
130
|
+
}
|
|
131
|
+
/** A function expression stored as a member of an object literal that a
|
|
132
|
+
* top-level statement creates (`ns.registry = { run: function () {} }`,
|
|
133
|
+
* `var ns = { util: { trim: function () {} } }`, at any literal depth): the
|
|
134
|
+
* statement, and a dotted path naming the member. The function's scope is
|
|
135
|
+
* the module scope, so it can be hoisted to a module function. */
|
|
136
|
+
function literalMemberFunction(fn) {
|
|
137
|
+
if (!ts.isFunctionExpression(fn) || fn.asteriskToken !== undefined)
|
|
138
|
+
return null;
|
|
139
|
+
if (fn.modifiers?.nodes.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword))
|
|
140
|
+
return null;
|
|
141
|
+
const keys = [];
|
|
142
|
+
let n = fn;
|
|
143
|
+
for (;;) {
|
|
144
|
+
const member = n.parent;
|
|
145
|
+
if (member === undefined || !ts.isPropertyAssignment(member) || member.initializer !== n)
|
|
146
|
+
return null;
|
|
147
|
+
const name = member.name;
|
|
148
|
+
if (!ts.isIdentifier(name) && !ts.isStringLiteral(name))
|
|
149
|
+
return null;
|
|
150
|
+
keys.unshift(name.text);
|
|
151
|
+
const literal = member.parent;
|
|
152
|
+
if (literal === undefined || !ts.isObjectLiteralExpression(literal))
|
|
153
|
+
return null;
|
|
154
|
+
const holder = literal.parent;
|
|
155
|
+
if (holder !== undefined && ts.isPropertyAssignment(holder)) {
|
|
156
|
+
n = literal;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (holder !== undefined &&
|
|
160
|
+
ts.isBinaryExpression(holder) &&
|
|
161
|
+
holder.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
162
|
+
holder.right === literal &&
|
|
163
|
+
holder.parent !== undefined &&
|
|
164
|
+
ts.isExpressionStatement(holder.parent) &&
|
|
165
|
+
ts.isSourceFile(holder.parent.parent))
|
|
166
|
+
return { stmt: holder.parent, path: [holder.left.getText(), ...keys].join(".") };
|
|
167
|
+
if (holder !== undefined &&
|
|
168
|
+
ts.isVariableDeclaration(holder) &&
|
|
169
|
+
holder.initializer === literal &&
|
|
170
|
+
ts.isIdentifier(holder.name)) {
|
|
171
|
+
const stmt = holder.parent?.parent;
|
|
172
|
+
if (stmt !== undefined && ts.isVariableStatement(stmt) && ts.isSourceFile(stmt.parent))
|
|
173
|
+
return { stmt, path: [holder.name.text, ...keys].join(".") };
|
|
174
|
+
}
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/** The text of a primitive literal an object literal itself gives `key`
|
|
179
|
+
* (`{ K: 1 }`, `{ "k": "v" }`, `-1`, `true`, `null`), or null. */
|
|
180
|
+
function ownLiteralMember(literal, key) {
|
|
181
|
+
// `__proto__: v` in a literal sets the prototype and makes no property.
|
|
182
|
+
if (!ts.isObjectLiteralExpression(literal) || key === "__proto__")
|
|
183
|
+
return null;
|
|
184
|
+
let found = null;
|
|
185
|
+
for (const m of literal.properties.nodes) {
|
|
186
|
+
const name = m.name;
|
|
187
|
+
const text = name !== undefined && (ts.isIdentifier(name) || ts.isStringLiteral(name)) ? name.text : null;
|
|
188
|
+
if (text !== key)
|
|
189
|
+
continue;
|
|
190
|
+
if (!ts.isPropertyAssignment(m) || found !== null)
|
|
191
|
+
return null;
|
|
192
|
+
found = primitiveLiteralText(m.initializer);
|
|
193
|
+
if (found === null)
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
return found;
|
|
197
|
+
}
|
|
198
|
+
/** Whether a top-level statement runs no code but its own. Its expressions
|
|
199
|
+
* are literals, identifiers, functions (not run), object and array literals
|
|
200
|
+
* without spreads or computed keys, `=` stores, `var` bindings without
|
|
201
|
+
* patterns, `&&`, `||`, `??`, `?:`, `,`, `!`, `typeof`, `void`, `===` and
|
|
202
|
+
* `!==`, none of which calls a function, and member reads and stores that
|
|
203
|
+
* `plainMember` accepts (no getter or setter runs). Every other form can
|
|
204
|
+
* run code: a call, `new` or tagged template, a class (static blocks and
|
|
205
|
+
* field initializers run), coercion (arithmetic, `+`, templates with
|
|
206
|
+
* substitutions, relational and loose comparisons, `in`, `instanceof`,
|
|
207
|
+
* computed keys), iteration (spreads, destructuring), `delete`, `await` and
|
|
208
|
+
* `yield`. */
|
|
209
|
+
function runsNoCode(stmt, plainMember) {
|
|
210
|
+
if (ts.isFunctionDeclaration(stmt) || ts.isEmptyStatement(stmt))
|
|
211
|
+
return true;
|
|
212
|
+
if (ts.isExpressionStatement(stmt))
|
|
213
|
+
return quietExpression(stmt.expression, plainMember);
|
|
214
|
+
if (!ts.isVariableStatement(stmt))
|
|
215
|
+
return false;
|
|
216
|
+
return stmt.declarationList.declarations.nodes.every((d) => ts.isIdentifier(d.name) &&
|
|
217
|
+
(d.initializer === undefined || quietExpression(d.initializer, plainMember)));
|
|
218
|
+
}
|
|
219
|
+
function quietExpression(e, plainMember) {
|
|
220
|
+
const quiet = (x) => quietExpression(x, plainMember);
|
|
221
|
+
if (ts.isParenthesizedExpression(e))
|
|
222
|
+
return quiet(e.expression);
|
|
223
|
+
if (ts.isIdentifier(e) ||
|
|
224
|
+
ts.isNumericLiteral(e) ||
|
|
225
|
+
ts.isBigIntLiteral(e) ||
|
|
226
|
+
ts.isStringLiteral(e) ||
|
|
227
|
+
ts.isNoSubstitutionTemplateLiteral(e) ||
|
|
228
|
+
ts.isRegularExpressionLiteral(e) ||
|
|
229
|
+
ts.isFunctionExpression(e) ||
|
|
230
|
+
ts.isArrowFunction(e) ||
|
|
231
|
+
e.kind === ts.SyntaxKind.TrueKeyword ||
|
|
232
|
+
e.kind === ts.SyntaxKind.FalseKeyword ||
|
|
233
|
+
e.kind === ts.SyntaxKind.NullKeyword ||
|
|
234
|
+
e.kind === ts.SyntaxKind.ThisKeyword)
|
|
235
|
+
return true;
|
|
236
|
+
if (ts.isObjectLiteralExpression(e))
|
|
237
|
+
return e.properties.nodes.every((m) => {
|
|
238
|
+
if (ts.isShorthandPropertyAssignment(m))
|
|
239
|
+
return m.objectAssignmentInitializer === undefined;
|
|
240
|
+
if (!ts.isPropertyAssignment(m))
|
|
241
|
+
return false;
|
|
242
|
+
const name = m.name;
|
|
243
|
+
if (!ts.isIdentifier(name) && !ts.isStringLiteral(name) && !ts.isNumericLiteral(name))
|
|
244
|
+
return false;
|
|
245
|
+
return quiet(m.initializer);
|
|
246
|
+
});
|
|
247
|
+
if (ts.isArrayLiteralExpression(e))
|
|
248
|
+
return e.elements.nodes.every((x) => ts.isOmittedExpression(x) || (!ts.isSpreadElement(x) && quiet(x)));
|
|
249
|
+
if (ts.isTypeOfExpression(e) || ts.isVoidExpression(e))
|
|
250
|
+
return quiet(e.expression);
|
|
251
|
+
if (ts.isPrefixUnaryExpression(e))
|
|
252
|
+
return e.operator === ts.SyntaxKind.ExclamationToken && quiet(e.operand);
|
|
253
|
+
if (ts.isConditionalExpression(e))
|
|
254
|
+
return quiet(e.condition) && quiet(e.whenTrue) && quiet(e.whenFalse);
|
|
255
|
+
if (ts.isPropertyAccessExpression(e) || ts.isElementAccessExpression(e))
|
|
256
|
+
return quietMember(e, plainMember);
|
|
257
|
+
if (!ts.isBinaryExpression(e))
|
|
258
|
+
return false;
|
|
259
|
+
switch (e.operatorToken.kind) {
|
|
260
|
+
case ts.SyntaxKind.EqualsToken:
|
|
261
|
+
if (ts.isIdentifier(e.left))
|
|
262
|
+
return quiet(e.right);
|
|
263
|
+
return ((ts.isPropertyAccessExpression(e.left) || ts.isElementAccessExpression(e.left)) &&
|
|
264
|
+
quietMember(e.left, plainMember) &&
|
|
265
|
+
quiet(e.right));
|
|
266
|
+
case ts.SyntaxKind.AmpersandAmpersandToken:
|
|
267
|
+
case ts.SyntaxKind.BarBarToken:
|
|
268
|
+
case ts.SyntaxKind.QuestionQuestionToken:
|
|
269
|
+
case ts.SyntaxKind.CommaToken:
|
|
270
|
+
case ts.SyntaxKind.EqualsEqualsEqualsToken:
|
|
271
|
+
case ts.SyntaxKind.ExclamationEqualsEqualsToken:
|
|
272
|
+
return quiet(e.left) && quiet(e.right);
|
|
273
|
+
default:
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
/** A member read or store target with a literal key on a receiver that
|
|
278
|
+
* runs no code, which `plainMember` accepts. */
|
|
279
|
+
function quietMember(e, plainMember) {
|
|
280
|
+
if (e.questionDotToken !== undefined)
|
|
281
|
+
return false;
|
|
282
|
+
if (ts.isElementAccessExpression(e) &&
|
|
283
|
+
!ts.isStringLiteral(e.argumentExpression) &&
|
|
284
|
+
!ts.isNumericLiteral(e.argumentExpression))
|
|
285
|
+
return false;
|
|
286
|
+
return plainMember(e) && quietExpression(e.expression, plainMember);
|
|
287
|
+
}
|
|
288
|
+
/** Whether an identifier is written where it appears: an assignment or
|
|
289
|
+
* update target, a destructuring assignment or loop target (through array
|
|
290
|
+
* and object patterns, defaults and rests), or a `var`, `let`, `const` or
|
|
291
|
+
* parameter binding of the name (a nested binding shadows it, which only
|
|
292
|
+
* makes the answer conservative). */
|
|
293
|
+
function writesBinding(id) {
|
|
294
|
+
let n = id;
|
|
295
|
+
for (let p = n.parent; p !== undefined; n = p, p = p.parent) {
|
|
296
|
+
if (ts.isPrefixUnaryExpression(p) || ts.isPostfixUnaryExpression(p))
|
|
297
|
+
return (p.operator === ts.SyntaxKind.PlusPlusToken || p.operator === ts.SyntaxKind.MinusMinusToken);
|
|
298
|
+
if (ts.isBinaryExpression(p)) {
|
|
299
|
+
const op = p.operatorToken.kind;
|
|
300
|
+
if (op >= ts.SyntaxKind.FirstAssignment && op <= ts.SyntaxKind.LastAssignment)
|
|
301
|
+
return p.left === n;
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
if (ts.isForOfStatement(p) || ts.isForInStatement(p))
|
|
305
|
+
return p.initializer === n;
|
|
306
|
+
if (ts.isVariableDeclaration(p) || ts.isParameter(p) || ts.isBindingElement(p))
|
|
307
|
+
return p.name === n;
|
|
308
|
+
if (ts.isParenthesizedExpression(p) ||
|
|
309
|
+
ts.isArrayLiteralExpression(p) ||
|
|
310
|
+
ts.isObjectLiteralExpression(p) ||
|
|
311
|
+
ts.isSpreadElement(p) ||
|
|
312
|
+
ts.isSpreadAssignment(p) ||
|
|
313
|
+
ts.isShorthandPropertyAssignment(p) ||
|
|
314
|
+
ts.isArrayBindingPattern(p) ||
|
|
315
|
+
ts.isObjectBindingPattern(p))
|
|
316
|
+
continue;
|
|
317
|
+
if (ts.isPropertyAssignment(p)) {
|
|
318
|
+
if (p.initializer !== n)
|
|
319
|
+
return false;
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
return false;
|
|
325
|
+
}
|
|
326
|
+
function enclosingFunctionLike(n) {
|
|
327
|
+
for (let p = n.parent; p !== undefined; p = p.parent)
|
|
328
|
+
if (ts.isFunctionLike(p))
|
|
329
|
+
return p;
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
function primitiveLiteralText(e) {
|
|
333
|
+
if (ts.isNumericLiteral(e) ||
|
|
334
|
+
ts.isStringLiteral(e) ||
|
|
335
|
+
e.kind === ts.SyntaxKind.TrueKeyword ||
|
|
336
|
+
e.kind === ts.SyntaxKind.FalseKeyword ||
|
|
337
|
+
e.kind === ts.SyntaxKind.NullKeyword)
|
|
338
|
+
return e.getText();
|
|
339
|
+
if (ts.isPrefixUnaryExpression(e) &&
|
|
340
|
+
e.operator === ts.SyntaxKind.MinusToken &&
|
|
341
|
+
ts.isNumericLiteral(e.operand))
|
|
342
|
+
return e.getText();
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
/** Whether a member expression only reads: not a store target, not
|
|
346
|
+
* updated, deleted or called. */
|
|
347
|
+
function isPlainRead(node) {
|
|
348
|
+
const p = node.parent;
|
|
349
|
+
if (p === undefined)
|
|
350
|
+
return false;
|
|
351
|
+
if (ts.isBinaryExpression(p) &&
|
|
352
|
+
p.left === node &&
|
|
353
|
+
p.operatorToken.kind >= ts.SyntaxKind.FirstAssignment &&
|
|
354
|
+
p.operatorToken.kind <= ts.SyntaxKind.LastAssignment)
|
|
355
|
+
return false;
|
|
356
|
+
if (ts.isPrefixUnaryExpression(p) || ts.isPostfixUnaryExpression(p)) {
|
|
357
|
+
const op = p.operator;
|
|
358
|
+
if (op === ts.SyntaxKind.PlusPlusToken || op === ts.SyntaxKind.MinusMinusToken)
|
|
359
|
+
return false;
|
|
360
|
+
}
|
|
361
|
+
if (ts.isDeleteExpression(p))
|
|
362
|
+
return false;
|
|
363
|
+
if ((ts.isCallExpression(p) || ts.isNewExpression(p)) && p.expression === node)
|
|
364
|
+
return false;
|
|
365
|
+
// Destructuring and for-in/of targets.
|
|
366
|
+
if (ts.isArrayLiteralExpression(p) || ts.isShorthandPropertyAssignment(p))
|
|
367
|
+
return false;
|
|
368
|
+
if ((ts.isForInStatement(p) || ts.isForOfStatement(p)) && p.initializer === node)
|
|
369
|
+
return false;
|
|
370
|
+
if (ts.isPropertyAssignment(p) &&
|
|
371
|
+
p.initializer === node &&
|
|
372
|
+
ts.isObjectLiteralExpression(p.parent)) {
|
|
373
|
+
// `({ a: x.k } = …)`: a target only inside an assignment pattern.
|
|
374
|
+
let q = p.parent;
|
|
375
|
+
while (q !== undefined &&
|
|
376
|
+
(ts.isObjectLiteralExpression(q) ||
|
|
377
|
+
ts.isArrayLiteralExpression(q) ||
|
|
378
|
+
ts.isPropertyAssignment(q) ||
|
|
379
|
+
ts.isParenthesizedExpression(q))) {
|
|
380
|
+
const up = q.parent;
|
|
381
|
+
if (up !== undefined && ts.isBinaryExpression(up) && up.left === q)
|
|
382
|
+
return false;
|
|
383
|
+
q = up;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return true;
|
|
387
|
+
}
|
|
388
|
+
/** Whether `e` is a property access or element access through `this`. */
|
|
389
|
+
function throughThis(e) {
|
|
390
|
+
while (ts.isParenthesizedExpression(e))
|
|
391
|
+
e = e.expression;
|
|
392
|
+
return ((ts.isPropertyAccessExpression(e) || ts.isElementAccessExpression(e)) &&
|
|
393
|
+
e.expression.kind === ts.SyntaxKind.ThisKeyword);
|
|
394
|
+
}
|
|
395
|
+
/** Whether a function body behaves the same in strict mode. */
|
|
396
|
+
function strictSafe(checker, fn) {
|
|
397
|
+
let safe = true;
|
|
398
|
+
// A repeated parameter name is a strict-mode error.
|
|
399
|
+
const params = new Set();
|
|
400
|
+
for (const p of fn.parameters.nodes) {
|
|
401
|
+
if (!ts.isIdentifier(p.name) || params.has(p.name.text))
|
|
402
|
+
return false;
|
|
403
|
+
params.add(p.name.text);
|
|
404
|
+
}
|
|
405
|
+
const visit = (n, nested) => {
|
|
406
|
+
if (!safe)
|
|
407
|
+
return;
|
|
408
|
+
if (ts.isIdentifier(n) && (n.text === "arguments" || STRICT_RESERVED.has(n.text)))
|
|
409
|
+
safe = false;
|
|
410
|
+
if (n.kind === ts.SyntaxKind.WithStatement)
|
|
411
|
+
safe = false;
|
|
412
|
+
if (nested && n.kind === ts.SyntaxKind.ThisKeyword)
|
|
413
|
+
safe = false;
|
|
414
|
+
if (ts.isDeleteExpression(n) && !throughThis(n.expression))
|
|
415
|
+
safe = false;
|
|
416
|
+
if (ts.isNumericLiteral(n) && /^0\d/.test(n.getText()))
|
|
417
|
+
safe = false;
|
|
418
|
+
// Octal escapes in strings and templates are strict-mode errors.
|
|
419
|
+
if ((ts.isStringLiteral(n) || ts.isNoSubstitutionTemplateLiteral(n)) &&
|
|
420
|
+
/\\(0\d|[1-7])/.test(n.getText()))
|
|
421
|
+
safe = false;
|
|
422
|
+
const assigns = ts.isBinaryExpression(n) &&
|
|
423
|
+
n.operatorToken.kind >= ts.SyntaxKind.FirstAssignment &&
|
|
424
|
+
n.operatorToken.kind <= ts.SyntaxKind.LastAssignment;
|
|
425
|
+
const counts = (ts.isPrefixUnaryExpression(n) || ts.isPostfixUnaryExpression(n)) &&
|
|
426
|
+
(n.operator === ts.SyntaxKind.PlusPlusToken || n.operator === ts.SyntaxKind.MinusMinusToken);
|
|
427
|
+
// `for (k in o)` and `for (k of a)` store into an expression head on
|
|
428
|
+
// every iteration, like `k = …`.
|
|
429
|
+
const loopHead = (ts.isForInStatement(n) || ts.isForOfStatement(n)) &&
|
|
430
|
+
!ts.isVariableDeclarationList(n.initializer)
|
|
431
|
+
? n.initializer
|
|
432
|
+
: undefined;
|
|
433
|
+
const target = assigns
|
|
434
|
+
? n.left
|
|
435
|
+
: counts
|
|
436
|
+
? n.operand
|
|
437
|
+
: loopHead;
|
|
438
|
+
// A store that sloppy mode drops (into a primitive, a frozen object or a
|
|
439
|
+
// read-only property) throws in strict mode: only stores through `this`,
|
|
440
|
+
// a fresh or method receiver object, are known to behave the same.
|
|
441
|
+
if (target !== undefined) {
|
|
442
|
+
let t = target;
|
|
443
|
+
while (ts.isParenthesizedExpression(t))
|
|
444
|
+
t = t.expression;
|
|
445
|
+
if ((ts.isPropertyAccessExpression(t) || ts.isElementAccessExpression(t)) && !throughThis(t))
|
|
446
|
+
safe = false;
|
|
447
|
+
if (ts.isIdentifier(t) && READ_ONLY_GLOBALS.has(t.text))
|
|
448
|
+
safe = false;
|
|
449
|
+
if (!ts.isIdentifier(t) &&
|
|
450
|
+
!ts.isPropertyAccessExpression(t) &&
|
|
451
|
+
!ts.isElementAccessExpression(t))
|
|
452
|
+
safe = false;
|
|
453
|
+
}
|
|
454
|
+
// A store into an undeclared name creates a global in sloppy mode and
|
|
455
|
+
// throws a ReferenceError in strict mode.
|
|
456
|
+
const stored = assigns ? n.left : loopHead;
|
|
457
|
+
if (stored !== undefined && ts.isIdentifier(stored)) {
|
|
458
|
+
let declared = false;
|
|
459
|
+
try {
|
|
460
|
+
const s = checker.getSymbolAtLocation(stored);
|
|
461
|
+
declared = s !== undefined && s.declarations.length > 0;
|
|
462
|
+
}
|
|
463
|
+
catch {
|
|
464
|
+
declared = false;
|
|
465
|
+
}
|
|
466
|
+
if (!declared)
|
|
467
|
+
safe = false;
|
|
468
|
+
}
|
|
469
|
+
const nestedHere = nested || (n !== fn && ts.isFunctionLike(n) && !ts.isArrowFunction(n));
|
|
470
|
+
ts.forEachChild(n, (c) => visit(c, nestedHere));
|
|
471
|
+
};
|
|
472
|
+
visit(fn, false);
|
|
473
|
+
return safe;
|
|
474
|
+
}
|
|
475
|
+
/** Whether an identifier named `name` appears in `fn`'s parameters or body. */
|
|
476
|
+
function mentions(fn, name) {
|
|
477
|
+
let found = false;
|
|
478
|
+
const visit = (n) => {
|
|
479
|
+
if (found)
|
|
480
|
+
return;
|
|
481
|
+
if (ts.isIdentifier(n) && n.text === name && n !== fn.name)
|
|
482
|
+
found = true;
|
|
483
|
+
ts.forEachChild(n, visit);
|
|
484
|
+
};
|
|
485
|
+
visit(fn);
|
|
486
|
+
return found;
|
|
487
|
+
}
|
|
488
|
+
function usesThis(fn) {
|
|
489
|
+
let found = false;
|
|
490
|
+
const visit = (n) => {
|
|
491
|
+
if (found)
|
|
492
|
+
return;
|
|
493
|
+
if (n.kind === ts.SyntaxKind.ThisKeyword)
|
|
494
|
+
found = true;
|
|
495
|
+
if (n !== fn && ts.isFunctionLike(n) && !ts.isArrowFunction(n))
|
|
496
|
+
return;
|
|
497
|
+
ts.forEachChild(n, visit);
|
|
498
|
+
};
|
|
499
|
+
visit(fn);
|
|
500
|
+
return found;
|
|
501
|
+
}
|
|
502
|
+
export function planStaticObjectRewrites(analysis, files) {
|
|
503
|
+
const graphs = computeConstantGraphs(analysis);
|
|
504
|
+
const checker = analysis.checker;
|
|
505
|
+
const kept = [];
|
|
506
|
+
const editsByFile = new Map();
|
|
507
|
+
const fileSet = new Set(files);
|
|
508
|
+
const edit = (sf, e) => {
|
|
509
|
+
let l = editsByFile.get(sf);
|
|
510
|
+
if (l === undefined)
|
|
511
|
+
editsByFile.set(sf, (l = []));
|
|
512
|
+
l.push(e);
|
|
513
|
+
};
|
|
514
|
+
const constantAtoms = new Map();
|
|
515
|
+
for (const o of graphs.objects)
|
|
516
|
+
constantAtoms.set(o.site.atom, o);
|
|
517
|
+
// Program-wide facts the conditions read.
|
|
518
|
+
const readNames = new Map();
|
|
519
|
+
for (const op of analysis.ops) {
|
|
520
|
+
if (op.kind !== "read" || op.name === null)
|
|
521
|
+
continue;
|
|
522
|
+
for (const a of analysis.nodes[op.recv].atoms) {
|
|
523
|
+
let s = readNames.get(a);
|
|
524
|
+
if (s === undefined)
|
|
525
|
+
readNames.set(a, (s = new Set()));
|
|
526
|
+
s.add(op.name);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
const computedRecv = new Set();
|
|
530
|
+
for (const op of analysis.ops)
|
|
531
|
+
if (op.kind !== "read" && op.kind !== "write" && op.kind !== "lengthWrite")
|
|
532
|
+
for (const a of analysis.nodes[op.recv].atoms)
|
|
533
|
+
computedRecv.add(a);
|
|
534
|
+
// One entry per (kind, syntax node): a node the analysis walked in
|
|
535
|
+
// several contexts (receiver classes, per-site clones) is rewritten only
|
|
536
|
+
// when the receivers of every context together satisfy the conditions.
|
|
537
|
+
const mergedOps = [];
|
|
538
|
+
{
|
|
539
|
+
const byKey = new Map();
|
|
540
|
+
const ids = new Map();
|
|
541
|
+
for (const op of analysis.ops) {
|
|
542
|
+
let id = ids.get(op.node);
|
|
543
|
+
if (id === undefined)
|
|
544
|
+
ids.set(op.node, (id = ids.size));
|
|
545
|
+
const key = `${op.kind}:${op.name ?? ""}:${id}`;
|
|
546
|
+
let entry = byKey.get(key);
|
|
547
|
+
if (entry === undefined) {
|
|
548
|
+
byKey.set(key, (entry = { op, atoms: new Set(), nullish: false }));
|
|
549
|
+
mergedOps.push(entry);
|
|
550
|
+
}
|
|
551
|
+
// A nullish receiver makes the read throw, so the rewrites decide on
|
|
552
|
+
// the other receivers (absent keys read undefined in the analysis:
|
|
553
|
+
// `ns.util` before `ns.util = {…}` runs), and `nullish` keeps the
|
|
554
|
+
// throw: a rewrite of such a read evaluates the read first. In an
|
|
555
|
+
// optional chain a nullish receiver short-circuits instead, so it
|
|
556
|
+
// counts.
|
|
557
|
+
const optional = (op.node.flags & ts.NodeFlags.OptionalChain) !== 0;
|
|
558
|
+
for (const a of analysis.nodes[op.recv].atoms) {
|
|
559
|
+
if (optional || !(a.kind === "prim" && (a.label === "undefined" || a.label === "null")))
|
|
560
|
+
entry.atoms.add(a);
|
|
561
|
+
else
|
|
562
|
+
entry.nullish = true;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
const forIns = [];
|
|
567
|
+
const reflective = [];
|
|
568
|
+
// Receivers of `x.propertyIsEnumerable(…)` calls, and whether the method
|
|
569
|
+
// is also reached any other way (`.call`, a stored reference).
|
|
570
|
+
const enumerabilityQueries = [];
|
|
571
|
+
let enumerabilityEscapes = false;
|
|
572
|
+
// Names stored to by assignments or updates.
|
|
573
|
+
const assignedNames = [];
|
|
574
|
+
for (const sf of analysis.files) {
|
|
575
|
+
const visit = (n) => {
|
|
576
|
+
if (ts.isForInStatement(n))
|
|
577
|
+
forIns.push(n.expression);
|
|
578
|
+
if (ts.isCallExpression(n) &&
|
|
579
|
+
ts.isPropertyAccessExpression(n.expression) &&
|
|
580
|
+
ts.isIdentifier(n.expression.name) &&
|
|
581
|
+
(REFLECTIVE_CALLS.has(n.expression.name.text) ||
|
|
582
|
+
n.expression.name.text === "propertyIsEnumerable"))
|
|
583
|
+
reflective.push(n);
|
|
584
|
+
if (ts.isIdentifier(n) && n.text === "propertyIsEnumerable") {
|
|
585
|
+
const access = n.parent;
|
|
586
|
+
const call = access?.parent;
|
|
587
|
+
if (access !== undefined &&
|
|
588
|
+
ts.isPropertyAccessExpression(access) &&
|
|
589
|
+
access.name === n &&
|
|
590
|
+
call !== undefined &&
|
|
591
|
+
ts.isCallExpression(call) &&
|
|
592
|
+
call.expression === access)
|
|
593
|
+
enumerabilityQueries.push(access.expression);
|
|
594
|
+
else
|
|
595
|
+
enumerabilityEscapes = true;
|
|
596
|
+
}
|
|
597
|
+
if (ts.isBinaryExpression(n) &&
|
|
598
|
+
n.operatorToken.kind >= ts.SyntaxKind.FirstAssignment &&
|
|
599
|
+
n.operatorToken.kind <= ts.SyntaxKind.LastAssignment &&
|
|
600
|
+
ts.isIdentifier(n.left))
|
|
601
|
+
assignedNames.push(n.left);
|
|
602
|
+
if ((ts.isPrefixUnaryExpression(n) || ts.isPostfixUnaryExpression(n)) &&
|
|
603
|
+
(n.operator === ts.SyntaxKind.PlusPlusToken ||
|
|
604
|
+
n.operator === ts.SyntaxKind.MinusMinusToken) &&
|
|
605
|
+
ts.isIdentifier(n.operand))
|
|
606
|
+
assignedNames.push(n.operand);
|
|
607
|
+
ts.forEachChild(n, visit);
|
|
608
|
+
};
|
|
609
|
+
visit(sf);
|
|
610
|
+
}
|
|
611
|
+
const declOf = (id) => {
|
|
612
|
+
try {
|
|
613
|
+
const s = checker.getSymbolAtLocation(id);
|
|
614
|
+
return s?.valueDeclaration ?? s?.declarations[0];
|
|
615
|
+
}
|
|
616
|
+
catch {
|
|
617
|
+
return undefined;
|
|
618
|
+
}
|
|
619
|
+
};
|
|
620
|
+
const readOps = new Map();
|
|
621
|
+
const writeOps = new Map();
|
|
622
|
+
for (const op of analysis.ops) {
|
|
623
|
+
if (op.kind === "read")
|
|
624
|
+
readOps.set(op.node, op);
|
|
625
|
+
if (op.kind === "write")
|
|
626
|
+
writeOps.set(op.node, op);
|
|
627
|
+
}
|
|
628
|
+
const reassigned = new Set();
|
|
629
|
+
for (const id of assignedNames) {
|
|
630
|
+
const d = declOf(id);
|
|
631
|
+
if (d !== undefined)
|
|
632
|
+
reassigned.add(d);
|
|
633
|
+
}
|
|
634
|
+
/** Whether evaluating `e` runs no code, so a rewrite that no longer
|
|
635
|
+
* evaluates it changes nothing: a name, `this`, or a member read whose
|
|
636
|
+
* receiver is such an expression and can only be constant objects (they
|
|
637
|
+
* have no accessors). A call, an assignment or any other expression may
|
|
638
|
+
* have effects. */
|
|
639
|
+
const effectFree = (e) => {
|
|
640
|
+
while (ts.isParenthesizedExpression(e))
|
|
641
|
+
e = e.expression;
|
|
642
|
+
if (ts.isIdentifier(e) || e.kind === ts.SyntaxKind.ThisKeyword)
|
|
643
|
+
return true;
|
|
644
|
+
let receiver;
|
|
645
|
+
if (ts.isPropertyAccessExpression(e) && e.questionDotToken === undefined)
|
|
646
|
+
receiver = e.expression;
|
|
647
|
+
else if (ts.isElementAccessExpression(e) &&
|
|
648
|
+
e.questionDotToken === undefined &&
|
|
649
|
+
ts.isStringLiteralLike(e.argumentExpression))
|
|
650
|
+
receiver = e.expression;
|
|
651
|
+
else
|
|
652
|
+
return false;
|
|
653
|
+
const op = readOps.get(e);
|
|
654
|
+
if (op === undefined)
|
|
655
|
+
return false;
|
|
656
|
+
const atoms = analysis.nodes[op.recv].atoms;
|
|
657
|
+
if (atoms.size === 0 || ![...atoms].every((a) => constantAtoms.has(a)))
|
|
658
|
+
return false;
|
|
659
|
+
return effectFree(receiver);
|
|
660
|
+
};
|
|
661
|
+
/** Whether an expression may evaluate to one of `atoms` (identifiers
|
|
662
|
+
* through their declarations' values, `new` of a known constructor path;
|
|
663
|
+
* anything else may). */
|
|
664
|
+
const mayBe = (e, atoms, ctorPath) => {
|
|
665
|
+
while (ts.isParenthesizedExpression(e))
|
|
666
|
+
e = e.expression;
|
|
667
|
+
if (ts.isNewExpression(e)) {
|
|
668
|
+
if (e.expression.getText() === ctorPath)
|
|
669
|
+
return [...atoms].some((a) => a.label.startsWith("new "));
|
|
670
|
+
return false;
|
|
671
|
+
}
|
|
672
|
+
if (ts.isIdentifier(e)) {
|
|
673
|
+
const d = declOf(e);
|
|
674
|
+
if (d === undefined)
|
|
675
|
+
return true;
|
|
676
|
+
for (const a of analysis.declValues(d))
|
|
677
|
+
if (atoms.has(a))
|
|
678
|
+
return true;
|
|
679
|
+
return false;
|
|
680
|
+
}
|
|
681
|
+
if (ts.isLiteralExpression(e) ||
|
|
682
|
+
ts.isObjectLiteralExpression(e) ||
|
|
683
|
+
ts.isArrayLiteralExpression(e))
|
|
684
|
+
return false;
|
|
685
|
+
return true;
|
|
686
|
+
};
|
|
687
|
+
/** `mayBe`, which also follows member reads: a constructor's `prototype`
|
|
688
|
+
* is its default prototype object, and a constant object's field holds
|
|
689
|
+
* the values stored to it. */
|
|
690
|
+
const mayBeValue = (e, atoms, ctorPath) => {
|
|
691
|
+
while (ts.isParenthesizedExpression(e))
|
|
692
|
+
e = e.expression;
|
|
693
|
+
if (!ts.isPropertyAccessExpression(e))
|
|
694
|
+
return mayBe(e, atoms, ctorPath);
|
|
695
|
+
const op = readOps.get(e);
|
|
696
|
+
if (op === undefined || op.name === null)
|
|
697
|
+
return true;
|
|
698
|
+
for (const a of analysis.nodes[op.recv].atoms) {
|
|
699
|
+
const proto = op.name === "prototype" ? analysis.protoOf.get(a) : undefined;
|
|
700
|
+
if (proto !== undefined) {
|
|
701
|
+
if (atoms.has(proto))
|
|
702
|
+
return true;
|
|
703
|
+
continue;
|
|
704
|
+
}
|
|
705
|
+
if (!constantAtoms.has(a))
|
|
706
|
+
return true;
|
|
707
|
+
const field = analysis.fields.get(a)?.get(op.name);
|
|
708
|
+
if (field !== undefined && [...analysis.nodes[field].atoms].some((v) => atoms.has(v)))
|
|
709
|
+
return true;
|
|
710
|
+
}
|
|
711
|
+
return false;
|
|
712
|
+
};
|
|
713
|
+
/** Whether the read `e` of a `prototype` member may yield one of `atoms`
|
|
714
|
+
* through a receiver that is not a function. An object's field holds the
|
|
715
|
+
* values stored to it by name (writes through a ⊤ receiver reach every
|
|
716
|
+
* object); ⊤, a ⊤ field and an object written by computed key may hold
|
|
717
|
+
* anything. */
|
|
718
|
+
const prototypeFieldMayBe = (e, atoms) => {
|
|
719
|
+
const op = readOps.get(e);
|
|
720
|
+
if (op === undefined)
|
|
721
|
+
return true;
|
|
722
|
+
for (const a of analysis.nodes[op.recv].atoms) {
|
|
723
|
+
if (analysis.protoOf.get(a) !== undefined)
|
|
724
|
+
continue;
|
|
725
|
+
if (a === analysis.top || computedRecv.has(a))
|
|
726
|
+
return true;
|
|
727
|
+
const field = analysis.fields.get(a)?.get("prototype");
|
|
728
|
+
if (field === undefined)
|
|
729
|
+
continue;
|
|
730
|
+
for (const v of analysis.nodes[field].atoms)
|
|
731
|
+
if (v === analysis.top || atoms.has(v))
|
|
732
|
+
return true;
|
|
733
|
+
}
|
|
734
|
+
return false;
|
|
735
|
+
};
|
|
736
|
+
/** Whether a reflective call may reach one of `atoms`: as an argument, or
|
|
737
|
+
* as the object `propertyIsEnumerable` is asked about. */
|
|
738
|
+
const reflectsOn = (atoms, ctorPath) => enumerabilityEscapes ||
|
|
739
|
+
enumerabilityQueries.some((recv) => {
|
|
740
|
+
// `F.prototype` is one of `atoms` (a class's prototype) when F may be
|
|
741
|
+
// that class's function, which `atoms` holds too: the analysis reads
|
|
742
|
+
// a prototype as ⊤ beside the class prototype objects it tracks. It
|
|
743
|
+
// also is when F is an object whose `prototype` field holds it.
|
|
744
|
+
let e = recv;
|
|
745
|
+
while (ts.isParenthesizedExpression(e))
|
|
746
|
+
e = e.expression;
|
|
747
|
+
if (ts.isPropertyAccessExpression(e) && e.name.text === "prototype")
|
|
748
|
+
return mayBeValue(e.expression, atoms, ctorPath) || prototypeFieldMayBe(e, atoms);
|
|
749
|
+
return mayBeValue(recv, atoms, ctorPath);
|
|
750
|
+
}) ||
|
|
751
|
+
reflective.some((call) => call.arguments.nodes.some((arg) => mayBe(arg, atoms, ctorPath)));
|
|
752
|
+
/** Whether a call that freezes, seals or redefines an object may reach one of `atoms`. */
|
|
753
|
+
const reshapes = (atoms, ctorPath) => reflective.some((call) => RESHAPING_CALLS.has(call.expression.name.getText()) &&
|
|
754
|
+
call.arguments.nodes.some((arg) => mayBe(arg, atoms, ctorPath)));
|
|
755
|
+
/** The reads of each member name, for the method checks. */
|
|
756
|
+
const readsOf = new Map();
|
|
757
|
+
for (const op of analysis.ops) {
|
|
758
|
+
if (op.kind !== "read" || op.name === null)
|
|
759
|
+
continue;
|
|
760
|
+
let l = readsOf.get(op.name);
|
|
761
|
+
if (l === undefined)
|
|
762
|
+
readsOf.set(op.name, (l = []));
|
|
763
|
+
l.push({ node: op.node, recv: analysis.nodes[op.recv].atoms });
|
|
764
|
+
}
|
|
765
|
+
/** Whether every read of member `key` through one of `atoms` is the callee of a call. */
|
|
766
|
+
const onlyCalled = (key, atoms) => (readsOf.get(key) ?? []).every(({ node, recv }) => {
|
|
767
|
+
if (![...recv].some((a) => atoms.has(a)))
|
|
768
|
+
return true;
|
|
769
|
+
const parent = node.parent;
|
|
770
|
+
return parent !== undefined && ts.isCallExpression(parent) && parent.expression === node;
|
|
771
|
+
});
|
|
772
|
+
const enumerates = (atoms, ctorPath) => forIns.some((e) => mayBe(e, atoms, ctorPath));
|
|
773
|
+
const noNameOrSource = (a) => {
|
|
774
|
+
const names = readNames.get(a);
|
|
775
|
+
return names === undefined || (!names.has("name") && !names.has("toString"));
|
|
776
|
+
};
|
|
777
|
+
/** Whether `node` runs only after the top-level statement `stmt` has run:
|
|
778
|
+
* in a later top-level statement, and not in a function declaration
|
|
779
|
+
* (which hoisting lets run earlier). */
|
|
780
|
+
const afterStatement = (node, stmt) => {
|
|
781
|
+
for (let p = node.parent; p !== undefined; p = p.parent)
|
|
782
|
+
if (ts.isFunctionDeclaration(p))
|
|
783
|
+
return false;
|
|
784
|
+
const top = topStatement(node);
|
|
785
|
+
if (top === null)
|
|
786
|
+
return false;
|
|
787
|
+
const stmts = node.getSourceFile().statements.nodes;
|
|
788
|
+
return stmts.indexOf(top) > stmts.indexOf(stmt);
|
|
789
|
+
};
|
|
790
|
+
/** Whether the binding `id` names holds its value whenever `at` runs: a
|
|
791
|
+
* parameter or a function declaration, or a variable declared with an
|
|
792
|
+
* initializer by an earlier top-level statement of the same file. None is
|
|
793
|
+
* ever assigned again. A variable read earlier is undefined, or throws in
|
|
794
|
+
* its temporal dead zone. */
|
|
795
|
+
const initializedAt = (id, at) => {
|
|
796
|
+
const d = declOf(id);
|
|
797
|
+
if (d === undefined || reassigned.has(d))
|
|
798
|
+
return false;
|
|
799
|
+
if (ts.isParameter(d) || ts.isFunctionDeclaration(d))
|
|
800
|
+
return true;
|
|
801
|
+
if (!ts.isVariableDeclaration(d) || d.initializer === undefined)
|
|
802
|
+
return false;
|
|
803
|
+
const stmt = d.parent?.parent;
|
|
804
|
+
if (stmt === undefined || !ts.isVariableStatement(stmt) || !ts.isSourceFile(stmt.parent))
|
|
805
|
+
return false;
|
|
806
|
+
return stmt.parent === at.getSourceFile() && afterStatement(at, stmt);
|
|
807
|
+
};
|
|
808
|
+
/** Whether evaluating `e` where `at` runs runs nothing and cannot throw: an
|
|
809
|
+
* initialized name, or a chain of member reads from constant objects
|
|
810
|
+
* (plain data) starting at one. */
|
|
811
|
+
const pureReceiver = (e, at) => {
|
|
812
|
+
while (ts.isParenthesizedExpression(e))
|
|
813
|
+
e = e.expression;
|
|
814
|
+
if (ts.isIdentifier(e))
|
|
815
|
+
return initializedAt(e, at);
|
|
816
|
+
if (!ts.isPropertyAccessExpression(e))
|
|
817
|
+
return false;
|
|
818
|
+
const op = readOps.get(e);
|
|
819
|
+
if (op === undefined)
|
|
820
|
+
return false;
|
|
821
|
+
const recv = analysis.nodes[op.recv].atoms;
|
|
822
|
+
if (recv.size !== 1 || !constantAtoms.has([...recv][0]))
|
|
823
|
+
return false;
|
|
824
|
+
return pureReceiver(e.expression, at);
|
|
825
|
+
};
|
|
826
|
+
/** Whether a store to `target` runs no code: its receiver is a constant
|
|
827
|
+
* object, which has no setters, reached without running anything, and the
|
|
828
|
+
* key is not `__proto__`, which Object.prototype stores through a setter. */
|
|
829
|
+
const inertStore = (target) => {
|
|
830
|
+
if (!ts.isPropertyAccessExpression(target) || !ts.isIdentifier(target.name))
|
|
831
|
+
return false;
|
|
832
|
+
if (target.name.text === "__proto__")
|
|
833
|
+
return false;
|
|
834
|
+
const op = writeOps.get(target);
|
|
835
|
+
if (op === undefined)
|
|
836
|
+
return false;
|
|
837
|
+
const recv = analysis.nodes[op.recv].atoms;
|
|
838
|
+
if (recv.size !== 1 || !constantAtoms.has([...recv][0]))
|
|
839
|
+
return false;
|
|
840
|
+
return pureReceiver(target.expression, target);
|
|
841
|
+
};
|
|
842
|
+
/** Whether evaluating `n` itself may run code of the program: converting
|
|
843
|
+
* an operand to a primitive or a property key (an arithmetic, relational or
|
|
844
|
+
* loose-equality operator, a compound assignment, `++`, a template
|
|
845
|
+
* substitution, a computed key) calls its valueOf, toString or
|
|
846
|
+
* Symbol.toPrimitive; `in`, `instanceof` and `delete` run traps and
|
|
847
|
+
* Symbol.hasInstance; spreading and destructuring run iterators and
|
|
848
|
+
* getters; a class runs its computed keys, static initializers and blocks. */
|
|
849
|
+
const runsImplicitly = (n) => {
|
|
850
|
+
if (ts.isBinaryExpression(n)) {
|
|
851
|
+
const op = n.operatorToken.kind;
|
|
852
|
+
if (op === ts.SyntaxKind.EqualsToken)
|
|
853
|
+
return ts.isObjectLiteralExpression(n.left) || ts.isArrayLiteralExpression(n.left);
|
|
854
|
+
return (op !== ts.SyntaxKind.EqualsEqualsEqualsToken &&
|
|
855
|
+
op !== ts.SyntaxKind.ExclamationEqualsEqualsToken &&
|
|
856
|
+
op !== ts.SyntaxKind.AmpersandAmpersandToken &&
|
|
857
|
+
op !== ts.SyntaxKind.BarBarToken &&
|
|
858
|
+
op !== ts.SyntaxKind.QuestionQuestionToken &&
|
|
859
|
+
op !== ts.SyntaxKind.CommaToken);
|
|
860
|
+
}
|
|
861
|
+
if (ts.isPrefixUnaryExpression(n))
|
|
862
|
+
return n.operator !== ts.SyntaxKind.ExclamationToken;
|
|
863
|
+
return (ts.isPostfixUnaryExpression(n) ||
|
|
864
|
+
ts.isDeleteExpression(n) ||
|
|
865
|
+
ts.isAwaitExpression(n) ||
|
|
866
|
+
ts.isYieldExpression(n) ||
|
|
867
|
+
ts.isTemplateExpression(n) ||
|
|
868
|
+
ts.isSpreadElement(n) ||
|
|
869
|
+
ts.isSpreadAssignment(n) ||
|
|
870
|
+
ts.isComputedPropertyName(n) ||
|
|
871
|
+
ts.isObjectBindingPattern(n) ||
|
|
872
|
+
ts.isArrayBindingPattern(n) ||
|
|
873
|
+
ts.isClassExpression(n));
|
|
874
|
+
};
|
|
875
|
+
/** Whether a statement only defines things: function declarations, and
|
|
876
|
+
* declarations and stores whose evaluation runs no code outside function
|
|
877
|
+
* bodies (no call, no read that could run a getter, no store that could run
|
|
878
|
+
* a setter, no implicit conversion or other implicit call). */
|
|
879
|
+
const definitionOnly = (stmt) => {
|
|
880
|
+
if (ts.isFunctionDeclaration(stmt))
|
|
881
|
+
return true;
|
|
882
|
+
if (!ts.isExpressionStatement(stmt) && !ts.isVariableStatement(stmt))
|
|
883
|
+
return false;
|
|
884
|
+
let runs = false;
|
|
885
|
+
const visit = (n) => {
|
|
886
|
+
if (runs)
|
|
887
|
+
return;
|
|
888
|
+
if (ts.isFunctionLike(n))
|
|
889
|
+
return;
|
|
890
|
+
if (ts.isCallExpression(n) ||
|
|
891
|
+
ts.isNewExpression(n) ||
|
|
892
|
+
ts.isTaggedTemplateExpression(n) ||
|
|
893
|
+
runsImplicitly(n))
|
|
894
|
+
runs = true;
|
|
895
|
+
if (ts.isPropertyAccessExpression(n) || ts.isElementAccessExpression(n)) {
|
|
896
|
+
const p = n.parent;
|
|
897
|
+
const isStoreTarget = p !== undefined &&
|
|
898
|
+
ts.isBinaryExpression(p) &&
|
|
899
|
+
p.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
900
|
+
p.left === n;
|
|
901
|
+
if (isStoreTarget) {
|
|
902
|
+
if (!inertStore(n))
|
|
903
|
+
runs = true;
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
// A read could run a getter; the receivers of reads are part of them.
|
|
907
|
+
if (!ts.isPropertyAccessExpression(p ?? n))
|
|
908
|
+
runs = true;
|
|
909
|
+
}
|
|
910
|
+
ts.forEachChild(n, visit);
|
|
911
|
+
};
|
|
912
|
+
visit(stmt);
|
|
913
|
+
return !runs;
|
|
914
|
+
};
|
|
915
|
+
const hoisted = new Map();
|
|
916
|
+
const used = new Set();
|
|
917
|
+
for (const sf of files)
|
|
918
|
+
for (const m of sf.text.matchAll(/[A-Za-z_$][\w$]*/g))
|
|
919
|
+
used.add(m[0]);
|
|
920
|
+
const classPlans = [];
|
|
921
|
+
// ── 1. constructors to classes ──────────────────────────────────────
|
|
922
|
+
let classes = 0;
|
|
923
|
+
const instanceOf = new Map();
|
|
924
|
+
for (const a of analysis.atoms.atoms)
|
|
925
|
+
if (a.kind === "object" && a.node !== undefined && a.label.startsWith("new ")) {
|
|
926
|
+
let l = instanceOf.get(a.node);
|
|
927
|
+
if (l === undefined)
|
|
928
|
+
instanceOf.set(a.node, (l = []));
|
|
929
|
+
l.push(a);
|
|
930
|
+
}
|
|
931
|
+
const escapedFns = new Set([...analysis.escapedFunctions].map((f) => f.node));
|
|
932
|
+
for (const [fnAtom, proto] of analysis.protoOf) {
|
|
933
|
+
const fnNode = fnAtom.node;
|
|
934
|
+
if (fnNode === undefined)
|
|
935
|
+
continue;
|
|
936
|
+
const sf = fnNode.getSourceFile();
|
|
937
|
+
if (!fileSet.has(sf))
|
|
938
|
+
continue;
|
|
939
|
+
const label = `${fnAtom.label}`;
|
|
940
|
+
const keep = (why) => {
|
|
941
|
+
kept.push(`class ${label}: ${why}`);
|
|
942
|
+
};
|
|
943
|
+
const site = assignedFunction(fnNode);
|
|
944
|
+
if (site === null) {
|
|
945
|
+
keep("not a function expression stored by a top-level statement");
|
|
946
|
+
continue;
|
|
947
|
+
}
|
|
948
|
+
const protoObject = constantAtoms.get(proto);
|
|
949
|
+
if (protoObject === undefined) {
|
|
950
|
+
keep("prototype is not a constant object");
|
|
951
|
+
continue;
|
|
952
|
+
}
|
|
953
|
+
if (analysis.escaped.has(fnAtom) || escapedFns.has(fnNode)) {
|
|
954
|
+
keep("escapes");
|
|
955
|
+
continue;
|
|
956
|
+
}
|
|
957
|
+
const edges = analysis.calls.filter((e) => e.callee.node === fnNode);
|
|
958
|
+
if (edges.some((e) => !ts.isNewExpression(e.site))) {
|
|
959
|
+
keep("called without new");
|
|
960
|
+
continue;
|
|
961
|
+
}
|
|
962
|
+
const assigned = analysis.fields.get(fnAtom)?.get("prototype");
|
|
963
|
+
if (assigned !== undefined && analysis.nodes[assigned].atoms.size > 0) {
|
|
964
|
+
keep("prototype replaced");
|
|
965
|
+
continue;
|
|
966
|
+
}
|
|
967
|
+
const instances = instanceOf.get(fnNode) ?? [];
|
|
968
|
+
const watched = new Set([proto, fnAtom, ...instances]);
|
|
969
|
+
if (instances.some((i) => analysis.escaped.has(i))) {
|
|
970
|
+
keep("an instance escapes");
|
|
971
|
+
continue;
|
|
972
|
+
}
|
|
973
|
+
// Instances enumerate inherited members only through for-in; own-key
|
|
974
|
+
// reflection (Object.keys, assign, JSON) sees the same either way. The
|
|
975
|
+
// prototype and the function itself must not be reflected on at all.
|
|
976
|
+
const ctorPath = site.lhs.getText();
|
|
977
|
+
const definitional = new Set([proto, fnAtom]);
|
|
978
|
+
if ([...watched].some((a) => computedRecv.has(a)) ||
|
|
979
|
+
enumerates(watched, ctorPath) ||
|
|
980
|
+
reflectsOn(definitional, ctorPath)) {
|
|
981
|
+
keep("enumeration or reflection may reach the prototype or instances");
|
|
982
|
+
continue;
|
|
983
|
+
}
|
|
984
|
+
// A frozen, sealed or redefined instance turns the stores that sloppy
|
|
985
|
+
// mode drops into strict-mode TypeErrors.
|
|
986
|
+
if (reshapes(watched, ctorPath)) {
|
|
987
|
+
keep("an instance may be frozen, sealed or redefined");
|
|
988
|
+
continue;
|
|
989
|
+
}
|
|
990
|
+
if (!noNameOrSource(fnAtom)) {
|
|
991
|
+
keep("reads name or toString");
|
|
992
|
+
continue;
|
|
993
|
+
}
|
|
994
|
+
if (!strictSafe(checker, fnNode)) {
|
|
995
|
+
keep("constructor body is not strict-mode safe");
|
|
996
|
+
continue;
|
|
997
|
+
}
|
|
998
|
+
// A named function expression binds its name in its own body; the
|
|
999
|
+
// class is declared under another name.
|
|
1000
|
+
const ownName = fnNode.name;
|
|
1001
|
+
if (ownName !== undefined && mentions(fnNode, ownName.text)) {
|
|
1002
|
+
keep("a named constructor refers to its own name");
|
|
1003
|
+
continue;
|
|
1004
|
+
}
|
|
1005
|
+
// The methods: one statement per prototype member, in this file.
|
|
1006
|
+
const methods = [];
|
|
1007
|
+
let ok = true;
|
|
1008
|
+
for (const f of protoObject.fields) {
|
|
1009
|
+
if (f.key === "constructor")
|
|
1010
|
+
continue;
|
|
1011
|
+
if (f.values.length !== 1 || f.values[0].kind !== "function" || f.stores !== 1) {
|
|
1012
|
+
ok = false;
|
|
1013
|
+
break;
|
|
1014
|
+
}
|
|
1015
|
+
const m = f.values[0];
|
|
1016
|
+
const mNode = m.node;
|
|
1017
|
+
const ms = mNode === undefined ? null : assignedFunction(mNode);
|
|
1018
|
+
if (ms === null ||
|
|
1019
|
+
mNode.getSourceFile() !== sf ||
|
|
1020
|
+
!ts.isPropertyAccessExpression(ms.lhs) ||
|
|
1021
|
+
!ts.isPropertyAccessExpression(ms.lhs.expression) ||
|
|
1022
|
+
ms.lhs.expression.name.text !== "prototype" ||
|
|
1023
|
+
ms.lhs.expression.expression.getText() !== site.lhs.getText() ||
|
|
1024
|
+
mNode.name !== undefined ||
|
|
1025
|
+
!strictSafe(checker, mNode) ||
|
|
1026
|
+
!noNameOrSource(m) ||
|
|
1027
|
+
!/^[A-Za-z_$][\w$]*$/.test(f.key) ||
|
|
1028
|
+
f.key === "constructor") {
|
|
1029
|
+
ok = false;
|
|
1030
|
+
break;
|
|
1031
|
+
}
|
|
1032
|
+
// Only ever called as a method: a class method is not constructible,
|
|
1033
|
+
// has no `prototype`, and a strict-mode call keeps a primitive or
|
|
1034
|
+
// missing `this` where sloppy mode would replace it.
|
|
1035
|
+
const calledAsMethod = analysis.calls
|
|
1036
|
+
.filter((e) => e.callee.node === mNode)
|
|
1037
|
+
.every((e) => ts.isCallExpression(e.site) &&
|
|
1038
|
+
ts.isPropertyAccessExpression(e.site.expression) &&
|
|
1039
|
+
e.site.expression.name.getText() === f.key);
|
|
1040
|
+
if (analysis.escaped.has(m) ||
|
|
1041
|
+
escapedFns.has(mNode) ||
|
|
1042
|
+
!calledAsMethod ||
|
|
1043
|
+
!onlyCalled(f.key, watched)) {
|
|
1044
|
+
ok = false;
|
|
1045
|
+
break;
|
|
1046
|
+
}
|
|
1047
|
+
methods.push({ name: f.key, fn: mNode, stmt: ms.stmt });
|
|
1048
|
+
}
|
|
1049
|
+
if (!ok) {
|
|
1050
|
+
keep("a prototype member is not a plain method stored by a top-level statement");
|
|
1051
|
+
continue;
|
|
1052
|
+
}
|
|
1053
|
+
// Only definitions between the constructor and its last method.
|
|
1054
|
+
const stmts = sf.statements.nodes;
|
|
1055
|
+
const first = stmts.indexOf(site.stmt);
|
|
1056
|
+
const last = Math.max(first, ...methods.map((m) => stmts.indexOf(m.stmt)));
|
|
1057
|
+
const methodStmts = new Set(methods.map((m) => m.stmt));
|
|
1058
|
+
if (methods.some((m) => stmts.indexOf(m.stmt) < first)) {
|
|
1059
|
+
keep("a method is stored before the constructor");
|
|
1060
|
+
continue;
|
|
1061
|
+
}
|
|
1062
|
+
let between = true;
|
|
1063
|
+
for (let i = first + 1; i < last; i++)
|
|
1064
|
+
if (!methodStmts.has(stmts[i]) && !definitionOnly(stmts[i]))
|
|
1065
|
+
between = false;
|
|
1066
|
+
if (!between) {
|
|
1067
|
+
keep("code runs between the constructor and its methods");
|
|
1068
|
+
continue;
|
|
1069
|
+
}
|
|
1070
|
+
classPlans.push({ sf, site, fn: fnNode, methods, fnAtom });
|
|
1071
|
+
classes++;
|
|
1072
|
+
}
|
|
1073
|
+
// The statement each hoisted class is declared at (before it).
|
|
1074
|
+
const classStatements = new Map();
|
|
1075
|
+
// The statement that stores each hoisted function or class, and the
|
|
1076
|
+
// function itself: a read of the member runs after the store when it is
|
|
1077
|
+
// inside that function or in a later top-level statement.
|
|
1078
|
+
const storeOf = new Map();
|
|
1079
|
+
for (const plan of classPlans) {
|
|
1080
|
+
const base = `__ns_${plan.site.lhs.getText().replace(/[^\w$]/g, "_")}`;
|
|
1081
|
+
let name = base;
|
|
1082
|
+
for (let i = 1; used.has(name); i++)
|
|
1083
|
+
name = `${base}_${i}`;
|
|
1084
|
+
used.add(name);
|
|
1085
|
+
hoisted.set(plan.fnAtom, name);
|
|
1086
|
+
classStatements.set(name, plan.site.stmt);
|
|
1087
|
+
storeOf.set(plan.fnAtom, { stmt: plan.site.stmt, fn: plan.fn });
|
|
1088
|
+
}
|
|
1089
|
+
const callEdits = [];
|
|
1090
|
+
const hoists = [];
|
|
1091
|
+
// ── 2. namespace functions to direct functions ─────────────────────
|
|
1092
|
+
let functions = 0;
|
|
1093
|
+
let directCalls = 0;
|
|
1094
|
+
let tableDispatches = 0;
|
|
1095
|
+
for (const o of graphs.objects) {
|
|
1096
|
+
if (o.site.kind === "prototype")
|
|
1097
|
+
continue;
|
|
1098
|
+
for (const f of o.fields) {
|
|
1099
|
+
if (f.values.length !== 1 || f.values[0].kind !== "function" || f.stores !== 1)
|
|
1100
|
+
continue;
|
|
1101
|
+
const fnAtom = f.values[0];
|
|
1102
|
+
const fnNode = fnAtom.node;
|
|
1103
|
+
if (fnNode === undefined || analysis.protoOf.has(fnAtom))
|
|
1104
|
+
continue;
|
|
1105
|
+
const assigned = assignedFunction(fnNode);
|
|
1106
|
+
// Also members of object literals a top-level statement creates.
|
|
1107
|
+
const site = assigned !== null
|
|
1108
|
+
? { stmt: assigned.stmt, path: assigned.lhs.getText() }
|
|
1109
|
+
: literalMemberFunction(fnNode);
|
|
1110
|
+
if (site === null || !fileSet.has(fnNode.getSourceFile()))
|
|
1111
|
+
continue;
|
|
1112
|
+
const fn = fnNode;
|
|
1113
|
+
if (fn.name !== undefined || usesThis(fn) || !noNameOrSource(fnAtom))
|
|
1114
|
+
continue;
|
|
1115
|
+
const sf = fnNode.getSourceFile();
|
|
1116
|
+
const base = `__ns_${site.path.replace(/[^\w$]/g, "_")}`;
|
|
1117
|
+
let name = base;
|
|
1118
|
+
for (let i = 1; used.has(name); i++)
|
|
1119
|
+
name = `${base}_${i}`;
|
|
1120
|
+
used.add(name);
|
|
1121
|
+
hoisted.set(fnAtom, name);
|
|
1122
|
+
storeOf.set(fnAtom, { stmt: site.stmt, fn });
|
|
1123
|
+
edit(sf, {
|
|
1124
|
+
start: ts.tokenStartOfNode(fn),
|
|
1125
|
+
end: fn.end,
|
|
1126
|
+
text: name,
|
|
1127
|
+
});
|
|
1128
|
+
hoists.push({ sf, stmt: site.stmt, name, fn });
|
|
1129
|
+
functions++;
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
// ── cross-file references ──────────────────────────────────────────
|
|
1133
|
+
// A read in another file of a constant namespace member that is a
|
|
1134
|
+
// hoisted function or class refers to it through the defining module's
|
|
1135
|
+
// exports: the overlay adds the binding to the module's exports literal
|
|
1136
|
+
// (`module.exports = { app, __ns_app_run: __ns_app_run }`) and the
|
|
1137
|
+
// reading file binds the module once, right after the top-level
|
|
1138
|
+
// statement that requires it (`const __ns_mod_0 = require("lib");`).
|
|
1139
|
+
// The added members are unobservable when the exports object is a
|
|
1140
|
+
// constant object nothing enumerates, reflects on, or lets escape; the
|
|
1141
|
+
// module is loaded by then, so the extra require only returns it; and
|
|
1142
|
+
// the defining module must not require the reading file (a cycle could
|
|
1143
|
+
// run the reading file's code before the module finished).
|
|
1144
|
+
const exportLiterals = new Map();
|
|
1145
|
+
const exportLiteralOf = (sf) => {
|
|
1146
|
+
if (exportLiterals.has(sf))
|
|
1147
|
+
return exportLiterals.get(sf);
|
|
1148
|
+
let found = null;
|
|
1149
|
+
for (const st of sf.statements.nodes) {
|
|
1150
|
+
if (!ts.isExpressionStatement(st) || !ts.isBinaryExpression(st.expression))
|
|
1151
|
+
continue;
|
|
1152
|
+
const b = st.expression;
|
|
1153
|
+
if (b.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
1154
|
+
b.left.getText() === "module.exports" &&
|
|
1155
|
+
ts.isObjectLiteralExpression(b.right))
|
|
1156
|
+
found = found === null ? b.right : null;
|
|
1157
|
+
}
|
|
1158
|
+
if (found !== null) {
|
|
1159
|
+
const o = graphs.objects.find((x) => x.site.node === found);
|
|
1160
|
+
const atoms = new Set(o === undefined ? [] : [o.site.atom]);
|
|
1161
|
+
if (o === undefined ||
|
|
1162
|
+
analysis.escaped.has(o.site.atom) ||
|
|
1163
|
+
computedRecv.has(o.site.atom) ||
|
|
1164
|
+
enumerates(atoms, "") ||
|
|
1165
|
+
reflectsOn(atoms, ""))
|
|
1166
|
+
found = null;
|
|
1167
|
+
}
|
|
1168
|
+
exportLiterals.set(sf, found);
|
|
1169
|
+
return found;
|
|
1170
|
+
};
|
|
1171
|
+
const filesByName = new Map();
|
|
1172
|
+
for (const f of analysis.files)
|
|
1173
|
+
filesByName.set(f.fileName, f);
|
|
1174
|
+
/** The program file `require(lit)` in `sf` loads: the checker's module,
|
|
1175
|
+
* else the file Node's resolver finds (the checker resolves only some
|
|
1176
|
+
* require forms), or null. */
|
|
1177
|
+
const requireTarget = (sf, lit) => {
|
|
1178
|
+
let target;
|
|
1179
|
+
try {
|
|
1180
|
+
target = checker.getSymbolAtLocation(lit)?.declarations[0];
|
|
1181
|
+
}
|
|
1182
|
+
catch {
|
|
1183
|
+
target = undefined;
|
|
1184
|
+
}
|
|
1185
|
+
if (target !== undefined && ts.isSourceFile(target))
|
|
1186
|
+
return target;
|
|
1187
|
+
const resolved = resolveCjsRuntime(sf.fileName, lit.text);
|
|
1188
|
+
return resolved.ok ? (filesByName.get(resolved.value) ?? null) : null;
|
|
1189
|
+
};
|
|
1190
|
+
const requiredFiles = (sf, node) => {
|
|
1191
|
+
const out = [];
|
|
1192
|
+
const visit = (n) => {
|
|
1193
|
+
if (ts.isCallExpression(n) &&
|
|
1194
|
+
ts.isIdentifier(n.expression) &&
|
|
1195
|
+
n.expression.text === "require" &&
|
|
1196
|
+
n.arguments.nodes.length === 1 &&
|
|
1197
|
+
ts.isStringLiteral(n.arguments.nodes[0])) {
|
|
1198
|
+
const target = requireTarget(sf, n.arguments.nodes[0]);
|
|
1199
|
+
if (target !== null)
|
|
1200
|
+
out.push(target);
|
|
1201
|
+
}
|
|
1202
|
+
ts.forEachChild(n, visit);
|
|
1203
|
+
};
|
|
1204
|
+
visit(node);
|
|
1205
|
+
return out;
|
|
1206
|
+
};
|
|
1207
|
+
/** The files `sf` requires, directly or through the files they require. */
|
|
1208
|
+
const requireClosures = new Map();
|
|
1209
|
+
const requiredClosure = (sf) => {
|
|
1210
|
+
let seen = requireClosures.get(sf);
|
|
1211
|
+
if (seen !== undefined)
|
|
1212
|
+
return seen;
|
|
1213
|
+
seen = new Set();
|
|
1214
|
+
const work = [sf];
|
|
1215
|
+
while (work.length > 0) {
|
|
1216
|
+
const f = work.pop();
|
|
1217
|
+
for (const t of requiredFiles(f, f))
|
|
1218
|
+
if (!seen.has(t)) {
|
|
1219
|
+
seen.add(t);
|
|
1220
|
+
work.push(t);
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
requireClosures.set(sf, seen);
|
|
1224
|
+
return seen;
|
|
1225
|
+
};
|
|
1226
|
+
/** Whether a top-level statement requires `target` each time it runs:
|
|
1227
|
+
* the statement is `require(…)`, an assignment of it, or declarations
|
|
1228
|
+
* one of which it initializes, optionally followed by member reads. A
|
|
1229
|
+
* require inside a function, a condition or another expression runs only
|
|
1230
|
+
* when that does. */
|
|
1231
|
+
/** The values a top-level statement computes: its declarations'
|
|
1232
|
+
* initializers, or its expression (an assignment's right side). */
|
|
1233
|
+
const statementValues = (st) => {
|
|
1234
|
+
if (ts.isVariableStatement(st))
|
|
1235
|
+
return st.declarationList.declarations.nodes.flatMap((d) => d.initializer !== undefined ? [d.initializer] : []);
|
|
1236
|
+
if (!ts.isExpressionStatement(st))
|
|
1237
|
+
return null;
|
|
1238
|
+
const e = st.expression;
|
|
1239
|
+
return [
|
|
1240
|
+
ts.isBinaryExpression(e) &&
|
|
1241
|
+
e.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
1242
|
+
ts.isIdentifier(e.left)
|
|
1243
|
+
? e.right
|
|
1244
|
+
: e,
|
|
1245
|
+
];
|
|
1246
|
+
};
|
|
1247
|
+
/** The require call `v` is, followed by member reads, or null. */
|
|
1248
|
+
const requireValue = (v) => {
|
|
1249
|
+
let e = v;
|
|
1250
|
+
for (;;) {
|
|
1251
|
+
if (ts.isParenthesizedExpression(e))
|
|
1252
|
+
e = e.expression;
|
|
1253
|
+
else if (ts.isPropertyAccessExpression(e) && e.questionDotToken === undefined)
|
|
1254
|
+
e = e.expression;
|
|
1255
|
+
else
|
|
1256
|
+
break;
|
|
1257
|
+
}
|
|
1258
|
+
return ts.isCallExpression(e) &&
|
|
1259
|
+
ts.isIdentifier(e.expression) &&
|
|
1260
|
+
e.expression.text === "require"
|
|
1261
|
+
? e
|
|
1262
|
+
: null;
|
|
1263
|
+
};
|
|
1264
|
+
const requiresWhenRun = (sf, st, target) => (statementValues(st) ?? []).some((v) => {
|
|
1265
|
+
const call = requireValue(v);
|
|
1266
|
+
return call !== null && requiredFiles(sf, call).includes(target);
|
|
1267
|
+
});
|
|
1268
|
+
/** Whether `node` sits inside a function of its top-level statement. */
|
|
1269
|
+
const insideFunction = (node) => {
|
|
1270
|
+
const top = topStatement(node);
|
|
1271
|
+
for (let p = node.parent; p !== undefined && p !== top; p = p.parent)
|
|
1272
|
+
if (ts.isFunctionLike(p))
|
|
1273
|
+
return true;
|
|
1274
|
+
return false;
|
|
1275
|
+
};
|
|
1276
|
+
/** The nodes whose statements must have run for an effect-free receiver
|
|
1277
|
+
* (effectFree) to be the constant object it reads as: each member read's
|
|
1278
|
+
* stores of that member, and a name's declaration. */
|
|
1279
|
+
const receiverDeps = (e) => {
|
|
1280
|
+
while (ts.isParenthesizedExpression(e))
|
|
1281
|
+
e = e.expression;
|
|
1282
|
+
if (ts.isIdentifier(e)) {
|
|
1283
|
+
const d = declOf(e);
|
|
1284
|
+
return d === undefined ? [] : [d];
|
|
1285
|
+
}
|
|
1286
|
+
if (!ts.isPropertyAccessExpression(e) && !ts.isElementAccessExpression(e))
|
|
1287
|
+
return [];
|
|
1288
|
+
const op = readOps.get(e);
|
|
1289
|
+
if (op === undefined || op.name === null)
|
|
1290
|
+
return [];
|
|
1291
|
+
const objects = analysis.nodes[op.recv].atoms;
|
|
1292
|
+
const stores = analysis.ops
|
|
1293
|
+
.filter((w) => w.kind === "write" &&
|
|
1294
|
+
w.name === op.name &&
|
|
1295
|
+
[...analysis.nodes[w.recv].atoms].some((a) => objects.has(a)))
|
|
1296
|
+
.map((w) => w.node);
|
|
1297
|
+
return [...stores, ...receiverDeps(e.expression)];
|
|
1298
|
+
};
|
|
1299
|
+
/** Whether `read` can only run after the statements holding `deps`: what
|
|
1300
|
+
* it reads exists by then, so a rewrite that no longer evaluates the read
|
|
1301
|
+
* cannot drop the TypeError or ReferenceError of an earlier read. In
|
|
1302
|
+
* another file, the defining module has finished loading unless it
|
|
1303
|
+
* requires the reading file. In the same file, a top-level read comes
|
|
1304
|
+
* after them. A read inside a function runs when the function is called:
|
|
1305
|
+
* the statements from the one that creates the function (the first, for
|
|
1306
|
+
* a hoisted declaration) to the last of them must only define things. */
|
|
1307
|
+
const createdBefore = (read, deps) => {
|
|
1308
|
+
const sf = read.getSourceFile();
|
|
1309
|
+
const stmts = sf.statements.nodes;
|
|
1310
|
+
let last = -1;
|
|
1311
|
+
for (const d of deps) {
|
|
1312
|
+
const file = d.getSourceFile();
|
|
1313
|
+
if (file !== sf) {
|
|
1314
|
+
if (requiredClosure(file).has(sf))
|
|
1315
|
+
return false;
|
|
1316
|
+
continue;
|
|
1317
|
+
}
|
|
1318
|
+
const at = stmts.indexOf(topStatement(d));
|
|
1319
|
+
if (at < 0)
|
|
1320
|
+
return false;
|
|
1321
|
+
last = Math.max(last, at);
|
|
1322
|
+
}
|
|
1323
|
+
if (last < 0)
|
|
1324
|
+
return true;
|
|
1325
|
+
const top = topStatement(read);
|
|
1326
|
+
if (!insideFunction(read))
|
|
1327
|
+
return stmts.indexOf(top) > last;
|
|
1328
|
+
let fn;
|
|
1329
|
+
for (let p = read.parent; p !== undefined && p !== top; p = p.parent)
|
|
1330
|
+
if (ts.isFunctionLike(p))
|
|
1331
|
+
fn = p;
|
|
1332
|
+
const from = fn !== undefined && ts.isFunctionDeclaration(fn) ? 0 : stmts.indexOf(top);
|
|
1333
|
+
return stmts.slice(from, last + 1).every(definitionOnly);
|
|
1334
|
+
};
|
|
1335
|
+
const moduleBindings = new Map();
|
|
1336
|
+
const exportAdds = new Map();
|
|
1337
|
+
const crossFileReference = (node, defining, name) => {
|
|
1338
|
+
if (process.env["SCRIPTC_SHAPE_CROSS_FILE_REFS"] === "0")
|
|
1339
|
+
return null;
|
|
1340
|
+
const sf = node.getSourceFile();
|
|
1341
|
+
if (!fileSet.has(sf) || exportLiteralOf(defining) === null)
|
|
1342
|
+
return null;
|
|
1343
|
+
// A cycle back to the reading file, directly or through other files,
|
|
1344
|
+
// could run the reading file's code before the module finished.
|
|
1345
|
+
if (requiredClosure(defining).has(sf))
|
|
1346
|
+
return null;
|
|
1347
|
+
// A class is declared at its constructor's statement: an exports
|
|
1348
|
+
// literal before it would read the class before its declaration.
|
|
1349
|
+
const classStmt = classStatements.get(name);
|
|
1350
|
+
if (classStmt !== undefined) {
|
|
1351
|
+
const ds = defining.statements.nodes;
|
|
1352
|
+
const exportsAt = ds.indexOf(topStatement(exportLiteralOf(defining)));
|
|
1353
|
+
if (exportsAt < ds.indexOf(classStmt))
|
|
1354
|
+
return null;
|
|
1355
|
+
}
|
|
1356
|
+
// The reading file's top-level statement that loads the module.
|
|
1357
|
+
const stmts = sf.statements.nodes;
|
|
1358
|
+
const at = stmts.findIndex((st) => requiresWhenRun(sf, st, defining));
|
|
1359
|
+
if (at < 0)
|
|
1360
|
+
return null;
|
|
1361
|
+
const top = topStatement(node);
|
|
1362
|
+
const inFunction = insideFunction(node);
|
|
1363
|
+
if (!inFunction && stmts.indexOf(top) <= at)
|
|
1364
|
+
return null;
|
|
1365
|
+
// A function may run before the binding below is initialized if the
|
|
1366
|
+
// statement that loads the module, or one before it, runs other code
|
|
1367
|
+
// (`var m = require("lib"), x = f();`): then its reads stay as written.
|
|
1368
|
+
if (inFunction) {
|
|
1369
|
+
const values = statementValues(stmts[at]);
|
|
1370
|
+
const onlyLoads = values !== null && values.every((v) => requireValue(v) !== null);
|
|
1371
|
+
if (!onlyLoads || !stmts.slice(0, at).every(definitionOnly))
|
|
1372
|
+
return null;
|
|
1373
|
+
}
|
|
1374
|
+
const key = `${sf.fileName}\0${defining.fileName}`;
|
|
1375
|
+
let binding = moduleBindings.get(key);
|
|
1376
|
+
if (binding === undefined) {
|
|
1377
|
+
binding = `__ns_mod_${moduleBindings.size}`;
|
|
1378
|
+
for (let i = 1; used.has(binding); i++)
|
|
1379
|
+
binding = `__ns_mod_${moduleBindings.size}_${i}`;
|
|
1380
|
+
used.add(binding);
|
|
1381
|
+
moduleBindings.set(key, binding);
|
|
1382
|
+
const req = stmts[at];
|
|
1383
|
+
let spec = null;
|
|
1384
|
+
const find = (n) => {
|
|
1385
|
+
if (spec === null &&
|
|
1386
|
+
ts.isCallExpression(n) &&
|
|
1387
|
+
ts.isIdentifier(n.expression) &&
|
|
1388
|
+
n.expression.text === "require" &&
|
|
1389
|
+
requiredFiles(sf, n).includes(defining))
|
|
1390
|
+
spec = n.arguments.nodes[0].getText();
|
|
1391
|
+
ts.forEachChild(n, find);
|
|
1392
|
+
};
|
|
1393
|
+
find(req);
|
|
1394
|
+
edit(sf, { start: req.end, end: req.end, text: `\nconst ${binding} = require(${spec});` });
|
|
1395
|
+
}
|
|
1396
|
+
let adds = exportAdds.get(defining);
|
|
1397
|
+
if (adds === undefined)
|
|
1398
|
+
exportAdds.set(defining, (adds = new Set()));
|
|
1399
|
+
adds.add(name);
|
|
1400
|
+
return `${binding}.${name}`;
|
|
1401
|
+
};
|
|
1402
|
+
// Direct references: `e.k` (called, constructed or read) in the same file
|
|
1403
|
+
// whose receiver is exactly the constant object holding a hoisted
|
|
1404
|
+
// function or class.
|
|
1405
|
+
/** Whether `node` runs only after `store` has stored its function. */
|
|
1406
|
+
const runsAfter = (node, store) => {
|
|
1407
|
+
for (let p = node.parent; p !== undefined; p = p.parent) {
|
|
1408
|
+
// A function declaration is created, and may be called, before any
|
|
1409
|
+
// statement of its scope runs.
|
|
1410
|
+
if (ts.isFunctionDeclaration(p))
|
|
1411
|
+
return false;
|
|
1412
|
+
if (p === store.fn)
|
|
1413
|
+
return true;
|
|
1414
|
+
}
|
|
1415
|
+
const top = topStatement(node);
|
|
1416
|
+
if (top === null)
|
|
1417
|
+
return false;
|
|
1418
|
+
const stmts = node.getSourceFile().statements.nodes;
|
|
1419
|
+
return stmts.indexOf(top) > stmts.indexOf(store.stmt);
|
|
1420
|
+
};
|
|
1421
|
+
for (const { op, atoms, nullish } of mergedOps) {
|
|
1422
|
+
if (op.kind !== "read" || op.name === null)
|
|
1423
|
+
continue;
|
|
1424
|
+
if (atoms.size !== 1)
|
|
1425
|
+
continue;
|
|
1426
|
+
const recv = [...atoms][0];
|
|
1427
|
+
const o = constantAtoms.get(recv);
|
|
1428
|
+
if (o === undefined)
|
|
1429
|
+
continue;
|
|
1430
|
+
const field = o.fields.find((f) => f.key === op.name);
|
|
1431
|
+
if (field === undefined || field.values.length !== 1)
|
|
1432
|
+
continue;
|
|
1433
|
+
const name = hoisted.get(field.values[0]);
|
|
1434
|
+
if (name === undefined)
|
|
1435
|
+
continue;
|
|
1436
|
+
const node = op.node;
|
|
1437
|
+
// Any read of the member: a callee, a `new` target, an `instanceof`
|
|
1438
|
+
// operand or a plain value (the binding holds the same function).
|
|
1439
|
+
const parent = node.parent;
|
|
1440
|
+
if (parent === undefined || ts.isDeleteExpression(parent))
|
|
1441
|
+
continue;
|
|
1442
|
+
if (!ts.isPropertyAccessExpression(node))
|
|
1443
|
+
continue;
|
|
1444
|
+
if (topStatement(node) === null)
|
|
1445
|
+
continue;
|
|
1446
|
+
// The reference replaces the whole member expression: its receiver
|
|
1447
|
+
// must be one that evaluating runs no code.
|
|
1448
|
+
if (!effectFree(node.expression)) {
|
|
1449
|
+
kept.push(`reference ${node.getText()}: the receiver may have effects`);
|
|
1450
|
+
continue;
|
|
1451
|
+
}
|
|
1452
|
+
if (!createdBefore(node, [field.values[0].node, ...receiverDeps(node.expression)])) {
|
|
1453
|
+
kept.push(`reference ${node.getText()}: it may run before the member is stored`);
|
|
1454
|
+
continue;
|
|
1455
|
+
}
|
|
1456
|
+
// The receiver's evaluation is dropped, and the binding exists from the
|
|
1457
|
+
// store on (a function) or from its declaration on (a class).
|
|
1458
|
+
if (!pureReceiver(node.expression, node))
|
|
1459
|
+
continue;
|
|
1460
|
+
if (!runsAfter(node, storeOf.get(field.values[0])))
|
|
1461
|
+
continue;
|
|
1462
|
+
if (node.getSourceFile() !== field.values[0].node.getSourceFile()) {
|
|
1463
|
+
const text = crossFileReference(node, field.values[0].node.getSourceFile(), name);
|
|
1464
|
+
if (text === null)
|
|
1465
|
+
continue;
|
|
1466
|
+
callEdits.push({
|
|
1467
|
+
sf: node.getSourceFile(),
|
|
1468
|
+
edit: {
|
|
1469
|
+
start: ts.tokenStartOfNode(node),
|
|
1470
|
+
end: node.end,
|
|
1471
|
+
text: keepRead(node, text, nullish),
|
|
1472
|
+
},
|
|
1473
|
+
});
|
|
1474
|
+
directCalls++;
|
|
1475
|
+
continue;
|
|
1476
|
+
}
|
|
1477
|
+
callEdits.push({
|
|
1478
|
+
sf: node.getSourceFile(),
|
|
1479
|
+
edit: {
|
|
1480
|
+
start: ts.tokenStartOfNode(node),
|
|
1481
|
+
end: node.end,
|
|
1482
|
+
text: keepRead(node, name, nullish),
|
|
1483
|
+
},
|
|
1484
|
+
});
|
|
1485
|
+
directCalls++;
|
|
1486
|
+
}
|
|
1487
|
+
// ── 4. constant primitive members ──────────────────────────────────
|
|
1488
|
+
// `e.k` whose receiver is exactly one constant object and whose member
|
|
1489
|
+
// is a primitive literal written in the object's own literal (`Kind = {
|
|
1490
|
+
// CIRCLE: 1 }`) reads that literal: the member exists from the moment
|
|
1491
|
+
// the object does and nothing writes it, so every read sees it. (A
|
|
1492
|
+
// member stored after the object was created could be read before the
|
|
1493
|
+
// store; those stay reads.)
|
|
1494
|
+
//
|
|
1495
|
+
// A member stored once by an unconditional top-level statement of the
|
|
1496
|
+
// object's own file (`app.math.EPSILON = 1e-9;`) folds too, at reads that
|
|
1497
|
+
// provably run after the store: reads inside functions, when no code can
|
|
1498
|
+
// run before the store (the statements before it call nothing, so no
|
|
1499
|
+
// function runs and no other module starts), and top-level reads after
|
|
1500
|
+
// it in the same file.
|
|
1501
|
+
const writesOf = new Map();
|
|
1502
|
+
for (const op of analysis.ops) {
|
|
1503
|
+
if (op.kind !== "write" || op.name === null)
|
|
1504
|
+
continue;
|
|
1505
|
+
for (const a of analysis.nodes[op.recv].atoms) {
|
|
1506
|
+
let byKey = writesOf.get(a);
|
|
1507
|
+
if (byKey === undefined)
|
|
1508
|
+
writesOf.set(a, (byKey = new Map()));
|
|
1509
|
+
let l = byKey.get(op.name);
|
|
1510
|
+
if (l === undefined)
|
|
1511
|
+
byKey.set(op.name, (l = []));
|
|
1512
|
+
if (!l.includes(op.node))
|
|
1513
|
+
l.push(op.node);
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
// Member reads and stores whose receiver can only be constant objects or
|
|
1517
|
+
// primitives: neither has accessors of its own, so no getter or setter
|
|
1518
|
+
// runs (a primitive receiver of a store throws, or reads its prototype).
|
|
1519
|
+
const memberReceivers = new Map();
|
|
1520
|
+
for (const op of analysis.ops) {
|
|
1521
|
+
if ((op.kind !== "read" && op.kind !== "write") || op.name === null)
|
|
1522
|
+
continue;
|
|
1523
|
+
let set = memberReceivers.get(op.node);
|
|
1524
|
+
if (set === undefined)
|
|
1525
|
+
memberReceivers.set(op.node, (set = new Set()));
|
|
1526
|
+
for (const a of analysis.nodes[op.recv].atoms)
|
|
1527
|
+
set.add(a);
|
|
1528
|
+
}
|
|
1529
|
+
const plainMember = (n) => {
|
|
1530
|
+
const atoms = memberReceivers.get(n);
|
|
1531
|
+
return (atoms !== undefined &&
|
|
1532
|
+
atoms.size > 0 &&
|
|
1533
|
+
[...atoms].every((a) => a.kind === "prim" || constantAtoms.has(a)));
|
|
1534
|
+
};
|
|
1535
|
+
const quietPrefix = new Map();
|
|
1536
|
+
const storedLiteral = (atom, site, key) => {
|
|
1537
|
+
const writes = writesOf.get(atom)?.get(key) ?? [];
|
|
1538
|
+
if (writes.length !== 1)
|
|
1539
|
+
return null;
|
|
1540
|
+
const target = writes[0];
|
|
1541
|
+
const assign = target.parent;
|
|
1542
|
+
if (assign === undefined ||
|
|
1543
|
+
!ts.isBinaryExpression(assign) ||
|
|
1544
|
+
assign.left !== target ||
|
|
1545
|
+
assign.operatorToken.kind !== ts.SyntaxKind.EqualsToken)
|
|
1546
|
+
return null;
|
|
1547
|
+
const stmt = assign.parent;
|
|
1548
|
+
if (stmt === undefined || !ts.isExpressionStatement(stmt) || !ts.isSourceFile(stmt.parent))
|
|
1549
|
+
return null;
|
|
1550
|
+
if (stmt.getSourceFile() !== site.getSourceFile())
|
|
1551
|
+
return null;
|
|
1552
|
+
const literal = primitiveLiteralText(assign.right);
|
|
1553
|
+
if (literal === null)
|
|
1554
|
+
return null;
|
|
1555
|
+
const statements = stmt.parent.statements.nodes;
|
|
1556
|
+
let quiet = quietPrefix.get(stmt);
|
|
1557
|
+
if (quiet === undefined) {
|
|
1558
|
+
quiet = statements
|
|
1559
|
+
.slice(0, statements.indexOf(stmt))
|
|
1560
|
+
.every((s) => runsNoCode(s, plainMember));
|
|
1561
|
+
quietPrefix.set(stmt, quiet);
|
|
1562
|
+
}
|
|
1563
|
+
return quiet ? { literal, stmt, statements } : null;
|
|
1564
|
+
};
|
|
1565
|
+
let foldedReads = 0;
|
|
1566
|
+
for (const { op, atoms, nullish } of mergedOps) {
|
|
1567
|
+
if (op.kind !== "read" || op.name === null)
|
|
1568
|
+
continue;
|
|
1569
|
+
if (atoms.size !== 1)
|
|
1570
|
+
continue;
|
|
1571
|
+
const atom = [...atoms][0];
|
|
1572
|
+
const o = constantAtoms.get(atom);
|
|
1573
|
+
if (o === undefined || o.site.kind !== "literal")
|
|
1574
|
+
continue;
|
|
1575
|
+
const field = o.fields.find((f) => f.key === op.name);
|
|
1576
|
+
if (field === undefined || field.stores !== 1)
|
|
1577
|
+
continue;
|
|
1578
|
+
const node = op.node;
|
|
1579
|
+
if (!ts.isPropertyAccessExpression(node) && !ts.isElementAccessExpression(node))
|
|
1580
|
+
continue;
|
|
1581
|
+
if (!isPlainRead(node) || topStatement(node) === null)
|
|
1582
|
+
continue;
|
|
1583
|
+
if (!effectFree(node.expression)) {
|
|
1584
|
+
kept.push(`constant read ${node.getText()}: the receiver may have effects`);
|
|
1585
|
+
continue;
|
|
1586
|
+
}
|
|
1587
|
+
if (!createdBefore(node, [o.site.node, ...receiverDeps(node.expression)])) {
|
|
1588
|
+
kept.push(`constant read ${node.getText()}: it may run before the object is created`);
|
|
1589
|
+
continue;
|
|
1590
|
+
}
|
|
1591
|
+
let literal = ownLiteralMember(o.site.node, op.name);
|
|
1592
|
+
if (literal === null && process.env["SCRIPTC_SHAPE_FOLD_STORES"] !== "0") {
|
|
1593
|
+
const stored = storedLiteral(atom, o.site.node, op.name);
|
|
1594
|
+
if (stored === null)
|
|
1595
|
+
continue;
|
|
1596
|
+
const inFunction = enclosingFunctionLike(node) !== null;
|
|
1597
|
+
const top = topStatement(node);
|
|
1598
|
+
const after = top.getSourceFile() === stored.stmt.getSourceFile() &&
|
|
1599
|
+
stored.statements.indexOf(top) > stored.statements.indexOf(stored.stmt);
|
|
1600
|
+
if (!inFunction && !after)
|
|
1601
|
+
continue;
|
|
1602
|
+
literal = stored.literal;
|
|
1603
|
+
}
|
|
1604
|
+
if (literal === null)
|
|
1605
|
+
continue;
|
|
1606
|
+
// An element key needs no parentheses (and a parenthesized literal key
|
|
1607
|
+
// would read as a computed one).
|
|
1608
|
+
const key = node.parent !== undefined &&
|
|
1609
|
+
ts.isElementAccessExpression(node.parent) &&
|
|
1610
|
+
node.parent.argumentExpression === node;
|
|
1611
|
+
callEdits.push({
|
|
1612
|
+
sf: node.getSourceFile(),
|
|
1613
|
+
edit: {
|
|
1614
|
+
start: ts.tokenStartOfNode(node),
|
|
1615
|
+
end: node.end,
|
|
1616
|
+
text: nullish ? keepRead(node, literal, true) : key ? literal : `(${literal})`,
|
|
1617
|
+
},
|
|
1618
|
+
});
|
|
1619
|
+
foldedReads++;
|
|
1620
|
+
}
|
|
1621
|
+
// Text of a node with the direct calls inside it applied (an edit
|
|
1622
|
+
// inside another edit's range is part of that edit's text).
|
|
1623
|
+
const sliceWithCalls = (sf, n) => {
|
|
1624
|
+
const from = ts.tokenStartOfNode(n);
|
|
1625
|
+
const inner = callEdits
|
|
1626
|
+
.filter((c) => c.sf === sf && c.edit.start >= from && c.edit.end <= n.end)
|
|
1627
|
+
.map((c) => c.edit)
|
|
1628
|
+
.sort((a, b) => a.start - b.start || b.end - a.end);
|
|
1629
|
+
let out = "";
|
|
1630
|
+
let at = from;
|
|
1631
|
+
for (const e of inner) {
|
|
1632
|
+
if (e.start < at)
|
|
1633
|
+
continue;
|
|
1634
|
+
out += sf.text.slice(at, e.start) + e.text;
|
|
1635
|
+
at = e.end;
|
|
1636
|
+
}
|
|
1637
|
+
return out + sf.text.slice(at, n.end);
|
|
1638
|
+
};
|
|
1639
|
+
// ── 3. calls through constant function tables ──────────────────────
|
|
1640
|
+
// `table[key](…)` where the table is exactly one constant object whose
|
|
1641
|
+
// members are all hoisted functions and the key is a string variable:
|
|
1642
|
+
// a comparison per member calls its function directly, and any other
|
|
1643
|
+
// key reads the table as written. The members do not use `this`, the
|
|
1644
|
+
// table has no accessors, and comparing a string runs no code, so only
|
|
1645
|
+
// the representation of the call changes.
|
|
1646
|
+
const tableCalls = [];
|
|
1647
|
+
// Whether a key parameter only ever holds one of the table's keys: its
|
|
1648
|
+
// function never escapes, every call of it passes a string literal key
|
|
1649
|
+
// of the table, and its body neither assigns the parameter nor uses
|
|
1650
|
+
// `arguments` (which aliases parameters in sloppy code). The dispatch
|
|
1651
|
+
// then needs no arm for other keys.
|
|
1652
|
+
const literalKeysOnly = (keyDecl, keys) => {
|
|
1653
|
+
if (process.env["SCRIPTC_SHAPE_EXHAUSTIVE_TABLES"] === "0")
|
|
1654
|
+
return false;
|
|
1655
|
+
if (!ts.isParameter(keyDecl) || !ts.isIdentifier(keyDecl.name))
|
|
1656
|
+
return false;
|
|
1657
|
+
const fn = keyDecl.parent;
|
|
1658
|
+
if (fn === undefined || !ts.isFunctionLike(fn) || escapedFns.has(fn))
|
|
1659
|
+
return false;
|
|
1660
|
+
for (const a of analysis.atoms.atoms)
|
|
1661
|
+
if (a.kind === "function" && a.node === fn && analysis.escaped.has(a))
|
|
1662
|
+
return false;
|
|
1663
|
+
const index = fn.parameters.nodes.indexOf(keyDecl);
|
|
1664
|
+
const name = keyDecl.name.text;
|
|
1665
|
+
// Any write of the name in the function, its other parameters included,
|
|
1666
|
+
// or a direct eval or `arguments` (which aliases parameters in sloppy
|
|
1667
|
+
// code) can give the key another value.
|
|
1668
|
+
let touched = false;
|
|
1669
|
+
const visit = (n) => {
|
|
1670
|
+
if (touched)
|
|
1671
|
+
return;
|
|
1672
|
+
if (ts.isIdentifier(n) && (n.text === "arguments" || n.text === "eval"))
|
|
1673
|
+
touched = true;
|
|
1674
|
+
else if (ts.isIdentifier(n) && n.text === name && n !== keyDecl.name && writesBinding(n))
|
|
1675
|
+
touched = true;
|
|
1676
|
+
ts.forEachChild(n, (c) => {
|
|
1677
|
+
visit(c);
|
|
1678
|
+
return undefined;
|
|
1679
|
+
});
|
|
1680
|
+
};
|
|
1681
|
+
for (const p of fn.parameters.nodes)
|
|
1682
|
+
visit(p);
|
|
1683
|
+
const body = fn.body;
|
|
1684
|
+
if (body === undefined)
|
|
1685
|
+
return false;
|
|
1686
|
+
visit(body);
|
|
1687
|
+
if (touched)
|
|
1688
|
+
return false;
|
|
1689
|
+
const edges = analysis.calls.filter((c) => c.callee.node === fn);
|
|
1690
|
+
if (edges.length === 0)
|
|
1691
|
+
return false;
|
|
1692
|
+
// A call lines its arguments up with the parameters only when its callee
|
|
1693
|
+
// is the function itself: a binding, or a constant object's member, that
|
|
1694
|
+
// holds nothing else. `call` and `apply` pass the this value first, and
|
|
1695
|
+
// a builtin that calls the function back chooses its own arguments.
|
|
1696
|
+
const isFn = (a) => a.kind === "function" && a.node === fn;
|
|
1697
|
+
const onlyFn = (values) => values.size > 0 && [...values].every(isFn);
|
|
1698
|
+
const callsFn = (callee) => {
|
|
1699
|
+
while (ts.isParenthesizedExpression(callee))
|
|
1700
|
+
callee = callee.expression;
|
|
1701
|
+
if (ts.isIdentifier(callee)) {
|
|
1702
|
+
const d = declOf(callee);
|
|
1703
|
+
return d !== undefined && onlyFn(analysis.declValues(d));
|
|
1704
|
+
}
|
|
1705
|
+
if (!ts.isPropertyAccessExpression(callee))
|
|
1706
|
+
return false;
|
|
1707
|
+
const op = readOps.get(callee);
|
|
1708
|
+
if (op === undefined || op.name === null)
|
|
1709
|
+
return false;
|
|
1710
|
+
const recv = analysis.nodes[op.recv].atoms;
|
|
1711
|
+
if (recv.size === 0)
|
|
1712
|
+
return false;
|
|
1713
|
+
for (const a of recv) {
|
|
1714
|
+
if (!constantAtoms.has(a))
|
|
1715
|
+
return false;
|
|
1716
|
+
const field = analysis.fields.get(a)?.get(op.name);
|
|
1717
|
+
if (field === undefined || !onlyFn(analysis.nodes[field].atoms))
|
|
1718
|
+
return false;
|
|
1719
|
+
}
|
|
1720
|
+
return true;
|
|
1721
|
+
};
|
|
1722
|
+
return edges.every((e) => {
|
|
1723
|
+
if (!ts.isCallExpression(e.site) || !callsFn(e.site.expression))
|
|
1724
|
+
return false;
|
|
1725
|
+
const args = e.site.arguments.nodes;
|
|
1726
|
+
if (args.slice(0, index + 1).some((a) => ts.isSpreadElement(a)))
|
|
1727
|
+
return false;
|
|
1728
|
+
const arg = args[index];
|
|
1729
|
+
return arg !== undefined && ts.isStringLiteral(arg) && keys.has(arg.text);
|
|
1730
|
+
});
|
|
1731
|
+
};
|
|
1732
|
+
for (const { op, atoms, nullish } of mergedOps) {
|
|
1733
|
+
if (op.kind !== "computedRead")
|
|
1734
|
+
continue;
|
|
1735
|
+
const node = op.node;
|
|
1736
|
+
if (!ts.isElementAccessExpression(node) || node.questionDotToken !== undefined)
|
|
1737
|
+
continue;
|
|
1738
|
+
const call = node.parent;
|
|
1739
|
+
if (call === undefined || !ts.isCallExpression(call) || call.expression !== node)
|
|
1740
|
+
continue;
|
|
1741
|
+
if (call.questionDotToken !== undefined || topStatement(call) === null)
|
|
1742
|
+
continue;
|
|
1743
|
+
const where = `table call ${node.getText()}`;
|
|
1744
|
+
if (atoms.size !== 1) {
|
|
1745
|
+
kept.push(`${where}: the table may be ${atoms.size} values`);
|
|
1746
|
+
continue;
|
|
1747
|
+
}
|
|
1748
|
+
const o = constantAtoms.get([...atoms][0]);
|
|
1749
|
+
if (o === undefined || o.fields.length === 0 || o.fields.length > MAX_TABLE_ARMS) {
|
|
1750
|
+
kept.push(`${where}: not a constant object of at most ${MAX_TABLE_ARMS} members`);
|
|
1751
|
+
continue;
|
|
1752
|
+
}
|
|
1753
|
+
// The arms call a member without evaluating the table expression.
|
|
1754
|
+
if (!effectFree(node.expression)) {
|
|
1755
|
+
kept.push(`${where}: the table expression may have effects`);
|
|
1756
|
+
continue;
|
|
1757
|
+
}
|
|
1758
|
+
const key = node.argumentExpression;
|
|
1759
|
+
if (!ts.isIdentifier(key))
|
|
1760
|
+
continue;
|
|
1761
|
+
const keyDecl = declOf(key);
|
|
1762
|
+
if (keyDecl === undefined)
|
|
1763
|
+
continue;
|
|
1764
|
+
const keyValues = analysis.declValues(keyDecl);
|
|
1765
|
+
if (keyValues.size === 0 ||
|
|
1766
|
+
![...keyValues].every((a) => a.kind === "prim" && a.label === "string")) {
|
|
1767
|
+
kept.push(`${where}: the key may be ${[...keyValues].map((a) => a.label).join(" | ")}`);
|
|
1768
|
+
continue;
|
|
1769
|
+
}
|
|
1770
|
+
const arms = [];
|
|
1771
|
+
for (const f of o.fields) {
|
|
1772
|
+
const fn = f.values.length === 1 ? f.values[0] : undefined;
|
|
1773
|
+
const name = fn === undefined ? undefined : hoisted.get(fn);
|
|
1774
|
+
if (name === undefined || fn.node.getSourceFile() !== call.getSourceFile())
|
|
1775
|
+
break;
|
|
1776
|
+
arms.push([f.key, name]);
|
|
1777
|
+
}
|
|
1778
|
+
if (arms.length !== o.fields.length) {
|
|
1779
|
+
kept.push(`${where}: a member is not a hoisted function of this file`);
|
|
1780
|
+
continue;
|
|
1781
|
+
}
|
|
1782
|
+
const armNodes = o.fields.map((f) => f.values[0].node);
|
|
1783
|
+
if (!createdBefore(call, [o.site.node, ...armNodes, ...receiverDeps(node.expression)])) {
|
|
1784
|
+
kept.push(`${where}: it may run before the table is created`);
|
|
1785
|
+
continue;
|
|
1786
|
+
}
|
|
1787
|
+
tableCalls.push({
|
|
1788
|
+
sf: call.getSourceFile(),
|
|
1789
|
+
call,
|
|
1790
|
+
arms,
|
|
1791
|
+
nullish,
|
|
1792
|
+
exhaustive: literalKeysOnly(keyDecl, new Set(arms.map(([k]) => k))),
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1795
|
+
for (const { sf, call, arms, nullish, exhaustive } of tableCalls) {
|
|
1796
|
+
const node = call.expression;
|
|
1797
|
+
const key = node.argumentExpression.getText();
|
|
1798
|
+
const args = call.arguments.nodes.map((a) => sliceWithCalls(sf, a)).join(", ");
|
|
1799
|
+
const table = sliceWithCalls(sf, node.expression);
|
|
1800
|
+
const tested = exhaustive ? arms.slice(0, -1) : arms;
|
|
1801
|
+
const text = tested
|
|
1802
|
+
.map(([k, name]) => `${key} === ${JSON.stringify(k)} ? ${name}(${args}) : `)
|
|
1803
|
+
.join("");
|
|
1804
|
+
if (exhaustive) {
|
|
1805
|
+
callEdits.push({
|
|
1806
|
+
sf,
|
|
1807
|
+
edit: {
|
|
1808
|
+
start: ts.tokenStartOfNode(call),
|
|
1809
|
+
end: call.end,
|
|
1810
|
+
text: `(${nullish ? `${table}[${key}], ` : ""}${text}${arms[arms.length - 1][1]}(${args}))`,
|
|
1811
|
+
},
|
|
1812
|
+
});
|
|
1813
|
+
tableDispatches++;
|
|
1814
|
+
continue;
|
|
1815
|
+
}
|
|
1816
|
+
callEdits.push({
|
|
1817
|
+
sf,
|
|
1818
|
+
edit: {
|
|
1819
|
+
start: ts.tokenStartOfNode(call),
|
|
1820
|
+
end: call.end,
|
|
1821
|
+
// A table that may be nullish is read first, where the call reads
|
|
1822
|
+
// it, so the read throws before the arguments run; on the constant
|
|
1823
|
+
// object it reads a plain member with a string key.
|
|
1824
|
+
text: `(${nullish ? `${table}[${key}], ` : ""}${text}${table}[${key}](${args}))`,
|
|
1825
|
+
},
|
|
1826
|
+
});
|
|
1827
|
+
tableDispatches++;
|
|
1828
|
+
}
|
|
1829
|
+
for (const h of hoists) {
|
|
1830
|
+
const params = h.fn.parameters.nodes
|
|
1831
|
+
.map((p) => h.sf.text.slice(ts.tokenStartOfNode(p), p.end))
|
|
1832
|
+
.join(", ");
|
|
1833
|
+
edit(h.sf, {
|
|
1834
|
+
start: ts.tokenStartOfNode(h.stmt),
|
|
1835
|
+
end: ts.tokenStartOfNode(h.stmt),
|
|
1836
|
+
text: `function ${h.name}(${params}) ${sliceWithCalls(h.sf, h.fn.body)}\n`,
|
|
1837
|
+
});
|
|
1838
|
+
}
|
|
1839
|
+
// Classes: a declaration at the constructor's statement, then the store.
|
|
1840
|
+
for (const plan of classPlans) {
|
|
1841
|
+
const { sf, site, fn, methods, fnAtom } = plan;
|
|
1842
|
+
const name = hoisted.get(fnAtom);
|
|
1843
|
+
const text = (n) => sliceWithCalls(sf, n);
|
|
1844
|
+
const params = (f) => f.parameters.nodes.map((p) => text(p)).join(", ");
|
|
1845
|
+
const body = [
|
|
1846
|
+
`class ${name} {`,
|
|
1847
|
+
` constructor(${params(fn)}) ${text(fn.body)}`,
|
|
1848
|
+
...methods.map((m) => ` ${m.name}(${params(m.fn)}) ${text(m.fn.body)}`),
|
|
1849
|
+
`}`,
|
|
1850
|
+
"",
|
|
1851
|
+
].join("\n");
|
|
1852
|
+
edit(sf, {
|
|
1853
|
+
start: ts.tokenStartOfNode(site.stmt),
|
|
1854
|
+
end: ts.tokenStartOfNode(site.stmt),
|
|
1855
|
+
text: body,
|
|
1856
|
+
});
|
|
1857
|
+
edit(sf, { start: ts.tokenStartOfNode(fn), end: fn.end, text: name });
|
|
1858
|
+
for (const m of methods)
|
|
1859
|
+
edit(sf, { start: ts.tokenStartOfNode(m.stmt), end: m.stmt.end, text: "" });
|
|
1860
|
+
}
|
|
1861
|
+
for (const c of callEdits)
|
|
1862
|
+
edit(c.sf, c.edit);
|
|
1863
|
+
for (const [sf, names] of exportAdds) {
|
|
1864
|
+
const literal = exportLiteralOf(sf);
|
|
1865
|
+
const props = literal.properties.nodes;
|
|
1866
|
+
const text = [...names].map((n) => `${n}: ${n}`).join(", ");
|
|
1867
|
+
const at = props.length > 0 ? props[props.length - 1].end : ts.tokenStartOfNode(literal) + 1;
|
|
1868
|
+
edit(sf, { start: at, end: at, text: props.length > 0 ? `, ${text}` : ` ${text} ` });
|
|
1869
|
+
}
|
|
1870
|
+
const out = new Map();
|
|
1871
|
+
const applied = new Map();
|
|
1872
|
+
for (const [sf, edits] of editsByFile) {
|
|
1873
|
+
out.set(sf.fileName, applyEdits(sf.text, edits));
|
|
1874
|
+
applied.set(sf.fileName, appliedEdits(edits));
|
|
1875
|
+
}
|
|
1876
|
+
return {
|
|
1877
|
+
files: out,
|
|
1878
|
+
edits: applied,
|
|
1879
|
+
classes,
|
|
1880
|
+
functions,
|
|
1881
|
+
directCalls,
|
|
1882
|
+
tableDispatches,
|
|
1883
|
+
foldedReads,
|
|
1884
|
+
kept,
|
|
1885
|
+
};
|
|
1886
|
+
}
|
|
1887
|
+
/** The edits applyEdits applies, in order. */
|
|
1888
|
+
function appliedEdits(edits) {
|
|
1889
|
+
const sorted = [...edits].sort((a, b) => a.start - b.start || b.end - a.end);
|
|
1890
|
+
const out = [];
|
|
1891
|
+
let at = 0;
|
|
1892
|
+
for (const e of sorted) {
|
|
1893
|
+
if (e.start < at)
|
|
1894
|
+
continue;
|
|
1895
|
+
out.push(e);
|
|
1896
|
+
at = e.end > e.start ? e.end : e.start;
|
|
1897
|
+
}
|
|
1898
|
+
return out;
|
|
1899
|
+
}
|
|
1900
|
+
/** A position of a rewritten file's original text in its rewritten text,
|
|
1901
|
+
* or null inside a replaced range or at an insertion (the text there
|
|
1902
|
+
* changed). */
|
|
1903
|
+
export function rewrittenPosition(edits, pos) {
|
|
1904
|
+
let shift = 0;
|
|
1905
|
+
for (const e of edits) {
|
|
1906
|
+
if (e.start > pos)
|
|
1907
|
+
break;
|
|
1908
|
+
if (e.end === e.start) {
|
|
1909
|
+
if (e.start === pos)
|
|
1910
|
+
return null;
|
|
1911
|
+
shift += e.text.length;
|
|
1912
|
+
continue;
|
|
1913
|
+
}
|
|
1914
|
+
if (pos === e.start)
|
|
1915
|
+
break;
|
|
1916
|
+
if (pos < e.end)
|
|
1917
|
+
return null;
|
|
1918
|
+
shift += e.text.length - (e.end - e.start);
|
|
1919
|
+
}
|
|
1920
|
+
return pos + shift;
|
|
1921
|
+
}
|
|
1922
|
+
/** Applies replacements and insertions; an edit inside an earlier
|
|
1923
|
+
* replacement is applied to the replaced text (nested edits move with the
|
|
1924
|
+
* text they sit in). */
|
|
1925
|
+
function applyEdits(text, edits) {
|
|
1926
|
+
const sorted = [...edits].sort((a, b) => a.start - b.start || b.end - a.end);
|
|
1927
|
+
const apply = (from, to, list) => {
|
|
1928
|
+
let out = "";
|
|
1929
|
+
let at = from;
|
|
1930
|
+
for (let i = 0; i < list.length; i++) {
|
|
1931
|
+
const e = list[i];
|
|
1932
|
+
if (e.start < at)
|
|
1933
|
+
continue;
|
|
1934
|
+
out += text.slice(at, e.start);
|
|
1935
|
+
if (e.end > e.start) {
|
|
1936
|
+
// Edits nested inside this replacement whose text is not literal:
|
|
1937
|
+
// a replacement that rebuilds its range from source pieces applies
|
|
1938
|
+
// them only through its own text, so nested edits are dropped here.
|
|
1939
|
+
out += e.text;
|
|
1940
|
+
at = e.end;
|
|
1941
|
+
}
|
|
1942
|
+
else {
|
|
1943
|
+
out += e.text;
|
|
1944
|
+
at = e.start;
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
return out + text.slice(at, to);
|
|
1948
|
+
};
|
|
1949
|
+
return apply(0, text.length, sorted);
|
|
1950
|
+
}
|
|
1951
|
+
//# sourceMappingURL=static-objects.js.map
|