@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
@@ -1,242 +1,242 @@
1
- import { ATTRIBUTE_DELIMITERS, SLOT_HTML } from '../constants';
2
- import { PACKAGE_NAME, TYPES } from './constants';
3
-
4
-
5
- type NodePath = ('firstChild' | 'firstElementChild' | 'nextElementSibling' | 'nextSibling')[];
6
-
7
-
8
- const NODE_CLOSING = 1;
9
-
10
- const NODE_COMMENT = 2;
11
-
12
- const NODE_ELEMENT = 3;
13
-
14
- const NODE_SLOT = 4;
15
-
16
- const NODE_VOID = 5;
17
-
18
- const NODE_WHITELIST: Record<string, number> = {
19
- '!': NODE_COMMENT,
20
- '/': NODE_CLOSING
21
- };
22
-
23
- const REGEX_CLEANUP_WHITESPACE = /\s+/g;
24
-
25
- const REGEX_EMPTY_ATTRIBUTES = /\s+[\w:-]+\s*=\s*["']\s*["']|\s+(?=>)/g;
26
-
27
- const REGEX_EMPTY_TEXT_NODES = /(>|}|\s)\s+(<|{|\s)/g;
28
-
29
- const REGEX_EVENTS = /(?:\s*on[\w-:]+\s*=(?:\s*["'][^"']*["'])*)/g;
30
-
31
- const REGEX_SLOT_ATTRIBUTES = /<[\w-]+([^><]*{{\$}}[^><]*)>/g;
32
-
33
- const REGEX_SLOT_NODES = /<([\w-]+|[\/!])(?:([^><]*{{\$}}[^><]*)|(?:[^><]*))?>|{{\$}}/g;
34
-
35
- const SLOT_MARKER = '{{$}}';
36
-
37
-
38
- [
39
- // html
40
- 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
41
- 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr',
42
-
43
- // svg
44
- 'animate', 'animateMotion', 'animateTransform', 'circle', 'ellipse',
45
- 'feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix',
46
- 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood',
47
- 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMergeNode',
48
- 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence',
49
- 'hatch', 'hatchpath', 'image', 'line', 'mpath', 'path', 'polygon', 'polyline',
50
- 'rect', 'set', 'stop', 'use', 'view'
51
- ].map(tag => NODE_WHITELIST[tag] = NODE_VOID);
52
-
53
-
54
- function methods(children: number, copy: NodePath, first: NodePath[number], next: NodePath[number]) {
55
- let length = copy.length,
56
- result: NodePath = new Array(length + 1 + children);
57
-
58
- for (let i = 0, n = length; i < n; i++) {
59
- result[i] = copy[i];
60
- }
61
-
62
- result[length] = first;
63
-
64
- for (let i = 0, n = children; i < n; i++) {
65
- result[length + 1 + i] = next;
66
- }
67
-
68
- return result;
69
- }
70
-
71
-
72
- const parse = (literals: string[]) => {
73
- let html = literals
74
- .join(SLOT_MARKER)
75
- .replace(REGEX_EMPTY_TEXT_NODES, '$1$2')
76
- .replace(REGEX_CLEANUP_WHITESPACE, ' ')
77
- .trim(),
78
- n = literals.length - 1;
79
-
80
- if (n === 0) {
81
- return { html, slots: null };
82
- }
83
-
84
- let attributes: Record<string, { names: string[], static: Record<string, string> }> = {},
85
- buffer = '',
86
- index = 0,
87
- level = 0,
88
- levels = [{ children: 0, elements: 0, path: [] as NodePath }],
89
- parsed = html.split(SLOT_MARKER),
90
- slot = 0,
91
- slots: (
92
- { path: NodePath; type: TYPES.Node } |
93
- { attributes: typeof attributes[string]; path: NodePath; type: TYPES.Attribute }
94
- )[] = [];
95
-
96
- {
97
- let attribute = '',
98
- buffer = '',
99
- char = '',
100
- quote = '';
101
-
102
- for (let match of html.matchAll(REGEX_SLOT_ATTRIBUTES)) {
103
- let found = match[1];
104
-
105
- if (attributes[found]) {
106
- continue;
107
- }
108
-
109
- let { names, static: s } = attributes[found] = { names: [], static: {} } as typeof attributes[string];
110
-
111
- for (let i = 0, n = found.length; i < n; i++) {
112
- char = found[i];
113
-
114
- if (char === ' ') {
115
- if (attribute && attribute in ATTRIBUTE_DELIMITERS) {
116
- s[attribute] ??= '';
117
- s[attribute] += `${buffer && s[attribute] ? ATTRIBUTE_DELIMITERS[attribute] : ''}${buffer}`;
118
- }
119
-
120
- buffer = '';
121
- }
122
- else if (char === '=') {
123
- attribute = buffer;
124
- buffer = '';
125
- }
126
- else if (char === '"' || char === "'") {
127
- if (!attribute) {
128
- continue;
129
- }
130
- else if (!quote) {
131
- quote = char;
132
- }
133
- else if (quote === char) {
134
- if (attribute && attribute in ATTRIBUTE_DELIMITERS) {
135
- s[attribute] ??= '';
136
- s[attribute] += `${buffer && s[attribute] ? ATTRIBUTE_DELIMITERS[attribute] : ''}${buffer}`;
137
- }
138
-
139
- attribute = '';
140
- buffer = '';
141
- quote = '';
142
- }
143
- }
144
- else if (char === '{' && char !== buffer) {
145
- buffer = char;
146
- }
147
- else {
148
- buffer += char;
149
-
150
- if (buffer === SLOT_MARKER) {
151
- buffer = '';
152
-
153
- if (attribute) {
154
- names.push(attribute);
155
-
156
- if (!quote) {
157
- attribute = '';
158
- }
159
- }
160
- else {
161
- names.push(TYPES.Attributes);
162
- }
163
- }
164
- }
165
- }
166
- }
167
- }
168
-
169
- {
170
- for (let match of html.matchAll(REGEX_SLOT_NODES)) {
171
- let parent = levels[level],
172
- type = match[1] === undefined ? NODE_SLOT : (
173
- NODE_WHITELIST[match[1].toLowerCase()] ||
174
- (match[0].at(-2) === '/' ? NODE_VOID : NODE_ELEMENT)
175
- );
176
-
177
- if ((match.index || 1) - 1 > index) {
178
- parent.children++;
179
- }
180
-
181
- if (type === NODE_ELEMENT || type === NODE_VOID) {
182
- let attr = match[2],
183
- path = parent.path.length
184
- ? methods(parent.elements, parent.path, 'firstElementChild', 'nextElementSibling')
185
- : methods(parent.children, [], 'firstChild', 'nextSibling');
186
-
187
- if (attr) {
188
- let attrs = attributes[attr];
189
-
190
- if (!attrs) {
191
- throw new Error(`${PACKAGE_NAME}: attribute metadata could not be found for '${attr}'`);
192
- }
193
-
194
- slots.push({ attributes: attrs, path, type: TYPES.Attribute });
195
-
196
- for (let i = 0, n = attrs.names.length; i < n; i++) {
197
- buffer += parsed[slot++];
198
- }
199
- }
200
-
201
- if (type === NODE_ELEMENT) {
202
- levels[++level] = { children: 0, elements: 0, path };
203
- }
204
-
205
- parent.elements++;
206
- }
207
- else if (type === NODE_SLOT) {
208
- buffer += parsed[slot++] + SLOT_HTML;
209
- slots.push({
210
- path: methods(parent.children, parent.path, 'firstChild', 'nextSibling'),
211
- type: TYPES.Node
212
- });
213
- }
214
-
215
- if (n === slot) {
216
- buffer += parsed[slot];
217
- break;
218
- }
219
-
220
- if (type === NODE_CLOSING) {
221
- level--;
222
- }
223
- else {
224
- parent.children++;
225
- }
226
-
227
- index = (match.index || 0) + match[0].length;
228
- }
229
- }
230
-
231
- buffer = buffer
232
- .replace(REGEX_EVENTS, '')
233
- .replace(REGEX_EMPTY_ATTRIBUTES, '');
234
-
235
- return {
236
- html: buffer,
237
- slots: slots.length ? slots : null
238
- };
239
- };
240
-
241
-
242
- export default { parse };
1
+ import { ATTRIBUTE_DELIMITERS, SLOT_HTML } from '../constants';
2
+ import { PACKAGE_NAME, TYPES } from './constants';
3
+
4
+
5
+ type NodePath = ('firstChild' | 'firstElementChild' | 'nextElementSibling' | 'nextSibling')[];
6
+
7
+
8
+ const NODE_CLOSING = 1;
9
+
10
+ const NODE_COMMENT = 2;
11
+
12
+ const NODE_ELEMENT = 3;
13
+
14
+ const NODE_SLOT = 4;
15
+
16
+ const NODE_VOID = 5;
17
+
18
+ const NODE_WHITELIST: Record<string, number> = {
19
+ '!': NODE_COMMENT,
20
+ '/': NODE_CLOSING
21
+ };
22
+
23
+ const REGEX_CLEANUP_WHITESPACE = /\s+/g;
24
+
25
+ const REGEX_EMPTY_ATTRIBUTES = /\s+[\w:-]+\s*=\s*["']\s*["']|\s+(?=>)/g;
26
+
27
+ const REGEX_EMPTY_TEXT_NODES = /(>|}|\s)\s+(<|{|\s)/g;
28
+
29
+ const REGEX_EVENTS = /(?:\s*on[\w-:]+\s*=(?:\s*["'][^"']*["'])*)/g;
30
+
31
+ const REGEX_SLOT_ATTRIBUTES = /<[\w-]+([^><]*{{\$}}[^><]*)>/g;
32
+
33
+ const REGEX_SLOT_NODES = /<([\w-]+|[\/!])(?:([^><]*{{\$}}[^><]*)|(?:[^><]*))?>|{{\$}}/g;
34
+
35
+ const SLOT_MARKER = '{{$}}';
36
+
37
+
38
+ [
39
+ // html
40
+ 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
41
+ 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr',
42
+
43
+ // svg
44
+ 'animate', 'animateMotion', 'animateTransform', 'circle', 'ellipse',
45
+ 'feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix',
46
+ 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood',
47
+ 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMergeNode',
48
+ 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence',
49
+ 'hatch', 'hatchpath', 'image', 'line', 'mpath', 'path', 'polygon', 'polyline',
50
+ 'rect', 'set', 'stop', 'use', 'view'
51
+ ].map(tag => NODE_WHITELIST[tag] = NODE_VOID);
52
+
53
+
54
+ function methods(children: number, copy: NodePath, first: NodePath[number], next: NodePath[number]) {
55
+ let length = copy.length,
56
+ result: NodePath = new Array(length + 1 + children);
57
+
58
+ for (let i = 0, n = length; i < n; i++) {
59
+ result[i] = copy[i];
60
+ }
61
+
62
+ result[length] = first;
63
+
64
+ for (let i = 0, n = children; i < n; i++) {
65
+ result[length + 1 + i] = next;
66
+ }
67
+
68
+ return result;
69
+ }
70
+
71
+
72
+ const parse = (literals: string[]) => {
73
+ let html = literals
74
+ .join(SLOT_MARKER)
75
+ .replace(REGEX_EMPTY_TEXT_NODES, '$1$2')
76
+ .replace(REGEX_CLEANUP_WHITESPACE, ' ')
77
+ .trim(),
78
+ n = literals.length - 1;
79
+
80
+ if (n === 0) {
81
+ return { html, slots: null };
82
+ }
83
+
84
+ let attributes: Record<string, { names: string[], static: Record<string, string> }> = {},
85
+ buffer = '',
86
+ index = 0,
87
+ level = 0,
88
+ levels = [{ children: 0, elements: 0, path: [] as NodePath }],
89
+ parsed = html.split(SLOT_MARKER),
90
+ slot = 0,
91
+ slots: (
92
+ { path: NodePath; type: TYPES.Node } |
93
+ { attributes: typeof attributes[string]; path: NodePath; type: TYPES.Attribute }
94
+ )[] = [];
95
+
96
+ {
97
+ let attribute = '',
98
+ buffer = '',
99
+ char = '',
100
+ quote = '';
101
+
102
+ for (let match of html.matchAll(REGEX_SLOT_ATTRIBUTES)) {
103
+ let found = match[1];
104
+
105
+ if (attributes[found]) {
106
+ continue;
107
+ }
108
+
109
+ let { names, static: s } = attributes[found] = { names: [], static: {} } as typeof attributes[string];
110
+
111
+ for (let i = 0, n = found.length; i < n; i++) {
112
+ char = found[i];
113
+
114
+ if (char === ' ') {
115
+ if (attribute && attribute in ATTRIBUTE_DELIMITERS) {
116
+ s[attribute] ??= '';
117
+ s[attribute] += `${buffer && s[attribute] ? ATTRIBUTE_DELIMITERS[attribute] : ''}${buffer}`;
118
+ }
119
+
120
+ buffer = '';
121
+ }
122
+ else if (char === '=') {
123
+ attribute = buffer;
124
+ buffer = '';
125
+ }
126
+ else if (char === '"' || char === "'") {
127
+ if (!attribute) {
128
+ continue;
129
+ }
130
+ else if (!quote) {
131
+ quote = char;
132
+ }
133
+ else if (quote === char) {
134
+ if (attribute && attribute in ATTRIBUTE_DELIMITERS) {
135
+ s[attribute] ??= '';
136
+ s[attribute] += `${buffer && s[attribute] ? ATTRIBUTE_DELIMITERS[attribute] : ''}${buffer}`;
137
+ }
138
+
139
+ attribute = '';
140
+ buffer = '';
141
+ quote = '';
142
+ }
143
+ }
144
+ else if (char === '{' && char !== buffer) {
145
+ buffer = char;
146
+ }
147
+ else {
148
+ buffer += char;
149
+
150
+ if (buffer === SLOT_MARKER) {
151
+ buffer = '';
152
+
153
+ if (attribute) {
154
+ names.push(attribute);
155
+
156
+ if (!quote) {
157
+ attribute = '';
158
+ }
159
+ }
160
+ else {
161
+ names.push(TYPES.Attributes);
162
+ }
163
+ }
164
+ }
165
+ }
166
+ }
167
+ }
168
+
169
+ {
170
+ for (let match of html.matchAll(REGEX_SLOT_NODES)) {
171
+ let parent = levels[level],
172
+ type = match[1] === undefined ? NODE_SLOT : (
173
+ NODE_WHITELIST[match[1].toLowerCase()] ||
174
+ (match[0].at(-2) === '/' ? NODE_VOID : NODE_ELEMENT)
175
+ );
176
+
177
+ if ((match.index || 1) - 1 > index) {
178
+ parent.children++;
179
+ }
180
+
181
+ if (type === NODE_ELEMENT || type === NODE_VOID) {
182
+ let attr = match[2],
183
+ path = parent.path.length
184
+ ? methods(parent.elements, parent.path, 'firstElementChild', 'nextElementSibling')
185
+ : methods(parent.children, [], 'firstChild', 'nextSibling');
186
+
187
+ if (attr) {
188
+ let attrs = attributes[attr];
189
+
190
+ if (!attrs) {
191
+ throw new Error(`${PACKAGE_NAME}: attribute metadata could not be found for '${attr}'`);
192
+ }
193
+
194
+ slots.push({ attributes: attrs, path, type: TYPES.Attribute });
195
+
196
+ for (let i = 0, n = attrs.names.length; i < n; i++) {
197
+ buffer += parsed[slot++];
198
+ }
199
+ }
200
+
201
+ if (type === NODE_ELEMENT) {
202
+ levels[++level] = { children: 0, elements: 0, path };
203
+ }
204
+
205
+ parent.elements++;
206
+ }
207
+ else if (type === NODE_SLOT) {
208
+ buffer += parsed[slot++] + SLOT_HTML;
209
+ slots.push({
210
+ path: methods(parent.children, parent.path, 'firstChild', 'nextSibling'),
211
+ type: TYPES.Node
212
+ });
213
+ }
214
+
215
+ if (n === slot) {
216
+ buffer += parsed[slot];
217
+ break;
218
+ }
219
+
220
+ if (type === NODE_CLOSING) {
221
+ level--;
222
+ }
223
+ else {
224
+ parent.children++;
225
+ }
226
+
227
+ index = (match.index || 0) + match[0].length;
228
+ }
229
+ }
230
+
231
+ buffer = buffer
232
+ .replace(REGEX_EVENTS, '')
233
+ .replace(REGEX_EMPTY_ATTRIBUTES, '');
234
+
235
+ return {
236
+ html: buffer,
237
+ slots: slots.length ? slots : null
238
+ };
239
+ };
240
+
241
+
242
+ export default { parse };
@@ -1,6 +1,6 @@
1
- import { plugin } from '@esportsplus/typescript/compiler';
2
- import reactivity from '@esportsplus/reactivity/compiler';
3
- import template from '..';
4
-
5
-
6
- export default plugin.tsc([reactivity, template]) as ReturnType<typeof plugin.tsc>;
1
+ import { plugin } from '@esportsplus/typescript/compiler';
2
+ import reactivity from '@esportsplus/reactivity/compiler';
3
+ import template from '..';
4
+
5
+
6
+ export default plugin.tsc([reactivity, template]) as ReturnType<typeof plugin.tsc>;
@@ -1,10 +1,10 @@
1
- import { plugin } from '@esportsplus/typescript/compiler';
2
- import { PACKAGE_NAME } from '../constants';
3
- import reactivity from '@esportsplus/reactivity/compiler';
4
- import template from '..';
5
-
6
-
7
- export default plugin.vite({
8
- name: PACKAGE_NAME,
9
- plugins: [reactivity, template]
10
- });
1
+ import { plugin } from '@esportsplus/typescript/compiler';
2
+ import { PACKAGE_NAME } from '../constants';
3
+ import reactivity from '@esportsplus/reactivity/compiler';
4
+ import template from '..';
5
+
6
+
7
+ export default plugin.vite({
8
+ name: PACKAGE_NAME,
9
+ plugins: [reactivity, template]
10
+ });