Skip to content

Commit f1988a3

Browse files
committed
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 (cherry picked from commit b341648)
1 parent d58ac53 commit f1988a3

18 files changed

+277
-20
lines changed

packages/@ember/-internals/glimmer/lib/helpers/-normalize-class.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { assert } from '@ember/debug';
2-
import { dasherize } from '@ember/string';
2+
import { dasherize } from '@ember/-internals/string';
33
import type { CapturedArguments } from '@glimmer/interfaces';
44
import { createComputeRef, valueForRef } from '@glimmer/reference';
55
import { internalHelper } from './internal-helper';

packages/@ember/-internals/glimmer/lib/utils/bindings.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { get } from '@ember/-internals/metal';
22
import { assert } from '@ember/debug';
3-
import { dasherize } from '@ember/string';
3+
import { dasherize } from '@ember/-internals/string';
44
import type { ElementOperations } from '@glimmer/interfaces';
55
import type { Reference } from '@glimmer/reference';
66
import {
+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
This module exists to separate the @ember/string methods used
3+
internally in ember-source, from those public methods that are
4+
now deprecated and to be removed.
5+
*/
6+
7+
import { Cache } from '@ember/-internals/utils';
8+
9+
const STRING_DASHERIZE_REGEXP = /[ _]/g;
10+
11+
const STRING_DASHERIZE_CACHE = new Cache<string, string>(1000, (key) =>
12+
decamelize(key).replace(STRING_DASHERIZE_REGEXP, '-')
13+
);
14+
15+
const STRING_CLASSIFY_REGEXP_1 = /^(-|_)+(.)?/;
16+
const STRING_CLASSIFY_REGEXP_2 = /(.)(-|_|\.|\s)+(.)?/g;
17+
const STRING_CLASSIFY_REGEXP_3 = /(^|\/|\.)([a-z])/g;
18+
19+
const CLASSIFY_CACHE = new Cache<string, string>(1000, (str) => {
20+
let replace1 = (_match: string, _separator: string, chr: string) =>
21+
chr ? `_${chr.toUpperCase()}` : '';
22+
let replace2 = (_match: string, initialChar: string, _separator: string, chr: string) =>
23+
initialChar + (chr ? chr.toUpperCase() : '');
24+
let parts = str.split('/');
25+
for (let i = 0; i < parts.length; i++) {
26+
parts[i] = parts[i]!.replace(STRING_CLASSIFY_REGEXP_1, replace1).replace(
27+
STRING_CLASSIFY_REGEXP_2,
28+
replace2
29+
);
30+
}
31+
return parts
32+
.join('/')
33+
.replace(STRING_CLASSIFY_REGEXP_3, (match /*, separator, chr */) => match.toUpperCase());
34+
});
35+
36+
const STRING_DECAMELIZE_REGEXP = /([a-z\d])([A-Z])/g;
37+
38+
const DECAMELIZE_CACHE = new Cache<string, string>(1000, (str) =>
39+
str.replace(STRING_DECAMELIZE_REGEXP, '$1_$2').toLowerCase()
40+
);
41+
42+
/**
43+
Defines string helper methods used internally in ember-source.
44+
45+
@class String
46+
@private
47+
*/
48+
49+
/**
50+
Replaces underscores, spaces, or camelCase with dashes.
51+
52+
```javascript
53+
import { dasherize } from '@ember/-internals/string';
54+
55+
dasherize('innerHTML'); // 'inner-html'
56+
dasherize('action_name'); // 'action-name'
57+
dasherize('css-class-name'); // 'css-class-name'
58+
dasherize('my favorite items'); // 'my-favorite-items'
59+
dasherize('privateDocs/ownerInvoice'; // 'private-docs/owner-invoice'
60+
```
61+
62+
@method dasherize
63+
@param {String} str The string to dasherize.
64+
@return {String} the dasherized string.
65+
@private
66+
*/
67+
export function dasherize(str: string): string {
68+
return STRING_DASHERIZE_CACHE.get(str);
69+
}
70+
71+
/**
72+
Returns the UpperCamelCase form of a string.
73+
74+
```javascript
75+
import { classify } from '@ember/string';
76+
77+
classify('innerHTML'); // 'InnerHTML'
78+
classify('action_name'); // 'ActionName'
79+
classify('css-class-name'); // 'CssClassName'
80+
classify('my favorite items'); // 'MyFavoriteItems'
81+
classify('private-docs/owner-invoice'); // 'PrivateDocs/OwnerInvoice'
82+
```
83+
84+
@method classify
85+
@param {String} str the string to classify
86+
@return {String} the classified string
87+
@private
88+
*/
89+
export function classify(str: string): string {
90+
return CLASSIFY_CACHE.get(str);
91+
}
92+
93+
/**
94+
Converts a camelized string into all lower case separated by underscores.
95+
96+
```javascript
97+
decamelize('innerHTML'); // 'inner_html'
98+
decamelize('action_name'); // 'action_name'
99+
decamelize('css-class-name'); // 'css-class-name'
100+
decamelize('my favorite items'); // 'my favorite items'
101+
```
102+
*/
103+
function decamelize(str: string): string {
104+
return DECAMELIZE_CACHE.get(str);
105+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/* eslint-disable qunit/no-test-expect-argument */
2+
import { classify } from '@ember/-internals/string';
3+
import { moduleFor, AbstractTestCase } from 'internal-test-helpers';
4+
5+
function test(assert, given, expected, description) {
6+
assert.deepEqual(classify(given), expected, description);
7+
}
8+
9+
moduleFor(
10+
'EmberInternalsString.classify',
11+
class extends AbstractTestCase {
12+
['@test String classify tests'](assert) {
13+
test(assert, 'my favorite items', 'MyFavoriteItems', 'classify normal string');
14+
test(assert, 'css-class-name', 'CssClassName', 'classify dasherized string');
15+
test(assert, 'action_name', 'ActionName', 'classify underscored string');
16+
test(
17+
assert,
18+
'privateDocs/ownerInvoice',
19+
'PrivateDocs/OwnerInvoice',
20+
'classify namespaced camelized string'
21+
);
22+
test(
23+
assert,
24+
'private_docs/owner_invoice',
25+
'PrivateDocs/OwnerInvoice',
26+
'classify namespaced underscored string'
27+
);
28+
test(
29+
assert,
30+
'private-docs/owner-invoice',
31+
'PrivateDocs/OwnerInvoice',
32+
'classify namespaced dasherized string'
33+
);
34+
test(assert, '-view-registry', '_ViewRegistry', 'classify prefixed dasherized string');
35+
test(
36+
assert,
37+
'components/-text-field',
38+
'Components/_TextField',
39+
'classify namespaced prefixed dasherized string'
40+
);
41+
test(assert, '_Foo_Bar', '_FooBar', 'classify underscore-prefixed underscored string');
42+
test(assert, '_Foo-Bar', '_FooBar', 'classify underscore-prefixed dasherized string');
43+
test(
44+
assert,
45+
'_foo/_bar',
46+
'_Foo/_Bar',
47+
'classify underscore-prefixed-namespaced underscore-prefixed string'
48+
);
49+
test(
50+
assert,
51+
'-foo/_bar',
52+
'_Foo/_Bar',
53+
'classify dash-prefixed-namespaced underscore-prefixed string'
54+
);
55+
test(
56+
assert,
57+
'-foo/-bar',
58+
'_Foo/_Bar',
59+
'classify dash-prefixed-namespaced dash-prefixed string'
60+
);
61+
test(assert, 'InnerHTML', 'InnerHTML', 'does nothing with classified string');
62+
test(assert, '_FooBar', '_FooBar', 'does nothing with classified prefixed string');
63+
}
64+
}
65+
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* eslint-disable qunit/no-test-expect-argument */
2+
import { dasherize } from '@ember/-internals/string';
3+
import { moduleFor, AbstractTestCase } from 'internal-test-helpers';
4+
5+
function test(assert, given, expected, description) {
6+
assert.deepEqual(dasherize(given), expected, description);
7+
}
8+
9+
moduleFor(
10+
'EmberInternalsString.dasherize',
11+
class extends AbstractTestCase {
12+
['@test String dasherize tests'](assert) {
13+
test(assert, 'my favorite items', 'my-favorite-items', 'dasherize normal string');
14+
test(assert, 'css-class-name', 'css-class-name', 'does nothing with dasherized string');
15+
test(assert, 'action_name', 'action-name', 'dasherize underscored string');
16+
test(assert, 'innerHTML', 'inner-html', 'dasherize camelcased string');
17+
test(
18+
assert,
19+
'toString',
20+
'to-string',
21+
'dasherize string that is the property name of Object.prototype'
22+
);
23+
test(
24+
assert,
25+
'PrivateDocs/OwnerInvoice',
26+
'private-docs/owner-invoice',
27+
'dasherize namespaced classified string'
28+
);
29+
test(
30+
assert,
31+
'privateDocs/ownerInvoice',
32+
'private-docs/owner-invoice',
33+
'dasherize namespaced camelized string'
34+
);
35+
test(
36+
assert,
37+
'private_docs/owner_invoice',
38+
'private-docs/owner-invoice',
39+
'dasherize namespaced underscored string'
40+
);
41+
}
42+
}
43+
);

packages/@ember/debug/container-debug-adapter.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { classify, dasherize } from '@ember/string';
1+
import { classify, dasherize } from '@ember/-internals/string';
22
import EmberObject from '@ember/object';
33
import { typeOf } from '@ember/utils';
44
import type { InternalOwner } from '@ember/-internals/owner';

packages/@ember/debug/data-adapter.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { InternalOwner } from '@ember/-internals/owner';
22
import { getOwner } from '@ember/-internals/owner';
33
import { _backburner, next } from '@ember/runloop';
44
import { get } from '@ember/object';
5-
import { dasherize } from '@ember/string';
5+
import { dasherize } from '@ember/-internals/string';
66
import Namespace from '@ember/application/namespace';
77
import type { NativeArray } from '@ember/array';
88
import EmberObject from '@ember/object';

packages/@ember/object/tests/observable_test.js

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { context } from '@ember/-internals/environment';
22
import { run } from '@ember/runloop';
33
import { get, computed } from '@ember/object';
4-
import { w } from '@ember/string';
54
import EmberObject, { observer } from '@ember/object';
65
import Observable from '@ember/object/observable';
76
import { A as emberA } from '@ember/array';
@@ -359,23 +358,23 @@ moduleFor(
359358

360359
['@test getting values should call function return value'](assert) {
361360
// get each property twice. Verify return.
362-
let keys = w('computed dependent');
361+
let keys = ['computed', 'dependent'];
363362

364363
keys.forEach(function (key) {
365364
assert.equal(object.get(key), key, `Try #1: object.get(${key}) should run function`);
366365
assert.equal(object.get(key), key, `Try #2: object.get(${key}) should run function`);
367366
});
368367

369368
// verify each call count. cached should only be called once
370-
w('computedCalls dependentCalls').forEach((key) => {
369+
['computedCalls', 'dependentCalls'].forEach((key) => {
371370
assert.equal(object[key].length, 1, `non-cached property ${key} should be called 1x`);
372371
});
373372
}
374373

375374
['@test setting values should call function return value'](assert) {
376375
// get each property twice. Verify return.
377-
let keys = w('computed dependent');
378-
let values = w('value1 value2');
376+
let keys = ['computed', 'dependent'];
377+
let values = ['value1', 'value2'];
379378

380379
keys.forEach((key) => {
381380
assert.equal(

packages/@ember/string/index.ts

+32
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ const DECAMELIZE_CACHE = new Cache<string, string>(1000, (str) =>
7676
7777
@class String
7878
@public
79+
@deprecated Add the package `@ember/string` to your project to use in place of this module.
7980
*/
8081

8182
/**
@@ -98,8 +99,10 @@ const DECAMELIZE_CACHE = new Cache<string, string>(1000, (str) =>
9899
@param {String} str The string to split
99100
@return {Array} array containing the split strings
100101
@public
102+
@deprecated Add `@ember/string` to your package.json
101103
*/
102104
export function w(str: string): string[] {
105+
deprecateImportFromInternalString();
103106
return str.split(/\s+/);
104107
}
105108

@@ -119,8 +122,10 @@ export function w(str: string): string[] {
119122
@param {String} str The string to decamelize.
120123
@return {String} the decamelized string.
121124
@public
125+
@deprecated Add `@ember/string` to your package.json
122126
*/
123127
export function decamelize(str: string): string {
128+
deprecateImportFromInternalString();
124129
return DECAMELIZE_CACHE.get(str);
125130
}
126131

@@ -141,8 +146,10 @@ export function decamelize(str: string): string {
141146
@param {String} str The string to dasherize.
142147
@return {String} the dasherized string.
143148
@public
149+
@deprecated Add `@ember/string` to your package.json
144150
*/
145151
export function dasherize(str: string): string {
152+
deprecateImportFromInternalString();
146153
return STRING_DASHERIZE_CACHE.get(str);
147154
}
148155

@@ -164,8 +171,10 @@ export function dasherize(str: string): string {
164171
@param {String} str The string to camelize.
165172
@return {String} the camelized string.
166173
@public
174+
@deprecated Add `@ember/string` to your package.json
167175
*/
168176
export function camelize(str: string): string {
177+
deprecateImportFromInternalString();
169178
return CAMELIZE_CACHE.get(str);
170179
}
171180

@@ -186,8 +195,10 @@ export function camelize(str: string): string {
186195
@param {String} str the string to classify
187196
@return {String} the classified string
188197
@public
198+
@deprecated Add `@ember/string` to your package.json
189199
*/
190200
export function classify(str: string): string {
201+
deprecateImportFromInternalString();
191202
return CLASSIFY_CACHE.get(str);
192203
}
193204

@@ -209,8 +220,10 @@ export function classify(str: string): string {
209220
@param {String} str The string to underscore.
210221
@return {String} the underscored string.
211222
@public
223+
@deprecated Add `@ember/string` to your package.json
212224
*/
213225
export function underscore(str: string): string {
226+
deprecateImportFromInternalString();
214227
return UNDERSCORE_CACHE.get(str);
215228
}
216229

@@ -231,11 +244,30 @@ export function underscore(str: string): string {
231244
@param {String} str The string to capitalize.
232245
@return {String} The capitalized string.
233246
@public
247+
@deprecated Add `@ember/string` to your package.json
234248
*/
235249
export function capitalize(str: string): string {
250+
deprecateImportFromInternalString();
236251
return CAPITALIZE_CACHE.get(str);
237252
}
238253

254+
function deprecateImportFromInternalString() {
255+
deprecate(
256+
'Importing from `@ember/string` without having the `@ember/string` package in your project is deprecated. Please add `@ember/string` to your `package.json',
257+
false,
258+
{
259+
id: 'ember-string.add-package',
260+
for: 'ember-source',
261+
since: {
262+
available: '4.10',
263+
enabled: '4.10',
264+
},
265+
until: '5.0.0',
266+
url: 'https://deprecations.emberjs.com/v4.x/#toc_ember-string-add-package',
267+
}
268+
);
269+
}
270+
239271
function deprecateImportFromString(
240272
name: string,
241273
message = `Importing ${name} from '@ember/string' is deprecated. Please import ${name} from '@ember/template' instead.`

packages/@ember/string/tests/camelize_test.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ import { camelize } from '@ember/string';
33
import { moduleFor, AbstractTestCase } from 'internal-test-helpers';
44

55
function test(assert, given, expected, description) {
6-
assert.deepEqual(camelize(given), expected, description);
6+
expectDeprecation(() => {
7+
assert.deepEqual(camelize(given), expected, description);
8+
}, 'Importing from `@ember/string` without having the `@ember/string` package in your project is deprecated. Please add `@ember/string` to your `package.json');
79
}
810

911
moduleFor(

0 commit comments

Comments
 (0)