@esportsplus/template 0.16.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 (90) hide show
  1. package/.editorconfig +9 -0
  2. package/.gitattributes +2 -0
  3. package/.github/dependabot.yml +25 -0
  4. package/.github/workflows/bump.yml +9 -0
  5. package/.github/workflows/dependabot.yml +12 -0
  6. package/.github/workflows/publish.yml +16 -0
  7. package/README.md +385 -0
  8. package/build/attributes.d.ts +5 -0
  9. package/build/attributes.js +212 -0
  10. package/build/compiler/codegen.d.ts +21 -0
  11. package/build/compiler/codegen.js +303 -0
  12. package/build/compiler/constants.d.ts +16 -0
  13. package/build/compiler/constants.js +19 -0
  14. package/build/compiler/index.d.ts +14 -0
  15. package/build/compiler/index.js +61 -0
  16. package/build/compiler/parser.d.ts +19 -0
  17. package/build/compiler/parser.js +164 -0
  18. package/build/compiler/plugins/tsc.d.ts +3 -0
  19. package/build/compiler/plugins/tsc.js +4 -0
  20. package/build/compiler/plugins/vite.d.ts +13 -0
  21. package/build/compiler/plugins/vite.js +8 -0
  22. package/build/compiler/ts-analyzer.d.ts +4 -0
  23. package/build/compiler/ts-analyzer.js +63 -0
  24. package/build/compiler/ts-parser.d.ts +24 -0
  25. package/build/compiler/ts-parser.js +67 -0
  26. package/build/constants.d.ts +12 -0
  27. package/build/constants.js +25 -0
  28. package/build/event/index.d.ts +10 -0
  29. package/build/event/index.js +90 -0
  30. package/build/event/onconnect.d.ts +3 -0
  31. package/build/event/onconnect.js +15 -0
  32. package/build/event/onresize.d.ts +3 -0
  33. package/build/event/onresize.js +26 -0
  34. package/build/event/ontick.d.ts +6 -0
  35. package/build/event/ontick.js +41 -0
  36. package/build/html.d.ts +9 -0
  37. package/build/html.js +7 -0
  38. package/build/index.d.ts +8 -0
  39. package/build/index.js +12 -0
  40. package/build/render.d.ts +3 -0
  41. package/build/render.js +8 -0
  42. package/build/slot/array.d.ts +25 -0
  43. package/build/slot/array.js +189 -0
  44. package/build/slot/cleanup.d.ts +4 -0
  45. package/build/slot/cleanup.js +23 -0
  46. package/build/slot/effect.d.ts +12 -0
  47. package/build/slot/effect.js +85 -0
  48. package/build/slot/index.d.ts +7 -0
  49. package/build/slot/index.js +14 -0
  50. package/build/slot/render.d.ts +2 -0
  51. package/build/slot/render.js +44 -0
  52. package/build/svg.d.ts +5 -0
  53. package/build/svg.js +14 -0
  54. package/build/types.d.ts +23 -0
  55. package/build/types.js +1 -0
  56. package/build/utilities.d.ts +7 -0
  57. package/build/utilities.js +31 -0
  58. package/package.json +43 -0
  59. package/src/attributes.ts +313 -0
  60. package/src/compiler/codegen.ts +492 -0
  61. package/src/compiler/constants.ts +25 -0
  62. package/src/compiler/index.ts +87 -0
  63. package/src/compiler/parser.ts +242 -0
  64. package/src/compiler/plugins/tsc.ts +6 -0
  65. package/src/compiler/plugins/vite.ts +10 -0
  66. package/src/compiler/ts-analyzer.ts +89 -0
  67. package/src/compiler/ts-parser.ts +112 -0
  68. package/src/constants.ts +44 -0
  69. package/src/event/index.ts +130 -0
  70. package/src/event/onconnect.ts +22 -0
  71. package/src/event/onresize.ts +37 -0
  72. package/src/event/ontick.ts +59 -0
  73. package/src/html.ts +18 -0
  74. package/src/index.ts +19 -0
  75. package/src/llm.txt +403 -0
  76. package/src/render.ts +13 -0
  77. package/src/slot/array.ts +257 -0
  78. package/src/slot/cleanup.ts +37 -0
  79. package/src/slot/effect.ts +114 -0
  80. package/src/slot/index.ts +17 -0
  81. package/src/slot/render.ts +61 -0
  82. package/src/svg.ts +27 -0
  83. package/src/types.ts +40 -0
  84. package/src/utilities.ts +53 -0
  85. package/storage/compiler-architecture-2026-01-13.md +420 -0
  86. package/test/dist/test.js +1912 -0
  87. package/test/dist/test.js.map +1 -0
  88. package/test/index.ts +648 -0
  89. package/test/vite.config.ts +23 -0
  90. package/tsconfig.json +8 -0
