ripple 0.3.3 → 0.3.5

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 (128) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/package.json +2 -2
  3. package/src/compiler/identifier-utils.js +1 -8
  4. package/src/compiler/phases/1-parse/index.js +101 -195
  5. package/src/compiler/phases/2-analyze/index.js +115 -174
  6. package/src/compiler/phases/2-analyze/prune.js +2 -2
  7. package/src/compiler/phases/3-transform/client/index.js +177 -261
  8. package/src/compiler/phases/3-transform/server/index.js +185 -42
  9. package/src/compiler/types/index.d.ts +15 -34
  10. package/src/compiler/utils.js +32 -20
  11. package/src/runtime/index-client.js +0 -17
  12. package/src/runtime/internal/client/bindings.js +118 -7
  13. package/src/runtime/internal/client/render.js +5 -1
  14. package/src/runtime/internal/client/runtime.js +1 -1
  15. package/src/runtime/internal/client/types.d.ts +4 -0
  16. package/src/runtime/internal/server/index.js +11 -0
  17. package/tests/client/array/array.copy-within.test.ripple +7 -7
  18. package/tests/client/array/array.derived.test.ripple +24 -24
  19. package/tests/client/array/array.iteration.test.ripple +7 -7
  20. package/tests/client/array/array.mutations.test.ripple +17 -17
  21. package/tests/client/array/array.to-methods.test.ripple +4 -4
  22. package/tests/client/async-suspend.test.ripple +3 -3
  23. package/tests/client/basic/basic.attributes.test.ripple +31 -31
  24. package/tests/client/basic/basic.collections.test.ripple +6 -6
  25. package/tests/client/basic/basic.components.test.ripple +8 -8
  26. package/tests/client/basic/basic.errors.test.ripple +31 -34
  27. package/tests/client/basic/basic.events.test.ripple +11 -11
  28. package/tests/client/basic/basic.get-set.test.ripple +18 -18
  29. package/tests/client/basic/basic.reactivity.test.ripple +36 -36
  30. package/tests/client/basic/basic.rendering.test.ripple +7 -7
  31. package/tests/client/basic/basic.utilities.test.ripple +4 -4
  32. package/tests/client/boundaries.test.ripple +7 -7
  33. package/tests/client/compiler/__snapshots__/compiler.typescript.test.ripple.snap +24 -0
  34. package/tests/client/compiler/compiler.assignments.test.ripple +12 -10
  35. package/tests/client/compiler/compiler.basic.test.ripple +57 -58
  36. package/tests/client/compiler/compiler.tracked-access.test.ripple +14 -8
  37. package/tests/client/compiler/compiler.typescript.test.ripple +31 -0
  38. package/tests/client/composite/composite.dynamic-components.test.ripple +6 -6
  39. package/tests/client/composite/composite.props.test.ripple +9 -9
  40. package/tests/client/composite/composite.reactivity.test.ripple +23 -23
  41. package/tests/client/composite/composite.render.test.ripple +52 -4
  42. package/tests/client/computed-properties.test.ripple +3 -3
  43. package/tests/client/context.test.ripple +3 -3
  44. package/tests/client/css/global-additional-cases.test.ripple +5 -2
  45. package/tests/client/css/style-identifier.test.ripple +40 -49
  46. package/tests/client/date.test.ripple +39 -39
  47. package/tests/client/dynamic-elements.test.ripple +37 -37
  48. package/tests/client/events.test.ripple +25 -25
  49. package/tests/client/for.test.ripple +8 -8
  50. package/tests/client/head.test.ripple +7 -7
  51. package/tests/client/html.test.ripple +2 -2
  52. package/tests/client/input-value.test.ripple +376 -177
  53. package/tests/client/lazy-destructuring.test.ripple +209 -0
  54. package/tests/client/map.test.ripple +20 -20
  55. package/tests/client/media-query.test.ripple +4 -4
  56. package/tests/client/object.test.ripple +5 -5
  57. package/tests/client/portal.test.ripple +4 -4
  58. package/tests/client/ref.test.ripple +3 -3
  59. package/tests/client/return.test.ripple +17 -17
  60. package/tests/client/set.test.ripple +10 -10
  61. package/tests/client/svg.test.ripple +6 -5
  62. package/tests/client/switch.test.ripple +10 -10
  63. package/tests/client/tracked-expression.test.ripple +3 -1
  64. package/tests/client/try.test.ripple +4 -4
  65. package/tests/client/url/url.derived.test.ripple +6 -7
  66. package/tests/client/url/url.parsing.test.ripple +9 -9
  67. package/tests/client/url/url.partial-removal.test.ripple +9 -9
  68. package/tests/client/url/url.reactivity.test.ripple +16 -16
  69. package/tests/client/url/url.serialization.test.ripple +3 -3
  70. package/tests/client/url-search-params/url-search-params.derived.test.ripple +7 -8
  71. package/tests/client/url-search-params/url-search-params.initialization.test.ripple +6 -4
  72. package/tests/client/url-search-params/url-search-params.iteration.test.ripple +12 -12
  73. package/tests/client/url-search-params/url-search-params.mutation.test.ripple +18 -18
  74. package/tests/client/url-search-params/url-search-params.retrieval.test.ripple +16 -16
  75. package/tests/client/url-search-params/url-search-params.serialization.test.ripple +4 -4
  76. package/tests/client/url-search-params/url-search-params.tracked-url.test.ripple +3 -3
  77. package/tests/hydration/build-components.js +4 -10
  78. package/tests/hydration/compiled/client/basic.js +4 -4
  79. package/tests/hydration/compiled/client/events.js +2 -0
  80. package/tests/hydration/compiled/client/for.js +2 -0
  81. package/tests/hydration/compiled/client/head.js +13 -11
  82. package/tests/hydration/compiled/client/hmr.js +4 -2
  83. package/tests/hydration/compiled/client/html.js +82 -95
  84. package/tests/hydration/compiled/client/if-children.js +8 -9
  85. package/tests/hydration/compiled/client/if.js +2 -0
  86. package/tests/hydration/compiled/client/mixed-control-flow.js +4 -2
  87. package/tests/hydration/compiled/client/portal.js +1 -1
  88. package/tests/hydration/compiled/client/reactivity.js +2 -0
  89. package/tests/hydration/compiled/client/return.js +2 -0
  90. package/tests/hydration/compiled/client/switch.js +2 -0
  91. package/tests/hydration/compiled/server/composite.js +2 -2
  92. package/tests/hydration/compiled/server/events.js +2 -0
  93. package/tests/hydration/compiled/server/for.js +2 -0
  94. package/tests/hydration/compiled/server/head.js +13 -11
  95. package/tests/hydration/compiled/server/hmr.js +2 -0
  96. package/tests/hydration/compiled/server/html.js +2 -0
  97. package/tests/hydration/compiled/server/if-children.js +2 -0
  98. package/tests/hydration/compiled/server/if.js +2 -0
  99. package/tests/hydration/compiled/server/mixed-control-flow.js +2 -0
  100. package/tests/hydration/compiled/server/portal.js +1 -1
  101. package/tests/hydration/compiled/server/reactivity.js +2 -0
  102. package/tests/hydration/compiled/server/return.js +2 -0
  103. package/tests/hydration/compiled/server/switch.js +2 -0
  104. package/tests/hydration/components/composite.ripple +1 -1
  105. package/tests/hydration/components/events.ripple +10 -8
  106. package/tests/hydration/components/for.ripple +22 -20
  107. package/tests/hydration/components/head.ripple +8 -6
  108. package/tests/hydration/components/hmr.ripple +3 -1
  109. package/tests/hydration/components/html.ripple +3 -1
  110. package/tests/hydration/components/if-children.ripple +9 -7
  111. package/tests/hydration/components/if.ripple +7 -5
  112. package/tests/hydration/components/mixed-control-flow.ripple +5 -3
  113. package/tests/hydration/components/portal.ripple +2 -2
  114. package/tests/hydration/components/reactivity.ripple +11 -9
  115. package/tests/hydration/components/return.ripple +13 -11
  116. package/tests/hydration/components/switch.ripple +6 -4
  117. package/tests/server/__snapshots__/compiler.test.ripple.snap +22 -0
  118. package/tests/server/await.test.ripple +2 -2
  119. package/tests/server/basic.attributes.test.ripple +21 -19
  120. package/tests/server/basic.components.test.ripple +5 -4
  121. package/tests/server/basic.test.ripple +21 -20
  122. package/tests/server/compiler.test.ripple +36 -5
  123. package/tests/server/composite.props.test.ripple +7 -6
  124. package/tests/server/context.test.ripple +3 -1
  125. package/tests/server/dynamic-elements.test.ripple +24 -24
  126. package/tests/server/head.test.ripple +7 -5
  127. package/tests/server/lazy-destructuring.test.ripple +103 -0
  128. package/tests/server/style-identifier.test.ripple +95 -16
