ripple 0.2.182 → 0.2.184
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 +4 -2
- package/src/compiler/errors.js +3 -1
- package/src/compiler/index.d.ts +2 -1
- package/src/compiler/phases/1-parse/index.js +525 -311
- package/src/compiler/phases/1-parse/style.js +3 -1
- package/src/compiler/phases/2-analyze/css-analyze.js +116 -97
- package/src/compiler/phases/2-analyze/index.js +81 -51
- package/src/compiler/phases/2-analyze/prune.js +200 -58
- package/src/compiler/phases/2-analyze/validation.js +9 -7
- package/src/compiler/phases/3-transform/client/index.js +871 -394
- package/src/compiler/phases/3-transform/segments.js +99 -53
- package/src/compiler/phases/3-transform/server/index.js +278 -121
- package/src/compiler/scope.js +51 -104
- package/src/compiler/types/index.d.ts +834 -197
- package/src/compiler/types/parse.d.ts +1668 -0
- package/src/compiler/utils.js +62 -74
- package/src/utils/ast.js +247 -192
- package/src/utils/builders.js +309 -247
- package/src/utils/sanitize_template_string.js +2 -2
|
@@ -1,25 +1,58 @@
|
|
|
1
|
+
/** @import * as AST from 'estree' */
|
|
2
|
+
/** @import { Visitors } from '#compiler' */
|
|
3
|
+
/** @typedef {0 | 1} Direction */
|
|
4
|
+
|
|
1
5
|
import { walk } from 'zimmerframe';
|
|
2
6
|
import { is_element_dom_element } from '../../utils.js';
|
|
3
7
|
|
|
4
8
|
const seen = new Set();
|
|
5
9
|
const regex_backslash_and_following_character = /\\(.)/g;
|
|
10
|
+
/** @type {Direction} */
|
|
6
11
|
const FORWARD = 0;
|
|
12
|
+
/** @type {Direction} */
|
|
7
13
|
const BACKWARD = 1;
|
|
8
14
|
|
|
9
15
|
// CSS selector constants
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
16
|
+
/**
|
|
17
|
+
* @param {number} start
|
|
18
|
+
* @param {number} end
|
|
19
|
+
* @returns {AST.CSS.Combinator}
|
|
20
|
+
*/
|
|
21
|
+
function create_descendant_combinator(start, end) {
|
|
22
|
+
return { name: ' ', type: 'Combinator', start, end };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {number} start
|
|
27
|
+
* @param {number} end
|
|
28
|
+
* @returns {AST.CSS.RelativeSelector}
|
|
29
|
+
*/
|
|
30
|
+
function create_nesting_selector(start, end) {
|
|
31
|
+
return {
|
|
32
|
+
type: 'RelativeSelector',
|
|
33
|
+
selectors: [{ type: 'NestingSelector', name: '&', start, end }],
|
|
34
|
+
combinator: null,
|
|
35
|
+
metadata: { is_global: false, is_global_like: false, scoped: false },
|
|
36
|
+
start,
|
|
37
|
+
end,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @param {number} start
|
|
43
|
+
* @param {number} end
|
|
44
|
+
* @returns {AST.CSS.RelativeSelector}
|
|
45
|
+
*/
|
|
46
|
+
function create_any_selector(start, end) {
|
|
47
|
+
return {
|
|
48
|
+
type: 'RelativeSelector',
|
|
49
|
+
selectors: [{ type: 'TypeSelector', name: '*', start, end }],
|
|
50
|
+
combinator: null,
|
|
51
|
+
metadata: { is_global: false, is_global_like: false, scoped: false },
|
|
52
|
+
start,
|
|
53
|
+
end,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
23
56
|
|
|
24
57
|
// Whitelist for attribute selectors on specific elements
|
|
25
58
|
const whitelist_attribute_selector = new Map([
|
|
@@ -72,6 +105,9 @@ const whitelist_attribute_selector = new Map([
|
|
|
72
105
|
['video', ['autoplay', 'controls', 'loop', 'muted', 'playsinline']],
|
|
73
106
|
]);
|
|
74
107
|
|
|
108
|
+
/**
|
|
109
|
+
* @param {AST.CSS.ComplexSelector} node
|
|
110
|
+
*/
|
|
75
111
|
function get_relative_selectors(node) {
|
|
76
112
|
const selectors = truncate(node);
|
|
77
113
|
|
|
@@ -80,12 +116,15 @@ function get_relative_selectors(node) {
|
|
|
80
116
|
|
|
81
117
|
// nesting could be inside pseudo classes like :is, :has or :where
|
|
82
118
|
for (let selector of selectors) {
|
|
83
|
-
walk(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
119
|
+
walk(
|
|
120
|
+
selector,
|
|
121
|
+
null,
|
|
122
|
+
/** @type {Visitors<AST.CSS.Node, null>} */ ({
|
|
123
|
+
NestingSelector() {
|
|
124
|
+
has_explicit_nesting_selector = true;
|
|
125
|
+
},
|
|
126
|
+
}),
|
|
127
|
+
);
|
|
89
128
|
|
|
90
129
|
// if we found one we can break from the others
|
|
91
130
|
if (has_explicit_nesting_selector) break;
|
|
@@ -95,17 +134,22 @@ function get_relative_selectors(node) {
|
|
|
95
134
|
if (selectors[0].combinator === null) {
|
|
96
135
|
selectors[0] = {
|
|
97
136
|
...selectors[0],
|
|
98
|
-
combinator:
|
|
137
|
+
combinator: create_descendant_combinator(selectors[0].start, selectors[0].end),
|
|
99
138
|
};
|
|
100
139
|
}
|
|
101
140
|
|
|
102
|
-
selectors.unshift(
|
|
141
|
+
selectors.unshift(create_nesting_selector(selectors[0].start, selectors[0].end));
|
|
103
142
|
}
|
|
104
143
|
}
|
|
105
144
|
|
|
106
145
|
return selectors;
|
|
107
146
|
}
|
|
108
147
|
|
|
148
|
+
/**
|
|
149
|
+
*
|
|
150
|
+
* @param {AST.CSS.ComplexSelector} node
|
|
151
|
+
* @returns {AST.CSS.RelativeSelector[]}
|
|
152
|
+
*/
|
|
109
153
|
function truncate(node) {
|
|
110
154
|
const i = node.children.findLastIndex(({ metadata, selectors }) => {
|
|
111
155
|
const first = selectors[0];
|
|
@@ -133,6 +177,13 @@ function truncate(node) {
|
|
|
133
177
|
});
|
|
134
178
|
}
|
|
135
179
|
|
|
180
|
+
/**
|
|
181
|
+
* @param {AST.CSS.RelativeSelector[]} relative_selectors
|
|
182
|
+
* @param {AST.CSS.Rule} rule
|
|
183
|
+
* @param {AST.Element} element
|
|
184
|
+
* @param {Direction} direction
|
|
185
|
+
* @returns {boolean}
|
|
186
|
+
*/
|
|
136
187
|
function apply_selector(relative_selectors, rule, element, direction) {
|
|
137
188
|
const rest_selectors = relative_selectors.slice();
|
|
138
189
|
const relative_selector = direction === FORWARD ? rest_selectors.shift() : rest_selectors.pop();
|
|
@@ -153,7 +204,13 @@ function apply_selector(relative_selectors, rule, element, direction) {
|
|
|
153
204
|
return matched;
|
|
154
205
|
}
|
|
155
206
|
|
|
156
|
-
|
|
207
|
+
/**
|
|
208
|
+
* @param {AST.Element} node
|
|
209
|
+
* @param {boolean} adjacent_only
|
|
210
|
+
* @returns {AST.Element[]}
|
|
211
|
+
*/
|
|
212
|
+
function get_ancestor_elements(node, adjacent_only) {
|
|
213
|
+
/** @type {AST.Element[]} */
|
|
157
214
|
const ancestors = [];
|
|
158
215
|
|
|
159
216
|
const path = node.metadata.path;
|
|
@@ -173,9 +230,20 @@ function get_ancestor_elements(node, adjacent_only, seen = new Set()) {
|
|
|
173
230
|
return ancestors;
|
|
174
231
|
}
|
|
175
232
|
|
|
233
|
+
/**
|
|
234
|
+
* @param {AST.Element} node
|
|
235
|
+
* @param {boolean} adjacent_only
|
|
236
|
+
* @returns {AST.Element[]}
|
|
237
|
+
*/
|
|
176
238
|
function get_descendant_elements(node, adjacent_only) {
|
|
239
|
+
/** @type {AST.Element[]} */
|
|
177
240
|
const descendants = [];
|
|
178
241
|
|
|
242
|
+
/**
|
|
243
|
+
* @param {AST.Node} current_node
|
|
244
|
+
* @param {number} depth
|
|
245
|
+
* @returns {void}
|
|
246
|
+
*/
|
|
179
247
|
function visit(current_node, depth = 0) {
|
|
180
248
|
if (current_node.type === 'Element' && current_node !== node) {
|
|
181
249
|
descendants.push(current_node);
|
|
@@ -183,21 +251,24 @@ function get_descendant_elements(node, adjacent_only) {
|
|
|
183
251
|
}
|
|
184
252
|
|
|
185
253
|
// Visit children based on Ripple's AST structure
|
|
186
|
-
if (current_node.children) {
|
|
187
|
-
for (const child of current_node.children) {
|
|
254
|
+
if (/** @type {AST.Element} */ (current_node).children) {
|
|
255
|
+
for (const child of /** @type {AST.Element} */ (current_node).children) {
|
|
188
256
|
visit(child, depth + 1);
|
|
189
257
|
}
|
|
190
258
|
}
|
|
191
259
|
|
|
192
|
-
if (current_node.body) {
|
|
193
|
-
for (const child of current_node.body) {
|
|
260
|
+
if (/** @type {AST.Component} */ (current_node).body) {
|
|
261
|
+
for (const child of /** @type {AST.Component} */ (current_node).body) {
|
|
194
262
|
visit(child, depth + 1);
|
|
195
263
|
}
|
|
196
264
|
}
|
|
197
265
|
|
|
198
266
|
// For template nodes and text interpolations
|
|
199
|
-
if (
|
|
200
|
-
|
|
267
|
+
if (
|
|
268
|
+
/** @type {AST.TextNode} */ (current_node).expression &&
|
|
269
|
+
typeof (/** @type {AST.TextNode} */ (current_node).expression) === 'object'
|
|
270
|
+
) {
|
|
271
|
+
visit(/** @type {AST.TextNode} */ (current_node).expression, depth + 1);
|
|
201
272
|
}
|
|
202
273
|
}
|
|
203
274
|
|
|
@@ -208,18 +279,12 @@ function get_descendant_elements(node, adjacent_only) {
|
|
|
208
279
|
}
|
|
209
280
|
}
|
|
210
281
|
|
|
211
|
-
if (node.body) {
|
|
212
|
-
for (const child of node.body) {
|
|
213
|
-
visit(child);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
282
|
return descendants;
|
|
218
283
|
}
|
|
219
284
|
|
|
220
285
|
/**
|
|
221
286
|
* Check if an element can render dynamic content that might affect CSS matching
|
|
222
|
-
* @param {
|
|
287
|
+
* @param {AST.Node} element
|
|
223
288
|
* @param {boolean} check_classes - Whether to check for dynamic class attributes
|
|
224
289
|
* @returns {boolean}
|
|
225
290
|
*/
|
|
@@ -230,14 +295,14 @@ function can_render_dynamic_content(element, check_classes = false) {
|
|
|
230
295
|
|
|
231
296
|
// Either a dynamic element or component (only can tell at runtime)
|
|
232
297
|
// But dynamic elements should return false ideally
|
|
233
|
-
if (element.id
|
|
298
|
+
if (/** @type {AST.Element} */ (element).id.tracked) {
|
|
234
299
|
return true;
|
|
235
300
|
}
|
|
236
301
|
|
|
237
302
|
// Check for dynamic class attributes if requested (for class-based selectors)
|
|
238
|
-
if (check_classes && element.attributes) {
|
|
239
|
-
for (const attr of element.attributes) {
|
|
240
|
-
if (attr.type === 'Attribute' && attr.name
|
|
303
|
+
if (check_classes && /** @type {AST.Element} */ (element).attributes) {
|
|
304
|
+
for (const attr of /** @type {AST.Element} */ (element).attributes) {
|
|
305
|
+
if (attr.type === 'Attribute' && attr.name.name === 'class') {
|
|
241
306
|
// Check if class value is an expression (not a static string)
|
|
242
307
|
if (attr.value && typeof attr.value === 'object') {
|
|
243
308
|
// If it's a CallExpression or other dynamic value, it's dynamic
|
|
@@ -252,8 +317,15 @@ function can_render_dynamic_content(element, check_classes = false) {
|
|
|
252
317
|
return false;
|
|
253
318
|
}
|
|
254
319
|
|
|
320
|
+
/**
|
|
321
|
+
* @param {AST.Node} node
|
|
322
|
+
* @param {Direction} direction
|
|
323
|
+
* @param {boolean} adjacent_only
|
|
324
|
+
* @returns {Map<AST.Element, boolean>}
|
|
325
|
+
*/
|
|
255
326
|
function get_possible_element_siblings(node, direction, adjacent_only) {
|
|
256
327
|
const siblings = new Map();
|
|
328
|
+
// Parent has to be an Element not a Component
|
|
257
329
|
const parent = get_element_parent(node);
|
|
258
330
|
|
|
259
331
|
if (!parent) {
|
|
@@ -261,7 +333,7 @@ function get_possible_element_siblings(node, direction, adjacent_only) {
|
|
|
261
333
|
}
|
|
262
334
|
|
|
263
335
|
// Get the container that holds the siblings
|
|
264
|
-
const container = parent.children ||
|
|
336
|
+
const container = parent.children || [];
|
|
265
337
|
const node_index = container.indexOf(node);
|
|
266
338
|
|
|
267
339
|
if (node_index === -1) return siblings;
|
|
@@ -292,7 +364,13 @@ function get_possible_element_siblings(node, direction, adjacent_only) {
|
|
|
292
364
|
}
|
|
293
365
|
}
|
|
294
366
|
// Stop at non-whitespace text nodes for adjacent selectors
|
|
295
|
-
else if (
|
|
367
|
+
else if (
|
|
368
|
+
adjacent_only &&
|
|
369
|
+
sibling.type === 'Text' &&
|
|
370
|
+
sibling.expression.type === 'Literal' &&
|
|
371
|
+
typeof sibling.expression.value === 'string' &&
|
|
372
|
+
sibling.expression.value.trim()
|
|
373
|
+
) {
|
|
296
374
|
break;
|
|
297
375
|
}
|
|
298
376
|
}
|
|
@@ -300,6 +378,14 @@ function get_possible_element_siblings(node, direction, adjacent_only) {
|
|
|
300
378
|
return siblings;
|
|
301
379
|
}
|
|
302
380
|
|
|
381
|
+
/**
|
|
382
|
+
* @param {AST.CSS.RelativeSelector} relative_selector
|
|
383
|
+
* @param {AST.CSS.RelativeSelector[]} rest_selectors
|
|
384
|
+
* @param {AST.CSS.Rule} rule
|
|
385
|
+
* @param {AST.Element} node
|
|
386
|
+
* @param {Direction} direction
|
|
387
|
+
* @returns {boolean}
|
|
388
|
+
*/
|
|
303
389
|
function apply_combinator(relative_selector, rest_selectors, rule, node, direction) {
|
|
304
390
|
const combinator =
|
|
305
391
|
direction == FORWARD ? rest_selectors[0]?.combinator : relative_selector.combinator;
|
|
@@ -358,7 +444,7 @@ function apply_combinator(relative_selector, rest_selectors, rule, node, directi
|
|
|
358
444
|
// Check if there are any elements after this component that could match the remaining selectors
|
|
359
445
|
const parent = get_element_parent(node);
|
|
360
446
|
if (parent) {
|
|
361
|
-
const container = parent.children ||
|
|
447
|
+
const container = parent.children || [];
|
|
362
448
|
const component_index = container.indexOf(possible_sibling);
|
|
363
449
|
|
|
364
450
|
// For adjacent combinator, only check immediate next element
|
|
@@ -411,7 +497,10 @@ function apply_combinator(relative_selector, rest_selectors, rule, node, directi
|
|
|
411
497
|
return true;
|
|
412
498
|
}
|
|
413
499
|
}
|
|
414
|
-
|
|
500
|
+
/**
|
|
501
|
+
* @param {AST.Node} node
|
|
502
|
+
* @returns {AST.Element | null}
|
|
503
|
+
*/
|
|
415
504
|
function get_element_parent(node) {
|
|
416
505
|
// Check if metadata and path exist
|
|
417
506
|
if (!node.metadata || !node.metadata.path) {
|
|
@@ -434,7 +523,8 @@ function get_element_parent(node) {
|
|
|
434
523
|
|
|
435
524
|
/**
|
|
436
525
|
* `true` if is a pseudo class that cannot be or is not scoped
|
|
437
|
-
* @param {
|
|
526
|
+
* @param {AST.CSS.SimpleSelector} selector
|
|
527
|
+
* @returns {boolean}
|
|
438
528
|
*/
|
|
439
529
|
function is_unscoped_pseudo_class(selector) {
|
|
440
530
|
return (
|
|
@@ -457,7 +547,7 @@ function is_unscoped_pseudo_class(selector) {
|
|
|
457
547
|
|
|
458
548
|
/**
|
|
459
549
|
* True if is `:global(...)` or `:global` and no pseudo class that is scoped.
|
|
460
|
-
* @param {
|
|
550
|
+
* @param {AST.CSS.RelativeSelector} relative_selector
|
|
461
551
|
*/
|
|
462
552
|
function is_global_simple(relative_selector) {
|
|
463
553
|
const first = relative_selector.selectors[0];
|
|
@@ -475,6 +565,11 @@ function is_global_simple(relative_selector) {
|
|
|
475
565
|
);
|
|
476
566
|
}
|
|
477
567
|
|
|
568
|
+
/**
|
|
569
|
+
* @param {AST.CSS.RelativeSelector} selector
|
|
570
|
+
* @param {AST.CSS.Rule} rule
|
|
571
|
+
* @return {boolean}
|
|
572
|
+
*/
|
|
478
573
|
function is_global(selector, rule) {
|
|
479
574
|
if (selector.metadata.is_global || selector.metadata.is_global_like) {
|
|
480
575
|
return true;
|
|
@@ -483,7 +578,7 @@ function is_global(selector, rule) {
|
|
|
483
578
|
let explicitly_global = false;
|
|
484
579
|
|
|
485
580
|
for (const s of selector.selectors) {
|
|
486
|
-
/** @type {
|
|
581
|
+
/** @type {AST.CSS.SelectorList | null} */
|
|
487
582
|
let selector_list = null;
|
|
488
583
|
let can_be_global = false;
|
|
489
584
|
let owner = rule;
|
|
@@ -497,7 +592,7 @@ function is_global(selector, rule) {
|
|
|
497
592
|
}
|
|
498
593
|
|
|
499
594
|
if (s.type === 'NestingSelector') {
|
|
500
|
-
owner = /** @type {
|
|
595
|
+
owner = /** @type {AST.CSS.Rule} */ (rule.metadata.parent_rule);
|
|
501
596
|
selector_list = owner.prelude;
|
|
502
597
|
}
|
|
503
598
|
|
|
@@ -516,10 +611,21 @@ function is_global(selector, rule) {
|
|
|
516
611
|
return explicitly_global || selector.selectors.length === 0;
|
|
517
612
|
}
|
|
518
613
|
|
|
614
|
+
/**
|
|
615
|
+
* @param {AST.Attribute} attribute
|
|
616
|
+
* @returns {attribute is AST.Attribute & { value: AST.Literal & { value: string } }}
|
|
617
|
+
*/
|
|
519
618
|
function is_text_attribute(attribute) {
|
|
520
|
-
return attribute.value
|
|
619
|
+
return attribute.value?.type === 'Literal' && typeof attribute.value.value === 'string';
|
|
521
620
|
}
|
|
522
621
|
|
|
622
|
+
/**
|
|
623
|
+
* @param {string | null} operator
|
|
624
|
+
* @param {string} expected_value
|
|
625
|
+
* @param {boolean} case_insensitive
|
|
626
|
+
* @param {string} value
|
|
627
|
+
* @returns {boolean}
|
|
628
|
+
*/
|
|
523
629
|
function test_attribute(operator, expected_value, case_insensitive, value) {
|
|
524
630
|
if (case_insensitive) {
|
|
525
631
|
expected_value = expected_value.toLowerCase();
|
|
@@ -543,6 +649,14 @@ function test_attribute(operator, expected_value, case_insensitive, value) {
|
|
|
543
649
|
}
|
|
544
650
|
}
|
|
545
651
|
|
|
652
|
+
/**
|
|
653
|
+
* @param {AST.Element} node
|
|
654
|
+
* @param {string} name
|
|
655
|
+
* @param {string | null} expected_value
|
|
656
|
+
* @param {string | null} operator
|
|
657
|
+
* @param {boolean} case_insensitive
|
|
658
|
+
* @returns {boolean}
|
|
659
|
+
*/
|
|
546
660
|
function attribute_matches(node, name, expected_value, operator, case_insensitive) {
|
|
547
661
|
for (const attribute of node.attributes) {
|
|
548
662
|
if (attribute.type === 'SpreadAttribute') return true;
|
|
@@ -564,6 +678,10 @@ function attribute_matches(node, name, expected_value, operator, case_insensitiv
|
|
|
564
678
|
return false;
|
|
565
679
|
}
|
|
566
680
|
|
|
681
|
+
/**
|
|
682
|
+
* @param {AST.CSS.RelativeSelector} relative_selector
|
|
683
|
+
* @returns {boolean}
|
|
684
|
+
*/
|
|
567
685
|
function is_outer_global(relative_selector) {
|
|
568
686
|
const first = relative_selector.selectors[0];
|
|
569
687
|
|
|
@@ -581,6 +699,13 @@ function is_outer_global(relative_selector) {
|
|
|
581
699
|
);
|
|
582
700
|
}
|
|
583
701
|
|
|
702
|
+
/**
|
|
703
|
+
* @param {AST.CSS.RelativeSelector} relative_selector
|
|
704
|
+
* @param {AST.CSS.Rule} rule
|
|
705
|
+
* @param {AST.Element} element
|
|
706
|
+
* @param {Direction} direction
|
|
707
|
+
* @return {boolean}
|
|
708
|
+
*/
|
|
584
709
|
function relative_selector_might_apply_to_node(relative_selector, rule, element, direction) {
|
|
585
710
|
// Sort :has(...) selectors in one bucket and everything else into another
|
|
586
711
|
const has_selectors = [];
|
|
@@ -617,8 +742,7 @@ function relative_selector_might_apply_to_node(relative_selector, rule, element,
|
|
|
617
742
|
// upwards and back-to-front, we need to first check the selectors inside :has(...), then check the rest of the
|
|
618
743
|
// selector in a way that is similar to ancestor matching. In a sense, we're treating `.x:has(.y)` as `.x .y`.
|
|
619
744
|
for (const has_selector of has_selectors) {
|
|
620
|
-
const complex_selectors = /** @type {
|
|
621
|
-
.children;
|
|
745
|
+
const complex_selectors = /** @type {AST.CSS.SelectorList} */ (has_selector.args).children;
|
|
622
746
|
let matched = false;
|
|
623
747
|
|
|
624
748
|
for (const complex_selector of complex_selectors) {
|
|
@@ -642,8 +766,10 @@ function relative_selector_might_apply_to_node(relative_selector, rule, element,
|
|
|
642
766
|
}
|
|
643
767
|
|
|
644
768
|
const selector_excluding_self = [
|
|
645
|
-
|
|
646
|
-
first.combinator
|
|
769
|
+
create_any_selector(first.start, first.end),
|
|
770
|
+
first.combinator
|
|
771
|
+
? first
|
|
772
|
+
: { ...first, combinator: create_descendant_combinator(first.start, first.end) },
|
|
647
773
|
...rest,
|
|
648
774
|
];
|
|
649
775
|
if (apply_selector(selector_excluding_self, rule, element, FORWARD)) {
|
|
@@ -701,6 +827,7 @@ function relative_selector_might_apply_to_node(relative_selector, rule, element,
|
|
|
701
827
|
selector.metadata.scoped = true;
|
|
702
828
|
}
|
|
703
829
|
|
|
830
|
+
/** @type {AST.Element | null} */
|
|
704
831
|
let el = element;
|
|
705
832
|
while (el) {
|
|
706
833
|
el.metadata.scoped = true;
|
|
@@ -797,7 +924,7 @@ function relative_selector_might_apply_to_node(relative_selector, rule, element,
|
|
|
797
924
|
case 'NestingSelector': {
|
|
798
925
|
let matched = false;
|
|
799
926
|
|
|
800
|
-
const parent = /** @type {
|
|
927
|
+
const parent = /** @type {AST.CSS.Rule} */ (rule.metadata.parent_rule);
|
|
801
928
|
|
|
802
929
|
for (const complex_selector of parent.prelude.children) {
|
|
803
930
|
if (
|
|
@@ -822,7 +949,10 @@ function relative_selector_might_apply_to_node(relative_selector, rule, element,
|
|
|
822
949
|
return true;
|
|
823
950
|
}
|
|
824
951
|
|
|
825
|
-
|
|
952
|
+
/**
|
|
953
|
+
* @param {string} str
|
|
954
|
+
* @returns {string}
|
|
955
|
+
*/
|
|
826
956
|
function unquote(str) {
|
|
827
957
|
if (
|
|
828
958
|
(str[0] === '"' && str[str.length - 1] === '"') ||
|
|
@@ -833,6 +963,10 @@ function unquote(str) {
|
|
|
833
963
|
return str;
|
|
834
964
|
}
|
|
835
965
|
|
|
966
|
+
/**
|
|
967
|
+
* @param {AST.CSS.Rule} rule
|
|
968
|
+
* @returns {AST.CSS.Rule[]}
|
|
969
|
+
*/
|
|
836
970
|
function get_parent_rules(rule) {
|
|
837
971
|
const rules = [rule];
|
|
838
972
|
let current = rule;
|
|
@@ -847,7 +981,7 @@ function get_parent_rules(rule) {
|
|
|
847
981
|
|
|
848
982
|
/**
|
|
849
983
|
* Check if a CSS rule contains animation or animation-name properties
|
|
850
|
-
* @param {
|
|
984
|
+
* @param {AST.CSS.Rule} rule
|
|
851
985
|
* @returns {boolean}
|
|
852
986
|
*/
|
|
853
987
|
function rule_has_animation(rule) {
|
|
@@ -865,8 +999,14 @@ function rule_has_animation(rule) {
|
|
|
865
999
|
return false;
|
|
866
1000
|
}
|
|
867
1001
|
|
|
1002
|
+
/**
|
|
1003
|
+
* @param {AST.CSS.StyleSheet} css
|
|
1004
|
+
* @param {AST.Element} element
|
|
1005
|
+
* @return {void}
|
|
1006
|
+
*/
|
|
868
1007
|
export function prune_css(css, element) {
|
|
869
|
-
|
|
1008
|
+
/** @type {Visitors<AST.CSS.Node, null>} */
|
|
1009
|
+
const visitors = {
|
|
870
1010
|
Rule(node, context) {
|
|
871
1011
|
if (node.metadata.is_global_block) {
|
|
872
1012
|
context.visit(node.prelude);
|
|
@@ -879,7 +1019,7 @@ export function prune_css(css, element) {
|
|
|
879
1019
|
|
|
880
1020
|
seen.clear();
|
|
881
1021
|
|
|
882
|
-
const rule = /** @type {
|
|
1022
|
+
const rule = /** @type {AST.CSS.Rule} */ (node.metadata.rule);
|
|
883
1023
|
|
|
884
1024
|
if (apply_selector(selectors, rule, element, BACKWARD) || rule_has_animation(rule)) {
|
|
885
1025
|
node.metadata.used = true;
|
|
@@ -899,5 +1039,7 @@ export function prune_css(css, element) {
|
|
|
899
1039
|
context.next();
|
|
900
1040
|
}
|
|
901
1041
|
},
|
|
902
|
-
}
|
|
1042
|
+
};
|
|
1043
|
+
|
|
1044
|
+
walk(css, null, visitors);
|
|
903
1045
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/** @import * as AST from 'estree' */
|
|
2
|
+
/** @import {AnalysisContext} from '#compiler' */
|
|
3
|
+
|
|
1
4
|
import { error } from '../../errors.js';
|
|
2
5
|
|
|
3
6
|
const invalid_nestings = {
|
|
@@ -113,7 +116,7 @@ const invalid_nestings = {
|
|
|
113
116
|
};
|
|
114
117
|
|
|
115
118
|
/**
|
|
116
|
-
* @param {
|
|
119
|
+
* @param {AST.Element} element
|
|
117
120
|
* @returns {string | null}
|
|
118
121
|
*/
|
|
119
122
|
function get_element_tag(element) {
|
|
@@ -121,11 +124,10 @@ function get_element_tag(element) {
|
|
|
121
124
|
}
|
|
122
125
|
|
|
123
126
|
/**
|
|
124
|
-
* @param {
|
|
125
|
-
* @param {
|
|
126
|
-
* @param {any} context
|
|
127
|
+
* @param {AST.Element} element
|
|
128
|
+
* @param {AnalysisContext} context
|
|
127
129
|
*/
|
|
128
|
-
export function validate_nesting(element,
|
|
130
|
+
export function validate_nesting(element, context) {
|
|
129
131
|
const tag = get_element_tag(element);
|
|
130
132
|
|
|
131
133
|
if (tag === null) {
|
|
@@ -146,8 +148,8 @@ export function validate_nesting(element, state, context) {
|
|
|
146
148
|
if (validation_set.has(tag)) {
|
|
147
149
|
error(
|
|
148
150
|
`Invalid HTML nesting: <${tag}> cannot be a descendant of <${parent_tag}>.`,
|
|
149
|
-
state.analysis.module.filename,
|
|
150
|
-
|
|
151
|
+
context.state.analysis.module.filename,
|
|
152
|
+
element,
|
|
151
153
|
);
|
|
152
154
|
}
|
|
153
155
|
}
|