@alloy-js/core 0.20.0-dev.3 → 0.20.0-dev.6

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 (137) hide show
  1. package/dist/src/binder.d.ts +62 -38
  2. package/dist/src/binder.d.ts.map +1 -1
  3. package/dist/src/binder.js +214 -173
  4. package/dist/src/components/Declaration.d.ts +2 -2
  5. package/dist/src/components/Declaration.d.ts.map +1 -1
  6. package/dist/src/components/Declaration.js +8 -2
  7. package/dist/src/components/MemberDeclaration.d.ts +2 -2
  8. package/dist/src/components/MemberDeclaration.d.ts.map +1 -1
  9. package/dist/src/components/MemberDeclaration.js +9 -5
  10. package/dist/src/components/MemberScope.d.ts +30 -13
  11. package/dist/src/components/MemberScope.d.ts.map +1 -1
  12. package/dist/src/components/MemberScope.js +37 -15
  13. package/dist/src/components/Output.d.ts.map +1 -1
  14. package/dist/src/components/Output.js +2 -5
  15. package/dist/src/components/ReferenceOrContent.d.ts +1 -1
  16. package/dist/src/components/ReferenceOrContent.d.ts.map +1 -1
  17. package/dist/src/components/Scope.d.ts +5 -5
  18. package/dist/src/components/Scope.d.ts.map +1 -1
  19. package/dist/src/components/Scope.js +9 -5
  20. package/dist/src/context/member-scope.d.ts +7 -8
  21. package/dist/src/context/member-scope.d.ts.map +1 -1
  22. package/dist/src/context/member-scope.js +5 -5
  23. package/dist/src/context/name-policy.d.ts.map +1 -1
  24. package/dist/src/context/name-policy.js +3 -0
  25. package/dist/src/context/scope.d.ts +1 -0
  26. package/dist/src/context/scope.d.ts.map +1 -1
  27. package/dist/src/context/scope.js +7 -0
  28. package/dist/src/inspect.browser.d.ts +5 -0
  29. package/dist/src/inspect.browser.d.ts.map +1 -0
  30. package/dist/src/inspect.browser.js +5 -0
  31. package/dist/src/inspect.d.ts +2 -0
  32. package/dist/src/inspect.d.ts.map +1 -0
  33. package/dist/src/inspect.js +1 -0
  34. package/dist/src/name-policy.d.ts +11 -0
  35. package/dist/src/name-policy.d.ts.map +1 -1
  36. package/dist/src/name-policy.js +3 -0
  37. package/dist/src/reactive-union-set.d.ts.map +1 -1
  38. package/dist/src/reactive-union-set.js +12 -8
  39. package/dist/src/refkey.d.ts +39 -3
  40. package/dist/src/refkey.d.ts.map +1 -1
  41. package/dist/src/refkey.js +52 -8
  42. package/dist/src/symbols/basic-scope.d.ts +14 -0
  43. package/dist/src/symbols/basic-scope.d.ts.map +1 -0
  44. package/dist/src/symbols/basic-scope.js +20 -0
  45. package/dist/src/symbols/basic-symbol.d.ts +19 -0
  46. package/dist/src/symbols/basic-symbol.d.ts.map +1 -0
  47. package/dist/src/symbols/basic-symbol.js +28 -0
  48. package/dist/src/symbols/index.d.ts +3 -1
  49. package/dist/src/symbols/index.d.ts.map +1 -1
  50. package/dist/src/symbols/index.js +3 -1
  51. package/dist/src/symbols/output-scope.d.ts +70 -41
  52. package/dist/src/symbols/output-scope.d.ts.map +1 -1
  53. package/dist/src/symbols/output-scope.js +98 -130
  54. package/dist/src/symbols/output-space.d.ts +25 -0
  55. package/dist/src/symbols/output-space.d.ts.map +1 -0
  56. package/dist/src/symbols/output-space.js +35 -0
  57. package/dist/src/symbols/output-symbol.d.ts +213 -37
  58. package/dist/src/symbols/output-symbol.d.ts.map +1 -1
  59. package/dist/src/symbols/output-symbol.js +323 -203
  60. package/dist/src/symbols/symbol-flow.d.ts +1 -1
  61. package/dist/src/symbols/symbol-flow.d.ts.map +1 -1
  62. package/dist/src/symbols/symbol-flow.js +22 -7
  63. package/dist/src/symbols/symbol-slot.d.ts +27 -9
  64. package/dist/src/symbols/symbol-slot.d.ts.map +1 -1
  65. package/dist/src/symbols/symbol-slot.js +20 -4
  66. package/dist/src/symbols/symbol-table.d.ts +19 -8
  67. package/dist/src/symbols/symbol-table.d.ts.map +1 -1
  68. package/dist/src/symbols/symbol-table.js +65 -16
  69. package/dist/src/tracer.d.ts +15 -3
  70. package/dist/src/tracer.d.ts.map +1 -1
  71. package/dist/src/tracer.js +39 -63
  72. package/dist/src/utils.d.ts +1 -1
  73. package/dist/src/utils.d.ts.map +1 -1
  74. package/dist/src/utils.js +4 -4
  75. package/dist/src/write-output.d.ts +1 -1
  76. package/dist/src/write-output.d.ts.map +1 -1
  77. package/dist/src/write-output.js +31 -37
  78. package/dist/test/components/declaration.test.js +9 -14
  79. package/dist/test/components/reference-or-content.test.js +2 -2
  80. package/dist/test/symbols/output-scope.test.js +33 -198
  81. package/dist/test/symbols/output-symbol.test.js +139 -385
  82. package/dist/test/symbols/resolution.test.js +431 -114
  83. package/dist/test/symbols/symbol-table.test.d.ts +2 -0
  84. package/dist/test/symbols/symbol-table.test.d.ts.map +1 -0
  85. package/dist/test/symbols/symbol-table.test.js +14 -0
  86. package/dist/test/symbols/utils.d.ts +10 -24
  87. package/dist/test/symbols/utils.d.ts.map +1 -1
  88. package/dist/test/symbols/utils.js +23 -45
  89. package/dist/tsconfig.tsbuildinfo +1 -1
  90. package/package.json +4 -2
  91. package/src/binder.ts +348 -273
  92. package/src/components/Declaration.tsx +13 -3
  93. package/src/components/MemberDeclaration.tsx +15 -8
  94. package/src/components/MemberScope.tsx +61 -20
  95. package/src/components/Output.tsx +0 -4
  96. package/src/components/Scope.tsx +16 -9
  97. package/src/context/member-scope.ts +10 -10
  98. package/src/context/name-policy.ts +3 -0
  99. package/src/context/scope.ts +9 -0
  100. package/src/inspect.browser.ts +6 -0
  101. package/src/inspect.ts +1 -0
  102. package/src/name-policy.ts +14 -0
  103. package/src/reactive-union-set.ts +14 -8
  104. package/src/refkey.ts +88 -14
  105. package/src/symbols/basic-scope.ts +23 -0
  106. package/src/symbols/basic-symbol.ts +32 -0
  107. package/src/symbols/index.ts +3 -1
  108. package/src/symbols/output-scope.ts +131 -170
  109. package/src/symbols/output-space.ts +49 -0
  110. package/src/symbols/output-symbol.ts +434 -258
  111. package/src/symbols/symbol-flow.ts +38 -9
  112. package/src/symbols/symbol-slot.tsx +46 -8
  113. package/src/symbols/symbol-table.ts +95 -21
  114. package/src/tracer.ts +53 -83
  115. package/src/utils.tsx +4 -4
  116. package/src/write-output.ts +33 -45
  117. package/temp/api.json +5551 -3066
  118. package/test/components/declaration.test.tsx +6 -19
  119. package/test/components/reference-or-content.test.tsx +2 -2
  120. package/test/symbols/output-scope.test.ts +33 -125
  121. package/test/symbols/output-symbol.test.ts +128 -348
  122. package/test/symbols/resolution.test.ts +530 -117
  123. package/test/symbols/symbol-table.test.ts +15 -0
  124. package/test/symbols/utils.ts +38 -74
  125. package/tsdoc.json +4 -0
  126. package/dist/src/slot.d.ts +0 -15
  127. package/dist/src/slot.d.ts.map +0 -1
  128. package/dist/src/slot.js +0 -50
  129. package/dist/src/symbols/flags.d.ts +0 -70
  130. package/dist/src/symbols/flags.d.ts.map +0 -1
  131. package/dist/src/symbols/flags.js +0 -72
  132. package/dist/test/components/slot.test.d.ts +0 -2
  133. package/dist/test/components/slot.test.d.ts.map +0 -1
  134. package/dist/test/components/slot.test.js +0 -134
  135. package/src/slot.ts +0 -89
  136. package/src/symbols/flags.ts +0 -82
  137. package/test/components/slot.test.tsx +0 -174
