Skip to content

Commit fe81c36

Browse files
authored
Merge pull request #933 from lifeart/embed-ember-string
feat: embed @ember/string utils
2 parents c821b41 + 619249c commit fe81c36

File tree

11 files changed

+314
-30
lines changed

11 files changed

+314
-30
lines changed

addon/addon/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import Ember from 'ember';
44
import { assert, deprecate, warn } from '@ember/debug';
55
import EmberObject from '@ember/object';
6-
import { dasherize, classify, underscore } from '@ember/string';
6+
import { dasherize, classify, underscore } from './string';
77
import { DEBUG } from '@glimmer/env';
88
import classFactory from './utils/class-factory';
99

addon/addon/string/cache.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
export default class Cache {
2+
constructor(limit, func, store) {
3+
this.limit = limit;
4+
this.func = func;
5+
this.store = store;
6+
this.size = 0;
7+
this.misses = 0;
8+
this.hits = 0;
9+
this.store = store || new Map();
10+
}
11+
get(key) {
12+
let value = this.store.get(key);
13+
if (this.store.has(key)) {
14+
this.hits++;
15+
return this.store.get(key);
16+
}
17+
else {
18+
this.misses++;
19+
value = this.set(key, this.func(key));
20+
}
21+
return value;
22+
}
23+
set(key, value) {
24+
if (this.limit > this.size) {
25+
this.size++;
26+
this.store.set(key, value);
27+
}
28+
return value;
29+
}
30+
purge() {
31+
this.store.clear();
32+
this.size = 0;
33+
this.hits = 0;
34+
this.misses = 0;
35+
}
36+
}

addon/addon/string/index.js

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/* eslint-disable no-useless-escape */
2+
import Cache from './cache';
3+
let STRINGS = {};
4+
export function setStrings(strings) {
5+
STRINGS = strings;
6+
}
7+
export function getStrings() {
8+
return STRINGS;
9+
}
10+
export function getString(name) {
11+
return STRINGS[name];
12+
}
13+
const STRING_DASHERIZE_REGEXP = /[ _]/g;
14+
const STRING_DASHERIZE_CACHE = new Cache(1000, (key) => decamelize(key).replace(STRING_DASHERIZE_REGEXP, '-'));
15+
const STRING_CLASSIFY_REGEXP_1 = /^(\-|_)+(.)?/;
16+
const STRING_CLASSIFY_REGEXP_2 = /(.)(\-|\_|\.|\s)+(.)?/g;
17+
const STRING_CLASSIFY_REGEXP_3 = /(^|\/|\.)([a-z])/g;
18+
const CLASSIFY_CACHE = new Cache(1000, (str) => {
19+
const replace1 = (_match, _separator, chr) => chr ? `_${chr.toUpperCase()}` : '';
20+
const replace2 = (_match, initialChar, _separator, chr) => initialChar + (chr ? chr.toUpperCase() : '');
21+
const parts = str.split('/');
22+
for (let i = 0; i < parts.length; i++) {
23+
parts[i] = parts[i]
24+
.replace(STRING_CLASSIFY_REGEXP_1, replace1)
25+
.replace(STRING_CLASSIFY_REGEXP_2, replace2);
26+
}
27+
return parts
28+
.join('/')
29+
.replace(STRING_CLASSIFY_REGEXP_3, (match /*, separator, chr */) => match.toUpperCase());
30+
});
31+
const STRING_UNDERSCORE_REGEXP_1 = /([a-z\d])([A-Z]+)/g;
32+
const STRING_UNDERSCORE_REGEXP_2 = /\-|\s+/g;
33+
const UNDERSCORE_CACHE = new Cache(1000, (str) => str
34+
.replace(STRING_UNDERSCORE_REGEXP_1, '$1_$2')
35+
.replace(STRING_UNDERSCORE_REGEXP_2, '_')
36+
.toLowerCase());
37+
const STRING_DECAMELIZE_REGEXP = /([a-z\d])([A-Z])/g;
38+
const DECAMELIZE_CACHE = new Cache(1000, (str) => str.replace(STRING_DECAMELIZE_REGEXP, '$1_$2').toLowerCase());
39+
/**
40+
Converts a camelized string into all lower case separated by underscores.
41+
42+
```javascript
43+
import { decamelize } from '@ember/string';
44+
45+
decamelize('innerHTML'); // 'inner_html'
46+
decamelize('action_name'); // 'action_name'
47+
decamelize('css-class-name'); // 'css-class-name'
48+
decamelize('my favorite items'); // 'my favorite items'
49+
```
50+
51+
@method decamelize
52+
@param {String} str The string to decamelize.
53+
@return {String} the decamelized string.
54+
@public
55+
*/
56+
export function decamelize(str) {
57+
return DECAMELIZE_CACHE.get(str);
58+
}
59+
/**
60+
Replaces underscores, spaces, or camelCase with dashes.
61+
62+
```javascript
63+
import { dasherize } from '@ember/string';
64+
65+
dasherize('innerHTML'); // 'inner-html'
66+
dasherize('action_name'); // 'action-name'
67+
dasherize('css-class-name'); // 'css-class-name'
68+
dasherize('my favorite items'); // 'my-favorite-items'
69+
dasherize('privateDocs/ownerInvoice'; // 'private-docs/owner-invoice'
70+
```
71+
72+
@method dasherize
73+
@param {String} str The string to dasherize.
74+
@return {String} the dasherized string.
75+
@public
76+
*/
77+
export function dasherize(str) {
78+
return STRING_DASHERIZE_CACHE.get(str);
79+
}
80+
/**
81+
Returns the UpperCamelCase form of a string.
82+
83+
```javascript
84+
import { classify } from '@ember/string';
85+
86+
classify('innerHTML'); // 'InnerHTML'
87+
classify('action_name'); // 'ActionName'
88+
classify('css-class-name'); // 'CssClassName'
89+
classify('my favorite items'); // 'MyFavoriteItems'
90+
classify('private-docs/owner-invoice'); // 'PrivateDocs/OwnerInvoice'
91+
```
92+
93+
@method classify
94+
@param {String} str the string to classify
95+
@return {String} the classified string
96+
@public
97+
*/
98+
export function classify(str) {
99+
return CLASSIFY_CACHE.get(str);
100+
}
101+
/**
102+
More general than decamelize. Returns the lower\_case\_and\_underscored
103+
form of a string.
104+
105+
```javascript
106+
import { underscore } from '@ember/string';
107+
108+
underscore('innerHTML'); // 'inner_html'
109+
underscore('action_name'); // 'action_name'
110+
underscore('css-class-name'); // 'css_class_name'
111+
underscore('my favorite items'); // 'my_favorite_items'
112+
underscore('privateDocs/ownerInvoice'); // 'private_docs/owner_invoice'
113+
```
114+
115+
@method underscore
116+
@param {String} str The string to underscore.
117+
@return {String} the underscored string.
118+
@public
119+
*/
120+
export function underscore(str) {
121+
return UNDERSCORE_CACHE.get(str);
122+
}

