ripple 0.2.83 → 0.2.85

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.
@@ -5,22 +5,22 @@ import { get_attribute_event_name, is_delegated, is_event_attribute } from '../u
5
5
  const regex_return_characters = /\r/g;
6
6
 
7
7
  const VOID_ELEMENT_NAMES = [
8
- 'area',
9
- 'base',
10
- 'br',
11
- 'col',
12
- 'command',
13
- 'embed',
14
- 'hr',
15
- 'img',
16
- 'input',
17
- 'keygen',
18
- 'link',
19
- 'meta',
20
- 'param',
21
- 'source',
22
- 'track',
23
- 'wbr',
8
+ 'area',
9
+ 'base',
10
+ 'br',
11
+ 'col',
12
+ 'command',
13
+ 'embed',
14
+ 'hr',
15
+ 'img',
16
+ 'input',
17
+ 'keygen',
18
+ 'link',
19
+ 'meta',
20
+ 'param',
21
+ 'source',
22
+ 'track',
23
+ 'wbr',
24
24
  ];
25
25
 
26
26
  /**
@@ -28,684 +28,690 @@ const VOID_ELEMENT_NAMES = [
28
28
  * @param {string} name
29
29
  */
30
30
  export function is_void_element(name) {
31
- return VOID_ELEMENT_NAMES.includes(name) || name.toLowerCase() === '!doctype';
31
+ return VOID_ELEMENT_NAMES.includes(name) || name.toLowerCase() === '!doctype';
32
32
  }
33
33
 
34
34
  const RESERVED_WORDS = [
35
- 'arguments',
36
- 'await',
37
- 'break',
38
- 'case',
39
- 'catch',
40
- 'class',
41
- 'const',
42
- 'continue',
43
- 'debugger',
44
- 'default',
45
- 'delete',
46
- 'do',
47
- 'else',
48
- 'enum',
49
- 'eval',
50
- 'export',
51
- 'extends',
52
- 'false',
53
- 'finally',
54
- 'for',
55
- 'function',
56
- 'if',
57
- 'implements',
58
- 'import',
59
- 'in',
60
- 'instanceof',
61
- 'interface',
62
- 'let',
63
- 'new',
64
- 'null',
65
- 'package',
66
- 'private',
67
- 'protected',
68
- 'public',
69
- 'return',
70
- 'static',
71
- 'super',
72
- 'switch',
73
- 'this',
74
- 'throw',
75
- 'true',
76
- 'try',
77
- 'typeof',
78
- 'var',
79
- 'void',
80
- 'while',
81
- 'with',
82
- 'yield',
35
+ 'arguments',
36
+ 'await',
37
+ 'break',
38
+ 'case',
39
+ 'catch',
40
+ 'class',
41
+ 'const',
42
+ 'continue',
43
+ 'debugger',
44
+ 'default',
45
+ 'delete',
46
+ 'do',
47
+ 'else',
48
+ 'enum',
49
+ 'eval',
50
+ 'export',
51
+ 'extends',
52
+ 'false',
53
+ 'finally',
54
+ 'for',
55
+ 'function',
56
+ 'if',
57
+ 'implements',
58
+ 'import',
59
+ 'in',
60
+ 'instanceof',
61
+ 'interface',
62
+ 'let',
63
+ 'new',
64
+ 'null',
65
+ 'package',
66
+ 'private',
67
+ 'protected',
68
+ 'public',
69
+ 'return',
70
+ 'static',
71
+ 'super',
72
+ 'switch',
73
+ 'this',
74
+ 'throw',
75
+ 'true',
76
+ 'try',
77
+ 'typeof',
78
+ 'var',
79
+ 'void',
80
+ 'while',
81
+ 'with',
82
+ 'yield',
83
83
  ];
84
84
 
85
85
  export function is_reserved(word) {
86
- return RESERVED_WORDS.includes(word);
86
+ return RESERVED_WORDS.includes(word);
87
87
  }
88
88
 
89
89
  /**
90
90
  * Attributes that are boolean, i.e. they are present or not present.
91
91
  */
92
92
  const DOM_BOOLEAN_ATTRIBUTES = [
93
- 'allowfullscreen',
94
- 'async',
95
- 'autofocus',
96
- 'autoplay',
97
- 'checked',
98
- 'controls',
99
- 'default',
100
- 'disabled',
101
- 'formnovalidate',
102
- 'hidden',
103
- 'indeterminate',
104
- 'inert',
105
- 'ismap',
106
- 'loop',
107
- 'multiple',
108
- 'muted',
109
- 'nomodule',
110
- 'novalidate',
111
- 'open',
112
- 'playsinline',
113
- 'readonly',
114
- 'required',
115
- 'reversed',
116
- 'seamless',
117
- 'selected',
118
- 'webkitdirectory',
119
- 'defer',
120
- 'disablepictureinpicture',
121
- 'disableremoteplayback',
93
+ 'allowfullscreen',
94
+ 'async',
95
+ 'autofocus',
96
+ 'autoplay',
97
+ 'checked',
98
+ 'controls',
99
+ 'default',
100
+ 'disabled',
101
+ 'formnovalidate',
102
+ 'hidden',
103
+ 'indeterminate',
104
+ 'inert',
105
+ 'ismap',
106
+ 'loop',
107
+ 'multiple',
108
+ 'muted',
109
+ 'nomodule',
110
+ 'novalidate',
111
+ 'open',
112
+ 'playsinline',
113
+ 'readonly',
114
+ 'required',
115
+ 'reversed',
116
+ 'seamless',
117
+ 'selected',
118
+ 'webkitdirectory',
119
+ 'defer',
120
+ 'disablepictureinpicture',
121
+ 'disableremoteplayback',
122
122
  ];
