@alloy-js/core 0.1.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 (229) hide show
  1. package/LICENSE.txt +7 -0
  2. package/api-extractor.json +11 -0
  3. package/babel.config.cjs +4 -0
  4. package/dist/src/binder.d.ts +333 -0
  5. package/dist/src/binder.d.ts.map +1 -0
  6. package/dist/src/binder.js +444 -0
  7. package/dist/src/binder.js.map +1 -0
  8. package/dist/src/code.d.ts +3 -0
  9. package/dist/src/code.d.ts.map +1 -0
  10. package/dist/src/code.js +156 -0
  11. package/dist/src/code.js.map +1 -0
  12. package/dist/src/components/Declaration.d.ts +29 -0
  13. package/dist/src/components/Declaration.d.ts.map +1 -0
  14. package/dist/src/components/Declaration.js +47 -0
  15. package/dist/src/components/Declaration.js.map +1 -0
  16. package/dist/src/components/Indent.d.ts +13 -0
  17. package/dist/src/components/Indent.d.ts.map +1 -0
  18. package/dist/src/components/Indent.js +23 -0
  19. package/dist/src/components/Indent.js.map +1 -0
  20. package/dist/src/components/MemberDeclaration.d.ts +30 -0
  21. package/dist/src/components/MemberDeclaration.d.ts.map +1 -0
  22. package/dist/src/components/MemberDeclaration.js +52 -0
  23. package/dist/src/components/MemberDeclaration.js.map +1 -0
  24. package/dist/src/components/MemberName.d.ts +2 -0
  25. package/dist/src/components/MemberName.d.ts.map +1 -0
  26. package/dist/src/components/MemberName.js +11 -0
  27. package/dist/src/components/MemberName.js.map +1 -0
  28. package/dist/src/components/MemberScope.d.ts +27 -0
  29. package/dist/src/components/MemberScope.d.ts.map +1 -0
  30. package/dist/src/components/MemberScope.js +28 -0
  31. package/dist/src/components/MemberScope.js.map +1 -0
  32. package/dist/src/components/Name.d.ts +2 -0
  33. package/dist/src/components/Name.d.ts.map +1 -0
  34. package/dist/src/components/Name.js +11 -0
  35. package/dist/src/components/Name.js.map +1 -0
  36. package/dist/src/components/Output.d.ts +31 -0
  37. package/dist/src/components/Output.d.ts.map +1 -0
  38. package/dist/src/components/Output.js +44 -0
  39. package/dist/src/components/Output.js.map +1 -0
  40. package/dist/src/components/Scope.d.ts +10 -0
  41. package/dist/src/components/Scope.d.ts.map +1 -0
  42. package/dist/src/components/Scope.js +25 -0
  43. package/dist/src/components/Scope.js.map +1 -0
  44. package/dist/src/components/SourceDirectory.d.ts +7 -0
  45. package/dist/src/components/SourceDirectory.d.ts.map +1 -0
  46. package/dist/src/components/SourceDirectory.js +38 -0
  47. package/dist/src/components/SourceDirectory.js.map +1 -0
  48. package/dist/src/components/SourceFile.d.ts +12 -0
  49. package/dist/src/components/SourceFile.d.ts.map +1 -0
  50. package/dist/src/components/SourceFile.js +26 -0
  51. package/dist/src/components/SourceFile.js.map +1 -0
  52. package/dist/src/components/index.d.ts +11 -0
  53. package/dist/src/components/index.d.ts.map +1 -0
  54. package/dist/src/components/index.js +11 -0
  55. package/dist/src/components/index.js.map +1 -0
  56. package/dist/src/components/stc/index.d.ts +26 -0
  57. package/dist/src/components/stc/index.d.ts.map +1 -0
  58. package/dist/src/components/stc/index.js +9 -0
  59. package/dist/src/components/stc/index.js.map +1 -0
  60. package/dist/src/context/assignment.d.ts +39 -0
  61. package/dist/src/context/assignment.d.ts.map +1 -0
  62. package/dist/src/context/assignment.js +39 -0
  63. package/dist/src/context/assignment.js.map +1 -0
  64. package/dist/src/context/binder.d.ts +9 -0
  65. package/dist/src/context/binder.d.ts.map +1 -0
  66. package/dist/src/context/binder.js +12 -0
  67. package/dist/src/context/binder.js.map +1 -0
  68. package/dist/src/context/declaration.d.ts +4 -0
  69. package/dist/src/context/declaration.d.ts.map +1 -0
  70. package/dist/src/context/declaration.js +3 -0
  71. package/dist/src/context/declaration.js.map +1 -0
  72. package/dist/src/context/indent.d.ts +5 -0
  73. package/dist/src/context/indent.d.ts.map +1 -0
  74. package/dist/src/context/indent.js +8 -0
  75. package/dist/src/context/indent.js.map +1 -0
  76. package/dist/src/context/index.d.ts +11 -0
  77. package/dist/src/context/index.d.ts.map +1 -0
  78. package/dist/src/context/index.js +11 -0
  79. package/dist/src/context/index.js.map +1 -0
  80. package/dist/src/context/member-declaration.d.ts +9 -0
  81. package/dist/src/context/member-declaration.d.ts.map +1 -0
  82. package/dist/src/context/member-declaration.js +9 -0
  83. package/dist/src/context/member-declaration.js.map +1 -0
  84. package/dist/src/context/member-scope.d.ts +13 -0
  85. package/dist/src/context/member-scope.d.ts.map +1 -0
  86. package/dist/src/context/member-scope.js +12 -0
  87. package/dist/src/context/member-scope.js.map +1 -0
  88. package/dist/src/context/name-policy.d.ts +5 -0
  89. package/dist/src/context/name-policy.d.ts.map +1 -0
  90. package/dist/src/context/name-policy.js +10 -0
  91. package/dist/src/context/name-policy.js.map +1 -0
  92. package/dist/src/context/scope.d.ts +5 -0
  93. package/dist/src/context/scope.d.ts.map +1 -0
  94. package/dist/src/context/scope.js +6 -0
  95. package/dist/src/context/scope.js.map +1 -0
  96. package/dist/src/context/source-directory.d.ts +9 -0
  97. package/dist/src/context/source-directory.d.ts.map +1 -0
  98. package/dist/src/context/source-directory.js +3 -0
  99. package/dist/src/context/source-directory.js.map +1 -0
  100. package/dist/src/context/source-file.d.ts +12 -0
  101. package/dist/src/context/source-file.d.ts.map +1 -0
  102. package/dist/src/context/source-file.js +3 -0
  103. package/dist/src/context/source-file.js.map +1 -0
  104. package/dist/src/context.d.ts +13 -0
  105. package/dist/src/context.d.ts.map +1 -0
  106. package/dist/src/context.js +30 -0
  107. package/dist/src/context.js.map +1 -0
  108. package/dist/src/index.d.ts +13 -0
  109. package/dist/src/index.d.ts.map +1 -0
  110. package/dist/src/index.js +13 -0
  111. package/dist/src/index.js.map +1 -0
  112. package/dist/src/jsx-runtime.d.ts +43 -0
  113. package/dist/src/jsx-runtime.d.ts.map +1 -0
  114. package/dist/src/jsx-runtime.js +172 -0
  115. package/dist/src/jsx-runtime.js.map +1 -0
  116. package/dist/src/name-policy.d.ts +5 -0
  117. package/dist/src/name-policy.d.ts.map +1 -0
  118. package/dist/src/name-policy.js +8 -0
  119. package/dist/src/name-policy.js.map +1 -0
  120. package/dist/src/refkey.d.ts +9 -0
  121. package/dist/src/refkey.d.ts.map +1 -0
  122. package/dist/src/refkey.js +44 -0
  123. package/dist/src/refkey.js.map +1 -0
  124. package/dist/src/render.d.ts +147 -0
  125. package/dist/src/render.d.ts.map +1 -0
  126. package/dist/src/render.js +317 -0
  127. package/dist/src/render.js.map +1 -0
  128. package/dist/src/tsdoc-metadata.json +11 -0
  129. package/dist/src/utils.d.ts +80 -0
  130. package/dist/src/utils.d.ts.map +1 -0
  131. package/dist/src/utils.js +219 -0
  132. package/dist/src/utils.js.map +1 -0
  133. package/dist/test/children.test.d.ts +2 -0
  134. package/dist/test/children.test.d.ts.map +1 -0
  135. package/dist/test/components/source-file.test.d.ts +2 -0
  136. package/dist/test/components/source-file.test.d.ts.map +1 -0
  137. package/dist/test/name-policy.test.d.ts +2 -0
  138. package/dist/test/name-policy.test.d.ts.map +1 -0
  139. package/dist/test/reactivity/ref-rendering.test.d.ts +2 -0
  140. package/dist/test/reactivity/ref-rendering.test.d.ts.map +1 -0
  141. package/dist/test/reactivity/test.test.d.ts +2 -0
  142. package/dist/test/reactivity/test.test.d.ts.map +1 -0
  143. package/dist/test/refkey.test.d.ts +2 -0
  144. package/dist/test/refkey.test.d.ts.map +1 -0
  145. package/dist/test/rendering/basic.test.d.ts +2 -0
  146. package/dist/test/rendering/basic.test.d.ts.map +1 -0
  147. package/dist/test/rendering/code.test.d.ts +2 -0
  148. package/dist/test/rendering/code.test.d.ts.map +1 -0
  149. package/dist/test/rendering/indent.test.d.ts +2 -0
  150. package/dist/test/rendering/indent.test.d.ts.map +1 -0
  151. package/dist/test/rendering/linebreaks.test.d.ts +2 -0
  152. package/dist/test/rendering/linebreaks.test.d.ts.map +1 -0
  153. package/dist/test/rendering/refkeys.test.d.ts +2 -0
  154. package/dist/test/rendering/refkeys.test.d.ts.map +1 -0
  155. package/dist/test/stc.test.d.ts +2 -0
  156. package/dist/test/stc.test.d.ts.map +1 -0
  157. package/dist/test/symbols.test.d.ts +2 -0
  158. package/dist/test/symbols.test.d.ts.map +1 -0
  159. package/dist/test/utils.test.d.ts +2 -0
  160. package/dist/test/utils.test.d.ts.map +1 -0
  161. package/dist/testing/extend-expect.d.ts +2 -0
  162. package/dist/testing/extend-expect.d.ts.map +1 -0
  163. package/dist/testing/extend-expect.js +22 -0
  164. package/dist/testing/extend-expect.js.map +1 -0
  165. package/dist/testing/index.d.ts +3 -0
  166. package/dist/testing/index.d.ts.map +1 -0
  167. package/dist/testing/index.js +3 -0
  168. package/dist/testing/index.js.map +1 -0
  169. package/dist/testing/render.d.ts +7 -0
  170. package/dist/testing/render.d.ts.map +1 -0
  171. package/dist/testing/render.js +25 -0
  172. package/dist/testing/render.js.map +1 -0
  173. package/dist/testing/vitest.d.js +1 -0
  174. package/dist/testing/vitest.d.js.map +1 -0
  175. package/dist/tsconfig.tsbuildinfo +1 -0
  176. package/package.json +64 -0
  177. package/src/binder.ts +838 -0
  178. package/src/code.ts +220 -0
  179. package/src/components/Declaration.tsx +53 -0
  180. package/src/components/Indent.tsx +33 -0
  181. package/src/components/MemberDeclaration.tsx +62 -0
  182. package/src/components/MemberName.tsx +11 -0
  183. package/src/components/MemberScope.tsx +40 -0
  184. package/src/components/Name.tsx +11 -0
  185. package/src/components/Output.tsx +69 -0
  186. package/src/components/Scope.tsx +27 -0
  187. package/src/components/SourceDirectory.tsx +43 -0
  188. package/src/components/SourceFile.tsx +33 -0
  189. package/src/components/index.tsx +10 -0
  190. package/src/components/stc/index.ts +9 -0
  191. package/src/context/assignment.ts +57 -0
  192. package/src/context/binder.ts +14 -0
  193. package/src/context/declaration.ts +5 -0
  194. package/src/context/indent.ts +10 -0
  195. package/src/context/index.ts +10 -0
  196. package/src/context/member-declaration.ts +10 -0
  197. package/src/context/member-scope.ts +17 -0
  198. package/src/context/name-policy.ts +13 -0
  199. package/src/context/scope.ts +8 -0
  200. package/src/context/source-directory.ts +11 -0
  201. package/src/context/source-file.ts +12 -0
  202. package/src/context.ts +53 -0
  203. package/src/index.ts +21 -0
  204. package/src/jsx-runtime.ts +266 -0
  205. package/src/name-policy.ts +13 -0
  206. package/src/refkey.ts +62 -0
  207. package/src/render.ts +389 -0
  208. package/src/utils.ts +288 -0
  209. package/temp/api.json +8840 -0
  210. package/test/children.test.tsx +33 -0
  211. package/test/components/source-file.test.tsx +45 -0
  212. package/test/name-policy.test.tsx +19 -0
  213. package/test/reactivity/ref-rendering.test.tsx +50 -0
  214. package/test/reactivity/test.test.tsx +83 -0
  215. package/test/refkey.test.ts +32 -0
  216. package/test/rendering/basic.test.tsx +156 -0
  217. package/test/rendering/code.test.tsx +62 -0
  218. package/test/rendering/indent.test.tsx +608 -0
  219. package/test/rendering/linebreaks.test.tsx +72 -0
  220. package/test/rendering/refkeys.test.tsx +35 -0
  221. package/test/stc.test.tsx +21 -0
  222. package/test/symbols.test.ts +406 -0
  223. package/test/utils.test.tsx +150 -0
  224. package/testing/extend-expect.ts +20 -0
  225. package/testing/index.ts +2 -0
  226. package/testing/render.ts +37 -0
  227. package/testing/vitest.d.ts +10 -0
  228. package/tsconfig.json +17 -0
  229. package/vitest.config.ts +18 -0
