🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
Sign inDemoInstall
Socket

postcss-selector-parser

Package Overview
Dependencies
Maintainers
3
Versions
61
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

postcss-selector-parser - npm Package Compare versions

Comparing version

to
4.0.0-rc.0

dist/util/ensureObject.js

6

API.md

@@ -642,3 +642,3 @@ # API Documentation

For now, changing the spaces required also updating or removing any of the
For now, changing the spaces required also updating or removing any of the
raws values that override them.

@@ -793,3 +793,3 @@

// CssSyntaxError: classValidator: ./test.css:1:5: classes may not have underscores or dashes in them
//
//
// > 1 | .foo-bar {

@@ -833,3 +833,3 @@ // | ^

// CssSyntaxError: classValidator: ./test.css:1:5: classes may not have underscores or dashes in them
//
//
// > 1 | .foo-bar {

@@ -836,0 +836,0 @@ // | ^

@@ -0,1 +1,5 @@

# 3.1.2
* Fix: Removed dot-prop dependency since it's no longer written in es5.
# 3.1.1

@@ -2,0 +6,0 @@

@@ -7,5 +7,5 @@ 'use strict';

var _dotProp = require('dot-prop');
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _dotProp2 = _interopRequireDefault(_dotProp);
var _WHITESPACE_TOKENS, _extends2;

@@ -84,2 +84,4 @@ var _indexesOf = require('indexes-of');

var _util = require('./util');
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }

@@ -91,2 +93,6 @@

