@esportsplus/template 0.16.0 → 0.16.2

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 (53) hide show
  1. package/.editorconfig +9 -9
  2. package/.gitattributes +2 -2
  3. package/.github/dependabot.yml +24 -24
  4. package/.github/workflows/bump.yml +8 -8
  5. package/.github/workflows/dependabot.yml +11 -11
  6. package/.github/workflows/publish.yml +16 -16
  7. package/README.md +385 -385
  8. package/build/compiler/codegen.js +9 -9
  9. package/build/compiler/index.js +3 -3
  10. package/{src/llm.txt → llm.txt} +403 -403
  11. package/package.json +10 -3
  12. package/src/attributes.ts +312 -312
  13. package/src/compiler/codegen.ts +492 -492
  14. package/src/compiler/constants.ts +24 -24
  15. package/src/compiler/index.ts +87 -87
  16. package/src/compiler/parser.ts +242 -242
  17. package/src/compiler/plugins/tsc.ts +6 -6
  18. package/src/compiler/plugins/vite.ts +10 -10
  19. package/src/compiler/ts-analyzer.ts +89 -89
  20. package/src/compiler/ts-parser.ts +112 -112
  21. package/src/constants.ts +44 -44
  22. package/src/event/index.ts +130 -130
  23. package/src/event/onconnect.ts +22 -22
  24. package/src/event/onresize.ts +37 -37
  25. package/src/event/ontick.ts +59 -59
  26. package/src/html.ts +18 -18
  27. package/src/index.ts +18 -18
  28. package/src/render.ts +13 -13
  29. package/src/slot/array.ts +257 -257
  30. package/src/slot/cleanup.ts +37 -37
  31. package/src/slot/effect.ts +114 -114
  32. package/src/slot/index.ts +16 -16
  33. package/src/slot/render.ts +61 -61
  34. package/src/svg.ts +27 -27
  35. package/src/types.ts +40 -40
  36. package/src/utilities.ts +53 -53
  37. package/test/attributes.test.ts +311 -0
  38. package/test/compiler/parser.test.ts +402 -0
  39. package/test/compiler/ts-analyzer.test.ts +296 -0
  40. package/test/constants.test.ts +153 -0
  41. package/test/event/index.test.ts +359 -0
  42. package/test/html.test.ts +33 -0
  43. package/test/index.ts +648 -648
  44. package/test/render.test.ts +154 -0
  45. package/test/slot/array.test.ts +475 -0
  46. package/test/slot/cleanup.test.ts +243 -0
  47. package/test/slot/effect.test.ts +263 -0
  48. package/test/slot/index.test.ts +176 -0
  49. package/test/slot/render.test.ts +216 -0
  50. package/test/svg.test.ts +92 -0
  51. package/test/utilities.test.ts +242 -0
  52. package/tsconfig.json +8 -8
  53. package/vitest.config.ts +21 -0
