utilitish 0.0.4 → 0.0.5

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.
@@ -2,25 +2,92 @@ export {};
2
2
  declare global {
3
3
  interface ArrayConstructor {
4
4
  /**
5
- * Combines multiple arrays element-wise, like Python's itertools.zip_longest .
6
- * @param arrays Arrays to zip together
7
- * @returns An array of arrays, each containing the i-th elements of the input arrays, undefined for the shortest arrays
5
+ * Combines multiple arrays element-wise, similar to Python's `itertools.zip_longest`.
6
+ *
7
+ * @example
8
+ * Array.zip([1, 2], ['a', 'b', 'c']);
9
+ * // => [[1, 'a'], [2, 'b'], [undefined, 'c']]
10
+ *
11
+ * @template T Type of the array elements
12
+ * @param {...T[][]} arrays Arrays to zip together
13
+ * @returns {Array<(T | undefined)[]>} A new array where each element is an array containing the elements at the same index from each input array. Missing elements are `undefined`.
8
14
  */
9
15
  zip(...arrays: any[][]): any[][];
10
16
  /**
11
- * Generates a sequence of numbers, similar to Python's range.
12
- * @param start First number, or length if end is not defined
13
- * @param end Last number (excluded)
14
- * @param step Step of the sequence (positive or negative)
15
- * @returns An array of numbers
17
+ * Generates a sequence of numbers, similar to Python's `range`.
18
+ *
19
+ * @example
20
+ * Array.range(5);
21
+ * // => [0, 1, 2, 3, 4]
22
+ *
23
+ * @example
24
+ * Array.range(2, 10, 2);
25
+ * // => [2, 4, 6, 8]
26
+ *
27
+ * @param {number} start First number, or the length if `end` is not provided
28
+ * @param {number} [end] Last number (excluded)
29
+ * @param {number} [step=1] Step between numbers (can be negative)
30
+ * @returns {number[]} An array containing the generated sequence
16
31
  */
17
32
  range(start: number, end?: number, step?: number): number[];
18
33
  /**
19
- * Creates an array filled with the same value or a generated value.
20
- * @param length Length of the array
21
- * @param value Value or function generating a value
22
- * @returns Filled array
34
+ * Creates an array filled with the same value or with values generated by a factory function.
35
+ *
36
+ * @example
37
+ * Array.repeat(3, 'x');
38
+ * // => ['x', 'x', 'x']
39
+ *
40
+ * @example
41
+ * Array.repeat(3, () => Math.random());
42
+ * // => [0.12, 0.45, 0.78] (values will differ)
43
+ *
44
+ * @template T Type of the array elements
45
+ * @param {number} length Length of the array (must be a non-negative integer)
46
+ * @param {T | (() => T)} value Value or function generating the value
47
+ * @returns {T[]} The filled array
23
48
  */
24
49
  repeat<T>(length: number, value: T | (() => T)): T[];
50
+ /**
51
+ * Creates an array filled with a given value or generated using a factory function.
52
+ * Supports creating multi-dimensional arrays by passing multiple sizes.
53
+ *
54
+ * @example
55
+ * // 1D array with primitive values
56
+ * Array.create('x', 5);
57
+ * // => ['x', 'x', 'x', 'x', 'x']
58
+ *
59
+ * @example
60
+ * // 1D array with random numbers
61
+ * Array.create(() => Math.random(), 5);
62
+ * // => [0.12, 0.87, 0.45, 0.76, 0.33] (values will differ)
63
+ *
64
+ * @example
65
+ * // 2D array (matrix)
66
+ * Array.create(0, 2, 3);
67
+ * // => [[0, 0, 0], [0, 0, 0]]
68
+ *
69
+ * @example
70
+ * // 2D array with distinct objects
71
+ * Array.create(() => ({ id: 0 }), 2, 3);
72
+ * // => [
73
+ * // [{id:0}, {id:0}, {id:0}],
74
+ * // [{id:0}, {id:0}, {id:0}]
75
+ * // ]
76
+ *
77
+ * @notes
78
+ * - If `sizes.length === 0`, returns `[]`.
79
+ * - If `valueOrFactory` is a primitive, all cells contain the same value.
80
+ * - If `valueOrFactory` is a function, it is called for each cell to produce a fresh value.
81
+ * - `sizes` should be integers >= 0; negative or non-integer values are not supported.
82
+ *
83
+ * @template T
84
+ * @param {T | (() => T)} valueOrFactory The value to fill the array with, or a factory function producing values.
85
+ * @param {...number} sizes Sizes for each dimension (1D => one number, 2D => two numbers, etc.).
86
+ * @returns {any[]} A multi-dimensional array of depth `sizes.length` filled with values from `valueOrFactory`.
87
+ *
88
+ * @remarks
89
+ * - This method is **static** and must be called on `Array`, not on an instance.
90
+ */
91
+ create<T>(valueOrFactory: T | (() => T), ...sizes: number[]): any[];
25
92
  }
26
93
  }
