@esportsplus/template 0.34.1 → 0.35.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,6 +1,6 @@
1
1
  import { Attributes, Element } from './types.js';
2
- declare const setClass: (element: Element, classlist: false | string | undefined, value: unknown) => void;
2
+ declare const setClass: (element: Element, classlist: false | string, value: unknown) => void;
3
3
  declare const setProperty: (element: Element, name: string, value: unknown) => void;
4
- declare const setProperties: (element: Element, value: Attributes | Attributes[]) => void;
5
- declare const setStyle: (element: Element, styles: false | string | undefined, value: unknown) => void;
4
+ declare const setProperties: (element: Element, value?: Attributes | Attributes[] | false | null | undefined) => void;
5
+ declare const setStyle: (element: Element, styles: false | string, value: unknown) => void;
6
6
  export { setClass, setProperty, setProperties, setStyle };
@@ -199,7 +199,10 @@ const setProperty = (element, name, value) => {
199
199
  }
200
200
  };
201
201
  const setProperties = function (element, value) {
202
- if (isObject(value)) {
202
+ if (!value) {
203
+ return;
204
+ }
205
+ else if (isObject(value)) {
203
206
  for (let name in value) {
204
207
  let v = value[name];
205
208
  if (v == null || v === false || v === '') {
@@ -4,9 +4,7 @@ type CodegenResult = {
4
4
  changed: boolean;
5
5
  code: string;
6
6
  };
7
- declare const addImport: (code: string) => string;
8
- declare const generateCode: (templates: TemplateInfo[], originalCode: string, sourceFile: ts.SourceFile, checker?: ts.TypeChecker) => CodegenResult;
9
- declare const generateReactiveInlining: (calls: ReactiveCallInfo[], code: string, sourceFile: ts.SourceFile) => string;
10
- declare const needsArraySlotImport: (sourceFile: ts.SourceFile) => boolean;
11
- export { addImport, generateCode, generateReactiveInlining, needsArraySlotImport };
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 };
12
10
  export type { CodegenResult };
@@ -1,11 +1,18 @@
1
1
  import { ts } from '@esportsplus/typescript';
2
- import { ast, code as c, uid } from '@esportsplus/typescript/compiler';
2
+ import { ast, code as c, imports, uid } from '@esportsplus/typescript/compiler';
3
+ import { COMPILER_ENTRYPOINT, COMPILER_TYPES, PACKAGE } from '../constants.js';
3
4
  import { analyzeExpression, generateAttributeBinding, generateSpreadBindings } from './type-analyzer.js';
4
- import { COMPILER_ENTRYPOINT, COMPILER_NAMESPACE, COMPILER_TYPES, PACKAGE, PACKAGE_COMPILER } from '../constants.js';
5
5
  import parser from './parser.js';
6
6
  const ARROW_EMPTY_PARAMS = /\(\s*\)\s*=>\s*$/;
7
- const REGEX_PACKAGE_IMPORT = new RegExp(`import\\s*\\{[^}]*\\}\\s*from\\s*['"]${PACKAGE.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}['"];?\\n?`, 'g');
8
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);
13
+ }
14
+ return alias;
15
+ }
9
16
  function collectNestedTemplateReplacements(ctx, node, exprStart, replacements) {
10
17
  if (isNestedHtmlTemplate(node)) {
11
18
  replacements.push({
@@ -36,7 +43,7 @@ function generateNestedTemplateCode(ctx, node) {
36
43
  }
37
44
  function generateNodeBinding(ctx, anchor, exprText, exprNode) {
38
45
  if (!exprNode) {
39
- return `${COMPILER_NAMESPACE}.slot(${anchor}, ${exprText});`;
46
+ return `${addImport(ctx, 'slot')}(${anchor}, ${exprText});`;
40
47
  }
41
48
  if (isNestedHtmlTemplate(exprNode)) {
42
49
  return `${anchor}.parentNode.insertBefore(${generateNestedTemplateCode(ctx, exprNode)}, ${anchor});`;
@@ -44,15 +51,15 @@ function generateNodeBinding(ctx, anchor, exprText, exprNode) {
44
51
  let slotType = analyzeExpression(exprNode, ctx.checker);
45
52
  switch (slotType) {
46
53
  case COMPILER_TYPES.Effect:
47
- return `new ${COMPILER_NAMESPACE}.EffectSlot(${anchor}, ${exprText});`;
54
+ return `new ${addImport(ctx, 'EffectSlot')}(${anchor}, ${exprText});`;
48
55
  case COMPILER_TYPES.ArraySlot:
49
- return `new ${COMPILER_NAMESPACE}.ArraySlot(${anchor}, ${exprText});`;
56
+ return `new ${addImport(ctx, 'ArraySlot')}(${anchor}, ${exprText});`;
50
57
  case COMPILER_TYPES.Static:
51
58
  return `${anchor}.textContent = ${exprText};`;
52
59
  case COMPILER_TYPES.DocumentFragment:
53
60
  return `${anchor}.parentNode.insertBefore(${exprText}, ${anchor});`;
54
61
  default:
55
- return `${COMPILER_NAMESPACE}.slot(${anchor}, ${exprText});`;
62
+ return `${addImport(ctx, 'slot')}(${anchor}, ${exprText});`;
56
63
  }
57
64
  }
58
65
  function generateTemplateCode(ctx, { html, slots }, exprTexts, exprNodes, isArrowBody) {
@@ -71,22 +78,25 @@ function generateTemplateCode(ctx, { html, slots }, exprTexts, exprNodes, isArro
71
78
  if (nodes.has(key)) {
72
79
  continue;
73
80
  }
74
- let ancestorVar = root, startIdx = 0;
81
+ let ancestor = root, start = 0;
75
82
  for (let j = path.length - 1; j >= 0; j--) {
76
83
  let prefix = path.slice(0, j).join('.');
77
84
  if (nodes.has(prefix)) {
78
- ancestorVar = nodes.get(prefix);
79
- startIdx = j;
85
+ ancestor = nodes.get(prefix);
86
+ start = j;
80
87
  break;
81
88
  }
82
89
  }
83
- let name = uid('element'), suffix = path.slice(startIdx).join('.');
84
- declarations.push(`${name} = ${ancestorVar}.${suffix} as ${COMPILER_NAMESPACE}.Element`);
90
+ let alias = addImport(ctx, 'Element'), name = uid('element'), segments = path.slice(start), value = `${ancestor}.${segments.join('!.')}`;
91
+ if (ancestor === root && segments[0] === 'firstChild') {
92
+ value = value.replace(`${ancestor}.firstChild!`, `(${ancestor}.firstChild! as ${alias})`);
93
+ }
94
+ declarations.push(`${name} = ${value} as ${alias}`);
85
95
  nodes.set(key, name);
86
96
  }
87
97
  code.push(isArrowBody ? '{' : `(() => {`, `let ${declarations.join(',\n')};`);
88
98
  for (let i = 0, n = slots.length; i < n; i++) {
89
- let elementVar = slots[i].path.length === 0
99
+ let element = slots[i].path.length === 0
90
100
  ? root
91
101
  : (nodes.get(slots[i].path.join('.')) || root), slot = slots[i];
92
102
  if (slot.type === COMPILER_TYPES.Attribute) {
@@ -94,19 +104,19 @@ function generateTemplateCode(ctx, { html, slots }, exprTexts, exprNodes, isArro
94
104
  for (let j = 0, m = names.length; j < m; j++) {
95
105
  let name = names[j];
96
106
  if (name === COMPILER_TYPES.Attributes) {
97
- let bindings = generateSpreadBindings(exprNodes[index], exprTexts[index] || 'undefined', elementVar, ctx.checker, COMPILER_NAMESPACE);
107
+ let bindings = generateSpreadBindings(exprTexts[index] || 'undefined', element, n => addImport(ctx, n));
98
108
  for (let k = 0, o = bindings.length; k < o; k++) {
99
109
  code.push(bindings[k]);
100
110
  }
101
111
  index++;
102
112
  }
103
113
  else {
104
- code.push(generateAttributeBinding(elementVar, name, exprTexts[index++] || 'undefined', slot.attributes.statics[name] || '', COMPILER_NAMESPACE));
114
+ code.push(generateAttributeBinding(element, name, exprTexts[index++] || 'undefined', slot.attributes.statics[name] || '', n => addImport(ctx, n)));
105
115
  }
106
116
  }
107
117
  }
108
118
  else {
109
- code.push(generateNodeBinding(ctx, elementVar, exprTexts[index] || 'undefined', exprNodes[index]));
119
+ code.push(generateNodeBinding(ctx, element, exprTexts[index] || 'undefined', exprNodes[index]));
110
120
  index++;
111
121
  }
112
122
  }
@@ -115,32 +125,13 @@ function generateTemplateCode(ctx, { html, slots }, exprTexts, exprNodes, isArro
115
125
  return code.join('\n');
116
126
  }
117
127
  function getOrCreateTemplateId(ctx, html) {
118
- let id = ctx.htmlToTemplateId.get(html);
128
+ let id = ctx.templates.get(html);
119
129
  if (!id) {
120
- id = uid('tmpl');
121
- ctx.hoistedFactories.set(id, html);
122
- ctx.htmlToTemplateId.set(html, id);
130
+ id = uid('template');
131
+ ctx.templates.set(html, id);
123
132
  }
124
133
  return id;
125
134
  }
126
- function hasArraySlotImport(sourceFile) {
127
- for (let i = 0, n = sourceFile.statements.length; i < n; i++) {
128
- let stmt = sourceFile.statements[i];
129
- if (!ts.isImportDeclaration(stmt) || !stmt.importClause?.namedBindings) {
130
- continue;
131
- }
132
- let bindings = stmt.importClause.namedBindings;
133
- if (!ts.isNamedImports(bindings)) {
134
- continue;
135
- }
136
- for (let j = 0, m = bindings.elements.length; j < m; j++) {
137
- if (bindings.elements[j].name.text === 'ArraySlot') {
138
- return true;
139
- }
140
- }
141
- }
142
- return false;
143
- }
144
135
  function isNestedHtmlTemplate(expr) {
145
136
  return ts.isTaggedTemplateExpression(expr) && ts.isIdentifier(expr.tag) && expr.tag.text === COMPILER_ENTRYPOINT;
146
137
  }
@@ -155,13 +146,7 @@ function rewriteExpression(ctx, expr) {
155
146
  collectNestedTemplateReplacements(ctx, expr, expr.getStart(), replacements);
156
147
  return c.replaceReverse(expr.getText(ctx.sourceFile), replacements);
157
148
  }
158
- const addImport = (code) => {
159
- return `import * as ${COMPILER_NAMESPACE} from '${PACKAGE_COMPILER}';\n` + code;
160
- };
161
- const removePackageImport = (code) => {
162
- return code.replace(REGEX_PACKAGE_IMPORT, '');
163
- };
164
- const generateCode = (templates, originalCode, sourceFile, checker) => {
149
+ const generateCode = (templates, originalCode, sourceFile, checker, existingAliases) => {
165
150
  if (templates.length === 0) {
166
151
  return { changed: false, code: originalCode };
167
152
  }
@@ -178,11 +163,11 @@ const generateCode = (templates, originalCode, sourceFile, checker) => {
178
163
  }
179
164
  let ctx = {
180
165
  checker,
181
- hoistedFactories: new Map(),
182
- htmlToTemplateId: new Map(),
166
+ templates: new Map(),
167
+ imports: existingAliases ?? new Map(),
183
168
  printer,
184
169
  sourceFile
185
- }, replacements = [];
170
+ }, replacements = [], templateAlias = addImport(ctx, 'template');
186
171
  for (let i = 0, n = rootTemplates.length; i < n; i++) {
187
172
  let exprTexts = [], template = rootTemplates[i];
188
173
  for (let j = 0, m = template.expressions.length; j < m; j++) {
@@ -207,16 +192,23 @@ const generateCode = (templates, originalCode, sourceFile, checker) => {
207
192
  });
208
193
  }
209
194
  let changed = replacements.length > 0, code = c.replaceReverse(originalCode, replacements);
210
- if (changed && ctx.hoistedFactories.size > 0) {
211
- let factories = [];
212
- for (let [id, html] of ctx.hoistedFactories) {
213
- factories.push(`const ${id} = ${COMPILER_NAMESPACE}.template(\`${html}\`);`);
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}\`);`);
214
202
  }
215
- code = addImport(factories.join('\n') + removePackageImport(code));
203
+ code = imports.modify(code, sourceFile, PACKAGE, {
204
+ add: new Set(aliasedImports),
205
+ remove: [COMPILER_ENTRYPOINT]
206
+ });
207
+ code = factories.join('\n') + '\n\n' + code;
216
208
  }
217
209
  return { changed, code };
218
210
  };
219
- const generateReactiveInlining = (calls, code, sourceFile) => {
211
+ const generateReactiveInlining = (calls, code, sourceFile, arraySlotAlias) => {
220
212
  if (calls.length === 0) {
221
213
  return code;
222
214
  }
@@ -225,7 +217,7 @@ const generateReactiveInlining = (calls, code, sourceFile) => {
225
217
  let call = calls[i];
226
218
  replacements.push({
227
219
  end: call.end,
228
- newText: `new ${COMPILER_NAMESPACE}.ArraySlot(
220
+ newText: `new ${arraySlotAlias}(
229
221
  ${printer.printNode(ts.EmitHint.Expression, call.arrayArg, sourceFile)},
230
222
  ${printer.printNode(ts.EmitHint.Expression, call.callbackArg, sourceFile)}
231
223
  )`,
@@ -234,9 +226,4 @@ const generateReactiveInlining = (calls, code, sourceFile) => {
234
226
  }
235
227
  return c.replaceReverse(code, replacements);
236
228
  };
237
- const needsArraySlotImport = (sourceFile) => {
238
- return ast.hasMatch(sourceFile, n => ts.isNewExpression(n) &&
239
- ts.isPropertyAccessExpression(n.expression) &&
240
- n.expression.name.text === 'ArraySlot') && !hasArraySlotImport(sourceFile);
241
- };
242
- export { addImport, generateCode, generateReactiveInlining, needsArraySlotImport };
229
+ export { generateCode, generateReactiveInlining };
@@ -6,9 +6,3 @@ type TransformResult = {
6
6
  };
7
7
  declare const transform: (sourceFile: ts.SourceFile, program: ts.Program) => TransformResult;
8
8
  export { transform };
9
- export * from '../attributes.js';
10
- export * from '../event/index.js';
11
- export { ArraySlot } from '../slot/array.js';
12
- export { EffectSlot } from '../slot/effect.js';
13
- export type * from '../types.js';
14
- export * from '../utilities.js';
@@ -1,8 +1,8 @@
1
- import { code as c } from '@esportsplus/typescript/compiler';
2
- import { addImport, generateCode, generateReactiveInlining, needsArraySlotImport } from './codegen.js';
3
- import { COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY } from '../constants.js';
4
- import { findHtmlTemplates, findReactiveCalls } from './ts-parser.js';
5
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
6
  const PATTERNS = [`${COMPILER_ENTRYPOINT}\``, `${COMPILER_ENTRYPOINT}.${COMPILER_ENTRYPOINT_REACTIVITY}`];
7
7
  const REGEX_BACKSLASH = /\\/g;
8
8
  const REGEX_FORWARD_SLASH = /\//g;
@@ -18,25 +18,29 @@ const transform = (sourceFile, program) => {
18
18
  checker = program.getTypeChecker();
19
19
  sourceFile = programSourceFile;
20
20
  }
21
- let changed = false, codegenChanged = false, needsImport = false, reactiveCalls = findReactiveCalls(sourceFile), result = code;
21
+ let changed = false, codegenChanged = false, existingAliases = new Map(), reactiveCalls = findReactiveCalls(sourceFile, checker), result = code;
22
22
  if (reactiveCalls.length > 0) {
23
+ let arraySlotAlias = uid('ArraySlot');
23
24
  changed = true;
24
- checker = undefined;
25
- result = generateReactiveInlining(reactiveCalls, result, sourceFile);
25
+ existingAliases.set('ArraySlot', arraySlotAlias);
26
+ result = generateReactiveInlining(reactiveCalls, result, sourceFile, arraySlotAlias);
26
27
  sourceFile = ts.createSourceFile(sourceFile.fileName, result, sourceFile.languageVersion, true);
27
- needsImport = needsArraySlotImport(sourceFile);
28
28
  }
29
- let templates = findHtmlTemplates(sourceFile);
29
+ let templates = findHtmlTemplates(sourceFile, checker);
30
30
  if (templates.length > 0) {
31
- let codegenResult = generateCode(templates, result, sourceFile, checker);
31
+ let codegenResult = generateCode(templates, result, sourceFile, checker, existingAliases);
32
32
  if (codegenResult.changed) {
33
33
  changed = true;
34
34
  codegenChanged = true;
35
35
  result = codegenResult.code;
36
36
  }
37
37
  }
38
- if (needsImport && !codegenChanged) {
39
- result = addImport(result);
38
+ if (existingAliases.size > 0 && !codegenChanged) {
39
+ let aliasedImports = [];
40
+ for (let [name, alias] of existingAliases) {
41
+ aliasedImports.push(`${name} as ${alias}`);
42
+ }
43
+ result = imports.modify(result, sourceFile, PACKAGE, { add: aliasedImports });
40
44
  }
41
45
  if (changed) {
42
46
  sourceFile = ts.createSourceFile(sourceFile.fileName, result, sourceFile.languageVersion, true);
@@ -44,8 +48,3 @@ const transform = (sourceFile, program) => {
44
48
  return { changed, code: result, sourceFile };
45
49
  };
46
50
  export { transform };
47
- export * from '../attributes.js';
48
- export * from '../event/index.js';
49
- export { ArraySlot } from '../slot/array.js';
50
- export { EffectSlot } from '../slot/effect.js';
51
- export * from '../utilities.js';
@@ -14,7 +14,7 @@ type TemplateInfo = {
14
14
  node: ts.TaggedTemplateExpression;
15
15
  start: number;
16
16
  };
17
- declare const findHtmlTemplates: (sourceFile: ts.SourceFile) => TemplateInfo[];
18
- declare const findReactiveCalls: (sourceFile: ts.SourceFile) => ReactiveCallInfo[];
17
+ declare const findHtmlTemplates: (sourceFile: ts.SourceFile, checker?: ts.TypeChecker) => TemplateInfo[];
18
+ declare const findReactiveCalls: (sourceFile: ts.SourceFile, checker?: ts.TypeChecker) => ReactiveCallInfo[];
19
19
  export { findHtmlTemplates, findReactiveCalls };
20
20
  export type { ReactiveCallInfo, TemplateInfo };
@@ -1,12 +1,38 @@
1
- import { COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY } from '../constants.js';
2
1
  import { ts } from '@esportsplus/typescript';
3
- function visitReactiveCalls(node, calls) {
2
+ import { COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY, PACKAGE } from '../constants.js';
3
+ function isHtmlFromPackage(node, checker) {
4
+ if (node.text !== COMPILER_ENTRYPOINT) {
5
+ return false;
6
+ }
7
+ if (!checker) {
8
+ return true;
9
+ }
10
+ let symbol = checker.getSymbolAtLocation(node);
11
+ if (!symbol) {
12
+ return true;
13
+ }
14
+ if (symbol.flags & ts.SymbolFlags.Alias) {
15
+ symbol = checker.getAliasedSymbol(symbol);
16
+ }
17
+ let declarations = symbol.getDeclarations();
18
+ if (!declarations || declarations.length === 0) {
19
+ return true;
20
+ }
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')) {
24
+ return true;
25
+ }
26
+ }
27
+ return false;
28
+ }
29
+ function visitReactiveCalls(node, calls, checker) {
4
30
  if (ts.isCallExpression(node) &&
5
31
  ts.isPropertyAccessExpression(node.expression) &&
6
32
  ts.isIdentifier(node.expression.expression) &&
7
- node.expression.expression.text === COMPILER_ENTRYPOINT &&
8
33
  node.expression.name.text === COMPILER_ENTRYPOINT_REACTIVITY &&
9
- node.arguments.length === 2) {
34
+ node.arguments.length === 2 &&
35
+ isHtmlFromPackage(node.expression.expression, checker)) {
10
36
  calls.push({
11
37
  arrayArg: node.arguments[0],
12
38
  callbackArg: node.arguments[1],
@@ -15,13 +41,13 @@ function visitReactiveCalls(node, calls) {
15
41
  start: node.getStart()
16
42
  });
17
43
  }
18
- ts.forEachChild(node, child => visitReactiveCalls(child, calls));
44
+ ts.forEachChild(node, child => visitReactiveCalls(child, calls, checker));
19
45
  }
20
- function visitTemplates(node, depth, templates) {
46
+ function visitTemplates(node, depth, templates, checker) {
21
47
  let nextDepth = (ts.isArrowFunction(node) || ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isMethodDeclaration(node))
22
48
  ? depth + 1
23
49
  : depth;
24
- if (ts.isTaggedTemplateExpression(node) && ts.isIdentifier(node.tag) && node.tag.text === COMPILER_ENTRYPOINT) {
50
+ if (ts.isTaggedTemplateExpression(node) && ts.isIdentifier(node.tag) && isHtmlFromPackage(node.tag, checker)) {
25
51
  let expressions = [], literals = [], template = node.template;
26
52
  if (ts.isNoSubstitutionTemplateLiteral(template)) {
27
53
  literals.push(template.text);
@@ -43,17 +69,17 @@ function visitTemplates(node, depth, templates) {
43
69
  start: node.getStart()
44
70
  });
45
71
  }
46
- ts.forEachChild(node, child => visitTemplates(child, nextDepth, templates));
72
+ ts.forEachChild(node, child => visitTemplates(child, nextDepth, templates, checker));
47
73
  }
48
- const findHtmlTemplates = (sourceFile) => {
74
+ const findHtmlTemplates = (sourceFile, checker) => {
49
75
  let templates = [];
50
- visitTemplates(sourceFile, 0, templates);
76
+ visitTemplates(sourceFile, 0, templates, checker);
51
77
  templates.sort((a, b) => a.depth !== b.depth ? b.depth - a.depth : a.start - b.start);
52
78
  return templates;
53
79
  };
54
- const findReactiveCalls = (sourceFile) => {
80
+ const findReactiveCalls = (sourceFile, checker) => {
55
81
  let calls = [];
56
- visitReactiveCalls(sourceFile, calls);
82
+ visitReactiveCalls(sourceFile, calls, checker);
57
83
  return calls;
58
84
  };
59
85
  export { findHtmlTemplates, findReactiveCalls };
@@ -1,6 +1,6 @@
1
1
  import { COMPILER_TYPES } from '../constants.js';
2
2
  import { ts } from '@esportsplus/typescript';
3
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[];
4
+ declare const generateAttributeBinding: (elementVar: string, name: string, expr: string, staticValue: string, addImport: (name: string) => string) => string;
5
+ declare const generateSpreadBindings: (exprCode: string, elementVar: string, addImport: (name: string) => string) => string[];
6
6
  export { analyzeExpression, generateAttributeBinding, generateSpreadBindings };
@@ -1,45 +1,5 @@
1
1
  import { COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY, COMPILER_TYPES, DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS } from '../constants.js';
2
2
  import { ts } from '@esportsplus/typescript';
3
- function analyzeSpread(expr, checker) {
4
- while (ts.isParenthesizedExpression(expr)) {
5
- expr = expr.expression;
6
- }
7
- if (ts.isObjectLiteralExpression(expr)) {
8
- let keys = [];
9
- for (let i = 0, n = expr.properties.length; i < n; i++) {
10
- let prop = expr.properties[i];
11
- if (ts.isPropertyAssignment(prop)) {
12
- if (ts.isIdentifier(prop.name) || ts.isStringLiteral(prop.name)) {
13
- keys.push(prop.name.text);
14
- }
15
- }
16
- else if (ts.isShorthandPropertyAssignment(prop)) {
17
- keys.push(prop.name.text);
18
- }
19
- else if (ts.isSpreadAssignment(prop)) {
20
- return { canUnpack: false, keys: [] };
21
- }
22
- }
23
- return { canUnpack: true, keys };
24
- }
25
- if (checker && (ts.isIdentifier(expr) || ts.isPropertyAccessExpression(expr))) {
26
- try {
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
- }
35
- if (keys.length > 0) {
36
- return { canUnpack: true, keys };
37
- }
38
- }
39
- catch { }
40
- }
41
- return { canUnpack: false, keys: [] };
42
- }
43
3
  function inferCOMPILER_TYPES(expr, checker) {
44
4
  while (ts.isParenthesizedExpression(expr)) {
45
5
  expr = expr.expression;
@@ -57,9 +17,6 @@ function inferCOMPILER_TYPES(expr, checker) {
57
17
  if (ts.isTaggedTemplateExpression(expr) && ts.isIdentifier(expr.tag) && expr.tag.text === COMPILER_ENTRYPOINT) {
58
18
  return COMPILER_TYPES.DocumentFragment;
59
19
  }
60
- if (ts.isArrayLiteralExpression(expr)) {
61
- return COMPILER_TYPES.ArraySlot;
62
- }
63
20
  if (ts.isNumericLiteral(expr) ||
64
21
  ts.isStringLiteral(expr) ||
65
22
  ts.isNoSubstitutionTemplateLiteral(expr) ||
@@ -88,98 +45,53 @@ function inferCOMPILER_TYPES(expr, checker) {
88
45
  if (isTypeFunction(type, checker)) {
89
46
  return COMPILER_TYPES.Effect;
90
47
  }
91
- if (isTypeArray(type, checker)) {
92
- return COMPILER_TYPES.ArraySlot;
93
- }
94
48
  }
95
49
  catch {
96
50
  }
97
51
  }
98
52
  return COMPILER_TYPES.Unknown;
99
53
  }
100
- function isTypeArray(type, checker) {
101
- if (checker.isArrayType(type)) {
102
- return true;
103
- }
104
- return type.getSymbol()?.getName() === 'ReactiveArray';
105
- }
106
54
  function isTypeFunction(type, checker) {
107
- if (type.getCallSignatures().length > 0) {
108
- return true;
109
- }
110
55
  if (type.isUnion()) {
56
+ let allFunctions = true, hasFunction = false;
111
57
  for (let i = 0, n = type.types.length; i < n; i++) {
112
58
  if (isTypeFunction(type.types[i], checker)) {
113
- return true;
59
+ hasFunction = true;
60
+ }
61
+ else {
62
+ allFunctions = false;
114
63
  }
115
64
  }
65
+ return hasFunction && allFunctions;
116
66
  }
117
- return false;
67
+ return type.getCallSignatures().length > 0;
118
68
  }
119
69
  const analyzeExpression = (expr, checker) => {
120
70
  return inferCOMPILER_TYPES(expr, checker);
121
71
  };
122
- const generateAttributeBinding = (elementVar, name, expr, staticValue, ns) => {
72
+ const generateAttributeBinding = (elementVar, name, expr, staticValue, addImport) => {
123
73
  if (name.startsWith('on') && name.length > 2) {
124
74
  let event = name.slice(2).toLowerCase(), key = name.toLowerCase();
125
75
  if (LIFECYCLE_EVENTS.has(key)) {
126
- return `${ns}.${key}(${elementVar}, ${expr});`;
76
+ return `${addImport(key)}(${elementVar}, ${expr});`;
127
77
  }
128
78
  if (DIRECT_ATTACH_EVENTS.has(key)) {
129
- return `${ns}.on(${elementVar}, '${event}', ${expr});`;
79
+ return `${addImport('on')}(${elementVar}, '${event}', ${expr});`;
130
80
  }
131
- return `${ns}.delegate(${elementVar}, '${event}', ${expr});`;
81
+ return `${addImport('delegate')}(${elementVar}, '${event}', ${expr});`;
132
82
  }
133
83
  if (name === 'class') {
134
- return `${ns}.setClass(${elementVar}, '${staticValue}', ${expr});`;
84
+ return `${addImport('setClass')}(${elementVar}, '${staticValue}', ${expr});`;
135
85
  }
136
86
  if (name === COMPILER_TYPES.Attributes) {
137
- return `${ns}.setProperties(${elementVar}, ${expr});`;
87
+ return `${addImport('setProperties')}(${elementVar}, ${expr});`;
138
88
  }
139
89
  if (name === 'style') {
140
- return `${ns}.setStyle(${elementVar}, '${staticValue}', ${expr});`;
90
+ return `${addImport('setStyle')}(${elementVar}, '${staticValue}', ${expr});`;
141
91
  }
142
- return `${ns}.setProperty(${elementVar}, '${name}', ${expr});`;
92
+ return `${addImport('setProperty')}(${elementVar}, '${name}', ${expr});`;
143
93
  };
144
- const generateSpreadBindings = (expr, exprCode, elementVar, checker, ns) => {
145
- while (ts.isParenthesizedExpression(expr)) {
146
- expr = expr.expression;
147
- }
148
- let analysis = analyzeSpread(expr, checker);
149
- if (!analysis.canUnpack) {
150
- return [`${ns}.setProperties(${elementVar}, ${exprCode});`];
151
- }
152
- let lines = [];
153
- if (ts.isObjectLiteralExpression(expr)) {
154
- for (let i = 0, n = analysis.keys.length; i < n; i++) {
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
- }
172
- if (value !== null) {
173
- lines.push(generateAttributeBinding(elementVar, key, value, '', ns));
174
- }
175
- }
176
- }
177
- else {
178
- for (let i = 0, n = analysis.keys.length; i < n; i++) {
179
- let key = analysis.keys[i];
180
- lines.push(generateAttributeBinding(elementVar, key, `${exprCode}.${key}`, '', ns));
181
- }
182
- }
183
- return lines;
94
+ const generateSpreadBindings = (exprCode, elementVar, addImport) => {
95
+ return [`${addImport('setProperties')}(${elementVar}, ${exprCode});`];
184
96
  };
185
97
  export { analyzeExpression, generateAttributeBinding, generateSpreadBindings };
@@ -2,7 +2,6 @@ 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;
6
5
  declare const enum COMPILER_TYPES {
7
6
  ArraySlot = "array-slot",
8
7
  Attributes = "attributes",
@@ -17,10 +16,9 @@ declare const enum COMPILER_TYPES {
17
16
  declare const DIRECT_ATTACH_EVENTS: Set<string>;
18
17
  declare const LIFECYCLE_EVENTS: Set<string>;
19
18
  declare const PACKAGE = "@esportsplus/template";
20
- declare const PACKAGE_COMPILER = "@esportsplus/template/compiler";
21
19
  declare const SLOT_HTML = "<!--$-->";
22
20
  declare const STATE_HYDRATING = 0;
23
21
  declare const STATE_NONE = 1;
24
22
  declare const STATE_WAITING = 2;
25
23
  declare const STORE: unique symbol;
26
- export { ARRAY_SLOT, CLEANUP, COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY, COMPILER_NAMESPACE, COMPILER_TYPES, DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS, PACKAGE, PACKAGE_COMPILER, SLOT_HTML, STATE_HYDRATING, STATE_NONE, STATE_WAITING, STORE, };
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, };
@@ -1,9 +1,7 @@
1
- import { uid } from '@esportsplus/typescript/compiler';
2
1
  const ARRAY_SLOT = Symbol('template.array.slot');
3
2
  const CLEANUP = Symbol('template.cleanup');
4
3
  const COMPILER_ENTRYPOINT = 'html';
5
4
  const COMPILER_ENTRYPOINT_REACTIVITY = 'reactive';
6
- const COMPILER_NAMESPACE = uid('template');
7
5
  var COMPILER_TYPES;
8
6
  (function (COMPILER_TYPES) {
9
7
  COMPILER_TYPES["ArraySlot"] = "array-slot";
@@ -30,10 +28,9 @@ const LIFECYCLE_EVENTS = new Set([
30
28
  'onconnect', 'ondisconnect', 'onrender', 'onresize', 'ontick'
31
29
  ]);
32
30
  const PACKAGE = '@esportsplus/template';
33
- const PACKAGE_COMPILER = '@esportsplus/template/compiler';
34
31
  const SLOT_HTML = '<!--$-->';
35
32
  const STATE_HYDRATING = 0;
36
33
  const STATE_NONE = 1;
37
34
  const STATE_WAITING = 2;
38
35
  const STORE = Symbol('template.store');
39
- export { ARRAY_SLOT, CLEANUP, COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY, COMPILER_NAMESPACE, COMPILER_TYPES, DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS, PACKAGE, PACKAGE_COMPILER, SLOT_HTML, STATE_HYDRATING, STATE_NONE, STATE_WAITING, 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, };