@pcg/text-kit 1.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +15 -0
- package/README.md +243 -0
- package/dist/index.d.ts +243 -0
- package/dist/index.js +324 -0
- package/dist/index.js.map +1 -0
- package/eslint.config.cjs +14 -0
- package/package.json +26 -0
- package/src/cases.ts +317 -0
- package/src/declination.ts +23 -0
- package/src/entities.ts +41 -0
- package/src/generators.ts +16 -0
- package/src/index.ts +5 -0
- package/src/pluralize.ts +35 -0
- package/tests/cases.test.ts +196 -0
- package/tests/declination.test.ts +14 -0
- package/tests/entities.test.ts +47 -0
- package/tests/generators.test.ts +11 -0
- package/tests/pluralize.test.ts +28 -0
- package/tsconfig.json +9 -0
- package/tsconfig.lib.json +9 -0
- package/tsdown.config.ts +11 -0
- package/vitest.config.ts +19 -0
package/src/cases.ts
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import * as cc from 'change-case';
|
|
2
|
+
import { default as cyrillicToTranslit } from 'cyrillic-to-translit-js';
|
|
3
|
+
import { createRandomAbbreviationString } from './generators.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Convert a string to string with the first character in uppercase.
|
|
7
|
+
* @example
|
|
8
|
+
* ucfirst('hello world'); // Hello world
|
|
9
|
+
**/
|
|
10
|
+
export const ucfirst = (input: string) => {
|
|
11
|
+
return input.charAt(0).toUpperCase() + input.substring(1);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Convert a string to string with the first character in lower case.
|
|
16
|
+
* @example
|
|
17
|
+
* lcfirst('Hello world'); // hello world
|
|
18
|
+
**/
|
|
19
|
+
export const lcfirst = (input: string) => {
|
|
20
|
+
return input.charAt(0).toLowerCase() + input.substring(1);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Convert a string to PascalCase.
|
|
25
|
+
* @example
|
|
26
|
+
* pascalCase('foo bar'); //=> 'FooBar'
|
|
27
|
+
* pascalCase('foo_bar'); //=> 'FooBar'
|
|
28
|
+
* pascalCase('foo-bar'); //=> 'FooBar'
|
|
29
|
+
* pascalCase('foo.bar'); //=> 'FooBar'
|
|
30
|
+
* pascalCase('fooBar'); //=> 'FooBar'
|
|
31
|
+
**/
|
|
32
|
+
export const pascalCase = (input: string) => {
|
|
33
|
+
return cc.pascalCase(input, {
|
|
34
|
+
mergeAmbiguousCharacters: true,
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Convert a string to camelCase.
|
|
40
|
+
* @example
|
|
41
|
+
* camelCase('foo bar'); //=> 'fooBar'
|
|
42
|
+
* camelCase('foo_bar'); //=> 'fooBar'
|
|
43
|
+
* camelCase('foo-bar'); //=> 'fooBar'
|
|
44
|
+
* camelCase('foo.bar'); //=> 'fooBar'
|
|
45
|
+
* camelCase('fooBar'); //=> 'fooBar'
|
|
46
|
+
* camelCase('FooBar'); //=> 'fooBar'
|
|
47
|
+
**/
|
|
48
|
+
export const camelCase = (input: string) => {
|
|
49
|
+
return cc.camelCase(input);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Convert a string to param-case.
|
|
54
|
+
* @example
|
|
55
|
+
* paramCase('foo bar'); //=> 'foo-bar'
|
|
56
|
+
* paramCase('foo_bar'); //=> 'foo-bar'
|
|
57
|
+
* paramCase('foo-bar'); //=> 'foo-bar'
|
|
58
|
+
* paramCase('foo.bar'); //=> 'foo-bar'
|
|
59
|
+
* paramCase('fooBar'); //=> 'foo-bar'
|
|
60
|
+
* paramCase('FooBar'); //=> 'foo-bar'
|
|
61
|
+
**/
|
|
62
|
+
export const paramCase = (input: string) => {
|
|
63
|
+
return cc.kebabCase(input);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Convert a string to "dot.case".
|
|
68
|
+
* @example
|
|
69
|
+
* dotCase('foo bar'); //=> 'foo.bar'
|
|
70
|
+
* dotCase('foo_bar'); //=> 'foo.bar'
|
|
71
|
+
* dotCase('foo-bar'); //=> 'foo.bar'
|
|
72
|
+
* dotCase('foo.bar'); //=> 'foo.bar'
|
|
73
|
+
* dotCase('fooBar'); //=> 'foo.bar'
|
|
74
|
+
* dotCase('FooBar'); //=> 'foo.bar'
|
|
75
|
+
**/
|
|
76
|
+
export const dotCase = (input: string) => {
|
|
77
|
+
return cc.dotCase(input);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Convert a string to snake_case.
|
|
82
|
+
* @example
|
|
83
|
+
* snakeCase('foo bar'); //=> 'foo_bar'
|
|
84
|
+
* snakeCase('foo_bar'); //=> 'foo_bar'
|
|
85
|
+
* snakeCase('foo-bar'); //=> 'foo_bar'
|
|
86
|
+
* snakeCase('foo.bar'); //=> 'foo_bar'
|
|
87
|
+
* snakeCase('fooBar'); //=> 'foo_bar'
|
|
88
|
+
* snakeCase('FooBar'); //=> 'foo_bar'
|
|
89
|
+
**/
|
|
90
|
+
export const snakeCase = (input: string) => {
|
|
91
|
+
return cc.snakeCase(input);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Convert a string to CONSTANT_CASE.
|
|
96
|
+
* @example
|
|
97
|
+
* constantCase('foo bar'); //=> 'FOO_BAR'
|
|
98
|
+
* constantCase('foo_bar'); //=> 'FOO_BAR'
|
|
99
|
+
* constantCase('foo-bar'); //=> 'FOO_BAR'
|
|
100
|
+
* constantCase('foo.bar'); //=> 'FOO_BAR'
|
|
101
|
+
* constantCase('fooBar'); //=> 'FOO_BAR'
|
|
102
|
+
* constantCase('FooBar'); //=> 'FOO_BAR'
|
|
103
|
+
**/
|
|
104
|
+
export const constantCase = (input: string) => {
|
|
105
|
+
return cc.constantCase(input);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Convert a string to sentence.
|
|
110
|
+
* @deprecated use sentenceCase instead
|
|
111
|
+
* @example
|
|
112
|
+
* toSentence('foo bar'); //=> 'Foo bar'
|
|
113
|
+
* toSentence('foo_bar'); //=> 'Foo bar'
|
|
114
|
+
* toSentence('foo-bar'); //=> 'Foo bar'
|
|
115
|
+
* toSentence('foo.bar'); //=> 'Foo bar'
|
|
116
|
+
* toSentence('fooBar'); //=> 'Foo bar'
|
|
117
|
+
* toSentence('FooBar'); //=> 'Foo bar'
|
|
118
|
+
* toSentence('foo bar baz'); //=> 'Foo bar baz'
|
|
119
|
+
**/
|
|
120
|
+
export const toSentence = (input: string) => {
|
|
121
|
+
return ucfirst(cc.noCase(input, {
|
|
122
|
+
delimiter: ' ',
|
|
123
|
+
}));
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Convert a string to sentence.
|
|
128
|
+
* @example
|
|
129
|
+
* sentenceCase('foo bar'); //=> 'Foo bar'
|
|
130
|
+
* sentenceCase('foo_bar'); //=> 'Foo bar'
|
|
131
|
+
* sentenceCase('foo-bar'); //=> 'Foo bar'
|
|
132
|
+
* sentenceCase('foo.bar'); //=> 'Foo bar'
|
|
133
|
+
* sentenceCase('fooBar'); //=> 'Foo bar'
|
|
134
|
+
* sentenceCase('FooBar'); //=> 'Foo bar'
|
|
135
|
+
* sentenceCase('foo bar baz'); //=> 'Foo bar baz'
|
|
136
|
+
**/
|
|
137
|
+
export const sentenceCase = (input: string) => {
|
|
138
|
+
return cc.sentenceCase(input);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Convert a string to upper cased sentence.
|
|
143
|
+
* @deprecated use capitalCase instead
|
|
144
|
+
* @example
|
|
145
|
+
* toUcSentence('foo bar'); //=> 'Foo Bar'
|
|
146
|
+
* toUcSentence('foo_bar'); //=> 'Foo Bar'
|
|
147
|
+
* toUcSentence('foo-bar'); //=> 'Foo Bar'
|
|
148
|
+
* toUcSentence('foo.bar'); //=> 'Foo Bar'
|
|
149
|
+
* toUcSentence('fooBar'); //=> 'Foo Bar'
|
|
150
|
+
* toUcSentence('FooBar'); //=> 'Foo Bar'
|
|
151
|
+
* toUcSentence('foo bar baz'); //=> 'Foo Bar Baz'
|
|
152
|
+
**/
|
|
153
|
+
export const toUcSentence = (input: string) => {
|
|
154
|
+
return cc.capitalCase(input);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Convert a string to upper cased sentence.
|
|
159
|
+
* @example
|
|
160
|
+
* capitalCase('foo bar'); //=> 'Foo Bar'
|
|
161
|
+
* capitalCase('foo_bar'); //=> 'Foo Bar'
|
|
162
|
+
* capitalCase('foo-bar'); //=> 'Foo Bar'
|
|
163
|
+
* capitalCase('foo.bar'); //=> 'Foo Bar'
|
|
164
|
+
* capitalCase('fooBar'); //=> 'Foo Bar'
|
|
165
|
+
* capitalCase('FooBar'); //=> 'Foo Bar'
|
|
166
|
+
* capitalCase('foo bar baz'); //=> 'Foo Bar Baz'
|
|
167
|
+
**/
|
|
168
|
+
export const capitalCase = (input: string) => {
|
|
169
|
+
return cc.capitalCase(input);
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Alias to "toUcSentence"
|
|
174
|
+
* @deprecated use capitalCase instead
|
|
175
|
+
**/
|
|
176
|
+
export const capitalize = (input: string) => toUcSentence(input);
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Convert a string to lower cased sentence.
|
|
180
|
+
* @deprecated use lowerSentenceCase instead
|
|
181
|
+
* @example
|
|
182
|
+
* toLcSentence('foo bar'); //=> 'foo bar'
|
|
183
|
+
* toLcSentence('foo_bar'); //=> 'foo bar'
|
|
184
|
+
* toLcSentence('foo-bar'); //=> 'foo bar'
|
|
185
|
+
* toLcSentence('foo.bar'); //=> 'foo bar'
|
|
186
|
+
* toLcSentence('fooBar'); //=> 'foo bar'
|
|
187
|
+
* toLcSentence('FooBar'); //=> 'foo bar'
|
|
188
|
+
* toLcSentence('Foo bar baz'); //=> 'foo bar baz'
|
|
189
|
+
**/
|
|
190
|
+
export const toLcSentence = (input: string) => {
|
|
191
|
+
return sentenceCase(input).toLowerCase();
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Convert a string to lower cased sentence.
|
|
196
|
+
* @example
|
|
197
|
+
* lowerSentenceCase('foo bar'); //=> 'foo bar'
|
|
198
|
+
* lowerSentenceCase('foo_bar'); //=> 'foo bar'
|
|
199
|
+
* lowerSentenceCase('foo-bar'); //=> 'foo bar'
|
|
200
|
+
* lowerSentenceCase('foo.bar'); //=> 'foo bar'
|
|
201
|
+
* lowerSentenceCase('fooBar'); //=> 'foo bar'
|
|
202
|
+
* lowerSentenceCase('FooBar'); //=> 'foo bar'
|
|
203
|
+
* lowerSentenceCase('Foo bar baz'); //=> 'foo bar baz'
|
|
204
|
+
**/
|
|
205
|
+
export const lowerSentenceCase = (input: string) => {
|
|
206
|
+
return sentenceCase(input).toLowerCase();
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Convert a table name to sql alias.
|
|
211
|
+
* @example
|
|
212
|
+
* toSqlAlias('foo bar'); //=> 'fb'
|
|
213
|
+
* toSqlAlias('book'); //=> 'b'
|
|
214
|
+
* toSqlAlias('article-category'); //=> 'ac'
|
|
215
|
+
**/
|
|
216
|
+
export const toSqlAlias = (input: string): string => {
|
|
217
|
+
return snakeCase(input)
|
|
218
|
+
.split('_')
|
|
219
|
+
.reduce((acc, word) => acc.concat(word[0]), '');
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
export interface ToAbbreviationOptions {
|
|
223
|
+
maxLength?: number;
|
|
224
|
+
minLength?: number;
|
|
225
|
+
lang?: 'uk' | 'ru' | 'mn';
|
|
226
|
+
iteration?: number;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Remove vowels from a word.
|
|
231
|
+
* @param word - word to remove vowels from
|
|
232
|
+
* @returns word without vowels
|
|
233
|
+
* @example
|
|
234
|
+
* removeVowels('foo'); //=> 'f'
|
|
235
|
+
*/
|
|
236
|
+
export const removeVowels = (word: string) => {
|
|
237
|
+
return word.replace(/[aeiou]/gi, '');
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Convert a string to abbreviation.
|
|
242
|
+
* @example
|
|
243
|
+
* toAbbreviation('Sabbath Schook'); //=> 'SB'
|
|
244
|
+
* toAbbreviation('Рожеві окуляри', {
|
|
245
|
+
* lang: 'uk',
|
|
246
|
+
* }); //=> 'RO'
|
|
247
|
+
* toAbbreviation('Удивительные факты', {
|
|
248
|
+
* lang: 'ru',
|
|
249
|
+
* }); //=> 'UF'
|
|
250
|
+
*/
|
|
251
|
+
export const toAbbreviation = (input: string, opts?: ToAbbreviationOptions): string => {
|
|
252
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
253
|
+
const transliterator = (cyrillicToTranslit as any)(opts?.lang ? {
|
|
254
|
+
preset: opts.lang,
|
|
255
|
+
} : undefined);
|
|
256
|
+
|
|
257
|
+
const words = transliterator
|
|
258
|
+
.transform(input)
|
|
259
|
+
.toUpperCase()
|
|
260
|
+
.replace(/[^A-Z ]/g, '')
|
|
261
|
+
.split(' ')
|
|
262
|
+
.filter((word: string) => word.length > 0);
|
|
263
|
+
|
|
264
|
+
// .map((word) =>).toUpperCase());
|
|
265
|
+
|
|
266
|
+
let abbreviation = '';
|
|
267
|
+
|
|
268
|
+
// Sabbath School => SS
|
|
269
|
+
if (words.length > 1) {
|
|
270
|
+
abbreviation = words.reduce((acc: string, word: string) => {
|
|
271
|
+
if (word.length >= 1) {
|
|
272
|
+
acc += word[0];
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return acc;
|
|
276
|
+
}, '');
|
|
277
|
+
} else if (words.length === 1) {
|
|
278
|
+
const word = words[0];
|
|
279
|
+
|
|
280
|
+
// Sabbath => SBBTH
|
|
281
|
+
if (word.length > 1) {
|
|
282
|
+
abbreviation = word.slice(0, 1) + removeVowels(word.slice(1));
|
|
283
|
+
} else {
|
|
284
|
+
abbreviation = word;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// If the maxLength option is set, trim the abbreviation before adding random characters and appending digits
|
|
289
|
+
if (opts?.maxLength && !opts?.iteration) {
|
|
290
|
+
abbreviation = abbreviation.slice(0, opts.maxLength);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// If the minLength option is set, ensure the abbreviation meets the minimum length by appending random characters before appending digits
|
|
294
|
+
if (opts?.minLength && abbreviation.length < opts.minLength) {
|
|
295
|
+
let charsNeeded = opts.minLength - abbreviation.length;
|
|
296
|
+
if (opts?.iteration && opts?.iteration > 0) {
|
|
297
|
+
charsNeeded -= 1;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (charsNeeded > 0) {
|
|
301
|
+
abbreviation += createRandomAbbreviationString(charsNeeded).toUpperCase();
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Append a number based on the iteration option
|
|
306
|
+
if (opts?.iteration) {
|
|
307
|
+
if (opts?.maxLength) {
|
|
308
|
+
// Calculate the maximum length the abbreviation can be, considering the digits and random characters
|
|
309
|
+
const maxAbbrLength = opts.maxLength - 1;
|
|
310
|
+
abbreviation = abbreviation.slice(0, maxAbbrLength);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
abbreviation += opts.iteration;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return abbreviation;
|
|
317
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decline a noun based on a number.
|
|
3
|
+
* @example
|
|
4
|
+
* const words = ['элемент', 'элемента', 'элементов'];
|
|
5
|
+
*
|
|
6
|
+
* decline(0, words, false) // => 'элементов'
|
|
7
|
+
* decline(24, words, false) // => 'элемента'
|
|
8
|
+
* decline(21, words, false) // => 'элемент'
|
|
9
|
+
*
|
|
10
|
+
* decline(0, words) // => '0 элементов'
|
|
11
|
+
* decline(24, words) // => '24 элемента'
|
|
12
|
+
* decline(21, words) // => '21 элемент'
|
|
13
|
+
*/
|
|
14
|
+
export const decline = (n: number, words: string[], concat = true) => {
|
|
15
|
+
const word =
|
|
16
|
+
words[
|
|
17
|
+
n % 100 > 4 && n % 100 < 20
|
|
18
|
+
? 2
|
|
19
|
+
: [2, 0, 1, 1, 1, 2][n % 10 < 5 ? n % 10 : 5]
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
return concat ? `${n} ${word}` : word;
|
|
23
|
+
};
|
package/src/entities.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { camelCase, pascalCase } from './cases.js';
|
|
2
|
+
import { singularToPlural } from './pluralize.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
Returns variations of entity type names
|
|
6
|
+
|
|
7
|
+
@example
|
|
8
|
+
| entityType | 'CodePuzzle' |
|
|
9
|
+
|----------------------------|-----------------------|
|
|
10
|
+
| pascalCaseEntityType | 'CodePuzzle' |
|
|
11
|
+
| camelCaseEntityType | 'CodePuzzle' |
|
|
12
|
+
| pluralEntityType | 'CodePuzzles' |
|
|
13
|
+
| pluralCamelCaseEntityType | 'codePuzzles' |
|
|
14
|
+
| pluralPascalCaseEntityType | 'CodePuzzles' |
|
|
15
|
+
| createMutationName | 'createCodePuzzle' |
|
|
16
|
+
| updateMutationName | 'updateCodePuzzle' |
|
|
17
|
+
| deleteMutationName | 'deleteCodePuzzle' |
|
|
18
|
+
| dublicateMutationName | 'dublicateCodePuzzle' |
|
|
19
|
+
| publishMutationName | 'publishCodePuzzle' |
|
|
20
|
+
*/
|
|
21
|
+
export const createEntityTypeNames = (entityType: string) => {
|
|
22
|
+
const pluralEntityType = singularToPlural(entityType); // codepuzzles
|
|
23
|
+
const camelCaseEntityType = camelCase(entityType); // codepuzzle
|
|
24
|
+
const pascalCaseEntityType = pascalCase(entityType); // CodePuzzle
|
|
25
|
+
|
|
26
|
+
const pluralPascalCaseEntityType = pascalCase(pluralEntityType); // CodePuzzles
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
pluralEntityType,
|
|
30
|
+
camelCaseEntityType,
|
|
31
|
+
pascalCaseEntityType,
|
|
32
|
+
pluralCamelCaseEntityType: camelCase(pluralEntityType),
|
|
33
|
+
pluralPascalCaseEntityType,
|
|
34
|
+
createMutationName: `create${pascalCaseEntityType}`,
|
|
35
|
+
updateMutationName: `update${pascalCaseEntityType}`,
|
|
36
|
+
deleteMutationName: `delete${pascalCaseEntityType}`,
|
|
37
|
+
dublicateMutationName: `dublicate${pascalCaseEntityType}`,
|
|
38
|
+
publishMutationName: `publish${pascalCaseEntityType}`,
|
|
39
|
+
unpublishMutationName: `unpublish${pascalCaseEntityType}`,
|
|
40
|
+
};
|
|
41
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { customAlphabet } from 'nanoid/non-secure';
|
|
2
|
+
|
|
3
|
+
export const createRandomString = (size = 8) => {
|
|
4
|
+
return customAlphabet('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', size)();
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const createRandomAbbreviationString = (size = 8) => {
|
|
8
|
+
return customAlphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ', size)();
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const createNumericCode = (num: number, length: number): string => {
|
|
12
|
+
// Add leading zeros if necessary using padStart
|
|
13
|
+
const numberStr = num.toString().padStart(length, '0');
|
|
14
|
+
|
|
15
|
+
return numberStr;
|
|
16
|
+
};
|
package/src/index.ts
ADDED
package/src/pluralize.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as pluralize from 'pluralize';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Change the plural form of a word to its singular form.
|
|
5
|
+
* @example
|
|
6
|
+
* pluralToSingular('books'); //=> 'book'
|
|
7
|
+
*/
|
|
8
|
+
export const singularToPlural = (input: string): string => {
|
|
9
|
+
return pluralize.plural(input);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Change the singular form of a word to its plural form.
|
|
14
|
+
* @example
|
|
15
|
+
* singularToPlural('book'); //=> 'books'
|
|
16
|
+
*/
|
|
17
|
+
export const pluralToSingular = (input: string): string => {
|
|
18
|
+
return pluralize.singular(input);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Checks if a given word is in its plural form.
|
|
23
|
+
*
|
|
24
|
+
* @param word - The word to check for plural form
|
|
25
|
+
* @returns `true` if the word is plural, `false` if it's singular
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* isPlural("cats"); // true
|
|
30
|
+
* isPlural("cat"); // false
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export const isPlural = (word: string): boolean =>
|
|
34
|
+
singularToPlural(word) === word;
|
|
35
|
+
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import {
|
|
2
|
+
describe, expect, test,
|
|
3
|
+
} from 'vitest';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
camelCase,
|
|
7
|
+
capitalCase,
|
|
8
|
+
constantCase,
|
|
9
|
+
dotCase,
|
|
10
|
+
lcfirst,
|
|
11
|
+
lowerSentenceCase,
|
|
12
|
+
paramCase,
|
|
13
|
+
pascalCase,
|
|
14
|
+
sentenceCase,
|
|
15
|
+
snakeCase,
|
|
16
|
+
toAbbreviation,
|
|
17
|
+
ToAbbreviationOptions,
|
|
18
|
+
toSqlAlias,
|
|
19
|
+
ucfirst,
|
|
20
|
+
} from '../src/cases.js';
|
|
21
|
+
|
|
22
|
+
describe('Cases', () => {
|
|
23
|
+
test('ucfirst', () => {
|
|
24
|
+
expect(ucfirst('simple')).toBe('Simple');
|
|
25
|
+
expect(ucfirst('S')).toBe('S');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('lcfirst', () => {
|
|
29
|
+
expect(lcfirst('Simple')).toBe('simple');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('camelCase', () => {
|
|
33
|
+
expect(camelCase('simple')).toBe('simple');
|
|
34
|
+
expect(camelCase('some.dot.case')).toBe('someDotCase');
|
|
35
|
+
expect(camelCase('some-param-case')).toBe('someParamCase');
|
|
36
|
+
expect(camelCase('some_param_case')).toBe('someParamCase');
|
|
37
|
+
expect(camelCase('SOME_PARAM_CASE')).toBe('someParamCase');
|
|
38
|
+
expect(camelCase('some spaced case')).toBe('someSpacedCase');
|
|
39
|
+
expect(camelCase('someCamelCase')).toBe('someCamelCase');
|
|
40
|
+
expect(camelCase('SomePascalCase')).toBe('somePascalCase');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('pascalCase', () => {
|
|
44
|
+
expect(pascalCase('simple')).toBe('Simple');
|
|
45
|
+
expect(pascalCase('some.dot.case')).toBe('SomeDotCase');
|
|
46
|
+
expect(pascalCase('some-param-case')).toBe('SomeParamCase');
|
|
47
|
+
expect(pascalCase('some spaced case')).toBe('SomeSpacedCase');
|
|
48
|
+
expect(pascalCase('someCamelCase')).toBe('SomeCamelCase');
|
|
49
|
+
expect(pascalCase('SomePascalCase')).toBe('SomePascalCase');
|
|
50
|
+
expect(pascalCase('upload-2')).toBe('Upload2');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('paramCase', () => {
|
|
54
|
+
expect(paramCase('simple')).toBe('simple');
|
|
55
|
+
expect(paramCase('some.dot.case')).toBe('some-dot-case');
|
|
56
|
+
expect(paramCase('some-param-case')).toBe('some-param-case');
|
|
57
|
+
expect(paramCase('some spaced case')).toBe('some-spaced-case');
|
|
58
|
+
expect(paramCase('someCamelCase')).toBe('some-camel-case');
|
|
59
|
+
expect(paramCase('SomePascalCase')).toBe('some-pascal-case');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('dotCase', () => {
|
|
63
|
+
expect(dotCase('simple')).toBe('simple');
|
|
64
|
+
expect(dotCase('some.dot.case')).toBe('some.dot.case');
|
|
65
|
+
expect(dotCase('some-param-case')).toBe('some.param.case');
|
|
66
|
+
expect(dotCase('some spaced case')).toBe('some.spaced.case');
|
|
67
|
+
expect(dotCase('someCamelCase')).toBe('some.camel.case');
|
|
68
|
+
expect(dotCase('SomePascalCase')).toBe('some.pascal.case');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('snakeCase', () => {
|
|
72
|
+
expect(snakeCase('simple')).toBe('simple');
|
|
73
|
+
expect(snakeCase('some.dot.case')).toBe('some_dot_case');
|
|
74
|
+
expect(snakeCase('some-param-case')).toBe('some_param_case');
|
|
75
|
+
expect(snakeCase('some spaced case')).toBe('some_spaced_case');
|
|
76
|
+
expect(snakeCase('someCamelCase')).toBe('some_camel_case');
|
|
77
|
+
expect(snakeCase('SomePascalCase')).toBe('some_pascal_case');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('constantCase', () => {
|
|
81
|
+
expect(constantCase('maxValue')).toBe('MAX_VALUE');
|
|
82
|
+
expect(constantCase('mp4-720')).toBe('MP4_720');
|
|
83
|
+
expect(constantCase('QUALITY_4K')).toBe('QUALITY_4_K');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('sentenceCase', () => {
|
|
87
|
+
expect(sentenceCase('simple')).toBe('Simple');
|
|
88
|
+
expect(sentenceCase('some.dot.case')).toBe('Some dot case');
|
|
89
|
+
expect(sentenceCase('some-param-case')).toBe('Some param case');
|
|
90
|
+
expect(sentenceCase('some spaced case')).toBe('Some spaced case');
|
|
91
|
+
expect(sentenceCase('someCamelCase')).toBe('Some camel case');
|
|
92
|
+
expect(sentenceCase('SomePascalCase')).toBe('Some pascal case');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test('capitalCase', () => {
|
|
96
|
+
expect(capitalCase('simple')).toBe('Simple');
|
|
97
|
+
expect(capitalCase('some.dot.case')).toBe('Some Dot Case');
|
|
98
|
+
expect(capitalCase('some-param-case')).toBe('Some Param Case');
|
|
99
|
+
expect(capitalCase('some spaced case')).toBe('Some Spaced Case');
|
|
100
|
+
expect(capitalCase('someCamelCase')).toBe('Some Camel Case');
|
|
101
|
+
expect(capitalCase('SomePascalCase')).toBe('Some Pascal Case');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('lowerSentenceCase', () => {
|
|
105
|
+
expect(lowerSentenceCase('simple')).toBe('simple');
|
|
106
|
+
expect(lowerSentenceCase('some.dot.case')).toBe('some dot case');
|
|
107
|
+
expect(lowerSentenceCase('some-param-case')).toBe('some param case');
|
|
108
|
+
expect(lowerSentenceCase('some spaced case')).toBe('some spaced case');
|
|
109
|
+
expect(lowerSentenceCase('someCamelCase')).toBe('some camel case');
|
|
110
|
+
expect(lowerSentenceCase('SomePascalCase')).toBe('some pascal case');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('toSqlAlias', () => {
|
|
114
|
+
expect(toSqlAlias('foo bar')).toBe('fb');
|
|
115
|
+
expect(toSqlAlias('book')).toBe('b');
|
|
116
|
+
expect(toSqlAlias('article-category')).toBe('ac');
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test.each<[string, string, ToAbbreviationOptions]>([
|
|
120
|
+
['Sabbath', 'SBBTH', {
|
|
121
|
+
}],
|
|
122
|
+
['Sabbath', 'SB', {
|
|
123
|
+
maxLength: 2,
|
|
124
|
+
}],
|
|
125
|
+
['Sabbath School', 'SS', {
|
|
126
|
+
}],
|
|
127
|
+
['Sabbath && (School)', 'SS', {
|
|
128
|
+
}],
|
|
129
|
+
['Рожеві окуляри', 'RO', {
|
|
130
|
+
lang: 'uk',
|
|
131
|
+
}],
|
|
132
|
+
['Удивительные факты', 'UF', {
|
|
133
|
+
lang: 'ru',
|
|
134
|
+
}],
|
|
135
|
+
[`Very long title but i dont know why, maybe because i can't stop write this title`, 'VLTBI', {
|
|
136
|
+
maxLength: 5,
|
|
137
|
+
}],
|
|
138
|
+
['Sabbath School', 'SS', {
|
|
139
|
+
maxLength: 5,
|
|
140
|
+
iteration: 0,
|
|
141
|
+
}],
|
|
142
|
+
['Sabbath School', 'SS1', {
|
|
143
|
+
maxLength: 5,
|
|
144
|
+
iteration: 1,
|
|
145
|
+
}],
|
|
146
|
+
['Sabbath', 'SBBTH', {
|
|
147
|
+
maxLength: 5,
|
|
148
|
+
iteration: 0,
|
|
149
|
+
}],
|
|
150
|
+
['Sabbath', 'SBBT1', {
|
|
151
|
+
maxLength: 5,
|
|
152
|
+
iteration: 1,
|
|
153
|
+
}],
|
|
154
|
+
])('toAbbreviation(%s) = %s (%j)', (
|
|
155
|
+
abbreviation: string,
|
|
156
|
+
expected: string,
|
|
157
|
+
opts: ToAbbreviationOptions,
|
|
158
|
+
) => {
|
|
159
|
+
expect(toAbbreviation(abbreviation, opts)).toBe(expected);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test.each<[string, number, ToAbbreviationOptions]>([
|
|
163
|
+
['Some text', 3, {
|
|
164
|
+
maxLength: 5,
|
|
165
|
+
minLength: 3,
|
|
166
|
+
}],
|
|
167
|
+
['Sabbath School', 6, {
|
|
168
|
+
maxLength: 6,
|
|
169
|
+
minLength: 6,
|
|
170
|
+
}],
|
|
171
|
+
['0_o', 3, {
|
|
172
|
+
maxLength: 5,
|
|
173
|
+
minLength: 3,
|
|
174
|
+
iteration: 1,
|
|
175
|
+
}],
|
|
176
|
+
['S4', 3, {
|
|
177
|
+
maxLength: 5,
|
|
178
|
+
minLength: 3,
|
|
179
|
+
iteration: 1,
|
|
180
|
+
}],
|
|
181
|
+
['333', 3, {
|
|
182
|
+
maxLength: 5,
|
|
183
|
+
minLength: 3,
|
|
184
|
+
iteration: 1,
|
|
185
|
+
}],
|
|
186
|
+
])('toAbbreviation with random strings: toAbbreviation(%s).length => %s (%j)', (
|
|
187
|
+
abbreviation,
|
|
188
|
+
expectedLenght,
|
|
189
|
+
opts,
|
|
190
|
+
) => {
|
|
191
|
+
const result = toAbbreviation(abbreviation, opts);
|
|
192
|
+
// console.log(abbreviation, result);
|
|
193
|
+
|
|
194
|
+
expect(result.length).toBe(expectedLenght);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { expect, test } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { decline } from '../src/declination.js';
|
|
4
|
+
const words = ['элемент', 'элемента', 'элементов'];
|
|
5
|
+
|
|
6
|
+
test('must decline word', () => {
|
|
7
|
+
expect(decline(0, words, false)).toBe('элементов');
|
|
8
|
+
expect(decline(24, words, false)).toBe('элемента');
|
|
9
|
+
expect(decline(21, words, false)).toBe('элемент');
|
|
10
|
+
|
|
11
|
+
expect(decline(0, words)).toBe('0 элементов');
|
|
12
|
+
expect(decline(24, words)).toBe('24 элемента');
|
|
13
|
+
expect(decline(21, words)).toBe('21 элемент');
|
|
14
|
+
});
|