Skip to content

Commit ad31df6

Browse files
committed
fix: add migration information
1 parent 7a56022 commit ad31df6

File tree

2 files changed

+251
-0
lines changed

2 files changed

+251
-0
lines changed

CHANGELOG.md

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
2.2.1-2.2.2
2+
-----------
3+
4+
* Update published docs.
5+
6+
2.2.0
7+
-----
8+
9+
* Full refactoring.
10+
* Switch to typescript.
11+
* Pre-defined CSS syntaxes were included.
12+
* The whole AST was documented.
13+
14+
### Migrating from 1.x
15+
16+
#### `CssSelectorParser` -> `createParser`
17+
18+
In 1.x versions there was `CssSelectorParser` class which had to be contructed and then configured.
19+
In 2.x versions there is `createParser()` function which returns a `parse()` function. All the configutation is passed
20+
to `createParser()` params.
21+
22+
Before:
23+
24+
```javascript
25+
var CssSelectorParser = require('css-selector-parser').CssSelectorParser,
26+
parser = new CssSelectorParser();
27+
parser.registerSelectorPseudos('has');
28+
parser.registerNumericPseudos('nth-child');
29+
parser.registerNestingOperators('>', '+', '~');
30+
parser.registerAttrEqualityMods('^', '$', '*', '~');
31+
32+
const selector = 'a[href^=/], .container:has(nav) > a[href]:lt($var):nth-child(5)';
33+
```
34+
35+
After:
36+
37+
```javascript
38+
import {createParser} from 'css-selector-parser';
39+
40+
const parse = createParser({
41+
syntax: {
42+
pseudoClasses: {
43+
// In 1.x any pseudo-classes were accepted.
44+
// in 2.x parser only accepts known psuedo-classes unless `unknown: accept` was specified.
45+
unknown: 'accept',
46+
definitions: {
47+
// This is a replacement for registerSelectorPseudos().
48+
Selector: ['has'],
49+
// This is a replacement for registerNumericPseudos().
50+
Formula: ['nth-child']
51+
}
52+
},
53+
// This is a replacement for registerNestingOperators().
54+
combinators: ['>', '+', '~'],
55+
attributes: {
56+
// This a replacement for registerAttrEqualityMods().
57+
// Note that equals sign ("=") is included into the operator definitions.
58+
operators: ['^=', '$=', '*=', '~=']
59+
}
60+
},
61+
// This is a replacement for enableSubstitutes()
62+
substitutes: true
63+
});
64+
65+
const selector = parse('a[href^=/], .container:has(nav) > a[href]:lt($var):nth-child(5)');
66+
```
67+
68+
* [All syntax definition options.](docs/interfaces/SyntaxDefinition.md).
69+
* [All the psudo-class definition options.](docs/interfaces/SyntaxDefinition.md#pseudoclasses).
70+
* [All the attribute definition options.](docs/interfaces/SyntaxDefinition.md#attributes).
71+
72+
#### Predefined CSS syntax definitions
73+
74+
You no longer need to make an extensive configuration of `css-selector-parser` in order to make it understand
75+
the necessary CSS standards. You can now just define CSS/CSS selectors version directly:
76+
77+
```javascript
78+
import {createParser} from 'css-selector-parser';
79+
80+
const parse = createParser({syntax: 'css3'});
81+
82+
const selector = parse('a[href^=/], .container:has(nav) > a[href]:nth-child(2n + 1)::before');
83+
```
84+
85+
Here are the pre-defined CSS standards for your disposal:
86+
87+
* `css1`: https://www.w3.org/TR/CSS1/
88+
* `css2`: https://www.w3.org/TR/CSS2/
89+
* `css3`/`selectors-3`: https://www.w3.org/TR/selectors-3/
90+
* `selectors-4`: https://www.w3.org/TR/selectors-4/
91+
* `latest`: refers to `selectors-4`
92+
* `progressive`: `latest` + accepts unknown psudo-classes, psudo-elements and attribute case sensitivity modifiers
93+
94+
#### Make sure you use proper `strict` value
95+
96+
CSS selector parser in modern browsers is very forgiving. For instance, it works fine with unclosed attribute
97+
selectors: `"[attr=value"`. If you would like to mimic this behavior from browsers, set `strict` to `false`, i.e.:
98+
99+
```javascript
100+
import {createParser} from 'css-selector-parser';
101+
102+
const parse = createParser({syntax: 'css3', strict: false});
103+
104+
const selector = parse(':lang(en'); // doesn't crash
105+
```
106+
107+
#### Render is now a separate export
108+
109+
`render()` method used to be a method of `CssSelectorParser` class. Now it can be imported directly and used.
110+
111+
Example:
112+
113+
```javascript
114+
import {createParser, render} from 'css-selector-parser';
115+
116+
const parse = createParser({syntax: 'progressive'});
117+
118+
const selector = parse('div#user-123.user:lang(en)');
119+
120+
console.log(render(selector)); // div#user-123.user:lang(en)
121+
```
122+
123+
#### AST changes
124+
125+
AST had a lot of changes.
126+
127+
#### Selector
128+
129+
[New type info.](docs/interfaces/AstSelector.md)
130+
131+
1. Type changed: `selector` -> `Selector`.
132+
2. Prop changed: `selectors` -> `rules`, also `selectors` contained `ruleSet[]`, which in turn has `rule` field,
133+
and new `rules` contains `Rule[]` directly.
134+
135+
Before: `{type: 'selector', selectors: [ {type: 'ruleSet', rule: {<RULE 1 DATA>}}, {type: 'ruleSet', rule: {<RULE 2 DATA>}} ]}`.
136+
137+
After: `{type: 'Selector', rules: [ {<RULE 1 DATA>}, {<RULE 2 DATA>} ]}`.
138+
139+
#### Rule
140+
141+
[New type info.](docs/interfaces/AstRule.md)
142+
143+
1. Type changed: `rule` -> `Rule`.
144+
2. Prop changed: `id: string` -> `ids: string[]`. According to the CSS spec one rule may have more than 1 `id`,
145+
so `#root#root` is a valid selector.
146+
3. Prop renamed: `nestingOperator` -> `combinator`. A proper name according to CSS spec was chosen.
147+
4. Prop renamed: `rule` -> `nestedRule`. A proper name to indicate nesting was chosen.
148+
5. Prop changed: `tagName: string` -> `tag: TagName | WildcardTag`. Using explicit distinction between
149+
TagName (i.e. `div`) and WildcardTag (`*`), because tag name can also be `*` if escaped properly (`\*`).
150+
6. Prop changed: `attrs` -> `attributes`. Attribute type was changed, see below.
151+
7. Prop changed: `pseudos` -> `pseudoClasses`. There are pseudo-elements and pseudo-classes, now they are separated
152+
properly (there is a separate `pseudoElement` property). Pseudo class type was changed, see below.
153+
154+
Before:
155+
156+
```javascript
157+
({
158+
type: 'rule',
159+
tagName: 'div',
160+
id: 'user-123',
161+
classNames: ['user'],
162+
attrs: [
163+
{name: 'role', operator: '$=', valueType: 'string', value: 'button'}
164+
],
165+
pseudos: [
166+
{name: 'lang', valueType: 'string', value: 'en'}
167+
],
168+
nestingOperator: '>'
169+
})
170+
```
171+
172+
After:
173+
174+
```javascript
175+
({
176+
type: 'Rule',
177+
tag: {type: 'TagName', name: 'div'},
178+
ids: ['user-123'],
179+
classNames: ['user'],
180+
attributes: [
181+
{type: 'Attribute', name: 'role', operator: '$=', value: {type: 'String', value: 'button'}}
182+
],
183+
pseudoClasses: [
184+
{type: 'PseudoClass', name: 'lang', value: {type: 'String', value: 'en'}}
185+
],
186+
combinator: '>'
187+
})
188+
```
189+
190+
#### Attribute
191+
192+
[New type info.](docs/interfaces/AstAttribute.md)
193+
194+
1. Type introduced: `Attribute`.
195+
2. Prop `value` and `valueType` were combined to a single prop `value` with a field `type`.
196+
197+
[All possible value types.](docs/interfaces/AstAttribute.md#value)
198+
199+
200+
##### Example 1
201+
202+
Before: `{name: 'role'}`.
203+
204+
After: `{type: 'Attribute', name: 'role'}`.
205+
206+
##### Example 2
207+
208+
Before: `{name: 'role', operator: '$=', valueType: 'string', value: 'button'}`.
209+
210+
After: `{type: 'Attribute', name: 'role', operator: '$=', value: {type: 'String', value: 'button'}}`.
211+
212+
##### Example 3
213+
214+
Before: `{name: 'role', operator: '=', valueType: 'substitute', value: 'var'}`.
215+
216+
After: `{type: 'Attribute', name: 'role', operator: '=', value: {type: 'Substitute', name: 'var'}}`.
217+
218+
#### Pseudo Classes
219+
220+
[New type info.](docs/interfaces/AstPseudoClass.md)
221+
222+
1. Type introduced: `PseudoClass`.
223+
2. Prop `value` and `valueType` were combined to a single prop `argument` with a field `type`.
224+
225+
[All possible argument types.](docs/interfaces/AstPseudoClass.md#argument)
226+
227+
##### Example 1
228+
229+
Before: `{name: 'visited'}`.
230+
231+
After: `{type: 'PseudoClass', name: 'visited'}`.
232+
233+
##### Example 2
234+
235+
Before: `{name: 'lang', valueType: 'string', value: 'en'}`.
236+
237+
After: `{type: 'PseudoClass', name: 'lang', argument: {type: 'String', value: 'en'}}`.
238+
239+
##### Example 3
240+
241+
Before: `{name: 'lang', valueType: 'substitute', value: 'var'}`.
242+
243+
After: `{type: 'PseudoClass', name: 'lang', argument: {type: 'Substitute', name: 'var'}}`.
244+
245+
##### Example 4
246+
247+
Before: `{name: 'has', valueType: 'selector', value: {type: 'selector', selectors: [{type: 'ruleSet', rule: {type: 'rule', tagName: 'div'}}]}}`.
248+
249+
After: `{type: 'PseudoClass', name: 'has', argument: {type: 'Selector', rules: [{type: 'Rule', tag: {type: 'TagName', name: 'div'}}]}}`.

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ css-selector-parser
1414
* `latest`: refers to `selectors-4`
1515
* `progressive`: `latest` + accepts unknown psudo-classes, psudo-elements and attribute case sensitivity modifiers
1616

17+
Important: [Migrating from 1.x](CHANGELOG.md#220).
18+
1719
Installation
1820
------------
1921

0 commit comments

Comments
 (0)