@huantv/vue
Version:
Hippy Vue for TV
105 lines (93 loc) • 2.97 kB
JavaScript
/* eslint-disable import/prefer-default-export */
import parseSelector from './parser';
import {
RuleSet,
InvalidSelector,
UniversalSelector,
IdSelector,
TypeSelector,
ClassSelector,
PseudoClassSelector,
AttributeSelector,
SimpleSelectorSequence,
Selector,
} from './css-selectors';
import { getBeforeLoadStyle } from '../../../util';
function isDeclaration(node) {
return node.type === 'declaration';
}
function createDeclaration(beforeLoadStyle) {
return (decl) => {
const newDecl = beforeLoadStyle(decl);
if (process.env.NODE_ENV !== 'production') {
if (!newDecl) {
throw new Error('beforeLoadStyle hook must returns the processed style object');
}
}
return newDecl;
};
}
function createSimpleSelectorFromAst(ast) {
switch (ast.type) {
case '*': return new UniversalSelector();
case '#': return new IdSelector(ast.identifier);
case '': return new TypeSelector(ast.identifier.replace(/-/, '').toLowerCase());
case '.': return new ClassSelector(ast.identifier);
case ':': return new PseudoClassSelector(ast.identifier);
case '[]': return ast.test ? new AttributeSelector(ast.property, ast.test, ast.value) : new AttributeSelector(ast.property);
default: return null;
}
}
function createSimpleSelectorSequenceFromAst(ast) {
if (ast.length === 0) {
return new InvalidSelector(new Error('Empty simple selector sequence.'));
}
if (ast.length === 1) {
return createSimpleSelectorFromAst(ast[0]);
}
return new SimpleSelectorSequence(ast.map(createSimpleSelectorFromAst));
}
function createSelectorFromAst(ast) {
if (ast.length === 0) {
return new InvalidSelector(new Error('Empty selector.'));
}
if (ast.length === 1) {
return createSimpleSelectorSequenceFromAst(ast[0][0]);
}
const simpleSelectorSequences = [];
for (let i = 0; i < ast.length; i += 1) {
const simpleSelectorSequence = createSimpleSelectorSequenceFromAst(ast[i][0]);
const combinator = ast[i][1];
if (combinator) {
simpleSelectorSequence.combinator = combinator;
}
simpleSelectorSequences.push(simpleSelectorSequence);
}
return new Selector(simpleSelectorSequences);
}
function createSelector(sel) {
try {
const parsedSelector = parseSelector(sel);
if (!parsedSelector) {
return new InvalidSelector(new Error('Empty selector'));
}
return createSelectorFromAst(parsedSelector.value);
} catch (e) {
return new InvalidSelector(e);
}
}
function fromAstNodes(astRules = []) {
const beforeLoadStyle = getBeforeLoadStyle();
return astRules.map((rule) => {
const declarations = rule.declarations
.filter(isDeclaration)
.map(createDeclaration(beforeLoadStyle));
const selectors = rule.selectors.map(createSelector);
const ruleSet = new RuleSet(selectors, declarations);
return ruleSet;
});
}
export { SelectorsMap } from './css-selectors-match';
export {
fromAstNodes,
};