@esportsplus/template 0.32.0 → 0.32.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.
- package/build/attributes.js +1 -2
- package/build/constants.d.ts +18 -3
- package/build/constants.js +31 -4
- package/build/html.d.ts +3 -3
- package/build/index.d.ts +3 -3
- package/build/index.js +3 -3
- package/build/slot/array.d.ts +2 -2
- package/build/slot/array.js +5 -4
- package/build/slot/render.js +3 -2
- package/build/transformer/codegen.d.ts +3 -9
- package/build/transformer/codegen.js +90 -147
- package/build/transformer/index.d.ts +1 -5
- package/build/transformer/index.js +30 -46
- package/build/transformer/parser.d.ts +3 -2
- package/build/transformer/parser.js +4 -4
- package/build/transformer/plugins/tsc.d.ts +2 -2
- package/build/transformer/plugins/tsc.js +3 -4
- package/build/transformer/plugins/vite.d.ts +11 -3
- package/build/transformer/plugins/vite.js +7 -37
- package/build/transformer/ts-parser.d.ts +1 -2
- package/build/transformer/ts-parser.js +28 -41
- package/build/transformer/type-analyzer.d.ts +4 -5
- package/build/transformer/type-analyzer.js +73 -118
- package/build/types.d.ts +1 -1
- package/package.json +7 -7
- package/src/attributes.ts +1 -4
- package/src/constants.ts +42 -6
- package/src/html.ts +3 -3
- package/src/index.ts +5 -3
- package/src/slot/array.ts +9 -6
- package/src/slot/render.ts +5 -2
- package/src/transformer/codegen.ts +119 -189
- package/src/transformer/index.ts +34 -54
- package/src/transformer/parser.ts +10 -7
- package/src/transformer/plugins/tsc.ts +3 -5
- package/src/transformer/plugins/vite.ts +7 -47
- package/src/transformer/ts-parser.ts +34 -54
- package/src/transformer/type-analyzer.ts +90 -158
- package/src/types.ts +1 -1
- package/test/vite.config.ts +1 -1
- package/build/event/constants.d.ts +0 -3
- package/build/event/constants.js +0 -13
- package/src/event/constants.ts +0 -16
- package/storage/rewrite-analysis-2026-01-04.md +0 -439
package/build/attributes.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { effect } from '@esportsplus/reactivity';
|
|
2
2
|
import { isArray, isObject } from '@esportsplus/utilities';
|
|
3
|
-
import { DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS, STATE_HYDRATING, STATE_NONE, STATE_WAITING } from './constants.js';
|
|
3
|
+
import { DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS, STATE_HYDRATING, STATE_NONE, STATE_WAITING, STORE } from './constants.js';
|
|
4
4
|
import { raf } from './utilities.js';
|
|
5
5
|
import q from '@esportsplus/queue';
|
|
6
6
|
import event from './event/index.js';
|
|
7
|
-
const STORE = Symbol();
|
|
8
7
|
let delimiters = {
|
|
9
8
|
class: ' ',
|
|
10
9
|
style: ';'
|
package/build/constants.d.ts
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
declare const ARRAY_SLOT: unique symbol;
|
|
2
2
|
declare const CLEANUP: unique symbol;
|
|
3
|
-
declare const
|
|
3
|
+
declare const COMPILER_ENTRYPOINT = "html";
|
|
4
|
+
declare const COMPILER_ENTRYPOINT_REACTIVITY = "reactive";
|
|
5
|
+
declare const COMPILER_NAMESPACE: string;
|
|
6
|
+
declare const enum COMPILER_TYPES {
|
|
7
|
+
ArraySlot = 0,
|
|
8
|
+
AttributeSlot = 1,
|
|
9
|
+
AttributeSpreadSlot = 2,
|
|
10
|
+
DocumentFragment = 3,
|
|
11
|
+
Effect = 4,
|
|
12
|
+
NodeSlot = 5,
|
|
13
|
+
Primitive = 6,
|
|
14
|
+
Static = 7,
|
|
15
|
+
Unknown = 8
|
|
16
|
+
}
|
|
17
|
+
declare const DIRECT_ATTACH_EVENTS: Set<string>;
|
|
18
|
+
declare const LIFECYCLE_EVENTS: Set<string>;
|
|
19
|
+
declare const PACKAGE = "@esportsplus/template";
|
|
4
20
|
declare const SLOT_HTML = "<!--$-->";
|
|
5
21
|
declare const STATE_HYDRATING = 0;
|
|
6
22
|
declare const STATE_NONE = 1;
|
|
7
23
|
declare const STATE_WAITING = 2;
|
|
8
24
|
declare const STORE: unique symbol;
|
|
9
|
-
export { ARRAY_SLOT, CLEANUP,
|
|
10
|
-
export * from './event/constants.js';
|
|
25
|
+
export { ARRAY_SLOT, CLEANUP, COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY, COMPILER_NAMESPACE, COMPILER_TYPES, DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS, PACKAGE, SLOT_HTML, STATE_HYDRATING, STATE_NONE, STATE_WAITING, STORE, };
|
package/build/constants.js
CHANGED
|
@@ -1,11 +1,38 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { uid } from '@esportsplus/typescript/transformer';
|
|
2
2
|
const ARRAY_SLOT = Symbol('template.array.slot');
|
|
3
3
|
const CLEANUP = Symbol('template.cleanup');
|
|
4
|
-
const
|
|
4
|
+
const COMPILER_ENTRYPOINT = 'html';
|
|
5
|
+
const COMPILER_ENTRYPOINT_REACTIVITY = 'reactive';
|
|
6
|
+
const COMPILER_NAMESPACE = uid('template');
|
|
7
|
+
var COMPILER_TYPES;
|
|
8
|
+
(function (COMPILER_TYPES) {
|
|
9
|
+
COMPILER_TYPES[COMPILER_TYPES["ArraySlot"] = 0] = "ArraySlot";
|
|
10
|
+
COMPILER_TYPES[COMPILER_TYPES["AttributeSlot"] = 1] = "AttributeSlot";
|
|
11
|
+
COMPILER_TYPES[COMPILER_TYPES["AttributeSpreadSlot"] = 2] = "AttributeSpreadSlot";
|
|
12
|
+
COMPILER_TYPES[COMPILER_TYPES["DocumentFragment"] = 3] = "DocumentFragment";
|
|
13
|
+
COMPILER_TYPES[COMPILER_TYPES["Effect"] = 4] = "Effect";
|
|
14
|
+
COMPILER_TYPES[COMPILER_TYPES["NodeSlot"] = 5] = "NodeSlot";
|
|
15
|
+
COMPILER_TYPES[COMPILER_TYPES["Primitive"] = 6] = "Primitive";
|
|
16
|
+
COMPILER_TYPES[COMPILER_TYPES["Static"] = 7] = "Static";
|
|
17
|
+
COMPILER_TYPES[COMPILER_TYPES["Unknown"] = 8] = "Unknown";
|
|
18
|
+
})(COMPILER_TYPES || (COMPILER_TYPES = {}));
|
|
19
|
+
;
|
|
20
|
+
const DIRECT_ATTACH_EVENTS = new Set([
|
|
21
|
+
'onblur',
|
|
22
|
+
'onerror',
|
|
23
|
+
'onfocus', 'onfocusin', 'onfocusout',
|
|
24
|
+
'onload',
|
|
25
|
+
'onplay', 'onpause', 'onended', 'ontimeupdate',
|
|
26
|
+
'onreset',
|
|
27
|
+
'onscroll', 'onsubmit'
|
|
28
|
+
]);
|
|
29
|
+
const LIFECYCLE_EVENTS = new Set([
|
|
30
|
+
'onconnect', 'ondisconnect', 'onrender', 'onresize', 'ontick'
|
|
31
|
+
]);
|
|
32
|
+
const PACKAGE = '@esportsplus/template';
|
|
5
33
|
const SLOT_HTML = '<!--$-->';
|
|
6
34
|
const STATE_HYDRATING = 0;
|
|
7
35
|
const STATE_NONE = 1;
|
|
8
36
|
const STATE_WAITING = 2;
|
|
9
37
|
const STORE = Symbol('template.store');
|
|
10
|
-
export { ARRAY_SLOT, CLEANUP,
|
|
11
|
-
export * from './event/constants.js';
|
|
38
|
+
export { ARRAY_SLOT, CLEANUP, COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY, COMPILER_NAMESPACE, COMPILER_TYPES, DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS, PACKAGE, SLOT_HTML, STATE_HYDRATING, STATE_NONE, STATE_WAITING, STORE, };
|
package/build/html.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Reactive } from '@esportsplus/reactivity';
|
|
2
2
|
import { Attribute, Attributes, Renderable } from './types.js';
|
|
3
3
|
import { ArraySlot } from './slot/array.js';
|
|
4
|
-
type Values<T> = Attribute | Attributes<any> |
|
|
4
|
+
type Values<T> = ArraySlot<T extends unknown[] ? T : never> | Attribute | Attributes<any> | Renderable<T>;
|
|
5
5
|
declare const html: {
|
|
6
6
|
<T>(_literals: TemplateStringsArray, ..._values: (Values<T> | Values<T>[])[]): DocumentFragment;
|
|
7
|
-
reactive<T>(_arr:
|
|
7
|
+
reactive<T>(_arr: Reactive<T[]>, _template: (value: T) => DocumentFragment): ArraySlot<T[]>;
|
|
8
8
|
};
|
|
9
9
|
export default html;
|
package/build/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import './runtime.js';
|
|
2
|
-
export { default as attributes } from './attributes.js';
|
|
3
|
-
export { default as event } from './event/index.js';
|
|
4
2
|
export { default as html } from './html.js';
|
|
5
3
|
export { default as render } from './render.js';
|
|
6
|
-
export { default as slot } from './slot/index.js';
|
|
7
4
|
export { default as svg } from './svg.js';
|
|
5
|
+
export { default as attributes } from './attributes.js';
|
|
6
|
+
export { default as event } from './event/index.js';
|
|
7
|
+
export { default as slot } from './slot/index.js';
|
|
8
8
|
export { ArraySlot } from './slot/array.js';
|
|
9
9
|
export { EffectSlot } from './slot/effect.js';
|
|
10
10
|
export type { Attributes, Element, Renderable } from './types.js';
|
package/build/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import './runtime.js';
|
|
2
|
-
export { default as attributes } from './attributes.js';
|
|
3
|
-
export { default as event } from './event/index.js';
|
|
4
2
|
export { default as html } from './html.js';
|
|
5
3
|
export { default as render } from './render.js';
|
|
6
|
-
export { default as slot } from './slot/index.js';
|
|
7
4
|
export { default as svg } from './svg.js';
|
|
5
|
+
export { default as attributes } from './attributes.js';
|
|
6
|
+
export { default as event } from './event/index.js';
|
|
7
|
+
export { default as slot } from './slot/index.js';
|
|
8
8
|
export { ArraySlot } from './slot/array.js';
|
|
9
9
|
export { EffectSlot } from './slot/effect.js';
|
|
10
10
|
export * from './utilities.js';
|
package/build/slot/array.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Reactive } from '@esportsplus/reactivity';
|
|
2
2
|
import html from '../html.js';
|
|
3
3
|
declare class ArraySlot<T> {
|
|
4
4
|
private array;
|
|
@@ -9,7 +9,7 @@ declare class ArraySlot<T> {
|
|
|
9
9
|
private signal;
|
|
10
10
|
private template;
|
|
11
11
|
readonly fragment: DocumentFragment;
|
|
12
|
-
constructor(array:
|
|
12
|
+
constructor(array: Reactive<T[]>, template: ((value: Reactive<T[]>[number]) => ReturnType<typeof html>));
|
|
13
13
|
private anchor;
|
|
14
14
|
private clear;
|
|
15
15
|
private pop;
|
package/build/slot/array.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { read, root,
|
|
2
|
-
import { ARRAY_SLOT
|
|
3
|
-
import { clone, marker, raf } from '../utilities.js';
|
|
1
|
+
import { read, root, signal, write } from '@esportsplus/reactivity';
|
|
2
|
+
import { ARRAY_SLOT } from '../constants.js';
|
|
3
|
+
import { clone, fragment, marker, raf } from '../utilities.js';
|
|
4
4
|
import { ondisconnect, remove } from './cleanup.js';
|
|
5
|
+
const EMPTY_FRAGMENT = fragment('');
|
|
5
6
|
class ArraySlot {
|
|
6
7
|
array;
|
|
7
8
|
marker;
|
|
@@ -129,7 +130,7 @@ class ArraySlot {
|
|
|
129
130
|
}
|
|
130
131
|
}
|
|
131
132
|
});
|
|
132
|
-
|
|
133
|
+
write(this.signal, this.nodes.length);
|
|
133
134
|
});
|
|
134
135
|
}
|
|
135
136
|
shift() {
|
package/build/slot/render.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isArray } from '@esportsplus/utilities';
|
|
2
|
-
import { ARRAY_SLOT
|
|
3
|
-
import { clone, text } from '../utilities.js';
|
|
2
|
+
import { ARRAY_SLOT } from '../constants.js';
|
|
3
|
+
import { clone, fragment, text } from '../utilities.js';
|
|
4
|
+
const EMPTY_FRAGMENT = fragment('');
|
|
4
5
|
export default function render(anchor, value) {
|
|
5
6
|
if (value == null || value === false || value === '') {
|
|
6
7
|
return EMPTY_FRAGMENT;
|
|
@@ -1,18 +1,12 @@
|
|
|
1
|
-
import type { ReactiveCallInfo, TemplateInfo } from './ts-parser.js';
|
|
2
1
|
import { ts } from '@esportsplus/typescript';
|
|
2
|
+
import type { ReactiveCallInfo, TemplateInfo } from './ts-parser.js';
|
|
3
3
|
type CodegenResult = {
|
|
4
4
|
changed: boolean;
|
|
5
5
|
code: string;
|
|
6
6
|
};
|
|
7
7
|
declare const addArraySlotImport: (code: string) => string;
|
|
8
|
-
declare const generateCode: (templates: TemplateInfo[], originalCode: string, sourceFile: ts.SourceFile) => CodegenResult;
|
|
8
|
+
declare const generateCode: (templates: TemplateInfo[], originalCode: string, sourceFile: ts.SourceFile, checker?: ts.TypeChecker) => CodegenResult;
|
|
9
9
|
declare const generateReactiveInlining: (calls: ReactiveCallInfo[], code: string, sourceFile: ts.SourceFile) => string;
|
|
10
|
-
declare const getNames: () => {
|
|
11
|
-
attr: string;
|
|
12
|
-
event: string;
|
|
13
|
-
slot: string;
|
|
14
|
-
};
|
|
15
10
|
declare const needsArraySlotImport: (sourceFile: ts.SourceFile) => boolean;
|
|
16
|
-
|
|
17
|
-
export { addArraySlotImport, generateCode, generateReactiveInlining, getNames, needsArraySlotImport, setTypeChecker };
|
|
11
|
+
export { addArraySlotImport, generateCode, generateReactiveInlining, needsArraySlotImport };
|
|
18
12
|
export type { CodegenResult };
|
|
@@ -1,42 +1,23 @@
|
|
|
1
|
-
import { addImport, applyReplacementsReverse, uid } from '@esportsplus/typescript/transformer';
|
|
2
|
-
import { analyzeExpression, generateAttributeBinding, generateSpreadBindings } from './type-analyzer.js';
|
|
3
1
|
import { ts } from '@esportsplus/typescript';
|
|
2
|
+
import { code as c, uid } from '@esportsplus/typescript/transformer';
|
|
3
|
+
import { analyzeExpression, generateAttributeBinding, generateSpreadBindings } from './type-analyzer.js';
|
|
4
|
+
import { COMPILER_ENTRYPOINT, COMPILER_NAMESPACE, COMPILER_TYPES, PACKAGE } from '../constants.js';
|
|
4
5
|
import parser from './parser.js';
|
|
5
6
|
const ARROW_EMPTY_PARAMS = /\(\s*\)\s*=>\s*$/;
|
|
6
|
-
let
|
|
7
|
-
function collectNestedTemplateReplacements(node, exprStart,
|
|
7
|
+
let printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
8
|
+
function collectNestedTemplateReplacements(ctx, node, exprStart, replacements) {
|
|
8
9
|
if (isNestedHtmlTemplate(node)) {
|
|
9
10
|
replacements.push({
|
|
10
11
|
end: node.end - exprStart,
|
|
11
|
-
newText: generateNestedTemplateCode(
|
|
12
|
+
newText: generateNestedTemplateCode(ctx, node),
|
|
12
13
|
start: node.getStart() - exprStart
|
|
13
14
|
});
|
|
14
15
|
}
|
|
15
16
|
else {
|
|
16
|
-
ts.forEachChild(node, child => collectNestedTemplateReplacements(child, exprStart,
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
function generateImports() {
|
|
20
|
-
let specifiers = [];
|
|
21
|
-
if (needsArraySlot) {
|
|
22
|
-
specifiers.push(`ArraySlot as ${nameArraySlot}`);
|
|
23
|
-
}
|
|
24
|
-
if (needsEffectSlot) {
|
|
25
|
-
specifiers.push(`EffectSlot as ${nameEffectSlot}`);
|
|
26
|
-
}
|
|
27
|
-
if (needsAttr) {
|
|
28
|
-
specifiers.push(`attributes as ${nameAttr}`);
|
|
29
|
-
}
|
|
30
|
-
if (needsEvent) {
|
|
31
|
-
specifiers.push(`event as ${nameEvent}`);
|
|
32
|
-
}
|
|
33
|
-
if (needsSlot) {
|
|
34
|
-
specifiers.push(`slot as ${nameSlot}`);
|
|
17
|
+
ts.forEachChild(node, child => collectNestedTemplateReplacements(ctx, child, exprStart, replacements));
|
|
35
18
|
}
|
|
36
|
-
specifiers.push(`template as ${nameTemplate}`);
|
|
37
|
-
return `import { ${specifiers.join(', ')} } from '@esportsplus/template';`;
|
|
38
19
|
}
|
|
39
|
-
function generateNestedTemplateCode(
|
|
20
|
+
function generateNestedTemplateCode(ctx, node) {
|
|
40
21
|
let expressions = [], exprTexts = [], literals = [], template = node.template;
|
|
41
22
|
if (ts.isNoSubstitutionTemplateLiteral(template)) {
|
|
42
23
|
literals.push(template.text);
|
|
@@ -47,42 +28,38 @@ function generateNestedTemplateCode(node, sourceFile) {
|
|
|
47
28
|
let expr = template.templateSpans[i].expression;
|
|
48
29
|
expressions.push(expr);
|
|
49
30
|
literals.push(template.templateSpans[i].literal.text);
|
|
50
|
-
exprTexts.push(rewriteExpression(
|
|
31
|
+
exprTexts.push(rewriteExpression(ctx, expr));
|
|
51
32
|
}
|
|
52
33
|
}
|
|
53
|
-
return generateTemplateCode(parser.parse(literals), exprTexts, expressions,
|
|
34
|
+
return generateTemplateCode(ctx, parser.parse(literals), exprTexts, expressions, false);
|
|
54
35
|
}
|
|
55
|
-
function generateNodeBinding(anchor, exprText, exprNode
|
|
36
|
+
function generateNodeBinding(ctx, anchor, exprText, exprNode) {
|
|
56
37
|
if (!exprNode) {
|
|
57
|
-
|
|
58
|
-
return `${nameSlot}(${anchor}, ${exprText});`;
|
|
38
|
+
return `${COMPILER_NAMESPACE}.slot(${anchor}, ${exprText});`;
|
|
59
39
|
}
|
|
60
40
|
if (isNestedHtmlTemplate(exprNode)) {
|
|
61
|
-
return `${anchor}.parentNode.insertBefore(${generateNestedTemplateCode(
|
|
41
|
+
return `${anchor}.parentNode.insertBefore(${generateNestedTemplateCode(ctx, exprNode)}, ${anchor});`;
|
|
62
42
|
}
|
|
63
|
-
let slotType = analyzeExpression(exprNode,
|
|
43
|
+
let slotType = analyzeExpression(exprNode, ctx.checker);
|
|
64
44
|
switch (slotType) {
|
|
65
|
-
case
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
return `new ${nameArraySlot}(${anchor}, ${exprText});`;
|
|
71
|
-
case 'static':
|
|
45
|
+
case COMPILER_TYPES.Effect:
|
|
46
|
+
return `new ${COMPILER_NAMESPACE}.EffectSlot(${anchor}, ${exprText});`;
|
|
47
|
+
case COMPILER_TYPES.ArraySlot:
|
|
48
|
+
return `new ${COMPILER_NAMESPACE}.ArraySlot(${anchor}, ${exprText});`;
|
|
49
|
+
case COMPILER_TYPES.Static:
|
|
72
50
|
return `${anchor}.textContent = ${exprText};`;
|
|
73
|
-
case
|
|
51
|
+
case COMPILER_TYPES.DocumentFragment:
|
|
74
52
|
return `${anchor}.parentNode.insertBefore(${exprText}, ${anchor});`;
|
|
75
53
|
default:
|
|
76
|
-
|
|
77
|
-
return `${nameSlot}(${anchor}, ${exprText});`;
|
|
54
|
+
return `${COMPILER_NAMESPACE}.slot(${anchor}, ${exprText});`;
|
|
78
55
|
}
|
|
79
56
|
}
|
|
80
|
-
function generateTemplateCode({ html, slots }, exprTexts, exprNodes,
|
|
57
|
+
function generateTemplateCode(ctx, { html, slots }, exprTexts, exprNodes, isArrowBody) {
|
|
81
58
|
if (!slots || slots.length === 0) {
|
|
82
|
-
return `${getOrCreateTemplateId(html)}()`;
|
|
59
|
+
return `${getOrCreateTemplateId(ctx, html)}()`;
|
|
83
60
|
}
|
|
84
61
|
let code = [], declarations = [], index = 0, nodes = new Map(), root = uid('root');
|
|
85
|
-
declarations.push(`${root} = ${getOrCreateTemplateId(html)}()`);
|
|
62
|
+
declarations.push(`${root} = ${getOrCreateTemplateId(ctx, html)}()`);
|
|
86
63
|
nodes.set('', root);
|
|
87
64
|
for (let i = 0, n = slots.length; i < n; i++) {
|
|
88
65
|
let path = slots[i].path;
|
|
@@ -111,26 +88,24 @@ function generateTemplateCode({ html, slots }, exprTexts, exprNodes, sourceFile,
|
|
|
111
88
|
let elementVar = slots[i].path.length === 0
|
|
112
89
|
? root
|
|
113
90
|
: (nodes.get(slots[i].path.join('.')) || root), slot = slots[i];
|
|
114
|
-
if (slot.type ===
|
|
115
|
-
|
|
116
|
-
|
|
91
|
+
if (slot.type === COMPILER_TYPES.AttributeSlot) {
|
|
92
|
+
let names = slot.attributes.names;
|
|
93
|
+
for (let j = 0, m = names.length; j < m; j++) {
|
|
94
|
+
let name = names[j];
|
|
117
95
|
if (name === 'spread') {
|
|
118
|
-
let bindings = generateSpreadBindings(exprNodes[index], exprTexts[index] || 'undefined', elementVar,
|
|
96
|
+
let bindings = generateSpreadBindings(exprNodes[index], exprTexts[index] || 'undefined', elementVar, ctx.checker, COMPILER_NAMESPACE);
|
|
119
97
|
for (let k = 0, o = bindings.length; k < o; k++) {
|
|
120
|
-
trackBindingUsage(bindings[k]);
|
|
121
98
|
code.push(bindings[k]);
|
|
122
99
|
}
|
|
123
100
|
index++;
|
|
124
101
|
}
|
|
125
102
|
else {
|
|
126
|
-
|
|
127
|
-
trackBindingUsage(binding);
|
|
128
|
-
code.push(binding);
|
|
103
|
+
code.push(generateAttributeBinding(elementVar, name, exprTexts[index++] || 'undefined', slot.attributes.statics[name] || '', COMPILER_NAMESPACE));
|
|
129
104
|
}
|
|
130
105
|
}
|
|
131
106
|
}
|
|
132
107
|
else {
|
|
133
|
-
code.push(generateNodeBinding(elementVar, exprTexts[index] || 'undefined', exprNodes[index]
|
|
108
|
+
code.push(generateNodeBinding(ctx, elementVar, exprTexts[index] || 'undefined', exprNodes[index]));
|
|
134
109
|
index++;
|
|
135
110
|
}
|
|
136
111
|
}
|
|
@@ -138,12 +113,12 @@ function generateTemplateCode({ html, slots }, exprTexts, exprNodes, sourceFile,
|
|
|
138
113
|
code.push(isArrowBody ? `}` : `})()`);
|
|
139
114
|
return code.join('\n');
|
|
140
115
|
}
|
|
141
|
-
function getOrCreateTemplateId(html) {
|
|
142
|
-
let id = htmlToTemplateId.get(html);
|
|
116
|
+
function getOrCreateTemplateId(ctx, html) {
|
|
117
|
+
let id = ctx.htmlToTemplateId.get(html);
|
|
143
118
|
if (!id) {
|
|
144
119
|
id = uid('tmpl');
|
|
145
|
-
hoistedFactories.set(id, html);
|
|
146
|
-
htmlToTemplateId.set(html, id);
|
|
120
|
+
ctx.hoistedFactories.set(id, html);
|
|
121
|
+
ctx.htmlToTemplateId.set(html, id);
|
|
147
122
|
}
|
|
148
123
|
return id;
|
|
149
124
|
}
|
|
@@ -165,98 +140,70 @@ function hasArraySlotImport(sourceFile) {
|
|
|
165
140
|
}
|
|
166
141
|
return false;
|
|
167
142
|
}
|
|
168
|
-
function
|
|
169
|
-
if (
|
|
170
|
-
ts.isIdentifier(node.expression) &&
|
|
171
|
-
node.expression.text === 'ArraySlot') {
|
|
172
|
-
return true;
|
|
173
|
-
}
|
|
174
|
-
let found = false;
|
|
175
|
-
ts.forEachChild(node, child => {
|
|
176
|
-
if (!found && hasArraySlotUsage(child)) {
|
|
177
|
-
found = true;
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
return found;
|
|
181
|
-
}
|
|
182
|
-
function hasNestedTemplates(node) {
|
|
183
|
-
if (isNestedHtmlTemplate(node)) {
|
|
143
|
+
function hasMatch(node, predicate) {
|
|
144
|
+
if (predicate(node)) {
|
|
184
145
|
return true;
|
|
185
146
|
}
|
|
186
147
|
let found = false;
|
|
187
148
|
ts.forEachChild(node, child => {
|
|
188
|
-
if (!found
|
|
189
|
-
found =
|
|
149
|
+
if (!found) {
|
|
150
|
+
found = hasMatch(child, predicate);
|
|
190
151
|
}
|
|
191
152
|
});
|
|
192
153
|
return found;
|
|
193
154
|
}
|
|
194
155
|
function isNestedHtmlTemplate(expr) {
|
|
195
|
-
return ts.isTaggedTemplateExpression(expr) && ts.isIdentifier(expr.tag) && expr.tag.text ===
|
|
156
|
+
return ts.isTaggedTemplateExpression(expr) && ts.isIdentifier(expr.tag) && expr.tag.text === COMPILER_ENTRYPOINT;
|
|
196
157
|
}
|
|
197
|
-
function isNestedTemplate(template,
|
|
198
|
-
for (let i = 0, n =
|
|
199
|
-
let
|
|
200
|
-
if (
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
for (let j = 0, m = other.expressions.length; j < m; j++) {
|
|
204
|
-
let expr = other.expressions[j];
|
|
205
|
-
if (template.start >= expr.getStart() && template.end <= expr.end) {
|
|
206
|
-
return true;
|
|
207
|
-
}
|
|
158
|
+
function isNestedTemplate(template, exprRanges) {
|
|
159
|
+
for (let i = 0, n = exprRanges.length; i < n; i++) {
|
|
160
|
+
let range = exprRanges[i];
|
|
161
|
+
if (template.start >= range.start && template.end <= range.end) {
|
|
162
|
+
return true;
|
|
208
163
|
}
|
|
209
164
|
}
|
|
210
165
|
return false;
|
|
211
166
|
}
|
|
212
|
-
function rewriteExpression(
|
|
167
|
+
function rewriteExpression(ctx, expr) {
|
|
213
168
|
if (isNestedHtmlTemplate(expr)) {
|
|
214
|
-
return generateNestedTemplateCode(
|
|
215
|
-
}
|
|
216
|
-
if (!hasNestedTemplates(expr)) {
|
|
217
|
-
return ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }).printNode(ts.EmitHint.Expression, expr, sourceFile);
|
|
218
|
-
}
|
|
219
|
-
let exprStart = expr.getStart(), replacements = [];
|
|
220
|
-
collectNestedTemplateReplacements(expr, exprStart, sourceFile, replacements);
|
|
221
|
-
return applyReplacementsReverse(expr.getText(sourceFile), replacements);
|
|
222
|
-
}
|
|
223
|
-
function trackBindingUsage(binding) {
|
|
224
|
-
if (binding.startsWith(nameEvent + '.')) {
|
|
225
|
-
needsEvent = true;
|
|
169
|
+
return generateNestedTemplateCode(ctx, expr);
|
|
226
170
|
}
|
|
227
|
-
|
|
228
|
-
|
|
171
|
+
if (!hasMatch(expr, n => isNestedHtmlTemplate(n))) {
|
|
172
|
+
return ctx.printer.printNode(ts.EmitHint.Expression, expr, ctx.sourceFile);
|
|
229
173
|
}
|
|
174
|
+
let replacements = [];
|
|
175
|
+
collectNestedTemplateReplacements(ctx, expr, expr.getStart(), replacements);
|
|
176
|
+
return c.replaceReverse(expr.getText(ctx.sourceFile), replacements);
|
|
230
177
|
}
|
|
231
178
|
const addArraySlotImport = (code) => {
|
|
232
|
-
return
|
|
179
|
+
return `import * as ${COMPILER_NAMESPACE} from '${PACKAGE}';\n` + code;
|
|
233
180
|
};
|
|
234
|
-
const generateCode = (templates, originalCode, sourceFile) => {
|
|
181
|
+
const generateCode = (templates, originalCode, sourceFile, checker) => {
|
|
235
182
|
if (templates.length === 0) {
|
|
236
183
|
return { changed: false, code: originalCode };
|
|
237
184
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
needsArraySlot = false;
|
|
247
|
-
needsAttr = false;
|
|
248
|
-
needsEffectSlot = false;
|
|
249
|
-
needsEvent = false;
|
|
250
|
-
needsSlot = false;
|
|
251
|
-
let rootTemplates = templates.filter(t => !isNestedTemplate(t, templates));
|
|
185
|
+
let ranges = [];
|
|
186
|
+
for (let i = 0, n = templates.length; i < n; i++) {
|
|
187
|
+
let exprs = templates[i].expressions;
|
|
188
|
+
for (let j = 0, m = exprs.length; j < m; j++) {
|
|
189
|
+
ranges.push({ end: exprs[j].end, start: exprs[j].getStart() });
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
let rootTemplates = templates.filter(t => !isNestedTemplate(t, ranges));
|
|
252
193
|
if (rootTemplates.length === 0) {
|
|
253
194
|
return { changed: false, code: originalCode };
|
|
254
195
|
}
|
|
255
|
-
let
|
|
196
|
+
let ctx = {
|
|
197
|
+
checker,
|
|
198
|
+
hoistedFactories: new Map(),
|
|
199
|
+
htmlToTemplateId: new Map(),
|
|
200
|
+
printer,
|
|
201
|
+
sourceFile
|
|
202
|
+
}, replacements = [];
|
|
256
203
|
for (let i = 0, n = rootTemplates.length; i < n; i++) {
|
|
257
204
|
let exprTexts = [], template = rootTemplates[i];
|
|
258
205
|
for (let j = 0, m = template.expressions.length; j < m; j++) {
|
|
259
|
-
exprTexts.push(rewriteExpression(template.expressions[j]
|
|
206
|
+
exprTexts.push(rewriteExpression(ctx, template.expressions[j]));
|
|
260
207
|
}
|
|
261
208
|
let codeBefore = originalCode.slice(0, template.start), isArrowBody = codeBefore.trimEnd().endsWith('=>'), parsed = parser.parse(template.literals);
|
|
262
209
|
if (isArrowBody && (!parsed.slots || parsed.slots.length === 0)) {
|
|
@@ -264,7 +211,7 @@ const generateCode = (templates, originalCode, sourceFile) => {
|
|
|
264
211
|
if (arrowMatch) {
|
|
265
212
|
replacements.push({
|
|
266
213
|
end: template.end,
|
|
267
|
-
newText: getOrCreateTemplateId(parsed.html),
|
|
214
|
+
newText: getOrCreateTemplateId(ctx, parsed.html),
|
|
268
215
|
start: template.start - arrowMatch[0].length
|
|
269
216
|
});
|
|
270
217
|
continue;
|
|
@@ -272,17 +219,17 @@ const generateCode = (templates, originalCode, sourceFile) => {
|
|
|
272
219
|
}
|
|
273
220
|
replacements.push({
|
|
274
221
|
end: template.end,
|
|
275
|
-
newText: generateTemplateCode(parsed, exprTexts, template.expressions,
|
|
222
|
+
newText: generateTemplateCode(ctx, parsed, exprTexts, template.expressions, isArrowBody),
|
|
276
223
|
start: template.start
|
|
277
224
|
});
|
|
278
225
|
}
|
|
279
|
-
let changed = replacements.length > 0, code =
|
|
280
|
-
if (changed && hoistedFactories.size > 0) {
|
|
226
|
+
let changed = replacements.length > 0, code = c.replaceReverse(originalCode, replacements);
|
|
227
|
+
if (changed && ctx.hoistedFactories.size > 0) {
|
|
281
228
|
let factories = [];
|
|
282
|
-
for (let [id, html] of hoistedFactories) {
|
|
283
|
-
factories.push(`const ${id} = ${
|
|
229
|
+
for (let [id, html] of ctx.hoistedFactories) {
|
|
230
|
+
factories.push(`const ${id} = ${COMPILER_NAMESPACE}.template(\`${html}\`);`);
|
|
284
231
|
}
|
|
285
|
-
code =
|
|
232
|
+
code = `import * as ${COMPILER_NAMESPACE} from '${PACKAGE}';\n\n` + factories.join('\n') + '\n\n' + code;
|
|
286
233
|
}
|
|
287
234
|
return { changed, code };
|
|
288
235
|
};
|
|
@@ -290,27 +237,23 @@ const generateReactiveInlining = (calls, code, sourceFile) => {
|
|
|
290
237
|
if (calls.length === 0) {
|
|
291
238
|
return code;
|
|
292
239
|
}
|
|
293
|
-
let
|
|
294
|
-
for (let i = calls.length
|
|
240
|
+
let replacements = [];
|
|
241
|
+
for (let i = 0, n = calls.length; i < n; i++) {
|
|
295
242
|
let call = calls[i];
|
|
296
|
-
|
|
297
|
-
|
|
243
|
+
replacements.push({
|
|
244
|
+
end: call.end,
|
|
245
|
+
newText: `new ${COMPILER_NAMESPACE}.ArraySlot(
|
|
298
246
|
${printer.printNode(ts.EmitHint.Expression, call.arrayArg, sourceFile)},
|
|
299
247
|
${printer.printNode(ts.EmitHint.Expression, call.callbackArg, sourceFile)}
|
|
300
|
-
)
|
|
301
|
-
|
|
248
|
+
)`,
|
|
249
|
+
start: call.start
|
|
250
|
+
});
|
|
302
251
|
}
|
|
303
|
-
return
|
|
252
|
+
return c.replaceReverse(code, replacements);
|
|
304
253
|
};
|
|
305
|
-
const getNames = () => ({
|
|
306
|
-
attr: nameAttr,
|
|
307
|
-
event: nameEvent,
|
|
308
|
-
slot: nameSlot
|
|
309
|
-
});
|
|
310
254
|
const needsArraySlotImport = (sourceFile) => {
|
|
311
|
-
return
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
currentChecker = checker;
|
|
255
|
+
return hasMatch(sourceFile, n => ts.isNewExpression(n) &&
|
|
256
|
+
ts.isPropertyAccessExpression(n.expression) &&
|
|
257
|
+
n.expression.name.text === 'ArraySlot') && !hasArraySlotImport(sourceFile);
|
|
315
258
|
};
|
|
316
|
-
export { addArraySlotImport, generateCode, generateReactiveInlining,
|
|
259
|
+
export { addArraySlotImport, generateCode, generateReactiveInlining, needsArraySlotImport };
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import { mightNeedTransform } from '@esportsplus/typescript/transformer';
|
|
2
1
|
import { ts } from '@esportsplus/typescript';
|
|
3
2
|
type TransformResult = {
|
|
4
3
|
changed: boolean;
|
|
5
4
|
code: string;
|
|
6
5
|
sourceFile: ts.SourceFile;
|
|
7
6
|
};
|
|
8
|
-
declare const PATTERNS: string[];
|
|
9
|
-
declare function createTransformer(program: ts.Program): ts.TransformerFactory<ts.SourceFile>;
|
|
10
7
|
declare const transform: (sourceFile: ts.SourceFile, program: ts.Program) => TransformResult;
|
|
11
|
-
export
|
|
12
|
-
export { createTransformer, mightNeedTransform, PATTERNS, transform };
|
|
8
|
+
export { transform };
|