cssprima
Version:
The most standards compliant CSS parser.
257 lines (208 loc) • 7.37 kB
JavaScript
;
var Types = require('../Types.js'),
Algorithms = require('./Algorithms.js'),
Tokenizer = require('../Tokenizer/Tokenizer.js');
// 5.3: Parser Entry Points
// ------------------------
// 5.3.1: Parse a stylesheet
// -------------------------
exports.parseStylesheet = function (input) {
var tokenizer, stylesheet, toplevel, returnValue;
tokenizer = new Tokenizer(input);
// Create a new stylesheet.
stylesheet = {
type: Types.STYLESHEET
};
// Consume a list of rules from the stream of tokens,
// with the top-level flag set.
toplevel = true;
returnValue = Algorithms.consumeRules(tokenizer, toplevel);
// Assign the returned value to the stylesheet’s value.
stylesheet.value = returnValue;
// Return the stylesheet.
return stylesheet;
};
// 5.3.2: Parse a list of rules
// ----------------------------
exports.parseRules = function (input) {
var tokenizer, returnList;
tokenizer = new Tokenizer(input);
// Consume a list of rules from the stream of tokens,
// with the top-level flag unset.
returnList = Algorithms.consumeRules(tokenizer, false);
// Return the returned list.
return returnList;
};
// 5.3.3: Parse a rule
// -------------------
exports.parseRule = function (input) {
var tokenizer, rule;
tokenizer = new Tokenizer(input);
// While the next input token is a <whitespace-token>,
// consume the next input token.
while (tokenizer.getNextToken().type === Types.WHITESPACE) {
tokenizer.consumeNextToken();
}
switch (tokenizer.getNextToken().type) {
case Types.EOF:
// If the next input token is an <EOF-token>, return a syntax error.
return {
type: Types.ERROR,
value: 'empty'
};
case Types.AT_KEYWORD:
// Otherwise, if the next input token is an <at-keyword-token>,
// consume an at-rule, and let rule be the return value.
rule = Algorithms.consumeAtRule(tokenizer);
break;
default:
// Otherwise, consume a qualified rule and let rule be the return value.
rule = Algorithms.consumeQualifiedRule(tokenizer);
// If nothing was returned, return a syntax error.
if (!rule) {
return {
type: Types.ERROR,
value: 'invalid'
};
}
}
// While the next input token is a <whitespace-token>,
// consume the next input token.
while (tokenizer.getNextToken().type === Types.WHITESPACE) {
tokenizer.consumeNextToken();
}
// If the next input token is an <EOF-token>, return rule.
if (tokenizer.getNextToken().type === Types.EOF) {
return rule;
}
// Otherwise, return a syntax error.
return {
type: Types.ERROR,
value: 'extra-input'
};
};
// 5.3.4: Parse a declaration
// --------------------------
exports.parseDeclaration = function (input) {
var tokenizer, returnValue;
tokenizer = new Tokenizer(input);
// While the next input token is a <whitespace-token>,
// consume the next input token.
while (tokenizer.getNextToken().type === Types.WHITESPACE) {
tokenizer.consumeNextToken();
}
if (tokenizer.getNextToken().type === Types.EOF) {
return {
type: Types.ERROR,
value: 'empty'
};
}
// If the next input token is not an <ident-token>, return a syntax error.
if (tokenizer.getNextToken().type !== Types.IDENT) {
return {
type: Types.ERROR,
value: 'invalid'
};
}
// Consume a declaration.
returnValue = Algorithms.consumeDeclaration(tokenizer);
// If anything was returned, return it.
if (returnValue) {
return returnValue;
}
// Otherwise, return a syntax error.
return {
type: Types.ERROR,
value: 'invalid'
};
};
// 5.3.5: Parse a list of declarations
// -----------------------------------
exports.parseDeclarations = function (input) {
var tokenizer, returnList;
tokenizer = new Tokenizer(input);
// Consume a list of declarations.
returnList = Algorithms.consumeDeclarations(tokenizer);
// Return the returned list.
return returnList;
};
// 5.3.6: Parse a component value
// ------------------------------
exports.parseComponentValue = function (input) {
var tokenizer, value;
tokenizer = new Tokenizer(input);
// While the next input token is a <whitespace-token>,
// consume the next input token.
while (tokenizer.getNextToken().type === Types.WHITESPACE) {
tokenizer.consumeNextToken();
}
// If the next input token is an <EOF-token>, return a syntax error
if (tokenizer.getNextToken().type === Types.EOF) {
return {
type: Types.ERROR,
value: 'empty'
};
}
// Consume a component value and let value be the return value.
value = Algorithms.consumeComponentValue(tokenizer);
// While the next input token is a <whitespace-token>,
// consume the next input token.
while (tokenizer.getNextToken().type === Types.WHITESPACE) {
tokenizer.consumeNextToken();
}
// If the next input token is an <EOF-token>, return value.
if (tokenizer.getNextToken().type === Types.EOF) {
return value;
}
// Otherwise, return a syntax error.
return {
type: Types.ERROR,
value: 'extra-input'
};
};
// 5.3.7: Parse a list of component values
// ---------------------------------------
exports.parseComponentValues = function (input) {
var tokenizer, returnList, componentValue;
tokenizer = new Tokenizer(input);
returnList = [];
// Repeatedly consume a component value until an <EOF-token> is returned,
// appending the returned values (except the final <EOF-token>) into a list.
for (;;) {
componentValue = Algorithms.consumeComponentValue(tokenizer);
if (componentValue.type === Types.EOF) {
// Return the list.
return returnList;
}
returnList.push(componentValue);
}
};
// 5.3.8: Parse a comma-separated list of component values
// -------------------------------------------------------
exports.parseCommaSeparatedComponentValues = function (input) {
var tokenizer, listOfCvls, cvl, componentValue;
tokenizer = new Tokenizer(input);
// Let list of cvls be an initially empty list of component value lists.
listOfCvls = [];
// Repeatedly consume a component value until an <EOF-token> or
// <comma-token> is returned, appending the returned values
// (except the final <EOF-token> or <comma-token>) into a list.
cvl = [];
for (;;) {
componentValue = Algorithms.consumeComponentValue(tokenizer);
if (componentValue.type !== Types.COMMA
&& componentValue.type !== Types.EOF) {
cvl.push(componentValue);
} else {
// Append the list to list of cvls.
listOfCvls.push(cvl);
// If it was a <comma-token> that was returned, repeat this step.
if (componentValue.type === Types.COMMA) {
cvl = [];
} else {
// Return list of cvls.
return listOfCvls;
}
}
}
};