@alloy-js/core 0.9.0 → 0.11.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 (162) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/src/binder.js +33 -2
  3. package/dist/src/code.js +1 -2
  4. package/dist/src/components/Block.js +2 -5
  5. package/dist/src/components/Declaration.js +2 -4
  6. package/dist/src/components/For.d.ts +1 -1
  7. package/dist/src/components/For.d.ts.map +1 -1
  8. package/dist/src/components/For.js +1 -2
  9. package/dist/src/components/Indent.js +2 -4
  10. package/dist/src/components/List.js +2 -5
  11. package/dist/src/components/MemberDeclaration.js +2 -4
  12. package/dist/src/components/MemberName.js +1 -2
  13. package/dist/src/components/MemberScope.js +2 -4
  14. package/dist/src/components/Name.js +1 -2
  15. package/dist/src/components/Output.js +2 -4
  16. package/dist/src/components/Prose.js +1 -2
  17. package/dist/src/components/ReferenceOrContent.d.ts +8 -0
  18. package/dist/src/components/ReferenceOrContent.d.ts.map +1 -0
  19. package/dist/src/components/ReferenceOrContent.js +11 -0
  20. package/dist/src/components/Scope.js +2 -4
  21. package/dist/src/components/Show.js +1 -2
  22. package/dist/src/components/SourceDirectory.js +2 -4
  23. package/dist/src/components/SourceFile.js +2 -5
  24. package/dist/src/components/StatementList.js +2 -4
  25. package/dist/src/components/Switch.d.ts +1 -1
  26. package/dist/src/components/Switch.d.ts.map +1 -1
  27. package/dist/src/components/Switch.js +1 -2
  28. package/dist/src/components/Wrap.js +2 -4
  29. package/dist/src/components/index.d.ts +1 -0
  30. package/dist/src/components/index.d.ts.map +1 -1
  31. package/dist/src/components/index.js +2 -2
  32. package/dist/src/components/stc/index.d.ts +1 -0
  33. package/dist/src/components/stc/index.d.ts.map +1 -1
  34. package/dist/src/components/stc/index.js +2 -2
  35. package/dist/src/components/stc/sti.js +1 -2
  36. package/dist/src/context/assignment.js +1 -2
  37. package/dist/src/context/binder.js +1 -2
  38. package/dist/src/context/declaration.js +1 -2
  39. package/dist/src/context/index.js +1 -2
  40. package/dist/src/context/member-declaration.js +1 -2
  41. package/dist/src/context/member-scope.js +1 -2
  42. package/dist/src/context/name-policy.js +1 -2
  43. package/dist/src/context/scope.js +1 -2
  44. package/dist/src/context/source-directory.js +1 -2
  45. package/dist/src/context/source-file.js +1 -2
  46. package/dist/src/context.js +1 -2
  47. package/dist/src/debug.js +13 -15
  48. package/dist/src/index.browser.js +1 -2
  49. package/dist/src/index.js +1 -2
  50. package/dist/src/jsx-runtime.d.ts +1 -1
  51. package/dist/src/jsx-runtime.d.ts.map +1 -1
  52. package/dist/src/jsx-runtime.js +1 -2
  53. package/dist/src/name-policy.js +1 -2
  54. package/dist/src/refkey.js +1 -2
  55. package/dist/src/render.js +1 -2
  56. package/dist/src/slot.js +1 -2
  57. package/dist/src/stc.js +1 -2
  58. package/dist/src/sti.js +1 -2
  59. package/dist/src/tap.js +1 -2
  60. package/dist/src/tsdoc-metadata.json +1 -1
  61. package/dist/src/utils.js +2 -4
  62. package/dist/src/write-output.browser.js +1 -2
  63. package/dist/src/write-output.js +1 -2
  64. package/dist/test/browser-build.test.js +85 -0
  65. package/dist/test/children.test.js +27 -0
  66. package/dist/test/components/block.test.js +45 -0
  67. package/dist/test/components/declaration.test.js +30 -0
  68. package/dist/test/components/list.test.js +86 -0
  69. package/dist/test/components/prose.test.js +25 -0
  70. package/dist/test/components/reference-or-content.test.d.ts +2 -0
  71. package/dist/test/components/reference-or-content.test.d.ts.map +1 -0
  72. package/dist/test/components/reference-or-content.test.js +149 -0
  73. package/dist/test/components/slot.test.js +134 -0
  74. package/dist/test/components/source-file.test.js +64 -0
  75. package/dist/test/components/wrap.test.js +35 -0
  76. package/dist/test/control-flow/for.test.js +185 -0
  77. package/dist/test/control-flow/match.test.js +67 -0
  78. package/dist/test/control-flow/show.test.js +29 -0
  79. package/dist/test/name-policy.test.js +19 -0
  80. package/dist/test/props-with-defaults.test.js +93 -0
  81. package/dist/test/reactivity/cleanup.test.js +77 -0
  82. package/dist/test/reactivity/memo.test.js +16 -0
  83. package/dist/test/reactivity/ref-rendering.test.js +37 -0
  84. package/dist/test/reactivity/test.test.js +61 -0
  85. package/dist/test/reactivity/untrack.test.js +23 -0
  86. package/dist/test/refkey.test.js +25 -0
  87. package/dist/test/rendering/basic.test.js +96 -0
  88. package/dist/test/rendering/code.test.js +55 -0
  89. package/dist/test/rendering/formatting.test.js +402 -0
  90. package/dist/test/rendering/indent.test.js +90 -0
  91. package/dist/test/rendering/memoization.test.js +25 -0
  92. package/dist/test/rendering/refkeys.test.js +32 -0
  93. package/dist/test/split-props.test.js +77 -0
  94. package/dist/test/stc.test.js +34 -0
  95. package/dist/test/symbols.test.js +504 -0
  96. package/dist/test/utils.test.js +221 -0
  97. package/dist/testing/extend-expect.js +1 -2
  98. package/dist/testing/index.js +1 -2
  99. package/dist/testing/render.js +1 -2
  100. package/dist/tsconfig.tsbuildinfo +1 -1
  101. package/package.json +14 -22
  102. package/src/components/For.tsx +2 -2
  103. package/src/components/ReferenceOrContent.tsx +22 -0
  104. package/src/components/index.tsx +1 -0
  105. package/src/components/stc/index.ts +1 -0
  106. package/src/debug.ts +12 -13
  107. package/src/jsx-runtime.ts +2 -2
  108. package/temp/api.json +208 -7
  109. package/test/components/reference-or-content.test.tsx +138 -0
  110. package/babel.config.cjs +0 -4
  111. package/dist/src/binder.js.map +0 -1
  112. package/dist/src/code.js.map +0 -1
  113. package/dist/src/components/Block.js.map +0 -1
  114. package/dist/src/components/Declaration.js.map +0 -1
  115. package/dist/src/components/For.js.map +0 -1
  116. package/dist/src/components/Indent.js.map +0 -1
  117. package/dist/src/components/List.js.map +0 -1
  118. package/dist/src/components/MemberDeclaration.js.map +0 -1
  119. package/dist/src/components/MemberName.js.map +0 -1
  120. package/dist/src/components/MemberScope.js.map +0 -1
  121. package/dist/src/components/Name.js.map +0 -1
  122. package/dist/src/components/Output.js.map +0 -1
  123. package/dist/src/components/Prose.js.map +0 -1
  124. package/dist/src/components/Scope.js.map +0 -1
  125. package/dist/src/components/Show.js.map +0 -1
  126. package/dist/src/components/SourceDirectory.js.map +0 -1
  127. package/dist/src/components/SourceFile.js.map +0 -1
  128. package/dist/src/components/StatementList.js.map +0 -1
  129. package/dist/src/components/Switch.js.map +0 -1
  130. package/dist/src/components/Wrap.js.map +0 -1
  131. package/dist/src/components/index.js.map +0 -1
  132. package/dist/src/components/stc/index.js.map +0 -1
  133. package/dist/src/components/stc/sti.js.map +0 -1
  134. package/dist/src/context/assignment.js.map +0 -1
  135. package/dist/src/context/binder.js.map +0 -1
  136. package/dist/src/context/declaration.js.map +0 -1
  137. package/dist/src/context/index.js.map +0 -1
  138. package/dist/src/context/member-declaration.js.map +0 -1
  139. package/dist/src/context/member-scope.js.map +0 -1
  140. package/dist/src/context/name-policy.js.map +0 -1
  141. package/dist/src/context/scope.js.map +0 -1
  142. package/dist/src/context/source-directory.js.map +0 -1
  143. package/dist/src/context/source-file.js.map +0 -1
  144. package/dist/src/context.js.map +0 -1
  145. package/dist/src/debug.js.map +0 -1
  146. package/dist/src/index.browser.js.map +0 -1
  147. package/dist/src/index.js.map +0 -1
  148. package/dist/src/jsx-runtime.js.map +0 -1
  149. package/dist/src/name-policy.js.map +0 -1
  150. package/dist/src/refkey.js.map +0 -1
  151. package/dist/src/render.js.map +0 -1
  152. package/dist/src/slot.js.map +0 -1
  153. package/dist/src/stc.js.map +0 -1
  154. package/dist/src/sti.js.map +0 -1
  155. package/dist/src/tap.js.map +0 -1
  156. package/dist/src/utils.js.map +0 -1
  157. package/dist/src/write-output.browser.js.map +0 -1
  158. package/dist/src/write-output.js.map +0 -1
  159. package/dist/testing/extend-expect.js.map +0 -1
  160. package/dist/testing/index.js.map +0 -1
  161. package/dist/testing/render.js.map +0 -1
  162. package/dist/testing/vitest.d.js.map +0 -1
