ripple 0.2.214 → 0.2.215

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 (83) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/package.json +2 -2
  3. package/src/compiler/errors.js +33 -1
  4. package/src/compiler/index.d.ts +2 -2
  5. package/src/compiler/index.js +8 -1
  6. package/src/compiler/phases/2-analyze/index.js +51 -8
  7. package/src/compiler/phases/2-analyze/prune.js +25 -12
  8. package/src/compiler/phases/2-analyze/validation.js +1 -0
  9. package/src/compiler/phases/3-transform/client/index.js +284 -51
  10. package/src/compiler/phases/3-transform/segments.js +5 -3
  11. package/src/compiler/phases/3-transform/server/index.js +81 -18
  12. package/src/compiler/types/index.d.ts +125 -90
  13. package/src/compiler/utils.js +20 -0
  14. package/src/runtime/internal/client/blocks.js +13 -2
  15. package/src/runtime/internal/client/constants.js +2 -0
  16. package/src/runtime/internal/client/hmr.js +112 -1
  17. package/src/runtime/internal/client/hydration.js +29 -2
  18. package/src/runtime/internal/client/index.js +3 -1
  19. package/src/runtime/internal/client/runtime.js +5 -1
  20. package/src/runtime/internal/client/template.js +29 -67
  21. package/src/runtime/internal/client/try.js +73 -2
  22. package/src/runtime/internal/server/index.js +1 -1
  23. package/tests/client/basic/basic.hmr.test.ripple +19 -0
  24. package/tests/client/compiler/compiler.basic.test.ripple +16 -0
  25. package/tests/client/css/style-identifier.test.ripple +396 -0
  26. package/tests/client/for.test.ripple +41 -0
  27. package/tests/client/switch.test.ripple +50 -0
  28. package/tests/client/try.test.ripple +75 -0
  29. package/tests/hydration/compiled/client/basic.js +10 -10
  30. package/tests/hydration/compiled/client/composite.js +8 -8
  31. package/tests/hydration/compiled/client/for.js +18 -18
  32. package/tests/hydration/compiled/client/head.js +1 -1
  33. package/tests/hydration/compiled/client/html-in-template.js +64 -0
  34. package/tests/hydration/compiled/client/html.js +1418 -13
  35. package/tests/hydration/compiled/client/if-children.js +7 -7
  36. package/tests/hydration/compiled/client/if.js +7 -7
  37. package/tests/hydration/compiled/client/mixed-control-flow.js +483 -0
  38. package/tests/hydration/compiled/client/nested-control-flow.js +1457 -0
  39. package/tests/hydration/compiled/client/portal.js +1 -1
  40. package/tests/hydration/compiled/client/reactivity.js +2 -2
  41. package/tests/hydration/compiled/client/return.js +103 -103
  42. package/tests/hydration/compiled/client/switch.js +205 -30
  43. package/tests/hydration/compiled/client/try.js +130 -0
  44. package/tests/hydration/compiled/server/composite.js +2 -0
  45. package/tests/hydration/compiled/server/html-in-template.js +96 -0
  46. package/tests/hydration/compiled/server/html.js +1704 -0
  47. package/tests/hydration/compiled/server/if-children.js +4 -0
  48. package/tests/hydration/compiled/server/mixed-control-flow.js +303 -0
  49. package/tests/hydration/compiled/server/nested-control-flow.js +733 -0
  50. package/tests/hydration/compiled/server/portal.js +9 -1
  51. package/tests/hydration/compiled/server/switch.js +153 -0
  52. package/tests/hydration/compiled/server/try.js +140 -0
  53. package/tests/hydration/components/html-in-template.ripple +24 -0
  54. package/tests/hydration/components/html.ripple +390 -1
  55. package/tests/hydration/components/mixed-control-flow.ripple +114 -0
  56. package/tests/hydration/components/nested-control-flow.ripple +269 -0
  57. package/tests/hydration/components/switch.ripple +78 -0
  58. package/tests/hydration/components/try.ripple +31 -0
  59. package/tests/hydration/html-in-template.test.js +45 -0
  60. package/tests/hydration/html.test.js +116 -20
  61. package/tests/hydration/mixed-control-flow.test.js +70 -0
  62. package/tests/hydration/nested-control-flow.test.js +203 -0
  63. package/tests/hydration/switch.test.js +67 -0
  64. package/tests/hydration/try.test.js +37 -0
  65. package/tests/server/__snapshots__/compiler.test.ripple.snap +3 -1
  66. package/tests/server/await.test.ripple +0 -2
  67. package/tests/server/basic.components.test.ripple +1 -1
  68. package/tests/server/basic.test.ripple +0 -2
  69. package/tests/server/compiler.test.ripple +0 -2
  70. package/tests/server/composite.test.ripple +0 -2
  71. package/tests/server/context.test.ripple +0 -2
  72. package/tests/server/dynamic-elements.test.ripple +2 -2
  73. package/tests/server/for.test.ripple +0 -3
  74. package/tests/server/html-nesting-validation.test.ripple +2 -4
  75. package/tests/server/if.test.ripple +0 -3
  76. package/tests/server/return.test.ripple +0 -3
  77. package/tests/server/streaming-ssr.test.ripple +1 -3
  78. package/tests/server/style-identifier.test.ripple +236 -0
  79. package/tests/server/switch.test.ripple +0 -3
  80. package/tests/server/try.test.ripple +82 -0
  81. package/tests/server/tsconfig.json +1 -0
  82. package/tests/setup-server.js +2 -0
  83. package/tsconfig.json +2 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,43 @@
