UNPKG

@huantv/vue

Version:
224 lines (208 loc) 5.15 kB
/* eslint-disable consistent-return */ /* eslint-disable import/no-mutable-exports */ /* eslint-disable import/prefer-default-export */ /* eslint-disable no-else-return */ /* eslint-disable no-param-reassign */ // Check the Regexp is support sticky flag. const REGEXP_SUPPORTING_STICKY_FLAG = (() => { try { return !!new RegExp('foo', 'y'); } catch (err) { return false; } })(); // Regexp strings const REGEXP_STRINGS = { whiteSpaceRegEx: '\\s*', universalSelectorRegEx: '\\*', simpleIdentifierSelectorRegEx: '(#|\\.|:|\\b)([_-\\w][_-\\w\\d]*)', attributeSelectorRegEx: '\\[\\s*([_-\\w][_-\\w\\d]*)\\s*(?:(=|\\^=|\\$=|\\*=|\\~=|\\|=)\\s*(?:([_-\\w][_-\\w\\d]*)|"((?:[^\\\\"]|\\\\(?:"|n|r|f|\\\\|0-9a-f))*)"|\'((?:[^\\\\\']|\\\\(?:\'|n|r|f|\\\\|0-9a-f))*)\')\\s*)?\\]', combinatorRegEx: '\\s*(\\+|~|>)?\\s*', }; // RegExp instance cache const REGEXPS = {}; // Execute the RegExp function execRegExp(regexpKey, text, start) { let flags = ''; // Check the sticky flag supporting, and cache the RegExp instance. if (REGEXP_SUPPORTING_STICKY_FLAG) { flags = 'gy'; } if (!REGEXPS[regexpKey]) { REGEXPS[regexpKey] = new RegExp(REGEXP_STRINGS[regexpKey], flags); } const regexp = REGEXPS[regexpKey]; let result; // Fallback to split the text if sticky is not supported. if (REGEXP_SUPPORTING_STICKY_FLAG) { regexp.lastIndex = start; result = regexp.exec(text); } else { text = text.slice(start, text.length); result = regexp.exec(text); if (!result) { return { result: null, regexp, }; } // add start index to prevent infinite loop caused by class name like .aa_bb.aa regexp.lastIndex = start + result[0].length; } return { result, regexp, }; } function parseUniversalSelector(text, start) { const { result, regexp } = execRegExp('universalSelectorRegEx', text, start); if (!result) { return null; } const end = regexp.lastIndex; return { value: { type: '*', }, start, end, }; } function parseSimpleIdentifierSelector(text, start) { const { result, regexp } = execRegExp('simpleIdentifierSelectorRegEx', text, start); if (!result) { return null; } const end = regexp.lastIndex; const type = result[1]; const identifier = result[2]; const value = { type, identifier }; return { value, start, end, }; } function parseAttributeSelector(text, start) { const { result, regexp } = execRegExp('attributeSelectorRegEx', text, start); if (!result) { return null; } const end = regexp.lastIndex; const property = result[1]; if (result[2]) { const test = result[2]; const value = result[3] || result[4] || result[5]; return { value: { type: '[]', property, test, value, }, start, end, }; } return { value: { type: '[]', property, }, start, end, }; } function parseSimpleSelector(text, start) { return parseUniversalSelector(text, start) || parseSimpleIdentifierSelector(text, start) || parseAttributeSelector(text, start); } function parseSimpleSelectorSequence(text, start) { let simpleSelector = parseSimpleSelector(text, start); if (!simpleSelector) { return null; } let { end } = simpleSelector; const value = []; while (simpleSelector) { value.push(simpleSelector.value); ({ end } = simpleSelector); simpleSelector = parseSimpleSelector(text, end); } return { start, end, value, }; } function parseCombinator(text, start) { const { result, regexp } = execRegExp('combinatorRegEx', text, start); if (!result) { return null; } let end; if (REGEXP_SUPPORTING_STICKY_FLAG) { end = regexp.lastIndex; } else { end = start; } const value = result[1] || ' '; return { start, end, value, }; } function parseSelector(text, start) { let end = start; const { result, regexp } = execRegExp('whiteSpaceRegEx', text, start); if (result) { end = regexp.lastIndex; } const value = []; let combinator; let expectSimpleSelector = true; let pair = []; let cssText; if (REGEXP_SUPPORTING_STICKY_FLAG) { cssText = [text]; } else { cssText = text.split(' '); } cssText.forEach((text) => { if (!REGEXP_SUPPORTING_STICKY_FLAG) { if (text === '') { return; } end = 0; } do { const simpleSelectorSequence = parseSimpleSelectorSequence(text, end); if (!simpleSelectorSequence) { if (expectSimpleSelector) { return null; } else { break; } } ({ end } = simpleSelectorSequence); if (combinator) { pair[1] = combinator.value; } pair = [simpleSelectorSequence.value, undefined]; value.push(pair); combinator = parseCombinator(text, end); if (combinator) { ({ end } = combinator); } expectSimpleSelector = combinator && combinator.value !== ' '; } while (combinator); }); return { start, end, value, }; } export default parseSelector;