123
123
 
124
124
  export function is_boolean_attribute(name) {
125
- return DOM_BOOLEAN_ATTRIBUTES.includes(name);
125
+ return DOM_BOOLEAN_ATTRIBUTES.includes(name);
126
126
  }
127
127
 
128
128
  const DOM_PROPERTIES = [
129
- ...DOM_BOOLEAN_ATTRIBUTES,
130
- 'formNoValidate',
131
- 'isMap',
132
- 'noModule',
133
- 'playsInline',
134
- 'readOnly',
135
- 'value',
136
- 'volume',
137
- 'defaultValue',
138
- 'defaultChecked',
139
- 'srcObject',
140
- 'noValidate',
141
- 'allowFullscreen',
142
- 'disablePictureInPicture',
143
- 'disableRemotePlayback',
129
+ ...DOM_BOOLEAN_ATTRIBUTES,
130
+ 'formNoValidate',
131
+ 'isMap',
132
+ 'noModule',
133
+ 'playsInline',
134
+ 'readOnly',
135
+ 'value',
136
+ 'volume',
137
+ 'defaultValue',
138
+ 'defaultChecked',
139
+ 'srcObject',
140
+ 'noValidate',
141
+ 'allowFullscreen',
142
+ 'disablePictureInPicture',
143
+ 'disableRemotePlayback',
144
144
  ];
145
145
 
146
146
  export function is_dom_property(name) {
147
- return DOM_PROPERTIES.includes(name);
147
+ return DOM_PROPERTIES.includes(name);
148
148
  }
149
149
 
150
150
  const unhoisted = { hoisted: false };
151
151
 
