diff --git a/src/language-handlebars/printer-glimmer.js b/src/language-handlebars/printer-glimmer.js index 2ab7a415..9261d0a3 100644 --- a/src/language-handlebars/printer-glimmer.js +++ b/src/language-handlebars/printer-glimmer.js @@ -249,7 +249,7 @@ function print(path, options, print) { return concat([""]); } case "StringLiteral": { - return `"${n.value}"`; + return printStringLiteral(n.value, options); } case "NumberLiteral": { return String(n.value); @@ -267,6 +267,50 @@ function print(path, options, print) { } } +/** + * Prints a string literal with the correct surrounding quotes based on + * `options.singleQuote` and the number of escaped quotes contained in + * the string literal. This function is the glimmer equivalent of `printString` + * in `common/util`, but has differences because of the way escaped characters + * are treated in hbs string literals. + * @param {string} stringLiteral - the string literal value + * @param {object} options - the prettier options object + */ +function printStringLiteral(stringLiteral, options) { + const double = { quote: '"', regex: /"/g }; + const single = { quote: "'", regex: /'/g }; + + const preferred = options.singleQuote ? single : double; + const alternate = preferred === single ? double : single; + + let shouldUseAlternateQuote = false; + + // If `stringLiteral` contains at least one of the quote preferred for + // enclosing the string, we might want to enclose with the alternate quote + // instead, to minimize the number of escaped quotes. + if ( + stringLiteral.includes(preferred.quote) || + stringLiteral.includes(alternate.quote) + ) { + const numPreferredQuotes = (stringLiteral.match(preferred.regex) || []) + .length; + const numAlternateQuotes = (stringLiteral.match(alternate.regex) || []) + .length; + + shouldUseAlternateQuote = numPreferredQuotes > numAlternateQuotes; + } + + const enclosingQuote = shouldUseAlternateQuote ? alternate : preferred; + const escapedStringLiteral = stringLiteral.replace( + enclosingQuote.regex, + `\\${enclosingQuote.quote}` + ); + + return `${enclosingQuote.quote}${escapedStringLiteral}${ + enclosingQuote.quote + }`; +} + function printPath(path, print) { return path.call(print, "path"); } diff --git a/tests/glimmer/__snapshots__/jsfmt.spec.js.snap b/tests/glimmer/__snapshots__/jsfmt.spec.js.snap index d44d733f..32d26673 100644 --- a/tests/glimmer/__snapshots__/jsfmt.spec.js.snap +++ b/tests/glimmer/__snapshots__/jsfmt.spec.js.snap @@ -134,6 +134,140 @@ exports[`block-statement.hbs - glimmer-verify 1`] = ` `; +exports[`block-statement.hbs - glimmer-verify 2`] = ` +{{#block param hashKey=hashValue as |blockParam|}} + Hello +{{/block}} + +{{#block almost80CharacterLongPositionalParamThatIsFirstAlmost80Chars helloWorldParam key=here}} +{{/block}} + +{{#block param param param param param param param hashKey=hashValue as |blockParam|}} + Hello +{{/block}} + +{{#block param param param param param param param hashKey=HashValue hashKey=hashValue}} + Hello +{{/block}} + +{{#block param param param param param param param param param param param param param}} + Hello +{{/block}} + +{{#block hashKey=HashValue hashKey=hashValue hashKey=HashValue hashKey=hashValue hashKey=HashValue}} + Hello +{{/block}} + +{{#block}} + {{#block}} + hello + {{/block}} +{{/block}} + +{{#block}} + {{#block param}} + hello + {{/block}} +{{/block}} + +{{#block param}} + {{#block param}} + hello + {{/block}} +{{/block}} + +{{#block}} + hello +{{/block}} + + + {{firstName}} + + + + {{firstName}} {{lastName}} + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +{{#block param hashKey=hashValue as |blockParam|}} + Hello +{{/block}} +{{#block + almost80CharacterLongPositionalParamThatIsFirstAlmost80Chars + helloWorldParam + key=here +}}{{/block}} +{{#block + param + param + param + param + param + param + param + hashKey=hashValue as |blockParam| +}} + Hello +{{/block}} +{{#block + param + param + param + param + param + param + param + hashKey=HashValue + hashKey=hashValue +}} + Hello +{{/block}} +{{#block + param + param + param + param + param + param + param + param + param + param + param + param + param +}} + Hello +{{/block}} +{{#block + hashKey=HashValue + hashKey=hashValue + hashKey=HashValue + hashKey=hashValue + hashKey=HashValue +}} + Hello +{{/block}} +{{#block}}{{#block}}hello{{/block}}{{/block}} +{{#block}} + {{#block param}} + hello + {{/block}} +{{/block}} +{{#block param}} + {{#block param}} + hello + {{/block}} +{{/block}} +{{#block}}hello{{/block}} + + {{firstName}} + + + {{firstName}} + {{lastName}} + +`; + exports[`component.hbs - glimmer-verify 1`] = ` {{@greeting}}, {{@name}}! @@ -178,6 +312,50 @@ exports[`component.hbs - glimmer-verify 1`] = ` `; +exports[`component.hbs - glimmer-verify 2`] = ` + +{{@greeting}}, {{@name}}! + +
+ + hello + + + + + + + + + + + + +
Hello
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +{{@greeting}} +, +{{@name}} +! +
+ + + hello + + + + + + + +
+ Hello +
+`; + exports[`concat-statement.hbs - glimmer-verify 1`] = `
Hello @@ -229,6 +407,57 @@ exports[`concat-statement.hbs - glimmer-verify 1`] = `
`; +exports[`concat-statement.hbs - glimmer-verify 2`] = ` +
+ Hello +
+ +
+ Hello +
+ + + +
+
+
+
+
+
+
+
+
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +
+ Hello +
+
+ Hello +
+ +
+
+
+
+
+
+
+
+
+
+`; + exports[`element-modifier-statement.hbs - glimmer-verify 1`] = `
Hello @@ -295,6 +524,72 @@ exports[`element-modifier-statement.hbs - glimmer-verify 1`] = `
`; +exports[`element-modifier-statement.hbs - glimmer-verify 2`] = ` +
+ Hello +
+ +
+ Hello +
+ +
+ Hello +
+ +
+ Hello +
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +
+ Hello +
+
+ Hello +
+
+ Hello +
+
+ Hello +
+`; + exports[`element-node.hbs - glimmer-verify 1`] = `
Hello @@ -361,6 +656,72 @@ exports[`element-node.hbs - glimmer-verify 1`] = ` `; +exports[`element-node.hbs - glimmer-verify 2`] = ` +
+ Hello +
+ +
+ Hello +
+ +
+ hi +
+ +
+ A long enough string to trigger a line break that would prevent wrapping. +
+ +
+ A long enough string to trigger a line break that would prevent wrapping more. +
+ +
+ A long enough string to trigger a line break that would prevent wrapping more and more. +
+ +
+ {{#block}} + {{hello}} + {{/block}} +
+ +
+ {{hello}} +
+ +
+ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +
+ Hello +
+
+ Hello +
+
+ hi +
+
+ A long enough string to trigger a line break that would prevent wrapping. +
+
+ A long enough string to trigger a line break that would prevent wrapping more. +
+
+ A long enough string to trigger a line break that would prevent wrapping more and more. +
+
+ {{#block}}{{hello}}{{/block}} +
+
+ {{hello}} +
+
+ +`; + exports[`else-if.hbs - glimmer-verify 1`] = ` {{#if a}} b @@ -496,6 +857,141 @@ exports[`else-if.hbs - glimmer-verify 1`] = ` {{/if}} `; +exports[`else-if.hbs - glimmer-verify 2`] = ` +{{#if a}} + b +{{else if c}} + d +{{else}} + e +{{/if}} + +{{#if a}} + b +{{else if c}} + d +{{else}} + hello + {{#if f}} + g + {{/if}} + e +{{/if}} + +{{#if a}} + b +{{else if c}} + d +{{else if e}} + f +{{else if g}} + h +{{else}} + j +{{/if}} + +
+ {{#if a}} + b + {{else if c}} + d + {{else}} + e + {{/if}} +
+ +
+
+ {{#if a}} + b + {{else if c}} + d + {{else}} + e + {{/if}} +
+
+ +{{#if a}} + b +{{else}} + {{#each c as |d|}} + e + {{/each}} +{{/if}} + +{{#if a}} + {{#if b}} + ab + {{else if c}} + ac + {{/if}} +{{/if}}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +{{#if a}} + b +{{else if c}} + d +{{else}} + e +{{/if}} +{{#if a}} + b +{{else if c}} + d +{{else}} + hello + {{#if f}} + g + {{/if}} + e +{{/if}} +{{#if a}} + b +{{else if c}} + d +{{else if e}} + f +{{else if g}} + h +{{else}} + j +{{/if}} +
+ {{#if a}} + b + {{else if c}} + d + {{else}} + e + {{/if}} +
+
+
+ {{#if a}} + b + {{else if c}} + d + {{else}} + e + {{/if}} +
+
+{{#if a}} + b +{{else}} + {{#each c as |d|}} + e + {{/each}} +{{/if}} +{{#if a}} + {{#if b}} + ab + {{else if c}} + ac + {{/if}} +{{/if}} +`; + exports[`literals.hbs - glimmer-verify 1`] = ` {{mustache true}} {{mustache 5}} @@ -514,6 +1010,24 @@ exports[`literals.hbs - glimmer-verify 1`] = ` {{!-- Mustache Comment }} --}} `; +exports[`literals.hbs - glimmer-verify 2`] = ` +{{mustache true}} +{{mustache 5}} +{{mustache undefined}} +{{mustache null}} + +{{! Mustache Comment}} +{{!-- Mustache Comment }} --}} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +{{mustache true}} +{{mustache 5}} +{{mustache undefined}} +{{mustache null}} + +{{! Mustache Comment}} +{{!-- Mustache Comment }} --}} +`; + exports[`loop.hbs - glimmer-verify 1`] = `
    {{#each speakers key="@index" as |speaker|}} @@ -530,6 +1044,54 @@ exports[`loop.hbs - glimmer-verify 1`] = `
`; +exports[`loop.hbs - glimmer-verify 2`] = ` +
    + {{#each speakers key="@index" as |speaker|}} +
  • {{speaker}}
  • + {{/each}} +
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +
    + {{#each speakers key='@index' as |speaker|}} +
  • + {{speaker}} +
  • + {{/each}} +
+`; + +exports[`string-literals.hbs - glimmer-verify 1`] = ` +{{"abc"}} +{{'abc'}} +{{" \\" \\" ' more double quote than single quote "}} +{{' \\' \\' " more single quote than double quote '}} +{{' " \\' \\" \\\\ '}} +{{" \\" \\' ' \\\\ "}} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +{{"abc"}} +{{"abc"}} +{{' " " \\' more double quote than single quote '}} +{{" ' ' \\" more single quote than double quote "}} +{{' " \\' \\" \\\\ '}} +{{" \\" \\' ' \\\\ "}} +`; + +exports[`string-literals.hbs - glimmer-verify 2`] = ` +{{"abc"}} +{{'abc'}} +{{" \\" \\" ' more double quote than single quote "}} +{{' \\' \\' " more single quote than double quote '}} +{{' " \\' \\" \\\\ '}} +{{" \\" \\' ' \\\\ "}} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +{{'abc'}} +{{'abc'}} +{{' " " \\' more double quote than single quote '}} +{{" ' ' \\" more single quote than double quote "}} +{{' " \\' \\" \\\\ '}} +{{" \\" \\' ' \\\\ "}} +`; + exports[`sub-expressions.hbs - glimmer-verify 1`] = `
+ +{{#block + (concat + (service) + (helper param hashPair=Value) + (largeNameHelper param param param param hashPair=value hashPair=value hashPair=Value) + hashPair=(helper param param param param param param hashPair=value hashPair=value hashPair=value) + hashPair=(does not need a line break due to being under 80 chars long) + ) +}} + +{{/block}} + +{{foobar-sub-component/foobar-foo + hook="stringLiteral" + foo= + (t + (concat "stringLiteral" (get blockParam "stringLiteral") hash=hash hash=hash) + foo=(simple-helper (hash hashKey=blockParam.foo assignParam=blockParam.bar)) + ) +}} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +
+{{#block + (concat + (service) + (helper param hashPair=Value) + (largeNameHelper + param param param param hashPair=value hashPair=value hashPair=Value + ) + hashPair=(helper + param + param + param + param + param + param + hashPair=value + hashPair=value + hashPair=value + ) + hashPair=(does not need a line break due to being under 80 chars long) + ) +}}{{/block}} +{{foobar-sub-component/foobar-foo + hook='stringLiteral' + foo=(t + (concat + 'stringLiteral' (get blockParam 'stringLiteral') hash=hash hash=hash + ) + foo=(simple-helper (hash hashKey=blockParam.foo assignParam=blockParam.bar)) + ) +}} +`; diff --git a/tests/glimmer/jsfmt.spec.js b/tests/glimmer/jsfmt.spec.js index da9b8840..4abf117d 100644 --- a/tests/glimmer/jsfmt.spec.js +++ b/tests/glimmer/jsfmt.spec.js @@ -1 +1,2 @@ run_spec(__dirname, ["glimmer"]); +run_spec(__dirname, ["glimmer"], { singleQuote: true }); diff --git a/tests/glimmer/string-literals.hbs b/tests/glimmer/string-literals.hbs new file mode 100644 index 00000000..f06cedca --- /dev/null +++ b/tests/glimmer/string-literals.hbs @@ -0,0 +1,6 @@ +{{"abc"}} +{{'abc'}} +{{" \" \" ' more double quote than single quote "}} +{{' \' \' " more single quote than double quote '}} +{{' " \' \" \\ '}} +{{" \" \' ' \\ "}}