postcss-merge-rules 5.0.6 → 5.1.2
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 +8 -6
- package/src/index.js +69 -36
- package/src/lib/ensureCompatibility.js +40 -8
- package/types/index.d.ts +9 -0
- package/types/lib/ensureCompatibility.d.ts +71 -0
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "postcss-merge-rules",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.1.2",
|
|
4
4
|
"description": "Merge CSS rules with PostCSS.",
|
|
5
|
+
"types": "types/index.d.ts",
|
|
5
6
|
"main": "src/index.js",
|
|
6
7
|
"files": [
|
|
7
8
|
"LICENSE-MIT",
|
|
8
|
-
"src"
|
|
9
|
+
"src",
|
|
10
|
+
"types"
|
|
9
11
|
],
|
|
10
12
|
"keywords": [
|
|
11
13
|
"css",
|
|
@@ -24,7 +26,7 @@
|
|
|
24
26
|
"dependencies": {
|
|
25
27
|
"browserslist": "^4.16.6",
|
|
26
28
|
"caniuse-api": "^3.0.0",
|
|
27
|
-
"cssnano-utils": "^3.0
|
|
29
|
+
"cssnano-utils": "^3.1.0",
|
|
28
30
|
"postcss-selector-parser": "^6.0.5"
|
|
29
31
|
},
|
|
30
32
|
"bugs": {
|
|
@@ -34,11 +36,11 @@
|
|
|
34
36
|
"node": "^10 || ^12 || >=14.0"
|
|
35
37
|
},
|
|
36
38
|
"devDependencies": {
|
|
39
|
+
"@types/caniuse-api": "^3.0.2",
|
|
37
40
|
"postcss": "^8.2.15",
|
|
38
|
-
"postcss-discard-comments": "^5.
|
|
41
|
+
"postcss-discard-comments": "^5.1.2"
|
|
39
42
|
},
|
|
40
43
|
"peerDependencies": {
|
|
41
44
|
"postcss": "^8.2.15"
|
|
42
|
-
}
|
|
43
|
-
"readme": "# [postcss][postcss]-merge-rules\n\n> Merge CSS rules with PostCSS.\n\n## Install\n\nWith [npm](https://npmjs.org/package/postcss-merge-rules) do:\n\n```\nnpm install postcss-merge-rules --save\n```\n\n## Examples\n\nThis module will attempt to merge *adjacent* CSS rules:\n\n### By declarations\n\n#### Input\n\n```css\na {\n color: blue;\n font-weight: bold\n}\n\np {\n color: blue;\n font-weight: bold\n}\n```\n\n#### Output\n\n```css\na,p {\n color: blue;\n font-weight: bold\n}\n```\n\n### By selectors\n\n#### Input\n\n```css\na {\n color: blue\n}\n\na {\n font-weight: bold\n}\n```\n\n#### Output\n\n```css\na {\n color: blue;\n font-weight: bold\n}\n```\n\n### By partial declarations\n\n#### Input\n\n```css\na {\n font-weight: bold\n}\n\np {\n color: blue;\n font-weight: bold\n}\n```\n\n#### Output\n\n```css\na,p {\n font-weight: bold\n}\n\np {\n color: blue\n}\n```\n\n## Usage\n\nSee the [PostCSS documentation](https://github.com/postcss/postcss#usage) for\nexamples for your environment.\n\n## Contributors\n\nSee [CONTRIBUTORS.md](https://github.com/cssnano/cssnano/blob/master/CONTRIBUTORS.md).\n\n## License\n\nMIT © [Ben Briggs](http://beneb.info)\n\n[postcss]: https://github.com/postcss/postcss\n"
|
|
45
|
+
}
|
|
44
46
|
}
|
package/src/index.js
CHANGED
|
@@ -8,8 +8,8 @@ const {
|
|
|
8
8
|
} = require('./lib/ensureCompatibility');
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* @param {postcss.Declaration} a
|
|
12
|
-
* @param {postcss.Declaration} b
|
|
11
|
+
* @param {import('postcss').Declaration} a
|
|
12
|
+
* @param {import('postcss').Declaration} b
|
|
13
13
|
* @return {boolean}
|
|
14
14
|
*/
|
|
15
15
|
function declarationIsEqual(a, b) {
|
|
@@ -19,8 +19,8 @@ function declarationIsEqual(a, b) {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* @param {postcss.Declaration[]} array
|
|
23
|
-
* @param {postcss.Declaration} decl
|
|
22
|
+
* @param {import('postcss').Declaration[]} array
|
|
23
|
+
* @param {import('postcss').Declaration} decl
|
|
24
24
|
* @return {number}
|
|
25
25
|
*/
|
|
26
26
|
function indexOfDeclaration(array, decl) {
|
|
@@ -29,21 +29,21 @@ function indexOfDeclaration(array, decl) {
|
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* Returns filtered array of matched or unmatched declarations
|
|
32
|
-
* @param {postcss.Declaration[]} a
|
|
33
|
-
* @param {postcss.Declaration[]} b
|
|
32
|
+
* @param {import('postcss').Declaration[]} a
|
|
33
|
+
* @param {import('postcss').Declaration[]} b
|
|
34
34
|
* @param {boolean} [not=false]
|
|
35
|
-
* @return {postcss.Declaration[]}
|
|
35
|
+
* @return {import('postcss').Declaration[]}
|
|
36
36
|
*/
|
|
37
37
|
function intersect(a, b, not) {
|
|
38
38
|
return a.filter((c) => {
|
|
39
|
-
const index =
|
|
39
|
+
const index = indexOfDeclaration(b, c) !== -1;
|
|
40
40
|
return not ? !index : index;
|
|
41
41
|
});
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
|
-
* @param {postcss.Declaration[]} a
|
|
46
|
-
* @param {postcss.Declaration[]} b
|
|
45
|
+
* @param {import('postcss').Declaration[]} a
|
|
46
|
+
* @param {import('postcss').Declaration[]} b
|
|
47
47
|
* @return {boolean}
|
|
48
48
|
*/
|
|
49
49
|
function sameDeclarationsAndOrder(a, b) {
|
|
@@ -54,8 +54,8 @@ function sameDeclarationsAndOrder(a, b) {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
|
-
* @param {postcss.Rule} ruleA
|
|
58
|
-
* @param {postcss.Rule} ruleB
|
|
57
|
+
* @param {import('postcss').Rule} ruleA
|
|
58
|
+
* @param {import('postcss').Rule} ruleB
|
|
59
59
|
* @param {string[]=} browsers
|
|
60
60
|
* @param {Map<string, boolean>=} compatibilityCache
|
|
61
61
|
* @return {boolean}
|
|
@@ -70,31 +70,52 @@ function canMerge(ruleA, ruleB, browsers, compatibilityCache) {
|
|
|
70
70
|
return false;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
const parent = sameParent(
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
const parent = sameParent(
|
|
74
|
+
/** @type {any} */ (ruleA),
|
|
75
|
+
/** @type {any} */ (ruleB)
|
|
76
|
+
);
|
|
77
|
+
if (
|
|
78
|
+
parent &&
|
|
79
|
+
ruleA.parent &&
|
|
80
|
+
ruleA.parent.type === 'atrule' &&
|
|
81
|
+
/** @type {import('postcss').AtRule} */ (ruleA.parent).name.includes(
|
|
82
|
+
'keyframes'
|
|
83
|
+
)
|
|
84
|
+
) {
|
|
76
85
|
return false;
|
|
77
86
|
}
|
|
78
87
|
return parent && (selectors.every(noVendor) || sameVendor(a, b));
|
|
79
88
|
}
|
|
80
89
|
|
|
81
90
|
/**
|
|
82
|
-
* @param {postcss.
|
|
83
|
-
* @return {postcss.Declaration
|
|
91
|
+
* @param {import('postcss').ChildNode} node
|
|
92
|
+
* @return {node is import('postcss').Declaration}
|
|
93
|
+
*/
|
|
94
|
+
function isDeclaration(node) {
|
|
95
|
+
return node.type === 'decl';
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* @param {import('postcss').Rule} rule
|
|
99
|
+
* @return {import('postcss').Declaration[]}
|
|
84
100
|
*/
|
|
85
101
|
function getDecls(rule) {
|
|
86
|
-
return rule.nodes.filter(
|
|
102
|
+
return rule.nodes.filter(isDeclaration);
|
|
87
103
|
}
|
|
88
104
|
|
|
105
|
+
/** @type {(...rules: import('postcss').Rule[]) => string} */
|
|
89
106
|
const joinSelectors = (...rules) => rules.map((s) => s.selector).join();
|
|
90
107
|
|
|
108
|
+
/**
|
|
109
|
+
* @param {...import('postcss').Rule} rules
|
|
110
|
+
* @return {number}
|
|
111
|
+
*/
|
|
91
112
|
function ruleLength(...rules) {
|
|
92
113
|
return rules.map((r) => (r.nodes.length ? String(r) : '')).join('').length;
|
|
93
114
|
}
|
|
94
115
|
|
|
95
116
|
/**
|
|
96
117
|
* @param {string} prop
|
|
97
|
-
* @return {{prefix: string
|
|
118
|
+
* @return {{prefix: string?, base:string?, rest:string[]}}
|
|
98
119
|
*/
|
|
99
120
|
function splitProp(prop) {
|
|
100
121
|
// Treat vendor prefixed properties as if they were unprefixed;
|
|
@@ -155,8 +176,8 @@ function isConflictingProp(propA, propB) {
|
|
|
155
176
|
}
|
|
156
177
|
|
|
157
178
|
/**
|
|
158
|
-
* @param {postcss.Rule} first
|
|
159
|
-
* @param {postcss.Rule} second
|
|
179
|
+
* @param {import('postcss').Rule} first
|
|
180
|
+
* @param {import('postcss').Rule} second
|
|
160
181
|
* @return {boolean} merged
|
|
161
182
|
*/
|
|
162
183
|
function mergeParents(first, second) {
|
|
@@ -178,9 +199,9 @@ function mergeParents(first, second) {
|
|
|
178
199
|
}
|
|
179
200
|
|
|
180
201
|
/**
|
|
181
|
-
* @param {postcss.Rule} first
|
|
182
|
-
* @param {postcss.Rule} second
|
|
183
|
-
* @return {postcss.Rule} mergedRule
|
|
202
|
+
* @param {import('postcss').Rule} first
|
|
203
|
+
* @param {import('postcss').Rule} second
|
|
204
|
+
* @return {import('postcss').Rule} mergedRule
|
|
184
205
|
*/
|
|
185
206
|
function partialMerge(first, second) {
|
|
186
207
|
let intersection = intersect(getDecls(first), getDecls(second));
|
|
@@ -190,7 +211,11 @@ function partialMerge(first, second) {
|
|
|
190
211
|
let nextRule = second.next();
|
|
191
212
|
if (!nextRule) {
|
|
192
213
|
// Grab next cousin
|
|
193
|
-
|
|
214
|
+
/** @type {any} */
|
|
215
|
+
const parentSibling =
|
|
216
|
+
/** @type {import('postcss').Container<import('postcss').ChildNode>} */ (
|
|
217
|
+
second.parent
|
|
218
|
+
).next();
|
|
194
219
|
nextRule = parentSibling && parentSibling.nodes && parentSibling.nodes[0];
|
|
195
220
|
}
|
|
196
221
|
if (nextRule && nextRule.type === 'rule' && canMerge(second, nextRule)) {
|
|
@@ -262,18 +287,21 @@ function partialMerge(first, second) {
|
|
|
262
287
|
receivingBlock.selector = joinSelectors(first, second);
|
|
263
288
|
receivingBlock.nodes = [];
|
|
264
289
|
|
|
265
|
-
|
|
290
|
+
/** @type {import('postcss').Container<import('postcss').ChildNode>} */ (
|
|
291
|
+
second.parent
|
|
292
|
+
).insertBefore(second, receivingBlock);
|
|
266
293
|
|
|
267
294
|
const firstClone = first.clone();
|
|
268
295
|
const secondClone = second.clone();
|
|
269
296
|
|
|
270
297
|
/**
|
|
271
|
-
* @param {function(postcss.Declaration):void} callback
|
|
272
|
-
* @
|
|
298
|
+
* @param {function(import('postcss').Declaration):void} callback
|
|
299
|
+
* @this {import('postcss').Rule}
|
|
300
|
+
* @return {function(import('postcss').Declaration)}
|
|
273
301
|
*/
|
|
274
302
|
function moveDecl(callback) {
|
|
275
303
|
return (decl) => {
|
|
276
|
-
if (
|
|
304
|
+
if (indexOfDeclaration(intersection, decl) !== -1) {
|
|
277
305
|
callback.call(this, decl);
|
|
278
306
|
}
|
|
279
307
|
};
|
|
@@ -308,10 +336,10 @@ function partialMerge(first, second) {
|
|
|
308
336
|
/**
|
|
309
337
|
* @param {string[]} browsers
|
|
310
338
|
* @param {Map<string, boolean>} compatibilityCache
|
|
311
|
-
* @return {function(postcss.Rule)}
|
|
339
|
+
* @return {function(import('postcss').Rule)}
|
|
312
340
|
*/
|
|
313
341
|
function selectorMerger(browsers, compatibilityCache) {
|
|
314
|
-
/** @type {postcss.Rule} */
|
|
342
|
+
/** @type {import('postcss').Rule | null} */
|
|
315
343
|
let cache = null;
|
|
316
344
|
return function (rule) {
|
|
317
345
|
// Prime the cache with the first rule, or alternately ensure that it is
|
|
@@ -342,11 +370,12 @@ function selectorMerger(browsers, compatibilityCache) {
|
|
|
342
370
|
// e.g. a { color: blue } a { font-weight: bold }
|
|
343
371
|
if (cache.selector === rule.selector) {
|
|
344
372
|
const cached = getDecls(cache);
|
|
345
|
-
rule.walk((
|
|
346
|
-
if (
|
|
347
|
-
|
|
373
|
+
rule.walk((node) => {
|
|
374
|
+
if (node.type === 'decl' && indexOfDeclaration(cached, node) !== -1) {
|
|
375
|
+
node.remove();
|
|
376
|
+
return;
|
|
348
377
|
}
|
|
349
|
-
cache.append(
|
|
378
|
+
/** @type {import('postcss').Rule} */ (cache).append(node);
|
|
350
379
|
});
|
|
351
380
|
rule.remove();
|
|
352
381
|
return;
|
|
@@ -356,12 +385,16 @@ function selectorMerger(browsers, compatibilityCache) {
|
|
|
356
385
|
cache = partialMerge(cache, rule);
|
|
357
386
|
};
|
|
358
387
|
}
|
|
359
|
-
|
|
388
|
+
/**
|
|
389
|
+
* @type {import('postcss').PluginCreator<void>}
|
|
390
|
+
* @return {import('postcss').Plugin}
|
|
391
|
+
*/
|
|
360
392
|
function pluginCreator() {
|
|
361
393
|
return {
|
|
362
394
|
postcssPlugin: 'postcss-merge-rules',
|
|
363
395
|
|
|
364
396
|
prepare(result) {
|
|
397
|
+
/** @type {typeof result.opts & browserslist.Options} */
|
|
365
398
|
const resultOpts = result.opts || {};
|
|
366
399
|
const browsers = browserslist(null, {
|
|
367
400
|
stats: resultOpts.stats,
|
|
@@ -15,21 +15,35 @@ const formValidation = 'form-validation';
|
|
|
15
15
|
const vendorPrefix =
|
|
16
16
|
/-(ah|apple|atsc|epub|hp|khtml|moz|ms|o|rim|ro|tc|wap|webkit|xv)-/;
|
|
17
17
|
|
|
18
|
+
const level2Sel = new Set(['=', '~=', '|=']);
|
|
19
|
+
const level3Sel = new Set(['^=', '$=', '*=']);
|
|
20
|
+
|
|
18
21
|
/**
|
|
19
22
|
* @param {string} selector
|
|
20
|
-
* @return {
|
|
23
|
+
* @return {RegExpMatchArray | null}
|
|
21
24
|
*/
|
|
22
25
|
function filterPrefixes(selector) {
|
|
23
26
|
return selector.match(vendorPrefix);
|
|
24
27
|
}
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Internet Explorer use :-ms-input-placeholder.
|
|
31
|
+
* Microsoft Edge use ::-ms-input-placeholder.
|
|
32
|
+
*
|
|
33
|
+
* @type {(selector: string) => number}
|
|
34
|
+
*/
|
|
28
35
|
const findMsInputPlaceholder = (selector) =>
|
|
29
36
|
~selector.search(/-ms-input-placeholder/i);
|
|
30
37
|
|
|
38
|
+
/**
|
|
39
|
+
* @param {string[]} selectorsA
|
|
40
|
+
* @param {string[]} selectorsB
|
|
41
|
+
* @return {boolean}
|
|
42
|
+
*/
|
|
31
43
|
function sameVendor(selectorsA, selectorsB) {
|
|
44
|
+
/** @type {(selectors: string[]) => string} */
|
|
32
45
|
let same = (selectors) => selectors.map(filterPrefixes).join();
|
|
46
|
+
/** @type {(selectors: string[]) => string | undefined} */
|
|
33
47
|
let findMsVendor = (selectors) => selectors.find(findMsInputPlaceholder);
|
|
34
48
|
return (
|
|
35
49
|
same(selectorsA) === same(selectorsB) &&
|
|
@@ -99,10 +113,18 @@ const pseudoElements = {
|
|
|
99
113
|
':visited': cssSel2,
|
|
100
114
|
};
|
|
101
115
|
|
|
116
|
+
/**
|
|
117
|
+
* @param {string} selector
|
|
118
|
+
* @return {boolean}
|
|
119
|
+
*/
|
|
102
120
|
function isCssMixin(selector) {
|
|
103
121
|
return selector[selector.length - 1] === ':';
|
|
104
122
|
}
|
|
105
123
|
|
|
124
|
+
/**
|
|
125
|
+
* @param {string} selector
|
|
126
|
+
* @return {boolean}
|
|
127
|
+
*/
|
|
106
128
|
function isHostPseudoClass(selector) {
|
|
107
129
|
return selector.includes(':host');
|
|
108
130
|
}
|
|
@@ -110,18 +132,28 @@ function isHostPseudoClass(selector) {
|
|
|
110
132
|
const isSupportedCache = new Map();
|
|
111
133
|
|
|
112
134
|
// Move to util in future
|
|
135
|
+
/**
|
|
136
|
+
* @param {string} feature
|
|
137
|
+
* @param {string[] | undefined} browsers
|
|
138
|
+
*/
|
|
113
139
|
function isSupportedCached(feature, browsers) {
|
|
114
140
|
const key = JSON.stringify({ feature, browsers });
|
|
115
141
|
let result = isSupportedCache.get(key);
|
|
116
142
|
|
|
117
143
|
if (!result) {
|
|
118
|
-
result = isSupported(feature, browsers);
|
|
144
|
+
result = isSupported(feature, /** @type {string[]} */ (browsers));
|
|
119
145
|
isSupportedCache.set(key, result);
|
|
120
146
|
}
|
|
121
147
|
|
|
122
148
|
return result;
|
|
123
149
|
}
|
|
124
150
|
|
|
151
|
+
/**
|
|
152
|
+
* @param {string[]} selectors
|
|
153
|
+
* @param{string[]=} browsers
|
|
154
|
+
* @param{Map<string,boolean>=} compatibilityCache
|
|
155
|
+
* @return {boolean}
|
|
156
|
+
*/
|
|
125
157
|
function ensureCompatibility(selectors, browsers, compatibilityCache) {
|
|
126
158
|
// Should not merge mixins
|
|
127
159
|
if (selectors.some(isCssMixin)) {
|
|
@@ -144,7 +176,8 @@ function ensureCompatibility(selectors, browsers, compatibilityCache) {
|
|
|
144
176
|
ast.walk((node) => {
|
|
145
177
|
const { type, value } = node;
|
|
146
178
|
if (type === 'pseudo') {
|
|
147
|
-
const entry =
|
|
179
|
+
const entry =
|
|
180
|
+
pseudoElements[/** @type {keyof pseudoElements} */ (value)];
|
|
148
181
|
if (!entry && noVendor(value)) {
|
|
149
182
|
compatible = false;
|
|
150
183
|
}
|
|
@@ -165,14 +198,13 @@ function ensureCompatibility(selectors, browsers, compatibilityCache) {
|
|
|
165
198
|
if (!node.operator) {
|
|
166
199
|
compatible = isSupportedCached(cssSel2, browsers);
|
|
167
200
|
}
|
|
168
|
-
|
|
169
201
|
if (value) {
|
|
170
202
|
// [foo="bar"], [foo~="bar"], [foo|="bar"]
|
|
171
|
-
if (
|
|
203
|
+
if (level2Sel.has(/** @type {string} */ (node.operator))) {
|
|
172
204
|
compatible = isSupportedCached(cssSel2, browsers);
|
|
173
205
|
}
|
|
174
206
|
// [foo^="bar"], [foo$="bar"], [foo*="bar"]
|
|
175
|
-
if (
|
|
207
|
+
if (level3Sel.has(/** @type {string} */ (node.operator))) {
|
|
176
208
|
compatible = isSupportedCached(cssSel3, browsers);
|
|
177
209
|
}
|
|
178
210
|
}
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {string[]} selectorsA
|
|
3
|
+
* @param {string[]} selectorsB
|
|
4
|
+
* @return {boolean}
|
|
5
|
+
*/
|
|
6
|
+
export function sameVendor(selectorsA: string[], selectorsB: string[]): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* @param {string} selector
|
|
9
|
+
* @return {boolean}
|
|
10
|
+
*/
|
|
11
|
+
export function noVendor(selector: string): boolean;
|
|
12
|
+
export const pseudoElements: {
|
|
13
|
+
':active': string;
|
|
14
|
+
':after': string;
|
|
15
|
+
':any-link': string;
|
|
16
|
+
':before': string;
|
|
17
|
+
':checked': string;
|
|
18
|
+
':default': string;
|
|
19
|
+
':dir': string;
|
|
20
|
+
':disabled': string;
|
|
21
|
+
':empty': string;
|
|
22
|
+
':enabled': string;
|
|
23
|
+
':first-child': string;
|
|
24
|
+
':first-letter': string;
|
|
25
|
+
':first-line': string;
|
|
26
|
+
':first-of-type': string;
|
|
27
|
+
':focus': string;
|
|
28
|
+
':focus-within': string;
|
|
29
|
+
':focus-visible': string;
|
|
30
|
+
':has': string;
|
|
31
|
+
':hover': string;
|
|
32
|
+
':in-range': string;
|
|
33
|
+
':indeterminate': string;
|
|
34
|
+
':invalid': string;
|
|
35
|
+
':is': string;
|
|
36
|
+
':lang': string;
|
|
37
|
+
':last-child': string;
|
|
38
|
+
':last-of-type': string;
|
|
39
|
+
':link': string;
|
|
40
|
+
':matches': string;
|
|
41
|
+
':not': string;
|
|
42
|
+
':nth-child': string;
|
|
43
|
+
':nth-last-child': string;
|
|
44
|
+
':nth-last-of-type': string;
|
|
45
|
+
':nth-of-type': string;
|
|
46
|
+
':only-child': string;
|
|
47
|
+
':only-of-type': string;
|
|
48
|
+
':optional': string;
|
|
49
|
+
':out-of-range': string;
|
|
50
|
+
':placeholder-shown': string;
|
|
51
|
+
':required': string;
|
|
52
|
+
':root': string;
|
|
53
|
+
':target': string;
|
|
54
|
+
'::after': string;
|
|
55
|
+
'::backdrop': string;
|
|
56
|
+
'::before': string;
|
|
57
|
+
'::first-letter': string;
|
|
58
|
+
'::first-line': string;
|
|
59
|
+
'::marker': string;
|
|
60
|
+
'::placeholder': string;
|
|
61
|
+
'::selection': string;
|
|
62
|
+
':valid': string;
|
|
63
|
+
':visited': string;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* @param {string[]} selectors
|
|
67
|
+
* @param{string[]=} browsers
|
|
68
|
+
* @param{Map<string,boolean>=} compatibilityCache
|
|
69
|
+
* @return {boolean}
|
|
70
|
+
*/
|
|
71
|
+
export function ensureCompatibility(selectors: string[], browsers?: string[] | undefined, compatibilityCache?: Map<string, boolean> | undefined): boolean;
|