152
152
  export function get_delegated_event(event_name, handler, state) {
153
- // Handle delegated event handlers. Bail out if not a delegated event.
154
- if (!handler || !is_delegated(event_name)) {
155
- return null;
156
- }
157
-
158
- /** @type {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression | null} */
159
- let target_function = null;
160
- let binding = null;
161
-
162
- if (handler.type === 'ArrowFunctionExpression' || handler.type === 'FunctionExpression') {
163
- target_function = handler;
164
- } else if (handler.type === 'Identifier') {
165
- binding = state.scope.get(handler.name);
166
-
167
- if (state.analysis.module.scope.references.has(handler.name)) {
168
- // If a binding with the same name is referenced in the module scope (even if not declared there), bail out
169
- return unhoisted;
170
- }
171
-
172
- if (binding != null) {
173
- for (const { path } of binding.references) {
174
- const parent = path.at(-1);
175
- if (parent === undefined) return unhoisted;
176
-
177
- const grandparent = path.at(-2);
178
-
179
- /** @type {AST.RegularElement | null} */
180
- let element = null;
181
- /** @type {string | null} */
182
- let event_name = null;
183
- if (
184
- parent.type === 'ExpressionTag' &&
185
- grandparent?.type === 'Attribute' &&
186
- is_event_attribute(grandparent)
187
- ) {
188
- element = /** @type {AST.RegularElement} */ (path.at(-3));
189
- const attribute = /** @type {AST.Attribute} */ (grandparent);
190
- event_name = get_attribute_event_name(attribute.name);
191
- }
192
-
193
- if (element && event_name) {
194
- if (
195
- element.type !== 'Element' ||
196
- element.metadata.has_spread ||
197
- !is_delegated(event_name)
198
- ) {
199
- return unhoisted;
200
- }
201
- } else if (parent.type !== 'FunctionDeclaration' && parent.type !== 'VariableDeclarator') {
202
- return unhoisted;
203
- }
204
- }
205
- }
206
-
207
- // If the binding is exported, bail out
208
- if (state.analysis.exports.find((node) => node.name === handler.name)) {
209
- return unhoisted;
210
- }
211
-
212
- if (binding !== null && binding.initial !== null && !binding.updated && !binding.is_called) {
213
- const binding_type = binding.initial.type;
214
-
215
- if (
216
- binding_type === 'ArrowFunctionExpression' ||
217
- binding_type === 'FunctionDeclaration' ||
218
- binding_type === 'FunctionExpression'
219
- ) {
220
- target_function = binding.initial;
221
- }
222
- }
223
- }
224
-
225
- // If we can't find a function, or the function has multiple parameters, bail out
226
- if (target_function == null || target_function.params.length > 1) {
227
- return unhoisted;
228
- }
229
-
230
- const visited_references = new Set();
231
- const scope = target_function.metadata.scope;
232
- for (const [reference] of scope.references) {
233
- // Bail out if the arguments keyword is used or $host is referenced
234
- if (reference === 'arguments') return unhoisted;
235
-
236
- const binding = scope.get(reference);
237
- const local_binding = state.scope.get(reference);
238
-
239
- // If we are referencing a binding that is shadowed in another scope then bail out.
240
- if (local_binding !== null && binding !== null && local_binding.node !== binding.node) {
241
- return unhoisted;
242
- }
243
-
244
- if (
245
- binding !== null &&
246
- // Bail out if the the binding is a rest param
247
- (binding.declaration_kind === 'rest_param' || // or any normal not reactive bindings that are mutated.
248
- // Bail out if we reference anything from the EachBlock (for now) that mutates in non-runes mode,
249
- (binding.kind === 'normal' && binding.updated))
250
- ) {
251
- return unhoisted;
252
- }
253
- visited_references.add(reference);
254
- }
255
-
256
- return { hoisted: true, function: target_function };
153
+ // Handle delegated event handlers. Bail out if not a delegated event.
154
+ if (!handler || !is_delegated(event_name)) {
155
+ return null;
156
+ }
157
+
158
+ /** @type {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression | null} */
159
+ let target_function = null;
160
+ let binding = null;
161
+
162
+ if (handler.type === 'ArrowFunctionExpression' || handler.type === 'FunctionExpression') {
163
+ target_function = handler;
164
+ } else if (handler.type === 'Identifier') {
165
+ binding = state.scope.get(handler.name);
166
+
167
+ if (state.analysis.module.scope.references.has(handler.name)) {
168
+ // If a binding with the same name is referenced in the module scope (even if not declared there), bail out
169
+ return unhoisted;
170
+ }
171
+
172
+ if (binding != null) {
173
+ for (const { path } of binding.references) {
174
+ const parent = path.at(-1);
175
+ if (parent === undefined) return unhoisted;
176
+
177
+ const grandparent = path.at(-2);
178
+
179
+ /** @type {AST.RegularElement | null} */
180
+ let element = null;
181
+ /** @type {string | null} */
182
+ let event_name = null;
183
+ if (
184
+ parent.type === 'ExpressionTag' &&
185
+ grandparent?.type === 'Attribute' &&
186
+ is_event_attribute(grandparent)
187
+ ) {
188
+ element = /** @type {AST.RegularElement} */ (path.at(-3));
189
+ const attribute = /** @type {AST.Attribute} */ (grandparent);
190
+ event_name = get_attribute_event_name(attribute.name);
191
+ }
192
+
193
+ if (element && event_name) {
194
+ if (
195
+ element.type !== 'Element' ||
196
+ element.metadata.has_spread ||
197
+ !is_delegated(event_name)
198
+ ) {
199
+ return unhoisted;
200
+ }
201
+ } else if (parent.type !== 'FunctionDeclaration' && parent.type !== 'VariableDeclarator') {
202
+ return unhoisted;
203
+ }
204
+ }
205
+ }
206
+
207
+ // If the binding is exported, bail out
208
+ if (state.analysis.exports.find((node) => node.name === handler.name)) {
209
+ return unhoisted;
210
+ }
211
+
212
+ if (binding !== null && binding.initial !== null && !binding.updated && !binding.is_called) {
213
+ const binding_type = binding.initial.type;
214
+
215
+ if (
216
+ binding_type === 'ArrowFunctionExpression' ||
217
+ binding_type === 'FunctionDeclaration' ||
218
+ binding_type === 'FunctionExpression'
219
+ ) {
220
+ target_function = binding.initial;
221
+ }
222
+ }
223
+ }
224
+
225
+ // If we can't find a function, or the function has multiple parameters, bail out
226
+ if (target_function == null || target_function.params.length > 1) {
227
+ return unhoisted;
228
+ }
229
+
230
+ const visited_references = new Set();
231
+ const scope = target_function.metadata.scope;
232
+ for (const [reference] of scope.references) {
233
+ // Bail out if the arguments keyword is used or $host is referenced
234
+ if (reference === 'arguments') return unhoisted;
235
+
236
+ const binding = scope.get(reference);
237
+ const local_binding = state.scope.get(reference);
238
+
239
+ // If we are referencing a binding that is shadowed in another scope then bail out.
240
+ if (local_binding !== null && binding !== null && local_binding.node !== binding.node) {
241
+ return unhoisted;
242
+ }
243
+
244
+ if (
245
+ binding !== null &&
246
+ // Bail out if the the binding is a rest param
247
+ (binding.declaration_kind === 'rest_param' || // or any normal not reactive bindings that are mutated.
248
+ // Bail out if we reference anything from the EachBlock (for now) that mutates in non-runes mode,
249
+ (binding.kind === 'normal' && binding.updated))
250
+ ) {
251
+ return unhoisted;
252
+ }
253
+ visited_references.add(reference);
254
+ }
255
+
256
+ return { hoisted: true, function: target_function };
257
257
  }
258
258
 
