Skip to content

Commit b1c4209

Browse files
committed
hack postcss to support inline comments
1 parent 7103b6a commit b1c4209

File tree

11 files changed

+409
-1
lines changed

11 files changed

+409
-1
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/node_modules/
2+
.DS_Store
3+
npm-debug.log

.npmignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
example
2+
test
3+
.gitignore

README.md

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,46 @@
11
# postcss-comment
2-
Allow postcss to support inline comments
2+
Allow postcss to support inline comments.
3+
4+
## Usage
5+
6+
```javascript
7+
var postcss = require('postcss-comment')
8+
9+
var fs = require('fs')
10+
11+
var file = __dirname + '/inline.css'
12+
13+
postcss()
14+
.process(
15+
fs.readFileSync(file, 'utf8'),
16+
{ from: file }
17+
)
18+
.then(function (result) {
19+
console.log(result.css)
20+
})
21+
22+
```
23+
24+
inline.css:
25+
```css
26+
// comments
27+
// comments
28+
.inline-comment { // comments
29+
// comments
30+
color: red; // comments
31+
} // comments
32+
// comments
33+
34+
```
35+
36+
outputs:
37+
```css
38+
/* comments */
39+
/* comments */
40+
.inline-comment { /* comments */
41+
/* comments */
42+
color: red; /* comments */
43+
} /* comments */
44+
/* comments */
45+
46+
```

example/inline.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// comments
2+
// comments
3+
.inline-comment { // comments
4+
// comments
5+
color: red; // comments
6+
} // comments
7+
// comments

example/inline.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
var postcss = require('..')
2+
var fs = require('fs')
3+
4+
var file = __dirname + '/inline.css'
5+
6+
postcss()
7+
.process(
8+
fs.readFileSync(file, 'utf8'),
9+
{ from: file }
10+
)
11+
.then(function (result) {
12+
console.log(result.css)
13+
})

index.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
var Parser = require('postcss/lib/parser')
2+
var tokenizer = require('./lib/tokenize')
3+
4+
Parser.prototype.tokenize = function () {
5+
this.tokens = tokenizer(this.input)
6+
}
7+
8+
module.exports = require('postcss')
9+

