@alloy-js/core 0.10.0 → 0.12.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 (183) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/src/binder.d.ts.map +1 -1
  3. package/dist/src/binder.js +100 -19
  4. package/dist/src/code.js +1 -2
  5. package/dist/src/components/Block.js +2 -5
  6. package/dist/src/components/Declaration.js +2 -4
  7. package/dist/src/components/For.d.ts +2 -2
  8. package/dist/src/components/For.d.ts.map +1 -1
  9. package/dist/src/components/For.js +1 -2
  10. package/dist/src/components/Indent.js +2 -4
  11. package/dist/src/components/List.js +2 -5
  12. package/dist/src/components/MemberDeclaration.js +2 -4
  13. package/dist/src/components/MemberName.js +1 -2
  14. package/dist/src/components/MemberScope.js +2 -4
  15. package/dist/src/components/Name.js +1 -2
  16. package/dist/src/components/Output.js +2 -4
  17. package/dist/src/components/Prose.js +1 -2
  18. package/dist/src/components/ReferenceOrContent.d.ts +8 -0
  19. package/dist/src/components/ReferenceOrContent.d.ts.map +1 -0
  20. package/dist/src/components/ReferenceOrContent.js +11 -0
  21. package/dist/src/components/Scope.js +2 -4
  22. package/dist/src/components/Show.js +1 -2
  23. package/dist/src/components/SourceDirectory.js +2 -4
  24. package/dist/src/components/SourceFile.js +2 -5
  25. package/dist/src/components/StatementList.js +2 -4
  26. package/dist/src/components/Switch.d.ts +1 -1
  27. package/dist/src/components/Switch.d.ts.map +1 -1
  28. package/dist/src/components/Switch.js +1 -2
  29. package/dist/src/components/Wrap.js +2 -4
  30. package/dist/src/components/index.d.ts +1 -0
  31. package/dist/src/components/index.d.ts.map +1 -1
  32. package/dist/src/components/index.js +2 -2
  33. package/dist/src/components/stc/index.d.ts +1 -0
  34. package/dist/src/components/stc/index.d.ts.map +1 -1
  35. package/dist/src/components/stc/index.js +2 -2
  36. package/dist/src/components/stc/sti.js +1 -2
  37. package/dist/src/context/assignment.js +1 -2
  38. package/dist/src/context/binder.js +1 -2
  39. package/dist/src/context/declaration.js +1 -2
  40. package/dist/src/context/index.js +1 -2
  41. package/dist/src/context/member-declaration.js +1 -2
  42. package/dist/src/context/member-scope.js +1 -2
  43. package/dist/src/context/name-policy.js +1 -2
  44. package/dist/src/context/scope.js +1 -2
  45. package/dist/src/context/source-directory.js +1 -2
  46. package/dist/src/context/source-file.js +1 -2
  47. package/dist/src/context.js +1 -2
  48. package/dist/src/debug.js +13 -15
  49. package/dist/src/index.browser.js +1 -2
  50. package/dist/src/index.js +1 -2
  51. package/dist/src/jsx-runtime.d.ts +1 -1
  52. package/dist/src/jsx-runtime.d.ts.map +1 -1
  53. package/dist/src/jsx-runtime.js +10 -5
  54. package/dist/src/name-policy.js +1 -2
  55. package/dist/src/refkey.js +1 -2
  56. package/dist/src/render.d.ts.map +1 -1
  57. package/dist/src/render.js +6 -2
  58. package/dist/src/scheduler.d.ts +8 -0
  59. package/dist/src/scheduler.d.ts.map +1 -0
  60. package/dist/src/scheduler.js +17 -0
  61. package/dist/src/slot.js +1 -2
  62. package/dist/src/stc.js +1 -2
  63. package/dist/src/sti.js +1 -2
  64. package/dist/src/tap.js +1 -2
  65. package/dist/src/tsdoc-metadata.json +1 -1
  66. package/dist/src/utils.js +2 -4
  67. package/dist/src/write-output.browser.js +1 -2
  68. package/dist/src/write-output.js +1 -2
  69. package/dist/test/browser-build.test.js +85 -0
  70. package/dist/test/children.test.js +27 -0
  71. package/dist/test/components/block.test.js +45 -0
  72. package/dist/test/components/declaration.test.js +32 -0
  73. package/dist/test/components/list.test.js +86 -0
  74. package/dist/test/components/prose.test.js +25 -0
  75. package/dist/test/components/reference-or-content.test.d.ts +2 -0
  76. package/dist/test/components/reference-or-content.test.d.ts.map +1 -0
  77. package/dist/test/components/reference-or-content.test.js +149 -0
  78. package/dist/test/components/slot.test.js +134 -0
  79. package/dist/test/components/source-file.test.js +64 -0
  80. package/dist/test/components/wrap.test.js +35 -0
  81. package/dist/test/control-flow/for.test.js +219 -0
  82. package/dist/test/control-flow/match.test.js +67 -0
  83. package/dist/test/control-flow/show.test.js +29 -0
  84. package/dist/test/name-policy.test.js +19 -0
  85. package/dist/test/props-with-defaults.test.js +93 -0
  86. package/dist/test/reactivity/circular-reactives.test.d.ts +2 -0
  87. package/dist/test/reactivity/circular-reactives.test.d.ts.map +1 -0
  88. package/dist/test/reactivity/circular-reactives.test.js +31 -0
  89. package/dist/test/reactivity/cleanup.test.js +82 -0
  90. package/dist/test/reactivity/memo.test.js +16 -0
  91. package/dist/test/reactivity/ref-rendering.test.js +37 -0
  92. package/dist/test/reactivity/test.test.js +61 -0
  93. package/dist/test/reactivity/untrack.test.js +26 -0
  94. package/dist/test/refkey.test.js +25 -0
  95. package/dist/test/rendering/basic.test.js +96 -0
  96. package/dist/test/rendering/code.test.js +55 -0
  97. package/dist/test/rendering/formatting.test.js +402 -0
  98. package/dist/test/rendering/indent.test.js +90 -0
  99. package/dist/test/rendering/memoization.test.js +27 -0
  100. package/dist/test/rendering/refkeys.test.js +32 -0
  101. package/dist/test/split-props.test.js +77 -0
  102. package/dist/test/stc.test.js +34 -0
  103. package/dist/test/symbols.test.js +877 -0
  104. package/dist/test/utils.test.d.ts.map +1 -1
  105. package/dist/test/utils.test.js +223 -0
  106. package/dist/testing/extend-expect.js +1 -2
  107. package/dist/testing/index.js +1 -2
  108. package/dist/testing/render.js +1 -2
  109. package/dist/tsconfig.tsbuildinfo +1 -1
  110. package/package.json +14 -22
  111. package/src/binder.ts +100 -17
  112. package/src/components/For.tsx +6 -6
  113. package/src/components/ReferenceOrContent.tsx +22 -0
  114. package/src/components/index.tsx +1 -0
  115. package/src/components/stc/index.ts +1 -0
  116. package/src/debug.ts +12 -13
  117. package/src/jsx-runtime.ts +24 -14
  118. package/src/render.ts +5 -0
  119. package/src/scheduler.ts +24 -0
  120. package/temp/api.json +216 -15
  121. package/test/components/declaration.test.tsx +2 -0
  122. package/test/components/list.test.tsx +0 -1
  123. package/test/components/reference-or-content.test.tsx +138 -0
  124. package/test/control-flow/for.test.tsx +34 -4
  125. package/test/reactivity/circular-reactives.test.tsx +32 -0
  126. package/test/reactivity/cleanup.test.tsx +5 -0
  127. package/test/reactivity/untrack.test.ts +3 -0
  128. package/test/rendering/memoization.test.tsx +2 -0
  129. package/test/symbols.test.ts +392 -13
  130. package/test/utils.test.tsx +2 -0
  131. package/babel.config.cjs +0 -4
  132. package/dist/src/binder.js.map +0 -1
  133. package/dist/src/code.js.map +0 -1
  134. package/dist/src/components/Block.js.map +0 -1
  135. package/dist/src/components/Declaration.js.map +0 -1
  136. package/dist/src/components/For.js.map +0 -1
  137. package/dist/src/components/Indent.js.map +0 -1
  138. package/dist/src/components/List.js.map +0 -1
  139. package/dist/src/components/MemberDeclaration.js.map +0 -1
  140. package/dist/src/components/MemberName.js.map +0 -1
  141. package/dist/src/components/MemberScope.js.map +0 -1
  142. package/dist/src/components/Name.js.map +0 -1
  143. package/dist/src/components/Output.js.map +0 -1
  144. package/dist/src/components/Prose.js.map +0 -1
  145. package/dist/src/components/Scope.js.map +0 -1
  146. package/dist/src/components/Show.js.map +0 -1
  147. package/dist/src/components/SourceDirectory.js.map +0 -1
  148. package/dist/src/components/SourceFile.js.map +0 -1
  149. package/dist/src/components/StatementList.js.map +0 -1
  150. package/dist/src/components/Switch.js.map +0 -1
  151. package/dist/src/components/Wrap.js.map +0 -1
  152. package/dist/src/components/index.js.map +0 -1
  153. package/dist/src/components/stc/index.js.map +0 -1
  154. package/dist/src/components/stc/sti.js.map +0 -1
  155. package/dist/src/context/assignment.js.map +0 -1
  156. package/dist/src/context/binder.js.map +0 -1
  157. package/dist/src/context/declaration.js.map +0 -1
  158. package/dist/src/context/index.js.map +0 -1
  159. package/dist/src/context/member-declaration.js.map +0 -1
  160. package/dist/src/context/member-scope.js.map +0 -1
  161. package/dist/src/context/name-policy.js.map +0 -1
  162. package/dist/src/context/scope.js.map +0 -1
  163. package/dist/src/context/source-directory.js.map +0 -1
  164. package/dist/src/context/source-file.js.map +0 -1
  165. package/dist/src/context.js.map +0 -1
  166. package/dist/src/debug.js.map +0 -1
  167. package/dist/src/index.browser.js.map +0 -1
  168. package/dist/src/index.js.map +0 -1
  169. package/dist/src/jsx-runtime.js.map +0 -1
  170. package/dist/src/name-policy.js.map +0 -1
  171. package/dist/src/refkey.js.map +0 -1
  172. package/dist/src/render.js.map +0 -1
  173. package/dist/src/slot.js.map +0 -1
  174. package/dist/src/stc.js.map +0 -1
  175. package/dist/src/sti.js.map +0 -1
  176. package/dist/src/tap.js.map +0 -1
  177. package/dist/src/utils.js.map +0 -1
  178. package/dist/src/write-output.browser.js.map +0 -1
  179. package/dist/src/write-output.js.map +0 -1
  180. package/dist/testing/extend-expect.js.map +0 -1
  181. package/dist/testing/index.js.map +0 -1
  182. package/dist/testing/render.js.map +0 -1
  183. package/dist/testing/vitest.d.js.map +0 -1