@@ -1,36 +1,51 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- Array.zip = function (...arrays) {
3
+ const utils_1 = require("../utils");
4
+ /**
5
+ * @see Array.zip
6
+ */
7
+ (0, utils_1.defineStaticIfNotExists)(Array, 'zip', function (...arrays) {
4
8
  if (arrays.length === 0)
5
9
  return [];
6
10
  const maxLen = Math.max(...arrays.map((arr) => arr.length));
7
- const result = [];
8
- for (let i = 0; i < maxLen; i++) {
9
- result.push(arrays.map((arr) => arr[i]));
10
- }
11
- return result;
12
- };
13
- Array.range = function (start, end, step = 1) {
11
+ return Array.from({ length: maxLen }, (_, i) => arrays.map((arr) => arr[i]));
12
+ });
13
+ /**
14
+ * @see Array.range
15
+ */
16
+ (0, utils_1.defineStaticIfNotExists)(Array, 'range', function (start, end, step = 1) {
14
17
  if (end === undefined) {
15
18
  end = start;
16
19
  start = 0;
17
20
  }
18
- const result = [];
19
21
  if (step === 0)
20
22
  throw new Error('step must not be 0');
23
+ const result = [];
21
24
  const condition = step > 0 ? (i) => i < end : (i) => i > end;
22
25
  for (let i = start; condition(i); i += step) {
23
26
  result.push(i);
24
27
  }
25
28
  return result;
26
- };
27
- Array.repeat = function (length, value) {
29
+ });
30
+ /**
31
+ * @see Array.repeat
32
+ */
33
+ (0, utils_1.defineStaticIfNotExists)(Array, 'repeat', function (length, value) {
28
34
  if (typeof length !== 'number' || !Number.isInteger(length) || length < 0) {
29
- throw new TypeError('Indices must be integers');
35
+ throw new TypeError('Length must be a non-negative integer');
30
36
  }
31
- const result = [];
32
- for (let i = 0; i < length; i++) {
33
- result.push(typeof value === 'function' ? value() : value);
37
+ return Array.from({ length }, () => (typeof value === 'function' ? value() : value));
38
+ });
39
+ /**
40
+ * @see Array.create
41
+ */
42
+ (0, utils_1.defineStaticIfNotExists)(Array, 'create', function (valueOrFactory, ...sizes) {
43
+ if (sizes.length === 0)
44
+ return [];
45
+ if (!sizes.every((s) => Number.isInteger(s) && s >= 0)) {
46
+ throw new TypeError('All sizes must be non-negative integers');
34
47
  }
35
- return result;
36
- };
48
+ const getValue = typeof valueOrFactory === 'function' ? valueOrFactory : () => valueOrFactory;
49
+ const createDimension = (dimIndex) => Array.from({ length: sizes[dimIndex] }, () => dimIndex === sizes.length - 1 ? getValue() : createDimension(dimIndex + 1));
50
+ return createDimension(0);
51
+ });
@@ -20,6 +20,6 @@ declare global {
20
20
  * @param key - The key to look up in the map.
21
21
  * @returns The array associated with the key.
22
22
  */
23
- ensureArray(this: Map<K, V[]>, key: K): V[];
23
+ ensureArray<L extends Array<any>>(this: Map<K, L>, key: K): L;
24
24
  }
25
25
  }
@@ -27,8 +27,15 @@ const utils_1 = require("../utils");
27
27
  }
28
28
  });
29
29
  (0, utils_1.defineIfNotExists)(Map.prototype, 'ensureArray', function (key) {
30
+ if (key === null || key === undefined) {
31
+ throw new TypeError('Key cannot be null or undefined');
32
+ }
30
33
  if (!this.has(key)) {
31
34
  this.set(key, []);
32
35
  }
33
- return this.get(key);
36
+ const arr = this.get(key);
37
+ if (!Array.isArray(arr)) {
38
+ throw new TypeError('Value for the key is not an array');
39
+ }
40
+ return arr;
34
41
  });
package/dist/utils.d.ts CHANGED
@@ -1,4 +1,27 @@
1
1
  export declare const defineIfNotExists: <T extends object>(prototype: T, name: string, fn: Function) => void;
