@alloy-js/core 0.5.0 → 0.7.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 (212) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/babel.config.cjs +4 -1
  3. package/dist/src/binder.d.ts +8 -2
  4. package/dist/src/binder.d.ts.map +1 -1
  5. package/dist/src/binder.js +41 -15
  6. package/dist/src/binder.js.map +1 -1
  7. package/dist/src/code.d.ts +2 -2
  8. package/dist/src/code.d.ts.map +1 -1
  9. package/dist/src/code.js +4 -4
  10. package/dist/src/code.js.map +1 -1
  11. package/dist/src/components/Block.d.ts +25 -0
  12. package/dist/src/components/Block.d.ts.map +1 -0
  13. package/dist/src/components/Block.js +25 -0
  14. package/dist/src/components/Block.js.map +1 -0
  15. package/dist/src/components/Declaration.d.ts.map +1 -1
  16. package/dist/src/components/Declaration.js +4 -0
  17. package/dist/src/components/Declaration.js.map +1 -1
  18. package/dist/src/components/For.d.ts +44 -0
  19. package/dist/src/components/For.d.ts.map +1 -0
  20. package/dist/src/components/For.js +41 -0
  21. package/dist/src/components/For.js.map +1 -0
  22. package/dist/src/components/Indent.d.ts +5 -9
  23. package/dist/src/components/Indent.d.ts.map +1 -1
  24. package/dist/src/components/Indent.js +7 -18
  25. package/dist/src/components/Indent.js.map +1 -1
  26. package/dist/src/components/List.d.ts +38 -0
  27. package/dist/src/components/List.d.ts.map +1 -0
  28. package/dist/src/components/List.js +40 -0
  29. package/dist/src/components/List.js.map +1 -0
  30. package/dist/src/components/MemberDeclaration.d.ts.map +1 -1
  31. package/dist/src/components/MemberDeclaration.js.map +1 -1
  32. package/dist/src/components/MemberName.js +1 -1
  33. package/dist/src/components/MemberName.js.map +1 -1
  34. package/dist/src/components/MemberScope.d.ts.map +1 -1
  35. package/dist/src/components/MemberScope.js.map +1 -1
  36. package/dist/src/components/Name.js +1 -1
  37. package/dist/src/components/Name.js.map +1 -1
  38. package/dist/src/components/Output.d.ts +2 -1
  39. package/dist/src/components/Output.d.ts.map +1 -1
  40. package/dist/src/components/Output.js +9 -1
  41. package/dist/src/components/Output.js.map +1 -1
  42. package/dist/src/components/Scope.d.ts.map +1 -1
  43. package/dist/src/components/Scope.js.map +1 -1
  44. package/dist/src/components/Show.d.ts +8 -0
  45. package/dist/src/components/Show.d.ts.map +1 -0
  46. package/dist/src/components/Show.js +4 -0
  47. package/dist/src/components/Show.js.map +1 -0
  48. package/dist/src/components/SourceDirectory.d.ts.map +1 -1
  49. package/dist/src/components/SourceDirectory.js +1 -0
  50. package/dist/src/components/SourceDirectory.js.map +1 -1
  51. package/dist/src/components/SourceFile.d.ts +2 -6
  52. package/dist/src/components/SourceFile.d.ts.map +1 -1
  53. package/dist/src/components/SourceFile.js +6 -13
  54. package/dist/src/components/SourceFile.js.map +1 -1
  55. package/dist/src/components/StatementList.d.ts +9 -0
  56. package/dist/src/components/StatementList.d.ts.map +1 -0
  57. package/dist/src/components/StatementList.js +17 -0
  58. package/dist/src/components/StatementList.js.map +1 -0
  59. package/dist/src/components/Switch.d.ts +41 -0
  60. package/dist/src/components/Switch.d.ts.map +1 -0
  61. package/dist/src/components/Switch.js +41 -0
  62. package/dist/src/components/Switch.js.map +1 -0
  63. package/dist/src/components/Wrap.d.ts +20 -0
  64. package/dist/src/components/Wrap.d.ts.map +1 -0
  65. package/dist/src/components/Wrap.js +15 -0
  66. package/dist/src/components/Wrap.js.map +1 -0
  67. package/dist/src/components/index.d.ts +8 -1
  68. package/dist/src/components/index.d.ts.map +1 -1
  69. package/dist/src/components/index.js +7 -0
  70. package/dist/src/components/index.js.map +1 -1
  71. package/dist/src/components/stc/index.d.ts +77 -6
  72. package/dist/src/components/stc/index.d.ts.map +1 -1
  73. package/dist/src/components/stc/index.js +17 -1
  74. package/dist/src/components/stc/index.js.map +1 -1
  75. package/dist/src/context/index.d.ts +0 -1
  76. package/dist/src/context/index.d.ts.map +1 -1
  77. package/dist/src/context/index.js +0 -1
  78. package/dist/src/context/index.js.map +1 -1
  79. package/dist/src/context.d.ts.map +1 -1
  80. package/dist/src/context.js +3 -3
  81. package/dist/src/context.js.map +1 -1
  82. package/dist/src/index.browser.d.ts +3 -0
  83. package/dist/src/index.browser.d.ts.map +1 -0
  84. package/dist/src/index.browser.js +3 -0
  85. package/dist/src/index.browser.js.map +1 -0
  86. package/dist/src/index.d.ts +1 -0
  87. package/dist/src/index.d.ts.map +1 -1
  88. package/dist/src/index.js +1 -0
  89. package/dist/src/index.js.map +1 -1
  90. package/dist/src/jsx-runtime.d.ts +139 -8
  91. package/dist/src/jsx-runtime.d.ts.map +1 -1
  92. package/dist/src/jsx-runtime.js +102 -12
  93. package/dist/src/jsx-runtime.js.map +1 -1
  94. package/dist/src/render.d.ts +107 -132
  95. package/dist/src/render.d.ts.map +1 -1
  96. package/dist/src/render.js +281 -177
  97. package/dist/src/render.js.map +1 -1
  98. package/dist/src/stc.d.ts +14 -0
  99. package/dist/src/stc.d.ts.map +1 -0
  100. package/dist/src/stc.js +52 -0
  101. package/dist/src/stc.js.map +1 -0
  102. package/dist/src/utils.d.ts +22 -15
  103. package/dist/src/utils.d.ts.map +1 -1
  104. package/dist/src/utils.js +95 -59
  105. package/dist/src/utils.js.map +1 -1
  106. package/dist/src/write-output.js +3 -3
  107. package/dist/src/write-output.js.map +1 -1
  108. package/dist/test/browser-build.test.d.ts +2 -0
  109. package/dist/test/browser-build.test.d.ts.map +1 -0
  110. package/dist/test/components/block.test.d.ts +2 -0
  111. package/dist/test/components/block.test.d.ts.map +1 -0
  112. package/dist/test/components/declaration.test.d.ts +2 -0
  113. package/dist/test/components/declaration.test.d.ts.map +1 -0
  114. package/dist/test/components/list.test.d.ts +2 -0
  115. package/dist/test/components/list.test.d.ts.map +1 -0
  116. package/dist/test/components/wrap.test.d.ts +2 -0
  117. package/dist/test/components/wrap.test.d.ts.map +1 -0
  118. package/dist/test/control-flow/for.test.d.ts +2 -0
  119. package/dist/test/control-flow/for.test.d.ts.map +1 -0
  120. package/dist/test/control-flow/match.test.d.ts +2 -0
  121. package/dist/test/control-flow/match.test.d.ts.map +1 -0
  122. package/dist/test/control-flow/show.test.d.ts +2 -0
  123. package/dist/test/control-flow/show.test.d.ts.map +1 -0
  124. package/dist/test/reactivity/cleanup.test.d.ts +2 -0
  125. package/dist/test/reactivity/cleanup.test.d.ts.map +1 -0
  126. package/dist/test/reactivity/memo.test.d.ts +2 -0
  127. package/dist/test/reactivity/memo.test.d.ts.map +1 -0
  128. package/dist/test/reactivity/untrack.test.d.ts +2 -0
  129. package/dist/test/reactivity/untrack.test.d.ts.map +1 -0
  130. package/dist/test/rendering/formatting.test.d.ts +2 -0
  131. package/dist/test/rendering/formatting.test.d.ts.map +1 -0
  132. package/dist/test/rendering/memoization.test.d.ts +2 -0
  133. package/dist/test/rendering/memoization.test.d.ts.map +1 -0
  134. package/dist/test/split-props.test.d.ts +2 -0
  135. package/dist/test/split-props.test.d.ts.map +1 -0
  136. package/dist/test/stc.test.d.ts.map +1 -1
  137. package/dist/test/utils.test.d.ts.map +1 -1
  138. package/dist/testing/extend-expect.js +4 -4
  139. package/dist/testing/extend-expect.js.map +1 -1
  140. package/dist/testing/render.d.ts +2 -3
  141. package/dist/testing/render.d.ts.map +1 -1
  142. package/dist/testing/render.js +2 -4
  143. package/dist/testing/render.js.map +1 -1
  144. package/dist/tsconfig.tsbuildinfo +1 -1
  145. package/package.json +6 -8
  146. package/src/binder.ts +54 -18
  147. package/src/code.ts +17 -12
  148. package/src/components/Block.tsx +44 -0
  149. package/src/components/Declaration.tsx +10 -4
  150. package/src/components/For.tsx +81 -0
  151. package/src/components/Indent.tsx +20 -27
  152. package/src/components/List.tsx +94 -0
  153. package/src/components/MemberDeclaration.tsx +9 -6
  154. package/src/components/MemberScope.tsx +4 -2
  155. package/src/components/Output.tsx +25 -13
  156. package/src/components/Scope.tsx +4 -2
  157. package/src/components/Show.tsx +11 -0
  158. package/src/components/SourceDirectory.tsx +5 -1
  159. package/src/components/SourceFile.tsx +12 -16
  160. package/src/components/StatementList.tsx +16 -0
  161. package/src/components/Switch.tsx +62 -0
  162. package/src/components/Wrap.tsx +29 -0
  163. package/src/components/index.tsx +8 -1
  164. package/src/components/stc/index.ts +18 -1
  165. package/src/context/index.ts +0 -1
  166. package/src/context.ts +2 -3
  167. package/src/index.browser.ts +2 -0
  168. package/src/index.ts +1 -0
  169. package/src/jsx-runtime.ts +245 -23
  170. package/src/render.ts +392 -198
  171. package/src/stc.ts +95 -0
  172. package/src/utils.ts +162 -95
  173. package/src/write-output.ts +3 -3
  174. package/temp/api.json +8407 -3301
  175. package/test/browser-build.test.ts +91 -0
  176. package/test/children.test.tsx +8 -10
  177. package/test/components/block.test.tsx +48 -0
  178. package/test/components/declaration.test.tsx +37 -0
  179. package/test/components/list.test.tsx +91 -0
  180. package/test/components/slot.test.tsx +31 -25
  181. package/test/components/source-file.test.tsx +11 -31
  182. package/test/components/wrap.test.tsx +42 -0
  183. package/test/control-flow/for.test.tsx +194 -0
  184. package/test/control-flow/match.test.tsx +49 -0
  185. package/test/control-flow/show.test.tsx +25 -0
  186. package/test/name-policy.test.tsx +5 -5
  187. package/test/reactivity/cleanup.test.tsx +91 -0
  188. package/test/reactivity/memo.test.tsx +17 -0
  189. package/test/reactivity/ref-rendering.test.tsx +3 -8
  190. package/test/reactivity/test.test.tsx +7 -6
  191. package/test/reactivity/untrack.test.ts +33 -0
  192. package/test/rendering/basic.test.tsx +25 -47
  193. package/test/rendering/code.test.tsx +3 -3
  194. package/test/rendering/formatting.test.tsx +487 -0
  195. package/test/rendering/indent.test.tsx +42 -529
  196. package/test/rendering/memoization.test.tsx +30 -0
  197. package/test/split-props.test.ts +87 -0
  198. package/test/stc.test.tsx +29 -8
  199. package/test/symbols.test.ts +87 -8
  200. package/test/utils.test.tsx +129 -20
  201. package/testing/extend-expect.ts +14 -4
  202. package/testing/render.ts +2 -4
  203. package/testing/vitest.d.ts +6 -1
  204. package/vitest.config.ts +1 -1
  205. package/dist/src/context/indent.d.ts +0 -5
  206. package/dist/src/context/indent.d.ts.map +0 -1
  207. package/dist/src/context/indent.js +0 -8
  208. package/dist/src/context/indent.js.map +0 -1
  209. package/dist/test/rendering/linebreaks.test.d.ts +0 -2
  210. package/dist/test/rendering/linebreaks.test.d.ts.map +0 -1
  211. package/src/context/indent.ts +0 -17
  212. package/test/rendering/linebreaks.test.tsx +0 -72
