@alloy-js/core 0.15.0 → 0.17.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.
Files changed (175) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/src/binder.d.ts +18 -235
  3. package/dist/src/binder.d.ts.map +1 -1
  4. package/dist/src/binder.js +85 -386
  5. package/dist/src/components/Block.d.ts +1 -1
  6. package/dist/src/components/Block.d.ts.map +1 -1
  7. package/dist/src/components/Block.js +3 -1
  8. package/dist/src/components/Declaration.d.ts +1 -1
  9. package/dist/src/components/Declaration.d.ts.map +1 -1
  10. package/dist/src/components/Declaration.js +5 -4
  11. package/dist/src/components/For.d.ts +1 -1
  12. package/dist/src/components/For.d.ts.map +1 -1
  13. package/dist/src/components/For.js +1 -1
  14. package/dist/src/components/Indent.d.ts +1 -1
  15. package/dist/src/components/Indent.d.ts.map +1 -1
  16. package/dist/src/components/List.d.ts +1 -1
  17. package/dist/src/components/List.d.ts.map +1 -1
  18. package/dist/src/components/List.js +2 -1
  19. package/dist/src/components/MemberDeclaration.d.ts +1 -1
  20. package/dist/src/components/MemberDeclaration.d.ts.map +1 -1
  21. package/dist/src/components/MemberDeclaration.js +3 -4
  22. package/dist/src/components/MemberScope.d.ts +1 -1
  23. package/dist/src/components/MemberScope.d.ts.map +1 -1
  24. package/dist/src/components/MemberScope.js +0 -2
  25. package/dist/src/components/Prose.d.ts +1 -1
  26. package/dist/src/components/Prose.d.ts.map +1 -1
  27. package/dist/src/components/ReferenceOrContent.d.ts +1 -1
  28. package/dist/src/components/ReferenceOrContent.d.ts.map +1 -1
  29. package/dist/src/components/Scope.d.ts +1 -1
  30. package/dist/src/components/Scope.d.ts.map +1 -1
  31. package/dist/src/components/Scope.js +3 -6
  32. package/dist/src/components/Show.d.ts +1 -1
  33. package/dist/src/components/Show.d.ts.map +1 -1
  34. package/dist/src/components/StatementList.d.ts +1 -1
  35. package/dist/src/components/StatementList.d.ts.map +1 -1
  36. package/dist/src/components/StatementList.js +1 -1
  37. package/dist/src/components/Switch.d.ts +1 -1
  38. package/dist/src/components/Switch.d.ts.map +1 -1
  39. package/dist/src/components/Switch.js +1 -1
  40. package/dist/src/components/Wrap.d.ts +1 -1
  41. package/dist/src/components/Wrap.d.ts.map +1 -1
  42. package/dist/src/context/assignment.d.ts +1 -1
  43. package/dist/src/context/assignment.d.ts.map +1 -1
  44. package/dist/src/context/binder.d.ts +2 -2
  45. package/dist/src/context/binder.d.ts.map +1 -1
  46. package/dist/src/context/declaration.d.ts +1 -1
  47. package/dist/src/context/declaration.d.ts.map +1 -1
  48. package/dist/src/context/member-declaration.d.ts +1 -1
  49. package/dist/src/context/member-declaration.d.ts.map +1 -1
  50. package/dist/src/context/member-declaration.js +0 -1
  51. package/dist/src/context/member-scope.d.ts +1 -1
  52. package/dist/src/context/member-scope.d.ts.map +1 -1
  53. package/dist/src/context/name-policy.d.ts +1 -1
  54. package/dist/src/context/name-policy.d.ts.map +1 -1
  55. package/dist/src/context/scope.d.ts +1 -1
  56. package/dist/src/context/scope.d.ts.map +1 -1
  57. package/dist/src/context/source-directory.d.ts +1 -1
  58. package/dist/src/context/source-directory.d.ts.map +1 -1
  59. package/dist/src/context/source-file.d.ts +2 -2
  60. package/dist/src/context/source-file.d.ts.map +1 -1
  61. package/dist/src/index.d.ts +4 -1
  62. package/dist/src/index.d.ts.map +1 -1
  63. package/dist/src/index.js +4 -1
  64. package/dist/src/jsx-runtime.d.ts +12 -3
  65. package/dist/src/jsx-runtime.d.ts.map +1 -1
  66. package/dist/src/jsx-runtime.js +6 -2
  67. package/dist/src/reactive-union-set.d.ts +29 -0
  68. package/dist/src/reactive-union-set.d.ts.map +1 -0
  69. package/dist/src/reactive-union-set.js +183 -0
  70. package/dist/src/refkey.d.ts +36 -0
  71. package/dist/src/refkey.d.ts.map +1 -1
  72. package/dist/src/refkey.js +40 -0
  73. package/dist/src/scheduler.d.ts +2 -2
  74. package/dist/src/scheduler.d.ts.map +1 -1
  75. package/dist/src/scheduler.js +27 -6
  76. package/dist/src/slot.d.ts +1 -1
  77. package/dist/src/slot.d.ts.map +1 -1
  78. package/dist/src/stc.d.ts +1 -1
  79. package/dist/src/stc.d.ts.map +1 -1
  80. package/dist/src/sti.d.ts +1 -1
  81. package/dist/src/sti.d.ts.map +1 -1
  82. package/dist/src/sti.js +1 -1
  83. package/dist/src/symbols/index.d.ts +6 -0
  84. package/dist/src/symbols/index.d.ts.map +1 -0
  85. package/dist/src/symbols/index.js +5 -0
  86. package/dist/src/symbols/output-scope.d.ts +116 -0
  87. package/dist/src/symbols/output-scope.d.ts.map +1 -0
  88. package/dist/src/symbols/output-scope.js +246 -0
  89. package/dist/src/symbols/output-symbol.d.ts +134 -0
  90. package/dist/src/symbols/output-symbol.d.ts.map +1 -0
  91. package/dist/src/symbols/output-symbol.js +379 -0
  92. package/dist/src/symbols/symbol-flow.d.ts +13 -0
  93. package/dist/src/symbols/symbol-flow.d.ts.map +1 -0
  94. package/dist/src/symbols/symbol-flow.js +74 -0
  95. package/dist/src/symbols/symbol-slot.d.ts +12 -0
  96. package/dist/src/symbols/symbol-slot.d.ts.map +1 -0
  97. package/dist/src/symbols/symbol-slot.js +36 -0
  98. package/dist/src/symbols/symbol-table.d.ts +14 -0
  99. package/dist/src/symbols/symbol-table.d.ts.map +1 -0
  100. package/dist/src/symbols/symbol-table.js +42 -0
  101. package/dist/src/tap.d.ts +2 -1
  102. package/dist/src/tap.d.ts.map +1 -1
  103. package/dist/src/tracer.d.ts +181 -0
  104. package/dist/src/tracer.d.ts.map +1 -0
  105. package/dist/src/tracer.js +441 -0
  106. package/dist/src/tsdoc-metadata.json +1 -1
  107. package/dist/test/components/slot.test.js +5 -7
  108. package/dist/test/reactive-union-set.test.d.ts +2 -0
  109. package/dist/test/reactive-union-set.test.d.ts.map +1 -0
  110. package/dist/test/reactive-union-set.test.js +170 -0
  111. package/dist/test/symbols/output-scope.test.d.ts +2 -0
  112. package/dist/test/symbols/output-scope.test.d.ts.map +1 -0
  113. package/dist/test/symbols/output-scope.test.js +342 -0
  114. package/dist/test/symbols/output-symbol.test.d.ts +2 -0
  115. package/dist/test/symbols/output-symbol.test.d.ts.map +1 -0
  116. package/dist/test/symbols/output-symbol.test.js +446 -0
  117. package/dist/test/symbols/resolution.test.d.ts +2 -0
  118. package/dist/test/symbols/resolution.test.d.ts.map +1 -0
  119. package/dist/test/symbols/resolution.test.js +140 -0
  120. package/dist/test/symbols/utils.d.ts +24 -0
  121. package/dist/test/symbols/utils.d.ts.map +1 -0
  122. package/dist/test/symbols/utils.js +46 -0
  123. package/dist/tsconfig.tsbuildinfo +1 -1
  124. package/package.json +3 -3
  125. package/src/binder.ts +148 -672
  126. package/src/components/Block.tsx +4 -1
  127. package/src/components/Declaration.tsx +6 -6
  128. package/src/components/For.tsx +1 -1
  129. package/src/components/Indent.tsx +1 -1
  130. package/src/components/List.tsx +1 -1
  131. package/src/components/MemberDeclaration.tsx +4 -4
  132. package/src/components/MemberScope.tsx +2 -5
  133. package/src/components/Prose.tsx +1 -1
  134. package/src/components/ReferenceOrContent.tsx +1 -1
  135. package/src/components/Scope.tsx +2 -6
  136. package/src/components/Show.tsx +1 -1
  137. package/src/components/StatementList.tsx +2 -1
  138. package/src/components/Switch.tsx +1 -1
  139. package/src/components/Wrap.tsx +1 -1
  140. package/src/context/assignment.ts +1 -1
  141. package/src/context/binder.ts +2 -2
  142. package/src/context/declaration.ts +1 -1
  143. package/src/context/member-declaration.ts +1 -1
  144. package/src/context/member-scope.ts +1 -1
  145. package/src/context/name-policy.ts +1 -1
  146. package/src/context/scope.ts +1 -1
  147. package/src/context/source-directory.ts +1 -1
  148. package/src/context/source-file.ts +2 -2
  149. package/src/index.ts +15 -0
  150. package/src/jsx-runtime.ts +18 -2
  151. package/src/reactive-union-set.ts +238 -0
  152. package/src/refkey.ts +40 -0
  153. package/src/scheduler.ts +31 -6
  154. package/src/slot.ts +1 -1
  155. package/src/stc.ts +3 -3
  156. package/src/sti.ts +5 -5
  157. package/src/symbols/index.ts +5 -0
  158. package/src/symbols/output-scope.ts +323 -0
  159. package/src/symbols/output-symbol.ts +512 -0
  160. package/src/symbols/symbol-flow.ts +104 -0
  161. package/src/symbols/symbol-slot.tsx +47 -0
  162. package/src/symbols/symbol-table.ts +72 -0
  163. package/src/tap.ts +2 -1
  164. package/src/tracer.ts +440 -0
  165. package/temp/api.json +4172 -1582
  166. package/test/components/slot.test.tsx +8 -11
  167. package/test/reactive-union-set.test.tsx +191 -0
  168. package/test/symbols/output-scope.test.ts +302 -0
  169. package/test/symbols/output-symbol.test.ts +459 -0
  170. package/test/symbols/resolution.test.ts +172 -0
  171. package/test/symbols/utils.ts +95 -0
  172. package/dist/test/symbols.test.d.ts +0 -2
  173. package/dist/test/symbols.test.d.ts.map +0 -1
  174. package/dist/test/symbols.test.js +0 -884
  175. package/test/symbols.test.ts +0 -1006
