ripple 0.3.2 → 0.3.4

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 +85 -0
  2. package/package.json +2 -2
  3. package/src/compiler/identifier-utils.js +0 -2
  4. package/src/compiler/phases/1-parse/index.js +101 -195
  5. package/src/compiler/phases/2-analyze/index.js +82 -174
  6. package/src/compiler/phases/2-analyze/prune.js +2 -2
  7. package/src/compiler/phases/3-transform/client/index.js +174 -264
  8. package/src/compiler/phases/3-transform/segments.js +0 -22
  9. package/src/compiler/phases/3-transform/server/index.js +185 -42
  10. package/src/compiler/types/index.d.ts +14 -33
  11. package/src/compiler/utils.js +32 -20
  12. package/src/runtime/index-client.js +0 -17
  13. package/src/runtime/internal/client/bindings.js +118 -7
  14. package/src/runtime/internal/client/render.js +5 -1
  15. package/src/runtime/internal/client/runtime.js +1 -1
  16. package/src/runtime/internal/client/types.d.ts +4 -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 +58 -60
  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 +185 -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/style-identifier.test.ripple +95 -16
  128. package/types/index.d.ts +4 -1
@@ -68,6 +68,46 @@ 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
+ binding.kind = path.has_default_value ? 'lazy_fallback' : 'lazy';
89
+
90
+ binding.transform = {
91
+ read: (_) => {
92
+ return path.expression(source_id);
93
+ },
94
+ };
95
+
96
+ if (writable) {
97
+ binding.transform.assign = (node, value) => {
98
+ return b.assignment(
99
+ '=',
100
+ /** @type {AST.MemberExpression} */ (path.update_expression(source_id)),
101
+ value,
102
+ );
103
+ };
104
+ binding.transform.update = (node) =>
105
+ b.update(node.operator, path.update_expression(source_id), node.prefix);
106
+ }
107
+ }
108
+ }
109
+ }
110
+
71
111
  /**
72
112
  * @param {AST.Function} node
73
113
  * @param {AnalysisContext} context
@@ -78,6 +118,19 @@ function visit_function(node, context) {
78
118
  path: [...context.path],
79
119
  };
80
120
 
121
+ // Set up lazy transforms for any lazy destructured parameters
122
+ for (let i = 0; i < node.params.length; i++) {
123
+ const param_node = node.params[i];
124
+ const param = param_node.type === 'AssignmentPattern' ? param_node.left : param_node;
125
+
126
+ if ((param.type === 'ObjectPattern' || param.type === 'ArrayPattern') && param.lazy) {
127
+ const param_id = b.id(context.state.scope.generate('param'));
128
+ setup_lazy_transforms(param, param_id, context.state, true);
129
+ // Store the generated identifier name on the pattern for the transform phase
130
+ param.metadata = { ...param.metadata, lazy_id: param_id.name };
131
+ }
132
+ }
133
+
81
134
  context.next({
82
135
  ...context.state,
83
136
  function_depth: (context.state.function_depth ?? 0) + 1,
@@ -239,7 +292,7 @@ const visitors = {
239
292
  if (context.path.at(-1)?.type !== 'Program') {
240
293
  // fatal since we don't have a transformation defined for this case
241
294
  error(
242
- '`#ripple.server` block can only be declared at the module level.',
295
+ '`#server` block can only be declared at the module level.',
243
296
  context.state.analysis.module.filename,
244
297
  node,
245
298
  );
@@ -291,6 +344,8 @@ const visitors = {
291
344
  if (
292
345
  binding.kind === 'prop' ||
293
346
  binding.kind === 'prop_fallback' ||
347
+ binding.kind === 'lazy' ||
348
+ binding.kind === 'lazy_fallback' ||
294
349
  binding.kind === 'for_pattern' ||
295
350
  (is_reference(node, /** @type {AST.Node} */ (parent)) &&
296
351
  node.tracked &&
@@ -303,45 +358,6 @@ const visitors = {
303
358
  }
304
359
  }
305
360
 
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
361
  context.next();
346
362
  },
347
363
 
@@ -358,13 +374,13 @@ const visitors = {
358
374
  context.state.metadata.tracking = true;
359
375
  }
360
376
 