2
+ /**
3
+ * Defines a **static** property on a constructor if it does not already exist
4
+ * (or if the existing property is writable **or** configurable).
5
+ *
6
+ * - Does **not** affect instance prototypes (use `defineIfNotExists` for `Foo.prototype`).
7
+ * - The property is created with: { enumerable: false, configurable: false, writable: false }
8
+ * making it non-enumerable and immutable after definition.
9
+ * - If an existing property is non-configurable AND non-writable, it will **not** be replaced.
10
+ *
11
+ * @template T
12
+ * @param {T} constructor The constructor object (e.g., `Array`, `String`, `Map`, ...)
13
+ * @param {string} name The name of the static method to define (e.g., `'create'`, `'range'`)
14
+ * @param {Function} fn The function to attach as a static property
15
+ *
16
+ * @example
17
+ * // Define Array.range if possible
18
+ * defineStaticIfNotExists(Array, 'range', function(start: number, end?: number) { ... });
19
+ *
20
+ * @remarks
21
+ * - To force replacement, delete the property first or use Object.defineProperty directly.
22
+ * - This function is meant to standardize the addition of static methods in utilitish.
23
+ */
24
+ export declare const defineStaticIfNotExists: <T extends object>(constructor: T, name: string, fn: Function) => void;
2
25
  export declare function resolveSelector<T, R>(selector?: keyof T | ((item: T) => R), fallback?: (item: T, index?: number) => R, name?: string): (item: T, index?: number) => R;
3
26
  export declare function assertValidSelector<T, R>(selector: any, name?: string): asserts selector is Selector<T, R>;
4
27
  export declare function isNumberOrString(value: unknown): value is string | number;
package/dist/utils.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.defineIfNotExists = void 0;
3
+ exports.defineStaticIfNotExists = exports.defineIfNotExists = void 0;
4
4
  exports.resolveSelector = resolveSelector;
5
5
  exports.assertValidSelector = assertValidSelector;
6
6
  exports.isNumberOrString = isNumberOrString;
@@ -16,6 +16,40 @@ const defineIfNotExists = (prototype, name, fn) => {
16
16
  }
17
17
  };
18
18
  exports.defineIfNotExists = defineIfNotExists;
19
+ /**
20
+ * Defines a **static** property on a constructor if it does not already exist
21
+ * (or if the existing property is writable **or** configurable).
22
+ *
23
+ * - Does **not** affect instance prototypes (use `defineIfNotExists` for `Foo.prototype`).
24
+ * - The property is created with: { enumerable: false, configurable: false, writable: false }
25
+ * making it non-enumerable and immutable after definition.
26
+ * - If an existing property is non-configurable AND non-writable, it will **not** be replaced.
27
+ *
28
+ * @template T
29
+ * @param {T} constructor The constructor object (e.g., `Array`, `String`, `Map`, ...)
30
+ * @param {string} name The name of the static method to define (e.g., `'create'`, `'range'`)
31
+ * @param {Function} fn The function to attach as a static property
32
+ *
33
+ * @example
34
+ * // Define Array.range if possible
35
+ * defineStaticIfNotExists(Array, 'range', function(start: number, end?: number) { ... });
36
+ *
37
+ * @remarks
38
+ * - To force replacement, delete the property first or use Object.defineProperty directly.
39
+ * - This function is meant to standardize the addition of static methods in utilitish.
40
+ */
41
+ const defineStaticIfNotExists = (constructor, name, fn) => {
42
+ const descriptor = Object.getOwnPropertyDescriptor(constructor, name);
43
+ if (!descriptor || descriptor.writable || descriptor.configurable) {
44
+ Object.defineProperty(constructor, name, {
45
+ value: fn,
46
+ enumerable: false,
47
+ configurable: false,
48
+ writable: false,
49
+ });
50
+ }
51
+ };
52
+ exports.defineStaticIfNotExists = defineStaticIfNotExists;
19
53
  function resolveSelector(selector, fallback, name = 'selector') {
20
54
  assertValidSelector(selector);
21
55
  if (typeof selector === 'function') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "utilitish",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -9,7 +9,8 @@
9
9
  ],
10
10
  "scripts": {
11
11
  "build": "tsc",
12
- "test": "jest"
12
+ "test": "jest",
13
+ "docs": "typedoc"
13
14
  },
14
15
  "keywords": [
15
16
  "typescript",
@@ -22,6 +23,7 @@
22
23
  "@types/jest": "^29.5.14",
23
24
  "jest": "^29.7.0",
24
25
  "ts-jest": "^29.3.4",
26
+ "typedoc": "^0.28.10",
25
27
  "typescript": "^5.8.3"
26
28
  }
27
29
  }