@@ -1,9 +1,12 @@
1
1
  import { useContext } from "../context.js";
2
2
  import { BinderContext } from "../context/binder.js";
3
3
  import { DeclarationContext } from "../context/declaration.js";
4
+ import { useScope } from "../context/scope.js";
4
5
  import { onCleanup } from "../reactivity.js";
5
- import { Refkey } from "../refkey.js";
6
+ import { Namekey, Refkey } from "../refkey.js";
6
7
  import type { Children } from "../runtime/component.js";
8
+ import { BasicScope } from "../symbols/basic-scope.js";
9
+ import { BasicSymbol } from "../symbols/basic-symbol.js";
7
10
  import { OutputSymbol } from "../symbols/output-symbol.js";
8
11
 
9
12
  /**
@@ -27,7 +30,7 @@ export interface DeclarationPropsWithInfo {
27
30
  /**
28
31
  * The name of this declaration.
29
32
  */
30
- name: string;
33
+ name: string | Namekey;
31
34
 
32
35
  /**
33
36
  * The unique key or array of unique keys for this declaration.
@@ -73,7 +76,14 @@ export function Declaration(props: DeclarationProps) {
73
76
  if ("symbol" in props) {
74
77
  declaration = props.symbol;
75
78
  } else {
76
- declaration = new OutputSymbol(props.name, {
79
+ const scope = useScope();
80
+ if (!(scope instanceof BasicScope)) {
81
+ throw new Error(
82
+ "Declaration component cannot create a symbol in a non-basic scope",
83
+ );
84
+ }
85
+
86
+ declaration = new BasicSymbol(props.name, scope.symbols, {
77
87
  binder,
78
88
  refkeys: [props.refkey ?? []].flat(),
79
89
  metadata: props.metadata,
@@ -1,9 +1,10 @@
1
1
  import { useContext } from "../context.js";
2
2
  import { BinderContext } from "../context/binder.js";
3
3
  import { MemberDeclarationContext } from "../context/member-declaration.js";
4
- import type { Refkey } from "../refkey.js";
4
+ import { useMemberContext } from "../context/member-scope.js";
5
+ import type { Namekey, Refkey } from "../refkey.js";
5
6
  import type { Children } from "../runtime/component.js";
6
- import { OutputSymbolFlags } from "../symbols/flags.js";
7
+ import { BasicSymbol } from "../symbols/basic-symbol.js";
7
8
  import { OutputSymbol } from "../symbols/output-symbol.js";
8
9
 
9
10
  /**
@@ -14,7 +15,7 @@ export interface MemberDeclarationPropsWithInfo {
14
15
  /**
15
16
  * The name of this declaration.
16
17
  */