259
259
  function get_hoisted_params(node, context) {
260
- const scope = context.state.scope;
261
-
262
- /** @type {Identifier[]} */
263
- const params = [];
264
-
265
- /**
266
- * We only want to push if it's not already present to avoid name clashing
267
- * @param {Identifier} id
268
- */
269
- function push_unique(id) {
270
- if (!params.find((param) => param.name === id.name)) {
271
- params.push(id);
272
- }
273
- }
274
-
275
- for (const [reference] of scope.references) {
276
- let binding = scope.get(reference);
277
-
278
- if (binding !== null && !scope.declarations.has(reference) && binding.initial !== node) {
279
- if (binding.kind === 'prop') {
280
- push_unique(b.id('__props'));
281
- } else if (binding.kind === 'prop_fallback') {
282
- push_unique(b.id(binding.node.name));
283
- } else if (
284
- // imports don't need to be hoisted
285
- binding.declaration_kind !== 'import'
286
- ) {
287
- // create a copy to remove start/end tags which would mess up source maps
288
- push_unique(b.id(binding.node.name));
289
- }
290
- }
291
- }
292
- return params;
260
+ const scope = context.state.scope;
261
+
262
+ /** @type {Identifier[]} */
263
+ const params = [];
264
+
265
+ /**
266
+ * We only want to push if it's not already present to avoid name clashing
267
+ * @param {Identifier} id
268
+ */
269
+ function push_unique(id) {
270
+ if (!params.find((param) => param.name === id.name)) {
271
+ params.push(id);
272
+ }
273
+ }
274
+
275
+ for (const [reference] of scope.references) {
276
+ let binding = scope.get(reference);
277
+
278
+ if (binding !== null && !scope.declarations.has(reference) && binding.initial !== node) {
279
+ if (binding.kind === 'prop') {
280
+ push_unique(b.id('__props'));
281
+ } else if (binding.kind === 'prop_fallback') {
282
+ push_unique(b.id(binding.node.name));
283
+ } else if (
284
+ // imports don't need to be hoisted
285
+ binding.declaration_kind !== 'import'
286
+ ) {
287
+ // create a copy to remove start/end tags which would mess up source maps
288
+ push_unique(b.id(binding.node.name));
289
+ }
290
+ }
291
+ }
292
+ return params;
293
293
  }
294
294
 
295
295
  export function build_hoisted_params(node, context) {
296
- const hoisted_params = get_hoisted_params(node, context);
297
- node.metadata.hoisted_params = hoisted_params;
298
-
299
- /** @type {Pattern[]} */
300
- const params = [];
301
-
302
- if (node.params.length === 0) {
303
- if (hoisted_params.length > 0) {
304
- // For the event object
305
- params.push(b.id(context.state.scope.generate('_')));
306
- }
307
- } else {
308
- for (const param of node.params) {
309
- params.push(/** @type {Pattern} */ (context.visit(param)));
310
- }
311
- }
312
-
313
- params.push(...hoisted_params, b.id('__block'));
314
- return params;
296
+ const hoisted_params = get_hoisted_params(node, context);
297
+ node.metadata.hoisted_params = hoisted_params;
298
+
299
+ /** @type {Pattern[]} */
300
+ const params = [];
301
+
302
+ if (node.params.length === 0) {
303
+ if (hoisted_params.length > 0) {
304
+ // For the event object
305
+ params.push(b.id(context.state.scope.generate('_')));
306
+ }
307
+ } else {
308
+ for (const param of node.params) {
309
+ params.push(/** @type {Pattern} */ (context.visit(param)));
310
+ }
311
+ }
312
+
313
+ params.push(...hoisted_params, b.id('__block'));
314
+ return params;
315
315
  }
316
316
 
317
317
  export function is_top_level_await(context) {
318
- if (!is_inside_component(context)) {
319
- return false;
320
- }
321
-
322
- for (let i = context.path.length - 1; i >= 0; i -= 1) {
323
- const context_node = context.path[i];
324
- const type = context_node.type;
325
-
326
- if (type === 'Component') {
327
- return true;
328
- }
329
-
330
- if (
331
- type === 'FunctionExpression' ||
332
- type === 'ArrowFunctionExpression' ||
333
- type === 'FunctionDeclaration'
334
- ) {
335
- return false;
336
- }
337
- }
338
- return true;
318
+ if (!is_inside_component(context)) {
319
+ return false;
320
+ }
321
+
322
+ for (let i = context.path.length - 1; i >= 0; i -= 1) {
323
+ const context_node = context.path[i];
324
+ const type = context_node.type;
325
+
326
+ if (type === 'Component') {
327
+ return true;
328
+ }
329
+
330
+ if (
331
+ type === 'FunctionExpression' ||
332
+ type === 'ArrowFunctionExpression' ||
333
+ type === 'FunctionDeclaration'
334
+ ) {
335
+ return false;
336
+ }
337
+ }
338
+ return true;
339
339
  }
340
340
 
341
341
  export function is_inside_component(context, includes_functions = false) {
342
- for (let i = context.path.length - 1; i >= 0; i -= 1) {
343
- const context_node = context.path[i];
344
- const type = context_node.type;
345
-
346
- if (
347
- !includes_functions &&
348
- (type === 'FunctionExpression' ||
349
- type === 'ArrowFunctionExpression' ||
350
- type === 'FunctionDeclaration')
351
- ) {
352
- return false;
353
- }
354
- if (type === 'Component') {
355
- return true;
356
- }
357
- }
358
- return false;
342
+ for (let i = context.path.length - 1; i >= 0; i -= 1) {
343
+ const context_node = context.path[i];
344
+ const type = context_node.type;
345
+
346
+ if (
347
+ !includes_functions &&
348
+ (type === 'FunctionExpression' ||
349
+ type === 'ArrowFunctionExpression' ||
350
+ type === 'FunctionDeclaration')
351
+ ) {
352
+ return false;
353
+ }
354
+ if (type === 'Component') {
355
+ return true;
356
+ }
357
+ }
358
+ return false;
359
359
  }
360
360
 
