UNPKG

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