Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix <LinkTo> usage with class attribute. #82

Merged
merged 12 commits into from
Aug 6, 2019
25 changes: 9 additions & 16 deletions lib/ast-input-transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -119,8 +111,8 @@ class AngleBracketInputPolyfill {
tag === 'Textarea'
? textareaAttributes
: isCheckbox
? checkboxAttributes
: inputAttributes;
? checkboxAttributes
: inputAttributes;

checkAttributes(node, supportedAttributes, moduleName);

Expand All @@ -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)
)
);

Expand Down
35 changes: 14 additions & 21 deletions lib/ast-link-to-transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'];
Expand Down Expand Up @@ -29,17 +30,8 @@ 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/6284c6222fe671a1be16432477cdf83c840dfcf0
// **** 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) {
if (node.tag.toLowerCase() === 'linkto') {
Expand All @@ -66,33 +58,33 @@ 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));
}
}

if (models) {
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)));
}
}

if (query) {
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)));
}
}

Expand All @@ -101,15 +93,16 @@ 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(
[...props, ...attrs].map(({ name, value, loc }) =>
b.pair(name, transformAttributeValue(value), loc)
b.pair(name, expressionForAttributeValue(b, value), loc)
)
);

Expand Down
26 changes: 5 additions & 21 deletions lib/ast-transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]/;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
)
)
);
}
Expand Down Expand Up @@ -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)
)
);

Expand Down
20 changes: 20 additions & 0 deletions lib/helpers/expression-for-attribute-value.js
Original file line number Diff line number Diff line change
@@ -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));
}
};
20 changes: 20 additions & 0 deletions tests/integration/components/link-to-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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|}}
<LinkTo @route="foo" class={{main}}>Link</LinkTo>
{{/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`<LinkTo @route="foo" class={{concat "ma" "in"}}>Link</LinkTo>`);

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`<LinkTo @route="bar" @model={{this.modelA}} class="main">Link</LinkTo>`);

Expand Down