vitest-pool-assemblyscript 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +110 -36
- package/binding.gyp +6 -6
- package/dist/{compiler-CscxCJw3.mjs → addon-interface-7FPjYh7J.mjs} +12 -141
- package/dist/addon-interface-7FPjYh7J.mjs.map +1 -0
- package/dist/{ast-visitor-DJLJd5dt.mjs → ast-visitor-C5gQqWD2.mjs} +1 -1
- package/dist/{ast-visitor-DJLJd5dt.mjs.map → ast-visitor-C5gQqWD2.mjs.map} +1 -1
- package/dist/{compile-runner-BJ_ZF3Ma.mjs → compile-runner-C-05LdGX.mjs} +7 -6
- package/dist/compile-runner-C-05LdGX.mjs.map +1 -0
- package/dist/compiler/transforms/strip-inline.mjs +2 -3
- package/dist/compiler/transforms/strip-inline.mjs.map +1 -1
- package/dist/compiler-YMrl5MY_.mjs +147 -0
- package/dist/compiler-YMrl5MY_.mjs.map +1 -0
- package/dist/config/index-v3.d.mts +2 -2
- package/dist/config/index.d.mts +3 -3
- package/dist/config/index.mjs +4 -4
- package/dist/{coverage-merge-DCEwyjMy.mjs → coverage-merge-CBXkpM1O.mjs} +1 -1
- package/dist/{coverage-merge-DCEwyjMy.mjs.map → coverage-merge-CBXkpM1O.mjs.map} +1 -1
- package/dist/coverage-provider/index.mjs +11 -11
- package/dist/coverage-provider/index.mjs.map +1 -1
- package/dist/{custom-provider-options-i_O0OSTV.d.mts → custom-provider-options-YTk1m7At.d.mts} +2 -2
- package/dist/{custom-provider-options-i_O0OSTV.d.mts.map → custom-provider-options-YTk1m7At.d.mts.map} +1 -1
- package/dist/feature-check-CNyjFX9M.mjs +82 -0
- package/dist/feature-check-CNyjFX9M.mjs.map +1 -0
- package/dist/index-internal.d.mts +1 -1
- package/dist/index-internal.d.mts.map +1 -1
- package/dist/index-internal.mjs +2 -1
- package/dist/index-v3.mjs +3 -3
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +4 -4
- package/dist/{load-user-imports-CYTTU22Q.mjs → load-user-imports-B3Iy_K8k.mjs} +4 -5
- package/dist/{load-user-imports-CYTTU22Q.mjs.map → load-user-imports-B3Iy_K8k.mjs.map} +1 -1
- package/dist/path-utils-t9OzjXYF.mjs +24 -0
- package/dist/path-utils-t9OzjXYF.mjs.map +1 -0
- package/dist/{pool-runner-init-D56aVMMD.d.mts → pool-runner-init-CvnB0-iN.d.mts} +2 -2
- package/dist/pool-runner-init-CvnB0-iN.d.mts.map +1 -0
- package/dist/{pool-runner-init-D1QamWkS.mjs → pool-runner-init-D8Ei957C.mjs} +6 -5
- package/dist/pool-runner-init-D8Ei957C.mjs.map +1 -0
- package/dist/pool-thread/compile-worker-thread.d.mts +1 -1
- package/dist/pool-thread/compile-worker-thread.mjs +7 -7
- package/dist/pool-thread/compile-worker-thread.mjs.map +1 -1
- package/dist/pool-thread/test-worker-thread.d.mts +1 -1
- package/dist/pool-thread/test-worker-thread.mjs +5 -5
- package/dist/pool-thread/test-worker-thread.mjs.map +1 -1
- package/dist/pool-thread/v3-tinypool-thread.d.mts +1 -1
- package/dist/pool-thread/v3-tinypool-thread.mjs +8 -8
- package/dist/pool-thread/v3-tinypool-thread.mjs.map +1 -1
- package/dist/resolve-config-BFNr7LW7.mjs.map +1 -1
- package/dist/{test-runner-CfhzcYNS.mjs → test-runner-WF857_Bk.mjs} +4 -4
- package/dist/{test-runner-CfhzcYNS.mjs.map → test-runner-WF857_Bk.mjs.map} +1 -1
- package/dist/{types-DmyeERkL.d.mts → types-D0nprJo1.d.mts} +1 -1
- package/dist/types-D0nprJo1.d.mts.map +1 -0
- package/dist/{vitest-file-tasks-BUwzh375.mjs → vitest-file-tasks-Bn9CrWt_.mjs} +1 -1
- package/dist/{vitest-file-tasks-BUwzh375.mjs.map → vitest-file-tasks-Bn9CrWt_.mjs.map} +1 -1
- package/dist/{vitest-tasks-ByPK8DvF.mjs → vitest-tasks--ow4pacR.mjs} +1 -1
- package/dist/{vitest-tasks-ByPK8DvF.mjs.map → vitest-tasks--ow4pacR.mjs.map} +1 -1
- package/dist/{wasm-names-CydfYzQK.mjs → wasm-names-BFtzQCH4.mjs} +1 -1
- package/dist/{wasm-names-CydfYzQK.mjs.map → wasm-names-BFtzQCH4.mjs.map} +1 -1
- package/dist/{worker-rpc-channel-lbhK7Qz8.mjs → worker-rpc-channel-CZZIxtv5.mjs} +1 -1
- package/dist/{worker-rpc-channel-lbhK7Qz8.mjs.map → worker-rpc-channel-CZZIxtv5.mjs.map} +1 -1
- package/package.json +17 -16
- package/prebuilds/darwin-arm64/vitest-pool-assemblyscript.glibc.node +0 -0
- package/prebuilds/darwin-x64/vitest-pool-assemblyscript.glibc.node +0 -0
- package/prebuilds/linux-arm64/vitest-pool-assemblyscript.glibc.node +0 -0
- package/prebuilds/linux-x64/vitest-pool-assemblyscript.glibc.node +0 -0
- package/prebuilds/linux-x64/vitest-pool-assemblyscript.musl.node +0 -0
- package/prebuilds/win32-arm64/vitest-pool-assemblyscript.glibc.node +0 -0
- package/prebuilds/win32-x64/vitest-pool-assemblyscript.glibc.node +0 -0
- package/scripts/install.js +53 -16
- package/src/{native-instrumentation → instrumentation/native}/addon.cpp +8 -8
- package/dist/compile-runner-BJ_ZF3Ma.mjs.map +0 -1
- package/dist/compiler-CscxCJw3.mjs.map +0 -1
- package/dist/node-check-CooGQMLH.mjs +0 -16
- package/dist/node-check-CooGQMLH.mjs.map +0 -1
- package/dist/pool-runner-init-D1QamWkS.mjs.map +0 -1
- package/dist/pool-runner-init-D56aVMMD.d.mts.map +0 -1
- package/dist/types-DmyeERkL.d.mts.map +0 -1
package/README.md
CHANGED
|
@@ -2,8 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
4
|
<img src="docs/images/as-icon.svg" height="50" align="middle">
|
|
5
|
-
➕
|
|
6
|
-
<
|
|
5
|
+
➕
|
|
6
|
+
<picture>
|
|
7
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/vitest-light.svg">
|
|
8
|
+
<source media="(prefers-color-scheme: light)" srcset="docs/images/vitest-dark.svg">
|
|
9
|
+
<img alt="Vitest logo" src="docs/images/vitest-dark.svg" height="30" align="middle">
|
|
10
|
+
</picture>
|
|
7
11
|
</p>
|
|
8
12
|
|
|
9
13
|
<p align="center">
|
|
@@ -24,29 +28,51 @@
|
|
|
24
28
|
</p>
|
|
25
29
|
|
|
26
30
|
<p align="center">
|
|
27
|
-
|
|
31
|
+
Check it out:
|
|
28
32
|
<br/>
|
|
29
|
-
<a href="#
|
|
33
|
+
<a href="#status">Status</a> |
|
|
34
|
+
<a href="#quick-start">Quick Start</a> |
|
|
35
|
+
<a href="#features">Features</a> |
|
|
36
|
+
<a href="#frequently-asked-questions">Frequently Asked Questions</a>
|
|
37
|
+
<br/>
|
|
38
|
+
<a href="#compatibility">Compatibility</a> |
|
|
39
|
+
<a href="#performance">Performance</a> |
|
|
40
|
+
<a href="#prior-work">Prior Work</a> |
|
|
41
|
+
<a href="#license">License</a>
|
|
42
|
+
</p>
|
|
43
|
+
<p align="center">
|
|
44
|
+
Dig in:
|
|
45
|
+
<br/>
|
|
46
|
+
<a href="#writing-tests">Writing Tests</a> |
|
|
47
|
+
<a href="docs/matchers-api.md">Matchers API</a> |
|
|
48
|
+
<a href="docs/configuration-guide.md">Configuration Guide</a> |
|
|
49
|
+
<a href="docs/providing-wasm-imports.md">Providing WASM Imports</a>
|
|
30
50
|
</p>
|
|
31
51
|
|
|
32
52
|
---
|
|
33
53
|
|
|
34
54
|
<br/>
|
|
35
55
|
<p align="center">
|
|
36
|
-
<img src="docs/images/example-small.gif" alt="vitest-pool-assemblyscript demo">
|
|
56
|
+
<img src="docs/images/example-small.gif" alt="vitest-pool-assemblyscript quick demo">
|
|
37
57
|
</p>
|
|
38
58
|
|
|
39
59
|
## Status
|
|
40
60
|
|
|
41
61
|
This project is relatively new to the scene, but is being improved every day. Please give it a try!
|
|
42
62
|
|
|
43
|
-
|
|
44
|
-
- [`describe()` and `test()` definition APIs](#writing-tests) are stable and not expected to change
|
|
45
|
-
- [`expect()` matchers API](docs/matchers-api.md) is stable and not expected to change. More are coming soon
|
|
46
|
-
- Native instrumentation prebuilds are available [across many platforms](#compatibility)
|
|
47
|
-
- See [Current Limitations & Roadmap](#current-limitations--roadmap) for important limitations to be aware of, and to see what's still planned.
|
|
63
|
+
All [listed features](#features) are working and assumed to be bug-free ([please report any](https://github.com/themattspiral/vitest-pool-assemblyscript/issues/new))
|
|
48
64
|
|
|
49
|
-
|
|
65
|
+
| Function | Status |
|
|
66
|
+
|---|---|
|
|
67
|
+
| [`describe()` and `test()` APIs](#writing-tests) | - stable<br/>- no breaking changes expected |
|
|
68
|
+
| [`expect()` API](docs/matchers-api.md) | - stable<br/>- no breaking changes expected<br/>- more coming soon |
|
|
69
|
+
| Code Coverage / Instrumentation | - function coverage stable [across platforms](#compatibility)<br/>- branch & line coverage coming soon |
|
|
70
|
+
| Hybrid Coverage Provider | - stable<br/>- v8 delegation, side-by-side JS coverage<br/>- istanbul delegation coming soon
|
|
71
|
+
|
|
72
|
+
See Also:
|
|
73
|
+
- [Current Limitations & Roadmap](#current-limitations--roadmap)
|
|
74
|
+
- [Frequently Asked Questions](#frequently-asked-questions)
|
|
75
|
+
- [Report a Bug / Request a Feature](https://github.com/themattspiral/vitest-pool-assemblyscript/issues/new)
|
|
50
76
|
|
|
51
77
|
---
|
|
52
78
|
|
|
@@ -162,17 +188,47 @@ npx vitest run
|
|
|
162
188
|
|
|
163
189
|
---
|
|
164
190
|
|
|
191
|
+
## Frequently Asked Questions
|
|
192
|
+
|
|
193
|
+
**Q: How does this work?**
|
|
194
|
+
<br/>
|
|
195
|
+
**A:** Vitest has a [custom pool API](https://vitest.dev/guide/advanced/pool.html) that lets you define the execution environment for the tests it runs (internally, vitest uses its own pools to run JavaScript and TypeScript tests). This custom pool uses the [AssemblyScript compiler](https://www.assemblyscript.org/compiler.html) to compile each test file to WASM, instruments the WASM binary for code coverage, then runs each test in an isolated WASM instance and reports results back to vitest through its standard RPC reporting mechanism.
|
|
196
|
+
|
|
197
|
+
**Q: So it is really using vitest?**
|
|
198
|
+
<br/>
|
|
199
|
+
**A:** Yes! It's a real vitest pool, not a clone of vitest - it hooks directly into the framework, receiving tests to run from vitest and reporting results back. The pool implements its own compilation, test execution, and [matchers in AS](docs/matchers-api.md), designed to mirror the [vitest expect() API](https://vitest.dev/api/expect.html). We don't use vite build integration, but that's the tradeoff of a custom pool - you can bring any execution environment to vitest.
|
|
200
|
+
|
|
201
|
+
The overall goal is tight vitest experience integration - most CLI commands, reporters, UI, and project configurations should work as you'd expect, and test runner behavior should match vitest's JS pool runner for features we've implemented (retries, timeouts, skip, only, fails, etc.). Some features aren't implemented yet due to effort and prioritization, and others necessarily differ given AssemblyScript's static typing and execution model. See the [configuration guide](docs/configuration-guide.md) and [limitations / roadmap](#current-limitations--roadmap) for specifics.
|
|
202
|
+
|
|
203
|
+
**Q: Will this work on my machine?**
|
|
204
|
+
<br/>
|
|
205
|
+
**A:** Probably! WASM coverage instrumentation requires native binaries, and we ship [prebuilt binaries for most common platforms](#compatibility). If your platform isn't listed, the npm package installation will fallback to trying to build the native code using a local C++ toolchain.
|
|
206
|
+
|
|
207
|
+
**Q: Do you support older versions of AssemblyScript?**
|
|
208
|
+
<br/>
|
|
209
|
+
**A:** It's tested against 0.28.9 currently, and that's the version I have any real experience with. Older versions might work but aren't actively tested. If you're stuck on an older version and run into issues, you're welcome to [open an issue](https://github.com/themattspiral/vitest-pool-assemblyscript/issues/new).
|
|
210
|
+
|
|
211
|
+
**Q: Is this an official vitest project?**
|
|
212
|
+
<br/>
|
|
213
|
+
**A:** No, this is a third-party community project. It's not affiliated with or endorsed by the vitest team, though we're grateful for their extensible architecture that makes projects like this possible, and the [other open-source projects](#prior-work) that provide vital functionality and reference architecture.
|
|
214
|
+
|
|
215
|
+
**Q: Are you a company? A bot?**
|
|
216
|
+
<br/>
|
|
217
|
+
**A:** Just [a person](https://github.com/themattspiral)! This started as a hobby project to improve my own AssemblyScript testing workflow and learn something about WASM internals, and it's grown from there. I use Claude Code for initial scaffolding and to help dig into the native instrumentation side in particular, but everything goes through me, and my intention is to contribute something useful and high-quality to the community. Feedback and contributions are welcome.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
165
221
|
## Compatibility
|
|
166
222
|
|
|
167
223
|
| Dependency | Supported Versions |
|
|
168
224
|
|---|---|
|
|
169
225
|
| Node.js | (20*), 22, 24+ |
|
|
170
|
-
| Vitest | 3.2.x, 4.x |
|
|
171
|
-
| AssemblyScript | 0.28+ |
|
|
226
|
+
| Vitest | 3.2.x, 4.x.x |
|
|
227
|
+
| AssemblyScript | 0.28.9+ ([more?](#frequently-asked-questions)) |
|
|
172
228
|
|
|
173
229
|
>ℹ️ ***Node 20 Support:** If you don't need code coverage, Node 20 should continue to work for test execution.
|
|
174
230
|
>
|
|
175
|
-
>WASM coverage instrumentation is implemented using WebAssembly
|
|
231
|
+
>WASM coverage instrumentation is implemented using [WebAssembly multi-memory](https://github.com/WebAssembly/multi-memory) to isolate coverage counters from user test memory. This feature shipped in V8 12.0 / Node 22.
|
|
176
232
|
|
|
177
233
|
**Platforms with prebuilt native binaries for coverage instrumentation & debug info:**
|
|
178
234
|
|
|
@@ -190,8 +246,8 @@ npx vitest run
|
|
|
190
246
|
Import `test`, `describe`, `expect` from `vitest-pool-assemblyscript/assembly`. These functions are designed to follow the vitest API as closely as possible, so that everything is familiar and easy to reason about.
|
|
191
247
|
|
|
192
248
|
- `it` is available as an alias for `test`
|
|
193
|
-
- `describe` and `test` have inline modifiers to quickly change their
|
|
194
|
-
- `TestOptions` allows per-test inline configuration of additional options
|
|
249
|
+
- `describe` and `test` have inline modifiers to quickly change their run mode (see below)
|
|
250
|
+
- `TestOptions` allows per-test inline configuration of additional options (aligned with vitest behavior)
|
|
195
251
|
|
|
196
252
|
```typescript
|
|
197
253
|
import { test, it, describe, expect, TestOptions } from "vitest-pool-assemblyscript/assembly";
|
|
@@ -215,17 +271,29 @@ describe("a suite of math operations", () => {
|
|
|
215
271
|
});
|
|
216
272
|
```
|
|
217
273
|
|
|
218
|
-
### Inline Modifiers: `.skip`, `.only`, `.fails`
|
|
274
|
+
### Inline Run Mode Modifiers: `.skip`, `.only`, `.fails`
|
|
275
|
+
|
|
276
|
+
These modify the way in which tests run in relation to each other, and/or how they report results.
|
|
277
|
+
|
|
278
|
+
They follow vitest JS-pool behavior.
|
|
219
279
|
|
|
220
280
|
```typescript
|
|
221
|
-
test.skip("not ready yet", () => {
|
|
281
|
+
test.skip("not ready yet", () => {
|
|
282
|
+
// test will register it exists, show as skipped
|
|
283
|
+
});
|
|
222
284
|
|
|
223
|
-
test.only("
|
|
285
|
+
test.only("debugging this test", () => {
|
|
286
|
+
// test will run by itself in this file
|
|
287
|
+
});
|
|
224
288
|
|
|
225
|
-
test.fails("expected to fail, so will actually pass", () => {
|
|
289
|
+
test.fails("conditions are expected to fail, so test will actually pass", () => {
|
|
226
290
|
expect(false).toBeTruthy();
|
|
227
291
|
});
|
|
228
292
|
|
|
293
|
+
test.fails("conditions are expected to fail but do not, so test will actually fail", () => {
|
|
294
|
+
expect(true).toBeTruthy();
|
|
295
|
+
});
|
|
296
|
+
|
|
229
297
|
describe.skip("entire suite skipped", () => { /* ... */ });
|
|
230
298
|
|
|
231
299
|
describe.only("only this suite runs", () => { /* ... */ });
|
|
@@ -233,9 +301,10 @@ describe.only("only this suite runs", () => { /* ... */ });
|
|
|
233
301
|
|
|
234
302
|
### Inline Test Options
|
|
235
303
|
|
|
236
|
-
`TestOptions` provides chainable configuration for `timeout`, `retry`, `skip`, `only`, and `fails
|
|
304
|
+
`TestOptions` provides chainable configuration for the vitest behavioral options: `timeout`, `retry`, `skip`, `only`, and `fails`
|
|
305
|
+
- While you define them slightly differently in AssemblyScript than JavaScript, their behavior matches the same options in vitest
|
|
237
306
|
- Options can be placed before or after the callback
|
|
238
|
-
- Suite options are inherited by nested tests and suites
|
|
307
|
+
- Suite options (in `describe`) are inherited by nested tests and nested suites
|
|
239
308
|
|
|
240
309
|
```typescript
|
|
241
310
|
// options before callback
|
|
@@ -261,12 +330,16 @@ test.fails("expected failure with retry", TestOptions.retry(3), () => {
|
|
|
261
330
|
});
|
|
262
331
|
```
|
|
263
332
|
|
|
264
|
-
See the [Matchers API documentation](docs/matchers-api.md) for details on the available `expect()` methods you can use within your tests.
|
|
265
|
-
|
|
266
333
|
### Lifecycle Hooks (Setup & Teardown)
|
|
267
334
|
|
|
268
335
|
Coming Soon!
|
|
269
336
|
|
|
337
|
+
### Test Matchers
|
|
338
|
+
|
|
339
|
+
We aim to follow the [vitest/jest `expect()` API](https://vitest.dev/api/expect.html) as closely as possible, with some necessary differences given AssemblyScript's static-typing.
|
|
340
|
+
|
|
341
|
+
See the AssemblyScript Pool [Matchers API documentation](docs/matchers-api.md) for details on the available `expect()` methods you can use within your tests.
|
|
342
|
+
|
|
270
343
|
---
|
|
271
344
|
|
|
272
345
|
## Current Limitations & Roadmap
|
|
@@ -314,16 +387,16 @@ These are known limitations which are currently being worked on.
|
|
|
314
387
|
|
|
315
388
|
## Performance
|
|
316
389
|
|
|
317
|
-
|
|
318
|
-
- Separate compile and test execution thread pools,
|
|
319
|
-
- Compile threads tuned to take advantage of significant Node V8 engine warmup time savings on consecutive AssemblyScript compilations
|
|
390
|
+
Many efforts have been made to compile and run tests as quickly as possible. Some optimizations that have been most useful:
|
|
391
|
+
- Separate compile and test execution thread pools, worker thread entry points, and runners for quicker startup and thread respawn after test timeouts
|
|
392
|
+
- Compile threads tuned to take advantage of significant Node V8 engine warmup time savings on consecutive AssemblyScript compilations (this is an ongoing investigation as I want to see how it behaves when scaled up significantly)
|
|
320
393
|
- In-memory compiled files and source maps to eliminate intermediate disk I/O
|
|
321
394
|
- Enforced hard timeouts for long-running WASM tests via thread termination, with intelligent resume
|
|
322
395
|
|
|
323
|
-
As such, it is capable of compiling dozens of test files comprising hundreds of tests in a few seconds
|
|
396
|
+
As such, it is capable of compiling dozens of test files comprising hundreds of tests in a few seconds, and is likely faster on your machine than mine:
|
|
324
397
|
|
|
325
398
|
<p align="center">
|
|
326
|
-
<img src="docs/images/example-fixtures-suite.gif" alt="vitest-pool-assemblyscript demo">
|
|
399
|
+
<img src="docs/images/example-fixtures-suite.gif" alt="vitest-pool-assemblyscript large suite performance demo">
|
|
327
400
|
</p>
|
|
328
401
|
|
|
329
402
|
---
|
|
@@ -332,15 +405,16 @@ As such, it is capable of compiling dozens of test files comprising hundreds of
|
|
|
332
405
|
|
|
333
406
|
There are several core pieces of software without which this project would not be possible.
|
|
334
407
|
|
|
335
|
-
- This project makes direct use of the [AssemblyScript language](https://www.assemblyscript.org) and its fantastic [compiler](https://www.assemblyscript.org/compiler.html)
|
|
336
|
-
-
|
|
337
|
-
-
|
|
338
|
-
-
|
|
408
|
+
- This project makes direct use of the [AssemblyScript language](https://www.assemblyscript.org) and its fantastic [compiler](https://www.assemblyscript.org/compiler.html). AS is a joy to work with when it comes to WASM because it's so familiar to everyday TypeScript usage.
|
|
409
|
+
- The key component that allows us to perform WASM instrumentation is [Binaryen](https://github.com/WebAssembly/binaryen), a C++ toolchain infrastructure library for WebAssembly. We started by using the fantastic [binaryen.js](https://github.com/AssemblyScript/binaryen.js/) - a JS port also from the folks behind AssemblyScript, and eventually migrated to the native library for some advanced source-map regeneration features.
|
|
410
|
+
- Thanks to the [Vitest team](https://github.com/vitest-dev) for creating the framework in the first place and making it extensible for different runtimes. Their internal pools were used as reference throughout development.
|
|
411
|
+
- Thanks to [`@cloudflare/vitest-pool-workers`](https://github.com/cloudflare/workers-sdk/tree/main/packages/vitest-pool-workers) for providing the leading example of a 3rd party vitest custom pool out in the wild.
|
|
412
|
+
- Particular gratitude is also owed to [assemblyscript-unittest-framework](https://github.com/wasm-ecosystem/assemblyscript-unittest-framework) for inspiring our test discovery and instrumentation expression-walking approaches.
|
|
339
413
|
|
|
340
414
|
---
|
|
341
415
|
|
|
342
416
|
## License
|
|
343
417
|
|
|
344
|
-
[MIT](LICENSE)
|
|
345
|
-
|
|
346
|
-
-
|
|
418
|
+
Licensed under the [MIT](LICENSE)
|
|
419
|
+
|
|
420
|
+
Portions of this software have been derived from third-party works which are licenced under different terms. These uses have been noted and are accompanied by their respective licenses in the [project license](LICENSE) and/or in applicable source code.
|
package/binding.gyp
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"targets": [
|
|
3
3
|
{
|
|
4
|
-
"target_name": "
|
|
4
|
+
"target_name": "wasm_binaryen_debug_instrumenter",
|
|
5
5
|
"sources": [
|
|
6
|
-
"src/
|
|
6
|
+
"src/instrumentation/native/addon.cpp"
|
|
7
7
|
],
|
|
8
8
|
"include_dirs": [
|
|
9
9
|
# node-addon-api C++ headers (N-API wrapper)
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"-lpthread"
|
|
28
28
|
],
|
|
29
29
|
# Enable C++ exceptions (node-gyp disables them by default)
|
|
30
|
-
"cflags_cc": ["-std=c++
|
|
30
|
+
"cflags_cc": ["-std=c++17", "-fexceptions", "-O3"],
|
|
31
31
|
"cflags!": ["-fno-exceptions"],
|
|
32
32
|
"cflags_cc!": ["-fno-exceptions"]
|
|
33
33
|
}],
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
"xcode_settings": {
|
|
39
39
|
"GCC_ENABLE_CPP_EXCEPTIONS": "YES",
|
|
40
40
|
"CLANG_CXX_LIBRARY": "libc++",
|
|
41
|
-
# Minimum macOS deployment target for C++
|
|
41
|
+
# Minimum macOS deployment target for C++17 support
|
|
42
42
|
"MACOSX_DEPLOYMENT_TARGET": "10.15",
|
|
43
|
-
"OTHER_CPLUSPLUSFLAGS": ["-std=c++
|
|
43
|
+
"OTHER_CPLUSPLUSFLAGS": ["-std=c++17", "-fexceptions", "-O3"]
|
|
44
44
|
}
|
|
45
45
|
}],
|
|
46
46
|
["OS=='win'", {
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"VCCLCompilerTool": {
|
|
53
53
|
# Enable C++ exception handling (/EHsc)
|
|
54
54
|
"ExceptionHandling": 1,
|
|
55
|
-
"AdditionalOptions": ["/std:c++
|
|
55
|
+
"AdditionalOptions": ["/std:c++17", "/permissive"]
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
}]
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { INTERNAL_PATH_LIB_PREFIX, POOL_ERROR_NAMES } from "./constants-DuBLuMjt.mjs";
|
|
2
|
-
import { createPoolError, debug
|
|
3
|
-
import {
|
|
2
|
+
import { createPoolError, debug } from "./debug-Cm1VFmaz.mjs";
|
|
3
|
+
import { toForwardSlash } from "./path-utils-t9OzjXYF.mjs";
|
|
4
|
+
import { getShortFunctionName } from "./wasm-names-BFtzQCH4.mjs";
|
|
4
5
|
import { createRequire } from "node:module";
|
|
5
|
-
import {
|
|
6
|
-
import { access, readFile } from "node:fs/promises";
|
|
7
|
-
import { main } from "assemblyscript/asc";
|
|
6
|
+
import { dirname, resolve } from "node:path";
|
|
8
7
|
import { fileURLToPath } from "node:url";
|
|
9
8
|
|
|
10
|
-
//#region src/
|
|
9
|
+
//#region src/instrumentation/addon-interface.ts
|
|
11
10
|
/**
|
|
12
11
|
* Native addon interface for extracting debug information from WebAssembly binaries
|
|
13
12
|
*
|
|
@@ -29,7 +28,7 @@ try {
|
|
|
29
28
|
try {
|
|
30
29
|
addon = nodeGypBuild(rootFromSrc);
|
|
31
30
|
} catch (err) {
|
|
32
|
-
throw createPoolError(`
|
|
31
|
+
throw createPoolError(`vitest-pool-assemblyscript native instrumentation addon not found. Searched from ${rootFromDist} and ${rootFromSrc}. Ensure prebuilds are available or run 'node node_modules/vitest-pool-assemblyscript/scripts/install.js' to compile from source. Original error: ${err instanceof Error ? err.message : String(err)}`, POOL_ERROR_NAMES.WASMInstrumentationError);
|
|
33
32
|
}
|
|
34
33
|
}
|
|
35
34
|
/**
|
|
@@ -46,8 +45,8 @@ try {
|
|
|
46
45
|
function convertLocation(rawLocation, debugSourceFiles, projectRoot) {
|
|
47
46
|
let filePath = debugSourceFiles[rawLocation.fileIndex];
|
|
48
47
|
if (!filePath) throw createPoolError(`No debug source file with index: ${rawLocation.fileIndex}}`, POOL_ERROR_NAMES.WASMInstrumentationError);
|
|
49
|
-
if (filePath.startsWith(INTERNAL_PATH_LIB_PREFIX)) filePath = resolve(projectRoot, "assembly", filePath.slice(INTERNAL_PATH_LIB_PREFIX.length));
|
|
50
|
-
else filePath = resolve(projectRoot, filePath);
|
|
48
|
+
if (filePath.startsWith(INTERNAL_PATH_LIB_PREFIX)) filePath = toForwardSlash(resolve(projectRoot, "assembly", filePath.slice(INTERNAL_PATH_LIB_PREFIX.length)));
|
|
49
|
+
else filePath = toForwardSlash(resolve(projectRoot, filePath));
|
|
51
50
|
return {
|
|
52
51
|
filePath,
|
|
53
52
|
line: rawLocation.line,
|
|
@@ -172,7 +171,7 @@ function transformDebugInfo(raw, logPrefix, projectRoot) {
|
|
|
172
171
|
* @throws {TypeError} If wasmBuffer or sourceMapBuffer are not Buffers
|
|
173
172
|
* @throws {Error} If WASM binary or source map is invalid
|
|
174
173
|
*/
|
|
175
|
-
|
|
174
|
+
const instrumentForCoverage = (wasmBuffer, sourceMapBuffer, instrumentationOptions, logModule, logLabel) => {
|
|
176
175
|
if (!Buffer.isBuffer(wasmBuffer)) throw createPoolError("instrumentForCoverage - wasmBuffer must be a Buffer", POOL_ERROR_NAMES.WASMInstrumentationError);
|
|
177
176
|
if (!Buffer.isBuffer(sourceMapBuffer)) throw createPoolError("instrumentForCoverage - sourceMapBuffer must be a Buffer", POOL_ERROR_NAMES.WASMInstrumentationError);
|
|
178
177
|
const interfaceLogPrefix = `[${logModule} Inst] ${logLabel}`;
|
|
@@ -200,136 +199,8 @@ function instrumentForCoverage(wasmBuffer, sourceMapBuffer, instrumentationOptio
|
|
|
200
199
|
sourceMap: nativeResult.sourceMap,
|
|
201
200
|
debugInfo
|
|
202
201
|
};
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
//#endregion
|
|
206
|
-
//#region src/compiler/index.ts
|
|
207
|
-
/**
|
|
208
|
-
* AssemblyScript Compiler
|
|
209
|
-
*
|
|
210
|
-
* Handles compilation of AssemblyScript source code to WASM binaries.
|
|
211
|
-
* Manages compiler options, transforms, and in-memory compilation.
|
|
212
|
-
*/
|
|
213
|
-
const POOL_ASSEMBLY_NODE_MODULES_PREFIX = "node_modules/vitest-pool-assemblyscript/assembly/";
|
|
214
|
-
const STRIP_INLINE_TRANSFORM = resolve(import.meta.dirname, "./compiler/transforms/strip-inline.mjs");
|
|
215
|
-
setImmediate(async () => {
|
|
216
|
-
try {
|
|
217
|
-
await access(STRIP_INLINE_TRANSFORM);
|
|
218
|
-
} catch {
|
|
219
|
-
throw createPoolError(`AS Compiler strip inline transform file not found at "${STRIP_INLINE_TRANSFORM}"`, POOL_ERROR_NAMES.CompilationError);
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
/**
|
|
223
|
-
* Compile AssemblyScript source code to WASM binary
|
|
224
|
-
*/
|
|
225
|
-
async function compileAssemblyScript(filename, options, logModule, logLabel, signal) {
|
|
226
|
-
throwPoolErrorIfAborted(signal);
|
|
227
|
-
const compileStart = performance.now();
|
|
228
|
-
const logPrefix = `[${logModule} ASC] ${logLabel}`;
|
|
229
|
-
const { shouldInstrument, instrumentationOptions, extraFlags } = options;
|
|
230
|
-
if (shouldInstrument && !instrumentationOptions) throw createPoolError("Instrumentation options are required for coverage instrumentation", POOL_ERROR_NAMES.CompilationError);
|
|
231
|
-
const stdoutLines = [];
|
|
232
|
-
const stderrLines = [];
|
|
233
|
-
let binary;
|
|
234
|
-
let sourceMap;
|
|
235
|
-
const entryFile = filename;
|
|
236
|
-
const outputFile = "output.wasm";
|
|
237
|
-
debug(`${logPrefix} - Compiling: "${filename}"`);
|
|
238
|
-
const stdout = { write: (text) => {
|
|
239
|
-
stdoutLines.push(text);
|
|
240
|
-
return true;
|
|
241
|
-
} };
|
|
242
|
-
const stderr = { write: (text) => {
|
|
243
|
-
stderrLines.push(text);
|
|
244
|
-
return true;
|
|
245
|
-
} };
|
|
246
|
-
const compilerFlags = [
|
|
247
|
-
entryFile,
|
|
248
|
-
"--optimizeLevel",
|
|
249
|
-
"0",
|
|
250
|
-
"--shrinkLevel",
|
|
251
|
-
"0",
|
|
252
|
-
"--runtime",
|
|
253
|
-
"stub",
|
|
254
|
-
...extraFlags || [],
|
|
255
|
-
"--outFile",
|
|
256
|
-
outputFile,
|
|
257
|
-
"--importMemory",
|
|
258
|
-
"--debug",
|
|
259
|
-
"--sourceMap",
|
|
260
|
-
"--exportStart",
|
|
261
|
-
"_start",
|
|
262
|
-
"--exportTable"
|
|
263
|
-
];
|
|
264
|
-
if (options.stripInline === true) {
|
|
265
|
-
compilerFlags.push("--transform", STRIP_INLINE_TRANSFORM);
|
|
266
|
-
debug(`${logPrefix} - Added Transform - Stripping @inline decorators`);
|
|
267
|
-
}
|
|
268
|
-
const ascStart = performance.now();
|
|
269
|
-
const result = await main(compilerFlags, {
|
|
270
|
-
stdout,
|
|
271
|
-
stderr,
|
|
272
|
-
writeFile: (name, contents, _baseDir) => {
|
|
273
|
-
throwPoolErrorIfAborted(signal);
|
|
274
|
-
if (name.endsWith(".wasm") && contents instanceof Uint8Array) {
|
|
275
|
-
binary = contents;
|
|
276
|
-
debug(`${logPrefix} - Captured binary in memory: "${name}"`);
|
|
277
|
-
} else if (name.endsWith(".wasm.map") && typeof contents === "string") {
|
|
278
|
-
debug(`${logPrefix} - Captured source map in memory: "${name}"`);
|
|
279
|
-
sourceMap = contents;
|
|
280
|
-
} else debug(`${logPrefix} - WARNING - Captured Unexpected File: "${name}" at baseDir: "${_baseDir}"`);
|
|
281
|
-
},
|
|
282
|
-
readFile: async (filename, baseDir) => {
|
|
283
|
-
const filePath = resolve(baseDir, filename);
|
|
284
|
-
try {
|
|
285
|
-
return await readFile(filePath, { encoding: "utf-8" });
|
|
286
|
-
} catch {
|
|
287
|
-
if (filename.startsWith(POOL_ASSEMBLY_NODE_MODULES_PREFIX)) {
|
|
288
|
-
const localPath = resolve(baseDir, "assembly", filename.substring(49));
|
|
289
|
-
try {
|
|
290
|
-
return await readFile(localPath, { encoding: "utf-8" });
|
|
291
|
-
} catch {
|
|
292
|
-
return null;
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
return null;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
});
|
|
299
|
-
debug(`${logPrefix} - TIMING asc.main: ${(performance.now() - ascStart).toFixed(2)} ms`);
|
|
300
|
-
if (result.error) {
|
|
301
|
-
const errorMessage = stderrLines.length > 0 ? `${result.error.message}\n\n${stderrLines.join("")}` : result.error.message;
|
|
302
|
-
throw createPoolError(errorMessage, POOL_ERROR_NAMES.CompilationError, errorMessage);
|
|
303
|
-
}
|
|
304
|
-
if (!binary) throw createPoolError(stderrLines.length > 0 ? `No WASM binary was generated\n\nAS Compiler output:\n${stderrLines.join("")}` : "No WASM binary was generated", POOL_ERROR_NAMES.CompilationError);
|
|
305
|
-
if (!sourceMap) throw createPoolError("Source map not captured from AssemblyScript Compiler", POOL_ERROR_NAMES.CompilationError);
|
|
306
|
-
const cleanBinary = binary;
|
|
307
|
-
const wasmSourceMap = sourceMap;
|
|
308
|
-
debug(`${logPrefix} - Compilation successful, clean binary size: ${cleanBinary.length} bytes`);
|
|
309
|
-
debug(`${logPrefix} - Source map generated, size: ${wasmSourceMap.length * 2} bytes`);
|
|
310
|
-
if (options.shouldInstrument) {
|
|
311
|
-
throwPoolErrorIfAborted(signal);
|
|
312
|
-
const instrumentStart = performance.now();
|
|
313
|
-
const instrumentResult = instrumentForCoverage(Buffer.from(cleanBinary), Buffer.from(wasmSourceMap), options.instrumentationOptions, logModule, logLabel);
|
|
314
|
-
const instCount = instrumentResult.debugInfo.instrumentedFunctionCount;
|
|
315
|
-
const instrumentEnd = performance.now();
|
|
316
|
-
debug(`${logPrefix} - TIMING Instrumented ${instCount} functions: ${(performance.now() - instrumentStart).toFixed(2)} ms`);
|
|
317
|
-
return {
|
|
318
|
-
binary: instrumentResult.instrumentedWasm,
|
|
319
|
-
sourceMap: instrumentResult.sourceMap,
|
|
320
|
-
debugInfo: instrumentResult.debugInfo,
|
|
321
|
-
isInstrumented: true,
|
|
322
|
-
compileTiming: instrumentEnd - compileStart
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
return {
|
|
326
|
-
binary: cleanBinary,
|
|
327
|
-
sourceMap: wasmSourceMap,
|
|
328
|
-
isInstrumented: false,
|
|
329
|
-
compileTiming: performance.now() - compileStart
|
|
330
|
-
};
|
|
331
|
-
}
|
|
202
|
+
};
|
|
332
203
|
|
|
333
204
|
//#endregion
|
|
334
|
-
export {
|
|
335
|
-
//# sourceMappingURL=
|
|
205
|
+
export { instrumentForCoverage };
|
|
206
|
+
//# sourceMappingURL=addon-interface-7FPjYh7J.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"addon-interface-7FPjYh7J.mjs","names":[],"sources":["../src/instrumentation/addon-interface.ts"],"sourcesContent":["/**\n * Native addon interface for extracting debug information from WebAssembly binaries\n *\n * This module wraps Binaryen's C++ API to provide expression-level debug locations\n * and basic block information that the JavaScript API doesn't expose.\n *\n * The native addon outputs raw data (0-based columns, relative paths) which this\n * wrapper transforms into the final BinaryDebugInfo format (1-based columns,\n * absolute paths, grouped by file and position).\n */\n\nimport { createRequire } from 'node:module';\nimport { resolve, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type {\n NativeAddon,\n NativeInstrumentationResult,\n NativeDebugInfoOutput,\n NativeFunctionDebugInfo,\n NativeExpressionDebugInfo,\n NativeSourceLocation,\n BinaryDebugInfo,\n FunctionDebugInfo,\n SourceLocation,\n ExpressionDebugInfo,\n InstrumentationResult,\n NativeInstrumentationOptions,\n InstrumentationOptions,\n InstrumentForCoverageFunc,\n} from '../types/types.js';\nimport { POOL_ERROR_NAMES, INTERNAL_PATH_LIB_PREFIX } from '../types/constants.js';\nimport { debug } from '../util/debug.js';\nimport { toForwardSlash } from '../util/path-utils.js';\nimport { createPoolError } from '../util/pool-errors.js';\nimport { getShortFunctionName } from '../wasm-executor/wasm-names.js';\n\n// Load the native addon via node-gyp-build\n// node-gyp-build checks: prebuilds/ first, then build/Release/\n// It searches from the given directory for a package.json to find the package root.\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst rootFromDist = resolve(__dirname, '..');\n// TODO: Verify if this src fallback is still needed — pool always runs from dist/ even locally.\n// If confirmed dead code, remove this and simplify to a single nodeGypBuild call.\nconst rootFromSrc = resolve(__dirname, '../..');\n\nconst require = createRequire(import.meta.url);\nconst nodeGypBuild: (dir: string) => NativeAddon = require('node-gyp-build');\n\nlet addon: NativeAddon;\ntry {\n addon = nodeGypBuild(rootFromDist);\n} catch {\n try {\n addon = nodeGypBuild(rootFromSrc);\n } catch (err) {\n throw createPoolError(\n `vitest-pool-assemblyscript native instrumentation addon not found. Searched from ${rootFromDist} and ${rootFromSrc}. `\n + `Ensure prebuilds are available or run 'node node_modules/vitest-pool-assemblyscript/scripts/install.js'`\n + ` to compile from source. Original error: ${err instanceof Error ? err.message : String(err)}`,\n POOL_ERROR_NAMES.WASMInstrumentationError\n );\n }\n}\n\n/**\n * Convert a raw location (0-indexed columns, path indexes) to\n * processed location (1-indexed columns, absolute path strings)\n *\n * Source map paths vary by import style and project structure:\n * - Relative imports: \"assembly/compare.ts\"\n * - Bare package imports: \"~lib/vitest-pool-assemblyscript/assembly/compare.ts\"\n * - Source outside project root: \"../assembly/compare.ts\" (e.g. test-external importing parent sources)\n *\n * All are normalized to absolute filesystem paths for consistent coverage key matching.\n */\nfunction convertLocation(\n rawLocation: NativeSourceLocation,\n debugSourceFiles: string[],\n projectRoot: string\n): SourceLocation {\n let filePath = debugSourceFiles[rawLocation.fileIndex];\n\n if (!filePath) {\n throw createPoolError(\n `No debug source file with index: ${rawLocation.fileIndex}}`,\n POOL_ERROR_NAMES.WASMInstrumentationError\n );\n }\n\n // Normalize to absolute path for consistent coverage key matching\n if (filePath.startsWith(INTERNAL_PATH_LIB_PREFIX)) {\n // ~lib/vitest-pool-assemblyscript/assembly/X.ts -> projectRoot/assembly/X.ts\n const relativePart = filePath.slice(INTERNAL_PATH_LIB_PREFIX.length);\n filePath = toForwardSlash(resolve(projectRoot, 'assembly', relativePart));\n } else {\n // Resolve relative path (handles both 'assembly/X.ts' and '../assembly/X.ts')\n filePath = toForwardSlash(resolve(projectRoot, filePath));\n }\n\n return {\n filePath,\n line: rawLocation.line,\n column: rawLocation.column + 1, // convert from 0-indexed to 1-indexed\n };\n}\n\n/**\n * Convert a raw expression to processed format\n */\nfunction convertExpression(\n rawExpr: NativeExpressionDebugInfo,\n debugSourceFiles: string[],\n projectRoot: string\n): ExpressionDebugInfo {\n const converted: ExpressionDebugInfo = {\n type: rawExpr.type,\n isBranch: rawExpr.isBranch,\n };\n\n if (rawExpr.branchPaths !== undefined) {\n converted.branchPaths = rawExpr.branchPaths;\n }\n\n if (rawExpr.location) {\n const convertedLocation = convertLocation(rawExpr.location, debugSourceFiles, projectRoot);\n if (convertedLocation) {\n converted.location = convertedLocation;\n }\n }\n\n return converted;\n}\n\n/**\n * Generate a position key to identify the SourceLocation uniquely\n * within a file. Does NOT include the file identifier.\n */\nfunction getPositionKey(location: SourceLocation) {\n return `${location.line}:${location.column}`;\n}\n\n/**\n * Convert a raw function to processed format and compute position key\n * Returns undefined if function has no valid representative location\n */\nfunction convertFunction(\n rawFunc: NativeFunctionDebugInfo,\n debugSourceFiles: string[],\n projectRoot: string\n): { func: FunctionDebugInfo; filePath: string; positionKey: string } | undefined {\n const representativeLocation = convertLocation(rawFunc.representativeLocation, debugSourceFiles, projectRoot);\n\n // Convert expressions\n const expressions: ExpressionDebugInfo[] = [];\n if (rawFunc.expressions) {\n for (const expr of rawFunc.expressions) {\n expressions.push(convertExpression(expr, debugSourceFiles, projectRoot));\n }\n }\n\n const converted: FunctionDebugInfo = {\n wasmIndex: rawFunc.wasmIndex,\n name: rawFunc.name,\n representativeLocation,\n coverageMemoryIndex: rawFunc.coverageMemoryIndex,\n expressions,\n basicBlocks: rawFunc.basicBlocks,\n };\n\n const filePath = representativeLocation.filePath;\n const positionKey = getPositionKey(representativeLocation);\n\n return { func: converted, filePath, positionKey };\n}\n\n/**\n * Check if two WASM function names are monomorphizations of the same generic function.\n * Generic monomorphizations share the same base name and suffix, differing only in\n * the type parameters inside angle brackets.\n *\n * e.g. \"assembly/compare/closeTo<bool\\2cbool>\" and \"assembly/compare/closeTo<bool\\2cu8>\"\n * e.g. \"assembly/expect/BaseExpectMatcher<bool>#constructor\" and \"assembly/expect/BaseExpectMatcher<i8>#constructor\"\n */\nfunction isGenericMonomorphizationMatch(nameA: string, nameB: string): boolean {\n const openA = nameA.indexOf('<');\n const openB = nameB.indexOf('<');\n\n // Both must contain generic type parameters\n if (openA === -1 || openB === -1) return false;\n\n const lastCloseA = nameA.lastIndexOf('>');\n const lastCloseB = nameB.lastIndexOf('>');\n\n if (lastCloseA === -1 || lastCloseB === -1) return false;\n\n // Prefix before '<' must match (includes module path, class, function name)\n const prefixA = nameA.substring(0, openA);\n const prefixB = nameB.substring(0, openB);\n if (prefixA !== prefixB) return false;\n\n // Suffix after last '>' must match (e.g. \"#constructor\", or empty)\n const suffixA = nameA.substring(lastCloseA + 1);\n const suffixB = nameB.substring(lastCloseB + 1);\n if (suffixA !== suffixB) return false;\n\n return true;\n}\n\n/**\n * Transform raw native addon output to processed BinaryDebugInfo\n */\nfunction transformDebugInfo(\n raw: NativeDebugInfoOutput,\n logPrefix: string,\n projectRoot: string,\n): BinaryDebugInfo {\n const functionsByFileAndPosition: Record<string, Record<string, FunctionDebugInfo[]>> = {};\n\n debug(`${logPrefix} - Converting ${raw.functions.length} functions`);\n\n let genericCollisionCount = 0;\n let skippedCount = 0;\n let instrumentedFunctionCount = 0;\n\n for (const rawFunc of raw.functions) {\n const result = convertFunction(rawFunc, raw.debugSourceFiles, projectRoot);\n if (!result) {\n debug(`${logPrefix} - WARNING: Skipped function (bad conversion): \"${rawFunc.name}\"`);\n skippedCount++;\n continue;\n }\n\n const { func, filePath, positionKey } = result;\n\n // Check for position collisions\n const existingAtPosition = functionsByFileAndPosition[filePath]?.[positionKey];\n if (existingAtPosition) {\n const existingName = existingAtPosition[0]!.name;\n\n // Only allow collision if both are monomorphizations of the same generic\n if (isGenericMonomorphizationMatch(existingName, func.name)) {\n existingAtPosition.push(func);\n genericCollisionCount++;\n instrumentedFunctionCount++;\n debug(\n `${logPrefix} - Generic monomorphization at ${filePath}:${positionKey}:`\n + ` \"${getShortFunctionName(func.name)}\" grouped with \"${getShortFunctionName(existingName)}\"`\n );\n continue;\n }\n\n throw createPoolError(\n `ERROR - Function Debug Position Collision at ${filePath}:${positionKey}: \"${getShortFunctionName(existingName)}\"`\n + ` will be replaced by \"${getShortFunctionName(func.name)}\". This is a bug. Please report it at:`\n + ` https://github.com/themattspiral/vitest-pool-assemblyscript/issues/new`,\n POOL_ERROR_NAMES.WASMInstrumentationError\n );\n }\n\n instrumentedFunctionCount++;\n\n // Group by file and position\n if (!functionsByFileAndPosition[filePath]) {\n functionsByFileAndPosition[filePath] = {};\n }\n\n functionsByFileAndPosition[filePath][positionKey] = [func];\n }\n\n debug(\n `${logPrefix} - BinaryDebugInfo transform complete: ${instrumentedFunctionCount} instrumented functions`\n + ` (${genericCollisionCount} generic collisions, ${skippedCount} skipped)`\n );\n\n return {\n debugSourceFiles: raw.debugSourceFiles,\n functionsByFileAndPosition,\n instrumentedFunctionCount,\n };\n}\n\n/**\n * Instrument a WASM binary for coverage collection and regenerate source map\n *\n * This function:\n * 1. Adds __coverage_memory import (multi-memory for coverage counters)\n * 2. Injects coverage counter increments at each function entry\n * 3. Regenerates source map with correct offsets after instrumentation\n * 4. Extracts debug info with coverageMemoryIndex assigned\n *\n * @param wasmBuffer - Buffer containing the clean WASM binary\n * @param sourceMapBuffer - Buffer containing the source map JSON\n * @returns Instrumented binary, regenerated source map, and debug info\n *\n * @throws {TypeError} If wasmBuffer or sourceMapBuffer are not Buffers\n * @throws {Error} If WASM binary or source map is invalid\n */\nexport const instrumentForCoverage: InstrumentForCoverageFunc = (\n wasmBuffer: Buffer,\n sourceMapBuffer: Buffer,\n instrumentationOptions: InstrumentationOptions,\n logModule: string,\n logLabel: string,\n): InstrumentationResult => {\n if (!Buffer.isBuffer(wasmBuffer)) {\n throw createPoolError(\n 'instrumentForCoverage - wasmBuffer must be a Buffer',\n POOL_ERROR_NAMES.WASMInstrumentationError\n );\n }\n if (!Buffer.isBuffer(sourceMapBuffer)) {\n throw createPoolError(\n 'instrumentForCoverage - sourceMapBuffer must be a Buffer',\n POOL_ERROR_NAMES.WASMInstrumentationError\n );\n }\n\n const interfaceLogPrefix = `[${logModule} Inst] ${logLabel}`;\n const nativeLogPrefix = `[${logModule} InstNative] ${logLabel}`;\n\n debug(`${interfaceLogPrefix} - Calling native instrumentForCoverage`);\n const startTime = performance.now();\n\n const options: NativeInstrumentationOptions = {\n coverageMemoryPagesMin: instrumentationOptions.coverageMemoryPagesMin,\n coverageMemoryPagesMax: instrumentationOptions.coverageMemoryPagesMax,\n excludedFiles: instrumentationOptions.relativeExcludedFiles,\n excludedLibraryFilePrefix: instrumentationOptions.excludedLibraryFilePrefix,\n excludedLibraryFileOverridePrefix: instrumentationOptions.excludedLibraryFileOverridePrefix,\n debug: instrumentationOptions.debug,\n logPrefix: nativeLogPrefix\n };\n const nativeResult: NativeInstrumentationResult = addon.instrumentForCoverage(wasmBuffer, sourceMapBuffer, options);\n const addonTime = performance.now();\n debug(`${interfaceLogPrefix} - TIMING Native addon: ${(addonTime - startTime).toFixed(2)} ms`);\n\n if (nativeResult.errors?.length) {\n throw createPoolError(\n `Errors encountered duriing native instrumentation: ${nativeResult.errors.join('\\n')}`,\n POOL_ERROR_NAMES.WASMInstrumentationError,\n );\n }\n\n const debugInfo = transformDebugInfo(nativeResult.debugInfo, interfaceLogPrefix, instrumentationOptions.projectRoot);\n \n const transformTime = performance.now();\n debug(`${interfaceLogPrefix} - TIMING DebugInfo Transform: ${(transformTime - addonTime).toFixed(2)} ms`);\n debug(`${interfaceLogPrefix} - Binary size: ${nativeResult.instrumentedWasm.length} bytes | Source map size: ${nativeResult.sourceMap.length * 2} bytes`);\n\n return {\n instrumentedWasm: nativeResult.instrumentedWasm,\n sourceMap: nativeResult.sourceMap,\n debugInfo,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ast-visitor-DJLJd5dt.mjs","names":[],"sources":["../src/util/ast-visitor.ts"],"sourcesContent":["/**\n * Base AST Visitor for AssemblyScript\n *\n * Provides reusable walking logic for traversing AS AST nodes.\n * Subclasses override hook methods to perform specific tasks.\n *\n * Used by:\n * - ast-parser.ts: Extract function metadata for coverage\n * - strip-inline.mts: Strip @inline decorators\n */\n\nimport {\n Node,\n Source,\n BlockStatement,\n FunctionDeclaration,\n MethodDeclaration,\n ClassDeclaration,\n NamespaceDeclaration,\n VariableStatement,\n VariableDeclaration,\n FunctionExpression,\n ExpressionStatement,\n BinaryExpression,\n PropertyAccessExpression,\n IfStatement,\n WhileStatement,\n DoStatement,\n ForStatement,\n ForOfStatement,\n SwitchStatement,\n SwitchCase,\n TryStatement,\n ThrowStatement,\n ReturnStatement,\n CallExpression,\n NewExpression,\n ParenthesizedExpression,\n TernaryExpression,\n CommaExpression,\n AssertionExpression,\n InstanceOfExpression,\n ElementAccessExpression,\n UnaryPostfixExpression,\n UnaryPrefixExpression,\n ClassExpression,\n ParameterNode,\n EnumDeclaration,\n EnumValueDeclaration,\n FieldDeclaration,\n InterfaceDeclaration,\n VoidStatement,\n} from 'assemblyscript';\n\nimport { ASNodeKind } from '../types/constants.js';\n\n/**\n * Abstract base class for AST visitors.\n *\n * Subclasses override hook methods to perform tasks during traversal:\n * - beforeVisit: Called before visiting each node (e.g., strip decorators)\n * - onFunctionDeclaration: Called when visiting a function declaration\n * - onMethodDeclaration: Called when visiting a method declaration\n * - onVariableDeclaration: Called when visiting a variable declaration\n * - onClassEnter/onClassExit: Called when entering/exiting a class\n */\nexport abstract class ASTVisitor {\n /**\n * Visit all statements in a source file\n */\n visitSource(source: Source): void {\n for (const stmt of source.statements) {\n this.visitNode(stmt);\n }\n }\n\n /**\n * Hook called before visiting each node.\n * Override to perform pre-visit tasks (e.g., stripping decorators).\n */\n protected beforeVisit(_node: Node): void {}\n\n /**\n * Hook called when entering a class declaration.\n * Override to track class context.\n */\n protected onClassEnter(_node: ClassDeclaration): void {}\n\n /**\n * Hook called when exiting a class declaration.\n * Override to restore class context.\n */\n protected onClassExit(_node: ClassDeclaration): void {}\n\n /**\n * Hook called when visiting a function declaration.\n * Override to extract function info or perform other tasks.\n * Return false to skip recursing into the function body.\n */\n protected onFunctionDeclaration(_node: FunctionDeclaration): boolean {\n return true; // Continue recursion by default\n }\n\n /**\n * Hook called when visiting a method declaration.\n * Override to extract method info or perform other tasks.\n * Return false to skip recursing into the method body.\n */\n protected onMethodDeclaration(_node: MethodDeclaration): boolean {\n return true; // Continue recursion by default\n }\n\n /**\n * Hook called when visiting a variable declaration.\n * Override to handle variable declarations (e.g., arrow functions).\n * Return false to skip recursing into the initializer.\n */\n protected onVariableDeclaration(_node: VariableDeclaration): boolean {\n return true; // Continue recursion by default\n }\n\n /**\n * Main visitor dispatch - routes to specific handler based on node kind\n */\n visitNode(node: Node): void {\n // Call pre-visit hook\n this.beforeVisit(node);\n\n // Recurse into children based on node kind\n switch (node.kind) {\n // Type nodes - no children to visit\n case ASNodeKind.NamedType:\n case ASNodeKind.FunctionType:\n case ASNodeKind.TypeName:\n case ASNodeKind.TypeParameter:\n break;\n\n // Parameter - may have default value\n case ASNodeKind.Parameter: {\n const param = node as ParameterNode;\n if (param.initializer) this.visitNode(param.initializer);\n break;\n }\n\n // Simple expressions - no children\n case ASNodeKind.Identifier:\n case ASNodeKind.False:\n case ASNodeKind.Literal:\n case ASNodeKind.Null:\n case ASNodeKind.Omitted:\n case ASNodeKind.Super:\n case ASNodeKind.This:\n case ASNodeKind.True:\n case ASNodeKind.Constructor:\n case ASNodeKind.Compiled:\n break;\n\n // Expressions with children\n case ASNodeKind.Assertion: {\n const expr = node as AssertionExpression;\n this.visitNode(expr.expression);\n break;\n }\n case ASNodeKind.Binary: {\n const expr = node as BinaryExpression;\n this.visitNode(expr.left);\n this.visitNode(expr.right);\n break;\n }\n case ASNodeKind.Call: {\n const expr = node as CallExpression;\n this.visitNode(expr.expression);\n for (const arg of expr.args) this.visitNode(arg);\n break;\n }\n case ASNodeKind.Class: {\n const expr = node as ClassExpression;\n this.visitNode(expr.declaration);\n break;\n }\n case ASNodeKind.Comma: {\n const expr = node as CommaExpression;\n for (const e of expr.expressions) this.visitNode(e);\n break;\n }\n case ASNodeKind.ElementAccess: {\n const expr = node as ElementAccessExpression;\n this.visitNode(expr.expression);\n this.visitNode(expr.elementExpression);\n break;\n }\n case ASNodeKind.Function: {\n const expr = node as FunctionExpression;\n this.visitNode(expr.declaration);\n break;\n }\n case ASNodeKind.InstanceOf: {\n const expr = node as InstanceOfExpression;\n this.visitNode(expr.expression);\n break;\n }\n case ASNodeKind.New: {\n const expr = node as NewExpression;\n for (const arg of expr.args) this.visitNode(arg);\n break;\n }\n case ASNodeKind.Parenthesized: {\n const expr = node as ParenthesizedExpression;\n this.visitNode(expr.expression);\n break;\n }\n case ASNodeKind.PropertyAccess: {\n const expr = node as PropertyAccessExpression;\n this.visitNode(expr.expression);\n break;\n }\n case ASNodeKind.Ternary: {\n const expr = node as TernaryExpression;\n this.visitNode(expr.condition);\n this.visitNode(expr.ifThen);\n this.visitNode(expr.ifElse);\n break;\n }\n case ASNodeKind.UnaryPostfix: {\n const expr = node as UnaryPostfixExpression;\n this.visitNode(expr.operand);\n break;\n }\n case ASNodeKind.UnaryPrefix: {\n const expr = node as UnaryPrefixExpression;\n this.visitNode(expr.operand);\n break;\n }\n\n // Statements with no interesting children\n case ASNodeKind.Break:\n case ASNodeKind.Continue:\n case ASNodeKind.Empty:\n case ASNodeKind.Export:\n case ASNodeKind.ExportDefault:\n case ASNodeKind.ExportImport:\n case ASNodeKind.Import:\n case ASNodeKind.Module:\n break;\n\n // Statements with children\n case ASNodeKind.Block: {\n const stmt = node as BlockStatement;\n for (const s of stmt.statements) this.visitNode(s);\n break;\n }\n case ASNodeKind.Do: {\n const stmt = node as DoStatement;\n this.visitNode(stmt.body);\n this.visitNode(stmt.condition);\n break;\n }\n case ASNodeKind.Expression: {\n const stmt = node as ExpressionStatement;\n this.visitNode(stmt.expression);\n break;\n }\n case ASNodeKind.For: {\n const stmt = node as ForStatement;\n if (stmt.initializer) this.visitNode(stmt.initializer);\n if (stmt.condition) this.visitNode(stmt.condition);\n if (stmt.incrementor) this.visitNode(stmt.incrementor);\n this.visitNode(stmt.body);\n break;\n }\n case ASNodeKind.ForOf: {\n const stmt = node as ForOfStatement;\n this.visitNode(stmt.variable);\n this.visitNode(stmt.iterable);\n this.visitNode(stmt.body);\n break;\n }\n case ASNodeKind.If: {\n const stmt = node as IfStatement;\n this.visitNode(stmt.condition);\n this.visitNode(stmt.ifTrue);\n if (stmt.ifFalse) this.visitNode(stmt.ifFalse);\n break;\n }\n case ASNodeKind.Return: {\n const stmt = node as ReturnStatement;\n if (stmt.value) this.visitNode(stmt.value);\n break;\n }\n case ASNodeKind.Switch: {\n const stmt = node as SwitchStatement;\n this.visitNode(stmt.condition);\n for (const switchCase of stmt.cases) this.visitNode(switchCase);\n break;\n }\n case ASNodeKind.Throw: {\n const stmt = node as ThrowStatement;\n this.visitNode(stmt.value);\n break;\n }\n case ASNodeKind.Try: {\n const stmt = node as TryStatement;\n for (const s of stmt.bodyStatements) this.visitNode(s);\n if (stmt.catchStatements) {\n for (const s of stmt.catchStatements) this.visitNode(s);\n }\n if (stmt.finallyStatements) {\n for (const s of stmt.finallyStatements) this.visitNode(s);\n }\n break;\n }\n case ASNodeKind.Variable: {\n const stmt = node as VariableStatement;\n for (const decl of stmt.declarations) this.visitNode(decl);\n break;\n }\n case ASNodeKind.Void: {\n const stmt = node as VoidStatement;\n this.visitNode(stmt.expression);\n break;\n }\n case ASNodeKind.While: {\n const stmt = node as WhileStatement;\n this.visitNode(stmt.condition);\n this.visitNode(stmt.body);\n break;\n }\n case ASNodeKind.SwitchCase: {\n const stmt = node as SwitchCase;\n if (stmt.label) this.visitNode(stmt.label);\n for (const s of stmt.statements) this.visitNode(s);\n break;\n }\n\n // Declaration statements\n case ASNodeKind.ImportDeclaration:\n case ASNodeKind.TypeDeclaration:\n break;\n\n case ASNodeKind.ClassDeclaration: {\n const decl = node as ClassDeclaration;\n this.onClassEnter(decl);\n for (const member of decl.members) this.visitNode(member);\n this.onClassExit(decl);\n break;\n }\n case ASNodeKind.EnumDeclaration: {\n const decl = node as EnumDeclaration;\n for (const value of decl.values) this.visitNode(value);\n break;\n }\n case ASNodeKind.EnumValueDeclaration: {\n const decl = node as EnumValueDeclaration;\n if (decl.initializer) this.visitNode(decl.initializer);\n break;\n }\n case ASNodeKind.FieldDeclaration: {\n const decl = node as FieldDeclaration;\n if (decl.initializer) this.visitNode(decl.initializer);\n break;\n }\n case ASNodeKind.FunctionDeclaration: {\n const decl = node as FunctionDeclaration;\n const shouldRecurse = this.onFunctionDeclaration(decl);\n if (shouldRecurse && decl.body) this.visitNode(decl.body);\n break;\n }\n case ASNodeKind.InterfaceDeclaration: {\n const decl = node as InterfaceDeclaration;\n for (const member of decl.members) this.visitNode(member);\n break;\n }\n case ASNodeKind.MethodDeclaration: {\n const decl = node as MethodDeclaration;\n const shouldRecurse = this.onMethodDeclaration(decl);\n if (shouldRecurse && decl.body) this.visitNode(decl.body);\n break;\n }\n case ASNodeKind.NamespaceDeclaration: {\n const decl = node as NamespaceDeclaration;\n for (const member of decl.members) this.visitNode(member);\n break;\n }\n case ASNodeKind.VariableDeclaration: {\n const decl = node as VariableDeclaration;\n const shouldRecurse = this.onVariableDeclaration(decl);\n if (shouldRecurse && decl.initializer) this.visitNode(decl.initializer);\n break;\n }\n\n // Special nodes - no action needed\n case ASNodeKind.ExportMember:\n case ASNodeKind.IndexSignature:\n case ASNodeKind.Comment:\n case ASNodeKind.Decorator:\n break;\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ast-visitor-C5gQqWD2.mjs","names":[],"sources":["../src/util/ast-visitor.ts"],"sourcesContent":["/**\n * Base AST Visitor for AssemblyScript\n *\n * Provides reusable walking logic for traversing AS AST nodes.\n * Subclasses override hook methods to perform specific tasks.\n *\n * Used by:\n * - ast-parser.ts: Extract function metadata for coverage\n * - strip-inline.mts: Strip @inline decorators\n */\n\nimport {\n Node,\n Source,\n BlockStatement,\n FunctionDeclaration,\n MethodDeclaration,\n ClassDeclaration,\n NamespaceDeclaration,\n VariableStatement,\n VariableDeclaration,\n FunctionExpression,\n ExpressionStatement,\n BinaryExpression,\n PropertyAccessExpression,\n IfStatement,\n WhileStatement,\n DoStatement,\n ForStatement,\n ForOfStatement,\n SwitchStatement,\n SwitchCase,\n TryStatement,\n ThrowStatement,\n ReturnStatement,\n CallExpression,\n NewExpression,\n ParenthesizedExpression,\n TernaryExpression,\n CommaExpression,\n AssertionExpression,\n InstanceOfExpression,\n ElementAccessExpression,\n UnaryPostfixExpression,\n UnaryPrefixExpression,\n ClassExpression,\n ParameterNode,\n EnumDeclaration,\n EnumValueDeclaration,\n FieldDeclaration,\n InterfaceDeclaration,\n VoidStatement,\n} from 'assemblyscript';\n\nimport { ASNodeKind } from '../types/constants.js';\n\n/**\n * Abstract base class for AST visitors.\n *\n * Subclasses override hook methods to perform tasks during traversal:\n * - beforeVisit: Called before visiting each node (e.g., strip decorators)\n * - onFunctionDeclaration: Called when visiting a function declaration\n * - onMethodDeclaration: Called when visiting a method declaration\n * - onVariableDeclaration: Called when visiting a variable declaration\n * - onClassEnter/onClassExit: Called when entering/exiting a class\n */\nexport abstract class ASTVisitor {\n /**\n * Visit all statements in a source file\n */\n visitSource(source: Source): void {\n for (const stmt of source.statements) {\n this.visitNode(stmt);\n }\n }\n\n /**\n * Hook called before visiting each node.\n * Override to perform pre-visit tasks (e.g., stripping decorators).\n */\n protected beforeVisit(_node: Node): void {}\n\n /**\n * Hook called when entering a class declaration.\n * Override to track class context.\n */\n protected onClassEnter(_node: ClassDeclaration): void {}\n\n /**\n * Hook called when exiting a class declaration.\n * Override to restore class context.\n */\n protected onClassExit(_node: ClassDeclaration): void {}\n\n /**\n * Hook called when visiting a function declaration.\n * Override to extract function info or perform other tasks.\n * Return false to skip recursing into the function body.\n */\n protected onFunctionDeclaration(_node: FunctionDeclaration): boolean {\n return true; // Continue recursion by default\n }\n\n /**\n * Hook called when visiting a method declaration.\n * Override to extract method info or perform other tasks.\n * Return false to skip recursing into the method body.\n */\n protected onMethodDeclaration(_node: MethodDeclaration): boolean {\n return true; // Continue recursion by default\n }\n\n /**\n * Hook called when visiting a variable declaration.\n * Override to handle variable declarations (e.g., arrow functions).\n * Return false to skip recursing into the initializer.\n */\n protected onVariableDeclaration(_node: VariableDeclaration): boolean {\n return true; // Continue recursion by default\n }\n\n /**\n * Main visitor dispatch - routes to specific handler based on node kind\n */\n visitNode(node: Node): void {\n // Call pre-visit hook\n this.beforeVisit(node);\n\n // Recurse into children based on node kind\n switch (node.kind) {\n // Type nodes - no children to visit\n case ASNodeKind.NamedType:\n case ASNodeKind.FunctionType:\n case ASNodeKind.TypeName:\n case ASNodeKind.TypeParameter:\n break;\n\n // Parameter - may have default value\n case ASNodeKind.Parameter: {\n const param = node as ParameterNode;\n if (param.initializer) this.visitNode(param.initializer);\n break;\n }\n\n // Simple expressions - no children\n case ASNodeKind.Identifier:\n case ASNodeKind.False:\n case ASNodeKind.Literal:\n case ASNodeKind.Null:\n case ASNodeKind.Omitted:\n case ASNodeKind.Super:\n case ASNodeKind.This:\n case ASNodeKind.True:\n case ASNodeKind.Constructor:\n case ASNodeKind.Compiled:\n break;\n\n // Expressions with children\n case ASNodeKind.Assertion: {\n const expr = node as AssertionExpression;\n this.visitNode(expr.expression);\n break;\n }\n case ASNodeKind.Binary: {\n const expr = node as BinaryExpression;\n this.visitNode(expr.left);\n this.visitNode(expr.right);\n break;\n }\n case ASNodeKind.Call: {\n const expr = node as CallExpression;\n this.visitNode(expr.expression);\n for (const arg of expr.args) this.visitNode(arg);\n break;\n }\n case ASNodeKind.Class: {\n const expr = node as ClassExpression;\n this.visitNode(expr.declaration);\n break;\n }\n case ASNodeKind.Comma: {\n const expr = node as CommaExpression;\n for (const e of expr.expressions) this.visitNode(e);\n break;\n }\n case ASNodeKind.ElementAccess: {\n const expr = node as ElementAccessExpression;\n this.visitNode(expr.expression);\n this.visitNode(expr.elementExpression);\n break;\n }\n case ASNodeKind.Function: {\n const expr = node as FunctionExpression;\n this.visitNode(expr.declaration);\n break;\n }\n case ASNodeKind.InstanceOf: {\n const expr = node as InstanceOfExpression;\n this.visitNode(expr.expression);\n break;\n }\n case ASNodeKind.New: {\n const expr = node as NewExpression;\n for (const arg of expr.args) this.visitNode(arg);\n break;\n }\n case ASNodeKind.Parenthesized: {\n const expr = node as ParenthesizedExpression;\n this.visitNode(expr.expression);\n break;\n }\n case ASNodeKind.PropertyAccess: {\n const expr = node as PropertyAccessExpression;\n this.visitNode(expr.expression);\n break;\n }\n case ASNodeKind.Ternary: {\n const expr = node as TernaryExpression;\n this.visitNode(expr.condition);\n this.visitNode(expr.ifThen);\n this.visitNode(expr.ifElse);\n break;\n }\n case ASNodeKind.UnaryPostfix: {\n const expr = node as UnaryPostfixExpression;\n this.visitNode(expr.operand);\n break;\n }\n case ASNodeKind.UnaryPrefix: {\n const expr = node as UnaryPrefixExpression;\n this.visitNode(expr.operand);\n break;\n }\n\n // Statements with no interesting children\n case ASNodeKind.Break:\n case ASNodeKind.Continue:\n case ASNodeKind.Empty:\n case ASNodeKind.Export:\n case ASNodeKind.ExportDefault:\n case ASNodeKind.ExportImport:\n case ASNodeKind.Import:\n case ASNodeKind.Module:\n break;\n\n // Statements with children\n case ASNodeKind.Block: {\n const stmt = node as BlockStatement;\n for (const s of stmt.statements) this.visitNode(s);\n break;\n }\n case ASNodeKind.Do: {\n const stmt = node as DoStatement;\n this.visitNode(stmt.body);\n this.visitNode(stmt.condition);\n break;\n }\n case ASNodeKind.Expression: {\n const stmt = node as ExpressionStatement;\n this.visitNode(stmt.expression);\n break;\n }\n case ASNodeKind.For: {\n const stmt = node as ForStatement;\n if (stmt.initializer) this.visitNode(stmt.initializer);\n if (stmt.condition) this.visitNode(stmt.condition);\n if (stmt.incrementor) this.visitNode(stmt.incrementor);\n this.visitNode(stmt.body);\n break;\n }\n case ASNodeKind.ForOf: {\n const stmt = node as ForOfStatement;\n this.visitNode(stmt.variable);\n this.visitNode(stmt.iterable);\n this.visitNode(stmt.body);\n break;\n }\n case ASNodeKind.If: {\n const stmt = node as IfStatement;\n this.visitNode(stmt.condition);\n this.visitNode(stmt.ifTrue);\n if (stmt.ifFalse) this.visitNode(stmt.ifFalse);\n break;\n }\n case ASNodeKind.Return: {\n const stmt = node as ReturnStatement;\n if (stmt.value) this.visitNode(stmt.value);\n break;\n }\n case ASNodeKind.Switch: {\n const stmt = node as SwitchStatement;\n this.visitNode(stmt.condition);\n for (const switchCase of stmt.cases) this.visitNode(switchCase);\n break;\n }\n case ASNodeKind.Throw: {\n const stmt = node as ThrowStatement;\n this.visitNode(stmt.value);\n break;\n }\n case ASNodeKind.Try: {\n const stmt = node as TryStatement;\n for (const s of stmt.bodyStatements) this.visitNode(s);\n if (stmt.catchStatements) {\n for (const s of stmt.catchStatements) this.visitNode(s);\n }\n if (stmt.finallyStatements) {\n for (const s of stmt.finallyStatements) this.visitNode(s);\n }\n break;\n }\n case ASNodeKind.Variable: {\n const stmt = node as VariableStatement;\n for (const decl of stmt.declarations) this.visitNode(decl);\n break;\n }\n case ASNodeKind.Void: {\n const stmt = node as VoidStatement;\n this.visitNode(stmt.expression);\n break;\n }\n case ASNodeKind.While: {\n const stmt = node as WhileStatement;\n this.visitNode(stmt.condition);\n this.visitNode(stmt.body);\n break;\n }\n case ASNodeKind.SwitchCase: {\n const stmt = node as SwitchCase;\n if (stmt.label) this.visitNode(stmt.label);\n for (const s of stmt.statements) this.visitNode(s);\n break;\n }\n\n // Declaration statements\n case ASNodeKind.ImportDeclaration:\n case ASNodeKind.TypeDeclaration:\n break;\n\n case ASNodeKind.ClassDeclaration: {\n const decl = node as ClassDeclaration;\n this.onClassEnter(decl);\n for (const member of decl.members) this.visitNode(member);\n this.onClassExit(decl);\n break;\n }\n case ASNodeKind.EnumDeclaration: {\n const decl = node as EnumDeclaration;\n for (const value of decl.values) this.visitNode(value);\n break;\n }\n case ASNodeKind.EnumValueDeclaration: {\n const decl = node as EnumValueDeclaration;\n if (decl.initializer) this.visitNode(decl.initializer);\n break;\n }\n case ASNodeKind.FieldDeclaration: {\n const decl = node as FieldDeclaration;\n if (decl.initializer) this.visitNode(decl.initializer);\n break;\n }\n case ASNodeKind.FunctionDeclaration: {\n const decl = node as FunctionDeclaration;\n const shouldRecurse = this.onFunctionDeclaration(decl);\n if (shouldRecurse && decl.body) this.visitNode(decl.body);\n break;\n }\n case ASNodeKind.InterfaceDeclaration: {\n const decl = node as InterfaceDeclaration;\n for (const member of decl.members) this.visitNode(member);\n break;\n }\n case ASNodeKind.MethodDeclaration: {\n const decl = node as MethodDeclaration;\n const shouldRecurse = this.onMethodDeclaration(decl);\n if (shouldRecurse && decl.body) this.visitNode(decl.body);\n break;\n }\n case ASNodeKind.NamespaceDeclaration: {\n const decl = node as NamespaceDeclaration;\n for (const member of decl.members) this.visitNode(member);\n break;\n }\n case ASNodeKind.VariableDeclaration: {\n const decl = node as VariableDeclaration;\n const shouldRecurse = this.onVariableDeclaration(decl);\n if (shouldRecurse && decl.initializer) this.visitNode(decl.initializer);\n break;\n }\n\n // Special nodes - no action needed\n case ASNodeKind.ExportMember:\n case ASNodeKind.IndexSignature:\n case ASNodeKind.Comment:\n case ASNodeKind.Decorator:\n break;\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAkEA,IAAsB,aAAtB,MAAiC;;;;CAI/B,YAAY,QAAsB;AAChC,OAAK,MAAM,QAAQ,OAAO,WACxB,MAAK,UAAU,KAAK;;;;;;CAQxB,AAAU,YAAY,OAAmB;;;;;CAMzC,AAAU,aAAa,OAA+B;;;;;CAMtD,AAAU,YAAY,OAA+B;;;;;;CAOrD,AAAU,sBAAsB,OAAqC;AACnE,SAAO;;;;;;;CAQT,AAAU,oBAAoB,OAAmC;AAC/D,SAAO;;;;;;;CAQT,AAAU,sBAAsB,OAAqC;AACnE,SAAO;;;;;CAMT,UAAU,MAAkB;AAE1B,OAAK,YAAY,KAAK;AAGtB,UAAQ,KAAK,MAAb;GAEE,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,WAAW,cACd;GAGF,KAAK,WAAW,WAAW;IACzB,MAAM,QAAQ;AACd,QAAI,MAAM,YAAa,MAAK,UAAU,MAAM,YAAY;AACxD;;GAIF,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,WAAW,SACd;GAGF,KAAK,WAAW,WAAW;IACzB,MAAM,OAAO;AACb,SAAK,UAAU,KAAK,WAAW;AAC/B;;GAEF,KAAK,WAAW,QAAQ;IACtB,MAAM,OAAO;AACb,SAAK,UAAU,KAAK,KAAK;AACzB,SAAK,UAAU,KAAK,MAAM;AAC1B;;GAEF,KAAK,WAAW,MAAM;IACpB,MAAM,OAAO;AACb,SAAK,UAAU,KAAK,WAAW;AAC/B,SAAK,MAAM,OAAO,KAAK,KAAM,MAAK,UAAU,IAAI;AAChD;;GAEF,KAAK,WAAW,OAAO;IACrB,MAAM,OAAO;AACb,SAAK,UAAU,KAAK,YAAY;AAChC;;GAEF,KAAK,WAAW,OAAO;IACrB,MAAM,OAAO;AACb,SAAK,MAAM,KAAK,KAAK,YAAa,MAAK,UAAU,EAAE;AACnD;;GAEF,KAAK,WAAW,eAAe;IAC7B,MAAM,OAAO;AACb,SAAK,UAAU,KAAK,WAAW;AAC/B,SAAK,UAAU,KAAK,kBAAkB;AACtC;;GAEF,KAAK,WAAW,UAAU;IACxB,MAAM,OAAO;AACb,SAAK,UAAU,KAAK,YAAY;AAChC;;GAEF,KAAK,WAAW,YAAY;IAC1B,MAAM,OAAO;AACb,SAAK,UAAU,KAAK,WAAW;AAC/B;;GAEF,KAAK,WAAW,KAAK;IACnB,MAAM,OAAO;AACb,SAAK,MAAM,OAAO,KAAK,KAAM,MAAK,UAAU,IAAI;AAChD;;GAEF,KAAK,WAAW,eAAe;IAC7B,MAAM,OAAO;AACb,SAAK,UAAU,KAAK,WAAW;AAC/B;;GAEF,KAAK,WAAW,gBAAgB;IAC9B,MAAM,OAAO;AACb,SAAK,UAAU,KAAK,WAAW;AAC/B;;GAEF,KAAK,WAAW,SAAS;IACvB,MAAM,OAAO;AACb,SAAK,UAAU,KAAK,UAAU;AAC9B,SAAK,UAAU,KAAK,OAAO;AAC3B,SAAK,UAAU,KAAK,OAAO;AAC3B;;GAEF,KAAK,WAAW,cAAc;IAC5B,MAAM,OAAO;AACb,SAAK,UAAU,KAAK,QAAQ;AAC5B;;GAEF,KAAK,WAAW,aAAa;IAC3B,MAAM,OAAO;AACb,SAAK,UAAU,KAAK,QAAQ;AAC5B;;GAIF,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,WAAW,OACd;GAGF,KAAK,WAAW,OAAO;IACrB,MAAM,OAAO;AACb,SAAK,MAAM,KAAK,KAAK,WAAY,MAAK,UAAU,EAAE;AAClD;;GAEF,KAAK,WAAW,IAAI;IAClB,MAAM,OAAO;AACb,SAAK,UAAU,KAAK,KAAK;AACzB,SAAK,UAAU,KAAK,UAAU;AAC9B;;GAEF,KAAK,WAAW,YAAY;IAC1B,MAAM,OAAO;AACb,SAAK,UAAU,KAAK,WAAW;AAC/B;;GAEF,KAAK,WAAW,KAAK;IACnB,MAAM,OAAO;AACb,QAAI,KAAK,YAAa,MAAK,UAAU,KAAK,YAAY;AACtD,QAAI,KAAK,UAAW,MAAK,UAAU,KAAK,UAAU;AAClD,QAAI,KAAK,YAAa,MAAK,UAAU,KAAK,YAAY;AACtD,SAAK,UAAU,KAAK,KAAK;AACzB;;GAEF,KAAK,WAAW,OAAO;IACrB,MAAM,OAAO;AACb,SAAK,UAAU,KAAK,SAAS;AAC7B,SAAK,UAAU,KAAK,SAAS;AAC7B,SAAK,UAAU,KAAK,KAAK;AACzB;;GAEF,KAAK,WAAW,IAAI;IAClB,MAAM,OAAO;AACb,SAAK,UAAU,KAAK,UAAU;AAC9B,SAAK,UAAU,KAAK,OAAO;AAC3B,QAAI,KAAK,QAAS,MAAK,UAAU,KAAK,QAAQ;AAC9C;;GAEF,KAAK,WAAW,QAAQ;IACtB,MAAM,OAAO;AACb,QAAI,KAAK,MAAO,MAAK,UAAU,KAAK,MAAM;AAC1C;;GAEF,KAAK,WAAW,QAAQ;IACtB,MAAM,OAAO;AACb,SAAK,UAAU,KAAK,UAAU;AAC9B,SAAK,MAAM,cAAc,KAAK,MAAO,MAAK,UAAU,WAAW;AAC/D;;GAEF,KAAK,WAAW,OAAO;IACrB,MAAM,OAAO;AACb,SAAK,UAAU,KAAK,MAAM;AAC1B;;GAEF,KAAK,WAAW,KAAK;IACnB,MAAM,OAAO;AACb,SAAK,MAAM,KAAK,KAAK,eAAgB,MAAK,UAAU,EAAE;AACtD,QAAI,KAAK,gBACP,MAAK,MAAM,KAAK,KAAK,gBAAiB,MAAK,UAAU,EAAE;AAEzD,QAAI,KAAK,kBACP,MAAK,MAAM,KAAK,KAAK,kBAAmB,MAAK,UAAU,EAAE;AAE3D;;GAEF,KAAK,WAAW,UAAU;IACxB,MAAM,OAAO;AACb,SAAK,MAAM,QAAQ,KAAK,aAAc,MAAK,UAAU,KAAK;AAC1D;;GAEF,KAAK,WAAW,MAAM;IACpB,MAAM,OAAO;AACb,SAAK,UAAU,KAAK,WAAW;AAC/B;;GAEF,KAAK,WAAW,OAAO;IACrB,MAAM,OAAO;AACb,SAAK,UAAU,KAAK,UAAU;AAC9B,SAAK,UAAU,KAAK,KAAK;AACzB;;GAEF,KAAK,WAAW,YAAY;IAC1B,MAAM,OAAO;AACb,QAAI,KAAK,MAAO,MAAK,UAAU,KAAK,MAAM;AAC1C,SAAK,MAAM,KAAK,KAAK,WAAY,MAAK,UAAU,EAAE;AAClD;;GAIF,KAAK,WAAW;GAChB,KAAK,WAAW,gBACd;GAEF,KAAK,WAAW,kBAAkB;IAChC,MAAM,OAAO;AACb,SAAK,aAAa,KAAK;AACvB,SAAK,MAAM,UAAU,KAAK,QAAS,MAAK,UAAU,OAAO;AACzD,SAAK,YAAY,KAAK;AACtB;;GAEF,KAAK,WAAW,iBAAiB;IAC/B,MAAM,OAAO;AACb,SAAK,MAAM,SAAS,KAAK,OAAQ,MAAK,UAAU,MAAM;AACtD;;GAEF,KAAK,WAAW,sBAAsB;IACpC,MAAM,OAAO;AACb,QAAI,KAAK,YAAa,MAAK,UAAU,KAAK,YAAY;AACtD;;GAEF,KAAK,WAAW,kBAAkB;IAChC,MAAM,OAAO;AACb,QAAI,KAAK,YAAa,MAAK,UAAU,KAAK,YAAY;AACtD;;GAEF,KAAK,WAAW,qBAAqB;IACnC,MAAM,OAAO;AAEb,QADsB,KAAK,sBAAsB,KAAK,IACjC,KAAK,KAAM,MAAK,UAAU,KAAK,KAAK;AACzD;;GAEF,KAAK,WAAW,sBAAsB;IACpC,MAAM,OAAO;AACb,SAAK,MAAM,UAAU,KAAK,QAAS,MAAK,UAAU,OAAO;AACzD;;GAEF,KAAK,WAAW,mBAAmB;IACjC,MAAM,OAAO;AAEb,QADsB,KAAK,oBAAoB,KAAK,IAC/B,KAAK,KAAM,MAAK,UAAU,KAAK,KAAK;AACzD;;GAEF,KAAK,WAAW,sBAAsB;IACpC,MAAM,OAAO;AACb,SAAK,MAAM,UAAU,KAAK,QAAS,MAAK,UAAU,OAAO;AACzD;;GAEF,KAAK,WAAW,qBAAqB;IACnC,MAAM,OAAO;AAEb,QADsB,KAAK,sBAAsB,KAAK,IACjC,KAAK,YAAa,MAAK,UAAU,KAAK,YAAY;AACvE;;GAIF,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,WAAW,UACd"}
|