postcss-merge-rules 5.0.2 → 5.0.6

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 CHANGED
@@ -1,17 +1,12 @@
1
1
  {
2
2
  "name": "postcss-merge-rules",
3
- "version": "5.0.2",
3
+ "version": "5.0.6",
4
4
  "description": "Merge CSS rules with PostCSS.",
5
- "main": "dist/index.js",
5
+ "main": "src/index.js",
6
6
  "files": [
7
7
  "LICENSE-MIT",
8
- "dist"
8
+ "src"
9
9
  ],
10
- "scripts": {
11
- "prebuild": "del-cli dist",
12
- "build": "cross-env BABEL_ENV=publish babel src --config-file ../../babel.config.json --out-dir dist --ignore \"**/__tests__/\"",
13
- "prepublish": "yarn build"
14
- },
15
10
  "keywords": [
16
11
  "css",
17
12
  "optimise",
@@ -29,9 +24,8 @@
29
24
  "dependencies": {
30
25
  "browserslist": "^4.16.6",
31
26
  "caniuse-api": "^3.0.0",
32
- "cssnano-utils": "^2.0.1",
33
- "postcss-selector-parser": "^6.0.5",
34
- "vendors": "^1.0.3"
27
+ "cssnano-utils": "^3.0.2",
28
+ "postcss-selector-parser": "^6.0.5"
35
29
  },
36
30
  "bugs": {
37
31
  "url": "https://github.com/cssnano/cssnano/issues"
@@ -40,10 +34,11 @@
40
34
  "node": "^10 || ^12 || >=14.0"
41
35
  },
42
36
  "devDependencies": {
43
- "postcss": "^8.2.15"
37
+ "postcss": "^8.2.15",
38
+ "postcss-discard-comments": "^5.0.3"
44
39
  },
45
40
  "peerDependencies": {
46
41
  "postcss": "^8.2.15"
47
42
  },
48
- "gitHead": "9b3c54fd94f3e2bdb503d1e21f171d7fe02f33ca"
49
- }
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"
44
+ }
@@ -1,17 +1,11 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
-
8
- var _browserslist = _interopRequireDefault(require("browserslist"));
9
-
10
- var _cssnanoUtils = require("cssnano-utils");
11
-
12
- var _ensureCompatibility = require("./lib/ensureCompatibility");
13
-
14
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
1
+ 'use strict';
2
+ const browserslist = require('browserslist');
3
+ const { sameParent } = require('cssnano-utils');
4
+ const {
5
+ ensureCompatibility,
6
+ sameVendor,
7
+ noVendor,
8
+ } = require('./lib/ensureCompatibility');
15
9
 
16
10
  /**
17
11
  * @param {postcss.Declaration} a
@@ -19,18 +13,20 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
19
13
  * @return {boolean}
20
14
  */
21
15
  function declarationIsEqual(a, b) {
22
- return a.important === b.important && a.prop === b.prop && a.value === b.value;
16
+ return (
17
+ a.important === b.important && a.prop === b.prop && a.value === b.value
18
+ );
23
19
  }
20
+
24
21
  /**
25
22
  * @param {postcss.Declaration[]} array
26
23
  * @param {postcss.Declaration} decl
27
24
  * @return {number}
28
25
  */
29
-
30
-
31
26
  function indexOfDeclaration(array, decl) {
32
- return array.findIndex(d => declarationIsEqual(d, decl));
27
+ return array.findIndex((d) => declarationIsEqual(d, decl));
33
28
  }
29
+
34
30
  /**
35
31
  * Returns filtered array of matched or unmatched declarations
36
32
  * @param {postcss.Declaration[]} a
@@ -38,189 +34,167 @@ function indexOfDeclaration(array, decl) {
38
34
  * @param {boolean} [not=false]
39
35
  * @return {postcss.Declaration[]}
40
36
  */