@@ -0,0 +1,25 @@
1
+ import { expect, it } from "vitest";
2
+ import { refkey } from "../src/refkey.js";
3
+ it("is stable when called with same values", () => {
4
+ const obj = {};
5
+ const key1 = refkey(obj);
6
+ const key2 = refkey(obj);
7
+ expect(key1).toBe(key2);
8
+ });
9
+ it("supports primitive values", () => {
10
+ const key1 = refkey("hi");
11
+ const key2 = refkey("hi");
12
+ expect(key1).toBe(key2);
13
+ });
14
+ it("composes multiple keys", () => {
15
+ const obj1 = {};
16
+ const obj2 = {};
17
+ const key1 = refkey(obj1, obj2, "hi");
18
+ const key2 = refkey(obj1, obj2, "hi");
19
+ expect(key1).toBe(key2);
20
+ });
21
+ it("can be called with no args and returns a fresh key", () => {
22
+ const key1 = refkey();
23
+ const key2 = refkey();
24
+ expect(key1).not.toBe(key2);
25
+ });
@@ -0,0 +1,96 @@
1
+ import { createIntrinsic as _$createIntrinsic, createComponent as _$createComponent, memo as _$memo } from "@alloy-js/core/jsx-runtime";
2
+ import { describe, expect, it } from "vitest";
3
+ import "../../testing/extend-expect.js";
4
+ describe("string nodes", () => {
5
+ it("renders string nodes with substitutions", () => {
6
+ const str = "hi";
7
+ expect(["a ", str, _$createIntrinsic("hbr", {}), str]).toRenderTo(`
8
+ a hi
9
+ hi
10
+ `);
11
+ });
12
+ });
13
+ describe("component nodes", () => {
14
+ function Str() {
15
+ return "Str";
16
+ }
17
+ function Arr() {
18
+ return ["Item 1", "\n" + "Item 2"];
19
+ }
20
+ function Nested() {
21
+ return _$createComponent(Str, {});
22
+ }
23
+ it("renders basic component", () => {
24
+ expect(_$createComponent(Str, {})).toRenderTo("Str");
25
+ });
26
+ it("renders array components", () => {
27
+ expect(_$createComponent(Arr, {})).toRenderTo("Item 1\nItem 2");
28
+ });
29
+ it("renders nested components", () => {
30
+ expect(_$createComponent(Nested, {})).toRenderTo("Str");
31
+ });
32
+ it("renders components on same line", () => {
33
+ expect([_$createComponent(Str, {}), " ", _$createComponent(Str, {})]).toRenderTo("Str Str");
34
+ });
35
+ });
36
+ describe("memo nodes", () => {
37
+ function getStr() {
38
+ return "Str";
39
+ }
40
+ function Foo() {
41
+ return "Foo";
42
+ }
43
+ function getFoo() {
44
+ return _$createComponent(Foo, {});
45
+ }
46
+ function getArr() {
47
+ return [_$createComponent(Foo, {}), "\n", _$createComponent(Foo, {})];
48
+ }
49
+ it("renders basic memos", () => {
50
+ expect([_$memo(getStr)]).toRenderTo("Str");
51
+ });
52
+ it("renders component memos", () => {
53
+ expect([_$memo(getFoo)]).toRenderTo("Foo");
54
+ });
55
+ it("renders array memos", () => {
56
+ expect([_$memo(getArr)]).toRenderTo("Foo\nFoo");
57
+ });
58
+ });
59
+ describe("array nodes", () => {
60
+ it("renders basic arrays", () => {
61
+ expect([["hi", " ", "hi"]]).toRenderTo("hi hi");
62
+ });
63
+ });
64
+ it("renders text fragments", () => {
65
+ function Foo() {
66
+ return "bye";
67
+ }
68
+ expect(["hi", _$createIntrinsic("hbr", {}), _$createComponent(Foo, {})]).toRenderTo(`
69
+ hi
70
+ bye
71
+ `);
72
+ });
73
+ it("renders basic components", () => {
74
+ function Bar(props) {
75
+ return props.children;
76
+ }
77
+ function Foo() {
78
+ return _$createComponent(Bar, {
79
+ children: "hello"
80
+ });
81
+ }
82
+ expect(_$createComponent(Foo, {})).toRenderTo("hello");
83
+ });
84
+ it("renders booleans appropriately", () => {
85
+ function Foo() {
86
+ return false;
87
+ }
88
+ expect(_$createComponent(Foo, {})).toRenderTo("");
89
+ });
90
+ it("keeps spaces between expressions", () => {
91
+ const str = "str";
92
+ function getStr() {
93
+ return "getStr";
94
+ }
95
+ expect(["a ", str, " ", str, " ", _$memo(getStr), " ", _$memo(getStr), " c"]).toRenderTo("a str str getStr getStr c");
96
+ });
@@ -0,0 +1,55 @@
1
+ import { createComponent as _$createComponent } from "@alloy-js/core/jsx-runtime";
2
+ import { code } from "@alloy-js/core";
3
+ import { expect, it } from "vitest";
4
+ import "../../testing/extend-expect.js";
5
+ it("renders simple strings", () => {
6
+ expect(code`foo`).toRenderTo("foo");
7
+ });
8
+ it("renders removes indents", () => {
9
+ expect(code`
10
+ foo
11
+ `).toRenderTo("foo");
12
+ });
13
+ it("renders allows substitutions of elements", () => {
14
+ function Foo() {
15
+ return "hi";
16
+ }
17
+ expect(code`
18
+ foo ${_$createComponent(Foo, {})} bar
19
+ `).toRenderTo("foo hi bar");
20
+ });
21
+ it("renders has auto-indentation", () => {
22
+ function Foo() {
23
+ return code`
24
+ hi
25
+ bye
26
+ `;
27
+ }
28
+ const template = code`
29
+ if (x === 1) {
30
+ ${_$createComponent(Foo, {})}
31
+ }
32
+ `;
33
+ expect(template).toRenderTo(`
34
+ if (x === 1) {
35
+ hi
36
+ bye
37
+ }
38
+ `);
39
+ });
40
+ it("handles blank lines", () => {
41
+ const template = code`
42
+ {
43
+ a
44
+
45
+ x
46
+ }
47
+ `;
48
+ expect(template).toRenderTo(`
49
+ {
50
+ a
51
+
52
+ x
53
+ }
54
+ `);
55
+ });
@@ -0,0 +1,402 @@
1
+ import { createIntrinsic as _$createIntrinsic, createComponent as _$createComponent, memo as _$memo } from "@alloy-js/core/jsx-runtime";
2
+ import { describe, expect, it } from "vitest";
3
+ import { For, Output, render, SourceFile } from "../../src/index.js";
4
+ import "../../testing/extend-expect.js";
5
+ import { d } from "../../testing/render.js";
6
+ describe("group", () => {
7
+ it("breaks when shouldBreak is passed", () => {
8
+ expect(_$createIntrinsic("group", {
9
+ shouldBreak: true,
10
+ get children() {
11
+ return ["hi", _$createIntrinsic("sbr", {}), "bye"];
12
+ }
13
+ })).toRenderTo(`
14
+ hi
15
+ bye
16
+ `);
17
+ });
18
+ });
19
+ describe("indent", () => {
20
+ it("indents its children", () => {
21
+ expect(["a", _$createIntrinsic("indent", {
22
+ get children() {
23
+ return [_$createIntrinsic("hardline", {}), "b"];
24
+ }
25
+ })]).toRenderTo(`
26
+ a
27
+ b
28
+ `);
29
+ });
30
+ });
31
+ describe("dedent and markAsRoot", () => {
32
+ it("dedents its children", () => {
33
+ expect(["base", _$createIntrinsic("indent", {
34
+ get children() {
35
+ return [_$createIntrinsic("hbr", {}), "a", _$createIntrinsic("dedent", {
36
+ get children() {
37
+ return [_$createIntrinsic("hardline", {}), "b"];
38
+ }
39
+ })];
40
+ }
41
+ })]).toRenderTo(`
42
+ base
43
+ a
44
+ b
45
+ `);
46
+ });
47
+ });
48
+ describe("dedentToRoot and setRoot", () => {
49
+ it("dedents to the indent level marked by the root when not marked", () => {
50
+ expect(["base", _$createIntrinsic("indent", {
51
+ get children() {
52
+ return [_$createIntrinsic("hbr", {}), "a", _$createIntrinsic("dedentToRoot", {
53
+ get children() {
54
+ return [_$createIntrinsic("hbr", {}), "b"];
55
+ }
56
+ })];
57
+ }
58
+ })]).toRenderTo(`
59
+ base
60
+ a
61
+ b
62
+ `);
63
+ });
64
+ it("dedents to the indent level marked by the root when marked", () => {
65
+ expect(["base", _$createIntrinsic("indent", {
66
+ get children() {
67
+ return [_$createIntrinsic("hbr", {}), "root", _$createIntrinsic("markAsRoot", {
68
+ get children() {
69
+ return _$createIntrinsic("indent", {
70
+ get children() {
71
+ return [_$createIntrinsic("hbr", {}), "a", _$createIntrinsic("dedentToRoot", {
72
+ get children() {
73
+ return [_$createIntrinsic("hbr", {}), "b"];
74
+ }
75
+ })];
76
+ }
77
+ });
78
+ }
79
+ })];
80
+ }
81
+ })]).toRenderTo(`
82
+ base
83
+ root
84
+ a
85
+ b
86
+ `);
87
+ });
88
+ });
89
+ describe("softline", () => {
90
+ it("breaks to to a new line when needed", () => {
91
+ expect(_$createIntrinsic("group", {
92
+ get children() {
93
+ return ["1234567890", _$createIntrinsic("softline", {}), "1234567890"];
94
+ }
95
+ })).toRenderTo(`12345678901234567890`, {
96
+ printWidth: 25
97
+ });
98
+ expect(_$createIntrinsic("group", {
99
+ get children() {
100
+ return ["1234567890", _$createIntrinsic("softline", {}), "1234567890"];
101
+ }
102
+ })).toRenderTo(`
103
+ 1234567890
104
+ 1234567890
105
+ `, {
106
+ printWidth: 15
107
+ });
108
+ expect(_$createIntrinsic("group", {
109
+ get children() {
110
+ return ["1234567890", _$createIntrinsic("sbr", {}), "1234567890"];
111
+ }
112
+ })).toRenderTo(`12345678901234567890`, {
113
+ printWidth: 25
114
+ });
115
+ expect(_$createIntrinsic("group", {
116
+ get children() {
117
+ return ["1234567890", _$createIntrinsic("sbr", {}), "1234567890"];
118
+ }
119
+ })).toRenderTo(`
120
+ 1234567890
121
+ 1234567890
122
+ `, {
123
+ printWidth: 15
124
+ });
125
+ });
126
+ });
127
+ describe("hardline", () => {
128
+ it("always breaks to a new line", () => {
129
+ expect(_$createIntrinsic("group", {
130
+ get children() {
131
+ return ["1234567890", _$createIntrinsic("hardline", {}), "1234567890"];
132
+ }
133
+ })).toRenderTo(`
134
+ 1234567890
135
+ 1234567890
136
+ `);
137
+ expect(_$createIntrinsic("group", {
138
+ get children() {
139
+ return ["1234567890", _$createIntrinsic("hbr", {}), "1234567890"];
140
+ }
141
+ })).toRenderTo(`
142
+ 1234567890
143
+ 1234567890
144
+ `);
145
+ });
146
+ });
147
+ describe("line", () => {
148
+ it("creates a new line when needed, is otherwise space", () => {
149
+ expect(_$createIntrinsic("group", {
150
+ get children() {
151
+ return ["1234567890", _$createIntrinsic("line", {}), "1234567890"];
152
+ }
153
+ })).toRenderTo(`1234567890 1234567890`, {
154
+ printWidth: 25
155
+ });
156
+ expect(_$createIntrinsic("group", {
157
+ get children() {
158
+ return ["1234567890", _$createIntrinsic("line", {}), "1234567890"];
159
+ }
160
+ })).toRenderTo(`
161
+ 1234567890
162
+ 1234567890
163
+ `, {
164
+ printWidth: 15
165
+ });
166
+ expect(_$createIntrinsic("group", {
167
+ get children() {
168
+ return ["1234567890", _$createIntrinsic("br", {}), "1234567890"];
169
+ }
170
+ })).toRenderTo(`1234567890 1234567890`, {
171
+ printWidth: 25
172
+ });
173
+ expect(_$createIntrinsic("group", {
174
+ get children() {
175
+ return ["1234567890", _$createIntrinsic("br", {}), "1234567890"];
176
+ }
177
+ })).toRenderTo(`
178
+ 1234567890
179
+ 1234567890
180
+ `, {
181
+ printWidth: 15
182
+ });
183
+ });
184
+ });
185
+ describe("literalline", () => {
186
+ it("always creates a new line", () => {
187
+ expect(["base", _$createIntrinsic("indent", {
188
+ get children() {
189
+ return [_$createIntrinsic("hbr", {}), "1234567890", _$createIntrinsic("literalline", {}), "1234567890", _$createIntrinsic("hbr", {}), "x"];
190
+ }
191
+ })]).toRenderTo(`
192
+ base
193
+ 1234567890
194
+ 1234567890
195
+ x
196
+ `);
197
+ expect(["base", _$createIntrinsic("indent", {
198
+ get children() {
199
+ return [_$createIntrinsic("hbr", {}), "1234567890", _$createIntrinsic("lbr", {}), "1234567890", _$createIntrinsic("hbr", {}), "x"];
200
+ }
201
+ })]).toRenderTo(`
202
+ base
203
+ 1234567890
204
+ 1234567890
205
+ x
206
+ `);
207
+ });
208
+ });
209
+ describe("lineSuffix and lineSuffixBoundary", () => {
210
+ it("adds a line suffix", () => {
211
+ expect(["hello", _$createIntrinsic("lineSuffix", {
212
+ children: "// comment"
213
+ }), " there", _$createIntrinsic("hbr", {}), "how", _$createIntrinsic("lineSuffix", {
214
+ children: "// another comment"
215
+ }), " are", " ", _$createIntrinsic("lineSuffixBoundary", {}), "you"]).toRenderTo(`
216
+ hello there// comment
217
+ how are // another comment
218
+ you
219
+ `);
220
+ });
221
+ });
222
+ describe("breakParent", () => {
223
+ it("breaks the parent group", () => {
224
+ expect(_$createIntrinsic("group", {
225
+ get children() {
226
+ return [_$createIntrinsic("breakParent", {}), "one", _$createIntrinsic("sbr", {}), "two"];
227
+ }
228
+ })).toRenderTo(`
229
+ one
230
+ two
231
+ `);
232
+ });
233
+ });
234
+ describe("ifBreak", () => {
235
+ it("renders the children when broken", () => {
236
+ expect(_$createIntrinsic("group", {
237
+ get children() {
238
+ return _$createIntrinsic("ifBreak", {
239
+ flatContents: "bye",
240
+ children: "hi"
241
+ });
242
+ }
243
+ })).toRenderTo(`bye`);
244
+ });
245
+ it("renders the children when not broken", () => {
246
+ expect(_$createIntrinsic("group", {
247
+ get children() {
248
+ return [_$createIntrinsic("ifBreak", {
249
+ flatContents: "bye",
250
+ children: "hi"
251
+ }), _$createIntrinsic("breakParent", {})];
252
+ }
253
+ })).toRenderTo(`hi`);
254
+ });
255
+ it("renders flatContents that are elements", () => {
256
+ function Foo() {
257
+ return "Foo";
258
+ }
259
+ const contents = [_$createComponent(Foo, {}), _$createComponent(Foo, {})];
260
+ expect(_$createIntrinsic("group", {
261
+ get children() {
262
+ return _$createIntrinsic("ifBreak", {
263
+ flatContents: contents,
264
+ children: "hi"
265
+ });
266
+ }
267
+ })).toRenderTo(`FooFoo`);
268
+ });
269
+ it("works with a group id", () => {
270
+ const id = Symbol();
271
+ expect([_$createIntrinsic("group", {
272
+ id: id,
273
+ get children() {
274
+ return ["a", _$createIntrinsic("hbr", {}), "b", _$createIntrinsic("hbr", {})];
275
+ }
276
+ }), _$createIntrinsic("ifBreak", {
277
+ groupId: id,
278
+ children: "c"
279
+ })]).toRenderTo(`a\nb\nc`);
280
+ });
281
+ });
282
+ describe("fill", () => {
283
+ it("fills the group with its children", () => {
284
+ const items = ["one", "two", "three", "four", "five", "six"];
285
+ // place a <br /> after every item except the last
286
+ const filledItems = items.map((item, index) => [item, _$memo(() => _$memo(() => index < items.length - 1)() && _$createIntrinsic("br", {}))]);
287
+ expect(_$createIntrinsic("fill", {
288
+ children: filledItems
289
+ })).toRenderTo(`one two three four\nfive six`, {
290
+ printWidth: 20
291
+ });
292
+ });
293
+ });
294
+ describe("align", () => {
295
+ it("aligns contents with a number of spaces", () => {
296
+ expect(["base", _$createIntrinsic("align", {
297
+ width: 4,
298
+ get children() {
299
+ return [_$createIntrinsic("hbr", {}), "hi"];
300
+ }
301
+ })]).toRenderTo(`
302
+ base
303
+ hi
304
+ `);
305
+ });
306
+ it("aligns contents with a string", () => {
307
+ expect(["base", _$createIntrinsic("align", {
308
+ string: "XXXX",
309
+ get children() {
310
+ return [_$createIntrinsic("hbr", {}), "hi"];
311
+ }
312
+ })]).toRenderTo(`
313
+ base
314
+ XXXXhi
315
+ `);
316
+ });
317
+ });
318
+ it("all works together", () => {
319
+ const argCount = 2;
320
+ const args = Array.from({
321
+ length: argCount
322
+ }, (_, i) => `arg${i + 1}`);
323
+ expect([_$createIntrinsic("group", {
324
+ get children() {
325
+ return ["async function foo(", _$createIntrinsic("indent", {
326
+ get children() {
327
+ return [_$createIntrinsic("sbr", {}), _$createComponent(For, {
328
+ each: args,
329
+ get joiner() {
330
+ return [",", _$createIntrinsic("br", {})];
331
+ },
332
+ children: arg => [arg, ": string"]
333
+ })];
334
+ }
335
+ }), _$createIntrinsic("sbr", {}), ")"];
336
+ }
337
+ }), ": void ", "{", _$createIntrinsic("indent", {
338
+ get children() {
339
+ return [_$createIntrinsic("hbr", {}), "// function body"];
340
+ }
341
+ }), _$createIntrinsic("hbr", {}), "}"]).toRenderTo(`
342
+ async function foo(arg1: string, arg2: string): void {
343
+ // function body
344
+ }
345
+ `, {
346
+ printWidth: 80
347
+ });
348
+ });
349
+ it("formats based on the output component props", () => {
350
+ const template = _$createComponent(Output, {
351
+ printWidth: 5,
352
+ get children() {
353
+ return _$createComponent(SourceFile, {
354
+ path: "foo.txt",
355
+ filetype: "text/plain",
356
+ get children() {
357
+ return _$createIntrinsic("group", {
358
+ get children() {
359
+ return ["1", _$createIntrinsic("br", {}), "2", _$createIntrinsic("br", {}), "3", _$createIntrinsic("br", {}), "4", _$createIntrinsic("br", {}), "5", _$createIntrinsic("br", {}), "6"];
360
+ }
361
+ });
362
+ }
363
+ });
364
+ }
365
+ });
366
+ const tree = render(template);
367
+ expect(tree.contents[0].contents).toEqual(d`
368
+ 1
369
+ 2
370
+ 3
371
+ 4
372
+ 5
373
+ 6
374
+ `);
375
+ });
376
+ it("formats based on the source file component props", () => {
377
+ const template = _$createComponent(Output, {
378
+ get children() {
379
+ return _$createComponent(SourceFile, {
380
+ path: "foo.txt",
381
+ filetype: "text/plain",
382
+ printWidth: 5,
383
+ get children() {
384
+ return _$createIntrinsic("group", {
385
+ get children() {
386
+ return ["1", _$createIntrinsic("br", {}), "2", _$createIntrinsic("br", {}), "3", _$createIntrinsic("br", {}), "4", _$createIntrinsic("br", {}), "5", _$createIntrinsic("br", {}), "6"];
387
+ }
388
+ });
389
+ }
390
+ });
391
+ }
392
+ });
393
+ const tree = render(template);
394
+ expect(tree.contents[0].contents).toEqual(d`
395
+ 1
396
+ 2
397
+ 3
398
+ 4
399
+ 5
400
+ 6
401
+ `);
402
+ });
@@ -0,0 +1,90 @@
1
+ import { createComponent as _$createComponent, createIntrinsic as _$createIntrinsic, memo as _$memo } from "@alloy-js/core/jsx-runtime";
2
+ // prettier-ignore
3
+ import { Indent } from "@alloy-js/core";
4
+ import { describe, expect, it } from "vitest";
5
+ import "../../testing/extend-expect.js";
6
+ describe("Indent component", () => {
7
+ it("indents explicitly indented content on a subsequent line", () => {
8
+ expect(["one", _$createComponent(Indent, {
9
+ children: "hi"
10
+ })]).toRenderTo("one\n hi");
11
+ });
12
+ it("indents explicitly indented content", () => {
13
+ expect(["one", _$createComponent(Indent, {
14
+ get children() {
15
+ return ["hi", _$createIntrinsic("hbr", {}), "bye"];
16
+ }
17
+ })]).toRenderTo(`
18
+ one
19
+ hi
20
+ bye
21
+ `);
22
+ });
23
+ it("indents memos", () => {
24
+ function getValue() {
25
+ return "hi";
26
+ }
27
+ expect(["base", _$createComponent(Indent, {
28
+ get children() {
29
+ return getValue();
30
+ }
31
+ }), _$createComponent(Indent, {
32
+ get children() {
33
+ return [_$memo(() => getValue()), _$createIntrinsic("hbr", {}), "bye"];
34
+ }
35
+ }), _$createComponent(Indent, {
36
+ get children() {
37
+ return ["bye", _$createIntrinsic("hbr", {}), _$memo(() => getValue())];
38
+ }
39
+ })]).toRenderTo(`
40
+ base
41
+ hi
42
+ hi
43
+ bye
44
+ bye
45
+ hi
46
+ `);
47
+ });
48
+ it("doesn't indent components on the same line with explicit indent", () => {
49
+ function Foo() {
50
+ return "Foo";
51
+ }
52
+ expect(["base", _$createComponent(Indent, {
53
+ get children() {
54
+ return [_$createComponent(Foo, {}), _$createComponent(Foo, {})];
55
+ }
56
+ })]).toRenderTo(`
57
+ base
58
+ FooFoo
59
+ `);
60
+ });
61
+ it("works with nested indents", () => {
62
+ expect(["base", _$createComponent(Indent, {
63
+ get children() {
64
+ return ["1", _$createIntrinsic("hbr", {}), "2", _$createComponent(Indent, {
65
+ get children() {
66
+ return ["3", _$createIntrinsic("hbr", {}), "4", _$createComponent(Indent, {
67
+ get children() {
68
+ return ["5", _$createIntrinsic("hbr", {}), "6"];
69
+ }
70
+ }), _$createIntrinsic("hbr", {}), "7", _$createIntrinsic("hbr", {}), "8"];
71
+ }
72
+ }), _$createIntrinsic("hbr", {}), "9", _$createIntrinsic("hbr", {}), "10"];
73
+ }
74
+ }), _$createIntrinsic("hbr", {}), "11", _$createIntrinsic("hbr", {}), "12"]).toRenderTo(`
75
+ base
76
+ 1
77
+ 2
78
+ 3
79
+ 4
80
+ 5
81
+ 6
82
+ 7
83
+ 8
84
+ 9
85
+ 10
86
+ 11
87
+ 12
88
+ `);
89
+ });
90
+ });
@@ -0,0 +1,27 @@
1
+ import { memo, createComponent as _$createComponent } from "@alloy-js/core/jsx-runtime";
2
+ import { ref } from "@vue/reactivity";
3
+ import { expect, it } from "vitest";
4
+ import { renderTree } from "../../src/render.js";
5
+ import { flushJobs } from "../../src/scheduler.js";
6
+ it("memoizes child components", () => {
7
+ let renderCount = 0;
8
+ function Child() {
9
+ renderCount++;
10
+ return "hi " + String(Math.random());
11
+ }
12
+ const doThing = ref();
13
+ const child1 = _$createComponent(Child, {});
14
+ const child2 = _$createComponent(Child, {});
15
+ const items = memo(() => {
16
+ const list = [child1];
17
+ if (doThing.value) {
18
+ list.push(child2);
19
+ }
20
+ return list;
21
+ });
22
+ const template = [items];
23
+ renderTree(template);
24
+ doThing.value = true;
25
+ flushJobs();
26
+ expect(renderCount).toBe(2);
27
+ });