@@ -68,6 +68,79 @@ function mark_control_flow_has_template(path) {
68
68
  }
69
69
  }
70
70
 
71
+ /**
72
+ * Set up lazy destructuring transforms for bindings extracted from a lazy pattern.
73
+ * Converts each destructured identifier into a binding that lazily accesses properties
74
+ * on the source identifier (e.g., `a` → `source.a` for object, `a` → `source[0]` for array).
75
+ * @param {AST.ObjectPattern | AST.ArrayPattern} pattern - The destructuring pattern with lazy: true
76
+ * @param {AST.Identifier} source_id - The identifier to access properties on
77
+ * @param {AnalysisState} state - The analysis state
78
+ * @param {boolean} writable - Whether assignments/updates should be supported (let vs const)
79
+ */
80
+ function setup_lazy_transforms(pattern, source_id, state, writable) {
81
+ const paths = extract_paths(pattern);
82
+
83
+ for (const path of paths) {
84
+ const name = /** @type {AST.Identifier} */ (path.node).name;
85
+ const binding = state.scope.get(name);
86
+
87
+ if (binding !== null) {
88
+ const has_fallback = path.has_default_value;
89
+ binding.kind = has_fallback ? 'lazy_fallback' : 'lazy';
90
+
91
+ binding.transform = {
92
+ read: (_) => {
93
+ return path.expression(source_id);
94
+ },
95
+ };
96
+
97
+ if (writable) {
98
+ binding.transform.assign = (node, value) => {
99
+ return b.assignment(
100
+ '=',
101
+ /** @type {AST.MemberExpression} */ (path.update_expression(source_id)),
102
+ value,
103
+ );
104
+ };
105
+
106
+ if (has_fallback) {
107
+ // For bindings with default values, generate proper fallback-aware update
108
+ // e.g., count++ with default 0 becomes:
109
+ // (() => { var _v = _$_.fallback(obj.count, 0); obj.count = _v + 1; return _v; })() for postfix
110
+ // (obj.count = _$_.fallback(obj.count, 0) + 1) for prefix
111
+ binding.transform.update = (node) => {
112
+ const member = path.update_expression(source_id);
113
+ const fallback_read = path.expression(source_id);
114
+ const delta = node.operator === '++' ? b.literal(1) : b.literal(-1);
115
+
116
+ if (node.prefix) {
117
+ // ++count: return new value
118
+ return b.assignment('=', member, b.binary('+', fallback_read, delta));
119
+ } else {
120
+ // count++: return old value, write new value
121
+ // Use IIFE to declare temp variable
122
+ const temp = b.id('_v');
123
+ return b.call(
124
+ b.arrow(
125
+ [],
126
+ b.block([
127
+ b.var(temp, fallback_read),
128
+ b.stmt(b.assignment('=', member, b.binary('+', temp, delta))),
129
+ b.return(temp),
130
+ ]),
131
+ ),
132
+ );
133
+ }
134
+ };
135
+ } else {
136
+ binding.transform.update = (node) =>
137
+ b.update(node.operator, path.update_expression(source_id), node.prefix);
138
+ }
139
+ }
140
+ }
141
+ }
142
+ }
143
+
71
144
  /**
72
145
  * @param {AST.Function} node
73
146
  * @param {AnalysisContext} context
@@ -78,6 +151,19 @@ function visit_function(node, context) {
78
151
  path: [...context.path],
79
152
  };
80
153
 
154
+ // Set up lazy transforms for any lazy destructured parameters
155
+ for (let i = 0; i < node.params.length; i++) {
156
+ const param_node = node.params[i];
157
+ const param = param_node.type === 'AssignmentPattern' ? param_node.left : param_node;
158
+
159
+ if ((param.type === 'ObjectPattern' || param.type === 'ArrayPattern') && param.lazy) {
160
+ const param_id = b.id(context.state.scope.generate('param'));
161
+ setup_lazy_transforms(param, param_id, context.state, true);
162
+ // Store the generated identifier name on the pattern for the transform phase
163
+ param.metadata = { ...param.metadata, lazy_id: param_id.name };
164
+ }
165
+ }
166
+
81
167
  context.next({
82
168
  ...context.state,
83
169
  function_depth: (context.state.function_depth ?? 0) + 1,
@@ -239,7 +325,7 @@ const visitors = {
239
325
  if (context.path.at(-1)?.type !== 'Program') {
240
326
  // fatal since we don't have a transformation defined for this case
241
327
  error(
242
- '`#ripple.server` block can only be declared at the module level.',
328
+ '`#server` block can only be declared at the module level.',
243
329
  context.state.analysis.module.filename,
244
330
  node,
245
331
  );
@@ -291,6 +377,8 @@ const visitors = {
291
377
  if (
292
378
  binding.kind === 'prop' ||
293
379
  binding.kind === 'prop_fallback' ||
380
+ binding.kind === 'lazy' ||
381
+ binding.kind === 'lazy_fallback' ||
294
382
  binding.kind === 'for_pattern' ||
295
383
  (is_reference(node, /** @type {AST.Node} */ (parent)) &&
