@esportsplus/template 0.31.6 → 0.32.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.
@@ -12,8 +12,7 @@ declare const getNames: () => {
12
12
  event: string;
13
13
  slot: string;
14
14
  };
15
- declare const initNamespace: () => void;
16
15
  declare const needsArraySlotImport: (sourceFile: ts.SourceFile) => boolean;
17
16
  declare const setTypeChecker: (checker: ts.TypeChecker | undefined) => void;
18
- export { addArraySlotImport, generateCode, generateReactiveInlining, getNames, initNamespace, needsArraySlotImport, setTypeChecker };
17
+ export { addArraySlotImport, generateCode, generateReactiveInlining, getNames, needsArraySlotImport, setTypeChecker };
19
18
  export type { CodegenResult };
@@ -1,10 +1,9 @@
1
- import { applyReplacementsReverse, uid } from '@esportsplus/typescript/transformer';
1
+ import { addImport, applyReplacementsReverse, uid } from '@esportsplus/typescript/transformer';
2
2
  import { analyzeExpression, generateAttributeBinding, generateSpreadBindings } from './type-analyzer.js';
3
3
  import { ts } from '@esportsplus/typescript';
4
4
  import parser from './parser.js';
5
5
  const ARROW_EMPTY_PARAMS = /\(\s*\)\s*=>\s*$/;
