Skip to content

Commit ce9490a

Browse files
committed
Accept a PostCSS Rule node as an input.
1 parent 36318ff commit ce9490a

File tree

5 files changed

+108
-13
lines changed

5 files changed

+108
-13
lines changed

API.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -612,11 +612,16 @@ var result = processor.process(' .class').result;
612612
// To have the parser normalize whitespace values, utilize the options
613613
var result = processor.process(' .class ', {lossless: false}).result;
614614
// => .class
615+
616+
// For better syntax errors, pass a PostCSS Rule node.
617+
var postcss = require('postcss');
618+
var rule = postcss.rule({selector: 'a'});
619+
var result = process.process(rule).result;
615620
```
616621

617622
Arguments:
618623

619-
* `cssText (string)`: The css to be parsed.
624+
* `css (string|object)`: Either a selector string or a PostCSS Rule node.
620625
* `[options] (object)`: Process options
621626

622627
Options:
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Snapshot report for `src/__tests__/postcss.js`
2+
3+
The actual snapshot is saved in `postcss.js.snap`.
4+
5+
Generated by [AVA](https://ava.li).
6+
7+
## missing open parenthesis
8+
9+
> Snapshot 1
10+
11+
`CssSyntaxError: <css input>:1:6: Expected an opening parenthesis.␊
12+
13+
> 1 | a b c) {}␊
14+
 |  ^␊
15+
`
16+
17+
## missing open square bracket
18+
19+
> Snapshot 1
20+
21+
`CssSyntaxError: <css input>:1:6: Expected an opening square bracket.␊
22+
23+
> 1 | a b c] {}␊
24+
 |  ^␊
25+
`
26+
27+
## missing pseudo class or pseudo element
28+
29+
> Snapshot 1
30+
31+
`CssSyntaxError: <css input>:1:6: Expected a pseudo-class or pseudo-element.␊
32+
33+
> 1 | a b c: {}␊
34+
 |  ^␊
35+
`
36+
37+
## space in between colon and word (incorrect pseudo)
38+
39+
> Snapshot 1
40+
41+
`CssSyntaxError: <css input>:1:5: Expected a pseudo-class or pseudo-element.␊
42+
43+
> 1 | a b: c {}␊
44+
 |  ^␊
45+
`
46+
47+
## string after colon (incorrect pseudo)
48+
49+
> Snapshot 1
50+
51+
`CssSyntaxError: <css input>:1:5: Expected a pseudo-class or pseudo-element.␊
52+
53+
> 1 | a b:"wow" {}␊
54+
 |  ^␊
55+
`
418 Bytes
Binary file not shown.

src/__tests__/postcss.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import test from 'ava';
2+
import postcss from 'postcss';
3+
import {parse} from './util/helpers';
4+
5+
function showCode (t, selector) {
6+
const rule = postcss.parse(selector).first;
7+
try {
8+
parse(rule);
9+
} catch (e) {
10+
t.snapshot(e.toString());
11+
}
12+
}
13+
14+
test('missing open square bracket', showCode, 'a b c] {}');
15+
test('missing open parenthesis', showCode, 'a b c) {}');
16+
test('missing pseudo class or pseudo element', showCode, 'a b c: {}');
17+
18+
test('space in between colon and word (incorrect pseudo)', showCode, 'a b: c {}');
19+
test('string after colon (incorrect pseudo)', showCode, 'a b:"wow" {}');

src/parser.js

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,14 @@ export default class Parser {
4343

4444
const selector = new Selector();
4545
this.root.append(selector);
46-
4746
this.current = selector;
47+
48+
this.css = typeof input.css === 'string' ? input.css : input.css.selector;
49+
4850
if (this.lossy) {
49-
this.tokens = tokenize({safe: input.safe, css: input.css.trim()});
51+
this.tokens = tokenize({safe: input.safe, css: this.css.trim()});
5052
} else {
51-
this.tokens = tokenize(input);
53+
this.tokens = tokenize(Object.assign({}, input, {css: this.css}));
5254
}
5355

5456
return this.loop();
@@ -175,20 +177,26 @@ export default class Parser {
175177
this.position ++;
176178
}
177179

178-
error (message) {
179-
throw new this.input.error(message); // eslint-disable-line new-cap
180+
error (message, opts) {
181+
throw new this.input.error(message, opts); // eslint-disable-line new-cap
180182
}
181183

182184
missingBackslash () {
183-
return this.error('Expected a backslash preceding the semicolon.');
185+
return this.error('Expected a backslash preceding the semicolon.', {
186+
index: this.currToken[6],
187+
});
184188
}
185189

186190
missingParenthesis () {
187-
return this.error('Expected opening parenthesis.');
191+
return this.error('Expected an opening parenthesis.', {
192+
index: this.currToken[6],
193+
});
188194
}
189195

190196
missingSquareBracket () {
191-
return this.error('Expected opening square bracket.');
197+
return this.error('Expected an opening square bracket.', {
198+
index: this.currToken[6],
199+
});
192200
}
193201

194202
namespace () {
@@ -256,7 +264,9 @@ export default class Parser {
256264
}
257265
}
258266
if (balanced) {
259-
this.error('Expected closing parenthesis.');
267+
this.error('Expected a closing parenthesis.', {
268+
index: this.currToken[6],
269+
});
260270
}
261271
}
262272

@@ -268,7 +278,9 @@ export default class Parser {
268278
this.position ++;
269279
}
270280
if (!this.currToken) {
271-
return this.error('Expected pseudo-class or pseudo-element');
281+
return this.error('Expected a pseudo-class or pseudo-element.', {
282+
index: this.position - 1,
283+
});
272284
}
273285
if (this.currToken[0] === tokens.word) {
274286
this.splitWord(false, (first, length) => {
@@ -288,11 +300,15 @@ export default class Parser {
288300
this.nextToken &&
289301
this.nextToken[0] === tokens.openParenthesis
290302
) {
291-
this.error('Misplaced parenthesis.');
303+
this.error('Misplaced parenthesis.', {
304+
index: this.nextToken[6],
305+
});
292306
}
293307
});
294308
} else {
295-
this.error('Unexpected "' + this.currToken[0] + '" found.');
309+
this.error('Expected a pseudo-class or pseudo-element.', {
310+
index: this.currToken[6],
311+
});
296312
}
297313
}
298314

0 commit comments

Comments
 (0)