41
-
42
-
43
37
  function intersect(a, b, not) {
44
- return a.filter(c => {
38
+ return a.filter((c) => {
45
39
  const index = ~indexOfDeclaration(b, c);
46
40
  return not ? !index : index;
47
41
  });
48
42
  }
43
+
49
44
  /**
50
45
  * @param {postcss.Declaration[]} a
51
46
  * @param {postcss.Declaration[]} b
52
47
  * @return {boolean}
53
48
  */
54
-
55
-
56
49
  function sameDeclarationsAndOrder(a, b) {
57
50
  if (a.length !== b.length) {
58
51
  return false;
59
52
  }
60
-
61
53
  return a.every((d, index) => declarationIsEqual(d, b[index]));
62
54
  }
55
+
63
56
  /**
64
57
  * @param {postcss.Rule} ruleA
65
58
  * @param {postcss.Rule} ruleB
66
59
  * @param {string[]=} browsers
67
- * @param {Object.<string, boolean>=} compatibilityCache
60
+ * @param {Map<string, boolean>=} compatibilityCache
68
61
  * @return {boolean}
69
62
  */
70
-
71
-
72
63
  function canMerge(ruleA, ruleB, browsers, compatibilityCache) {
73
64
  const a = ruleA.selectors;
74
65
  const b = ruleB.selectors;
66
+
75
67
  const selectors = a.concat(b);
76
68
 
77
- if (!(0, _ensureCompatibility.ensureCompatibility)(selectors, browsers, compatibilityCache)) {
69
+ if (!ensureCompatibility(selectors, browsers, compatibilityCache)) {
78
70
  return false;
79
71
  }
80
72
 
81
- const parent = (0, _cssnanoUtils.sameParent)(ruleA, ruleB);
82
- const {
83
- name
84
- } = ruleA.parent;
85
-
86
- if (parent && name && ~name.indexOf('keyframes')) {
73
+ const parent = sameParent(ruleA, ruleB);
74
+ const { name } = ruleA.parent;
75
+ if (parent && name && name.includes('keyframes')) {
87
76
  return false;
88
77
  }
89
-
90
- return parent && (selectors.every(_ensureCompatibility.noVendor) || (0, _ensureCompatibility.sameVendor)(a, b));
78
+ return parent && (selectors.every(noVendor) || sameVendor(a, b));
91
79
  }
80
+
92
81
  /**
93
82
  * @param {postcss.Rule} rule
94
83
  * @return {postcss.Declaration[]}
95
84
  */
96
-
97
-
98
85
  function getDecls(rule) {
99
- return rule.nodes.filter(node => node.type === 'decl');
86
+ return rule.nodes.filter((node) => node.type === 'decl');
100
87
  }
101
88
 
102
- const joinSelectors = (...rules) => rules.map(s => s.selector).join();
89
+ const joinSelectors = (...rules) => rules.map((s) => s.selector).join();
103
90
 
104
91
  function ruleLength(...rules) {
105
- return rules.map(r => r.nodes.length ? String(r) : '').join('').length;
92
+ return rules.map((r) => (r.nodes.length ? String(r) : '')).join('').length;
106
93
  }
94
+
107
95
  /**
108
96
  * @param {string} prop
109
97
  * @return {{prefix: string, base:string, rest:string[]}}
110
98
  */
111
-
112
-
113
99
  function splitProp(prop) {
114
100
  // Treat vendor prefixed properties as if they were unprefixed;
115
101
  // moving them when combined with non-prefixed properties can
116
102
  // cause issues. e.g. moving -webkit-background-clip when there
117
103
  // is a background shorthand definition.
118
- const parts = prop.split('-');
119
104
 
105
+ const parts = prop.split('-');
120
106
  if (prop[0] !== '-') {
121
107
  return {
122
108
  prefix: '',
123
109
  base: parts[0],
124
- rest: parts.slice(1)
110
+ rest: parts.slice(1),
125
111
  };
126
- } // Don't split css variables
127
-
128
-
112
+ }
113
+ // Don't split css variables
129
114
  if (prop[1] === '-') {
130
115
  return {
131
116
  prefix: null,
132
117
  base: null,
133
- rest: [prop]
118
+ rest: [prop],
134
119
  };
135
- } // Found prefix
136
-
137
-
120
+ }
121
+ // Found prefix
138
122
  return {
139
123
  prefix: parts[1],
140
124
  base: parts[2],
141
- rest: parts.slice(3)
125
+ rest: parts.slice(3),
142
126
  };
143
127
  }
128
+
144
129
  /**
145
130
  * @param {string} propA
146
131
  * @param {string} propB
147
132
  */
148
-
149
-
150
133
  function isConflictingProp(propA, propB) {
151
134
  if (propA === propB) {
152
135
  // Same specificity
153
136
  return true;
154
137
  }
155
-
156
138
  const a = splitProp(propA);
157
- const b = splitProp(propB); // Don't resort css variables
158
-
139
+ const b = splitProp(propB);
140
+ // Don't resort css variables
159
141
  if (!a.base && !b.base) {
160
142
  return true;
161
- } // Different base;
162
-
163
-
143
+ }
144
+ // Different base;
164
145
  if (a.base !== b.base) {
165
146
  return false;
166
- } // Conflict if rest-count mismatches
167
-
168
-
147
+ }
148
+ // Conflict if rest-count mismatches
169
149
  if (a.rest.length !== b.rest.length) {
170
150
  return true;
171
- } // Conflict if rest parameters are equal (same but unprefixed)
172
-
151
+ }
173
152
 
