diff --git a/transforms/angle-brackets/known-helpers.js b/transforms/angle-brackets/known-helpers.js index 87a7ee7b9..57d4e18e5 100755 --- a/transforms/angle-brackets/known-helpers.js +++ b/transforms/angle-brackets/known-helpers.js @@ -18,14 +18,12 @@ const KNOWN_HELPERS = [ 'loc', 'log', 'mut', - 'outlet', 'partial', 'query-params', 'readonly', 'unbound', 'unless', 'with', - 'yield', // Glimmer VM 'identity', // glimmer blocks diff --git a/transforms/angle-brackets/telemetry/mock-invokables.js b/transforms/angle-brackets/telemetry/mock-invokables.js index 9715c6ea1..a00d44221 100644 --- a/transforms/angle-brackets/telemetry/mock-invokables.js +++ b/transforms/angle-brackets/telemetry/mock-invokables.js @@ -101,4 +101,7 @@ module.exports = { 'app/helpers/nested/helper': { type: 'Helper', }, + 'app/helpers/fooknownhelper': { + type: 'Helper', + }, }; diff --git a/transforms/angle-brackets/transform.js b/transforms/angle-brackets/transform.js index c4f3e97a9..7d0fb0e43 100755 --- a/transforms/angle-brackets/transform.js +++ b/transforms/angle-brackets/transform.js @@ -326,7 +326,7 @@ function getNonDataAttributesFromParams(params) { return params.filter((it) => !isDataAttrPathExpression(it)); } -function shouldIgnoreMustacheStatement(fullName, config, invokableData) { +function isKnownHelper(fullName, config, invokableData) { let { helpers, components } = invokableData; let isTelemetryData = !!(helpers || components); @@ -337,11 +337,18 @@ function shouldIgnoreMustacheStatement(fullName, config, invokableData) { } if (isTelemetryData) { + let isComponent = + !config.helpers.includes(name) && + [...(components || []), ...BUILT_IN_COMPONENTS].includes(name); + + if (isComponent) { + return false; + } + let mergedHelpers = [...KNOWN_HELPERS, ...(helpers || [])]; let isHelper = mergedHelpers.includes(name) || config.helpers.includes(name); - let isComponent = [...(components || []), ...BUILT_IN_COMPONENTS].includes(name); let strName = `${name}`; // coerce boolean and number to string - return (isHelper || !isComponent) && !strName.includes('.'); + return isHelper && !strName.includes('.'); } else { return KNOWN_HELPERS.includes(name) || config.helpers.includes(name); } @@ -363,7 +370,7 @@ function nodeHasPositionalParameters(node) { return false; } -function transformNode(node, fileInfo, config) { +function transformComponentNode(node, fileInfo, config) { if ( hasValuelessDataParams(node.params) && shouldSkipDataTestParams(node.params, config.includeValuelessDataTestAttributes) @@ -425,6 +432,10 @@ function transformNode(node, fileInfo, config) { ); } +function transformHelperNode(node) { + return b.mustache(b.sexpr(node.path, node.params, node.hash)); +} + function subExpressionToMustacheStatement(subExpression) { return b.mustache(subExpression.path, subExpression.params, subExpression.hash); } @@ -457,22 +468,29 @@ function transformToAngleBracket(fileInfo, config, invokableData) { * Transform the attributes names & values properly */ return { - MustacheStatement(node) { + MustacheStatement(node, walkerPath) { const tagName = `${node.path && node.path.original}`; if (config.components && !config.components.includes(tagName)) return; + const isTagKnownHelper = isKnownHelper(tagName, config, invokableData); + // Don't change attribute statements - const isValidMustache = - node.loc.source !== '(synthetic)' && - !shouldIgnoreMustacheStatement(tagName, config, invokableData); + const isValidMustacheComponent = node.loc.source !== '(synthetic)' && !isTagKnownHelper; const isNestedComponent = isNestedComponentTagName(tagName); if ( - isValidMustache && + isValidMustacheComponent && (node.hash.pairs.length > 0 || node.params.length > 0 || isNestedComponent) ) { - return transformNode(node, fileInfo, config); + return transformComponentNode(node, fileInfo, config); + } else if ( + isTagKnownHelper && + node.path.type !== 'SubExpression' && + walkerPath.parent.node.type !== 'AttrNode' && + walkerPath.parent.node.type !== 'ConcatStatement' + ) { + return transformHelperNode(node, walkerPath); } }, BlockStatement(node) { @@ -480,11 +498,8 @@ function transformToAngleBracket(fileInfo, config, invokableData) { if (config.components && !config.components.includes(tagName)) return; - if ( - !shouldIgnoreMustacheStatement(node.path.original, config, invokableData) || - isWallStreet(tagName) - ) { - return transformNode(node, fileInfo, config); + if (!isKnownHelper(node.path.original, config, invokableData) || isWallStreet(tagName)) { + return transformComponentNode(node, fileInfo, config); } }, AttrNode: { diff --git a/transforms/angle-brackets/transform.test.js b/transforms/angle-brackets/transform.test.js index 86256cf4f..3bd2cc907 100644 --- a/transforms/angle-brackets/transform.test.js +++ b/transforms/angle-brackets/transform.test.js @@ -288,7 +288,6 @@ test('deeply-nested-sub', () => { ) }} `; - /** * NOTE: An issue has been opened in `ember-template-recast` (https://github.com/ember-template-lint/ember-template-recast/issues/82) * regarding to create an API to allow a transform to customize the whitespace for newly created nodes. @@ -477,7 +476,7 @@ test('let', () => { {{#let (capitalize this.person.firstName) (capitalize this.person.lastName) as |firstName lastName| }} - Welcome back {{concat firstName ' ' lastName}} + Welcome back {{(concat firstName ' ' lastName)}} Account Details: First Name: {{firstName}} @@ -555,8 +554,8 @@ test('link-to-inline', () => { Segments Segments {{segment.name}} - {{t \\"show\\"}} - {{t \\"show\\"}} + {{(t \\"show\\")}} + {{(t \\"show\\")}} Show Show Show @@ -840,7 +839,7 @@ test('t-helper', () => { expect(runTest('t-helper.hbs', input)).toMatchInlineSnapshot(` " - {{t \\"some.string\\" param=\\"string\\" another=1}} + {{(t \\"some.string\\" param=\\"string\\" another=1)}} " `); }); @@ -978,7 +977,7 @@ test('skip-default-helpers', () => { expect(runTest('skip-default-helpers.hbs', input, options)).toMatchInlineSnapshot(` "
- {{liquid-outlet}} + {{(liquid-outlet)}}
@@ -998,11 +997,11 @@ test('skip-default-helpers', () => { Two {{/liquid-if}} - {{moment '12-25-1995' 'MM-DD-YYYY'}} - {{moment-from '1995-12-25' '2995-12-25' hideAffix=true}} + {{(moment '12-25-1995' 'MM-DD-YYYY')}} + {{(moment-from '1995-12-25' '2995-12-25' hideAffix=true)}} - {{some-helper1 foo=true}} - {{some-helper2 foo=true}} + {{(some-helper1 foo=true)}} + {{(some-helper2 foo=true)}} " `); }); @@ -1040,7 +1039,7 @@ test('skip-default-helpers (no-config)', () => { expect(runTest('skip-default-helpers.hbs', input)).toMatchInlineSnapshot(` "
- {{liquid-outlet}} + {{(liquid-outlet)}}
@@ -1060,8 +1059,8 @@ test('skip-default-helpers (no-config)', () => { Two {{/liquid-if}} - {{moment '12-25-1995' 'MM-DD-YYYY'}} - {{moment-from '1995-12-25' '2995-12-25' hideAffix=true}} + {{(moment '12-25-1995' 'MM-DD-YYYY')}} + {{(moment-from '1995-12-25' '2995-12-25' hideAffix=true)}} @@ -1087,8 +1086,8 @@ test('custom-options', () => { expect(runTest('custom-options.hbs', input, options)).toMatchInlineSnapshot(` " - {{some-helper1 foo=true}} - {{some-helper2 foo=true}} + {{(some-helper1 foo=true)}} + {{(some-helper2 foo=true)}} {{link-to \\"Title\\" \\"some.route\\"}} {{textarea value=this.model.body}} {{input type=\\"checkbox\\" name=\\"email-opt-in\\" checked=this.model.emailPreference}} @@ -1181,7 +1180,7 @@ test('preserve arguments', () => { " {{foo-bar data-baz class=\\"baz\\"}} - {{t \\"show\\"}} + {{(t \\"show\\")}} " `); }); @@ -1278,7 +1277,6 @@ test('wallstreet-telemetry', () => { let input = ` {{nested$helper}} {{nested::helper}} - {{nested$helper param="cool!"}} {{nested::helper param="yeah!"}} {{helper-1}} `; @@ -1286,10 +1284,27 @@ test('wallstreet-telemetry', () => { expect(runTest('wallstreet-telemetry.hbs', input)).toMatchInlineSnapshot(` " {{nested$helper}} - {{nested::helper}} - {{nested$helper param=\\"cool!\\"}} - {{nested::helper param=\\"yeah!\\"}} - {{helper-1}} + {{(nested::helper)}} + {{(nested::helper param=\\"yeah!\\")}} + {{(helper-1)}} + " + `); +}); + +test('wrapping-helpers-with-parens', () => { + let input = ` + {{fooknownhelper}} + {{(fooknownhelper)}} + {{fooknownhelper data-test-foo foo="bar"}} + {{foounknownhelper}} + `; + + expect(runTest('wrapping-helpers-with-parens.hbs', input)).toMatchInlineSnapshot(` + " + {{(fooknownhelper)}} + {{(fooknownhelper)}} + {{(fooknownhelper data-test-foo foo=\\"bar\\")}} + {{foounknownhelper}} " `); }); @@ -1335,3 +1350,23 @@ test('No telemetry', () => { " `); }); + +test('pipe', () => { + let input = `"}} as |bar|>`; + + expect(runTestWithData('pipe.hbs', input, {}, {})).toMatchInlineSnapshot( + `"\\"}} as |bar|>"` + ); +}); + +test('outlet', () => { + let input = `{{outlet}}`; + + expect(runTestWithData('pipe.hbs', input, {}, {})).toMatchInlineSnapshot(`"{{outlet}}"`); +}); + +test('yield', () => { + let input = `{{yield}}`; + + expect(runTestWithData('pipe.hbs', input, {}, {})).toMatchInlineSnapshot(`"{{yield}}"`); +});