|
| 1 | +# 4.0.1 |
| 2 | + |
| 3 | +This release has **BREAKING CHANGES** that were required to fix regressions in 4.0.0. Please read carefully. |
| 4 | + |
| 5 | +* Combinators |
| 6 | + - **Descendant Combinators** The value of descendant combinators used to be all of the spaces found between the selectors. |
| 7 | + This made it hard to check for a descendant combinator in comparison to other types of combinators. |
| 8 | + In 4.0.1 this changed to being just a single space (`" "`). For descendant selectors with no comments, |
| 9 | + additional space is now stored in `node.spaces.before`. Depending on the location of comments, |
| 10 | + additional spaces are stored in `node.raws.spaces.before`, `node.raws.spaces.after`, |
| 11 | + or `node.raws.value`. |
| 12 | + Upgrade hints: |
| 13 | + * `node.type === "combinator" && / /.test(node.value)` => `node.type === "combinator" && node.value === " "` |
| 14 | + * `node.type === "combinator" && / /.test(node.value)` => `node.type === "combinator" && / /.test(node.toString())` |
| 15 | + - **Named Combinators** Although, nonstandard and unlikely to ever become a standard, named combinators |
| 16 | + like `/deep/` and `/for/` are now properly parsed as combinators. The value is unescaped and normalized as lowercase. |
| 17 | + The original value for the combinator name is stored in `node.raws.value`. |
| 18 | + |
| 19 | +# 4.0.0 |
| 20 | + |
| 21 | +This release has **BREAKING CHANGES** that were required to fix bugs regarding values with escape sequences. Please read carefully. |
| 22 | + |
| 23 | +* **Identifiers with escapes** - CSS escape sequences are now hidden from the public API by default. |
| 24 | + The normal value of a node like a class name or ID, or an aspect of a node such as attribute |
| 25 | + selector's value, is unescaped. Escapes representing Non-ascii characters are unescaped into |
| 26 | + unicode characters. For example: `bu\tton, .\31 00, #i\2764\FE0Fu, [attr="value is \"quoted\""]` |
| 27 | + will parse respectively to the values `button`, `100`, `i❤️u`, `value is "quoted"`. |
| 28 | + The original escape sequences for these values can be found in the corresponding property name |
| 29 | + in `node.raws`. Where possible, deprecation warnings were added, but the nature |
| 30 | + of escape handling makes it impossible to detect what is escaped or not. Our expectation is |
| 31 | + that most users are neither expecting nor handling escape sequences in their use of this library, |
| 32 | + and so for them, this is a bug fix. Users who are taking care to handle escapes correctly can |
| 33 | + now update their code to remove the escape handling and let us do it for them. |
| 34 | + |
| 35 | +* **Mutating values with escapes** - When you make an update to a node property that has escape handling |
| 36 | + The value is assumed to be unescaped, and any special characters are escaped automatically and |
| 37 | + the corresponding `raws` value is immediately updated. This can result in changes to the original |
| 38 | + escape format. Where the exact value of the escape sequence is important there are methods that |
| 39 | + allow both values to be set in conjunction. There are a number of new convenience methods for |
| 40 | + manipulating values that involve escapes, especially for attributes values where the quote mark |
| 41 | + is involved. See https://github.com/postcss/postcss-selector-parser/pull/133 for an extensive |
| 42 | + write-up on these changes. |
| 43 | + |
| 44 | + |
| 45 | +**Upgrade/API Example** |
| 46 | + |
| 47 | +In `3.x` there was no unescape handling and internal consistency of several properties was the caller's job to maintain. It was very easy for the developer |
| 48 | +to create a CSS file that did not parse correctly when some types of values |
| 49 | +were in use. |
| 50 | + |
| 51 | +```js |
| 52 | +const selectorParser = require("postcss-selector-parser"); |
| 53 | +let attr = selectorParser.attribute({attribute: "id", operator: "=", value: "a-value"}); |
| 54 | +attr.value; // => "a-value" |
| 55 | +attr.toString(); // => [id=a-value] |
| 56 | +// Add quotes to an attribute's value. |
| 57 | +// All these values have to be set by the caller to be consistent: |
| 58 | +// no internal consistency is maintained. |
| 59 | +attr.raws.unquoted = attr.value |
| 60 | +attr.value = "'" + attr.value + "'"; |
| 61 | +attr.value; // => "'a-value'" |
| 62 | +attr.quoted = true; |
| 63 | +attr.toString(); // => "[id='a-value']" |
| 64 | +``` |
| 65 | + |
| 66 | +In `4.0` there is a convenient API for setting and mutating values |
| 67 | +that may need escaping. Especially for attributes. |
| 68 | + |
| 69 | +```js |
| 70 | +const selectorParser = require("postcss-selector-parser"); |
| 71 | + |
| 72 | +// The constructor requires you specify the exact escape sequence |
| 73 | +let className = selectorParser.className({value: "illegal class name", raws: {value: "illegal\\ class\\ name"}}); |
| 74 | +className.toString(); // => '.illegal\\ class\\ name' |
| 75 | + |
| 76 | +// So it's better to set the value as a property |
| 77 | +className = selectorParser.className(); |
| 78 | +// Most properties that deal with identifiers work like this |
| 79 | +className.value = "escape for me"; |
| 80 | +className.value; // => 'escape for me' |
| 81 | +className.toString(); // => '.escape\\ for\\ me' |
| 82 | + |
| 83 | +// emoji and all non-ascii are escaped to ensure it works in every css file. |
| 84 | +className.value = "😱🦄😍"; |
| 85 | +className.value; // => '😱🦄😍' |
| 86 | +className.toString(); // => '.\\1F631\\1F984\\1F60D' |
| 87 | + |
| 88 | +// you can control the escape sequence if you want, or do bad bad things |
| 89 | +className.setPropertyAndEscape('value', 'xxxx', 'yyyy'); |
| 90 | +className.value; // => "xxxx" |
| 91 | +className.toString(); // => ".yyyy" |
| 92 | + |
| 93 | +// Pass a value directly through to the css output without escaping it. |
| 94 | +className.setPropertyWithoutEscape('value', '$REPLACE_ME$'); |
| 95 | +className.value; // => "$REPLACE_ME$" |
| 96 | +className.toString(); // => ".$REPLACE_ME$" |
| 97 | + |
| 98 | +// The biggest changes are to the Attribute class |
| 99 | +// passing quoteMark explicitly is required to avoid a deprecation warning. |
| 100 | +let attr = selectorParser.attribute({attribute: "id", operator: "=", value: "a-value", quoteMark: null}); |
| 101 | +attr.toString(); // => "[id=a-value]" |
| 102 | +// Get the value with quotes on it and any necessary escapes. |
| 103 | +// This is the same as reading attr.value in 3.x. |
| 104 | +attr.getQuotedValue(); // => "a-value"; |
| 105 | +attr.quoteMark; // => null |
| 106 | + |
| 107 | +// Add quotes to an attribute's value. |
| 108 | +attr.quoteMark = "'"; // This is all that's required. |
| 109 | +attr.toString(); // => "[id='a-value']" |
| 110 | +attr.quoted; // => true |
| 111 | +// The value is still the same, only the quotes have changed. |
| 112 | +attr.value; // => a-value |
| 113 | +attr.getQuotedValue(); // => "'a-value'"; |
| 114 | + |
| 115 | +// deprecated assignment, no warning because there's no escapes |
| 116 | +attr.value = "new-value"; |
| 117 | +// no quote mark is needed so it is removed |
| 118 | +attr.getQuotedValue(); // => "new-value"; |
| 119 | + |
| 120 | +// deprecated assignment, |
| 121 | +attr.value = "\"a 'single quoted' value\""; |
| 122 | +// > (node:27859) DeprecationWarning: Assigning an attribute a value containing characters that might need to be escaped is deprecated. Call attribute.setValue() instead. |
| 123 | +attr.getQuotedValue(); // => '"a \'single quoted\' value"'; |
| 124 | +// quote mark inferred from first and last characters. |
| 125 | +attr.quoteMark; // => '"' |
| 126 | + |
| 127 | +// setValue takes options to make manipulating the value simple. |
| 128 | +attr.setValue('foo', {smart: true}); |
| 129 | +// foo doesn't require any escapes or quotes. |
| 130 | +attr.toString(); // => '[id=foo]' |
| 131 | +attr.quoteMark; // => null |
| 132 | + |
| 133 | +// An explicit quote mark can be specified |
| 134 | +attr.setValue('foo', {quoteMark: '"'}); |
| 135 | +attr.toString(); // => '[id="foo"]' |
| 136 | + |
| 137 | +// preserves quote mark by default |
| 138 | +attr.setValue('bar'); |
| 139 | +attr.toString(); // => '[id="bar"]' |
| 140 | +attr.quoteMark = null; |
| 141 | +attr.toString(); // => '[id=bar]' |
| 142 | + |
| 143 | +// with no arguments, it preserves quote mark even when it's not a great idea |
| 144 | +attr.setValue('a value \n that should be quoted'); |
| 145 | +attr.toString(); // => '[id=a\\ value\\ \\A\\ that\\ should\\ be\\ quoted]' |
| 146 | + |
| 147 | +// smart preservation with a specified default |
| 148 | +attr.setValue('a value \n that should be quoted', {smart: true, preferCurrentQuoteMark: true, quoteMark: "'"}); |
| 149 | +// => "[id='a value \\A that should be quoted']" |
| 150 | +attr.quoteMark = '"'; |
| 151 | +// => '[id="a value \\A that should be quoted"]' |
| 152 | + |
| 153 | +// this keeps double quotes because it wants to quote the value and the existing value has double quotes. |
| 154 | +attr.setValue('this should be quoted', {smart: true, preferCurrentQuoteMark: true, quoteMark: "'"}); |
| 155 | +// => '[id="this should be quoted"]' |
| 156 | + |
| 157 | +// picks single quotes because the value has double quotes |
| 158 | +attr.setValue('a "double quoted" value', {smart: true, preferCurrentQuoteMark: true, quoteMark: "'"}); |
| 159 | +// => "[id='a "double quoted" value']" |
| 160 | + |
| 161 | +// setPropertyAndEscape lets you do anything you want. Even things that are a bad idea and illegal. |
| 162 | +attr.setPropertyAndEscape('value', 'xxxx', 'the password is 42'); |
| 163 | +attr.value; // => "xxxx" |
| 164 | +attr.toString(); // => "[id=the password is 42]" |
| 165 | + |
| 166 | +// Pass a value directly through to the css output without escaping it. |
| 167 | +attr.setPropertyWithoutEscape('value', '$REPLACEMENT$'); |
| 168 | +attr.value; // => "$REPLACEMENT$" |
| 169 | +attr.toString(); // => "[id=$REPLACEMENT$]" |
| 170 | +``` |
| 171 | + |
1 | 172 | # 3.1.2
|
2 | 173 |
|
3 | 174 | * Fix: Removed dot-prop dependency since it's no longer written in es5.
|
|
0 commit comments