17
- name: string;
18
+ name: string | Namekey;
18
19
 
19
20
  /**
20
21
  * The refkey or array refkeys for this declaration.
@@ -87,13 +88,19 @@ export function MemberDeclaration(props: MemberDeclarationProps) {
87
88
  );
88
89
  }
89
90
 
90
- declaration = new OutputSymbol(infoProps.name!, {
91
+ const scopeContext = useMemberContext()!;
92
+ if (!(scopeContext.ownerSymbol instanceof BasicSymbol)) {
93
+ throw new Error(
94
+ "MemberDeclaration component cannot create a symbol in a non-basic scope",
95
+ );
96
+ }
97
+ const space =
98
+ infoProps.static ?
99
+ scopeContext.ownerSymbol.staticMembers
100
+ : scopeContext.ownerSymbol.instanceMembers;
101
+ declaration = new BasicSymbol(infoProps.name, space, {
91
102
  refkeys: infoProps.refkey,
92
103
  metadata: infoProps.metadata,
93
- flags:
94
- infoProps.static ?
95
- OutputSymbolFlags.StaticMember
96
- : OutputSymbolFlags.InstanceMember,
97
104
  });
98
105
  }
99
106
 
@@ -1,41 +1,82 @@
1
- import { MemberScopeContext } from "../context/member-scope.js";
1
+ import { MemberContext } from "../context/member-scope.js";
2
+
3
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
4
+ import { ScopeContext } from "../context/scope.js";
2
5
  import type { Children } from "../runtime/component.js";
6
+ import { OutputScope } from "../symbols/output-scope.js";
3
7
  import type { OutputSymbol } from "../symbols/output-symbol.js";
4
- export interface MemberScopeProps {
8
+ import { Scope } from "./Scope.jsx";
9
+
10
+ /**
11
+ * Declare a member scope by providing an already created scope. The scope is
12
+ * exposed via {@link ScopeContext}.
13
+ */
14
+ export interface MemberScopePropsWithValue {
15
+ /**
16
+ * The scope to use. If not provided, a new scope will be created.
17
+ */
18
+ value: OutputScope;
19
+
20
+ children?: Children;
21
+ }
22
+
23
+ /**
24
+ * Create a member scope by providing a name and optional metadata.
25
+ */
26
+ export interface MemberScopePropsWithInfo {
5
27
  /**
6
- * The name of the member scope.
28
+ * The name of this scope.
7
29
  */
8
30
  name?: string;
9
31
 
10
32
  /**
11
- * The symbol that owns these members. This symbol must have either
12
- * {@link OutputSymbolFlags.InstanceMemberContainer} or
13
- * {@link OutputSymbolFlags.StaticMemberContainer}.
33
+ * The symbol whose members provide the symbols for this scope.
34
+ */
35
+ ownerSymbol: OutputSymbol;
36
+
37
+ /**
38
+ * Additional metadata for the scope.
14
39
  */
15
- owner: OutputSymbol;
40
+ metadata?: Record<string, unknown>;
41
+
16
42
  children?: Children;
17
43
  }
