postcss-selector-parser
Advanced tools
Comparing version
@@ -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. |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
173848
24.98%35
12.9%3137
30.33%20
5.26%1
Infinity%+ Added
+ Added
- Removed
- Removed
- Removed