153
+ // Conflict if rest parameters are equal (same but unprefixed)
174
154
  return a.rest.every((s, index) => b.rest[index] === s);
175
155
  }
156
+
176
157
  /**
177
158
  * @param {postcss.Rule} first
178
159
  * @param {postcss.Rule} second
179
160
  * @return {boolean} merged
180
161
  */
181
-
182
-
183
162
  function mergeParents(first, second) {
184
163
  // Null check for detached rules
185
164
  if (!first.parent || !second.parent) {
186
165
  return false;
187
- } // Check if parents share node
188
-
166
+ }
189
167
 
168
+ // Check if parents share node
190
169
  if (first.parent === second.parent) {
191
170
  return false;
192
- } // sameParent() already called by canMerge()
171
+ }
193
172
 
173
+ // sameParent() already called by canMerge()
194
174
 
195
175
  second.remove();
196
176
  first.parent.append(second);
197
177
  return true;
198
178
  }
179
+
199
180
  /**
200
181
  * @param {postcss.Rule} first
201
182
  * @param {postcss.Rule} second
202
183
  * @return {postcss.Rule} mergedRule
203
184
  */
204
-
205
-
206
185
  function partialMerge(first, second) {
207
186
  let intersection = intersect(getDecls(first), getDecls(second));
208
-
209
187
  if (!intersection.length) {
210
188
  return second;
211
189
  }
212
-
213
190
  let nextRule = second.next();
214
-
215
191
  if (!nextRule) {
216
192
  // Grab next cousin
217
193
  const parentSibling = second.parent.next();
218
194
  nextRule = parentSibling && parentSibling.nodes && parentSibling.nodes[0];
219
195
  }
220
-
221
196
  if (nextRule && nextRule.type === 'rule' && canMerge(second, nextRule)) {
222
197
  let nextIntersection = intersect(getDecls(second), getDecls(nextRule));
223
-
224
198
  if (nextIntersection.length > intersection.length) {
225
199
  mergeParents(second, nextRule);
226
200
  first = second;
@@ -229,45 +203,52 @@ function partialMerge(first, second) {
229
203
  }
230
204
  }
231
205
 
232
- const firstDecls = getDecls(first); // Filter out intersections with later conflicts in First
206
+ const firstDecls = getDecls(first);
233
207
 
208
+ // Filter out intersections with later conflicts in First
234
209
  intersection = intersection.filter((decl, intersectIndex) => {
235
210
  const indexOfDecl = indexOfDeclaration(firstDecls, decl);
236
- const nextConflictInFirst = firstDecls.slice(indexOfDecl + 1).filter(d => isConflictingProp(d.prop, decl.prop));
237
-
211
+ const nextConflictInFirst = firstDecls
212
+ .slice(indexOfDecl + 1)
213
+ .filter((d) => isConflictingProp(d.prop, decl.prop));
238
214
  if (!nextConflictInFirst.length) {
239
215
  return true;
240
216
  }
241
-
242
- const nextConflictInIntersection = intersection.slice(intersectIndex + 1).filter(d => isConflictingProp(d.prop, decl.prop));
243
-
217
+ const nextConflictInIntersection = intersection
218
+ .slice(intersectIndex + 1)
219
+ .filter((d) => isConflictingProp(d.prop, decl.prop));
244
220
  if (!nextConflictInIntersection.length) {
245
221
  return false;
246
222
  }
247
-
248
223
  if (nextConflictInFirst.length !== nextConflictInIntersection.length) {
249
224
  return false;
250
225
  }
226
+ return nextConflictInFirst.every((d, index) =>
227
+ declarationIsEqual(d, nextConflictInIntersection[index])
228
+ );
229
+ });
251
230
 
252
- return nextConflictInFirst.every((d, index) => declarationIsEqual(d, nextConflictInIntersection[index]));
253
- }); // Filter out intersections with previous conflicts in Second
254
-
231
+ // Filter out intersections with previous conflicts in Second
255
232
  const secondDecls = getDecls(second);