1
1
  # ripple
2
2
 
3
+ ## 0.2.215
4
+
5
+ ### Patch Changes
6
+
7
+ - [#742](https://github.com/Ripple-TS/ripple/pull/742)
8
+ [`a9ecda4`](https://github.com/Ripple-TS/ripple/commit/a9ecda4e3f29e3b934d9f5ee80d55c059ba36ebe)
9
+ Thanks [@copilot-swe-agent](https://github.com/apps/copilot-swe-agent)! - Fix
10
+ catch block not executing when used with pending block in try statements.
11
+ Previously, errors thrown inside async components within
12
+ `try { ... } pending { ... } catch { ... }` blocks were lost as unhandled
13
+ promise rejections. Now errors are properly caught and the catch block is
14
+ rendered. Also fixes the server-side rendering to not include pending content in
15
+ the final output when the async operation resolves or errors.
16
+
17
+ - [#744](https://github.com/Ripple-TS/ripple/pull/744)
18
+ [`6653c5c`](https://github.com/Ripple-TS/ripple/commit/6653c5cebfbd4dce129906a25686ef9c63dc592a)
19
+ Thanks [@leonidaz](https://github.com/leonidaz)! - Fix compiler analysis
20
+ incorrectly marking untrackable nodes as tracked. `MemberExpression` now only
21
+ enables tracking when the member or its property is actually marked as
22
+ `tracked`, and unconditional tracking side-effects were removed from
23
+ `CallExpression` and `NewExpression` visitors.
24
+
25
+ Also fixes the client transform for `TrackedExpression` in TypeScript mode to
26
+ emit a `['#v']` member access (marked as `tracked`) instead of the runtime
27
+ `_$_.get(...)` call, aligning TSX output with tracked-access semantics.
28
+
29
+ - [#733](https://github.com/Ripple-TS/ripple/pull/733)
30
+ [`307dcf3`](https://github.com/Ripple-TS/ripple/commit/307dcf30f27dae987a19a59508cc2593c839eda3)
31
+ Thanks [@trueadm](https://github.com/trueadm)! - Fix client HMR updates when a
32
+ wrapped component has not mounted yet. The runtime now avoids calling `set()` on
33
+ an undefined tracked source and keeps wrapper HMR state synchronized across
34
+ update chains.
35
+ - Updated dependencies
36
+ [[`a9ecda4`](https://github.com/Ripple-TS/ripple/commit/a9ecda4e3f29e3b934d9f5ee80d55c059ba36ebe),
37
+ [`6653c5c`](https://github.com/Ripple-TS/ripple/commit/6653c5cebfbd4dce129906a25686ef9c63dc592a),
38
+ [`307dcf3`](https://github.com/Ripple-TS/ripple/commit/307dcf30f27dae987a19a59508cc2593c839eda3)]:
39
+ - ripple@0.2.215
40
+
3
41
  ## 0.2.214
4
42
 
5
43
  ### Patch Changes
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.214",
6
+ "version": "0.2.215",
7
7
  "type": "module",
8
8
  "module": "src/runtime/index-client.js",
9
9
  "main": "src/runtime/index-client.js",
@@ -96,6 +96,6 @@
96
96
  "vscode-languageserver-types": "^3.17.5"
97
97
  },
98
98
  "peerDependencies": {
99
- "ripple": "0.2.214"
99
+ "ripple": "0.2.215"
100
100
  }
101
101
  }
@@ -9,9 +9,14 @@
9
9
  * @param {string | null} filename
10
10
  * @param {AST.Node} node
11
11
  * @param {RippleCompileError[]} [errors]
12
+ * @param {AST.CommentWithLocation[]} [comments]
12
13
  * @returns {void}
13
14
  */
14
- export function error(message, filename, node, errors) {
15
+ export function error(message, filename, node, errors, comments) {
16
+ if (errors && comments && is_ripple_error_suppressed(node, comments)) {
17
+ return;
18
+ }
19
+
15
20
  const error = /** @type {RippleCompileError} */ (new Error(message));
16
21
 
17
22
  // same as the acorn compiler error
@@ -43,3 +48,30 @@ export function error(message, filename, node, errors) {
43
48
  error.type = 'fatal';
44
49
  throw error;
45
50
  }
51
+
52
+ /**
53
+ * @param {AST.CommentWithLocation} comment
54
+ * @return {boolean}
55
+ */
56
+ function is_ripple_error_suppress_comment(comment) {
57
+ const text = comment.value.trim();
58
+ return text.startsWith('@ripple-ignore') || text.startsWith('@ripple-expect-error');
59
+ }
60
+
61
+ /**
62
+ * @param {AST.Node} node
63
+ * @param {AST.CommentWithLocation[]} comments
64
+ */
65
+ function is_ripple_error_suppressed(node, comments) {
66
+ if (node.loc) {
67
+ const node_start_line = node.loc.start.line;
68
+ for (const comment of comments) {
69
+ if (comment.type === 'Line' && comment.loc.start.line === node_start_line - 1) {
70
+ if (is_ripple_error_suppress_comment(comment)) {
71
+ return true;
72
+ }
73
+ }
74
+ }
75
+ }
76
+ return false;
77
+ }
@@ -101,6 +101,7 @@ interface SharedCompileOptions {
101
101
  }
102
102
  export interface CompileOptions extends SharedCompileOptions {
103
103
  mode?: 'client' | 'server';
104
+ hmr?: boolean;
104
105
  }
105
106
 
106
107
  export interface ParseOptions {
@@ -115,8 +116,7 @@ export interface AnalyzeOptions extends ParseOptions, Pick<CompileOptions, 'mode
115
116
  }
116
117
 
117
118
  export interface VolarCompileOptions
118
- extends Omit<ParseOptions, 'errors' | 'comments'>,
119
- SharedCompileOptions {}
119
+ extends Omit<ParseOptions, 'errors' | 'comments'>, SharedCompileOptions {}
120
120
 
121
121
  export function parse(source: string, options?: ParseOptions): AST.Program;
122
122
 
@@ -34,7 +34,14 @@ export function compile(source, filename, options = {}) {
34
34
  options?.minify_css ?? false,
35
35
  options?.dev ?? false,
36
36
  )
37
- : transform_client(filename, source, analysis, false, options?.minify_css ?? false);
37
+ : transform_client(
38
+ filename,
39
+ source,
40
+ analysis,
41
+ false,
42
+ options?.minify_css ?? false,
43
+ options?.hmr ?? false,
44
+ );
38
45
 
39
46
  return result;
40
47
  }
@@ -141,6 +141,7 @@ function error_return_keyword(node, context, message) {
141
141
  context.state.analysis.module.filename,
142
142
  return_keyword_node,
143
143
  context.state.loose ? context.state.analysis.errors : undefined,
144
+ context.state.analysis.comments,
144
145
  );
145
146
  }
146
147
 
@@ -281,6 +282,7 @@ const visitors = {
281
282
  context.state.analysis.module.filename,
282
283
  node,
283
284
  context.state.loose ? context.state.analysis.errors : undefined,
285
+ context.state.analysis.comments,
284
286
  );
285
287
  }
286
288
  }
@@ -307,7 +309,13 @@ const visitors = {
307
309
  MemberExpression(node, context) {
308
310
  const parent = context.path.at(-1);
309
311
 
310
- if (context.state.metadata?.tracking === false && parent?.type !== 'AssignmentExpression') {
312
+ if (
313
+ context.state.metadata?.tracking === false &&
314
+ parent?.type !== 'AssignmentExpression' &&
315
+ (node.tracked ||
316
+ ((node.property.type === 'Identifier' || node.property.type === 'Literal') &&
317
+ /** @type {AST.TrackedNode} */ (node.property).tracked))
318
+ ) {
311
319
  context.state.metadata.tracking = true;
312
320
  }
313
321
 
@@ -321,6 +329,7 @@ const visitors = {
321
329
  context.state.analysis.module.filename,
322
330
  node,
323
331
  context.state.loose ? context.state.analysis.errors : undefined,
332
+ context.state.analysis.comments,
324
333
  );
325
334
  } else {
326
335
  component.metadata.styleIdentifierPresent = true;
@@ -346,6 +355,7 @@ const visitors = {
346
355
  context.state.analysis.module.filename,
347
356
  node.property,
348
357
  context.state.loose ? context.state.analysis.errors : undefined,
358
+ context.state.analysis.comments,
349
359
  );
350
360
  }
351
361
 
@@ -377,6 +387,7 @@ const visitors = {
377
387
  context.state.analysis.module.filename,
378
388
  node.property,
379
389
  context.state.loose ? context.state.analysis.errors : undefined,
390
+ context.state.analysis.comments,
380
391
  );
381
392
  }
382
393
  }
@@ -391,6 +402,7 @@ const visitors = {
391
402
  context.state.analysis.module.filename,
392
403
  node.object,
393
404
  context.state.loose ? context.state.analysis.errors : undefined,
405
+ context.state.analysis.comments,
394
406
  );
395
407
  }
396
408
  }
@@ -416,13 +428,10 @@ const visitors = {
416
428
  context.state.analysis.module.filename,
417
429
  node.callee,
418
430
  context.state.loose ? context.state.analysis.errors : undefined,
431
+ context.state.analysis.comments,
419
432
  );
420
433
  }
421
434
 
422
- if (context.state.metadata?.tracking === false) {
423
- context.state.metadata.tracking = true;
424
- }
425
-
426
435
  if (!is_inside_component(context, true)) {
427
436
  mark_as_tracked(context.path);
428
437
  }
@@ -431,9 +440,6 @@ const visitors = {
431
440
  },
432
441
 
433
442
  NewExpression(node, context) {
434
- if (context.state.metadata?.tracking === false) {
435
- context.state.metadata.tracking = true;
436
- }
437
443
  context.next();
438
444
  },
439
445
 
@@ -447,6 +453,7 @@ const visitors = {
447
453
  state.analysis.module.filename,
448
454
  declarator.id,
449
455
  context.state.loose ? context.state.analysis.errors : undefined,
456
+ context.state.analysis.comments,
450
457
  );
451
458
  }
452
459
  const metadata = { tracking: false, await: false };
@@ -477,6 +484,7 @@ const visitors = {
477
484
  state.analysis.module.filename,
478
485
  path.node,
479
486
  context.state.loose ? context.state.analysis.errors : undefined,
487
+ context.state.analysis.comments,
480
488
  );
481
489
  }
482
490
  }
@@ -536,6 +544,7 @@ const visitors = {
536
544
  context.state.analysis.module.filename,
537
545
  props,
538
546
  context.state.loose ? context.state.analysis.errors : undefined,
547
+ context.state.analysis.comments,
539
548
  );
540
549
  }
541
550
  }
@@ -582,6 +591,7 @@ const visitors = {
582
591
  context.state.analysis.module.filename,
583
592
  property,
584
593
  context.state.loose ? context.state.analysis.errors : undefined,
594
+ context.state.analysis.comments,
585
595
  );
586
596
  }