361
361
  export function is_component_level_function(context) {
362
- for (let i = context.path.length - 1; i >= 0; i -= 1) {
363
- const context_node = context.path[i];
364
- const type = context_node.type;
365
-
366
- if (type === 'BlockStatement' && context_node.body.find((n) => n.type === 'Component')) {
367
- return true;
368
- }
369
-
370
- if (
371
- type === 'FunctionExpression' ||
372
- type === 'ArrowFunctionExpression' ||
373
- type === 'FunctionDeclaration'
374
- ) {
375
- return false;
376
- }
377
- }
378
- return true;
362
+ for (let i = context.path.length - 1; i >= 0; i -= 1) {
363
+ const context_node = context.path[i];
364
+ const type = context_node.type;
365
+
366
+ if (type === 'BlockStatement' && context_node.body.find((n) => n.type === 'Component')) {
367
+ return true;
368
+ }
369
+
370
+ if (
371
+ type === 'FunctionExpression' ||
372
+ type === 'ArrowFunctionExpression' ||
373
+ type === 'FunctionDeclaration'
374
+ ) {
375
+ return false;
376
+ }
377
+ }
378
+ return true;
379
379
  }
380
380
 
381
381
  export function is_ripple_track_call(callee, context) {
382
382
  return (
383
- (callee.type === 'Identifier' && callee.name === 'track') ||
383
+ (callee.type === 'Identifier' && (callee.name === 'track' || callee.name === 'trackSplit')) ||
384
384
  (callee.type === 'MemberExpression' &&
385
385
  callee.object.type === 'Identifier' &&
386
386
  callee.property.type === 'Identifier' &&
387
- callee.property.name === 'track' &&
387
+ (callee.property.name === 'track' || callee.property.name === 'trackSplit') &&
388
388
  !callee.computed &&
389
389
  is_ripple_import(callee, context))
390
390
  );
391
391
  }
392
392
 
393
393
  export function is_inside_call_expression(context) {
394
- for (let i = context.path.length - 1; i >= 0; i -= 1) {
395
- const context_node = context.path[i];
396
- const type = context_node.type;
397
-
398
- if (
399
- type === 'FunctionExpression' ||
400
- type === 'ArrowFunctionExpression' ||
401
- type === 'FunctionDeclaration'
402
- ) {
403
- return false;
404
- }
405
- if (type === 'CallExpression') {
406
- const callee = context_node.callee;
407
- if (is_ripple_track_call(callee, context)) {
408
- return false;
409
- }
410
- return true;
411
- }
412
- }
413
- return false;
394
+ for (let i = context.path.length - 1; i >= 0; i -= 1) {
395
+ const context_node = context.path[i];
396
+ const type = context_node.type;
397
+
398
+ if (
399
+ type === 'FunctionExpression' ||
400
+ type === 'ArrowFunctionExpression' ||
401
+ type === 'FunctionDeclaration'
402
+ ) {
403
+ return false;
404
+ }
405
+ if (type === 'CallExpression') {
406
+ const callee = context_node.callee;
407
+ if (is_ripple_track_call(callee, context)) {
408
+ return false;
409
+ }
410
+ return true;
411
+ }
412
+ }
413
+ return false;
414
414
  }
415
415
 
416
416
  export function is_value_static(node) {
417
- if (node.type === 'Literal') {
418
- return true;
419
- }
420
- if (node.type === 'ArrayExpression') {
421
- return true;
422
- }
423
- if (node.type === 'NewExpression') {
424
- if (node.callee.type === 'Identifier' && node.callee.name === 'Array') {
425
- return true;
426
- }
427
- return false;
428
- }
429
-
430
- return false;
417
+ if (node.type === 'Literal') {
418
+ return true;
419
+ }
420
+ if (node.type === 'ArrayExpression') {
421
+ return true;
422
+ }
423
+ if (node.type === 'NewExpression') {
424
+ if (node.callee.type === 'Identifier' && node.callee.name === 'Array') {
425
+ return true;
426
+ }
427
+ return false;
428
+ }
429
+
430
+ return false;
431
431
  }
432
432
 
433
433
  export function is_ripple_import(callee, context) {
434
- if (callee.type === 'Identifier') {
435
- const binding = context.state.scope.get(callee.name);
436
-
437
- return (
438
- binding?.declaration_kind === 'import' &&
439
- binding.initial.source.type === 'Literal' &&
440
- binding.initial.source.value === 'ripple'
441
- );
442
- } else if (
443
- callee.type === 'MemberExpression' &&
444
- callee.object.type === 'Identifier' &&
445
- !callee.computed
446
- ) {
447
- const binding = context.state.scope.get(callee.object.name);
448
-
449
- return (
450
- binding?.declaration_kind === 'import' &&
451
- binding.initial.source.type === 'Literal' &&
452
- binding.initial.source.value === 'ripple'
453
- );
454
- }
455
-
456
- return false;
434
+ if (callee.type === 'Identifier') {
435
+ const binding = context.state.scope.get(callee.name);
436
+
437
+ return (
438
+ binding?.declaration_kind === 'import' &&
439
+ binding.initial.source.type === 'Literal' &&
440
+ binding.initial.source.value === 'ripple'
441
+ );
442
+ } else if (
443
+ callee.type === 'MemberExpression' &&
444
+ callee.object.type === 'Identifier' &&
445
+ !callee.computed
446
+ ) {
447
+ const binding = context.state.scope.get(callee.object.name);
448
+
449
+ return (
450
+ binding?.declaration_kind === 'import' &&
451
+ binding.initial.source.type === 'Literal' &&
452
+ binding.initial.source.value === 'ripple'
453
+ );
454
+ }
455
+
456
+ return false;
457
457
  }