addon/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
},
2828
"devDependencies": {},
2929
"peerDependencies": {
30-
"@ember/string": "^3.0.1",
3130
"ember-source": "^4.8.3 || >= 5.0.0"
3231
},
3332
"peerDependenciesMeta": {

package-lock.json

Lines changed: 5 additions & 27 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test-app/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
"dependencies": {},
3030
"devDependencies": {
3131
"@ember/optional-features": "^2.0.0",
32-
"@ember/string": "^3.0.1",
3332
"@ember/test-helpers": "^2.8.1",
3433
"babel-eslint": "^10.1.0",
3534
"broccoli-asset-rev": "^3.0.0",
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { test } from 'qunit';
2+
3+
export default function (fn) {
4+
return function (given, expected, description) {
5+
test(description, function (assert) {
6+
assert.deepEqual(fn(given), expected);
7+
});
8+
};
9+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { module } from 'qunit';
2+
import { classify } from 'ember-resolver/string/index';
3+
import createTestFunction from '../helpers/create-test-function';
4+
5+
module('classify');
6+
7+
const test = createTestFunction(classify);
8+
9+
test('my favorite items', 'MyFavoriteItems', 'classify normal string');
10+
test('css-class-name', 'CssClassName', 'classify dasherized string');
11+
test('action_name', 'ActionName', 'classify underscored string');
12+
test(
13+
'privateDocs/ownerInvoice',
14+
'PrivateDocs/OwnerInvoice',
15+
'classify namespaced camelized string'
16+
);
17+
test(
18+
'private_docs/owner_invoice',
19+
'PrivateDocs/OwnerInvoice',
20+
'classify namespaced underscored string'
21+
);
22+
test(
23+
'private-docs/owner-invoice',
24+
'PrivateDocs/OwnerInvoice',
25+
'classify namespaced dasherized string'
26+
);
27+
test('-view-registry', '_ViewRegistry', 'classify prefixed dasherized string');
28+
test(
29+
'components/-text-field',
30+
'Components/_TextField',
31+
'classify namespaced prefixed dasherized string'
32+
);
33+
test('_Foo_Bar', '_FooBar', 'classify underscore-prefixed underscored string');
34+
test('_Foo-Bar', '_FooBar', 'classify underscore-prefixed dasherized string');
35+
test(
36+
'_foo/_bar',
37+
'_Foo/_Bar',
38+
'classify underscore-prefixed-namespaced underscore-prefixed string'
39+
);
40+
test(
41+
'-foo/_bar',
42+
'_Foo/_Bar',
43+
'classify dash-prefixed-namespaced underscore-prefixed string'
44+
);
45+
test(
46+
'-foo/-bar',
47+
'_Foo/_Bar',
48+
'classify dash-prefixed-namespaced dash-prefixed string'
49+
);
50+
test('InnerHTML', 'InnerHTML', 'does nothing with classified string');
51+
test('_FooBar', '_FooBar', 'does nothing with classified prefixed string');
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { module } from 'qunit';
2+
import { dasherize } from 'ember-resolver/string/index';
3+
import createTestFunction from '../helpers/create-test-function';
4+
5+
module('dasherize');
6+
7+
const test = createTestFunction(dasherize);
8+
9+
test('my favorite items', 'my-favorite-items', 'dasherize normal string');
10+
test('css-class-name', 'css-class-name', 'does nothing with dasherized string');
11+
test('action_name', 'action-name', 'dasherize underscored string');
12+
test('innerHTML', 'inner-html', 'dasherize camelcased string');
13+
test(
14+
'toString',
15+
'to-string',
16+
'dasherize string that is the property name of Object.prototype'
17+
);
18+
test(
19+
'PrivateDocs/OwnerInvoice',
20+
'private-docs/owner-invoice',
21+
'dasherize namespaced classified string'
22+
);
23+
test(
24+
'privateDocs/ownerInvoice',
25+
'private-docs/owner-invoice',
26+
'dasherize namespaced camelized string'
27+
);
28+
test(
29+
'private_docs/owner_invoice',
30+
'private-docs/owner-invoice',
31+
'dasherize namespaced underscored string'
32+
);

0 commit comments

Comments
 (0)