587
597
  }
@@ -639,6 +649,7 @@ const visitors = {
639
649
  context.state.analysis.module.filename,
640
650
  switch_case,
641
651
  context.state.loose ? context.state.analysis.errors : undefined,
652
+ context.state.analysis.comments,
642
653
  );
643
654
  }
644
655
  }
@@ -712,6 +723,7 @@ const visitors = {
712
723
  context.state.analysis.module.filename,
713
724
  node.body,
714
725
  context.state.loose ? context.state.analysis.errors : undefined,
726
+ context.state.analysis.comments,
715
727
  );
716
728
  }
717
729
  },
@@ -734,6 +746,7 @@ const visitors = {
734
746
  context.state.analysis.module.filename,
735
747
  /** @type {AST.Identifier} */ (declaration.id),
736
748
  context.state.loose ? context.state.analysis.errors : undefined,
749
+ context.state.analysis.comments,
737
750
  );
738
751
  // TODO: the client and server rendering doesn't currently support components
739
752
  // If we're going to support this, we need to account also for anonymous object declaration
@@ -762,6 +775,7 @@ const visitors = {
762
775
  context.state.analysis.module.filename,
763
776
  decl.init,
764
777
  context.state.loose ? context.state.analysis.errors : undefined,
778
+ context.state.analysis.comments,
765
779
  );