458
458
 
459
459
  export function is_declared_function_within_component(node, context) {
460
- const component = context.path.find((n) => n.type === 'Component');
461
-
462
- if (node.type === 'Identifier' && component) {
463
- const binding = context.state.scope.get(node.name);
464
- const component_scope = context.state.scopes.get(component);
465
-
466
- if (binding !== null && component_scope !== null) {
467
- if (
468
- binding.declaration_kind !== 'function' &&
469
- binding.initial?.type !== 'FunctionDeclaration' &&
470
- binding.initial?.type !== 'ArrowFunctionExpression' &&
471
- binding.initial?.type !== 'FunctionExpression'
472
- ) {
473
- return false;
474
- }
475
- let scope = binding.scope;
476
-
477
- while (scope !== null) {
478
- if (scope === component_scope) {
479
- return true;
480
- }
481
- scope = scope.parent;
482
- }
483
- }
484
- }
485
-
486
- return false;
460
+ const component = context.path.find((n) => n.type === 'Component');
461
+
462
+ if (node.type === 'Identifier' && component) {
463
+ const binding = context.state.scope.get(node.name);
464
+ const component_scope = context.state.scopes.get(component);
465
+
466
+ if (binding !== null && component_scope !== null) {
467
+ if (
468
+ binding.declaration_kind !== 'function' &&
469
+ binding.initial?.type !== 'FunctionDeclaration' &&
470
+ binding.initial?.type !== 'ArrowFunctionExpression' &&
471
+ binding.initial?.type !== 'FunctionExpression'
472
+ ) {
473
+ return false;
474
+ }
475
+ let scope = binding.scope;
476
+
477
+ while (scope !== null) {
478
+ if (scope === component_scope) {
479
+ return true;
480
+ }
481
+ scope = scope.parent;
482
+ }
483
+ }
484
+ }
485
+
486
+ return false;
487
487
  }
488
488
 
489
489
  function is_non_coercive_operator(operator) {
490
- return ['=', '||=', '&&=', '??='].includes(operator);
490
+ return ['=', '||=', '&&=', '??='].includes(operator);
491
491
  }
492
492
 
493
493
  export function visit_assignment_expression(node, context, build_assignment) {
494
- if (
495
- node.left.type === 'ArrayPattern' ||
496
- node.left.type === 'ObjectPattern' ||
497
- node.left.type === 'RestElement'
498
- ) {
499
- const value = /** @type {Expression} */ (context.visit(node.right));
500
- const should_cache = value.type !== 'Identifier';
501
- const rhs = should_cache ? b.id('$$value') : value;
502
-
503
- let changed = false;
504
-
505
- const assignments = extract_paths(node.left).map((path) => {
506
- const value = path.expression?.(rhs);
507
-
508
- let assignment = build_assignment('=', path.node, value, context);
509
- if (assignment !== null) changed = true;
510
-
511
- return (
512
- assignment ??
513
- b.assignment(
514
- '=',
515
- /** @type {Pattern} */ (context.visit(path.node)),
516
- /** @type {Expression} */ (context.visit(value)),
517
- )
518
- );
519
- });
520
-
521
- if (!changed) {
522
- // No change to output -> nothing to transform -> we can keep the original assignment
523
- return null;
524
- }
525
-
526
- const is_standalone = /** @type {Node} */ (context.path.at(-1)).type.endsWith('Statement');
527
- const sequence = b.sequence(assignments);
528
-
529
- if (!is_standalone) {
530
- // this is part of an expression, we need the sequence to end with the value
531
- sequence.expressions.push(rhs);
532
- }
533
-
534
- if (should_cache) {
535
- // the right hand side is a complex expression, wrap in an IIFE to cache it
536
- const iife = b.arrow([rhs], sequence);
537
-
538
- const iife_is_async =
539
- is_expression_async(value) ||
540
- assignments.some((assignment) => is_expression_async(assignment));
541
-
542
- return iife_is_async ? b.await(b.call(b.async(iife), value)) : b.call(iife, value);
543
- }
544
-
545
- return sequence;
546
- }
547
-
548
- if (node.left.type !== 'Identifier' && node.left.type !== 'MemberExpression') {
549
- throw new Error(`Unexpected assignment type ${node.left.type}`);
550
- }
551
-
552
- const transformed = build_assignment(node.operator, node.left, node.right, context);
553
-
554
- if (transformed === node.left) {
555
- return node;
556
- }
557
-
558
- return transformed;
494
+ if (
495
+ node.left.type === 'ArrayPattern' ||
496
+ node.left.type === 'ObjectPattern' ||
497
+ node.left.type === 'RestElement'
498
+ ) {
499
+ const value = /** @type {Expression} */ (context.visit(node.right));
500
+ const should_cache = value.type !== 'Identifier';
501
+ const rhs = should_cache ? b.id('$$value') : value;
502
+
503
+ let changed = false;
504
+
505
+ const assignments = extract_paths(node.left).map((path) => {
506
+ const value = path.expression?.(rhs);
507
+
508
+ let assignment = build_assignment('=', path.node, value, context);
509
+ if (assignment !== null) changed = true;
510
+
511
+ return (
512
+ assignment ??
513
+ b.assignment(
514
+ '=',
515
+ /** @type {Pattern} */ (context.visit(path.node)),
516
+ /** @type {Expression} */ (context.visit(value)),
517
+ )
518
+ );
519
+ });
520
+
521
+ if (!changed) {
522
+ // No change to output -> nothing to transform -> we can keep the original assignment
523
+ return null;
524
+ }
525
+
526
+ const is_standalone = /** @type {Node} */ (context.path.at(-1)).type.endsWith('Statement');
527
+ const sequence = b.sequence(assignments);
528
+
529
+ if (!is_standalone) {
530
+ // this is part of an expression, we need the sequence to end with the value
531
+ sequence.expressions.push(rhs);
532
+ }
533
+
534
+ if (should_cache) {
535
+ // the right hand side is a complex expression, wrap in an IIFE to cache it
536
+ const iife = b.arrow([rhs], sequence);
537
+
538
+ const iife_is_async =
539
+ is_expression_async(value) ||
540
+ assignments.some((assignment) => is_expression_async(assignment));
541
+
542
+ return iife_is_async ? b.await(b.call(b.async(iife), value)) : b.call(iife, value);
543
+ }
544
+
545
+ return sequence;
546
+ }
547
+
548
+ if (node.left.type !== 'Identifier' && node.left.type !== 'MemberExpression') {
549
+ throw new Error(`Unexpected assignment type ${node.left.type}`);
550
+ }
551
+
552
+ const transformed = build_assignment(node.operator, node.left, node.right, context);
553
+
554
+ if (transformed === node.left) {
555
+ return node;
556
+ }
557
+
558
+ return transformed;
559
559
  }