package/test/stc.test.tsx CHANGED
@@ -1,5 +1,6 @@
1
- import { code, Indent, stc } from "@alloy-js/core";
2
- import { expect, it } from "vitest";
1
+ import { stc } from "@alloy-js/core";
2
+ import { hbr, indent, Indent } from "@alloy-js/core/stc";
3
+ import { describe, expect, it } from "vitest";
3
4
  import "../testing/extend-expect.js";
4
5
 
5
6
  it("is applied by output", () => {
@@ -7,15 +8,35 @@ it("is applied by output", () => {
7
8
  return "Foo component";
8
9
  }
9
10
  const FooStc = stc(Foo);
10
- const IndentStc = stc(Indent);
11
11
 
12
- expect(code`
13
- ${FooStc({ x: "hi" })}
14
- ${IndentStc().code`
12
+ expect([
13
+ FooStc(),
14
+ Indent().code`
15
15
  child!
16
- `}
17
- `).toRenderTo(`
16
+ child2!
17
+ `,
18
+ ]).toRenderTo(`
18
19
  Foo component
19
20
  child!
21
+ child2!
20
22
  `);
21
23
  });
24
+
25
+ describe("works with formatting", () => {
26
+ it("handles lines", () => {
27
+ expect(["foo", hbr(), "bar", hbr(), "baz"]).toRenderTo(`
28
+ foo
29
+ bar
30
+ baz
31
+ `);
32
+ });
33
+
34
+ it("handles indents", () => {
35
+ expect(["foo", indent().children([hbr(), "bar", hbr(), "baz"])])
36
+ .toRenderTo(`
37
+ foo
38
+ bar
39
+ baz
40
+ `);
41
+ });
42
+ });
@@ -158,7 +158,7 @@ describe("static members", () => {
158
158
  const resolution = binder.resolveDeclarationByKey(
159
159
  root,
160
160
  undefined,
161
- staticSym.refkey,
161
+ staticSym.refkeys[0],
162
162
  );
163
163
  expect(resolution.value).toBeDefined();
164
164
  const { commonScope, pathUp, pathDown, targetDeclaration, memberPath } =
@@ -202,7 +202,7 @@ describe("static members", () => {
202
202
  const resolution = binder.resolveDeclarationByKey(
203
203
  root,
204
204
  undefined,
205
- nested_static.refkey,
205
+ nested_static.refkeys[0],
206
206
  );
207
207
  expect(resolution.value).toBeDefined();
208
208
  const { commonScope, pathUp, pathDown, targetDeclaration, memberPath } =
@@ -284,7 +284,7 @@ describe("instance members", () => {
284
284
  const resolution = binder.resolveDeclarationByKey(
285
285
  undefined,
286
286
  rootSym.instanceMemberScope!,
287
- instance.refkey,
287
+ instance.refkeys[0],
288
288
  );
289
289
  expect(resolution.value).toBeDefined();
290
290
  const { commonScope, pathUp, pathDown, targetDeclaration, memberPath } =
@@ -318,7 +318,7 @@ describe("instance members", () => {
318
318
  });
319
319
 
320
320
  expect(() =>
321
- binder.resolveDeclarationByKey(root, undefined, instance.refkey),
321
+ binder.resolveDeclarationByKey(root, undefined, instance.refkeys[0]),
322
322
  ).toThrow(/Cannot resolve member symbols/);
323
323
  });
324
324
  });
@@ -349,7 +349,10 @@ describe("instantiating members", () => {
349
349
  instantiation.flags & OutputSymbolFlags.InstanceMemberContainer,
350
350
  ).toBeTruthy();
351
351
  expect(instantiation.instanceMemberScope).toBeDefined();
352
- const expectedRefkey = refkey(instantiation.refkey, instance.refkey);
352
+ const expectedRefkey = refkey(
353
+ instantiation.refkeys[0],
354
+ instance.refkeys[0],
355
+ );
353
356
  expect(
354
357
  instantiation.instanceMemberScope!.symbolsByRefkey.get(expectedRefkey),
355
358
  ).toBeDefined();
@@ -380,7 +383,10 @@ describe("instantiating members", () => {
380
383
  instantiation.flags & OutputSymbolFlags.InstanceMemberContainer,
381
384
  ).toBeTruthy();
382
385
  expect(instantiation.instanceMemberScope).toBeDefined();
383
- const expectedRefkey = refkey(instantiation.refkey, instance.refkey);
386
+ const expectedRefkey = refkey(
387
+ instantiation.refkeys[0],
388
+ instance.refkeys[0],
389
+ );
384
390
  expect(
385
391
  instantiation.instanceMemberScope!.symbolsByRefkey.get(expectedRefkey),
386
392
  ).toBeDefined();
@@ -393,7 +399,7 @@ describe("instantiating members", () => {
393
399
  flags: OutputSymbolFlags.InstanceMember,
394
400
  });
395
401
  const newExpectedRefkey = refkey(
396
- instantiation.refkey,
402
+ instantiation.refkeys[0],
397
403
  newInstanceMemberRefkey,
398
404
  );
399
405
  expect(
@@ -558,7 +564,80 @@ describe("refkey resolution", () => {
558
564
 
559
565
  expect(resolvedSym.value).toBe(undefined);
560
566
 
561
- sym.refkey = key;
567
+ sym.refkeys[0] = key;
568
+ expect(resolvedSym.value?.targetDeclaration).toBe(sym);
569
+ });
570
+ });
571
+
572
+ describe("Deleting symbols", () => {
573
+ it("updates resolutions", () => {
574
+ const key = refkey();
575
+ const binder = createOutputBinder();
576
+
577
+ const resolvedSym = binder.resolveDeclarationByKey(
578
+ undefined,
579
+ undefined,
580
+ key,
581
+ );
582
+
583
+ const sym = binder.createSymbol({
584
+ name: "foo",
585
+ scope: binder.globalScope,
586
+ });
587
+
588
+ expect(resolvedSym.value).toBe(undefined);
589
+
590
+ sym.refkeys[0] = key;
562
591
  expect(resolvedSym.value?.targetDeclaration).toBe(sym);
592
+
593
+ binder.deleteSymbol(sym);
594
+
595
+ expect(resolvedSym.value).toBe(undefined);
596
+ });
597
+
598
+ it("removes from parent scopes", () => {
599
+ const binder = createOutputBinder();
600
+ const result = binder.resolveFQN("root.root#instance");
601
+ expect(result.value).toBeUndefined();
602
+
603
+ const {
604
+ symbols: { instance, root, staticc },
605
+ scopes: { rootScope },
606
+ } = createScopeTree(binder, {
607
+ rootScope: {
608
+ symbols: {
609
+ root: {
610
+ flags:
611
+ OutputSymbolFlags.InstanceMemberContainer |
612
+ OutputSymbolFlags.StaticMemberContainer,
613
+ instanceMembers: {
614
+ instance: {
615
+ flags: OutputSymbolFlags.InstanceMember,
616
+ },
617
+ },
618
+ staticMembers: {
619
+ staticc: {
620
+ flags: OutputSymbolFlags.StaticMember,
621
+ },
622
+ },
623
+ },
624
+ },
625
+ },
626
+ });
627
+
628
+ const staticScope = root.staticMemberScope!;
629
+ const instanceScope = root.instanceMemberScope!;
630
+
631
+ expect(staticScope.symbols.size).toBe(1);
632
+ binder.deleteSymbol(staticc);
633
+ expect(staticScope.symbols.size).toBe(0);
634
+
635
+ expect(instanceScope.symbols.size).toBe(1);
636
+ binder.deleteSymbol(instance);
637
+ expect(instanceScope.symbols.size).toBe(0);
638
+
639
+ expect(rootScope.symbols.size).toBe(1);
640
+ binder.deleteSymbol(root);
641
+ expect(rootScope.symbols.size).toBe(0);
563
642
  });
564
643
  });
@@ -1,5 +1,8 @@
1
+ import { Children } from "@alloy-js/core/jsx-runtime";
2
+ import { computed, ref, triggerRef } from "@vue/reactivity";
1
3
  import { describe, expect, it } from "vitest";
2
- import { join, mapJoin } from "../src/utils.js";
4
+ import { renderTree } from "../src/render.js";
5
+ import { children, join, mapJoin } from "../src/utils.js";
3
6
  import "../testing/extend-expect.js";
4
7
 
5
8
  describe("mapJoin", () => {
@@ -10,15 +13,19 @@ describe("mapJoin", () => {
10
13
  ]);
11
14
 
12
15
  function Foo(props: { key: string; value: number }) {
13
- return <>Key: {props.key}, Value: {props.value}</>;
16
+ return (
17
+ <>
18
+ Key: {props.key}, Value: {props.value}
19
+ </>
20
+ );
14
21
  }
15
22
 
16
- const joined = mapJoin(map, (
17
- key,
18
- value,
19
- ) => <Foo key={key} value={value} />);
23
+ const joined = mapJoin(
24
+ () => map,
25
+ (key, value) => <Foo key={key} value={value} />,
26
+ );
20
27
 
21
- expect(joined).toRenderTo(`
28
+ expect(joined()).toRenderTo(`
22
29
  Key: a, Value: 1
23
30
  Key: b, Value: 2
24
31
  `);
@@ -31,14 +38,63 @@ describe("mapJoin", () => {
31
38
  return <>Value: {props.value}</>;
32
39
  }
33
40
 
34
- const joined = mapJoin(arr, (value) => <Foo value={value} />);
41
+ const joined = mapJoin(
42
+ () => arr,
43
+ (value) => <Foo value={value} />,
44
+ );
35
45
 
36
- expect(joined).toRenderTo(`
46
+ expect(joined()).toRenderTo(`
37
47
  Value: 1
38
48
  Value: 2
39
49
  `);
40
50
  });
41
51
 
52
+ it("can map an array reactively (without render)", () => {
53
+ const arr = ref([1, 2]);
54
+
55
+ function Foo(props: { value: number }) {
56
+ return <>Value: {props.value}</>;
57
+ }
58
+
59
+ const joined = mapJoin(
60
+ () => arr.value,
61
+ (value) => {
62
+ return <Foo value={value} />;
63
+ },
64
+ );
65
+
66
+ const len = computed(() => {
67
+ return joined().length;
68
+ });
69
+ expect(len.value).toBe(4);
70
+ arr.value.push(3);
71
+ triggerRef(arr);
72
+ expect(len.value).toBe(6);
73
+ });
74
+
75
+ it("can map an array reactively (with render)", () => {
76
+ let callCount = 0;
77
+ const arr = ref([1, 2]);
78
+
79
+ function Foo(props: { value: number }) {
80
+ callCount++;
81
+ return <>Value: {props.value}</>;
82
+ }
83
+
84
+ const joined = mapJoin(
85
+ () => arr.value,
86
+ (value) => {
87
+ return <Foo value={value} />;
88
+ },
89
+ );
90
+
91
+ renderTree(joined);
92
+
93
+ expect(callCount).toBe(2);
94
+ arr.value.push(3);
95
+ triggerRef(arr);
96
+ expect(callCount).toBe(3);
97
+ });
42
98
  it("can map a joiner", () => {
43
99
  const arr = [1, 2];
44
100
 
@@ -46,9 +102,13 @@ describe("mapJoin", () => {
46
102
  return <>Value: {props.value}</>;
47
103
  }
48
104
 
49
- const joined = mapJoin(arr, (value) => <Foo value={value} />, {
50
- joiner: "-",
51
- });
105
+ const joined = mapJoin(
106
+ () => arr,
107
+ (value) => <Foo value={value} />,
108
+ {
109
+ joiner: "-",
110
+ },
111
+ );
52
112
 
53
113
  expect(joined).toRenderTo(`
54
114
  Value: 1-Value: 2
@@ -62,10 +122,14 @@ describe("mapJoin", () => {
62
122
  return <>Value: {props.value}</>;
63
123
  }
64
124
 
65
- const joined = mapJoin(arr, (value) => <Foo value={value} />, {
66
- joiner: "-",
67
- ender: ";",
68
- });
125
+ const joined = mapJoin(
126
+ () => arr,
127
+ (value) => <Foo value={value} />,
128
+ {
129
+ joiner: "-",
130
+ ender: ";",
131
+ },
132
+ );
69
133
 
70
134
  expect(joined).toRenderTo(`
71
135
  Value: 1-Value: 2;
@@ -79,10 +143,14 @@ describe("mapJoin", () => {
79
143
  return <>Value: {props.value}</>;
80
144
  }
81
145
 
82
- const joined = mapJoin(arr, (value) => <Foo value={value} />, {
83
- joiner: "-",
84
- ender: ";",
85
- });
146
+ const joined = mapJoin(
147
+ () => arr,
148
+ (value) => <Foo value={value} />,
149
+ {
150
+ joiner: "-",
151
+ ender: ";",
152
+ },
153
+ );
86
154
 
87
155
  expect(joined).toRenderTo(`
88
156
  Value: 1-Value: 2;
@@ -148,3 +216,44 @@ describe("join", () => {
148
216
  `);
149
217
  });
150
218
  });
219
+
220
+ describe("children", () => {
221
+ let resolvedChildren: Children;
222
+ function ResolveChildren(props: any) {
223
+ resolvedChildren = children(() => props.children, {
224
+ preserveFragments: props.preserveFragments,
225
+ })();
226
+ }
227
+
228
+ it("resolves a single child", () => {
229
+ renderTree(<ResolveChildren>1</ResolveChildren>);
230
+ expect(resolvedChildren).toEqual("1");
231
+ });
232
+
233
+ it("resolves multiple children", () => {
234
+ renderTree(<ResolveChildren>1{"2"}3</ResolveChildren>);
235
+ expect(resolvedChildren).toEqual(["1", "2", "3"]);
236
+ });
237
+
238
+ it("resolves fragments by default", () => {
239
+ renderTree(
240
+ <ResolveChildren>
241
+ <>1</>
242
+ <>2</>
243
+ <>3</>
244
+ </ResolveChildren>,
245
+ );
246
+ expect(resolvedChildren).toEqual(["1", "2", "3"]);
247
+ });
248
+
249
+ it("preserves fragments if asked", () => {
250
+ renderTree(
251
+ <ResolveChildren preserveFragments>
252
+ <>1</>
253
+ <>2</>
254
+ <>3</>
255
+ </ResolveChildren>,
256
+ );
257
+ expect(resolvedChildren).toEqual([["1"], ["2"], ["3"]]);
258
+ });
259
+ });
@@ -1,12 +1,22 @@
1
- import { Children, renderTree } from "@alloy-js/core";
1
+ import { Children, printTree, renderTree } from "@alloy-js/core";
2
2
  import { expect } from "vitest";
3
- import { dedent, printTree } from "./render.js";
3
+ import { dedent } from "./render.js";
4
+
5
+ interface ToRenderToOptions {
6
+ printWidth?: number;
7
+ tabWidth?: number;
8
+ useTabs?: boolean;
9
+ }
4
10
 
5
11
  expect.extend({
6
- toRenderTo(received: Children, expectedRaw: string) {
12
+ toRenderTo(
13
+ received: Children,
14
+ expectedRaw: string,
15
+ renderOptions?: ToRenderToOptions,
16
+ ) {
7
17
  const { isNot } = this;
8
18
  const tree = renderTree(received);
9
- const actual = printTree(tree);
19
+ const actual = printTree(tree, renderOptions);
10
20
  const expected = dedent(expectedRaw);
11
21
  return {
12
22
  pass: actual === expected,
package/testing/render.ts CHANGED
@@ -1,9 +1,7 @@
1
- import { RenderTextTree, renderTree } from "@alloy-js/core";
1
+ import { printTree, renderTree } from "@alloy-js/core";
2
2
  import { Children } from "../src/jsx-runtime.js";
3
3
 
4
- export function printTree(tree: RenderTextTree) {
5
- return (tree as any).flat(Infinity).join("");
6
- }
4
+ export { printTree } from "@alloy-js/core";
7
5
 
8
6
  export function renderToString(element: Children) {
9
7
  return printTree(renderTree(element));
@@ -1,7 +1,12 @@
1
1
  import "vitest";
2
2
 
3
+ interface ToRenderToRenderOptions {
4
+ printWidth?: number;
5
+ tabWidth?: number;
6
+ useTabs?: boolean;
7
+ }
3
8
  interface CustomMatchers<R = unknown> {
4
- toRenderTo: (str: string) => R;
9
+ toRenderTo: (str: string, options?: ToRenderToRenderOptions) => R;
5
10
  }
6
11
 
7
12
  declare module "vitest" {
package/vitest.config.ts CHANGED
@@ -12,7 +12,7 @@ export default defineConfig({
12
12
  sourceMaps: "both",
13
13
  babelHelpers: "bundled",
14
14
  extensions: [".ts", ".tsx"],
15
- presets: ["@babel/preset-typescript", ["@alloy-js/babel-preset", {}]],
15
+ presets: ["@babel/preset-typescript", ["@alloy-js/babel-preset"]],
16
16
  }),
17
17
  ],
18
18
  });
@@ -1,5 +0,0 @@
1
- import { IndentState } from "../components/Indent.jsx";
2
- import { ComponentContext } from "../context.js";
3
- export declare const IndentContext: ComponentContext<IndentState>;
4
- export declare const TestContext: ComponentContext<string>;
5
- //# sourceMappingURL=indent.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"indent.d.ts","sourceRoot":"","sources":["../../../src/context/indent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EACL,gBAAgB,EAGjB,MAAM,eAAe,CAAC;AAEvB,eAAO,MAAM,aAAa,EAAE,gBAAgB,CAAC,WAAW,CAOvD,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,gBAAgB,CAAC,MAAM,CAAyB,CAAC"}
@@ -1,8 +0,0 @@
1
- import { createContext, createNamedContext } from "../context.js";
2
- export const IndentContext = createNamedContext("Indent", {
3
- level: 0,
4
- indent: " ",
5
- indentString: ""
6
- });
7
- export const TestContext = createContext("test");
8
- //# sourceMappingURL=indent.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"indent.js","names":["createContext","createNamedContext","IndentContext","level","indent","indentString","TestContext"],"sources":["../../../src/context/indent.ts"],"sourcesContent":[null],"mappings":"AACA,SAEEA,aAAa,EACbC,kBAAkB,QACb,eAAe;AAEtB,OAAO,MAAMC,aAA4C,GAAGD,kBAAkB,CAC5E,QAAQ,EACR;EACEE,KAAK,EAAE,CAAC;EACRC,MAAM,EAAE,IAAI;EACZC,YAAY,EAAE;AAChB,CACF,CAAC;AAED,OAAO,MAAMC,WAAqC,GAAGN,aAAa,CAAC,MAAM,CAAC","ignoreList":[]}
@@ -1,2 +0,0 @@
1
- import "../../testing/extend-expect.js";
2
- //# sourceMappingURL=linebreaks.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"linebreaks.test.d.ts","sourceRoot":"","sources":["../../../test/rendering/linebreaks.test.tsx"],"names":[],"mappings":"AACA,OAAO,gCAAgC,CAAC"}
@@ -1,17 +0,0 @@
1
- import { IndentState } from "../components/Indent.jsx";
2
- import {
3
- ComponentContext,
4
- createContext,
5
- createNamedContext,
6
- } from "../context.js";
7
-
8
- export const IndentContext: ComponentContext<IndentState> = createNamedContext(
9
- "Indent",
10
- {
11
- level: 0,
12
- indent: " ",
13
- indentString: "",
14
- },
15
- );
16
-
17
- export const TestContext: ComponentContext<string> = createContext("test");
@@ -1,72 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import "../../testing/extend-expect.js";
3
-
4
- describe("empty lines are preserved", () => {
5
- it("fragment", () => {
6
- const frag = <>
7
- hi
8
-
9
- </>;
10
-
11
- expect(<>
12
- { frag }
13
- hi
14
- </>).toRenderTo(`
15
- hi
16
-
17
- hi
18
- `);
19
- });
20
-
21
- it("memo for fragment", () => {
22
- const frag = <>
23
- hi
24
-
25
- </>;
26
- function getTrue() {
27
- return true;
28
- }
29
-
30
- expect(<>
31
- { getTrue() ? frag : undefined }
32
- hi
33
- </>).toRenderTo(`
34
- hi
35
-
36
- hi
37
- `);
38
- });
39
-
40
- it("after components", () => {
41
- function Foo() {
42
- return "hi";
43
- }
44
-
45
- expect(<>
46
- <Foo />
47
-
48
- hi
49
- </>).toRenderTo(`
50
- hi
51
-
52
- hi
53
- `);
54
- });
55
- });
56
-
57
- // this would be a nice feature to have
58
- describe.skip("empty lines are removed when the only thing on the line is a falsy value", () => {
59
- it("false", () => {
60
- expect(<>
61
- {false}
62
- hi
63
- </>).toRenderTo("hi");
64
- });
65
-
66
- it("undefined", () => {
67
- expect(<>
68
- {undefined}
69
- hi
70
- </>).toRenderTo("hi");
71
- });
72
- });