diff --git a/packages/@ember/-internals/glimmer/tests/integration/components/class-bindings-test.js b/packages/@ember/-internals/glimmer/tests/integration/components/class-bindings-test.js index a5c6951bc72..b451caa8db5 100644 --- a/packages/@ember/-internals/glimmer/tests/integration/components/class-bindings-test.js +++ b/packages/@ember/-internals/glimmer/tests/integration/components/class-bindings-test.js @@ -125,82 +125,6 @@ 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( - '{{foo-bar classNameBindings="this.model.someInitiallyTrueProperty this.model.someInitiallyFalseProperty this.model.someInitiallyUndefinedProperty :static this.model.isBig:big this.model.isOpen:open:closed this.model.isUp::down this.model.bar:isTruthy:isFalsy"}}', - { - model: { - someInitiallyTrueProperty: true, - someInitiallyFalseProperty: false, - isBig: true, - isOpen: false, - isUp: true, - bar: true, - }, - } - ); - - this.assertComponentElement(this.firstChild, { - attrs: { - class: classes('ember-view some-initially-true-property static big closed isTruthy'), - }, - content: 'hello', - }); - - runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { - attrs: { - class: classes('ember-view some-initially-true-property static big closed isTruthy'), - }, - content: 'hello', - }); - - runTask(() => { - set(this.context, 'model.someInitiallyTrueProperty', false); - set(this.context, 'model.someInitiallyFalseProperty', true); - set(this.context, 'model.someInitiallyUndefinedProperty', true); - set(this.context, 'model.isBig', false); - set(this.context, 'model.isOpen', true); - set(this.context, 'model.isUp', false); - set(this.context, 'model.bar', false); - }); - - this.assertComponentElement(this.firstChild, { - attrs: { - class: classes( - 'ember-view some-initially-false-property some-initially-undefined-property static open down isFalsy' - ), - }, - content: 'hello', - }); - - runTask(() => { - set(this.context, 'model', { - someInitiallyTrueProperty: true, - someInitiallyFalseProperty: false, - someInitiallyUndefinedProperty: undefined, - isBig: true, - isOpen: false, - isUp: true, - bar: true, - }); - }); - - this.assertComponentElement(this.firstChild, { - attrs: { - class: classes('ember-view some-initially-true-property static big closed isTruthy'), - }, - content: 'hello', - }); - } - ['@test it can have class name bindings with nested paths']() { let FooBarComponent = Component.extend({ classNameBindings: ['foo.bar', 'is.enabled:enabled', 'is.happy:happy:sad'], @@ -346,47 +270,6 @@ 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, - }); - - this.assertComponentElement(this.firstChild, { - tagName: 'div', - attrs: { class: classes('ember-view enabled') }, - content: 'hello', - }); - - runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { - tagName: 'div', - attrs: { class: classes('ember-view enabled') }, - content: 'hello', - }); - - runTask(() => set(this.context, 'foo', false)); - - this.assertComponentElement(this.firstChild, { - tagName: 'div', - attrs: { class: classes('ember-view disabled') }, - content: 'hello', - }); - - runTask(() => set(this.context, 'foo', true)); - - this.assertComponentElement(this.firstChild, { - tagName: 'div', - attrs: { class: classes('ember-view enabled') }, - content: 'hello', - }); - } - ['@test :: class name syntax works with an empty true class']() { let FooBarComponent = Component.extend({ classNameBindings: ['isEnabled::not-enabled'], @@ -678,212 +561,3 @@ moduleFor( } } ); - -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"}}'); - - this.assertComponentElement(this.firstChild, { - tagName: 'div', - content: 'hello', - attrs: { class: classes('foo ember-view') }, - }); - - runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { - tagName: 'div', - content: 'hello', - attrs: { class: classes('foo ember-view') }, - }); - } - - ['@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"}}', { - birdman: true, - }); - - this.assertComponentElement(this.firstChild, { - tagName: 'div', - content: 'hello', - attrs: { class: classes('respeck myName ember-view') }, - }); - - runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { - tagName: 'div', - content: 'hello', - attrs: { class: classes('respeck myName ember-view') }, - }); - } - - ['@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"}}', { - myName: true, - }); - - this.assertComponentElement(this.firstChild, { - tagName: 'div', - content: 'hello', - attrs: { class: classes('respeck ember-view') }, - }); - - runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { - tagName: 'div', - content: 'hello', - attrs: { class: classes('respeck ember-view') }, - }); - } - - ['@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"}}', { - myName: false, - }); - - this.assertComponentElement(this.firstChild, { - tagName: 'div', - content: 'hello', - attrs: { class: classes('shade ember-view') }, - }); - - runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { - tagName: 'div', - content: 'hello', - attrs: { class: classes('shade ember-view') }, - }); - } - - ['@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"}}', { - myName: false, - }); - - this.assertComponentElement(this.firstChild, { - tagName: 'div', - content: 'hello', - attrs: { class: classes('ember-view') }, - }); - - runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { - tagName: 'div', - content: 'hello', - attrs: { class: classes('ember-view') }, - }); - } - - ['@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 }); - - this.assertComponentElement(this.firstChild, { - tagName: 'div', - content: 'hello', - attrs: { class: classes('ember-view') }, - }); - - runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { - tagName: 'div', - content: 'hello', - attrs: { class: classes('ember-view') }, - }); - } - - ['@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"}}', { - swag: false, - }); - - this.assertComponentElement(this.firstChild, { - tagName: 'div', - content: 'hello', - attrs: { class: classes('scrub ember-view') }, - }); - - runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { - tagName: 'div', - content: 'hello', - attrs: { class: classes('scrub ember-view') }, - }); - } - - ['@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"}}', { - swag: true, - }); - - this.assertComponentElement(this.firstChild, { - tagName: 'div', - content: 'hello', - attrs: { class: classes('fresh ember-view') }, - }); - - runTask(() => this.rerender()); - - this.assertComponentElement(this.firstChild, { - tagName: 'div', - content: 'hello', - attrs: { class: classes('fresh ember-view') }, - }); - } - } -); diff --git a/packages/@ember/-internals/glimmer/tests/integration/components/link-to/routing-curly-test.js b/packages/@ember/-internals/glimmer/tests/integration/components/link-to/routing-curly-test.js index b8cc6247317..3df012cfa86 100644 --- a/packages/@ember/-internals/glimmer/tests/integration/components/link-to/routing-curly-test.js +++ b/packages/@ember/-internals/glimmer/tests/integration/components/link-to/routing-curly-test.js @@ -579,60 +579,6 @@ moduleFor( ); } - async [`@test [DEPRECATED] it 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:C29) " - ); - - this.addTemplate( - 'index', - ` -

Home

- - ` - ); - - let controller; - - this.add( - 'controller:index', - class extends Controller { - constructor(...args) { - super(...args); - controller = this; - } - - foo = false; - } - ); - - await expectDeprecationAsync( - () => this.visit('/'), - /Passing the `@class` argument to is deprecated\./, - EMBER_MODERNIZED_BUILT_IN_COMPONENTS - ); - - assert.equal( - this.$('#about-link > a.foo-is-false').length, - 1, - 'The about-link was rendered with the falsy class' - ); - - await expectDeprecation( - () => runTask(() => controller.set('foo', true)), - /Passing the `@class` argument to is deprecated\./, - EMBER_MODERNIZED_BUILT_IN_COMPONENTS - ); - - assert.equal( - this.$('#about-link > a.foo-is-true').length, - 1, - 'The about-link was rendered with the truthy class after toggling the property' - ); - } - async ['@test Using {{link-to}} inside a non-routable engine errors'](assert) { this.add( 'engine:not-routable', diff --git a/packages/ember-template-compiler/lib/plugins/index.ts b/packages/ember-template-compiler/lib/plugins/index.ts index 06d4b3b5c05..1cf5dd39ad6 100644 --- a/packages/ember-template-compiler/lib/plugins/index.ts +++ b/packages/ember-template-compiler/lib/plugins/index.ts @@ -10,7 +10,6 @@ import TransformEachInIntoEach from './transform-each-in-into-each'; import TransformEachTrackArray from './transform-each-track-array'; import TransformInElement from './transform-in-element'; import TransformLinkTo from './transform-link-to'; -import TransformOldClassBindingSyntax from './transform-old-class-binding-syntax'; import TransformQuotedBindingsIntoJustBindings from './transform-quoted-bindings-into-just-bindings'; import TransformResolutions from './transform-resolutions'; import TransformWrapMountAndOutlet from './transform-wrap-mount-and-outlet'; @@ -20,7 +19,6 @@ import { EMBER_DYNAMIC_HELPERS_AND_MODIFIERS, EMBER_NAMED_BLOCKS } from '@ember/ // order of plugins is important export const RESOLUTION_MODE_TRANSFORMS = Object.freeze( [ - TransformOldClassBindingSyntax, TransformQuotedBindingsIntoJustBindings, AssertReservedNamedArguments, TransformActionSyntax, diff --git a/packages/ember-template-compiler/lib/plugins/transform-old-class-binding-syntax.ts b/packages/ember-template-compiler/lib/plugins/transform-old-class-binding-syntax.ts deleted file mode 100644 index 19351f3c8db..00000000000 --- a/packages/ember-template-compiler/lib/plugins/transform-old-class-binding-syntax.ts +++ /dev/null @@ -1,154 +0,0 @@ -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?.moduleName; - - return { - name: 'transform-old-class-binding-syntax', - - visitor: { - MustacheStatement(node: AST.MustacheStatement) { - process(b, node, moduleName); - }, - - BlockStatement(node: AST.BlockStatement) { - process(b, node, moduleName); - }, - }, - }; -} - -function process( - b: Builders, - node: AST.BlockStatement | AST.MustacheStatement, - moduleName: string | undefined -) { - let allOfTheMicrosyntaxes: AST.HashPair[] = []; - let allOfTheMicrosyntaxIndexes: number[] = []; - let classPair: AST.HashPair | undefined; - - each(node.hash.pairs, (pair, index) => { - 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') { - classPair = pair; - } - }); - - if (allOfTheMicrosyntaxes.length === 0) { - return; - } - - let classValue: AST.Expression[] = []; - - if (classPair) { - classValue.push(classPair.value); - classValue.push(b.string(' ')); - } else { - classPair = b.pair('class', null as any); - node.hash.pairs.push(classPair); - } - - each(allOfTheMicrosyntaxIndexes, (index) => { - node.hash.pairs.splice(index, 1); - }); - - each(allOfTheMicrosyntaxes, ({ value }) => { - let sexprs: AST.Expression[] = []; - // TODO: add helpful deprecation when both `classNames` and `classNameBindings` can - // be removed. - - if (value.type === 'StringLiteral') { - let microsyntax = parseMicrosyntax(value.original); - - buildSexprs(microsyntax, sexprs, b); - - classValue.push(...sexprs); - } - }); - - let hash = b.hash(); - classPair.value = b.sexpr(b.path('concat'), classValue, hash); -} - -function buildSexprs(microsyntax: string[][], sexprs: AST.Expression[], b: Builders) { - for (let i = 0; i < microsyntax.length; i++) { - let [propName, activeClass, inactiveClass] = microsyntax[i]; - let sexpr; - - // :my-class-name microsyntax for static values - if (propName === '') { - sexpr = b.string(activeClass); - } else { - let params: AST.Expression[] = [b.path(propName)]; - - if (activeClass || activeClass === '') { - params.push(b.string(activeClass)); - } else { - let sexprParams = [b.string(propName), b.path(propName)]; - - let hash = b.hash(); - if (activeClass !== undefined) { - hash.pairs.push(b.pair('activeClass', b.string(activeClass))); - } - - if (inactiveClass !== undefined) { - hash.pairs.push(b.pair('inactiveClass', b.string(inactiveClass))); - } - - params.push(b.sexpr(b.path('-normalize-class'), sexprParams, hash)); - } - - if (inactiveClass || inactiveClass === '') { - params.push(b.string(inactiveClass)); - } - - sexpr = b.sexpr(b.path('if'), params); - } - - sexprs.push(sexpr); - sexprs.push(b.string(' ')); - } -} - -function each(list: T[], callback: (t: T, i: number) => void) { - for (let i = 0; i < list.length; i++) { - callback(list[i], i); - } -} - -function parseMicrosyntax(string: string): string[][] { - let segments = string.split(' '); - let ret: string[][] = []; - - for (let i = 0; i < segments.length; i++) { - ret[i] = segments[i].split(':'); - } - - return ret; -}