postcss-selector-parser
Advanced tools
Comparing version 3.0.0 to 3.1.0
84
API.md
@@ -579,2 +579,26 @@ # API Documentation | ||
### `attribute.qualifiedAttribute` | ||
Returns the attribute name qualified with the namespace if one is given. | ||
### `attribute.offsetOf(part)` | ||
Returns the offset of the attribute part specified relative to the | ||
start of the node of the output string. This is useful in raising | ||
error messages about a specific part of the attribute, especially | ||
in combination with `attribute.sourceIndex`. | ||
Returns `-1` if the name is invalid or the value doesn't exist in this | ||
attribute. | ||
The legal values for `part` are: | ||
* `"ns"` - alias for "namespace" | ||
* `"namespace"` - the namespace if it exists. | ||
* `"attribute"` - the attribute name | ||
* `"attributeNS"` - the start of the attribute or its namespace | ||
* `"operator"` - the match operator of the attribute | ||
* `"value"` - The value (string or identifier) | ||
* `"insensitive"` - the case insensitivity flag | ||
### `attribute.raws.unquoted` | ||
@@ -592,10 +616,58 @@ | ||
### `attribute.raws.insensitive` | ||
### `attribute.spaces` | ||
If there is an `i` specifying case insensitivity, returns that `i` along with the whitespace | ||
around it. | ||
Like `node.spaces` with the `before` and `after` values containing the spaces | ||
around the element, the parts of the attribute can also have spaces before | ||
and after them. The for each of `attribute`, `operator`, `value` and | ||
`insensitive` there is corresponding property of the same nam in | ||
`node.spaces` that has an optional `before` or `after` string containing only | ||
whitespace. | ||
```css | ||
[id=Bar i ] /* " i " */ | ||
[id=Bar i ] /* " i " */ | ||
Note that corresponding values in `attributes.raws.spaces` contain values | ||
including any comments. If set, these values will override the | ||
`attribute.spaces` value. Take care to remove them if changing | ||
`attribute.spaces`. | ||
### `attribute.raws` | ||
The raws object stores comments and other information necessary to re-render | ||
the node exactly as it was in the source. | ||
If a comment is embedded within the identifiers for the `namespace`, `attribute` | ||
or `value` then a property is placed in the raws for that value containing the full source of the propery including comments. | ||
If a comment is embedded within the space between parts of the attribute | ||
then the raw for that space is set accordingly. | ||
Setting an attribute's property `raws` value to be deleted. | ||
For now, changing the spaces required also updating or removing any of the | ||
raws values that override them. | ||
Example: `[ /*before*/ href /* after-attr */ = /* after-operator */ te/*inside-value*/st/* wow */ /*omg*/i/*bbq*/ /*whodoesthis*/]` would parse as: | ||
```js | ||
{ | ||
attribute: "href", | ||
operatator: "=", | ||
value: "test", | ||
spaces: { | ||
before: '', | ||
after: '', | ||
attribute: { before: ' ', after: ' ' }, | ||
operator: { after: ' ' }, | ||
value: { after: ' ' }, | ||
insensitive: { after: ' ' } | ||
}, | ||
raws: { | ||
spaces: { | ||
attribute: { before: ' /*before*/ ', after: ' /* after-attr */ ' }, | ||
operator: { after: ' /* after-operator */ ' }, | ||
value: { after: '/* wow */ /*omg*/' }, | ||
insensitive: { after: '/*bbq*/ /*whodoesthis*/' } | ||
}, | ||
unquoted: 'test', | ||
value: 'te/*inside-value*/st' | ||
} | ||
} | ||
``` | ||
@@ -602,0 +674,0 @@ |
@@ -1,3 +0,11 @@ | ||
# 3.0.0-rc.0 | ||
# 3.1.0 | ||
* Fixed numerous bugs in attribute nodes relating to the handling of comments | ||
and whitespace. There's significant changes to `attrNode.spaces` and `attrNode.raws` since the `3.0.0` release. | ||
* Added `Attribute#offsetOf(part)` to get the offset location of | ||
attribute parts like `"operator"` and `"value"`. This is most | ||
often added to `Attribute#sourceIndex` for error reporting. | ||
# 3.0.0 | ||
## Breaking changes | ||
@@ -4,0 +12,0 @@ |
@@ -169,2 +169,3 @@ 'use strict'; | ||
var lastAdded = null; | ||
var spaceAfterMeaningfulToken = false; | ||
@@ -181,13 +182,17 @@ while (pos < len) { | ||
} | ||
spaceAfterMeaningfulToken = true; | ||
if (this.options.lossy) { | ||
break; | ||
} | ||
if (!lastAdded || this.content(next) === 'i') { | ||
spaceBefore = content; | ||
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); | ||
if (existingComment) { | ||
_dotProp2.default.set(node, commentProp, existingComment + content); | ||
} | ||
} else { | ||
if (lastAdded === 'operator') { | ||
_dotProp2.default.set(node, 'raws.' + lastAdded, _dotProp2.default.get(node, lastAdded) + content); | ||
} else { | ||
_dotProp2.default.set(node, lastAdded, _dotProp2.default.get(node, lastAdded) + content); | ||
} | ||
spaceBefore = spaceBefore + content; | ||
commentBefore = commentBefore + content; | ||
} | ||
@@ -199,7 +204,19 @@ break; | ||
lastAdded = 'operator'; | ||
} else if (!node.namespace && next) { | ||
node.namespace = '' + this.parseSpace(spaceBefore) + content; | ||
} else if ((!node.namespace || lastAdded === "namespace" && !spaceAfterMeaningfulToken) && next) { | ||
if (spaceBefore) { | ||
_dotProp2.default.set(node, 'spaces.attribute.before', spaceBefore); | ||
spaceBefore = ''; | ||
} | ||
if (commentBefore) { | ||
_dotProp2.default.set(node, 'raws.spaces.attribute.before', spaceBefore); | ||
commentBefore = ''; | ||
} | ||
node.namespace = (node.namespace || "") + content; | ||
var rawValue = _dotProp2.default.get(node, "raws.namespace"); | ||
if (rawValue) { | ||
node.raws.namespace += content; | ||
} | ||
lastAdded = 'namespace'; | ||
spaceBefore = ''; | ||
} | ||
spaceAfterMeaningfulToken = false; | ||
break; | ||
@@ -212,2 +229,3 @@ case tokens.dollar: | ||
} | ||
spaceAfterMeaningfulToken = false; | ||
break; | ||
@@ -220,2 +238,3 @@ case tokens.combinator: | ||
if (content !== '|') { | ||
spaceAfterMeaningfulToken = false; | ||
break; | ||
@@ -229,24 +248,53 @@ } | ||
} | ||
spaceAfterMeaningfulToken = false; | ||
break; | ||
case tokens.word: | ||
if (next && this.content(next) === '|' && attr[pos + 2] && attr[pos + 2][0] !== tokens.equals && !node.operator && !node.namespace) { | ||
if (next && this.content(next) === '|' && attr[pos + 2] && attr[pos + 2][0] !== tokens.equals && // this look-ahead probably fails with comment nodes involved. | ||
!node.operator && !node.namespace) { | ||
node.namespace = content; | ||
lastAdded = 'namespace'; | ||
} else if (!node.attribute) { | ||
node.attribute = '' + this.parseSpace(spaceBefore) + commentBefore + content; | ||
} else if (!node.attribute || lastAdded === "attribute" && !spaceAfterMeaningfulToken) { | ||
if (spaceBefore) { | ||
_dotProp2.default.set(node, 'spaces.attribute.before', spaceBefore); | ||
spaceBefore = ''; | ||
} | ||
if (commentBefore) { | ||
_dotProp2.default.set(node, 'raws.spaces.attribute.before', commentBefore); | ||
commentBefore = ''; | ||
} | ||
node.attribute = (node.attribute || "") + content; | ||
var _rawValue = _dotProp2.default.get(node, "raws.attribute"); | ||
if (_rawValue) { | ||
node.raws.attribute += content; | ||
} | ||
lastAdded = 'attribute'; | ||
spaceBefore = ''; | ||
commentBefore = ''; | ||
} else if (!node.value) { | ||
node.value = 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; | ||
} | ||
lastAdded = 'value'; | ||
_dotProp2.default.set(node, 'raws.unquoted', content); | ||
_dotProp2.default.set(node, 'raws.unquoted', _dotProp2.default.get(node, 'raws.unquoted', '') + content); | ||
} else if (content === 'i') { | ||
node.insensitive = true; | ||
if (!this.options.lossy) { | ||
lastAdded = 'raws.insensitive'; | ||
_dotProp2.default.set(node, lastAdded, '' + spaceBefore + content); | ||
spaceBefore = ''; | ||
if (node.value && (node.quoted || spaceAfterMeaningfulToken)) { | ||
node.insensitive = true; | ||
lastAdded = 'insensitive'; | ||
if (spaceBefore) { | ||
_dotProp2.default.set(node, 'spaces.insensitive.before', spaceBefore); | ||
spaceBefore = ''; | ||
} | ||
if (commentBefore) { | ||
_dotProp2.default.set(node, 'raws.spaces.insensitive.before', commentBefore); | ||
commentBefore = ''; | ||
} | ||
} else if (node.value) { | ||
lastAdded = 'value'; | ||
node.value += 'i'; | ||
if (node.raws.value) { | ||
node.raws.value += 'i'; | ||
} | ||
} | ||
} | ||
spaceAfterMeaningfulToken = false; | ||
break; | ||
@@ -263,2 +311,3 @@ case tokens.str: | ||
_dotProp2.default.set(node, 'raws.unquoted', content.slice(1, -1)); | ||
spaceAfterMeaningfulToken = false; | ||
break; | ||
@@ -274,8 +323,15 @@ case tokens.equals: | ||
lastAdded = 'operator'; | ||
spaceAfterMeaningfulToken = false; | ||
break; | ||
case tokens.comment: | ||
if (lastAdded) { | ||
_dotProp2.default.set(node, lastAdded, _dotProp2.default.get(node, lastAdded) + content); | ||
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); | ||
} else { | ||
var lastValue = _dotProp2.default.get(node, 'raws.' + lastAdded, _dotProp2.default.get(node, lastAdded, '')); | ||
_dotProp2.default.set(node, 'raws.' + lastAdded, lastValue + content); | ||
} | ||
} else { | ||
commentBefore = content; | ||
commentBefore = commentBefore + content; | ||
} | ||
@@ -282,0 +338,0 @@ break; |
@@ -5,2 +5,4 @@ '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 _namespace = require('./namespace'); | ||
@@ -31,26 +33,157 @@ | ||
_this.type = _types.ATTRIBUTE; | ||
_this.raws = opts.raws || {}; | ||
_this.raws = _this.raws || {}; | ||
_this._constructed = true; | ||
return _this; | ||
} | ||
Attribute.prototype.toString = function toString() { | ||
var selector = [this.spaces.before, '[', this.ns, this.attribute]; | ||
Attribute.prototype._spacesFor = function _spacesFor(name) { | ||
var attrSpaces = { before: '', after: '' }; | ||
var spaces = this.spaces[name] || {}; | ||
var rawSpaces = this.raws.spaces && this.raws.spaces[name] || {}; | ||
return Object.assign(attrSpaces, spaces, rawSpaces); | ||
}; | ||
if (this.raws.operator) { | ||
selector.push(this.raws.operator); | ||
} else if (this.operator) { | ||
selector.push(this.operator); | ||
Attribute.prototype._valueFor = function _valueFor(name) { | ||
return this.raws[name] || this[name]; | ||
}; | ||
Attribute.prototype._stringFor = function _stringFor(name) { | ||
var spaceName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : name; | ||
var concat = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultAttrConcat; | ||
var attrSpaces = this._spacesFor(spaceName); | ||
return concat(this._valueFor(name), attrSpaces); | ||
}; | ||
/** | ||
* returns the offset of the attribute part specified relative to the | ||
* start of the node of the output string. | ||
* | ||
* * "ns" - alias for "namespace" | ||
* * "namespace" - the namespace if it exists. | ||
* * "attribute" - the attribute name | ||
* * "attributeNS" - the start of the attribute or its namespace | ||
* * "operator" - the match operator of the attribute | ||
* * "value" - The value (string or identifier) | ||
* * "insensitive" - the case insensitivity flag; | ||
* @param part One of the possible values inside an attribute. | ||
* @returns -1 if the name is invalid or the value doesn't exist in this attribute. | ||
*/ | ||
Attribute.prototype.offsetOf = function offsetOf(name) { | ||
var count = 1; | ||
var attributeSpaces = this._spacesFor("attribute"); | ||
count += attributeSpaces.before.length; | ||
if (name === "namespace" || name === "ns") { | ||
return this.namespace ? count : -1; | ||
} | ||
if (this.value) { | ||
selector.push(this.value); | ||
if (name === "attributeNS") { | ||
return count; | ||
} | ||
if (this.raws.insensitive) { | ||
selector.push(this.raws.insensitive); | ||
} else if (this.insensitive) { | ||
selector.push(' i'); | ||
count += this.namespaceString.length; | ||
if (this.namespace) { | ||
count += 1; | ||
} | ||
if (name === "attribute") { | ||
return count; | ||
} | ||
count += this._valueFor("attribute").length; | ||
count += attributeSpaces.after.length; | ||
var operatorSpaces = this._spacesFor("operator"); | ||
count += operatorSpaces.before.length; | ||
var operator = this._valueFor("operator"); | ||
if (name === "operator") { | ||
return operator ? count : -1; | ||
} | ||
count += operator.length; | ||
count += operatorSpaces.after.length; | ||
var valueSpaces = this._spacesFor("value"); | ||
count += valueSpaces.before.length; | ||
var value = this._valueFor("value"); | ||
if (name === "value") { | ||
return value ? count : -1; | ||
} | ||
count += value.length; | ||
count += valueSpaces.after.length; | ||
var insensitiveSpaces = this._spacesFor("insensitive"); | ||
count += insensitiveSpaces.before.length; | ||
if (name === "insensitive") { | ||
return this.insensitive ? count : -1; | ||
} | ||
return -1; | ||
}; | ||
Attribute.prototype.toString = function toString() { | ||
var _this2 = this; | ||
var selector = [this.spaces.before, '[']; | ||
selector.push(this._stringFor('qualifiedAttribute', 'attribute')); | ||
if (this.operator && this.value) { | ||
selector.push(this._stringFor('operator')); | ||
selector.push(this._stringFor('value')); | ||
selector.push(this._stringFor('insensitiveFlag', 'insensitive', function (attrValue, attrSpaces) { | ||
if (attrValue.length > 0 && !_this2.quoted && attrSpaces.before.length === 0 && !(_this2.spaces.value && _this2.spaces.value.after)) { | ||
attrSpaces.before = " "; | ||
} | ||
return defaultAttrConcat(attrValue, attrSpaces); | ||
})); | ||
} | ||
selector.push(']'); | ||
return selector.concat(this.spaces.after).join(''); | ||
selector.push(this.spaces.after); | ||
return selector.join(''); | ||
}; | ||
_createClass(Attribute, [{ | ||
key: 'qualifiedAttribute', | ||
get: function get() { | ||
return this.qualifiedName(this.raws.attribute || this.attribute); | ||
} | ||
}, { | ||
key: 'insensitiveFlag', | ||
get: function get() { | ||
return this.insensitive ? 'i' : ''; | ||
} | ||
}, { | ||
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; | ||
}, | ||
set: function set(v) { | ||
this._namespace = v; | ||
if (this._constructed) { | ||
delete this.raws.namespace; | ||
} | ||
} | ||
}, { | ||
key: 'attribute', | ||
get: function get() { | ||
return this._attribute; | ||
}, | ||
set: function set(v) { | ||
this._attribute = v; | ||
if (this._constructed) { | ||
delete this.raws.attibute; | ||
} | ||
} | ||
}]); | ||
return Attribute; | ||
@@ -60,2 +193,7 @@ }(_namespace2.default); | ||
exports.default = Attribute; | ||
function defaultAttrConcat(attrValue, attrSpaces) { | ||
return '' + attrSpaces.before + attrValue + attrSpaces.after; | ||
} | ||
module.exports = exports['default']; |
@@ -28,12 +28,50 @@ 'use strict'; | ||
Namespace.prototype.qualifiedName = function qualifiedName(value) { | ||
if (this.namespace) { | ||
return this.namespaceString + '|' + value; | ||
} else { | ||
return value; | ||
} | ||
}; | ||
Namespace.prototype.toString = function toString() { | ||
return [this.spaces.before, this.ns, String(this.value), this.spaces.after].join(''); | ||
return [this.spaces.before, this.qualifiedName(this.value), this.spaces.after].join(''); | ||
}; | ||
_createClass(Namespace, [{ | ||
key: 'namespace', | ||
get: function get() { | ||
return this._namespace; | ||
}, | ||
set: function set(namespace) { | ||
this._namespace = namespace; | ||
if (this.raws) { | ||
delete this.raws.namespace; | ||
} | ||
} | ||
}, { | ||
key: 'ns', | ||
get: function get() { | ||
var n = this.namespace; | ||
return n ? (typeof n === 'string' ? n : '') + '|' : ''; | ||
return this._namespace; | ||
}, | ||
set: function set(namespace) { | ||
this._namespace = namespace; | ||
if (this.raws) { | ||
delete this.raws.namespace; | ||
} | ||
} | ||
}, { | ||
key: 'namespaceString', | ||
get: function get() { | ||
if (this.namespace) { | ||
var ns = this.raws && this.raws.namespace || this.namespace; | ||
if (ns === true) { | ||
return ''; | ||
} else { | ||
return ns; | ||
} | ||
} else { | ||
return ''; | ||
} | ||
} | ||
}]); | ||
@@ -40,0 +78,0 @@ |
@@ -45,13 +45,6 @@ 'use strict'; | ||
for (var key in opts) { | ||
this[key] = opts[key]; | ||
} | ||
var _opts$spaces = opts.spaces; | ||
_opts$spaces = _opts$spaces === undefined ? {} : _opts$spaces; | ||
var _opts$spaces$before = _opts$spaces.before, | ||
before = _opts$spaces$before === undefined ? '' : _opts$spaces$before, | ||
_opts$spaces$after = _opts$spaces.after, | ||
after = _opts$spaces$after === undefined ? '' : _opts$spaces$after; | ||
this.spaces = { before: before, after: after }; | ||
Object.assign(this, opts); | ||
this.spaces = this.spaces || {}; | ||
this.spaces.before = this.spaces.before || ''; | ||
this.spaces.after = this.spaces.after || ''; | ||
} | ||
@@ -58,0 +51,0 @@ |
{ | ||
"name": "postcss-selector-parser", | ||
"version": "3.0.0", | ||
"version": "3.1.0", | ||
"devDependencies": { | ||
@@ -5,0 +5,0 @@ "ava": "^0.20.0", |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
125061
2044
0