var WHITESPACE_TOKENS = (_WHITESPACE_TOKENS = {}, _WHITESPACE_TOKENS[tokens.space] = true, _WHITESPACE_TOKENS[tokens.cr] = true, _WHITESPACE_TOKENS[tokens.feed] = true, _WHITESPACE_TOKENS[tokens.newline] = true, _WHITESPACE_TOKENS[tokens.tab] = true, _WHITESPACE_TOKENS);
var WHITESPACE_EQUIV_TOKENS = _extends({}, WHITESPACE_TOKENS, (_extends2 = {}, _extends2[tokens.comment] = true, _extends2));
function getSource(startLine, startColumn, endLine, endColumn) {

@@ -105,2 +111,35 @@ return {

function getTokenSource(token) {
return getSource(token[_tokenize.FIELDS.START_LINE], token[_tokenize.FIELDS.START_COL], token[_tokenize.FIELDS.END_LINE], token[_tokenize.FIELDS.END_COL]);
}
function unescapeProp(node, prop) {
var value = node[prop];
if (typeof value !== "string") {
return;
}
if (value.indexOf("\\") !== -1) {
(0, _util.ensureObject)(node, 'raws');
node[prop] = (0, _util.unesc)(value);
if (node.raws[prop] === undefined) {
node.raws[prop] = value;
}
}
return node;
}
function convertWhitespaceNodesToSpace(nodes) {
var space = "";
var rawSpace = "";
nodes.forEach(function (n) {
space += n.spaces.before + n.spaces.after;
rawSpace += n.toString();
});
if (rawSpace === space) {
rawSpace = undefined;
}
var result = { space: space, rawSpace: rawSpace };
return result;
}
var Parser = function () {

@@ -124,5 +163,2 @@ function Parser(rule) {

if (this.options.lossy) {
this.css = this.css.trim();
}
this.tokens = (0, _tokenize2.default)({

@@ -152,8 +188,8 @@ css: this.css,

this.position++;
while (this.position < this.tokens.length && this.currToken[0] !== tokens.closeSquare) {
while (this.position < this.tokens.length && this.currToken[_tokenize.FIELDS.TYPE] !== tokens.closeSquare) {
attr.push(this.currToken);
this.position++;
}
if (this.currToken[0] !== tokens.closeSquare) {
return this.expected('closing square bracket', this.currToken[5]);
if (this.currToken[_tokenize.FIELDS.TYPE] !== tokens.closeSquare) {
return this.expected('closing square bracket', this.currToken[_tokenize.FIELDS.START_POS]);
}

@@ -164,7 +200,7 @@

source: getSource(startingToken[1], startingToken[2], this.currToken[3], this.currToken[4]),
sourceIndex: startingToken[5]
sourceIndex: startingToken[_tokenize.FIELDS.START_POS]
};
if (len === 1 && !~[tokens.word].indexOf(attr[0][0])) {
return this.expected('attribute', attr[0][5]);
if (len === 1 && !~[tokens.word].indexOf(attr[0][_tokenize.FIELDS.TYPE])) {
return this.expected('attribute', attr[0][_tokenize.FIELDS.START_POS]);
}

@@ -183,7 +219,10 @@

switch (token[0]) {
switch (token[_tokenize.FIELDS.TYPE]) {
case tokens.space:
if (len === 1 || pos === 0 && this.content(next) === '|') {
return this.expected('attribute', token[5], content);
}
// if (
// len === 1 ||
// pos === 0 && this.content(next) === '|'
// ) {
// return this.expected('attribute', token[TOKEN.START_POS], content);
// }
spaceAfterMeaningfulToken = true;

@@ -194,8 +233,10 @@ if (this.options.lossy) {

if (lastAdded) {
var spaceProp = 'spaces.' + lastAdded + '.after';
_dotProp2.default.set(node, spaceProp, _dotProp2.default.get(node, spaceProp, '') + content);
var commentProp = 'raws.spaces.' + lastAdded + '.after';
var existingComment = _dotProp2.default.get(node, commentProp);
(0, _util.ensureObject)(node, 'spaces', lastAdded);
var prevContent = node.spaces[lastAdded].after || '';
node.spaces[lastAdded].after = prevContent + content;
var existingComment = (0, _util.getProp)(node, 'raws', 'spaces', lastAdded, 'after') || null;
if (existingComment) {
_dotProp2.default.set(node, commentProp, existingComment + content);
node.raws.spaces[lastAdded].after = existingComment + content;
}

@@ -208,3 +249,3 @@ } else {

case tokens.asterisk:
if (next[0] === tokens.equals) {
if (next[_tokenize.FIELDS.TYPE] === tokens.equals) {
node.operator = content;

@@ -214,11 +255,13 @@ lastAdded = 'operator';

if (spaceBefore) {
_dotProp2.default.set(node, 'spaces.attribute.before', spaceBefore);
(0, _util.ensureObject)(node, 'spaces', 'attribute');
node.spaces.attribute.before = spaceBefore;
spaceBefore = '';
}
if (commentBefore) {
_dotProp2.default.set(node, 'raws.spaces.attribute.before', spaceBefore);
(0, _util.ensureObject)(node, 'raws', 'spaces', 'attribute');
node.raws.spaces.attribute.before = spaceBefore;
commentBefore = '';
}
node.namespace = (node.namespace || "") + content;
var rawValue = _dotProp2.default.get(node, "raws.namespace");
var rawValue = (0, _util.getProp)(node, 'raws', 'namespace') || null;
if (rawValue) {

@@ -233,3 +276,3 @@ node.raws.namespace += content;

case tokens.caret:
if (next[0] === tokens.equals) {
if (next[_tokenize.FIELDS.TYPE] === tokens.equals) {
node.operator = content;

@@ -241,3 +284,3 @@ lastAdded = 'operator';

case tokens.combinator:
if (content === '~' && next[0] === tokens.equals) {
if (content === '~' && next[_tokenize.FIELDS.TYPE] === tokens.equals) {
node.operator = content;

@@ -250,3 +293,3 @@ lastAdded = 'operator';

}
if (next[0] === tokens.equals) {
if (next[_tokenize.FIELDS.TYPE] === tokens.equals) {
node.operator = content;

@@ -260,3 +303,3 @@ lastAdded = 'operator';

case tokens.word:
if (next && this.content(next) === '|' && attr[pos + 2] && attr[pos + 2][0] !== tokens.equals && // this look-ahead probably fails with comment nodes involved.
if (next && this.content(next) === '|' && attr[pos + 2] && attr[pos + 2][_tokenize.FIELDS.TYPE] !== tokens.equals && // this look-ahead probably fails with comment nodes involved.
!node.operator && !node.namespace) {

@@ -267,11 +310,14 @@ node.namespace = content;

if (spaceBefore) {
_dotProp2.default.set(node, 'spaces.attribute.before', spaceBefore);
(0, _util.ensureObject)(node, 'spaces', 'attribute');
node.spaces.attribute.before = spaceBefore;
spaceBefore = '';
}
if (commentBefore) {
_dotProp2.default.set(node, 'raws.spaces.attribute.before', commentBefore);
(0, _util.ensureObject)(node, 'raws', 'spaces', 'attribute');
node.raws.spaces.attribute.before = commentBefore;
commentBefore = '';
}
node.attribute = (node.attribute || "") + content;
var _rawValue = _dotProp2.default.get(node, "raws.attribute");
var _rawValue = (0, _util.getProp)(node, 'raws', 'attribute') || null;
if (_rawValue) {

@@ -282,19 +328,30 @@ node.raws.attribute += content;

} else if (!node.value || lastAdded === "value" && !spaceAfterMeaningfulToken) {
node.value = (node.value || "") + content;
var _rawValue2 = _dotProp2.default.get(node, "raws.value");
if (_rawValue2) {
node.raws.value += content;
var _unescaped = (0, _util.unesc)(content);
var oldRawValue = (0, _util.getProp)(node, 'raws', 'value') || '';
var oldValue = node.value || '';
node.value = oldValue + _unescaped;
node.quoteMark = null;
if (_unescaped !== content || oldRawValue) {
(0, _util.ensureObject)(node, 'raws');
node.raws.value = (oldRawValue || oldValue) + content;
}
lastAdded = 'value';
_dotProp2.default.set(node, 'raws.unquoted', _dotProp2.default.get(node, 'raws.unquoted', '') + content);
} else if (content === 'i') {
if (node.value && (node.quoted || spaceAfterMeaningfulToken)) {
node.insensitive = true;
} else {
var insensitive = content === 'i' || content === "I";
if (node.value && (node.quoteMark || spaceAfterMeaningfulToken)) {
node.insensitive = insensitive;
if (!insensitive || content === "I") {
(0, _util.ensureObject)(node, 'raws');
node.raws.insensitiveFlag = content;
}
lastAdded = 'insensitive';
if (spaceBefore) {
_dotProp2.default.set(node, 'spaces.insensitive.before', spaceBefore);
(0, _util.ensureObject)(node, 'spaces', 'insensitive');
node.spaces.insensitive.before = spaceBefore;
spaceBefore = '';
}
if (commentBefore) {
_dotProp2.default.set(node, 'raws.spaces.insensitive.before', commentBefore);
(0, _util.ensureObject)(node, 'raws', 'spaces', 'insensitive');
node.raws.spaces.insensitive.before = commentBefore;
commentBefore = '';

@@ -304,5 +361,5 @@ }

lastAdded = 'value';
node.value += 'i';
node.value += content;
if (node.raws.value) {
node.raws.value += 'i';
node.raws.value += content;
}

@@ -316,9 +373,17 @@ }

return this.error('Expected an attribute followed by an operator preceding the string.', {
index: token[5]
index: token[_tokenize.FIELDS.START_POS]
});
}
node.value = content;
node.quoted = true;
var _unescapeValue = (0, _attribute.unescapeValue)(content),
unescaped = _unescapeValue.unescaped,
quoteMark = _unescapeValue.quoteMark;
node.value = unescaped;
node.quoteMark = quoteMark;
lastAdded = 'value';
_dotProp2.default.set(node, 'raws.unquoted', content.slice(1, -1));
(0, _util.ensureObject)(node, 'raws');
node.raws.value = content;
spaceAfterMeaningfulToken = false;

@@ -328,6 +393,6 @@ break;

if (!node.attribute) {
return this.expected('attribute', token[5], content);
return this.expected('attribute', token[_tokenize.FIELDS.START_POS], content);
}
if (node.value) {
return this.error('Unexpected "=" found; an operator was already defined.', { index: token[5] });
return this.error('Unexpected "=" found; an operator was already defined.', { index: token[_tokenize.FIELDS.START_POS] });
}

@@ -340,8 +405,13 @@ node.operator = node.operator ? node.operator + content : content;

if (lastAdded) {
if (spaceAfterMeaningfulToken || next && next[0] === tokens.space) {
var lastComment = _dotProp2.default.get(node, 'raws.spaces.' + lastAdded + '.after', _dotProp2.default.get(node, 'spaces.' + lastAdded + '.after', ''));
_dotProp2.default.set(node, 'raws.spaces.' + lastAdded + '.after', lastComment + content);
if (spaceAfterMeaningfulToken || next && next[_tokenize.FIELDS.TYPE] === tokens.space) {
var lastComment = (0, _util.getProp)(node, 'spaces', lastAdded, 'after') || '';
var rawLastComment = (0, _util.getProp)(node, 'raws', 'spaces', lastAdded, 'after') || lastComment;
(0, _util.ensureObject)(node, 'raws', 'spaces', lastAdded);
node.raws.spaces[lastAdded].after = rawLastComment + content;
} else {
var lastValue = _dotProp2.default.get(node, 'raws.' + lastAdded, _dotProp2.default.get(node, lastAdded, ''));
_dotProp2.default.set(node, 'raws.' + lastAdded, lastValue + content);
var lastValue = node[lastAdded] || '';
var rawLastValue = (0, _util.getProp)(node, 'raws', lastAdded) || lastValue;
(0, _util.ensureObject)(node, 'raws');
node.raws[lastAdded] = rawLastValue + content;
}

@@ -353,7 +423,8 @@ } else {

default:
return this.error('Unexpected "' + content + '" found.', { index: token[5] });
return this.error('Unexpected "' + content + '" found.', { index: token[_tokenize.FIELDS.START_POS] });
}
pos++;
}
unescapeProp(node, "attribute");
unescapeProp(node, "namespace");
this.newNode(new _attribute2.default(node));

@@ -363,27 +434,125 @@ this.position++;

/**
* return a node containing meaningless garbage up to (but not including) the specified token position.
* if the token position is negative, all remaining tokens are consumed.
*
* This returns an array containing a single string node if all whitespace,
* otherwise an array of comment nodes with space before and after.
*
* These tokens are not added to the current selector, the caller can add them or use them to amend
* a previous node's space metadata.
*
* In lossy mode, this returns only comments.
*/
Parser.prototype.parseWhitespaceEquivalentTokens = function parseWhitespaceEquivalentTokens(stopPosition) {
if (stopPosition < 0) {
stopPosition = this.tokens.length;
}
var startPosition = this.position;
var nodes = [];
var space = "";
var lastComment = undefined;
do {
if (WHITESPACE_TOKENS[this.currToken[_tokenize.FIELDS.TYPE]]) {
if (!this.options.lossy) {
space += this.content();
}
} else if (this.currToken[_tokenize.FIELDS.TYPE] === tokens.comment) {
var spaces = {};
if (space) {
spaces.before = space;
space = "";
}
lastComment = new _comment2.default({
value: this.content(),
source: getTokenSource(this.currToken),
sourceIndex: this.currToken[_tokenize.FIELDS.START_POS],
spaces: spaces
});
nodes.push(lastComment);
}
} while (++this.position < stopPosition);
if (space) {
if (lastComment) {
lastComment.spaces.after = space;
} else if (!this.options.lossy) {
var firstToken = this.tokens[startPosition];
var lastToken = this.tokens[this.position - 1];
nodes.push(new _string2.default({
value: '',
source: getSource(firstToken[_tokenize.FIELDS.START_LINE], firstToken[_tokenize.FIELDS.START_COL], lastToken[_tokenize.FIELDS.END_LINE], lastToken[_tokenize.FIELDS.END_COL]),
sourceIndex: firstToken[_tokenize.FIELDS.START_POS],
spaces: { before: space, after: '' }
}));
}
}
return nodes;
};
Parser.prototype.combinator = function combinator() {
var current = this.currToken;
var _this2 = this;
if (this.content() === '|') {
return this.namespace();
}
// We need to decide between a space that's a descendant combinator and meaningless whitespace at the end of a selector.
var nextSigTokenPos = this.locateNextMeaningfulToken(this.position);
if (nextSigTokenPos < 0 || this.tokens[nextSigTokenPos][_tokenize.FIELDS.TYPE] === tokens.comma) {
var nodes = this.parseWhitespaceEquivalentTokens(nextSigTokenPos);
if (nodes.length > 0) {
var last = this.current.last;
if (last) {
var _convertWhitespaceNod = convertWhitespaceNodesToSpace(nodes),
space = _convertWhitespaceNod.space,
rawSpace = _convertWhitespaceNod.rawSpace;
if (rawSpace !== undefined) {
last.rawSpaceAfter += rawSpace;
}
last.spaces.after += space;
} else {
nodes.forEach(function (n) {
return _this2.newNode(n);
});
}
}
return;
}
var spaceBeforeCombinator = undefined;
if (nextSigTokenPos > this.position && this.tokens[nextSigTokenPos][_tokenize.FIELDS.TYPE] === tokens.combinator) {
spaceBeforeCombinator = convertWhitespaceNodesToSpace(this.parseWhitespaceEquivalentTokens(nextSigTokenPos));
}
var current = this.currToken;
var node = new _combinator2.default({
value: '',
source: getSource(current[1], current[2], current[3], current[4]),
sourceIndex: current[5]
source: getTokenSource(current),
sourceIndex: current[_tokenize.FIELDS.START_POS]
});
while (this.position < this.tokens.length && this.currToken && (this.currToken[0] === tokens.space || this.currToken[0] === tokens.combinator)) {
while (this.position < this.tokens.length && this.currToken && (this.currToken[_tokenize.FIELDS.TYPE] === tokens.space || this.currToken[_tokenize.FIELDS.TYPE] === tokens.combinator)) {
var content = this.content();
if (this.nextToken && this.nextToken[0] === tokens.combinator) {
node.spaces.before = this.parseSpace(content);
node.source = getSource(this.nextToken[1], this.nextToken[2], this.nextToken[3], this.nextToken[4]);
node.sourceIndex = this.nextToken[5];
} else if (this.prevToken && this.prevToken[0] === tokens.combinator) {
node.spaces.after = this.parseSpace(content);
} else if (this.currToken[0] === tokens.combinator) {
if (this.nextToken && this.nextToken[_tokenize.FIELDS.TYPE] === tokens.combinator) {
node.spaces.before = this.optionalSpace(content);
node.source = getTokenSource(this.nextToken);
node.sourceIndex = this.nextToken[_tokenize.FIELDS.START_POS];
} else if (this.prevToken && this.prevToken[_tokenize.FIELDS.TYPE] === tokens.combinator) {
node.spaces.after = this.optionalSpace(content);
} else if (this.currToken[_tokenize.FIELDS.TYPE] === tokens.combinator) {
node.value = content;
} else if (this.currToken[0] === tokens.space) {
node.value = this.parseSpace(content, ' ');
} else if (this.currToken[_tokenize.FIELDS.TYPE] === tokens.space) {
node.value = this.requiredSpace(content);
}
this.position++;
}
if (spaceBeforeCombinator) {
if (spaceBeforeCombinator.rawSpace !== undefined) {
node.rawSpaceBefore = spaceBeforeCombinator.rawSpace + node.rawSpaceBefore;
}
node.spaces.before = spaceBeforeCombinator.space + node.spaces.before;
}
return this.newNode(node);

@@ -408,4 +577,4 @@ };

value: this.content(),
source: getSource(current[1], current[2], current[3], current[4]),
sourceIndex: current[5]
source: getTokenSource(current),
sourceIndex: current[_tokenize.FIELDS.START_POS]
}));

@@ -421,3 +590,3 @@ this.position++;

return this.error('Expected a backslash preceding the semicolon.', {
index: this.currToken[5]
index: this.currToken[_tokenize.FIELDS.START_POS]
});

@@ -427,7 +596,7 @@ };

Parser.prototype.missingParenthesis = function missingParenthesis() {
return this.expected('opening parenthesis', this.currToken[5]);
return this.expected('opening parenthesis', this.currToken[_tokenize.FIELDS.START_POS]);
};
Parser.prototype.missingSquareBracket = function missingSquareBracket() {
return this.expected('opening square bracket', this.currToken[5]);
return this.expected('opening square bracket', this.currToken[_tokenize.FIELDS.START_POS]);
};

@@ -437,6 +606,6 @@

var before = this.prevToken && this.content(this.prevToken) || true;
if (this.nextToken[0] === tokens.word) {
if (this.nextToken[_tokenize.FIELDS.TYPE] === tokens.word) {
this.position++;
return this.word(before);
} else if (this.nextToken[0] === tokens.asterisk) {
} else if (this.nextToken[_tokenize.FIELDS.TYPE] === tokens.asterisk) {
this.position++;

@@ -448,7 +617,14 @@ return this.universal(before);

Parser.prototype.nesting = function nesting() {
if (this.nextToken) {
var nextContent = this.content(this.nextToken);
if (nextContent === "|") {
this.position++;
return;
}
}
var current = this.currToken;
this.newNode(new _nesting2.default({
value: this.content(),
source: getSource(current[1], current[2], current[3], current[4]),
sourceIndex: current[5]
source: getTokenSource(current),
sourceIndex: current[_tokenize.FIELDS.START_POS]
}));

@@ -468,6 +644,6 @@ this.position++;

while (this.position < this.tokens.length && balanced) {
if (this.currToken[0] === tokens.openParenthesis) {
if (this.currToken[_tokenize.FIELDS.TYPE] === tokens.openParenthesis) {
balanced++;
}
if (this.currToken[0] === tokens.closeParenthesis) {
if (this.currToken[_tokenize.FIELDS.TYPE] === tokens.closeParenthesis) {
balanced--;

@@ -485,16 +661,30 @@ }

} else {
last.value += '(';
// I think this case should be an error. It's used to implement a basic parse of media queries
// but I don't think it's a good idea.
var parenStart = this.currToken;
var parenValue = "(";
var parenEnd = void 0;
while (this.position < this.tokens.length && balanced) {
if (this.currToken[0] === tokens.openParenthesis) {
if (this.currToken[_tokenize.FIELDS.TYPE] === tokens.openParenthesis) {
balanced++;
}
if (this.currToken[0] === tokens.closeParenthesis) {
if (this.currToken[_tokenize.FIELDS.TYPE] === tokens.closeParenthesis) {
balanced--;
}
last.value += this.parseParenthesisToken(this.currToken);
parenEnd = this.currToken;
parenValue += this.parseParenthesisToken(this.currToken);
this.position++;
}
if (last) {
last.appendToPropertyAndEscape("value", parenValue, parenValue);
} else {
this.newNode(new _string2.default({
value: parenValue,
source: getSource(parenStart[_tokenize.FIELDS.START_LINE], parenStart[_tokenize.FIELDS.START_COL], parenEnd[_tokenize.FIELDS.END_LINE], parenEnd[_tokenize.FIELDS.END_COL]),
sourceIndex: parenStart[_tokenize.FIELDS.START_POS]
}));
}
}
if (balanced) {
return this.expected('closing parenthesis', this.currToken[5]);
return this.expected('closing parenthesis', this.currToken[_tokenize.FIELDS.START_POS]);
}

@@ -504,7 +694,7 @@ };

Parser.prototype.pseudo = function pseudo() {
var _this2 = this;
var _this3 = this;
var pseudoStr = '';
var startingToken = this.currToken;
while (this.currToken && this.currToken[0] === tokens.colon) {
while (this.currToken && this.currToken[_tokenize.FIELDS.TYPE] === tokens.colon) {
pseudoStr += this.content();

@@ -516,13 +706,13 @@ this.position++;

}
if (this.currToken[0] === tokens.word) {
if (this.currToken[_tokenize.FIELDS.TYPE] === tokens.word) {
this.splitWord(false, function (first, length) {
pseudoStr += first;
_this2.newNode(new _pseudo2.default({
_this3.newNode(new _pseudo2.default({
value: pseudoStr,
source: getSource(startingToken[1], startingToken[2], _this2.currToken[3], _this2.currToken[4]),
sourceIndex: startingToken[5]
source: getSource(startingToken[1], startingToken[2], _this3.currToken[3], _this3.currToken[4]),
sourceIndex: startingToken[_tokenize.FIELDS.START_POS]
}));
if (length > 1 && _this2.nextToken && _this2.nextToken[0] === tokens.openParenthesis) {
_this2.error('Misplaced parenthesis.', {
index: _this2.nextToken[5]
if (length > 1 && _this3.nextToken && _this3.nextToken[_tokenize.FIELDS.TYPE] === tokens.openParenthesis) {
_this3.error('Misplaced parenthesis.', {
index: _this3.nextToken[_tokenize.FIELDS.START_POS]
});

@@ -532,3 +722,3 @@ }

} else {
return this.expected(['pseudo-class', 'pseudo-element'], this.currToken[5]);
return this.expected(['pseudo-class', 'pseudo-element'], this.currToken[_tokenize.FIELDS.START_POS]);
}

@@ -540,7 +730,7 @@ };

// Handle space before and after the selector
if (this.position === 0 || this.prevToken[0] === tokens.comma || this.prevToken[0] === tokens.openParenthesis) {
this.spaces = this.parseSpace(content);
if (this.position === 0 || this.prevToken[_tokenize.FIELDS.TYPE] === tokens.comma || this.prevToken[_tokenize.FIELDS.TYPE] === tokens.openParenthesis) {
this.spaces = this.optionalSpace(content);
this.position++;
} else if (this.position === this.tokens.length - 1 || this.nextToken[0] === tokens.comma || this.nextToken[0] === tokens.closeParenthesis) {
this.current.last.spaces.after = this.parseSpace(content);
} else if (this.position === this.tokens.length - 1 || this.nextToken[_tokenize.FIELDS.TYPE] === tokens.comma || this.nextToken[_tokenize.FIELDS.TYPE] === tokens.closeParenthesis) {
this.current.last.spaces.after = this.optionalSpace(content);
this.position++;

@@ -556,4 +746,4 @@ } else {

value: this.content(),
source: getSource(current[1], current[2], current[3], current[4]),
sourceIndex: current[5]
source: getTokenSource(current),
sourceIndex: current[_tokenize.FIELDS.START_POS]
}));

@@ -572,4 +762,4 @@ this.position++;

value: this.content(),
source: getSource(current[1], current[2], current[3], current[4]),
sourceIndex: current[5]
source: getTokenSource(current),
sourceIndex: current[_tokenize.FIELDS.START_POS]
}), namespace);

@@ -580,7 +770,7 @@ this.position++;

Parser.prototype.splitWord = function splitWord(namespace, firstCallback) {
var _this3 = this;
var _this4 = this;
var nextToken = this.nextToken;
var word = this.content();
while (nextToken && ~[tokens.dollar, tokens.caret, tokens.equals, tokens.word].indexOf(nextToken[0])) {
while (nextToken && ~[tokens.dollar, tokens.caret, tokens.equals, tokens.word].indexOf(nextToken[_tokenize.FIELDS.TYPE])) {
this.position++;

@@ -591,4 +781,4 @@ var current = this.content();

var next = this.nextToken;
if (next && next[0] === tokens.space) {
word += this.parseSpace(this.content(next), ' ');
if (next && next[_tokenize.FIELDS.TYPE] === tokens.space) {
word += this.requiredSpace(this.content(next));
this.position++;

@@ -613,28 +803,32 @@ }

if (i === 0 && firstCallback) {
return firstCallback.call(_this3, value, indices.length);
return firstCallback.call(_this4, value, indices.length);
}
var node = void 0;
var current = _this3.currToken;
var sourceIndex = current[5] + indices[i];
var current = _this4.currToken;
var sourceIndex = current[_tokenize.FIELDS.START_POS] + indices[i];
var source = getSource(current[1], current[2] + ind, current[3], current[2] + (index - 1));
if (~hasClass.indexOf(ind)) {
node = new _className2.default({
var classNameOpts = {
value: value.slice(1),
source: source,
sourceIndex: sourceIndex
});
};
node = new _className2.default(unescapeProp(classNameOpts, "value"));
} else if (~hasId.indexOf(ind)) {
node = new _id2.default({
var idOpts = {
value: value.slice(1),
source: source,
sourceIndex: sourceIndex
});
};
node = new _id2.default(unescapeProp(idOpts, "value"));
} else {
node = new _tag2.default({
var tagOpts = {
value: value,
source: source,
sourceIndex: sourceIndex
});
};
unescapeProp(tagOpts, "value");
node = new _tag2.default(tagOpts);
}
_this3.newNode(node, namespace);
_this4.newNode(node, namespace);
// Ensure that the namespace is used only once

@@ -663,3 +857,3 @@ namespace = null;

Parser.prototype.parse = function parse(throwOnParenthesis) {
switch (this.currToken[0]) {
switch (this.currToken[_tokenize.FIELDS.TYPE]) {
case tokens.space:

@@ -730,39 +924,17 @@ this.space();

Parser.prototype.parseNamespace = function parseNamespace(namespace) {
if (this.options.lossy && typeof namespace === 'string') {
var trimmed = namespace.trim();
if (!trimmed.length) {
return true;
}
return trimmed;
}
return namespace;
Parser.prototype.requiredSpace = function requiredSpace(space) {
return this.options.lossy ? ' ' : space;
};
Parser.prototype.parseSpace = function parseSpace(space) {
var replacement = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
return this.options.lossy ? replacement : space;
Parser.prototype.optionalSpace = function optionalSpace(space) {
return this.options.lossy ? '' : space;
};
Parser.prototype.parseValue = function parseValue(value) {
if (!this.options.lossy || !value || typeof value !== 'string') {
return value;
}
return value.trim();
};
Parser.prototype.parseParenthesisToken = function parseParenthesisToken(token) {
var content = this.content(token);
if (!this.options.lossy) {
if (token[_tokenize.FIELDS.TYPE] === tokens.space) {
return this.requiredSpace(content);
} else {
return content;
}
if (token[0] === tokens.space) {
return this.parseSpace(content, ' ');
}
return this.parseValue(content);
};

@@ -772,3 +944,10 @@

if (namespace) {
node.namespace = this.parseNamespace(namespace);
if (/^ +$/.test(namespace)) {
if (!this.options.lossy) {
this.spaces = (this.spaces || '') + namespace;
}
namespace = true;
}
node.namespace = namespace;
unescapeProp(node, "namespace");
}

@@ -785,5 +964,24 @@ if (this.spaces) {

return this.css.slice(token[5], token[6]);
return this.css.slice(token[_tokenize.FIELDS.START_POS], token[_tokenize.FIELDS.END_POS]);
};
/**
* returns the index of the next non-whitespace, non-comment token.
* returns -1 if no meaningful token is found.
*/
Parser.prototype.locateNextMeaningfulToken = function locateNextMeaningfulToken() {
var startPosition = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.position + 1;
var searchPosition = startPosition;
while (searchPosition < this.tokens.length) {
if (WHITESPACE_EQUIV_TOKENS[this.tokens[searchPosition][_tokenize.FIELDS.TYPE]]) {
searchPosition++;
continue;
} else {
return searchPosition;
}
}
return -1;
};
_createClass(Parser, [{

@@ -790,0 +988,0 @@ key: 'currToken',

@@ -98,3 +98,3 @@ "use strict";

* Process rule into a selector AST.
*
*
* @param rule {postcss.Rule | string} The css selector to be processed

@@ -114,3 +114,3 @@ * @param options The options for processing

* Process rule into a selector AST synchronously.
*
*
* @param rule {postcss.Rule | string} The css selector to be processed

@@ -128,3 +128,3 @@ * @param options The options for processing

* Process a selector into a transformed value asynchronously
*
*
* @param rule {postcss.Rule | string} The css selector to be processed

@@ -144,3 +144,3 @@ * @param options The options for processing

* Process a selector into a transformed value synchronously.
*
*
* @param rule {postcss.Rule | string} The css selector to be processed

@@ -158,3 +158,3 @@ * @param options The options for processing

* Process a selector into a new selector string asynchronously.
*
*
* @param rule {postcss.Rule | string} The css selector to be processed

@@ -174,3 +174,3 @@ * @param options The options for processing

* Process a selector into a new selector string synchronously.
*
*
* @param rule {postcss.Rule | string} The css selector to be processed

@@ -177,0 +177,0 @@ * @param options The options for processing

@@ -1,12 +0,24 @@

'use strict';
"use strict";
exports.__esModule = true;
var _CSSESC_QUOTE_OPTIONS;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _namespace = require('./namespace');
exports.unescapeValue = unescapeValue;
var _cssesc = require("cssesc");
var _cssesc2 = _interopRequireDefault(_cssesc);
var _unesc = require("../util/unesc");
var _unesc2 = _interopRequireDefault(_unesc);
var _namespace = require("./namespace");
var _namespace2 = _interopRequireDefault(_namespace);
var _types = require('./types');
var _types = require("./types");

@@ -21,2 +33,57 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var _require = require("util"),
deprecate = _require.deprecate;
var WRAPPED_IN_QUOTES = /^('|")(.*)\1$/;
var warnOfDeprecatedValueAssignment = deprecate(function () {}, "Assigning an attribute a value containing characters that might need to be escaped is deprecated. " + "Call attribute.setValue() instead.");
var warnOfDeprecatedQuotedAssignment = deprecate(function () {}, "Assigning attr.quoted is deprecated and has no effect. Assign to attr.quoteMark instead.");
var warnOfDeprecatedConstructor = deprecate(function () {}, "Constructing an Attribute selector with a value without specifying quoteMark is deprecated. Note: The value should be unescaped now.");
function unescapeValue(value) {
var deprecatedUsage = false;
var quoteMark = null;
var unescaped = value;
var m = unescaped.match(WRAPPED_IN_QUOTES);
if (m) {
quoteMark = m[1];
unescaped = m[2];
}
unescaped = (0, _unesc2.default)(unescaped);
if (unescaped !== value) {
deprecatedUsage = true;
}
return {
deprecatedUsage: deprecatedUsage,
unescaped: unescaped,
quoteMark: quoteMark
};
}
function handleDeprecatedContructorOpts(opts) {
if (opts.quoteMark !== undefined) {
return opts;
}
if (opts.value === undefined) {
return opts;
}
warnOfDeprecatedConstructor();
var _unescapeValue = unescapeValue(opts.value),
quoteMark = _unescapeValue.quoteMark,
unescaped = _unescapeValue.unescaped;
if (!opts.raws) {
opts.raws = {};
}
if (opts.raws.value === undefined) {
opts.raws.value = opts.value;
}
opts.value = unescaped;
opts.quoteMark = quoteMark;
return opts;
}
var Attribute = function (_Namespace) {

@@ -30,6 +97,14 @@ _inherits(Attribute, _Namespace);

var _this = _possibleConstructorReturn(this, _Namespace.call(this, opts));
var _this = _possibleConstructorReturn(this, _Namespace.call(this, handleDeprecatedContructorOpts(opts)));
_this.type = _types.ATTRIBUTE;
_this.raws = _this.raws || {};
Object.defineProperty(_this.raws, 'unquoted', {
get: deprecate(function () {
return _this.value;
}, "attr.raws.unquoted is deprecated. Call attr.value instead."),
set: deprecate(function () {
return _this.value;
}, "Setting attr.raws.unquoted is deprecated and has no effect. attr.value is unescaped by default now.")
});
_this._constructed = true;

@@ -39,2 +114,140 @@ return _this;

/**
* Returns the Attribute's value quoted such that it would be legal to use
* in the value of a css file. The original value's quotation setting
* used for stringification is left unchanged. See `setValue(value, options)`
* if you want to control the quote settings of a new value for the attribute.
*
* You can also change the quotation used for the current value by setting quoteMark.
*
* Options:
* * quoteMark {'"' | "'" | null} - Use this value to quote the value. If this
* option is not set, the original value for quoteMark will be used. If
* indeterminate, a double quote is used. The legal values are:
* * `null` - the value will be unquoted and characters will be escaped as necessary.
* * `'` - the value will be quoted with a single quote and single quotes are escaped.
* * `"` - the value will be quoted with a double quote and double quotes are escaped.
* * preferCurrentQuoteMark {boolean} - if true, prefer the source quote mark
* over the quoteMark option value.
* * smart {boolean} - if true, will select a quote mark based on the value
* and the other options specified here. See the `smartQuoteMark()`
* method.
**/
Attribute.prototype.getQuotedValue = function getQuotedValue() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var quoteMark = this._determineQuoteMark(options);
var cssescopts = CSSESC_QUOTE_OPTIONS[quoteMark];
var escaped = (0, _cssesc2.default)(this._value, cssescopts);
return escaped;
};
Attribute.prototype._determineQuoteMark = function _determineQuoteMark(options) {
return options.smart ? this.smartQuoteMark(options) : this.preferredQuoteMark(options);
};
/**
* Set the unescaped value with the specified quotation options. The value
* provided must not include any wrapping quote marks -- those quotes will
* be interpreted as part of the value and escaped accordingly.
*/
Attribute.prototype.setValue = function setValue(value) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
this._value = value;
this._quoteMark = this._determineQuoteMark(options);
this._syncRawValue();
};
/**
* Intelligently select a quoteMark value based on the value's contents. If
* the value is a legal CSS ident, it will not be quoted. Otherwise a quote
* mark will be picked that minimizes the number of escapes.
*
* If there's no clear winner, the quote mark from these options is used,
* then the source quote mark (this is inverted if `preferCurrentQuoteMark` is
* true). If the quoteMark is unspecified, a double quote is used.
*
* @param options This takes the quoteMark and preferCurrentQuoteMark options
* from the quoteValue method.
*/
Attribute.prototype.smartQuoteMark = function smartQuoteMark(options) {
var v = this.value;
var numSingleQuotes = v.replace(/[^']/g, '').length;
var numDoubleQuotes = v.replace(/[^"]/g, '').length;
if (numSingleQuotes + numDoubleQuotes === 0) {
var escaped = (0, _cssesc2.default)(v, { isIdentifier: true });
if (escaped === v) {
return Attribute.NO_QUOTE;
} else {
var pref = this.preferredQuoteMark(options);
if (pref === Attribute.NO_QUOTE) {
// pick a quote mark that isn't none and see if it's smaller
var quote = this.quoteMark || options.quoteMark || Attribute.DOUBLE_QUOTE;
var opts = CSSESC_QUOTE_OPTIONS[quote];
var quoteValue = (0, _cssesc2.default)(v, opts);
if (quoteValue.length < escaped.length) {
return quote;
}
}
return pref;
}
} else if (numDoubleQuotes === numSingleQuotes) {
return this.preferredQuoteMark(options);
} else if (numDoubleQuotes < numSingleQuotes) {
return Attribute.DOUBLE_QUOTE;
} else {
return Attribute.SINGLE_QUOTE;
}
};
/**
* Selects the preferred quote mark based on the options and the current quote mark value.
* If you want the quote mark to depend on the attribute value, call `smartQuoteMark(opts)`
* instead.
*/
Attribute.prototype.preferredQuoteMark = function preferredQuoteMark(options) {
var quoteMark = options.preferCurrentQuoteMark ? this.quoteMark : options.quoteMark;
if (quoteMark === undefined) {
quoteMark = options.preferCurrentQuoteMark ? options.quoteMark : this.quoteMark;
}
if (quoteMark === undefined) {
quoteMark = Attribute.DOUBLE_QUOTE;
}
return quoteMark;
};
Attribute.prototype._syncRawValue = function _syncRawValue() {
var rawValue = (0, _cssesc2.default)(this._value, CSSESC_QUOTE_OPTIONS[this.quoteMark]);
if (rawValue === this._value) {
if (this.raws) {
delete this.raws.value;
}
} else {
this.raws.value = rawValue;
}
};
Attribute.prototype._handleEscapes = function _handleEscapes(prop, value) {
if (this._constructed) {
var escaped = (0, _cssesc2.default)(value, { isIdentifier: true });
if (escaped !== value) {
this.raws[prop] = escaped;
} else {
delete this.raws[prop];
}
}
};
Attribute.prototype._spacesFor = function _spacesFor(name) {

@@ -47,6 +260,2 @@ var attrSpaces = { before: '', after: '' };

Attribute.prototype._valueFor = function _valueFor(name) {
return this.raws[name] || this[name];
};
Attribute.prototype._stringFor = function _stringFor(name) {

@@ -57,3 +266,3 @@ var spaceName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : name;

var attrSpaces = this._spacesFor(spaceName);
return concat(this._valueFor(name), attrSpaces);
return concat(this.stringifyProperty(name), attrSpaces);
};

@@ -96,7 +305,7 @@

count += this._valueFor("attribute").length;
count += this.stringifyProperty("attribute").length;
count += attributeSpaces.after.length;
var operatorSpaces = this._spacesFor("operator");
count += operatorSpaces.before.length;
var operator = this._valueFor("operator");
var operator = this.stringifyProperty("operator");
if (name === "operator") {

@@ -110,3 +319,3 @@ return operator ? count : -1;

count += valueSpaces.before.length;
var value = this._valueFor("value");
var value = this.stringifyProperty("value");
if (name === "value") {

@@ -129,3 +338,3 @@ return value ? count : -1;

var selector = [this.spaces.before, '['];
var selector = [this.rawSpaceBefore, '['];

@@ -146,3 +355,3 @@ selector.push(this._stringFor('qualifiedAttribute', 'attribute'));

selector.push(']');
selector.push(this.spaces.after);
selector.push(this.rawSpaceAfter);
return selector.join('');

@@ -152,8 +361,49 @@ };

_createClass(Attribute, [{
key: 'qualifiedAttribute',
key: "quoted",
get: function get() {
var qm = this.quoteMark;
return qm === "'" || qm === '"';
},
set: function set(value) {
warnOfDeprecatedQuotedAssignment();
}
/**
* returns a single (`'`) or double (`"`) quote character if the value is quoted.
* returns `null` if the value is not quoted.
* returns `undefined` if the quotation state is unknown (this can happen when
* the attribute is constructed without specifying a quote mark.)
*/
}, {
key: "quoteMark",
get: function get() {
return this._quoteMark;
}
/**
* Set the quote mark to be used by this attribute's value.
* If the quote mark changes, the raw (escaped) value at `attr.raws.value` of the attribute
* value is updated accordingly.
*
* @param {"'" | '"' | null} quoteMark The quote mark or `null` if the value should be unquoted.
*/
,
set: function set(quoteMark) {
if (!this._constructed) {
this._quoteMark = quoteMark;
return;
}
if (this._quoteMark !== quoteMark) {
this._quoteMark = quoteMark;
this._syncRawValue();
}
}
}, {
key: "qualifiedAttribute",
get: function get() {
return this.qualifiedName(this.raws.attribute || this.attribute);
}
}, {
key: 'insensitiveFlag',
key: "insensitiveFlag",
get: function get() {

@@ -163,33 +413,48 @@ return this.insensitive ? 'i' : '';

}, {
key: 'value',
key: "value",
get: function get() {
return this._value;
},
set: function set(v) {
this._value = v;
if (this._constructed) {
delete this.raws.value;
}
}
}, {
key: 'namespace',
get: function get() {
return this._namespace;
},
/**
* Before 3.0, the value had to be set to an escaped value including any wrapped
* quote marks. In 3.0, the semantics of `Attribute.value` changed so that the value
* is unescaped during parsing and any quote marks are removed.
*
* Because the ambiguity of this semantic change, if you set `attr.value = newValue`,
* a deprecation warning is raised when the new value contains any characters that would
* require escaping (including if it contains wrapped quotes).
*
* Instead, you should call `attr.setValue(newValue, opts)` and pass options that describe
* how the new value is quoted.
*/
,
set: function set(v) {
this._namespace = v;
if (this._constructed) {
delete this.raws.namespace;
var _unescapeValue2 = unescapeValue(v),
deprecatedUsage = _unescapeValue2.deprecatedUsage,
unescaped = _unescapeValue2.unescaped,
quoteMark = _unescapeValue2.quoteMark;
if (deprecatedUsage) {
warnOfDeprecatedValueAssignment();
}
if (unescaped === this._value && quoteMark === this._quoteMark) {
return;
}
this._value = unescaped;
this._quoteMark = quoteMark;
this._syncRawValue();
} else {
this._value = v;
}
}
}, {
key: 'attribute',
key: "attribute",
get: function get() {
return this._attribute;
},
set: function set(v) {
this._attribute = v;
if (this._constructed) {
delete this.raws.attibute;
}
set: function set(name) {
this._handleEscapes("attribute", name);
this._attribute = name;
}

@@ -201,8 +466,15 @@ }]);

Attribute.NO_QUOTE = null;
Attribute.SINGLE_QUOTE = "'";
Attribute.DOUBLE_QUOTE = '"';
exports.default = Attribute;
var CSSESC_QUOTE_OPTIONS = (_CSSESC_QUOTE_OPTIONS = {
"'": { quotes: 'single', wrap: true },
'"': { quotes: 'double', wrap: true }
}, _CSSESC_QUOTE_OPTIONS[null] = { isIdentifier: true }, _CSSESC_QUOTE_OPTIONS);
function defaultAttrConcat(attrValue, attrSpaces) {
return '' + attrSpaces.before + attrValue + attrSpaces.after;
}
module.exports = exports['default'];
return "" + attrSpaces.before + attrValue + attrSpaces.after;
}

@@ -5,6 +5,14 @@ 'use strict';

var _namespace = require('./namespace');
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _namespace2 = _interopRequireDefault(_namespace);
var _cssesc = require('cssesc');
var _cssesc2 = _interopRequireDefault(_cssesc);
var _util = require('../util');
var _node = require('./node');
var _node2 = _interopRequireDefault(_node);
var _types = require('./types');

@@ -20,4 +28,4 @@

var ClassName = function (_Namespace) {
_inherits(ClassName, _Namespace);
var ClassName = function (_Node) {
_inherits(ClassName, _Node);

@@ -27,5 +35,6 @@ function ClassName(opts) {

var _this = _possibleConstructorReturn(this, _Namespace.call(this, opts));
var _this = _possibleConstructorReturn(this, _Node.call(this, opts));
_this.type = _types.CLASS;
_this._constructed = true;
return _this;

@@ -35,9 +44,28 @@ }

ClassName.prototype.toString = function toString() {
return [this.spaces.before, this.ns, String('.' + this.value), this.spaces.after].join('');
return [this.rawSpaceBefore, String('.' + this.stringifyProperty("value")), this.rawSpaceAfter].join('');
};
_createClass(ClassName, [{
key: 'value',
set: function set(v) {
if (this._constructed) {
var escaped = (0, _cssesc2.default)(v, { isIdentifier: true });
if (escaped !== v) {
(0, _util.ensureObject)(this, "raws");
this.raws.value = escaped;
} else if (this.raws) {
delete this.raws.value;
}
}
this._value = v;
},
get: function get() {
return this._value;
}
}]);
return ClassName;
}(_namespace2.default);
}(_node2.default);
exports.default = ClassName;
module.exports = exports['default'];

@@ -53,3 +53,3 @@ "use strict";

function isNamespace(node) {
return isClassName(node) || isAttribute(node) || isTag(node);
return isAttribute(node) || isTag(node);
}

@@ -5,5 +5,5 @@ 'use strict';

var _namespace = require('./namespace');
var _node = require('./node');
var _namespace2 = _interopRequireDefault(_namespace);
var _node2 = _interopRequireDefault(_node);

@@ -20,4 +20,4 @@ var _types = require('./types');

var ID = function (_Namespace) {
_inherits(ID, _Namespace);
var ID = function (_Node) {
_inherits(ID, _Node);

@@ -27,3 +27,3 @@ function ID(opts) {

var _this = _possibleConstructorReturn(this, _Namespace.call(this, opts));
var _this = _possibleConstructorReturn(this, _Node.call(this, opts));

@@ -35,9 +35,9 @@ _this.type = _types.ID;

ID.prototype.toString = function toString() {
return [this.spaces.before, this.ns, String('#' + this.value), this.spaces.after].join('');
return [this.rawSpaceBefore, String('#' + this.stringifyProperty("value")), this.rawSpaceAfter].join('');
};
return ID;
}(_namespace2.default);
}(_node2.default);
exports.default = ID;
module.exports = exports['default'];

@@ -7,2 +7,8 @@ 'use strict';

var _cssesc = require('cssesc');
var _cssesc2 = _interopRequireDefault(_cssesc);
var _util = require('../util');
var _node = require('./node');

@@ -38,3 +44,3 @@

Namespace.prototype.toString = function toString() {
return [this.spaces.before, this.qualifiedName(this.value), this.spaces.after].join('');
return [this.rawSpaceBefore, this.qualifiedName(this.stringifyProperty("value")), this.rawSpaceAfter].join('');
};

@@ -48,4 +54,16 @@

set: function set(namespace) {
if (namespace === true || namespace === "*" || namespace === "&") {
this._namespace = namespace;
if (this.raws) {
delete this.raws.namespace;
}
return;
}
var escaped = (0, _cssesc2.default)(namespace, { isIdentifier: true });
this._namespace = namespace;
if (this.raws) {
if (escaped !== namespace) {
(0, _util.ensureObject)(this, "raws");
this.raws.namespace = escaped;
} else if (this.raws) {
delete this.raws.namespace;

@@ -60,6 +78,3 @@ }

set: function set(namespace) {
this._namespace = namespace;
if (this.raws) {
delete this.raws.namespace;
}
this.namespace = namespace;
}

@@ -70,3 +85,3 @@ }, {

if (this.namespace) {
var ns = this.raws && this.raws.namespace || this.namespace;
var ns = this.stringifyProperty("namespace");
if (ns === true) {

@@ -73,0 +88,0 @@ return '';

@@ -5,4 +5,8 @@ 'use strict';

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _util = require('../util');
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

@@ -40,7 +44,7 @@

var _class = function () {
function _class() {
var Node = function () {
function Node() {
var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, _class);
_classCallCheck(this, Node);

@@ -53,3 +57,3 @@ Object.assign(this, opts);

_class.prototype.remove = function remove() {
Node.prototype.remove = function remove() {
if (this.parent) {

@@ -62,3 +66,3 @@ this.parent.removeChild(this);

_class.prototype.replaceWith = function replaceWith() {
Node.prototype.replaceWith = function replaceWith() {
if (this.parent) {

@@ -73,11 +77,11 @@ for (var index in arguments) {

_class.prototype.next = function next() {
Node.prototype.next = function next() {
return this.parent.at(this.parent.index(this) + 1);
};
_class.prototype.prev = function prev() {
Node.prototype.prev = function prev() {
return this.parent.at(this.parent.index(this) - 1);
};
_class.prototype.clone = function clone() {
Node.prototype.clone = function clone() {
var overrides = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

@@ -92,10 +96,101 @@

_class.prototype.toString = function toString() {
return [this.spaces.before, String(this.value), this.spaces.after].join('');
/**
* Some non-standard syntax doesn't follow normal escaping rules for css.
* This allows non standard syntax to be appended to an existing property
* by specifying the escaped value. By specifying the escaped value,
* illegal characters are allowed to be directly inserted into css output.
* @param {string} name the property to set
* @param {any} value the unescaped value of the property
* @param {string} valueEscaped optional. the escaped value of the property.
*/
Node.prototype.appendToPropertyAndEscape = function appendToPropertyAndEscape(name, value, valueEscaped) {
if (!this.raws) {
this.raws = {};
}
var originalValue = this[name];
var originalEscaped = this.raws[name];
this[name] = originalValue + value; // this may trigger a setter that updates raws, so it has to be set first.
if (originalEscaped || valueEscaped !== value) {
this.raws[name] = (originalEscaped || originalValue) + valueEscaped;
} else {
delete this.raws[name]; // delete any escaped value that was created by the setter.
}
};
return _class;
/**
* Some non-standard syntax doesn't follow normal escaping rules for css.
* This allows the escaped value to be specified directly, allowing illegal
* characters to be directly inserted into css output.
* @param {string} name the property to set
* @param {any} value the unescaped value of the property
* @param {string} valueEscaped the escaped value of the property.
*/
Node.prototype.setPropertyAndEscape = function setPropertyAndEscape(name, value, valueEscaped) {
if (!this.raws) {
this.raws = {};
}
this[name] = value; // this may trigger a setter that updates raws, so it has to be set first.
this.raws[name] = valueEscaped;
};
/**
* When you want a value to passed through to CSS directly. This method
* deletes the corresponding raw value causing the stringifier to fallback
* to the unescaped value.
* @param {string} name the property to set.
* @param {any} value The value that is both escaped and unescaped.
*/
Node.prototype.setPropertyWithoutEscape = function setPropertyWithoutEscape(name, value) {
this[name] = value; // this may trigger a setter that updates raws, so it has to be set first.
if (this.raws) {
delete this.raws[name];
}
};
Node.prototype.stringifyProperty = function stringifyProperty(name) {
return this.raws && this.raws[name] || this[name];
};
Node.prototype.toString = function toString() {
return [this.rawSpaceBefore, String(this.stringifyProperty("value")), this.rawSpaceAfter].join('');
};
_createClass(Node, [{
key: 'rawSpaceBefore',
get: function get() {
var rawSpace = this.raws && this.raws.spaces && this.raws.spaces.before;
if (rawSpace === undefined) {
rawSpace = this.spaces && this.spaces.before;
}
return rawSpace || "";
},
set: function set(raw) {
(0, _util.ensureObject)(this, "raws", "spaces");
this.raws.spaces.before = raw;
}
}, {
key: 'rawSpaceAfter',
get: function get() {
var rawSpace = this.raws && this.raws.spaces && this.raws.spaces.after;
if (rawSpace === undefined) {
rawSpace = this.spaces.after;
}
return rawSpace || "";
},
set: function set(raw) {
(0, _util.ensureObject)(this, "raws", "spaces");
this.raws.spaces.after = raw;
}
}]);
return Node;
}();
exports.default = _class;
exports.default = Node;
module.exports = exports['default'];

@@ -33,3 +33,3 @@ 'use strict';

var params = this.length ? '(' + this.map(String).join(',') + ')' : '';
return [this.spaces.before, String(this.value), params, this.spaces.after].join('');
return [this.rawSpaceBefore, this.stringifyProperty("value"), params, this.rawSpaceAfter].join('');
};

@@ -36,0 +36,0 @@

@@ -35,5 +35,5 @@ 'use strict';

var str = this.reduce(function (memo, selector) {
var sel = String(selector);
return sel ? memo + sel + ',' : '';
}, '').slice(0, -1);
memo.push(String(selector));
return memo;
}, []).join(',');
return this.trailingComma ? str + ',' : str;

@@ -40,0 +40,0 @@ };

'use strict';
exports.__esModule = true;
exports.FIELDS = undefined;
var _unescapable, _wordDelimiters;
exports.default = tokenize;

@@ -12,4 +16,72 @@

var wordEnd = /[ \n\t\r\(\)\*:;!&'"\+\|~>,=$^\[\]\\]|\/(?=\*)/g;
var unescapable = (_unescapable = {}, _unescapable[t.tab] = true, _unescapable[t.newline] = true, _unescapable[t.cr] = true, _unescapable[t.feed] = true, _unescapable);
var wordDelimiters = (_wordDelimiters = {}, _wordDelimiters[t.space] = true, _wordDelimiters[t.tab] = true, _wordDelimiters[t.newline] = true, _wordDelimiters[t.cr] = true, _wordDelimiters[t.feed] = true, _wordDelimiters[t.ampersand] = true, _wordDelimiters[t.asterisk] = true, _wordDelimiters[t.bang] = true, _wordDelimiters[t.comma] = true, _wordDelimiters[t.colon] = true, _wordDelimiters[t.semicolon] = true, _wordDelimiters[t.openParenthesis] = true, _wordDelimiters[t.closeParenthesis] = true, _wordDelimiters[t.openSquare] = true, _wordDelimiters[t.closeSquare] = true, _wordDelimiters[t.singleQuote] = true, _wordDelimiters[t.doubleQuote] = true, _wordDelimiters[t.plus] = true, _wordDelimiters[t.pipe] = true, _wordDelimiters[t.tilde] = true, _wordDelimiters[t.greaterThan] = true, _wordDelimiters[t.equals] = true, _wordDelimiters[t.dollar] = true, _wordDelimiters[t.caret] = true, _wordDelimiters[t.slash] = true, _wordDelimiters);
var hex = {};
var hexChars = "0123456789abcdefABCDEF";
for (var i = 0; i < hexChars.length; i++) {
hex[hexChars.charCodeAt(i)] = true;
}
/**
* Returns the last index of the bar css word
* @param {string} css The string in which the word begins
* @param {number} start The index into the string where word's first letter occurs
*/
function consumeWord(css, start) {
var next = start;
var code = void 0;
do {
code = css.charCodeAt(next);
if (wordDelimiters[code]) {
return next - 1;
} else if (code === t.backslash) {
next = consumeEscape(css, next) + 1;
} else {
// All other characters are part of the word
next++;
}
} while (next < css.length);
return next - 1;
}
/**
* Returns the last index of the escape sequence
* @param {string} css The string in which the sequence begins
* @param {number} start The index into the string where escape character (`\`) occurs.
*/
function consumeEscape(css, start) {
var next = start;
var code = css.charCodeAt(next + 1);
if (unescapable[code]) {
// just consume the escape char
} else if (hex[code]) {
var hexDigits = 0;
// consume up to 6 hex chars
do {
next++;
hexDigits++;
code = css.charCodeAt(next + 1);
} while (hex[code] && hexDigits < 6);
// if fewer than 6 hex chars, a trailing space ends the escape
if (hexDigits < 6 && code === t.space) {
next++;
}
} else {
// the next char is part of the current word
next++;
}
return next;
}
var FIELDS = exports.FIELDS = {
TYPE: 0,
START_LINE: 1,
START_COL: 2,
END_LINE: 3,
END_COL: 4,
START_POS: 5,
END_POS: 6
};
function tokenize(input) {

@@ -59,5 +131,5 @@ var tokens = [];

switch (code) {
case t.newline:
case t.space:
case t.tab:
case t.newline:
case t.cr:

@@ -140,20 +212,2 @@ case t.feed:

case t.backslash:
next = start;
escaped = true;
while (css.charCodeAt(next + 1) === t.backslash) {
next += 1;
escaped = !escaped;
}
code = css.charCodeAt(next + 1);
if (escaped && code !== t.slash && code !== t.space && code !== t.newline && code !== t.tab && code !== t.cr && code !== t.feed) {
next += 1;
}
tokenType = t.word;
endLine = line;
endColumn = next - offset;
end = next + 1;
break;
default:

@@ -183,10 +237,3 @@ if (code === t.slash && css.charCodeAt(start + 1) === t.asterisk) {

} else {
wordEnd.lastIndex = start + 1;
wordEnd.test(css);
if (wordEnd.lastIndex === 0) {
next = css.length - 1;
} else {
next = wordEnd.lastIndex - 2;
}
next = consumeWord(css, start);
tokenType = t.word;

@@ -208,3 +255,4 @@ endLine = line;

start, // [5] Start position / Source index
end]);
end] // [6] End position
);

@@ -221,3 +269,2 @@ // Reset offset for the next token

return tokens;
}
module.exports = exports['default'];
}
'use strict';
exports.__esModule = true;
var ampersand = exports.ampersand = '&'.charCodeAt(0);
var asterisk = exports.asterisk = '*'.charCodeAt(0);
var at = exports.at = '@'.charCodeAt(0);
var comma = exports.comma = ','.charCodeAt(0);
var colon = exports.colon = ':'.charCodeAt(0);
var semicolon = exports.semicolon = ';'.charCodeAt(0);
var openParenthesis = exports.openParenthesis = '('.charCodeAt(0);
var closeParenthesis = exports.closeParenthesis = ')'.charCodeAt(0);
var openSquare = exports.openSquare = '['.charCodeAt(0);
var closeSquare = exports.closeSquare = ']'.charCodeAt(0);
var dollar = exports.dollar = '$'.charCodeAt(0);
var tilde = exports.tilde = '~'.charCodeAt(0);
var caret = exports.caret = '^'.charCodeAt(0);
var plus = exports.plus = '+'.charCodeAt(0);
var equals = exports.equals = '='.charCodeAt(0);
var pipe = exports.pipe = '|'.charCodeAt(0);
var greaterThan = exports.greaterThan = '>'.charCodeAt(0);
var space = exports.space = ' '.charCodeAt(0);
var singleQuote = exports.singleQuote = '\''.charCodeAt(0);
var doubleQuote = exports.doubleQuote = '"'.charCodeAt(0);
var slash = exports.slash = '/'.charCodeAt(0);
var ampersand = exports.ampersand = 38;
var asterisk = exports.asterisk = 42;
var at = exports.at = 64;
var comma = exports.comma = 44;
var colon = exports.colon = 58;
var semicolon = exports.semicolon = 59;
var openParenthesis = exports.openParenthesis = 40;
var closeParenthesis = exports.closeParenthesis = 41;
var openSquare = exports.openSquare = 91;
var closeSquare = exports.closeSquare = 93;
var dollar = exports.dollar = 36;
var tilde = exports.tilde = 126;
var caret = exports.caret = 94;
var plus = exports.plus = 43;
var equals = exports.equals = 61;
var pipe = exports.pipe = 124;
var greaterThan = exports.greaterThan = 62;
var space = exports.space = 32;
var singleQuote = exports.singleQuote = 39;
var doubleQuote = exports.doubleQuote = 34;
var slash = exports.slash = 47;
var bang = exports.bang = 33;

@@ -26,0 +27,0 @@ var backslash = exports.backslash = 92;

{
"name": "postcss-selector-parser",
"version": "3.1.1",
"version": "4.0.0-rc.0",
"devDependencies": {
"ava": "^0.20.0",
"ava": "^0.24.0",
"babel-cli": "^6.4.0",

@@ -22,4 +22,5 @@ "babel-core": "^6.4.0",

"minimist": "^1.2.0",
"nyc": "^10.0.0",
"postcss": "^6.0.6"
"nyc": "^11.4.1",
"postcss": "^6.0.6",
"semver": "^5.5.0"
},

@@ -38,7 +39,9 @@ "main": "dist/index.js",

"prepublish": "del-cli dist && BABEL_ENV=publish babel src --out-dir dist --ignore /__tests__/",
"lintfix": "eslint --fix src",
"report": "nyc report --reporter=html",
"test": "nyc ava src/__tests__/*.js"
"test": "nyc ava src/__tests__/*.js",
"testone": "ava"
},
"dependencies": {
"dot-prop": "^4.1.1",
"cssesc": "^1.0.1",
"indexes-of": "^1.0.1",

@@ -45,0 +48,0 @@ "uniq": "^1.0.1"

@@ -17,7 +17,8 @@ // Type definitions for postcss-selector-parser 2.2.3

// TODO: Conditional types in TS 1.8 will really clean this up.
declare function parser(): parser.Processor<never>;
declare function parser<Transform extends any>(processor: parser.AsyncProcessor<Transform>): parser.Processor<Transform, never>;
declare function parser(processor: parser.AsyncProcessor): parser.Processor<never>;
declare function parser<Transform extends any>(processor: parser.SyncProcessor<Transform>): parser.Processor<Transform, never>;
declare function parser(processor: parser.SyncProcessor): parser.Processor<never>;
declare function parser<Transform>(processor: parser.AsyncProcessor<Transform>): parser.Processor<Transform, never>;
declare function parser(processor: parser.AsyncProcessor<void>): parser.Processor<never, never>;
declare function parser<Transform>(processor: parser.SyncProcessor<Transform>): parser.Processor<Transform>;
declare function parser(processor: parser.SyncProcessor<void>): parser.Processor<never>;
declare function parser<Transform>(processor?: parser.SyncProcessor<Transform> | parser.AsyncProcessor<Transform>): parser.Processor<Transform>;

@@ -48,4 +49,5 @@

type Selectors = string | PostCSSRuleNode
type SyncProcessor<Transform = void> = (root: parser.Root) => Transform
type AsyncProcessor<Transform = void> = (root: parser.Root) => Transform | PromiseLike<Transform>
type ProcessorFn<ReturnType = void> = (root: parser.Root) => ReturnType;
type SyncProcessor<Transform = void> = ProcessorFn<Transform>;
type AsyncProcessor<Transform = void> = ProcessorFn<PromiseLike<Transform>>;

@@ -160,2 +162,4 @@ const TAG: "tag";

sourceIndex: number;
rawSpaceBefore: string;
rawSpaceAfter: string;
remove(): Node;

@@ -166,2 +170,29 @@ replaceWith(...nodes: Node[]): Node;

clone(opts: {[override: string]:any}): Node;
/**
* Some non-standard syntax doesn't follow normal escaping rules for css,
* this allows the escaped value to be specified directly, allowing illegal characters to be
* directly inserted into css output.
* @param name the property to set
* @param value the unescaped value of the property
* @param valueEscaped optional. the escaped value of the property.
*/
setPropertyAndEscape(name: string, value: any, valueEscaped: string);
/**
* When you want a value to passed through to CSS directly. This method
* deletes the corresponding raw value causing the stringifier to fallback
* to the unescaped value.
* @param name the property to set.
* @param value The value that is both escaped and unescaped.
*/
setPropertyWithoutEscape(name: string, value: any);
/**
* Some non-standard syntax doesn't follow normal escaping rules for css.
* This allows non standard syntax to be appended to an existing property
* by specifying the escaped value. By specifying the escaped value,
* illegal characters are allowed to be directly inserted into css output.
* @param {string} name the property to set
* @param {any} value the unescaped value of the property
* @param {string} valueEscaped optional. the escaped value of the property.
*/
appendToPropertyAndEscape(name, value, valueEscaped);
toString(): string;

@@ -226,3 +257,3 @@ }

}
function isNamespace(node: any): node is ClassName | Attribute | Tag;
function isNamespace(node: any): node is Attribute | Tag;

@@ -252,3 +283,3 @@ interface Root extends Container<undefined> {

interface ClassName extends Namespace {
interface ClassName extends Base {
type: "class";

@@ -260,2 +291,10 @@ }

type AttributeOperator = "=" | "~=" | "|=" | "^=" | "$=" | "*=";
type QuoteMark = '"' | "'" | null;
interface PreferredQuoteMarkOptions {
quoteMark?: QuoteMark;
preferCurrentQuoteMark?: boolean;
}
interface SmartQuoteMarkOptions extends PreferredQuoteMarkOptions {
smart?: boolean;
}
interface AttributeOptions extends NamespaceOptions<string | undefined> {

@@ -265,2 +304,4 @@ attribute: string;

insensitive?: boolean;
quoteMark?: QuoteMark;
/** @deprecated Use quoteMark instead. */
quoted?: boolean;

@@ -294,2 +335,3 @@ spaces?: {

insensitive?: boolean;
quoteMark: QuoteMark;
quoted?: boolean;

@@ -305,5 +347,7 @@ spaces: {

raws: {
/** @deprecated The attribute value is unquoted, use that instead.. */
unquoted?: string;
attribute?: string;
operator?: string;
/** The value of the attribute with quotes and escapes. */
value?: string;

@@ -322,3 +366,48 @@ insensitive?: string;

readonly qualifiedAttribute: string;
/**
* The case insensitivity flag or an empty string depending on whether this
* attribute is case insensitive.
*/
readonly insensitiveFlag : 'i' | '';
/**
* Returns the attribute's value quoted such that it would be legal to use
* in the value of a css file. The original value's quotation setting
* used for stringification is left unchanged. See `setValue(value, options)`
* if you want to control the quote settings of a new value for the attribute or
* `set quoteMark(mark)` if you want to change the quote settings of the current
* value.
*
* You can also change the quotation used for the current value by setting quoteMark.
**/
getQuotedValue(options?: SmartQuoteMarkOptions): string;
/**
* Set the unescaped value with the specified quotation options. The value
* provided must not include any wrapping quote marks -- those quotes will
* be interpreted as part of the value and escaped accordingly.
* @param value
*/
setValue(value: string, options?: SmartQuoteMarkOptions): void;
/**
* Intelligently select a quoteMark value based on the value's contents. If
* the value is a legal CSS ident, it will not be quoted. Otherwise a quote
* mark will be picked that minimizes the number of escapes.
*
* If there's no clear winner, the quote mark from these options is used,
* then the source quote mark (this is inverted if `preferCurrentQuoteMark` is
* true). If the quoteMark is unspecified, a double quote is used.
**/
smartQuoteMark(options: PreferredQuoteMarkOptions): QuoteMark;
/**
* Selects the preferred quote mark based on the options and the current quote mark value.
* If you want the quote mark to depend on the attribute value, call `smartQuoteMark(opts)`
* instead.
*/
preferredQuoteMark(options: PreferredQuoteMarkOptions): QuoteMark
/**
* returns the offset of the attribute part specified relative to the

@@ -325,0 +414,0 @@ * start of the node of the output string.