Skip to content

Commit

Permalink
Ensure codemod mode ignores whitespace control.
Browse files Browse the repository at this point in the history
`handlebars.parse` automatically applies whitespace control to the AST
before it is returned. For example, parsing the following template
([feel free to review the AST on
ASTExplorer](https://astexplorer.net/#/gist/f850c5457b808756107c0bc5ad226989/b0366df64be5c01b5f9eadd93e795b3b9d65d2c7)):

```hbs
 {{#foo}}
   {{~bar~}} {{baz~}}
 {{/foo}}
```

Using `Handlebars.parse`, the AST returned would have truncated the following whitespace:

* The whitespace prior to the `{{#foo}}`
* The newline following `{{#foo}}`
* The leading whitespace before `{{~bar~}}`
* The whitespace between `{{~bar~}}` and `{{baz~}}`
* The newline after `{{baz~}}`
* The whitespace prior to the `{{/foo}}`

A future version of `handlebars` (likely 4.5.0) will have a new method named
`parseWithoutProcessing`. When we update to that version we can remove
the custom workaround here.
  • Loading branch information
rwjblue committed Oct 28, 2019
1 parent c996080 commit f1b9619
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 23 deletions.
3 changes: 1 addition & 2 deletions packages/@glimmer/syntax/handlebars-shim.js
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
import { parse } from './handlebars/compiler/base';
export { parse };
export { parse, parser as Parser } from './handlebars/compiler/base';
20 changes: 13 additions & 7 deletions packages/@glimmer/syntax/lib/parser/tokenizer-event-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -379,20 +379,26 @@ const syntax: Syntax = {
Walker,
};

// emulate parseWithoutProcessing (from https://github.com/wycats/handlebars.js/pull/1584)
// can be removed when we update to Handlebars 4.5.0
function codemodParse(html: string, parseOptions?: HandlebarsParseOptions) {
// this sets up parser.yy and parser.yy.locInfo
handlebars.parse(html, parseOptions);

// casting to any here, because Parser is not listed in the types
return (handlebars as any).Parser.parse(html);
}

export function preprocess(html: string, options: PreprocessOptions = {}): AST.Template {
let mode = options.mode || 'precompile';

let ast: HBS.Program;
if (typeof html === 'object') {
ast = html;
} else if (mode === 'codemod') {
ast = codemodParse(html, options.parseOptions);
} else {
let parseOptions = options.parseOptions || {};

if (mode === 'codemod') {
parseOptions.ignoreStandalone = true;
}

ast = handlebars.parse(html, parseOptions) as HBS.Program;
ast = handlebars.parse(html, options.parseOptions) as HBS.Program;
}

let entityParser = undefined;
Expand Down
22 changes: 8 additions & 14 deletions packages/@glimmer/syntax/test/generation/print-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,25 +97,19 @@ QUnit.module('[glimmer-syntax] Code generation - source -> source', function() {
templates.forEach(buildTest);

[
// custom HTML Entities
'< &   > ©2018',

// whitespace control
'\n{{~var~}} ',
'\n{{~#foo-bar~}} {{~else if x~}} {{~else~}} {{~/foo-bar~}} ',

// newlines after opening block
'{{#each}}\n <li> foo </li>\n{{/each}}',
].forEach(buildTest);

test('whitespace control is preserved', function(assert) {
let before = '\n{{~var~}} ';
let after = '{{~var~}}';

assert.equal(printTransform(before), after);
});

test('block whitespace control is preserved', function(assert) {
let before = '\n{{~#foo-bar~}} {{~else if x~}} {{~else~}} {{~/foo-bar~}} ';
let after = '{{~#foo-bar~}}{{~else if x~}}{{~else~}}{{~/foo-bar~}}';

assert.equal(printTransform(before), after);
});
// "stand alone"
' {{#foo}}\n {{bar}}\n {{/foo}}',
].forEach(buildTest);
});

QUnit.module('[glimmer-syntax] Code generation - override', function() {
Expand Down

0 comments on commit f1b9619

Please sign in to comment.