@@ -0,0 +1,311 @@
1
+ import { describe, expect, it, beforeEach } from 'vitest';
2
+ import { setList, setProperty, setProperties } from '../src/attributes';
3
+ import type { Element } from '../src/types';
4
+
5
+
6
+ describe('attributes', () => {
7
+ let element: HTMLElement & Record<symbol, unknown>;
8
+
9
+ beforeEach(() => {
10
+ element = document.createElement('div') as HTMLElement & Record<symbol, unknown>;
11
+ });
12
+
13
+ describe('setProperty', () => {
14
+ it('sets string property', () => {
15
+ setProperty(element as unknown as Element, 'id', 'test-id');
16
+
17
+ expect(element.id).toBe('test-id');
18
+ });
19
+
20
+ it('sets numeric property as attribute', () => {
21
+ setProperty(element as unknown as Element, 'data-count', 42);
22
+
23
+ expect(element.getAttribute('data-count')).toBe('42');
24
+ });
25
+
26
+ it('sets boolean true property', () => {
27
+ let input = document.createElement('input') as HTMLInputElement & Record<symbol, unknown>;
28
+
29
+ setProperty(input as unknown as Element, 'disabled', true);
30
+
31
+ expect(input.disabled).toBe(true);
32
+ });
33
+
34
+ it('removes attribute for null value', () => {
35
+ element.setAttribute('data-test', 'value');
36
+ setProperty(element as unknown as Element, 'data-test', null);
37
+
38
+ expect(element.hasAttribute('data-test')).toBe(false);
39
+ });
40
+
41
+ it('removes attribute for false value', () => {
42
+ element.setAttribute('data-test', 'value');
43
+ setProperty(element as unknown as Element, 'data-test', false);
44
+
45
+ expect(element.hasAttribute('data-test')).toBe(false);
46
+ });
47
+
48
+ it('removes attribute for empty string', () => {
49
+ element.setAttribute('data-test', 'value');
50
+ setProperty(element as unknown as Element, 'data-test', '');
51
+
52
+ expect(element.hasAttribute('data-test')).toBe(false);
53
+ });
54
+
55
+ it('sets className for class property', () => {
56
+ setProperty(element as unknown as Element, 'class', 'my-class');
57
+
58
+ expect(element.className).toBe('my-class');
59
+ });
60
+
61
+ it('sets style attribute', () => {
62
+ setProperty(element as unknown as Element, 'style', 'color: red');
63
+
64
+ expect(element.getAttribute('style')).toBe('color: red');
65
+ });
66
+
67
+ it('sets data-* attributes via setAttribute', () => {
68
+ setProperty(element as unknown as Element, 'data-value', 'test');
69
+
70
+ expect(element.getAttribute('data-value')).toBe('test');
71
+ });
72
+
73
+ it('handles SVG elements via ownerSVGElement check', () => {
74
+ let rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect') as SVGRectElement;
75
+ let svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg') as SVGSVGElement;
76
+
77
+ svg.appendChild(rect);
78
+
79
+ setProperty(rect as unknown as Element, 'width', '100');
80
+
81
+ expect(rect.getAttribute('width')).toBe('100');
82
+ });
83
+ });
84
+
85
+ describe('setList', () => {
86
+ it('applies class list from string', () => {
87
+ setList(element as unknown as Element, 'class', 'foo bar baz');
88
+
89
+ // Class values are applied to className
90
+ expect(element.className).toContain('foo');
91
+ expect(element.className).toContain('bar');
92
+ expect(element.className).toContain('baz');
93
+ });
94
+
95
+ it('merges static and dynamic classes', () => {
96
+ setList(element as unknown as Element, 'class', 'dynamic', { class: 'static' });
97
+
98
+ expect(element.className).toBe('static dynamic');
99
+ });
100
+
101
+ it('applies style list from string', () => {
102
+ setList(element as unknown as Element, 'style', 'color: red');
103
+
104
+ expect(element.getAttribute('style')).toContain('color');
105
+ });
106
+
107
+ it('merges static and dynamic styles', () => {
108
+ setList(element as unknown as Element, 'style', 'font-size: 14px', { style: 'color: red' });
109
+
110
+ expect(element.getAttribute('style')).toBe('color: red;font-size: 14px');
111
+ });
112
+
113
+ it('handles null value', () => {
114
+ setList(element as unknown as Element, 'class', null);
115
+
116
+ expect(element.className).toBe('');
117
+ });
118
+
119
+ it('handles false value', () => {
120
+ setList(element as unknown as Element, 'class', false);
121
+
122
+ expect(element.className).toBe('');
123
+ });
124
+
125
+ it('handles empty string value', () => {
126
+ setList(element as unknown as Element, 'class', '');
127
+
128
+ expect(element.className).toBe('');
129
+ });
130
+
131
+ it('handles array of values', () => {
132
+ setList(element as unknown as Element, 'class', ['foo', 'bar', 'baz']);
133
+
134
+ expect(element.className).toContain('foo');
135
+ expect(element.className).toContain('bar');
136
+ expect(element.className).toContain('baz');
137
+ });
138
+
139
+ it('filters null/false/empty from array', () => {
140
+ setList(element as unknown as Element, 'class', ['foo', null, 'bar', false, '', 'baz']);
141
+
142
+ expect(element.className).toContain('foo');
143
+ expect(element.className).toContain('bar');
144
+ expect(element.className).toContain('baz');
145
+ });
146
+
147
+ it('applies whitespace-padded class values', () => {
148
+ setList(element as unknown as Element, 'class', ' foo bar ');
149
+
150
+ expect(element.className).toContain('foo');
151
+ expect(element.className).toContain('bar');
152
+ });
153
+
154
+ it('handles style with semicolons', () => {
155
+ setList(element as unknown as Element, 'style', 'color: red; font-size: 14px;');
156
+
157
+ expect(element.getAttribute('style')).toContain('color: red');
158
+ expect(element.getAttribute('style')).toContain('font-size: 14px');
159
+ });
160
+ });
161
+
162
+ describe('setProperties', () => {
163
+ it('sets multiple properties from object', () => {
164
+ setProperties(element as unknown as Element, {
165
+ 'data-one': 'value1',
166
+ 'data-two': 'value2',
167
+ id: 'my-id'
168
+ });
169
+
170
+ expect(element.id).toBe('my-id');
171
+ expect(element.getAttribute('data-one')).toBe('value1');
172
+ expect(element.getAttribute('data-two')).toBe('value2');
173
+ });
174
+
175
+ it('handles null properties object', () => {
176
+ setProperties(element as unknown as Element, null);
177
+
178
+ expect(element.attributes.length).toBe(0);
179
+ });
180
+
181
+ it('handles undefined properties object', () => {
182
+ setProperties(element as unknown as Element, undefined);
183
+
184
+ expect(element.attributes.length).toBe(0);
185
+ });
186
+
187
+ it('handles false properties object', () => {
188
+ setProperties(element as unknown as Element, false);
189
+
190
+ expect(element.attributes.length).toBe(0);
191
+ });
192
+
193
+ it('filters null property values', () => {
194
+ setProperties(element as unknown as Element, {
195
+ 'data-keep': 'value',
196
+ 'data-skip': null as unknown as string
197
+ });
198
+
199
+ expect(element.getAttribute('data-keep')).toBe('value');
200
+ expect(element.hasAttribute('data-skip')).toBe(false);
201
+ });
202
+
203
+ it('filters false property values', () => {
204
+ setProperties(element as unknown as Element, {
205
+ 'data-keep': 'value',
206
+ 'data-skip': false as unknown as string
207
+ });
208
+
209
+ expect(element.getAttribute('data-keep')).toBe('value');
210
+ expect(element.hasAttribute('data-skip')).toBe(false);
211
+ });
212
+
213
+ it('filters empty string property values', () => {
214
+ setProperties(element as unknown as Element, {
215
+ 'data-keep': 'value',
216
+ 'data-skip': ''
217
+ });
218
+
219
+ expect(element.getAttribute('data-keep')).toBe('value');
220
+ expect(element.hasAttribute('data-skip')).toBe(false);
221
+ });
222
+
223
+ it('handles class property via setList', () => {
224
+ setProperties(element as unknown as Element, {
225
+ class: 'foo bar'
226
+ });
227
+
228
+ expect(element.className).toContain('foo');
229
+ expect(element.className).toContain('bar');
230
+ });
231
+
232
+ it('handles style property via setList', () => {
233
+ setProperties(element as unknown as Element, {
234
+ style: 'color: red'
235
+ });
236
+
237
+ expect(element.getAttribute('style')).toContain('color: red');
238
+ });
239
+
240
+ it('handles array of properties objects', () => {
241
+ setProperties(element as unknown as Element, [
242
+ { 'data-one': 'value1' },
243
+ { 'data-two': 'value2' }
244
+ ]);
245
+
246
+ expect(element.getAttribute('data-one')).toBe('value1');
247
+ expect(element.getAttribute('data-two')).toBe('value2');
248
+ });
249
+
250
+ it('later properties override earlier ones in array', () => {
251
+ setProperties(element as unknown as Element, [
252
+ { id: 'first' },
253
+ { id: 'second' }
254
+ ]);
255
+
256
+ expect(element.id).toBe('second');
257
+ });
258
+
259
+ it('handles nested arrays', () => {
260
+ setProperties(element as unknown as Element, [
261
+ [{ 'data-one': 'value1' }],
262
+ { 'data-two': 'value2' }
263
+ ] as unknown as Record<string, string>[]);
264
+
265
+ expect(element.getAttribute('data-one')).toBe('value1');
266
+ expect(element.getAttribute('data-two')).toBe('value2');
267
+ });
268
+
269
+ it('handles static attributes merge with class', () => {
270
+ setProperties(element as unknown as Element, { class: 'dynamic' }, { class: 'static' });
271
+
272
+ expect(element.className).toBe('static dynamic');
273
+ });
274
+
275
+ it('handles static attributes merge with style', () => {
276
+ setProperties(element as unknown as Element, { style: 'font-size: 14px' }, { style: 'color: red' });
277
+
278
+ expect(element.getAttribute('style')).toContain('color: red');
279
+ expect(element.getAttribute('style')).toContain('font-size: 14px');
280
+ });
281
+ });
282
+
283
+ describe('reactive functions', () => {
284
+ it('setProperty handles reactive function', async () => {
285
+ let value = 'initial';
286
+
287
+ setProperty(element as unknown as Element, 'id', () => value);
288
+
289
+ expect(element.id).toBe('initial');
290
+ });
291
+
292
+ it('setList handles reactive function for class', async () => {
293
+ let classes = 'foo bar';
294
+
295
+ setList(element as unknown as Element, 'class', () => classes);
296
+
297
+ // Reactive functions update the element className through the effect system
298
+ expect(element.className).toContain('foo');
299
+ expect(element.className).toContain('bar');
300
+ });
301
+
302
+ it('setList handles reactive function for style', async () => {
303
+ let style = 'color: red';
304
+
305
+ setList(element as unknown as Element, 'style', () => style);
306
+
307
+ // Reactive functions update the element style through the effect system
308
+ expect(element.getAttribute('style')).toContain('color');
309
+ });
310
+ });
311
+ });