@alloy-js/core 0.23.0-dev.17 → 0.23.0-dev.19
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/dist/dev/src/devtools/devtools-server.browser.js +3 -0
- package/dist/dev/src/devtools/devtools-server.browser.js.map +1 -1
- package/dist/dev/src/devtools/devtools-server.js +15 -1
- package/dist/dev/src/devtools/devtools-server.js.map +1 -1
- package/dist/dev/src/reactivity.js +44 -34
- package/dist/dev/src/reactivity.js.map +1 -1
- package/dist/dev/src/symbols/output-symbol.js +77 -7
- package/dist/dev/src/symbols/output-symbol.js.map +1 -1
- package/dist/dev/src/symbols/symbol-table.js +13 -3
- package/dist/dev/src/symbols/symbol-table.js.map +1 -1
- package/dist/dev/test/reactivity/shallow-reactive.test.js +4 -0
- package/dist/dev/test/reactivity/shallow-reactive.test.js.map +1 -1
- package/dist/dev/test/symbols/deconflicted-name.test.js +120 -0
- package/dist/dev/test/symbols/deconflicted-name.test.js.map +1 -0
- package/dist/dev/test/symbols/output-scope.test.js +41 -0
- package/dist/dev/test/symbols/output-scope.test.js.map +1 -1
- package/dist/src/devtools/devtools-server.browser.d.ts +1 -0
- package/dist/src/devtools/devtools-server.browser.d.ts.map +1 -1
- package/dist/src/devtools/devtools-server.browser.js +3 -0
- package/dist/src/devtools/devtools-server.browser.js.map +1 -1
- package/dist/src/devtools/devtools-server.d.ts +5 -0
- package/dist/src/devtools/devtools-server.d.ts.map +1 -1
- package/dist/src/devtools/devtools-server.js +15 -1
- package/dist/src/devtools/devtools-server.js.map +1 -1
- package/dist/src/reactivity.d.ts.map +1 -1
- package/dist/src/reactivity.js +44 -34
- package/dist/src/reactivity.js.map +1 -1
- package/dist/src/symbols/output-symbol.d.ts +35 -0
- package/dist/src/symbols/output-symbol.d.ts.map +1 -1
- package/dist/src/symbols/output-symbol.js +77 -7
- package/dist/src/symbols/output-symbol.js.map +1 -1
- package/dist/src/symbols/symbol-table.d.ts.map +1 -1
- package/dist/src/symbols/symbol-table.js +13 -3
- package/dist/src/symbols/symbol-table.js.map +1 -1
- package/dist/test/reactivity/shallow-reactive.test.js +4 -0
- package/dist/test/reactivity/shallow-reactive.test.js.map +1 -1
- package/dist/test/symbols/deconflicted-name.test.d.ts +2 -0
- package/dist/test/symbols/deconflicted-name.test.d.ts.map +1 -0
- package/dist/test/symbols/deconflicted-name.test.js +120 -0
- package/dist/test/symbols/deconflicted-name.test.js.map +1 -0
- package/dist/test/symbols/output-scope.test.js +41 -0
- package/dist/test/symbols/output-scope.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/docs/api/types/OutputSymbol.md +42 -40
- package/package.json +1 -1
- package/src/devtools/devtools-server.browser.ts +4 -0
- package/src/devtools/devtools-server.ts +16 -1
- package/src/reactivity.ts +53 -40
- package/src/symbols/output-symbol.ts +92 -10
- package/src/symbols/symbol-table.ts +13 -3
- package/temp/api.json +61 -1
- package/test/reactivity/shallow-reactive.test.tsx +4 -0
- package/test/symbols/deconflicted-name.test.ts +120 -0
- package/test/symbols/output-scope.test.ts +38 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
2
|
+
import { refreshDebugState } from "../../src/devtools/devtools-server.js";
|
|
2
3
|
import {
|
|
3
4
|
getReactiveCreationLocation,
|
|
4
5
|
shallowReactive,
|
|
@@ -10,6 +11,7 @@ describe("shallowReactive creation location", () => {
|
|
|
10
11
|
beforeEach(() => {
|
|
11
12
|
origDebug = process.env.ALLOY_DEBUG;
|
|
12
13
|
process.env.ALLOY_DEBUG = "1";
|
|
14
|
+
refreshDebugState();
|
|
13
15
|
});
|
|
14
16
|
|
|
15
17
|
afterEach(() => {
|
|
@@ -18,6 +20,7 @@ describe("shallowReactive creation location", () => {
|
|
|
18
20
|
} else {
|
|
19
21
|
process.env.ALLOY_DEBUG = origDebug;
|
|
20
22
|
}
|
|
23
|
+
refreshDebugState();
|
|
21
24
|
});
|
|
22
25
|
|
|
23
26
|
it("stores creation location keyed by raw target when debug enabled", () => {
|
|
@@ -31,6 +34,7 @@ describe("shallowReactive creation location", () => {
|
|
|
31
34
|
|
|
32
35
|
it("does not store location when debug is disabled", () => {
|
|
33
36
|
delete process.env.ALLOY_DEBUG;
|
|
37
|
+
refreshDebugState();
|
|
34
38
|
const raw = { y: 2 };
|
|
35
39
|
shallowReactive(raw);
|
|
36
40
|
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { Binder, createOutputBinder } from "../../src/binder.js";
|
|
3
|
+
import { flushJobs } from "../../src/scheduler.js";
|
|
4
|
+
import { BasicScope } from "../../src/symbols/basic-scope.js";
|
|
5
|
+
import { BasicSymbol } from "../../src/symbols/basic-symbol.js";
|
|
6
|
+
import type { OutputSymbol } from "../../src/symbols/output-symbol.js";
|
|
7
|
+
|
|
8
|
+
function setup(
|
|
9
|
+
nameConflictResolver?: (name: string, syms: OutputSymbol[]) => void,
|
|
10
|
+
) {
|
|
11
|
+
const binder: Binder = createOutputBinder({ nameConflictResolver });
|
|
12
|
+
const scope = new BasicScope("root", undefined, { binder });
|
|
13
|
+
return { binder, scope };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
describe("deconflictedName", () => {
|
|
17
|
+
it("default resolver renames losers via deconflictedName and reverts on removal", () => {
|
|
18
|
+
const { scope } = setup();
|
|
19
|
+
const a = new BasicSymbol("foo", scope.symbols, {});
|
|
20
|
+
const b = new BasicSymbol("foo", scope.symbols, {});
|
|
21
|
+
flushJobs();
|
|
22
|
+
expect(a.name).toBe("foo");
|
|
23
|
+
expect(b.name).toBe("foo_2");
|
|
24
|
+
expect(a.deconflictedName).toBeUndefined();
|
|
25
|
+
expect(b.deconflictedName).toBe("foo_2");
|
|
26
|
+
|
|
27
|
+
b.delete();
|
|
28
|
+
flushJobs();
|
|
29
|
+
expect(a.name).toBe("foo");
|
|
30
|
+
expect(a.deconflictedName).toBeUndefined();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("works with a custom rename scheme that doesn't match the default _N pattern", () => {
|
|
34
|
+
// Resolver uses a `$foo` prefix instead of `foo_N` suffix — the old
|
|
35
|
+
// isAutoAlias regex would never match this.
|
|
36
|
+
const customResolver = (_: string, symbols: OutputSymbol[]) => {
|
|
37
|
+
if (symbols.length === 0) return;
|
|
38
|
+
symbols[0].deconflictedName = undefined;
|
|
39
|
+
for (let i = 1; i < symbols.length; i++) {
|
|
40
|
+
symbols[i].deconflictedName = "$" + symbols[i].originalName;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const { scope } = setup(customResolver);
|
|
44
|
+
|
|
45
|
+
const a = new BasicSymbol("foo", scope.symbols, {});
|
|
46
|
+
const b = new BasicSymbol("foo", scope.symbols, {});
|
|
47
|
+
flushJobs();
|
|
48
|
+
expect(a.name).toBe("foo");
|
|
49
|
+
expect(b.name).toBe("$foo");
|
|
50
|
+
|
|
51
|
+
b.delete();
|
|
52
|
+
flushJobs();
|
|
53
|
+
// Survivor reverts to the original name regardless of scheme.
|
|
54
|
+
expect(a.name).toBe("foo");
|
|
55
|
+
expect(a.deconflictedName).toBeUndefined();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("direct .name assignment does not clear an active deconflictedName", () => {
|
|
59
|
+
const { scope } = setup();
|
|
60
|
+
const a = new BasicSymbol("foo", scope.symbols, {});
|
|
61
|
+
const b = new BasicSymbol("foo", scope.symbols, {});
|
|
62
|
+
flushJobs();
|
|
63
|
+
expect(b.name).toBe("foo_2");
|
|
64
|
+
|
|
65
|
+
// User-assigns the name while a conflict rename is active.
|
|
66
|
+
b.name = "bar";
|
|
67
|
+
// Effective name still shows the deconflict rename (resolver wins while active).
|
|
68
|
+
expect(b.name).toBe("foo_2");
|
|
69
|
+
|
|
70
|
+
// Once the collision clears, the user-assigned name takes effect.
|
|
71
|
+
a.delete();
|
|
72
|
+
flushJobs();
|
|
73
|
+
expect(b.deconflictedName).toBeUndefined();
|
|
74
|
+
expect(b.name).toBe("bar");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("detects conflict when different original names normalize to the same policy name", () => {
|
|
78
|
+
// Mirrors PR #394: under camelCase, `foo_bar` and `fooBar` both become
|
|
79
|
+
// `fooBar` — they collide on the rendered name and should be deconflicted.
|
|
80
|
+
const toCamel = (n: string) =>
|
|
81
|
+
n.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
82
|
+
const { scope } = setup();
|
|
83
|
+
|
|
84
|
+
const a = new BasicSymbol("foo_bar", scope.symbols, {
|
|
85
|
+
namePolicy: toCamel,
|
|
86
|
+
});
|
|
87
|
+
const b = new BasicSymbol("fooBar", scope.symbols, {
|
|
88
|
+
namePolicy: toCamel,
|
|
89
|
+
});
|
|
90
|
+
flushJobs();
|
|
91
|
+
|
|
92
|
+
expect(a.name).toBe("fooBar");
|
|
93
|
+
// Without canonical-name grouping, `b` would keep its original `fooBar`
|
|
94
|
+
// and silently collide with `a`'s policy-applied name.
|
|
95
|
+
expect(b.name).not.toBe("fooBar");
|
|
96
|
+
expect(b.name).toMatch(/^fooBar/);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("survivor reverts when the winner is removed (canonical-name cohort lookup)", () => {
|
|
100
|
+
// After `a` is removed, the delete hook must find `b` as a member of the
|
|
101
|
+
// same canonical-name cohort so it can clear its deconflictedName.
|
|
102
|
+
const toCamel = (n: string) =>
|
|
103
|
+
n.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
104
|
+
const { scope } = setup();
|
|
105
|
+
|
|
106
|
+
const a = new BasicSymbol("foo_bar", scope.symbols, {
|
|
107
|
+
namePolicy: toCamel,
|
|
108
|
+
});
|
|
109
|
+
const b = new BasicSymbol("fooBar", scope.symbols, {
|
|
110
|
+
namePolicy: toCamel,
|
|
111
|
+
});
|
|
112
|
+
flushJobs();
|
|
113
|
+
expect(b.deconflictedName).toBeDefined();
|
|
114
|
+
|
|
115
|
+
a.delete();
|
|
116
|
+
flushJobs();
|
|
117
|
+
expect(b.deconflictedName).toBeUndefined();
|
|
118
|
+
expect(b.name).toBe("fooBar");
|
|
119
|
+
});
|
|
120
|
+
});
|
|
@@ -206,3 +206,41 @@ describe("OutputScope#children", () => {
|
|
|
206
206
|
expect(child2.parent).toBe(parentScope);
|
|
207
207
|
});
|
|
208
208
|
});
|
|
209
|
+
|
|
210
|
+
describe("symbol name deduplication with name policy", () => {
|
|
211
|
+
it("deduplicates symbols whose names collide after name policy", () => {
|
|
212
|
+
const scope = createScope("scope");
|
|
213
|
+
const policy = (name: string) => name.toUpperCase();
|
|
214
|
+
const [s1] = createSymbol("foo", scope, { namePolicy: policy });
|
|
215
|
+
const [s2] = createSymbol("FOO", scope, { namePolicy: policy });
|
|
216
|
+
|
|
217
|
+
flushJobs();
|
|
218
|
+
|
|
219
|
+
expect(s1.name).toBe("FOO");
|
|
220
|
+
expect(s2.name).toBe("FOO_2");
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it("deduplicates symbols when policy adds a prefix", () => {
|
|
224
|
+
const scope = createScope("scope");
|
|
225
|
+
const policy = (name: string) => (name === "reserved" ? `@${name}` : name);
|
|
226
|
+
const [s1] = createSymbol("reserved", scope, { namePolicy: policy });
|
|
227
|
+
const [s2] = createSymbol("reserved", scope, { namePolicy: policy });
|
|
228
|
+
|
|
229
|
+
flushJobs();
|
|
230
|
+
|
|
231
|
+
expect(s1.name).toBe("@reserved");
|
|
232
|
+
expect(s2.name).toBe("reserved_2");
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it("does not deduplicates symbols with different names after policy", () => {
|
|
236
|
+
const scope = createScope("scope");
|
|
237
|
+
const policy = (name: string) => `prefix_${name}`;
|
|
238
|
+
const [s1] = createSymbol("foo", scope, { namePolicy: policy });
|
|
239
|
+
const [s2] = createSymbol("bar", scope, { namePolicy: policy });
|
|
240
|
+
|
|
241
|
+
flushJobs();
|
|
242
|
+
|
|
243
|
+
expect(s1.name).toBe("prefix_foo");
|
|
244
|
+
expect(s2.name).toBe("prefix_bar");
|
|
245
|
+
});
|
|
246
|
+
});
|