diff --git a/src/parse/state/mustache.ts b/src/parse/state/mustache.ts index d71642cd1f..3ca6003242 100644 --- a/src/parse/state/mustache.ts +++ b/src/parse/state/mustache.ts @@ -1,6 +1,7 @@ import readExpression from '../read/expression'; import { whitespace } from '../../utils/patterns'; import { trimStart, trimEnd } from '../../utils/trim'; +import reservedNames from '../../utils/reservedNames'; import { Parser } from '../index'; import { Node } from '../../interfaces'; @@ -168,8 +169,15 @@ export default function mustache(parser: Parser) { do { parser.allowWhitespace(); + + const start = parser.index; const destructuredContext = parser.read(validIdentifier); + if (!destructuredContext) parser.error(`Expected name`); + if (reservedNames.has(destructuredContext)) { + parser.error(`'${destructuredContext}' is a reserved word in JavaScript and cannot be used here`, start); + } + block.destructuredContexts.push(destructuredContext); parser.allowWhitespace(); } while (parser.eat(',')); @@ -180,7 +188,11 @@ export default function mustache(parser: Parser) { parser.allowWhitespace(); parser.eat(']', true); } else { - block.context = parser.read(validIdentifier); // TODO check it's not a keyword + const start = parser.index; + block.context = parser.read(validIdentifier); + if (reservedNames.has(block.context)) { + parser.error(`'${block.context}' is a reserved word in JavaScript and cannot be used here`, start); + } if (!block.context) parser.error(`Expected name`); } diff --git a/src/utils/reservedNames.ts b/src/utils/reservedNames.ts index 1e5b28740e..e0d1e860e3 100644 --- a/src/utils/reservedNames.ts +++ b/src/utils/reservedNames.ts @@ -49,7 +49,4 @@ const reservedNames = new Set([ 'yield', ]); -// prevent e.g. `{{#each states as state}}` breaking -reservedNames.add('state'); - export default reservedNames; diff --git a/test/validator/samples/each-block-invalid-context-destructured/errors.json b/test/validator/samples/each-block-invalid-context-destructured/errors.json new file mode 100644 index 0000000000..b14ef63251 --- /dev/null +++ b/test/validator/samples/each-block-invalid-context-destructured/errors.json @@ -0,0 +1,8 @@ +[{ + "message": "'case' is a reserved word in JavaScript and cannot be used here", + "loc": { + "line": 1, + "column": 18 + }, + "pos": 18 +}] \ No newline at end of file diff --git a/test/validator/samples/each-block-invalid-context-destructured/input.html b/test/validator/samples/each-block-invalid-context-destructured/input.html new file mode 100644 index 0000000000..ce31634a85 --- /dev/null +++ b/test/validator/samples/each-block-invalid-context-destructured/input.html @@ -0,0 +1,3 @@ +{{#each cases as [case]}} + {{case.title}} +{{/each}} \ No newline at end of file diff --git a/test/validator/samples/each-block-invalid-context/errors.json b/test/validator/samples/each-block-invalid-context/errors.json new file mode 100644 index 0000000000..eecb97266b --- /dev/null +++ b/test/validator/samples/each-block-invalid-context/errors.json @@ -0,0 +1,8 @@ +[{ + "message": "'case' is a reserved word in JavaScript and cannot be used here", + "loc": { + "line": 1, + "column": 17 + }, + "pos": 17 +}] \ No newline at end of file diff --git a/test/validator/samples/each-block-invalid-context/input.html b/test/validator/samples/each-block-invalid-context/input.html new file mode 100644 index 0000000000..212c29ecdc --- /dev/null +++ b/test/validator/samples/each-block-invalid-context/input.html @@ -0,0 +1,3 @@ +{{#each cases as case}} + {{case.title}} +{{/each}} \ No newline at end of file