vitest-pool-assemblyscript 0.8.0 → 0.9.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 +10 -13
- package/assembly/compare.ts +453 -95
- package/assembly/expect.ts +113 -62
- package/assembly/index.ts +0 -10
- package/assembly/utils.ts +168 -0
- package/dist/{addon-interface-_pNXcbib.mjs → addon-interface-CYFXMbK7.mjs} +4 -3
- package/dist/addon-interface-CYFXMbK7.mjs.map +1 -0
- package/dist/{ast-visitor-C5gQqWD2.mjs → ast-visitor-CWEOd3UH.mjs} +15 -2
- package/dist/ast-visitor-CWEOd3UH.mjs.map +1 -0
- package/dist/{compile-runner-DOMhsLQE.mjs → compile-runner-BGQhBkBo.mjs} +8 -7
- package/dist/compile-runner-BGQhBkBo.mjs.map +1 -0
- package/dist/compiler/transforms/deep-equals.d.mts +14 -0
- package/dist/compiler/transforms/deep-equals.d.mts.map +1 -0
- package/dist/compiler/transforms/deep-equals.mjs +245 -0
- package/dist/compiler/transforms/deep-equals.mjs.map +1 -0
- package/dist/compiler/transforms/strip-inline.mjs +2 -2
- package/dist/{compiler-CIXpfKq0.mjs → compiler-hUlDr5vL.mjs} +14 -6
- package/dist/compiler-hUlDr5vL.mjs.map +1 -0
- package/dist/config/index-v3.d.mts +33 -3
- package/dist/config/index-v3.d.mts.map +1 -1
- package/dist/config/index-v3.mjs.map +1 -1
- package/dist/config/index.d.mts +29 -4
- package/dist/config/index.d.mts.map +1 -0
- package/dist/config/index.mjs +6 -6
- package/dist/{constants-DuBLuMjt.mjs → constants-DbxJ3hzg.mjs} +10 -97
- package/dist/constants-DbxJ3hzg.mjs.map +1 -0
- package/dist/coverage-provider/index.mjs +30 -10
- package/dist/coverage-provider/index.mjs.map +1 -1
- package/dist/{debug-Cm1VFmaz.mjs → debug-DtRAL4rM.mjs} +38 -4
- package/dist/debug-DtRAL4rM.mjs.map +1 -0
- package/dist/{feature-check-ELxw_Mji.mjs → feature-check-Bje3ntpV.mjs} +2 -2
- package/dist/{feature-check-ELxw_Mji.mjs.map → feature-check-Bje3ntpV.mjs.map} +1 -1
- package/dist/index-internal.d.mts +1 -1
- package/dist/index-internal.d.mts.map +1 -1
- package/dist/index-internal.mjs +4 -4
- package/dist/index-v3.d.mts.map +1 -1
- package/dist/index-v3.mjs +8 -7
- package/dist/index-v3.mjs.map +1 -1
- package/dist/index.d.mts +1 -2
- package/dist/index.mjs +6 -6
- package/dist/{load-user-imports-B3Iy_K8k.mjs → load-user-imports-Bx5ZlhSm.mjs} +9 -9
- package/dist/load-user-imports-Bx5ZlhSm.mjs.map +1 -0
- package/dist/{pool-runner-init-BDQtAGwQ.mjs → pool-runner-init-BqkwQ2tk.mjs} +7 -7
- package/dist/pool-runner-init-BqkwQ2tk.mjs.map +1 -0
- package/dist/{pool-runner-init-CvnB0-iN.d.mts → pool-runner-init-CNpRdA5u.d.mts} +2 -2
- package/dist/pool-runner-init-CNpRdA5u.d.mts.map +1 -0
- package/dist/pool-thread/compile-worker-thread.d.mts +1 -1
- package/dist/pool-thread/compile-worker-thread.d.mts.map +1 -1
- package/dist/pool-thread/compile-worker-thread.mjs +10 -13
- 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.d.mts.map +1 -1
- package/dist/pool-thread/test-worker-thread.mjs +8 -11
- 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.d.mts.map +1 -1
- package/dist/pool-thread/v3-tinypool-thread.mjs +12 -18
- package/dist/pool-thread/v3-tinypool-thread.mjs.map +1 -1
- package/dist/{resolve-config-DhZ4lOSK.mjs → resolve-config-s9gSJSMc.mjs} +14 -5
- package/dist/resolve-config-s9gSJSMc.mjs.map +1 -0
- package/dist/{test-runner-C4I9VknR.mjs → test-runner-BGqc9uCK.mjs} +4 -4
- package/dist/{test-runner-C4I9VknR.mjs.map → test-runner-BGqc9uCK.mjs.map} +1 -1
- package/dist/{types-D0nprJo1.d.mts → types-DHVk5iAx.d.mts} +17 -11
- package/dist/types-DHVk5iAx.d.mts.map +1 -0
- package/dist/vitest-file-tasks-D8sOClGX.mjs +149 -0
- package/dist/vitest-file-tasks-D8sOClGX.mjs.map +1 -0
- package/dist/{vitest-tasks--ow4pacR.mjs → vitest-tasks-BZ24sghI.mjs} +6 -4
- package/dist/vitest-tasks-BZ24sghI.mjs.map +1 -0
- package/package.json +11 -14
- 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/src/instrumentation/native/addon.cpp +29 -3
- package/dist/addon-interface-_pNXcbib.mjs.map +0 -1
- package/dist/ast-visitor-C5gQqWD2.mjs.map +0 -1
- package/dist/compile-runner-DOMhsLQE.mjs.map +0 -1
- package/dist/compiler-CIXpfKq0.mjs.map +0 -1
- package/dist/constants-DuBLuMjt.mjs.map +0 -1
- package/dist/custom-provider-options-YTk1m7At.d.mts +0 -26
- package/dist/custom-provider-options-YTk1m7At.d.mts.map +0 -1
- package/dist/debug-Cm1VFmaz.mjs.map +0 -1
- package/dist/load-user-imports-B3Iy_K8k.mjs.map +0 -1
- package/dist/pool-runner-init-BDQtAGwQ.mjs.map +0 -1
- package/dist/pool-runner-init-CvnB0-iN.d.mts.map +0 -1
- package/dist/resolve-config-DhZ4lOSK.mjs.map +0 -1
- package/dist/types-D0nprJo1.d.mts.map +0 -1
- package/dist/vitest-file-tasks-Bn9CrWt_.mjs +0 -61
- package/dist/vitest-file-tasks-Bn9CrWt_.mjs.map +0 -1
- package/dist/vitest-tasks--ow4pacR.mjs.map +0 -1
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { ASCommonFlags, ASDecoratorKind, ASNodeKind, ASSourceKind, INTERNAL_PATH_LIB_PREFIX } from "../../constants-DbxJ3hzg.mjs";
|
|
2
|
+
import { ASTVisitor } from "../../ast-visitor-CWEOd3UH.mjs";
|
|
3
|
+
import { Source, Tokenizer } from "assemblyscript";
|
|
4
|
+
import { Transform } from "assemblyscript/transform";
|
|
5
|
+
|
|
6
|
+
//#region src/compiler/transforms/deep-equals.mts
|
|
7
|
+
/**
|
|
8
|
+
* AssemblyScript Compiler Transform: Deep Equality & Stringification for User-Defined Objects
|
|
9
|
+
*
|
|
10
|
+
* Injects three methods into user-defined classes at `afterParse`:
|
|
11
|
+
*
|
|
12
|
+
* 1. `__vitest_assemblyscript_deep_equals` — deep equality comparison for `toEqual()`
|
|
13
|
+
* - If the class defines `@operator("==")`: delegates to `this == other`
|
|
14
|
+
* - If the class defines `.equals()`: delegates to `this.equals(other)`
|
|
15
|
+
* - Otherwise: compares all stored instance fields via the pool's `equals()` function
|
|
16
|
+
*
|
|
17
|
+
* 2. `__vitest_assemblyscript_typename` — returns the runtime class name via `nameof<ClassName>()`
|
|
18
|
+
* - Virtual dispatch ensures correct runtime name even for base-typed variables
|
|
19
|
+
* - Used by stringifyValue() for user-facing output and by RTM type name tracking
|
|
20
|
+
*
|
|
21
|
+
* 3. `__vitest_assemblyscript_stringify` — returns comma-separated field entries for stringification
|
|
22
|
+
* - Always stringifies all stored instance fields regardless of operator==/equals()
|
|
23
|
+
* - Follows super chain via isDefined guard, same pattern as deep equality
|
|
24
|
+
* - Uses @global bridge __vitest_assemblyscript_stringify_value to call stringifyValue()
|
|
25
|
+
*
|
|
26
|
+
* Scoping:
|
|
27
|
+
* - Only user source files (not node_modules, not AS stdlib)
|
|
28
|
+
* - Blanket injection into all user classes (always enabled)
|
|
29
|
+
*
|
|
30
|
+
* Cross-module function availability:
|
|
31
|
+
* - Structural bodies reference @global functions from assembly/compare.ts and assembly/utils.ts
|
|
32
|
+
* which are available in all source files without import
|
|
33
|
+
* - Loaded transitively: user test → vitest-pool-assemblyscript/assembly → compare.ts → utils.ts
|
|
34
|
+
*
|
|
35
|
+
* AST injection:
|
|
36
|
+
* - Method source is generated as a string, then parsed into an AST node using
|
|
37
|
+
* `Parser.parseClassMember()` via a temporary `Source` + `Tokenizer`
|
|
38
|
+
*
|
|
39
|
+
* @see https://www.assemblyscript.org/compiler.html#transforms
|
|
40
|
+
* @see https://github.com/AssemblyScript/assemblyscript/blob/main/src/ast.ts
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* Visitor that finds class declarations and injects deep equality, typename, and stringify methods.
|
|
44
|
+
* Uses ASTVisitor for full recursive traversal (finds classes inside namespaces, etc).
|
|
45
|
+
*/
|
|
46
|
+
var DeepEqualsVisitor = class extends ASTVisitor {
|
|
47
|
+
constructor(parser, barrelPath) {
|
|
48
|
+
super();
|
|
49
|
+
this.parser = parser;
|
|
50
|
+
this.barrelPath = barrelPath;
|
|
51
|
+
}
|
|
52
|
+
onClassEnter(node) {
|
|
53
|
+
processClass(this.parser, node, this.barrelPath);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* AssemblyScript compiler transform that injects deep equality, typename, and stringify methods
|
|
58
|
+
* into user-defined classes
|
|
59
|
+
*/
|
|
60
|
+
var DeepEqualsTransform = class extends Transform {
|
|
61
|
+
afterParse(parser) {
|
|
62
|
+
const sources = this.program.sources;
|
|
63
|
+
const barrelPath = `${INTERNAL_PATH_LIB_PREFIX}index.ts`;
|
|
64
|
+
const barrelSource = sources.find((s) => s.normalizedPath === barrelPath);
|
|
65
|
+
if (!barrelSource) console.warn(`[deep-equals transform] WARNING: Could not find barrel source "${barrelPath}" in compilation`);
|
|
66
|
+
const visitor = new DeepEqualsVisitor(parser, barrelSource ? barrelPath : "");
|
|
67
|
+
const userSources = sources.filter((source) => (source.sourceKind === ASSourceKind.User || source.sourceKind === ASSourceKind.UserEntry) && !source.normalizedPath.startsWith("~lib/"));
|
|
68
|
+
for (const source of userSources) visitor.visitSource(source);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Process a class declaration: inject deep equality, typename, and stringify methods.
|
|
73
|
+
*/
|
|
74
|
+
function processClass(parser, classDecl, barrelPath) {
|
|
75
|
+
const className = classDecl.name.text;
|
|
76
|
+
const sourcePath = barrelPath || classDecl.range.source.normalizedPath;
|
|
77
|
+
const typeSuffix = getTypeParameterSuffix(classDecl);
|
|
78
|
+
injectDeepEquals(parser, classDecl, className, typeSuffix, sourcePath);
|
|
79
|
+
injectTypename(parser, classDecl, className, typeSuffix, sourcePath);
|
|
80
|
+
injectStringify(parser, classDecl, sourcePath);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Inject the deep equality comparison method into a class.
|
|
84
|
+
*
|
|
85
|
+
* Behavior depends on user-defined equality semantics:
|
|
86
|
+
* - @operator("==") present: delegates to `this == other`
|
|
87
|
+
* - .equals() present: delegates to `this.equals(other)`
|
|
88
|
+
* - Neither: field-by-field structural comparison
|
|
89
|
+
*
|
|
90
|
+
* All methods use a usize parameter for inheritance compatibility — AS treats child methods
|
|
91
|
+
* with the same name as overrides, requiring compatible parameter types. Each body casts
|
|
92
|
+
* the pointer to its own type via changetype.
|
|
93
|
+
*/
|
|
94
|
+
function injectDeepEquals(parser, classDecl, className, typeSuffix, sourcePath) {
|
|
95
|
+
if (hasMethod(classDecl, "__vitest_assemblyscript_deep_equals")) return;
|
|
96
|
+
const typedCast = `const other = changetype<${className}${typeSuffix}>(__other);`;
|
|
97
|
+
const EQ = "__vitest_assemblyscript_EqualityResult";
|
|
98
|
+
let methodBody;
|
|
99
|
+
if (hasOperatorEquals(classDecl)) methodBody = `${typedCast} return (this == other) ? ${EQ}.Equal : ${EQ}.NotEqual;`;
|
|
100
|
+
else if (hasMethod(classDecl, "equals")) methodBody = `${typedCast} return this.equals(other) ? ${EQ}.Equal : ${EQ}.NotEqual;`;
|
|
101
|
+
else methodBody = `${typedCast} ${generateStructuralBody(classDecl)}`;
|
|
102
|
+
injectClassMember(parser, classDecl, `${"__vitest_assemblyscript_deep_equals"}(__other: usize): ${EQ} { ${methodBody} }`, sourcePath);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Inject the typename method into a class.
|
|
106
|
+
*
|
|
107
|
+
* Returns the class's own name via nameof<ClassName>(). No super chain — each class returns
|
|
108
|
+
* its own name. Virtual dispatch ensures the correct runtime class name is returned even
|
|
109
|
+
* when the variable is typed as a base class.
|
|
110
|
+
*/
|
|
111
|
+
function injectTypename(parser, classDecl, className, typeSuffix, sourcePath) {
|
|
112
|
+
if (hasMethod(classDecl, "__vitest_assemblyscript_typename")) return;
|
|
113
|
+
injectClassMember(parser, classDecl, `${"__vitest_assemblyscript_typename"}(): string { return nameof<${className}${typeSuffix}>(); }`, sourcePath);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Inject the stringify method into a class.
|
|
117
|
+
*
|
|
118
|
+
* Returns comma-separated "fieldName: value" entries for all stored instance fields.
|
|
119
|
+
* Always stringifies all fields regardless of operator==/equals() — stringify shows
|
|
120
|
+
* full object state, not equality-relevant fields only.
|
|
121
|
+
*
|
|
122
|
+
* Follows the super chain via isDefined guard, same pattern as deep equality.
|
|
123
|
+
* Uses @global bridge __vitest_assemblyscript_stringify_value to call stringifyValue().
|
|
124
|
+
*/
|
|
125
|
+
function injectStringify(parser, classDecl, sourcePath) {
|
|
126
|
+
if (hasMethod(classDecl, "__vitest_assemblyscript_stringify")) return;
|
|
127
|
+
injectClassMember(parser, classDecl, `${"__vitest_assemblyscript_stringify"}(): string { ${generateStringifyBody(classDecl)} }`, sourcePath);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Check if a class has a specific instance method by name
|
|
131
|
+
*/
|
|
132
|
+
function hasMethod(classDecl, methodName) {
|
|
133
|
+
return classDecl.members.some((member) => member.kind === ASNodeKind.MethodDeclaration && member.name.text === methodName && member.is(ASCommonFlags.Instance));
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Check if a class has an @operator("==") decorator on any method.
|
|
137
|
+
* The AS compiler uses DecoratorKind.Operator (2) for @operator and
|
|
138
|
+
* DecoratorKind.OperatorBinary (3) for @operator.binary — check both.
|
|
139
|
+
*/
|
|
140
|
+
function hasOperatorEquals(classDecl) {
|
|
141
|
+
for (const member of classDecl.members) {
|
|
142
|
+
if (member.kind !== ASNodeKind.MethodDeclaration) continue;
|
|
143
|
+
const decorators = member.decorators;
|
|
144
|
+
if (!decorators) continue;
|
|
145
|
+
for (const decorator of decorators) {
|
|
146
|
+
const kind = decorator.decoratorKind;
|
|
147
|
+
if (kind !== ASDecoratorKind.Operator && kind !== ASDecoratorKind.OperatorBinary) continue;
|
|
148
|
+
const args = decorator.args;
|
|
149
|
+
if (!args || args.length === 0) continue;
|
|
150
|
+
if (args[0].value === "==") return true;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Get the type parameter suffix for a class declaration.
|
|
157
|
+
* Returns empty string for non-generic classes, "<T>" for single param,
|
|
158
|
+
* "<K, V>" for multiple params, etc.
|
|
159
|
+
*/
|
|
160
|
+
function getTypeParameterSuffix(classDecl) {
|
|
161
|
+
const typeParams = classDecl.typeParameters;
|
|
162
|
+
if (!typeParams || typeParams.length === 0) return "";
|
|
163
|
+
return `<${typeParams.map((param) => param.name.text).join(", ")}>`;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Collect stored instance fields from a class declaration.
|
|
167
|
+
* Includes public, private, protected fields.
|
|
168
|
+
* Excludes: static fields, getters, setters, constructors, methods.
|
|
169
|
+
*/
|
|
170
|
+
function getStoredInstanceFields(classDecl) {
|
|
171
|
+
return classDecl.members.filter((member) => {
|
|
172
|
+
if (member.kind !== ASNodeKind.FieldDeclaration) return false;
|
|
173
|
+
if (member.is(ASCommonFlags.Static)) return false;
|
|
174
|
+
if (member.is(ASCommonFlags.Get) || member.is(ASCommonFlags.Set)) return false;
|
|
175
|
+
return true;
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Generate the structural comparison body for a class.
|
|
180
|
+
* Delegates all field comparisons to the pool's equals function, which handles
|
|
181
|
+
* primitives, strings, containers, nullables, and nested user types recursively.
|
|
182
|
+
*
|
|
183
|
+
* Uses a shared `__result` variable to capture and propagate EqualityResult from
|
|
184
|
+
* each comparison, so type mismatch information from nested comparisons is preserved.
|
|
185
|
+
*/
|
|
186
|
+
function generateStructuralBody(classDecl) {
|
|
187
|
+
const fields = getStoredInstanceFields(classDecl);
|
|
188
|
+
const EQ = "__vitest_assemblyscript_EqualityResult";
|
|
189
|
+
if (fields.length === 0) return `return ${EQ}.Equal;`;
|
|
190
|
+
const hasSuper = classDecl.extendsType !== null;
|
|
191
|
+
const comparisons = [];
|
|
192
|
+
comparisons.push(`let __result: ${EQ};`);
|
|
193
|
+
if (hasSuper) comparisons.push(`if (isDefined(super.${"__vitest_assemblyscript_deep_equals"})) { __result = super.${"__vitest_assemblyscript_deep_equals"}(__other); if (__result != ${EQ}.Equal) return __result; }`);
|
|
194
|
+
for (const field of fields) {
|
|
195
|
+
const fieldName = field.name.text;
|
|
196
|
+
comparisons.push(`${"__vitest_assemblyscript_equals_path_push"}(".${fieldName}"); __result = ${"__vitest_assemblyscript_compare_equals"}(this.${fieldName}, other.${fieldName}); if (__result != ${EQ}.Equal) return __result; ${"__vitest_assemblyscript_equals_path_pop"}();`);
|
|
197
|
+
}
|
|
198
|
+
return comparisons.join(" ") + ` return ${EQ}.Equal;`;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Generate the stringify body for a class.
|
|
202
|
+
* Produces comma-separated "fieldName: value" entries using the @global stringify bridge.
|
|
203
|
+
* Follows the super chain if the class extends another class.
|
|
204
|
+
*/
|
|
205
|
+
function generateStringifyBody(classDecl) {
|
|
206
|
+
const fields = getStoredInstanceFields(classDecl);
|
|
207
|
+
const hasSuper = classDecl.extendsType !== null;
|
|
208
|
+
const SV = "__vitest_assemblyscript_stringify_value";
|
|
209
|
+
const SUPER_METHOD = "__vitest_assemblyscript_stringify";
|
|
210
|
+
if (fields.length === 0 && !hasSuper) return `return "";`;
|
|
211
|
+
const parts = [];
|
|
212
|
+
parts.push(`let s = "";`);
|
|
213
|
+
if (hasSuper) parts.push(`if (isDefined(super.${SUPER_METHOD})) { s += super.${SUPER_METHOD}(); if (s != "") s += ", "; }`);
|
|
214
|
+
let firstField = true;
|
|
215
|
+
for (const field of fields) {
|
|
216
|
+
const fieldName = field.name.text;
|
|
217
|
+
if (!firstField) parts.push(`s += ", ";`);
|
|
218
|
+
parts.push(`s += "${fieldName}: " + ${SV}(this.${fieldName});`);
|
|
219
|
+
firstField = false;
|
|
220
|
+
}
|
|
221
|
+
parts.push(`return s;`);
|
|
222
|
+
return parts.join(" ");
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Parse a method source string and inject it as a member of the given class.
|
|
226
|
+
*
|
|
227
|
+
* Creates a temporary Source and Tokenizer, uses the parser's parseClassMember()
|
|
228
|
+
* to produce a proper AST node, then appends it to the class's members array.
|
|
229
|
+
*
|
|
230
|
+
* The temporary source uses the pool's assembly barrel file (assembly/index.ts) as its
|
|
231
|
+
* normalizedPath instead of the user's source file. This prevents the source map from
|
|
232
|
+
* incorrectly attributing generated code to user source lines. The AS compiler requires
|
|
233
|
+
* the normalizedPath to be a real source in the compilation for identifier resolution
|
|
234
|
+
* (synthetic paths cause assertion failures in maybeCompileEnclosingSource).
|
|
235
|
+
*/
|
|
236
|
+
function injectClassMember(parser, classDecl, memberSource, barrelPath) {
|
|
237
|
+
const tokenizer = new Tokenizer(new Source(ASSourceKind.User, barrelPath, memberSource));
|
|
238
|
+
tokenizer.next();
|
|
239
|
+
const member = parser.parseClassMember(tokenizer, classDecl);
|
|
240
|
+
if (member) classDecl.members.push(member);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
//#endregion
|
|
244
|
+
export { DeepEqualsTransform as default };
|
|
245
|
+
//# sourceMappingURL=deep-equals.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deep-equals.mjs","names":[],"sources":["../../../src/compiler/transforms/deep-equals.mts"],"sourcesContent":["/**\n * AssemblyScript Compiler Transform: Deep Equality & Stringification for User-Defined Objects\n *\n * Injects three methods into user-defined classes at `afterParse`:\n *\n * 1. `__vitest_assemblyscript_deep_equals` — deep equality comparison for `toEqual()`\n * - If the class defines `@operator(\"==\")`: delegates to `this == other`\n * - If the class defines `.equals()`: delegates to `this.equals(other)`\n * - Otherwise: compares all stored instance fields via the pool's `equals()` function\n *\n * 2. `__vitest_assemblyscript_typename` — returns the runtime class name via `nameof<ClassName>()`\n * - Virtual dispatch ensures correct runtime name even for base-typed variables\n * - Used by stringifyValue() for user-facing output and by RTM type name tracking\n *\n * 3. `__vitest_assemblyscript_stringify` — returns comma-separated field entries for stringification\n * - Always stringifies all stored instance fields regardless of operator==/equals()\n * - Follows super chain via isDefined guard, same pattern as deep equality\n * - Uses @global bridge __vitest_assemblyscript_stringify_value to call stringifyValue()\n *\n * Scoping:\n * - Only user source files (not node_modules, not AS stdlib)\n * - Blanket injection into all user classes (always enabled)\n *\n * Cross-module function availability:\n * - Structural bodies reference @global functions from assembly/compare.ts and assembly/utils.ts\n * which are available in all source files without import\n * - Loaded transitively: user test → vitest-pool-assemblyscript/assembly → compare.ts → utils.ts\n *\n * AST injection:\n * - Method source is generated as a string, then parsed into an AST node using\n * `Parser.parseClassMember()` via a temporary `Source` + `Tokenizer`\n *\n * @see https://www.assemblyscript.org/compiler.html#transforms\n * @see https://github.com/AssemblyScript/assemblyscript/blob/main/src/ast.ts\n */\n\nimport {\n ClassDeclaration,\n DeclarationStatement,\n DecoratorNode,\n FieldDeclaration,\n MethodDeclaration,\n Parser,\n Source,\n Tokenizer,\n} from 'assemblyscript';\nimport { Transform } from 'assemblyscript/transform';\n\nimport { ASTVisitor } from '../../util/ast-visitor.js';\nimport {\n ASSEMBLYSCRIPT_LIB_PREFIX,\n COMPARE_EQUALS_EXPORT_ALIAS,\n DEEP_EQUALS_INJECTED_METHOD_NAME,\n EQUALITY_RESULT_ENUM_NAME,\n EQUALS_PATH_POP_GLOBAL_ALIAS,\n EQUALS_PATH_PUSH_GLOBAL_ALIAS,\n INTERNAL_PATH_LIB_PREFIX,\n STRINGIFY_INJECTED_METHOD_NAME,\n STRINGIFY_VALUE_GLOBAL_ALIAS,\n TYPENAME_INJECTED_METHOD_NAME,\n ASCommonFlags,\n ASDecoratorKind,\n ASNodeKind,\n ASSourceKind,\n} from '../../types/constants.js';\n\n/**\n * Visitor that finds class declarations and injects deep equality, typename, and stringify methods.\n * Uses ASTVisitor for full recursive traversal (finds classes inside namespaces, etc).\n */\nclass DeepEqualsVisitor extends ASTVisitor {\n constructor(\n private parser: Parser,\n private barrelPath: string,\n ) {\n super();\n }\n\n protected onClassEnter(node: ClassDeclaration): void {\n processClass(this.parser, node, this.barrelPath);\n }\n}\n\n/**\n * AssemblyScript compiler transform that injects deep equality, typename, and stringify methods\n * into user-defined classes\n */\nclass DeepEqualsTransform extends Transform {\n afterParse(parser: Parser): void {\n const sources = (this as Transform).program.sources;\n\n // Find the pool's assembly barrel file — used as the normalizedPath for injected\n // methods so the source map attributes them to pool internals, not user code.\n // The AS compiler requires a real source in the compilation for identifier resolution.\n const barrelPath = `${INTERNAL_PATH_LIB_PREFIX}index.ts`;\n const barrelSource = sources.find((s: Source) => s.normalizedPath === barrelPath);\n if (!barrelSource) {\n // This should never happen — the barrel is always loaded transitively via user imports.\n // If it does, fall back to the class's own source path (incorrect attribution but functional).\n console.warn(`[deep-equals transform] WARNING: Could not find barrel source \"${barrelPath}\" in compilation`);\n }\n\n const resolvedBarrelPath = barrelSource ? barrelPath : '';\n const visitor = new DeepEqualsVisitor(parser, resolvedBarrelPath);\n\n // Filter to user source files only (same scoping as strip-inline transform)\n const userSources = sources.filter((source: Source) =>\n (source.sourceKind === ASSourceKind.User || source.sourceKind === ASSourceKind.UserEntry)\n && !source.normalizedPath.startsWith(ASSEMBLYSCRIPT_LIB_PREFIX)\n );\n\n for (const source of userSources) {\n visitor.visitSource(source);\n }\n }\n}\n\n/**\n * Process a class declaration: inject deep equality, typename, and stringify methods.\n */\nfunction processClass(parser: Parser, classDecl: ClassDeclaration, barrelPath: string): void {\n const className = classDecl.name.text;\n\n // Use the barrel path if available, otherwise fall back to the class's own source path\n const sourcePath = barrelPath || classDecl.range.source.normalizedPath;\n\n // Build the type suffix for generic classes (e.g. \"Pair\" → \"Pair<T>\" or \"Pair<K, V>\")\n const typeSuffix = getTypeParameterSuffix(classDecl);\n\n injectDeepEquals(parser, classDecl, className, typeSuffix, sourcePath);\n injectTypename(parser, classDecl, className, typeSuffix, sourcePath);\n injectStringify(parser, classDecl, sourcePath);\n}\n\n/**\n * Inject the deep equality comparison method into a class.\n *\n * Behavior depends on user-defined equality semantics:\n * - @operator(\"==\") present: delegates to `this == other`\n * - .equals() present: delegates to `this.equals(other)`\n * - Neither: field-by-field structural comparison\n *\n * All methods use a usize parameter for inheritance compatibility — AS treats child methods\n * with the same name as overrides, requiring compatible parameter types. Each body casts\n * the pointer to its own type via changetype.\n */\nfunction injectDeepEquals(\n parser: Parser, classDecl: ClassDeclaration,\n className: string, typeSuffix: string, sourcePath: string,\n): void {\n if (hasMethod(classDecl, DEEP_EQUALS_INJECTED_METHOD_NAME)) return;\n\n const typedCast = `const other = changetype<${className}${typeSuffix}>(__other);`;\n const EQ = EQUALITY_RESULT_ENUM_NAME;\n let methodBody: string;\n\n if (hasOperatorEquals(classDecl)) {\n methodBody = `${typedCast} return (this == other) ? ${EQ}.Equal : ${EQ}.NotEqual;`;\n } else if (hasMethod(classDecl, 'equals')) {\n methodBody = `${typedCast} return this.equals(other) ? ${EQ}.Equal : ${EQ}.NotEqual;`;\n } else {\n methodBody = `${typedCast} ${generateStructuralBody(classDecl)}`;\n }\n\n const methodSource =\n `${DEEP_EQUALS_INJECTED_METHOD_NAME}(__other: usize): ${EQ} { ${methodBody} }`;\n\n injectClassMember(parser, classDecl, methodSource, sourcePath);\n}\n\n/**\n * Inject the typename method into a class.\n *\n * Returns the class's own name via nameof<ClassName>(). No super chain — each class returns\n * its own name. Virtual dispatch ensures the correct runtime class name is returned even\n * when the variable is typed as a base class.\n */\nfunction injectTypename(\n parser: Parser, classDecl: ClassDeclaration,\n className: string, typeSuffix: string, sourcePath: string,\n): void {\n if (hasMethod(classDecl, TYPENAME_INJECTED_METHOD_NAME)) return;\n\n const methodSource =\n `${TYPENAME_INJECTED_METHOD_NAME}(): string { return nameof<${className}${typeSuffix}>(); }`;\n\n injectClassMember(parser, classDecl, methodSource, sourcePath);\n}\n\n/**\n * Inject the stringify method into a class.\n *\n * Returns comma-separated \"fieldName: value\" entries for all stored instance fields.\n * Always stringifies all fields regardless of operator==/equals() — stringify shows\n * full object state, not equality-relevant fields only.\n *\n * Follows the super chain via isDefined guard, same pattern as deep equality.\n * Uses @global bridge __vitest_assemblyscript_stringify_value to call stringifyValue().\n */\nfunction injectStringify(\n parser: Parser, classDecl: ClassDeclaration,\n sourcePath: string,\n): void {\n if (hasMethod(classDecl, STRINGIFY_INJECTED_METHOD_NAME)) return;\n\n const methodBody = generateStringifyBody(classDecl);\n const methodSource =\n `${STRINGIFY_INJECTED_METHOD_NAME}(): string { ${methodBody} }`;\n\n injectClassMember(parser, classDecl, methodSource, sourcePath);\n}\n\n// =============================================================================\n// Detection helpers\n// =============================================================================\n\n/**\n * Check if a class has a specific instance method by name\n */\nfunction hasMethod(classDecl: ClassDeclaration, methodName: string): boolean {\n return classDecl.members.some(member =>\n member.kind === ASNodeKind.MethodDeclaration\n && (member as MethodDeclaration).name.text === methodName\n && member.is(ASCommonFlags.Instance)\n );\n}\n\n/**\n * Check if a class has an @operator(\"==\") decorator on any method.\n * The AS compiler uses DecoratorKind.Operator (2) for @operator and\n * DecoratorKind.OperatorBinary (3) for @operator.binary — check both.\n */\nfunction hasOperatorEquals(classDecl: ClassDeclaration): boolean {\n for (const member of classDecl.members) {\n if (member.kind !== ASNodeKind.MethodDeclaration) continue;\n\n const decorators = member.decorators;\n if (!decorators) continue;\n\n for (const decorator of decorators) {\n const kind = (decorator as DecoratorNode).decoratorKind;\n if (kind !== ASDecoratorKind.Operator && kind !== ASDecoratorKind.OperatorBinary) continue;\n\n // Check if the decorator argument is \"==\"\n const args = (decorator as DecoratorNode).args;\n if (!args || args.length === 0) continue;\n\n // The first argument is a string literal with the operator name.\n // At the AST level, LiteralExpression has a .value property for string literals.\n // The AS type declarations expose it as Expression, but the runtime type is\n // StringLiteralExpression with a .value: string property.\n const firstArg = args[0] as any;\n if (firstArg.value === '==') {\n return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Get the type parameter suffix for a class declaration.\n * Returns empty string for non-generic classes, \"<T>\" for single param,\n * \"<K, V>\" for multiple params, etc.\n */\nfunction getTypeParameterSuffix(classDecl: ClassDeclaration): string {\n const typeParams = classDecl.typeParameters;\n if (!typeParams || typeParams.length === 0) {\n return '';\n }\n\n const paramNames = typeParams.map(param => param.name.text);\n return `<${paramNames.join(', ')}>`;\n}\n\n// =============================================================================\n// Structural body generation\n// =============================================================================\n\n/**\n * Collect stored instance fields from a class declaration.\n * Includes public, private, protected fields.\n * Excludes: static fields, getters, setters, constructors, methods.\n */\nfunction getStoredInstanceFields(classDecl: ClassDeclaration): FieldDeclaration[] {\n return classDecl.members.filter(member => {\n if (member.kind !== ASNodeKind.FieldDeclaration) return false;\n\n // Exclude static fields\n if (member.is(ASCommonFlags.Static)) return false;\n\n // Exclude getters and setters (these are MethodDeclarations in AS,\n // but guard against FieldDeclarations with these flags just in case)\n if (member.is(ASCommonFlags.Get) || member.is(ASCommonFlags.Set)) return false;\n\n return true;\n }) as FieldDeclaration[];\n}\n\n/**\n * Generate the structural comparison body for a class.\n * Delegates all field comparisons to the pool's equals function, which handles\n * primitives, strings, containers, nullables, and nested user types recursively.\n *\n * Uses a shared `__result` variable to capture and propagate EqualityResult from\n * each comparison, so type mismatch information from nested comparisons is preserved.\n */\nfunction generateStructuralBody(classDecl: ClassDeclaration): string {\n const fields = getStoredInstanceFields(classDecl);\n const EQ = EQUALITY_RESULT_ENUM_NAME;\n\n // No fields: always equal (two instances of an empty class are structurally identical)\n if (fields.length === 0) {\n return `return ${EQ}.Equal;`;\n }\n\n // Check if class extends another class — if so, include super comparison\n const hasSuper = classDecl.extendsType !== null;\n\n const comparisons: string[] = [];\n\n // Declare a shared result variable for capturing and propagating EqualityResult\n comparisons.push(`let __result: ${EQ};`);\n\n // Super class comparison: delegate to superclass's deep equality comparison method if it exists.\n // Passes __other (raw usize) since the parent's method also takes usize.\n if (hasSuper) {\n comparisons.push(\n `if (isDefined(super.${DEEP_EQUALS_INJECTED_METHOD_NAME})) { `\n + `__result = super.${DEEP_EQUALS_INJECTED_METHOD_NAME}(__other); `\n + `if (__result != ${EQ}.Equal) return __result; `\n + `}`\n );\n }\n\n for (const field of fields) {\n const fieldName = field.name.text;\n comparisons.push(\n `${EQUALS_PATH_PUSH_GLOBAL_ALIAS}(\".${fieldName}\"); `\n + `__result = ${COMPARE_EQUALS_EXPORT_ALIAS}(this.${fieldName}, other.${fieldName}); `\n + `if (__result != ${EQ}.Equal) return __result; `\n + `${EQUALS_PATH_POP_GLOBAL_ALIAS}();`\n );\n }\n\n return comparisons.join(' ') + ` return ${EQ}.Equal;`;\n}\n\n/**\n * Generate the stringify body for a class.\n * Produces comma-separated \"fieldName: value\" entries using the @global stringify bridge.\n * Follows the super chain if the class extends another class.\n */\nfunction generateStringifyBody(classDecl: ClassDeclaration): string {\n const fields = getStoredInstanceFields(classDecl);\n const hasSuper = classDecl.extendsType !== null;\n const SV = STRINGIFY_VALUE_GLOBAL_ALIAS;\n const SUPER_METHOD = STRINGIFY_INJECTED_METHOD_NAME;\n\n // No fields and no super: return empty string\n if (fields.length === 0 && !hasSuper) {\n return `return \"\";`;\n }\n\n const parts: string[] = [];\n parts.push(`let s = \"\";`);\n\n if (hasSuper) {\n parts.push(\n `if (isDefined(super.${SUPER_METHOD})) { `\n + `s += super.${SUPER_METHOD}(); `\n + `if (s != \"\") s += \", \"; `\n + `}`\n );\n }\n\n let firstField = true;\n for (const field of fields) {\n const fieldName = field.name.text;\n if (!firstField) {\n parts.push(`s += \", \";`);\n }\n parts.push(`s += \"${fieldName}: \" + ${SV}(this.${fieldName});`);\n firstField = false;\n }\n\n parts.push(`return s;`);\n return parts.join(' ');\n}\n\n// =============================================================================\n// AST injection\n// =============================================================================\n\n/**\n * Parse a method source string and inject it as a member of the given class.\n *\n * Creates a temporary Source and Tokenizer, uses the parser's parseClassMember()\n * to produce a proper AST node, then appends it to the class's members array.\n *\n * The temporary source uses the pool's assembly barrel file (assembly/index.ts) as its\n * normalizedPath instead of the user's source file. This prevents the source map from\n * incorrectly attributing generated code to user source lines. The AS compiler requires\n * the normalizedPath to be a real source in the compilation for identifier resolution\n * (synthetic paths cause assertion failures in maybeCompileEnclosingSource).\n */\nfunction injectClassMember(\n parser: Parser,\n classDecl: ClassDeclaration,\n memberSource: string,\n barrelPath: string,\n): void {\n const tempSource = new Source(\n ASSourceKind.User,\n barrelPath,\n memberSource,\n );\n\n const tokenizer = new Tokenizer(tempSource);\n\n // Advance past the initial token so the parser is positioned correctly\n tokenizer.next();\n\n const member = parser.parseClassMember(tokenizer, classDecl);\n if (member) {\n classDecl.members.push(member as DeclarationStatement);\n }\n}\n\nexport default DeepEqualsTransform;\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ASDecoratorKind, ASSourceKind } from "../../constants-
|
|
2
|
-
import { ASTVisitor } from "../../ast-visitor-
|
|
1
|
+
import { ASDecoratorKind, ASSourceKind } from "../../constants-DbxJ3hzg.mjs";
|
|
2
|
+
import { ASTVisitor } from "../../ast-visitor-CWEOd3UH.mjs";
|
|
3
3
|
import { Transform } from "assemblyscript/transform";
|
|
4
4
|
|
|
5
5
|
//#region src/compiler/transforms/strip-inline.mts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { POOL_ERROR_NAMES } from "./constants-
|
|
2
|
-
import { createPoolError, debug, throwPoolErrorIfAborted } from "./debug-
|
|
3
|
-
import { clearNativeBuildError, hasNativeBuildError, warnASInstrumentationNotLoaded } from "./feature-check-
|
|
1
|
+
import { POOL_ERROR_NAMES } from "./constants-DbxJ3hzg.mjs";
|
|
2
|
+
import { createPoolError, debug, throwPoolErrorIfAborted } from "./debug-DtRAL4rM.mjs";
|
|
3
|
+
import { clearNativeBuildError, hasNativeBuildError, warnASInstrumentationNotLoaded } from "./feature-check-Bje3ntpV.mjs";
|
|
4
4
|
import { basename, resolve } from "node:path";
|
|
5
5
|
import { access, readFile } from "node:fs/promises";
|
|
6
6
|
import { main } from "assemblyscript/asc";
|
|
@@ -14,7 +14,7 @@ import { main } from "assemblyscript/asc";
|
|
|
14
14
|
*/
|
|
15
15
|
let nativeAddon;
|
|
16
16
|
try {
|
|
17
|
-
nativeAddon = await import("./addon-interface-
|
|
17
|
+
nativeAddon = await import("./addon-interface-CYFXMbK7.mjs");
|
|
18
18
|
clearNativeBuildError();
|
|
19
19
|
} catch (err) {
|
|
20
20
|
if (await hasNativeBuildError()) debug(`[Compiler] Native instrumentation addon not loaded (known build failure): ${err?.message ?? String(err)}`);
|
|
@@ -22,12 +22,18 @@ try {
|
|
|
22
22
|
}
|
|
23
23
|
const POOL_ASSEMBLY_NODE_MODULES_PREFIX = "node_modules/vitest-pool-assemblyscript/assembly/";
|
|
24
24
|
const STRIP_INLINE_TRANSFORM = resolve(import.meta.dirname, "./compiler/transforms/strip-inline.mjs");
|
|
25
|
+
const DEEP_EQUALS_TRANSFORM = resolve(import.meta.dirname, "./compiler/transforms/deep-equals.mjs");
|
|
25
26
|
setImmediate(async () => {
|
|
26
27
|
try {
|
|
27
28
|
await access(STRIP_INLINE_TRANSFORM);
|
|
28
29
|
} catch {
|
|
29
30
|
throw createPoolError(`AS Compiler strip inline transform file not found at "${STRIP_INLINE_TRANSFORM}"`, POOL_ERROR_NAMES.CompilationError);
|
|
30
31
|
}
|
|
32
|
+
try {
|
|
33
|
+
await access(DEEP_EQUALS_TRANSFORM);
|
|
34
|
+
} catch {
|
|
35
|
+
throw createPoolError(`AS Compiler deep equals transform file not found at "${DEEP_EQUALS_TRANSFORM}"`, POOL_ERROR_NAMES.CompilationError);
|
|
36
|
+
}
|
|
31
37
|
});
|
|
32
38
|
/**
|
|
33
39
|
* Compile AssemblyScript source code to WASM binary
|
|
@@ -69,7 +75,9 @@ async function compileAssemblyScript(filename, options, logModule, logLabel, sig
|
|
|
69
75
|
"--sourceMap",
|
|
70
76
|
"--exportStart",
|
|
71
77
|
"_start",
|
|
72
|
-
"--exportTable"
|
|
78
|
+
"--exportTable",
|
|
79
|
+
"--transform",
|
|
80
|
+
DEEP_EQUALS_TRANSFORM
|
|
73
81
|
];
|
|
74
82
|
if (options.stripInline === true) {
|
|
75
83
|
compilerFlags.push("--transform", STRIP_INLINE_TRANSFORM);
|
|
@@ -144,4 +152,4 @@ async function compileAssemblyScript(filename, options, logModule, logLabel, sig
|
|
|
144
152
|
|
|
145
153
|
//#endregion
|
|
146
154
|
export { compileAssemblyScript };
|
|
147
|
-
//# sourceMappingURL=compiler-
|
|
155
|
+
//# sourceMappingURL=compiler-hUlDr5vL.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compiler-hUlDr5vL.mjs","names":["ascMain"],"sources":["../src/compiler/index.ts"],"sourcesContent":["/**\n * AssemblyScript Compiler\n *\n * Handles compilation of AssemblyScript source code to WASM binaries.\n * Manages compiler options, transforms, and in-memory compilation.\n */\n\nimport { main as ascMain } from 'assemblyscript/asc';\nimport { basename, resolve } from 'node:path';\nimport { access, readFile, writeFile, mkdir } from 'node:fs/promises';\n\nimport type {\n AssemblyScriptCompilerResult,\n AssemblyScriptCompilerOptions,\n NativeAddonInterface\n} from '../types/types.js';\nimport { POOL_ERROR_NAMES } from '../types/constants.js';\nimport { debug } from '../util/debug.js';\nimport { createPoolError, throwPoolErrorIfAborted } from '../util/pool-errors.js';\nimport { clearNativeBuildError, hasNativeBuildError, warnASInstrumentationNotLoaded } from '../util/feature-check.js';\n\nlet nativeAddon: NativeAddonInterface | undefined;\ntry {\n nativeAddon = await import('../instrumentation/addon-interface.js');\n // Addon loaded successfully — clear any stale build error marker (fire and forget)\n clearNativeBuildError();\n} catch (err: any) {\n const knownBuildFailure = await hasNativeBuildError();\n if (knownBuildFailure) {\n // Marker file exists — coverage provider will warn the user, just debug log here\n debug(`[Compiler] Native instrumentation addon not loaded (known build failure): ${err?.message ?? String(err)}`);\n } else {\n // Unexpected failure — no marker file, warn the user\n warnASInstrumentationNotLoaded(err?.message ?? String(err));\n }\n}\n\nconst DEBUG_WRITE_FILES = false;\n\n// Path prefix the AS compiler uses when resolving bare `vitest-pool-assemblyscript/assembly` imports\n// via node_modules. Used to detect self-imports and redirect to local assembly/ dir when running locally in-tree.\nconst POOL_ASSEMBLY_NODE_MODULES_PREFIX = 'node_modules/vitest-pool-assemblyscript/assembly/';\n\n// paths assume that we're running from dist/\nconst STRIP_INLINE_TRANSFORM = resolve(import.meta.dirname, './compiler/transforms/strip-inline.mjs');\nconst DEEP_EQUALS_TRANSFORM = resolve(import.meta.dirname, './compiler/transforms/deep-equals.mjs');\n\nsetImmediate(async () => {\n try {\n await access(STRIP_INLINE_TRANSFORM);\n } catch {\n throw createPoolError(\n `AS Compiler strip inline transform file not found at \"${STRIP_INLINE_TRANSFORM}\"`,\n POOL_ERROR_NAMES.CompilationError\n );\n }\n\n try {\n await access(DEEP_EQUALS_TRANSFORM);\n } catch {\n throw createPoolError(\n `AS Compiler deep equals transform file not found at \"${DEEP_EQUALS_TRANSFORM}\"`,\n POOL_ERROR_NAMES.CompilationError\n );\n }\n});\n\n/**\n * Compile AssemblyScript source code to WASM binary\n */\nexport async function compileAssemblyScript(\n filename: string,\n options: AssemblyScriptCompilerOptions,\n logModule: string,\n logLabel: string,\n signal?: AbortSignal\n): Promise<AssemblyScriptCompilerResult> {\n throwPoolErrorIfAborted(signal);\n\n const compileStart = performance.now();\n const logPrefix = `[${logModule} ASC] ${logLabel}`;\n\n const { shouldInstrument, instrumentationOptions, extraFlags } = options;\n\n if (shouldInstrument && !instrumentationOptions) {\n throw createPoolError(\n 'Instrumentation options are required for coverage instrumentation',\n POOL_ERROR_NAMES.CompilationError\n );\n }\n\n const stdoutLines: string[] = [];\n const stderrLines: string[] = [];\n let binary: Uint8Array | undefined;\n let sourceMap: string | undefined;\n\n // Use full path as entry file so AS compiler can resolve relative imports\n const entryFile = filename;\n // Use simple output name to avoid AS compiler prepending it to source map paths\n const outputFile = 'output.wasm';\n\n debug(`${logPrefix} - Compiling: \"${filename}\"`);\n\n // Capture stdout/stderr (for potential error reporting)\n const stdout = {\n write: (text: string) => {\n stdoutLines.push(text);\n return true;\n }\n };\n\n const stderr = {\n write: (text: string) => {\n stderrLines.push(text);\n return true;\n }\n };\n\n // Build compiler flags\n const compilerFlags = [\n entryFile,\n\n // overrideable, though not recommended\n '--optimizeLevel', '0', // No optimization for easier debugging\n '--shrinkLevel', '0', // No shrink\n '--runtime', 'stub', // stub runtime (no GC)\n\n ...(extraFlags || []),\n\n // non-overrideable\n '--outFile', outputFile,\n '--importMemory', // Import memory from JS (enables imports during WASM start)\n '--debug', // Include debug info\n '--sourceMap', // Generate source maps for error reporting\n '--exportStart', '_start', // Export start function for explicit initialization control\n '--exportTable', // Export function table for direct test execution\n\n // Injects deep equality comparison method into user-defined classes for toEqual support\n '--transform', DEEP_EQUALS_TRANSFORM,\n ];\n\n // Add transform to strip @inline decorators if requested\n // This improves coverage accuracy by preventing functions from being inlined,\n // and enables correct source-mapped error reporting for errors originating\n // inside inlined functions.\n if (options.stripInline === true) {\n compilerFlags.push(\n '--transform', STRIP_INLINE_TRANSFORM\n );\n debug(`${logPrefix} - Added Transform - Stripping @inline decorators`);\n }\n\n // Compile with AssemblyScript compiler\n const ascStart = performance.now();\n const result = await ascMain(compilerFlags, {\n stdout,\n stderr,\n // Let AS read from filesystem for import resolution\n // WASM binary and source map are captured in memory via writeFile callback\n writeFile: (name: string, contents: string | Uint8Array, _baseDir: string) => {\n throwPoolErrorIfAborted(signal);\n\n if (name.endsWith('.wasm') && contents instanceof Uint8Array) {\n binary = contents;\n debug(`${logPrefix} - Captured binary in memory: \"${name}\"`);\n } else if (name.endsWith('.wasm.map') && typeof contents === 'string') {\n debug(`${logPrefix} - Captured source map in memory: \"${name}\"`);\n sourceMap = contents;\n } else {\n debug(`${logPrefix} - WARNING - Captured Unexpected File: \"${name}\" at baseDir: \"${_baseDir}\"`);\n }\n },\n \n // Custom readFile enables in-tree resolution of bare pool assembly imports.\n // When a test file imports 'vitest-pool-assemblyscript/assembly', the AS compiler\n // resolves it to a node_modules path. This works when the package is installed,\n // but fails in-tree (the package isn't in its own node_modules). The fallback\n // redirects these to the local assembly/ directory when the normal path isn't found.\n readFile: async (filename, baseDir): Promise<string | null> => {\n const filePath = resolve(baseDir, filename);\n\n try {\n return await readFile(filePath, { encoding: 'utf-8' });\n } catch {\n // Fallback: when running in-tree, redirect pool assembly imports to local assembly/ dir\n if (filename.startsWith(POOL_ASSEMBLY_NODE_MODULES_PREFIX)) {\n const localSubpath = filename.substring(POOL_ASSEMBLY_NODE_MODULES_PREFIX.length);\n const localPath = resolve(baseDir, 'assembly', localSubpath);\n\n try {\n return await readFile(localPath, { encoding: 'utf-8' });\n } catch {\n return null;\n }\n }\n\n return null;\n }\n },\n });\n\n debug(`${logPrefix} - TIMING asc.main: ${(performance.now() - ascStart).toFixed(2)} ms`);\n\n if (result.error) {\n const errorMessage = stderrLines.length > 0\n ? `${result.error.message}\\n\\n${stderrLines.join('')}`\n : result.error.message;\n\n throw createPoolError(errorMessage, POOL_ERROR_NAMES.CompilationError, errorMessage);\n }\n\n if (!binary) {\n const errorMessage = stderrLines.length > 0\n ? `No WASM binary was generated\\n\\nAS Compiler output:\\n${stderrLines.join('')}`\n : 'No WASM binary was generated';\n\n throw createPoolError(errorMessage, POOL_ERROR_NAMES.CompilationError);\n }\n\n if (!sourceMap) {\n throw createPoolError('Source map not captured from AssemblyScript Compiler', POOL_ERROR_NAMES.CompilationError);\n }\n\n const cleanBinary: Uint8Array = binary;\n const wasmSourceMap: string = sourceMap;\n\n debug(`${logPrefix} - Compilation successful, clean binary size: ${cleanBinary.length} bytes`);\n debug(`${logPrefix} - Source map generated, size: ${wasmSourceMap.length * 2} bytes`);\n \n if (DEBUG_WRITE_FILES) {\n // Write source map for debugging\n const dir = './debug';\n // TODO - handle non-.ts extensions\n const sourceMapFileName = `${basename(filename, '.ts')}.ts.map`;\n const sourceMapPath = `${dir}/${sourceMapFileName}`;\n\n // Create directory if it doesn't exist\n try {\n await mkdir(dir, { recursive: true });\n } catch {\n // Directory already exists or creation failed, continue\n }\n\n // Format as well-formed JSON\n const formattedSourceMap = JSON.stringify(JSON.parse(wasmSourceMap), null, 2);\n\n writeFile(sourceMapPath, formattedSourceMap, { encoding: 'utf8' });\n debug(`${logPrefix} - Wrote source map to: \"${sourceMapPath}\"`);\n\n // Also write WASM binary for inspection\n const wasmPath = sourceMapPath.replace('.map', '.wasm');\n writeFile(wasmPath, cleanBinary);\n debug(`${logPrefix} - Wrote WASM binary to: \"${wasmPath}\"`);\n }\n\n // Instrument binary for coverage if requested and available\n if (options.shouldInstrument && nativeAddon) {\n throwPoolErrorIfAborted(signal);\n\n const instrumentStart = performance.now();\n const wasmBuffer = Buffer.from(cleanBinary);\n const sourceMapBuffer = Buffer.from(wasmSourceMap);\n\n const instrumentResult = nativeAddon.instrumentForCoverage(wasmBuffer, sourceMapBuffer, options.instrumentationOptions!, logModule, logLabel);\n const instCount = instrumentResult.debugInfo.instrumentedFunctionCount;\n\n const instrumentEnd = performance.now();\n debug(`${logPrefix} - TIMING Instrumented ${instCount} functions: ${(performance.now() - instrumentStart).toFixed(2)} ms`);\n\n return {\n binary: instrumentResult.instrumentedWasm,\n sourceMap: instrumentResult.sourceMap,\n debugInfo: instrumentResult.debugInfo,\n isInstrumented: true,\n compileTiming: instrumentEnd - compileStart,\n };\n }\n\n // No instrumentation requested\n return {\n binary: cleanBinary,\n sourceMap: wasmSourceMap,\n isInstrumented: false,\n compileTiming: performance.now() - compileStart,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,36 @@
|
|
|
1
|
-
import { AssemblyScriptPoolOptions, WasmImportsFactory, WasmImportsFactoryInfo } from "../types-
|
|
2
|
-
import "
|
|
1
|
+
import { AssemblyScriptPoolOptions, HybridProviderOptions, WasmImportsFactory, WasmImportsFactoryInfo } from "../types-DHVk5iAx.mjs";
|
|
2
|
+
import { CoverageV8Options } from "vitest/node";
|
|
3
3
|
import { ConfigEnv, UserWorkspaceConfig, ViteUserConfig } from "vitest/config";
|
|
4
4
|
|
|
5
|
+
//#region src/config/custom-provider-options-v3.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Module augmentation for vitest 3.x — augments `CustomProviderOptions`.
|
|
8
|
+
*
|
|
9
|
+
* In v3, `CoverageOptions` is a generic type alias and cannot be augmented
|
|
10
|
+
* via TypeScript declaration merging (a type alias and an interface with the
|
|
11
|
+
* same name in the same scope produces `Duplicate identifier`). The only
|
|
12
|
+
* augmentation point that's an interface in both v3 and v4 is
|
|
13
|
+
* `CustomProviderOptions`, so the v3 entry uses that.
|
|
14
|
+
*
|
|
15
|
+
* v3's native `CustomProviderOptions` is also very narrow (only fields with
|
|
16
|
+
* defaults plus `customProviderModule`), so this augmentation widens it via
|
|
17
|
+
* `Omit<CoverageV8Options, 'provider'>` to give v3 users full coverage
|
|
18
|
+
* configuration typing alongside the AssemblyScript-specific fields from
|
|
19
|
+
* `HybridProviderOptions`.
|
|
20
|
+
*
|
|
21
|
+
* Loaded as a side-effect import from `./index-v3.ts` (the v3 config entry
|
|
22
|
+
* point) so it only takes effect for users who explicitly import the v3
|
|
23
|
+
* entry. v4 users get the equivalent typing from `./coverage-options.ts`,
|
|
24
|
+
* which augments `CoverageOptions` directly.
|
|
25
|
+
*/
|
|
26
|
+
declare module "vitest/node" {
|
|
27
|
+
interface CustomProviderOptions extends HybridProviderOptions, Omit<CoverageV8Options, "provider"> {
|
|
28
|
+
provider: "custom";
|
|
29
|
+
/** Name of the module or path to a file to load the custom provider from */
|
|
30
|
+
customProviderModule: string;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
5
34
|
//#region src/config/config-helpers-v3.d.ts
|
|
6
35
|
/**
|
|
7
36
|
* AssemblyScript pool configuration with proper typing for poolOptions
|
|
@@ -14,7 +43,8 @@ import { ConfigEnv, UserWorkspaceConfig, ViteUserConfig } from "vitest/config";
|
|
|
14
43
|
* use type intersection to add poolOptions.assemblyScript typing.
|
|
15
44
|
*
|
|
16
45
|
* Note: Coverage is NOT included here because it's global-only config in Vitest.
|
|
17
|
-
* Coverage typing comes from the CustomProviderOptions augmentation
|
|
46
|
+
* Coverage typing comes from the `CustomProviderOptions` augmentation loaded
|
|
47
|
+
* via the `./index-v3.ts` side-effect import.
|
|
18
48
|
*/
|
|
19
49
|
type AssemblyScriptUserConfig<T extends ViteUserConfig> = T & {
|
|
20
50
|
test?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-v3.d.mts","names":[],"sources":["../../src/config/config-helpers-v3.ts"],"mappings":";;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index-v3.d.mts","names":[],"sources":["../../src/config/custom-provider-options-v3.ts","../../src/config/config-helpers-v3.ts"],"mappings":";;;;;;;;AAE2C;;;;;;;;;;;;;;;;;;YAuB/B,qBAAA,SAA8B,qBAAA,EAAuB,IAAA,CAAK,iBAAA;IAClE,QAAA;ICOJ;IDJG,oBAAA;EAAA;AAAA;;;;;;;;;;;;;;;;;KCIS,wBAAA,WAAmC,cAAA,IAAkB,CAAA;EAC/D,IAAA;IAEE,WAAA;MACE,cAAA,GAAiB,yBAAA;IAAA;EAAA;AAAA;;;;KAQX,0BAAA,GAA6B,wBAAA,CAAyB,cAAA;;;;KAKtD,iCAAA,GAAoC,wBAAA,CAAyB,mBAAA;;;;;;AALzE;;;;;AAKA;;;;;AA+BA;;;;;;;;;AAGA;;;;;iBAHgB,0BAAA,CACd,MAAA,EAAQ,0BAAA,GACP,0BAAA;AAAA,iBACa,0BAAA,CACd,MAAA,EAAQ,OAAA,CAAQ,0BAAA,IACf,OAAA,CAAQ,0BAAA;AAAA,iBACK,0BAAA,CACd,MAAA,GAAS,GAAA,EAAK,SAAA,KAAc,0BAAA,GAA6B,OAAA,CAAQ,0BAAA,KAC/D,GAAA,EAAK,SAAA,KAAc,0BAAA,GAA6B,OAAA,CAAQ,0BAAA;;;;;;;;;AAF5D;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDA;;;;;;iBAAgB,2BAAA,CACd,MAAA,EAAQ,iCAAA,GACP,iCAAA;AAAA,iBACa,2BAAA,CACd,MAAA,EAAQ,OAAA,CAAQ,iCAAA,IACf,OAAA,CAAQ,iCAAA;AAAA,iBACK,2BAAA,CACd,MAAA,GAAS,GAAA,EAAK,SAAA,KAAc,iCAAA,GAAoC,OAAA,CAAQ,iCAAA,KACtE,GAAA,EAAK,SAAA,KAAc,iCAAA,GAAoC,OAAA,CAAQ,iCAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-v3.mjs","names":[],"sources":["../../src/config/config-helpers-v3.ts"],"sourcesContent":["/**\n * Configuration helpers for vitest-pool-assemblyscript\n *\n * Provides custom type-safe config helpers similar to Cloudflare's vitest-pool-workers\n * to work around TypeScript's ProjectConfig poolOptions type narrowing in Vitest v3.\n */\n\nimport type { ViteUserConfig, UserWorkspaceConfig, ConfigEnv } from 'vitest/config';\n\nimport type { AssemblyScriptPoolOptions } from '../types/types.js';\n\n/**\n * Type for config that may be a value, Promise, or function\n */\ntype AnyConfigExport<T extends ViteUserConfig> =\n | T\n | Promise<T>\n | ((env: ConfigEnv) => T | Promise<T>);\n\n/**\n * AssemblyScript pool configuration with proper typing for poolOptions\n *\n * Use this type with `defineAssemblyScriptConfig` for root-level configs,\n * or `defineAssemblyScriptProject` for project-level configs.\n * \n * Vitest v3's ProjectConfig narrows poolOptions as an inline object type,\n * which cannot be augmented via TypeScript module augmentation. Config helpers\n * use type intersection to add poolOptions.assemblyScript typing.\n *\n * Note: Coverage is NOT included here because it's global-only config in Vitest.\n * Coverage typing comes from the CustomProviderOptions augmentation
|
|
1
|
+
{"version":3,"file":"index-v3.mjs","names":[],"sources":["../../src/config/config-helpers-v3.ts"],"sourcesContent":["/**\n * Configuration helpers for vitest-pool-assemblyscript\n *\n * Provides custom type-safe config helpers similar to Cloudflare's vitest-pool-workers\n * to work around TypeScript's ProjectConfig poolOptions type narrowing in Vitest v3.\n */\n\nimport type { ViteUserConfig, UserWorkspaceConfig, ConfigEnv } from 'vitest/config';\n\nimport type { AssemblyScriptPoolOptions } from '../types/types.js';\n\n/**\n * Type for config that may be a value, Promise, or function\n */\ntype AnyConfigExport<T extends ViteUserConfig> =\n | T\n | Promise<T>\n | ((env: ConfigEnv) => T | Promise<T>);\n\n/**\n * AssemblyScript pool configuration with proper typing for poolOptions\n *\n * Use this type with `defineAssemblyScriptConfig` for root-level configs,\n * or `defineAssemblyScriptProject` for project-level configs.\n * \n * Vitest v3's ProjectConfig narrows poolOptions as an inline object type,\n * which cannot be augmented via TypeScript module augmentation. Config helpers\n * use type intersection to add poolOptions.assemblyScript typing.\n *\n * Note: Coverage is NOT included here because it's global-only config in Vitest.\n * Coverage typing comes from the `CustomProviderOptions` augmentation loaded\n * via the `./index-v3.ts` side-effect import.\n */\nexport type AssemblyScriptUserConfig<T extends ViteUserConfig> = T & {\n test?: {\n // pool?: string;\n poolOptions?: {\n assemblyScript?: AssemblyScriptPoolOptions;\n };\n };\n};\n\n/**\n * Root-level config type with AssemblyScript pool support\n */\nexport type AssemblyScriptConfigExport = AssemblyScriptUserConfig<ViteUserConfig>;\n\n/**\n * Project-level config type with AssemblyScript pool support\n */\nexport type AssemblyScriptProjectConfigExport = AssemblyScriptUserConfig<UserWorkspaceConfig>;\n\n/**\n * Define a root-level Vitest config with AssemblyScript pool options.\n *\n * This is a type-safe wrapper that properly types `poolOptions.assemblyScript`\n * for both root and project-level configurations.\n *\n * @example\n * ```ts\n * import { defineAssemblyScriptConfig } from 'vitest-pool-assemblyscript/config';\n *\n * export default defineAssemblyScriptConfig({\n * test: {\n * name: 'assemblyscript-unit-tests',\n * pool: 'vitest-pool-assemblyscript',\n * include: ['test/assembly/**/*.as.test.ts'], // example\n * poolOptions: {\n * assemblyScript: { // optional },\n * },\n * coverage: {\n * provider: 'custom',\n * customProviderModule: 'vitest-pool-assemblyscript/coverage',\n * include: ['src/**/*.ts'], // example JS/TS sources (v8 provider)\n * assemblyScriptInclude: ['assembly/**/*.ts'], // example AS sources\n * assemblyScriptExclude: ['**/*.as.test.ts'], // exclude AS test files\n * },\n * },\n * });\n * ```\n */\nexport function defineAssemblyScriptConfig(\n config: AssemblyScriptConfigExport\n): AssemblyScriptConfigExport;\nexport function defineAssemblyScriptConfig(\n config: Promise<AssemblyScriptConfigExport>\n): Promise<AssemblyScriptConfigExport>;\nexport function defineAssemblyScriptConfig(\n config: (env: ConfigEnv) => AssemblyScriptConfigExport | Promise<AssemblyScriptConfigExport>\n): (env: ConfigEnv) => AssemblyScriptConfigExport | Promise<AssemblyScriptConfigExport>;\nexport function defineAssemblyScriptConfig(\n config: AnyConfigExport<AssemblyScriptConfigExport>\n): AnyConfigExport<AssemblyScriptConfigExport> {\n // Pass through - this is just for type safety\n return config;\n}\n\n/**\n * Define a project-level Vitest config with AssemblyScript pool options.\n *\n * Use this when defining AssemblyScript test projects within a workspace.\n *\n * @example\n * ```ts\n * import { defineConfig, defineProject } from 'vitest/config';\n * import { defineAssemblyScriptProject } from 'vitest-pool-assemblyscript/config';\n *\n * export default defineConfig({\n * test: {\n * projects: [\n * defineProject({\n * test: {\n * name: { label: 'typescript-unit-tests', color: 'blue' },\n * }\n * }),\n * defineAssemblyScriptProject({\n * test: {\n * name: { label: 'assemblyscript-unit-tests', color: 'yellow' },\n * pool: 'vitest-pool-assemblyscript',\n * include: ['test/assembly/**/*.as.test.ts'], // example\n * poolOptions: {\n * assemblyScript: { // optional },\n * },\n * },\n * }),\n * ],\n * coverage: { // coverage section is global only in vitest\n * provider: 'custom',\n * customProviderModule: 'vitest-pool-assemblyscript/coverage',\n * include: ['src/**/*.ts'], // example JS/TS sources (v8 provider)\n * assemblyScriptInclude: ['assembly/**/*.ts'], // example AS sources\n * assemblyScriptExclude: ['**/*.as.test.ts'], // exclude AS test files\n * },\n * },\n * });\n * ```\n */\nexport function defineAssemblyScriptProject(\n config: AssemblyScriptProjectConfigExport\n): AssemblyScriptProjectConfigExport;\nexport function defineAssemblyScriptProject(\n config: Promise<AssemblyScriptProjectConfigExport>\n): Promise<AssemblyScriptProjectConfigExport>;\nexport function defineAssemblyScriptProject(\n config: (env: ConfigEnv) => AssemblyScriptProjectConfigExport | Promise<AssemblyScriptProjectConfigExport>\n): (env: ConfigEnv) => AssemblyScriptProjectConfigExport | Promise<AssemblyScriptProjectConfigExport>;\nexport function defineAssemblyScriptProject(\n config: AnyConfigExport<AssemblyScriptProjectConfigExport>\n): AnyConfigExport<AssemblyScriptProjectConfigExport> {\n // Pass through - this is just for type safety\n return config;\n}\n"],"mappings":";AA0FA,SAAgB,2BACd,QAC6C;AAE7C,QAAO;;AAoDT,SAAgB,4BACd,QACoD;AAEpD,QAAO"}
|
package/dist/config/index.d.mts
CHANGED
|
@@ -1,4 +1,29 @@
|
|
|
1
|
-
import { AssemblyScriptPoolOptions, WasmImportsFactory, WasmImportsFactoryInfo } from "../types-
|
|
2
|
-
import "../
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { AssemblyScriptPoolOptions, HybridProviderOptions, WasmImportsFactory, WasmImportsFactoryInfo } from "../types-DHVk5iAx.mjs";
|
|
2
|
+
import { createAssemblyScriptPool } from "../pool-runner-init-CNpRdA5u.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/config/coverage-options.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Module augmentation for vitest 4.1.1+ — augments `CoverageOptions` directly.
|
|
7
|
+
*
|
|
8
|
+
* In v4.1.1+ (vitest PR #9931), `CoverageOptions` was flattened from a
|
|
9
|
+
* generic discriminated type alias into a single interface that covers all
|
|
10
|
+
* coverage providers. `CustomProviderOptions` became a deprecated alias
|
|
11
|
+
* (`interface CustomProviderOptions extends CoverageOptions {}`), so the
|
|
12
|
+
* canonical augmentation point is now `CoverageOptions` itself.
|
|
13
|
+
*
|
|
14
|
+
* Adds AssemblyScript-specific coverage fields used by the hybrid coverage
|
|
15
|
+
* provider. `provider` and `customProviderModule` are already declared on
|
|
16
|
+
* `CoverageOptions` natively in v4.1.1+, so no narrowing is needed here.
|
|
17
|
+
*
|
|
18
|
+
* Loaded as a side-effect import from `./index.ts` (the v4 config entry
|
|
19
|
+
* point) so it only takes effect for users who explicitly import the v4
|
|
20
|
+
* entry. v3 users get the equivalent typing from
|
|
21
|
+
* `./custom-provider-options-v3.ts`, which augments `CustomProviderOptions`
|
|
22
|
+
* (the only augmentation point that's an interface in both versions).
|
|
23
|
+
*/
|
|
24
|
+
declare module "vitest/node" {
|
|
25
|
+
interface CoverageOptions extends HybridProviderOptions {}
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { type AssemblyScriptPoolOptions, type WasmImportsFactory, type WasmImportsFactoryInfo, createAssemblyScriptPool };
|
|
29
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/config/coverage-options.ts"],"mappings":";;;;;;;AAA2C;;;;;;;;;;;;;;;;;YAsB/B,eAAA,SAAwB,qBAAA;AAAA"}
|
package/dist/config/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import "../constants-
|
|
2
|
-
import "../resolve-config-
|
|
3
|
-
import "../debug-
|
|
4
|
-
import "../vitest-file-tasks-
|
|
5
|
-
import "../vitest-tasks
|
|
1
|
+
import "../constants-DbxJ3hzg.mjs";
|
|
2
|
+
import "../resolve-config-s9gSJSMc.mjs";
|
|
3
|
+
import "../debug-DtRAL4rM.mjs";
|
|
4
|
+
import "../vitest-file-tasks-D8sOClGX.mjs";
|
|
5
|
+
import "../vitest-tasks-BZ24sghI.mjs";
|
|
6
6
|
import "../worker-rpc-channel-CZZIxtv5.mjs";
|
|
7
|
-
import { createAssemblyScriptPool } from "../pool-runner-init-
|
|
7
|
+
import { createAssemblyScriptPool } from "../pool-runner-init-BqkwQ2tk.mjs";
|
|
8
8
|
|
|
9
9
|
export { createAssemblyScriptPool };
|