Skip to content

Commit

Permalink
Fix <LinkTo> usage with class attribute. (#82)
Browse files Browse the repository at this point in the history
Fix <LinkTo> usage with `class` attribute.
  • Loading branch information
rwjblue authored Aug 6, 2019
2 parents 061f313 + 2856267 commit dc65871
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 48 deletions.
12 changes: 2 additions & 10 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 Down Expand Up @@ -137,7 +129,7 @@ class AngleBracketInputPolyfill {

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: 9 additions & 17 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/4f4fe68b6c9de49e633ceb7f41a0c13b6fcc6cc6
// **** 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 @@ -109,7 +101,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)
)
);

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(p => expressionForAttributeValue(b, p)));
}
};
28 changes: 28 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,34 @@ 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 static route with class concat statement', async function(assert) {
await render(hbs`<LinkTo @route="foo" class="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

0 comments on commit dc65871

Please sign in to comment.