296
384
  node.tracked &&
@@ -303,45 +391,6 @@ const visitors = {
303
391
  }
304
392
  }
305
393
 
306
- // Validate #ripple namespace usage
307
- const source_name = node.metadata?.source_name;
308
- if (typeof source_name === 'string' && source_name.startsWith('#ripple.')) {
309
- // Cannot assign to a #ripple namespace identifier (left side)
310
- if (
311
- (parent?.type === 'AssignmentExpression' && parent.left === node) ||
312
- parent?.type === 'UpdateExpression'
313
- ) {
314
- error(
315
- `Cannot assign to \`${source_name}\`. The \`#ripple\` namespace is read-only.`,
316
- context.state.analysis.module.filename,
317
- node,
318
- context.state.loose ? context.state.analysis.errors : undefined,
319
- context.state.analysis.comments,
320
- );
321
- return context.next();
322
- }
323
-
324
- // Valid: callee of a CallExpression
325
- if (parent?.type === 'CallExpression' && parent.callee === node) {
326
- return context.next();
327
- }
328
-
329
- // Valid: object of a MemberExpression (further validated in MemberExpression visitor)
330
- if (parent?.type === 'MemberExpression' && parent.object === node) {
331
- return context.next();
332
- }
333
-
334
- // Everything else is an invalid bare reference
335
- error(
336
- `\`${source_name}\` must be called as a function, e.g., \`${source_name}(...)\`.`,
337
- context.state.analysis.module.filename,
338
- node,
339
- context.state.loose ? context.state.analysis.errors : undefined,
340
- context.state.analysis.comments,
341
- );
342
- return context.next();
343
- }
344
-
345
394
  context.next();
