@esportsplus/template 0.37.0 → 0.38.1

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.
@@ -1,10 +1,11 @@
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
+ prepend: string[];
6
+ replacements: ReplacementIntent[];
7
+ templates: Map<string, string>;
6
8
  };
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 };
9
+ declare const generateCode: (templates: TemplateInfo[], sourceFile: ts.SourceFile, checker?: ts.TypeChecker) => CodegenResult;
10
+ export { generateCode };
10
11
  export type { CodegenResult };
@@ -1,48 +1,47 @@
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, DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS, PACKAGE } from '../constants.js';
2
+ import { ast, uid } from '@esportsplus/typescript/compiler';
3
+ import { COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY, COMPILER_NAMESPACE, COMPILER_TYPES, DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS } from '../constants.js';
4
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 });
8
- function addImport(ctx, name) {
9
- let alias = ctx.imports.get(name);
10
- if (!alias) {
11
- alias = uid(name);
12
- ctx.imports.set(name, alias);
8
+ function collectNestedReplacements(ctx, node, exprStart, replacements) {
9
+ if (isNestedHtmlTemplate(node)) {
10
+ replacements.push({
11
+ end: node.end - exprStart,
12
+ newText: generateNestedTemplateCode(ctx, node),
13
+ start: node.getStart(ctx.sourceFile) - exprStart
14
+ });
15
+ }
16
+ else if (isReactiveCall(node)) {
17
+ replacements.push({
18
+ end: node.end - exprStart,
19
+ newText: rewriteReactiveCall(ctx, node),
20
+ start: node.getStart(ctx.sourceFile) - exprStart
21
+ });
22
+ }
23
+ else {
24
+ ts.forEachChild(node, child => collectNestedReplacements(ctx, child, exprStart, replacements));
13
25
  }
14
- return alias;
15
26
  }
16
- function generateAttributeBinding(ctx, element, name, expr, staticValue) {
27
+ function generateAttributeBinding(element, name, expr, staticValue) {
17
28
  if (name.startsWith('on') && name.length > 2) {
18
29
  let event = name.slice(2).toLowerCase(), key = name.toLowerCase();
19
30
  if (LIFECYCLE_EVENTS.has(key)) {
20
- return `${addImport(ctx, key)}(${element}, ${expr});`;
31
+ return `${COMPILER_NAMESPACE}.${key}(${element}, ${expr});`;
21
32
  }
22
33
  if (DIRECT_ATTACH_EVENTS.has(key)) {
23
- return `${addImport(ctx, 'on')}(${element}, '${event}', ${expr});`;
34
+ return `${COMPILER_NAMESPACE}.on(${element}, '${event}', ${expr});`;
24
35
  }
25
- return `${addImport(ctx, 'delegate')}(${element}, '${event}', ${expr});`;
36
+ return `${COMPILER_NAMESPACE}.delegate(${element}, '${event}', ${expr});`;
26
37
  }
27
38
  if (name === 'class') {
28
- return `${addImport(ctx, 'setClass')}(${element}, '${staticValue}', ${expr});`;
39
+ return `${COMPILER_NAMESPACE}.setClass(${element}, '${staticValue}', ${expr});`;
29
40
  }
30
41
  if (name === 'style') {
31
- return `${addImport(ctx, 'setStyle')}(${element}, '${staticValue}', ${expr});`;
32
- }
33
- return `${addImport(ctx, 'setProperty')}(${element}, '${name}', ${expr});`;
34
- }
35
- function collectNestedTemplateReplacements(ctx, node, exprStart, replacements) {
36
- if (isNestedHtmlTemplate(node)) {
37
- replacements.push({
38
- end: node.end - exprStart,
39
- newText: generateNestedTemplateCode(ctx, node),
40
- start: node.getStart() - exprStart
41
- });
42
- }
43
- else {
44
- ts.forEachChild(node, child => collectNestedTemplateReplacements(ctx, child, exprStart, replacements));
42
+ return `${COMPILER_NAMESPACE}.setStyle(${element}, '${staticValue}', ${expr});`;
45
43
  }
44
+ return `${COMPILER_NAMESPACE}.setProperty(${element}, '${name}', ${expr});`;
46
45
  }
47
46
  function generateNestedTemplateCode(ctx, node) {
48
47
  let expressions = [], exprTexts = [], literals = [], template = node.template;
@@ -62,23 +61,23 @@ function generateNestedTemplateCode(ctx, node) {
62
61
  }
63
62
  function generateNodeBinding(ctx, anchor, exprText, exprNode) {
64
63
  if (!exprNode) {
65
- return `${addImport(ctx, 'slot')}(${anchor}, ${exprText});`;
64
+ return `${COMPILER_NAMESPACE}.slot(${anchor}, ${exprText});`;
66
65
  }
67
66
  if (isNestedHtmlTemplate(exprNode)) {
68
- return `${anchor}.parentNode.insertBefore(${generateNestedTemplateCode(ctx, exprNode)}, ${anchor});`;
67
+ return `${anchor}.parentNode!.insertBefore(${generateNestedTemplateCode(ctx, exprNode)}, ${anchor});`;
69
68
  }
70
69
  let slotType = analyze(exprNode, ctx.checker);
71
70
  switch (slotType) {
72
- case COMPILER_TYPES.Effect:
73
- return `new ${addImport(ctx, 'EffectSlot')}(${anchor}, ${exprText});`;
74
71
  case COMPILER_TYPES.ArraySlot:
75
- return `new ${addImport(ctx, 'ArraySlot')}(${anchor}, ${exprText});`;
72
+ return `${anchor}.parentNode!.insertBefore(new ${COMPILER_NAMESPACE}.ArraySlot(${exprText}).fragment, ${anchor});`;
73
+ case COMPILER_TYPES.DocumentFragment:
74
+ return `${anchor}.parentNode!.insertBefore(${exprText}, ${anchor});`;
75
+ case COMPILER_TYPES.Effect:
76
+ return `new ${COMPILER_NAMESPACE}.EffectSlot(${anchor}, ${exprText});`;
76
77
  case COMPILER_TYPES.Static:
77
78
  return `${anchor}.textContent = ${exprText};`;
78
- case COMPILER_TYPES.DocumentFragment:
79
- return `${anchor}.parentNode.insertBefore(${exprText}, ${anchor});`;
80
79
  default:
81
- return `${addImport(ctx, 'slot')}(${anchor}, ${exprText});`;
80
+ return `${COMPILER_NAMESPACE}.slot(${anchor}, ${exprText});`;
82
81
  }
83
82
  }
84
83
  function generateTemplateCode(ctx, { html, slots }, exprTexts, exprNodes, isArrowBody) {
@@ -106,11 +105,11 @@ function generateTemplateCode(ctx, { html, slots }, exprTexts, exprNodes, isArro
106
105
  break;
107
106
  }
108
107
  }
109
- let alias = addImport(ctx, 'Element'), name = uid('element'), segments = path.slice(start), value = `${ancestor}.${segments.join('!.')}`;
108
+ let name = uid('element'), segments = path.slice(start), value = `${ancestor}.${segments.join('!.')}`;
110
109
  if (ancestor === root && segments[0] === 'firstChild') {
111
- value = value.replace(`${ancestor}.firstChild!`, `(${ancestor}.firstChild! as ${alias})`);
110
+ value = value.replace(`${ancestor}.firstChild!`, `(${ancestor}.firstChild! as ${COMPILER_NAMESPACE}.Element)`);
112
111
  }
113
- declarations.push(`${name} = ${value} as ${alias}`);
112
+ declarations.push(`${name} = ${value} as ${COMPILER_NAMESPACE}.Element`);
114
113
  nodes.set(key, name);
115
114
  }
116
115
  code.push(isArrowBody ? '{' : `(() => {`, `let ${declarations.join(',\n')};`);
@@ -123,11 +122,11 @@ function generateTemplateCode(ctx, { html, slots }, exprTexts, exprNodes, isArro
123
122
  for (let j = 0, m = names.length; j < m; j++) {
124
123
  let name = names[j];
125
124
  if (name === COMPILER_TYPES.Attributes) {
126
- code.push(`${addImport(ctx, 'setProperties')}(${element}, ${exprTexts[index] || 'undefined'});`);
125
+ code.push(`${COMPILER_NAMESPACE}.setProperties(${element}, ${exprTexts[index] || 'undefined'});`);
127
126
  index++;
128
127
  }
129
128
  else {
130
- code.push(generateAttributeBinding(ctx, element, name, exprTexts[index++] || 'undefined', slot.attributes.statics[name] || ''));
129
+ code.push(generateAttributeBinding(element, name, exprTexts[index++] || 'undefined', slot.attributes.statics[name] || ''));
131
130
  }
132
131
  }
133
132
  }
@@ -151,95 +150,131 @@ function getOrCreateTemplateId(ctx, html) {
151
150
  function isNestedHtmlTemplate(expr) {
152
151
  return ts.isTaggedTemplateExpression(expr) && ts.isIdentifier(expr.tag) && expr.tag.text === COMPILER_ENTRYPOINT;
153
152
  }
153
+ function isReactiveCall(expr) {
154
+ return (ts.isCallExpression(expr) &&
155
+ ts.isPropertyAccessExpression(expr.expression) &&
156
+ ts.isIdentifier(expr.expression.expression) &&
157
+ expr.expression.expression.text === COMPILER_ENTRYPOINT &&
158
+ expr.expression.name.text === COMPILER_ENTRYPOINT_REACTIVITY);
159
+ }
160
+ function replaceReverse(text, replacements) {
161
+ let sorted = replacements.slice().sort((a, b) => b.start - a.start);
162
+ for (let i = 0, n = sorted.length; i < n; i++) {
163
+ let r = sorted[i];
164
+ text = text.slice(0, r.start) + r.newText + text.slice(r.end);
165
+ }
166
+ return text;
167
+ }
154
168
  function rewriteExpression(ctx, expr) {
155
169
  if (isNestedHtmlTemplate(expr)) {
156
170
  return generateNestedTemplateCode(ctx, expr);
157
171
  }
158
- if (!ast.hasMatch(expr, n => isNestedHtmlTemplate(n))) {
172
+ if (isReactiveCall(expr)) {
173
+ return rewriteReactiveCall(ctx, expr);
174
+ }
175
+ if (!ast.hasMatch(expr, n => isNestedHtmlTemplate(n) || isReactiveCall(n))) {
159
176
  return ctx.printer.printNode(ts.EmitHint.Expression, expr, ctx.sourceFile);
160
177
  }
161
178
  let replacements = [];
162
- collectNestedTemplateReplacements(ctx, expr, expr.getStart(), replacements);
163
- return c.replaceReverse(expr.getText(ctx.sourceFile), replacements);
179
+ collectNestedReplacements(ctx, expr, expr.getStart(ctx.sourceFile), replacements);
180
+ return replaceReverse(expr.getText(ctx.sourceFile), replacements);
181
+ }
182
+ function rewriteReactiveCall(ctx, node) {
183
+ let arrayArg = node.arguments[0], arrayText = ctx.printer.printNode(ts.EmitHint.Expression, arrayArg, ctx.sourceFile), callbackArg = node.arguments[1], callbackText = rewriteExpression(ctx, callbackArg);
184
+ return `${arrayText}, ${callbackText}`;
164
185
  }
165
- const generateCode = (templates, originalCode, sourceFile, checker, existingAliases) => {
186
+ function discoverTemplatesInExpression(ctx, node) {
187
+ if (isNestedHtmlTemplate(node)) {
188
+ let template = node, expressions = [], literals = [], tpl = template.template;
189
+ if (ts.isNoSubstitutionTemplateLiteral(tpl)) {
190
+ literals.push(tpl.text);
191
+ }
192
+ else if (ts.isTemplateExpression(tpl)) {
193
+ literals.push(tpl.head.text);
194
+ for (let i = 0, n = tpl.templateSpans.length; i < n; i++) {
195
+ expressions.push(tpl.templateSpans[i].expression);
196
+ literals.push(tpl.templateSpans[i].literal.text);
197
+ }
198
+ }
199
+ let parsed = parser.parse(literals);
200
+ getOrCreateTemplateId(ctx, parsed.html);
201
+ for (let i = 0, n = expressions.length; i < n; i++) {
202
+ discoverTemplatesInExpression(ctx, expressions[i]);
203
+ }
204
+ }
205
+ else if (isReactiveCall(node)) {
206
+ let call = node;
207
+ if (call.arguments.length >= 2) {
208
+ discoverTemplatesInExpression(ctx, call.arguments[1]);
209
+ }
210
+ }
211
+ else {
212
+ ts.forEachChild(node, child => discoverTemplatesInExpression(ctx, child));
213
+ }
214
+ }
215
+ function discoverAllTemplates(ctx, templates) {
216
+ for (let i = 0, n = templates.length; i < n; i++) {
217
+ let parsed = parser.parse(templates[i].literals);
218
+ getOrCreateTemplateId(ctx, parsed.html);
219
+ for (let j = 0, m = templates[i].expressions.length; j < m; j++) {
220
+ discoverTemplatesInExpression(ctx, templates[i].expressions[j]);
221
+ }
222
+ }
223
+ }
224
+ const generateCode = (templates, sourceFile, checker) => {
225
+ let result = {
226
+ prepend: [],
227
+ replacements: [],
228
+ templates: new Map()
229
+ };
166
230
  if (templates.length === 0) {
167
- return { changed: false, code: originalCode };
231
+ return result;
168
232
  }
169
233
  let ranges = [];
170
234
  for (let i = 0, n = templates.length; i < n; i++) {
171
235
  let exprs = templates[i].expressions;
172
236
  for (let j = 0, m = exprs.length; j < m; j++) {
173
- ranges.push({ end: exprs[j].end, start: exprs[j].getStart() });
237
+ ranges.push({ end: exprs[j].end, start: exprs[j].getStart(sourceFile) });
174
238
  }
175
239
  }
176
- let rootTemplates = templates.filter(t => !ast.inRange(ranges, t.start, t.end));
240
+ let rootTemplates = templates.filter(t => !ast.inRange(ranges, t.node.getStart(sourceFile), t.node.end));
177
241
  if (rootTemplates.length === 0) {
178
- return { changed: false, code: originalCode };
242
+ return result;
179
243
  }
180
244
  let ctx = {
181
245
  checker,
182
- imports: existingAliases ?? new Map(),
183
246
  printer,
184
247
  sourceFile,
185
- templates: new Map(),
186
- }, replacements = [], templateAlias = addImport(ctx, 'template');
248
+ templates: result.templates
249
+ };
187
250
  for (let i = 0, n = rootTemplates.length; i < n; i++) {
188
- let exprTexts = [], template = rootTemplates[i];
189
- for (let j = 0, m = template.expressions.length; j < m; j++) {
190
- exprTexts.push(rewriteExpression(ctx, template.expressions[j]));
191
- }
192
- let codeBefore = originalCode.slice(0, template.start), isArrowBody = codeBefore.trimEnd().endsWith('=>'), parsed = parser.parse(template.literals);
193
- if (isArrowBody && (!parsed.slots || parsed.slots.length === 0)) {
194
- let arrowMatch = codeBefore.match(ARROW_EMPTY_PARAMS);
195
- if (arrowMatch) {
196
- replacements.push({
197
- end: template.end,
198
- newText: getOrCreateTemplateId(ctx, parsed.html),
199
- start: template.start - arrowMatch[0].length
200
- });
201
- continue;
202
- }
203
- }
204
- replacements.push({
205
- end: template.end,
206
- newText: generateTemplateCode(ctx, parsed, exprTexts, template.expressions, isArrowBody),
207
- start: template.start
208
- });
209
- }
210
- let changed = replacements.length > 0, code = c.replaceReverse(originalCode, replacements);
211
- if (changed && ctx.templates.size > 0) {
212
- let aliasedImports = [], factories = [], updatedSourceFile = ts.createSourceFile(sourceFile.fileName, code, sourceFile.languageVersion, true);
213
- for (let [name, alias] of ctx.imports) {
214
- aliasedImports.push(`${name} as ${alias}`);
215
- }
216
- for (let [html, id] of ctx.templates) {
217
- factories.push(`const ${id} = ${templateAlias}(\`${html}\`);`);
218
- }
219
- code = imports.modify(code, updatedSourceFile, PACKAGE, {
220
- add: new Set(aliasedImports),
221
- remove: [COMPILER_ENTRYPOINT]
251
+ let template = rootTemplates[i];
252
+ result.replacements.push({
253
+ generate: (sf) => {
254
+ let codeBefore = sf.getFullText().slice(0, template.node.getStart(sf)), exprTexts = [], isArrowBody = codeBefore.trimEnd().endsWith('=>'), localCtx = {
255
+ checker,
256
+ printer,
257
+ sourceFile: sf,
258
+ templates: ctx.templates
259
+ }, parsed = parser.parse(template.literals);
260
+ for (let j = 0, m = template.expressions.length; j < m; j++) {
261
+ exprTexts.push(rewriteExpression(localCtx, template.expressions[j]));
262
+ }
263
+ if (isArrowBody && (!parsed.slots || parsed.slots.length === 0)) {
264
+ let arrowMatch = codeBefore.match(ARROW_EMPTY_PARAMS);
265
+ if (arrowMatch) {
266
+ return getOrCreateTemplateId(localCtx, parsed.html);
267
+ }
268
+ }
269
+ return generateTemplateCode(localCtx, parsed, exprTexts, template.expressions, isArrowBody);
270
+ },
271
+ node: template.node
222
272
  });
223
- code = factories.join('\n') + '\n\n' + code;
224
- }
225
- return { changed, code };
226
- };
227
- const generateReactiveInlining = (calls, code, sourceFile, arraySlotAlias) => {
228
- if (calls.length === 0) {
229
- return code;
230
273
  }
231
- let replacements = [];
232
- for (let i = 0, n = calls.length; i < n; i++) {
233
- let call = calls[i];
234
- replacements.push({
235
- end: call.end,
236
- newText: `new ${arraySlotAlias}(
237
- ${printer.printNode(ts.EmitHint.Expression, call.arrayArg, sourceFile)},
238
- ${printer.printNode(ts.EmitHint.Expression, call.callbackArg, sourceFile)}
239
- )`,
240
- start: call.start
241
- });
274
+ discoverAllTemplates(ctx, templates);
275
+ for (let [html, id] of ctx.templates) {
276
+ result.prepend.push(`const ${id} = ${COMPILER_NAMESPACE}.template(\`${html}\`);`);
242
277
  }
243
- return c.replaceReverse(code, replacements);
278
+ return result;
244
279
  };
245
- export { generateCode, generateReactiveInlining };
280
+ export { generateCode };
@@ -1,10 +1,3 @@
1
- import type { PluginContext } from '@esportsplus/typescript/compiler';
2
- import { ts } from '@esportsplus/typescript';
3
- type TransformResult = {
4
- changed: boolean;
5
- code: string;
6
- sourceFile: ts.SourceFile;
7
- };
8
- declare const analyze: (sourceFile: ts.SourceFile, program: ts.Program, context: PluginContext) => void;
9
- declare const transform: (sourceFile: ts.SourceFile, program: ts.Program, context?: PluginContext) => TransformResult;
10
- export { analyze, transform };
1
+ import type { Plugin } from '@esportsplus/typescript/compiler';
2
+ declare const plugin: Plugin;
3
+ export default plugin;
@@ -1,82 +1,63 @@
1
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';
2
+ import { COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY, COMPILER_NAMESPACE, PACKAGE } from '../constants.js';
3
+ import { generateCode } from './codegen.js';
5
4
  import { findHtmlTemplates, findReactiveCalls } from './ts-parser.js';
6
- const CONTEXT_KEY = 'template:analyzed';
7
- const PATTERNS = [`${COMPILER_ENTRYPOINT}\``, `${COMPILER_ENTRYPOINT}.${COMPILER_ENTRYPOINT_REACTIVITY}`];
8
- const REGEX_BACKSLASH = /\\/g;
9
- const REGEX_FORWARD_SLASH = /\//g;
10
- function getAnalyzedFile(context, filename) {
11
- return context?.get(CONTEXT_KEY)?.get(filename);
12
- }
13
- const analyze = (sourceFile, program, context) => {
14
- let code = sourceFile.getFullText();
15
- if (!c.contains(code, { patterns: PATTERNS })) {
16
- return;
17
- }
18
- let checker = program.getTypeChecker(), filename = sourceFile.fileName, files = context.get(CONTEXT_KEY), programSourceFile = program.getSourceFile(filename)
19
- || program.getSourceFile(filename.replace(REGEX_BACKSLASH, '/'))
20
- || program.getSourceFile(filename.replace(REGEX_FORWARD_SLASH, '\\'));
21
- if (programSourceFile) {
22
- sourceFile = programSourceFile;
23
- }
24
- if (!files) {
25
- files = new Map();
26
- context.set(CONTEXT_KEY, files);
5
+ const PATTERNS = [
6
+ `${COMPILER_ENTRYPOINT}\``,
7
+ `${COMPILER_ENTRYPOINT}.${COMPILER_ENTRYPOINT_REACTIVITY}`
8
+ ];
9
+ function isInRange(ranges, start, end) {
10
+ for (let i = 0, n = ranges.length; i < n; i++) {
11
+ let range = ranges[i];
12
+ if (start >= range.start && end <= range.end) {
13
+ return true;
14
+ }
27
15
  }
28
- files.set(filename, {
29
- reactiveCalls: findReactiveCalls(sourceFile, checker),
30
- templates: findHtmlTemplates(sourceFile, checker)
31
- });
32
- };
33
- const transform = (sourceFile, program, context) => {
34
- let code = sourceFile.getFullText(), filename = sourceFile.fileName;
35
- let analyzed = getAnalyzedFile(context, filename);
36
- if (!analyzed) {
37
- if (!c.contains(code, { patterns: PATTERNS })) {
38
- return { changed: false, code, sourceFile };
16
+ return false;
17
+ }
18
+ let printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
19
+ const plugin = {
20
+ patterns: PATTERNS,
21
+ transform: (ctx) => {
22
+ let importsIntent = [], prepend = [], replacements = [], removeImports = [];
23
+ let templates = findHtmlTemplates(ctx.sourceFile, ctx.checker);
24
+ let templateRanges = [];
25
+ for (let i = 0, n = templates.length; i < n; i++) {
26
+ templateRanges.push({
27
+ end: templates[i].end,
28
+ start: templates[i].start
29
+ });
39
30
  }
40
- let checker = program.getTypeChecker(), programSourceFile = program.getSourceFile(filename)
41
- || program.getSourceFile(filename.replace(REGEX_BACKSLASH, '/'))
42
- || program.getSourceFile(filename.replace(REGEX_FORWARD_SLASH, '\\'));
43
- if (programSourceFile) {
44
- sourceFile = programSourceFile;
31
+ let reactiveCalls = findReactiveCalls(ctx.sourceFile, ctx.checker);
32
+ for (let i = 0, n = reactiveCalls.length; i < n; i++) {
33
+ let call = reactiveCalls[i];
34
+ if (isInRange(templateRanges, call.start, call.end)) {
35
+ continue;
36
+ }
37
+ replacements.push({
38
+ generate: (sourceFile) => `new ${COMPILER_NAMESPACE}.ArraySlot(${printer.printNode(ts.EmitHint.Expression, call.arrayArg, sourceFile)}, ${printer.printNode(ts.EmitHint.Expression, call.callbackArg, sourceFile)})`,
39
+ node: call.node
40
+ });
45
41
  }
46
- analyzed = {
47
- reactiveCalls: findReactiveCalls(sourceFile, checker),
48
- templates: findHtmlTemplates(sourceFile, checker)
49
- };
50
- }
51
- let changed = false, codegenChanged = false, existingAliases = new Map(), result = code;
52
- if (analyzed.reactiveCalls.length > 0) {
53
- changed = true;
54
- existingAliases.set('ArraySlot', uid('ArraySlot'));
55
- result = generateReactiveInlining(analyzed.reactiveCalls, result, sourceFile, existingAliases.get('ArraySlot'));
56
- sourceFile = ts.createSourceFile(sourceFile.fileName, result, sourceFile.languageVersion, true);
57
- analyzed = {
58
- reactiveCalls: [],
59
- templates: findHtmlTemplates(sourceFile, program.getTypeChecker())
60
- };
61
- }
62
- if (analyzed.templates.length > 0) {
63
- let codegenResult = generateCode(analyzed.templates, result, sourceFile, program.getTypeChecker(), existingAliases);
64
- if (codegenResult.changed) {
65
- changed = true;
66
- codegenChanged = true;
67
- result = codegenResult.code;
42
+ if (templates.length > 0) {
43
+ let result = generateCode(templates, ctx.sourceFile, ctx.checker);
44
+ prepend.push(...result.prepend);
45
+ replacements.push(...result.replacements);
46
+ removeImports.push(COMPILER_ENTRYPOINT);
68
47
  }
69
- }
70
- if (existingAliases.size > 0 && !codegenChanged) {
71
- let aliasedImports = [];
72
- for (let [name, alias] of existingAliases) {
73
- aliasedImports.push(`${name} as ${alias}`);
48
+ if (replacements.length === 0 && prepend.length === 0) {
49
+ return {};
74
50
  }
75
- result = imports.modify(result, sourceFile, PACKAGE, { add: aliasedImports });
76
- }
77
- if (changed) {
78
- sourceFile = ts.createSourceFile(sourceFile.fileName, result, sourceFile.languageVersion, true);
51
+ importsIntent.push({
52
+ namespace: COMPILER_NAMESPACE,
53
+ package: PACKAGE,
54
+ remove: removeImports
55
+ });
56
+ return {
57
+ imports: importsIntent,
58
+ prepend,
59
+ replacements
60
+ };
79
61
  }
80
- return { changed, code: result, sourceFile };
81
62
  };
82
- export { analyze, transform };
63
+ export default plugin;
@@ -1,3 +1,2 @@
1
- import { plugin } from '@esportsplus/typescript/compiler';
2
- declare const _default: ReturnType<typeof plugin.tsc>;
3
- export default _default;
1
+ import plugin from '../index.js';
2
+ export default plugin;
@@ -1,3 +1,2 @@
1
- import { plugin } from '@esportsplus/typescript/compiler';
2
- import { analyze, transform } from '../index.js';
3
- export default plugin.tsc({ analyze, transform });
1
+ import plugin from '../index.js';
2
+ export default plugin;
@@ -1,8 +1,7 @@
1
1
  import { plugin } from '@esportsplus/typescript/compiler';
2
2
  import { PACKAGE } from '../../constants.js';
3
- import { analyze, transform } from '../index.js';
3
+ import templatePlugin from '../index.js';
4
4
  export default plugin.vite({
5
- analyze,
6
5
  name: PACKAGE,
7
- transform
6
+ plugins: [templatePlugin]
8
7
  });
@@ -2,6 +2,7 @@ declare const ARRAY_SLOT: unique symbol;
2
2
  declare const CLEANUP: unique symbol;
3
3
  declare const COMPILER_ENTRYPOINT = "html";
4
4
  declare const COMPILER_ENTRYPOINT_REACTIVITY = "reactive";
5
+ declare const COMPILER_NAMESPACE: string;
5
6
  declare const enum COMPILER_TYPES {
6
7
  ArraySlot = "array-slot",
7
8
  Attributes = "attributes",
@@ -21,4 +22,4 @@ declare const STATE_HYDRATING = 0;
21
22
  declare const STATE_NONE = 1;
22
23
  declare const STATE_WAITING = 2;
23
24
  declare const STORE: unique symbol;
24
- export { ARRAY_SLOT, CLEANUP, COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY, COMPILER_TYPES, DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS, PACKAGE, SLOT_HTML, STATE_HYDRATING, STATE_NONE, STATE_WAITING, STORE, };
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, };
@@ -1,7 +1,9 @@
1
+ import { uid } from '@esportsplus/typescript/compiler';
1
2
  const ARRAY_SLOT = Symbol('template.array.slot');
2
3
  const CLEANUP = Symbol('template.cleanup');
3
4
  const COMPILER_ENTRYPOINT = 'html';
4
5
  const COMPILER_ENTRYPOINT_REACTIVITY = 'reactive';
6
+ const COMPILER_NAMESPACE = uid('template');
5
7
  var COMPILER_TYPES;
6
8
  (function (COMPILER_TYPES) {
7
9
  COMPILER_TYPES["ArraySlot"] = "array-slot";
@@ -33,4 +35,4 @@ const STATE_HYDRATING = 0;
33
35
  const STATE_NONE = 1;
34
36
  const STATE_WAITING = 2;
35
37
  const STORE = Symbol('template.store');
36
- export { ARRAY_SLOT, CLEANUP, COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY, COMPILER_TYPES, DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS, PACKAGE, SLOT_HTML, STATE_HYDRATING, STATE_NONE, STATE_WAITING, STORE, };
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/package.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "author": "ICJR",
3
3
  "dependencies": {
4
4
  "@esportsplus/queue": "^0.2.0",
5
- "@esportsplus/reactivity": "^0.27.3",
6
- "@esportsplus/typescript": "^0.24.2",
5
+ "@esportsplus/reactivity": "^0.28.1",
6
+ "@esportsplus/typescript": "^0.25.0",
7
7
  "@esportsplus/utilities": "^0.27.2",
8
8
  "serve": "^14.2.5"
9
9
  },
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "type": "module",
37
37
  "types": "./build/index.d.ts",
38
- "version": "0.37.0",
38
+ "version": "0.38.1",
39
39
  "scripts": {
40
40
  "build": "tsc",
41
41
  "build:test": "vite build --config test/vite.config.ts",