766
780
  continue;
767
781
  }
@@ -773,6 +787,7 @@ const visitors = {
773
787
  context.state.analysis.module.filename,
774
788
  path.node,
775
789
  context.state.loose ? context.state.analysis.errors : undefined,
790
+ context.state.analysis.comments,
776
791
  );
777
792
  }
778
793
  }
@@ -783,6 +798,7 @@ const visitors = {
783
798
  context.state.analysis.module.filename,
784
799
  decl,
785
800
  context.state.loose ? context.state.analysis.errors : undefined,
801
+ context.state.analysis.comments,
786
802
  );
787
803
  }
788
804
  } else if (node.specifiers) {
@@ -801,6 +817,7 @@ const visitors = {
801
817
  context.state.analysis.module.filename,
802
818
  specifier,
803
819
  context.state.loose ? context.state.analysis.errors : undefined,
820
+ context.state.analysis.comments,
804
821
  );
805
822
  }
806
823
  } else {
@@ -809,6 +826,7 @@ const visitors = {
809
826
  context.state.analysis.module.filename,
810
827
  node,
811
828
  context.state.loose ? context.state.analysis.errors : undefined,
829
+ context.state.analysis.comments,
812
830
  );
813
831
  }
814
832
 
@@ -863,6 +881,7 @@ const visitors = {
863
881
  context.state.analysis.module.filename,
864
882
  node.consequent,
865
883
  context.state.loose ? context.state.analysis.errors : undefined,
884
+ context.state.analysis.comments,
866
885
  );
