Skip to content

Commit

Permalink
Merge pull request #19375 from emberjs/deprecate-template-transforms
Browse files Browse the repository at this point in the history
[DEPRECATION] Deprecate old class binding syntax and {{attrs}}
  • Loading branch information
rwjblue authored Feb 3, 2021
2 parents 68a1c4f + 65cceb3 commit 905ea77
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,9 @@ moduleFor(
expectDeprecation(
`The use of \`{{partial}}\` is deprecated, please refactor the "troll" partial to a component`
);
expectDeprecation(
'Using {{attrs}} to reference named arguments has been deprecated. {{attrs.wat}} should be updated to {{@wat}}. (L1:C2) '
);

this.setupEngineWithAttrs([]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ moduleFor(
}

['@test it can have class name bindings in the template']() {
expectDeprecation(
"Passing the `classNameBindings` property as an argument within templates has been deprecated. Instead, you can pass the class argument and use concatenation to produce the class value dynamically. ('-top-level' @ L1:C0) "
);

this.registerComponent('foo-bar', { template: 'hello' });

this.render(
Expand Down Expand Up @@ -343,6 +347,10 @@ moduleFor(
}

['@test const bindings can be set as attrs']() {
expectDeprecation(
"Passing the `classNameBindings` property as an argument within templates has been deprecated. Instead, you can pass the class argument and use concatenation to produce the class value dynamically. ('-top-level' @ L1:C0) "
);

this.registerComponent('foo-bar', { template: 'hello' });
this.render('{{foo-bar classNameBindings="this.foo:enabled:disabled"}}', {
foo: true,
Expand Down Expand Up @@ -675,6 +683,10 @@ moduleFor(
'ClassBinding integration',
class extends RenderingTestCase {
['@test it should apply classBinding without condition always']() {
expectDeprecation(
"Passing the `classBinding` property as an argument within templates has been deprecated. Instead, you can pass the class argument and use concatenation to produce the class value dynamically. ('-top-level' @ L1:C0) "
);

this.registerComponent('foo-bar', { template: 'hello' });

this.render('{{foo-bar classBinding=":foo"}}');
Expand All @@ -695,6 +707,10 @@ moduleFor(
}

['@test it should merge classBinding with class']() {
expectDeprecation(
"Passing the `classBinding` property as an argument within templates has been deprecated. Instead, you can pass the class argument and use concatenation to produce the class value dynamically. ('-top-level' @ L1:C0) "
);

this.registerComponent('foo-bar', { template: 'hello' });

this.render('{{foo-bar classBinding="this.birdman:respeck" class="myName"}}', {
Expand All @@ -717,6 +733,10 @@ moduleFor(
}

['@test it should apply classBinding with only truthy condition']() {
expectDeprecation(
"Passing the `classBinding` property as an argument within templates has been deprecated. Instead, you can pass the class argument and use concatenation to produce the class value dynamically. ('-top-level' @ L1:C0) "
);

this.registerComponent('foo-bar', { template: 'hello' });

this.render('{{foo-bar classBinding="this.myName:respeck"}}', {
Expand All @@ -739,6 +759,10 @@ moduleFor(
}

['@test it should apply classBinding with only falsy condition']() {
expectDeprecation(
"Passing the `classBinding` property as an argument within templates has been deprecated. Instead, you can pass the class argument and use concatenation to produce the class value dynamically. ('-top-level' @ L1:C0) "
);

this.registerComponent('foo-bar', { template: 'hello' });

this.render('{{foo-bar classBinding="this.myName::shade"}}', {
Expand All @@ -761,6 +785,10 @@ moduleFor(
}

['@test it should apply nothing when classBinding is falsy but only supplies truthy class']() {
expectDeprecation(
"Passing the `classBinding` property as an argument within templates has been deprecated. Instead, you can pass the class argument and use concatenation to produce the class value dynamically. ('-top-level' @ L1:C0) "
);

this.registerComponent('foo-bar', { template: 'hello' });

this.render('{{foo-bar classBinding="this.myName:respeck"}}', {
Expand All @@ -783,6 +811,10 @@ moduleFor(
}

['@test it should apply nothing when classBinding is truthy but only supplies falsy class']() {
expectDeprecation(
"Passing the `classBinding` property as an argument within templates has been deprecated. Instead, you can pass the class argument and use concatenation to produce the class value dynamically. ('-top-level' @ L1:C0) "
);

this.registerComponent('foo-bar', { template: 'hello' });

this.render('{{foo-bar classBinding="this.myName::shade"}}', { myName: true });
Expand All @@ -803,6 +835,10 @@ moduleFor(
}

['@test it should apply classBinding with falsy condition']() {
expectDeprecation(
"Passing the `classBinding` property as an argument within templates has been deprecated. Instead, you can pass the class argument and use concatenation to produce the class value dynamically. ('-top-level' @ L1:C0) "
);

this.registerComponent('foo-bar', { template: 'hello' });

this.render('{{foo-bar classBinding="this.swag:fresh:scrub"}}', {
Expand All @@ -825,6 +861,10 @@ moduleFor(
}

['@test it should apply classBinding with truthy condition']() {
expectDeprecation(
"Passing the `classBinding` property as an argument within templates has been deprecated. Instead, you can pass the class argument and use concatenation to produce the class value dynamically. ('-top-level' @ L1:C0) "
);

this.registerComponent('foo-bar', { template: 'hello' });

this.render('{{foo-bar classBinding="this.swag:fresh:scrub"}}', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1303,6 +1303,10 @@ moduleFor(
}

['@test non-block with properties on attrs']() {
expectDeprecation(
"Using {{attrs}} to reference named arguments has been deprecated. {{attrs.someProp}} should be updated to {{@someProp}}. ('my-app/templates/components/non-block.hbs' @ L1:C24) "
);

this.registerComponent('non-block', {
template: 'In layout - someProp: {{attrs.someProp}}',
});
Expand Down Expand Up @@ -1512,6 +1516,22 @@ moduleFor(
}

['@test this.attrs.foo === attrs.foo === @foo === foo']() {
expectDeprecation(
"Using {{attrs}} to reference named arguments has been deprecated. {{attrs.value}} should be updated to {{@value}}. ('my-app/templates/components/foo-bar.hbs' @ L1:C8) "
);

expectDeprecation(
"Using {{attrs}} to reference named arguments has been deprecated. {{attrs.value}} should be updated to {{@value}}. ('my-app/templates/components/foo-bar.hbs' @ L1:C31) "
);

expectDeprecation(
"Using {{attrs}} to reference named arguments has been deprecated. {{attrs.items}} should be updated to {{@items}}. ('my-app/templates/components/foo-bar.hbs' @ L1:C82) "
);

expectDeprecation(
"Using {{attrs}} to reference named arguments has been deprecated. {{attrs.items}} should be updated to {{@items}}. ('my-app/templates/components/foo-bar.hbs' @ L1:C135) "
);

this.registerComponent('foo-bar', {
template: strip`
Args: {{this.attrs.value}} | {{attrs.value}} | {{@value}} | {{this.value}}
Expand Down Expand Up @@ -1606,6 +1626,10 @@ moduleFor(
}

['@test block with properties on attrs']() {
expectDeprecation(
"Using {{attrs}} to reference named arguments has been deprecated. {{attrs.someProp}} should be updated to {{@someProp}}. ('my-app/templates/components/with-block.hbs' @ L1:C24) "
);

this.registerComponent('with-block', {
template: 'In layout - someProp: {{attrs.someProp}} - {{yield}}',
});
Expand Down Expand Up @@ -3605,6 +3629,13 @@ moduleFor(
}

['@test using attrs for positional params']() {
expectDeprecation(
"Using {{attrs}} to reference named arguments has been deprecated. {{attrs.myVar}} should be updated to {{@myVar}}. ('my-app/templates/components/foo-bar.hbs' @ L1:C10) "
);
expectDeprecation(
"Using {{attrs}} to reference named arguments has been deprecated. {{attrs.myVar2}} should be updated to {{@myVar2}}. ('my-app/templates/components/foo-bar.hbs' @ L1:C65) "
);

let MyComponent = Component.extend();

this.registerComponent('foo-bar', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -478,13 +478,13 @@ moduleFor(

['@test nested component helpers']() {
this.registerComponent('foo-bar', {
template: 'yippie! {{attrs.location}} {{yield}}',
template: 'yippie! {{@location}} {{yield}}',
});
this.registerComponent('baz-qux', {
template: 'yummy {{attrs.location}} {{yield}}',
template: 'yummy {{@location}} {{yield}}',
});
this.registerComponent('corge-grault', {
template: 'delicious {{attrs.location}} {{yield}}',
template: 'delicious {{@location}} {{yield}}',
});

this.render(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,43 +320,6 @@ moduleFor(
});
}

// See https://github.com/emberjs/ember.js/issues/17771
[`@skip The <LinkTo /> component supports 'classNameBindings' with custom values [GH #11699]`](
assert
) {
this.addTemplate(
'index',
`
<h3 class="home">Home</h3>
<LinkTo id='about-link' @route='about' @classNameBindings='foo:foo-is-true:foo-is-false'>About</LinkTo>
`
);

this.add(
'controller:index',
Controller.extend({
foo: false,
})
);

return this.visit('/').then(() => {
assert.equal(
this.$('#about-link.foo-is-false').length,
1,
'The about-link was rendered with the falsy class'
);

let controller = this.applicationInstance.lookup('controller:index');
runTask(() => controller.set('foo', true));

assert.equal(
this.$('#about-link.foo-is-true').length,
1,
'The about-link was rendered with the truthy class after toggling the property'
);
});
}

async ['@test Using <LinkTo> inside a non-routable engine errors'](assert) {
this.add(
'engine:not-routable',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,10 @@ moduleFor(
[`@test The {{link-to}} component supports 'classNameBindings' with custom values [GH #11699]`](
assert
) {
expectDeprecation(
"Passing the `classNameBindings` property as an argument within templates has been deprecated. Instead, you can pass the class argument and use concatenation to produce the class value dynamically. ('my-app/templates/index.hbs' @ L3:C8) "
);

this.addTemplate(
'index',
`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,10 @@ moduleFor(
}

['@test [#12718] a nice error is shown when a bound action function is undefined and it is passed as attrs.foo']() {
expectDeprecation(
"Using {{attrs}} to reference named arguments has been deprecated. {{attrs.external-action}} should be updated to {{@external-action}}. ('my-app/templates/components/inner-component.hbs' @ L1:C43) "
);

this.registerComponent('inner-component', {
template:
'<button id="inner-button" {{action (action attrs.external-action)}}>Click me</button>',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { deprecate } from '@ember/debug';
import { AST, ASTPlugin } from '@glimmer/syntax';
import calculateLocationDisplay from '../system/calculate-location-display';
import { EmberASTPluginEnvironment } from '../types';

/**
Expand Down Expand Up @@ -27,6 +29,7 @@ import { EmberASTPluginEnvironment } from '../types';

export default function transformAttrsIntoArgs(env: EmberASTPluginEnvironment): ASTPlugin {
let { builders: b } = env.syntax;
let { moduleName } = env.meta;

let stack: string[][] = [[]];

Expand All @@ -47,6 +50,26 @@ export default function transformAttrsIntoArgs(env: EmberASTPluginEnvironment):
PathExpression(node: AST.PathExpression): AST.Node | void {
if (isAttrs(node, stack[stack.length - 1])) {
let path = b.path(node.original.substr(6)) as AST.PathExpression;

deprecate(
`Using {{attrs}} to reference named arguments has been deprecated. {{attrs.${
path.original
}}} should be updated to {{@${path.original}}}. ${calculateLocationDisplay(
moduleName,
node.loc
)}`,
false,
{
id: 'attrs-arg-access',
url: 'https://deprecations.emberjs.com/v3.x/#toc_attrs-arg-access',
until: '4.0.0',
for: 'ember-source',
since: {
enabled: '3.26.0',
},
}
);

path.original = `@${path.original}`;
path.data = true;
return path;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,32 @@
import { deprecate } from '@ember/debug';
import { AST, ASTPlugin } from '@glimmer/syntax';
import calculateLocationDisplay from '../system/calculate-location-display';
import { Builders, EmberASTPluginEnvironment } from '../types';

export default function transformOldClassBindingSyntax(env: EmberASTPluginEnvironment): ASTPlugin {
let b = env.syntax.builders;
let { moduleName } = env.meta;

return {
name: 'transform-old-class-binding-syntax',

visitor: {
MustacheStatement(node: AST.MustacheStatement) {
process(b, node);
process(b, node, moduleName);
},

BlockStatement(node: AST.BlockStatement) {
process(b, node);
process(b, node, moduleName);
},
},
};
}

function process(b: Builders, node: AST.BlockStatement | AST.MustacheStatement) {
function process(
b: Builders,
node: AST.BlockStatement | AST.MustacheStatement,
moduleName: string
) {
let allOfTheMicrosyntaxes: AST.HashPair[] = [];
let allOfTheMicrosyntaxIndexes: number[] = [];
let classPair: AST.HashPair | undefined;
Expand All @@ -28,6 +35,24 @@ function process(b: Builders, node: AST.BlockStatement | AST.MustacheStatement)
let { key } = pair;

if (key === 'classBinding' || key === 'classNameBindings') {
deprecate(
`Passing the \`${key}\` property as an argument within templates has been deprecated. Instead, you can pass the class argument and use concatenation to produce the class value dynamically. ${calculateLocationDisplay(
moduleName,
node.loc
)}`,
false,
{
id: 'class-binding-and-class-name-bindings-in-templates',
url:
'https://deprecations.emberjs.com/v3.x/#toc_class-binding-and-class-name-bindings-in-templates',
until: '4.0.0',
for: 'ember-source',
since: {
enabled: '3.26.0',
},
}
);

allOfTheMicrosyntaxIndexes.push(index);
allOfTheMicrosyntaxes.push(pair);
} else if (key === 'class') {
Expand Down

0 comments on commit 905ea77

Please sign in to comment.