1 | 'use strict';
|
2 |
|
3 | exports.__esModule = true;
|
4 | exports.default = safeTokenize;
|
5 | var SINGLE_QUOTE = 39;
|
6 | var DOUBLE_QUOTE = 34;
|
7 | var BACKSLASH = 92;
|
8 | var SLASH = 47;
|
9 | var NEWLINE = 10;
|
10 | var SPACE = 32;
|
11 | var FEED = 12;
|
12 | var TAB = 9;
|
13 | var CR = 13;
|
14 | var OPEN_PARENTHESES = 40;
|
15 | var CLOSE_PARENTHESES = 41;
|
16 | var OPEN_CURLY = 123;
|
17 | var CLOSE_CURLY = 125;
|
18 | var SEMICOLON = 59;
|
19 | var ASTERICK = 42;
|
20 | var COLON = 58;
|
21 | var AT = 64;
|
22 | var RE_AT_END = /[ \n\t\r\{\(\)'"\\;/]/g;
|
23 | var RE_WORD_END = /[ \n\t\r\(\)\{\}:;@!'"\\]|\/(?=\*)/g;
|
24 | var RE_BAD_BRACKET = /.[\\\/\("'\n]/;
|
25 |
|
26 | function 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 | }
|
238 | module.exports = exports['default']; |
\ | No newline at end of file |