6
- const TEMPLATE_IMPORT = /import\s+\{[^}]*\}\s+from\s+['"]@esportsplus\/template['"];?\s*\n?/g;
7
- let currentChecker, hoistedFactories = new Map(), htmlToTemplateId = new Map(), ns = '';
6
+ let currentChecker, hoistedFactories = new Map(), htmlToTemplateId = new Map(), nameArraySlot = '', nameAttr = '', nameEffectSlot = '', nameEvent = '', nameSlot = '', nameTemplate = '', needsArraySlot = false, needsAttr = false, needsEffectSlot = false, needsEvent = false, needsSlot = false;
8
7
  function collectNestedTemplateReplacements(node, exprStart, sourceFile, replacements) {
9
8
  if (isNestedHtmlTemplate(node)) {
10
9
  replacements.push({
@@ -18,7 +17,24 @@ function collectNestedTemplateReplacements(node, exprStart, sourceFile, replacem
18
17
  }
19
18
  }
20
19
  function generateImports() {
21
- return `import * as ${ns} from '@esportsplus/template';`;
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}`);
35
+ }
36
+ specifiers.push(`template as ${nameTemplate}`);
37
+ return `import { ${specifiers.join(', ')} } from '@esportsplus/template';`;
22
38
  }
23
39
  function generateNestedTemplateCode(node, sourceFile) {
24
40
  let expressions = [], exprTexts = [], literals = [], template = node.template;
@@ -38,7 +54,8 @@ function generateNestedTemplateCode(node, sourceFile) {
38
54
  }
39
55
  function generateNodeBinding(anchor, exprText, exprNode, sourceFile) {
40
56
  if (!exprNode) {
41
- return `${ns}.slot(${anchor}, ${exprText});`;
57
+ needsSlot = true;
58
+ return `${nameSlot}(${anchor}, ${exprText});`;
42
59
  }
43
60
  if (isNestedHtmlTemplate(exprNode)) {
44
61
  return `${anchor}.parentNode.insertBefore(${generateNestedTemplateCode(exprNode, sourceFile)}, ${anchor});`;
@@ -46,15 +63,18 @@ function generateNodeBinding(anchor, exprText, exprNode, sourceFile) {
46
63
  let slotType = analyzeExpression(exprNode, currentChecker);
47
64
  switch (slotType) {
48
65
  case 'effect':
49
- return `new ${ns}.EffectSlot(${anchor}, ${exprText});`;
66
+ needsEffectSlot = true;
67
+ return `new ${nameEffectSlot}(${anchor}, ${exprText});`;
50
68
  case 'array-slot':
51
- return `new ${ns}.ArraySlot(${anchor}, ${exprText});`;
69
+ needsArraySlot = true;
70
+ return `new ${nameArraySlot}(${anchor}, ${exprText});`;
52
71
  case 'static':
53
72
  return `${anchor}.textContent = ${exprText};`;
54
73
  case 'document-fragment':
55
74
  return `${anchor}.parentNode.insertBefore(${exprText}, ${anchor});`;
56
75
  default:
57
- return `${ns}.slot(${anchor}, ${exprText});`;
76
+ needsSlot = true;
77
+ return `${nameSlot}(${anchor}, ${exprText});`;
58
78
  }
59
79
  }
60
80
  function generateTemplateCode({ html, slots }, exprTexts, exprNodes, sourceFile, isArrowBody) {
@@ -97,12 +117,14 @@ function generateTemplateCode({ html, slots }, exprTexts, exprNodes, sourceFile,
97
117
  if (name === 'spread') {
98
118
  let bindings = generateSpreadBindings(exprNodes[index], exprTexts[index] || 'undefined', elementVar, sourceFile, currentChecker);
99
119
  for (let k = 0, o = bindings.length; k < o; k++) {
120
+ trackBindingUsage(bindings[k]);
100
121
  code.push(bindings[k]);
101
122
  }
102
123
  index++;
103
124
  }
104
125
  else {
105
126
  let binding = generateAttributeBinding(elementVar, name, exprTexts[index++] || 'undefined', slot.attributes.statics[name] || '');
127
+ trackBindingUsage(binding);
106
128
  code.push(binding);
107
129
  }
108
130
  }
@@ -198,13 +220,34 @@ function rewriteExpression(expr, sourceFile) {
198
220
  collectNestedTemplateReplacements(expr, exprStart, sourceFile, replacements);
199
221
  return applyReplacementsReverse(expr.getText(sourceFile), replacements);
200
222
  }
223
+ function trackBindingUsage(binding) {
224
+ if (binding.startsWith(nameEvent + '.')) {
225
+ needsEvent = true;
226
+ }
227
+ else if (binding.startsWith(nameAttr + '.')) {
228
+ needsAttr = true;
229
+ }
230
+ }
201
231
  const addArraySlotImport = (code) => {
202
- return `import * as ${ns} from '@esportsplus/template';\n\n` + code.replace(TEMPLATE_IMPORT, '');
232
+ return addImport(code, '@esportsplus/template', ['ArraySlot']);
203
233
  };
204
234
  const generateCode = (templates, originalCode, sourceFile) => {
205
235
  if (templates.length === 0) {
206
236
  return { changed: false, code: originalCode };
207
237
  }
238
+ hoistedFactories.clear();
239
+ htmlToTemplateId.clear();
240
+ nameArraySlot = uid('ArraySlot');
241
+ nameAttr = uid('attr');
242
+ nameEffectSlot = uid('EffectSlot');
243
+ nameEvent = uid('event');
244
+ nameSlot = uid('slot');
245
+ nameTemplate = uid('template');
246
+ needsArraySlot = false;
247
+ needsAttr = false;
248
+ needsEffectSlot = false;
249
+ needsEvent = false;
250
+ needsSlot = false;
208
251
  let rootTemplates = templates.filter(t => !isNestedTemplate(t, templates));
209
252
  if (rootTemplates.length === 0) {
210
253
  return { changed: false, code: originalCode };
@@ -237,9 +280,8 @@ const generateCode = (templates, originalCode, sourceFile) => {
237
280
  if (changed && hoistedFactories.size > 0) {
238
281
  let factories = [];
239
282
  for (let [id, html] of hoistedFactories) {
240
- factories.push(`const ${id} = ${ns}.template(\`${html}\`);`);
283
+ factories.push(`const ${id} = ${nameTemplate}(\`${html}\`);`);
241
284
  }
242
- code = code.replace(TEMPLATE_IMPORT, '');
243
285
  code = generateImports() + '\n\n' + factories.join('\n') + '\n\n' + code;
244
286
  }
245
287
  return { changed, code };
@@ -252,7 +294,7 @@ const generateReactiveInlining = (calls, code, sourceFile) => {
252
294
  for (let i = calls.length - 1; i >= 0; i--) {
253
295
  let call = calls[i];
254
296
  result = result.slice(0, call.start);
255
- result += `new ${ns}.ArraySlot(
297
+ result += `new ${nameArraySlot}(
256
298
  ${printer.printNode(ts.EmitHint.Expression, call.arrayArg, sourceFile)},
257
299
  ${printer.printNode(ts.EmitHint.Expression, call.callbackArg, sourceFile)}
258
300
  )`;
@@ -261,19 +303,14 @@ const generateReactiveInlining = (calls, code, sourceFile) => {
261
303
  return result;
262
304
  };
263
305
  const getNames = () => ({
264
- attr: `${ns}.attributes`,
265
- event: `${ns}.event`,
266
- slot: `${ns}.slot`
306
+ attr: nameAttr,
307
+ event: nameEvent,
308
+ slot: nameSlot
267
309
  });
268
- const initNamespace = () => {
269
- hoistedFactories.clear();
270
- htmlToTemplateId.clear();
271
- ns = uid('t');
272
- };
273
310
  const needsArraySlotImport = (sourceFile) => {
274
311
  return hasArraySlotUsage(sourceFile) && !hasArraySlotImport(sourceFile);
275
312
  };
276
313
  const setTypeChecker = (checker) => {
277
314
  currentChecker = checker;
278
315
  };
279
- export { addArraySlotImport, generateCode, generateReactiveInlining, getNames, initNamespace, needsArraySlotImport, setTypeChecker };
316
+ export { addArraySlotImport, generateCode, generateReactiveInlining, getNames, needsArraySlotImport, setTypeChecker };
@@ -1,19 +1,18 @@
1
1
  import { mightNeedTransform } from '@esportsplus/typescript/transformer';
2
- import { addArraySlotImport, generateCode, generateReactiveInlining, initNamespace, needsArraySlotImport, setTypeChecker } from './codegen.js';
2
+ import { addArraySlotImport, generateCode, generateReactiveInlining, needsArraySlotImport, setTypeChecker } from './codegen.js';
3
3
  import { findHtmlTemplates, findReactiveCalls } from './ts-parser.js';
4
4
  import { ts } from '@esportsplus/typescript';
5
5
  const PATTERNS = ['html`', 'html.reactive'];
6
6
  function createTransformer(program) {
7
- let printer = ts.createPrinter(), typeChecker = program.getTypeChecker();
7
+ let typeChecker = program.getTypeChecker();
8
8
  return (_context) => {
9
9
  return (sourceFile) => {
10
- let code = printer.printFile(sourceFile);
10
+ let code = sourceFile.getFullText();
11
11
  if (!mightNeedTransform(code, { patterns: PATTERNS })) {
12
12
  return sourceFile;
13
13
  }
14
- let reparsed = ts.createSourceFile(sourceFile.fileName, code, sourceFile.languageVersion, true);
15
14
  setTypeChecker(typeChecker);
16
- let result = transformCode(code, reparsed);
15
+ let result = transformCode(code, sourceFile);
17
16
  if (!result.changed) {
18
17
  return sourceFile;
19
18
  }
@@ -23,7 +22,6 @@ function createTransformer(program) {
23
22
  }
24
23
  function transformCode(code, sourceFile) {
25
24
  let changed = false, result = code;
26
- initNamespace();
27
25
  let reactiveCalls = findReactiveCalls(sourceFile);
28
26
  if (reactiveCalls.length > 0) {
29
27
  result = generateReactiveInlining(reactiveCalls, result, sourceFile);
@@ -47,18 +45,18 @@ function transformCode(code, sourceFile) {
47
45
  return { changed, code: result, sourceFile };
48
46
  }
49
47
  const transform = (sourceFile, program) => {
50
- let printer = ts.createPrinter(), code = printer.printFile(sourceFile);
48
+ let code = sourceFile.getFullText();
51
49
  if (!mightNeedTransform(code, { patterns: PATTERNS })) {
52
50
  return { changed: false, code, sourceFile };
53
51
  }
54
- let reparsed = ts.createSourceFile(sourceFile.fileName, code, sourceFile.languageVersion, true);
55
52
  let programSourceFile = program.getSourceFile(sourceFile.fileName);
56
53
  if (programSourceFile) {
57
54
  setTypeChecker(program.getTypeChecker());
55
+ sourceFile = programSourceFile;
58
56
  }
59
57
  else {
60
58
  setTypeChecker(undefined);
61
59
  }
62
- return transformCode(code, reparsed);
60
+ return transformCode(code, sourceFile);
63
61
  };
64
62
  export { createTransformer, mightNeedTransform, PATTERNS, transform };
@@ -1,4 +1,4 @@
1
- import { createTransformer, mightNeedTransform, PATTERNS } from '../index.js';
1
+ import { mightNeedTransform, PATTERNS, transform } from '../index.js';
2
2
  import { program, TRANSFORM_PATTERN } from '@esportsplus/typescript/transformer';
3
3
  import { ts } from '@esportsplus/typescript';
4
4
  export default (options) => {
@@ -17,14 +17,11 @@ export default (options) => {
17
17
  return null;
18
18
  }
19
19
  try {
20
- let p = program.get(root), printer = ts.createPrinter(), sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true), transformer = createTransformer(p), result = ts.transform(sourceFile, [transformer]), transformed = result.transformed[0];
21
- if (transformed === sourceFile) {
22
- result.dispose();
20
+ let sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true), result = transform(sourceFile, program.get(root));
21
+ if (!result.changed) {
23
22
  return null;
24
23
  }
25
- let output = printer.printFile(transformed);
26
- result.dispose();
27
- return { code: output, map: null };
24
+ return { code: result.code, map: null };
28
25
  }
29
26
  catch (error) {
30
27
  console.error(`@esportsplus/template: Error transforming ${id}:`, error);
package/package.json CHANGED
@@ -2,12 +2,12 @@
2
2
  "author": "ICJR",
3
3
  "dependencies": {
4
4
  "@esportsplus/queue": "^0.2.0",
5
- "@esportsplus/reactivity": "^0.24.5",
5
+ "@esportsplus/reactivity": "^0.25.2",
6
6
  "@esportsplus/utilities": "^0.27.2",
7
7
  "serve": "^14.2.5"
8
8
  },
9
9
  "devDependencies": {
10
- "@esportsplus/typescript": "^0.17.0",
10
+ "@esportsplus/typescript": "^0.17.3",
11
11
  "@types/node": "^25.0.3",
12
12
  "vite": "^7.3.0",
13
13
  "vite-tsconfig-paths": "^6.0.3"
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "type": "module",
42
42
  "types": "./build/index.d.ts",
43
- "version": "0.31.6",
43
+ "version": "0.32.0",
44
44
  "scripts": {
45
45
  "build": "tsc",
46
46
  "build:test": "vite build --config test/vite.config.ts",
@@ -1,4 +1,4 @@
1
- import { applyReplacementsReverse, uid } from '@esportsplus/typescript/transformer';
1
+ import { addImport, applyReplacementsReverse, uid } from '@esportsplus/typescript/transformer';
2
2
  import type { Replacement } from '@esportsplus/typescript/transformer';
3
3
  import type { ReactiveCallInfo, TemplateInfo } from './ts-parser';
4
4
  import { analyzeExpression, generateAttributeBinding, generateSpreadBindings } from './type-analyzer';
@@ -33,13 +33,21 @@ type ParseResult = {
33
33
 
34
34
  const ARROW_EMPTY_PARAMS = /\(\s*\)\s*=>\s*$/;
35
35
 
36
- const TEMPLATE_IMPORT = /import\s+\{[^}]*\}\s+from\s+['"]@esportsplus\/template['"];?\s*\n?/g;
37
-
38
36
 
39
37
  let currentChecker: ts.TypeChecker | undefined,
40
38
  hoistedFactories = new Map<string, string>(),
41
39
  htmlToTemplateId = new Map<string, string>(),
42
- ns = '';
40
+ nameArraySlot = '',
41
+ nameAttr = '',
42
+ nameEffectSlot = '',
43
+ nameEvent = '',
44
+ nameSlot = '',
45
+ nameTemplate = '',
46
+ needsArraySlot = false,
47
+ needsAttr = false,
48
+ needsEffectSlot = false,
49
+ needsEvent = false,
50
+ needsSlot = false;
43
51
 
44
52
 
45
53
  function collectNestedTemplateReplacements(
@@ -61,7 +69,31 @@ function collectNestedTemplateReplacements(
61
69
  }
62
70
 
63
71
  function generateImports(): string {
64
- return `import * as ${ns} from '@esportsplus/template';`;
72
+ let specifiers: string[] = [];
73
+
74
+ if (needsArraySlot) {
75
+ specifiers.push(`ArraySlot as ${nameArraySlot}`);
76
+ }
77
+
78
+ if (needsEffectSlot) {
79
+ specifiers.push(`EffectSlot as ${nameEffectSlot}`);
80
+ }
81
+
82
+ if (needsAttr) {
83
+ specifiers.push(`attributes as ${nameAttr}`);
84
+ }
85
+
86
+ if (needsEvent) {
87
+ specifiers.push(`event as ${nameEvent}`);
88
+ }
89
+
90
+ if (needsSlot) {
91
+ specifiers.push(`slot as ${nameSlot}`);
92
+ }
93
+
94
+ specifiers.push(`template as ${nameTemplate}`);
95
+
96
+ return `import { ${specifiers.join(', ')} } from '@esportsplus/template';`;
65
97
  }
66
98
 
67
99
  function generateNestedTemplateCode(node: ts.TaggedTemplateExpression, sourceFile: ts.SourceFile): string {
@@ -96,7 +128,8 @@ function generateNestedTemplateCode(node: ts.TaggedTemplateExpression, sourceFil
96
128
 
97
129
  function generateNodeBinding(anchor: string, exprText: string, exprNode: ts.Expression | undefined, sourceFile: ts.SourceFile): string {
98
130
  if (!exprNode) {
99
- return `${ns}.slot(${anchor}, ${exprText});`;
131
+ needsSlot = true;
132
+ return `${nameSlot}(${anchor}, ${exprText});`;
100
133
  }
101
134
 
102
135
  if (isNestedHtmlTemplate(exprNode)) {
@@ -107,10 +140,12 @@ function generateNodeBinding(anchor: string, exprText: string, exprNode: ts.Expr
107
140
 
108
141
  switch (slotType) {
109
142
  case 'effect':
110
- return `new ${ns}.EffectSlot(${anchor}, ${exprText});`;
143
+ needsEffectSlot = true;
144
+ return `new ${nameEffectSlot}(${anchor}, ${exprText});`;
111
145
 
112
146
  case 'array-slot':
113
- return `new ${ns}.ArraySlot(${anchor}, ${exprText});`;
147
+ needsArraySlot = true;
148
+ return `new ${nameArraySlot}(${anchor}, ${exprText});`;
114
149
 
115
150
  case 'static':
116
151
  return `${anchor}.textContent = ${exprText};`;
@@ -119,7 +154,8 @@ function generateNodeBinding(anchor: string, exprText: string, exprNode: ts.Expr
119
154
  return `${anchor}.parentNode.insertBefore(${exprText}, ${anchor});`;
120
155
 
121
156
  default:
122
- return `${ns}.slot(${anchor}, ${exprText});`;
157
+ needsSlot = true;
158
+ return `${nameSlot}(${anchor}, ${exprText});`;
123
159
  }
124
160
  }
125
161
 
@@ -201,6 +237,7 @@ function generateTemplateCode(
201
237
  );
202
238
 
203
239
  for (let k = 0, o = bindings.length; k < o; k++) {
240
+ trackBindingUsage(bindings[k]);
204
241
  code.push(bindings[k]);
205
242
  }
206
243
 
@@ -214,6 +251,7 @@ function generateTemplateCode(
214
251
  slot.attributes.statics[name] || ''
215
252
  );
216
253
 
254
+ trackBindingUsage(binding);
217
255
  code.push(binding);
218
256
  }
219
257
  }
@@ -343,11 +381,18 @@ function rewriteExpression(expr: ts.Expression, sourceFile: ts.SourceFile): stri
343
381
  return applyReplacementsReverse(expr.getText(sourceFile), replacements);
344
382
  }
345
383
 
384
+ function trackBindingUsage(binding: string): void {
385
+ if (binding.startsWith(nameEvent + '.')) {
386
+ needsEvent = true;
387
+ }
388
+ else if (binding.startsWith(nameAttr + '.')) {
389
+ needsAttr = true;
390
+ }
391
+ }
346
392
 
347
393
 
348
394
  const addArraySlotImport = (code: string): string => {
349
- // Strip original @esportsplus/template imports (they lose symbol bindings in TS 5.9.3)
350
- return `import * as ${ns} from '@esportsplus/template';\n\n` + code.replace(TEMPLATE_IMPORT, '');
395
+ return addImport(code, '@esportsplus/template', ['ArraySlot']);
351
396
  };
352
397
 
353
398
  const generateCode = (templates: TemplateInfo[], originalCode: string, sourceFile: ts.SourceFile): CodegenResult => {
@@ -355,6 +400,20 @@ const generateCode = (templates: TemplateInfo[], originalCode: string, sourceFil
355
400
  return { changed: false, code: originalCode };
356
401
  }
357
402
 
403
+ hoistedFactories.clear();
404
+ htmlToTemplateId.clear();
405
+ nameArraySlot = uid('ArraySlot');
406
+ nameAttr = uid('attr');
407
+ nameEffectSlot = uid('EffectSlot');
408
+ nameEvent = uid('event');
409
+ nameSlot = uid('slot');
410
+ nameTemplate = uid('template');
411
+ needsArraySlot = false;
412
+ needsAttr = false;
413
+ needsEffectSlot = false;
414
+ needsEvent = false;
415
+ needsSlot = false;
416
+
358
417
  let rootTemplates = templates.filter(t => !isNestedTemplate(t, templates));
359
418
 
360
419
  if (rootTemplates.length === 0) {
@@ -409,11 +468,9 @@ const generateCode = (templates: TemplateInfo[], originalCode: string, sourceFil
409
468
  let factories: string[] = [];
410
469
 
411
470
  for (let [id, html] of hoistedFactories) {
412
- factories.push(`const ${id} = ${ns}.template(\`${html}\`);`);
471
+ factories.push(`const ${id} = ${nameTemplate}(\`${html}\`);`);
413
472
  }
414
473
 
415
- // Strip original @esportsplus/template imports (they lose symbol bindings in TS 5.9.3)
416
- code = code.replace(TEMPLATE_IMPORT, '');
417
474
  code = generateImports() + '\n\n' + factories.join('\n') + '\n\n' + code;
418
475
  }
419
476
 
@@ -432,7 +489,7 @@ const generateReactiveInlining = (calls: ReactiveCallInfo[], code: string, sourc
432
489
  let call = calls[i];
433
490
 
434
491
  result = result.slice(0, call.start);
435
- result += `new ${ns}.ArraySlot(
492
+ result += `new ${nameArraySlot}(
436
493
  ${printer.printNode(ts.EmitHint.Expression, call.arrayArg, sourceFile)},
437
494
  ${printer.printNode(ts.EmitHint.Expression, call.callbackArg, sourceFile)}
438
495
  )`;
@@ -443,17 +500,11 @@ const generateReactiveInlining = (calls: ReactiveCallInfo[], code: string, sourc
443
500
  };
444
501
 
445
502
  const getNames = () => ({
446
- attr: `${ns}.attributes`,
447
- event: `${ns}.event`,
448
- slot: `${ns}.slot`
503
+ attr: nameAttr,
504
+ event: nameEvent,
505
+ slot: nameSlot
449
506
  });
450
507
 
451
- const initNamespace = (): void => {
452
- hoistedFactories.clear();
453
- htmlToTemplateId.clear();
454
- ns = uid('t');
455
- };
456
-
457
508
  const needsArraySlotImport = (sourceFile: ts.SourceFile): boolean => {
458
509
  return hasArraySlotUsage(sourceFile) && !hasArraySlotImport(sourceFile);
459
510
  };
@@ -463,5 +514,5 @@ const setTypeChecker = (checker: ts.TypeChecker | undefined): void => {
463
514
  };
464
515
 
465
516
 
466
- export { addArraySlotImport, generateCode, generateReactiveInlining, getNames, initNamespace, needsArraySlotImport, setTypeChecker };
517
+ export { addArraySlotImport, generateCode, generateReactiveInlining, getNames, needsArraySlotImport, setTypeChecker };
467
518
  export type { CodegenResult };
@@ -1,5 +1,5 @@
1
1
  import { mightNeedTransform } from '@esportsplus/typescript/transformer';
2
- import { addArraySlotImport, generateCode, generateReactiveInlining, initNamespace, needsArraySlotImport, setTypeChecker } from './codegen';
2
+ import { addArraySlotImport, generateCode, generateReactiveInlining, needsArraySlotImport, setTypeChecker } from './codegen';
3
3
  import { findHtmlTemplates, findReactiveCalls } from './ts-parser';
4
4
  import { ts } from '@esportsplus/typescript';
5
5
 
@@ -15,24 +15,19 @@ const PATTERNS = ['html`', 'html.reactive'];
15
15
 
16
16
 
17
17
  function createTransformer(program: ts.Program): ts.TransformerFactory<ts.SourceFile> {
18
- let printer = ts.createPrinter(),
19
- typeChecker = program.getTypeChecker();
18
+ let typeChecker = program.getTypeChecker();
20
19
 
21
20
  return (_context: ts.TransformationContext) => {
22
21
  return (sourceFile: ts.SourceFile): ts.SourceFile => {
23
- // Use printer to get current text representation (handles chained transformers)
24
- let code = printer.printFile(sourceFile);
22
+ let code = sourceFile.getFullText();
25
23
 
26
24
  if (!mightNeedTransform(code, { patterns: PATTERNS })) {
27
25
  return sourceFile;
28
26
  }
29
27
 
30
- // Re-parse the printed code to get accurate positions
31
- let reparsed = ts.createSourceFile(sourceFile.fileName, code, sourceFile.languageVersion, true);
32
-
33
28
  setTypeChecker(typeChecker);
34
29
 
35
- let result = transformCode(code, reparsed);
30
+ let result = transformCode(code, sourceFile);
36
31
 
37
32
  if (!result.changed) {
38
33
  return sourceFile;
@@ -47,8 +42,6 @@ function transformCode(code: string, sourceFile: ts.SourceFile): TransformResult
47
42
  let changed = false,
48
43
  result = code;
49
44
 
50
- initNamespace();
51
-
52
45
  let reactiveCalls = findReactiveCalls(sourceFile);
53
46
 
54
47
  if (reactiveCalls.length > 0) {
@@ -81,27 +74,23 @@ function transformCode(code: string, sourceFile: ts.SourceFile): TransformResult
81
74
 
82
75
 
83
76
  const transform = (sourceFile: ts.SourceFile, program: ts.Program): TransformResult => {
84
- // Use printer to get current text representation (handles chained transformers)
85
- let printer = ts.createPrinter(),
86
- code = printer.printFile(sourceFile);
77
+ let code = sourceFile.getFullText();
87
78
 
88
79
  if (!mightNeedTransform(code, { patterns: PATTERNS })) {
89
80
  return { changed: false, code, sourceFile };
90
81
  }
91
82
 
92
- // Re-parse the printed code to get accurate positions
93
- let reparsed = ts.createSourceFile(sourceFile.fileName, code, sourceFile.languageVersion, true);
94
-
95
83
  let programSourceFile = program.getSourceFile(sourceFile.fileName);
96
84
 
97
85
  if (programSourceFile) {
98
86
  setTypeChecker(program.getTypeChecker());
87
+ sourceFile = programSourceFile;
99
88
  }
100
89
  else {
101
90
  setTypeChecker(undefined);
102
91
  }
103
92
 
104
- return transformCode(code, reparsed);
93
+ return transformCode(code, sourceFile);
105
94
  };
106
95
 
107
96
 
@@ -1,4 +1,4 @@
1
- import { createTransformer, mightNeedTransform, PATTERNS } from '../index';
1
+ import { mightNeedTransform, PATTERNS, transform } from '../index';
2
2
  import { program, TRANSFORM_PATTERN } from '@esportsplus/typescript/transformer';
3
3
  import type { Plugin, ResolvedConfig } from 'vite';
4
4
  import { ts } from '@esportsplus/typescript';
@@ -25,23 +25,14 @@ export default (options?: { root?: string }): Plugin => {
25
25
  }
26
26
 
27
27
  try {
28
- let p = program.get(root),
29
- printer = ts.createPrinter(),
30
- sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true),
31
- transformer = createTransformer(p),
32
- result = ts.transform(sourceFile, [transformer]),
33
- transformed = result.transformed[0];
34
-
35
- if (transformed === sourceFile) {
36
- result.dispose();
28
+ let sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true),
29
+ result = transform(sourceFile, program.get(root));
30
+
31
+ if (!result.changed) {
37
32
  return null;
38
33
  }
39
34
 
40
- let output = printer.printFile(transformed);
41
-
42
- result.dispose();
43
-
44
- return { code: output, map: null };
35
+ return { code: result.code, map: null };
45
36
  }
46
37
  catch (error) {
47
38
  console.error(`@esportsplus/template: Error transforming ${id}:`, error);