You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							155 lines
						
					
					
						
							5.0 KiB
						
					
					
				
			
		
		
	
	
							155 lines
						
					
					
						
							5.0 KiB
						
					
					
				'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; | 
						|
    }); | 
						|
} |