@alloy-js/core 0.16.0 → 0.18.0-dev.2
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/CHANGELOG.md +15 -0
- package/dist/src/binder.d.ts +19 -235
- package/dist/src/binder.d.ts.map +1 -1
- package/dist/src/binder.js +85 -386
- package/dist/src/code.d.ts +1 -1
- package/dist/src/code.d.ts.map +1 -1
- package/dist/src/components/Block.d.ts +1 -1
- package/dist/src/components/Block.d.ts.map +1 -1
- package/dist/src/components/Block.js +3 -1
- package/dist/src/components/Declaration.d.ts +2 -2
- package/dist/src/components/Declaration.d.ts.map +1 -1
- package/dist/src/components/Declaration.js +6 -5
- package/dist/src/components/For.d.ts +1 -1
- package/dist/src/components/For.d.ts.map +1 -1
- package/dist/src/components/For.js +1 -1
- package/dist/src/components/Indent.d.ts +1 -1
- package/dist/src/components/Indent.d.ts.map +1 -1
- package/dist/src/components/List.d.ts +1 -1
- package/dist/src/components/List.d.ts.map +1 -1
- package/dist/src/components/List.js +3 -1
- package/dist/src/components/MemberDeclaration.d.ts +3 -3
- package/dist/src/components/MemberDeclaration.d.ts.map +1 -1
- package/dist/src/components/MemberDeclaration.js +4 -4
- package/dist/src/components/MemberScope.d.ts +2 -2
- package/dist/src/components/MemberScope.d.ts.map +1 -1
- package/dist/src/components/MemberScope.js +0 -2
- package/dist/src/components/Output.d.ts +1 -1
- package/dist/src/components/Output.d.ts.map +1 -1
- package/dist/src/components/Output.js +1 -1
- package/dist/src/components/Prose.d.ts +1 -1
- package/dist/src/components/Prose.d.ts.map +1 -1
- package/dist/src/components/ReferenceOrContent.d.ts +1 -1
- package/dist/src/components/ReferenceOrContent.d.ts.map +1 -1
- package/dist/src/components/Scope.d.ts +2 -2
- package/dist/src/components/Scope.d.ts.map +1 -1
- package/dist/src/components/Scope.js +3 -6
- package/dist/src/components/Show.d.ts +1 -1
- package/dist/src/components/Show.d.ts.map +1 -1
- package/dist/src/components/SourceDirectory.d.ts +1 -1
- package/dist/src/components/SourceDirectory.d.ts.map +1 -1
- package/dist/src/components/SourceDirectory.js +1 -1
- package/dist/src/components/SourceFile.d.ts +1 -1
- package/dist/src/components/SourceFile.d.ts.map +1 -1
- package/dist/src/components/SourceFile.js +1 -1
- package/dist/src/components/StatementList.d.ts +1 -1
- package/dist/src/components/StatementList.d.ts.map +1 -1
- package/dist/src/components/StatementList.js +1 -1
- package/dist/src/components/Switch.d.ts +2 -2
- package/dist/src/components/Switch.d.ts.map +1 -1
- package/dist/src/components/Switch.js +2 -1
- package/dist/src/components/Wrap.d.ts +1 -1
- package/dist/src/components/Wrap.d.ts.map +1 -1
- package/dist/src/context/assignment.d.ts +1 -1
- package/dist/src/context/assignment.d.ts.map +1 -1
- package/dist/src/context/binder.d.ts +3 -3
- package/dist/src/context/binder.d.ts.map +1 -1
- package/dist/src/context/declaration.d.ts +1 -1
- package/dist/src/context/declaration.d.ts.map +1 -1
- package/dist/src/context/member-declaration.d.ts +1 -1
- package/dist/src/context/member-declaration.d.ts.map +1 -1
- package/dist/src/context/member-declaration.js +0 -1
- package/dist/src/context/member-scope.d.ts +1 -1
- package/dist/src/context/member-scope.d.ts.map +1 -1
- package/dist/src/context/name-policy.d.ts +1 -1
- package/dist/src/context/name-policy.d.ts.map +1 -1
- package/dist/src/context/scope.d.ts +1 -1
- package/dist/src/context/scope.d.ts.map +1 -1
- package/dist/src/context/source-directory.d.ts +1 -1
- package/dist/src/context/source-directory.d.ts.map +1 -1
- package/dist/src/context/source-file.d.ts +2 -2
- package/dist/src/context/source-file.d.ts.map +1 -1
- package/dist/src/context.d.ts +2 -2
- package/dist/src/context.d.ts.map +1 -1
- package/dist/src/context.js +1 -1
- package/dist/src/debug.d.ts +1 -0
- package/dist/src/debug.d.ts.map +1 -1
- package/dist/src/debug.js +4 -1
- package/dist/src/index.d.ts +8 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +8 -2
- package/dist/src/jsx-runtime.d.ts +4 -272
- package/dist/src/jsx-runtime.d.ts.map +1 -1
- package/dist/src/jsx-runtime.js +3 -315
- package/dist/src/props-combinators.d.ts +19 -0
- package/dist/src/props-combinators.d.ts.map +1 -0
- package/dist/src/props-combinators.js +108 -0
- package/dist/src/reactive-union-set.d.ts +29 -0
- package/dist/src/reactive-union-set.d.ts.map +1 -0
- package/dist/src/reactive-union-set.js +183 -0
- package/dist/src/reactivity.d.ts +75 -0
- package/dist/src/reactivity.d.ts.map +1 -0
- package/dist/src/reactivity.js +141 -0
- package/dist/src/refkey.d.ts +36 -0
- package/dist/src/refkey.d.ts.map +1 -1
- package/dist/src/refkey.js +40 -0
- package/dist/src/render.d.ts +5 -1
- package/dist/src/render.d.ts.map +1 -1
- package/dist/src/render.js +68 -15
- package/dist/src/runtime/component.d.ts +24 -0
- package/dist/src/runtime/component.d.ts.map +1 -0
- package/dist/src/runtime/component.js +19 -0
- package/dist/src/runtime/intrinsic.d.ts +168 -0
- package/dist/src/runtime/intrinsic.d.ts.map +1 -0
- package/dist/src/runtime/intrinsic.js +11 -0
- package/dist/src/scheduler.d.ts +2 -2
- package/dist/src/scheduler.d.ts.map +1 -1
- package/dist/src/scheduler.js +27 -6
- package/dist/src/slot.d.ts +2 -2
- package/dist/src/slot.d.ts.map +1 -1
- package/dist/src/slot.js +1 -1
- package/dist/src/stc.d.ts +1 -1
- package/dist/src/stc.d.ts.map +1 -1
- package/dist/src/sti.d.ts +7 -6
- package/dist/src/sti.d.ts.map +1 -1
- package/dist/src/sti.js +1 -1
- package/dist/src/symbols/flags.d.ts +70 -0
- package/dist/src/symbols/flags.d.ts.map +1 -0
- package/dist/src/symbols/flags.js +72 -0
- package/dist/src/symbols/index.d.ts +7 -0
- package/dist/src/symbols/index.d.ts.map +1 -0
- package/dist/src/symbols/index.js +6 -0
- package/dist/src/symbols/output-scope.d.ts +94 -0
- package/dist/src/symbols/output-scope.d.ts.map +1 -0
- package/dist/src/symbols/output-scope.js +222 -0
- package/dist/src/symbols/output-symbol.d.ts +89 -0
- package/dist/src/symbols/output-symbol.d.ts.map +1 -0
- package/dist/src/symbols/output-symbol.js +333 -0
- package/dist/src/symbols/symbol-flow.d.ts +13 -0
- package/dist/src/symbols/symbol-flow.d.ts.map +1 -0
- package/dist/src/symbols/symbol-flow.js +74 -0
- package/dist/src/symbols/symbol-slot.d.ts +12 -0
- package/dist/src/symbols/symbol-slot.d.ts.map +1 -0
- package/dist/src/symbols/symbol-slot.js +36 -0
- package/dist/src/symbols/symbol-table.d.ts +14 -0
- package/dist/src/symbols/symbol-table.d.ts.map +1 -0
- package/dist/src/symbols/symbol-table.js +42 -0
- package/dist/src/tap.d.ts +3 -2
- package/dist/src/tap.d.ts.map +1 -1
- package/dist/src/tracer.d.ts +238 -0
- package/dist/src/tracer.d.ts.map +1 -0
- package/dist/src/tracer.js +496 -0
- package/dist/src/tsdoc-metadata.json +1 -1
- package/dist/src/utils.d.ts +4 -3
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +2 -1
- package/dist/test/components/slot.test.js +5 -7
- package/dist/test/props-with-defaults.test.js +1 -1
- package/dist/test/reactive-union-set.test.d.ts +2 -0
- package/dist/test/reactive-union-set.test.d.ts.map +1 -0
- package/dist/test/reactive-union-set.test.js +170 -0
- package/dist/test/reactivity/cleanup.test.js +2 -1
- package/dist/test/reactivity/memo.test.js +1 -1
- package/dist/test/reactivity/untrack.test.js +1 -1
- package/dist/test/rendering/memoization.test.js +2 -1
- package/dist/test/split-props.test.js +1 -1
- package/dist/test/symbols/output-scope.test.d.ts +2 -0
- package/dist/test/symbols/output-scope.test.d.ts.map +1 -0
- package/dist/test/symbols/output-scope.test.js +343 -0
- package/dist/test/symbols/output-symbol.test.d.ts +2 -0
- package/dist/test/symbols/output-symbol.test.d.ts.map +1 -0
- package/dist/test/symbols/output-symbol.test.js +447 -0
- package/dist/test/symbols/resolution.test.d.ts +2 -0
- package/dist/test/symbols/resolution.test.d.ts.map +1 -0
- package/dist/test/symbols/resolution.test.js +141 -0
- package/dist/test/symbols/utils.d.ts +25 -0
- package/dist/test/symbols/utils.d.ts.map +1 -0
- package/dist/test/symbols/utils.js +47 -0
- package/dist/testing/extend-expect.d.ts +15 -0
- package/dist/testing/extend-expect.d.ts.map +1 -1
- package/dist/testing/extend-expect.js +2 -1
- package/dist/testing/render.d.ts +1 -1
- package/dist/testing/render.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +28 -24
- package/src/binder.ts +146 -672
- package/src/code.ts +1 -1
- package/src/components/Block.tsx +4 -1
- package/src/components/Declaration.tsx +8 -7
- package/src/components/For.tsx +2 -1
- package/src/components/Indent.tsx +1 -1
- package/src/components/List.tsx +3 -1
- package/src/components/MemberDeclaration.tsx +7 -6
- package/src/components/MemberScope.tsx +2 -5
- package/src/components/Output.tsx +2 -1
- package/src/components/Prose.tsx +1 -1
- package/src/components/ReferenceOrContent.tsx +1 -1
- package/src/components/Scope.tsx +3 -7
- package/src/components/Show.tsx +1 -1
- package/src/components/SourceDirectory.tsx +2 -1
- package/src/components/SourceFile.tsx +2 -1
- package/src/components/StatementList.tsx +2 -1
- package/src/components/Switch.tsx +2 -1
- package/src/components/Wrap.tsx +1 -1
- package/src/context/assignment.ts +1 -1
- package/src/context/binder.ts +3 -3
- package/src/context/declaration.ts +1 -1
- package/src/context/member-declaration.ts +1 -1
- package/src/context/member-scope.ts +1 -1
- package/src/context/name-policy.ts +1 -1
- package/src/context/scope.ts +1 -1
- package/src/context/source-directory.ts +1 -1
- package/src/context/source-file.ts +2 -2
- package/src/context.ts +3 -7
- package/src/debug.ts +5 -1
- package/src/index.ts +15 -1
- package/src/jsx-runtime.ts +15 -674
- package/src/props-combinators.ts +148 -0
- package/src/reactive-union-set.ts +238 -0
- package/src/reactivity.ts +230 -0
- package/src/refkey.ts +40 -0
- package/src/render.ts +97 -26
- package/src/runtime/component.ts +67 -0
- package/src/runtime/intrinsic.ts +199 -0
- package/src/scheduler.ts +31 -6
- package/src/slot.ts +3 -4
- package/src/stc.ts +2 -2
- package/src/sti.ts +11 -11
- package/src/symbols/flags.ts +82 -0
- package/src/symbols/index.ts +6 -0
- package/src/symbols/output-scope.ts +296 -0
- package/src/symbols/output-symbol.ts +459 -0
- package/src/symbols/symbol-flow.ts +100 -0
- package/src/symbols/symbol-slot.tsx +48 -0
- package/src/symbols/symbol-table.ts +72 -0
- package/src/tap.ts +3 -2
- package/src/tracer.ts +474 -0
- package/src/utils.tsx +7 -5
- package/temp/api.json +7446 -5133
- package/test/components/slot.test.tsx +8 -11
- package/test/props-with-defaults.test.ts +1 -1
- package/test/reactive-union-set.test.tsx +191 -0
- package/test/reactivity/cleanup.test.tsx +2 -1
- package/test/reactivity/memo.test.tsx +1 -1
- package/test/reactivity/untrack.test.ts +1 -1
- package/test/rendering/basic.test.tsx +1 -1
- package/test/rendering/memoization.test.tsx +1 -1
- package/test/split-props.test.ts +1 -1
- package/test/symbols/output-scope.test.ts +300 -0
- package/test/symbols/output-symbol.test.ts +456 -0
- package/test/symbols/resolution.test.ts +170 -0
- package/test/symbols/utils.ts +93 -0
- package/test/utils.test.tsx +1 -1
- package/testing/extend-expect.ts +16 -0
- package/testing/render.ts +1 -2
- package/LICENSE +0 -7
- package/dist/test/symbols.test.d.ts +0 -2
- package/dist/test/symbols.test.d.ts.map +0 -1
- package/dist/test/symbols.test.js +0 -884
- package/test/symbols.test.ts +0 -1006
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { computed, isReactive, proxyRefs, toRefs } from "@vue/reactivity";
|
|
2
|
+
import { untrack } from "./reactivity.js";
|
|
3
|
+
|
|
4
|
+
export function mergeProps<T, U>(source: T, source1: U): T & U;
|
|
5
|
+
export function mergeProps<T, U, V>(
|
|
6
|
+
source: T,
|
|
7
|
+
source1: U,
|
|
8
|
+
source2: V,
|
|
9
|
+
): T & U & V;
|
|
10
|
+
export function mergeProps<T, U, V, W>(
|
|
11
|
+
source: T,
|
|
12
|
+
source1: U,
|
|
13
|
+
source2: V,
|
|
14
|
+
source3: W,
|
|
15
|
+
): T & U & V & W;
|
|
16
|
+
export function mergeProps(...sources: any): any {
|
|
17
|
+
const target = {};
|
|
18
|
+
for (let i = 0; i < sources.length; i++) {
|
|
19
|
+
let source = sources[i];
|
|
20
|
+
if (typeof source === "function") source = source();
|
|
21
|
+
if (source) {
|
|
22
|
+
const descriptors = Object.getOwnPropertyDescriptors(source);
|
|
23
|
+
for (const key in descriptors) {
|
|
24
|
+
if (key in target) continue;
|
|
25
|
+
Object.defineProperty(target, key, {
|
|
26
|
+
enumerable: true,
|
|
27
|
+
get() {
|
|
28
|
+
for (let i = sources.length - 1; i >= 0; i--) {
|
|
29
|
+
let s = sources[i];
|
|
30
|
+
if (typeof s === "function") s = s();
|
|
31
|
+
const v = (s || {})[key];
|
|
32
|
+
if (v !== undefined) return v;
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return target;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type SplitProps<T, K extends (readonly (keyof T)[])[]> = [
|
|
43
|
+
...{
|
|
44
|
+
[P in keyof K]: P extends `${number}` ?
|
|
45
|
+
Pick<T, Extract<K[P], readonly (keyof T)[]>[number]>
|
|
46
|
+
: never;
|
|
47
|
+
},
|
|
48
|
+
{ [P in keyof T as Exclude<P, K[number][number]>]: T[P] },
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
export function splitProps<
|
|
52
|
+
T extends Record<any, any>,
|
|
53
|
+
K extends [readonly (keyof T)[], ...(readonly (keyof T)[])[]],
|
|
54
|
+
>(props: T, ...keys: K): SplitProps<T, K> {
|
|
55
|
+
if (isReactive(props)) {
|
|
56
|
+
const refs = untrack(() => toRefs(props));
|
|
57
|
+
const remainingKeys = new Set(Object.keys(refs));
|
|
58
|
+
|
|
59
|
+
const result: any = keys.map((keySet) => {
|
|
60
|
+
const resultSet: any = {};
|
|
61
|
+
for (const key of keySet) {
|
|
62
|
+
resultSet[key] = refs[key];
|
|
63
|
+
remainingKeys.delete(key as string);
|
|
64
|
+
}
|
|
65
|
+
return proxyRefs(resultSet);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const remaining: any = {};
|
|
69
|
+
for (const key of remainingKeys) {
|
|
70
|
+
remaining[key] = refs[key];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return [...result, proxyRefs(remaining)] as any;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const descriptors = Object.getOwnPropertyDescriptors(props);
|
|
77
|
+
const remainingKeys = new Set(Object.keys(descriptors));
|
|
78
|
+
const result: any = keys.map((keySet) => {
|
|
79
|
+
const resultSet: any = {};
|
|
80
|
+
for (const key of keySet) {
|
|
81
|
+
if (key in descriptors) {
|
|
82
|
+
Object.defineProperty(resultSet, key, descriptors[key]);
|
|
83
|
+
remainingKeys.delete(key as string);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return resultSet;
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const remaining: any = {};
|
|
90
|
+
for (const key of remainingKeys) {
|
|
91
|
+
Object.defineProperty(remaining, key, descriptors[key]);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return [...result, remaining] as any;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Applies default values to a props object. Reactive props are handled properly
|
|
99
|
+
* by ensuring that their value is not accessed by `defaultProps`, avoiding any
|
|
100
|
+
* unintended side effects.
|
|
101
|
+
*/
|
|
102
|
+
export function defaultProps<T extends {}>(props: T, defaults: Partial<T>): T {
|
|
103
|
+
if (isReactive(props)) {
|
|
104
|
+
const refs = untrack(() => toRefs(props));
|
|
105
|
+
for (const key in defaults) {
|
|
106
|
+
const originalRef = refs[key];
|
|
107
|
+
refs[key] = computed(() =>
|
|
108
|
+
originalRef.value === undefined ? defaults[key] : originalRef.value,
|
|
109
|
+
) as any;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return proxyRefs(refs);
|
|
113
|
+
}
|
|
114
|
+
const withDefaults = {} as T;
|
|
115
|
+
const copied = new Set<string>();
|
|
116
|
+
for (const key in defaults) {
|
|
117
|
+
copied.add(key);
|
|
118
|
+
const desc = Object.getOwnPropertyDescriptor(props, key);
|
|
119
|
+
if (!desc) {
|
|
120
|
+
withDefaults[key] = defaults[key]!;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (desc.get) {
|
|
125
|
+
const originalGet = desc.get;
|
|
126
|
+
desc.get = function () {
|
|
127
|
+
const value = originalGet.call(this);
|
|
128
|
+
return value === undefined ? defaults[key as keyof T] : value;
|
|
129
|
+
};
|
|
130
|
+
Object.defineProperty(withDefaults, key, desc);
|
|
131
|
+
} else {
|
|
132
|
+
desc.value =
|
|
133
|
+
desc.value === undefined ? defaults[key as keyof T] : desc.value;
|
|
134
|
+
Object.defineProperty(withDefaults, key, desc);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const descriptors = Object.getOwnPropertyDescriptors(props);
|
|
139
|
+
for (const key in descriptors) {
|
|
140
|
+
if (copied.has(key)) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
Object.defineProperty(withDefaults, key, descriptors[key]);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return withDefaults;
|
|
148
|
+
}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ITERATE_KEY,
|
|
3
|
+
ReactiveFlags,
|
|
4
|
+
shallowReactive,
|
|
5
|
+
shallowReadonly,
|
|
6
|
+
track,
|
|
7
|
+
TrackOpTypes,
|
|
8
|
+
trigger,
|
|
9
|
+
TriggerOpTypes,
|
|
10
|
+
} from "@vue/reactivity";
|
|
11
|
+
import { effect } from "./reactivity.js";
|
|
12
|
+
|
|
13
|
+
export interface ReactiveUnionSetOptions<T> {
|
|
14
|
+
onAdd?: OnReactiveSetAddCallback<T>;
|
|
15
|
+
onDelete?: OnReactiveSetDeleteCallback<T>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type OnReactiveSetDeleteCallback<T> = (value: T) => void;
|
|
19
|
+
export type OnReactiveSetAddCallback<T> = (value: T) => T;
|
|
20
|
+
|
|
21
|
+
export class ReactiveUnionSet<T> extends Set<T> {
|
|
22
|
+
private _subsets: Set<Set<T>>;
|
|
23
|
+
private _onAdd?: OnReactiveSetAddCallback<T>;
|
|
24
|
+
private _onDelete?: OnReactiveSetDeleteCallback<T>;
|
|
25
|
+
private _refcounts: Map<T, number> = new Map();
|
|
26
|
+
private _indexes: { add: (arg: T) => void; delete: (arg: T) => void }[] = [];
|
|
27
|
+
|
|
28
|
+
[ReactiveFlags.IS_REACTIVE] = true;
|
|
29
|
+
|
|
30
|
+
private _handleAdd(value: T) {
|
|
31
|
+
value = this._onAdd ? this._onAdd(value) : value;
|
|
32
|
+
|
|
33
|
+
for (const index of this._indexes) {
|
|
34
|
+
index.add(value);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private _handleDelete(value: T) {
|
|
41
|
+
if (this._onDelete) {
|
|
42
|
+
this._onDelete(value);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
for (const index of this._indexes) {
|
|
46
|
+
index.delete(value);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
constructor(options: ReactiveUnionSetOptions<T> = {}) {
|
|
53
|
+
super();
|
|
54
|
+
|
|
55
|
+
this._subsets = new Set();
|
|
56
|
+
this._onAdd = options.onAdd;
|
|
57
|
+
this._onDelete = options.onDelete;
|
|
58
|
+
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
get size() {
|
|
63
|
+
track(this, TrackOpTypes.ITERATE, ITERATE_KEY);
|
|
64
|
+
return super.size;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
[Symbol.iterator](): SetIterator<T> {
|
|
68
|
+
track(this, TrackOpTypes.ITERATE, ITERATE_KEY);
|
|
69
|
+
return super[Symbol.iterator]();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
keys(): SetIterator<T> {
|
|
73
|
+
track(this, TrackOpTypes.ITERATE, ITERATE_KEY);
|
|
74
|
+
return super.keys();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
values(): SetIterator<T> {
|
|
78
|
+
track(this, TrackOpTypes.ITERATE, ITERATE_KEY);
|
|
79
|
+
return super.values();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
entries(): SetIterator<[T, T]> {
|
|
83
|
+
track(this, TrackOpTypes.ITERATE, ITERATE_KEY);
|
|
84
|
+
return super.entries();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
add(item: T) {
|
|
88
|
+
if (this._refcounts.has(item)) {
|
|
89
|
+
this._refcounts.set(item, this._refcounts.get(item)! + 1);
|
|
90
|
+
} else {
|
|
91
|
+
this._refcounts.set(item, 1);
|
|
92
|
+
super.add(item);
|
|
93
|
+
this._handleAdd(item);
|
|
94
|
+
trigger(this, TriggerOpTypes.ADD, item, item);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return this;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
delete(item: T) {
|
|
101
|
+
const count = this._refcounts.get(item);
|
|
102
|
+
if (count === undefined) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (count > 1) {
|
|
107
|
+
this._refcounts.set(item, count - 1);
|
|
108
|
+
} else {
|
|
109
|
+
this._refcounts.delete(item);
|
|
110
|
+
super.delete(item);
|
|
111
|
+
this._handleDelete(item);
|
|
112
|
+
trigger(this, TriggerOpTypes.DELETE, undefined, item);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
addSubset(subset: Set<T>, options: ReactiveUnionSetOptions<T> = {}) {
|
|
119
|
+
if (this._subsets.has(subset)) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const { onAdd, onDelete } = options;
|
|
124
|
+
|
|
125
|
+
this._subsets.add(subset);
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Contains a map of the previous values and their mapped values
|
|
129
|
+
* that were added to the parent set.
|
|
130
|
+
*/
|
|
131
|
+
const prevValues = new Map<T, T>();
|
|
132
|
+
|
|
133
|
+
effect(() => {
|
|
134
|
+
for (const [prevSourceValue, prevTargetValue] of prevValues) {
|
|
135
|
+
if (!subset.has(prevSourceValue)) {
|
|
136
|
+
onDelete?.(prevSourceValue);
|
|
137
|
+
prevValues.delete(prevSourceValue);
|
|
138
|
+
this.delete(prevTargetValue);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
for (const value of subset) {
|
|
143
|
+
if (!prevValues.has(value)) {
|
|
144
|
+
if (onAdd) {
|
|
145
|
+
const added = onAdd(value);
|
|
146
|
+
prevValues.set(value, added);
|
|
147
|
+
} else {
|
|
148
|
+
this.add(value);
|
|
149
|
+
prevValues.set(value, value);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
createDerivedSet<U>(mapper: (value: T) => U | U[]) {
|
|
157
|
+
const set = shallowReactive(new Set<U>());
|
|
158
|
+
const refcounts = new Map<U, number>();
|
|
159
|
+
|
|
160
|
+
function ref(value: U) {
|
|
161
|
+
if (refcounts.has(value)) {
|
|
162
|
+
const count = refcounts.get(value)! + 1;
|
|
163
|
+
refcounts.set(value, count);
|
|
164
|
+
return count;
|
|
165
|
+
} else {
|
|
166
|
+
refcounts.set(value, 1);
|
|
167
|
+
set.add(value);
|
|
168
|
+
return 1;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function unref(value: U) {
|
|
173
|
+
const count = refcounts.get(value)!;
|
|
174
|
+
|
|
175
|
+
if (count > 1) {
|
|
176
|
+
refcounts.set(value, count - 1);
|
|
177
|
+
return count - 1;
|
|
178
|
+
} else {
|
|
179
|
+
refcounts.delete(value);
|
|
180
|
+
set.delete(value);
|
|
181
|
+
return 0;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
this._indexes.push({
|
|
186
|
+
add: (value: T) => {
|
|
187
|
+
effect((prev: U[] | U | undefined) => {
|
|
188
|
+
for (const id of [prev].flat()) {
|
|
189
|
+
unref(id as any);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const mappedValue = mapper(value);
|
|
193
|
+
for (const id of [mappedValue].flat()) {
|
|
194
|
+
ref(id as any);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return mappedValue;
|
|
198
|
+
});
|
|
199
|
+
},
|
|
200
|
+
delete: (value: T) => {
|
|
201
|
+
const mappedValue = mapper(value);
|
|
202
|
+
for (const id of [mappedValue].flat()) {
|
|
203
|
+
unref(id as any);
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
return shallowReadonly(set);
|
|
209
|
+
}
|
|
210
|
+
createIndex<U>(mapper: (value: T) => U | U[]): ReadonlyMap<U, T> {
|
|
211
|
+
const index = shallowReactive(new Map<U, T>());
|
|
212
|
+
this._indexes.push({
|
|
213
|
+
add: (value: T) => {
|
|
214
|
+
effect((oldValue) => {
|
|
215
|
+
for (const id of [oldValue].flat()) {
|
|
216
|
+
index.delete(id as U);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const mappedValue = mapper(value);
|
|
220
|
+
|
|
221
|
+
for (const id of [mappedValue].flat()) {
|
|
222
|
+
index.set(id as U, value as any);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return mappedValue;
|
|
226
|
+
});
|
|
227
|
+
},
|
|
228
|
+
delete: (value: T) => {
|
|
229
|
+
const mappedValue = mapper(value);
|
|
230
|
+
for (const id of [mappedValue].flat()) {
|
|
231
|
+
index.delete(id as U);
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
return shallowReadonly(index);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import {
|
|
2
|
+
pauseTracking,
|
|
3
|
+
ReactiveEffectRunner,
|
|
4
|
+
resetTracking,
|
|
5
|
+
ShallowReactive,
|
|
6
|
+
shallowRef,
|
|
7
|
+
stop,
|
|
8
|
+
effect as vueEffect,
|
|
9
|
+
} from "@vue/reactivity";
|
|
10
|
+
import type { RenderedTextTree } from "./render.js";
|
|
11
|
+
import type { Children, ComponentCreator } from "./runtime/component.js";
|
|
12
|
+
import { scheduler } from "./scheduler.js";
|
|
13
|
+
import type { OutputSymbol } from "./symbols/output-symbol.js";
|
|
14
|
+
import { trace, TracePhase } from "./tracer.js";
|
|
15
|
+
|
|
16
|
+
// check for multiple versions of alloy here.
|
|
17
|
+
if ((globalThis as any).__ALLOY__) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
"Multiple versions of Alloy are loaded for this project. This will likely cause undesirable behavior.",
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
(globalThis as any).__ALLOY__ = true;
|
|
23
|
+
|
|
24
|
+
export function getElementCache() {
|
|
25
|
+
return getContext()!.elementCache;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type ElementCacheKey =
|
|
29
|
+
| ComponentCreator
|
|
30
|
+
| (() => unknown)
|
|
31
|
+
| CustomContext;
|
|
32
|
+
|
|
33
|
+
export type ElementCache = Map<ElementCacheKey, RenderedTextTree>;
|
|
34
|
+
|
|
35
|
+
export interface Disposable {
|
|
36
|
+
(): void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface Context {
|
|
40
|
+
disposables: Disposable[];
|
|
41
|
+
owner: Context | null;
|
|
42
|
+
|
|
43
|
+
// context providers
|
|
44
|
+
context?: Record<symbol, unknown>;
|
|
45
|
+
|
|
46
|
+
// store random info about the node
|
|
47
|
+
meta?: Record<string, any>;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A cache of RenderTextTree nodes created within this context,
|
|
51
|
+
* indexed by the component or function which created them.
|
|
52
|
+
*/
|
|
53
|
+
elementCache: ElementCache;
|
|
54
|
+
/**
|
|
55
|
+
* When this context was created by a component, this will
|
|
56
|
+
* be the component that created it.
|
|
57
|
+
*/
|
|
58
|
+
componentOwner?: ComponentCreator<unknown>;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Whether this context will take an emitted symbol.
|
|
62
|
+
*/
|
|
63
|
+
takesSymbols: boolean;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The symbol that this component has taken.
|
|
67
|
+
*/
|
|
68
|
+
takenSymbols?: ShallowReactive<Set<OutputSymbol>>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let globalContext: Context | null = null;
|
|
72
|
+
export function getContext() {
|
|
73
|
+
return globalContext;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface RootOptions {
|
|
77
|
+
componentOwner?: ComponentCreator<any>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function root<T>(fn: (d: Disposable) => T, options?: RootOptions): T {
|
|
81
|
+
const context: Context = {
|
|
82
|
+
componentOwner: options?.componentOwner,
|
|
83
|
+
disposables: [],
|
|
84
|
+
owner: globalContext,
|
|
85
|
+
context: {},
|
|
86
|
+
elementCache: new Map(),
|
|
87
|
+
takesSymbols: false,
|
|
88
|
+
takenSymbols: undefined,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
globalContext = context;
|
|
92
|
+
let ret;
|
|
93
|
+
try {
|
|
94
|
+
ret = untrack(() =>
|
|
95
|
+
fn(() => {
|
|
96
|
+
for (const d of context!.disposables) {
|
|
97
|
+
d();
|
|
98
|
+
}
|
|
99
|
+
}),
|
|
100
|
+
);
|
|
101
|
+
} finally {
|
|
102
|
+
globalContext = globalContext!.owner;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return ret;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function untrack<T>(fn: () => T): T {
|
|
109
|
+
pauseTracking();
|
|
110
|
+
const v = fn();
|
|
111
|
+
resetTracking();
|
|
112
|
+
return v;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function memo<T>(fn: () => T, equal?: boolean): () => T {
|
|
116
|
+
const o = shallowRef();
|
|
117
|
+
effect((prev) => {
|
|
118
|
+
const res = fn();
|
|
119
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
120
|
+
(!equal || prev !== res) && (o.value = res);
|
|
121
|
+
return res;
|
|
122
|
+
}, undefined as T);
|
|
123
|
+
return () => o.value;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function effect<T>(fn: (prev?: T) => T, current?: T) {
|
|
127
|
+
const context: Context = {
|
|
128
|
+
context: {},
|
|
129
|
+
disposables: [] as (() => void)[],
|
|
130
|
+
owner: globalContext,
|
|
131
|
+
elementCache: new Map(),
|
|
132
|
+
takesSymbols: false,
|
|
133
|
+
takenSymbols: undefined,
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const cleanupFn = (final: boolean) => {
|
|
137
|
+
const d = context.disposables;
|
|
138
|
+
context.disposables = [];
|
|
139
|
+
for (let k = 0, len = d.length; k < len; k++) d[k]();
|
|
140
|
+
|
|
141
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
142
|
+
final && stop(runner);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
onCleanup(() => cleanupFn(true));
|
|
146
|
+
const runner: ReactiveEffectRunner<void> = vueEffect(
|
|
147
|
+
() => {
|
|
148
|
+
cleanupFn(false);
|
|
149
|
+
|
|
150
|
+
const oldContext = globalContext;
|
|
151
|
+
globalContext = context;
|
|
152
|
+
try {
|
|
153
|
+
current = fn(current);
|
|
154
|
+
} finally {
|
|
155
|
+
globalContext = oldContext;
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
scheduler: scheduler(() => runner),
|
|
160
|
+
onTrack(event) {
|
|
161
|
+
trace(TracePhase.effect.track, () => {
|
|
162
|
+
return `tracking ${event.target}, ${event.key}`;
|
|
163
|
+
});
|
|
164
|
+
},
|
|
165
|
+
onTrigger(event) {
|
|
166
|
+
trace(TracePhase.effect.trigger, () => {
|
|
167
|
+
return `triggering ${event.target}, ${event.key}`;
|
|
168
|
+
});
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
// allow recursive effects (recursive option does nothing, possible bug)
|
|
174
|
+
(runner as any).effect.flags |= 1 << 5;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Register a cleanup function which is called when the current reactive scope
|
|
179
|
+
* is recalculated or disposed. This is useful to clean up any side effects
|
|
180
|
+
* created in the reactive scope.
|
|
181
|
+
*
|
|
182
|
+
* @remarks
|
|
183
|
+
*
|
|
184
|
+
* When onCleanup is called inside a component definition, the provided function
|
|
185
|
+
* is called when the component is removed from the tree. This can be useful to
|
|
186
|
+
* clean up any side effects created as a result of rendering the component. For
|
|
187
|
+
* example, if rendering a component creates a symbol, `onCleanup` can be used
|
|
188
|
+
* to remove the symbol when the component is removed from the tree.
|
|
189
|
+
*
|
|
190
|
+
* When onCleanup is called inside a memo or effect, the function is called when
|
|
191
|
+
* the effect is refreshed (e.g. when a memo or computed recalculates) or
|
|
192
|
+
* disposed (e.g. it is no longer needed because it is attached to a component
|
|
193
|
+
* which was removed).
|
|
194
|
+
*/
|
|
195
|
+
export function onCleanup(fn: Disposable) {
|
|
196
|
+
if (globalContext != null) {
|
|
197
|
+
globalContext.disposables.push(fn);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Create a custom reactive context for the children returned by
|
|
203
|
+
* the provided context.
|
|
204
|
+
*/
|
|
205
|
+
export interface CustomContext {
|
|
206
|
+
[CUSTOM_CONTEXT_SYM]: true;
|
|
207
|
+
useCustomContext: (useCb: CustomContextChildrenCallback) => void;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export type CustomContextChildrenCallback = (child: Children) => void;
|
|
211
|
+
const CUSTOM_CONTEXT_SYM = Symbol();
|
|
212
|
+
|
|
213
|
+
export function createCustomContext(
|
|
214
|
+
useCallback: (useChildren: CustomContextChildrenCallback) => void,
|
|
215
|
+
): CustomContext {
|
|
216
|
+
return {
|
|
217
|
+
[CUSTOM_CONTEXT_SYM]: true,
|
|
218
|
+
useCustomContext(useCb: (children: Children) => void): void {
|
|
219
|
+
useCallback(useCb);
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function isCustomContext(child: Children): child is CustomContext {
|
|
225
|
+
return (
|
|
226
|
+
typeof child === "object" &&
|
|
227
|
+
child !== null &&
|
|
228
|
+
Object.hasOwn(child, CUSTOM_CONTEXT_SYM)
|
|
229
|
+
);
|
|
230
|
+
}
|
package/src/refkey.ts
CHANGED
|
@@ -48,6 +48,20 @@ function getKey(value: unknown): Refkey {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
const knownRefkeys = new Map<string, Refkey>();
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Create a refkey for the provided arguments. Passing no arguments returns a
|
|
54
|
+
* fresh refkey that is guaranteed to be unique. Otherwise, the arguments passed
|
|
55
|
+
* will be used to create a refkey for those values. Providing the same
|
|
56
|
+
* arguments will always return the same refkey.
|
|
57
|
+
*
|
|
58
|
+
* @remarks
|
|
59
|
+
*
|
|
60
|
+
* Values are compared using the SameValueZero algorithm, which considers
|
|
61
|
+
* objects the same if they are reference identical, and primitives the same if
|
|
62
|
+
* they are the same value, with the exception of `NaN`, which is always considered
|
|
63
|
+
* equal to other `NaN` values, and `-0`, which is considered identical to `+0`
|
|
64
|
+
*/
|
|
51
65
|
export function refkey(...args: unknown[]): Refkey {
|
|
52
66
|
const keys = args.length === 0 ? [getKey({})] : args.map((v) => getKey(v));
|
|
53
67
|
|
|
@@ -60,3 +74,29 @@ export function refkey(...args: unknown[]): Refkey {
|
|
|
60
74
|
knownRefkeys.set(compositeKey, key);
|
|
61
75
|
return key;
|
|
62
76
|
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Create a refkey for an instantiation of a symbol.
|
|
80
|
+
*
|
|
81
|
+
* @param base - The refkey of the symbol holding the instantiation.
|
|
82
|
+
* @param member - The refkey of the non-instantiated member symbol (either the
|
|
83
|
+
* instance or static member symbol)
|
|
84
|
+
*
|
|
85
|
+
* @remarks
|
|
86
|
+
*
|
|
87
|
+
* Refkeys for instantiated and copied members are a composite refkey of the
|
|
88
|
+
* owner's refkey and the member's refkey. So for example, given a refkey for an
|
|
89
|
+
* instantiation of a class `rk1`, and a refkey for the instance member of that
|
|
90
|
+
* class `rk2`, the refkey for the instantiated static member is
|
|
91
|
+
* `refkey(rk1, rk2)`. This function will return the same refkey given those
|
|
92
|
+
* same parameters.
|
|
93
|
+
*
|
|
94
|
+
* When a static member symbol `rk3` is owned by another static or instance
|
|
95
|
+
* member symbol (i.e. the outer symbol is itself a member container), the
|
|
96
|
+
* refkey of the instaniated static member is still just the composite of the
|
|
97
|
+
* instantiated variable refkey and the refkey of the inner member
|
|
98
|
+
* `refkey(rk1, rk3)`.
|
|
99
|
+
*/
|
|
100
|
+
export function memberRefkey(base: Refkey, member: Refkey): Refkey {
|
|
101
|
+
return refkey(base, member);
|
|
102
|
+
}
|