From db2651ba5c3e06db90c758544c6422980917bff9 Mon Sep 17 00:00:00 2001 From: evilebottnawi Date: Tue, 19 Mar 2019 14:38:13 +0300 Subject: [PATCH] refactor: remove unnecessary stuff --- src/__tests__/exceptions.js | 43 +++++++++++------ src/parser.js | 96 ++++++++++++++++++------------------- 2 files changed, 76 insertions(+), 63 deletions(-) diff --git a/src/__tests__/exceptions.js b/src/__tests__/exceptions.js index a8dec86..fc9629f 100644 --- a/src/__tests__/exceptions.js +++ b/src/__tests__/exceptions.js @@ -1,27 +1,40 @@ import {throws} from './util/helpers'; // Unclosed elements -throws('unclosed string', 'a[href="wow]'); -throws('unclosed comment', '/* oops'); -throws('unclosed pseudo element', 'button::'); -throws('unclosed pseudo class', 'a:'); -throws('unclosed attribute selector', '[name="james"][href'); +throws('unclosed string', 'a[href="wow]', 'Unclosed quote'); +throws('unclosed comment', '/* oops', 'Unclosed comment'); +throws('unclosed pseudo element', 'button::', 'Expected a pseudo-class or pseudo-element.'); +throws('unclosed pseudo class', 'a:', 'Expected a pseudo-class or pseudo-element.'); +throws('unclosed attribute selector', '[name', 'Expected a closing square bracket.'); +throws('unclosed attribute selector (2)', '[name=', 'Expected a closing square bracket.'); +throws('unclosed attribute selector (3)', '[name="james"', 'Expected a closing square bracket.'); +throws('unclosed attribute selector (4)', '[name="james"][href', 'Expected a closing square bracket.'); +throws('unclosed attribute selector (5)', '[name="james"][href', 'Expected a closing square bracket.'); -throws('no opening parenthesis', ')'); -throws('no opening parenthesis (2)', ':global.foo)'); -throws('no opening parenthesis (3)', 'h1:not(h2:not(h3)))'); +throws('invalid attribute selector', '[]', 'Expected an attribute.'); +throws('invalid attribute selector (2)', '["hello"]', 'Expected an attribute.'); +throws('invalid attribute selector (3)', '[="hello"]', 'Expected an attribute, found "=" instead.'); -throws('no opening square bracket', ']'); -throws('no opening square bracket (2)', ':global.foo]'); -throws('no opening square bracket (3)', '[global]]'); +throws('no opening parenthesis', ')', 'Expected an opening parenthesis.'); +throws('no opening parenthesis (2)', ':global.foo)', 'Expected an opening parenthesis.'); +throws('no opening parenthesis (3)', 'h1:not(h2:not(h3)))', 'Expected an opening parenthesis.'); -throws('bad pseudo element', 'button::"after"'); -throws('missing closing parenthesis in pseudo', ':not([attr="test"]:not([attr="test"])'); +throws('no opening square bracket', ']', 'Expected an opening square bracket.'); +throws('no opening square bracket (2)', ':global.foo]', 'Expected an opening square bracket.'); +throws('no opening square bracket (3)', '[global]]', 'Expected an opening square bracket.'); -throws('bad syntax', '-moz-osx-font-smoothing: grayscale'); -throws('bad syntax (2)', '! .body'); +throws('bad pseudo element', 'button::"after"', 'Expected a pseudo-class or pseudo-element.'); +throws('missing closing parenthesis in pseudo', ':not([attr="test"]:not([attr="test"])', 'Expected a closing parenthesis.'); + +throws('bad syntax', '-moz-osx-font-smoothing: grayscale', 'Expected a pseudo-class or pseudo-element.'); +throws('bad syntax (2)', '! .body', 'Unexpected \'!\'. Escaping special characters with \\ may help.'); throws('missing backslash for semicolon', '.;'); throws('missing backslash for semicolon (2)', '.\;'); throws('unexpected / foo', '-Option\/root', "Unexpected '/'. Escaping special characters with \\ may help."); throws('bang in selector', '.foo !optional', "Unexpected '!'. Escaping special characters with \\ may help."); + +throws('misplaced parenthesis', ':not(', 'Expected a closing parenthesis.'); +throws('misplaced parenthesis (2)', ':not)', 'Expected an opening parenthesis.'); +throws('misplaced parenthesis (3)', ':not((', 'Expected a closing parenthesis.'); +throws('misplaced parenthesis (4)', ':not))', 'Expected an opening parenthesis.'); diff --git a/src/parser.js b/src/parser.js index 736d239..bae8eea 100644 --- a/src/parser.js +++ b/src/parser.js @@ -144,11 +144,18 @@ export default class Parser { attr.push(this.currToken); this.position ++; } - if (this.currToken[TOKEN.TYPE] !== tokens.closeSquare) { - return this.expected('closing square bracket', this.currToken[TOKEN.START_POS]); + + if (!this.currToken) { + this.position --; + return this.missingClosingSquareBracket(); } const len = attr.length; + + if (len === 0) { + return this.expected('attribute', this.currToken[TOKEN.START_POS]); + } + const node = { source: getSource( startingToken[1], @@ -465,8 +472,7 @@ export default class Parser { if (rawSpace === space) { rawSpace = undefined; } - let result = {space, rawSpace}; - return result; + return {space, rawSpace}; } isNamedCombinator (position = this.position) { @@ -475,30 +481,27 @@ export default class Parser { this.tokens[position + 2] && this.tokens[position + 2][TOKEN.TYPE] === tokens.slash; } + namedCombinator () { - if (this.isNamedCombinator()) { - let nameRaw = this.content(this.tokens[this.position + 1]); - let name = unesc(nameRaw).toLowerCase(); - let raws = {}; - if (name !== nameRaw) { - raws.value = `/${nameRaw}/`; - } - let node = new Combinator({ - value: `/${name}/`, - source: getSource( - this.currToken[TOKEN.START_LINE], - this.currToken[TOKEN.START_COL], - this.tokens[this.position + 2][TOKEN.END_LINE], - this.tokens[this.position + 2][TOKEN.END_COL], - ), - sourceIndex: this.currToken[TOKEN.START_POS], - raws, - }); - this.position = this.position + 3; - return node; - } else { - this.unexpected(); + let nameRaw = this.content(this.tokens[this.position + 1]); + let name = unesc(nameRaw).toLowerCase(); + let raws = {}; + if (name !== nameRaw) { + raws.value = `/${nameRaw}/`; } + let node = new Combinator({ + value: `/${name}/`, + source: getSource( + this.currToken[TOKEN.START_LINE], + this.currToken[TOKEN.START_COL], + this.tokens[this.position + 2][TOKEN.END_LINE], + this.tokens[this.position + 2][TOKEN.END_COL], + ), + sourceIndex: this.currToken[TOKEN.START_POS], + raws, + }); + this.position = this.position + 3; + return node; } combinator () { @@ -620,14 +623,22 @@ export default class Parser { }); } - missingParenthesis () { + missingOpeningParenthesis () { return this.expected('opening parenthesis', this.currToken[TOKEN.START_POS]); } - missingSquareBracket () { + missingClosingParenthesis () { + return this.expected('closing parenthesis', this.currToken[TOKEN.START_POS]); + } + + missingOpeningSquareBracket () { return this.expected('opening square bracket', this.currToken[TOKEN.START_POS]); } + missingClosingSquareBracket () { + return this.expected('closing square bracket', this.currToken[TOKEN.START_POS]); + } + unexpected () { return this.error(`Unexpected '${this.content()}'. Escaping special characters with \\ may help.`, this.currToken[TOKEN.START_POS]); } @@ -702,6 +713,10 @@ export default class Parser { parenValue += this.parseParenthesisToken(this.currToken); this.position ++; } + if (unbalanced) { + this.position --; + return this.missingClosingParenthesis(); + } if (last) { last.appendToPropertyAndEscape("value", parenValue, parenValue); } else { @@ -718,7 +733,8 @@ export default class Parser { } } if (unbalanced) { - return this.expected('closing parenthesis', this.currToken[TOKEN.START_POS]); + this.position --; + return this.missingClosingParenthesis(); } } @@ -733,22 +749,13 @@ export default class Parser { return this.expected(['pseudo-class', 'pseudo-element'], this.position - 1); } if (this.currToken[TOKEN.TYPE] === tokens.word) { - this.splitWord(false, (first, length) => { + this.splitWord(false, (first) => { pseudoStr += first; this.newNode(new Pseudo({ value: pseudoStr, source: getTokenSourceSpan(startingToken, this.currToken), sourceIndex: startingToken[TOKEN.START_POS], })); - if ( - length > 1 && - this.nextToken && - this.nextToken[TOKEN.TYPE] === tokens.openParenthesis - ) { - this.error('Misplaced parenthesis.', { - index: this.nextToken[TOKEN.START_POS], - }); - } }); } else { return this.expected(['pseudo-class', 'pseudo-element'], this.currToken[TOKEN.START_POS]); @@ -813,13 +820,6 @@ export default class Parser { this.position ++; let current = this.content(); word += current; - if (current.lastIndexOf('\\') === current.length - 1) { - let next = this.nextToken; - if (next && next[TOKEN.TYPE] === tokens.space) { - word += this.requiredSpace(this.content(next)); - this.position ++; - } - } nextToken = this.nextToken; } const hasClass = indexesOf(word, '.').filter(i => word[i - 1] !== '\\'); @@ -905,7 +905,7 @@ export default class Parser { break; case tokens.closeParenthesis: if (throwOnParenthesis) { - this.missingParenthesis(); + this.missingOpeningParenthesis(); } break; case tokens.openSquare: @@ -938,7 +938,7 @@ export default class Parser { break; // These cases throw; no break needed. case tokens.closeSquare: - this.missingSquareBracket(); + this.missingOpeningSquareBracket(); case tokens.semicolon: this.missingBackslash(); default: