@esportsplus/template 0.35.1 → 0.38.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.
@@ -0,0 +1,4 @@
1
+ import { COMPILER_TYPES } from '../constants.js';
2
+ import { ts } from '@esportsplus/typescript';
3
+ declare const analyze: (expr: ts.Expression, checker?: ts.TypeChecker) => COMPILER_TYPES;
4
+ export { analyze };
@@ -1,6 +1,17 @@
1
- import { COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY, COMPILER_TYPES, DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS } from '../constants.js';
1
+ import { COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY, COMPILER_TYPES } from '../constants.js';
2
2
  import { ts } from '@esportsplus/typescript';
3
- function inferCOMPILER_TYPES(expr, checker) {
3
+ function isTypeFunction(type, checker) {
4
+ if (type.isUnion()) {
5
+ for (let i = 0, n = type.types.length; i < n; i++) {
6
+ if (!isTypeFunction(type.types[i], checker)) {
7
+ return false;
8
+ }
9
+ }
10
+ return type.types.length > 0;
11
+ }
12
+ return type.getCallSignatures().length > 0;
13
+ }
14
+ const analyze = (expr, checker) => {
4
15
  while (ts.isParenthesizedExpression(expr)) {
5
16
  expr = expr.expression;
6
17
  }
@@ -30,7 +41,7 @@ function inferCOMPILER_TYPES(expr, checker) {
30
41
  return COMPILER_TYPES.Primitive;
31
42
  }
32
43
  if (ts.isConditionalExpression(expr)) {
33
- let whenFalse = inferCOMPILER_TYPES(expr.whenFalse, checker), whenTrue = inferCOMPILER_TYPES(expr.whenTrue, checker);
44
+ let whenFalse = analyze(expr.whenFalse, checker), whenTrue = analyze(expr.whenTrue, checker);
34
45
  if (whenTrue === whenFalse) {
35
46
  return whenTrue;
36
47
  }
@@ -50,48 +61,5 @@ function inferCOMPILER_TYPES(expr, checker) {
50
61
  }
51
62
  }
52
63
  return COMPILER_TYPES.Unknown;
53
- }
54
- function isTypeFunction(type, checker) {
55
- if (type.isUnion()) {
56
- let allFunctions = true, hasFunction = false;
57
- for (let i = 0, n = type.types.length; i < n; i++) {
58
- if (isTypeFunction(type.types[i], checker)) {
59
- hasFunction = true;
60
- }
61
- else {
62
- allFunctions = false;
63
- }
64
- }
65
- return hasFunction && allFunctions;
66
- }
67
- return type.getCallSignatures().length > 0;
68
- }
69
- const analyzeExpression = (expr, checker) => {
70
- return inferCOMPILER_TYPES(expr, checker);
71
- };
72
- const generateAttributeBinding = (elementVar, name, expr, staticValue, addImport) => {
73
- if (name.startsWith('on') && name.length > 2) {
74
- let event = name.slice(2).toLowerCase(), key = name.toLowerCase();
75
- if (LIFECYCLE_EVENTS.has(key)) {
76
- return `${addImport(key)}(${elementVar}, ${expr});`;
77
- }
78
- if (DIRECT_ATTACH_EVENTS.has(key)) {
79
- return `${addImport('on')}(${elementVar}, '${event}', ${expr});`;
80
- }
81
- return `${addImport('delegate')}(${elementVar}, '${event}', ${expr});`;
82
- }
83
- if (name === 'class') {
84
- return `${addImport('setClass')}(${elementVar}, '${staticValue}', ${expr});`;
85
- }
86
- if (name === COMPILER_TYPES.Attributes) {
87
- return `${addImport('setProperties')}(${elementVar}, ${expr});`;
88
- }
89
- if (name === 'style') {
90
- return `${addImport('setStyle')}(${elementVar}, '${staticValue}', ${expr});`;
91
- }
92
- return `${addImport('setProperty')}(${elementVar}, '${name}', ${expr});`;
93
- };
94
- const generateSpreadBindings = (exprCode, elementVar, addImport) => {
95
- return [`${addImport('setProperties')}(${elementVar}, ${exprCode});`];
96
64
  };
97
- export { analyzeExpression, generateAttributeBinding, generateSpreadBindings };
65
+ export { analyze };
@@ -1,10 +1,12 @@
1
+ import type { ReplacementIntent } from '@esportsplus/typescript/compiler';
1
2
  import { ts } from '@esportsplus/typescript';
2
- import type { ReactiveCallInfo, TemplateInfo } from './ts-parser.js';
3
+ import type { TemplateInfo } from './ts-parser.js';
3
4
  type CodegenResult = {
4
- changed: boolean;
5
- code: string;
5
+ imports: Map<string, string>;
6
+ prepend: string[];
7
+ replacements: ReplacementIntent[];
8
+ templates: Map<string, string>;
6
9
  };
7
- declare const generateCode: (templates: TemplateInfo[], originalCode: string, sourceFile: ts.SourceFile, checker?: ts.TypeChecker, existingAliases?: Map<string, string>) => CodegenResult;
8
- declare const generateReactiveInlining: (calls: ReactiveCallInfo[], code: string, sourceFile: ts.SourceFile, arraySlotAlias: string) => string;
9
- export { generateCode, generateReactiveInlining };
10
+ declare const generateCode: (templates: TemplateInfo[], sourceFile: ts.SourceFile, checker?: ts.TypeChecker, existingAliases?: Map<string, string>) => CodegenResult;
11
+ export { generateCode };
10
12
  export type { CodegenResult };
@@ -1,7 +1,7 @@
1
1
  import { ts } from '@esportsplus/typescript';
2
- import { ast, code as c, imports, uid } from '@esportsplus/typescript/compiler';
3
- import { COMPILER_ENTRYPOINT, COMPILER_TYPES, PACKAGE } from '../constants.js';
4
- import { analyzeExpression, generateAttributeBinding, generateSpreadBindings } from './type-analyzer.js';
2
+ import { ast, uid } from '@esportsplus/typescript/compiler';
3
+ import { COMPILER_ENTRYPOINT, COMPILER_TYPES, DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS } from '../constants.js';
4
+ import { analyze } from './analyzer.js';
5
5
  import parser from './parser.js';
6
6
  const ARROW_EMPTY_PARAMS = /\(\s*\)\s*=>\s*$/;
7
7
  let printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
@@ -18,13 +18,32 @@ function collectNestedTemplateReplacements(ctx, node, exprStart, replacements) {
18
18
  replacements.push({
19
19
  end: node.end - exprStart,
20
20
  newText: generateNestedTemplateCode(ctx, node),
21
- start: node.getStart() - exprStart
21
+ start: node.getStart(ctx.sourceFile) - exprStart
22
22
  });
23
23
  }
24
24
  else {
25
25
  ts.forEachChild(node, child => collectNestedTemplateReplacements(ctx, child, exprStart, replacements));
26
26
  }
27
27
  }
28
+ function generateAttributeBinding(ctx, element, name, expr, staticValue) {
29
+ if (name.startsWith('on') && name.length > 2) {
30
+ let event = name.slice(2).toLowerCase(), key = name.toLowerCase();
31
+ if (LIFECYCLE_EVENTS.has(key)) {
32
+ return `${addImport(ctx, key)}(${element}, ${expr});`;
33
+ }
34
+ if (DIRECT_ATTACH_EVENTS.has(key)) {
35
+ return `${addImport(ctx, 'on')}(${element}, '${event}', ${expr});`;
36
+ }
37
+ return `${addImport(ctx, 'delegate')}(${element}, '${event}', ${expr});`;
38
+ }
39
+ if (name === 'class') {
40
+ return `${addImport(ctx, 'setClass')}(${element}, '${staticValue}', ${expr});`;
41
+ }
42
+ if (name === 'style') {
43
+ return `${addImport(ctx, 'setStyle')}(${element}, '${staticValue}', ${expr});`;
44
+ }
45
+ return `${addImport(ctx, 'setProperty')}(${element}, '${name}', ${expr});`;
46
+ }
28
47
  function generateNestedTemplateCode(ctx, node) {
29
48
  let expressions = [], exprTexts = [], literals = [], template = node.template;
30
49
  if (ts.isNoSubstitutionTemplateLiteral(template)) {
@@ -48,7 +67,7 @@ function generateNodeBinding(ctx, anchor, exprText, exprNode) {
48
67
  if (isNestedHtmlTemplate(exprNode)) {
49
68
  return `${anchor}.parentNode.insertBefore(${generateNestedTemplateCode(ctx, exprNode)}, ${anchor});`;
50
69
  }
51
- let slotType = analyzeExpression(exprNode, ctx.checker);
70
+ let slotType = analyze(exprNode, ctx.checker);
52
71
  switch (slotType) {
53
72
  case COMPILER_TYPES.Effect:
54
73
  return `new ${addImport(ctx, 'EffectSlot')}(${anchor}, ${exprText});`;
@@ -104,14 +123,11 @@ function generateTemplateCode(ctx, { html, slots }, exprTexts, exprNodes, isArro
104
123
  for (let j = 0, m = names.length; j < m; j++) {
105
124
  let name = names[j];
106
125
  if (name === COMPILER_TYPES.Attributes) {
107
- let bindings = generateSpreadBindings(exprTexts[index] || 'undefined', element, n => addImport(ctx, n));
108
- for (let k = 0, o = bindings.length; k < o; k++) {
109
- code.push(bindings[k]);
110
- }
126
+ code.push(`${addImport(ctx, 'setProperties')}(${element}, ${exprTexts[index] || 'undefined'});`);
111
127
  index++;
112
128
  }
113
129
  else {
114
- code.push(generateAttributeBinding(element, name, exprTexts[index++] || 'undefined', slot.attributes.statics[name] || '', n => addImport(ctx, n)));
130
+ code.push(generateAttributeBinding(ctx, element, name, exprTexts[index++] || 'undefined', slot.attributes.statics[name] || ''));
115
131
  }
116
132
  }
117
133
  }
@@ -135,6 +151,14 @@ function getOrCreateTemplateId(ctx, html) {
135
151
  function isNestedHtmlTemplate(expr) {
136
152
  return ts.isTaggedTemplateExpression(expr) && ts.isIdentifier(expr.tag) && expr.tag.text === COMPILER_ENTRYPOINT;
137
153
  }
154
+ function replaceReverse(text, replacements) {
155
+ let sorted = replacements.slice().sort((a, b) => b.start - a.start);
156
+ for (let i = 0, n = sorted.length; i < n; i++) {
157
+ let r = sorted[i];
158
+ text = text.slice(0, r.start) + r.newText + text.slice(r.end);
159
+ }
160
+ return text;
161
+ }
138
162
  function rewriteExpression(ctx, expr) {
139
163
  if (isNestedHtmlTemplate(expr)) {
140
164
  return generateNestedTemplateCode(ctx, expr);
@@ -143,87 +167,65 @@ function rewriteExpression(ctx, expr) {
143
167
  return ctx.printer.printNode(ts.EmitHint.Expression, expr, ctx.sourceFile);
144
168
  }
145
169
  let replacements = [];
146
- collectNestedTemplateReplacements(ctx, expr, expr.getStart(), replacements);
147
- return c.replaceReverse(expr.getText(ctx.sourceFile), replacements);
170
+ collectNestedTemplateReplacements(ctx, expr, expr.getStart(ctx.sourceFile), replacements);
171
+ return replaceReverse(expr.getText(ctx.sourceFile), replacements);
148
172
  }
149
- const generateCode = (templates, originalCode, sourceFile, checker, existingAliases) => {
173
+ const generateCode = (templates, sourceFile, checker, existingAliases) => {
174
+ let result = {
175
+ imports: existingAliases ?? new Map(),
176
+ prepend: [],
177
+ replacements: [],
178
+ templates: new Map()
179
+ };
150
180
  if (templates.length === 0) {
151
- return { changed: false, code: originalCode };
181
+ return result;
152
182
  }
153
183
  let ranges = [];
154
184
  for (let i = 0, n = templates.length; i < n; i++) {
155
185
  let exprs = templates[i].expressions;
156
186
  for (let j = 0, m = exprs.length; j < m; j++) {
157
- ranges.push({ end: exprs[j].end, start: exprs[j].getStart() });
187
+ ranges.push({ end: exprs[j].end, start: exprs[j].getStart(sourceFile) });
158
188
  }
159
189
  }
160
- let rootTemplates = templates.filter(t => !ast.inRange(ranges, t.start, t.end));
190
+ let rootTemplates = templates.filter(t => !ast.inRange(ranges, t.node.getStart(sourceFile), t.node.end));
161
191
  if (rootTemplates.length === 0) {
162
- return { changed: false, code: originalCode };
192
+ return result;
163
193
  }
164
194
  let ctx = {
165
195
  checker,
166
- templates: new Map(),
167
- imports: existingAliases ?? new Map(),
196
+ imports: result.imports,
168
197
  printer,
169
- sourceFile
170
- }, replacements = [], templateAlias = addImport(ctx, 'template');
198
+ sourceFile,
199
+ templates: result.templates
200
+ }, templateAlias = addImport(ctx, 'template');
171
201
  for (let i = 0, n = rootTemplates.length; i < n; i++) {
172
- let exprTexts = [], template = rootTemplates[i];
173
- for (let j = 0, m = template.expressions.length; j < m; j++) {
174
- exprTexts.push(rewriteExpression(ctx, template.expressions[j]));
175
- }
176
- let codeBefore = originalCode.slice(0, template.start), isArrowBody = codeBefore.trimEnd().endsWith('=>'), parsed = parser.parse(template.literals);
177
- if (isArrowBody && (!parsed.slots || parsed.slots.length === 0)) {
178
- let arrowMatch = codeBefore.match(ARROW_EMPTY_PARAMS);
179
- if (arrowMatch) {
180
- replacements.push({
181
- end: template.end,
182
- newText: getOrCreateTemplateId(ctx, parsed.html),
183
- start: template.start - arrowMatch[0].length
184
- });
185
- continue;
186
- }
187
- }
188
- replacements.push({
189
- end: template.end,
190
- newText: generateTemplateCode(ctx, parsed, exprTexts, template.expressions, isArrowBody),
191
- start: template.start
192
- });
193
- }
194
- let changed = replacements.length > 0, code = c.replaceReverse(originalCode, replacements);
195
- if (changed && ctx.templates.size > 0) {
196
- let aliasedImports = [], factories = [];
197
- for (let [name, alias] of ctx.imports) {
198
- aliasedImports.push(`${name} as ${alias}`);
199
- }
200
- for (let [html, id] of ctx.templates) {
201
- factories.push(`const ${id} = ${templateAlias}(\`${html}\`);`);
202
- }
203
- code = imports.modify(code, sourceFile, PACKAGE, {
204
- add: new Set(aliasedImports),
205
- remove: [COMPILER_ENTRYPOINT]
202
+ let template = rootTemplates[i];
203
+ result.replacements.push({
204
+ generate: (sf) => {
205
+ let codeBefore = sf.getFullText().slice(0, template.node.getStart(sf)), exprTexts = [], isArrowBody = codeBefore.trimEnd().endsWith('=>'), localCtx = {
206
+ checker,
207
+ imports: ctx.imports,
208
+ printer,
209
+ sourceFile: sf,
210
+ templates: ctx.templates
211
+ }, parsed = parser.parse(template.literals);
212
+ for (let j = 0, m = template.expressions.length; j < m; j++) {
213
+ exprTexts.push(rewriteExpression(localCtx, template.expressions[j]));
214
+ }
215
+ if (isArrowBody && (!parsed.slots || parsed.slots.length === 0)) {
216
+ let arrowMatch = codeBefore.match(ARROW_EMPTY_PARAMS);
217
+ if (arrowMatch) {
218
+ return getOrCreateTemplateId(localCtx, parsed.html);
219
+ }
220
+ }
221
+ return generateTemplateCode(localCtx, parsed, exprTexts, template.expressions, isArrowBody);
222
+ },
223
+ node: template.node
206
224
  });
207
- code = factories.join('\n') + '\n\n' + code;
208
- }
209
- return { changed, code };
210
- };
211
- const generateReactiveInlining = (calls, code, sourceFile, arraySlotAlias) => {
212
- if (calls.length === 0) {
213
- return code;
214
225
  }
215
- let replacements = [];
216
- for (let i = 0, n = calls.length; i < n; i++) {
217
- let call = calls[i];
218
- replacements.push({
219
- end: call.end,
220
- newText: `new ${arraySlotAlias}(
221
- ${printer.printNode(ts.EmitHint.Expression, call.arrayArg, sourceFile)},
222
- ${printer.printNode(ts.EmitHint.Expression, call.callbackArg, sourceFile)}
223
- )`,
224
- start: call.start
225
- });
226
+ for (let [html, id] of ctx.templates) {
227
+ result.prepend.push(`const ${id} = ${templateAlias}(\`${html}\`);`);
226
228
  }
227
- return c.replaceReverse(code, replacements);
229
+ return result;
228
230
  };
229
- export { generateCode, generateReactiveInlining };
231
+ export { generateCode };
@@ -1,8 +1,5 @@
1
- import { ts } from '@esportsplus/typescript';
2
- type TransformResult = {
3
- changed: boolean;
4
- code: string;
5
- sourceFile: ts.SourceFile;
6
- };
7
- declare const transform: (sourceFile: ts.SourceFile, program: ts.Program) => TransformResult;
8
- export { transform };
1
+ import type { Plugin } from '@esportsplus/typescript/compiler';
2
+ import reactiveInliningPlugin from './reactive-inlining.js';
3
+ declare const templatePlugin: Plugin;
4
+ export default templatePlugin;
5
+ export { reactiveInliningPlugin, templatePlugin };
@@ -1,50 +1,38 @@
1
- import { ts } from '@esportsplus/typescript';
2
- import { code as c, imports, uid } from '@esportsplus/typescript/compiler';
3
- import { COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY, PACKAGE } from '../constants.js';
4
- import { generateCode, generateReactiveInlining } from './codegen.js';
5
- import { findHtmlTemplates, findReactiveCalls } from './ts-parser.js';
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, existingAliases = new Map(), reactiveCalls = findReactiveCalls(sourceFile, checker), result = code;
22
- if (reactiveCalls.length > 0) {
23
- let arraySlotAlias = uid('ArraySlot');
24
- changed = true;
25
- existingAliases.set('ArraySlot', arraySlotAlias);
26
- result = generateReactiveInlining(reactiveCalls, result, sourceFile, arraySlotAlias);
27
- sourceFile = ts.createSourceFile(sourceFile.fileName, result, sourceFile.languageVersion, true);
28
- }
29
- let templates = findHtmlTemplates(sourceFile, checker);
30
- if (templates.length > 0) {
31
- let codegenResult = generateCode(templates, result, sourceFile, checker, existingAliases);
32
- if (codegenResult.changed) {
33
- changed = true;
34
- codegenChanged = true;
35
- result = codegenResult.code;
1
+ import { COMPILER_ENTRYPOINT, PACKAGE } from '../constants.js';
2
+ import { generateCode } from './codegen.js';
3
+ import reactiveInliningPlugin, { SHARED_KEY } from './reactive-inlining.js';
4
+ import { findHtmlTemplates } from './ts-parser.js';
5
+ const PATTERNS = [`${COMPILER_ENTRYPOINT}\``];
6
+ const templatePlugin = {
7
+ patterns: PATTERNS,
8
+ transform: (ctx) => {
9
+ let templates = findHtmlTemplates(ctx.sourceFile, ctx.checker);
10
+ if (templates.length === 0) {
11
+ return {};
12
+ }
13
+ let existingAliases = new Map(), existingArraySlotAlias = ctx.shared.get(SHARED_KEY);
14
+ if (existingArraySlotAlias) {
15
+ existingAliases.set('ArraySlot', existingArraySlotAlias);
16
+ }
17
+ let result = generateCode(templates, ctx.sourceFile, ctx.checker, existingAliases);
18
+ if (result.replacements.length === 0) {
19
+ return {};
36
20
  }
37
- }
38
- if (existingAliases.size > 0 && !codegenChanged) {
39
21
  let aliasedImports = [];
40
- for (let [name, alias] of existingAliases) {
22
+ for (let [name, alias] of result.imports) {
41
23
  aliasedImports.push(`${name} as ${alias}`);
42
24
  }
43
- result = imports.modify(result, sourceFile, PACKAGE, { add: aliasedImports });
44
- }
45
- if (changed) {
46
- sourceFile = ts.createSourceFile(sourceFile.fileName, result, sourceFile.languageVersion, true);
25
+ let imports = [{
26
+ add: aliasedImports,
27
+ package: PACKAGE,
28
+ remove: [COMPILER_ENTRYPOINT]
29
+ }];
30
+ return {
31
+ imports,
32
+ prepend: result.prepend,
33
+ replacements: result.replacements
34
+ };
47
35
  }
48
- return { changed, code: result, sourceFile };
49
36
  };
50
- export { transform };
37
+ export default templatePlugin;
38
+ export { reactiveInliningPlugin, templatePlugin };
@@ -1,3 +1,3 @@
1
1
  import { plugin } from '@esportsplus/typescript/compiler';
2
- import { transform } from '../index.js';
3
- export default plugin.tsc(transform);
2
+ import { reactiveInliningPlugin, templatePlugin } from '../index.js';
3
+ export default plugin.tsc([reactiveInliningPlugin, templatePlugin]);
@@ -1,13 +1,13 @@
1
1
  declare const _default: ({ root }?: {
2
2
  root?: string;
3
3
  }) => {
4
- configResolved(config: import("vite").ResolvedConfig): void;
5
- enforce: string;
4
+ configResolved: (config: unknown) => void;
5
+ enforce: "pre";
6
6
  name: string;
7
- transform(code: string, id: string): {
7
+ transform: (code: string, id: string) => {
8
8
  code: string;
9
9
  map: null;
10
10
  } | null;
11
- watchChange(id: string): void;
11
+ watchChange: (id: string) => void;
12
12
  };
13
13
  export default _default;
@@ -1,7 +1,7 @@
1
1
  import { plugin } from '@esportsplus/typescript/compiler';
2
2
  import { PACKAGE } from '../../constants.js';
3
- import { transform } from '../index.js';
3
+ import { reactiveInliningPlugin, templatePlugin } from '../index.js';
4
4
  export default plugin.vite({
5
5
  name: PACKAGE,
6
- transform
6
+ plugins: [reactiveInliningPlugin, templatePlugin]
7
7
  });
@@ -0,0 +1,5 @@
1
+ import type { Plugin } from '@esportsplus/typescript/compiler';
2
+ declare const SHARED_KEY = "template:arraySlotAlias";
3
+ declare const plugin: Plugin;
4
+ export default plugin;
5
+ export { SHARED_KEY };
@@ -0,0 +1,75 @@
1
+ import { ts } from '@esportsplus/typescript';
2
+ import { uid } from '@esportsplus/typescript/compiler';
3
+ import { COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY, PACKAGE } from '../constants.js';
4
+ const PATTERNS = [`${COMPILER_ENTRYPOINT}.${COMPILER_ENTRYPOINT_REACTIVITY}`];
5
+ const SHARED_KEY = 'template:arraySlotAlias';
6
+ let printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
7
+ function isHtmlFromPackage(node, checker) {
8
+ if (node.text !== COMPILER_ENTRYPOINT) {
9
+ return false;
10
+ }
11
+ if (!checker) {
12
+ return true;
13
+ }
14
+ let symbol = checker.getSymbolAtLocation(node);
15
+ if (!symbol) {
16
+ return true;
17
+ }
18
+ if (symbol.flags & ts.SymbolFlags.Alias) {
19
+ symbol = checker.getAliasedSymbol(symbol);
20
+ }
21
+ let declarations = symbol.getDeclarations();
22
+ if (!declarations || declarations.length === 0) {
23
+ return true;
24
+ }
25
+ for (let i = 0, n = declarations.length; i < n; i++) {
26
+ let filename = declarations[i].getSourceFile().fileName;
27
+ if (filename.includes(PACKAGE) || filename.includes('@esportsplus/template')) {
28
+ return true;
29
+ }
30
+ }
31
+ return false;
32
+ }
33
+ function visit(node, calls, checker) {
34
+ if (ts.isCallExpression(node) &&
35
+ ts.isPropertyAccessExpression(node.expression) &&
36
+ ts.isIdentifier(node.expression.expression) &&
37
+ node.expression.name.text === COMPILER_ENTRYPOINT_REACTIVITY &&
38
+ node.arguments.length === 2 &&
39
+ isHtmlFromPackage(node.expression.expression, checker)) {
40
+ calls.push({
41
+ arrayArg: node.arguments[0],
42
+ callbackArg: node.arguments[1],
43
+ node
44
+ });
45
+ }
46
+ ts.forEachChild(node, child => visit(child, calls, checker));
47
+ }
48
+ const plugin = {
49
+ patterns: PATTERNS,
50
+ transform: (ctx) => {
51
+ let calls = [];
52
+ visit(ctx.sourceFile, calls, ctx.checker);
53
+ if (calls.length === 0) {
54
+ return {};
55
+ }
56
+ let arraySlotAlias = uid('ArraySlot'), replacements = [];
57
+ ctx.shared.set(SHARED_KEY, arraySlotAlias);
58
+ for (let i = 0, n = calls.length; i < n; i++) {
59
+ let call = calls[i];
60
+ replacements.push({
61
+ generate: (sourceFile) => `new ${arraySlotAlias}(${printer.printNode(ts.EmitHint.Expression, call.arrayArg, sourceFile)}, ${printer.printNode(ts.EmitHint.Expression, call.callbackArg, sourceFile)})`,
62
+ node: call.node
63
+ });
64
+ }
65
+ return {
66
+ imports: [{
67
+ add: [`ArraySlot as ${arraySlotAlias}`],
68
+ package: PACKAGE
69
+ }],
70
+ replacements
71
+ };
72
+ }
73
+ };
74
+ export default plugin;
75
+ export { SHARED_KEY };
@@ -19,8 +19,8 @@ function isHtmlFromPackage(node, checker) {
19
19
  return true;
20
20
  }
21
21
  for (let i = 0, n = declarations.length; i < n; i++) {
22
- let fileName = declarations[i].getSourceFile().fileName;
23
- if (fileName.includes(PACKAGE) || fileName.includes('@esportsplus/template')) {
22
+ let filename = declarations[i].getSourceFile().fileName;
23
+ if (filename.includes(PACKAGE) || filename.includes('@esportsplus/template')) {
24
24
  return true;
25
25
  }
26
26
  }
package/package.json CHANGED
@@ -2,14 +2,14 @@
2
2
  "author": "ICJR",
3
3
  "dependencies": {
4
4
  "@esportsplus/queue": "^0.2.0",
5
- "@esportsplus/reactivity": "^0.27.0",
5
+ "@esportsplus/reactivity": "^0.28.0",
6
+ "@esportsplus/typescript": "^0.25.0",
6
7
  "@esportsplus/utilities": "^0.27.2",
7
8
  "serve": "^14.2.5"
8
9
  },
9
10
  "devDependencies": {
10
- "@esportsplus/typescript": "^0.22.0",
11
11
  "@types/node": "^25.0.3",
12
- "vite": "^7.3.0",
12
+ "vite": "^7.3.1",
13
13
  "vite-tsconfig-paths": "^6.0.3"
14
14
  },
15
15
  "exports": {
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "type": "module",
37
37
  "types": "./build/index.d.ts",
38
- "version": "0.35.1",
38
+ "version": "0.38.0",
39
39
  "scripts": {
40
40
  "build": "tsc",
41
41
  "build:test": "vite build --config test/vite.config.ts",