From ff9e96b686eefb9e84b08b0777c1666a4f885358 Mon Sep 17 00:00:00 2001 From: Gavin Joyce Date: Mon, 14 Oct 2019 12:30:01 +0100 Subject: [PATCH] RFC #449 : Deprecate {{partial}} --- packages/@ember/-internals/glimmer/index.ts | 1 + .../@ember/-internals/glimmer/lib/resolver.ts | 70 +++++- .../integration/application/engine-test.js | 16 +- .../components/curly-components-test.js | 8 +- .../tests/integration/helpers/partial-test.js | 232 ++++++++++-------- packages/@ember/-internals/views/index.d.ts | 4 - packages/@ember/-internals/views/index.js | 1 - .../views/lib/system/lookup_partial.js | 55 ----- packages/@ember/deprecated-features/index.ts | 1 + 9 files changed, 224 insertions(+), 164 deletions(-) delete mode 100644 packages/@ember/-internals/views/lib/system/lookup_partial.js diff --git a/packages/@ember/-internals/glimmer/index.ts b/packages/@ember/-internals/glimmer/index.ts index 3af6cac534b..b7b49048079 100644 --- a/packages/@ember/-internals/glimmer/index.ts +++ b/packages/@ember/-internals/glimmer/index.ts @@ -340,6 +340,7 @@ @method partial @for Ember.Templates.helpers @param {String} partialName The name of the template to render minus the leading underscore. + @deprecated Use a component instead @public */ diff --git a/packages/@ember/-internals/glimmer/lib/resolver.ts b/packages/@ember/-internals/glimmer/lib/resolver.ts index 89603e35e98..3df374f1ea8 100644 --- a/packages/@ember/-internals/glimmer/lib/resolver.ts +++ b/packages/@ember/-internals/glimmer/lib/resolver.ts @@ -1,13 +1,15 @@ import { privatize as P } from '@ember/-internals/container'; import { ENV } from '@ember/-internals/environment'; import { Factory, FactoryClass, LookupOptions, Owner } from '@ember/-internals/owner'; -import { lookupPartial, OwnedTemplateMeta } from '@ember/-internals/views'; +import { OwnedTemplateMeta } from '@ember/-internals/views'; import { EMBER_GLIMMER_SET_COMPONENT_TEMPLATE, EMBER_MODULE_UNIFICATION, } from '@ember/canary-features'; import { isTemplateOnlyComponent } from '@ember/component/template-only'; -import { assert } from '@ember/debug'; +import { assert, deprecate } from '@ember/debug'; +import { PARTIALS } from '@ember/deprecated-features'; +import EmberError from '@ember/error'; import { _instrumentStart } from '@ember/instrumentation'; import { ComponentDefinition, @@ -176,6 +178,62 @@ function lookupComponent(owner: Owner, name: string, options: LookupOptions): Op return lookupComponentPair(owner, name); } +let lookupPartial: { templateName: string; owner: Owner } | any; +let templateFor: { owner: Owner; underscored: string; name: string } | any; +let parseUnderscoredName: { templateName: string } | any; + +if (PARTIALS) { + lookupPartial = function(templateName: string, owner: Owner) { + deprecate( + `The use of \`{{partial}}\` is deprecated, please refactor the "${templateName}" partial to a component`, + false, + { + id: 'ember-views.partial', + until: '4.0.0', + url: 'https://deprecations.emberjs.com/v3.x#toc_ember-views-partial', + } + ); + + if (templateName === null) { + return; + } + + let template = templateFor(owner, parseUnderscoredName(templateName), templateName); + + assert(`Unable to find partial with name "${templateName}"`, Boolean(template)); + + return template; + }; + + templateFor = function(owner: any, underscored: string, name: string) { + if (PARTIALS) { + if (!name) { + return; + } + assert(`templateNames are not allowed to contain periods: ${name}`, name.indexOf('.') === -1); + + if (!owner) { + throw new EmberError( + 'Container was not found when looking up a views template. ' + + 'This is most likely due to manually instantiating an Ember.View. ' + + 'See: http://git.io/EKPpnA' + ); + } + + return owner.lookup(`template:${underscored}`) || owner.lookup(`template:${name}`); + } + }; + + parseUnderscoredName = function(templateName: string) { + let nameParts = templateName.split('/'); + let lastPart = nameParts[nameParts.length - 1]; + + nameParts[nameParts.length - 1] = `_${lastPart}`; + + return nameParts.join('/'); + }; +} + interface IBuiltInHelpers { [name: string]: Helper | undefined; } @@ -306,8 +364,12 @@ export default class RuntimeResolver implements IRuntimeResolver { - let partial = this._lookupPartial(name, meta); - return this.handle(partial); + if (PARTIALS) { + let partial = this._lookupPartial(name, meta); + return this.handle(partial); + } else { + return null; + } } // end CompileTimeLookup diff --git a/packages/@ember/-internals/glimmer/tests/integration/application/engine-test.js b/packages/@ember/-internals/glimmer/tests/integration/application/engine-test.js index 297e955ca02..b9e95a4c745 100644 --- a/packages/@ember/-internals/glimmer/tests/integration/application/engine-test.js +++ b/packages/@ember/-internals/glimmer/tests/integration/application/engine-test.js @@ -251,6 +251,10 @@ moduleFor( } ['@test attrs in an engine']() { + expectDeprecation( + `The use of \`{{partial}}\` is deprecated, please refactor the "troll" partial to a component` + ); + this.setupEngineWithAttrs([]); return this.visit('/').then(() => { @@ -431,7 +435,11 @@ moduleFor( } ['@test visit() with partials in routable engine'](assert) { - assert.expect(2); + assert.expect(3); + + expectDeprecation( + `The use of \`{{partial}}\` is deprecated, please refactor the "foo" partial to a component` + ); let hooks = []; @@ -449,7 +457,11 @@ moduleFor( } ['@test visit() with partials in non-routable engine'](assert) { - assert.expect(2); + assert.expect(3); + + expectDeprecation( + `The use of \`{{partial}}\` is deprecated, please refactor the "foo" partial to a component` + ); let hooks = []; diff --git a/packages/@ember/-internals/glimmer/tests/integration/components/curly-components-test.js b/packages/@ember/-internals/glimmer/tests/integration/components/curly-components-test.js index b69dddea30b..ac6d85cf2f5 100644 --- a/packages/@ember/-internals/glimmer/tests/integration/components/curly-components-test.js +++ b/packages/@ember/-internals/glimmer/tests/integration/components/curly-components-test.js @@ -760,7 +760,9 @@ moduleFor( template: '{{partial "partialWithYield"}} - In component', }); - this.render('{{#foo-bar}}hello{{/foo-bar}}'); + expectDeprecation(() => { + this.render('{{#foo-bar}}hello{{/foo-bar}}'); + }, 'The use of `{{partial}}` is deprecated, please refactor the "partialWithYield" partial to a component'); this.assertComponentElement(this.firstChild, { content: 'yielded: [hello] - In component', @@ -780,7 +782,9 @@ moduleFor( template: '{{partial "partialWithYield"}} - In component', }); - this.render('{{#foo-bar as |value|}}{{value}}{{/foo-bar}}'); + expectDeprecation(() => { + this.render('{{#foo-bar as |value|}}{{value}}{{/foo-bar}}'); + }, 'The use of `{{partial}}` is deprecated, please refactor the "partialWithYield" partial to a component'); this.assertComponentElement(this.firstChild, { content: 'yielded: [hello] - In component', diff --git a/packages/@ember/-internals/glimmer/tests/integration/helpers/partial-test.js b/packages/@ember/-internals/glimmer/tests/integration/helpers/partial-test.js index 8b114820988..54bc7ddb247 100644 --- a/packages/@ember/-internals/glimmer/tests/integration/helpers/partial-test.js +++ b/packages/@ember/-internals/glimmer/tests/integration/helpers/partial-test.js @@ -9,7 +9,9 @@ moduleFor( ['@test should render other templates registered with the container']() { this.registerPartial('_subTemplateFromContainer', 'sub-template'); - this.render(`This {{partial "subTemplateFromContainer"}} is pretty great.`); + expectDeprecation(() => { + this.render(`This {{partial "subTemplateFromContainer"}} is pretty great.`); + }, 'The use of `{{partial}}` is deprecated, please refactor the "subTemplateFromContainer" partial to a component'); this.assertStableRerender(); @@ -19,7 +21,9 @@ moduleFor( ['@test should render other slash-separated templates registered with the container']() { this.registerPartial('child/_subTemplateFromContainer', 'sub-template'); - this.render(`This {{partial "child/subTemplateFromContainer"}} is pretty great.`); + expectDeprecation(() => { + this.render(`This {{partial "child/subTemplateFromContainer"}} is pretty great.`); + }, 'The use of `{{partial}}` is deprecated, please refactor the "child/subTemplateFromContainer" partial to a component'); this.assertStableRerender(); @@ -29,12 +33,14 @@ moduleFor( ['@test should use the current context']() { this.registerPartial('_person_name', '{{this.model.firstName}} {{this.model.lastName}}'); - this.render('Who is {{partial "person_name"}}?', { - model: { - firstName: 'Kris', - lastName: 'Selden', - }, - }); + expectDeprecation(() => { + this.render('Who is {{partial "person_name"}}?', { + model: { + firstName: 'Kris', + lastName: 'Selden', + }, + }); + }, 'The use of `{{partial}}` is deprecated, please refactor the "person_name" partial to a component'); this.assertStableRerender(); @@ -53,18 +59,22 @@ moduleFor( this.registerPartial('_subTemplate', 'sub-template'); this.registerPartial('_otherTemplate', 'other-template'); - this.render( - 'This {{partial templates.partialName}} is pretty {{partial nonexistent}}great.', - { - templates: { partialName: 'subTemplate' }, - } - ); + expectDeprecation(() => { + this.render( + 'This {{partial templates.partialName}} is pretty {{partial nonexistent}}great.', + { + templates: { partialName: 'subTemplate' }, + } + ); + }, 'The use of `{{partial}}` is deprecated, please refactor the "subTemplate" partial to a component'); this.assertStableRerender(); this.assertText('This sub-template is pretty great.'); - runTask(() => set(this.context, 'templates.partialName', 'otherTemplate')); + expectDeprecation(() => { + runTask(() => set(this.context, 'templates.partialName', 'otherTemplate')); + }, 'The use of `{{partial}}` is deprecated, please refactor the "otherTemplate" partial to a component'); this.assertText('This other-template is pretty great.'); @@ -72,31 +82,37 @@ moduleFor( this.assertText('This is pretty great.'); - runTask(() => set(this.context, 'templates', { partialName: 'subTemplate' })); + expectDeprecation(() => { + runTask(() => set(this.context, 'templates', { partialName: 'subTemplate' })); + }, 'The use of `{{partial}}` is deprecated, please refactor the "subTemplate" partial to a component'); this.assertText('This sub-template is pretty great.'); } - ['@test partial using data from {{#each}}']() { + ['@test 1234 partial using data from {{#each}}']() { this.registerPartial('show-item', '{{item}}'); - this.render( - strip` - {{#each this.model.items as |item|}} - {{item}}: {{partial 'show-item'}} | - {{/each}}`, - { - model: { - items: emberA(['apple', 'orange', 'banana']), - }, - } - ); + expectDeprecation(() => { + this.render( + strip` + {{#each this.model.items as |item|}} + {{item}}: {{partial 'show-item'}} | + {{/each}}`, + { + model: { + items: emberA(['apple', 'orange', 'banana']), + }, + } + ); + }, 'The use of `{{partial}}` is deprecated, please refactor the "show-item" partial to a component'); this.assertStableRerender(); this.assertText('apple: apple |orange: orange |banana: banana |'); - runTask(() => this.context.model.items.pushObject('strawberry')); + expectDeprecation(() => { + runTask(() => this.context.model.items.pushObject('strawberry')); + }, 'The use of `{{partial}}` is deprecated, please refactor the "show-item" partial to a component'); this.assertText('apple: apple |orange: orange |banana: banana |strawberry: strawberry |'); @@ -112,15 +128,17 @@ moduleFor( ['@test partial using `{{get` on data from {{#with}}']() { this.registerPartial('show-id', '{{get item "id"}}'); - this.render( - strip` - {{#with this.model as |item|}} - {{item.name}}: {{partial 'show-id'}} - {{/with}}`, - { - model: { id: 1, name: 'foo' }, - } - ); + expectDeprecation(() => { + this.render( + strip` + {{#with this.model as |item|}} + {{item.name}}: {{partial 'show-id'}} + {{/with}}`, + { + model: { id: 1, name: 'foo' }, + } + ); + }, 'The use of `{{partial}}` is deprecated, please refactor the "show-id" partial to a component'); this.assertStableRerender(); @@ -142,25 +160,31 @@ moduleFor( ['@test partial using `{{get` on data from {{#each}}']() { this.registerPartial('show-item', '{{get item "id"}}'); - this.render( - strip` - {{#each items as |item|}} - {{item.id}}: {{partial 'show-item'}} | - {{/each}}`, - { - items: emberA([{ id: 1 }, { id: 2 }, { id: 3 }]), - } - ); + expectDeprecation(() => { + this.render( + strip` + {{#each items as |item|}} + {{item.id}}: {{partial 'show-item'}} | + {{/each}}`, + { + items: emberA([{ id: 1 }, { id: 2 }, { id: 3 }]), + } + ); + }, 'The use of `{{partial}}` is deprecated, please refactor the "show-item" partial to a component'); this.assertStableRerender(); this.assertText('1: 1 |2: 2 |3: 3 |'); - runTask(() => this.context.items.pushObject({ id: 4 })); + expectDeprecation(() => { + runTask(() => this.context.items.pushObject({ id: 4 })); + }, 'The use of `{{partial}}` is deprecated, please refactor the "show-item" partial to a component'); this.assertText('1: 1 |2: 2 |3: 3 |4: 4 |'); - runTask(() => set(this.context, 'items', emberA([{ id: 1 }, { id: 2 }, { id: 3 }]))); + expectDeprecation(() => { + runTask(() => set(this.context, 'items', emberA([{ id: 1 }, { id: 2 }, { id: 3 }]))); + }, 'The use of `{{partial}}` is deprecated, please refactor the "show-item" partial to a component'); this.assertText('1: 1 |2: 2 |3: 3 |'); } @@ -168,21 +192,25 @@ moduleFor( ['@test partial using conditional on data from {{#each}}']() { this.registerPartial('show-item', '{{#if item}}{{item}}{{/if}}'); - this.render( - strip` - {{#each items as |item|}} - {{item}}: {{partial 'show-item'}} | - {{/each}}`, - { - items: emberA(['apple', null, 'orange', 'banana']), - } - ); + expectDeprecation(() => { + this.render( + strip` + {{#each items as |item|}} + {{item}}: {{partial 'show-item'}} | + {{/each}}`, + { + items: emberA(['apple', null, 'orange', 'banana']), + } + ); + }, 'The use of `{{partial}}` is deprecated, please refactor the "show-item" partial to a component'); this.assertStableRerender(); this.assertText('apple: apple |: |orange: orange |banana: banana |'); - runTask(() => this.context.items.pushObject('strawberry')); + expectDeprecation(() => { + runTask(() => this.context.items.pushObject('strawberry')); + }, 'The use of `{{partial}}` is deprecated, please refactor the "show-item" partial to a component'); this.assertText('apple: apple |: |orange: orange |banana: banana |strawberry: strawberry |'); @@ -201,21 +229,25 @@ moduleFor( this.registerPartial('inner-partial', '[inner: {{name}}]'); - this.render( - strip` - {{#each names as |name i|}} - {{i}}: {{partial 'outer-partial'}} - {{/each}}`, - { - names: emberA(['Alex', 'Ben']), - } - ); + expectDeprecation(() => { + this.render( + strip` + {{#each names as |name i|}} + {{i}}: {{partial 'outer-partial'}} + {{/each}}`, + { + names: emberA(['Alex', 'Ben']), + } + ); + }, 'The use of `{{partial}}` is deprecated, please refactor the "outer-partial" partial to a component'); this.assertStableRerender(); this.assertText('0: [outer: Alex] [inner: Alex]1: [outer: Ben] [inner: Ben]'); - runTask(() => this.context.names.pushObject('Sophie')); + expectDeprecation(() => { + runTask(() => this.context.names.pushObject('Sophie')); + }, 'The use of `{{partial}}` is deprecated, please refactor the "outer-partial" partial to a component'); this.assertText( '0: [outer: Alex] [inner: Alex]1: [outer: Ben] [inner: Ben]2: [outer: Sophie] [inner: Sophie]' @@ -254,13 +286,15 @@ moduleFor( ` ); - this.render( - strip` - {{#with 'Sophie' as |person1|}} - Hi {{person1}} (aged {{age}}). {{partial 'person2-partial'}} - {{/with}}`, - { age: 0 } - ); + expectDeprecation(() => { + this.render( + strip` + {{#with 'Sophie' as |person1|}} + Hi {{person1}} (aged {{age}}). {{partial 'person2-partial'}} + {{/with}}`, + { age: 0 } + ); + }, 'The use of `{{partial}}` is deprecated, please refactor the "person2-partial" partial to a component'); this.assertStableRerender(); @@ -285,18 +319,20 @@ moduleFor( this.registerPartial('_odd', 'ODD{{i}}'); this.registerPartial('_even', 'EVEN{{i}}'); - this.render( - strip` - {{#each this.model.items as |template i|}} - {{this.model.type}}: {{partial template}} - {{/each}}`, - { - model: { - items: ['even', 'odd', 'even', 'odd'], - type: 'number', - }, - } - ); + expectDeprecation(() => { + this.render( + strip` + {{#each this.model.items as |template i|}} + {{this.model.type}}: {{partial template}} + {{/each}}`, + { + model: { + items: ['even', 'odd', 'even', 'odd'], + type: 'number', + }, + } + ); + }, 'The use of `{{partial}}` is deprecated, please refactor the "odd" partial to a component'); this.assertStableRerender(); @@ -335,7 +371,9 @@ moduleFor( this.assertText('Nothing!'); - runTask(() => set(this.context, 'item.thing', 'thing')); + expectDeprecation(() => { + runTask(() => set(this.context, 'item.thing', 'thing')); + }, 'The use of `{{partial}}` is deprecated, please refactor the "thing" partial to a component'); this.assertText('thing'); @@ -362,13 +400,15 @@ moduleFor( ` ); - this.render( - strip` - {{#outer-component name=name as |outer|}} - {{partial 'some-partial'}} - {{/outer-component}}`, - { name: 'Sophie' } - ); + expectDeprecation(() => { + this.render( + strip` + {{#outer-component name=name as |outer|}} + {{partial 'some-partial'}} + {{/outer-component}}`, + { name: 'Sophie' } + ); + }, 'The use of `{{partial}}` is deprecated, please refactor the "some-partial" partial to a component'); this.assertStableRerender(); diff --git a/packages/@ember/-internals/views/index.d.ts b/packages/@ember/-internals/views/index.d.ts index 079c0f6e758..143017ca5ae 100644 --- a/packages/@ember/-internals/views/index.d.ts +++ b/packages/@ember/-internals/views/index.d.ts @@ -35,10 +35,6 @@ export function isSimpleClick(event: Event): boolean; export function constructStyleDeprecationMessage(affectedStyle: any): string; -export function hasPartial(name: string, owner: any): boolean; - -export function lookupPartial(templateName: string, owner: Owner): TemplateFactory; - export function getViewId(view: any): string; export const MUTABLE_CELL: string; diff --git a/packages/@ember/-internals/views/index.js b/packages/@ember/-internals/views/index.js index 7b14200d9be..6224d9e17bf 100644 --- a/packages/@ember/-internals/views/index.js +++ b/packages/@ember/-internals/views/index.js @@ -26,5 +26,4 @@ export { default as ViewStateSupport } from './lib/mixins/view_state_support'; export { default as ViewMixin } from './lib/mixins/view_support'; export { default as ActionSupport } from './lib/mixins/action_support'; export { MUTABLE_CELL } from './lib/compat/attrs'; -export { default as lookupPartial, hasPartial } from './lib/system/lookup_partial'; export { default as ActionManager } from './lib/system/action_manager'; diff --git a/packages/@ember/-internals/views/lib/system/lookup_partial.js b/packages/@ember/-internals/views/lib/system/lookup_partial.js deleted file mode 100644 index c02c6668321..00000000000 --- a/packages/@ember/-internals/views/lib/system/lookup_partial.js +++ /dev/null @@ -1,55 +0,0 @@ -import { assert } from '@ember/debug'; -import EmberError from '@ember/error'; - -function parseUnderscoredName(templateName) { - let nameParts = templateName.split('/'); - let lastPart = nameParts[nameParts.length - 1]; - - nameParts[nameParts.length - 1] = `_${lastPart}`; - - return nameParts.join('/'); -} - -export default function lookupPartial(templateName, owner) { - if (templateName == null) { - return; - } - - let template = templateFor(owner, parseUnderscoredName(templateName), templateName); - - assert(`Unable to find partial with name "${templateName}"`, Boolean(template)); - - return template; -} - -export function hasPartial(name, owner) { - if (!owner) { - throw new EmberError( - 'Container was not found when looking up a views template. ' + - 'This is most likely due to manually instantiating an Ember.View. ' + - 'See: http://git.io/EKPpnA' - ); - } - - return ( - owner.hasRegistration(`template:${parseUnderscoredName(name)}`) || - owner.hasRegistration(`template:${name}`) - ); -} - -function templateFor(owner, underscored, name) { - if (!name) { - return; - } - assert(`templateNames are not allowed to contain periods: ${name}`, name.indexOf('.') === -1); - - if (!owner) { - throw new EmberError( - 'Container was not found when looking up a views template. ' + - 'This is most likely due to manually instantiating an Ember.View. ' + - 'See: http://git.io/EKPpnA' - ); - } - - return owner.lookup(`template:${underscored}`) || owner.lookup(`template:${name}`); -} diff --git a/packages/@ember/deprecated-features/index.ts b/packages/@ember/deprecated-features/index.ts index d49510de203..5f5e9cff49f 100644 --- a/packages/@ember/deprecated-features/index.ts +++ b/packages/@ember/deprecated-features/index.ts @@ -15,3 +15,4 @@ export const APP_CTRL_ROUTER_PROPS = !!'3.10.0-beta.1'; export const FUNCTION_PROTOTYPE_EXTENSIONS = !!'3.11.0-beta.1'; export const MOUSE_ENTER_LEAVE_MOVE_EVENTS = !!'3.13.0-beta.1'; export const EMBER_COMPONENT_IS_VISIBLE = !!'3.15.0-beta.1'; +export const PARTIALS = !!'3.15.0-beta.1';