256
- intersection = intersection.filter(decl => {
257
- const nextConflictIndex = secondDecls.findIndex(d => isConflictingProp(d.prop, decl.prop));
258
-
233
+ intersection = intersection.filter((decl) => {
234
+ const nextConflictIndex = secondDecls.findIndex((d) =>
235
+ isConflictingProp(d.prop, decl.prop)
236
+ );
259
237
  if (nextConflictIndex === -1) {
260
238
  return false;
261
239
  }
262
-
263
240
  if (!declarationIsEqual(secondDecls[nextConflictIndex], decl)) {
264
241
  return false;
265
242
  }
266
-
267
- if (decl.prop.toLowerCase() !== 'direction' && decl.prop.toLowerCase() !== 'unicode-bidi' && secondDecls.some(declaration => declaration.prop.toLowerCase() === 'all')) {
243
+ if (
244
+ decl.prop.toLowerCase() !== 'direction' &&
245
+ decl.prop.toLowerCase() !== 'unicode-bidi' &&
246
+ secondDecls.some(
247
+ (declaration) => declaration.prop.toLowerCase() === 'all'
248
+ )
249
+ ) {
268
250
  return false;
269
251
  }
270
-
271
252
  secondDecls.splice(nextConflictIndex, 1);
272
253
  return true;
273
254
  });
@@ -280,56 +261,55 @@ function partialMerge(first, second) {
280
261
  const receivingBlock = second.clone();
281
262
  receivingBlock.selector = joinSelectors(first, second);
282
263
  receivingBlock.nodes = [];
264
+
283
265
  second.parent.insertBefore(second, receivingBlock);
266
+
284
267
  const firstClone = first.clone();
285
268
  const secondClone = second.clone();
269
+
286
270
  /**
287
271
  * @param {function(postcss.Declaration):void} callback
288
272
  * @return {function(postcss.Declaration)}
289
273
  */
290
-
291
274
  function moveDecl(callback) {
292
- return decl => {
275
+ return (decl) => {
293
276
  if (~indexOfDeclaration(intersection, decl)) {
294
277
  callback.call(this, decl);
295
278
  }
296
279
  };
297
280
  }
298
-
299
- firstClone.walkDecls(moveDecl(decl => {
300
- decl.remove();
301
- receivingBlock.append(decl);
302
- }));
303
- secondClone.walkDecls(moveDecl(decl => decl.remove()));
281
+ firstClone.walkDecls(
282
+ moveDecl((decl) => {
283
+ decl.remove();
284
+ receivingBlock.append(decl);
285
+ })
286
+ );
287
+ secondClone.walkDecls(moveDecl((decl) => decl.remove()));
304
288
  const merged = ruleLength(firstClone, receivingBlock, secondClone);
305
289
  const original = ruleLength(first, second);
306
-
307
290
  if (merged < original) {
308
291
  first.replaceWith(firstClone);
309
292
  second.replaceWith(secondClone);
310
- [firstClone, receivingBlock, secondClone].forEach(r => {
293
+ [firstClone, receivingBlock, secondClone].forEach((r) => {
311
294
  if (!r.nodes.length) {
312
295
  r.remove();
313
296
  }
314
297
  });
315
-
316
298
  if (!secondClone.parent) {
317
299
  return receivingBlock;
318
300
  }
319
-
320
301
  return secondClone;
321
302
  } else {
322
303
  receivingBlock.remove();
323
304
  return second;
324
305
  }
325
306
  }
307
+
326
308
  /**
327
309
  * @param {string[]} browsers
328
- * @param {Object.<string, boolean>} compatibilityCache
310
+ * @param {Map<string, boolean>} compatibilityCache
329
311
  * @return {function(postcss.Rule)}
330
312
  */
331
-
332
-
333
313
  function selectorMerger(browsers, compatibilityCache) {
334
314
  /** @type {postcss.Rule} */
335
315
  let cache = null;
@@ -339,43 +319,40 @@ function selectorMerger(browsers, compatibilityCache) {
339
319
  if (!cache || !canMerge(rule, cache, browsers, compatibilityCache)) {
340
320
  cache = rule;
341
321
  return;
342
- } // Ensure that we don't deduplicate the same rule; this is sometimes
322
+ }
323
+ // Ensure that we don't deduplicate the same rule; this is sometimes
343
324
  // caused by a partial merge
344
-
345
-
346
325
  if (cache === rule) {
347
326
  cache = rule;
348
327
  return;
349
- } // Parents merge: check if the rules have same parents, but not same parent nodes
328
+ }
350
329
 
330
+ // Parents merge: check if the rules have same parents, but not same parent nodes
331
+ mergeParents(cache, rule);
351
332
 
352
- mergeParents(cache, rule); // Merge when declarations are exactly equal
333
+ // Merge when declarations are exactly equal
353
334
  // e.g. h1 { color: red } h2 { color: red }
354
-
355
335
  if (sameDeclarationsAndOrder(getDecls(rule), getDecls(cache))) {
356
336
  rule.selector = joinSelectors(cache, rule);
357
337
  cache.remove();
358
338
  cache = rule;
359
339
  return;
360
- } // Merge when both selectors are exactly equal
340
+ }
341
+ // Merge when both selectors are exactly equal
361
342
  // e.g. a { color: blue } a { font-weight: bold }
362
-
363
-
364
343
  if (cache.selector === rule.selector) {
365
344
  const cached = getDecls(cache);
366
- rule.walk(decl => {
345
+ rule.walk((decl) => {
367
346
  if (~indexOfDeclaration(cached, decl)) {
368
347
  return decl.remove();
369
348
  }
370
-
371
349
  cache.append(decl);
372
350
  });
373
351
  rule.remove();
374
352
  return;
375
- } // Partial merge: check if the rule contains a subset of the last; if
353
+ }
354
+ // Partial merge: check if the rule contains a subset of the last; if
376
355
  // so create a joined selector with the subset, if smaller.
377
-
378
-
379
356
  cache = partialMerge(cache, rule);
380
357
  };
381
358
  }
@@ -386,24 +363,21 @@ function pluginCreator() {
386
363
 
387
364
  prepare(result) {
388
365
  const resultOpts = result.opts || {};
389
- const browsers = (0, _browserslist.default)(null, {
366
+ const browsers = browserslist(null, {
390
367
  stats: resultOpts.stats,
391
368
  path: __dirname,
392
- env: resultOpts.env
369
+ env: resultOpts.env,
393
370
  });
394
- const compatibilityCache = {};
371
+
372
+ const compatibilityCache = new Map();
395
373
  return {
396
374
  OnceExit(css) {
397
375
  css.walkRules(selectorMerger(browsers, compatibilityCache));
398
- }
399
-
376
+ },
400
377
  };
401
- }
402
-
378
+ },
403
379
  };
404
380
  }
405
381
 
406
382
  pluginCreator.postcss = true;
407
- var _default = pluginCreator;
408
- exports.default = _default;
409
- module.exports = exports.default;
383
+ module.exports = pluginCreator;
@@ -1,23 +1,9 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.filterPrefixes = filterPrefixes;
7
- exports.sameVendor = sameVendor;
8
- exports.noVendor = noVendor;
9
- exports.ensureCompatibility = ensureCompatibility;
10
- exports.pseudoElements = void 0;
11
-
12
- var _caniuseApi = require("caniuse-api");
13
-
14
- var _postcssSelectorParser = _interopRequireDefault(require("postcss-selector-parser"));
15
-
16
- var _vendors = _interopRequireDefault(require("vendors"));
17
-
18
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
1
+ 'use strict';
2
+ const { isSupported } = require('caniuse-api');
3
+ const selectorParser = require('postcss-selector-parser');
19
4
 
20
5
  const simpleSelectorRe = /^#?[-._a-z0-9 ]+$/i;
6
+
21
7
  const cssSel2 = 'css-sel2';
22
8
  const cssSel3 = 'css-sel3';
23
9
  const cssGencontent = 'css-gencontent';
@@ -25,38 +11,38 @@ const cssFirstLetter = 'css-first-letter';
25
11
  const cssFirstLine = 'css-first-line';
26
12
  const cssInOutOfRange = 'css-in-out-of-range';
27
13
  const formValidation = 'form-validation';
28
- /** @type {string[]} */
29
14
 
30
- const prefixes = _vendors.default.map(v => `-${v}-`);
15
+ const vendorPrefix =
16
+ /-(ah|apple|atsc|epub|hp|khtml|moz|ms|o|rim|ro|tc|wap|webkit|xv)-/;
17
+
31
18
  /**
32
19
  * @param {string} selector
33
20
  * @return {string[]}
34
21
  */
35
-
36
-
37
22
  function filterPrefixes(selector) {
38
- return prefixes.filter(prefix => selector.indexOf(prefix) !== -1);
39
- } // Internet Explorer use :-ms-input-placeholder.
40
- // Microsoft Edge use ::-ms-input-placeholder.
41
-
23
+ return selector.match(vendorPrefix);
24
+ }
42
25
 
43
- const findMsInputPlaceholder = selector => ~selector.search(/-ms-input-placeholder/i);
26
+ // Internet Explorer use :-ms-input-placeholder.
27
+ // Microsoft Edge use ::-ms-input-placeholder.
28
+ const findMsInputPlaceholder = (selector) =>
29
+ ~selector.search(/-ms-input-placeholder/i);
44
30
 
45
31
  function sameVendor(selectorsA, selectorsB) {
46
- let same = selectors => selectors.map(filterPrefixes).join();
47
-
48
- let findMsVendor = selectors => selectors.find(findMsInputPlaceholder);
49
-
50
- return same(selectorsA) === same(selectorsB) && !(findMsVendor(selectorsA) && findMsVendor(selectorsB));
32
+ let same = (selectors) => selectors.map(filterPrefixes).join();
33
+ let findMsVendor = (selectors) => selectors.find(findMsInputPlaceholder);
34
+ return (
35
+ same(selectorsA) === same(selectorsB) &&
36
+ !(findMsVendor(selectorsA) && findMsVendor(selectorsB))
37
+ );
51
38
  }
39
+
52
40
  /**
53
41
  * @param {string} selector
54
42
  * @return {boolean}
55
43
  */
56
-
57
-
58
44
  function noVendor(selector) {
59
- return !filterPrefixes(selector).length;
45
+ return !vendorPrefix.test(selector);
60
46
  }
61
47
 
62
48
  const pseudoElements = {
@@ -110,9 +96,8 @@ const pseudoElements = {
110
96
  '::placeholder': 'css-placeholder',
111
97
  '::selection': 'css-selection',
112
98
  ':valid': formValidation,
113
- ':visited': cssSel2
99
+ ':visited': cssSel2,
114
100
  };
115
- exports.pseudoElements = pseudoElements;
116
101
 
117
102
  function isCssMixin(selector) {
118
103
  return selector[selector.length - 1] === ':';
@@ -122,18 +107,16 @@ function isHostPseudoClass(selector) {
122
107
  return selector.includes(':host');
123
108
  }
124
109
 
125
- const isSupportedCache = {}; // Move to util in future
110
+ const isSupportedCache = new Map();
126
111
 
112
+ // Move to util in future
127
113
  function isSupportedCached(feature, browsers) {
128
- const key = JSON.stringify({
129
- feature,
130
- browsers
131
- });
132
- let result = isSupportedCache[key];
114
+ const key = JSON.stringify({ feature, browsers });
115
+ let result = isSupportedCache.get(key);
133
116
 
134
117
  if (!result) {
135
- result = (0, _caniuseApi.isSupported)(feature, browsers);
136
- isSupportedCache[key] = result;
118
+ result = isSupported(feature, browsers);
119
+ isSupportedCache.set(key, result);
137
120
  }
138
121
 
139
122
  return result;
@@ -143,52 +126,40 @@ function ensureCompatibility(selectors, browsers, compatibilityCache) {
143
126
  // Should not merge mixins
144
127
  if (selectors.some(isCssMixin)) {
145
128
  return false;
146
- } // Should not merge :host selector https://github.com/angular/angular-cli/issues/18672
147
-
129
+ }
148
130
 
131
+ // Should not merge :host selector https://github.com/angular/angular-cli/issues/18672
149
132
  if (selectors.some(isHostPseudoClass)) {
150
133
  return false;
151
134
  }
152
-
153
- return selectors.every(selector => {
135
+ return selectors.every((selector) => {
154
136
  if (simpleSelectorRe.test(selector)) {
155
137
  return true;
156
138
  }
157
-
158
- if (compatibilityCache && selector in compatibilityCache) {
159
- return compatibilityCache[selector];
139
+ if (compatibilityCache && compatibilityCache.has(selector)) {
140
+ return compatibilityCache.get(selector);
160
141
  }
161
-
162
142
  let compatible = true;
163
- (0, _postcssSelectorParser.default)(ast => {
164
- ast.walk(node => {
165
- const {
166
- type,
167
- value
168
- } = node;
169
-
143
+ selectorParser((ast) => {
144
+ ast.walk((node) => {
145
+ const { type, value } = node;
170
146
  if (type === 'pseudo') {
171
147
  const entry = pseudoElements[value];
172
-
173
148
  if (!entry && noVendor(value)) {
174
149
  compatible = false;
175
150
  }
176
-
177
151
  if (entry && compatible) {
178
152
  compatible = isSupportedCached(entry, browsers);
179
153
  }
180
154
  }
181
-
182
155
  if (type === 'combinator') {
183
- if (~value.indexOf('~')) {
156
+ if (value.includes('~')) {
184
157
  compatible = isSupportedCached(cssSel3, browsers);
185
158
  }
186
-
187
- if (~value.indexOf('>') || ~value.indexOf('+')) {
159
+ if (value.includes('>') || value.includes('+')) {
188
160
  compatible = isSupportedCached(cssSel2, browsers);
189
161
  }
190
162
  }
191
-
192
163
  if (type === 'attribute' && node.attribute) {
193
164
  // [foo]
194
165
  if (!node.operator) {
@@ -197,22 +168,20 @@ function ensureCompatibility(selectors, browsers, compatibilityCache) {
197
168
 
198
169
  if (value) {
199
170
  // [foo="bar"], [foo~="bar"], [foo|="bar"]
200
- if (~['=', '~=', '|='].indexOf(node.operator)) {
171
+ if (['=', '~=', '|='].includes(node.operator)) {
201
172
  compatible = isSupportedCached(cssSel2, browsers);
202
- } // [foo^="bar"], [foo$="bar"], [foo*="bar"]
203
-
204
-
205
- if (~['^=', '$=', '*='].indexOf(node.operator)) {
173
+ }
174
+ // [foo^="bar"], [foo$="bar"], [foo*="bar"]
175
+ if (['^=', '$=', '*='].includes(node.operator)) {
206
176
  compatible = isSupportedCached(cssSel3, browsers);
207
177
  }
208
- } // [foo="bar" i]
209
-
178
+ }
210
179
 
180
+ // [foo="bar" i]
211
181
  if (node.insensitive) {
212
182
  compatible = isSupportedCached('css-case-insensitive', browsers);
213
183
  }
214
184
  }
215
-
216
185
  if (!compatible) {
217
186
  // If this node was not compatible,
218
187
  // break out early from walking the rest
@@ -220,11 +189,11 @@ function ensureCompatibility(selectors, browsers, compatibilityCache) {
220
189
  }
221
190
  });
222
191
  }).processSync(selector);
223
-
224
192
  if (compatibilityCache) {
225
- compatibilityCache[selector] = compatible;
193
+ compatibilityCache.set(selector, compatible);
226
194
  }
227
-
228
195
  return compatible;
229
196
  });
230
- }
197
+ }
198
+
199
+ module.exports = { sameVendor, noVendor, pseudoElements, ensureCompatibility };