From f1b9619932149517e13df479f2981a36d63c2053 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 27 Oct 2019 20:35:59 -0400 Subject: [PATCH] Ensure codemod mode ignores whitespace control. `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. --- packages/@glimmer/syntax/handlebars-shim.js | 3 +-- .../lib/parser/tokenizer-event-handlers.ts | 20 +++++++++++------ .../syntax/test/generation/print-test.ts | 22 +++++++------------ 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/packages/@glimmer/syntax/handlebars-shim.js b/packages/@glimmer/syntax/handlebars-shim.js index 15763a07d5..7de100ed74 100644 --- a/packages/@glimmer/syntax/handlebars-shim.js +++ b/packages/@glimmer/syntax/handlebars-shim.js @@ -1,2 +1 @@ -import { parse } from './handlebars/compiler/base'; -export { parse }; +export { parse, parser as Parser } from './handlebars/compiler/base'; diff --git a/packages/@glimmer/syntax/lib/parser/tokenizer-event-handlers.ts b/packages/@glimmer/syntax/lib/parser/tokenizer-event-handlers.ts index a348a64dde..b3a16a0685 100644 --- a/packages/@glimmer/syntax/lib/parser/tokenizer-event-handlers.ts +++ b/packages/@glimmer/syntax/lib/parser/tokenizer-event-handlers.ts @@ -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; diff --git a/packages/@glimmer/syntax/test/generation/print-test.ts b/packages/@glimmer/syntax/test/generation/print-test.ts index 891a399066..0a0ed7dc24 100644 --- a/packages/@glimmer/syntax/test/generation/print-test.ts +++ b/packages/@glimmer/syntax/test/generation/print-test.ts @@ -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
  • foo
  • \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() {