123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- 'use strict';
- var Tokenizer = require('../tokenizer');
- var List = require('../utils/list');
- var sequence = require('./sequence');
- var noop = function() {};
- function createParseContext(name) {
- return function() {
- return this[name]();
- };
- }
- function processConfig(config) {
- var parserConfig = {
- context: {},
- scope: {},
- atrule: {},
- pseudo: {}
- };
- if (config.parseContext) {
- for (var name in config.parseContext) {
- switch (typeof config.parseContext[name]) {
- case 'function':
- parserConfig.context[name] = config.parseContext[name];
- break;
- case 'string':
- parserConfig.context[name] = createParseContext(config.parseContext[name]);
- break;
- }
- }
- }
- if (config.scope) {
- for (var name in config.scope) {
- parserConfig.scope[name] = config.scope[name];
- }
- }
- if (config.atrule) {
- for (var name in config.atrule) {
- var atrule = config.atrule[name];
- if (atrule.parse) {
- parserConfig.atrule[name] = atrule.parse;
- }
- }
- }
- if (config.pseudo) {
- for (var name in config.pseudo) {
- var pseudo = config.pseudo[name];
- if (pseudo.parse) {
- parserConfig.pseudo[name] = pseudo.parse;
- }
- }
- }
- if (config.node) {
- for (var name in config.node) {
- parserConfig[name] = config.node[name].parse;
- }
- }
- return parserConfig;
- }
- module.exports = function createParser(config) {
- var parser = {
- scanner: new Tokenizer(),
- filename: '<unknown>',
- needPositions: false,
- onParseError: noop,
- onParseErrorThrow: false,
- parseAtrulePrelude: true,
- parseRulePrelude: true,
- parseValue: true,
- parseCustomProperty: false,
- readSequence: sequence,
- createList: function() {
- return new List();
- },
- createSingleNodeList: function(node) {
- return new List().appendData(node);
- },
- getFirstListNode: function(list) {
- return list && list.first();
- },
- getLastListNode: function(list) {
- return list.last();
- },
- parseWithFallback: function(consumer, fallback) {
- var startToken = this.scanner.currentToken;
- try {
- return consumer.call(this);
- } catch (e) {
- if (this.onParseErrorThrow) {
- throw e;
- }
- var fallbackNode = fallback.call(this, startToken);
- this.onParseErrorThrow = true;
- this.onParseError(e, fallbackNode);
- this.onParseErrorThrow = false;
- return fallbackNode;
- }
- },
- getLocation: function(start, end) {
- if (this.needPositions) {
- return this.scanner.getLocationRange(
- start,
- end,
- this.filename
- );
- }
- return null;
- },
- getLocationFromList: function(list) {
- if (this.needPositions) {
- var head = this.getFirstListNode(list);
- var tail = this.getLastListNode(list);
- return this.scanner.getLocationRange(
- head !== null ? head.loc.start.offset - this.scanner.startOffset : this.scanner.tokenStart,
- tail !== null ? tail.loc.end.offset - this.scanner.startOffset : this.scanner.tokenStart,
- this.filename
- );
- }
- return null;
- }
- };
- config = processConfig(config || {});
- for (var key in config) {
- parser[key] = config[key];
- }
- return function(source, options) {
- options = options || {};
- var context = options.context || 'default';
- var ast;
- parser.scanner.setSource(source, options.offset, options.line, options.column);
- parser.filename = options.filename || '<unknown>';
- parser.needPositions = Boolean(options.positions);
- parser.onParseError = typeof options.onParseError === 'function' ? options.onParseError : noop;
- parser.onParseErrorThrow = false;
- parser.parseAtrulePrelude = 'parseAtrulePrelude' in options ? Boolean(options.parseAtrulePrelude) : true;
- parser.parseRulePrelude = 'parseRulePrelude' in options ? Boolean(options.parseRulePrelude) : true;
- parser.parseValue = 'parseValue' in options ? Boolean(options.parseValue) : true;
- parser.parseCustomProperty = 'parseCustomProperty' in options ? Boolean(options.parseCustomProperty) : false;
- if (!parser.context.hasOwnProperty(context)) {
- throw new Error('Unknown context `' + context + '`');
- }
- ast = parser.context[context].call(parser, options);
- if (!parser.scanner.eof) {
- parser.scanner.error();
- }
- return ast;
- };
- };
|