867
886
  }
868
887
 
@@ -879,6 +898,7 @@ const visitors = {
879
898
  context.state.analysis.module.filename,
880
899
  node.alternate,
881
900
  context.state.loose ? context.state.analysis.errors : undefined,
901
+ context.state.analysis.comments,
882
902
  );
883
903
  }
884
904
 
@@ -966,6 +986,7 @@ const visitors = {
966
986
  state.analysis.module.filename,
967
987
  node.block,
968
988
  context.state.loose ? context.state.analysis.errors : undefined,
989
+ context.state.analysis.comments,
969
990
  );
970
991
  }
971
992
 
@@ -982,6 +1003,7 @@ const visitors = {
982
1003
  state.analysis.module.filename,
983
1004
  node.pending,
984
1005
  context.state.loose ? context.state.analysis.errors : undefined,
1006
+ context.state.analysis.comments,
985
1007
  );
986
1008
  }
987
1009
  }
@@ -1167,6 +1189,7 @@ const visitors = {
1167
1189
  },
1168
1190
  },
1169
1191
  context.state.loose ? context.state.analysis.errors : undefined,
1192
+ context.state.analysis.comments,
1170
1193
  );
1171
1194
  }
1172
1195
  if (attr.name.type === 'Identifier') {
@@ -1178,6 +1201,21 @@ const visitors = {
1178
1201
  state.analysis.module.filename,
1179
1202
  attr,
1180
1203
  context.state.loose ? context.state.analysis.errors : undefined,
1204
+ context.state.analysis.comments,
1205
+ );
1206
+ }
1207
+
1208
+ if (
1209
+ attr.value &&
1210
+ attr.value.type === 'MemberExpression' &&
1211
+ attr.value.object.type === 'StyleIdentifier'
1212
+ ) {
1213
+ error(
1214
+ '`#style` cannot be used directly on DOM elements. Pass the class to a child component instead.',
1215
+ state.analysis.module.filename,
1216
+ attr.value.object,
1217
+ context.state.loose ? context.state.analysis.errors : undefined,
1218
+ context.state.analysis.comments,
1181
1219
  );
1182
1220
  }
