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.
@@ -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
- * @returns A new string with the first character in uppercase.
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, detecting camelCase, kebab-case, snake_case, and spaces.
11
- * @returns An array of words extracted from the string.
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
- * @returns A camelCased version of the string.
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
- * @returns A kebab-cased version of the string.
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
- * @returns A snake_cased version of the string.
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
- * @param n - Maximum length of the string.
32
- * @returns A truncated string.
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
- * @returns The reversed string.
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
- * @returns `true` if the string is empty or whitespace only, `false` otherwise.
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 usable in URLs.
47
- * @returns A slugified version of the string.
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
- * If `end` is not provided, only the character at `start` is replaced.
53
- * If `replaceString` is not provided, the range is simply removed.
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
- * @param start - Start index of the replacement (inclusive).
56
- * @param end - End index of the replacement (exclusive). Defaults to `start`.
57
- * @param replaceString - The string to insert in place. Defaults to `''`.
58
- * @returns A new string with the specified range replaced.
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 utils_1 = require("../utils");
4
- (0, utils_1.defineIfNotExists)(String.prototype, 'splitWords', function () {
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
- (0, utils_1.defineIfNotExists)(String.prototype, 'camelCase', function () {
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
- (0, utils_1.defineIfNotExists)(String.prototype, 'kebabCase', function () {
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
- (0, utils_1.defineIfNotExists)(String.prototype, 'snakeCase', function () {
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
- (0, utils_1.defineIfNotExists)(String.prototype, 'truncate', function (n) {
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
- (0, utils_1.defineIfNotExists)(String.prototype, 'reverse', function () {
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
- (0, utils_1.defineIfNotExists)(String.prototype, 'isEmpty', function () {
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
- (0, utils_1.defineIfNotExists)(String.prototype, 'slugify', function () {
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
- (0, utils_1.defineIfNotExists)(String.prototype, 'capitalize', function () {
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
- (0, utils_1.defineIfNotExists)(String.prototype, 'replaceRange', function (start, end, replaceString = '') {
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,3 @@
1
+ import { Selector } from './core.utils';
2
+ export declare function mapToObject<K extends PropertyKey, V>(map: Map<K, V>): Record<K, V>;
3
+ export declare function sortBy<T>(arr: T[], direction: 'asc' | 'desc', selector?: Selector<T, number | string>): T[];
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "utilitish",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
File without changes
File without changes