18
44
 
45
+ export type MemberScopeProps =
46
+ | MemberScopePropsWithValue
47
+ | MemberScopePropsWithInfo;
48
+
19
49
  /**
20
- * Declare a member scope, which is a scope that holds instance and static
21
- * members. This scope is then used for nested instance or static member
22
- * declarations and resolution of instance members.
50
+ * Declare a member scope, which is a lexical scope whose symbols are provided
51
+ * by the owner symbol.
23
52
  *
24
53
  * @remarks
25
54
  *
26
- * The member scope contains scopes for both instance and static members.
27
- * However, it does not affect the resolution of static members.
28
- *
29
- * @see {@link (MemberScopeContext:variable)}
55
+ * This is used to create members of a symbol, e.g. for class members and the
56
+ * like. In some languages, this scope may provide symbols which are can be
57
+ * referenced lexically, but in other languages, these members may not be in
58
+ * scope and instead must be referenced via the owner symbol itself.
30
59
  */
31
60
  export function MemberScope(props: MemberScopeProps) {
32
- const context: MemberScopeContext = {
33
- instanceMembers: props.owner.instanceMemberScope,
34
- staticMembers: props.owner.staticMemberScope,
61
+ if ("value" in props) {
62
+ const sym = props.value;
63
+ if (!sym.isMemberScope) {
64
+ throw new Error(
65
+ "MemberScope must be passed a value that is a member scope.",
66
+ );
67
+ }
68
+ }
69
+
70
+ const context: MemberContext = {
71
+ ownerSymbol:
72
+ "value" in props ? props.value.ownerSymbol! : props.ownerSymbol!,
35
73
  };
74
+
36
75
  return (
37
- <MemberScopeContext.Provider value={context}>
38
- {props.children}
39
- </MemberScopeContext.Provider>
76
+ <Scope {...props}>
77
+ <MemberContext.Provider value={context}>
78
+ {props.children}
79
+ </MemberContext.Provider>
80
+ </Scope>
40
81
  );
41
82
  }
@@ -9,7 +9,6 @@ import { NamePolicy } from "../name-policy.js";
9
9
  import { getContext } from "../reactivity.js";
10
10
  import { PrintTreeOptions } from "../render.js";
11
11
  import type { Children } from "../runtime/component.js";
12
- import { extensionEffects } from "../slot.js";
13
12
  import { SourceDirectory } from "./SourceDirectory.js";
14
13
 
15
14
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -71,9 +70,6 @@ export function Output(props: OutputProps) {
71
70
 
72
71
  return (
73
72
  <BinderContext.Provider value={binder}>
74
- {() => {
75
- extensionEffects.forEach((e) => e());
76
- }}
77
73
  {props.namePolicy ?
78
74
  <NamePolicyContext.Provider value={props.namePolicy}>
79
75
  {dir}
@@ -1,6 +1,8 @@
1
- import { ScopeContext } from "../context/scope.js";
1
+ import { ScopeContext, useScope } from "../context/scope.js";
2
2
  import type { Children } from "../runtime/component.js";
3
+ import { BasicScope } from "../symbols/basic-scope.js";
3
4
  import { OutputScope } from "../symbols/output-scope.js";
5
+ import { OutputSymbol } from "../symbols/output-symbol.js";
4
6
 
5
7
  /**
6
8
  * Declare a scope by providing an already created scope. The scope is merely
@@ -19,12 +21,6 @@ export interface ScopePropsWithValue {
19
21
  * Create a scope by providing a name and optional metadata.
20
22
  */
21
23
  export interface ScopePropsWithInfo {
22
- /**
23
- * The kind of scope. This may be used by application code to determine how
24
- * to handle symbols in this scope. It is not used by the core framework.
25
- */
26
- kind?: string;
27
-
28
24
  /**
29
25
  * The name of this scope.
30
26
  */
@@ -35,6 +31,11 @@ export interface ScopePropsWithInfo {
35
31
  */
36
32
  metadata?: Record<string, unknown>;
37
33
 
34
+ /**
35
+ * Create a member scope with the owner symbol providing the in-scope symbols.
36
+ */
37
+ ownerSymbol?: OutputSymbol;
38
+
38
39
  children?: Children;
39
40
  }
40
41
 
@@ -51,9 +52,15 @@ export function Scope(props: ScopeProps) {
51
52
  if ("value" in props) {
52
53
  scope = props.value;
53
54
  } else {
54
- scope = new OutputScope(props.name ?? "", {
55
- kind: props.kind,
55
+ const parentScope = useScope();
56
+ if (parentScope && !(parentScope instanceof BasicScope)) {
57
+ throw new Error(
58
+ "Scope component can only make scopes within a BasicScope",
59
+ );
60
+ }
61
+ scope = new BasicScope(props.name ?? "", parentScope, {
56
62
  metadata: props.metadata,
63
+ ownerSymbol: props.ownerSymbol,
57
64
  });
58
65
  }
59
66
 
@@ -3,19 +3,19 @@ import {
3
3
  createNamedContext,
4
4
  useContext,
5
5
  } from "../context.js";
6
- import type { OutputScope } from "../symbols/output-scope.js";
6
+ import { OutputSymbol } from "../symbols/output-symbol.js";
7
7
 
8
8
  /**
9
- * The member scope context provides the instance and static member scopes that
10
- * are used for member declarations and instance member resolution.
9
+ * The member context provides the symbol upon which new member symbols
10
+ * should be created.
11
11
  */
12
- export interface MemberScopeContext {
13
- staticMembers?: OutputScope;
14
- instanceMembers?: OutputScope;
12
+ export interface MemberContext {
13
+ ownerSymbol: OutputSymbol;
15
14
  }
16
- export const MemberScopeContext: ComponentContext<MemberScopeContext> =
17
- createNamedContext("MemberScope");
18
15
 
19
- export function useMemberScope() {
20
- return useContext(MemberScopeContext)!;
16
+ export const MemberContext: ComponentContext<MemberContext> =
17
+ createNamedContext("MemberContext");
18
+
19
+ export function useMemberContext() {
20
+ return useContext(MemberContext);
21
21
  }
@@ -10,6 +10,9 @@ export const NamePolicyContext: ComponentContext<NamePolicy<string>> =
10
10
  getName(name) {
11
11
  return name;
12
12
  },
13
+ for(element) {
14
+ return (name) => name;
15
+ },
13
16
  });
14
17
 
15
18
  export function useNamePolicy() {
@@ -11,3 +11,12 @@ export const ScopeContext: ComponentContext<OutputScope> =
11
11
  export function useScope() {
12
12
  return useContext(ScopeContext)!;
13
13
  }
14
+
15
+ export function useMemberScope() {
16
+ const scope = useScope();
17
+ if (!scope.isMemberScope) {
18
+ throw new Error("Expected a member scope, but got a non-member scope.");
19
+ }
20
+
21
+ return scope;
22
+ }
@@ -0,0 +1,6 @@
1
+ // inspection is not supported in browsers
2
+ export function inspect() {
3
+ return "custom inspect";
4
+ }
5
+
6
+ inspect.custom = Symbol();
package/src/inspect.ts ADDED
@@ -0,0 +1 @@
1
+ export { inspect } from "util";
@@ -1,5 +1,16 @@
1
+ export interface NamePolicyGetter {
2
+ (originalName: string): string;
3
+ }
1
4
  export interface NamePolicy<TElements extends string> {
5
+ /**
6
+ * Apply the language policy to the provided name for the provided element
7
+ * type.
8
+ */
2
9
  getName(originalName: string, element: TElements): string;
10
+ /**
11
+ * Get a function that takes a name and applies the naming policy to it.
12
+ */
13
+ for(element: TElements): NamePolicyGetter;
3
14
  }
4
15
 
5
16
  export function createNamePolicy<T extends string>(
@@ -9,5 +20,8 @@ export function createNamePolicy<T extends string>(
9
20
  getName(name, element) {
10
21
  return namer(name, element);
11
22
  },
23
+ for(element) {
24
+ return (name) => namer(name, element);
25
+ },
12
26
  };
13
27
  }
@@ -8,7 +8,7 @@ import {
8
8
  trigger,
9
9
  TriggerOpTypes,
10
10
  } from "@vue/reactivity";
11
- import { effect } from "./reactivity.js";
11
+ import { effect, untrack } from "./reactivity.js";
12
12
 
13
13
  export interface ReactiveUnionSetOptions<T> {
14
14
  onAdd?: OnReactiveSetAddCallback<T>;
@@ -133,7 +133,7 @@ export class ReactiveUnionSet<T> extends Set<T> {
133
133
  effect(() => {
134
134
  for (const [prevSourceValue, prevTargetValue] of prevValues) {
135
135
  if (!subset.has(prevSourceValue)) {
136
- onDelete?.(prevSourceValue);
136
+ untrack(() => onDelete?.(prevSourceValue));
137
137
  prevValues.delete(prevSourceValue);
138
138
  this.delete(prevTargetValue);
139
139
  }
@@ -142,7 +142,7 @@ export class ReactiveUnionSet<T> extends Set<T> {
142
142
  for (const value of subset) {
143
143
  if (!prevValues.has(value)) {
144
144
  if (onAdd) {
145
- const added = onAdd(value);
145
+ const added = untrack(() => onAdd(value));
146
146
  prevValues.set(value, added);
147
147
  } else {
148
148
  this.add(value);
@@ -207,22 +207,28 @@ export class ReactiveUnionSet<T> extends Set<T> {
207
207
 
208
208
  return shallowReadonly(set);
209
209
  }
210
+
210
211
  createIndex<U>(mapper: (value: T) => U | U[]): ReadonlyMap<U, T> {
211
212
  const index = shallowReactive(new Map<U, T>());
212
213
  this._indexes.push({
213
214
  add: (value: T) => {
214
215
  effect((oldValue) => {
215
- for (const id of [oldValue].flat()) {
216
- index.delete(id as U);
216
+ if (oldValue) {
217
+ for (const id of [oldValue].flat()) {
218
+ index.delete(id as U);
219
+ }
217
220
  }
218
221
 
219
- const mappedValue = mapper(value);
222
+ // we filter to avoid overwriting existing values (first wins)
223
+ const mappedValues = [mapper(value)]
224
+ .flat()
225
+ .filter((v) => untrack(() => !index.has(v as U)));
220
226
 
221
- for (const id of [mappedValue].flat()) {
227
+ for (const id of mappedValues) {
222
228
  index.set(id as U, value as any);
223
229
  }
224
230
 
225
- return mappedValue;
231
+ return mappedValues;
226
232
  });
227
233
  },
228
234
  delete: (value: T) => {
package/src/refkey.ts CHANGED
@@ -1,14 +1,14 @@
1
1
  import { markRaw } from "@vue/reactivity";
2
2
 
3
- const objectIds = new WeakMap<WeakKey, Refkey>();
3
+ const objectIds = new WeakMap<WeakKey, string>();
4
4
  let objId = 0;
5
5
 
6
- function getObjectKey(value: WeakKey) {
6
+ function getObjectKey(value: WeakKey): string {
7
7
  if (objectIds.has(value)) {
8
8
  return objectIds.get(value)!;
9
9
  }
10
10
 
11
- const key = createRefkey(`o${objId++}`);
11
+ const key = `o${objId++}`;
12
12
  objectIds.set(value, key);
13
13
 
14
14
  return key;
@@ -16,10 +16,34 @@ function getObjectKey(value: WeakKey) {
16
16
 
17
17
  const RefkeySym: unique symbol = Symbol();
18
18
 
19
- export type Refkey = { key: string; [RefkeySym]: true };
19
+ export type RefkeyBase = {
20
+ [RefkeySym]: true;
21
+ };
20
22
 
21
- function createRefkey(key: string): Refkey {
22
- const refkey: Refkey = {
23
+ export type Refkey = SymbolRefkey | MemberRefkey | Namekey;
24
+
25
+ export interface SymbolRefkey extends RefkeyBase {
26
+ key: string;
27
+ }
28
+
29
+ export interface NamekeyOptions {
30
+ ignoreNamePolicy?: boolean;
31
+ ignoreNameConflict?: boolean;
32
+ }
33
+
34
+ export interface Namekey<TOptions extends NamekeyOptions = NamekeyOptions>
35
+ extends SymbolRefkey {
36
+ name: string;
37
+ options: TOptions;
38
+ }
39
+
40
+ export interface MemberRefkey extends RefkeyBase {
41
+ base: Refkey;
42
+ member: Refkey;
43
+ }
44
+
45
+ function createSymbolRefkey(key: string): SymbolRefkey {
46
+ const refkey: SymbolRefkey = {
23
47
  key,
24
48
  [RefkeySym]: true,
25
49
  };
@@ -37,13 +61,34 @@ export function isRefkey(value: unknown): value is Refkey {
37
61
  );
38
62
  }
39
63
 
40
- function getKey(value: unknown): Refkey {
41
- if (isRefkey(value)) {
42
- return value;
64
+ export function isSymbolRefkey(value: unknown): value is SymbolRefkey {
65
+ return isRefkey(value) && Object.hasOwn(value, "key");
66
+ }
67
+
68
+ export function isMemberRefkey(value: unknown): value is MemberRefkey {
69
+ return (
70
+ isRefkey(value) &&
71
+ Object.hasOwn(value, "base") &&
72
+ Object.hasOwn(value, "member")
73
+ );
74
+ }
75
+
76
+ export function isNamekey(value: unknown): value is Namekey {
77
+ return isRefkey(value) && Object.hasOwn(value, "name");
78
+ }
79
+
80
+ /**
81
+ * This gets the key for a symbol refkey based on the value provided. Refkey values
82
+ * return the key of that refkey, objects get a unique key for that specific object,
83
+ * and otherwise the key is based on the value.
84
+ */
85
+ function getKey(value: unknown): SymbolRefkey["key"] {
86
+ if (isSymbolRefkey(value)) {
87
+ return value.key;
43
88
  } else if (typeof value === "object" && value !== null) {
44
89
  return getObjectKey(value);
45
90
  } else {
46
- return createRefkey(`s${String(value)}`);
91
+ return `s${String(value)}`;
47
92
  }
48
93
  }
49
94
 
@@ -65,16 +110,41 @@ const knownRefkeys = new Map<string, Refkey>();
65
110
  export function refkey(...args: unknown[]): Refkey {
66
111
  const keys = args.length === 0 ? [getKey({})] : args.map((v) => getKey(v));
67
112
 
68
- const compositeKey = keys.map((v) => v.key).join("\u2063");
113
+ const compositeKey = keys.join("\u2063");
69
114
  if (knownRefkeys.has(compositeKey)) {
70
115
  return knownRefkeys.get(compositeKey)!;
71
116
  }
72
117
 
73
- const key = createRefkey(compositeKey);
118
+ const key = createSymbolRefkey(compositeKey);
74
119
  knownRefkeys.set(compositeKey, key);
75
120
  return key;
76
121
  }
77
122
 
123
+ /**
124
+ * Create a namekey with the given name. The namekey is a unique refkey that
125
+ * represents a single symbol with the given name and the provided
126
+ * naming-related options.
127
+ *
128
+ * @example
129
+ * ```tsx
130
+ * const myClass = namekey("MyClass");
131
+ *
132
+ * return <>
133
+ * <ClassDeclaration name={myClass} />
134
+ * {myClass}
135
+ * </>
136
+ * ```
137
+ *
138
+ * Renders a class and a reference to that class.
139
+ */
140
+ export function namekey(name: string, options: NamekeyOptions = {}): Namekey {
141
+ return {
142
+ key: getObjectKey({}),
143
+ name,
144
+ options,
145
+ [RefkeySym]: true,
146
+ };
147
+ }
78
148
  /**
79
149
  * Create a refkey for an instantiation of a symbol.
80
150
  *
@@ -97,6 +167,10 @@ export function refkey(...args: unknown[]): Refkey {
97
167
  * instantiated variable refkey and the refkey of the inner member
98
168
  * `refkey(rk1, rk3)`.
99
169
  */
100
- export function memberRefkey(base: Refkey, member: Refkey): Refkey {
101
- return refkey(base, member);
170
+ export function memberRefkey(base: Refkey, member: Refkey): MemberRefkey {
171
+ return {
172
+ base,
173
+ member,
174
+ [RefkeySym]: true,
175
+ };
102
176
  }
@@ -0,0 +1,23 @@
1
+ import { OutputScope } from "./output-scope.js";
2
+
3
+ /**
4
+ * BasicScope is a kind of OutputScope that has a single declaration space named
5
+ * `symbols`. It is suitable for use in simple language implementations where
6
+ * there isn't much in the way of unique scope semantics.
7
+ */
8
+ export class BasicScope extends OutputScope {
9
+ public static readonly defaultDeclarationSpace = "symbols";
10
+ public static readonly declarationSpaces = ["symbols"] as const;
11
+
12
+ get symbols() {
13
+ return this.spaceFor("symbols")!;
14
+ }
15
+
16
+ get symbolNames() {
17
+ return this.spaceFor("symbols")!.symbolNames;
18
+ }
19
+
20
+ get symbolsByRefkey() {
21
+ return this.spaceFor("symbols")!.symbolsByRefkey;
22
+ }
23
+ }
@@ -0,0 +1,32 @@
1
+ import { OutputSymbol } from "./output-symbol.js";
2
+
3
+ /**
4
+ * BasicSymbol is a kind of OutputSymbol that has instance and static members.
5
+ * It is suitable for use in simple language implementations where there isn't
6
+ * much in the way of unique symbol semantics.
7
+ *
8
+ * @remarks
9
+ *
10
+ * Instantiation is done by copying symbols from instance members to static
11
+ * members of the instantiation target.
12
+ *
13
+ */
14
+ export class BasicSymbol extends OutputSymbol {
15
+ public static readonly memberSpaces = ["static", "instance"];
16
+
17
+ copy() {
18
+ const options = this.getCopyOptions();
19
+ const copiedSymbol = new BasicSymbol(this.name, undefined, options);
20
+ this.initializeCopy(copiedSymbol);
21
+
22
+ return copiedSymbol;
23
+ }
24
+
25
+ get instanceMembers() {
26
+ return this.memberSpaceFor("instance")!;
27
+ }
28
+
29
+ get staticMembers() {
30
+ return this.memberSpaceFor("static")!;
31
+ }
32
+ }
@@ -1,5 +1,7 @@
1
- export * from "./flags.js";
1
+ export * from "./basic-scope.js";
2
+ export * from "./basic-symbol.js";
2
3
  export * from "./output-scope.js";
4
+ export * from "./output-space.js";
3
5
  export * from "./output-symbol.js";
4
6
  export * from "./symbol-flow.js";
5
7
  export * from "./symbol-slot.js";