1183
1221
 
@@ -1205,6 +1243,7 @@ const visitors = {
1205
1243
  state.analysis.module.filename,
1206
1244
  node,
1207
1245
  context.state.loose ? context.state.analysis.errors : undefined,
1246
+ context.state.analysis.comments,
1208
1247
  );
1209
1248
  }
1210
1249
  } else {
@@ -1246,6 +1285,7 @@ const visitors = {
1246
1285
  state.analysis.module.filename,
1247
1286
  item,
1248
1287
  context.state.loose ? context.state.analysis.errors : undefined,
1288
+ context.state.analysis.comments,
1249
1289
  );
1250
1290
  }
1251
1291
  }
@@ -1261,6 +1301,7 @@ const visitors = {
1261
1301
  state.analysis.module.filename,
1262
1302
  attribute,
1263
1303
  context.state.loose ? context.state.analysis.errors : undefined,
1304
+ context.state.analysis.comments,
1264
1305
  );
1265
1306
  }
1266
1307
  }
@@ -1286,6 +1327,7 @@ const visitors = {
1286
1327
  context.state.analysis.module.filename,
1287
1328
  node.expression,
1288
1329
  context.state.loose ? context.state.analysis.errors : undefined,
1330
+ context.state.analysis.comments,
1289
1331
  );
1290
1332
  }
1291
1333
 
@@ -1320,6 +1362,7 @@ const visitors = {
1320
1362
  context.state.analysis.module.filename,
1321
1363
  adjusted_node,
1322
1364
  context.state.loose ? context.state.analysis.errors : undefined,
1365
+ context.state.analysis.comments,
1323
1366
  );
1324
1367
  }
1325
1368
  }
@@ -236,18 +236,6 @@ function apply_selector(relative_selectors, rule, element, direction) {
236
236
  selector: selector,
237
237
  });
238
238
  }
239
-
240
- // Also store in top_scoped_classes if standalone selector
241
- if (
242
- is_standalone_class_selector(relative_selector, selector) &&
243
- !top_scoped_classes.has(name)
244
- ) {
245
- top_scoped_classes.set(name, {
246
- start: selector.start,
247
- end: selector.end,
248
- selector: selector,
249
- });
250
- }
251
239
  }
252
240
  }
253
241
  }
@@ -1090,6 +1078,31 @@ export function prune_css(css, element, styleClasses, topScopedClasses) {
1090
1078
  node.metadata.used = true;
1091
1079
  }
1092
1080
 
1081
+ // Populate top_scoped_classes for truly standalone class selectors (for #style support).
1082
+ // A class is standalone only when the entire effective selector chain (after resolving
1083
+ // nesting and stripping :global) is a single RelativeSelector with a single ClassSelector.
1084
+ // This prevents classes from compound selectors like `.wrapper .nested` or selectors
1085
+ // inside :global() from being treated as valid #style targets.
1086
+ if (selectors.length === 1) {
1087
+ const sole_selector = selectors[0];
1088
+ if (
1089
+ !sole_selector.metadata.is_global &&
1090
+ !sole_selector.metadata.is_global_like &&
1091
+ sole_selector.selectors.length === 1 &&
1092
+ sole_selector.selectors[0].type === 'ClassSelector'
1093
+ ) {
1094
+ const class_selector = sole_selector.selectors[0];
1095
+ const name = class_selector.name.replace(regex_backslash_and_following_character, '$1');
1096
+ if (!top_scoped_classes.has(name)) {
1097
+ top_scoped_classes.set(name, {
1098
+ start: class_selector.start,
1099
+ end: class_selector.end,
1100
+ selector: class_selector,
1101
+ });
1102
+ }
1103
+ }
1104
+ }
1105
+
1093
1106
  context.next();
1094
1107
  },
1095
1108
  PseudoClassSelector(node, context) {
@@ -155,6 +155,7 @@ export function validate_nesting(element, context, errors) {
155
155
  context.state.analysis.module.filename,
156
156
  element,
157
157
  errors,
158
+ context.state.analysis.comments,
158
159
  );
159
160
  } else {
160
161
  // if my parent has a set of invalid children