Skip to content

Commit

Permalink
Merge pull request #566 from glimmerjs/migrate-compiler-errors
Browse files Browse the repository at this point in the history
Migrate compile and syntax errors
  • Loading branch information
chadhietala authored Jul 8, 2017
2 parents 0466a5d + 65b584a commit bd4d35e
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 177 deletions.
45 changes: 0 additions & 45 deletions packages/@glimmer/runtime/test/compile-errors-test.ts

This file was deleted.

132 changes: 0 additions & 132 deletions packages/@glimmer/runtime/test/initial-render-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1146,137 +1146,5 @@ function applyMixins(derivedCtor: any, baseCtors: any[]) {

applyMixins(Rehydration, [RehydrationTests]);

class CompileErrorTests extends RenderTests {
@test "A helpful error message is provided for unclosed elements"() {
this.assert.throws(() => {
this.compile('\n<div class="my-div" \n foo={{bar}}>\n<span>\n</span>\n');
}, /Unclosed element `div` \(on line 2\)\./);

this.assert.throws(() => {
this.compile('\n<div class="my-div">\n<span>\n');
}, /Unclosed element `span` \(on line 3\)\./);
}

@test "A helpful error message is provided for unmatched end tags"() {
this.assert.throws(() => {
this.compile("</p>");
}, /Closing tag `p` \(on line 1\) without an open tag\./);

this.assert.throws(() => {
this.compile("<em>{{ foo }}</em> \n {{ bar }}\n</div>");
}, /Closing tag `div` \(on line 3\) without an open tag\./);
}

@test "A helpful error message is provided for end tags for void elements"() {
this.assert.throws(() => {
this.compile("<input></input>");
}, /Invalid end tag `input` \(on line 1\) \(void elements cannot have end tags\)./);

this.assert.throws(() => {
this.compile("<div>\n <input></input>\n</div>");
}, /Invalid end tag `input` \(on line 2\) \(void elements cannot have end tags\)./);

this.assert.throws(() => {
this.compile("\n\n</br>");
}, /Invalid end tag `br` \(on line 3\) \(void elements cannot have end tags\)./);
}

@test "A helpful error message is provided for end tags with attributes"() {
this.assert.throws(() => {
this.compile('<div>\nSomething\n\n</div foo="bar">');
}, /Invalid end tag: closing tag must not have attributes, in `div` \(on line 4\)\./);
}

@test "A helpful error message is provided for mismatched start/end tags"() {
this.assert.throws(() => {
this.compile("<div>\n<p>\nSomething\n\n</div>");
}, /Closing tag `div` \(on line 5\) did not match last open tag `p` \(on line 2\)\./);
}

@test "error line numbers include comment lines"() {
this.assert.throws(() => {
this.compile("<div>\n<p>\n{{! some comment}}\n\n</div>");
}, /Closing tag `div` \(on line 5\) did not match last open tag `p` \(on line 2\)\./);
}

@test "error line numbers include mustache only lines"() {
this.assert.throws(() => {
this.compile("<div>\n<p>\n{{someProp}}\n\n</div>");
}, /Closing tag `div` \(on line 5\) did not match last open tag `p` \(on line 2\)\./);
}

@test "error line numbers include block lines"() {
this.assert.throws(() => {
this.compile("<div>\n<p>\n{{#some-comment}}\n{{/some-comment}}\n</div>");
}, /Closing tag `div` \(on line 5\) did not match last open tag `p` \(on line 2\)\./);
}

@test "error line numbers include whitespace control mustaches"() {
this.assert.throws(() => {
this.compile("<div>\n<p>\n{{someProp~}}\n\n</div>{{some-comment}}");
}, /Closing tag `div` \(on line 5\) did not match last open tag `p` \(on line 2\)\./);
}

@test "error line numbers include multiple mustache lines"() {
this.assert.throws(() => {
this.compile("<div>\n<p>\n{{some-comment}}</div>{{some-comment}}");
}, /Closing tag `div` \(on line 3\) did not match last open tag `p` \(on line 2\)\./);
}

@test "Block params in HTML syntax - Throws exception if given zero parameters"() {
this.assert.throws(() => {
this.compile('<x-bar as ||>foo</x-bar>');
}, /Cannot use zero block parameters: 'as \|\|'/);

this.assert.throws(() => {
this.compile('<x-bar as | |>foo</x-bar>');
}, /Cannot use zero block parameters: 'as \| \|'/);
}

@test "Block params in HTML syntax - Throws an error on invalid block params syntax"() {
this.assert.throws(() => {
this.compile('<x-bar as |x y>{{x}},{{y}}</x-bar>');
}, /Invalid block parameters syntax: 'as |x y'/);

this.assert.throws(() => {
this.compile('<x-bar as |x| y>{{x}},{{y}}</x-bar>');
}, /Invalid block parameters syntax: 'as \|x\| y'/);

this.assert.throws(() => {
this.compile('<x-bar as |x| y|>{{x}},{{y}}</x-bar>');
}, /Invalid block parameters syntax: 'as \|x\| y\|'/);
}

@test "Block params in HTML syntax - Throws an error on invalid identifiers for params"() {
this.assert.throws(() => {
this.compile('<x-bar as |x foo.bar|></x-bar>');
}, /Invalid identifier for block parameters: 'foo\.bar' in 'as \|x foo\.bar|'/);

this.assert.throws(() => {
this.compile('<x-bar as |x "foo"|></x-bar>');
}, /Syntax error at line 1 col 17: " is not a valid character within attribute names/);

this.assert.throws(() => {
this.compile('<x-bar as |foo[bar]|></x-bar>');
}, /Invalid identifier for block parameters: 'foo\[bar\]' in 'as \|foo\[bar\]\|'/);
}

@test "Unquoted attribute with expression throws an exception"() {
this.assert.throws(() => this.compile('<img class=foo{{bar}}>'), expectedError(1));
this.assert.throws(() => this.compile('<img class={{foo}}{{bar}}>'), expectedError(1));
this.assert.throws(() => this.compile('<img \nclass={{foo}}bar>'), expectedError(2));
this.assert.throws(() => this.compile('<div \nclass\n=\n{{foo}}&amp;bar ></div>'), expectedError(4));

function expectedError(line: number) {
return new Error(
`An unquoted attribute value must be a string or a mustache, ` +
`preceeded by whitespace or a '=' character, and ` +
`followed by whitespace, a '>' character, or '/>' (on line ${line})`
);
}
}
}

module("Rehydration Tests", Rehydration);
module("Rendering Error Cases", CompileErrorTests);
module("Initial Render Tests", RenderingTest);
96 changes: 96 additions & 0 deletions packages/@glimmer/runtime/test/invalid-html-errors-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { RenderTests, test, module } from "@glimmer/test-helpers";

class CompileErrorTests extends RenderTests {
@test "A helpful error message is provided for unclosed elements"() {
this.assert.throws(() => {
this.compile('\n<div class="my-div" \n foo={{bar}}>\n<span>\n</span>\n');
}, /Unclosed element `div` \(on line 2\)\./);

this.assert.throws(() => {
this.compile('\n<div class="my-div">\n<span>\n');
}, /Unclosed element `span` \(on line 3\)\./);
}

@test "A helpful error message is provided for unmatched end tags"() {
this.assert.throws(() => {
this.compile("</p>");
}, /Closing tag `p` \(on line 1\) without an open tag\./);

this.assert.throws(() => {
this.compile("<em>{{ foo }}</em> \n {{ bar }}\n</div>");
}, /Closing tag `div` \(on line 3\) without an open tag\./);
}

@test "A helpful error message is provided for end tags for void elements"() {
this.assert.throws(() => {
this.compile("<input></input>");
}, /Invalid end tag `input` \(on line 1\) \(void elements cannot have end tags\)./);

this.assert.throws(() => {
this.compile("<div>\n <input></input>\n</div>");
}, /Invalid end tag `input` \(on line 2\) \(void elements cannot have end tags\)./);

this.assert.throws(() => {
this.compile("\n\n</br>");
}, /Invalid end tag `br` \(on line 3\) \(void elements cannot have end tags\)./);
}

@test "A helpful error message is provided for end tags with attributes"() {
this.assert.throws(() => {
this.compile('<div>\nSomething\n\n</div foo="bar">');
}, /Invalid end tag: closing tag must not have attributes, in `div` \(on line 4\)\./);
}

@test "A helpful error message is provided for mismatched start/end tags"() {
this.assert.throws(() => {
this.compile("<div>\n<p>\nSomething\n\n</div>");
}, /Closing tag `div` \(on line 5\) did not match last open tag `p` \(on line 2\)\./);
}

@test "error line numbers include comment lines"() {
this.assert.throws(() => {
this.compile("<div>\n<p>\n{{! some comment}}\n\n</div>");
}, /Closing tag `div` \(on line 5\) did not match last open tag `p` \(on line 2\)\./);
}

@test "error line numbers include mustache only lines"() {
this.assert.throws(() => {
this.compile("<div>\n<p>\n{{someProp}}\n\n</div>");
}, /Closing tag `div` \(on line 5\) did not match last open tag `p` \(on line 2\)\./);
}

@test "error line numbers include block lines"() {
this.assert.throws(() => {
this.compile("<div>\n<p>\n{{#some-comment}}\n{{/some-comment}}\n</div>");
}, /Closing tag `div` \(on line 5\) did not match last open tag `p` \(on line 2\)\./);
}

@test "error line numbers include whitespace control mustaches"() {
this.assert.throws(() => {
this.compile("<div>\n<p>\n{{someProp~}}\n\n</div>{{some-comment}}");
}, /Closing tag `div` \(on line 5\) did not match last open tag `p` \(on line 2\)\./);
}

@test "error line numbers include multiple mustache lines"() {
this.assert.throws(() => {
this.compile("<div>\n<p>\n{{some-comment}}</div>{{some-comment}}");
}, /Closing tag `div` \(on line 3\) did not match last open tag `p` \(on line 2\)\./);
}

@test "Unquoted attribute with expression throws an exception"() {
this.assert.throws(() => this.compile('<img class=foo{{bar}}>'), expectedError(1));
this.assert.throws(() => this.compile('<img class={{foo}}{{bar}}>'), expectedError(1));
this.assert.throws(() => this.compile('<img \nclass={{foo}}bar>'), expectedError(2));
this.assert.throws(() => this.compile('<div \nclass\n=\n{{foo}}&amp;bar ></div>'), expectedError(4));

function expectedError(line: number) {
return new Error(
`An unquoted attribute value must be a string or a mustache, ` +
`preceeded by whitespace or a '=' character, and ` +
`followed by whitespace, a '>' character, or '/>' (on line ${line})`
);
}
}
}

module("Rendering Error Cases", CompileErrorTests);
79 changes: 79 additions & 0 deletions packages/@glimmer/runtime/test/syntax-errors-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { RenderTests, module, test } from "@glimmer/test-helpers";

class SyntaxErrors extends RenderTests {
@test "context switching using ../ is not allowed"() {
this.assert.throws(() => {
this.compile('<div><p>{{../value}}</p></div>');
}, new Error("Changing context using \"../\" is not supported in Glimmer: \"../value\" on line 1."));
}

@test "mixing . and / is not allowed"() {
this.assert.throws(() => {
this.compile('<div><p>{{a/b.c}}</p></div>');
}, new Error("Mixing '.' and '/' in paths is not supported in Glimmer; use only '.' to separate property paths: \"a/b.c\" on line 1."));
}

@test "explicit self ref with ./ is not allowed"() {
this.assert.throws(() => {
this.compile('<div><p>{{./value}}</p></div>');
}, new Error("Using \"./\" is not supported in Glimmer and unnecessary: \"./value\" on line 1."));
}

@test "helper invocation with dot-paths are not allowed"() {
this.assert.throws(() => {
this.compile('{{foo.bar some="args"}}');
}, new Error("`foo.bar` is not a valid name for a helper on line 1."));
}

@test "sub-expression helper invocation with dot-paths are not allowed"() {
this.assert.throws(() => {
this.compile('{{log (foo.bar some="args")}}');
}, new Error("`foo.bar` is not a valid name for a helper on line 1."));
}

@test "sub-expression modifier invocation with dot-paths are not allowed"() {
this.assert.throws(() => {
this.compile('<div {{foo.bar some="args"}} />');
}, new Error("`foo.bar` is not a valid name for a modifier on line 1."));
}

@test "Block params in HTML syntax - Throws exception if given zero parameters"() {
this.assert.throws(() => {
this.compile('<x-bar as ||>foo</x-bar>');
}, /Cannot use zero block parameters: 'as \|\|'/);

this.assert.throws(() => {
this.compile('<x-bar as | |>foo</x-bar>');
}, /Cannot use zero block parameters: 'as \| \|'/);
}

@test "Block params in HTML syntax - Throws an error on invalid block params syntax"() {
this.assert.throws(() => {
this.compile('<x-bar as |x y>{{x}},{{y}}</x-bar>');
}, /Invalid block parameters syntax: 'as |x y'/);

this.assert.throws(() => {
this.compile('<x-bar as |x| y>{{x}},{{y}}</x-bar>');
}, /Invalid block parameters syntax: 'as \|x\| y'/);

this.assert.throws(() => {
this.compile('<x-bar as |x| y|>{{x}},{{y}}</x-bar>');
}, /Invalid block parameters syntax: 'as \|x\| y\|'/);
}

@test "Block params in HTML syntax - Throws an error on invalid identifiers for params"() {
this.assert.throws(() => {
this.compile('<x-bar as |x foo.bar|></x-bar>');
}, /Invalid identifier for block parameters: 'foo\.bar' in 'as \|x foo\.bar|'/);

this.assert.throws(() => {
this.compile('<x-bar as |x "foo"|></x-bar>');
}, /Syntax error at line 1 col 17: " is not a valid character within attribute names/);

this.assert.throws(() => {
this.compile('<x-bar as |foo[bar]|></x-bar>');
}, /Invalid identifier for block parameters: 'foo\[bar\]' in 'as \|foo\[bar\]\|'/);
}
}

module('Syntax Errors', SyntaxErrors);

0 comments on commit bd4d35e

Please sign in to comment.