@@ -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,25 @@
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
+ it("memoizes child components", () => {
6
+ let renderCount = 0;
7
+ function Child() {
8
+ renderCount++;
9
+ return "hi " + String(Math.random());
10
+ }
11
+ const doThing = ref();
12
+ const child1 = _$createComponent(Child, {});
13
+ const child2 = _$createComponent(Child, {});
14
+ const items = memo(() => {
15
+ const list = [child1];
16
+ if (doThing.value) {
17
+ list.push(child2);
18
+ }
19
+ return list;
20
+ });
21
+ const template = [items];
22
+ renderTree(template);
23
+ doThing.value = true;
24
+ expect(renderCount).toBe(2);
25
+ });
@@ -0,0 +1,32 @@
1
+ import { createComponent as _$createComponent } from "@alloy-js/core/jsx-runtime";
2
+ import { refkey } from "@alloy-js/core";
3
+ import { SourceFile } from "@alloy-js/core/stc";
4
+ import { expect, it } from "vitest";
5
+ import "../../testing/extend-expect.js";
6
+ it("is rendered properly in the tree", () => {
7
+ const key = refkey("foo");
8
+ function Reference(props) {
9
+ expect(props.refkey).toEqual(key);
10
+ return "Reference";
11
+ }
12
+ expect(_$createComponent(SourceFile, {
13
+ filetype: "typescript",
14
+ path: "foo.ts",
15
+ reference: Reference,
16
+ children: key
17
+ })).toRenderTo("Reference");
18
+ });
19
+ it("is rendered properly in the tree with code", () => {
20
+ const key = refkey("foo");
21
+ function Reference(props) {
22
+ expect(props.refkey).toEqual(key);
23
+ return "Reference";
24
+ }
25
+ expect(SourceFile({
26
+ filetype: "typescript",
27
+ path: "foo.ts",
28
+ reference: Reference
29
+ }).code`
30
+ ${key}
31
+ `).toRenderTo("Reference");
32
+ });
@@ -0,0 +1,77 @@
1
+ import { effect, reactive } from "@vue/reactivity";
2
+ import { expect, it, vi } from "vitest";
3
+ import { splitProps } from "../src/jsx-runtime.js";
4
+ it("splits regular object props", () => {
5
+ const props = {
6
+ a: 1,
7
+ b: 2,
8
+ c: 3
9
+ };
10
+ const [ab, rest] = splitProps(props, ["a", "b"]);
11
+ expect(ab).toEqual({
12
+ a: 1,
13
+ b: 2
14
+ });
15
+ expect(rest).toEqual({
16
+ c: 3
17
+ });
18
+ });
19
+ it("splits props with getters without invoking them", () => {
20
+ const getterA = vi.fn(() => 1);
21
+ const getterB = vi.fn(() => 2);
22
+ const props = {
23
+ get a() {
24
+ return getterA();
25
+ },
26
+ get b() {
27
+ return getterB();
28
+ },
29
+ c: 3
30
+ };
31
+ const [ab, rest] = splitProps(props, ["a", "b"]);
32
+ expect(getterA).not.toHaveBeenCalled();
33
+ expect(getterB).not.toHaveBeenCalled();
34
+ expect(ab.a).toBe(1);
35
+ expect(getterA).toHaveBeenCalledTimes(1);
36
+ expect(ab.b).toBe(2);
37
+ expect(getterB).toHaveBeenCalledTimes(1);
38
+ expect(rest).toEqual({
39
+ c: 3
40
+ });
41
+ });
42
+ it("splits reactive props without observing them initially", () => {
43
+ const props = reactive({
44
+ a: 1,
45
+ b: 2,
46
+ c: 3
47
+ });
48
+ const [ab, rest] = splitProps(props, ["a", "b"]);
49
+ expect(ab.a).toBe(1);
50
+ expect(ab.b).toBe(2);
51
+ expect(rest.c).toBe(3);
52
+ });
53
+ it("ensures effect is not triggered by splitProps but by accessing reactive props", () => {
54
+ const props = reactive({
55
+ a: 1,
56
+ b: 2,
57
+ c: 3
58
+ });
59
+ let splits;
60
+ const splitEffect = vi.fn(() => {
61
+ splits = splitProps(props, ["a", "b"]);
62
+ });
63
+ effect(splitEffect);
64
+ expect(splitEffect).toHaveBeenCalledTimes(1);
65
+ const observeEffect = vi.fn(() => {
66
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
67
+ splits[0].a;
68
+ });
69
+ effect(observeEffect);
70
+ expect(observeEffect).toHaveBeenCalledTimes(1);
71
+ props.a = 2;
72
+ expect(splitEffect).toHaveBeenCalledTimes(1);
73
+ expect(observeEffect).toHaveBeenCalledTimes(2);
74
+ splits[0].a = 3;
75
+ expect(splitEffect).toHaveBeenCalledTimes(1);
76
+ expect(observeEffect).toHaveBeenCalledTimes(3);
77
+ });
@@ -0,0 +1,34 @@
1
+ import { stc } from "@alloy-js/core";
2
+ import { hbr, indent, Indent } from "@alloy-js/core/stc";
3
+ import { describe, expect, it } from "vitest";
4
+ import "../testing/extend-expect.js";
5
+ it("is applied by output", () => {
6
+ function Foo() {
7
+ return "Foo component";
8
+ }
9
+ const FooStc = stc(Foo);
10
+ expect([FooStc(), Indent().code`
11
+ child!
12
+ child2!
13
+ `]).toRenderTo(`
14
+ Foo component
15
+ child!
16
+ child2!
17
+ `);
18
+ });
19
+ describe("works with formatting", () => {
20
+ it("handles lines", () => {
21
+ expect(["foo", hbr(), "bar", hbr(), "baz"]).toRenderTo(`
22
+ foo
23
+ bar
24
+ baz
25
+ `);
26
+ });
27
+ it("handles indents", () => {
28
+ expect(["foo", indent().children([hbr(), "bar", hbr(), "baz"])]).toRenderTo(`
29
+ foo
30
+ bar
31
+ baz
32
+ `);
33
+ });
34
+ });