361
- // Track #ripple.style.className or #ripple.style['className'] references
377
+ // Track #style.className or #style['className'] references
362
378
  if (node.object.type === 'StyleIdentifier') {
363
379
  const component = is_inside_component(context, true);
364
380
 
365
381
  if (!component) {
366
382
  error(
367
- '`#ripple.style` can only be used within a component',
383
+ '`#style` can only be used within a component',
368
384
  context.state.analysis.module.filename,
369
385
  node,
370
386
  context.state.loose ? context.state.analysis.errors : undefined,
@@ -378,19 +394,19 @@ const visitors = {
378
394
  let className = null;
379
395
 
380
396
  if (!node.computed && node.property.type === 'Identifier') {
381
- // #ripple.style.test
397
+ // #style.test
382
398
  className = node.property.name;
383
399
  } else if (
384
400
  node.computed &&
385
401
  node.property.type === 'Literal' &&
386
402
  typeof node.property.value === 'string'
387
403
  ) {
388
- // #ripple.style['test']
404
+ // #style['test']
389
405
  className = node.property.value;
390
406
  } else {
391
- // #ripple.style[expression] - dynamic, not allowed
407
+ // #style[expression] - dynamic, not allowed
392
408
  error(
393
- '`#ripple.style` property access must use a dot property or static string for css class name, not a dynamic expression',
409
+ '`#style` property access must use a dot property or static string for css class name, not a dynamic expression',
394
410
  context.state.analysis.module.filename,
395
411
  node.property,
396
412
  context.state.loose ? context.state.analysis.errors : undefined,
@@ -407,71 +423,6 @@ const visitors = {
407
423
  context.state.analysis.metadata.serverIdentifierPresent = true;
408
424
  }
409
425
 
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
426
  if (node.object.type === 'Identifier' && !node.object.tracked) {
476
427
  const binding = context.state.scope.get(node.object.name);
477
428
 
@@ -544,38 +495,6 @@ const visitors = {
544
495
  },
545
496
 
546
497
  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
498
  context.next();
580
499
  },
581
500
 
@@ -611,6 +530,18 @@ const visitors = {
611
530
  }
612
531
  visit(declarator, state);
613
532
  } else {
533
+ // Handle lazy destructuring patterns
534
+ if (
535
+ (declarator.id.type === 'ObjectPattern' || declarator.id.type === 'ArrayPattern') &&
536
+ declarator.id.lazy
537
+ ) {
538
+ const lazy_id = b.id(state.scope.generate('lazy'));
539
+ const writable = node.kind !== 'const';
540
+ setup_lazy_transforms(declarator.id, lazy_id, state, writable);
541
+ // Store the generated identifier name on the pattern for the transform phase
542
+ declarator.id.metadata = { ...declarator.id.metadata, lazy_id: lazy_id.name };
543
+ }
544
+
614
545
  const paths = extract_paths(declarator.id);
615
546
 
616
547
  for (const path of paths) {
@@ -640,10 +571,10 @@ const visitors = {
640
571
  component.metadata.styleIdentifierPresent = true;
641
572
  }
642
573
 
643
- // #ripple.style must only be used for property access (e.g., #ripple.style.className)
574
+ // #style must only be used for property access (e.g., #style.className)
644
575
  if (!parent || parent.type !== 'MemberExpression' || parent.object !== node) {
645
576
  error(
646
- '`#ripple.style` can only be used for property access, e.g., `#ripple.style.className`.',
577
+ '`#style` can only be used for property access, e.g., `#style.className`.',
647
578
  context.state.analysis.module.filename,
648
579
  node,
649
580
  context.state.loose ? context.state.analysis.errors : undefined,
@@ -656,10 +587,10 @@ const visitors = {
656
587
  ServerIdentifier(node, context) {
657
588
  const parent = context.path.at(-1);
658
589
 
659
- // #ripple.server must only be used for member access (e.g., #ripple.server.functionName(...))
590
+ // #server must only be used for member access (e.g., #server.functionName(...))
660
591
  if (!parent || parent.type !== 'MemberExpression' || parent.object !== node) {
661
592
  error(
662
- '`#ripple.server` can only be used for member access, e.g., `#ripple.server.functionName(...)`.',
593
+ '`#server` can only be used for member access, e.g., `#server.functionName(...)`.',
663
594
  context.state.analysis.module.filename,
664
595
  node,
665
596
  context.state.loose ? context.state.analysis.errors : undefined,
@@ -685,32 +616,9 @@ const visitors = {
685
616
  if (node.params.length > 0) {
686
617
  const props = node.params[0];
687
618
 
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
- }
619
+ if ((props.type === 'ObjectPattern' || props.type === 'ArrayPattern') && props.lazy) {
620
+ // Lazy destructuring: &{...} or &[...] — set up lazy transforms
621
+ setup_lazy_transforms(props, b.id('__props'), context.state, true);
714
622
  } else if (props.type === 'AssignmentPattern') {
715
623
  error(
716
624
  'Props are always an object, use destructured props with default values instead',
@@ -1408,7 +1316,7 @@ const visitors = {
1408
1316
  attr.value.object.type === 'StyleIdentifier'
1409
1317
  ) {
1410
1318
  error(
1411
- '`#ripple.style` cannot be used directly on DOM elements. Pass the class to a child component instead.',
1319
+ '`#style` cannot be used directly on DOM elements. Pass the class to a child component instead.',
1412
1320
  state.analysis.module.filename,
1413
1321
  attr.value.object,
1414
1322
  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 (