@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
|
@@ -1,62 +1,46 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { addArraySlotImport, generateCode, generateReactiveInlining, needsArraySlotImport
|
|
1
|
+
import { code as c } from '@esportsplus/typescript/transformer';
|
|
2
|
+
import { addArraySlotImport, generateCode, generateReactiveInlining, needsArraySlotImport } from './codegen.js';
|
|
3
|
+
import { COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY } from '../constants.js';
|
|
3
4
|
import { findHtmlTemplates, findReactiveCalls } from './ts-parser.js';
|
|
4
5
|
import { ts } from '@esportsplus/typescript';
|
|
5
|
-
const PATTERNS = [
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
function transformCode(code, sourceFile) {
|
|
24
|
-
let changed = false, result = code;
|
|
25
|
-
let reactiveCalls = findReactiveCalls(sourceFile);
|
|
6
|
+
const PATTERNS = [`${COMPILER_ENTRYPOINT}\``, `${COMPILER_ENTRYPOINT}.${COMPILER_ENTRYPOINT_REACTIVITY}`];
|
|
7
|
+
const REGEX_BACKSLASH = /\\/g;
|
|
8
|
+
const REGEX_FORWARD_SLASH = /\//g;
|
|
9
|
+
const transform = (sourceFile, program) => {
|
|
10
|
+
let code = sourceFile.getFullText();
|
|
11
|
+
if (!c.contains(code, { patterns: PATTERNS })) {
|
|
12
|
+
return { changed: false, code, sourceFile };
|
|
13
|
+
}
|
|
14
|
+
let checker, fileName = sourceFile.fileName, programSourceFile = program.getSourceFile(fileName)
|
|
15
|
+
|| program.getSourceFile(fileName.replace(REGEX_BACKSLASH, '/'))
|
|
16
|
+
|| program.getSourceFile(fileName.replace(REGEX_FORWARD_SLASH, '\\'));
|
|
17
|
+
if (programSourceFile) {
|
|
18
|
+
checker = program.getTypeChecker();
|
|
19
|
+
sourceFile = programSourceFile;
|
|
20
|
+
}
|
|
21
|
+
let changed = false, codegenChanged = false, needsImport = false, reactiveCalls = findReactiveCalls(sourceFile), result = code;
|
|
26
22
|
if (reactiveCalls.length > 0) {
|
|
27
|
-
result = generateReactiveInlining(reactiveCalls, result, sourceFile);
|
|
28
23
|
changed = true;
|
|
24
|
+
checker = undefined;
|
|
25
|
+
result = generateReactiveInlining(reactiveCalls, result, sourceFile);
|
|
29
26
|
sourceFile = ts.createSourceFile(sourceFile.fileName, result, sourceFile.languageVersion, true);
|
|
30
|
-
|
|
31
|
-
result = addArraySlotImport(result);
|
|
32
|
-
sourceFile = ts.createSourceFile(sourceFile.fileName, result, sourceFile.languageVersion, true);
|
|
33
|
-
}
|
|
34
|
-
setTypeChecker(undefined);
|
|
27
|
+
needsImport = needsArraySlotImport(sourceFile);
|
|
35
28
|
}
|
|
36
29
|
let templates = findHtmlTemplates(sourceFile);
|
|
37
30
|
if (templates.length > 0) {
|
|
38
|
-
let codegenResult = generateCode(templates, result, sourceFile);
|
|
31
|
+
let codegenResult = generateCode(templates, result, sourceFile, checker);
|
|
39
32
|
if (codegenResult.changed) {
|
|
40
33
|
changed = true;
|
|
34
|
+
codegenChanged = true;
|
|
41
35
|
result = codegenResult.code;
|
|
42
|
-
sourceFile = ts.createSourceFile(sourceFile.fileName, result, sourceFile.languageVersion, true);
|
|
43
36
|
}
|
|
44
37
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const transform = (sourceFile, program) => {
|
|
48
|
-
let code = sourceFile.getFullText();
|
|
49
|
-
if (!mightNeedTransform(code, { patterns: PATTERNS })) {
|
|
50
|
-
return { changed: false, code, sourceFile };
|
|
38
|
+
if (needsImport && !codegenChanged) {
|
|
39
|
+
result = addArraySlotImport(result);
|
|
51
40
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
setTypeChecker(program.getTypeChecker());
|
|
55
|
-
sourceFile = programSourceFile;
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
setTypeChecker(undefined);
|
|
41
|
+
if (changed) {
|
|
42
|
+
sourceFile = ts.createSourceFile(sourceFile.fileName, result, sourceFile.languageVersion, true);
|
|
59
43
|
}
|
|
60
|
-
return
|
|
44
|
+
return { changed, code: result, sourceFile };
|
|
61
45
|
};
|
|
62
|
-
export {
|
|
46
|
+
export { transform };
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
+
import { COMPILER_TYPES } from '../constants.js';
|
|
1
2
|
type NodePath = ('firstChild' | 'firstElementChild' | 'nextElementSibling' | 'nextSibling')[];
|
|
2
3
|
declare const _default: {
|
|
3
4
|
parse: (literals: string[]) => {
|
|
4
5
|
html: string;
|
|
5
6
|
slots: ({
|
|
6
7
|
path: NodePath;
|
|
7
|
-
type:
|
|
8
|
+
type: COMPILER_TYPES.NodeSlot;
|
|
8
9
|
} | {
|
|
9
10
|
attributes: {
|
|
10
11
|
names: string[];
|
|
11
12
|
statics: Record<string, string>;
|
|
12
13
|
};
|
|
13
14
|
path: NodePath;
|
|
14
|
-
type:
|
|
15
|
+
type: COMPILER_TYPES.AttributeSlot;
|
|
15
16
|
})[] | null;
|
|
16
17
|
};
|
|
17
18
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { COMPILER_TYPES, PACKAGE, SLOT_HTML } from '../constants.js';
|
|
2
2
|
const ATTRIBUTE_DELIMITERS = {
|
|
3
3
|
class: ' ',
|
|
4
4
|
style: ';'
|
|
@@ -125,9 +125,9 @@ const parse = (literals) => {
|
|
|
125
125
|
if (attr) {
|
|
126
126
|
let attrs = attributes[attr];
|
|
127
127
|
if (!attrs) {
|
|
128
|
-
throw new Error(
|
|
128
|
+
throw new Error(`${PACKAGE}: attribute metadata could not be found for '${attr}'`);
|
|
129
129
|
}
|
|
130
|
-
slots.push({ attributes: attrs, path, type:
|
|
130
|
+
slots.push({ attributes: attrs, path, type: COMPILER_TYPES.AttributeSlot });
|
|
131
131
|
for (let i = 0, n = attrs.names.length; i < n; i++) {
|
|
132
132
|
buffer += parsed[slot++];
|
|
133
133
|
}
|
|
@@ -139,7 +139,7 @@ const parse = (literals) => {
|
|
|
139
139
|
}
|
|
140
140
|
else if (type === NODE_SLOT) {
|
|
141
141
|
buffer += parsed[slot++] + SLOT_HTML;
|
|
142
|
-
slots.push({ path: methods(parent.children, parent.path, 'firstChild', 'nextSibling'), type:
|
|
142
|
+
slots.push({ path: methods(parent.children, parent.path, 'firstChild', 'nextSibling'), type: COMPILER_TYPES.NodeSlot });
|
|
143
143
|
}
|
|
144
144
|
if (n === slot) {
|
|
145
145
|
buffer += parsed[slot];
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
declare const _default:
|
|
1
|
+
import { plugin } from '@esportsplus/typescript/transformer';
|
|
2
|
+
declare const _default: ReturnType<typeof plugin.tsc>;
|
|
3
3
|
export default _default;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
1
|
+
import { plugin } from '@esportsplus/typescript/transformer';
|
|
2
|
+
import { transform } from '../index.js';
|
|
3
|
+
export default plugin.tsc(transform);
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
declare const _default: (options?: {
|
|
1
|
+
declare const _default: ({ root }?: {
|
|
3
2
|
root?: string;
|
|
4
|
-
}) =>
|
|
3
|
+
}) => {
|
|
4
|
+
configResolved(config: import("vite").ResolvedConfig): void;
|
|
5
|
+
enforce: string;
|
|
6
|
+
name: string;
|
|
7
|
+
transform(code: string, id: string): {
|
|
8
|
+
code: string;
|
|
9
|
+
map: null;
|
|
10
|
+
} | null;
|
|
11
|
+
watchChange(id: string): void;
|
|
12
|
+
};
|
|
5
13
|
export default _default;
|
|
@@ -1,37 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
export default (
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
name: '@esportsplus/template/plugin-vite',
|
|
9
|
-
configResolved(config) {
|
|
10
|
-
root = options?.root ?? config.root;
|
|
11
|
-
},
|
|
12
|
-
transform(code, id) {
|
|
13
|
-
if (!TRANSFORM_PATTERN.test(id) || id.includes('node_modules')) {
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
if (!mightNeedTransform(code, { patterns: PATTERNS })) {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
try {
|
|
20
|
-
let sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true), result = transform(sourceFile, program.get(root));
|
|
21
|
-
if (!result.changed) {
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
return { code: result.code, map: null };
|
|
25
|
-
}
|
|
26
|
-
catch (error) {
|
|
27
|
-
console.error(`@esportsplus/template: Error transforming ${id}:`, error);
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
watchChange(id) {
|
|
32
|
-
if (TRANSFORM_PATTERN.test(id)) {
|
|
33
|
-
program.delete(root);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
};
|
|
1
|
+
import { plugin } from '@esportsplus/typescript/transformer';
|
|
2
|
+
import { PACKAGE } from '../../constants.js';
|
|
3
|
+
import { transform } from '../index.js';
|
|
4
|
+
export default plugin.vite({
|
|
5
|
+
name: PACKAGE,
|
|
6
|
+
transform
|
|
7
|
+
});
|
|
@@ -16,6 +16,5 @@ type TemplateInfo = {
|
|
|
16
16
|
};
|
|
17
17
|
declare const findHtmlTemplates: (sourceFile: ts.SourceFile) => TemplateInfo[];
|
|
18
18
|
declare const findReactiveCalls: (sourceFile: ts.SourceFile) => ReactiveCallInfo[];
|
|
19
|
-
|
|
20
|
-
export { findHtmlTemplates, findReactiveCalls, getTemplateExpressions };
|
|
19
|
+
export { findHtmlTemplates, findReactiveCalls };
|
|
21
20
|
export type { ReactiveCallInfo, TemplateInfo };
|
|
@@ -1,38 +1,11 @@
|
|
|
1
|
+
import { COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY } from '../constants.js';
|
|
1
2
|
import { ts } from '@esportsplus/typescript';
|
|
2
|
-
function extractTemplateInfo(node, depth) {
|
|
3
|
-
let expressions = [], literals = [], template = node.template;
|
|
4
|
-
if (ts.isNoSubstitutionTemplateLiteral(template)) {
|
|
5
|
-
literals.push(template.text);
|
|
6
|
-
}
|
|
7
|
-
else if (ts.isTemplateExpression(template)) {
|
|
8
|
-
literals.push(template.head.text);
|
|
9
|
-
for (let i = 0, n = template.templateSpans.length; i < n; i++) {
|
|
10
|
-
let span = template.templateSpans[i];
|
|
11
|
-
expressions.push(span.expression);
|
|
12
|
-
literals.push(span.literal.text);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
return {
|
|
16
|
-
depth,
|
|
17
|
-
end: node.end,
|
|
18
|
-
expressions,
|
|
19
|
-
literals,
|
|
20
|
-
node,
|
|
21
|
-
start: node.getStart()
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
function isFunctionNode(node) {
|
|
25
|
-
return (ts.isArrowFunction(node) ||
|
|
26
|
-
ts.isFunctionDeclaration(node) ||
|
|
27
|
-
ts.isFunctionExpression(node) ||
|
|
28
|
-
ts.isMethodDeclaration(node));
|
|
29
|
-
}
|
|
30
3
|
function visitReactiveCalls(node, calls) {
|
|
31
4
|
if (ts.isCallExpression(node) &&
|
|
32
5
|
ts.isPropertyAccessExpression(node.expression) &&
|
|
33
6
|
ts.isIdentifier(node.expression.expression) &&
|
|
34
|
-
node.expression.expression.text ===
|
|
35
|
-
node.expression.name.text ===
|
|
7
|
+
node.expression.expression.text === COMPILER_ENTRYPOINT &&
|
|
8
|
+
node.expression.name.text === COMPILER_ENTRYPOINT_REACTIVITY &&
|
|
36
9
|
node.arguments.length === 2) {
|
|
37
10
|
calls.push({
|
|
38
11
|
arrayArg: node.arguments[0],
|
|
@@ -45,9 +18,30 @@ function visitReactiveCalls(node, calls) {
|
|
|
45
18
|
ts.forEachChild(node, child => visitReactiveCalls(child, calls));
|
|
46
19
|
}
|
|
47
20
|
function visitTemplates(node, depth, templates) {
|
|
48
|
-
let nextDepth =
|
|
49
|
-
|
|
50
|
-
|
|
21
|
+
let nextDepth = (ts.isArrowFunction(node) || ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isMethodDeclaration(node))
|
|
22
|
+
? depth + 1
|
|
23
|
+
: depth;
|
|
24
|
+
if (ts.isTaggedTemplateExpression(node) && ts.isIdentifier(node.tag) && node.tag.text === COMPILER_ENTRYPOINT) {
|
|
25
|
+
let expressions = [], literals = [], template = node.template;
|
|
26
|
+
if (ts.isNoSubstitutionTemplateLiteral(template)) {
|
|
27
|
+
literals.push(template.text);
|
|
28
|
+
}
|
|
29
|
+
else if (ts.isTemplateExpression(template)) {
|
|
30
|
+
literals.push(template.head.text);
|
|
31
|
+
for (let i = 0, n = template.templateSpans.length; i < n; i++) {
|
|
32
|
+
let span = template.templateSpans[i];
|
|
33
|
+
expressions.push(span.expression);
|
|
34
|
+
literals.push(span.literal.text);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
templates.push({
|
|
38
|
+
depth,
|
|
39
|
+
end: node.end,
|
|
40
|
+
expressions,
|
|
41
|
+
literals,
|
|
42
|
+
node,
|
|
43
|
+
start: node.getStart()
|
|
44
|
+
});
|
|
51
45
|
}
|
|
52
46
|
ts.forEachChild(node, child => visitTemplates(child, nextDepth, templates));
|
|
53
47
|
}
|
|
@@ -62,11 +56,4 @@ const findReactiveCalls = (sourceFile) => {
|
|
|
62
56
|
visitReactiveCalls(sourceFile, calls);
|
|
63
57
|
return calls;
|
|
64
58
|
};
|
|
65
|
-
|
|
66
|
-
let exprs = [];
|
|
67
|
-
for (let i = 0, n = info.expressions.length; i < n; i++) {
|
|
68
|
-
exprs.push(info.expressions[i].getText(sourceFile));
|
|
69
|
-
}
|
|
70
|
-
return exprs;
|
|
71
|
-
};
|
|
72
|
-
export { findHtmlTemplates, findReactiveCalls, getTemplateExpressions };
|
|
59
|
+
export { findHtmlTemplates, findReactiveCalls };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
+
import { COMPILER_TYPES } from '../constants.js';
|
|
1
2
|
import { ts } from '@esportsplus/typescript';
|
|
2
|
-
|
|
3
|
-
declare const
|
|
4
|
-
declare const
|
|
5
|
-
declare const generateSpreadBindings: (expr: ts.Expression, exprCode: string, elementVar: string, sourceFile: ts.SourceFile, checker?: ts.TypeChecker) => string[];
|
|
3
|
+
declare const analyzeExpression: (expr: ts.Expression, checker?: ts.TypeChecker) => COMPILER_TYPES;
|
|
4
|
+
declare const generateAttributeBinding: (elementVar: string, name: string, expr: string, staticValue: string, ns: string) => string;
|
|
5
|
+
declare const generateSpreadBindings: (expr: ts.Expression, exprCode: string, elementVar: string, checker: ts.TypeChecker | undefined, ns: string) => string[];
|
|
6
6
|
export { analyzeExpression, generateAttributeBinding, generateSpreadBindings };
|
|
7
|
-
export type { SlotType };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS } from '../event/constants.js';
|
|
1
|
+
import { COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY, COMPILER_TYPES, DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS } from '../constants.js';
|
|
3
2
|
import { ts } from '@esportsplus/typescript';
|
|
4
3
|
function analyzeSpread(expr, checker) {
|
|
5
4
|
while (ts.isParenthesizedExpression(expr)) {
|
|
@@ -25,143 +24,84 @@ function analyzeSpread(expr, checker) {
|
|
|
25
24
|
}
|
|
26
25
|
if (checker && (ts.isIdentifier(expr) || ts.isPropertyAccessExpression(expr))) {
|
|
27
26
|
try {
|
|
28
|
-
let keys =
|
|
27
|
+
let keys = [], props = checker.getTypeAtLocation(expr).getProperties();
|
|
28
|
+
for (let i = 0, n = props.length; i < n; i++) {
|
|
29
|
+
let name = props[i].getName();
|
|
30
|
+
if (name.startsWith('__') || name.startsWith('[')) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
keys.push(name);
|
|
34
|
+
}
|
|
29
35
|
if (keys.length > 0) {
|
|
30
36
|
return { canUnpack: true, keys };
|
|
31
37
|
}
|
|
32
38
|
}
|
|
33
|
-
catch {
|
|
34
|
-
}
|
|
39
|
+
catch { }
|
|
35
40
|
}
|
|
36
41
|
return { canUnpack: false, keys: [] };
|
|
37
42
|
}
|
|
38
|
-
function
|
|
39
|
-
let keys = [], props = type.getProperties();
|
|
40
|
-
for (let i = 0, n = props.length; i < n; i++) {
|
|
41
|
-
let name = props[i].getName();
|
|
42
|
-
if (name.startsWith('__') || name.startsWith('[')) {
|
|
43
|
-
continue;
|
|
44
|
-
}
|
|
45
|
-
keys.push(name);
|
|
46
|
-
}
|
|
47
|
-
return keys;
|
|
48
|
-
}
|
|
49
|
-
function getObjectPropertyValue(expr, key, sourceFile) {
|
|
50
|
-
for (let i = 0, n = expr.properties.length; i < n; i++) {
|
|
51
|
-
let prop = expr.properties[i];
|
|
52
|
-
if (ts.isPropertyAssignment(prop)) {
|
|
53
|
-
let name = ts.isIdentifier(prop.name)
|
|
54
|
-
? prop.name.text
|
|
55
|
-
: ts.isStringLiteral(prop.name) ? prop.name.text : null;
|
|
56
|
-
if (name === key) {
|
|
57
|
-
return prop.initializer.getText(sourceFile);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
else if (ts.isShorthandPropertyAssignment(prop) && prop.name.text === key) {
|
|
61
|
-
return prop.name.text;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
function inferSlotType(expr, ctx) {
|
|
43
|
+
function inferCOMPILER_TYPES(expr, checker) {
|
|
67
44
|
while (ts.isParenthesizedExpression(expr)) {
|
|
68
45
|
expr = expr.expression;
|
|
69
46
|
}
|
|
70
47
|
if (ts.isArrowFunction(expr) || ts.isFunctionExpression(expr)) {
|
|
71
|
-
return
|
|
48
|
+
return COMPILER_TYPES.Effect;
|
|
72
49
|
}
|
|
73
50
|
if (ts.isCallExpression(expr) &&
|
|
74
51
|
ts.isPropertyAccessExpression(expr.expression) &&
|
|
75
52
|
ts.isIdentifier(expr.expression.expression) &&
|
|
76
|
-
expr.expression.expression.text ===
|
|
77
|
-
expr.expression.name.text ===
|
|
78
|
-
return
|
|
53
|
+
expr.expression.expression.text === COMPILER_ENTRYPOINT &&
|
|
54
|
+
expr.expression.name.text === COMPILER_ENTRYPOINT_REACTIVITY) {
|
|
55
|
+
return COMPILER_TYPES.ArraySlot;
|
|
79
56
|
}
|
|
80
|
-
if (ts.isTaggedTemplateExpression(expr) && ts.isIdentifier(expr.tag) && expr.tag.text ===
|
|
81
|
-
return
|
|
57
|
+
if (ts.isTaggedTemplateExpression(expr) && ts.isIdentifier(expr.tag) && expr.tag.text === COMPILER_ENTRYPOINT) {
|
|
58
|
+
return COMPILER_TYPES.DocumentFragment;
|
|
82
59
|
}
|
|
83
60
|
if (ts.isArrayLiteralExpression(expr)) {
|
|
84
|
-
return
|
|
85
|
-
}
|
|
86
|
-
if (ts.isStringLiteral(expr) || ts.isNoSubstitutionTemplateLiteral(expr)) {
|
|
87
|
-
return 'static';
|
|
88
|
-
}
|
|
89
|
-
if (ts.isNumericLiteral(expr)) {
|
|
90
|
-
return 'static';
|
|
61
|
+
return COMPILER_TYPES.ArraySlot;
|
|
91
62
|
}
|
|
92
|
-
if (
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
63
|
+
if (ts.isNumericLiteral(expr) ||
|
|
64
|
+
ts.isStringLiteral(expr) ||
|
|
65
|
+
ts.isNoSubstitutionTemplateLiteral(expr) ||
|
|
66
|
+
expr.kind === ts.SyntaxKind.TrueKeyword ||
|
|
67
|
+
expr.kind === ts.SyntaxKind.FalseKeyword ||
|
|
68
|
+
expr.kind === ts.SyntaxKind.NullKeyword ||
|
|
69
|
+
expr.kind === ts.SyntaxKind.UndefinedKeyword) {
|
|
70
|
+
return COMPILER_TYPES.Static;
|
|
97
71
|
}
|
|
98
72
|
if (ts.isTemplateExpression(expr)) {
|
|
99
|
-
return
|
|
73
|
+
return COMPILER_TYPES.Primitive;
|
|
100
74
|
}
|
|
101
75
|
if (ts.isConditionalExpression(expr)) {
|
|
102
|
-
let whenFalse =
|
|
76
|
+
let whenFalse = inferCOMPILER_TYPES(expr.whenFalse, checker), whenTrue = inferCOMPILER_TYPES(expr.whenTrue, checker);
|
|
103
77
|
if (whenTrue === whenFalse) {
|
|
104
78
|
return whenTrue;
|
|
105
79
|
}
|
|
106
|
-
if (whenTrue ===
|
|
107
|
-
return
|
|
80
|
+
if (whenTrue === COMPILER_TYPES.Effect || whenFalse === COMPILER_TYPES.Effect) {
|
|
81
|
+
return COMPILER_TYPES.Effect;
|
|
108
82
|
}
|
|
109
|
-
return
|
|
110
|
-
}
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (isTypeFunction(type, checker)) {
|
|
117
|
-
return 'effect';
|
|
118
|
-
}
|
|
119
|
-
if (isTypeArray(type, checker)) {
|
|
120
|
-
return 'array-slot';
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
catch {
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
if (ts.isPropertyAccessExpression(expr)) {
|
|
127
|
-
try {
|
|
128
|
-
let type = checker.getTypeAtLocation(expr);
|
|
129
|
-
if (isTypeFunction(type, checker)) {
|
|
130
|
-
return 'effect';
|
|
131
|
-
}
|
|
132
|
-
if (isTypeArray(type, checker)) {
|
|
133
|
-
return 'array-slot';
|
|
134
|
-
}
|
|
83
|
+
return COMPILER_TYPES.Unknown;
|
|
84
|
+
}
|
|
85
|
+
if (checker && (ts.isIdentifier(expr) || ts.isPropertyAccessExpression(expr) || ts.isCallExpression(expr))) {
|
|
86
|
+
try {
|
|
87
|
+
let type = checker.getTypeAtLocation(expr);
|
|
88
|
+
if (isTypeFunction(type, checker)) {
|
|
89
|
+
return COMPILER_TYPES.Effect;
|
|
135
90
|
}
|
|
136
|
-
|
|
91
|
+
if (isTypeArray(type, checker)) {
|
|
92
|
+
return COMPILER_TYPES.ArraySlot;
|
|
137
93
|
}
|
|
138
94
|
}
|
|
139
|
-
|
|
140
|
-
try {
|
|
141
|
-
let type = checker.getTypeAtLocation(expr);
|
|
142
|
-
if (isTypeFunction(type, checker)) {
|
|
143
|
-
return 'effect';
|
|
144
|
-
}
|
|
145
|
-
if (isTypeArray(type, checker)) {
|
|
146
|
-
return 'array-slot';
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
catch {
|
|
150
|
-
}
|
|
95
|
+
catch {
|
|
151
96
|
}
|
|
152
97
|
}
|
|
153
|
-
return
|
|
98
|
+
return COMPILER_TYPES.Unknown;
|
|
154
99
|
}
|
|
155
100
|
function isTypeArray(type, checker) {
|
|
156
|
-
|
|
157
|
-
if (typeStr.endsWith('[]') || typeStr.startsWith('Array<') || typeStr.startsWith('ReactiveArray<')) {
|
|
158
|
-
return true;
|
|
159
|
-
}
|
|
160
|
-
let symbol = type.getSymbol();
|
|
161
|
-
if (symbol && (symbol.getName() === 'Array' || symbol.getName() === 'ReactiveArray')) {
|
|
101
|
+
if (checker.isArrayType(type)) {
|
|
162
102
|
return true;
|
|
163
103
|
}
|
|
164
|
-
return
|
|
104
|
+
return type.getSymbol()?.getName() === 'ReactiveArray';
|
|
165
105
|
}
|
|
166
106
|
function isTypeFunction(type, checker) {
|
|
167
107
|
if (type.getCallSignatures().length > 0) {
|
|
@@ -177,52 +117,67 @@ function isTypeFunction(type, checker) {
|
|
|
177
117
|
return false;
|
|
178
118
|
}
|
|
179
119
|
const analyzeExpression = (expr, checker) => {
|
|
180
|
-
return
|
|
120
|
+
return inferCOMPILER_TYPES(expr, checker);
|
|
181
121
|
};
|
|
182
|
-
const generateAttributeBinding = (elementVar, name, expr, staticValue) => {
|
|
183
|
-
let n = getNames();
|
|
122
|
+
const generateAttributeBinding = (elementVar, name, expr, staticValue, ns) => {
|
|
184
123
|
if (name.startsWith('on') && name.length > 2) {
|
|
185
124
|
let event = name.slice(2).toLowerCase(), key = name.toLowerCase();
|
|
186
125
|
if (LIFECYCLE_EVENTS.has(key)) {
|
|
187
|
-
return `${
|
|
126
|
+
return `${ns}.event.${key}(${elementVar}, ${expr});`;
|
|
188
127
|
}
|
|
189
128
|
if (DIRECT_ATTACH_EVENTS.has(key)) {
|
|
190
|
-
return `${
|
|
129
|
+
return `${ns}.event.direct(${elementVar}, '${event}', ${expr});`;
|
|
191
130
|
}
|
|
192
|
-
return `${
|
|
131
|
+
return `${ns}.event.delegate(${elementVar}, '${event}', ${expr});`;
|
|
193
132
|
}
|
|
194
133
|
if (name === 'class') {
|
|
195
|
-
return `${
|
|
134
|
+
return `${ns}.attributes.setClass(${elementVar}, '${staticValue}', ${expr});`;
|
|
196
135
|
}
|
|
197
136
|
if (name === 'spread') {
|
|
198
|
-
return `${
|
|
137
|
+
return `${ns}.attributes.spread(${elementVar}, ${expr});`;
|
|
199
138
|
}
|
|
200
139
|
if (name === 'style') {
|
|
201
|
-
return `${
|
|
140
|
+
return `${ns}.attributes.setStyle(${elementVar}, '${staticValue}', ${expr});`;
|
|
202
141
|
}
|
|
203
|
-
return `${
|
|
142
|
+
return `${ns}.attributes.setProperty(${elementVar}, '${name}', ${expr});`;
|
|
204
143
|
};
|
|
205
|
-
const generateSpreadBindings = (expr, exprCode, elementVar,
|
|
144
|
+
const generateSpreadBindings = (expr, exprCode, elementVar, checker, ns) => {
|
|
206
145
|
while (ts.isParenthesizedExpression(expr)) {
|
|
207
146
|
expr = expr.expression;
|
|
208
147
|
}
|
|
209
148
|
let analysis = analyzeSpread(expr, checker);
|
|
210
149
|
if (!analysis.canUnpack) {
|
|
211
|
-
return [`${
|
|
150
|
+
return [`${ns}.attributes.spread(${elementVar}, ${exprCode});`];
|
|
212
151
|
}
|
|
213
152
|
let lines = [];
|
|
214
153
|
if (ts.isObjectLiteralExpression(expr)) {
|
|
215
154
|
for (let i = 0, n = analysis.keys.length; i < n; i++) {
|
|
216
|
-
let key = analysis.keys[i], value =
|
|
155
|
+
let key = analysis.keys[i], value = null;
|
|
156
|
+
for (let j = 0, m = expr.properties.length; j < m; j++) {
|
|
157
|
+
let prop = expr.properties[j];
|
|
158
|
+
if (ts.isPropertyAssignment(prop)) {
|
|
159
|
+
let text = ts.isIdentifier(prop.name)
|
|
160
|
+
? prop.name.text
|
|
161
|
+
: ts.isStringLiteral(prop.name) ? prop.name.text : null;
|
|
162
|
+
if (text === key) {
|
|
163
|
+
value = prop.initializer.getText();
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
else if (ts.isShorthandPropertyAssignment(prop) && prop.name.text === key) {
|
|
168
|
+
value = prop.name.text;
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
217
172
|
if (value !== null) {
|
|
218
|
-
lines.push(generateAttributeBinding(elementVar, key, value, ''));
|
|
173
|
+
lines.push(generateAttributeBinding(elementVar, key, value, '', ns));
|
|
219
174
|
}
|
|
220
175
|
}
|
|
221
176
|
}
|
|
222
177
|
else {
|
|
223
178
|
for (let i = 0, n = analysis.keys.length; i < n; i++) {
|
|
224
179
|
let key = analysis.keys[i];
|
|
225
|
-
lines.push(generateAttributeBinding(elementVar, key, `${exprCode}.${key}`, ''));
|
|
180
|
+
lines.push(generateAttributeBinding(elementVar, key, `${exprCode}.${key}`, '', ns));
|
|
226
181
|
}
|
|
227
182
|
}
|
|
228
183
|
return lines;
|
package/build/types.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ type Attributes<T extends HTMLElement = Element> = {
|
|
|
17
17
|
type Effect<T> = () => T extends [] ? Renderable<T>[] : Renderable<T>;
|
|
18
18
|
type Element = HTMLElement & Attributes<any>;
|
|
19
19
|
type Primitive = bigint | boolean | null | number | string | undefined;
|
|
20
|
-
type Renderable<T> =
|
|
20
|
+
type Renderable<T> = ArraySlot<T> | DocumentFragment | Effect<T> | Node | NodeList | Primitive | Renderable<T>[];
|
|
21
21
|
type SlotGroup = {
|
|
22
22
|
head: Element;
|
|
23
23
|
tail: Element;
|