@@ -0,0 +1,303 @@
1
+ import { ast, uid } from '@esportsplus/typescript/compiler';
2
+ import { pick } from '@esportsplus/utilities';
3
+ import { analyze } from './ts-analyzer.js';
4
+ import { DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS } from '../constants.js';
5
+ import { ENTRYPOINT, ENTRYPOINT_REACTIVITY, NAMESPACE, TYPES } from './constants.js';
6
+ import { extractTemplateParts } from './ts-parser.js';
7
+ import { ts } from '@esportsplus/typescript';
8
+ import parser from './parser.js';
9
+ let printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
10
+ function collectNestedReplacements(ctx, node, replacements) {
11
+ if (isNestedHtmlTemplate(node)) {
12
+ replacements.push({
13
+ end: node.end,
14
+ start: node.getStart(ctx.sourceFile),
15
+ text: generateNestedTemplateCode(ctx, node)
16
+ });
17
+ return;
18
+ }
19
+ if (isReactiveCall(node)) {
20
+ let call = node;
21
+ replacements.push({
22
+ end: node.end,
23
+ start: node.getStart(ctx.sourceFile),
24
+ text: `new ${NAMESPACE}.ArraySlot(
25
+ ${rewriteExpression(ctx, call.arguments[0])},
26
+ ${rewriteExpression(ctx, call.arguments[1])}
27
+ )`
28
+ });
29
+ return;
30
+ }
31
+ ts.forEachChild(node, child => collectNestedReplacements(ctx, child, replacements));
32
+ }
33
+ function discoverTemplatesInExpression(ctx, node) {
34
+ if (isNestedHtmlTemplate(node)) {
35
+ let { expressions, literals } = extractTemplateParts(node.template), parsed = parser.parse(literals);
36
+ getTemplateID(ctx, parsed.html);
37
+ for (let i = 0, n = expressions.length; i < n; i++) {
38
+ discoverTemplatesInExpression(ctx, expressions[i]);
39
+ }
40
+ return;
41
+ }
42
+ ts.forEachChild(node, child => discoverTemplatesInExpression(ctx, child));
43
+ }
44
+ function generateAttributeBinding(element, name, expr, attributes) {
45
+ if (name.startsWith('on') && name.length > 2) {
46
+ let event = name.slice(2).toLowerCase(), key = name.toLowerCase();
47
+ if (LIFECYCLE_EVENTS.has(key)) {
48
+ return `${NAMESPACE}.${key}(${element}, ${expr});`;
49
+ }
50
+ if (DIRECT_ATTACH_EVENTS.has(key)) {
51
+ return `${NAMESPACE}.on(${element}, '${event}', ${expr});`;
52
+ }
53
+ return `${NAMESPACE}.delegate(${element}, '${event}', ${expr});`;
54
+ }
55
+ if (name === 'class' || name === 'style') {
56
+ return `${NAMESPACE}.setList(${element}, '${name}', ${expr}, ${attributes});`;
57
+ }
58
+ return `${NAMESPACE}.setProperty(${element}, '${name}', ${expr});`;
59
+ }
60
+ function generateNestedTemplateCode(ctx, node) {
61
+ let { expressions, literals } = extractTemplateParts(node.template), exprTexts = [];
62
+ for (let i = 0, n = expressions.length; i < n; i++) {
63
+ exprTexts.push(rewriteExpression(ctx, expressions[i]));
64
+ }
65
+ return generateTemplateCode(ctx, parser.parse(literals), exprTexts, expressions, node);
66
+ }
67
+ function generateNodeBinding(ctx, anchor, exprText, exprNode) {
68
+ if (!exprNode) {
69
+ return `${NAMESPACE}.slot(${anchor}, ${exprText});`;
70
+ }
71
+ if (isNestedHtmlTemplate(exprNode)) {
72
+ return `${anchor}.parentNode!.insertBefore(${generateNestedTemplateCode(ctx, exprNode)}, ${anchor});`;
73
+ }
74
+ switch (analyze(exprNode, ctx.checker)) {
75
+ case TYPES.ArraySlot:
76
+ return `${anchor}.parentNode!.insertBefore(new ${NAMESPACE}.ArraySlot(${exprText}).fragment, ${anchor});`;
77
+ case TYPES.DocumentFragment:
78
+ return `${anchor}.parentNode!.insertBefore(${exprText}, ${anchor});`;
79
+ case TYPES.Effect:
80
+ return `new ${NAMESPACE}.EffectSlot(${anchor}, ${exprText});`;
81
+ case TYPES.Static:
82
+ return `${anchor}.textContent = ${exprText};`;
83
+ default:
84
+ return `${NAMESPACE}.slot(${anchor}, ${exprText});`;
85
+ }
86
+ }
87
+ function generateTemplateCode(ctx, { html, slots }, exprTexts, exprNodes, templateNode) {
88
+ if (!slots || slots.length === 0) {
89
+ return `${getTemplateID(ctx, html)}()`;
90
+ }
91
+ let attributes = new Map(), code = [], declarations = [], index = 0, isArrowBody = isArrowExpressionBody(templateNode), nodes = new Map(), root = uid('root');
92
+ declarations.push(`${root} = ${getTemplateID(ctx, html)}()`);
93
+ nodes.set('', root);
94
+ for (let i = 0, n = slots.length; i < n; i++) {
95
+ let path = slots[i].path;
96
+ if (path.length === 0) {
97
+ continue;
98
+ }
99
+ let key = path.join('.');
100
+ if (nodes.has(key)) {
101
+ continue;
102
+ }
103
+ let ancestor = root, start = 0;
104
+ for (let j = path.length - 1; j >= 0; j--) {
105
+ let prefix = path.slice(0, j).join('.');
106
+ if (nodes.has(prefix)) {
107
+ ancestor = nodes.get(prefix);
108
+ start = j;
109
+ break;
110
+ }
111
+ }
112
+ let name = uid('element'), segments = path.slice(start), value = `${ancestor}.${segments.join('!.')}`;
113
+ if (ancestor === root && segments[0] === 'firstChild') {
114
+ value = value.replace(`${ancestor}.firstChild!`, `(${root}.firstChild! as ${NAMESPACE}.Element)`);
115
+ }
116
+ declarations.push(`${name} = ${value} as ${NAMESPACE}.Element`);
117
+ nodes.set(key, name);
118
+ }
119
+ code.push(isArrowBody ? '{' : `(() => {`);
120
+ for (let i = 0, n = slots.length; i < n; i++) {
121
+ let element = slots[i].path.length === 0
122
+ ? root
123
+ : (nodes.get(slots[i].path.join('.')) || root), slot = slots[i];
124
+ if (slot.type === TYPES.Attribute) {
125
+ let names = slot.attributes.names;
126
+ for (let j = 0, m = names.length; j < m; j++) {
127
+ let name = names[j];
128
+ if (name === TYPES.Attributes) {
129
+ let exprNode = exprNodes[index];
130
+ if (exprNode && ts.isObjectLiteralExpression(exprNode)) {
131
+ let canExpand = true, props = exprNode.properties;
132
+ for (let k = 0, p = props.length; k < p; k++) {
133
+ let prop = props[k];
134
+ if (ts.isSpreadAssignment(prop) ||
135
+ (ts.isPropertyAssignment(prop) && ts.isComputedPropertyName(prop.name)) ||
136
+ (ts.isShorthandPropertyAssignment(prop) && prop.objectAssignmentInitializer)) {
137
+ canExpand = false;
138
+ break;
139
+ }
140
+ }
141
+ if (canExpand) {
142
+ for (let k = 0, p = props.length; k < p; k++) {
143
+ let prop = props[k];
144
+ if (ts.isPropertyAssignment(prop)) {
145
+ let propName = ts.isIdentifier(prop.name)
146
+ ? prop.name.text
147
+ : ts.isStringLiteral(prop.name)
148
+ ? prop.name.text
149
+ : null;
150
+ if (propName) {
151
+ code.push(generateAttributeBinding(element, propName, rewriteExpression(ctx, prop.initializer), getAttributes(declarations, i, propName, slot, attributes)));
152
+ }
153
+ }
154
+ else if (ts.isShorthandPropertyAssignment(prop)) {
155
+ let propName = prop.name.text;
156
+ code.push(generateAttributeBinding(element, propName, propName, getAttributes(declarations, i, propName, slot, attributes)));
157
+ }
158
+ else if (ts.isMethodDeclaration(prop) && ts.isIdentifier(prop.name)) {
159
+ let propName = prop.name.text;
160
+ code.push(generateAttributeBinding(element, propName, printer.printNode(ts.EmitHint.Expression, prop, ctx.sourceFile), getAttributes(declarations, i, propName, slot, attributes)));
161
+ }
162
+ }
163
+ }
164
+ else {
165
+ code.push(`${NAMESPACE}.setProperties(
166
+ ${element}, ${exprTexts[index] || 'undefined'},
167
+ ${getAttributes(declarations, i, 'attributes', slot, attributes)}
168
+ );`);
169
+ }
170
+ }
171
+ else {
172
+ code.push(`${NAMESPACE}.setProperties(
173
+ ${element}, ${exprTexts[index] || 'undefined'},
174
+ ${getAttributes(declarations, i, 'attributes', slot, attributes)}
175
+ );`);
176
+ }
177
+ index++;
178
+ }
179
+ else {
180
+ code.push(generateAttributeBinding(element, name, exprTexts[index++] || 'undefined', getAttributes(declarations, i, name, slot, attributes)));
181
+ }
182
+ }
183
+ }
184
+ else {
185
+ code.push(generateNodeBinding(ctx, element, exprTexts[index] || 'undefined', exprNodes[index]));
186
+ index++;
187
+ }
188
+ }
189
+ code.splice(1, 0, `let ${declarations.join(',\n')};`);
190
+ code.push(`return ${root};`);
191
+ code.push(isArrowBody ? `}` : `})()`);
192
+ return code.join('\n');
193
+ }
194
+ function getAttributes(declarations, i, name, slot, attributes) {
195
+ if (name !== 'class' && name !== 'attributes' && name !== 'style') {
196
+ return undefined;
197
+ }
198
+ let attribute = attributes.get(i);
199
+ if (!attribute) {
200
+ declarations.push(`${attribute = uid('attributes')} = ${JSON.stringify(pick(slot.attributes.static, ['class', 'style']))}`);
201
+ attributes.set(i, attribute);
202
+ }
203
+ return attribute;
204
+ }
205
+ function getTemplateID(ctx, html) {
206
+ let id = ctx.templates.get(html);
207
+ if (!id) {
208
+ id = uid('template');
209
+ ctx.templates.set(html, id);
210
+ }
211
+ return id;
212
+ }
213
+ function isArrowExpressionBody(node) {
214
+ return ts.isArrowFunction(node.parent) && node.parent.body === node;
215
+ }
216
+ function isNestedHtmlTemplate(expr) {
217
+ return ts.isTaggedTemplateExpression(expr) && ts.isIdentifier(expr.tag) && expr.tag.text === ENTRYPOINT;
218
+ }
219
+ function isReactiveCall(expr) {
220
+ return (ts.isCallExpression(expr) &&
221
+ ts.isPropertyAccessExpression(expr.expression) &&
222
+ ts.isIdentifier(expr.expression.expression) &&
223
+ expr.expression.expression.text === ENTRYPOINT &&
224
+ expr.expression.name.text === ENTRYPOINT_REACTIVITY);
225
+ }
226
+ const generateCode = (templates, sourceFile, checker, callRanges = []) => {
227
+ let result = {
228
+ prepend: [],
229
+ replacements: [],
230
+ templates: new Map()
231
+ };
232
+ if (templates.length === 0) {
233
+ return result;
234
+ }
235
+ let ranges = [...callRanges];
236
+ for (let i = 0, n = templates.length; i < n; i++) {
237
+ let exprs = templates[i].expressions;
238
+ for (let j = 0, m = exprs.length; j < m; j++) {
239
+ ranges.push({ end: exprs[j].end, start: exprs[j].getStart(sourceFile) });
240
+ }
241
+ }
242
+ let root = templates.filter(t => !ast.inRange(ranges, t.node.getStart(sourceFile), t.node.end));
243
+ if (root.length === 0) {
244
+ return result;
245
+ }
246
+ let ctx = {
247
+ checker,
248
+ sourceFile,
249
+ templates: result.templates
250
+ };
251
+ for (let i = 0, n = root.length; i < n; i++) {
252
+ let exprTexts = [], parsed = parser.parse(root[i].literals), template = root[i];
253
+ for (let j = 0, m = template.expressions.length; j < m; j++) {
254
+ exprTexts.push(rewriteExpression(ctx, template.expressions[j]));
255
+ }
256
+ if (isArrowExpressionBody(template.node) &&
257
+ template.node.parent.parameters.length === 0 &&
258
+ (!parsed.slots || parsed.slots.length === 0)) {
259
+ let code = getTemplateID(ctx, parsed.html);
260
+ result.replacements.push({
261
+ generate: () => code,
262
+ node: template.node
263
+ });
264
+ }
265
+ else {
266
+ let code = generateTemplateCode(ctx, parsed, exprTexts, template.expressions, template.node);
267
+ result.replacements.push({
268
+ generate: () => code,
269
+ node: template.node
270
+ });
271
+ }
272
+ }
273
+ for (let i = 0, n = templates.length; i < n; i++) {
274
+ getTemplateID(ctx, parser.parse(templates[i].literals).html);
275
+ for (let j = 0, m = templates[i].expressions.length; j < m; j++) {
276
+ discoverTemplatesInExpression(ctx, templates[i].expressions[j]);
277
+ }
278
+ }
279
+ for (let [html, id] of ctx.templates) {
280
+ result.prepend.push(`const ${id} = ${NAMESPACE}.template(\`${html}\`);`);
281
+ }
282
+ return result;
283
+ };
284
+ const rewriteExpression = (ctx, expr) => {
285
+ if (isNestedHtmlTemplate(expr)) {
286
+ return generateNestedTemplateCode(ctx, expr);
287
+ }
288
+ if (isReactiveCall(expr)) {
289
+ return `${rewriteExpression(ctx, expr.arguments[0])}, ${rewriteExpression(ctx, expr.arguments[1])}`;
290
+ }
291
+ if (!ast.test(expr, n => isNestedHtmlTemplate(n) || isReactiveCall(n))) {
292
+ return printer.printNode(ts.EmitHint.Expression, expr, ctx.sourceFile);
293
+ }
294
+ let replacements = [], start = expr.getStart(ctx.sourceFile), text = expr.getText(ctx.sourceFile);
295
+ ts.forEachChild(expr, child => collectNestedReplacements(ctx, child, replacements));
296
+ replacements.sort((a, b) => b.start - a.start);
297
+ for (let i = 0, n = replacements.length; i < n; i++) {
298
+ let r = replacements[i];
299
+ text = text.slice(0, r.start - start) + r.text + text.slice(r.end - start);
300
+ }
301
+ return text;
302
+ };
303
+ export { generateCode, printer, rewriteExpression };
@@ -0,0 +1,16 @@
1
+ declare const ENTRYPOINT = "html";
2
+ declare const ENTRYPOINT_REACTIVITY = "reactive";
3
+ declare const NAMESPACE: string;
4
+ declare const enum TYPES {
5
+ ArraySlot = "array-slot",
6
+ Attributes = "attributes",
7
+ Attribute = "attribute",
8
+ DocumentFragment = "document-fragment",
9
+ Effect = "effect",
10
+ Node = "node",
11
+ Primitive = "primitive",
12
+ Static = "static",
13
+ Unknown = "unknown"
14
+ }
15
+ export { ENTRYPOINT, ENTRYPOINT_REACTIVITY, NAMESPACE, TYPES };
16
+ export { PACKAGE_NAME } from '../constants.js';
@@ -0,0 +1,19 @@
1
+ import { uid } from '@esportsplus/typescript/compiler';
2
+ const ENTRYPOINT = 'html';
3
+ const ENTRYPOINT_REACTIVITY = 'reactive';
4
+ const NAMESPACE = uid('template');
5
+ var TYPES;
6
+ (function (TYPES) {
7
+ TYPES["ArraySlot"] = "array-slot";
8
+ TYPES["Attributes"] = "attributes";
9
+ TYPES["Attribute"] = "attribute";
10
+ TYPES["DocumentFragment"] = "document-fragment";
11
+ TYPES["Effect"] = "effect";
12
+ TYPES["Node"] = "node";
13
+ TYPES["Primitive"] = "primitive";
14
+ TYPES["Static"] = "static";
15
+ TYPES["Unknown"] = "unknown";
16
+ })(TYPES || (TYPES = {}));
17
+ ;
18
+ export { ENTRYPOINT, ENTRYPOINT_REACTIVITY, NAMESPACE, TYPES };
19
+ export { PACKAGE_NAME } from '../constants.js';
@@ -0,0 +1,14 @@
1
+ import type { ImportIntent, ReplacementIntent, TransformContext } from '@esportsplus/typescript/compiler';
2
+ declare const _default: {
3
+ patterns: string[];
4
+ transform: (ctx: TransformContext) => {
5
+ imports?: undefined;
6
+ prepend?: undefined;
7
+ replacements?: undefined;
8
+ } | {
9
+ imports: ImportIntent[];
10
+ prepend: string[];
11
+ replacements: ReplacementIntent[];
12
+ };
13
+ };
14
+ export default _default;
@@ -0,0 +1,61 @@
1
+ import { ts } from '@esportsplus/typescript';
2
+ import { ast } from '@esportsplus/typescript/compiler';
3
+ import { ENTRYPOINT, ENTRYPOINT_REACTIVITY, NAMESPACE, PACKAGE_NAME } from './constants.js';
4
+ import { generateCode, printer, rewriteExpression } from './codegen.js';
5
+ import { findHtmlTemplates, findReactiveCalls } from './ts-parser.js';
6
+ export default {
7
+ patterns: [
8
+ `${ENTRYPOINT}\``,
9
+ `${ENTRYPOINT}.${ENTRYPOINT_REACTIVITY}`
10
+ ],
11
+ transform: (ctx) => {
12
+ let callRanges = [], callTemplates = new Map(), imports = [], prepend = [], ranges = [], remove = [], replacements = [], templates = findHtmlTemplates(ctx.sourceFile, ctx.checker);
13
+ for (let i = 0, n = templates.length; i < n; i++) {
14
+ ranges.push({
15
+ end: templates[i].end,
16
+ start: templates[i].start
17
+ });
18
+ }
19
+ let calls = findReactiveCalls(ctx.sourceFile, ctx.checker);
20
+ for (let i = 0, n = calls.length; i < n; i++) {
21
+ let call = calls[i];
22
+ if (ast.inRange(ranges, call.start, call.end)) {
23
+ continue;
24
+ }
25
+ callRanges.push({
26
+ end: call.callbackArg.end,
27
+ start: call.callbackArg.getStart(ctx.sourceFile)
28
+ });
29
+ let rewrittenCallback = rewriteExpression({
30
+ checker: ctx.checker,
31
+ sourceFile: ctx.sourceFile,
32
+ templates: callTemplates
33
+ }, call.callbackArg);
34
+ replacements.push({
35
+ generate: (sourceFile) => `new ${NAMESPACE}.ArraySlot(
36
+ ${printer.printNode(ts.EmitHint.Expression, call.arrayArg, sourceFile)},
37
+ ${rewrittenCallback}
38
+ )`,
39
+ node: call.node
40
+ });
41
+ }
42
+ for (let [html, id] of callTemplates) {
43
+ prepend.push(`const ${id} = ${NAMESPACE}.template(\`${html}\`);`);
44
+ }
45
+ if (templates.length > 0) {
46
+ let result = generateCode(templates, ctx.sourceFile, ctx.checker, callRanges);
47
+ prepend.push(...result.prepend);
48
+ replacements.push(...result.replacements);
49
+ remove.push(ENTRYPOINT);
50
+ }
51
+ if (replacements.length === 0 && prepend.length === 0) {
52
+ return {};
53
+ }
54
+ imports.push({
55
+ namespace: NAMESPACE,
56
+ package: PACKAGE_NAME,
57
+ remove: remove
58
+ });
59
+ return { imports, prepend, replacements };
60
+ }
61
+ };
@@ -0,0 +1,19 @@
1
+ import { TYPES } from './constants.js';
2
+ type NodePath = ('firstChild' | 'firstElementChild' | 'nextElementSibling' | 'nextSibling')[];
3
+ declare const _default: {
4
+ parse: (literals: string[]) => {
5
+ html: string;
6
+ slots: ({
7
+ path: NodePath;
8
+ type: TYPES.Node;
9
+ } | {
10
+ attributes: {
11
+ names: string[];
12
+ static: Record<string, string>;
13
+ };
14
+ path: NodePath;
15
+ type: TYPES.Attribute;
16
+ })[] | null;
17
+ };
18
+ };
19
+ export default _default;
@@ -0,0 +1,164 @@
1
+ import { ATTRIBUTE_DELIMITERS, SLOT_HTML } from '../constants.js';
2
+ import { PACKAGE_NAME, TYPES } from './constants.js';
3
+ const NODE_CLOSING = 1;
4
+ const NODE_COMMENT = 2;
5
+ const NODE_ELEMENT = 3;
6
+ const NODE_SLOT = 4;
7
+ const NODE_VOID = 5;
8
+ const NODE_WHITELIST = {
9
+ '!': NODE_COMMENT,
10
+ '/': NODE_CLOSING
11
+ };
12
+ const REGEX_CLEANUP_WHITESPACE = /\s+/g;
13
+ const REGEX_EMPTY_ATTRIBUTES = /\s+[\w:-]+\s*=\s*["']\s*["']|\s+(?=>)/g;
14
+ const REGEX_EMPTY_TEXT_NODES = /(>|}|\s)\s+(<|{|\s)/g;
15
+ const REGEX_EVENTS = /(?:\s*on[\w-:]+\s*=(?:\s*["'][^"']*["'])*)/g;
16
+ const REGEX_SLOT_ATTRIBUTES = /<[\w-]+([^><]*{{\$}}[^><]*)>/g;
17
+ const REGEX_SLOT_NODES = /<([\w-]+|[\/!])(?:([^><]*{{\$}}[^><]*)|(?:[^><]*))?>|{{\$}}/g;
18
+ const SLOT_MARKER = '{{$}}';
19
+ [
20
+ 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
21
+ 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr',
22
+ 'animate', 'animateMotion', 'animateTransform', 'circle', 'ellipse',
23
+ 'feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix',
24
+ 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood',
25
+ 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMergeNode',
26
+ 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence',
27
+ 'hatch', 'hatchpath', 'image', 'line', 'mpath', 'path', 'polygon', 'polyline',
28
+ 'rect', 'set', 'stop', 'use', 'view'
29
+ ].map(tag => NODE_WHITELIST[tag] = NODE_VOID);
30
+ function methods(children, copy, first, next) {
31
+ let length = copy.length, result = new Array(length + 1 + children);
32
+ for (let i = 0, n = length; i < n; i++) {
33
+ result[i] = copy[i];
34
+ }
35
+ result[length] = first;
36
+ for (let i = 0, n = children; i < n; i++) {
37
+ result[length + 1 + i] = next;
38
+ }
39
+ return result;
40
+ }
41
+ const parse = (literals) => {
42
+ let html = literals
43
+ .join(SLOT_MARKER)
44
+ .replace(REGEX_EMPTY_TEXT_NODES, '$1$2')
45
+ .replace(REGEX_CLEANUP_WHITESPACE, ' ')
46
+ .trim(), n = literals.length - 1;
47
+ if (n === 0) {
48
+ return { html, slots: null };
49
+ }
50
+ let attributes = {}, buffer = '', index = 0, level = 0, levels = [{ children: 0, elements: 0, path: [] }], parsed = html.split(SLOT_MARKER), slot = 0, slots = [];
51
+ {
52
+ let attribute = '', buffer = '', char = '', quote = '';
53
+ for (let match of html.matchAll(REGEX_SLOT_ATTRIBUTES)) {
54
+ let found = match[1];
55
+ if (attributes[found]) {
56
+ continue;
57
+ }
58
+ let { names, static: s } = attributes[found] = { names: [], static: {} };
59
+ for (let i = 0, n = found.length; i < n; i++) {
60
+ char = found[i];
61
+ if (char === ' ') {
62
+ if (attribute && attribute in ATTRIBUTE_DELIMITERS) {
63
+ s[attribute] ??= '';
64
+ s[attribute] += `${buffer && s[attribute] ? ATTRIBUTE_DELIMITERS[attribute] : ''}${buffer}`;
65
+ }
66
+ buffer = '';
67
+ }
68
+ else if (char === '=') {
69
+ attribute = buffer;
70
+ buffer = '';
71
+ }
72
+ else if (char === '"' || char === "'") {
73
+ if (!attribute) {
74
+ continue;
75
+ }
76
+ else if (!quote) {
77
+ quote = char;
78
+ }
79
+ else if (quote === char) {
80
+ if (attribute && attribute in ATTRIBUTE_DELIMITERS) {
81
+ s[attribute] ??= '';
82
+ s[attribute] += `${buffer && s[attribute] ? ATTRIBUTE_DELIMITERS[attribute] : ''}${buffer}`;
83
+ }
84
+ attribute = '';
85
+ buffer = '';
86
+ quote = '';
87
+ }
88
+ }
89
+ else if (char === '{' && char !== buffer) {
90
+ buffer = char;
91
+ }
92
+ else {
93
+ buffer += char;
94
+ if (buffer === SLOT_MARKER) {
95
+ buffer = '';
96
+ if (attribute) {
97
+ names.push(attribute);
98
+ if (!quote) {
99
+ attribute = '';
100
+ }
101
+ }
102
+ else {
103
+ names.push(TYPES.Attributes);
104
+ }
105
+ }
106
+ }
107
+ }
108
+ }
109
+ }
110
+ {
111
+ for (let match of html.matchAll(REGEX_SLOT_NODES)) {
112
+ let parent = levels[level], type = match[1] === undefined ? NODE_SLOT : (NODE_WHITELIST[match[1].toLowerCase()] ||
113
+ (match[0].at(-2) === '/' ? NODE_VOID : NODE_ELEMENT));
114
+ if ((match.index || 1) - 1 > index) {
115
+ parent.children++;
116
+ }
117
+ if (type === NODE_ELEMENT || type === NODE_VOID) {
118
+ let attr = match[2], path = parent.path.length
119
+ ? methods(parent.elements, parent.path, 'firstElementChild', 'nextElementSibling')
120
+ : methods(parent.children, [], 'firstChild', 'nextSibling');
121
+ if (attr) {
122
+ let attrs = attributes[attr];
123
+ if (!attrs) {
124
+ throw new Error(`${PACKAGE_NAME}: attribute metadata could not be found for '${attr}'`);
125
+ }
126
+ slots.push({ attributes: attrs, path, type: TYPES.Attribute });
127
+ for (let i = 0, n = attrs.names.length; i < n; i++) {
128
+ buffer += parsed[slot++];
129
+ }
130
+ }
131
+ if (type === NODE_ELEMENT) {
132
+ levels[++level] = { children: 0, elements: 0, path };
133
+ }
134
+ parent.elements++;
135
+ }
136
+ else if (type === NODE_SLOT) {
137
+ buffer += parsed[slot++] + SLOT_HTML;
138
+ slots.push({
139
+ path: methods(parent.children, parent.path, 'firstChild', 'nextSibling'),
140
+ type: TYPES.Node
141
+ });
142
+ }
143
+ if (n === slot) {
144
+ buffer += parsed[slot];
145
+ break;
146
+ }
147
+ if (type === NODE_CLOSING) {
148
+ level--;
149
+ }
150
+ else {
151
+ parent.children++;
152
+ }
153
+ index = (match.index || 0) + match[0].length;
154
+ }
155
+ }
156
+ buffer = buffer
157
+ .replace(REGEX_EVENTS, '')
158
+ .replace(REGEX_EMPTY_ATTRIBUTES, '');
159
+ return {
160
+ html: buffer,
161
+ slots: slots.length ? slots : null
162
+ };
163
+ };
164
+ export default { parse };
@@ -0,0 +1,3 @@
1
+ import { plugin } from '@esportsplus/typescript/compiler';
2
+ declare const _default: ReturnType<typeof plugin.tsc>;
3
+ export default _default;
@@ -0,0 +1,4 @@
1
+ import { plugin } from '@esportsplus/typescript/compiler';
2
+ import reactivity from '@esportsplus/reactivity/compiler';
3
+ import template from '../index.js';
4
+ export default plugin.tsc([reactivity, template]);
@@ -0,0 +1,13 @@
1
+ declare const _default: ({ root }?: {
2
+ root?: string;
3
+ }) => {
4
+ configResolved: (config: unknown) => void;
5
+ enforce: "pre";
6
+ name: string;
7
+ transform: (code: string, id: string) => {
8
+ code: string;
9
+ map: null;
10
+ } | null;
11
+ watchChange: (id: string) => void;
12
+ };
13
+ export default _default;
@@ -0,0 +1,8 @@
1
+ import { plugin } from '@esportsplus/typescript/compiler';
2
+ import { PACKAGE_NAME } from '../constants.js';
3
+ import reactivity from '@esportsplus/reactivity/compiler';
4
+ import template from '../index.js';
5
+ export default plugin.vite({
6
+ name: PACKAGE_NAME,
7
+ plugins: [reactivity, template]
8
+ });
@@ -0,0 +1,4 @@
1
+ import { ts } from '@esportsplus/typescript';
2
+ import { TYPES } from './constants.js';
3
+ declare const analyze: (expr: ts.Expression, checker?: ts.TypeChecker) => TYPES;
4
+ export { analyze };