| 183 | } |
| 184 | |
| 185 | parse(input) { |
| 186 | const checkToken = (a, b) => !this.escaping && this.stringState === StringState.None && a === b; |
| 187 | |
| 188 | const checkSES = c => { |
| 189 | if (this.escaping) { |
| 190 | return false; |
| 191 | } |
| 192 | |
| 193 | if (c != '"' && c != '\'') { |
| 194 | return false; |
| 195 | } |
| 196 | |
| 197 | const state = c == '"' ? StringState.Double : StringState.Single; |
| 198 | |
| 199 | // start |
| 200 | if (this.stringState == StringState.None) { |
| 201 | this.stringState = state; |
| 202 | return true; |
| 203 | } |
| 204 | |
| 205 | // end |
| 206 | if (this.stringState == state) { |
| 207 | this.stringState = StringState.None; |
| 208 | return true; |
| 209 | } |
| 210 | |
| 211 | return false; |
| 212 | }; |
| 213 | |
| 214 | input = input.replace(/\/\*[\w\W]*?\*\//g, ''); |
| 215 | |
| 216 | for (let i = 0; i < input.length; i++) { |
| 217 | const peek = () => input[i + 1]; |
| 218 | |
| 219 | const c = input[i]; |
| 220 | if (c == '\\') { |
| 221 | this.escaping = true; |
| 222 | continue; |
| 223 | } |
| 224 | |
| 225 | // console.log(`${c} | state: ${this.mainState}`); |
| 226 | |
| 227 | const finishRule = () => { |
| 228 | this.currentRule.addProperty(this.currentProp, this.currentValue); |
| 229 | |
| 230 | this.currentProp = ''; |
| 231 | this.currentValue = ''; |
| 232 | this.currentSelector = ''; |
| 233 | }; |
| 234 | |
| 235 | switch (this.atState) { |
| 236 | case AtState.Name: { |
| 237 | // begin nested cond `(...)` |
| 238 | if (checkToken(c, '(')) { |
| 239 | this.currentAtCond = '('; |
| 240 | |
| 241 | this.atState = AtState.Cond; |
| 242 | continue; |