123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- 'use strict';
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.pseudoElements = undefined;
- exports.default = ensureCompatibility;
- var _caniuseApi = require('caniuse-api');
- var _postcssSelectorParser = require('postcss-selector-parser');
- var _postcssSelectorParser2 = _interopRequireDefault(_postcssSelectorParser);
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
- const simpleSelectorRe = /^#?[-._a-z0-9 ]+$/i;
- const cssSel2 = 'css-sel2';
- const cssSel3 = 'css-sel3';
- const cssGencontent = 'css-gencontent';
- const cssFirstLetter = 'css-first-letter';
- const cssFirstLine = 'css-first-line';
- const cssInOutOfRange = 'css-in-out-of-range';
- const pseudoElements = exports.pseudoElements = {
- ':active': cssSel2,
- ':after': cssGencontent,
- ':before': cssGencontent,
- ':checked': cssSel3,
- ':default': 'css-default-pseudo',
- ':dir': 'css-dir-pseudo',
- ':disabled': cssSel3,
- ':empty': cssSel3,
- ':enabled': cssSel3,
- ':first-child': cssSel2,
- ':first-letter': cssFirstLetter,
- ':first-line': cssFirstLine,
- ':first-of-type': cssSel3,
- ':focus': cssSel2,
- ':focus-within': 'css-focus-within',
- ':has': 'css-has',
- ':hover': cssSel2,
- ':in-range': cssInOutOfRange,
- ':indeterminate': 'css-indeterminate-pseudo',
- ':lang': cssSel2,
- ':last-child': cssSel3,
- ':last-of-type': cssSel3,
- ':matches': 'css-matches-pseudo',
- ':not': cssSel3,
- ':nth-child': cssSel3,
- ':nth-last-child': cssSel3,
- ':nth-last-of-type': cssSel3,
- ':nth-of-type': cssSel3,
- ':only-child': cssSel3,
- ':only-of-type': cssSel3,
- ':optional': 'css-optional-pseudo',
- ':out-of-range': cssInOutOfRange,
- ':placeholder-shown': 'css-placeholder-shown',
- ':root': cssSel3,
- ':target': cssSel3,
- '::after': cssGencontent,
- '::backdrop': 'dialog',
- '::before': cssGencontent,
- '::first-letter': cssFirstLetter,
- '::first-line': cssFirstLine,
- '::marker': 'css-marker-pseudo',
- '::placeholder': 'css-placeholder',
- '::selection': 'css-selection'
- };
- function isCssMixin(selector) {
- return selector[selector.length - 1] === ':';
- }
- const isSupportedCache = {};
- // Move to util in future
- function isSupportedCached(feature, browsers) {
- const key = JSON.stringify({ feature, browsers });
- let result = isSupportedCache[key];
- if (!result) {
- result = (0, _caniuseApi.isSupported)(feature, browsers);
- isSupportedCache[key] = result;
- }
- return result;
- }
- function ensureCompatibility(selectors, browsers, compatibilityCache) {
- // Should not merge mixins
- if (selectors.some(isCssMixin)) {
- return false;
- }
- return selectors.every(selector => {
- if (simpleSelectorRe.test(selector)) {
- return true;
- }
- if (compatibilityCache && selector in compatibilityCache) {
- return compatibilityCache[selector];
- }
- let compatible = true;
- (0, _postcssSelectorParser2.default)(ast => {
- ast.walk(node => {
- const { type, value } = node;
- if (type === 'pseudo') {
- const entry = pseudoElements[value];
- if (entry && compatible) {
- compatible = isSupportedCached(entry, browsers);
- }
- }
- if (type === 'combinator') {
- if (~value.indexOf('~')) {
- compatible = isSupportedCached(cssSel3, browsers);
- }
- if (~value.indexOf('>') || ~value.indexOf('+')) {
- compatible = isSupportedCached(cssSel2, browsers);
- }
- }
- if (type === 'attribute' && node.attribute) {
- // [foo]
- if (!node.operator) {
- compatible = isSupportedCached(cssSel2, browsers);
- }
- if (value) {
- // [foo="bar"], [foo~="bar"], [foo|="bar"]
- if (~['=', '~=', '|='].indexOf(node.operator)) {
- compatible = isSupportedCached(cssSel2, browsers);
- }
- // [foo^="bar"], [foo$="bar"], [foo*="bar"]
- if (~['^=', '$=', '*='].indexOf(node.operator)) {
- compatible = isSupportedCached(cssSel3, browsers);
- }
- }
- // [foo="bar" i]
- if (node.insensitive) {
- compatible = isSupportedCached('css-case-insensitive', browsers);
- }
- }
- if (!compatible) {
- // If this node was not compatible,
- // break out early from walking the rest
- return false;
- }
- });
- }).processSync(selector);
- if (compatibilityCache) {
- compatibilityCache[selector] = compatible;
- }
- return compatible;
- });
- }
|