postcss-selector-parser
Advanced tools
Comparing version
92
API.md
@@ -19,3 +19,3 @@ # API Documentation | ||
selectors.eachUniversal(function (selector) { | ||
selector.removeSelf(); | ||
selector.remove(); | ||
}); | ||
@@ -97,2 +97,15 @@ }; | ||
### `parser.nesting([props])` | ||
Creates a new nesting selector. | ||
```js | ||
parser.nesting(); | ||
// => & | ||
``` | ||
Arguments: | ||
* `props (object)`: The new node's properties. | ||
### `parser.pseudo([props])` | ||
@@ -181,4 +194,4 @@ | ||
A string representation of the selector type. It can be one of the following; | ||
`attribute`, `class`, `combinator`, `comment`, `id`, `pseudo`, `root`, | ||
`selector`, `string`, `tag`, or `universal`. | ||
`attribute`, `class`, `combinator`, `comment`, `id`, `nesting`, `pseudo`, | ||
`root`, `selector`, `string`, `tag`, or `universal`. | ||
@@ -233,3 +246,3 @@ ```js | ||
### `node.removeSelf()` | ||
### `node.remove()` | ||
@@ -240,3 +253,3 @@ Removes the node from its parent node. | ||
if (node.type === 'id') { | ||
node.removeSelf(); | ||
node.remove(); | ||
} | ||
@@ -383,3 +396,3 @@ ``` | ||
Note that these methods only work on a container's immediate children; recursive | ||
iteration is provided by `container.eachInside`. | ||
iteration is provided by `container.walk`. | ||
@@ -409,3 +422,3 @@ ### `container.each(callback)` | ||
### `container.eachInside(callback)` | ||
### `container.walk(callback)` | ||
@@ -416,3 +429,3 @@ Like `container#each`, but will also iterate child nodes as long as they are | ||
```js | ||
selectors.eachInside(function (selector, index) { | ||
selectors.walk(function (selector, index) { | ||
// all nodes | ||
@@ -430,3 +443,3 @@ }); | ||
### `container.eachInside` proxies | ||
### `container.walk` proxies | ||
@@ -437,10 +450,11 @@ The container class provides proxy methods for iterating over types of nodes, | ||
* `container.eachAttribute` | ||
* `container.eachClass` | ||
* `container.eachCombinator` | ||
* `container.eachComment` | ||
* `container.eachId` | ||
* `container.eachPseudo` | ||
* `container.eachTag` | ||
* `container.eachUniversal` | ||
* `container.walkAttributes` | ||
* `container.walkClasses` | ||
* `container.walkCombinators` | ||
* `container.walkComments` | ||
* `container.walkIds` | ||
* `container.walkNesting` | ||
* `container.walkPseudos` | ||
* `container.walkTags` | ||
* `container.walkUniversals` | ||
@@ -486,3 +500,3 @@ ### `container.split(callback)` | ||
```js | ||
selectors.eachInside(function (selector) { | ||
selectors.walk(function (selector) { | ||
if (selector.type !== 'class') { | ||
@@ -500,6 +514,6 @@ var className = parser.className({value: 'theme-name'}); | ||
### `container.remove(node)` | ||
### `container.removeChild(node)` | ||
Remove the node from the container. Note that you can also use | ||
`node.removeSelf()` if you would like to remove just a single node. | ||
`node.remove()` if you would like to remove just a single node. | ||
@@ -547,3 +561,39 @@ ```js | ||
own (such as `h1:not(h2, h3)`), they will be its children. Note that the pseudo | ||
`value` will always contain the colons preceeding the pseudo identifier. This | ||
`value` will always contain the colons preceding the pseudo identifier. This | ||
is so that both `:before` and `::before` are properly represented in the AST. | ||
## Attribute nodes | ||
### `attribute.quoted` | ||
Returns `true` if the attribute's value is wrapped in quotation marks, false if it is not. | ||
Remains `undefined` if there is no attribute value. | ||
```css | ||
[href=foo] /* false */ | ||
[href='foo'] /* true */ | ||
[href="foo"] /* true */ | ||
[href] /* undefined */ | ||
``` | ||
### `attribute.raws.unquoted` | ||
Returns the unquoted content of the attribute's value. | ||
Remains `undefined` if there is no attribute value. | ||
```css | ||
[href=foo] /* foo */ | ||
[href='foo'] /* foo */ | ||
[href="foo"] /* foo */ | ||
[href] /* undefined */ | ||
``` | ||
### `attribute.raws.insensitive` | ||
If there is an `i` specifying case insensitivity, returns that `i` along with the whitespace | ||
around it. | ||
```css | ||
[id=Bar i ] /* " i " */ | ||
[id=Bar i ] /* " i " */ | ||
``` |
@@ -0,1 +1,21 @@ | ||
# 2.0.0 | ||
This release contains the following breaking changes: | ||
* Renamed all `eachInside` iterators to `walk`. For example, `eachTag` is now | ||
`walkTags`, and `eachInside` is now `walk`. | ||
* Renamed `Node#removeSelf()` to `Node#remove()`. | ||
* Renamed `Container#remove()` to `Container#removeChild()`. | ||
* Renamed `Node#raw` to `Node#raws` (thanks to @davidtheclark). | ||
* Now parses `&` as the *nesting* selector, rather than a *tag* selector. | ||
* Fixes misinterpretation of Sass interpolation (e.g. `#{foo}`) as an | ||
id selector (thanks to @davidtheclark). | ||
and; | ||
* Fixes parsing of attribute selectors with equals signs in them | ||
(e.g. `[data-attr="foo=bar"]`) (thanks to @montmanu). | ||
* Adds `quoted` and `raw.unquoted` properties to attribute nodes | ||
(thanks to @davidtheclark). | ||
# 1.3.3 | ||
@@ -2,0 +22,0 @@ |
@@ -29,2 +29,6 @@ 'use strict'; | ||
var _nesting = require('./selectors/nesting'); | ||
var _nesting2 = _interopRequireDefault(_nesting); | ||
var _pseudo = require('./selectors/pseudo'); | ||
@@ -80,2 +84,6 @@ | ||
parser.nesting = function (opts) { | ||
return new _nesting2.default(opts); | ||
}; | ||
parser.pseudo = function (opts) { | ||
@@ -82,0 +90,0 @@ return new _pseudo2.default(opts); |
@@ -51,2 +51,6 @@ 'use strict'; | ||
var _nesting = require('./selectors/nesting'); | ||
var _nesting2 = _interopRequireDefault(_nesting); | ||
var _sortAscending = require('./sortAscending'); | ||
@@ -95,3 +99,3 @@ | ||
var str = ''; | ||
var attr = undefined; | ||
var attr = void 0; | ||
var startingToken = this.currToken; | ||
@@ -106,3 +110,3 @@ this.position++; | ||
} | ||
var parts = str.split(/((?:[*~^$|]?)=)/); | ||
var parts = str.split(/((?:[*~^$|]?=))([^]*)/); | ||
var namespace = parts[0].split(/(\|)/g); | ||
@@ -140,4 +144,6 @@ var attributeProps = { | ||
attr.insensitive = true; | ||
attr.raw.insensitive = insensitive[1]; | ||
attr.raws.insensitive = insensitive[1]; | ||
} | ||
attr.quoted = attr.value[0] === '\'' || attr.value[0] === '"'; | ||
attr.raws.unquoted = attr.quoted ? attr.value.slice(1, -1) : attr.value; | ||
} | ||
@@ -238,2 +244,20 @@ this.newNode(attr); | ||
Parser.prototype.nesting = function nesting() { | ||
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] | ||
})); | ||
this.position++; | ||
}; | ||
Parser.prototype.parentheses = function parentheses() { | ||
@@ -268,11 +292,11 @@ var last = this.current.last; | ||
} else { | ||
var balanced = 1; | ||
var _balanced = 1; | ||
this.position++; | ||
last.value += '('; | ||
while (this.position < this.tokens.length && balanced) { | ||
while (this.position < this.tokens.length && _balanced) { | ||
if (this.currToken[0] === '(') { | ||
balanced++; | ||
_balanced++; | ||
} | ||
if (this.currToken[0] === ')') { | ||
balanced--; | ||
_balanced--; | ||
} | ||
@@ -282,3 +306,3 @@ last.value += this.currToken[1]; | ||
} | ||
if (balanced) { | ||
if (_balanced) { | ||
this.error('Expected closing parenthesis.'); | ||
@@ -303,3 +327,3 @@ } | ||
(function () { | ||
var pseudo = undefined; | ||
var pseudo = void 0; | ||
_this.splitWord(false, function (first, length) { | ||
@@ -408,2 +432,9 @@ pseudoStr += first; | ||
var hasId = (0, _indexesOf2.default)(word, '#'); | ||
// Eliminate Sass interpolations from the list of id indexes | ||
var interpolations = (0, _indexesOf2.default)(word, '#{'); | ||
if (interpolations.length) { | ||
hasId = hasId.filter(function (hashIndex) { | ||
return ! ~interpolations.indexOf(hashIndex); | ||
}); | ||
} | ||
var indices = (0, _sortAscending2.default)((0, _uniq2.default)((0, _flatten2.default)([[0], hasClass, hasId]))); | ||
@@ -416,3 +447,3 @@ indices.forEach(function (ind, i) { | ||
} | ||
var node = undefined; | ||
var node = void 0; | ||
if (~hasClass.indexOf(ind)) { | ||
@@ -520,2 +551,5 @@ node = new _className2.default({ | ||
break; | ||
case '&': | ||
this.nesting(); | ||
break; | ||
case 'combinator': | ||
@@ -522,0 +556,0 @@ this.combinator(); |
@@ -26,3 +26,3 @@ 'use strict'; | ||
_this.type = 'attribute'; | ||
_this.raw = {}; | ||
_this.raws = {}; | ||
return _this; | ||
@@ -40,4 +40,4 @@ } | ||
} | ||
if (this.raw.insensitive) { | ||
selector.push(this.raw.insensitive); | ||
if (this.raws.insensitive) { | ||
selector.push(this.raws.insensitive); | ||
} else if (this.insensitive) { | ||
@@ -44,0 +44,0 @@ selector.push(' i'); |
@@ -56,3 +56,3 @@ 'use strict'; | ||
Container.prototype.remove = function remove(child) { | ||
Container.prototype.removeChild = function removeChild(child) { | ||
child = this.index(child); | ||
@@ -62,3 +62,3 @@ this.at(child).parent = undefined; | ||
var index = undefined; | ||
var index = void 0; | ||
for (var id in this.indexes) { | ||
@@ -103,3 +103,3 @@ index = this.indexes[id]; | ||
var index = undefined; | ||
var index = void 0; | ||
for (var id in this.indexes) { | ||
@@ -119,3 +119,3 @@ index = this.indexes[id]; | ||
var index = undefined; | ||
var index = void 0; | ||
for (var id in this.indexes) { | ||
@@ -147,4 +147,4 @@ index = this.indexes[id]; | ||
var index = undefined, | ||
result = undefined; | ||
var index = void 0, | ||
result = void 0; | ||
while (this.indexes[id] < this.length) { | ||
@@ -167,3 +167,3 @@ index = this.indexes[id]; | ||
Container.prototype.eachInside = function eachInside(callback) { | ||
Container.prototype.walk = function walk(callback) { | ||
return this.each(function (node, i) { | ||
@@ -173,3 +173,3 @@ var result = callback(node, i); | ||
if (result !== false && node.length) { | ||
result = node.eachInside(callback); | ||
result = node.walk(callback); | ||
} | ||
@@ -183,6 +183,6 @@ | ||
Container.prototype.eachAttribute = function eachAttribute(callback) { | ||
Container.prototype.walkAttributes = function walkAttributes(callback) { | ||
var _this2 = this; | ||
return this.eachInside(function (selector) { | ||
return this.walk(function (selector) { | ||
if (selector.type === 'attribute') { | ||
@@ -194,6 +194,6 @@ return callback.call(_this2, selector); | ||
Container.prototype.eachClass = function eachClass(callback) { | ||
Container.prototype.walkClasses = function walkClasses(callback) { | ||
var _this3 = this; | ||
return this.eachInside(function (selector) { | ||
return this.walk(function (selector) { | ||
if (selector.type === 'class') { | ||
@@ -205,6 +205,6 @@ return callback.call(_this3, selector); | ||
Container.prototype.eachCombinator = function eachCombinator(callback) { | ||
Container.prototype.walkCombinators = function walkCombinators(callback) { | ||
var _this4 = this; | ||
return this.eachInside(function (selector) { | ||
return this.walk(function (selector) { | ||
if (selector.type === 'combinator') { | ||
@@ -216,6 +216,6 @@ return callback.call(_this4, selector); | ||
Container.prototype.eachComment = function eachComment(callback) { | ||
Container.prototype.walkComments = function walkComments(callback) { | ||
var _this5 = this; | ||
return this.eachInside(function (selector) { | ||
return this.walk(function (selector) { | ||
if (selector.type === 'comment') { | ||
@@ -227,6 +227,6 @@ return callback.call(_this5, selector); | ||
Container.prototype.eachId = function eachId(callback) { | ||
Container.prototype.walkIds = function walkIds(callback) { | ||
var _this6 = this; | ||
return this.eachInside(function (selector) { | ||
return this.walk(function (selector) { | ||
if (selector.type === 'id') { | ||
@@ -238,7 +238,7 @@ return callback.call(_this6, selector); | ||
Container.prototype.eachPseudo = function eachPseudo(callback) { | ||
Container.prototype.walkNesting = function walkNesting(callback) { | ||
var _this7 = this; | ||
return this.eachInside(function (selector) { | ||
if (selector.type === 'pseudo') { | ||
return this.walk(function (selector) { | ||
if (selector.type === 'nesting') { | ||
return callback.call(_this7, selector); | ||
@@ -249,7 +249,7 @@ } | ||
Container.prototype.eachTag = function eachTag(callback) { | ||
Container.prototype.walkPseudos = function walkPseudos(callback) { | ||
var _this8 = this; | ||
return this.eachInside(function (selector) { | ||
if (selector.type === 'tag') { | ||
return this.walk(function (selector) { | ||
if (selector.type === 'pseudo') { | ||
return callback.call(_this8, selector); | ||
@@ -260,7 +260,7 @@ } | ||
Container.prototype.eachUniversal = function eachUniversal(callback) { | ||
Container.prototype.walkTags = function walkTags(callback) { | ||
var _this9 = this; | ||
return this.eachInside(function (selector) { | ||
if (selector.type === 'universal') { | ||
return this.walk(function (selector) { | ||
if (selector.type === 'tag') { | ||
return callback.call(_this9, selector); | ||
@@ -271,8 +271,18 @@ } | ||
Container.prototype.split = function split(callback) { | ||
Container.prototype.walkUniversals = function walkUniversals(callback) { | ||
var _this10 = this; | ||
return this.walk(function (selector) { | ||
if (selector.type === 'universal') { | ||
return callback.call(_this10, selector); | ||
} | ||
}); | ||
}; | ||
Container.prototype.split = function split(callback) { | ||
var _this11 = this; | ||
var current = []; | ||
return this.reduce(function (memo, node, index) { | ||
var split = callback.call(_this10, node); | ||
var split = callback.call(_this11, node); | ||
current.push(node); | ||
@@ -282,3 +292,3 @@ if (split) { | ||
current = []; | ||
} else if (index === _this10.length - 1) { | ||
} else if (index === _this11.length - 1) { | ||
memo.push(current); | ||
@@ -285,0 +295,0 @@ } |
@@ -51,5 +51,5 @@ 'use strict'; | ||
_class.prototype.removeSelf = function removeSelf() { | ||
_class.prototype.remove = function remove() { | ||
if (this.parent) { | ||
this.parent.remove(this); | ||
this.parent.removeChild(this); | ||
} | ||
@@ -65,3 +65,3 @@ this.parent = undefined; | ||
} | ||
this.removeSelf(); | ||
this.remove(); | ||
} | ||
@@ -68,0 +68,0 @@ return this; |
@@ -26,5 +26,6 @@ 'use strict'; | ||
colon = 58, | ||
ampersand = 38, | ||
at = 64, | ||
atEnd = /[ \n\t\r\{\(\)'"\\;/]/g, | ||
wordEnd = /[ \n\t\r\(\)\*:;@!'"\+\|~>,\[\]\\]|\/(?=\*)/g; | ||
wordEnd = /[ \n\t\r\(\)\*:;@!&'"\+\|~>,\[\]\\]|\/(?=\*)/g; | ||
@@ -35,13 +36,13 @@ function tokenize(input) { | ||
var code = undefined, | ||
next = undefined, | ||
quote = undefined, | ||
lines = undefined, | ||
last = undefined, | ||
content = undefined, | ||
escape = undefined, | ||
nextLine = undefined, | ||
nextOffset = undefined, | ||
escaped = undefined, | ||
escapePos = undefined; | ||
var code = 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; | ||
@@ -107,2 +108,6 @@ var length = css.length; | ||
case ampersand: | ||
tokens.push(['&', '&', line, pos - offset, pos]); | ||
break; | ||
case comma: | ||
@@ -109,0 +114,0 @@ tokens.push([',', ',', line, pos - offset, pos]); |
{ | ||
"name": "postcss-selector-parser", | ||
"version": "1.3.3", | ||
"version": "2.0.0", | ||
"devDependencies": { | ||
"ava": "^0.12.0", | ||
"ava": "^0.14.0", | ||
"babel-cli": "^6.4.0", | ||
@@ -17,2 +17,4 @@ "babel-core": "^6.4.0", | ||
"eslint-config-cssnano": "^2.0.0", | ||
"glob": "^7.0.3", | ||
"minimist": "^1.2.0", | ||
"nyc": "^6.0.0" | ||
@@ -31,3 +33,4 @@ }, | ||
"report": "nyc report --reporter=html", | ||
"test": "nyc ava src/__tests__/*.js" | ||
"test": "nyc node batchTests.js 'src/__tests__/*.js'", | ||
"test-fast": "nyc ava src/__tests__/*.js" | ||
}, | ||
@@ -48,3 +51,4 @@ "dependencies": { | ||
"ava": { | ||
"require": "babel-core/register" | ||
"require": "babel-core/register", | ||
"serial": true | ||
}, | ||
@@ -51,0 +55,0 @@ "nyc": { |
84881
6.29%25
4.17%1473
4.91%15
15.38%