| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 | "use strict";var Parser = require("fastparse");var uniRegexp = require("./uni-regexp");function unescape(str) {	return str.replace(/\\(.)/g, "$1");}function commentMatch(match, content) {	this.selector.nodes.push({		type: "comment",		content: content	});}function typeMatch(type) {	return function(match, name) {		this.selector.nodes.push({			type: type,			name: unescape(name)		});	};}function pseudoClassStartMatch(match, name) {	var newToken = {		type: "pseudo-class",		name: unescape(name),		content: ""	};	this.selector.nodes.push(newToken);	this.token = newToken;	this.brackets = 1;	return "inBrackets";}function nestedPseudoClassStartMatch(match, name, after) {	var newSelector = {		type: "selector",		nodes: []	};	var newToken = {		type: "nested-pseudo-class",		name: unescape(name),		nodes: [newSelector]	};	if(after) {		newSelector.before = after;	}	this.selector.nodes.push(newToken);	this.stack.push(this.root);	this.root = newToken;	this.selector = newSelector;}function nestedEnd(match, before) {	if(this.stack.length > 0) {		if(before) {			this.selector.after = before;		}		this.root = this.stack.pop();		this.selector = this.root.nodes[this.root.nodes.length - 1];	} else {		this.selector.nodes.push({			type: "invalid",			value: match		});	}}function operatorMatch(match, before, operator, after) {	var token = {		type: "operator",		operator: operator	};	if(before) {		token.before = before;	}	if(after) {		token.after = after;	}	this.selector.nodes.push(token);}function spacingMatch(match) {	this.selector.nodes.push({		type: "spacing",		value: match	});}function elementMatch(match, namespace, name) {	var newToken = {		type: "element",		name: unescape(name)	};	if(namespace) {		newToken.namespace = unescape(namespace.substr(0, namespace.length - 1));	}	this.selector.nodes.push(newToken);}function universalMatch(match, namespace) {	var newToken = {		type: "universal"	};	if(namespace) {		newToken.namespace = unescape(namespace.substr(0, namespace.length - 1));	}	this.selector.nodes.push(newToken);}function attributeMatch(match, content) {	this.selector.nodes.push({		type: "attribute",		content: content	});}function invalidMatch(match) {	this.selector.nodes.push({		type: "invalid",		value: match	});}function irrelevantSpacingStartMatch(match) {	this.selector.before = match;}function irrelevantSpacingEndMatch(match) {	this.selector.after = match;}function nextSelectorMatch(match, before, after) {	var newSelector = {		type: "selector",		nodes: []	};	if(before) {		this.selector.after = before;	}	if(after) {		newSelector.before = after;	}	this.root.nodes.push(newSelector);	this.selector = newSelector;}function addToCurrent(match) {	this.token.content += match;}function bracketStart(match) {	this.token.content += match;	this.brackets++;}function bracketEnd(match) {	if(--this.brackets === 0) {		return "selector";	}	this.token.content += match;}function getSelectors() {	// The assignment here is split to preserve the property enumeration order.	var selectors = {		"/\\*([\\s\\S]*?)\\*/": commentMatch	};	// https://www.w3.org/TR/CSS21/syndata.html#characters	// 4.1.3: identifiers (...) can contain only the characters [a-zA-Z0-9] and	// ISO 10646 characters U+00A0 and higher, plus the hyphen (-) and the underscore (_)	//	// 10ffff is the maximum allowed in current Unicode	selectors[uniRegexp.typeMatchClass] = typeMatch("class");	selectors[uniRegexp.typeMatchId] = typeMatch("id");	var selectorsSecondHalf = {		":(not|matches|has|local|global)\\((\\s*)": nestedPseudoClassStartMatch,		":((?:\\\\.|[A-Za-z_\\-0-9])+)\\(": pseudoClassStartMatch,		":((?:\\\\.|[A-Za-z_\\-0-9])+)": typeMatch("pseudo-class"),		"::((?:\\\\.|[A-Za-z_\\-0-9])+)": typeMatch("pseudo-element"),		"(\\*\\|)((?:\\\\.|[A-Za-z_\\-0-9])+)": elementMatch,		"(\\*\\|)\\*": universalMatch,		"((?:\\\\.|[A-Za-z_\\-0-9])*\\|)?\\*": universalMatch,		"((?:\\\\.|[A-Za-z_\\-0-9])*\\|)?((?:\\\\.|[A-Za-z_\\-])(?:\\\\.|[A-Za-z_\\-0-9])*)": elementMatch,		"\\[([^\\]]+)\\]": attributeMatch,		"(\\s*)\\)": nestedEnd,		"(\\s*)((?:\\|\\|)|(?:>>)|[>+~])(\\s*)": operatorMatch,		"(\\s*),(\\s*)": nextSelectorMatch,		"\\s+$": irrelevantSpacingEndMatch,		"^\\s+": irrelevantSpacingStartMatch,		"\\s+": spacingMatch,		".": invalidMatch	};	var selector;	for (selector in selectorsSecondHalf) {		if (Object.prototype.hasOwnProperty.call(selectorsSecondHalf, selector)) {			selectors[selector] = selectorsSecondHalf[selector];		}	}	return selectors;}var parser = new Parser({	selector: getSelectors(),	inBrackets: {		"/\\*[\\s\\S]*?\\*/": addToCurrent,		"\"([^\\\\\"]|\\\\.)*\"": addToCurrent,		"'([^\\\\']|\\\\.)*'": addToCurrent,		"[^()'\"/]+": addToCurrent,		"\\(": bracketStart,		"\\)": bracketEnd,		".": addToCurrent	}});function parse(str) {	var selectorNode = {		type: "selector",		nodes: []	};	var rootNode = {		type: "selectors",		nodes: [			selectorNode		]	};	parser.parse("selector", str, {		stack: [],		root: rootNode,		selector: selectorNode	});	return rootNode;}module.exports = parse;
 |