ripple 0.2.147 → 0.2.148

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 CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Ripple is an elegant TypeScript UI framework",
4
4
  "license": "MIT",
5
5
  "author": "Dominic Gannaway",
6
- "version": "0.2.147",
6
+ "version": "0.2.148",
7
7
  "type": "module",
8
8
  "module": "src/runtime/index-client.js",
9
9
  "main": "src/runtime/index-client.js",
@@ -81,6 +81,6 @@
81
81
  "typescript": "^5.9.2"
82
82
  },
83
83
  "peerDependencies": {
84
- "ripple": "0.2.147"
84
+ "ripple": "0.2.148"
85
85
  }
86
86
  }
@@ -45,8 +45,6 @@ function mark_control_flow_has_template(path) {
45
45
 
46
46
  function visit_function(node, context) {
47
47
  node.metadata = {
48
- hoisted: false,
49
- hoisted_params: [],
50
48
  scope: context.state.scope,
51
49
  tracked: false,
52
50
  };
@@ -722,12 +720,7 @@ const visitors = {
722
720
  const handler = visit(attr.value, state);
723
721
  const delegated_event = get_delegated_event(event_name, handler, state);
724
722
 
725
- if (delegated_event !== null) {
726
- if (delegated_event.hoisted) {
727
- delegated_event.function.metadata.hoisted = true;
728
- delegated_event.hoisted = true;
729
- }
730
-
723
+ if (delegated_event) {
731
724
  if (attr.metadata === undefined) {
732
725
  attr.metadata = {};
733
726
  }
@@ -17,7 +17,6 @@ import {
17
17
  } from '../../../../constants.js';
18
18
  import { sanitize_template_string } from '../../../../utils/sanitize_template_string.js';
19
19
  import {
20
- build_hoisted_params,
21
20
  is_inside_component,
22
21
  build_assignment,
23
22
  visit_assignment_expression,
@@ -75,16 +74,6 @@ function visit_function(node, context) {
75
74
  }
76
75
  }
77
76
 
78
- if (metadata?.hoisted === true) {
79
- const params = build_hoisted_params(node, context);
80
-
81
- return /** @type {FunctionExpression} */ ({
82
- ...node,
83
- params,
84
- body: context.visit(node.body, state),
85
- });
86
- }
87
-
88
77
  let body = context.visit(node.body, {
89
78
  ...state,
90
79
  // we are new context so tracking no longer applies
@@ -132,13 +121,7 @@ function visit_head_element(node, context) {
132
121
  '_$_.head',
133
122
  b.arrow(
134
123
  [b.id('__anchor')],
135
- b.block([
136
- ...init,
137
- ...update.map((u) => {
138
- debugger;
139
- }),
140
- ...final,
141
- ]),
124
+ b.block([...init, ...update.map((u) => u.operation), ...final]),
142
125
  ),
143
126
  ),
144
127
  );
@@ -985,21 +968,7 @@ const visitors = {
985
968
  state.events.add(event_name);
986
969
  }
987
970
 
988
- // Hoist function if we can, otherwise we leave the function as is
989
- if (attr.metadata.delegated.hoisted) {
990
- if (attr.metadata.delegated.function === attr.value) {
991
- const func_name = state.scope.root.unique('on_' + event_name);
992
- state.hoisted.push(b.var(func_name, handler));
993
- handler = func_name;
994
- }
995
-
996
- const hoisted_params = /** @type {Expression[]} */ (
997
- attr.metadata.delegated.function.metadata.hoisted_params
998
- );
999
-
1000
- const args = [handler, b.id('__block'), ...hoisted_params];
1001
- delegated_assignment = b.array(args);
1002
- } else if (
971
+ if (
1003
972
  (handler.type === 'Identifier' &&
1004
973
  is_declared_function_within_component(handler, context)) ||
1005
974
  handler.type === 'ArrowFunctionExpression' ||
@@ -2125,7 +2094,6 @@ function transform_ts_child(node, context) {
2125
2094
  .map((child) => visit(child, state))
2126
2095
  .filter((child) => child.type !== 'JSXText' || child.value.trim() !== '');
2127
2096
 
2128
- debugger;
2129
2097
  state.init.push(b.stmt(b.jsx_fragment(children)));
2130
2098
  } else {
2131
2099
  throw new Error('TODO');
@@ -323,8 +323,5 @@ export interface TransformContext {
323
323
  * Delegated event result
324
324
  */
325
325
  export interface DelegatedEventResult {
326
- /** Whether event was hoisted */
327
- hoisted: boolean;
328
- /** The hoisted function */
329
326
  function?: FunctionExpression | FunctionDeclaration | ArrowFunctionExpression;
330
327
  }
@@ -169,206 +169,19 @@ export function is_dom_property(name) {
169
169
  return DOM_PROPERTIES.includes(name);
170
170
  }
171
171
 
172
- const unhoisted = { hoisted: false };
173
-
174
172
  /**
175
- * Determines if an event handler can be hoisted for delegation
173
+ * Determines if an event handler can be delegated
176
174
  * @param {string} event_name
177
175
  * @param {Expression} handler
178
176
  * @param {CompilerState} state
179
- * @returns {DelegatedEventResult | null}
177
+ * @returns {boolean}
180
178
  */
181
179
  export function get_delegated_event(event_name, handler, state) {
182
180
  // Handle delegated event handlers. Bail out if not a delegated event.
183
181
  if (!handler || !is_delegated(event_name)) {
184
- return null;
185
- }
186
-
187
- /** @type {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression | null} */
188
- let target_function = null;
189
- let binding = null;
190
-
191
- if (handler.type === 'ArrowFunctionExpression' || handler.type === 'FunctionExpression') {
192
- target_function = handler;
193
- } else if (handler.type === 'Identifier') {
194
- binding = state.scope.get(handler.name);
195
-
196
- if (state.analysis.module.scope.references.has(handler.name)) {
197
- // If a binding with the same name is referenced in the module scope (even if not declared there), bail out
198
- return unhoisted;
199
- }
200
-
201
- if (binding != null) {
202
- for (const { path } of binding.references) {
203
- const parent = path.at(-1);
204
- if (parent === undefined) {
205
- return unhoisted;
206
- }
207
-
208
- const grandparent = path.at(-2);
209
-
210
- /** @type {Element | null} */
211
- let element = null;
212
- /** @type {string | null} */
213
- let event_name = null;
214
- if (
215
- parent.type === 'Expression' &&
216
- grandparent?.type === 'Attribute' &&
217
- is_event_attribute(grandparent)
218
- ) {
219
- element = /** @type {Element} */ (path.at(-3));
220
- const attribute = /** @type {Attribute} */ (grandparent);
221
- event_name = get_attribute_event_name(attribute.name.name);
222
- }
223
-
224
- if (element && event_name) {
225
- if (
226
- element.type !== 'Element' ||
227
- element.metadata.has_spread ||
228
- !is_delegated(event_name)
229
- ) {
230
- return unhoisted;
231
- }
232
- } else if (
233
- parent.type !== 'FunctionDeclaration' &&
234
- parent.type !== 'VariableDeclarator' &&
235
- parent.type !== 'Attribute'
236
- ) {
237
- return unhoisted;
238
- }
239
- }
240
- }
241
-
242
- // If the binding is exported, bail out
243
- if (
244
- state.analysis?.exports?.find(
245
- (/** @type {{name: string}} */ node) => node.name === handler.name,
246
- )
247
- ) {
248
- return unhoisted;
249
- }
250
-
251
- if (binding !== null && binding.initial !== null && !binding.updated && !binding.is_called) {
252
- const binding_type = binding.initial.type;
253
-
254
- if (
255
- binding_type === 'ArrowFunctionExpression' ||
256
- binding_type === 'FunctionDeclaration' ||
257
- binding_type === 'FunctionExpression'
258
- ) {
259
- target_function = binding.initial;
260
- }
261
- }
262
- }
263
-
264
- // If we can't find a function, or the function has multiple parameters, bail out
265
- if (target_function == null || target_function.params.length > 1) {
266
- return unhoisted;
267
- }
268
-
269
- const visited_references = new Set();
270
- const scope = target_function.metadata.scope;
271
- for (const [reference, ref_nodes] of scope.references) {
272
- // Bail out if the arguments keyword is used or $host is referenced
273
- if (reference === 'arguments') return unhoisted;
274
-
275
- const binding = scope.get(reference);
276
- const local_binding = state.scope.get(reference);
277
-
278
- if (local_binding === null || binding == null) {
279
- return unhoisted;
280
- }
281
-
282
- // If we are referencing a binding that is shadowed in another scope then bail out.
283
- if (local_binding.node !== binding.node) {
284
- return unhoisted;
285
- }
286
- const is_tracked = ref_nodes.some(({ node }) => node.tracked);
287
-
288
- if (
289
- binding !== null &&
290
- // Bail out if the the binding is a rest param
291
- (binding.declaration_kind === 'rest_param' || // or any normal not reactive bindings that are mutated.
292
- // Bail out if we reference anything from the EachBlock (for now) that mutates in non-runes mode,
293
- (binding.kind === 'normal' && !is_tracked && binding.updated))
294
- ) {
295
- return unhoisted;
296
- }
297
- visited_references.add(reference);
298
- }
299
-
300
- return { hoisted: true, function: target_function };
301
- }
302
-
303
- /**
304
- * @param {Node} node
305
- * @param {TransformContext} context
306
- * @returns {Identifier[]}
307
- */
308
- function get_hoisted_params(node, context) {
309
- const scope = context.state.scope;
310
-
311
- /** @type {Identifier[]} */
312
- const params = [];
313
-
314
- /**
315
- * We only want to push if it's not already present to avoid name clashing
316
- * @param {Identifier} id
317
- */
318
- function push_unique(id) {
319
- if (!params.find((param) => param.name === id.name)) {
320
- params.push(id);
321
- }
322
- }
323
-
324
- for (const [reference] of scope.references) {
325
- let binding = scope.get(reference);
326
-
327
- if (binding !== null && !scope.declarations.has(reference) && binding.initial !== node) {
328
- if (binding.kind === 'prop') {
329
- push_unique(b.id('__props'));
330
- } else if (binding.kind === 'for_pattern') {
331
- push_unique(binding.metadata.pattern);
332
- } else if (binding.kind === 'prop_fallback') {
333
- push_unique(b.id(binding.node.name));
334
- } else if (
335
- // imports don't need to be hoisted
336
- binding.declaration_kind !== 'import'
337
- ) {
338
- // create a copy to remove start/end tags which would mess up source maps
339
- push_unique(b.id(binding.node.name));
340
- }
341
- }
342
- }
343
- return params;
344
- }
345
-
346
- /**
347
- * Builds the parameter list for a hoisted function
348
- * @param {FunctionDeclaration|FunctionExpression|ArrowFunctionExpression} node
349
- * @param {TransformContext} context
350
- * @returns {Pattern[]}
351
- */
352
- export function build_hoisted_params(node, context) {
353
- const hoisted_params = get_hoisted_params(node, context);
354
- node.metadata.hoisted_params = hoisted_params;
355
-
356
- /** @type {Pattern[]} */
357
- const params = [];
358
-
359
- if (node.params.length === 0) {
360
- if (hoisted_params.length > 0) {
361
- // For the event object
362
- params.push(b.id(context.state.scope.generate('_')));
363
- }
364
- } else {
365
- for (const param of node.params) {
366
- params.push(/** @type {Pattern} */ (context.visit(param)));
367
- }
182
+ return false;
368
183
  }
369
-
370
- params.push(...hoisted_params, b.id('__block'));
371
- return params;
184
+ return true;
372
185
  }
373
186
 
374
187
  /**