postcss-selector-parser
Advanced tools
Comparing version
57
API.md
@@ -11,3 +11,3 @@ # API Documentation | ||
```js | ||
var parser = require('postcss-selector-parser'); | ||
const parser = require('postcss-selector-parser'); | ||
``` | ||
@@ -20,7 +20,7 @@ | ||
```js | ||
var processor = parser(); | ||
const processor = parser(); | ||
// or, with optional transform function | ||
var transform = function (selectors) { | ||
selectors.eachUniversal(function (selector) { | ||
const transform = selectors => { | ||
selectors.eachUniversal(selector => { | ||
selector.remove(); | ||
@@ -30,6 +30,6 @@ }); | ||
var processor = parser(transform) | ||
const processor = parser(transform) | ||
// Example | ||
var result = processor.process('*.class').result; | ||
const result = processor.processSync('*.class'); | ||
// => .class | ||
@@ -228,3 +228,3 @@ ``` | ||
```js | ||
var id = parser.id({value: 'search'}); | ||
const id = parser.id({value: 'search'}); | ||
console.log(String(id)); | ||
@@ -239,3 +239,3 @@ // => #search | ||
```js | ||
var next = id.next(); | ||
const next = id.next(); | ||
if (next && next.type !== 'combinator') { | ||
@@ -251,4 +251,4 @@ throw new Error('Qualified IDs are not allowed!'); | ||
```js | ||
var attr = selectors.first.first; | ||
var className = parser.className({value: 'test'}); | ||
const attr = selectors.first.first; | ||
const className = parser.className({value: 'test'}); | ||
attr.replaceWith(className); | ||
@@ -277,3 +277,3 @@ ``` | ||
```js | ||
var cloned = parser.id({value: 'search'}); | ||
const cloned = parser.id({value: 'search'}); | ||
String(cloned); | ||
@@ -418,4 +418,4 @@ | ||
```js | ||
var className; | ||
selectors.each(function (selector, index) { | ||
let className; | ||
selectors.each((selector, index) => { | ||
if (selector.type === 'class') { | ||
@@ -442,3 +442,3 @@ className = selector.value; | ||
```js | ||
selectors.walk(function (selector, index) { | ||
selectors.walk((selector, index) => { | ||
// all nodes | ||
@@ -480,3 +480,3 @@ }); | ||
// (input) => h1 h2>>h3 | ||
var list = selectors.first.split((selector) => { | ||
const list = selectors.first.split(selector => { | ||
return selector.type === 'combinator'; | ||
@@ -499,3 +499,3 @@ }); | ||
```js | ||
var id = parser.id({value: 'search'}); | ||
const id = parser.id({value: 'search'}); | ||
selector.append(id); | ||
@@ -513,5 +513,5 @@ ``` | ||
```js | ||
selectors.walk(function (selector) { | ||
selectors.walk(selector => { | ||
if (selector.type !== 'class') { | ||
var className = parser.className({value: 'theme-name'}); | ||
const className = parser.className({value: 'theme-name'}); | ||
selector.parent.insertAfter(selector, className); | ||
@@ -614,15 +614,24 @@ } | ||
### `process(cssText, [options])` | ||
### `process|processSync(css, [options])` | ||
Processes the `cssText`, returning the parsed output | ||
Processes the `css`, returning the parsed output. An async method is exposed | ||
as `process`. | ||
```js | ||
var processor = parser(); | ||
const processor = parser(); | ||
var result = processor.process(' .class').result; | ||
const result = processor.processSync(' .class'); | ||
// => .class | ||
// Asynchronous operation | ||
processor.process(' .class').then(result => /* ... */); | ||
// To have the parser normalize whitespace values, utilize the options | ||
var result = processor.process(' .class ', {lossless: false}).result; | ||
const result = processor.processSync(' .class ', {lossless: false}); | ||
// => .class | ||
// For better syntax errors, pass a PostCSS Rule node. | ||
const postcss = require('postcss'); | ||
const rule = postcss.rule({selector: 'a'}); | ||
const result = process.process(rule); | ||
``` | ||
@@ -632,3 +641,3 @@ | ||
* `cssText (string)`: The css to be parsed. | ||
* `css (string|object)`: Either a selector string or a PostCSS Rule node. | ||
* `[options] (object)`: Process options | ||
@@ -635,0 +644,0 @@ |
@@ -0,1 +1,22 @@ | ||
# 3.0.0-rc.0 | ||
## Breaking changes | ||
* Some tweaks to the tokenizer/attribute selector parsing mean that whitespace | ||
locations might be slightly different to the 2.x code. | ||
* Better attribute selector parsing with more validation; postcss-selector-parser | ||
no longer uses regular expressions to parse attribute selectors. | ||
* Added an async API (thanks to @jacobp100); the default `process` API is now | ||
async, and the sync API is now accessed through `processSync` instead. | ||
* Tweaks handling of Less interpolation (thanks to @jwilsson). | ||
* Removes support for Node 0.12. | ||
## Other changes | ||
* Set the parent when inserting a node (thanks to @chriseppstein). | ||
* Correctly adjust indices when using insertBefore/insertAfter (thanks to @tivac). | ||
* Fixes handling of namespaces with qualified tag selectors. | ||
* Now accepts a PostCSS rule node for better syntax errors. | ||
* Now more memory efficient when tokenizing selectors. | ||
# 2.2.3 | ||
@@ -2,0 +23,0 @@ |
@@ -7,5 +7,5 @@ 'use strict'; | ||
var _flatten = require('flatten'); | ||
var _dotProp = require('dot-prop'); | ||
var _flatten2 = _interopRequireDefault(_flatten); | ||
var _dotProp2 = _interopRequireDefault(_dotProp); | ||
@@ -76,2 +76,6 @@ var _indexesOf = require('indexes-of'); | ||
var _tokenTypes = require('./tokenTypes'); | ||
var tokens = _interopRequireWildcard(_tokenTypes); | ||
var _types = require('./selectors/types'); | ||
@@ -87,2 +91,15 @@ | ||
function getSource(startLine, startColumn, endLine, endColumn) { | ||
return { | ||
start: { | ||
line: startLine, | ||
column: startColumn | ||
}, | ||
end: { | ||
line: endLine, | ||
column: endColumn | ||
} | ||
}; | ||
} | ||
var Parser = function () { | ||
@@ -97,10 +114,13 @@ function Parser(input) { | ||
var selectors = new _selector2.default(); | ||
this.root.append(selectors); | ||
var selector = new _selector2.default(); | ||
this.root.append(selector); | ||
this.current = selector; | ||
this.current = selectors; | ||
this.css = typeof input.css === 'string' ? input.css : input.css.selector; | ||
if (this.lossy) { | ||
this.tokens = (0, _tokenize2.default)({ safe: input.safe, css: input.css.trim() }); | ||
this.css = this.css.trim(); | ||
this.tokens = (0, _tokenize2.default)({ safe: input.safe, css: this.css }); | ||
} else { | ||
this.tokens = (0, _tokenize2.default)(input); | ||
this.tokens = (0, _tokenize2.default)(Object.assign({}, input, { css: this.css })); | ||
} | ||
@@ -112,55 +132,136 @@ | ||
Parser.prototype.attribute = function attribute() { | ||
var str = ''; | ||
var attr = void 0; | ||
var attr = []; | ||
var startingToken = this.currToken; | ||
this.position++; | ||
while (this.position < this.tokens.length && this.currToken[0] !== ']') { | ||
str += this.tokens[this.position][1]; | ||
while (this.position < this.tokens.length && this.currToken[0] !== tokens.closeSquare) { | ||
attr.push(this.currToken); | ||
this.position++; | ||
} | ||
if (this.position === this.tokens.length && !~str.indexOf(']')) { | ||
this.error('Expected a closing square bracket.'); | ||
if (this.currToken[0] !== tokens.closeSquare) { | ||
return this.expected('closing square bracket', this.currToken[5]); | ||
} | ||
var parts = str.split(/((?:[*~^$|]?=))([^]*)/); | ||
var namespace = parts[0].split(/(\|)/g); | ||
var attributeProps = { | ||
operator: parts[1], | ||
value: parts[2], | ||
source: { | ||
start: { | ||
line: startingToken[2], | ||
column: startingToken[3] | ||
}, | ||
end: { | ||
line: this.currToken[2], | ||
column: this.currToken[3] | ||
} | ||
}, | ||
sourceIndex: startingToken[4] | ||
var len = attr.length; | ||
var node = { | ||
source: getSource(startingToken[1], startingToken[2], this.currToken[3], this.currToken[4]), | ||
sourceIndex: startingToken[5] | ||
}; | ||
if (namespace.length > 1) { | ||
if (namespace[0] === '') { | ||
namespace[0] = true; | ||
} | ||
attributeProps.attribute = this.parseValue(namespace[2]); | ||
attributeProps.namespace = this.parseNamespace(namespace[0]); | ||
} else { | ||
attributeProps.attribute = this.parseValue(parts[0]); | ||
if (len === 1 && !~[tokens.word].indexOf(attr[0][0])) { | ||
return this.expected('attribute', attr[0][5]); | ||
} | ||
attr = new _attribute2.default(attributeProps); | ||
if (parts[2]) { | ||
var insensitive = parts[2].split(/(\s+i\s*?)$/); | ||
var trimmedValue = insensitive[0].trim(); | ||
attr.value = this.lossy ? trimmedValue : insensitive[0]; | ||
if (insensitive[1]) { | ||
attr.insensitive = true; | ||
if (!this.lossy) { | ||
attr.raws.insensitive = insensitive[1]; | ||
} | ||
var pos = 0; | ||
var spaceBefore = ''; | ||
var commentBefore = ''; | ||
var lastAdded = null; | ||
while (pos < len) { | ||
var token = attr[pos]; | ||
var content = this.content(token); | ||
var next = attr[pos + 1]; | ||
switch (token[0]) { | ||
case tokens.space: | ||
if (len === 1 || pos === 0 && this.content(next) === '|') { | ||
return this.expected('attribute', token[5], content); | ||
} | ||
if (this.lossy) { | ||
break; | ||
} | ||
if (!lastAdded || this.content(next) === 'i') { | ||
spaceBefore = content; | ||
} else { | ||
_dotProp2.default.set(node, lastAdded, _dotProp2.default.get(node, lastAdded) + content); | ||
} | ||
break; | ||
case tokens.asterisk: | ||
if (next[0] === tokens.equals) { | ||
node.operator = content; | ||
lastAdded = 'operator'; | ||
} else if (!node.namespace && next) { | ||
node.namespace = '' + this.parseSpace(spaceBefore) + content; | ||
lastAdded = 'namespace'; | ||
spaceBefore = ''; | ||
} | ||
break; | ||
case tokens.dollar: | ||
case tokens.caret: | ||
if (next[0] === tokens.equals) { | ||
node.operator = content; | ||
lastAdded = 'operator'; | ||
} | ||
break; | ||
case tokens.combinator: | ||
if (content === '~' && next[0] === tokens.equals) { | ||
node.operator = content; | ||
lastAdded = 'operator'; | ||
} | ||
if (content !== '|') { | ||
break; | ||
} | ||
if (next[0] === tokens.equals) { | ||
node.operator = content; | ||
lastAdded = 'operator'; | ||
} else if (!node.namespace && !node.attribute) { | ||
node.namespace = true; | ||
} | ||
break; | ||
case tokens.word: | ||
if (next && this.content(next) === '|' && attr[pos + 2] && attr[pos + 2][0] !== tokens.equals && !node.operator && !node.namespace) { | ||
node.namespace = content; | ||
lastAdded = 'namespace'; | ||
} else if (!node.attribute) { | ||
node.attribute = '' + this.parseSpace(spaceBefore) + commentBefore + content; | ||
lastAdded = 'attribute'; | ||
spaceBefore = ''; | ||
commentBefore = ''; | ||
} else if (!node.value) { | ||
node.value = content; | ||
lastAdded = 'value'; | ||
_dotProp2.default.set(node, 'raws.unquoted', content); | ||
} else if (content === 'i') { | ||
node.insensitive = true; | ||
if (!this.lossy) { | ||
lastAdded = 'raws.insensitive'; | ||
_dotProp2.default.set(node, lastAdded, '' + spaceBefore + content); | ||
spaceBefore = ''; | ||
} | ||
} | ||
break; | ||
case tokens.str: | ||
if (!node.attribute || !node.operator) { | ||
return this.error('Expected an attribute followed by an operator preceding the string.', { | ||
index: token[5] | ||
}); | ||
} | ||
node.value = content; | ||
node.quoted = true; | ||
lastAdded = 'value'; | ||
_dotProp2.default.set(node, 'raws.unquoted', content.slice(1, -1)); | ||
break; | ||
case tokens.equals: | ||
if (!node.attribute) { | ||
return this.expected('attribute', token[5], content); | ||
} | ||
if (node.value) { | ||
return this.error('Unexpected "=" found; an operator was already defined.', { index: token[5] }); | ||
} | ||
node.operator = node.operator ? '' + node.operator + content : content; | ||
lastAdded = 'operator'; | ||
break; | ||
case tokens.comment: | ||
if (lastAdded) { | ||
_dotProp2.default.set(node, lastAdded, _dotProp2.default.get(node, lastAdded) + content); | ||
} else { | ||
commentBefore = content; | ||
} | ||
break; | ||
default: | ||
return this.error('Unexpected "' + content + '" found.', { index: token[5] }); | ||
} | ||
attr.quoted = trimmedValue[0] === '\'' || trimmedValue[0] === '"'; | ||
attr.raws.unquoted = attr.quoted ? trimmedValue.slice(1, -1) : trimmedValue; | ||
pos++; | ||
} | ||
this.newNode(attr); | ||
this.newNode(new _attribute2.default(node)); | ||
this.position++; | ||
@@ -170,3 +271,4 @@ }; | ||
Parser.prototype.combinator = function combinator() { | ||
if (this.currToken[1] === '|') { | ||
var current = this.currToken; | ||
if (this.content() === '|') { | ||
return this.namespace(); | ||
@@ -176,28 +278,17 @@ } | ||
value: '', | ||
source: { | ||
start: { | ||
line: this.currToken[2], | ||
column: this.currToken[3] | ||
}, | ||
end: { | ||
line: this.currToken[2], | ||
column: this.currToken[3] | ||
} | ||
}, | ||
sourceIndex: this.currToken[4] | ||
source: getSource(current[1], current[2], current[3], current[4]), | ||
sourceIndex: current[5] | ||
}); | ||
while (this.position < this.tokens.length && this.currToken && (this.currToken[0] === 'space' || this.currToken[0] === 'combinator')) { | ||
if (this.nextToken && this.nextToken[0] === 'combinator') { | ||
node.spaces.before = this.parseSpace(this.currToken[1]); | ||
node.source.start.line = this.nextToken[2]; | ||
node.source.start.column = this.nextToken[3]; | ||
node.source.end.column = this.nextToken[3]; | ||
node.source.end.line = this.nextToken[2]; | ||
node.sourceIndex = this.nextToken[4]; | ||
} else if (this.prevToken && this.prevToken[0] === 'combinator') { | ||
node.spaces.after = this.parseSpace(this.currToken[1]); | ||
} else if (this.currToken[0] === 'combinator') { | ||
node.value = this.currToken[1]; | ||
} else if (this.currToken[0] === 'space') { | ||
node.value = this.parseSpace(this.currToken[1], ' '); | ||
while (this.position < this.tokens.length && this.currToken && (this.currToken[0] === tokens.space || this.currToken[0] === 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) { | ||
node.value = content; | ||
} else if (this.currToken[0] === tokens.space) { | ||
node.value = this.parseSpace(content, ' '); | ||
} | ||
@@ -215,5 +306,5 @@ this.position++; | ||
} | ||
var selectors = new _selector2.default(); | ||
this.current.parent.append(selectors); | ||
this.current = selectors; | ||
var selector = new _selector2.default(); | ||
this.current.parent.append(selector); | ||
this.current = selector; | ||
this.position++; | ||
@@ -223,42 +314,35 @@ }; | ||
Parser.prototype.comment = function comment() { | ||
var node = new _comment2.default({ | ||
value: this.currToken[1], | ||
source: { | ||
start: { | ||
line: this.currToken[2], | ||
column: this.currToken[3] | ||
}, | ||
end: { | ||
line: this.currToken[4], | ||
column: this.currToken[5] | ||
} | ||
}, | ||
sourceIndex: this.currToken[6] | ||
}); | ||
this.newNode(node); | ||
var current = this.currToken; | ||
this.newNode(new _comment2.default({ | ||
value: this.content(), | ||
source: getSource(current[1], current[2], current[3], current[4]), | ||
sourceIndex: current[5] | ||
})); | ||
this.position++; | ||
}; | ||
Parser.prototype.error = function error(message) { | ||
throw new this.input.error(message); // eslint-disable-line new-cap | ||
Parser.prototype.error = function error(message, opts) { | ||
throw new this.input.error(message, opts); // eslint-disable-line new-cap | ||
}; | ||
Parser.prototype.missingBackslash = function missingBackslash() { | ||
return this.error('Expected a backslash preceding the semicolon.'); | ||
return this.error('Expected a backslash preceding the semicolon.', { | ||
index: this.currToken[5] | ||
}); | ||
}; | ||
Parser.prototype.missingParenthesis = function missingParenthesis() { | ||
return this.error('Expected opening parenthesis.'); | ||
return this.expected('opening parenthesis', this.currToken[5]); | ||
}; | ||
Parser.prototype.missingSquareBracket = function missingSquareBracket() { | ||
return this.error('Expected opening square bracket.'); | ||
return this.expected('opening square bracket', this.currToken[5]); | ||
}; | ||
Parser.prototype.namespace = function namespace() { | ||
var before = this.prevToken && this.prevToken[1] || true; | ||
if (this.nextToken[0] === 'word') { | ||
var before = this.prevToken && this.content(this.prevToken) || true; | ||
if (this.nextToken[0] === tokens.word) { | ||
this.position++; | ||
return this.word(before); | ||
} else if (this.nextToken[0] === '*') { | ||
} else if (this.nextToken[0] === tokens.asterisk) { | ||
this.position++; | ||
@@ -270,15 +354,7 @@ return this.universal(before); | ||
Parser.prototype.nesting = function nesting() { | ||
var current = this.currToken; | ||
this.newNode(new _nesting2.default({ | ||
value: this.currToken[1], | ||
source: { | ||
start: { | ||
line: this.currToken[2], | ||
column: this.currToken[3] | ||
}, | ||
end: { | ||
line: this.currToken[2], | ||
column: this.currToken[3] | ||
} | ||
}, | ||
sourceIndex: this.currToken[4] | ||
value: this.content(), | ||
source: getSource(current[1], current[2], current[3], current[4]), | ||
sourceIndex: current[5] | ||
})); | ||
@@ -290,2 +366,4 @@ this.position++; | ||
var last = this.current.last; | ||
var balanced = 1; | ||
this.position++; | ||
if (last && last.type === types.PSEUDO) { | ||
@@ -296,9 +374,7 @@ var selector = new _selector2.default(); | ||
this.current = selector; | ||
var balanced = 1; | ||
this.position++; | ||
while (this.position < this.tokens.length && balanced) { | ||
if (this.currToken[0] === '(') { | ||
if (this.currToken[0] === tokens.openParenthesis) { | ||
balanced++; | ||
} | ||
if (this.currToken[0] === ')') { | ||
if (this.currToken[0] === tokens.closeParenthesis) { | ||
balanced--; | ||
@@ -309,21 +385,16 @@ } | ||
} else { | ||
selector.parent.source.end.line = this.currToken[2]; | ||
selector.parent.source.end.column = this.currToken[3]; | ||
selector.parent.source.end.line = this.currToken[3]; | ||
selector.parent.source.end.column = this.currToken[4]; | ||
this.position++; | ||
} | ||
} | ||
if (balanced) { | ||
this.error('Expected closing parenthesis.'); | ||
} | ||
this.current = cache; | ||
} else { | ||
var _balanced = 1; | ||
this.position++; | ||
last.value += '('; | ||
while (this.position < this.tokens.length && _balanced) { | ||
if (this.currToken[0] === '(') { | ||
_balanced++; | ||
while (this.position < this.tokens.length && balanced) { | ||
if (this.currToken[0] === tokens.openParenthesis) { | ||
balanced++; | ||
} | ||
if (this.currToken[0] === ')') { | ||
_balanced--; | ||
if (this.currToken[0] === tokens.closeParenthesis) { | ||
balanced--; | ||
} | ||
@@ -333,6 +404,6 @@ last.value += this.parseParenthesisToken(this.currToken); | ||
} | ||
if (_balanced) { | ||
this.error('Expected closing parenthesis.'); | ||
} | ||
} | ||
if (balanced) { | ||
return this.expected('closing parenthesis', this.currToken[5]); | ||
} | ||
}; | ||
@@ -345,34 +416,25 @@ | ||
var startingToken = this.currToken; | ||
while (this.currToken && this.currToken[0] === ':') { | ||
pseudoStr += this.currToken[1]; | ||
while (this.currToken && this.currToken[0] === tokens.colon) { | ||
pseudoStr += this.content(); | ||
this.position++; | ||
} | ||
if (!this.currToken) { | ||
return this.error('Expected pseudo-class or pseudo-element'); | ||
return this.expected(['pseudo-class', 'pseudo-element'], this.position - 1); | ||
} | ||
if (this.currToken[0] === 'word') { | ||
var pseudo = void 0; | ||
if (this.currToken[0] === tokens.word) { | ||
this.splitWord(false, function (first, length) { | ||
pseudoStr += first; | ||
pseudo = new _pseudo2.default({ | ||
_this.newNode(new _pseudo2.default({ | ||
value: pseudoStr, | ||
source: { | ||
start: { | ||
line: startingToken[2], | ||
column: startingToken[3] | ||
}, | ||
end: { | ||
line: _this.currToken[4], | ||
column: _this.currToken[5] | ||
} | ||
}, | ||
sourceIndex: startingToken[4] | ||
}); | ||
_this.newNode(pseudo); | ||
if (length > 1 && _this.nextToken && _this.nextToken[0] === '(') { | ||
_this.error('Misplaced parenthesis.'); | ||
source: getSource(startingToken[1], startingToken[2], _this.currToken[3], _this.currToken[4]), | ||
sourceIndex: startingToken[5] | ||
})); | ||
if (length > 1 && _this.nextToken && _this.nextToken[0] === tokens.openParenthesis) { | ||
_this.error('Misplaced parenthesis.', { | ||
index: _this.nextToken[5] | ||
}); | ||
} | ||
}); | ||
} else { | ||
this.error('Unexpected "' + this.currToken[0] + '" found.'); | ||
return this.expected(['pseudo-class', 'pseudo-element'], this.currToken[5]); | ||
} | ||
@@ -382,9 +444,9 @@ }; | ||
Parser.prototype.space = function space() { | ||
var token = this.currToken; | ||
var content = this.content(); | ||
// Handle space before and after the selector | ||
if (this.position === 0 || this.prevToken[0] === ',' || this.prevToken[0] === '(') { | ||
this.spaces = this.parseSpace(token[1]); | ||
if (this.position === 0 || this.prevToken[0] === tokens.comma || this.prevToken[0] === tokens.openParenthesis) { | ||
this.spaces = this.parseSpace(content); | ||
this.position++; | ||
} else if (this.position === this.tokens.length - 1 || this.nextToken[0] === ',' || this.nextToken[0] === ')') { | ||
this.current.last.spaces.after = this.parseSpace(token[1]); | ||
} 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); | ||
this.position++; | ||
@@ -397,16 +459,7 @@ } else { | ||
Parser.prototype.string = function string() { | ||
var token = this.currToken; | ||
var current = this.currToken; | ||
this.newNode(new _string2.default({ | ||
value: this.currToken[1], | ||
source: { | ||
start: { | ||
line: token[2], | ||
column: token[3] | ||
}, | ||
end: { | ||
line: token[4], | ||
column: token[5] | ||
} | ||
}, | ||
sourceIndex: token[6] | ||
value: this.content(), | ||
source: getSource(current[1], current[2], current[3], current[4]), | ||
sourceIndex: current[5] | ||
})); | ||
@@ -418,19 +471,11 @@ this.position++; | ||
var nextToken = this.nextToken; | ||
if (nextToken && nextToken[1] === '|') { | ||
if (nextToken && this.content(nextToken) === '|') { | ||
this.position++; | ||
return this.namespace(); | ||
} | ||
var current = this.currToken; | ||
this.newNode(new _universal2.default({ | ||
value: this.currToken[1], | ||
source: { | ||
start: { | ||
line: this.currToken[2], | ||
column: this.currToken[3] | ||
}, | ||
end: { | ||
line: this.currToken[2], | ||
column: this.currToken[3] | ||
} | ||
}, | ||
sourceIndex: this.currToken[4] | ||
value: this.content(), | ||
source: getSource(current[1], current[2], current[3], current[4]), | ||
sourceIndex: current[5] | ||
}), namespace); | ||
@@ -444,11 +489,11 @@ this.position++; | ||
var nextToken = this.nextToken; | ||
var word = this.currToken[1]; | ||
while (nextToken && nextToken[0] === 'word') { | ||
var word = this.content(); | ||
while (nextToken && ~[tokens.dollar, tokens.caret, tokens.equals, tokens.word].indexOf(nextToken[0])) { | ||
this.position++; | ||
var current = this.currToken[1]; | ||
var current = this.content(); | ||
word += current; | ||
if (current.lastIndexOf('\\') === current.length - 1) { | ||
var next = this.nextToken; | ||
if (next && next[0] === 'space') { | ||
word += this.parseSpace(next[1], ' '); | ||
if (next && next[0] === tokens.space) { | ||
word += this.parseSpace(this.content(next), ' '); | ||
this.position++; | ||
@@ -468,3 +513,3 @@ } | ||
} | ||
var indices = (0, _sortAscending2.default)((0, _uniq2.default)((0, _flatten2.default)([[0], hasClass, hasId]))); | ||
var indices = (0, _sortAscending2.default)((0, _uniq2.default)([0].concat(hasClass, hasId))); | ||
indices.forEach(function (ind, i) { | ||
@@ -477,16 +522,10 @@ var index = indices[i + 1] || word.length; | ||
var node = void 0; | ||
var current = _this2.currToken; | ||
var sourceIndex = current[5] + indices[i]; | ||
var source = getSource(current[1], current[2] + ind, current[3], current[2] + (index - 1)); | ||
if (~hasClass.indexOf(ind)) { | ||
node = new _className2.default({ | ||
value: value.slice(1), | ||
source: { | ||
start: { | ||
line: _this2.currToken[2], | ||
column: _this2.currToken[3] + ind | ||
}, | ||
end: { | ||
line: _this2.currToken[4], | ||
column: _this2.currToken[3] + (index - 1) | ||
} | ||
}, | ||
sourceIndex: _this2.currToken[6] + indices[i] | ||
source: source, | ||
sourceIndex: sourceIndex | ||
}); | ||
@@ -496,13 +535,4 @@ } else if (~hasId.indexOf(ind)) { | ||
value: value.slice(1), | ||
source: { | ||
start: { | ||
line: _this2.currToken[2], | ||
column: _this2.currToken[3] + ind | ||
}, | ||
end: { | ||
line: _this2.currToken[4], | ||
column: _this2.currToken[3] + (index - 1) | ||
} | ||
}, | ||
sourceIndex: _this2.currToken[6] + indices[i] | ||
source: source, | ||
sourceIndex: sourceIndex | ||
}); | ||
@@ -512,16 +542,9 @@ } else { | ||
value: value, | ||
source: { | ||
start: { | ||
line: _this2.currToken[2], | ||
column: _this2.currToken[3] + ind | ||
}, | ||
end: { | ||
line: _this2.currToken[4], | ||
column: _this2.currToken[3] + (index - 1) | ||
} | ||
}, | ||
sourceIndex: _this2.currToken[6] + indices[i] | ||
source: source, | ||
sourceIndex: sourceIndex | ||
}); | ||
} | ||
_this2.newNode(node, namespace); | ||
// Ensure that the namespace is used only once | ||
namespace = null; | ||
}); | ||
@@ -533,3 +556,3 @@ this.position++; | ||
var nextToken = this.nextToken; | ||
if (nextToken && nextToken[1] === '|') { | ||
if (nextToken && this.content(nextToken) === '|') { | ||
this.position++; | ||
@@ -550,12 +573,12 @@ return this.namespace(); | ||
switch (this.currToken[0]) { | ||
case 'space': | ||
case tokens.space: | ||
this.space(); | ||
break; | ||
case 'comment': | ||
case tokens.comment: | ||
this.comment(); | ||
break; | ||
case '(': | ||
case tokens.openParenthesis: | ||
this.parentheses(); | ||
break; | ||
case ')': | ||
case tokens.closeParenthesis: | ||
if (throwOnParenthesis) { | ||
@@ -565,33 +588,34 @@ this.missingParenthesis(); | ||
break; | ||
case '[': | ||
case tokens.openSquare: | ||
this.attribute(); | ||
break; | ||
case ']': | ||
this.missingSquareBracket(); | ||
break; | ||
case 'at-word': | ||
case 'word': | ||
case tokens.dollar: | ||
case tokens.caret: | ||
case tokens.equals: | ||
case tokens.word: | ||
this.word(); | ||
break; | ||
case ':': | ||
case tokens.colon: | ||
this.pseudo(); | ||
break; | ||
case ';': | ||
this.missingBackslash(); | ||
break; | ||
case ',': | ||
case tokens.comma: | ||
this.comma(); | ||
break; | ||
case '*': | ||
case tokens.asterisk: | ||
this.universal(); | ||
break; | ||
case '&': | ||
case tokens.ampersand: | ||
this.nesting(); | ||
break; | ||
case 'combinator': | ||
case tokens.combinator: | ||
this.combinator(); | ||
break; | ||
case 'string': | ||
case tokens.str: | ||
this.string(); | ||
break; | ||
// These cases throw; no break needed. | ||
case tokens.closeSquare: | ||
this.missingSquareBracket(); | ||
case tokens.semicolon: | ||
this.missingBackslash(); | ||
} | ||
@@ -604,2 +628,14 @@ }; | ||
Parser.prototype.expected = function expected(description, index, found) { | ||
if (Array.isArray(description)) { | ||
var last = description.pop(); | ||
description = description.join(', ') + ' or ' + last; | ||
} | ||
var an = /^[aeiou]/.test(description[0]) ? 'an' : 'a'; | ||
if (!found) { | ||
return this.error('Expected ' + an + ' ' + description + '.', { index: index }); | ||
} | ||
return this.error('Expected ' + an + ' ' + description + ', found "' + found + '" instead.', { index: index }); | ||
}; | ||
Parser.prototype.parseNamespace = function parseNamespace(namespace) { | ||
@@ -618,20 +654,26 @@ if (this.lossy && typeof namespace === 'string') { | ||
Parser.prototype.parseSpace = function parseSpace(space, replacement) { | ||
return this.lossy ? replacement || '' : space; | ||
Parser.prototype.parseSpace = function parseSpace(space) { | ||
var replacement = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; | ||
return this.lossy ? replacement : space; | ||
}; | ||
Parser.prototype.parseValue = function parseValue(value) { | ||
return this.lossy && value && typeof value === 'string' ? value.trim() : value; | ||
if (!this.lossy || !value || typeof value !== 'string') { | ||
return value; | ||
} | ||
return value.trim(); | ||
}; | ||
Parser.prototype.parseParenthesisToken = function parseParenthesisToken(token) { | ||
var content = this.content(token); | ||
if (!this.lossy) { | ||
return token[1]; | ||
return content; | ||
} | ||
if (token[0] === 'space') { | ||
return this.parseSpace(token[1], ' '); | ||
if (token[0] === tokens.space) { | ||
return this.parseSpace(content, ' '); | ||
} | ||
return this.parseValue(token[1]); | ||
return this.parseValue(content); | ||
}; | ||
@@ -650,2 +692,8 @@ | ||
Parser.prototype.content = function content() { | ||
var token = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.currToken; | ||
return this.css.slice(token[5], token[6]); | ||
}; | ||
_createClass(Parser, [{ | ||
@@ -652,0 +700,0 @@ key: 'currToken', |
@@ -5,4 +5,2 @@ '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 _parser = require('./parser'); | ||
@@ -21,27 +19,41 @@ | ||
this.func = func || function noop() {}; | ||
this.funcRes = null; | ||
return this; | ||
} | ||
Processor.prototype.process = function process(selectors) { | ||
Processor.prototype._input = function _input(rule) { | ||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var input = new _parser2.default({ | ||
css: selectors, | ||
error: function error(e) { | ||
throw new Error(e); | ||
return new _parser2.default({ | ||
css: rule, | ||
error: function error(e, opts) { | ||
if (typeof rule === 'string') { | ||
throw new Error(e); | ||
} | ||
throw rule.error(e, opts); // eslint-disable-line new-cap | ||
}, | ||
options: options | ||
}); | ||
this.res = input; | ||
this.func(input); | ||
return this; | ||
}; | ||
_createClass(Processor, [{ | ||
key: 'result', | ||
get: function get() { | ||
return String(this.res); | ||
Processor.prototype.process = function process(rule, options) { | ||
var input = void 0; | ||
try { | ||
input = this._input(rule, options); | ||
} catch (e) { | ||
return Promise.reject(e); | ||
} | ||
}]); | ||
return Promise.resolve(this.func(input)).then(function () { | ||
return String(input); | ||
}); | ||
}; | ||
Processor.prototype.processSync = function processSync(rule) { | ||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var input = this._input(rule, options); | ||
this.func(input); | ||
return String(input); | ||
}; | ||
return Processor; | ||
@@ -48,0 +60,0 @@ }(); |
@@ -22,3 +22,5 @@ 'use strict'; | ||
function Attribute(opts) { | ||
function Attribute() { | ||
var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
_classCallCheck(this, Attribute); | ||
@@ -29,3 +31,3 @@ | ||
_this.type = _types.ATTRIBUTE; | ||
_this.raws = {}; | ||
_this.raws = opts.raws || {}; | ||
return _this; | ||
@@ -32,0 +34,0 @@ } |
@@ -104,5 +104,8 @@ 'use strict'; | ||
Container.prototype.insertAfter = function insertAfter(oldNode, newNode) { | ||
newNode.parent = this; | ||
var oldIndex = this.index(oldNode); | ||
this.nodes.splice(oldIndex + 1, 0, newNode); | ||
newNode.parent = this; | ||
var index = void 0; | ||
@@ -112,3 +115,3 @@ for (var id in this.indexes) { | ||
if (oldIndex <= index) { | ||
this.indexes[id] = index + this.nodes.length; | ||
this.indexes[id] = index + 1; | ||
} | ||
@@ -121,10 +124,13 @@ } | ||
Container.prototype.insertBefore = function insertBefore(oldNode, newNode) { | ||
newNode.parent = this; | ||
var oldIndex = this.index(oldNode); | ||
this.nodes.splice(oldIndex, 0, newNode); | ||
newNode.parent = this; | ||
var index = void 0; | ||
for (var id in this.indexes) { | ||
index = this.indexes[id]; | ||
if (oldIndex <= index) { | ||
this.indexes[id] = index + this.nodes.length; | ||
if (index <= oldIndex) { | ||
this.indexes[id] = index + 1; | ||
} | ||
@@ -131,0 +137,0 @@ } |
@@ -5,63 +5,50 @@ 'use strict'; | ||
exports.default = tokenize; | ||
var singleQuote = 39, | ||
doubleQuote = 34, | ||
backslash = 92, | ||
slash = 47, | ||
newline = 10, | ||
space = 32, | ||
feed = 12, | ||
tab = 9, | ||
cr = 13, | ||
plus = 43, | ||
gt = 62, | ||
tilde = 126, | ||
pipe = 124, | ||
comma = 44, | ||
openBracket = 40, | ||
closeBracket = 41, | ||
openSq = 91, | ||
closeSq = 93, | ||
semicolon = 59, | ||
asterisk = 42, | ||
colon = 58, | ||
ampersand = 38, | ||
at = 64, | ||
atEnd = /[ \n\t\r\{\(\)'"\\;/]/g, | ||
wordEnd = /[ \n\t\r\(\)\*:;@!&'"\+\|~>,\[\]\\]|\/(?=\*)/g; | ||
var _tokenTypes = require('./tokenTypes'); | ||
var t = _interopRequireWildcard(_tokenTypes); | ||
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; } } | ||
var wordEnd = /[ \n\t\r\(\)\*:;!&'"\+\|~>,=$^\[\]\\]|\/(?=\*)/g; | ||
function tokenize(input) { | ||
var tokens = []; | ||
var css = input.css.valueOf(); | ||
var _css = css, | ||
length = _css.length; | ||
var offset = -1; | ||
var line = 1; | ||
var start = 0; | ||
var end = 0; | ||
var code = void 0, | ||
content = void 0, | ||
endColumn = void 0, | ||
endLine = void 0, | ||
escaped = void 0, | ||
escapePos = void 0, | ||
last = void 0, | ||
lines = void 0, | ||
next = void 0, | ||
quote = void 0, | ||
lines = void 0, | ||
last = void 0, | ||
content = void 0, | ||
escape = void 0, | ||
nextLine = void 0, | ||
nextOffset = void 0, | ||
escaped = void 0, | ||
escapePos = void 0; | ||
quote = void 0, | ||
tokenType = void 0; | ||
var length = css.length; | ||
var offset = -1; | ||
var line = 1; | ||
var pos = 0; | ||
var unclosed = function unclosed(what, end) { | ||
function unclosed(what, fix) { | ||
if (input.safe) { | ||
css += end; | ||
css += fix; | ||
next = css.length - 1; | ||
} else { | ||
throw input.error('Unclosed ' + what, line, pos - offset, pos); | ||
throw input.error('Unclosed ' + what, line, start - offset, start); | ||
} | ||
}; | ||
} | ||
while (pos < length) { | ||
code = css.charCodeAt(pos); | ||
while (start < length) { | ||
code = css.charCodeAt(start); | ||
if (code === newline) { | ||
offset = pos; | ||
if (code === t.newline) { | ||
offset = start; | ||
line += 1; | ||
@@ -71,74 +58,63 @@ } | ||
switch (code) { | ||
case newline: | ||
case space: | ||
case tab: | ||
case cr: | ||
case feed: | ||
next = pos; | ||
case t.newline: | ||
case t.space: | ||
case t.tab: | ||
case t.cr: | ||
case t.feed: | ||
next = start; | ||
do { | ||
next += 1; | ||
code = css.charCodeAt(next); | ||
if (code === newline) { | ||
if (code === t.newline) { | ||
offset = next; | ||
line += 1; | ||
} | ||
} while (code === space || code === newline || code === tab || code === cr || code === feed); | ||
} while (code === t.space || code === t.newline || code === t.tab || code === t.cr || code === t.feed); | ||
tokens.push(['space', css.slice(pos, next), line, pos - offset, pos]); | ||
pos = next - 1; | ||
tokenType = t.space; | ||
endLine = line; | ||
endColumn = start - offset; | ||
end = next; | ||
break; | ||
case plus: | ||
case gt: | ||
case tilde: | ||
case pipe: | ||
next = pos; | ||
case t.plus: | ||
case t.greaterThan: | ||
case t.tilde: | ||
case t.pipe: | ||
next = start; | ||
do { | ||
next += 1; | ||
code = css.charCodeAt(next); | ||
} while (code === plus || code === gt || code === tilde || code === pipe); | ||
tokens.push(['combinator', css.slice(pos, next), line, pos - offset, pos]); | ||
pos = next - 1; | ||
break; | ||
} while (code === t.plus || code === t.greaterThan || code === t.tilde || code === t.pipe); | ||
case asterisk: | ||
tokens.push(['*', '*', line, pos - offset, pos]); | ||
tokenType = t.combinator; | ||
endLine = line; | ||
endColumn = start - offset; | ||
end = next; | ||
break; | ||
case ampersand: | ||
tokens.push(['&', '&', line, pos - offset, pos]); | ||
// Consume these characters as single tokens. | ||
case t.asterisk: | ||
case t.ampersand: | ||
case t.comma: | ||
case t.equals: | ||
case t.dollar: | ||
case t.caret: | ||
case t.openSquare: | ||
case t.closeSquare: | ||
case t.colon: | ||
case t.semicolon: | ||
case t.openParenthesis: | ||
case t.closeParenthesis: | ||
next = start; | ||
tokenType = code; | ||
endLine = line; | ||
endColumn = start - offset; | ||
end = next + 1; | ||
break; | ||
case comma: | ||
tokens.push([',', ',', line, pos - offset, pos]); | ||
break; | ||
case openSq: | ||
tokens.push(['[', '[', line, pos - offset, pos]); | ||
break; | ||
case closeSq: | ||
tokens.push([']', ']', line, pos - offset, pos]); | ||
break; | ||
case colon: | ||
tokens.push([':', ':', line, pos - offset, pos]); | ||
break; | ||
case semicolon: | ||
tokens.push([';', ';', line, pos - offset, pos]); | ||
break; | ||
case openBracket: | ||
tokens.push(['(', '(', line, pos - offset, pos]); | ||
break; | ||
case closeBracket: | ||
tokens.push([')', ')', line, pos - offset, pos]); | ||
break; | ||
case singleQuote: | ||
case doubleQuote: | ||
quote = code === singleQuote ? "'" : '"'; | ||
next = pos; | ||
case t.singleQuote: | ||
case t.doubleQuote: | ||
quote = code === t.singleQuote ? "'" : '"'; | ||
next = start; | ||
do { | ||
@@ -151,3 +127,3 @@ escaped = false; | ||
escapePos = next; | ||
while (css.charCodeAt(escapePos - 1) === backslash) { | ||
while (css.charCodeAt(escapePos - 1) === t.backslash) { | ||
escapePos -= 1; | ||
@@ -158,36 +134,29 @@ escaped = !escaped; | ||
tokens.push(['string', css.slice(pos, next + 1), line, pos - offset, line, next - offset, pos]); | ||
pos = next; | ||
tokenType = t.str; | ||
endLine = line; | ||
endColumn = start - offset; | ||
end = next + 1; | ||
break; | ||
case at: | ||
atEnd.lastIndex = pos + 1; | ||
atEnd.test(css); | ||
if (atEnd.lastIndex === 0) { | ||
next = css.length - 1; | ||
} else { | ||
next = atEnd.lastIndex - 2; | ||
} | ||
tokens.push(['at-word', css.slice(pos, next + 1), line, pos - offset, line, next - offset, pos]); | ||
pos = next; | ||
break; | ||
case backslash: | ||
next = pos; | ||
escape = true; | ||
while (css.charCodeAt(next + 1) === backslash) { | ||
case t.backslash: | ||
next = start; | ||
escaped = true; | ||
while (css.charCodeAt(next + 1) === t.backslash) { | ||
next += 1; | ||
escape = !escape; | ||
escaped = !escaped; | ||
} | ||
code = css.charCodeAt(next + 1); | ||
if (escape && code !== slash && code !== space && code !== newline && code !== tab && code !== cr && code !== feed) { | ||
if (escaped && code !== t.slash && code !== t.space && code !== t.newline && code !== t.tab && code !== t.cr && code !== t.feed) { | ||
next += 1; | ||
} | ||
tokens.push(['word', css.slice(pos, next + 1), line, pos - offset, line, next - offset, pos]); | ||
pos = next; | ||
tokenType = t.word; | ||
endLine = line; | ||
endColumn = next - offset; | ||
end = next + 1; | ||
break; | ||
default: | ||
if (code === slash && css.charCodeAt(pos + 1) === asterisk) { | ||
next = css.indexOf('*/', pos + 2) + 1; | ||
if (code === t.slash && css.charCodeAt(start + 1) === t.asterisk) { | ||
next = css.indexOf('*/', start + 2) + 1; | ||
if (next === 0) { | ||
@@ -197,3 +166,3 @@ unclosed('comment', '*/'); | ||
content = css.slice(pos, next + 1); | ||
content = css.slice(start, next + 1); | ||
lines = content.split('\n'); | ||
@@ -210,9 +179,8 @@ last = lines.length - 1; | ||
tokens.push(['comment', content, line, pos - offset, nextLine, next - nextOffset, pos]); | ||
offset = nextOffset; | ||
tokenType = t.comment; | ||
line = nextLine; | ||
pos = next; | ||
endLine = nextLine; | ||
endColumn = next - nextOffset; | ||
} else { | ||
wordEnd.lastIndex = pos + 1; | ||
wordEnd.lastIndex = start + 1; | ||
wordEnd.test(css); | ||
@@ -225,10 +193,28 @@ if (wordEnd.lastIndex === 0) { | ||
tokens.push(['word', css.slice(pos, next + 1), line, pos - offset, line, next - offset, pos]); | ||
pos = next; | ||
tokenType = t.word; | ||
endLine = line; | ||
endColumn = next - offset; | ||
} | ||
end = next + 1; | ||
break; | ||
} | ||
pos++; | ||
// Ensure that the token structure remains consistent | ||
tokens.push([tokenType, // [0] Token type | ||
line, // [1] Starting line | ||
start - offset, // [2] Starting column | ||
endLine, // [3] Ending line | ||
endColumn, // [4] Ending column | ||
start, // [5] Start position / Source index | ||
end] // [6] End position | ||
); | ||
// Reset offset for the next token | ||
if (nextOffset) { | ||
offset = nextOffset; | ||
nextOffset = null; | ||
} | ||
start = end; | ||
} | ||
@@ -235,0 +221,0 @@ |
{ | ||
"name": "postcss-selector-parser", | ||
"version": "2.2.3", | ||
"version": "3.0.0-rc.0", | ||
"devDependencies": { | ||
"ava": "^0.17.0", | ||
"ava": "^0.20.0", | ||
"babel-cli": "^6.4.0", | ||
@@ -22,3 +22,4 @@ "babel-core": "^6.4.0", | ||
"minimist": "^1.2.0", | ||
"nyc": "^10.0.0" | ||
"nyc": "^10.0.0", | ||
"postcss": "^6.0.6" | ||
}, | ||
@@ -36,7 +37,6 @@ "main": "dist/index.js", | ||
"report": "nyc report --reporter=html", | ||
"test": "nyc ava src/__tests__/*.js", | ||
"test-012": "nyc ava src/__tests__/*.js" | ||
"test": "nyc ava src/__tests__/*.js" | ||
}, | ||
"dependencies": { | ||
"flatten": "^1.0.2", | ||
"dot-prop": "^4.1.1", | ||
"indexes-of": "^1.0.1", | ||
@@ -46,2 +46,5 @@ "uniq": "^1.0.1" | ||
"license": "MIT", | ||
"engines": { | ||
"node": ">=4" | ||
}, | ||
"homepage": "https://github.com/postcss/postcss-selector-parser", | ||
@@ -48,0 +51,0 @@ "author": { |
@@ -16,5 +16,5 @@ # postcss-selector-parser [](https://travis-ci.org/postcss/postcss-selector-parser) | ||
```js | ||
var parser = require('postcss-selector-parser'); | ||
var transform = function (selectors) { | ||
selectors.eachInside(function (selector) { | ||
const parser = require('postcss-selector-parser'); | ||
const transform = selectors => { | ||
selectors.eachInside(selector => { | ||
// do something with the selector | ||
@@ -25,3 +25,3 @@ console.log(String(selector)) | ||
var transformed = parser(transform).process('h1, h2, h3').result; | ||
const transformed = parser(transform).processSync('h1, h2, h3'); | ||
``` | ||
@@ -32,7 +32,10 @@ | ||
```js | ||
var parser = require('postcss-selector-parser'); | ||
var normalized = parser().process('h1, h2, h3', {lossless:false}).result; | ||
const parser = require('postcss-selector-parser'); | ||
const normalized = parser().processSync('h1, h2, h3', {lossless: false}); | ||
// -> h1,h2,h3 | ||
``` | ||
Async support is provided through `parser.process` and will resolve a Promise | ||
with the resulting selector string. | ||
## API | ||
@@ -39,0 +42,0 @@ |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
97291
6.59%27
3.85%1631
4.55%50
6.38%19
5.56%1
Infinity%+ Added
+ Added
+ Added
- Removed
- Removed