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