From a5da5bc6080ffbd64ccd9e6a16ba1a233edefee9 Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 7 Jun 2019 12:23:09 +0200 Subject: [PATCH] Fix not honoring indent after inline text Lexer was silently ignoring indent after a tag with inline text Now : ``` li foo span bar ``` throw an error and give you the solution --- lib/index.js | 2 +- lib/parser.js | 37 ++++++++++++++++++++++-- test/fixtures/inline-text-nested-tag.sgr | 2 ++ test/index.js | 6 ++++ 4 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 test/fixtures/inline-text-nested-tag.sgr diff --git a/lib/index.js b/lib/index.js index 6d6bd08..f2bb33e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2,7 +2,7 @@ const lex = require('./lexer') const parse = require('./parser') module.exports = function SugarMLParser(input, options) { - return parse(lex(input, options)) + return parse(lex(input, options),input,options) } module.exports.lex = lex diff --git a/lib/parser.js b/lib/parser.js index 9596b91..1589c6e 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -2,11 +2,11 @@ const SugarmlError = require('./error') // Our target output is a reshape AST // (https://github.com/reshape/reshape#reshape-ast) -module.exports = tokens => { +module.exports = (tokens,input,options={}) => { let current = 0 let indentLevel = 0 let token = tokens[current] - + function walk(ctx) { token = tokens[current] @@ -151,9 +151,42 @@ module.exports = tokens => { // searching for contents const currentIndent = indentLevel + var forbiddenChildren=false + var inlineText='' + //If next token is 'text', we must not have child tokens + if (token && token.type==='text'){ + inlineText = token.value; //Remember inline text value for futur use (in case of error) + node.content.push(walk(node.content)) //Get text + forbiddenChildren=true + } + // now we recurse to get the contents, looping while the indent level is // greater than that of the current node, to pick up everything nested node.content.push(walk(node.content)) + if (forbiddenChildren && indentLevel > currentIndent){ + let errorLine + if (token){ + errorLine = tokens[current-2].line; //With other token to parse, error line is 2 tokens before + }else{ + errorLine = tokens[current-1].line; //Without anymore tokens to parse, error is on the last line + } + //Compute the awaited input + let splited = input.split('\n') //Split input line by line + let regex = inlineText.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '$'; //Make regex from inlineText + let firstLine = splited[errorLine - 2].replace(new RegExp(regex),'') //Remove inlineText from first Error line + let thirdLine = splited[errorLine - 1] //Second line become third + let secondLine = thirdLine.match(/^\s+/)[0] + '| ' + inlineText //Second line is *pipe* + inlineText we removed on first error line + let shouldBe = ` 1 | ${firstLine}\n 2 | ${secondLine}\n 3 | ${thirdLine}\n` //Pretty output + throw new SugarmlError({ + message: `Inline text and nested tags cannot both be used at the same time. To resolve this error format your template as :\n\n${shouldBe}`, + location: { + filename: options.filename, + line: errorLine, + col: 0, + src: input + } + }) + } while (indentLevel > currentIndent) { // eslint-disable-line node.content.push(walk(node.content)) diff --git a/test/fixtures/inline-text-nested-tag.sgr b/test/fixtures/inline-text-nested-tag.sgr new file mode 100644 index 0000000..a13c27d --- /dev/null +++ b/test/fixtures/inline-text-nested-tag.sgr @@ -0,0 +1,2 @@ +li foo + span bar diff --git a/test/index.js b/test/index.js index 82c416e..586b40d 100644 --- a/test/index.js +++ b/test/index.js @@ -103,6 +103,12 @@ test('sugarml own comments', t => { return compare(t, 'sugarml-comments') }) +test('invalid nested tag after inline text error', t => { + return error('inline-text-nested-tag', t).catch(err => { + t.regex(err.toString(), /Inline text and nested tags cannot both be used at the same time. To resolve this error format your template as :\n\n 1 | li \n 2 | | foo\n 3 | span bar/) + }) +}) + function compare(t, name, log) { let html, expected