Skip to content

Commit 8206d53

Browse files
committed
Merge branch 'add/pos'
2 parents 27e8f61 + 08083bf commit 8206d53

23 files changed

+1417
-156
lines changed

index.js

Lines changed: 92 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,45 @@
11

2-
module.exports = function(css){
2+
module.exports = function(css, options){
3+
options = options || {};
4+
5+
/**
6+
* Positional.
7+
*/
8+
9+
var lineno = 1;
10+
var column = 1;
11+
12+
/**
13+
* Update lineno and column based on `str`.
14+
*/
15+
16+
function updatePosition(str) {
17+
var lines = str.match(/\n/g);
18+
if (lines) lineno += lines.length;
19+
var i = str.lastIndexOf('\n');
20+
column = ~i ? str.length-i : column + str.length;
21+
}
22+
23+
function position() {
24+
var start = { line: lineno, column: column };
25+
if (!options.position) return positionNoop;
26+
return function(node){
27+
node.position = {
28+
start: start,
29+
end: { line: lineno, column: column }
30+
};
31+
whitespace();
32+
return node;
33+
}
34+
}
35+
36+
/**
37+
* Return `node`.
38+
*/
39+
function positionNoop(node) {
40+
whitespace();
41+
return node;
42+
}
343

444
/**
545
* Parse stylesheet.
@@ -27,7 +67,7 @@ module.exports = function(css){
2767
*/
2868

2969
function close() {
30-
return match(/^}\s*/);
70+
return match(/^}/);
3171
}
3272

3373
/**
@@ -53,7 +93,9 @@ module.exports = function(css){
5393
function match(re) {
5494
var m = re.exec(css);
5595
if (!m) return;
56-
css = css.slice(m[0].length);
96+
var str = m[0];
97+
updatePosition(str);
98+
css = css.slice(str.length);
5799
return m;
58100
}
59101

@@ -81,20 +123,22 @@ module.exports = function(css){
81123
*/
82124

83125
function comment() {
126+
var pos = position();
84127
if ('/' != css[0] || '*' != css[1]) return;
85128

86129
var i = 2;
87130
while (null != css[i] && ('*' != css[i] || '/' != css[i + 1])) ++i;
88131
i += 2;
89132

90133
var str = css.slice(2, i - 2);
134+
column += 2;
135+
updatePosition(str);
91136
css = css.slice(i);
92-
whitespace();
93-
94-
return {
137+
column += 2;
138+
return pos({
95139
type: 'comment',
96140
comment: str
97-
};
141+
});
98142
}
99143

100144
/**
@@ -112,6 +156,8 @@ module.exports = function(css){
112156
*/
113157

114158
function declaration() {
159+
var pos = position();
160+
115161
// prop
116162
var prop = match(/^(\*?[-\w]+)\s*/);
117163
if (!prop) return;
@@ -121,18 +167,18 @@ module.exports = function(css){
121167
if (!match(/^:\s*/)) return;
122168

123169
// val
124-
var val = match(/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)\s*/);
170+
var val = match(/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)/);
125171
if (!val) return;
126-
val = val[0].trim();
127-
128-
// ;
129-
match(/^[;\s]*/);
130172

131-
return {
173+
var ret = pos({
132174
type: 'declaration',
133175
property: prop,
134-
value: val
135-
};
176+
value: val[0].trim()
177+
});
178+
179+
// ;
180+
match(/^[;\s]*/);
181+
return ret;
136182
}
137183

138184
/**
@@ -163,6 +209,7 @@ module.exports = function(css){
163209
function keyframe() {
164210
var m;
165211
var vals = [];
212+
var pos = position();
166213

167214
while (m = match(/^(from|to|\d+%|\.\d+%|\d+\.\d+%)\s*/)) {
168215
vals.push(m[1]);
@@ -171,19 +218,21 @@ module.exports = function(css){
171218

172219
if (!vals.length) return;
173220

174-
return {
221+
return pos({
175222
type: 'keyframe',
176223
values: vals,
177224
declarations: declarations()
178-
};
225+
});
179226
}
180227

181228
/**
182229
* Parse keyframes.
183230
*/
184231

185232
function atkeyframes() {
233+
var pos = position();
186234
var m = match(/^@([-\w]+)?keyframes */);
235+
187236
if (!m) return;
188237
var vendor = m[1];
189238

@@ -204,20 +253,22 @@ module.exports = function(css){
204253

205254
if (!close()) return;
206255

207-
return {
256+
return pos({
208257
type: 'keyframes',
209258
name: name,
210259
vendor: vendor,
211260
keyframes: frames
212-
};
261+
});
213262
}
214263

215264
/**
216265
* Parse supports.
217266
*/
218267

219268
function atsupports() {
269+
var pos = position();
220270
var m = match(/^@supports *([^{]+)/);
271+
221272
if (!m) return;
222273
var supports = m[1].trim();
223274

@@ -228,19 +279,21 @@ module.exports = function(css){
228279

229280
if (!close()) return;
230281

231-
return {
282+
return pos({
232283
type: 'supports',
233284
supports: supports,
234285
rules: style
235-
};
286+
});
236287
}
237288

238289
/**
239290
* Parse media.
240291
*/
241292

242293
function atmedia() {
294+
var pos = position();
243295
var m = match(/^@media *([^{]+)/);
296+
244297
if (!m) return;
245298
var media = m[1].trim();
246299

@@ -251,18 +304,19 @@ module.exports = function(css){
251304

252305
if (!close()) return;
253306

254-
return {
307+
return pos({
255308
type: 'media',
256309
media: media,
257310
rules: style
258-
};
311+
});
259312
}
260313

261314
/**
262315
* Parse paged media.
263316
*/
264317

265318
function atpage() {
319+
var pos = position();
266320
var m = match(/^@page */);
267321
if (!m) return;
268322

@@ -281,20 +335,22 @@ module.exports = function(css){
281335

282336
if (!close()) return;
283337

284-
return {
338+
return pos({
285339
type: 'page',
286340
selectors: sel,
287341
declarations: decls
288-
};
342+
});
289343
}
290344

291345
/**
292346
* Parse document.
293347
*/
294348

295349
function atdocument() {
350+
var pos = position();
296351
var m = match(/^@([-\w]+)?document *([^{]+)/);
297352
if (!m) return;
353+
298354
var vendor = m[1].trim();
299355
var doc = m[2].trim();
300356

@@ -305,12 +361,12 @@ module.exports = function(css){
305361

306362
if (!close()) return;
307363

308-
return {
364+
return pos({
309365
type: 'document',
310366
document: doc,
311367
vendor: vendor,
312368
rules: style
313-
};
369+
});
314370
}
315371

316372
/**
@@ -342,11 +398,12 @@ module.exports = function(css){
342398
*/
343399

344400
function _atrule(name) {
345-
var m = match(new RegExp('^@' + name + ' *([^;\\n]+);\\s*'));
401+
var pos = position();
402+
var m = match(new RegExp('^@' + name + ' *([^;\\n]+);'));
346403
if (!m) return;
347404
var ret = { type: name };
348405
ret[name] = m[1].trim();
349-
return ret;
406+
return pos(ret);
350407
}
351408

352409
/**
@@ -369,15 +426,19 @@ module.exports = function(css){
369426
*/
370427

371428
function rule() {
429+
var pos = position();
372430
var sel = selector();
431+
373432
if (!sel) return;
374433
comments();
375-
return {
434+
435+
return pos({
376436
type: 'rule',
377437
selectors: sel,
378438
declarations: declarations()
379-
};
439+
});
380440
}
381441

382442
return stylesheet();
383443
};
444+

test/cases/charset.json

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,59 @@
44
"rules": [
55
{
66
"type": "charset",
7-
"charset": "\"UTF-8\""
7+
"charset": "\"UTF-8\"",
8+
"position": {
9+
"start": {
10+
"line": 1,
11+
"column": 1
12+
},
13+
"end": {
14+
"line": 1,
15+
"column": 18
16+
}
17+
}
818
},
919
{
1020
"type": "comment",
11-
"comment": " Set the encoding of the style sheet to Unicode UTF-8"
21+
"comment": " Set the encoding of the style sheet to Unicode UTF-8",
22+
"position": {
23+
"start": {
24+
"line": 1,
25+
"column": 25
26+
},
27+
"end": {
28+
"line": 1,
29+
"column": 82
30+
}
31+
}
1232
},
1333
{
1434
"type": "charset",
15-
"charset": "'iso-8859-15'"
35+
"charset": "'iso-8859-15'",
36+
"position": {
37+
"start": {
38+
"line": 2,
39+
"column": 1
40+
},
41+
"end": {
42+
"line": 2,
43+
"column": 24
44+
}
45+
}
1646
},
1747
{
1848
"type": "comment",
19-
"comment": " Set the encoding of the style sheet to Latin-9 (Western European languages, with euro sign) "
49+
"comment": " Set the encoding of the style sheet to Latin-9 (Western European languages, with euro sign) ",
50+
"position": {
51+
"start": {
52+
"line": 2,
53+
"column": 25
54+
},
55+
"end": {
56+
"line": 2,
57+
"column": 122
58+
}
59+
}
2060
}
2161
]
2262
}

0 commit comments

Comments
 (0)