tscommons-esm-core 0.0.2
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/dist/classes/commons-cache.d.mts +25 -0
- package/dist/classes/commons-cache.mjs +115 -0
- package/dist/classes/commons-cache.mjs.map +1 -0
- package/dist/classes/commons-cursor.d.mts +29 -0
- package/dist/classes/commons-cursor.mjs +108 -0
- package/dist/classes/commons-cursor.mjs.map +1 -0
- package/dist/classes/commons-fixed-date-range.d.mts +70 -0
- package/dist/classes/commons-fixed-date-range.mjs +232 -0
- package/dist/classes/commons-fixed-date-range.mjs.map +1 -0
- package/dist/classes/commons-fixed-date.d.mts +119 -0
- package/dist/classes/commons-fixed-date.mjs +588 -0
- package/dist/classes/commons-fixed-date.mjs.map +1 -0
- package/dist/classes/commons-fixed-duration.d.mts +96 -0
- package/dist/classes/commons-fixed-duration.mjs +478 -0
- package/dist/classes/commons-fixed-duration.mjs.map +1 -0
- package/dist/classes/commons-join-table.d.mts +29 -0
- package/dist/classes/commons-join-table.mjs +71 -0
- package/dist/classes/commons-join-table.mjs.map +1 -0
- package/dist/classes/commons-tally.d.mts +32 -0
- package/dist/classes/commons-tally.mjs +122 -0
- package/dist/classes/commons-tally.mjs.map +1 -0
- package/dist/classes/commons-timestamp-join-table.d.mts +11 -0
- package/dist/classes/commons-timestamp-join-table.mjs +25 -0
- package/dist/classes/commons-timestamp-join-table.mjs.map +1 -0
- package/dist/classes/commons-window-carousell.d.mts +15 -0
- package/dist/classes/commons-window-carousell.mjs +114 -0
- package/dist/classes/commons-window-carousell.mjs.map +1 -0
- package/dist/consts/commons-chars.d.mts +4 -0
- package/dist/consts/commons-chars.mjs +6 -0
- package/dist/consts/commons-chars.mjs.map +1 -0
- package/dist/consts/commons-const.d.mts +3 -0
- package/dist/consts/commons-const.mjs +5 -0
- package/dist/consts/commons-const.mjs.map +1 -0
- package/dist/consts/commons-regex.d.mts +41 -0
- package/dist/consts/commons-regex.mjs +44 -0
- package/dist/consts/commons-regex.mjs.map +1 -0
- package/dist/consts/commons-stopwords.d.mts +2 -0
- package/dist/consts/commons-stopwords.mjs +111 -0
- package/dist/consts/commons-stopwords.mjs.map +1 -0
- package/dist/enums/emap-rank-direction.d.mts +4 -0
- package/dist/enums/emap-rank-direction.mjs +6 -0
- package/dist/enums/emap-rank-direction.mjs.map +1 -0
- package/dist/helpers/commons-array.d.mts +22 -0
- package/dist/helpers/commons-array.mjs +363 -0
- package/dist/helpers/commons-array.mjs.map +1 -0
- package/dist/helpers/commons-base.d.mts +83 -0
- package/dist/helpers/commons-base.mjs +363 -0
- package/dist/helpers/commons-base.mjs.map +1 -0
- package/dist/helpers/commons-date.d.mts +78 -0
- package/dist/helpers/commons-date.mjs +775 -0
- package/dist/helpers/commons-date.mjs.map +1 -0
- package/dist/helpers/commons-encoding.d.mts +6 -0
- package/dist/helpers/commons-encoding.mjs +25 -0
- package/dist/helpers/commons-encoding.mjs.map +1 -0
- package/dist/helpers/commons-fixed-date.d.mts +10 -0
- package/dist/helpers/commons-fixed-date.mjs +67 -0
- package/dist/helpers/commons-fixed-date.mjs.map +1 -0
- package/dist/helpers/commons-fixed-duration.d.mts +3 -0
- package/dist/helpers/commons-fixed-duration.mjs +14 -0
- package/dist/helpers/commons-fixed-duration.mjs.map +1 -0
- package/dist/helpers/commons-map.d.mts +10 -0
- package/dist/helpers/commons-map.mjs +38 -0
- package/dist/helpers/commons-map.mjs.map +1 -0
- package/dist/helpers/commons-matrix.d.mts +5 -0
- package/dist/helpers/commons-matrix.mjs +46 -0
- package/dist/helpers/commons-matrix.mjs.map +1 -0
- package/dist/helpers/commons-number.d.mts +27 -0
- package/dist/helpers/commons-number.mjs +425 -0
- package/dist/helpers/commons-number.mjs.map +1 -0
- package/dist/helpers/commons-object.d.mts +4 -0
- package/dist/helpers/commons-object.mjs +44 -0
- package/dist/helpers/commons-object.mjs.map +1 -0
- package/dist/helpers/commons-string.d.mts +55 -0
- package/dist/helpers/commons-string.mjs +680 -0
- package/dist/helpers/commons-string.mjs.map +1 -0
- package/dist/helpers/commons-tree.d.mts +13 -0
- package/dist/helpers/commons-tree.mjs +81 -0
- package/dist/helpers/commons-tree.mjs.map +1 -0
- package/dist/helpers/commons-type.d.mts +308 -0
- package/dist/helpers/commons-type.mjs +1632 -0
- package/dist/helpers/commons-type.mjs.map +1 -0
- package/dist/index.d.mts +40 -0
- package/dist/index.mjs +33 -0
- package/dist/index.mjs.map +1 -0
- package/dist/types/tarray-with-errors.d.mts +4 -0
- package/dist/types/tarray-with-errors.mjs +2 -0
- package/dist/types/tarray-with-errors.mjs.map +1 -0
- package/dist/types/tdate-range.d.mts +5 -0
- package/dist/types/tdate-range.mjs +9 -0
- package/dist/types/tdate-range.mjs.map +1 -0
- package/dist/types/tdefined.d.mts +4 -0
- package/dist/types/tdefined.mjs +2 -0
- package/dist/types/tdefined.mjs.map +1 -0
- package/dist/types/tempty-object.d.mts +3 -0
- package/dist/types/tempty-object.mjs +2 -0
- package/dist/types/tempty-object.mjs.map +1 -0
- package/dist/types/tencoded.d.mts +6 -0
- package/dist/types/tencoded.mjs +2 -0
- package/dist/types/tencoded.mjs.map +1 -0
- package/dist/types/tenum-object.d.mts +3 -0
- package/dist/types/tenum-object.mjs +2 -0
- package/dist/types/tenum-object.mjs.map +1 -0
- package/dist/types/tinterquartile-model.d.mts +16 -0
- package/dist/types/tinterquartile-model.mjs +29 -0
- package/dist/types/tinterquartile-model.mjs.map +1 -0
- package/dist/types/tmap-rank.d.mts +4 -0
- package/dist/types/tmap-rank.mjs +2 -0
- package/dist/types/tmap-rank.mjs.map +1 -0
- package/dist/types/tmodules.d.mts +3 -0
- package/dist/types/tmodules.mjs +2 -0
- package/dist/types/tmodules.mjs.map +1 -0
- package/dist/types/tprimative.d.mts +4 -0
- package/dist/types/tprimative.mjs +2 -0
- package/dist/types/tprimative.mjs.map +1 -0
- package/dist/types/tproperty-object.d.mts +3 -0
- package/dist/types/tproperty-object.mjs +2 -0
- package/dist/types/tproperty-object.mjs.map +1 -0
- package/dist/types/tt-or-tarray.d.mts +2 -0
- package/dist/types/tt-or-tarray.mjs +9 -0
- package/dist/types/tt-or-tarray.mjs.map +1 -0
- package/package.json +27 -0
|
@@ -0,0 +1,680 @@
|
|
|
1
|
+
import { COMMONS_ALPHABET_CHARACTERS, COMMONS_CONSONANT_CHARACTERS, COMMONS_DEFAULT_PUNCTUATION_CHARACTERS, COMMONS_VOWEL_CHARACTERS } from '../consts/commons-chars.mjs';
|
|
2
|
+
import { commonsTypeIsString } from './commons-type.mjs';
|
|
3
|
+
// Casing methods
|
|
4
|
+
export function commonsStringUcWords(value) {
|
|
5
|
+
// easier to do this via a loop rather than a regex
|
|
6
|
+
let lastWord = false;
|
|
7
|
+
return value
|
|
8
|
+
.toString()
|
|
9
|
+
.split('')
|
|
10
|
+
.map((c) => {
|
|
11
|
+
const isWord = /^[A-Z]$/i.test(c);
|
|
12
|
+
try {
|
|
13
|
+
if (!isWord || lastWord)
|
|
14
|
+
return c;
|
|
15
|
+
return c.toUpperCase();
|
|
16
|
+
}
|
|
17
|
+
finally {
|
|
18
|
+
lastWord = isWord;
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
.join('');
|
|
22
|
+
}
|
|
23
|
+
export function commonsStringCamelCase(value, ucFirst = true) {
|
|
24
|
+
return value
|
|
25
|
+
.toString()
|
|
26
|
+
.replace(/([A-Z])/g, ' $1')
|
|
27
|
+
.replace(/[^a-z0-9]/ig, ' ')
|
|
28
|
+
.replace(/[ ]{2,}/, ' ')
|
|
29
|
+
.trim()
|
|
30
|
+
.split(' ')
|
|
31
|
+
.map((s) => s.trim())
|
|
32
|
+
.filter((s) => s !== '')
|
|
33
|
+
.map((s, index) => {
|
|
34
|
+
if (index === 0 && !ucFirst)
|
|
35
|
+
return s.toLowerCase();
|
|
36
|
+
if (s.length < 2)
|
|
37
|
+
return s.toUpperCase();
|
|
38
|
+
return s.substring(0, 1).toUpperCase() + s.substring(1);
|
|
39
|
+
})
|
|
40
|
+
.join('');
|
|
41
|
+
}
|
|
42
|
+
function delimeterCase(value, delimeter) {
|
|
43
|
+
return value
|
|
44
|
+
.toString()
|
|
45
|
+
.replace(/([A-Z])/g, ' $1')
|
|
46
|
+
.replace(/[^a-z0-9]/ig, ' ')
|
|
47
|
+
.replace(/[ ]{2,}/, ' ')
|
|
48
|
+
.trim()
|
|
49
|
+
.split(' ')
|
|
50
|
+
.map((s) => s.trim().toLowerCase())
|
|
51
|
+
.filter((s) => s !== '')
|
|
52
|
+
.join(delimeter);
|
|
53
|
+
}
|
|
54
|
+
export function commonsStringSnakeCase(value) {
|
|
55
|
+
return delimeterCase(value, '_');
|
|
56
|
+
}
|
|
57
|
+
export function commonsStringKebabCase(value) {
|
|
58
|
+
return delimeterCase(value, '-');
|
|
59
|
+
}
|
|
60
|
+
export function commonsStringDashedCase(value) {
|
|
61
|
+
return commonsStringKebabCase(value);
|
|
62
|
+
}
|
|
63
|
+
export function commonsStringRegexEscapeString(term) {
|
|
64
|
+
return term
|
|
65
|
+
.replace(/[.]/g, '\\.')
|
|
66
|
+
.replace(/[?]/g, '[?]')
|
|
67
|
+
.replace(/[*]/g, '[*]')
|
|
68
|
+
.replace(/[+]/g, '[+]')
|
|
69
|
+
.replace(/[(]/g, '\\(')
|
|
70
|
+
.replace(/[)]/g, '\\)')
|
|
71
|
+
.replace(/\[/g, '\\[)')
|
|
72
|
+
.replace(/\]/g, '\\]')
|
|
73
|
+
.replace(/[{]/g, '[{]')
|
|
74
|
+
.replace(/[}]/g, '[}]');
|
|
75
|
+
}
|
|
76
|
+
// Simple character, word and sentence methods
|
|
77
|
+
export function commonsStringIsAlphabet(c) {
|
|
78
|
+
return c.length === 1
|
|
79
|
+
&& COMMONS_ALPHABET_CHARACTERS.includes(c.toLowerCase());
|
|
80
|
+
}
|
|
81
|
+
export function commonsStringIsVowel(c) {
|
|
82
|
+
return commonsStringIsAlphabet(c)
|
|
83
|
+
&& COMMONS_VOWEL_CHARACTERS.includes(c.toLowerCase());
|
|
84
|
+
}
|
|
85
|
+
export function commonsStringIsConsonant(c) {
|
|
86
|
+
return commonsStringIsAlphabet(c)
|
|
87
|
+
&& COMMONS_CONSONANT_CHARACTERS.includes(c.toLowerCase());
|
|
88
|
+
}
|
|
89
|
+
export function commonsStringRegexLike(term) {
|
|
90
|
+
return `^${commonsStringRegexEscapeString(term)}$`
|
|
91
|
+
.replace(/%/g, '(?:.|\\s)*');
|
|
92
|
+
}
|
|
93
|
+
export function commonsStringRtrim(value, characters = ' \r\n\0') {
|
|
94
|
+
const chars = characters.split('');
|
|
95
|
+
if (chars.length === 0)
|
|
96
|
+
return value;
|
|
97
|
+
while (value.length > 0 && chars.includes(value.substr(value.length - 1, 1))) {
|
|
98
|
+
value = value.substr(0, value.length - 1);
|
|
99
|
+
}
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
102
|
+
export function commonsStringLtrim(value, characters = ' \r\n\0') {
|
|
103
|
+
const chars = characters.split('');
|
|
104
|
+
if (chars.length === 0)
|
|
105
|
+
return value;
|
|
106
|
+
while (value.length > 0 && chars.includes(value.substr(0, 1))) {
|
|
107
|
+
value = value.substr(1);
|
|
108
|
+
}
|
|
109
|
+
return value;
|
|
110
|
+
}
|
|
111
|
+
export function commonsStringTrim(value, characters = ' \r\n\0') {
|
|
112
|
+
return commonsStringLtrim(commonsStringRtrim(value, characters), characters);
|
|
113
|
+
}
|
|
114
|
+
export function commonsStringSplitString(value, splitter = /[\r\n]/g, trim = true, excludeEmpty = true) {
|
|
115
|
+
return value
|
|
116
|
+
.split(splitter)
|
|
117
|
+
.map((s) => trim ? s.trim() : s)
|
|
118
|
+
.filter((s) => !excludeEmpty || s !== '');
|
|
119
|
+
}
|
|
120
|
+
// Complex word and sentence methods
|
|
121
|
+
export function commonsStringLimitLength(value, length = 128, soft = false) {
|
|
122
|
+
if (value.length <= length)
|
|
123
|
+
return value;
|
|
124
|
+
let hard = value.substr(0, length - 3); // -2 = make room for ...
|
|
125
|
+
if (!soft)
|
|
126
|
+
return `${hard}...`;
|
|
127
|
+
const fallback = hard;
|
|
128
|
+
while (hard.length > 1) {
|
|
129
|
+
if (/[^a-zA-Z0-9]/.test(hard.slice(-1)))
|
|
130
|
+
return `${hard.substr(0, hard.length - 1)}...`;
|
|
131
|
+
hard = hard.substr(0, hard.length - 1);
|
|
132
|
+
}
|
|
133
|
+
return `${fallback}...`;
|
|
134
|
+
}
|
|
135
|
+
export function commonsStringIsCapitalised(value) {
|
|
136
|
+
return /^[A-Z]+$/.test(value.replace(/[^a-z]/i, ''));
|
|
137
|
+
}
|
|
138
|
+
function capitaliseString(value, capitalised) {
|
|
139
|
+
return capitalised ? value.toUpperCase() : value;
|
|
140
|
+
}
|
|
141
|
+
export function commonsStringPluralise(singular, quantity = 2, autoDetectEndings = true) {
|
|
142
|
+
if (singular.length === 0)
|
|
143
|
+
return '';
|
|
144
|
+
if (quantity === 1)
|
|
145
|
+
return singular;
|
|
146
|
+
if (quantity === 0)
|
|
147
|
+
return commonsStringPluralise(singular, 2, autoDetectEndings);
|
|
148
|
+
const capitalised = commonsStringIsCapitalised(singular);
|
|
149
|
+
const last = singular.charAt(singular.length - 1);
|
|
150
|
+
if (!/[a-z]/i.test(last)) {
|
|
151
|
+
// doesn't end with a-z
|
|
152
|
+
return `${singular}${capitaliseString('s', capitalised)}`;
|
|
153
|
+
}
|
|
154
|
+
if (autoDetectEndings) {
|
|
155
|
+
const same = `
|
|
156
|
+
accommodation advice alms aluminum ammends
|
|
157
|
+
baggage barracks binoculars bison bourgeois breadfruit
|
|
158
|
+
cannon caribou cattle chalk chassis chinos clippers clothes clothing cod concrete corps correspondence crossroads
|
|
159
|
+
deer dice doldrums dozen dungarees
|
|
160
|
+
education eggfruit elk eyeglasses
|
|
161
|
+
flour food fruit furniture
|
|
162
|
+
gallows glasses goldfish grapefruit greenfly grouse gymnastics
|
|
163
|
+
haddock halibut headquarters help homework
|
|
164
|
+
ides information insignia
|
|
165
|
+
jackfruit jeans
|
|
166
|
+
kennels knickers knowledge kudos
|
|
167
|
+
leggings lego luggage
|
|
168
|
+
means monkfish moose mullet music
|
|
169
|
+
nailclippers news
|
|
170
|
+
offspring oxygen
|
|
171
|
+
pants passionfruit pike pliers police premises public pyjamas
|
|
172
|
+
reindeer rendezvous
|
|
173
|
+
salmon scenery scissors series shambles sheep shellfish shorts shrimp smithereens species squid staff starfruit sugar swine
|
|
174
|
+
tongs trousers trout tuna tweezers
|
|
175
|
+
wheat whitebait wood
|
|
176
|
+
you
|
|
177
|
+
`
|
|
178
|
+
.replace(/\s+/, ' ')
|
|
179
|
+
.split(' ')
|
|
180
|
+
.map((word) => commonsStringTrim(word))
|
|
181
|
+
.filter((word) => word !== '');
|
|
182
|
+
if (same.includes(singular.toLowerCase()))
|
|
183
|
+
return singular;
|
|
184
|
+
switch (singular.toLowerCase()) {
|
|
185
|
+
case 'cafe': return capitaliseString('cafes', capitalised);
|
|
186
|
+
case 'child': return capitaliseString('children', capitalised);
|
|
187
|
+
case 'woman': return capitaliseString('women', capitalised);
|
|
188
|
+
case 'man': return capitaliseString('men', capitalised);
|
|
189
|
+
case 'mouse': return capitaliseString('mice', capitalised);
|
|
190
|
+
case 'goose': return capitaliseString('geese', capitalised);
|
|
191
|
+
case 'potato': return capitaliseString('potatoes', capitalised);
|
|
192
|
+
case 'tomato': return capitaliseString('tomatoes', capitalised);
|
|
193
|
+
case 'fungus': return capitaliseString('fungae', capitalised);
|
|
194
|
+
case 'day':
|
|
195
|
+
case 'monday':
|
|
196
|
+
case 'tuesday':
|
|
197
|
+
case 'wednesday':
|
|
198
|
+
case 'thursday':
|
|
199
|
+
case 'friday':
|
|
200
|
+
case 'saturday':
|
|
201
|
+
case 'sunday':
|
|
202
|
+
return capitaliseString(`${singular.toLowerCase()}s`, capitalised);
|
|
203
|
+
}
|
|
204
|
+
if (/(craft|ies)$/.test(singular.toLowerCase()))
|
|
205
|
+
return singular;
|
|
206
|
+
if (/(ch|x|s|sh)$/i.test(singular))
|
|
207
|
+
return `${singular}${capitaliseString('es', capitalised)}`;
|
|
208
|
+
const regex1 = /^(.+)(f|fe)$/i.exec(singular);
|
|
209
|
+
if (regex1 !== null)
|
|
210
|
+
return `${regex1[1]}${capitaliseString('ves', capitalised)}`;
|
|
211
|
+
const regex2 = /^(.+[abcdfghjklmnpqrstvwxyz])y$/i.exec(singular);
|
|
212
|
+
if (regex2 !== null)
|
|
213
|
+
return `${regex2[1]}${capitaliseString('ies', capitalised)}`;
|
|
214
|
+
}
|
|
215
|
+
return `${singular}${capitaliseString('s', capitalised)}`;
|
|
216
|
+
}
|
|
217
|
+
export function commonsStringSingularise(plural) {
|
|
218
|
+
const capitalised = commonsStringIsCapitalised(plural);
|
|
219
|
+
const last = plural.charAt(plural.length - 1);
|
|
220
|
+
if (!/[a-z]/i.test(last)) {
|
|
221
|
+
// doesn't end with a-z
|
|
222
|
+
return plural;
|
|
223
|
+
}
|
|
224
|
+
if (plural.toLowerCase().endsWith('us'))
|
|
225
|
+
return plural;
|
|
226
|
+
if (plural.toLowerCase().endsWith('ess'))
|
|
227
|
+
return plural;
|
|
228
|
+
if (plural.toLowerCase().endsWith('is'))
|
|
229
|
+
return plural;
|
|
230
|
+
const same = `
|
|
231
|
+
accommodation advice alms aluminum ammends
|
|
232
|
+
baggage barracks binoculars bison bourgeois breadfruit
|
|
233
|
+
cannon caribou cattle chalk chassis chinos clippers clothes clothing cod concrete corps correspondence crossroads
|
|
234
|
+
deer dice doldrums dozen dungarees
|
|
235
|
+
education eggfruit elk eyeglasses
|
|
236
|
+
flour food fruit furniture
|
|
237
|
+
gallows glasses goldfish grapefruit greenfly grouse gymnastics
|
|
238
|
+
haddock halibut headquarters help homework
|
|
239
|
+
ides information insignia
|
|
240
|
+
jackfruit jeans
|
|
241
|
+
kennels knickers knowledge kudos
|
|
242
|
+
leggings lego luggage
|
|
243
|
+
means monkfish moose mullet music
|
|
244
|
+
nailclippers news
|
|
245
|
+
offspring oxygen
|
|
246
|
+
pants passionfruit pike pliers police premises public pyjamas
|
|
247
|
+
reindeer rendezvous
|
|
248
|
+
salmon scenery scissors series shambles sheep shellfish shorts shrimp smithereens species squid staff starfruit sugar swine
|
|
249
|
+
tongs trousers trout tuna tweezers
|
|
250
|
+
wheat whitebait wood
|
|
251
|
+
you
|
|
252
|
+
`
|
|
253
|
+
.replace(/\s+/, ' ')
|
|
254
|
+
.split(' ')
|
|
255
|
+
.map((word) => commonsStringTrim(word))
|
|
256
|
+
.filter((word) => word !== '');
|
|
257
|
+
if (same.includes(plural.toLowerCase()))
|
|
258
|
+
return plural;
|
|
259
|
+
switch (plural.toLowerCase()) {
|
|
260
|
+
case 'cafes': return capitaliseString('cafe', capitalised);
|
|
261
|
+
case 'children': return capitaliseString('child', capitalised);
|
|
262
|
+
case 'women': return capitaliseString('woman', capitalised);
|
|
263
|
+
case 'men': return capitaliseString('man', capitalised);
|
|
264
|
+
case 'mice': return capitaliseString('mouse', capitalised);
|
|
265
|
+
case 'geese': return capitaliseString('goose', capitalised);
|
|
266
|
+
case 'potatoes': return capitaliseString('potato', capitalised);
|
|
267
|
+
case 'tomatoes': return capitaliseString('tomato', capitalised);
|
|
268
|
+
case 'fungae': return capitaliseString('fungus', capitalised);
|
|
269
|
+
case 'days':
|
|
270
|
+
case 'mondays':
|
|
271
|
+
case 'tuesdays':
|
|
272
|
+
case 'wednesdays':
|
|
273
|
+
case 'thursdays':
|
|
274
|
+
case 'fridays':
|
|
275
|
+
case 'saturdays':
|
|
276
|
+
case 'sundays':
|
|
277
|
+
return capitaliseString(plural.substring(0, plural.length - 1).toLowerCase(), capitalised);
|
|
278
|
+
}
|
|
279
|
+
if (/(craft|ies)$/.test(plural.toLowerCase()))
|
|
280
|
+
return plural;
|
|
281
|
+
if (/(ch|x|s|sh)es$/i.test(plural))
|
|
282
|
+
return plural.substring(0, plural.length - 2);
|
|
283
|
+
const regex1 = /^(.+)ves$/i.exec(plural);
|
|
284
|
+
if (regex1 !== null)
|
|
285
|
+
return `${regex1[1]}${capitaliseString('f', capitalised)}`; // not ideal, as it conflates 'f' and 'fe' suffixes
|
|
286
|
+
const regex2 = /^(.+[abcdfghjklmnpqrstvwxyz])ies$/i.exec(plural);
|
|
287
|
+
if (regex2 !== null)
|
|
288
|
+
return `${regex2[1]}${capitaliseString('y', capitalised)}`;
|
|
289
|
+
if (!plural.toLowerCase().endsWith('s'))
|
|
290
|
+
return plural;
|
|
291
|
+
return plural.substring(0, plural.length - 1);
|
|
292
|
+
}
|
|
293
|
+
function noOrNumber(quantity, none = false, capitaliseNoNone = false) {
|
|
294
|
+
if (quantity === 0) {
|
|
295
|
+
const wording = none ? 'none' : 'no';
|
|
296
|
+
return capitaliseNoNone ? commonsStringUcWords(wording) : wording;
|
|
297
|
+
}
|
|
298
|
+
return quantity.toString();
|
|
299
|
+
}
|
|
300
|
+
export function commonsStringQuantify(singular, quantity, autoDetectEndings = true, capitaliseNoNone = false) {
|
|
301
|
+
if (singular.length === 0)
|
|
302
|
+
return noOrNumber(quantity, true, capitaliseNoNone);
|
|
303
|
+
const capitalised = commonsStringIsCapitalised(singular);
|
|
304
|
+
return capitaliseString(`${noOrNumber(quantity, false, capitaliseNoNone)} ${commonsStringPluralise(singular, quantity, autoDetectEndings)}`, capitalised);
|
|
305
|
+
}
|
|
306
|
+
function isVowelOrY(c) {
|
|
307
|
+
return commonsStringIsVowel(c) || c.toLowerCase() === 'y';
|
|
308
|
+
}
|
|
309
|
+
function isConsonantNotY(c) {
|
|
310
|
+
return commonsStringIsConsonant(c) && c.toLowerCase() !== 'y';
|
|
311
|
+
}
|
|
312
|
+
export function commonsStringSplitWords(sentence, allowHyphens = true, allowApostrophies = false) {
|
|
313
|
+
if (!allowHyphens)
|
|
314
|
+
sentence = sentence.replace('-', ' - ');
|
|
315
|
+
if (!allowApostrophies)
|
|
316
|
+
sentence = sentence.replace('\'', ' \' ');
|
|
317
|
+
return sentence
|
|
318
|
+
.split(/[^-'A-Za-z]/)
|
|
319
|
+
.map((word) => commonsStringTrim(word))
|
|
320
|
+
.filter((word) => word !== '');
|
|
321
|
+
}
|
|
322
|
+
export function commonsStringInternalRoughSyllables(word) {
|
|
323
|
+
// assumes that syllables consist of vowels in the center of each syllable
|
|
324
|
+
const chars = commonsStringTrim(word.toLowerCase()).split('');
|
|
325
|
+
const stack = [];
|
|
326
|
+
let allowConsume = false;
|
|
327
|
+
let build = '';
|
|
328
|
+
let reset = true;
|
|
329
|
+
while (true) {
|
|
330
|
+
const c = chars.shift();
|
|
331
|
+
if (c === undefined)
|
|
332
|
+
break;
|
|
333
|
+
if (!commonsStringIsAlphabet(c)) { // non-character
|
|
334
|
+
if (build.length > 0)
|
|
335
|
+
stack.push(build);
|
|
336
|
+
build = '';
|
|
337
|
+
reset = true;
|
|
338
|
+
allowConsume = false; // don't consume future single consonant
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
const isVowel = isVowelOrY(c);
|
|
342
|
+
if (allowConsume && isVowel) { // double vowel; concatinate with last
|
|
343
|
+
stack.push(`${stack.pop()}${c}`);
|
|
344
|
+
allowConsume = true; // consume future single consonant
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
if (allowConsume && !isVowel) {
|
|
348
|
+
// append to last stacked word
|
|
349
|
+
stack.push(`${stack.pop()}${c}`);
|
|
350
|
+
allowConsume = false; // don't consume future single consonant
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
if (isVowel) {
|
|
354
|
+
if (chars.length === 0 && stack.length > 0 && !reset) {
|
|
355
|
+
// absorb terminal vowels
|
|
356
|
+
stack.push(`${stack.pop()}${c}`);
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
stack.push(`${build}${c}`);
|
|
360
|
+
build = '';
|
|
361
|
+
allowConsume = true;
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
build += c;
|
|
365
|
+
}
|
|
366
|
+
if (build !== '') {
|
|
367
|
+
if (build.length > 1) {
|
|
368
|
+
stack.push(build);
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
stack.push(`${stack.pop()}${build}`);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
// attempt to make syllables start with consonants where possible
|
|
375
|
+
for (let i = 1; i < stack.length; i++) {
|
|
376
|
+
if (stack[i - 1].length < 2)
|
|
377
|
+
continue;
|
|
378
|
+
if (isVowelOrY(stack[i].charAt(0)) && isConsonantNotY(stack[i - 1].slice(-1))) {
|
|
379
|
+
stack[i] = `${stack[i - 1].slice(-1)}${stack[i]}`;
|
|
380
|
+
stack[i - 1] = stack[i - 1].slice(0, stack[i - 1].length - 1);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return stack;
|
|
384
|
+
}
|
|
385
|
+
export function commonsStringRoughSyllables(wordOrWords) {
|
|
386
|
+
// assumes that syllables consist of vowels in the center of each syllable
|
|
387
|
+
// it gets complicated trying to cater for multiple words, so we just split and process for each
|
|
388
|
+
const total = [];
|
|
389
|
+
for (const word of commonsStringSplitWords(wordOrWords)) {
|
|
390
|
+
const syllables = commonsStringInternalRoughSyllables(word);
|
|
391
|
+
for (const syllable of syllables)
|
|
392
|
+
total.push(syllable);
|
|
393
|
+
}
|
|
394
|
+
return total;
|
|
395
|
+
}
|
|
396
|
+
export function commonsStringSplitSentences(paragraph, breakChars = /[.!?]/, allowDecimals = true, breakOnMultipleHyphens = true) {
|
|
397
|
+
if (breakOnMultipleHyphens) {
|
|
398
|
+
// multiple hyphens count as breaks; single count as hyphenated words
|
|
399
|
+
paragraph = paragraph.replace(/-{2,}/g, '. ');
|
|
400
|
+
}
|
|
401
|
+
if (!breakChars.test('\r')) {
|
|
402
|
+
paragraph = paragraph.replace(/\r/, ' ');
|
|
403
|
+
}
|
|
404
|
+
if (!breakChars.test('\n')) {
|
|
405
|
+
paragraph = paragraph.replace(/\n/, ' ');
|
|
406
|
+
}
|
|
407
|
+
// We don't use split, as we want to preserve the break characters
|
|
408
|
+
const chars = commonsStringTrim(paragraph).split('');
|
|
409
|
+
const sentences = [];
|
|
410
|
+
let build = '';
|
|
411
|
+
while (true) {
|
|
412
|
+
const c = chars.shift();
|
|
413
|
+
if (c === undefined)
|
|
414
|
+
break;
|
|
415
|
+
if (breakChars.test(c)) {
|
|
416
|
+
if (build === '' && sentences.length > 0) {
|
|
417
|
+
// concatenate multiple break characters onto the end of the last sentence
|
|
418
|
+
sentences.push(`${sentences.pop()}${c}`);
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
if (commonsStringTrim(build) === '') {
|
|
422
|
+
// nothing to push
|
|
423
|
+
build = '';
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
if (!allowDecimals
|
|
427
|
+
|| !/[-0-9]/.test(build.slice(-1))
|
|
428
|
+
|| chars.length === 0
|
|
429
|
+
|| !/[0-9]/.test(chars[0])) {
|
|
430
|
+
sentences.push(`${commonsStringLtrim(build)}${c}`);
|
|
431
|
+
build = '';
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
build += c;
|
|
436
|
+
}
|
|
437
|
+
if (commonsStringTrim(build) !== '')
|
|
438
|
+
sentences.push(commonsStringTrim(build));
|
|
439
|
+
return sentences;
|
|
440
|
+
}
|
|
441
|
+
export function commonsStringFleschKincaidReadingEase(paragraph) {
|
|
442
|
+
const words = commonsStringSplitWords(paragraph);
|
|
443
|
+
const sentences = commonsStringSplitSentences(paragraph);
|
|
444
|
+
const syllables = commonsStringRoughSyllables(paragraph);
|
|
445
|
+
return 206.835 - (1.015 * (words.length / sentences.length)) - (84.6 * (syllables.length / words.length));
|
|
446
|
+
}
|
|
447
|
+
export function commonsStringAutomatedReadabilityIndex(paragraph) {
|
|
448
|
+
const words = commonsStringSplitWords(paragraph);
|
|
449
|
+
const sentences = commonsStringSplitSentences(paragraph);
|
|
450
|
+
const characters = [];
|
|
451
|
+
for (const word of words) {
|
|
452
|
+
for (const c of word.split('')) {
|
|
453
|
+
if (commonsStringIsAlphabet(c))
|
|
454
|
+
characters.push(c);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
return (4.71 * (characters.length / words.length)) + (0.5 * (words.length / sentences.length)) - 21.43;
|
|
458
|
+
}
|
|
459
|
+
export function commonsStringSanitiseExtendedUnicodeChars(src, options = {}) {
|
|
460
|
+
options = {
|
|
461
|
+
trim: true,
|
|
462
|
+
dashes: true,
|
|
463
|
+
quotes: true,
|
|
464
|
+
backTick: true,
|
|
465
|
+
spaces: true,
|
|
466
|
+
ellipsis: true,
|
|
467
|
+
blank: true,
|
|
468
|
+
bullets: true,
|
|
469
|
+
...options
|
|
470
|
+
};
|
|
471
|
+
if (options.trim)
|
|
472
|
+
src = src.trim();
|
|
473
|
+
if (options.dashes)
|
|
474
|
+
src = src.replace(/[-\u058a\u05be\u1400\u1806\u2010-\u2015\u2053\u207b\u208b\u2212\u2e17\u2e1a\u2e3a\u2e3b\u2e40\u2e5d\u301c\u3030\u30a0\ufe31\ufe32\ufe58\ufe63\uff0d]|\uD803\udead/g, '-');
|
|
475
|
+
if (options.quotes)
|
|
476
|
+
src = src.replace(/[\u2018\u2019\u201a\u201b]/g, '\'').replace(/[\u201c-\u201f]/g, '"');
|
|
477
|
+
if (options.backTick)
|
|
478
|
+
src = src.replace(/`/g, '\'');
|
|
479
|
+
if (options.spaces)
|
|
480
|
+
src = src.replace(/[\u00a0\u2000-\u200c\u202f\ufeff]/g, ' ');
|
|
481
|
+
if (options.ellipsis)
|
|
482
|
+
src = src.replace(/\u2026/, '...');
|
|
483
|
+
if (options.blank)
|
|
484
|
+
src = src.replace(/[\u200d\u2060]/g, '');
|
|
485
|
+
if (options.bullets)
|
|
486
|
+
src = src.replace(/[\u2022]/g, '*');
|
|
487
|
+
return src;
|
|
488
|
+
}
|
|
489
|
+
export function commonsStringBuildPunctuationRegexString(chars) {
|
|
490
|
+
const charsArray = commonsTypeIsString(chars) ? chars.split('') : [...chars];
|
|
491
|
+
const hyphenIndex = charsArray.indexOf('-');
|
|
492
|
+
if (hyphenIndex > -1) {
|
|
493
|
+
charsArray.splice(hyphenIndex, 1);
|
|
494
|
+
charsArray.unshift('-');
|
|
495
|
+
}
|
|
496
|
+
for (let i = charsArray.length; i-- > 0;) {
|
|
497
|
+
if (charsArray[i] === ']')
|
|
498
|
+
charsArray[i] = '\\]';
|
|
499
|
+
if (charsArray[i] === '\\')
|
|
500
|
+
charsArray[i] = '\\\\';
|
|
501
|
+
}
|
|
502
|
+
return `[${charsArray.join('')}]`;
|
|
503
|
+
}
|
|
504
|
+
export var ECommonsTokeniseHyphenSplit;
|
|
505
|
+
(function (ECommonsTokeniseHyphenSplit) {
|
|
506
|
+
ECommonsTokeniseHyphenSplit["ALL"] = "all";
|
|
507
|
+
ECommonsTokeniseHyphenSplit["NONE"] = "none";
|
|
508
|
+
ECommonsTokeniseHyphenSplit["MULTIPLE"] = "multiple"; // split on multiple, e.g. She said--because she was minded to--that they would go there later.
|
|
509
|
+
})(ECommonsTokeniseHyphenSplit || (ECommonsTokeniseHyphenSplit = {}));
|
|
510
|
+
export function commonsStringTokenise(text, puncChars = COMMONS_DEFAULT_PUNCTUATION_CHARACTERS, options = {}) {
|
|
511
|
+
options = {
|
|
512
|
+
hyphenSplit: ECommonsTokeniseHyphenSplit.ALL,
|
|
513
|
+
keepNonSpacedPunctuation: false,
|
|
514
|
+
returnPunctuationAsWords: true,
|
|
515
|
+
...options
|
|
516
|
+
};
|
|
517
|
+
options.sanitiseExtendedUnicodeChars = {
|
|
518
|
+
dashes: false,
|
|
519
|
+
quotes: false,
|
|
520
|
+
backTick: false,
|
|
521
|
+
ellipsis: false,
|
|
522
|
+
blank: false,
|
|
523
|
+
...options.sanitiseExtendedUnicodeChars
|
|
524
|
+
};
|
|
525
|
+
const PUNC_CHARS_ARRAY = commonsTypeIsString(puncChars) ? puncChars.split('') : [...puncChars];
|
|
526
|
+
switch (options.hyphenSplit) {
|
|
527
|
+
case ECommonsTokeniseHyphenSplit.ALL:
|
|
528
|
+
// add hyphens to the punctuation characters
|
|
529
|
+
PUNC_CHARS_ARRAY.push('-');
|
|
530
|
+
break;
|
|
531
|
+
case ECommonsTokeniseHyphenSplit.MULTIPLE:
|
|
532
|
+
// consider hyphens a non-punctuation character
|
|
533
|
+
// but pre-expand any multiples in the text
|
|
534
|
+
text = text.replace(/-{2,}/g, ' - ');
|
|
535
|
+
break;
|
|
536
|
+
default:
|
|
537
|
+
// consider hyphens a non-punctuation character
|
|
538
|
+
break;
|
|
539
|
+
}
|
|
540
|
+
const regexChars = commonsStringBuildPunctuationRegexString(puncChars);
|
|
541
|
+
const ANY_PUNC = new RegExp(`(${regexChars})`, 'g');
|
|
542
|
+
const START_PUNC = new RegExp(`(^|\\s)(${regexChars})`, 'g');
|
|
543
|
+
const END_PUNC = new RegExp(`(${regexChars})($|\\s)`, 'g');
|
|
544
|
+
text = commonsStringSanitiseExtendedUnicodeChars(text.replace(/\s/g, ' '), {
|
|
545
|
+
...options.sanitiseExtendedUnicodeChars,
|
|
546
|
+
trim: true,
|
|
547
|
+
spaces: true
|
|
548
|
+
});
|
|
549
|
+
if (options.keepNonSpacedPunctuation) {
|
|
550
|
+
text = text
|
|
551
|
+
.replace(START_PUNC, ' $2 ') // space before punc
|
|
552
|
+
.replace(END_PUNC, ' $1 '); // space after punc
|
|
553
|
+
// have to correct for words that have multi-punctionation
|
|
554
|
+
const rebuild = [];
|
|
555
|
+
for (let word of text.split(' ')) {
|
|
556
|
+
const tail = [];
|
|
557
|
+
while (true) {
|
|
558
|
+
if (word === '')
|
|
559
|
+
break;
|
|
560
|
+
if (PUNC_CHARS_ARRAY.includes(word[0])) {
|
|
561
|
+
rebuild.push(word[0]);
|
|
562
|
+
word = word.substring(1);
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
565
|
+
if (PUNC_CHARS_ARRAY.includes(word[word.length - 1])) {
|
|
566
|
+
tail.unshift(word[word.length - 1]);
|
|
567
|
+
word = word.substring(0, word.length - 1);
|
|
568
|
+
continue;
|
|
569
|
+
}
|
|
570
|
+
break;
|
|
571
|
+
}
|
|
572
|
+
rebuild.push(word);
|
|
573
|
+
rebuild.push(...tail);
|
|
574
|
+
}
|
|
575
|
+
text = rebuild.join(' ');
|
|
576
|
+
}
|
|
577
|
+
else {
|
|
578
|
+
text = text
|
|
579
|
+
.replace(ANY_PUNC, ' $1 ');
|
|
580
|
+
}
|
|
581
|
+
return text
|
|
582
|
+
.split(' ')
|
|
583
|
+
.map((s) => s.trim())
|
|
584
|
+
.filter((s) => {
|
|
585
|
+
if (s === '')
|
|
586
|
+
return false;
|
|
587
|
+
if (PUNC_CHARS_ARRAY.includes(s))
|
|
588
|
+
return options.returnPunctuationAsWords || false;
|
|
589
|
+
return true;
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
export function commonsStringTokensToSentences(tokens, terminalPuncChars = '.?!', allowDotAfterAbbreviatedWords = []) {
|
|
593
|
+
const TERMINAL_CHARS_ARRAY = commonsTypeIsString(terminalPuncChars) ? terminalPuncChars.split('') : [...terminalPuncChars];
|
|
594
|
+
const sentences = [];
|
|
595
|
+
let current = [];
|
|
596
|
+
let lastWord;
|
|
597
|
+
while (true) {
|
|
598
|
+
const next = tokens.shift();
|
|
599
|
+
if (!next)
|
|
600
|
+
break;
|
|
601
|
+
if (TERMINAL_CHARS_ARRAY.includes(next)) {
|
|
602
|
+
if (next === '.' && lastWord && allowDotAfterAbbreviatedWords.includes(lastWord)) {
|
|
603
|
+
// ignore words like Mr. Smith
|
|
604
|
+
continue;
|
|
605
|
+
}
|
|
606
|
+
sentences.push([...current, next]);
|
|
607
|
+
current = [];
|
|
608
|
+
lastWord = undefined;
|
|
609
|
+
continue;
|
|
610
|
+
}
|
|
611
|
+
current.push(next);
|
|
612
|
+
lastWord = next;
|
|
613
|
+
}
|
|
614
|
+
if (current.length > 0)
|
|
615
|
+
sentences.push(current);
|
|
616
|
+
return sentences;
|
|
617
|
+
}
|
|
618
|
+
export function commonsStringNormaliseAccents(s) {
|
|
619
|
+
return s.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
|
|
620
|
+
}
|
|
621
|
+
export function commonsStringGobblePrefix(s, gobbleUntil, includeUntil = false) {
|
|
622
|
+
if (gobbleUntil instanceof RegExp) {
|
|
623
|
+
const clone = new RegExp(gobbleUntil);
|
|
624
|
+
let i = s.search(clone);
|
|
625
|
+
if (i === -1)
|
|
626
|
+
return s;
|
|
627
|
+
if (!includeUntil) {
|
|
628
|
+
const match = clone.exec(s.substring(i));
|
|
629
|
+
if (!match)
|
|
630
|
+
throw new Error('Regex search found a match, but subsequent exec did not match. This may be a regex specific error');
|
|
631
|
+
const matched = match[0];
|
|
632
|
+
i += matched.length;
|
|
633
|
+
}
|
|
634
|
+
return s.substring(i);
|
|
635
|
+
}
|
|
636
|
+
else {
|
|
637
|
+
let i = s.indexOf(gobbleUntil);
|
|
638
|
+
if (i === -1)
|
|
639
|
+
return s;
|
|
640
|
+
if (!includeUntil)
|
|
641
|
+
i += gobbleUntil.length;
|
|
642
|
+
return s.substring(i);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
export function commonsStringGobbleSuffix(s, gobbleFrom, includeFrom = false) {
|
|
646
|
+
if (gobbleFrom instanceof RegExp) {
|
|
647
|
+
const clone = new RegExp(gobbleFrom);
|
|
648
|
+
// this is a nasty inefficient way of doing it, but struggling to come up with a better way
|
|
649
|
+
if (!clone.test(s))
|
|
650
|
+
return s;
|
|
651
|
+
let i = s.length;
|
|
652
|
+
while (true) {
|
|
653
|
+
if (clone.test(s.substring(i)))
|
|
654
|
+
break;
|
|
655
|
+
i--;
|
|
656
|
+
if (i < 0)
|
|
657
|
+
return s;
|
|
658
|
+
}
|
|
659
|
+
const match = clone.exec(s);
|
|
660
|
+
if (!match)
|
|
661
|
+
throw new Error('Test for suffix returned a gt 0 result but then that wasn\'t found in the regex exec. Possibly the regex is malformed?');
|
|
662
|
+
if (includeFrom)
|
|
663
|
+
i += match[0].length;
|
|
664
|
+
return s.substring(0, i);
|
|
665
|
+
}
|
|
666
|
+
else {
|
|
667
|
+
let i = s.lastIndexOf(gobbleFrom);
|
|
668
|
+
if (i === -1)
|
|
669
|
+
return s;
|
|
670
|
+
if (includeFrom)
|
|
671
|
+
i += gobbleFrom.length;
|
|
672
|
+
return s.substring(0, i);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
export function commonsStringGobblePrefixAndSuffix(s, gobbleUntil, gobbleFrom, includeUntilAndFrom = false) {
|
|
676
|
+
s = commonsStringGobblePrefix(s, gobbleUntil, includeUntilAndFrom);
|
|
677
|
+
s = commonsStringGobbleSuffix(s, gobbleFrom, includeUntilAndFrom);
|
|
678
|
+
return s;
|
|
679
|
+
}
|
|
680
|
+
//# sourceMappingURL=commons-string.mjs.map
|