From b341648d255b62adfe5fb31c7569f2cccfa0968e Mon Sep 17 00:00:00 2001 From: Katie Gengler Date: Wed, 4 Jan 2023 17:46:59 -0500 Subject: [PATCH 1/3] Deprecate @ember/string when used from ember-source; point users to add the `@ember/string` addon - Duplicate a portion of @ember/string in @ember/-internals/string for internal use by ember-source without triggering deprecations --- .../glimmer/lib/helpers/-normalize-class.ts | 2 +- .../-internals/glimmer/lib/utils/bindings.ts | 2 +- packages/@ember/-internals/string/index.ts | 105 ++++++++++++++++++ .../-internals/string/tests/classify_test.js | 65 +++++++++++ .../-internals/string/tests/dasherize_test.js | 43 +++++++ .../@ember/debug/container-debug-adapter.ts | 2 +- packages/@ember/debug/data-adapter.ts | 2 +- .../@ember/object/tests/observable_test.js | 9 +- packages/@ember/string/index.ts | 32 ++++++ packages/@ember/string/tests/camelize_test.js | 4 +- .../@ember/string/tests/capitalize_test.js | 4 +- packages/@ember/string/tests/classify_test.js | 4 +- .../@ember/string/tests/dasherize_test.js | 4 +- .../@ember/string/tests/decamelize_test.js | 4 +- .../@ember/string/tests/underscore_test.js | 4 +- packages/@ember/string/tests/w_test.js | 4 +- .../ember/tests/routing/query_params_test.js | 2 +- .../router_service_test/urlFor_test.js | 5 +- 18 files changed, 277 insertions(+), 20 deletions(-) create mode 100644 packages/@ember/-internals/string/index.ts create mode 100644 packages/@ember/-internals/string/tests/classify_test.js create mode 100644 packages/@ember/-internals/string/tests/dasherize_test.js diff --git a/packages/@ember/-internals/glimmer/lib/helpers/-normalize-class.ts b/packages/@ember/-internals/glimmer/lib/helpers/-normalize-class.ts index 52b2989294b..5603e12c135 100644 --- a/packages/@ember/-internals/glimmer/lib/helpers/-normalize-class.ts +++ b/packages/@ember/-internals/glimmer/lib/helpers/-normalize-class.ts @@ -1,5 +1,5 @@ import { assert } from '@ember/debug'; -import { dasherize } from '@ember/string'; +import { dasherize } from '@ember/-internals/string'; import type { CapturedArguments } from '@glimmer/interfaces'; import { createComputeRef, valueForRef } from '@glimmer/reference'; import { internalHelper } from './internal-helper'; diff --git a/packages/@ember/-internals/glimmer/lib/utils/bindings.ts b/packages/@ember/-internals/glimmer/lib/utils/bindings.ts index 26069564072..aa04023b570 100644 --- a/packages/@ember/-internals/glimmer/lib/utils/bindings.ts +++ b/packages/@ember/-internals/glimmer/lib/utils/bindings.ts @@ -1,6 +1,6 @@ import { get } from '@ember/-internals/metal'; import { assert } from '@ember/debug'; -import { dasherize } from '@ember/string'; +import { dasherize } from '@ember/-internals/string'; import type { ElementOperations } from '@glimmer/interfaces'; import type { Reference } from '@glimmer/reference'; import { diff --git a/packages/@ember/-internals/string/index.ts b/packages/@ember/-internals/string/index.ts new file mode 100644 index 00000000000..e2e2591b6b4 --- /dev/null +++ b/packages/@ember/-internals/string/index.ts @@ -0,0 +1,105 @@ +/* + This module exists to separate the @ember/string methods used + internally in ember-source, from those public methods that are + now deprecated and to be removed. +*/ + +import { Cache } from '@ember/-internals/utils'; + +const STRING_DASHERIZE_REGEXP = /[ _]/g; + +const STRING_DASHERIZE_CACHE = new Cache(1000, (key) => + decamelize(key).replace(STRING_DASHERIZE_REGEXP, '-') +); + +const STRING_CLASSIFY_REGEXP_1 = /^(-|_)+(.)?/; +const STRING_CLASSIFY_REGEXP_2 = /(.)(-|_|\.|\s)+(.)?/g; +const STRING_CLASSIFY_REGEXP_3 = /(^|\/|\.)([a-z])/g; + +const CLASSIFY_CACHE = new Cache(1000, (str) => { + let replace1 = (_match: string, _separator: string, chr: string) => + chr ? `_${chr.toUpperCase()}` : ''; + let replace2 = (_match: string, initialChar: string, _separator: string, chr: string) => + initialChar + (chr ? chr.toUpperCase() : ''); + let parts = str.split('/'); + for (let i = 0; i < parts.length; i++) { + parts[i] = parts[i]!.replace(STRING_CLASSIFY_REGEXP_1, replace1).replace( + STRING_CLASSIFY_REGEXP_2, + replace2 + ); + } + return parts + .join('/') + .replace(STRING_CLASSIFY_REGEXP_3, (match /*, separator, chr */) => match.toUpperCase()); +}); + +const STRING_DECAMELIZE_REGEXP = /([a-z\d])([A-Z])/g; + +const DECAMELIZE_CACHE = new Cache(1000, (str) => + str.replace(STRING_DECAMELIZE_REGEXP, '$1_$2').toLowerCase() +); + +/** + Defines string helper methods used internally in ember-source. + + @class String + @private + */ + +/** + Replaces underscores, spaces, or camelCase with dashes. + + ```javascript + import { dasherize } from '@ember/-internals/string'; + + dasherize('innerHTML'); // 'inner-html' + dasherize('action_name'); // 'action-name' + dasherize('css-class-name'); // 'css-class-name' + dasherize('my favorite items'); // 'my-favorite-items' + dasherize('privateDocs/ownerInvoice'; // 'private-docs/owner-invoice' + ``` + + @method dasherize + @param {String} str The string to dasherize. + @return {String} the dasherized string. + @private + */ +export function dasherize(str: string): string { + return STRING_DASHERIZE_CACHE.get(str); +} + +/** + Returns the UpperCamelCase form of a string. + + ```javascript + import { classify } from '@ember/string'; + + classify('innerHTML'); // 'InnerHTML' + classify('action_name'); // 'ActionName' + classify('css-class-name'); // 'CssClassName' + classify('my favorite items'); // 'MyFavoriteItems' + classify('private-docs/owner-invoice'); // 'PrivateDocs/OwnerInvoice' + ``` + + @method classify + @param {String} str the string to classify + @return {String} the classified string + @private + */ +export function classify(str: string): string { + return CLASSIFY_CACHE.get(str); +} + +/** + Converts a camelized string into all lower case separated by underscores. + + ```javascript + decamelize('innerHTML'); // 'inner_html' + decamelize('action_name'); // 'action_name' + decamelize('css-class-name'); // 'css-class-name' + decamelize('my favorite items'); // 'my favorite items' + ``` + */ +function decamelize(str: string): string { + return DECAMELIZE_CACHE.get(str); +} diff --git a/packages/@ember/-internals/string/tests/classify_test.js b/packages/@ember/-internals/string/tests/classify_test.js new file mode 100644 index 00000000000..a167dbfcbcb --- /dev/null +++ b/packages/@ember/-internals/string/tests/classify_test.js @@ -0,0 +1,65 @@ +/* eslint-disable qunit/no-test-expect-argument */ +import { classify } from '@ember/-internals/string'; +import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; + +function test(assert, given, expected, description) { + assert.deepEqual(classify(given), expected, description); +} + +moduleFor( + 'EmberInternalsString.classify', + class extends AbstractTestCase { + ['@test String classify tests'](assert) { + test(assert, 'my favorite items', 'MyFavoriteItems', 'classify normal string'); + test(assert, 'css-class-name', 'CssClassName', 'classify dasherized string'); + test(assert, 'action_name', 'ActionName', 'classify underscored string'); + test( + assert, + 'privateDocs/ownerInvoice', + 'PrivateDocs/OwnerInvoice', + 'classify namespaced camelized string' + ); + test( + assert, + 'private_docs/owner_invoice', + 'PrivateDocs/OwnerInvoice', + 'classify namespaced underscored string' + ); + test( + assert, + 'private-docs/owner-invoice', + 'PrivateDocs/OwnerInvoice', + 'classify namespaced dasherized string' + ); + test(assert, '-view-registry', '_ViewRegistry', 'classify prefixed dasherized string'); + test( + assert, + 'components/-text-field', + 'Components/_TextField', + 'classify namespaced prefixed dasherized string' + ); + test(assert, '_Foo_Bar', '_FooBar', 'classify underscore-prefixed underscored string'); + test(assert, '_Foo-Bar', '_FooBar', 'classify underscore-prefixed dasherized string'); + test( + assert, + '_foo/_bar', + '_Foo/_Bar', + 'classify underscore-prefixed-namespaced underscore-prefixed string' + ); + test( + assert, + '-foo/_bar', + '_Foo/_Bar', + 'classify dash-prefixed-namespaced underscore-prefixed string' + ); + test( + assert, + '-foo/-bar', + '_Foo/_Bar', + 'classify dash-prefixed-namespaced dash-prefixed string' + ); + test(assert, 'InnerHTML', 'InnerHTML', 'does nothing with classified string'); + test(assert, '_FooBar', '_FooBar', 'does nothing with classified prefixed string'); + } + } +); diff --git a/packages/@ember/-internals/string/tests/dasherize_test.js b/packages/@ember/-internals/string/tests/dasherize_test.js new file mode 100644 index 00000000000..090cb1b429d --- /dev/null +++ b/packages/@ember/-internals/string/tests/dasherize_test.js @@ -0,0 +1,43 @@ +/* eslint-disable qunit/no-test-expect-argument */ +import { dasherize } from '@ember/-internals/string'; +import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; + +function test(assert, given, expected, description) { + assert.deepEqual(dasherize(given), expected, description); +} + +moduleFor( + 'EmberInternalsString.dasherize', + class extends AbstractTestCase { + ['@test String dasherize tests'](assert) { + test(assert, 'my favorite items', 'my-favorite-items', 'dasherize normal string'); + test(assert, 'css-class-name', 'css-class-name', 'does nothing with dasherized string'); + test(assert, 'action_name', 'action-name', 'dasherize underscored string'); + test(assert, 'innerHTML', 'inner-html', 'dasherize camelcased string'); + test( + assert, + 'toString', + 'to-string', + 'dasherize string that is the property name of Object.prototype' + ); + test( + assert, + 'PrivateDocs/OwnerInvoice', + 'private-docs/owner-invoice', + 'dasherize namespaced classified string' + ); + test( + assert, + 'privateDocs/ownerInvoice', + 'private-docs/owner-invoice', + 'dasherize namespaced camelized string' + ); + test( + assert, + 'private_docs/owner_invoice', + 'private-docs/owner-invoice', + 'dasherize namespaced underscored string' + ); + } + } +); diff --git a/packages/@ember/debug/container-debug-adapter.ts b/packages/@ember/debug/container-debug-adapter.ts index 88e0b08c819..e62fcb0ed7b 100644 --- a/packages/@ember/debug/container-debug-adapter.ts +++ b/packages/@ember/debug/container-debug-adapter.ts @@ -1,4 +1,4 @@ -import { classify, dasherize } from '@ember/string'; +import { classify, dasherize } from '@ember/-internals/string'; import EmberObject from '@ember/object'; import { typeOf } from '@ember/utils'; import type Owner from '@ember/owner'; diff --git a/packages/@ember/debug/data-adapter.ts b/packages/@ember/debug/data-adapter.ts index 48a48d5d3a8..c8d4af0a1f9 100644 --- a/packages/@ember/debug/data-adapter.ts +++ b/packages/@ember/debug/data-adapter.ts @@ -2,7 +2,7 @@ import type Owner from '@ember/owner'; import { getOwner } from '@ember/-internals/owner'; import { _backburner, next } from '@ember/runloop'; import { get } from '@ember/object'; -import { dasherize } from '@ember/string'; +import { dasherize } from '@ember/-internals/string'; import Namespace from '@ember/application/namespace'; import type { NativeArray } from '@ember/array'; import EmberObject from '@ember/object'; diff --git a/packages/@ember/object/tests/observable_test.js b/packages/@ember/object/tests/observable_test.js index a000ec06e9e..c23f55dd650 100644 --- a/packages/@ember/object/tests/observable_test.js +++ b/packages/@ember/object/tests/observable_test.js @@ -1,7 +1,6 @@ import { context } from '@ember/-internals/environment'; import { run } from '@ember/runloop'; import { get, computed } from '@ember/object'; -import { w } from '@ember/string'; import EmberObject, { observer } from '@ember/object'; import Observable from '@ember/object/observable'; import { A as emberA } from '@ember/array'; @@ -359,7 +358,7 @@ moduleFor( ['@test getting values should call function return value'](assert) { // get each property twice. Verify return. - let keys = w('computed dependent'); + let keys = ['computed', 'dependent']; keys.forEach(function (key) { assert.equal(object.get(key), key, `Try #1: object.get(${key}) should run function`); @@ -367,15 +366,15 @@ moduleFor( }); // verify each call count. cached should only be called once - w('computedCalls dependentCalls').forEach((key) => { + ['computedCalls', 'dependentCalls'].forEach((key) => { assert.equal(object[key].length, 1, `non-cached property ${key} should be called 1x`); }); } ['@test setting values should call function return value'](assert) { // get each property twice. Verify return. - let keys = w('computed dependent'); - let values = w('value1 value2'); + let keys = ['computed', 'dependent']; + let values = ['value1', 'value2']; keys.forEach((key) => { assert.equal( diff --git a/packages/@ember/string/index.ts b/packages/@ember/string/index.ts index d96d1604eae..7f845c66a95 100644 --- a/packages/@ember/string/index.ts +++ b/packages/@ember/string/index.ts @@ -76,6 +76,7 @@ const DECAMELIZE_CACHE = new Cache(1000, (str) => @class String @public + @deprecated Add the package `@ember/string` to your project to use in place of this module. */ /** @@ -98,8 +99,10 @@ const DECAMELIZE_CACHE = new Cache(1000, (str) => @param {String} str The string to split @return {Array} array containing the split strings @public + @deprecated Add `@ember/string` to your package.json */ export function w(str: string): string[] { + deprecateImportFromInternalString(); return str.split(/\s+/); } @@ -119,8 +122,10 @@ export function w(str: string): string[] { @param {String} str The string to decamelize. @return {String} the decamelized string. @public + @deprecated Add `@ember/string` to your package.json */ export function decamelize(str: string): string { + deprecateImportFromInternalString(); return DECAMELIZE_CACHE.get(str); } @@ -141,8 +146,10 @@ export function decamelize(str: string): string { @param {String} str The string to dasherize. @return {String} the dasherized string. @public + @deprecated Add `@ember/string` to your package.json */ export function dasherize(str: string): string { + deprecateImportFromInternalString(); return STRING_DASHERIZE_CACHE.get(str); } @@ -164,8 +171,10 @@ export function dasherize(str: string): string { @param {String} str The string to camelize. @return {String} the camelized string. @public + @deprecated Add `@ember/string` to your package.json */ export function camelize(str: string): string { + deprecateImportFromInternalString(); return CAMELIZE_CACHE.get(str); } @@ -186,8 +195,10 @@ export function camelize(str: string): string { @param {String} str the string to classify @return {String} the classified string @public + @deprecated Add `@ember/string` to your package.json */ export function classify(str: string): string { + deprecateImportFromInternalString(); return CLASSIFY_CACHE.get(str); } @@ -209,8 +220,10 @@ export function classify(str: string): string { @param {String} str The string to underscore. @return {String} the underscored string. @public + @deprecated Add `@ember/string` to your package.json */ export function underscore(str: string): string { + deprecateImportFromInternalString(); return UNDERSCORE_CACHE.get(str); } @@ -231,11 +244,30 @@ export function underscore(str: string): string { @param {String} str The string to capitalize. @return {String} The capitalized string. @public + @deprecated Add `@ember/string` to your package.json */ export function capitalize(str: string): string { + deprecateImportFromInternalString(); return CAPITALIZE_CACHE.get(str); } +function deprecateImportFromInternalString() { + deprecate( + 'Importing from `@ember/string` without having the `@ember/string` package in your project is deprecated. Please add `@ember/string` to your `package.json', + false, + { + id: 'ember-string.add-package', + for: 'ember-source', + since: { + available: '4.10', + enabled: '4.10', + }, + until: '5.0.0', + url: 'https://deprecations.emberjs.com/v4.x/#toc_ember-string-add-package', + } + ); +} + function deprecateImportFromString( name: string, message = `Importing ${name} from '@ember/string' is deprecated. Please import ${name} from '@ember/template' instead.` diff --git a/packages/@ember/string/tests/camelize_test.js b/packages/@ember/string/tests/camelize_test.js index 1cb053fa798..c579be15ead 100644 --- a/packages/@ember/string/tests/camelize_test.js +++ b/packages/@ember/string/tests/camelize_test.js @@ -3,7 +3,9 @@ import { camelize } from '@ember/string'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; function test(assert, given, expected, description) { - assert.deepEqual(camelize(given), expected, description); + expectDeprecation(() => { + assert.deepEqual(camelize(given), expected, description); + }, 'Importing from `@ember/string` without having the `@ember/string` package in your project is deprecated. Please add `@ember/string` to your `package.json'); } moduleFor( diff --git a/packages/@ember/string/tests/capitalize_test.js b/packages/@ember/string/tests/capitalize_test.js index 7b11679722a..4fc1e757bc4 100644 --- a/packages/@ember/string/tests/capitalize_test.js +++ b/packages/@ember/string/tests/capitalize_test.js @@ -3,7 +3,9 @@ import { capitalize } from '@ember/string'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; function test(assert, given, expected, description) { - assert.deepEqual(capitalize(given), expected, description); + expectDeprecation(() => { + assert.deepEqual(capitalize(given), expected, description); + }, 'Importing from `@ember/string` without having the `@ember/string` package in your project is deprecated. Please add `@ember/string` to your `package.json'); } moduleFor( diff --git a/packages/@ember/string/tests/classify_test.js b/packages/@ember/string/tests/classify_test.js index 5232ccbf8c5..13dca64b245 100644 --- a/packages/@ember/string/tests/classify_test.js +++ b/packages/@ember/string/tests/classify_test.js @@ -3,7 +3,9 @@ import { classify } from '@ember/string'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; function test(assert, given, expected, description) { - assert.deepEqual(classify(given), expected, description); + expectDeprecation(() => { + assert.deepEqual(classify(given), expected, description); + }, 'Importing from `@ember/string` without having the `@ember/string` package in your project is deprecated. Please add `@ember/string` to your `package.json'); } moduleFor( diff --git a/packages/@ember/string/tests/dasherize_test.js b/packages/@ember/string/tests/dasherize_test.js index 9f41db6957b..98fb5a5dcf1 100644 --- a/packages/@ember/string/tests/dasherize_test.js +++ b/packages/@ember/string/tests/dasherize_test.js @@ -3,7 +3,9 @@ import { dasherize } from '@ember/string'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; function test(assert, given, expected, description) { - assert.deepEqual(dasherize(given), expected, description); + expectDeprecation(() => { + assert.deepEqual(dasherize(given), expected, description); + }, 'Importing from `@ember/string` without having the `@ember/string` package in your project is deprecated. Please add `@ember/string` to your `package.json'); } moduleFor( diff --git a/packages/@ember/string/tests/decamelize_test.js b/packages/@ember/string/tests/decamelize_test.js index f37af0c66a2..d5620398cd1 100644 --- a/packages/@ember/string/tests/decamelize_test.js +++ b/packages/@ember/string/tests/decamelize_test.js @@ -3,7 +3,9 @@ import { decamelize } from '@ember/string'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; function test(assert, given, expected, description) { - assert.deepEqual(decamelize(given), expected, description); + expectDeprecation(() => { + assert.deepEqual(decamelize(given), expected, description); + }, 'Importing from `@ember/string` without having the `@ember/string` package in your project is deprecated. Please add `@ember/string` to your `package.json'); } moduleFor( diff --git a/packages/@ember/string/tests/underscore_test.js b/packages/@ember/string/tests/underscore_test.js index 69a1b83b33b..11ea62ab652 100644 --- a/packages/@ember/string/tests/underscore_test.js +++ b/packages/@ember/string/tests/underscore_test.js @@ -3,7 +3,9 @@ import { underscore } from '@ember/string'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; function test(assert, given, expected, description) { - assert.deepEqual(underscore(given), expected, description); + expectDeprecation(() => { + assert.deepEqual(underscore(given), expected, description); + }, 'Importing from `@ember/string` without having the `@ember/string` package in your project is deprecated. Please add `@ember/string` to your `package.json'); } moduleFor( diff --git a/packages/@ember/string/tests/w_test.js b/packages/@ember/string/tests/w_test.js index e9fada90f2a..ae5dc9912bd 100644 --- a/packages/@ember/string/tests/w_test.js +++ b/packages/@ember/string/tests/w_test.js @@ -3,7 +3,9 @@ import { w } from '@ember/string'; import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; function test(assert, given, expected, description) { - assert.deepEqual(w(given), expected, description); + expectDeprecation(() => { + assert.deepEqual(w(given), expected, description); + }, 'Importing from `@ember/string` without having the `@ember/string` package in your project is deprecated. Please add `@ember/string` to your `package.json'); } moduleFor( diff --git a/packages/ember/tests/routing/query_params_test.js b/packages/ember/tests/routing/query_params_test.js index 618e4a4b6e4..3d213fcac5e 100644 --- a/packages/ember/tests/routing/query_params_test.js +++ b/packages/ember/tests/routing/query_params_test.js @@ -1,5 +1,5 @@ import Controller from '@ember/controller'; -import { dasherize } from '@ember/string'; +import { dasherize } from '@ember/-internals/string'; import EmberObject, { get, computed } from '@ember/object'; import { RSVP } from '@ember/-internals/runtime'; import { A as emberA } from '@ember/array'; diff --git a/packages/ember/tests/routing/router_service_test/urlFor_test.js b/packages/ember/tests/routing/router_service_test/urlFor_test.js index 8b091812e58..486709c2c5b 100644 --- a/packages/ember/tests/routing/router_service_test/urlFor_test.js +++ b/packages/ember/tests/routing/router_service_test/urlFor_test.js @@ -1,11 +1,10 @@ import Controller from '@ember/controller'; -import { capitalize } from '@ember/string'; import Route from '@ember/routing/route'; import { get } from '@ember/object'; import { RouterTestCase, moduleFor } from 'internal-test-helpers'; function setupController(app, name) { - let controllerName = `${capitalize(name)}Controller`; + let controllerName = `${name}Controller`; Object.defineProperty(app, controllerName, { get() { @@ -30,7 +29,7 @@ moduleFor( ['@test RouterService#urlFor returns URL for simple route with dynamic segments'](assert) { assert.expect(1); - setupController(this.application, 'dynamic'); + setupController(this.application, 'Dynamic'); let dynamicModel = { id: 1, contents: 'much dynamicism' }; From 0175865af03fdc48298816469914f26ac0641c9a Mon Sep 17 00:00:00 2001 From: Katie Gengler Date: Thu, 5 Jan 2023 14:05:32 -0500 Subject: [PATCH 2/3] Deprecate accessing @ember/string methods off of the Ember module --- packages/ember/index.ts | 61 +++++++++++++------------- packages/ember/tests/reexports_test.js | 34 ++++++++++---- 2 files changed, 56 insertions(+), 39 deletions(-) diff --git a/packages/ember/index.ts b/packages/ember/index.ts index 6403995abb5..16f9e3aeb1e 100644 --- a/packages/ember/index.ts +++ b/packages/ember/index.ts @@ -633,39 +633,40 @@ Object.defineProperty(Ember, 'TEMPLATES', { enumerable: false, }); -const deprecateImportFromString = function ( - name: string, - message = `Importing ${name} from '@ember/string' is deprecated. Please import ${name} from '@ember/template' instead.` -) { - deprecate(message, false, { - id: 'ember-string.htmlsafe-ishtmlsafe', - for: 'ember-source', - since: { - available: '4.10', - enabled: '4.10', - }, - until: '5.0.0', - url: 'https://deprecations.emberjs.com/v3.x/#toc_ember-string-htmlsafe-ishtmlsafe', - }); -}; -// NOTE: these are expressly *not* in the public API, because they were -// deprecated and removed. TODO: remove them after we land the TS conversion, -// and after confirming doing so is safe -- the state of the `@ember/string` -// conversion remains confused. -Object.defineProperty(Ember.String, 'htmlSafe', { - enumerable: true, - configurable: true, - get() { - deprecateImportFromString('htmlSafe'); - return htmlSafe; - }, -}); -Object.defineProperty(Ember.String, 'isHTMLSafe', { +function deprecateStringUseOnEmberModule() { + deprecate( + 'Using `Ember.String` is deprecated. Please import methods directly from `@ember/string`.', + false, + { + id: 'ember-string.from-ember-module', + for: 'ember-source', + since: { + available: '4.10', + enabled: '4.10.', + }, + until: '5.0.0', + url: 'https://deprecations.emberjs.com/v4.x/#toc_ember-string-from-ember-module', + } + ); +} + +Object.defineProperty(Ember, 'String', { enumerable: true, configurable: true, get() { - deprecateImportFromString('isHTMLSafe'); - return isHTMLSafe; + deprecateStringUseOnEmberModule(); + + return { + camelize, + capitalize, + classify, + dasherize, + decamelize, + underscore, + w, + htmlSafe, + isHTMLSafe, + }; }, }); diff --git a/packages/ember/tests/reexports_test.js b/packages/ember/tests/reexports_test.js index a7a98b15896..f9ebbb92a51 100644 --- a/packages/ember/tests/reexports_test.js +++ b/packages/ember/tests/reexports_test.js @@ -28,7 +28,7 @@ moduleFor( glimmer.htmlSafe, 'Ember.String.htmlSafe is exported correctly' ); - }, /Importing htmlSafe from '@ember\/string' is deprecated/); + }, 'Using `Ember.String` is deprecated. Please import methods directly from `@ember/string`.'); assert.notEqual(glimmer.htmlSafe, undefined, 'Ember.String.htmlSafe is not `undefined`'); } @@ -40,10 +40,33 @@ moduleFor( glimmer.isHTMLSafe, 'Ember.String.isHTMLSafe is exported correctly' ); - }, /Importing isHTMLSafe from '@ember\/string' is deprecated/); + }, 'Using `Ember.String` is deprecated. Please import methods directly from `@ember/string`.'); assert.notEqual(glimmer.isHTMLSafe, undefined, 'Ember.String.isHTMLSafe is not `undefined`'); } + ['@test Ember.String methods export correctly (but deprecated)'](assert) { + let string = require('@ember/string'); + let methods = [ + 'camelize', + 'capitalize', + 'classify', + 'dasherize', + 'decamelize', + 'underscore', + 'w', + ]; + methods.forEach((method) => { + expectDeprecation(() => { + assert.equal( + Ember.String[method], + string[method], + `Ember.String.${method} is exported correctly` + ); + }, 'Using `Ember.String` is deprecated. Please import methods directly from `@ember/string`.'); + assert.notEqual(string[method], undefined, `Ember.String.${method} is not \`undefined\``); + }); + } + '@test Ember.FEATURES is exported'(assert) { for (let feature in FEATURES) { assert.equal( @@ -255,13 +278,6 @@ let allExports = [ ['inject.service', '@ember/service', 'service'], // @ember/string - ['String.camelize', '@ember/string', 'camelize'], - ['String.capitalize', '@ember/string', 'capitalize'], - ['String.classify', '@ember/string', 'classify'], - ['String.dasherize', '@ember/string', 'dasherize'], - ['String.decamelize', '@ember/string', 'decamelize'], - ['String.underscore', '@ember/string', 'underscore'], - ['String.w', '@ember/string', 'w'], ['STRINGS', '@ember/string', { get: '_getStrings', set: '_setStrings' }], // @ember/template From e6a9f628d1396e92549dbdd13fb69d41c950d7d4 Mon Sep 17 00:00:00 2001 From: Katie Gengler Date: Thu, 5 Jan 2023 14:41:06 -0500 Subject: [PATCH 3/3] Deprecate Ember.STRINGS - Remove `getString` from string_registry, it was unused internally and not exposed publicly. --- packages/@ember/string/lib/string_registry.ts | 16 ++++++++++++++-- packages/ember/tests/reexports_test.js | 10 ++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/packages/@ember/string/lib/string_registry.ts b/packages/@ember/string/lib/string_registry.ts index 344d32f6224..114226a49ab 100644 --- a/packages/@ember/string/lib/string_registry.ts +++ b/packages/@ember/string/lib/string_registry.ts @@ -1,16 +1,28 @@ +import { deprecate } from '@ember/debug'; + // STATE within a module is frowned upon, this exists // to support Ember.STRINGS but shield ember internals from this legacy global // API. let STRINGS: { [key: string]: string } = {}; export function setStrings(strings: { [key: string]: string }) { + deprecateEmberStrings(); STRINGS = strings; } export function getStrings(): { [key: string]: string } { + deprecateEmberStrings(); return STRINGS; } -export function getString(name: string): string | undefined { - return STRINGS[name]; +function deprecateEmberStrings() { + deprecate('Ember.STRINGS is deprecated. It is no longer used by Ember.', false, { + id: 'ember-strings', + for: 'ember-source', + since: { + available: '4.10', + enabled: '4.10.', + }, + until: '5.0.0', + }); } diff --git a/packages/ember/tests/reexports_test.js b/packages/ember/tests/reexports_test.js index f9ebbb92a51..95a844c6a9d 100644 --- a/packages/ember/tests/reexports_test.js +++ b/packages/ember/tests/reexports_test.js @@ -67,6 +67,16 @@ moduleFor( }); } + ['@test Ember.STRINGS is deprecated'](assert) { + expectDeprecation(() => { + assert.ok(Ember.STRINGS); + }, 'Ember.STRINGS is deprecated. It is no longer used by Ember.'); + + expectDeprecation(() => { + Ember.STRINGS = {}; + }, 'Ember.STRINGS is deprecated. It is no longer used by Ember.'); + } + '@test Ember.FEATURES is exported'(assert) { for (let feature in FEATURES) { assert.equal(