e3d3eda2e1
Converts the tool chain to use babel, eslint, and webpack vs. the previous proprietary solutions. Additionally begins enforcing additional linting concerns as well as updates the code to reflect these rules. Fixes #855 Fixes #993
235 lines
9.7 KiB
JavaScript
235 lines
9.7 KiB
JavaScript
describe('parser', function() {
|
|
if (!Handlebars.print) {
|
|
return;
|
|
}
|
|
|
|
function astFor(template) {
|
|
var ast = Handlebars.parse(template);
|
|
return Handlebars.print(ast);
|
|
}
|
|
|
|
it('parses simple mustaches', function() {
|
|
equals(astFor('{{123}}'), '{{ NUMBER{123} [] }}\n');
|
|
equals(astFor('{{"foo"}}'), '{{ "foo" [] }}\n');
|
|
equals(astFor('{{false}}'), '{{ BOOLEAN{false} [] }}\n');
|
|
equals(astFor('{{true}}'), '{{ BOOLEAN{true} [] }}\n');
|
|
equals(astFor('{{foo}}'), '{{ PATH:foo [] }}\n');
|
|
equals(astFor('{{foo?}}'), '{{ PATH:foo? [] }}\n');
|
|
equals(astFor('{{foo_}}'), '{{ PATH:foo_ [] }}\n');
|
|
equals(astFor('{{foo-}}'), '{{ PATH:foo- [] }}\n');
|
|
equals(astFor('{{foo:}}'), '{{ PATH:foo: [] }}\n');
|
|
});
|
|
|
|
it('parses simple mustaches with data', function() {
|
|
equals(astFor('{{@foo}}'), '{{ @PATH:foo [] }}\n');
|
|
});
|
|
|
|
it('parses simple mustaches with data paths', function() {
|
|
equals(astFor('{{@../foo}}'), '{{ @PATH:foo [] }}\n');
|
|
});
|
|
|
|
it('parses mustaches with paths', function() {
|
|
equals(astFor('{{foo/bar}}'), '{{ PATH:foo/bar [] }}\n');
|
|
});
|
|
|
|
it('parses mustaches with this/foo', function() {
|
|
equals(astFor('{{this/foo}}'), '{{ PATH:foo [] }}\n');
|
|
});
|
|
|
|
it('parses mustaches with - in a path', function() {
|
|
equals(astFor('{{foo-bar}}'), '{{ PATH:foo-bar [] }}\n');
|
|
});
|
|
|
|
it('parses mustaches with parameters', function() {
|
|
equals(astFor('{{foo bar}}'), '{{ PATH:foo [PATH:bar] }}\n');
|
|
});
|
|
|
|
it('parses mustaches with string parameters', function() {
|
|
equals(astFor('{{foo bar \"baz\" }}'), '{{ PATH:foo [PATH:bar, "baz"] }}\n');
|
|
});
|
|
|
|
it('parses mustaches with NUMBER parameters', function() {
|
|
equals(astFor('{{foo 1}}'), '{{ PATH:foo [NUMBER{1}] }}\n');
|
|
});
|
|
|
|
it('parses mustaches with BOOLEAN parameters', function() {
|
|
equals(astFor('{{foo true}}'), '{{ PATH:foo [BOOLEAN{true}] }}\n');
|
|
equals(astFor('{{foo false}}'), '{{ PATH:foo [BOOLEAN{false}] }}\n');
|
|
});
|
|
|
|
it('parses mustaches with undefined and null paths', function() {
|
|
equals(astFor('{{undefined}}'), '{{ UNDEFINED [] }}\n');
|
|
equals(astFor('{{null}}'), '{{ NULL [] }}\n');
|
|
});
|
|
it('parses mustaches with undefined and null parameters', function() {
|
|
equals(astFor('{{foo undefined null}}'), '{{ PATH:foo [UNDEFINED, NULL] }}\n');
|
|
});
|
|
|
|
it('parses mutaches with DATA parameters', function() {
|
|
equals(astFor('{{foo @bar}}'), '{{ PATH:foo [@PATH:bar] }}\n');
|
|
});
|
|
|
|
it('parses mustaches with hash arguments', function() {
|
|
equals(astFor('{{foo bar=baz}}'), '{{ PATH:foo [] HASH{bar=PATH:baz} }}\n');
|
|
equals(astFor('{{foo bar=1}}'), '{{ PATH:foo [] HASH{bar=NUMBER{1}} }}\n');
|
|
equals(astFor('{{foo bar=true}}'), '{{ PATH:foo [] HASH{bar=BOOLEAN{true}} }}\n');
|
|
equals(astFor('{{foo bar=false}}'), '{{ PATH:foo [] HASH{bar=BOOLEAN{false}} }}\n');
|
|
equals(astFor('{{foo bar=@baz}}'), '{{ PATH:foo [] HASH{bar=@PATH:baz} }}\n');
|
|
|
|
equals(astFor('{{foo bar=baz bat=bam}}'), '{{ PATH:foo [] HASH{bar=PATH:baz, bat=PATH:bam} }}\n');
|
|
equals(astFor('{{foo bar=baz bat="bam"}}'), '{{ PATH:foo [] HASH{bar=PATH:baz, bat="bam"} }}\n');
|
|
|
|
equals(astFor("{{foo bat='bam'}}"), '{{ PATH:foo [] HASH{bat="bam"} }}\n');
|
|
|
|
equals(astFor('{{foo omg bar=baz bat=\"bam\"}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam"} }}\n');
|
|
equals(astFor('{{foo omg bar=baz bat=\"bam\" baz=1}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=NUMBER{1}} }}\n');
|
|
equals(astFor('{{foo omg bar=baz bat=\"bam\" baz=true}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{true}} }}\n');
|
|
equals(astFor('{{foo omg bar=baz bat=\"bam\" baz=false}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{false}} }}\n');
|
|
});
|
|
|
|
it('parses contents followed by a mustache', function() {
|
|
equals(astFor('foo bar {{baz}}'), 'CONTENT[ \'foo bar \' ]\n{{ PATH:baz [] }}\n');
|
|
});
|
|
|
|
it('parses a partial', function() {
|
|
equals(astFor('{{> foo }}'), '{{> PARTIAL:foo }}\n');
|
|
equals(astFor('{{> "foo" }}'), '{{> PARTIAL:foo }}\n');
|
|
equals(astFor('{{> 1 }}'), '{{> PARTIAL:1 }}\n');
|
|
});
|
|
|
|
it('parses a partial with context', function() {
|
|
equals(astFor('{{> foo bar}}'), '{{> PARTIAL:foo PATH:bar }}\n');
|
|
});
|
|
|
|
it('parses a partial with hash', function() {
|
|
equals(astFor('{{> foo bar=bat}}'), '{{> PARTIAL:foo HASH{bar=PATH:bat} }}\n');
|
|
});
|
|
|
|
it('parses a partial with context and hash', function() {
|
|
equals(astFor('{{> foo bar bat=baz}}'), '{{> PARTIAL:foo PATH:bar HASH{bat=PATH:baz} }}\n');
|
|
});
|
|
|
|
it('parses a partial with a complex name', function() {
|
|
equals(astFor('{{> shared/partial?.bar}}'), '{{> PARTIAL:shared/partial?.bar }}\n');
|
|
});
|
|
|
|
it('parses a comment', function() {
|
|
equals(astFor('{{! this is a comment }}'), "{{! ' this is a comment ' }}\n");
|
|
});
|
|
|
|
it('parses a multi-line comment', function() {
|
|
equals(astFor('{{!\nthis is a multi-line comment\n}}'), "{{! \'\nthis is a multi-line comment\n\' }}\n");
|
|
});
|
|
|
|
it('parses an inverse section', function() {
|
|
equals(astFor('{{#foo}} bar {{^}} baz {{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n CONTENT[ ' baz ' ]\n");
|
|
});
|
|
|
|
it('parses an inverse (else-style) section', function() {
|
|
equals(astFor('{{#foo}} bar {{else}} baz {{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n CONTENT[ ' baz ' ]\n");
|
|
});
|
|
|
|
it('parses multiple inverse sections', function() {
|
|
equals(astFor('{{#foo}} bar {{else if bar}}{{else}} baz {{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n BLOCK:\n PATH:if [PATH:bar]\n PROGRAM:\n {{^}}\n CONTENT[ ' baz ' ]\n");
|
|
});
|
|
|
|
it('parses empty blocks', function() {
|
|
equals(astFor('{{#foo}}{{/foo}}'), 'BLOCK:\n PATH:foo []\n PROGRAM:\n');
|
|
});
|
|
|
|
it('parses empty blocks with empty inverse section', function() {
|
|
equals(astFor('{{#foo}}{{^}}{{/foo}}'), 'BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n');
|
|
});
|
|
|
|
it('parses empty blocks with empty inverse (else-style) section', function() {
|
|
equals(astFor('{{#foo}}{{else}}{{/foo}}'), 'BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n');
|
|
});
|
|
|
|
it('parses non-empty blocks with empty inverse section', function() {
|
|
equals(astFor('{{#foo}} bar {{^}}{{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n");
|
|
});
|
|
|
|
it('parses non-empty blocks with empty inverse (else-style) section', function() {
|
|
equals(astFor('{{#foo}} bar {{else}}{{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n");
|
|
});
|
|
|
|
it('parses empty blocks with non-empty inverse section', function() {
|
|
equals(astFor('{{#foo}}{{^}} bar {{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n CONTENT[ ' bar ' ]\n");
|
|
});
|
|
|
|
it('parses empty blocks with non-empty inverse (else-style) section', function() {
|
|
equals(astFor('{{#foo}}{{else}} bar {{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n CONTENT[ ' bar ' ]\n");
|
|
});
|
|
|
|
it('parses a standalone inverse section', function() {
|
|
equals(astFor('{{^foo}}bar{{/foo}}'), "BLOCK:\n PATH:foo []\n {{^}}\n CONTENT[ 'bar' ]\n");
|
|
});
|
|
it('throws on old inverse section', function() {
|
|
shouldThrow(function() {
|
|
astFor('{{else foo}}bar{{/foo}}');
|
|
}, Error);
|
|
});
|
|
|
|
it('parses block with block params', function() {
|
|
equals(astFor('{{#foo as |bar baz|}}content{{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n");
|
|
});
|
|
|
|
it('parses inverse block with block params', function() {
|
|
equals(astFor('{{^foo as |bar baz|}}content{{/foo}}'), "BLOCK:\n PATH:foo []\n {{^}}\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n");
|
|
});
|
|
it('parses chained inverse block with block params', function() {
|
|
equals(astFor('{{#foo}}{{else foo as |bar baz|}}content{{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n BLOCK:\n PATH:foo []\n PROGRAM:\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n");
|
|
});
|
|
it('raises if there\'s a Parse error', function() {
|
|
shouldThrow(function() {
|
|
astFor('foo{{^}}bar');
|
|
}, Error, /Parse error on line 1/);
|
|
shouldThrow(function() {
|
|
astFor('{{foo}');
|
|
}, Error, /Parse error on line 1/);
|
|
shouldThrow(function() {
|
|
astFor('{{foo &}}');
|
|
}, Error, /Parse error on line 1/);
|
|
shouldThrow(function() {
|
|
astFor('{{#goodbyes}}{{/hellos}}');
|
|
}, Error, /goodbyes doesn't match hellos/);
|
|
|
|
shouldThrow(function() {
|
|
astFor('{{{{goodbyes}}}} {{{{/hellos}}}}');
|
|
}, Error, /goodbyes doesn't match hellos/);
|
|
});
|
|
|
|
it('should handle invalid paths', function() {
|
|
shouldThrow(function() {
|
|
astFor('{{foo/../bar}}');
|
|
}, Error, /Invalid path: foo\/\.\. - 1:2/);
|
|
shouldThrow(function() {
|
|
astFor('{{foo/./bar}}');
|
|
}, Error, /Invalid path: foo\/\. - 1:2/);
|
|
shouldThrow(function() {
|
|
astFor('{{foo/this/bar}}');
|
|
}, Error, /Invalid path: foo\/this - 1:2/);
|
|
});
|
|
|
|
it('knows how to report the correct line number in errors', function() {
|
|
shouldThrow(function() {
|
|
astFor('hello\nmy\n{{foo}');
|
|
}, Error, /Parse error on line 3/);
|
|
shouldThrow(function() {
|
|
astFor('hello\n\nmy\n\n{{foo}');
|
|
}, Error, /Parse error on line 5/);
|
|
});
|
|
|
|
it('knows how to report the correct line number in errors when the first character is a newline', function() {
|
|
shouldThrow(function() {
|
|
astFor('\n\nhello\n\nmy\n\n{{foo}');
|
|
}, Error, /Parse error on line 7/);
|
|
});
|
|
|
|
describe('externally compiled AST', function() {
|
|
it('can pass through an already-compiled AST', function() {
|
|
equals(astFor(new Handlebars.AST.Program([new Handlebars.AST.ContentStatement('Hello')], null)), 'CONTENT[ \'Hello\' ]\n');
|
|
});
|
|
});
|
|
});
|