@esportsplus/template 0.32.0 → 0.32.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/build/attributes.js +1 -2
  2. package/build/constants.d.ts +18 -3
  3. package/build/constants.js +31 -4
  4. package/build/html.d.ts +3 -3
  5. package/build/index.d.ts +3 -3
  6. package/build/index.js +3 -3
  7. package/build/slot/array.d.ts +2 -2
  8. package/build/slot/array.js +5 -4
  9. package/build/slot/render.js +3 -2
  10. package/build/transformer/codegen.d.ts +3 -9
  11. package/build/transformer/codegen.js +90 -147
  12. package/build/transformer/index.d.ts +1 -5
  13. package/build/transformer/index.js +30 -46
  14. package/build/transformer/parser.d.ts +3 -2
  15. package/build/transformer/parser.js +4 -4
  16. package/build/transformer/plugins/tsc.d.ts +2 -2
  17. package/build/transformer/plugins/tsc.js +3 -4
  18. package/build/transformer/plugins/vite.d.ts +11 -3
  19. package/build/transformer/plugins/vite.js +7 -37
  20. package/build/transformer/ts-parser.d.ts +1 -2
  21. package/build/transformer/ts-parser.js +28 -41
  22. package/build/transformer/type-analyzer.d.ts +4 -5
  23. package/build/transformer/type-analyzer.js +73 -118
  24. package/build/types.d.ts +1 -1
  25. package/package.json +7 -7
  26. package/src/attributes.ts +1 -4
  27. package/src/constants.ts +42 -6
  28. package/src/html.ts +3 -3
  29. package/src/index.ts +5 -3
  30. package/src/slot/array.ts +9 -6
  31. package/src/slot/render.ts +5 -2
  32. package/src/transformer/codegen.ts +119 -189
  33. package/src/transformer/index.ts +34 -54
  34. package/src/transformer/parser.ts +10 -7
  35. package/src/transformer/plugins/tsc.ts +3 -5
  36. package/src/transformer/plugins/vite.ts +7 -47
  37. package/src/transformer/ts-parser.ts +34 -54
  38. package/src/transformer/type-analyzer.ts +90 -158
  39. package/src/types.ts +1 -1
  40. package/test/vite.config.ts +1 -1
  41. package/build/event/constants.d.ts +0 -3
  42. package/build/event/constants.js +0 -13
  43. package/src/event/constants.ts +0 -16
  44. package/storage/rewrite-analysis-2026-01-04.md +0 -439
@@ -1,5 +1,8 @@
1
- // Inlined to avoid importing constants.ts which depends on utilities.ts (uses document)
2
- const SLOT_HTML = '<!--$-->';
1
+ import {
2
+ COMPILER_TYPES,
3
+ PACKAGE,
4
+ SLOT_HTML
5
+ } from '../constants';
3
6
 
4
7
 
5
8
  type NodePath = ('firstChild' | 'firstElementChild' | 'nextElementSibling' | 'nextSibling')[];