560
560
 
561
561
  export function build_assignment(operator, left, right, context) {
562
- let object = left;
563
-
564
- while (object.type === 'MemberExpression') {
565
- // @ts-expect-error
566
- object = object.object;
567
- }
568
-
569
- if (object.type !== 'Identifier') {
570
- return null;
571
- }
572
-
573
- const binding = context.state.scope.get(object.name);
574
- if (!binding) return null;
575
-
576
- const transform = binding.transform;
577
-
578
- // reassignment
579
- if (object === left || (left.type === 'MemberExpression' && left.computed && operator === '=')) {
580
- const assign_fn = transform?.assign || transform?.assign_tracked;
581
- if (assign_fn) {
582
- let value = /** @type {Expression} */ (
583
- context.visit(build_assignment_value(operator, left, right))
584
- );
585
-
586
- return assign_fn(
587
- object,
588
- value,
589
- left.type === 'MemberExpression' && left.computed
590
- ? context.visit(left.property)
591
- : undefined,
592
- );
593
- }
594
- }
595
-
596
- // mutation
597
- if (transform?.mutate) {
598
- return transform.mutate(
599
- object,
600
- b.assignment(
601
- operator,
602
- /** @type {Pattern} */ (context.visit(left)),
603
- /** @type {Expression} */ (context.visit(right)),
604
- ),
605
- );
606
- }
607
-
608
- return null;
562
+ let object = left;
563
+
564
+ while (object.type === 'MemberExpression') {
565
+ // @ts-expect-error
566
+ object = object.object;
567
+ }
568
+
569
+ if (object.type !== 'Identifier') {
570
+ return null;
571
+ }
572
+
573
+ const binding = context.state.scope.get(object.name);
574
+ if (!binding) return null;
575
+
576
+ const transform = binding.transform;
577
+
578
+ // reassignment
579
+ if (object === left || (left.type === 'MemberExpression' && left.computed && operator === '=')) {
580
+ const assign_fn = transform?.assign || transform?.assign_tracked;
581
+ if (assign_fn) {
582
+ let value = /** @type {Expression} */ (
583
+ context.visit(build_assignment_value(operator, left, right))
584
+ );
585
+
586
+ return assign_fn(
587
+ object,
588
+ value,
589
+ left.type === 'MemberExpression' && left.computed
590
+ ? context.visit(left.property)
591
+ : undefined,
592
+ );
593
+ }
594
+ }
595
+
596
+ // mutation
597
+ if (transform?.mutate) {
598
+ return transform.mutate(
599
+ object,
600
+ b.assignment(
601
+ operator,
602
+ /** @type {Pattern} */ (context.visit(left)),
603
+ /** @type {Expression} */ (context.visit(right)),
604
+ ),
605
+ );
606
+ }
607
+
608
+ return null;
609
609
  }
610
610
 
611
611
  const ATTR_REGEX = /[&"<]/g;
612
612
  const CONTENT_REGEX = /[&<]/g;
613
613
 
614
614
  export function escape_html(value, is_attr = false) {
615
- const str = String(value ?? '');
615
+ const str = String(value ?? '');
616
616
 
617
- const pattern = is_attr ? ATTR_REGEX : CONTENT_REGEX;
618
- pattern.lastIndex = 0;
617
+ const pattern = is_attr ? ATTR_REGEX : CONTENT_REGEX;
618
+ pattern.lastIndex = 0;
619
619
 
620
- let escaped = '';
621
- let last = 0;
620
+ let escaped = '';
621
+ let last = 0;
622
622
 
623
- while (pattern.test(str)) {
624
- const i = pattern.lastIndex - 1;
625
- const ch = str[i];
626
- escaped += str.substring(last, i) + (ch === '&' ? '&amp;' : ch === '"' ? '&quot;' : '&lt;');
627
- last = i + 1;
628
- }
623
+ while (pattern.test(str)) {
624
+ const i = pattern.lastIndex - 1;
625
+ const ch = str[i];
626
+ escaped += str.substring(last, i) + (ch === '&' ? '&amp;' : ch === '"' ? '&quot;' : '&lt;');
627
+ last = i + 1;
628
+ }
629
629
 
630
- return escaped + str.substring(last);
630
+ return escaped + str.substring(last);
631
631
  }
632
632
 
633
633
  export function hash(str) {
634
- str = str.replace(regex_return_characters, '');
635
- let hash = 5381;
636
- let i = str.length;
634
+ str = str.replace(regex_return_characters, '');
635
+ let hash = 5381;
636
+ let i = str.length;
637
637
 
638
- while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i);
639
- return (hash >>> 0).toString(36);
638
+ while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i);
639
+ return (hash >>> 0).toString(36);
640
640
  }