@@ -0,0 +1,14 @@
1
+ import { Binder } from "../binder.js";
2
+ import { ComponentContext, createContext, useContext } from "../context.js";
3
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
4
+ import type { Output } from "../components/Output.js";
5
+
6
+ /**
7
+ * The binder context provides the binder instance to all components. This
8
+ * context is provided by the {@link Output | output component}.
9
+ */
10
+ export const BinderContext: ComponentContext<Binder> = createContext();
11
+
12
+ export function useBinder() {
13
+ return useContext(BinderContext)!;
14
+ }
@@ -0,0 +1,5 @@
1
+ import { OutputSymbol } from "../binder.js";
2
+ import { ComponentContext, createContext } from "../context.js";
3
+
4
+ export const DeclarationContext: ComponentContext<OutputSymbol> =
5
+ createContext();
@@ -0,0 +1,10 @@
1
+ import { IndentState } from "../components/Indent.jsx";
2
+ import { ComponentContext, createContext } from "../context.js";
3
+
4
+ export const IndentContext: ComponentContext<IndentState> = createContext({
5
+ level: 0,
6
+ indent: " ",
7
+ indentString: "",
8
+ });
9
+
10
+ export const TestContext: ComponentContext<string> = createContext("test");
@@ -0,0 +1,10 @@
1
+ export * from "./assignment.js";
2
+ export * from "./binder.js";
3
+ export * from "./declaration.js";
4
+ export * from "./indent.js";
5
+ export * from "./member-declaration.js";
6
+ export * from "./member-scope.js";
7
+ export * from "./name-policy.js";
8
+ export * from "./scope.js";
9
+ export * from "./source-directory.js";
10
+ export * from "./source-file.js";
@@ -0,0 +1,10 @@
1
+ import { OutputSymbol } from "../binder.js";
2
+ import { ComponentContext, createContext } from "../context.js";
3
+
4
+ /**
5
+ * Provides the symbol for the member currently being declared.
6
+ *
7
+ * @see {@link DeclarationContext} for getting the symbol for the current non-member declaration.
8
+ */
9
+ export const MemberDeclarationContext: ComponentContext<OutputSymbol> =
10
+ createContext();
@@ -0,0 +1,17 @@
1
+ import { OutputScope } from "../binder.js";
2
+ import { ComponentContext, createContext, useContext } from "../context.js";
3
+
4
+ /**
5
+ * The member scope context provides the instance and static member scopes that
6
+ * are used for member declarations and instance member resolution.
7
+ */
8
+ export interface MemberScopeContext {
9
+ staticMembers?: OutputScope;
10
+ instanceMembers?: OutputScope;
11
+ }
12
+ export const MemberScopeContext: ComponentContext<MemberScopeContext> =
13
+ createContext();
14
+
15
+ export function useMemberScope() {
16
+ return useContext(MemberScopeContext)!;
17
+ }
@@ -0,0 +1,13 @@
1
+ import { ComponentContext, createContext, useContext } from "../context.js";
2
+ import { NamePolicy } from "../name-policy.js";
3
+
4
+ export const NamePolicyContext: ComponentContext<NamePolicy<string>> =
5
+ createContext<NamePolicy<string>>({
6
+ getName(name) {
7
+ return name;
8
+ },
9
+ });
10
+
11
+ export function useNamePolicy() {
12
+ return useContext(NamePolicyContext)!;
13
+ }
@@ -0,0 +1,8 @@
1
+ import { OutputScope } from "../binder.js";
2
+ import { ComponentContext, createContext, useContext } from "../context.js";
3
+
4
+ export const ScopeContext: ComponentContext<OutputScope> = createContext();
5
+
6
+ export function useScope() {
7
+ return useContext(ScopeContext)!;
8
+ }
@@ -0,0 +1,11 @@
1
+ import { ComponentContext, createContext } from "../context.js";
2
+ import { SourceFileContext } from "./source-file.js";
3
+
4
+ export interface SourceDirectoryContext {
5
+ contents: (SourceDirectoryContext | SourceFileContext)[];
6
+ addContent(content: SourceDirectoryContext | SourceFileContext): void;
7
+ path: string;
8
+ }
9
+
10
+ export const SourceDirectoryContext: ComponentContext<SourceDirectoryContext> =
11
+ createContext();
@@ -0,0 +1,12 @@
1
+ import { ComponentContext, createContext } from "../context.js";
2
+ import { ComponentDefinition } from "../jsx-runtime.js";
3
+ import { Refkey } from "../refkey.js";
4
+
5
+ export interface SourceFileContext {
6
+ path: string;
7
+ filetype: string;
8
+ reference?: ComponentDefinition<{ refkey: Refkey }>;
9
+ }
10
+
11
+ export const SourceFileContext: ComponentContext<SourceFileContext> =
12
+ createContext();
package/src/context.ts ADDED
@@ -0,0 +1,53 @@
1
+ import {
2
+ Children,
3
+ ComponentDefinition,
4
+ effect,
5
+ getContext,
6
+ untrack,
7
+ } from "@alloy-js/core/jsx-runtime";
8
+ import { shallowRef } from "@vue/reactivity";
9
+
10
+ export interface ComponentContext<T> {
11
+ id: symbol;
12
+ default: T | undefined;
13
+ Provider: ComponentDefinition<ContextProviderProps<T>>;
14
+ }
15
+
16
+ export interface ContextProviderProps<T = unknown> {
17
+ value?: T;
18
+ children?: Children;
19
+ }
20
+
21
+ export function useContext<T>(context: ComponentContext<T>): T | undefined {
22
+ // context must come from a parent
23
+ let current = getContext();
24
+ while (current) {
25
+ if (Object.hasOwn(current.context!, context.id)) {
26
+ return current.context![context.id] as T | undefined;
27
+ }
28
+ current = current.owner;
29
+ }
30
+
31
+ return context.default;
32
+ }
33
+
34
+ export function createContext<T = unknown>(
35
+ defaultValue?: T,
36
+ ): ComponentContext<T> {
37
+ const id = Symbol("context");
38
+ return {
39
+ id,
40
+ default: defaultValue,
41
+ Provider(props: ContextProviderProps<T>) {
42
+ const context = getContext();
43
+
44
+ const rendered = shallowRef();
45
+ effect(() => {
46
+ context!.context![id] = props.value;
47
+ rendered.value = untrack(() => props.children);
48
+ });
49
+
50
+ return rendered.value;
51
+ },
52
+ };
53
+ }
package/src/index.ts ADDED
@@ -0,0 +1,21 @@
1
+ export * from "@alloy-js/core/jsx-runtime";
2
+ export {
3
+ computed,
4
+ isProxy,
5
+ reactive,
6
+ ref,
7
+ shallowReactive,
8
+ shallowRef,
9
+ toRaw,
10
+ type Ref,
11
+ } from "@vue/reactivity";
12
+ export * from "./binder.js";
13
+ export * from "./code.js";
14
+ export * from "./components/index.js";
15
+ export * from "./context.js";
16
+ export * from "./context/index.js";
17
+ export * from "./jsx-runtime.js";
18
+ export * from "./name-policy.js";
19
+ export * from "./refkey.js";
20
+ export * from "./render.js";
21
+ export * from "./utils.js";
@@ -0,0 +1,266 @@
1
+ // Much of the implementations in this file are inspired by vuerx-js
2
+ // See: https://github.com/ryansolid/vuerx-jsx.
3
+ import {
4
+ pauseTracking,
5
+ Ref,
6
+ resetTracking,
7
+ shallowRef,
8
+ stop,
9
+ effect as vueEffect,
10
+ } from "@vue/reactivity";
11
+ import { Refkey } from "./refkey.js";
12
+
13
+ if ((globalThis as any).ALLOY) {
14
+ throw new Error(
15
+ "Multiple versions of the JSX Runtime have been loaded. This will likely cause undesirable behavior.",
16
+ );
17
+ }
18
+ (globalThis as any).ALLOY = true;
19
+
20
+ export interface Disposable {
21
+ (): void;
22
+ }
23
+
24
+ export interface Context {
25
+ disposables: Disposable[];
26
+ owner: Context | null;
27
+
28
+ // context providers
29
+ context?: Record<symbol, unknown>;
30
+
31
+ // store random info about the node
32
+ meta?: Record<string, any>;
33
+ }
34
+
35
+ let globalContext: Context | null = null;
36
+ export function getContext() {
37
+ return globalContext;
38
+ }
39
+
40
+ export function root<T>(fn: (d: Disposable) => T, src?: string): T {
41
+ globalContext = {
42
+ src,
43
+ disposables: [],
44
+ owner: globalContext,
45
+ context: {},
46
+ } as any;
47
+ let ret;
48
+ try {
49
+ ret = untrack(() =>
50
+ fn(() => {
51
+ for (const d of globalContext!.disposables) {
52
+ d();
53
+ }
54
+ }),
55
+ );
56
+ } finally {
57
+ globalContext = globalContext!.owner;
58
+ }
59
+
60
+ return ret;
61
+ }
62
+
63
+ export function untrack<T>(fn: () => T): T {
64
+ pauseTracking();
65
+ const v = fn();
66
+ resetTracking();
67
+ return v;
68
+ }
69
+
70
+ export function memo<T>(fn: () => T, equal?: boolean): () => T {
71
+ const o = shallowRef();
72
+ effect((prev) => {
73
+ const res = fn();
74
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
75
+ (!equal || prev !== res) && (o.value = res);
76
+ return res;
77
+ });
78
+ return () => o.value;
79
+ }
80
+
81
+ export function effect<T>(fn: (prev?: T) => T, current?: T) {
82
+ const context = {
83
+ src: "effect",
84
+ context: {},
85
+ disposables: [] as (() => void)[],
86
+ owner: globalContext,
87
+ } as any;
88
+
89
+ const cleanupFn = (final: boolean) => {
90
+ const d = context.disposables;
91
+ context.disposables = [];
92
+ for (let k = 0, len = d.length; k < len; k++) d[k]();
93
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
94
+ final && stop(c);
95
+ };
96
+
97
+ const c = vueEffect(() => {
98
+ cleanupFn(false);
99
+ const oldContext = globalContext;
100
+ globalContext = context;
101
+ try {
102
+ current = fn(current);
103
+ } finally {
104
+ globalContext = oldContext;
105
+ }
106
+ });
107
+
108
+ cleanup(() => cleanupFn(true));
109
+ }
110
+
111
+ function cleanup(fn: Disposable) {
112
+ if (globalContext != null) {
113
+ globalContext.disposables.push(fn);
114
+ }
115
+ }
116
+
117
+ export type Child =
118
+ | string
119
+ | boolean
120
+ | number
121
+ | undefined
122
+ | null
123
+ | (() => Child | Children)
124
+ | Child[]
125
+ | Ref
126
+ | Refkey;
127
+
128
+ export type Children = Child | Child[];
129
+ export type Props = Record<string, unknown>;
130
+
131
+ export interface ComponentDefinition<TProps = Props> {
132
+ (props: TProps): Child | Children;
133
+ }
134
+ export interface Component<TProps = Props> {
135
+ (props: TProps): Child | Children;
136
+ tag?: symbol;
137
+ }
138
+ export interface ComponentCreator<TProps = Props> {
139
+ component: Component<TProps>;
140
+ (): Child | Children;
141
+ props: Props;
142
+ tag?: symbol;
143
+ }
144
+
145
+ // debugging utilities
146
+ const renderStack: {
147
+ component: Component<any>;
148
+ props: Props;
149
+ }[] = [];
150
+
151
+ export const shouldDebug = !!process.env.ALLOY_DEBUG;
152
+
153
+ export function pushStack(component: Component<any>, props: Props) {
154
+ if (!shouldDebug) return;
155
+ renderStack.push({ component, props });
156
+ }
157
+
158
+ export function popStack() {
159
+ if (!shouldDebug) return;
160
+ renderStack.pop();
161
+ }
162
+
163
+ export function printRenderStack() {
164
+ if (!shouldDebug) return;
165
+
166
+ // eslint-disable-next-line no-console
167
+ console.error("Error rendering:");
168
+ for (let i = renderStack.length - 1; i >= 0; i--) {
169
+ const { component, props } = renderStack[i];
170
+ // eslint-disable-next-line no-console
171
+ console.error(` at ${component.name}(${inspectProps(props)})`);
172
+ }
173
+ }
174
+
175
+ function inspectProps(props: Props) {
176
+ return JSON.stringify(
177
+ Object.fromEntries(
178
+ Object.entries(props).map(([key, value]) => {
179
+ let safeValue;
180
+ switch (typeof value) {
181
+ case "string":
182
+ case "number":
183
+ case "boolean":
184
+ safeValue = value;
185
+ break;
186
+ case "undefined":
187
+ safeValue = "undefined";
188
+ break;
189
+ case "object":
190
+ safeValue = value ? "{...}" : null;
191
+ break;
192
+ case "function":
193
+ safeValue = "function";
194
+ break;
195
+ }
196
+ return [key, safeValue];
197
+ }),
198
+ ),
199
+ );
200
+ }
201
+
202
+ // These can be removed with a smarter transform that encodes the information we
203
+ // need in the compiled JSX output.
204
+ export function isComponentCreator(item: unknown): item is ComponentCreator {
205
+ return typeof item === "function" && (item as any).component;
206
+ }
207
+
208
+ export function createComponent<TProps extends Props = Props>(
209
+ C: Component<TProps>,
210
+ props: TProps,
211
+ ): ComponentCreator<TProps> {
212
+ const creator: ComponentCreator<TProps> = () => /* */ C(props);
213
+ creator.props = props;
214
+ creator.component = C;
215
+ if (C.tag) {
216
+ creator.tag = C.tag;
217
+ }
218
+
219
+ return creator;
220
+ }
221
+
222
+ export function taggedComponent<TProps = Props>(
223
+ tag: symbol,
224
+ component: Component<TProps>,
225
+ ): Component<TProps> {
226
+ component.tag = tag;
227
+ return component;
228
+ }
229
+
230
+ export function mergeProps<T, U>(source: T, source1: U): T & U;
231
+ export function mergeProps<T, U, V>(
232
+ source: T,
233
+ source1: U,
234
+ source2: V,
235
+ ): T & U & V;
236
+ export function mergeProps<T, U, V, W>(
237
+ source: T,
238
+ source1: U,
239
+ source2: V,
240
+ source3: W,
241
+ ): T & U & V & W;
242
+ export function mergeProps(...sources: any): any {
243
+ const target = {};
244
+ for (let i = 0; i < sources.length; i++) {
245
+ let source = sources[i];
246
+ if (typeof source === "function") source = source();
247
+ if (source) {
248
+ const descriptors = Object.getOwnPropertyDescriptors(source);
249
+ for (const key in descriptors) {
250
+ if (key in target) continue;
251
+ Object.defineProperty(target, key, {
252
+ enumerable: true,
253
+ get() {
254
+ for (let i = sources.length - 1; i >= 0; i--) {
255
+ let s = sources[i];
256
+ if (typeof s === "function") s = s();
257
+ const v = (s || {})[key];
258
+ if (v !== undefined) return v;
259
+ }
260
+ },
261
+ });
262
+ }
263
+ }
264
+ }
265
+ return target;
266
+ }
@@ -0,0 +1,13 @@
1
+ export interface NamePolicy<TElements extends string> {
2
+ getName(originalName: string, element: TElements): string;
3
+ }
4
+
5
+ export function createNamePolicy<T extends string>(
6
+ namer: (name: string, elements: T) => string,
7
+ ): NamePolicy<T> {
8
+ return {
9
+ getName(name, element) {
10
+ return namer(name, element);
11
+ },
12
+ };
13
+ }
package/src/refkey.ts ADDED
@@ -0,0 +1,62 @@
1
+ import { markRaw } from "@vue/reactivity";
2
+
3
+ const objectIds = new WeakMap<WeakKey, Refkey>();
4
+ let objId = 0;
5
+
6
+ function getObjectKey(value: WeakKey) {
7
+ if (objectIds.has(value)) {
8
+ return objectIds.get(value)!;
9
+ }
10
+
11
+ const key = createRefkey(`o${objId++}`);
12
+ objectIds.set(value, key);
13
+
14
+ return key;
15
+ }
16
+
17
+ const RefkeySym: unique symbol = Symbol();
18
+
19
+ export type Refkey = { key: string; [RefkeySym]: true };
20
+
21
+ function createRefkey(key: string): Refkey {
22
+ const refkey: Refkey = {
23
+ key,
24
+ [RefkeySym]: true,
25
+ };
26
+
27
+ markRaw(refkey);
28
+
29
+ return refkey;
30
+ }
31
+
32
+ export function isRefkey(value: unknown): value is Refkey {
33
+ return (
34
+ typeof value === "object" &&
35
+ value !== null &&
36
+ Object.hasOwn(value, RefkeySym)
37
+ );
38
+ }
39
+
40
+ function getKey(value: unknown): Refkey {
41
+ if (isRefkey(value)) {
42
+ return value;
43
+ } else if (typeof value === "object" && value !== null) {
44
+ return getObjectKey(value);
45
+ } else {
46
+ return createRefkey(`s${String(value)}`);
47
+ }
48
+ }
49
+
50
+ const knownRefkeys = new Map<string, Refkey>();
51
+ export function refkey(...args: unknown[]): Refkey {
52
+ const keys = args.length === 0 ? [getKey({})] : args.map((v) => getKey(v));
53
+
54
+ const compositeKey = keys.map((v) => v.key).join("\u2063");
55
+ if (knownRefkeys.has(compositeKey)) {
56
+ return knownRefkeys.get(compositeKey)!;
57
+ }
58
+
59
+ const key = createRefkey(compositeKey);
60
+ knownRefkeys.set(compositeKey, key);
61
+ return key;
62
+ }