346
395
  },
347
396
 
@@ -358,13 +407,13 @@ const visitors = {
358
407
  context.state.metadata.tracking = true;
359
408
  }
360
409
 
361
- // Track #ripple.style.className or #ripple.style['className'] references
410
+ // Track #style.className or #style['className'] references
362
411
  if (node.object.type === 'StyleIdentifier') {
363
412
  const component = is_inside_component(context, true);
364
413
 
365
414
  if (!component) {
366
415
  error(
367
- '`#ripple.style` can only be used within a component',
416
+ '`#style` can only be used within a component',
368
417
  context.state.analysis.module.filename,
369
418
  node,
370
419
  context.state.loose ? context.state.analysis.errors : undefined,
@@ -378,19 +427,19 @@ const visitors = {
378
427
  let className = null;
379
428
 
380
429
  if (!node.computed && node.property.type === 'Identifier') {
381
- // #ripple.style.test
430
+ // #style.test
382
431
  className = node.property.name;
383
432
  } else if (
384
433
  node.computed &&
385
434
  node.property.type === 'Literal' &&
386
435
  typeof node.property.value === 'string'
387
436
  ) {
388
- // #ripple.style['test']
437
+ // #style['test']
389
438
  className = node.property.value;
390
439
  } else {
391
- // #ripple.style[expression] - dynamic, not allowed
440
+ // #style[expression] - dynamic, not allowed
392
441
  error(
393
- '`#ripple.style` property access must use a dot property or static string for css class name, not a dynamic expression',
442
+ '`#style` property access must use a dot property or static string for css class name, not a dynamic expression',
394
443
  context.state.analysis.module.filename,
395
444
  node.property,
396
445
  context.state.loose ? context.state.analysis.errors : undefined,
@@ -407,71 +456,6 @@ const visitors = {
407
456
  context.state.analysis.metadata.serverIdentifierPresent = true;
408
457
  }
409
458
 
410
- // Validate #ripple namespace member access
411
- if (
412
- node.object.type === 'Identifier' &&
413
- typeof node.object.metadata?.source_name === 'string' &&
414
- node.object.metadata.source_name.startsWith('#ripple.')
415
- ) {
416
- const ripple_source = node.object.metadata.source_name;
417
- const member_parent = context.path.at(-1);
418
-
419
- // No computed property access on #ripple namespace
420
- if (node.computed) {
421
- error(
422
- `Computed property access is not allowed on \`${ripple_source}\`. Use dot notation instead.`,
423
- context.state.analysis.module.filename,
424
- node,
425
- context.state.loose ? context.state.analysis.errors : undefined,
426
- context.state.analysis.comments,
427
- );
428
- return context.next();
429
- }
430
-
431
- if (ripple_source === '#ripple.array') {
432
- // Only .from, .of, and .fromAsync are allowed on #ripple.array
433
- const allowed_methods = new Set(['from', 'of', 'fromAsync']);
434
- const prop_name = node.property.type === 'Identifier' ? node.property.name : null;
435
-
436
- if (prop_name === null || !allowed_methods.has(prop_name)) {
437
- error(
438
- `Only \`.from\`, \`.of\`, and \`.fromAsync\` are allowed on \`#ripple.array\`.${prop_name ? ` Got \`.${prop_name}\`.` : ''}`,
439
- context.state.analysis.module.filename,
440
- node.property,
441
- context.state.loose ? context.state.analysis.errors : undefined,
442
- context.state.analysis.comments,
443
- );
444
- return context.next();
445
- }
446
- } else {
447
- // No member access allowed for other #ripple namespaces
448
- error(
449
- `Member access is not allowed on \`${ripple_source}\`. Use \`${ripple_source}(...)\` to call it directly.`,
450
- context.state.analysis.module.filename,
451
- node,
452
- context.state.loose ? context.state.analysis.errors : undefined,
453
- context.state.analysis.comments,
454
- );
455
- return context.next();
456
- }
457
-
458
- // All #ripple member expressions must be called as a function
459
- if (!(member_parent?.type === 'CallExpression' && member_parent.callee === node)) {
460
- const prop_name = node.property.type === 'Identifier' ? node.property.name : null;
461
- const full_name = prop_name ? `${ripple_source}.${prop_name}` : ripple_source;
462
- error(
463
- `\`${full_name}\` must be called as a function, e.g., \`${full_name}(...)\`.`,
464
- context.state.analysis.module.filename,
465
- node,
466
- context.state.loose ? context.state.analysis.errors : undefined,
467
- context.state.analysis.comments,
468
- );
469
- return context.next();
470
- }
471
-
472
- return context.next();
473
- }
474
-
475
459
  if (node.object.type === 'Identifier' && !node.object.tracked) {
476
460
  const binding = context.state.scope.get(node.object.name);
477
461
 
@@ -544,38 +528,6 @@ const visitors = {
544
528
  },
545
529
 
546
530
  NewExpression(node, context) {
547
- const callee = node.callee;
548
-
549
- // Cannot use `new` with #ripple namespace
550
- if (
551
- callee.type === 'Identifier' &&
552
- typeof callee.metadata?.source_name === 'string' &&
553
- callee.metadata.source_name.startsWith('#ripple.')
554
- ) {
555
- error(
556
- `Cannot use \`new\` with \`${callee.metadata.source_name}\`. Use \`${callee.metadata.source_name}(...)\` instead.`,
557
- context.state.analysis.module.filename,
558
- node,
559
- context.state.loose ? context.state.analysis.errors : undefined,
560
- context.state.analysis.comments,
561
- );
562
- }
563
-
564
- if (
565
- callee.type === 'MemberExpression' &&
566
- callee.object.type === 'Identifier' &&
567
- typeof callee.object.metadata?.source_name === 'string' &&
568
- callee.object.metadata.source_name.startsWith('#ripple.')
569
- ) {
570
- error(
571
- `Cannot use \`new\` with the \`#ripple\` namespace.`,
572
- context.state.analysis.module.filename,
573
- node,
574
- context.state.loose ? context.state.analysis.errors : undefined,
575
- context.state.analysis.comments,
576
- );
577
- }
578
-
579
531
  context.next();
580
532
  },
581
533
 
@@ -611,6 +563,18 @@ const visitors = {
611
563
  }
612
564
  visit(declarator, state);
613
565
  } else {
566
+ // Handle lazy destructuring patterns
567
+ if (
568
+ (declarator.id.type === 'ObjectPattern' || declarator.id.type === 'ArrayPattern') &&
569
+ declarator.id.lazy
570
+ ) {
571
+ const lazy_id = b.id(state.scope.generate('lazy'));
572
+ const writable = node.kind !== 'const';
573
+ setup_lazy_transforms(declarator.id, lazy_id, state, writable);
574
+ // Store the generated identifier name on the pattern for the transform phase
575
+ declarator.id.metadata = { ...declarator.id.metadata, lazy_id: lazy_id.name };
576
+ }
577
+
614
578
  const paths = extract_paths(declarator.id);
615
579
 
616
580
  for (const path of paths) {
@@ -640,10 +604,10 @@ const visitors = {
640
604
  component.metadata.styleIdentifierPresent = true;
641
605
  }
642
606
 
643
- // #ripple.style must only be used for property access (e.g., #ripple.style.className)
607
+ // #style must only be used for property access (e.g., #style.className)
644
608
  if (!parent || parent.type !== 'MemberExpression' || parent.object !== node) {
645
609
  error(
646
- '`#ripple.style` can only be used for property access, e.g., `#ripple.style.className`.',
610
+ '`#style` can only be used for property access, e.g., `#style.className`.',
647
611
  context.state.analysis.module.filename,
648
612
  node,
649
613
  context.state.loose ? context.state.analysis.errors : undefined,
@@ -656,10 +620,10 @@ const visitors = {
656
620
  ServerIdentifier(node, context) {
657
621
  const parent = context.path.at(-1);
658
622
 
659
- // #ripple.server must only be used for member access (e.g., #ripple.server.functionName(...))
623
+ // #server must only be used for member access (e.g., #server.functionName(...))
660
624
  if (!parent || parent.type !== 'MemberExpression' || parent.object !== node) {
661
625
  error(
662
- '`#ripple.server` can only be used for member access, e.g., `#ripple.server.functionName(...)`.',
626
+ '`#server` can only be used for member access, e.g., `#server.functionName(...)`.',
663
627
  context.state.analysis.module.filename,
664
628
  node,
665
629
  context.state.loose ? context.state.analysis.errors : undefined,
@@ -685,32 +649,9 @@ const visitors = {
685
649
  if (node.params.length > 0) {
686
650
  const props = node.params[0];
687
651
 
688
- if (props.type === 'ObjectPattern') {
689
- const paths = extract_paths(props);
690
-
691
- for (const path of paths) {
692
- const name = /** @type {AST.Identifier} */ (path.node).name;
693
- const binding = context.state.scope.get(name);
694
-
695
- if (binding !== null) {
696
- binding.kind = path.has_default_value ? 'prop_fallback' : 'prop';
697
-
698
- binding.transform = {
699
- read: (_) => {
700
- return path.expression(b.id('__props'));
701
- },
702
- assign: (node, value) => {
703
- return b.assignment(
704
- '=',
705
- /** @type {AST.MemberExpression} */ (path.expression(b.id('__props'))),
706
- value,
707
- );
708
- },
709
- update: (node) =>
710
- b.update(node.operator, path.expression(b.id('__props')), node.prefix),
711
- };
712
- }
713
- }
652
+ if ((props.type === 'ObjectPattern' || props.type === 'ArrayPattern') && props.lazy) {
653
+ // Lazy destructuring: &{...} or &[...] — set up lazy transforms
654
+ setup_lazy_transforms(props, b.id('__props'), context.state, true);
714
655
  } else if (props.type === 'AssignmentPattern') {
715
656
  error(
716
657
  'Props are always an object, use destructured props with default values instead',
@@ -1408,7 +1349,7 @@ const visitors = {
1408
1349
  attr.value.object.type === 'StyleIdentifier'
1409
1350
  ) {
1410
1351
  error(
1411
- '`#ripple.style` cannot be used directly on DOM elements. Pass the class to a child component instead.',
1352
+ '`#style` cannot be used directly on DOM elements. Pass the class to a child component instead.',
1412
1353
  state.analysis.module.filename,
1413
1354
  attr.value.object,
1414
1355
  context.state.loose ? context.state.analysis.errors : undefined,
@@ -1078,11 +1078,11 @@ export function prune_css(css, element, styleClasses, topScopedClasses) {
1078
1078
  node.metadata.used = true;
1079
1079
  }
1080
1080
 
1081
- // Populate top_scoped_classes for truly standalone class selectors (for #ripple.style support).
1081
+ // Populate top_scoped_classes for truly standalone class selectors (for #style support).
1082
1082
  // A class is standalone only when the entire effective selector chain (after resolving
1083
1083
  // nesting and stripping :global) is a single RelativeSelector with a single ClassSelector.
1084
1084
  // This prevents classes from compound selectors like `.wrapper .nested` or selectors
1085
- // inside :global() from being treated as valid #ripple.style targets.
1085
+ // inside :global() from being treated as valid #style targets.
1086
1086
  if (selectors.length === 1) {
1087
1087
  const sole_selector = selectors[0];
1088
1088
  if (