utilitish 0.0.6 → 0.0.7
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/array/array-constructor.js +5 -5
- package/dist/array/array-constructor.spec.d.ts +2 -0
- package/dist/array/array-constructor.spec.js +130 -0
- package/dist/array/array-prototype.d.ts +341 -84
- package/dist/array/array-prototype.js +38 -53
- package/dist/array/array-prototype.spec.d.ts +1 -0
- package/dist/array/array-prototype.spec.js +536 -0
- package/dist/map/map-prototype.d.ts +69 -9
- package/dist/map/map-prototype.js +16 -3
- package/dist/map/map-prototype.spec.d.ts +1 -0
- package/dist/map/map-prototype.spec.js +261 -0
- package/dist/object/object-prototype.d.ts +61 -8
- package/dist/object/object-prototype.js +9 -0
- package/dist/object/object-prototype.spec.d.ts +1 -0
- package/dist/object/object-prototype.spec.js +110 -0
- package/dist/set/set-prototype.d.ts +83 -5
- package/dist/set/set-prototype.js +21 -6
- package/dist/set/set-prototype.spec.d.ts +1 -0
- package/dist/set/set-prototype.spec.js +122 -0
- package/dist/string/string-prototype.d.ts +143 -24
- package/dist/string/string-prototype.js +41 -11
- package/dist/string/string-prototype.spec.d.ts +1 -0
- package/dist/string/string-prototype.spec.js +115 -0
- package/dist/utils/logic.utils.d.ts +3 -0
- package/dist/utils/logic.utils.js +41 -0
- package/package.json +1 -1
- /package/dist/{utils.d.ts → utils/core.utils.d.ts} +0 -0
- /package/dist/{utils.js → utils/core.utils.js} +0 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
require("../set/set-prototype");
|
|
4
|
+
describe('Set.prototype', () => {
|
|
5
|
+
describe('toList()', () => {
|
|
6
|
+
it('should return array with all values in insertion order', () => {
|
|
7
|
+
const set = new Set([3, 1, 2]);
|
|
8
|
+
expect(set.toList()).toEqual([3, 1, 2]);
|
|
9
|
+
});
|
|
10
|
+
it('should return empty array when set is empty', () => {
|
|
11
|
+
const set = new Set();
|
|
12
|
+
expect(set.toList()).toEqual([]);
|
|
13
|
+
});
|
|
14
|
+
it('should return a new array instance (not same reference)', () => {
|
|
15
|
+
const set = new Set([1, 2, 3]);
|
|
16
|
+
const arr = set.toList();
|
|
17
|
+
expect(Array.isArray(arr)).toBe(true);
|
|
18
|
+
expect(arr).not.toBe(set);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
describe('hasAny()', () => {
|
|
22
|
+
describe('with multiple items', () => {
|
|
23
|
+
it('should return true when at least one item is present', () => {
|
|
24
|
+
const set = new Set([1, 2, 3]);
|
|
25
|
+
expect(set.hasAny(0, 2)).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
it('should return false when no items are present', () => {
|
|
28
|
+
const set = new Set([1, 2, 3]);
|
|
29
|
+
expect(set.hasAny(4, 5)).toBe(false);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
describe('with edge cases', () => {
|
|
33
|
+
it('should return false when called with no arguments', () => {
|
|
34
|
+
const set = new Set([1, 2, 3]);
|
|
35
|
+
expect(set.hasAny()).toBe(false);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
describe('includes()', () => {
|
|
40
|
+
describe('with multiple items as arguments', () => {
|
|
41
|
+
it('should return true when all items are present', () => {
|
|
42
|
+
const set = new Set([1, 2, 3]);
|
|
43
|
+
expect(set.includes(1, 2)).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
it('should return false when at least one item is missing', () => {
|
|
46
|
+
const set = new Set([1, 2, 3]);
|
|
47
|
+
expect(set.includes(1, 4)).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
describe('with Set as argument', () => {
|
|
51
|
+
it('should return true when all items from Set are present', () => {
|
|
52
|
+
const set = new Set([1, 2, 3]);
|
|
53
|
+
expect(set.includes(new Set([1, 2]))).toBe(true);
|
|
54
|
+
});
|
|
55
|
+
it('should return false when some items from Set are missing', () => {
|
|
56
|
+
const set = new Set([1, 2, 3]);
|
|
57
|
+
expect(set.includes(new Set([1, 4]))).toBe(false);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
describe('with edge cases', () => {
|
|
61
|
+
it('should return true when called with no arguments', () => {
|
|
62
|
+
const set = new Set([1, 2, 3]);
|
|
63
|
+
expect(set.includes()).toBe(true);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
describe('union()', () => {
|
|
68
|
+
describe('with multiple Sets', () => {
|
|
69
|
+
it('should return a new Set with all unique values', () => {
|
|
70
|
+
const a = new Set([1, 2]);
|
|
71
|
+
const b = new Set([2, 3]);
|
|
72
|
+
expect(a.union(b)).toEqual(new Set([1, 2, 3]));
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
describe('with no arguments', () => {
|
|
76
|
+
it('should return a copy of the Set when no arguments provided', () => {
|
|
77
|
+
const a = new Set([1, 2]);
|
|
78
|
+
expect(a.union()).toEqual(new Set([1, 2]));
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
describe('error handling', () => {
|
|
82
|
+
it('should throw TypeError when argument is not a Set', () => {
|
|
83
|
+
const a = new Set([1, 2]);
|
|
84
|
+
// @ts-expect-error
|
|
85
|
+
expect(() => a.union([3, 4])).toThrow(TypeError);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
describe('intersection()', () => {
|
|
90
|
+
describe('with multiple Sets', () => {
|
|
91
|
+
it('should return a new Set with only common values', () => {
|
|
92
|
+
const a = new Set([1, 2, 3]);
|
|
93
|
+
const b = new Set([2, 3, 4]);
|
|
94
|
+
expect(a.intersection(b)).toEqual(new Set([2, 3]));
|
|
95
|
+
});
|
|
96
|
+
it('should return empty Set when no common values exist', () => {
|
|
97
|
+
const a = new Set([1, 2]);
|
|
98
|
+
const b = new Set([3, 4]);
|
|
99
|
+
expect(a.intersection(b)).toEqual(new Set());
|
|
100
|
+
});
|
|
101
|
+
it('should work with multiple Sets at once', () => {
|
|
102
|
+
const a = new Set([1, 2, 3, 4]);
|
|
103
|
+
const b = new Set([2, 3, 5]);
|
|
104
|
+
const c = new Set([3, 6]);
|
|
105
|
+
expect(a.intersection(b, c)).toEqual(new Set([3]));
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
describe('with no arguments', () => {
|
|
109
|
+
it('should return a copy of the Set when no arguments provided', () => {
|
|
110
|
+
const a = new Set([1, 2]);
|
|
111
|
+
expect(a.intersection()).toEqual(new Set([1, 2]));
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
describe('error handling', () => {
|
|
115
|
+
it('should throw TypeError when argument is not a Set', () => {
|
|
116
|
+
const a = new Set([1, 2]);
|
|
117
|
+
// @ts-expect-error
|
|
118
|
+
expect(() => a.intersection([2])).toThrow(TypeError);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
@@ -2,60 +2,179 @@ export {};
|
|
|
2
2
|
declare global {
|
|
3
3
|
interface String {
|
|
4
4
|
/**
|
|
5
|
-
* Capitalizes the first character of the string.
|
|
6
|
-
*
|
|
5
|
+
* Capitalizes the first character of the string (uppercase) and keeps the rest unchanged.
|
|
6
|
+
*
|
|
7
|
+
* @this {string} The string to capitalize
|
|
8
|
+
* @returns {string} A new string with the first character in uppercase
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* 'hello world'.capitalize(); // 'Hello world'
|
|
12
|
+
* 'HELLO'.capitalize(); // 'HELLO'
|
|
13
|
+
*
|
|
14
|
+
* @remarks
|
|
15
|
+
* - Only affects the first character
|
|
16
|
+
* - Returns an empty string for empty input
|
|
17
|
+
* - Does not normalize the rest of the string
|
|
7
18
|
*/
|
|
8
19
|
capitalize(): string;
|
|
9
20
|
/**
|
|
10
|
-
* Splits the string into an array of words
|
|
11
|
-
*
|
|
21
|
+
* Splits the string into an array of words by detecting camelCase, kebab-case, snake_case, and spaces.
|
|
22
|
+
* Useful as a foundation for case conversion methods.
|
|
23
|
+
*
|
|
24
|
+
* @this {string} The string to split
|
|
25
|
+
* @returns {string[]} An array of individual words extracted from the string
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* 'helloWorld'.splitWords(); // ['hello', 'World']
|
|
29
|
+
* 'hello-world'.splitWords(); // ['hello', 'world']
|
|
30
|
+
* 'hello_world'.splitWords(); // ['hello', 'world']
|
|
31
|
+
* 'HelloWorld'.splitWords(); // ['Hello', 'World']
|
|
32
|
+
*
|
|
33
|
+
* @remarks
|
|
34
|
+
* - Handles transitions from lowercase to uppercase (camelCase)
|
|
35
|
+
* - Handles consecutive uppercase letters (HTMLParser → HTML Parser)
|
|
36
|
+
* - Treats spaces, hyphens, and underscores as word separators
|
|
37
|
+
* - Filters out empty strings
|
|
12
38
|
*/
|
|
13
39
|
splitWords(): string[];
|
|
14
40
|
/**
|
|
15
|
-
* Converts the string to camelCase.
|
|
16
|
-
*
|
|
41
|
+
* Converts the string to camelCase format.
|
|
42
|
+
*
|
|
43
|
+
* @this {string} The string to convert
|
|
44
|
+
* @returns {string} The camelCased version of the string
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* 'hello-world'.camelCase(); // 'helloWorld'
|
|
48
|
+
* 'hello_world'.camelCase(); // 'helloWorld'
|
|
49
|
+
* 'HelloWorld'.camelCase(); // 'helloWorld'
|
|
50
|
+
*
|
|
51
|
+
* @remarks
|
|
52
|
+
* - First word is lowercase, subsequent words have uppercase first letter
|
|
53
|
+
* - Uses `splitWords()` internally to handle various naming conventions
|
|
17
54
|
*/
|
|
18
55
|
camelCase(): string;
|
|
19
56
|
/**
|
|
20
|
-
* Converts the string to kebab-case.
|
|
21
|
-
*
|
|
57
|
+
* Converts the string to kebab-case format.
|
|
58
|
+
*
|
|
59
|
+
* @this {string} The string to convert
|
|
60
|
+
* @returns {string} The kebab-cased version of the string
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* 'helloWorld'.kebabCase(); // 'hello-world'
|
|
64
|
+
* 'hello_world'.kebabCase(); // 'hello-world'
|
|
65
|
+
* 'HelloWorld'.kebabCase(); // 'hello-world'
|
|
66
|
+
*
|
|
67
|
+
* @remarks
|
|
68
|
+
* - All letters are lowercase
|
|
69
|
+
* - Words are separated by hyphens
|
|
70
|
+
* - Uses `splitWords()` internally
|
|
22
71
|
*/
|
|
23
72
|
kebabCase(): string;
|
|
24
73
|
/**
|
|
25
|
-
* Converts the string to snake_case.
|
|
26
|
-
*
|
|
74
|
+
* Converts the string to snake_case format.
|
|
75
|
+
*
|
|
76
|
+
* @this {string} The string to convert
|
|
77
|
+
* @returns {string} The snake_cased version of the string
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* 'helloWorld'.snakeCase(); // 'hello_world'
|
|
81
|
+
* 'hello-world'.snakeCase(); // 'hello_world'
|
|
82
|
+
* 'HelloWorld'.snakeCase(); // 'hello_world'
|
|
83
|
+
*
|
|
84
|
+
* @remarks
|
|
85
|
+
* - All letters are lowercase
|
|
86
|
+
* - Words are separated by underscores
|
|
87
|
+
* - Uses `splitWords()` internally
|
|
27
88
|
*/
|
|
28
89
|
snakeCase(): string;
|
|
29
90
|
/**
|
|
30
91
|
* Truncates the string to a maximum number of characters, appending '...' if truncated.
|
|
31
|
-
*
|
|
32
|
-
* @
|
|
92
|
+
*
|
|
93
|
+
* @this {string} The string to truncate
|
|
94
|
+
* @param {number} n - Maximum length of the result (not including the '...')
|
|
95
|
+
* @returns {string} The truncated string with '...' appended if truncated, otherwise the original string
|
|
96
|
+
* @throws {TypeError} If n is not a non-negative integer
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* 'hello world'.truncate(5); // 'hello...'
|
|
100
|
+
* 'hello'.truncate(10); // 'hello'
|
|
101
|
+
*
|
|
102
|
+
* @remarks
|
|
103
|
+
* - The '...' is added after the truncated portion, so total length is n + 3
|
|
104
|
+
* - Negative or non-integer values throw an error
|
|
33
105
|
*/
|
|
34
106
|
truncate(n: number): string;
|
|
35
107
|
/**
|
|
36
|
-
* Reverses the characters in the string.
|
|
37
|
-
*
|
|
108
|
+
* Reverses the characters in the string, properly handling Unicode surrogate pairs.
|
|
109
|
+
*
|
|
110
|
+
* @this {string} The string to reverse
|
|
111
|
+
* @returns {string} The reversed string
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* 'hello'.reverse(); // 'olleh'
|
|
115
|
+
* '👋world'.reverse(); // 'dlrow👋'
|
|
116
|
+
*
|
|
117
|
+
* @remarks
|
|
118
|
+
* - Uses spread operator to properly handle Unicode characters
|
|
119
|
+
* - Works correctly with emoji and other multi-byte characters
|
|
38
120
|
*/
|
|
39
121
|
reverse(): string;
|
|
40
122
|
/**
|
|
41
|
-
* Checks if the string is empty or contains only whitespace.
|
|
42
|
-
*
|
|
123
|
+
* Checks if the string is empty or contains only whitespace characters.
|
|
124
|
+
*
|
|
125
|
+
* @this {string} The string to check
|
|
126
|
+
* @returns {boolean} True if the string is empty or whitespace-only, false otherwise
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ''.isEmpty(); // true
|
|
130
|
+
* ' '.isEmpty(); // true
|
|
131
|
+
* 'hello'.isEmpty(); // false
|
|
132
|
+
* ' hello '.isEmpty(); // false
|
|
133
|
+
*
|
|
134
|
+
* @remarks
|
|
135
|
+
* - Uses `trim()` internally, so handles all whitespace characters
|
|
43
136
|
*/
|
|
44
137
|
isEmpty(): boolean;
|
|
45
138
|
/**
|
|
46
|
-
* Converts the string into a slug
|
|
47
|
-
*
|
|
139
|
+
* Converts the string into a URL-friendly slug format.
|
|
140
|
+
* Combines normalization, lowercasing, whitespace handling, and special character removal.
|
|
141
|
+
*
|
|
142
|
+
* @this {string} The string to slugify
|
|
143
|
+
* @returns {string} A URL-safe slug version of the string
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* 'Hello World'.slugify(); // 'hello-world'
|
|
147
|
+
* 'Héllo Wørld'.slugify(); // 'hello-world'
|
|
148
|
+
* 'Hello World!!!'.slugify(); // 'hello-world'
|
|
149
|
+
*
|
|
150
|
+
* @remarks
|
|
151
|
+
* - Normalizes Unicode characters (NFD decomposition)
|
|
152
|
+
* - Removes accents and diacritical marks
|
|
153
|
+
* - Converts to lowercase
|
|
154
|
+
* - Replaces spaces and special characters with hyphens
|
|
155
|
+
* - Removes leading/trailing hyphens
|
|
156
|
+
* - Collapses multiple consecutive hyphens into one
|
|
48
157
|
*/
|
|
49
158
|
slugify(): string;
|
|
50
159
|
/**
|
|
51
160
|
* Replaces a substring between `start` and `end` indices with a given string.
|
|
52
|
-
*
|
|
53
|
-
*
|
|
161
|
+
* Provides precise control over which portion of the string to replace.
|
|
162
|
+
*
|
|
163
|
+
* @this {string} The string to modify
|
|
164
|
+
* @param {number} start - Start index of the replacement range (inclusive)
|
|
165
|
+
* @param {number} [end] - End index of the replacement range (exclusive); defaults to start + 1
|
|
166
|
+
* @param {string} [replaceString=''] - The string to insert in place of the removed portion
|
|
167
|
+
* @returns {string} A new string with the range replaced
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* 'hello world'.replaceRange(0, 5, 'goodbye'); // 'goodbye world'
|
|
171
|
+
* 'hello'.replaceRange(2, 2, 'XX'); // 'heXXllo'
|
|
172
|
+
* 'hello'.replaceRange(1, 4); // 'ho'
|
|
54
173
|
*
|
|
55
|
-
* @
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
174
|
+
* @remarks
|
|
175
|
+
* - If end is not provided, defaults to replacing only the character at start
|
|
176
|
+
* - If replaceString is not provided, the range is simply removed
|
|
177
|
+
* - Uses slice() internally for safe index handling
|
|
59
178
|
*/
|
|
60
179
|
replaceRange(start: number, end: number, replaceString?: string): string;
|
|
61
180
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const
|
|
4
|
-
|
|
3
|
+
const core_utils_1 = require("../utils/core.utils");
|
|
4
|
+
/**
|
|
5
|
+
* @see String.prototype.splitWords
|
|
6
|
+
*/
|
|
7
|
+
(0, core_utils_1.defineIfNotExists)(String.prototype, 'splitWords', function () {
|
|
5
8
|
return this.replace(/([a-z0-9])([A-Z])/g, '$1 $2') // helloWorld → hello World
|
|
6
9
|
.replace(/([A-Z])([A-Z][a-z])/g, '$1 $2') // HTMLParser → HTML Parser
|
|
7
10
|
.replace(/[^a-zA-Z0-9]+/g, ' ')
|
|
@@ -9,47 +12,74 @@ const utils_1 = require("../utils");
|
|
|
9
12
|
.split(/\s+/)
|
|
10
13
|
.filter(Boolean);
|
|
11
14
|
});
|
|
12
|
-
|
|
15
|
+
/**
|
|
16
|
+
* @see String.prototype.camelCase
|
|
17
|
+
*/
|
|
18
|
+
(0, core_utils_1.defineIfNotExists)(String.prototype, 'camelCase', function () {
|
|
13
19
|
const words = this.splitWords().map((w) => w.toLowerCase());
|
|
14
20
|
return words
|
|
15
21
|
.map((word, i) => (i === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1)))
|
|
16
22
|
.join('');
|
|
17
23
|
});
|
|
18
|
-
|
|
24
|
+
/**
|
|
25
|
+
* @see String.prototype.kebabCase
|
|
26
|
+
*/
|
|
27
|
+
(0, core_utils_1.defineIfNotExists)(String.prototype, 'kebabCase', function () {
|
|
19
28
|
return this.splitWords()
|
|
20
29
|
.map((w) => w.toLowerCase())
|
|
21
30
|
.join('-');
|
|
22
31
|
});
|
|
23
|
-
|
|
32
|
+
/**
|
|
33
|
+
* @see String.prototype.snakeCase
|
|
34
|
+
*/
|
|
35
|
+
(0, core_utils_1.defineIfNotExists)(String.prototype, 'snakeCase', function () {
|
|
24
36
|
return this.splitWords()
|
|
25
37
|
.map((w) => w.toLowerCase())
|
|
26
38
|
.join('_');
|
|
27
39
|
});
|
|
28
|
-
|
|
40
|
+
/**
|
|
41
|
+
* @see String.prototype.truncate
|
|
42
|
+
*/
|
|
43
|
+
(0, core_utils_1.defineIfNotExists)(String.prototype, 'truncate', function (n) {
|
|
29
44
|
if (typeof n !== 'number' || !Number.isInteger(n) || n < 0) {
|
|
30
45
|
throw new TypeError('Truncate length must be a non-negative integer');
|
|
31
46
|
}
|
|
32
47
|
return this.length > n ? this.slice(0, n) + '...' : this.toString();
|
|
33
48
|
});
|
|
34
|
-
|
|
49
|
+
/**
|
|
50
|
+
* @see String.prototype.reverse
|
|
51
|
+
*/
|
|
52
|
+
(0, core_utils_1.defineIfNotExists)(String.prototype, 'reverse', function () {
|
|
35
53
|
return [...this].reverse().join('');
|
|
36
54
|
});
|
|
37
|
-
|
|
55
|
+
/**
|
|
56
|
+
* @see String.prototype.isEmpty
|
|
57
|
+
*/
|
|
58
|
+
(0, core_utils_1.defineIfNotExists)(String.prototype, 'isEmpty', function () {
|
|
38
59
|
return this.trim().length === 0;
|
|
39
60
|
});
|
|
40
|
-
|
|
61
|
+
/**
|
|
62
|
+
* @see String.prototype.slugify
|
|
63
|
+
*/
|
|
64
|
+
(0, core_utils_1.defineIfNotExists)(String.prototype, 'slugify', function () {
|
|
41
65
|
return this.normalize('NFD')
|
|
42
66
|
.replace(/[̀-ͯ]/g, '')
|
|
43
67
|
.replace(/[^a-zA-Z0-9]+/g, '-')
|
|
44
68
|
.replace(/^-+|-+$/g, '')
|
|
45
69
|
.toLowerCase();
|
|
46
70
|
});
|
|
47
|
-
|
|
71
|
+
/**
|
|
72
|
+
* @see String.prototype.capitalize
|
|
73
|
+
*/
|
|
74
|
+
(0, core_utils_1.defineIfNotExists)(String.prototype, 'capitalize', function () {
|
|
48
75
|
if (this.length === 0)
|
|
49
76
|
return '';
|
|
50
77
|
return this.charAt(0).toUpperCase() + this.slice(1);
|
|
51
78
|
});
|
|
52
|
-
|
|
79
|
+
/**
|
|
80
|
+
* @see String.prototype.replaceRange
|
|
81
|
+
*/
|
|
82
|
+
(0, core_utils_1.defineIfNotExists)(String.prototype, 'replaceRange', function (start, end, replaceString = '') {
|
|
53
83
|
if (!Number.isInteger(start) || !Number.isInteger(end)) {
|
|
54
84
|
throw new TypeError('start and end must be integers');
|
|
55
85
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '../string/string-prototype';
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
require("../string/string-prototype");
|
|
4
|
+
describe('String.prototype', () => {
|
|
5
|
+
describe('capitalize()', () => {
|
|
6
|
+
it('should capitalize the first character', () => {
|
|
7
|
+
expect('hello'.capitalize()).toBe('Hello');
|
|
8
|
+
expect('Hello'.capitalize()).toBe('Hello');
|
|
9
|
+
expect(''.capitalize()).toBe('');
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
describe('splitWords()', () => {
|
|
13
|
+
it('should split camelCase, kebab-case, snake_case, and spaces', () => {
|
|
14
|
+
expect('helloWorld'.splitWords()).toEqual(['hello', 'World']);
|
|
15
|
+
expect('hello-world'.splitWords()).toEqual(['hello', 'world']);
|
|
16
|
+
expect('hello_world'.splitWords()).toEqual(['hello', 'world']);
|
|
17
|
+
expect('hello world'.splitWords()).toEqual(['hello', 'world']);
|
|
18
|
+
expect('HTMLParser'.splitWords()).toEqual(['HTML', 'Parser']);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
describe('camelCase()', () => {
|
|
22
|
+
it('should convert to camelCase', () => {
|
|
23
|
+
expect('hello world'.camelCase()).toBe('helloWorld');
|
|
24
|
+
expect('Hello_world-test'.camelCase()).toBe('helloWorldTest');
|
|
25
|
+
expect('helloWorldTest'.camelCase()).toBe('helloWorldTest');
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
describe('kebabCase()', () => {
|
|
29
|
+
it('should convert to kebab-case', () => {
|
|
30
|
+
expect('hello world'.kebabCase()).toBe('hello-world');
|
|
31
|
+
expect('Hello_worldTest'.kebabCase()).toBe('hello-world-test');
|
|
32
|
+
expect('hello-world-test'.kebabCase()).toBe('hello-world-test');
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
describe('snakeCase()', () => {
|
|
36
|
+
it('should convert to snake_case', () => {
|
|
37
|
+
expect('hello world'.snakeCase()).toBe('hello_world');
|
|
38
|
+
expect('Hello-worldTest'.snakeCase()).toBe('hello_world_test');
|
|
39
|
+
expect('hello_world_test'.snakeCase()).toBe('hello_world_test');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe('truncate()', () => {
|
|
43
|
+
it('should truncate and add ... if needed', () => {
|
|
44
|
+
expect('hello world'.truncate(5)).toBe('hello...');
|
|
45
|
+
expect('hello'.truncate(10)).toBe('hello');
|
|
46
|
+
});
|
|
47
|
+
it('should throw if n is not a non-negative integer', () => {
|
|
48
|
+
expect(() => 'abc'.truncate(-1)).toThrowError(TypeError);
|
|
49
|
+
expect(() => 'abc'.truncate(1.5)).toThrowError(TypeError);
|
|
50
|
+
expect(() => 'abc'.truncate('a')).toThrowError(TypeError);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
describe('reverse()', () => {
|
|
54
|
+
it('should reverse the string', () => {
|
|
55
|
+
expect('abc'.reverse()).toBe('cba');
|
|
56
|
+
expect('été'.reverse()).toBe('été');
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
describe('isEmpty()', () => {
|
|
60
|
+
it('should return true for empty or whitespace strings', () => {
|
|
61
|
+
expect(''.isEmpty()).toBe(true);
|
|
62
|
+
expect(' '.isEmpty()).toBe(true);
|
|
63
|
+
});
|
|
64
|
+
it('should return false for non-empty strings', () => {
|
|
65
|
+
expect('abc'.isEmpty()).toBe(false);
|
|
66
|
+
expect(' a '.isEmpty()).toBe(false);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
describe('slugify()', () => {
|
|
70
|
+
it('should slugify a string', () => {
|
|
71
|
+
expect('Hello World!'.slugify()).toBe('hello-world');
|
|
72
|
+
expect("Éléphant à l'été".slugify()).toBe('elephant-a-l-ete');
|
|
73
|
+
expect(' --Hello__World-- '.slugify()).toBe('hello-world');
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
describe('replaceRange()', () => {
|
|
77
|
+
it('should replace a single character at the given index', () => {
|
|
78
|
+
expect('hello'.replaceRange(1, 2, 'a')).toBe('hallo');
|
|
79
|
+
});
|
|
80
|
+
it('should replace a range of characters', () => {
|
|
81
|
+
expect('abcdef'.replaceRange(2, 5, 'Z')).toBe('abZf');
|
|
82
|
+
});
|
|
83
|
+
it('should remove a range if replaceString is omitted', () => {
|
|
84
|
+
expect('abcdef'.replaceRange(1, 4)).toBe('aef');
|
|
85
|
+
});
|
|
86
|
+
it('should work when start > end (swaps automatically)', () => {
|
|
87
|
+
expect('abcdef'.replaceRange(5, 2, 'X')).toBe('abXf');
|
|
88
|
+
});
|
|
89
|
+
it('should insert at the end if start and end are equal to length', () => {
|
|
90
|
+
expect('abc'.replaceRange(3, 3, 'Z')).toBe('abcZ');
|
|
91
|
+
});
|
|
92
|
+
describe('error handling', () => {
|
|
93
|
+
it('should throw if start or end is negative', () => {
|
|
94
|
+
expect(() => 'abc'.replaceRange(-1, 2)).toThrow(RangeError);
|
|
95
|
+
expect(() => 'abc'.replaceRange(1, -2)).toThrow(RangeError);
|
|
96
|
+
});
|
|
97
|
+
it('should throw if start or end is out of bounds', () => {
|
|
98
|
+
expect(() => 'abc'.replaceRange(0, 4)).toThrow(RangeError);
|
|
99
|
+
expect(() => 'abc'.replaceRange(5, 1)).toThrow(RangeError);
|
|
100
|
+
});
|
|
101
|
+
it('should throw if start or end is not an integer', () => {
|
|
102
|
+
expect(() => 'abc'.replaceRange(1.5, 2)).toThrow(TypeError);
|
|
103
|
+
expect(() => 'abc'.replaceRange(1, 2.2)).toThrow(TypeError);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe('edge cases', () => {
|
|
107
|
+
it('should default replaceString to empty string', () => {
|
|
108
|
+
expect('hello'.replaceRange(1, 4)).toBe('ho');
|
|
109
|
+
});
|
|
110
|
+
it('should support empty string', () => {
|
|
111
|
+
expect(''.replaceRange(0, 0, 'x')).toBe('x');
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mapToObject = mapToObject;
|
|
4
|
+
exports.sortBy = sortBy;
|
|
5
|
+
const core_utils_1 = require("./core.utils");
|
|
6
|
+
function mapToObject(map) {
|
|
7
|
+
const obj = {};
|
|
8
|
+
for (const [key, value] of map) {
|
|
9
|
+
// Validate that key is not null or undefined
|
|
10
|
+
if (key === null || key === undefined) {
|
|
11
|
+
throw new TypeError(`Invalid key: key cannot be null or undefined. Key received: ${String(key)}`);
|
|
12
|
+
}
|
|
13
|
+
const keyType = typeof key;
|
|
14
|
+
// Only allow string, number, or symbol
|
|
15
|
+
if (keyType !== 'string' && keyType !== 'number' && keyType !== 'symbol') {
|
|
16
|
+
throw new TypeError(`Invalid key type: keys must be string, number, or symbol, received ${keyType}. Key value: ${String(key)}`);
|
|
17
|
+
}
|
|
18
|
+
obj[key] = value;
|
|
19
|
+
}
|
|
20
|
+
return obj;
|
|
21
|
+
}
|
|
22
|
+
function sortBy(arr, direction, selector) {
|
|
23
|
+
if (arr.length === 0)
|
|
24
|
+
return arr.slice();
|
|
25
|
+
const getValue = (0, core_utils_1.resolveSelector)(selector, (item) => item);
|
|
26
|
+
if (!selector && !arr.every((item) => (0, core_utils_1.isNumberOrString)(item))) {
|
|
27
|
+
throw new TypeError('Array elements must be number or string if no selector is provided');
|
|
28
|
+
}
|
|
29
|
+
return arr.slice().sort((a, b) => {
|
|
30
|
+
const valA = getValue(a);
|
|
31
|
+
const valB = getValue(b);
|
|
32
|
+
if (!(0, core_utils_1.isNumberOrString)(valA) || !(0, core_utils_1.isNumberOrString)(valB)) {
|
|
33
|
+
throw new TypeError('Selector must return number or string');
|
|
34
|
+
}
|
|
35
|
+
if (valA > valB)
|
|
36
|
+
return direction === 'asc' ? 1 : -1;
|
|
37
|
+
if (valA < valB)
|
|
38
|
+
return direction === 'asc' ? -1 : 1;
|
|
39
|
+
return 0;
|
|
40
|
+
});
|
|
41
|
+
}
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|