lib/tokenize.js

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
var SINGLE_QUOTE = 39; // `''
2+
var DOUBLE_QUOTE = 34; // `"'
3+
var BACKSLASH = 92; // `\'
4+
var SLASH = 47; // `/'
5+
var NEWLINE = 10; // `\n'
6+
var SPACE = 32; // ` '
7+
var FEED = 12; // `\f'
8+
var TAB = 9; // `\t'
9+
var CR = 13; // `\r'
10+
var OPEN_PARENTHESES = 40; // `('
11+
var CLOSE_PARENTHESES = 41; // `)'
12+
var OPEN_CURLY = 123; // `{'
13+
var CLOSE_CURLY = 125; // `}'
14+
var SEMICOLON = 59; // `;'
15+
var ASTERICK = 42; // `*'
16+
var COLON = 58; // `:'
17+
var AT = 64; // `@'
18+
var RE_AT_END = /[ \n\t\r\{\(\)'"\\;/]/g;
19+
var RE_WORD_END = /[ \n\t\r\(\)\{\}:;@!'"\\]|\/(?=\*)/g;
20+
var RE_BAD_BRACKET = /.[\\\/\("'\n]/;
21+
22+
module.exports = function tokenize(input) {
23+
var tokens = [];
24+
var css = input.css.valueOf();
25+
26+
var code, next, quote, lines, last, content, escape,
27+
nextLine, nextOffset, escaped, escapePos, prev, n;
28+
29+
var length = css.length;
30+
var offset = -1;
31+
var line = 1;
32+
var pos = 0;
33+
34+
function unclosed(what) {
35+
throw input.error('Unclosed ' + what, line, pos - offset);
36+
}
37+
38+
while ( pos < length ) {
39+
code = css.charCodeAt(pos);
40+
41+
if ( code === NEWLINE ) {
42+
offset = pos;
43+
line += 1;
44+
}
45+
46+
switch ( code ) {
47+
case NEWLINE:
48+
case SPACE:
49+
case TAB:
50+
case CR:
51+
case FEED:
52+
next = pos;
53+
do {
54+
next += 1;
55+
code = css.charCodeAt(next);
56+
if ( code === NEWLINE ) {
57+
offset = next;
58+
line += 1;
59+
}
60+
} while ( code === SPACE ||
61+
code === NEWLINE ||
62+
code === TAB ||
63+
code === CR ||
64+
code === FEED );
65+
66+
tokens.push(['space', css.slice(pos, next)]);
67+
pos = next - 1;
68+
break;
69+
70+
case OPEN_CURLY:
71+
tokens.push(['{', '{', line, pos - offset]);
72+
break;
73+
74+
case CLOSE_CURLY:
75+
tokens.push(['}', '}', line, pos - offset]);
76+
break;
77+
78+
case COLON:
79+
tokens.push([':', ':', line, pos - offset]);
80+
break;
81+
82+
case SEMICOLON:
83+
tokens.push([';', ';', line, pos - offset]);
84+
break;
85+
86+
case OPEN_PARENTHESES:
87+
prev = tokens.length ? tokens[tokens.length - 1][1] : '';
88+
n = css.charCodeAt(pos + 1);
89+
if ( prev === 'url' && n !== SINGLE_QUOTE && n !== DOUBLE_QUOTE &&
90+
n !== SPACE && n !== NEWLINE && n !== TAB &&
91+
n !== FEED && n !== CR ) {
92+
next = pos;
93+
do {
94+
escaped = false;
95+
next = css.indexOf(')', next + 1);
96+
if ( next === -1 ) unclosed('bracket');
97+
escapePos = next;
98+
while ( css.charCodeAt(escapePos - 1) === BACKSLASH ) {
99+
escapePos -= 1;
100+
escaped = !escaped;
101+
}
102+
} while ( escaped );
103+
104+
tokens.push(['brackets', css.slice(pos, next + 1),
105+
line, pos - offset,
106+
line, next - offset
107+
]);
108+
pos = next;
109+
110+
} else {
111+
next = css.indexOf(')', pos + 1);
112+
content = css.slice(pos, next + 1);
113+
114+
if ( next === -1 || RE_BAD_BRACKET.test(content) ) {
115+
tokens.push(['(', '(', line, pos - offset]);
116+
} else {
117+
tokens.push(['brackets', content,
118+
line, pos - offset,
119+
line, next - offset
120+
]);
121+
pos = next;
122+
}
123+
}
124+
125+
break;
126+
127+
case CLOSE_PARENTHESES:
128+
tokens.push([')', ')', line, pos - offset]);
129+
break;
130+
131+
case SINGLE_QUOTE:
132+
case DOUBLE_QUOTE:
133+
quote = code === SINGLE_QUOTE ? '\'' : '"';
134+
next = pos;
135+
do {
136+
escaped = false;
137+
next = css.indexOf(quote, next + 1);
138+
if ( next === -1 ) unclosed('quote');
139+
escapePos = next;
140+
while ( css.charCodeAt(escapePos - 1) === BACKSLASH ) {
141+
escapePos -= 1;
142+
escaped = !escaped;
143+
}
144+
} while ( escaped );
145+
146+
tokens.push(['string', css.slice(pos, next + 1),
147+
line, pos - offset,
148+
line, next - offset
149+
]);
150+
pos = next;
151+
break;
152+
153+
case AT:
154+
RE_AT_END.lastIndex = pos + 1;
155+
RE_AT_END.test(css);
156+
if ( RE_AT_END.lastIndex === 0 ) {
157+
next = css.length - 1;
158+
} else {
159+
next = RE_AT_END.lastIndex - 2;
160+
}
161+
tokens.push(['at-word', css.slice(pos, next + 1),
162+
line, pos - offset,
163+
line, next - offset
164+
]);
165+
pos = next;
166+
break;
167+
168+
case BACKSLASH:
169+
next = pos;
170+
escape = true;
171+
while ( css.charCodeAt(next + 1) === BACKSLASH ) {
172+
next += 1;
173+
escape = !escape;
174+
}
175+
code = css.charCodeAt(next + 1);
176+
if ( escape && (code !== SLASH &&
177+
code !== SPACE &&
178+
code !== NEWLINE &&
179+
code !== TAB &&
180+
code !== CR &&
181+
code !== FEED ) ) {
182+
next += 1;
183+
}
184+
tokens.push(['word', css.slice(pos, next + 1),
185+
line, pos - offset,
186+
line, next - offset
187+
]);
188+
pos = next;
189+
break;
190+
191+
default:
192+
if ( code === SLASH && css.charCodeAt(pos + 1) === ASTERICK ) {
193+
next = css.indexOf('*/', pos + 2) + 1;
194+
if ( next === 0 ) unclosed('comment');
195+
196+
content = css.slice(pos, next + 1);
197+
lines = content.split('\n');
198+
last = lines.length - 1;
199+
200+
if ( last > 0 ) {
201+
nextLine = line + last;
202+
nextOffset = next - lines[last].length;
203+
} else {
204+
nextLine = line;
205+
nextOffset = offset;
206+
}
207+
208+
tokens.push(['comment', content,
209+
line, pos - offset,
210+
nextLine, next - nextOffset
211+
]);
212+
213+
offset = nextOffset;
214+
line = nextLine;
215+
pos = next;
216+
217+
} else if ( code === SLASH && css.charCodeAt(pos + 1) === SLASH ) {
218+
next = css.indexOf('\n', pos + 2);
219+
if (next === -1) {
220+
next = css.length - 1
221+
} else {
222+
next = next - 1
223+
}
224+
225+
content = '/*' + css.slice(pos + 2, next + 1) + ' */';
226+
227+
nextLine = line;
228+
nextOffset = offset;
229+
230+
tokens.push(['comment', content,
231+
line, pos - offset,
232+
nextLine, next - nextOffset
233+
]);
234+
235+
offset = nextOffset;
236+
line = nextLine;
237+
pos = next;
238+
239+
} else {
240+
RE_WORD_END.lastIndex = pos + 1;
241+
RE_WORD_END.test(css);
242+
if ( RE_WORD_END.lastIndex === 0 ) {
243+
next = css.length - 1;
244+
} else {
245+
next = RE_WORD_END.lastIndex - 2;
246+
}
247+
248+
tokens.push(['word', css.slice(pos, next + 1),
249+
line, pos - offset,
250+
line, next - offset
251+
]);
252+
pos = next;
253+
}
254+
255+
break;
256+
}
257+
258+
pos++;
259+
}
260+
261+
return tokens;
262+
}

package.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "postcss-comment",
3+
"version": "0.0.1",
4+
"description": "Allow postcss to support inline comments",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "tap test/*.js"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/zoubin/postcss-comment.git"
12+
},
13+
"keywords": [
14+
"postcss",
15+
"inline",
16+
"comment"
17+
],
18+
"author": "zoubin",
19+
"license": "MIT",
20+
"bugs": {
21+
"url": "https://github.com/zoubin/postcss-comment/issues"
22+
},
23+
"homepage": "https://github.com/zoubin/postcss-comment#readme",
24+
"dependencies": {},
25+
"peerDependencies": {
26+
"postcss": "^5.0.10"
27+
},
28+
"devDependencies": {
29+
"tap": "^2.2.0"
30+
}
31+
}

test/fixtures/inline.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// comments
2+
// comments
3+
.inline-comment { // comments
4+
// comments
5+
color: red; // comments
6+
} // comments
7+
// comments

test/fixtures/inline.expected.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/* comments */
2+
/* comments */
3+
.inline-comment { /* comments */
4+
/* comments */
5+
color: red; /* comments */
6+
} /* comments */
7+
/* comments */

0 commit comments

Comments
 (0)