@@ -1,4 +1,7 @@
1
- import { Children, childrenArray, computed, Indent } from "@alloy-js/core";
1
+ import { computed } from "@vue/reactivity";
2
+ import { Children } from "../jsx-runtime.js";
3
+ import { childrenArray } from "../utils.jsx";
4
+ import { Indent } from "./Indent.jsx";
2
5
 
3
6
  export interface BlockProps {
4
7
  /**
@@ -1,9 +1,9 @@
1
- import { OutputSymbol } from "../binder.js";
2
1
  import { useContext } from "../context.js";
3
2
  import { BinderContext } from "../context/binder.js";
4
3
  import { DeclarationContext } from "../context/declaration.js";
5
4
  import { Children, onCleanup } from "../jsx-runtime.js";
6
5
  import { Refkey } from "../refkey.js";
6
+ import { OutputSymbol } from "../symbols/output-symbol.js";
7
7
 
8
8
  /**
9
9
  * Create a declaration by providing an already created symbol. The symbol is
@@ -68,18 +68,18 @@ export function Declaration(props: DeclarationProps) {
68
68
  throw new Error("Need binder context to create declarations");
69
69
  }
70
70
 
71
- let declaration;
71
+ let declaration: OutputSymbol;
72
72
  if ("symbol" in props) {
73
73
  declaration = props.symbol;
74
74
  } else {
75
- declaration = binder.createSymbol({
76
- name: props.name!,
77
- refkey: props.refkey,
75
+ declaration = new OutputSymbol(props.name, {
76
+ binder,
77
+ refkeys: [props.refkey ?? []].flat(),
78
78
  metadata: props.metadata,
79
79
  });
80
80
 
81
81
  onCleanup(() => {
82
- binder.deleteSymbol(declaration!);
82
+ declaration.delete();
83
83
  });
84
84
  }
85
85
 
@@ -1,5 +1,5 @@
1
- import { Children, memo } from "@alloy-js/core/jsx-runtime";
2
1
  import { isRef, Ref } from "@vue/reactivity";
2
+ import { type Children, memo } from "../jsx-runtime.js";
3
3
  import { baseListPropsToMapJoinArgs, mapJoin } from "../utils.js";
4
4
  import { BaseListProps } from "./List.jsx";
5
5
 
@@ -1,4 +1,4 @@
1
- import { Children } from "@alloy-js/core/jsx-runtime";
1
+ import type { Children } from "../jsx-runtime.js";
2
2
 
3
3
  export interface IndentProps {
4
4
  children: Children;
@@ -1,4 +1,4 @@
1
- import { Children, memo, splitProps } from "@alloy-js/core/jsx-runtime";
1
+ import { Children, memo, splitProps } from "../jsx-runtime.js";
2
2
  import { childrenArray } from "../utils.js";
3
3
  import { For } from "./For.jsx";
4
4
 
@@ -1,9 +1,9 @@
1
- import { OutputSymbol, OutputSymbolFlags } from "../binder.js";
2
1
  import { useContext } from "../context.js";
3
2
  import { BinderContext } from "../context/binder.js";
4
3
  import { MemberDeclarationContext } from "../context/member-declaration.js";
5
4
  import { Children } from "../jsx-runtime.js";
6
5
  import { Refkey } from "../refkey.js";
6
+ import { OutputSymbol, OutputSymbolFlags } from "../symbols/output-symbol.js";
7
7
 
8
8
  /**
9
9
  * Create a member declaration by providing a symbol name and optional symbol
@@ -85,9 +85,9 @@ export function MemberDeclaration(props: MemberDeclarationProps) {
85
85
  "Must provide a member name, or else provide a member symbol",
86
86
  );
87
87
  }
88
- declaration = binder.createSymbol({
89
- name: infoProps.name!,
90
- refkey: infoProps.refkey,
88
+
89
+ declaration = new OutputSymbol(infoProps.name!, {
90
+ refkeys: infoProps.refkey,
91
91
  metadata: infoProps.metadata,
92
92
  flags:
93
93
  infoProps.static ?
@@ -1,9 +1,6 @@
1
- import { OutputSymbol } from "../binder.js";
2
- import { Children } from "../jsx-runtime.js";
3
-
4
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
5
- import { OutputSymbolFlags } from "../binder.js";
6
1
  import { MemberScopeContext } from "../context/member-scope.js";
2
+ import { Children } from "../jsx-runtime.js";
3
+ import { OutputSymbol } from "../symbols/output-symbol.js";
7
4
  export interface MemberScopeProps {
8
5
  /**
9
6
  * The name of the member scope.
@@ -1,5 +1,5 @@
1
1
  import { childrenArray, computed } from "@alloy-js/core";
2
- import { Children } from "@alloy-js/core/jsx-runtime";
2
+ import type { Children } from "../jsx-runtime.js";
3
3
 
4
4
  export interface Prose {
5
5
  children: Children;
@@ -1,7 +1,7 @@
1
- import { Children } from "@alloy-js/core/jsx-runtime";
2
1
  import { computed } from "@vue/reactivity";
3
2
  import { useContext } from "../context.js";
4
3
  import { BinderContext } from "../context/binder.js";
4
+ import type { Children } from "../jsx-runtime.js";
5
5
  import type { Refkey } from "../refkey.js";
6
6
 
7
7
  export interface ReferenceOrContentProps {
@@ -1,8 +1,6 @@
1
- import { OutputScope } from "../binder.js";
2
- import { useContext } from "../context.js";
3
- import { BinderContext } from "../context/binder.js";
4
1
  import { ScopeContext } from "../context/scope.js";
5
2
  import { Children } from "../jsx-runtime.js";
3
+ import { OutputScope } from "../symbols/output-scope.js";
6
4
 
7
5
  /**
8
6
  * Declare a scope by providing an already created scope. The scope is merely
@@ -53,11 +51,9 @@ export function Scope(props: ScopeProps) {
53
51
  if ("value" in props) {
54
52
  scope = props.value;
55
53
  } else {
56
- const binder = useContext(BinderContext)!;
57
- scope = binder.createScope({
54
+ scope = new OutputScope(props.name ?? "", {
58
55
  kind: props.kind,
59
56
  metadata: props.metadata,
60
- name: props.name ?? "",
61
57
  });
62
58
  }
63
59
 
@@ -1,4 +1,4 @@
1
- import { Children } from "@alloy-js/core/jsx-runtime";
1
+ import type { Children } from "../jsx-runtime.js";
2
2
 
3
3
  export interface ShowProps {
4
4
  children: Children;
@@ -1,4 +1,5 @@
1
- import { Children, List } from "@alloy-js/core";
1
+ import type { Children } from "../jsx-runtime.js";
2
+ import { List } from "./List.jsx";
2
3
 
3
4
  export interface StatementListProps {
4
5
  children: Children;
@@ -1,4 +1,4 @@
1
- import { Children, memo, taggedComponent } from "@alloy-js/core/jsx-runtime";
1
+ import { type Children, memo, taggedComponent } from "../jsx-runtime.js";
2
2
  import { childrenArray, findKeyedChildren } from "../utils.js";
3
3
 
4
4
  export interface SwitchProps {
@@ -1,4 +1,4 @@
1
- import { Children, ComponentDefinition } from "@alloy-js/core/jsx-runtime";
1
+ import { Children, ComponentDefinition } from "../jsx-runtime.js";
2
2
 
3
3
  export interface WrapProps<TProps> {
4
4
  /**
@@ -1,9 +1,9 @@
1
- import { OutputSymbol } from "../binder.js";
2
1
  import {
3
2
  ComponentContext,
4
3
  createNamedContext,
5
4
  useContext,
6
5
  } from "../context.js";
6
+ import type { OutputSymbol } from "../symbols/output-symbol.js";
7
7
 
8
8
  export interface AssignmentContext {
9
9
  /**
@@ -1,4 +1,4 @@
1
- import { Binder } from "../binder.js";
1
+ import type { Binder } from "../binder.js";
2
2
  import {
3
3
  ComponentContext,
4
4
  createNamedContext,
@@ -15,5 +15,5 @@ export const BinderContext: ComponentContext<Binder> =
15
15
  createNamedContext("Binder");
16
16
 
17
17
  export function useBinder() {
18
- return useContext(BinderContext)!;
18
+ return useContext(BinderContext);
19
19
  }
@@ -1,5 +1,5 @@
1
- import { OutputSymbol } from "../binder.js";
2
1
  import { ComponentContext, createNamedContext } from "../context.js";
2
+ import type { OutputSymbol } from "../symbols/output-symbol.js";
3
3
 
4
4
  export const DeclarationContext: ComponentContext<OutputSymbol> =
5
5
  createNamedContext("Declaration");
@@ -1,9 +1,9 @@
1
- import { OutputSymbol } from "../binder.js";
2
1
  import {
3
2
  ComponentContext,
4
3
  createNamedContext,
5
4
  useContext,
6
5
  } from "../context.js";
6
+ import type { OutputSymbol } from "../symbols/output-symbol.js";
7
7
 
8
8
  /**
9
9
  * Provides the symbol for the member currently being declared.
@@ -1,9 +1,9 @@
1
- import { OutputScope } from "../binder.js";
2
1
  import {
3
2
  ComponentContext,
4
3
  createNamedContext,
5
4
  useContext,
6
5
  } from "../context.js";
6
+ import type { OutputScope } from "../symbols/output-scope.js";
7
7
 
8
8
  /**
9
9
  * The member scope context provides the instance and static member scopes that
@@ -3,7 +3,7 @@ import {
3
3
  createNamedContext,
4
4
  useContext,
5
5
  } from "../context.js";
6
- import { NamePolicy } from "../name-policy.js";
6
+ import type { NamePolicy } from "../name-policy.js";
7
7
 
8
8
  export const NamePolicyContext: ComponentContext<NamePolicy<string>> =
9
9
  createNamedContext<NamePolicy<string>>("NamePolicy", {
@@ -1,9 +1,9 @@
1
- import { OutputScope } from "../binder.js";
2
1
  import {
3
2
  ComponentContext,
4
3
  createNamedContext,
5
4
  useContext,
6
5
  } from "../context.js";
6
+ import type { OutputScope } from "../symbols/output-scope.js";
7
7
 
8
8
  export const ScopeContext: ComponentContext<OutputScope> =
9
9
  createNamedContext("Scope");
@@ -1,5 +1,5 @@
1
1
  import { ComponentContext, createNamedContext } from "../context.js";
2
- import { SourceFileContext } from "./source-file.js";
2
+ import type { SourceFileContext } from "./source-file.js";
3
3
 
4
4
  export interface SourceDirectoryContext {
5
5
  contents: (SourceDirectoryContext | SourceFileContext)[];
@@ -1,6 +1,6 @@
1
1
  import { ComponentContext, createNamedContext } from "../context.js";
2
- import { ComponentDefinition } from "../jsx-runtime.js";
3
- import { Refkey } from "../refkey.js";
2
+ import type { ComponentDefinition } from "../jsx-runtime.js";
3
+ import type { Refkey } from "../refkey.js";
4
4
 
5
5
  export interface SourceFileContext {
6
6
  path: string;
package/src/index.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  export {
2
+ TrackOpTypes,
3
+ TriggerOpTypes,
2
4
  computed,
3
5
  isProxy,
6
+ isReactive,
7
+ isRef,
4
8
  reactive,
5
9
  ref,
6
10
  shallowReactive,
@@ -8,7 +12,15 @@ export {
8
12
  toRaw,
9
13
  toRef,
10
14
  toRefs,
15
+ track,
16
+ trigger,
17
+ watch,
18
+ type Reactive,
11
19
  type Ref,
20
+ type ShallowReactive,
21
+ type ShallowRef,
22
+ type ToRef,
23
+ type ToRefs,
12
24
  } from "@vue/reactivity";
13
25
  export * from "./binder.js";
14
26
  export * from "./code.js";
@@ -17,10 +29,13 @@ export * from "./context.js";
17
29
  export * from "./context/index.js";
18
30
  export * from "./jsx-runtime.js";
19
31
  export * from "./name-policy.js";
32
+ export * from "./reactive-union-set.js";
20
33
  export * from "./refkey.js";
21
34
  export * from "./render.js";
22
35
  export * from "./stc.js";
23
36
  export * from "./sti.js";
37
+ export * from "./symbols/index.js";
38
+ export * from "./symbols/symbol-flow.js";
24
39
  export * from "./tap.js";
25
40
  export * from "./utils.js";
26
41
  export * from "./write-output.js";
@@ -8,14 +8,16 @@ import {
8
8
  ReactiveEffectRunner,
9
9
  Ref,
10
10
  resetTracking,
11
+ ShallowReactive,
11
12
  shallowRef,
12
13
  stop,
13
14
  toRefs,
14
15
  effect as vueEffect,
15
16
  } from "@vue/reactivity";
16
- import { Refkey } from "./refkey.js";
17
- import { RenderedTextTree } from "./render.js";
17
+ import type { Refkey } from "./refkey.js";
18
+ import type { RenderedTextTree } from "./render.js";
18
19
  import { scheduler } from "./scheduler.js";
20
+ import type { OutputSymbol } from "./symbols/output-symbol.js";
19
21
 
20
22
  if ((globalThis as any).ALLOY) {
21
23
  throw new Error(
@@ -48,6 +50,16 @@ export interface Context {
48
50
  * be the component that created it.
49
51
  */
50
52
  componentOwner?: ComponentCreator<unknown>;
53
+
54
+ /**
55
+ * Whether this context will take an emitted symbol.
56
+ */
57
+ takesSymbols: boolean;
58
+
59
+ /**
60
+ * The symbol that this component has taken.
61
+ */
62
+ takenSymbols?: ShallowReactive<Set<OutputSymbol>>;
51
63
  }
52
64
 
53
65
  let globalContext: Context | null = null;
@@ -76,6 +88,8 @@ export function root<T>(fn: (d: Disposable) => T, options?: RootOptions): T {
76
88
  owner: globalContext,
77
89
  context: {},
78
90
  elementCache: new Map(),
91
+ takesSymbols: false,
92
+ takenSymbols: undefined,
79
93
  };
80
94
 
81
95
  globalContext = context;
@@ -119,6 +133,8 @@ export function effect<T>(fn: (prev?: T) => T, current?: T) {
119
133
  disposables: [] as (() => void)[],
120
134
  owner: globalContext,
121
135
  elementCache: new Map(),
136
+ takesSymbols: false,
137
+ takenSymbols: undefined,
122
138
  };
123
139
 
124
140
  const cleanupFn = (final: boolean) => {
@@ -0,0 +1,238 @@
1
+ import { effect } from "@alloy-js/core/jsx-runtime";
2
+ import {
3
+ ITERATE_KEY,
4
+ ReactiveFlags,
5
+ shallowReactive,
6
+ shallowReadonly,
7
+ track,
8
+ TrackOpTypes,
9
+ trigger,
10
+ TriggerOpTypes,
11
+ } from "@vue/reactivity";
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
+ }
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
+ }