From 38c421284300d33336be6f5c2ec20b991e48b92e Mon Sep 17 00:00:00 2001 From: Alon Bukai Date: Sun, 4 Aug 2019 18:34:11 +0300 Subject: [PATCH 01/10] feat: Add failing test with dynamic class --- tests/integration/components/link-to-test.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/integration/components/link-to-test.js b/tests/integration/components/link-to-test.js index f5bf5dc..0eb5483 100644 --- a/tests/integration/components/link-to-test.js +++ b/tests/integration/components/link-to-test.js @@ -39,6 +39,26 @@ module('Integration | Component | link-to', function(hooks) { assert.dom('a').hasText('Link'); }); + test('it supports static route with class property', async function(assert) { + await render(hbs` + {{#with (concat "ma" "in") as |main|}} + Link + {{/with}} + `); + + assert.dom('a').hasAttribute('href', '#/foo'); + assert.dom('a').hasClass('main'); + assert.dom('a').hasText('Link'); + }); + + test('it supports static route with dynamic class', async function(assert) { + await render(hbs`Link`); + + assert.dom('a').hasAttribute('href', '#/foo'); + assert.dom('a').hasClass('main'); + assert.dom('a').hasText('Link'); + }); + test('it supports dynamic route', async function(assert) { await render(hbs`Link`); From ee26617e4f2c42a0e854aeffbc22915073b466a9 Mon Sep 17 00:00:00 2001 From: Alon Bukai Date: Sun, 4 Aug 2019 20:56:28 +0300 Subject: [PATCH 02/10] chore: Fix link to AST explorer Too much https --- lib/ast-link-to-transform.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ast-link-to-transform.js b/lib/ast-link-to-transform.js index fdffdf0..4b715bb 100644 --- a/lib/ast-link-to-transform.js +++ b/lib/ast-link-to-transform.js @@ -29,7 +29,7 @@ class AngleBracketLinkToPolyfill { let b = this.syntax.builders; let { moduleName } = this; - // in order to debug in https://https://astexplorer.net/#/gist/0590eb883edfcd163b183514df4cc717 + // in order to debug in https://astexplorer.net/#/gist/0590eb883edfcd163b183514df4cc717 // **** copy from here **** function transformAttributeValue(attributeValue) { switch (attributeValue.type) { From 58525f7af566c33461faef3c5ac4fa309102eadb Mon Sep 17 00:00:00 2001 From: Alon Bukai Date: Mon, 5 Aug 2019 10:33:13 +0300 Subject: [PATCH 03/10] fix: Add LinkTo transform path to handle helpers --- lib/ast-link-to-transform.js | 15 +++++++++++---- tests/integration/components/link-to-test.js | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/ast-link-to-transform.js b/lib/ast-link-to-transform.js index 4b715bb..dfe0d17 100644 --- a/lib/ast-link-to-transform.js +++ b/lib/ast-link-to-transform.js @@ -36,6 +36,12 @@ class AngleBracketLinkToPolyfill { case 'TextNode': return b.string(attributeValue.chars); case 'MustacheStatement': + if (attributeValue.params.length) { + // Deals with helper usage + return b.path( + b.sexpr(attributeValue.path.original, attributeValue.params, null, attributeValue.loc) + ); + } return b.path(attributeValue.path); } } @@ -101,10 +107,11 @@ class AngleBracketLinkToPolyfill { .map(attribute => Object.assign({}, attribute, { name: attribute.name.slice(1) })); let attrs = attributes .filter(({ name }) => supportsAttribute(name, supportedHTMLAttributes)) - .map(attribute => - attributeToPropertyMap[attribute.name] - ? Object.assign({}, attribute, { name: attributeToPropertyMap[attribute.name] }) - : attribute + .map( + attribute => + attributeToPropertyMap[attribute.name] + ? Object.assign({}, attribute, { name: attributeToPropertyMap[attribute.name] }) + : attribute ); let hash = b.hash( diff --git a/tests/integration/components/link-to-test.js b/tests/integration/components/link-to-test.js index 0eb5483..9cc8ae0 100644 --- a/tests/integration/components/link-to-test.js +++ b/tests/integration/components/link-to-test.js @@ -52,7 +52,7 @@ module('Integration | Component | link-to', function(hooks) { }); test('it supports static route with dynamic class', async function(assert) { - await render(hbs`Link`); + await render(hbs`Link`); assert.dom('a').hasAttribute('href', '#/foo'); assert.dom('a').hasClass('main'); From 59d23c91ac086645a12ff2590e03d6c4ccd86ba4 Mon Sep 17 00:00:00 2001 From: Alon Bukai Date: Mon, 5 Aug 2019 10:34:21 +0300 Subject: [PATCH 04/10] chore: Update ASTExplorer URL --- lib/ast-link-to-transform.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ast-link-to-transform.js b/lib/ast-link-to-transform.js index dfe0d17..8c6ace4 100644 --- a/lib/ast-link-to-transform.js +++ b/lib/ast-link-to-transform.js @@ -29,7 +29,7 @@ class AngleBracketLinkToPolyfill { let b = this.syntax.builders; let { moduleName } = this; - // in order to debug in https://astexplorer.net/#/gist/0590eb883edfcd163b183514df4cc717 + // in order to debug in https://astexplorer.net/#/gist/0590eb883edfcd163b183514df4cc717/6284c6222fe671a1be16432477cdf83c840dfcf0 // **** copy from here **** function transformAttributeValue(attributeValue) { switch (attributeValue.type) { From eec6cdf4e1311820f7c2c929a279a3be45cf8564 Mon Sep 17 00:00:00 2001 From: Alon Bukai Date: Tue, 6 Aug 2019 13:20:38 +0300 Subject: [PATCH 05/10] feat: Extract attributeValue into helper function Used in all transforms --- lib/ast-input-transform.js | 25 ++++++---------- lib/ast-link-to-transform.js | 30 +++++-------------- lib/ast-transform.js | 26 ++++------------ lib/helpers/expression-for-attribute-value.js | 20 +++++++++++++ 4 files changed, 42 insertions(+), 59 deletions(-) create mode 100644 lib/helpers/expression-for-attribute-value.js diff --git a/lib/ast-input-transform.js b/lib/ast-input-transform.js index e9d9d44..fc485b4 100644 --- a/lib/ast-input-transform.js +++ b/lib/ast-input-transform.js @@ -2,6 +2,7 @@ const checkAttributes = require('./helpers/check-attributes'); const supportsAttribute = require('./helpers/supports-attribute'); +const expressionForAttributeValue = require('./helpers/expression-for-attribute-value'); const getTag = require('./helpers/get-tag'); const reLines = /(.*?(?:\r\n?|\n|$))/gm; @@ -97,15 +98,6 @@ class AngleBracketInputPolyfill { // in order to debug in https://https://astexplorer.net/#/gist/0590eb883edfcd163b183514df4cc717 // **** copy from here **** - function transformAttributeValue(attributeValue) { - switch (attributeValue.type) { - case 'TextNode': - return b.string(attributeValue.chars); - case 'MustacheStatement': - return b.path(attributeValue.path); - } - } - let visitor = { ElementNode(node) { let tag = getTag(node, sourceLines); @@ -119,8 +111,8 @@ class AngleBracketInputPolyfill { tag === 'Textarea' ? textareaAttributes : isCheckbox - ? checkboxAttributes - : inputAttributes; + ? checkboxAttributes + : inputAttributes; checkAttributes(node, supportedAttributes, moduleName); @@ -129,15 +121,16 @@ class AngleBracketInputPolyfill { .map(attribute => Object.assign({}, attribute, { name: attribute.name.slice(1) })); let attrs = attributes .filter(({ name }) => supportsAttribute(name, supportedAttributes)) - .map(attribute => - attributeToPropertyMap[attribute.name] - ? Object.assign({}, attribute, { name: attributeToPropertyMap[attribute.name] }) - : attribute + .map( + attribute => + attributeToPropertyMap[attribute.name] + ? Object.assign({}, attribute, { name: attributeToPropertyMap[attribute.name] }) + : attribute ); let hash = b.hash( [...props, ...attrs].map(({ name, value, loc }) => - b.pair(name, transformAttributeValue(value), loc) + b.pair(name, expressionForAttributeValue(b, value), loc) ) ); diff --git a/lib/ast-link-to-transform.js b/lib/ast-link-to-transform.js index 8c6ace4..0c92163 100644 --- a/lib/ast-link-to-transform.js +++ b/lib/ast-link-to-transform.js @@ -2,6 +2,7 @@ const checkAttributes = require('./helpers/check-attributes'); const supportsAttribute = require('./helpers/supports-attribute'); +const expressionForAttributeValue = require('./helpers/expression-for-attribute-value'); const SilentError = require('silent-error'); const reservedProps = ['@route', '@model', '@models', '@query']; @@ -31,21 +32,6 @@ class AngleBracketLinkToPolyfill { // in order to debug in https://astexplorer.net/#/gist/0590eb883edfcd163b183514df4cc717/6284c6222fe671a1be16432477cdf83c840dfcf0 // **** copy from here **** - function transformAttributeValue(attributeValue) { - switch (attributeValue.type) { - case 'TextNode': - return b.string(attributeValue.chars); - case 'MustacheStatement': - if (attributeValue.params.length) { - // Deals with helper usage - return b.path( - b.sexpr(attributeValue.path.original, attributeValue.params, null, attributeValue.loc) - ); - } - return b.path(attributeValue.path); - } - } - let visitor = { ElementNode(node) { if (node.tag.toLowerCase() === 'linkto') { @@ -72,17 +58,17 @@ class AngleBracketLinkToPolyfill { if (route) { if (needsParamsHelper) { - helperParams.push(b.pair('route', transformAttributeValue(route.value))); + helperParams.push(b.pair('route', expressionForAttributeValue(b, route.value))); } else { - params.push(transformAttributeValue(route.value)); + params.push(expressionForAttributeValue(b, route.value)); } } if (model) { if (needsParamsHelper) { - helperParams.push(b.pair('model', transformAttributeValue(model.value))); + helperParams.push(b.pair('model', expressionForAttributeValue(b, model.value))); } else { - params.push(transformAttributeValue(model.value)); + params.push(expressionForAttributeValue(b, model.value)); } } @@ -90,7 +76,7 @@ class AngleBracketLinkToPolyfill { if (models.value.path.original === 'array') { params.push(...models.value.params); } else { - helperParams.push(b.pair('models', transformAttributeValue(models.value))); + helperParams.push(b.pair('models', expressionForAttributeValue(b, models.value))); } } @@ -98,7 +84,7 @@ class AngleBracketLinkToPolyfill { if (query.value.path.original === 'hash') { params.push(b.sexpr('query-params', null, query.value.hash, query.loc)); } else { - helperParams.push(b.pair('query', transformAttributeValue(query.value))); + helperParams.push(b.pair('query', expressionForAttributeValue(b, query.value))); } } @@ -116,7 +102,7 @@ class AngleBracketLinkToPolyfill { let hash = b.hash( [...props, ...attrs].map(({ name, value, loc }) => - b.pair(name, transformAttributeValue(value), loc) + b.pair(name, expressionForAttributeValue(b, value), loc) ) ); diff --git a/lib/ast-transform.js b/lib/ast-transform.js index 1d56883..0e44187 100644 --- a/lib/ast-transform.js +++ b/lib/ast-transform.js @@ -2,6 +2,7 @@ const getTag = require('./helpers/get-tag'); const sourceForNode = require('./helpers/source-for-node'); +const expressionForAttributeValue = require('./helpers/expression-for-attribute-value'); const reLines = /(.*?(?:\r\n?|\n|$))/gm; const ALPHA = /[A-Za-z]/; @@ -33,25 +34,6 @@ class AngleBracketPolyfill { return string.replace(/::/g, '/'); } - function isSimple(mustache) { - return mustache.params.length === 0 && mustache.hash.pairs.length === 0; - } - - function expressionForAttributeValue(value) { - if (value.type === 'TextNode') { - return b.string(value.chars); - } else if (value.type === 'MustacheStatement') { - // TODO: Resolve ambiguous case data-foo="{{is-this-a-helper}}" - if (isSimple(value)) { - return value.path; - } else { - return b.sexpr(value.path, value.params, value.hash, value.loc); - } - } else if (value.type === 'ConcatStatement') { - return b.sexpr('concat', value.parts.map(expressionForAttributeValue)); - } - } - function getSelfClosing(element) { if ('selfClosing' in element) { return element.selfClosing; @@ -125,7 +107,9 @@ class AngleBracketPolyfill { 'hash', [], b.hash( - attrs.map(attr => b.pair(attr.name, expressionForAttributeValue(attr.value), attr.loc)) + attrs.map(attr => + b.pair(attr.name, expressionForAttributeValue(b, attr.value), attr.loc) + ) ) ); } @@ -196,7 +180,7 @@ class AngleBracketPolyfill { let hash = b.hash( args.map(arg => - b.pair(arg.name.slice(1), expressionForAttributeValue(arg.value), arg.loc) + b.pair(arg.name.slice(1), expressionForAttributeValue(b, arg.value), arg.loc) ) ); diff --git a/lib/helpers/expression-for-attribute-value.js b/lib/helpers/expression-for-attribute-value.js new file mode 100644 index 0000000..1544383 --- /dev/null +++ b/lib/helpers/expression-for-attribute-value.js @@ -0,0 +1,20 @@ +'use strict'; + +function isSimple(mustache) { + return mustache.params.length === 0 && mustache.hash.pairs.length === 0; +} + +module.exports = function expressionForAttributeValue(b, value) { + if (value.type === 'TextNode') { + return b.string(value.chars); + } else if (value.type === 'MustacheStatement') { + // TODO: Resolve ambiguous case data-foo="{{is-this-a-helper}}" + if (isSimple(value)) { + return value.path; + } else { + return b.sexpr(value.path, value.params, value.hash, value.loc); + } + } else if (value.type === 'ConcatStatement') { + return b.sexpr('concat', value.parts.map(expressionForAttributeValue)); + } +}; From cb654c87a3efd5784f522ce345d7555f442adf1e Mon Sep 17 00:00:00 2001 From: Alon Bukai Date: Tue, 6 Aug 2019 14:36:45 +0300 Subject: [PATCH 06/10] chore: Fix lint issues --- lib/helpers/check-attributes.js | 4 +++- lib/helpers/supports-attribute.js | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/helpers/check-attributes.js b/lib/helpers/check-attributes.js index 5612615..b81bf9e 100644 --- a/lib/helpers/check-attributes.js +++ b/lib/helpers/check-attributes.js @@ -9,7 +9,9 @@ module.exports = function checkAttributes(node, supported, moduleName) { if (node.modifiers.length > 0) { throw new SilentError( - `Passing element modifiers to the <${node.tag}> component ${sourceReference} is not supported by ember-angle-bracket-invocation-polyfill.` + `Passing element modifiers to the <${ + node.tag + }> component ${sourceReference} is not supported by ember-angle-bracket-invocation-polyfill.` ); } diff --git a/lib/helpers/supports-attribute.js b/lib/helpers/supports-attribute.js index d0f2d41..699d37e 100644 --- a/lib/helpers/supports-attribute.js +++ b/lib/helpers/supports-attribute.js @@ -1,7 +1,8 @@ 'use strict'; module.exports = function supportsAttribute(name, supported) { - return !!supported.find(supportedName => - supportedName instanceof RegExp ? supportedName.exec(name) : name === supportedName + return !!supported.find( + supportedName => + supportedName instanceof RegExp ? supportedName.exec(name) : name === supportedName ); }; From 8e47714996f53d979b627ff1793e0a95d4e6bfc4 Mon Sep 17 00:00:00 2001 From: Alon Bukai Date: Tue, 6 Aug 2019 15:01:10 +0300 Subject: [PATCH 07/10] chore: Fix lint issues for real --- lib/ast-input-transform.js | 13 ++++++------- lib/ast-link-to-transform.js | 9 ++++----- lib/helpers/check-attributes.js | 4 +--- lib/helpers/supports-attribute.js | 5 ++--- 4 files changed, 13 insertions(+), 18 deletions(-) diff --git a/lib/ast-input-transform.js b/lib/ast-input-transform.js index fc485b4..6261180 100644 --- a/lib/ast-input-transform.js +++ b/lib/ast-input-transform.js @@ -111,8 +111,8 @@ class AngleBracketInputPolyfill { tag === 'Textarea' ? textareaAttributes : isCheckbox - ? checkboxAttributes - : inputAttributes; + ? checkboxAttributes + : inputAttributes; checkAttributes(node, supportedAttributes, moduleName); @@ -121,11 +121,10 @@ class AngleBracketInputPolyfill { .map(attribute => Object.assign({}, attribute, { name: attribute.name.slice(1) })); let attrs = attributes .filter(({ name }) => supportsAttribute(name, supportedAttributes)) - .map( - attribute => - attributeToPropertyMap[attribute.name] - ? Object.assign({}, attribute, { name: attributeToPropertyMap[attribute.name] }) - : attribute + .map(attribute => + attributeToPropertyMap[attribute.name] + ? Object.assign({}, attribute, { name: attributeToPropertyMap[attribute.name] }) + : attribute ); let hash = b.hash( diff --git a/lib/ast-link-to-transform.js b/lib/ast-link-to-transform.js index 0c92163..9e6d321 100644 --- a/lib/ast-link-to-transform.js +++ b/lib/ast-link-to-transform.js @@ -93,11 +93,10 @@ class AngleBracketLinkToPolyfill { .map(attribute => Object.assign({}, attribute, { name: attribute.name.slice(1) })); let attrs = attributes .filter(({ name }) => supportsAttribute(name, supportedHTMLAttributes)) - .map( - attribute => - attributeToPropertyMap[attribute.name] - ? Object.assign({}, attribute, { name: attributeToPropertyMap[attribute.name] }) - : attribute + .map(attribute => + attributeToPropertyMap[attribute.name] + ? Object.assign({}, attribute, { name: attributeToPropertyMap[attribute.name] }) + : attribute ); let hash = b.hash( diff --git a/lib/helpers/check-attributes.js b/lib/helpers/check-attributes.js index b81bf9e..5612615 100644 --- a/lib/helpers/check-attributes.js +++ b/lib/helpers/check-attributes.js @@ -9,9 +9,7 @@ module.exports = function checkAttributes(node, supported, moduleName) { if (node.modifiers.length > 0) { throw new SilentError( - `Passing element modifiers to the <${ - node.tag - }> component ${sourceReference} is not supported by ember-angle-bracket-invocation-polyfill.` + `Passing element modifiers to the <${node.tag}> component ${sourceReference} is not supported by ember-angle-bracket-invocation-polyfill.` ); } diff --git a/lib/helpers/supports-attribute.js b/lib/helpers/supports-attribute.js index 699d37e..d0f2d41 100644 --- a/lib/helpers/supports-attribute.js +++ b/lib/helpers/supports-attribute.js @@ -1,8 +1,7 @@ 'use strict'; module.exports = function supportsAttribute(name, supported) { - return !!supported.find( - supportedName => - supportedName instanceof RegExp ? supportedName.exec(name) : name === supportedName + return !!supported.find(supportedName => + supportedName instanceof RegExp ? supportedName.exec(name) : name === supportedName ); }; From 1fdbaf93a331d359a6d14ac430e0e598c0abd092 Mon Sep 17 00:00:00 2001 From: Alon Bukai Date: Tue, 6 Aug 2019 15:25:10 +0300 Subject: [PATCH 08/10] fix: attributeValue() ConcatStatement transform --- lib/helpers/expression-for-attribute-value.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers/expression-for-attribute-value.js b/lib/helpers/expression-for-attribute-value.js index 1544383..04ba990 100644 --- a/lib/helpers/expression-for-attribute-value.js +++ b/lib/helpers/expression-for-attribute-value.js @@ -15,6 +15,6 @@ module.exports = function expressionForAttributeValue(b, value) { return b.sexpr(value.path, value.params, value.hash, value.loc); } } else if (value.type === 'ConcatStatement') { - return b.sexpr('concat', value.parts.map(expressionForAttributeValue)); + return b.sexpr('concat', value.parts.map(p => expressionForAttributeValue(b, p))); } }; From bd9ad7aeeaa3f0a9a79a4878e442762d956caceb Mon Sep 17 00:00:00 2001 From: Alon Bukai Date: Tue, 6 Aug 2019 15:25:33 +0300 Subject: [PATCH 09/10] chore: Add LinkTo test for concat statement --- tests/integration/components/link-to-test.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/integration/components/link-to-test.js b/tests/integration/components/link-to-test.js index 9cc8ae0..c4d5445 100644 --- a/tests/integration/components/link-to-test.js +++ b/tests/integration/components/link-to-test.js @@ -59,6 +59,14 @@ module('Integration | Component | link-to', function(hooks) { assert.dom('a').hasText('Link'); }); + test('it supports static route with class concat statement', async function(assert) { + await render(hbs`Link`); + + assert.dom('a').hasAttribute('href', '#/foo'); + assert.dom('a').hasClass('main'); + assert.dom('a').hasText('Link'); + }); + test('it supports dynamic route', async function(assert) { await render(hbs`Link`); From 28562670370957e119be6be14bf7bdaa1e732920 Mon Sep 17 00:00:00 2001 From: Alon Bukai Date: Tue, 6 Aug 2019 15:30:20 +0300 Subject: [PATCH 10/10] chore: Update LinkTo ASTExplorer link --- lib/ast-link-to-transform.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ast-link-to-transform.js b/lib/ast-link-to-transform.js index 9e6d321..511d82f 100644 --- a/lib/ast-link-to-transform.js +++ b/lib/ast-link-to-transform.js @@ -30,7 +30,7 @@ class AngleBracketLinkToPolyfill { let b = this.syntax.builders; let { moduleName } = this; - // in order to debug in https://astexplorer.net/#/gist/0590eb883edfcd163b183514df4cc717/6284c6222fe671a1be16432477cdf83c840dfcf0 + // in order to debug in https://astexplorer.net/#/gist/0590eb883edfcd163b183514df4cc717/4f4fe68b6c9de49e633ceb7f41a0c13b6fcc6cc6 // **** copy from here **** let visitor = { ElementNode(node) {