@@ -92,8 +95,8 @@ const parse = (literals: string[]) => {
92
95
  parsed = html.split(SLOT_MARKER),
93
96
  slot = 0,
94
97
  slots: (
95
- { path: NodePath; type: 'slot' } |
96
- { attributes: typeof attributes[string]; path: NodePath; type: 'attributes' }
98
+ { path: NodePath; type: COMPILER_TYPES.NodeSlot } |
99
+ { attributes: typeof attributes[string]; path: NodePath; type: COMPILER_TYPES.AttributeSlot }
97
100
  )[] = [];
98
101
 
99
102
  {
@@ -186,10 +189,10 @@ const parse = (literals: string[]) => {
186
189
  let attrs = attributes[attr];
187
190
 
188
191
  if (!attrs) {
189
- throw new Error(`@esportsplus/template: attribute metadata could not be found for '${attr}'`);
192
+ throw new Error(`${PACKAGE}: attribute metadata could not be found for '${attr}'`);
190
193
  }
191
194
 
192
- slots.push({ attributes: attrs, path, type: 'attributes' });
195
+ slots.push({ attributes: attrs, path, type: COMPILER_TYPES.AttributeSlot });
193
196
 
194
197
  for (let i = 0, n = attrs.names.length; i < n; i++) {
195
198
  buffer += parsed[slot++];
@@ -204,7 +207,7 @@ const parse = (literals: string[]) => {
204
207
  }
205
208
  else if (type === NODE_SLOT) {
206
209
  buffer += parsed[slot++] + SLOT_HTML;
207
- slots.push({ path: methods(parent.children, parent.path, 'firstChild', 'nextSibling'), type: 'slot' });
210
+ slots.push({ path: methods(parent.children, parent.path, 'firstChild', 'nextSibling'), type: COMPILER_TYPES.NodeSlot });
208
211
  }
209
212
 
210
213
  if (n === slot) {
@@ -1,7 +1,5 @@
1
- import { createTransformer } from '../index';
2
- import { ts } from '@esportsplus/typescript';
1
+ import { plugin } from '@esportsplus/typescript/transformer';
2
+ import { transform } from '..';
3
3
 
4
4
 
5
- export default (program: ts.Program): ts.TransformerFactory<ts.SourceFile> => {
6
- return createTransformer(program);
7
- };
5
+ export default plugin.tsc(transform) as ReturnType<typeof plugin.tsc>;
@@ -1,49 +1,9 @@
1
- import { mightNeedTransform, PATTERNS, transform } from '../index';
2
- import { program, TRANSFORM_PATTERN } from '@esportsplus/typescript/transformer';
3
- import type { Plugin, ResolvedConfig } from 'vite';
4
- import { ts } from '@esportsplus/typescript';
1
+ import { plugin } from '@esportsplus/typescript/transformer';
2
+ import { PACKAGE } from '../../constants';
3
+ import { transform } from '..';
5
4
 
6
5
 
7
- export default (options?: { root?: string }): Plugin => {
8
- let root: string;
9
-
10
- return {
11
- enforce: 'pre',
12
- name: '@esportsplus/template/plugin-vite',
13
-
14
- configResolved(config: ResolvedConfig) {
15
- root = options?.root ?? config.root;
16
- },
17
-
18
- transform(code: string, id: string) {
19
- if (!TRANSFORM_PATTERN.test(id) || id.includes('node_modules')) {
20
- return null;
21
- }
22
-
23
- if (!mightNeedTransform(code, { patterns: PATTERNS })) {
24
- return null;
25
- }
26
-
27
- try {
28
- let sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true),
29
- result = transform(sourceFile, program.get(root));
30
-
31
- if (!result.changed) {
32
- return null;
33
- }
34
-
35
- return { code: result.code, map: null };
36
- }
37
- catch (error) {
38
- console.error(`@esportsplus/template: Error transforming ${id}:`, error);
39
- return null;
40
- }
41
- },
42
-
43
- watchChange(id: string) {
44
- if (TRANSFORM_PATTERN.test(id)) {
45
- program.delete(root);
46
- }
47
- }
48
- };
49
- };
6
+ export default plugin.vite({
7
+ name: PACKAGE,
8
+ transform
9
+ });
@@ -1,3 +1,4 @@
1
+ import { COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY } from '../constants';
1
2
  import { ts } from '@esportsplus/typescript';
2
3
 
3
4
 
@@ -19,51 +20,13 @@ type TemplateInfo = {
19
20
  };
20
21
 
21
22
 
22
- function extractTemplateInfo(node: ts.TaggedTemplateExpression, depth: number): TemplateInfo {
23
- let expressions: ts.Expression[] = [],
24
- literals: string[] = [],
25
- template = node.template;
26
-
27
- if (ts.isNoSubstitutionTemplateLiteral(template)) {
28
- literals.push(template.text);
29
- }
30
- else if (ts.isTemplateExpression(template)) {
31
- literals.push(template.head.text);
32
-
33
- for (let i = 0, n = template.templateSpans.length; i < n; i++) {
34
- let span = template.templateSpans[i];
35
-
36
- expressions.push(span.expression);
37
- literals.push(span.literal.text);
38
- }
39
- }
40
-
41
- return {
42
- depth,
43
- end: node.end,
44
- expressions,
45
- literals,
46
- node,
47
- start: node.getStart()
48
- };
49
- }
50
-
51
- function isFunctionNode(node: ts.Node): boolean {
52
- return (
53
- ts.isArrowFunction(node) ||
54
- ts.isFunctionDeclaration(node) ||
55
- ts.isFunctionExpression(node) ||
56
- ts.isMethodDeclaration(node)
57
- );
58
- }
59
-
60
23
  function visitReactiveCalls(node: ts.Node, calls: ReactiveCallInfo[]): void {
61
24
  if (
62
25
  ts.isCallExpression(node) &&
63
26
  ts.isPropertyAccessExpression(node.expression) &&
64
27
  ts.isIdentifier(node.expression.expression) &&
65
- node.expression.expression.text === 'html' &&
66
- node.expression.name.text === 'reactive' &&
28
+ node.expression.expression.text === COMPILER_ENTRYPOINT &&
29
+ node.expression.name.text === COMPILER_ENTRYPOINT_REACTIVITY &&
67
30
  node.arguments.length === 2
68
31
  ) {
69
32
  calls.push({
@@ -79,10 +42,37 @@ function visitReactiveCalls(node: ts.Node, calls: ReactiveCallInfo[]): void {
79
42
  }
80
43
 
81
44
  function visitTemplates(node: ts.Node, depth: number, templates: TemplateInfo[]): void {
82
- let nextDepth = isFunctionNode(node) ? depth + 1 : depth;
45
+ let nextDepth = (ts.isArrowFunction(node) || ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isMethodDeclaration(node))
46
+ ? depth + 1
47
+ : depth;
48
+
49
+ if (ts.isTaggedTemplateExpression(node) && ts.isIdentifier(node.tag) && node.tag.text === COMPILER_ENTRYPOINT) {
50
+ let expressions: ts.Expression[] = [],
51
+ literals: string[] = [],
52
+ template = node.template;
53
+
54
+ if (ts.isNoSubstitutionTemplateLiteral(template)) {
55
+ literals.push(template.text);
56
+ }
57
+ else if (ts.isTemplateExpression(template)) {
58
+ literals.push(template.head.text);
59
+
60
+ for (let i = 0, n = template.templateSpans.length; i < n; i++) {
61
+ let span = template.templateSpans[i];
62
+
63
+ expressions.push(span.expression);
64
+ literals.push(span.literal.text);
65
+ }
66
+ }
83
67
 
84
- if (ts.isTaggedTemplateExpression(node) && ts.isIdentifier(node.tag) && node.tag.text === 'html') {
85
- templates.push(extractTemplateInfo(node, depth));
68
+ templates.push({
69
+ depth,
70
+ end: node.end,
71
+ expressions,
72
+ literals,
73
+ node,
74
+ start: node.getStart()
75
+ });
86
76
  }
87
77
 
88
78
  ts.forEachChild(node, child => visitTemplates(child, nextDepth, templates));
@@ -108,16 +98,6 @@ const findReactiveCalls = (sourceFile: ts.SourceFile): ReactiveCallInfo[] => {
108
98
  return calls;
109
99
  };
110
100
 
111
- const getTemplateExpressions = (info: TemplateInfo, sourceFile: ts.SourceFile): string[] => {
112
- let exprs: string[] = [];
113
-
114
- for (let i = 0, n = info.expressions.length; i < n; i++) {
115
- exprs.push(info.expressions[i].getText(sourceFile));
116
- }
117
-
118
- return exprs;
119
- };
120
-
121
101
 
122
- export { findHtmlTemplates, findReactiveCalls, getTemplateExpressions };
102
+ export { findHtmlTemplates, findReactiveCalls };
123
103
  export type { ReactiveCallInfo, TemplateInfo };
@@ -1,21 +1,13 @@
1
- import { getNames } from './codegen';
2
- import { DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS } from '../event/constants';
1
+ import {
2
+ COMPILER_ENTRYPOINT,
3
+ COMPILER_ENTRYPOINT_REACTIVITY,
4
+ COMPILER_TYPES,
5
+ DIRECT_ATTACH_EVENTS,
6
+ LIFECYCLE_EVENTS
7
+ } from '../constants';
3
8
  import { ts } from '@esportsplus/typescript';
4
9
 
5
10
 
6
- type AnalyzerContext = {
7
- checker?: ts.TypeChecker;
8
- };
9
-
10
- type SlotType =
11
- | 'array-slot'
12
- | 'document-fragment'
13
- | 'effect'
14
- | 'node'
15
- | 'primitive'
16
- | 'static'
17
- | 'unknown';
18
-
19
11
  type SpreadAnalysis = {
20
12
  canUnpack: boolean;
21
13
  keys: string[];
@@ -51,188 +43,112 @@ function analyzeSpread(expr: ts.Expression, checker?: ts.TypeChecker): SpreadAna
51
43
 
52
44
  if (checker && (ts.isIdentifier(expr) || ts.isPropertyAccessExpression(expr))) {
53
45
  try {
54
- let keys = extractTypePropertyKeys(checker.getTypeAtLocation(expr));
55
-
56
- if (keys.length > 0) {
57
- return { canUnpack: true, keys };
58
- }
59
- }
60
- catch {
61
- }
62
- }
63
-
64
- return { canUnpack: false, keys: [] };
65
- }
66
-
67
- function extractTypePropertyKeys(type: ts.Type): string[] {
68
- let keys: string[] = [],
69
- props = type.getProperties();
70
-
71
- for (let i = 0, n = props.length; i < n; i++) {
72
- let name = props[i].getName();
73
-
74
- if (name.startsWith('__') || name.startsWith('[')) {
75
- continue;
76
- }
46
+ let keys: string[] = [],
47
+ props = checker.getTypeAtLocation(expr).getProperties();
77
48
 
78
- keys.push(name);
79
- }
49
+ for (let i = 0, n = props.length; i < n; i++) {
50
+ let name = props[i].getName();
80
51
 
81
- return keys;
82
- }
83
-
84
- function getObjectPropertyValue(expr: ts.ObjectLiteralExpression, key: string, sourceFile: ts.SourceFile): string | null {
85
- for (let i = 0, n = expr.properties.length; i < n; i++) {
86
- let prop = expr.properties[i];
52
+ if (name.startsWith('__') || name.startsWith('[')) {
53
+ continue;
54
+ }
87
55
 
88
- if (ts.isPropertyAssignment(prop)) {
89
- let name = ts.isIdentifier(prop.name)
90
- ? prop.name.text
91
- : ts.isStringLiteral(prop.name) ? prop.name.text : null;
56
+ keys.push(name);
57
+ }
92
58
 
93
- if (name === key) {
94
- return prop.initializer.getText(sourceFile);
59
+ if (keys.length > 0) {
60
+ return { canUnpack: true, keys };
95
61
  }
96
62
  }
97
- else if (ts.isShorthandPropertyAssignment(prop) && prop.name.text === key) {
98
- return prop.name.text;
99
- }
63
+ catch { }
100
64
  }
101
65
 
102
- return null;
66
+ return { canUnpack: false, keys: [] };
103
67
  }
104
68
 
105
- function inferSlotType(expr: ts.Expression, ctx?: AnalyzerContext): SlotType {
69
+ function inferCOMPILER_TYPES(expr: ts.Expression, checker?: ts.TypeChecker): COMPILER_TYPES {
106
70
  while (ts.isParenthesizedExpression(expr)) {
107
71
  expr = expr.expression;
108
72
  }
109
73
 
110
74
  if (ts.isArrowFunction(expr) || ts.isFunctionExpression(expr)) {
111
- return 'effect';
75
+ return COMPILER_TYPES.Effect;
112
76
  }
113
77
 
114
78
  if (
115
79
  ts.isCallExpression(expr) &&
116
80
  ts.isPropertyAccessExpression(expr.expression) &&
117
81
  ts.isIdentifier(expr.expression.expression) &&
118
- expr.expression.expression.text === 'html' &&
119
- expr.expression.name.text === 'reactive'
82
+ expr.expression.expression.text === COMPILER_ENTRYPOINT &&
83
+ expr.expression.name.text === COMPILER_ENTRYPOINT_REACTIVITY
120
84
  ) {
121
- return 'array-slot';
85
+ return COMPILER_TYPES.ArraySlot;
122
86
  }
123
87
 
124
- if (ts.isTaggedTemplateExpression(expr) && ts.isIdentifier(expr.tag) && expr.tag.text === 'html') {
125
- return 'document-fragment';
88
+ if (ts.isTaggedTemplateExpression(expr) && ts.isIdentifier(expr.tag) && expr.tag.text === COMPILER_ENTRYPOINT) {
89
+ return COMPILER_TYPES.DocumentFragment;
126
90
  }
127
91
 
128
92
  if (ts.isArrayLiteralExpression(expr)) {
129
- return 'array-slot';
130
- }
131
-
132
- if (ts.isStringLiteral(expr) || ts.isNoSubstitutionTemplateLiteral(expr)) {
133
- return 'static';
134
- }
135
-
136
- if (ts.isNumericLiteral(expr)) {
137
- return 'static';
138
- }
139
-
140
- if (expr.kind === ts.SyntaxKind.TrueKeyword || expr.kind === ts.SyntaxKind.FalseKeyword) {
141
- return 'static';
93
+ return COMPILER_TYPES.ArraySlot;
142
94
  }
143
95
 
144
- if (expr.kind === ts.SyntaxKind.NullKeyword || expr.kind === ts.SyntaxKind.UndefinedKeyword) {
145
- return 'static';
96
+ if (
97
+ ts.isNumericLiteral(expr) ||
98
+ ts.isStringLiteral(expr) ||
99
+ ts.isNoSubstitutionTemplateLiteral(expr) ||
100
+ expr.kind === ts.SyntaxKind.TrueKeyword ||
101
+ expr.kind === ts.SyntaxKind.FalseKeyword ||
102
+ expr.kind === ts.SyntaxKind.NullKeyword ||
103
+ expr.kind === ts.SyntaxKind.UndefinedKeyword
104
+ ) {
105
+ return COMPILER_TYPES.Static;
146
106
  }
147
107
 
148
108
  if (ts.isTemplateExpression(expr)) {
149
- return 'primitive';
109
+ return COMPILER_TYPES.Primitive;
150
110
  }
151
111
 
152
112
  if (ts.isConditionalExpression(expr)) {
153
- let whenFalse = inferSlotType(expr.whenFalse, ctx),
154
- whenTrue = inferSlotType(expr.whenTrue, ctx);
113
+ let whenFalse = inferCOMPILER_TYPES(expr.whenFalse, checker),
114
+ whenTrue = inferCOMPILER_TYPES(expr.whenTrue, checker);
155
115
 
156
116
  if (whenTrue === whenFalse) {
157
117
  return whenTrue;
158
118
  }
159
119
 
160
- if (whenTrue === 'effect' || whenFalse === 'effect') {
161
- return 'effect';
120
+ if (whenTrue === COMPILER_TYPES.Effect || whenFalse === COMPILER_TYPES.Effect) {
121
+ return COMPILER_TYPES.Effect;
162
122
  }
163
123
 
164
- return 'unknown';
124
+ return COMPILER_TYPES.Unknown;
165
125
  }
166
126
 
167
- if (ctx?.checker) {
168
- let checker = ctx.checker;
169
-
170
- if (ts.isIdentifier(expr)) {
171
- try {
172
- let type = checker.getTypeAtLocation(expr);
173
-
174
- if (isTypeFunction(type, checker)) {
175
- return 'effect';
176
- }
127
+ if (checker && (ts.isIdentifier(expr) || ts.isPropertyAccessExpression(expr) || ts.isCallExpression(expr))) {
128
+ try {
129
+ let type = checker.getTypeAtLocation(expr);
177
130
 
178
- if (isTypeArray(type, checker)) {
179
- return 'array-slot';
180
- }
181
- }
182
- catch {
131
+ if (isTypeFunction(type, checker)) {
132
+ return COMPILER_TYPES.Effect;
183
133
  }
184
- }
185
-
186
- if (ts.isPropertyAccessExpression(expr)) {
187
- try {
188
- let type = checker.getTypeAtLocation(expr);
189
134
 
190
- if (isTypeFunction(type, checker)) {
191
- return 'effect';
192
- }
193
-
194
- if (isTypeArray(type, checker)) {
195
- return 'array-slot';
196
- }
197
- }
198
- catch {
135
+ if (isTypeArray(type, checker)) {
136
+ return COMPILER_TYPES.ArraySlot;
199
137
  }
200
138
  }
201
-
202
- if (ts.isCallExpression(expr)) {
203
- try {
204
- let type = checker.getTypeAtLocation(expr);
205
-
206
- if (isTypeFunction(type, checker)) {
207
- return 'effect';
208
- }
209
-
210
- if (isTypeArray(type, checker)) {
211
- return 'array-slot';
212
- }
213
- }
214
- catch {
215
- }
139
+ catch {
216
140
  }
217
141
  }
218
142
 
219
- return 'unknown';
143
+ return COMPILER_TYPES.Unknown;
220
144
  }
221
145
 
222
146
  function isTypeArray(type: ts.Type, checker: ts.TypeChecker): boolean {
223
- let typeStr = checker.typeToString(type);
224
-
225
- if (typeStr.endsWith('[]') || typeStr.startsWith('Array<') || typeStr.startsWith('ReactiveArray<')) {
226
- return true;
227
- }
228
-
229
- let symbol = type.getSymbol();
230
-
231
- if (symbol && (symbol.getName() === 'Array' || symbol.getName() === 'ReactiveArray')) {
147
+ if (checker.isArrayType(type)) {
232
148
  return true;
233
149
  }
234
150
 
235
- return false;
151
+ return type.getSymbol()?.getName() === 'ReactiveArray';
236
152
  }
237
153
 
238
154
  function isTypeFunction(type: ts.Type, checker: ts.TypeChecker): boolean {
@@ -252,49 +168,47 @@ function isTypeFunction(type: ts.Type, checker: ts.TypeChecker): boolean {
252
168
  }
253
169
 
254
170
 
255
- const analyzeExpression = (expr: ts.Expression, checker?: ts.TypeChecker): SlotType => {
256
- return inferSlotType(expr, checker ? { checker } : undefined);
171
+ const analyzeExpression = (expr: ts.Expression, checker?: ts.TypeChecker): COMPILER_TYPES => {
172
+ return inferCOMPILER_TYPES(expr, checker);
257
173
  };
258
174
 
259
- const generateAttributeBinding = (elementVar: string, name: string, expr: string, staticValue: string): string => {
260
- let n = getNames();
261
-
175
+ const generateAttributeBinding = (elementVar: string, name: string, expr: string, staticValue: string, ns: string): string => {
262
176
  if (name.startsWith('on') && name.length > 2) {
263
177
  let event = name.slice(2).toLowerCase(),
264
178
  key = name.toLowerCase();
265
179
 
266
180
  if (LIFECYCLE_EVENTS.has(key)) {
267
- return `${n.event}.${key}(${elementVar}, ${expr});`;
181
+ return `${ns}.event.${key}(${elementVar}, ${expr});`;
268
182
  }
269
183
 
270
184
  if (DIRECT_ATTACH_EVENTS.has(key)) {
271
- return `${n.event}.direct(${elementVar}, '${event}', ${expr});`;
185
+ return `${ns}.event.direct(${elementVar}, '${event}', ${expr});`;
272
186
  }
273
187
 
274
- return `${n.event}.delegate(${elementVar}, '${event}', ${expr});`;
188
+ return `${ns}.event.delegate(${elementVar}, '${event}', ${expr});`;
275
189
  }
276
190
 
277
191
  if (name === 'class') {
278
- return `${n.attr}.setClass(${elementVar}, '${staticValue}', ${expr});`;
192
+ return `${ns}.attributes.setClass(${elementVar}, '${staticValue}', ${expr});`;
279
193
  }
280
194
 
281
195
  if (name === 'spread') {
282
- return `${n.attr}.spread(${elementVar}, ${expr});`;
196
+ return `${ns}.attributes.spread(${elementVar}, ${expr});`;
283
197
  }
284
198
 
285
199
  if (name === 'style') {
286
- return `${n.attr}.setStyle(${elementVar}, '${staticValue}', ${expr});`;
200
+ return `${ns}.attributes.setStyle(${elementVar}, '${staticValue}', ${expr});`;
287
201
  }
288
202
 
289
- return `${n.attr}.setProperty(${elementVar}, '${name}', ${expr});`;
203
+ return `${ns}.attributes.setProperty(${elementVar}, '${name}', ${expr});`;
290
204
  };
291
205
 
292
206
  const generateSpreadBindings = (
293
207
  expr: ts.Expression,
294
208
  exprCode: string,
295
209
  elementVar: string,
296
- sourceFile: ts.SourceFile,
297
- checker?: ts.TypeChecker
210
+ checker: ts.TypeChecker | undefined,
211
+ ns: string
298
212
  ): string[] => {
299
213
  while (ts.isParenthesizedExpression(expr)) {
300
214
  expr = expr.expression;
@@ -303,7 +217,7 @@ const generateSpreadBindings = (
303
217
  let analysis = analyzeSpread(expr, checker);
304
218
 
305
219
  if (!analysis.canUnpack) {
306
- return [`${getNames().attr}.spread(${elementVar}, ${exprCode});`];
220
+ return [`${ns}.attributes.spread(${elementVar}, ${exprCode});`];
307
221
  }
308
222
 
309
223
  let lines: string[] = [];
@@ -311,10 +225,29 @@ const generateSpreadBindings = (
311
225
  if (ts.isObjectLiteralExpression(expr)) {
312
226
  for (let i = 0, n = analysis.keys.length; i < n; i++) {
313
227
  let key = analysis.keys[i],
314
- value = getObjectPropertyValue(expr, key, sourceFile);
228
+ value: string | null = null;
229
+
230
+ for (let j = 0, m = expr.properties.length; j < m; j++) {
231
+ let prop = expr.properties[j];
232
+
233
+ if (ts.isPropertyAssignment(prop)) {
234
+ let text = ts.isIdentifier(prop.name)
235
+ ? prop.name.text
236
+ : ts.isStringLiteral(prop.name) ? prop.name.text : null;
237
+
238
+ if (text === key) {
239
+ value = prop.initializer.getText();
240
+ break;
241
+ }
242
+ }
243
+ else if (ts.isShorthandPropertyAssignment(prop) && prop.name.text === key) {
244
+ value = prop.name.text;
245
+ break;
246
+ }
247
+ }
315
248
 
316
249
  if (value !== null) {
317
- lines.push(generateAttributeBinding(elementVar, key, value, ''));
250
+ lines.push(generateAttributeBinding(elementVar, key, value, '', ns));
318
251
  }
319
252
  }
320
253
  }
@@ -322,7 +255,7 @@ const generateSpreadBindings = (
322
255
  for (let i = 0, n = analysis.keys.length; i < n; i++) {
323
256
  let key = analysis.keys[i];
324
257
 
325
- lines.push(generateAttributeBinding(elementVar, key, `${exprCode}.${key}`, ''));
258
+ lines.push(generateAttributeBinding(elementVar, key, `${exprCode}.${key}`, '', ns));
326
259
  }
327
260
  }
328
261
 
@@ -331,4 +264,3 @@ const generateSpreadBindings = (
331
264
 
332
265
 
333
266
  export { analyzeExpression, generateAttributeBinding, generateSpreadBindings };
334
- export type { SlotType };
package/src/types.ts CHANGED
@@ -26,7 +26,7 @@ type Element = HTMLElement & Attributes<any>;
26
26
  // - Importing from ^ causes 'cannot be named without a reference to...' error
27
27
  type Primitive = bigint | boolean | null | number | string | undefined;
28
28
 
29
- type Renderable<T> = DocumentFragment | ArraySlot<T> | Effect<T> | Node | NodeList | Primitive | Renderable<T>[];
29
+ type Renderable<T> = ArraySlot<T> | DocumentFragment | Effect<T> | Node | NodeList | Primitive | Renderable<T>[];
30
30
 
31
31
  type SlotGroup = {
32
32
  head: Element;
@@ -40,7 +40,7 @@ export default defineConfig({
40
40
  },
41
41
  plugins: [
42
42
  tsconfigPaths(),
43
- templatePlugin()
43
+ templatePlugin({ root: __dirname })
44
44
  ],
45
45
  resolve: {
46
46
  alias: {
@@ -1,3 +0,0 @@
1
- declare const DIRECT_ATTACH_EVENTS: Set<string>;
2
- declare const LIFECYCLE_EVENTS: Set<string>;
3
- export { DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS };
@@ -1,13 +0,0 @@
1
- const DIRECT_ATTACH_EVENTS = new Set([
2
- 'onblur',
3
- 'onerror',
4
- 'onfocus', 'onfocusin', 'onfocusout',
5
- 'onload',
6
- 'onplay', 'onpause', 'onended', 'ontimeupdate',
7
- 'onreset',
8
- 'onscroll', 'onsubmit'
9
- ]);
10
- const LIFECYCLE_EVENTS = new Set([
11
- 'onconnect', 'ondisconnect', 'onrender', 'onresize', 'ontick'
12
- ]);
13
- export { DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS };
@@ -1,16 +0,0 @@
1
- const DIRECT_ATTACH_EVENTS = new Set<string>([
2
- 'onblur',
3
- 'onerror',
4
- 'onfocus', 'onfocusin', 'onfocusout',
5
- 'onload',
6
- 'onplay', 'onpause', 'onended', 'ontimeupdate',
7
- 'onreset',
8
- 'onscroll', 'onsubmit'
9
- ]);
10
-
11
- const LIFECYCLE_EVENTS = new Set<string>([
12
- 'onconnect', 'ondisconnect', 'onrender', 'onresize', 'ontick'
13
- ]);
14
-
15
-
16
- export { DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS };