@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
|
@@ -4,46 +4,48 @@ An output symbol is a named entity that can be referenced in your output code.
|
|
|
4
4
|
|
|
5
5
|
## Members
|
|
6
6
|
|
|
7
|
-
| | |
|
|
8
|
-
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
9
|
-
| \_\_v\_skip | boolean |
|
|
10
|
-
| \[inspect.custom] | () => string |
|
|
11
|
-
| constructor | (name: string \| Namekey, spaces: OutputSpace\[] \| OutputSpace \| undefined, options: OutputSymbolOptions) | Constructs a new instance of the [`OutputSymbol`](OutputSymbol.md) class
|
|
12
|
-
| aliasTarget | [OutputSymbol](../outputsymbol/) \| undefined | The symbol that this symbol is an alias for.
|
|
13
|
-
| binder | [Binder](../binder/) \| undefined | The binder that is tracking this symbol.
|
|
14
|
-
|
|
|
15
|
-
|
|
|
16
|
-
|
|
|
17
|
-
|
|
|
18
|
-
|
|
|
19
|
-
|
|
|
20
|
-
|
|
|
21
|
-
|
|
|
22
|
-
|
|
|
23
|
-
|
|
|
24
|
-
|
|
|
25
|
-
|
|
|
26
|
-
|
|
|
27
|
-
|
|
|
28
|
-
|
|
|
29
|
-
|
|
|
30
|
-
|
|
|
31
|
-
|
|
|
32
|
-
|
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
|
|
|
37
|
-
|
|
|
38
|
-
|
|
|
39
|
-
|
|
|
40
|
-
|
|
|
41
|
-
|
|
|
42
|
-
|
|
|
43
|
-
|
|
|
44
|
-
|
|
|
45
|
-
|
|
|
46
|
-
|
|
|
7
|
+
| | | |
|
|
8
|
+
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
9
|
+
| \_\_v\_skip | boolean | |
|
|
10
|
+
| \[inspect.custom] | () => string | |
|
|
11
|
+
| constructor | (name: string \| Namekey, spaces: OutputSpace\[] \| OutputSpace \| undefined, options: OutputSymbolOptions) | Constructs a new instance of the [`OutputSymbol`](OutputSymbol.md) class |
|
|
12
|
+
| aliasTarget | [OutputSymbol](../outputsymbol/) \| undefined | The symbol that this symbol is an alias for. |
|
|
13
|
+
| binder | [Binder](../binder/) \| undefined | The binder that is tracking this symbol. |
|
|
14
|
+
| canonicalName | string | The canonical requested name for this symbol: the result of applying the symbol’s name policy to its originalName, or the original name itself when no policy applies. This is the name the symbol would carry if there were no conflicts, and is stable across the symbol’s lifetime (it depends only on the immutable `originalName` and the name policy). Used by [SymbolTable](../symboltable/) as the grouping key for name-conflict resolution, so that symbols whose original names normalize to the same policy-applied name (e.g. `foo_bar` and `fooBar` under camelCase) are recognized as conflicting. |
|
|
15
|
+
| copy | () => OutputSymbol | Create a clone of this symbol whose name and flags reactively track the original. |
|
|
16
|
+
| copyMembersTo | (targetSymbol: OutputSymbol) => void | Copy the members of this symbol to the target symbol. This is reactive - whenever a member is added to this symbol, it will be copied to the target symbol. |
|
|
17
|
+
| copyToSpace | (space: OutputSpace) => OutputSymbol | Copy this symbol into the given space. Calls \[unresolved link] and places the result in `space`, then returns the copy. |
|
|
18
|
+
| dealias | () => OutputSymbol | If this symbol is an alias for another symbol, return the the aliased symbol. Otherwise, return this symbol. |
|
|
19
|
+
| debugInfo | Record\<string, unknown> | |
|
|
20
|
+
| deconflictedName | string \| undefined | The name assigned by a name-conflict resolver, or `undefined` when the symbol is not currently renamed by conflict resolution. Resolvers should assign to this slot (rather than `name`) to record that a rename exists only because of a conflict. On re-deconfliction (e.g. after a conflicting symbol is removed), resolvers clear this slot by assigning `undefined`; the effective name then falls back to the user-assigned name, which in turn falls back to the original name. Name policy is applied to values written here (unless `ignoreNamePolicy` is true), matching `name`‘s behavior. |
|
|
21
|
+
| delete | () => void | |
|
|
22
|
+
| protected getCopyOptions | () => { binder: Binder \| undefined; aliasTarget: OutputSymbol \| undefined; metadata: Record\<string, unknown>; transient: boolean; } | |
|
|
23
|
+
| hasTypeSymbol | boolean | Whether this symbol has its symbol representing its type available. |
|
|
24
|
+
| id | number | The unique id of this symbol. |
|
|
25
|
+
| ignoreNameConflict | boolean | Whether the name of this symbol bypasses the active name conflict resolution. When true, the name of this symbol will be fixed, though it may conflict with other symbols which are also ignoring name conflict resolution. |
|
|
26
|
+
| ignoreNamePolicy | boolean | Whether the name of this symbol bypasses the active name policy. When true, the name of this symbol will be fixed, though it may conflict with other symbols which are also ignoring the name policy. |
|
|
27
|
+
| protected initializeCopy | (copy: OutputSymbol) => void | Wires up reactive member-space copying and name tracking from this symbol to its `copy`. |
|
|
28
|
+
| isAlias | boolean | Whether this symbol is an alias for another symbol. |
|
|
29
|
+
| isMemberSymbol | boolean | Whether this symbol is a member of another symbol. |
|
|
30
|
+
| isMoved | boolean | Whether this symbol’s members have been moved to another symbol. |
|
|
31
|
+
| isTransient | boolean | Whether this symbol is a transient symbol. Transient symbols cannot be referenced and are meant to be combined with other symbols. |
|
|
32
|
+
| isTyped | boolean | Whether this symbol’s members are provided by a type symbol. The `typeSymbol` property is this symbol. It may not be available yet, so check `hasTypeSymbol`. |
|
|
33
|
+
| memberSpaceFor | (spaceKey: string) => OutputMemberSpace \| undefined | Get the member space for the given key. |
|
|
34
|
+
| memberSpaces | [OutputMemberSpace](../outputmemberspace/)\[] | The member spaces of this symbol. |
|
|
35
|
+
| memberSpaces | Readonly\<string\[]> | The member space keys for this symbol type. Subclasses override this to declare which member spaces are created on construction (e.g., `["static", "instance"]`). |
|
|
36
|
+
| metadata | Record\<string, unknown> | An arbitrary bag of metadata for this symbol. This property is read only, but the metadata is a reactive object. |
|
|
37
|
+
| movedTo | [OutputSymbol](../outputsymbol/) \| undefined | The symbol that this symbol’s members have been moved to. |
|
|
38
|
+
| moveMembersTo | (targetSymbol: OutputSymbol) => void | Move member symbols from this transient symbol to the target symbol. This is reactive - whenever a member is added to this symbol, it will be moved to the target symbol. |
|
|
39
|
+
| name | string | The name of this symbol. Assigning to this property applies the active name policy (unless `ignoreNamePolicy` is true) before storing the value. The effective name is computed as `deconflictedName ?? userName`, so if a name-conflict resolver has assigned a deconflictedName, that value is returned here; otherwise the value most recently assigned to `name` is returned. |
|
|
40
|
+
| namePolicy | [NamePolicyGetter](../namepolicygetter/) \| undefined | |
|
|
41
|
+
| originalName | string | Read only. The requested name of this symbol. The symbol’s actual name may be different depending on naming policy or conflicts with other symbols. |
|
|
42
|
+
| ownerSymbol | [OutputSymbol](../outputsymbol/) \| undefined | When this is a member symbol, this returns the symbol that this is symbol is a member of. |
|
|
43
|
+
| refkeys | [Refkey](../refkey/)\[] | The refkeys for this symbol. |
|
|
44
|
+
| resolveMemberByName | (name: string) => OutputSymbol \| undefined | Get a member symbol by name from this symbol’s member spaces. Checks member spaces in order until it finds a member with that name. |
|
|
45
|
+
| scope | import(”./output-scope.js”).[OutputScope](../outputscope/) \| undefined | The scope this symbol is in. When this symbol is a member symbol, this will return undefined. |
|
|
46
|
+
| spaces | [OutputSpace](../outputspace/)\[] | The declaration or member spaces this symbol belongs to. |
|
|
47
|
+
| toString | () => string | |
|
|
48
|
+
| type | [OutputSymbol](../outputsymbol/) \| undefined | The symbol which defines the type of this symbol. The type symbol provides information about the value this symbol contains, such as what members it has. |
|
|
47
49
|
|
|
48
50
|
## Remarks
|
|
49
51
|
|
package/package.json
CHANGED
|
@@ -153,6 +153,19 @@ function isNodeEnvironment() {
|
|
|
153
153
|
);
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
// Cached once at module load. Stable for production runs. Tests that modify
|
|
157
|
+
// process.env.ALLOY_DEBUG dynamically must call refreshDebugState() afterward.
|
|
158
|
+
let _envDebugEnabled: boolean =
|
|
159
|
+
isNodeEnvironment() && Boolean(process.env.ALLOY_DEBUG);
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Invalidates the cached env-var result for isDevtoolsEnabled(). Call this in
|
|
163
|
+
* test beforeEach hooks after modifying process.env.ALLOY_DEBUG.
|
|
164
|
+
*/
|
|
165
|
+
export function refreshDebugState(): void {
|
|
166
|
+
_envDebugEnabled = isNodeEnvironment() && Boolean(process.env.ALLOY_DEBUG);
|
|
167
|
+
}
|
|
168
|
+
|
|
156
169
|
function getCwd() {
|
|
157
170
|
if (!isNodeEnvironment()) return undefined;
|
|
158
171
|
try {
|
|
@@ -177,7 +190,7 @@ function resolveDebugPort() {
|
|
|
177
190
|
/** Returns true when devtools are enabled (via env var or explicit call). */
|
|
178
191
|
export function isDevtoolsEnabled() {
|
|
179
192
|
if (!isNodeEnvironment()) return false;
|
|
180
|
-
return devtoolsExplicitlyEnabled ||
|
|
193
|
+
return devtoolsExplicitlyEnabled || _envDebugEnabled;
|
|
181
194
|
}
|
|
182
195
|
|
|
183
196
|
/** Returns true when a devtools client is currently connected. */
|
|
@@ -463,6 +476,8 @@ export async function resetDevtoolsServerForTests() {
|
|
|
463
476
|
loggedDevtoolsLinks = false;
|
|
464
477
|
subscribedPromise = null;
|
|
465
478
|
resolveSubscribed = null;
|
|
479
|
+
// Re-read the env var in case tests modified process.env.ALLOY_DEBUG
|
|
480
|
+
refreshDebugState();
|
|
466
481
|
// Close the trace DB so each test starts fresh
|
|
467
482
|
closeTrace();
|
|
468
483
|
}
|
package/src/reactivity.ts
CHANGED
|
@@ -255,13 +255,16 @@ export function effect<T>(
|
|
|
255
255
|
};
|
|
256
256
|
|
|
257
257
|
const debugInfo = options?.debug;
|
|
258
|
-
const effectId =
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
258
|
+
const effectId =
|
|
259
|
+
isDebugEnabled() ?
|
|
260
|
+
debug.effect.register({
|
|
261
|
+
name: debugInfo?.name ?? fn.name,
|
|
262
|
+
type: debugInfo?.type,
|
|
263
|
+
createdAt: captureSourceLocation(),
|
|
264
|
+
contextId: context.id,
|
|
265
|
+
ownerContextId: resolveOwnerEffectContextId(context),
|
|
266
|
+
})
|
|
267
|
+
: -1;
|
|
265
268
|
|
|
266
269
|
if (effectId !== -1) {
|
|
267
270
|
context.meta ??= {};
|
|
@@ -458,13 +461,15 @@ export function ref<T>(
|
|
|
458
461
|
options?: { isInfrastructure?: boolean },
|
|
459
462
|
): Ref<T> {
|
|
460
463
|
const result = vueRef(value) as Ref<T>;
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
464
|
+
if (isDebugEnabled()) {
|
|
465
|
+
debug.effect.registerRef({
|
|
466
|
+
id: refId(result),
|
|
467
|
+
kind: "ref",
|
|
468
|
+
createdAt: captureSourceLocation(),
|
|
469
|
+
createdByEffectId: globalContext?.meta?.effectId,
|
|
470
|
+
isInfrastructure: options?.isInfrastructure,
|
|
471
|
+
});
|
|
472
|
+
}
|
|
468
473
|
return result;
|
|
469
474
|
}
|
|
470
475
|
|
|
@@ -492,24 +497,28 @@ export function shallowReactive<T extends object>(
|
|
|
492
497
|
|
|
493
498
|
export function shallowRef<T>(value?: T, options?: { label?: string }): Ref<T> {
|
|
494
499
|
const result = vueShallowRef(value) as Ref<T>;
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
500
|
+
if (isDebugEnabled()) {
|
|
501
|
+
debug.effect.registerRef({
|
|
502
|
+
id: refId(result),
|
|
503
|
+
kind: "shallowRef",
|
|
504
|
+
label: options?.label,
|
|
505
|
+
createdAt: captureSourceLocation(),
|
|
506
|
+
createdByEffectId: globalContext?.meta?.effectId,
|
|
507
|
+
});
|
|
508
|
+
}
|
|
502
509
|
return result;
|
|
503
510
|
}
|
|
504
511
|
|
|
505
512
|
export function computed<T>(getter: () => T): Ref<T> {
|
|
506
513
|
const result = vueComputed(getter) as Ref<T>;
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
514
|
+
if (isDebugEnabled()) {
|
|
515
|
+
debug.effect.registerRef({
|
|
516
|
+
id: refId(result),
|
|
517
|
+
kind: "computed",
|
|
518
|
+
createdAt: captureSourceLocation(),
|
|
519
|
+
createdByEffectId: globalContext?.meta?.effectId,
|
|
520
|
+
});
|
|
521
|
+
}
|
|
513
522
|
return result;
|
|
514
523
|
}
|
|
515
524
|
|
|
@@ -522,12 +531,14 @@ export function toRef<T extends object, K extends keyof T>(
|
|
|
522
531
|
defaultValue === undefined ?
|
|
523
532
|
(vueToRef(object, key) as Ref<T[K]>)
|
|
524
533
|
: (vueToRef(object, key, defaultValue) as Ref<T[K]>);
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
534
|
+
if (isDebugEnabled()) {
|
|
535
|
+
debug.effect.registerRef({
|
|
536
|
+
id: refId(result),
|
|
537
|
+
kind: "toRef",
|
|
538
|
+
createdAt: captureSourceLocation(),
|
|
539
|
+
createdByEffectId: globalContext?.meta?.effectId,
|
|
540
|
+
});
|
|
541
|
+
}
|
|
531
542
|
return result;
|
|
532
543
|
}
|
|
533
544
|
|
|
@@ -535,13 +546,15 @@ export function toRefs<T extends object>(
|
|
|
535
546
|
object: T,
|
|
536
547
|
): { [K in keyof T]: Ref<T[K]> } {
|
|
537
548
|
const result = vueToRefs(object) as { [K in keyof T]: Ref<T[K]> };
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
549
|
+
if (isDebugEnabled()) {
|
|
550
|
+
for (const refValue of Object.values(result) as Ref<unknown>[]) {
|
|
551
|
+
debug.effect.registerRef({
|
|
552
|
+
id: refId(refValue),
|
|
553
|
+
kind: "toRef",
|
|
554
|
+
createdAt: captureSourceLocation(),
|
|
555
|
+
createdByEffectId: globalContext?.meta?.effectId,
|
|
556
|
+
});
|
|
557
|
+
}
|
|
545
558
|
}
|
|
546
559
|
return result;
|
|
547
560
|
}
|
|
@@ -178,31 +178,113 @@ export abstract class OutputSymbol {
|
|
|
178
178
|
return this.#originalName;
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
//
|
|
182
|
-
|
|
181
|
+
// The user-assigned name (as set by constructor or direct `.name =`
|
|
182
|
+
// assignments). Always defined after construction.
|
|
183
|
+
#userName!: string;
|
|
184
|
+
|
|
185
|
+
// The name assigned by a name-conflict resolver, if any. When present, this
|
|
186
|
+
// takes precedence over `#userName` in the computed `name` getter. Resolvers
|
|
187
|
+
// assign via the `deconflictedName` setter; clearing (setting to undefined)
|
|
188
|
+
// causes the symbol to fall back to its user-assigned name.
|
|
189
|
+
#deconflictedName: string | undefined;
|
|
190
|
+
|
|
183
191
|
/**
|
|
184
192
|
* The name of this symbol. Assigning to this property applies the active
|
|
185
193
|
* name policy (unless `ignoreNamePolicy` is true) before storing the value.
|
|
186
194
|
*
|
|
195
|
+
* The effective name is computed as `deconflictedName ?? userName`, so if a
|
|
196
|
+
* name-conflict resolver has assigned a {@link OutputSymbol.deconflictedName | deconflictedName}, that value
|
|
197
|
+
* is returned here; otherwise the value most recently assigned to `name` is
|
|
198
|
+
* returned.
|
|
199
|
+
*
|
|
187
200
|
* @reactive
|
|
188
201
|
*/
|
|
189
202
|
get name() {
|
|
190
203
|
track(this, TrackOpTypes.GET, "name");
|
|
191
|
-
return this.#
|
|
204
|
+
return this.#deconflictedName ?? this.#userName;
|
|
192
205
|
}
|
|
193
206
|
|
|
194
207
|
set name(name: string) {
|
|
195
|
-
const
|
|
208
|
+
const policyApplied =
|
|
209
|
+
this.#namePolicy && !this.#ignoreNamePolicy ?
|
|
210
|
+
this.#namePolicy(name)
|
|
211
|
+
: name;
|
|
196
212
|
|
|
197
|
-
if (
|
|
213
|
+
if (this.#userName === policyApplied) {
|
|
198
214
|
return;
|
|
199
215
|
}
|
|
200
216
|
|
|
201
|
-
this.#
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
217
|
+
const old = this.#deconflictedName ?? this.#userName;
|
|
218
|
+
this.#userName = policyApplied;
|
|
219
|
+
const next = this.#deconflictedName ?? this.#userName;
|
|
220
|
+
if (next !== old) {
|
|
221
|
+
trigger(this, TriggerOpTypes.SET, "name", next, old);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* The name assigned by a name-conflict resolver, or `undefined` when the
|
|
227
|
+
* symbol is not currently renamed by conflict resolution.
|
|
228
|
+
*
|
|
229
|
+
* Resolvers should assign to this slot (rather than `name`) to record that a
|
|
230
|
+
* rename exists only because of a conflict. On re-deconfliction (e.g. after
|
|
231
|
+
* a conflicting symbol is removed), resolvers clear this slot by assigning
|
|
232
|
+
* `undefined`; the effective {@link OutputSymbol.name | name} then falls back to the
|
|
233
|
+
* user-assigned name, which in turn falls back to the original name.
|
|
234
|
+
*
|
|
235
|
+
* Name policy is applied to values written here (unless `ignoreNamePolicy`
|
|
236
|
+
* is true), matching `name`'s behavior.
|
|
237
|
+
*
|
|
238
|
+
* @reactive
|
|
239
|
+
*/
|
|
240
|
+
get deconflictedName(): string | undefined {
|
|
241
|
+
track(this, TrackOpTypes.GET, "deconflictedName");
|
|
242
|
+
return this.#deconflictedName;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
set deconflictedName(value: string | undefined) {
|
|
246
|
+
const policyApplied =
|
|
247
|
+
value !== undefined && this.#namePolicy && !this.#ignoreNamePolicy ?
|
|
248
|
+
this.#namePolicy(value)
|
|
249
|
+
: value;
|
|
250
|
+
|
|
251
|
+
if (this.#deconflictedName === policyApplied) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const oldName = this.#deconflictedName ?? this.#userName;
|
|
256
|
+
const oldDeconflicted = this.#deconflictedName;
|
|
257
|
+
this.#deconflictedName = policyApplied;
|
|
258
|
+
trigger(
|
|
259
|
+
this,
|
|
260
|
+
TriggerOpTypes.SET,
|
|
261
|
+
"deconflictedName",
|
|
262
|
+
policyApplied,
|
|
263
|
+
oldDeconflicted,
|
|
264
|
+
);
|
|
265
|
+
const nextName = this.#deconflictedName ?? this.#userName;
|
|
266
|
+
if (nextName !== oldName) {
|
|
267
|
+
trigger(this, TriggerOpTypes.SET, "name", nextName, oldName);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* The canonical requested name for this symbol: the result of applying the
|
|
273
|
+
* symbol's name policy to its {@link OutputSymbol.originalName | originalName}, or the original name
|
|
274
|
+
* itself when no policy applies. This is the name the symbol would carry if
|
|
275
|
+
* there were no conflicts, and is stable across the symbol's lifetime (it
|
|
276
|
+
* depends only on the immutable `originalName` and the name policy).
|
|
277
|
+
*
|
|
278
|
+
* Used by {@link SymbolTable} as the grouping key for name-conflict
|
|
279
|
+
* resolution, so that symbols whose original names normalize to the same
|
|
280
|
+
* policy-applied name (e.g. `foo_bar` and `fooBar` under camelCase) are
|
|
281
|
+
* recognized as conflicting.
|
|
282
|
+
*/
|
|
283
|
+
get canonicalName(): string {
|
|
284
|
+
if (this.#ignoreNamePolicy || !this.#namePolicy) {
|
|
285
|
+
return this.originalName;
|
|
286
|
+
}
|
|
287
|
+
return this.#namePolicy(this.originalName);
|
|
206
288
|
}
|
|
207
289
|
|
|
208
290
|
#id: number;
|
|
@@ -13,7 +13,7 @@ export abstract class SymbolTable extends ReactiveUnionSet<OutputSymbol> {
|
|
|
13
13
|
#deconflictNames = () => {
|
|
14
14
|
for (const name of this.#namesToDeconflict) {
|
|
15
15
|
const conflictedSymbols = [...this].filter(
|
|
16
|
-
(sym) => sym.
|
|
16
|
+
(sym) => sym.canonicalName === name && !sym.ignoreNameConflict,
|
|
17
17
|
);
|
|
18
18
|
if (this.#nameConflictResolver) {
|
|
19
19
|
this.#nameConflictResolver(name, conflictedSymbols);
|
|
@@ -67,7 +67,7 @@ export abstract class SymbolTable extends ReactiveUnionSet<OutputSymbol> {
|
|
|
67
67
|
`${formatSymbolName(symbol)} added to ${formatSymbolTableName(this)}`,
|
|
68
68
|
);
|
|
69
69
|
|
|
70
|
-
this.#namesToDeconflict.add(symbol.
|
|
70
|
+
this.#namesToDeconflict.add(symbol.canonicalName);
|
|
71
71
|
|
|
72
72
|
queueJob(this.#deconflictNames);
|
|
73
73
|
|
|
@@ -79,6 +79,12 @@ export abstract class SymbolTable extends ReactiveUnionSet<OutputSymbol> {
|
|
|
79
79
|
() =>
|
|
80
80
|
`${formatSymbolName(symbol)} removed from ${formatSymbolTableName(this)}`,
|
|
81
81
|
);
|
|
82
|
+
// Re-run conflict resolution for the deleted symbol's canonical name
|
|
83
|
+
// so survivors in the same cohort (those that share the canonical
|
|
84
|
+
// name) can clear any prior `deconflictedName` rename now that the
|
|
85
|
+
// collision is reduced.
|
|
86
|
+
this.#namesToDeconflict.add(symbol.canonicalName);
|
|
87
|
+
queueJob(this.#deconflictNames);
|
|
82
88
|
},
|
|
83
89
|
});
|
|
84
90
|
|
|
@@ -135,8 +141,12 @@ export abstract class SymbolTable extends ReactiveUnionSet<OutputSymbol> {
|
|
|
135
141
|
* to have a suffix of _2, _3, etc.
|
|
136
142
|
*/
|
|
137
143
|
function defaultConflictHandler(_: string, conflictedSymbols: OutputSymbol[]) {
|
|
144
|
+
if (conflictedSymbols.length === 0) return;
|
|
145
|
+
// The first symbol keeps its original name; clear any prior deconflict
|
|
146
|
+
// rename so it reverts after a collision is resolved.
|
|
147
|
+
conflictedSymbols[0].deconflictedName = undefined;
|
|
138
148
|
for (let i = 1; i < conflictedSymbols.length; i++) {
|
|
139
|
-
conflictedSymbols[i].
|
|
149
|
+
conflictedSymbols[i].deconflictedName =
|
|
140
150
|
conflictedSymbols[i].originalName + "_" + (i + 1);
|
|
141
151
|
}
|
|
142
152
|
}
|
package/temp/api.json
CHANGED
|
@@ -17645,6 +17645,36 @@
|
|
|
17645
17645
|
"isProtected": false,
|
|
17646
17646
|
"isAbstract": false
|
|
17647
17647
|
},
|
|
17648
|
+
{
|
|
17649
|
+
"kind": "Property",
|
|
17650
|
+
"canonicalReference": "@alloy-js/core!OutputSymbol#canonicalName:member",
|
|
17651
|
+
"docComment": "/**\n * The canonical requested name for this symbol: the result of applying the\n * symbol's name policy to its {@link OutputSymbol.originalName | originalName}, or the original name\n * itself when no policy applies. This is the name the symbol would carry if\n * there were no conflicts, and is stable across the symbol's lifetime (it\n * depends only on the immutable `originalName` and the name policy).\n *\n * Used by {@link SymbolTable} as the grouping key for name-conflict\n * resolution, so that symbols whose original names normalize to the same\n * policy-applied name (e.g. `foo_bar` and `fooBar` under camelCase) are\n * recognized as conflicting.\n */\n",
|
|
17652
|
+
"excerptTokens": [
|
|
17653
|
+
{
|
|
17654
|
+
"kind": "Content",
|
|
17655
|
+
"text": "get canonicalName(): "
|
|
17656
|
+
},
|
|
17657
|
+
{
|
|
17658
|
+
"kind": "Content",
|
|
17659
|
+
"text": "string"
|
|
17660
|
+
},
|
|
17661
|
+
{
|
|
17662
|
+
"kind": "Content",
|
|
17663
|
+
"text": ";"
|
|
17664
|
+
}
|
|
17665
|
+
],
|
|
17666
|
+
"isReadonly": true,
|
|
17667
|
+
"isOptional": false,
|
|
17668
|
+
"releaseTag": "Public",
|
|
17669
|
+
"name": "canonicalName",
|
|
17670
|
+
"propertyTypeTokenRange": {
|
|
17671
|
+
"startIndex": 1,
|
|
17672
|
+
"endIndex": 2
|
|
17673
|
+
},
|
|
17674
|
+
"isStatic": false,
|
|
17675
|
+
"isProtected": false,
|
|
17676
|
+
"isAbstract": false
|
|
17677
|
+
},
|
|
17648
17678
|
{
|
|
17649
17679
|
"kind": "Method",
|
|
17650
17680
|
"canonicalReference": "@alloy-js/core!OutputSymbol#copy:member(1)",
|
|
@@ -17843,6 +17873,36 @@
|
|
|
17843
17873
|
"isProtected": false,
|
|
17844
17874
|
"isAbstract": false
|
|
17845
17875
|
},
|
|
17876
|
+
{
|
|
17877
|
+
"kind": "Property",
|
|
17878
|
+
"canonicalReference": "@alloy-js/core!OutputSymbol#deconflictedName:member",
|
|
17879
|
+
"docComment": "/**\n * The name assigned by a name-conflict resolver, or `undefined` when the\n * symbol is not currently renamed by conflict resolution.\n *\n * Resolvers should assign to this slot (rather than `name`) to record that a\n * rename exists only because of a conflict. On re-deconfliction (e.g. after\n * a conflicting symbol is removed), resolvers clear this slot by assigning\n * `undefined`; the effective {@link OutputSymbol.name | name} then falls back to the\n * user-assigned name, which in turn falls back to the original name.\n *\n * Name policy is applied to values written here (unless `ignoreNamePolicy`\n * is true), matching `name`'s behavior.\n *\n *\n * @reactive\n */\n",
|
|
17880
|
+
"excerptTokens": [
|
|
17881
|
+
{
|
|
17882
|
+
"kind": "Content",
|
|
17883
|
+
"text": "get deconflictedName(): "
|
|
17884
|
+
},
|
|
17885
|
+
{
|
|
17886
|
+
"kind": "Content",
|
|
17887
|
+
"text": "string | undefined"
|
|
17888
|
+
},
|
|
17889
|
+
{
|
|
17890
|
+
"kind": "Content",
|
|
17891
|
+
"text": ";\n\nset deconflictedName(value: string | undefined);"
|
|
17892
|
+
}
|
|
17893
|
+
],
|
|
17894
|
+
"isReadonly": false,
|
|
17895
|
+
"isOptional": false,
|
|
17896
|
+
"releaseTag": "Public",
|
|
17897
|
+
"name": "deconflictedName",
|
|
17898
|
+
"propertyTypeTokenRange": {
|
|
17899
|
+
"startIndex": 1,
|
|
17900
|
+
"endIndex": 2
|
|
17901
|
+
},
|
|
17902
|
+
"isStatic": false,
|
|
17903
|
+
"isProtected": false,
|
|
17904
|
+
"isAbstract": false
|
|
17905
|
+
},
|
|
17846
17906
|
{
|
|
17847
17907
|
"kind": "Method",
|
|
17848
17908
|
"canonicalReference": "@alloy-js/core!OutputSymbol#delete:member(1)",
|
|
@@ -18496,7 +18556,7 @@
|
|
|
18496
18556
|
{
|
|
18497
18557
|
"kind": "Property",
|
|
18498
18558
|
"canonicalReference": "@alloy-js/core!OutputSymbol#name:member",
|
|
18499
|
-
"docComment": "/**\n * The name of this symbol. Assigning to this property applies the active\n * name policy (unless `ignoreNamePolicy` is true) before storing the value.\n *\n *\n * @reactive\n */\n",
|
|
18559
|
+
"docComment": "/**\n * The name of this symbol. Assigning to this property applies the active\n * name policy (unless `ignoreNamePolicy` is true) before storing the value.\n *\n * The effective name is computed as `deconflictedName ?? userName`, so if a\n * name-conflict resolver has assigned a {@link OutputSymbol.deconflictedName | deconflictedName}, that value\n * is returned here; otherwise the value most recently assigned to `name` is\n * returned.\n *\n *\n * @reactive\n */\n",
|
|
18500
18560
|
"excerptTokens": [
|
|
18501
18561
|
{
|
|
18502
18562
|
"kind": "Content",
|