641
641
 
642
642
  export function is_element_dom_element(node) {
643
- return (
644
- node.id.type === 'Identifier' &&
645
- node.id.name[0].toLowerCase() === node.id.name[0] &&
646
- node.id.name !== 'children' &&
647
- !node.id.tracked
648
- );
643
+ return (
644
+ node.id.type === 'Identifier' &&
645
+ node.id.name[0].toLowerCase() === node.id.name[0] &&
646
+ node.id.name !== 'children' &&
647
+ !node.id.tracked
648
+ );
649
649
  }
650
650
 
651
- export function normalize_children(children) {
652
- const normalized = [];
653
-
654
- for (const node of children) {
655
- normalize_child(node, normalized);
656
- }
657
-
658
- for (let i = normalized.length - 1; i >= 0; i--) {
659
- const child = normalized[i];
660
- const prev_child = normalized[i - 1];
661
-
662
- if (child.type === 'Text' && prev_child?.type === 'Text') {
663
- if (child.expression.type === 'Literal' && prev_child.expression.type === 'Literal') {
664
- prev_child.expression = b.literal(
665
- prev_child.expression.value + String(child.expression.value),
666
- );
667
- } else {
668
- prev_child.expression = b.binary(
669
- '+',
670
- prev_child.expression,
671
- b.call('String', child.expression),
672
- );
673
- }
674
- normalized.splice(i, 1);
675
- }
676
- }
677
-
678
- return normalized;
651
+ export function normalize_children(children, context) {
652
+ const normalized = [];
653
+
654
+ for (const node of children) {
655
+ normalize_child(node, normalized, context);
656
+ }
657
+
658
+ for (let i = normalized.length - 1; i >= 0; i--) {
659
+ const child = normalized[i];
660
+ const prev_child = normalized[i - 1];
661
+
662
+ if (child.type === 'Text' && prev_child?.type === 'Text') {
663
+ if (child.expression.type === 'Literal' && prev_child.expression.type === 'Literal') {
664
+ prev_child.expression = b.literal(
665
+ prev_child.expression.value + String(child.expression.value),
666
+ );
667
+ } else {
668
+ prev_child.expression = b.binary(
669
+ '+',
670
+ prev_child.expression,
671
+ b.call('String', child.expression),
672
+ );
673
+ }
674
+ normalized.splice(i, 1);
675
+ }
676
+ }
677
+
678
+ return normalized;
679
679
  }
680
680
 
681
- function normalize_child(node, normalized) {
682
- if (node.type === 'EmptyStatement') {
683
- return;
684
- } else if (node.type === 'Element' && node.id.type === 'Identifier' && node.id.name === 'style') {
685
- return;
686
- } else {
687
- normalized.push(node);
688
- }
681
+ function normalize_child(node, normalized, context) {
682
+ if (node.type === 'EmptyStatement') {
683
+ return;
684
+ } else if (
685
+ node.type === 'Element' &&
686
+ node.id.type === 'Identifier' &&
687
+ ((node.id.name === 'style' && !context.state.inside_head) ||
688
+ node.id.name === 'head' ||
689
+ (node.id.name === 'title' && context.state.inside_head))
690
+ ) {
691
+ return;
692
+ } else {
693
+ normalized.push(node);
694
+ }
689
695
  }
690
696
 
691
697
  export function build_getter(node, context) {
692
- const state = context.state;
698
+ const state = context.state;
693
699
 
694
- for (let i = context.path.length - 1; i >= 0; i -= 1) {
695
- const binding = state.scope.get(node.name);
696
- const transform = binding?.transform;
700
+ for (let i = context.path.length - 1; i >= 0; i -= 1) {
701
+ const binding = state.scope.get(node.name);
702
+ const transform = binding?.transform;
697
703
 
698
- // don't transform the declaration itself
699
- if (node !== binding?.node) {
700
- const read_fn = transform?.read;
704
+ // don't transform the declaration itself
705
+ if (node !== binding?.node) {
706
+ const read_fn = transform?.read;
701
707
 
702
- if (read_fn) {
703
- return read_fn(node, context.state?.metadata?.spread, context.visit);
704
- }
705
- }
706
- }
708
+ if (read_fn) {
709
+ return read_fn(node, context.state?.metadata?.spread, context.visit);
710
+ }
711
+ }
712
+ }
707
713
 
708
- return node;
714
+ return node;
709
715
  }
710
716
 
711
717
  export function determine_namespace_for_children(element_name, current_namespace) {
@@ -722,4 +728,4 @@ export function determine_namespace_for_children(element_name, current_namespace
722
728
  }
723
729
 
724
730
  return current_namespace;
725
- }
731
+ }