@naman_deep_singh/js-extensions 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +388 -39
- package/dist/{array-extensions.js → cjs/array-extensions.js} +18 -0
- package/dist/{index.d.ts → cjs/index.d.ts} +6 -0
- package/dist/{index.js → cjs/index.js} +12 -3
- package/dist/cjs/number-extensions.js +103 -0
- package/dist/cjs/object-extensions.js +103 -0
- package/dist/cjs/performance.d.ts +18 -0
- package/dist/cjs/performance.js +63 -0
- package/dist/{string-extensions.js → cjs/string-extensions.js} +15 -0
- package/dist/{types.d.ts → cjs/types.d.ts} +20 -0
- package/dist/cjs/validation.d.ts +4 -0
- package/dist/cjs/validation.js +31 -0
- package/dist/esm/array-extensions.d.ts +1 -0
- package/dist/esm/array-extensions.js +80 -0
- package/dist/esm/index.d.ts +46 -0
- package/dist/esm/index.js +50 -0
- package/dist/esm/number-extensions.d.ts +1 -0
- package/dist/esm/number-extensions.js +100 -0
- package/dist/esm/object-extensions.d.ts +1 -0
- package/dist/esm/object-extensions.js +100 -0
- package/dist/esm/performance.d.ts +18 -0
- package/dist/esm/performance.js +57 -0
- package/dist/esm/string-extensions.d.ts +1 -0
- package/dist/esm/string-extensions.js +66 -0
- package/dist/esm/types.d.ts +71 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/validation.d.ts +4 -0
- package/dist/esm/validation.js +25 -0
- package/dist/types/array-extensions.d.ts +1 -0
- package/dist/types/index.d.ts +46 -0
- package/dist/types/number-extensions.d.ts +1 -0
- package/dist/types/object-extensions.d.ts +1 -0
- package/dist/types/performance.d.ts +18 -0
- package/dist/types/string-extensions.d.ts +1 -0
- package/dist/types/types.d.ts +71 -0
- package/dist/types/validation.d.ts +4 -0
- package/package.json +23 -8
- package/dist/number-extensions.js +0 -72
- package/dist/object-extensions.js +0 -53
- package/src/array-extensions.ts +0 -73
- package/src/index.ts +0 -55
- package/src/number-extensions.ts +0 -73
- package/src/object-extensions.ts +0 -53
- package/src/string-extensions.ts +0 -63
- package/src/types.ts +0 -56
- package/tsconfig.json +0 -22
- /package/dist/{array-extensions.d.ts → cjs/array-extensions.d.ts} +0 -0
- /package/dist/{number-extensions.d.ts → cjs/number-extensions.d.ts} +0 -0
- /package/dist/{object-extensions.d.ts → cjs/object-extensions.d.ts} +0 -0
- /package/dist/{string-extensions.d.ts → cjs/string-extensions.d.ts} +0 -0
- /package/dist/{types.js → cjs/types.js} +0 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extendObject = extendObject;
|
|
4
|
+
// Object prototype extensions
|
|
5
|
+
const performance_1 = require("./performance");
|
|
6
|
+
function extendObject() {
|
|
7
|
+
Object.prototype.isEmpty = function () {
|
|
8
|
+
return Object.keys(this).length === 0;
|
|
9
|
+
};
|
|
10
|
+
Object.prototype.pick = function (keys) {
|
|
11
|
+
const result = {};
|
|
12
|
+
const obj = this;
|
|
13
|
+
keys.forEach(key => {
|
|
14
|
+
if (key in obj) {
|
|
15
|
+
result[key] = obj[key];
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
return result;
|
|
19
|
+
};
|
|
20
|
+
Object.prototype.omit = function (keys) {
|
|
21
|
+
const result = { ...this };
|
|
22
|
+
keys.forEach(key => {
|
|
23
|
+
delete result[key];
|
|
24
|
+
});
|
|
25
|
+
return result;
|
|
26
|
+
};
|
|
27
|
+
Object.prototype.deepClone = function () {
|
|
28
|
+
return (0, performance_1.withCache)(`clone_${JSON.stringify(this)}`, () => {
|
|
29
|
+
if (this === null || typeof this !== 'object')
|
|
30
|
+
return this;
|
|
31
|
+
// Handle Date objects
|
|
32
|
+
if (this instanceof Date)
|
|
33
|
+
return new Date(this.getTime());
|
|
34
|
+
// Handle Array objects
|
|
35
|
+
if (Array.isArray(this)) {
|
|
36
|
+
return this.map(item => {
|
|
37
|
+
if (item && typeof item === 'object' && typeof item.deepClone === 'function') {
|
|
38
|
+
return item.deepClone();
|
|
39
|
+
}
|
|
40
|
+
return item;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
// Handle regular objects
|
|
44
|
+
const cloned = {};
|
|
45
|
+
Object.keys(this).forEach(key => {
|
|
46
|
+
const value = this[key];
|
|
47
|
+
if (value && typeof value === 'object' && typeof value.deepClone === 'function') {
|
|
48
|
+
cloned[key] = value.deepClone();
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
cloned[key] = value;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
return cloned;
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
Object.prototype.merge = function (other) {
|
|
58
|
+
return { ...this, ...other };
|
|
59
|
+
};
|
|
60
|
+
Object.prototype.deepFreeze = function () {
|
|
61
|
+
const propNames = Object.getOwnPropertyNames(this);
|
|
62
|
+
for (const name of propNames) {
|
|
63
|
+
const value = this[name];
|
|
64
|
+
if (value && typeof value === 'object') {
|
|
65
|
+
value.deepFreeze();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return Object.freeze(this);
|
|
69
|
+
};
|
|
70
|
+
Object.prototype.hasPath = function (path) {
|
|
71
|
+
const keys = path.split('.');
|
|
72
|
+
let current = this;
|
|
73
|
+
for (const key of keys) {
|
|
74
|
+
if (current == null || !(key in current))
|
|
75
|
+
return false;
|
|
76
|
+
current = current[key];
|
|
77
|
+
}
|
|
78
|
+
return true;
|
|
79
|
+
};
|
|
80
|
+
Object.prototype.getPath = function (path, defaultValue) {
|
|
81
|
+
const keys = path.split('.');
|
|
82
|
+
let current = this;
|
|
83
|
+
for (const key of keys) {
|
|
84
|
+
if (current == null || !(key in current))
|
|
85
|
+
return defaultValue;
|
|
86
|
+
current = current[key];
|
|
87
|
+
}
|
|
88
|
+
return current;
|
|
89
|
+
};
|
|
90
|
+
Object.prototype.setPath = function (path, value) {
|
|
91
|
+
const keys = path.split('.');
|
|
92
|
+
let current = this;
|
|
93
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
94
|
+
const key = keys[i];
|
|
95
|
+
if (!(key in current) || typeof current[key] !== 'object') {
|
|
96
|
+
current[key] = {};
|
|
97
|
+
}
|
|
98
|
+
current = current[key];
|
|
99
|
+
}
|
|
100
|
+
current[keys[keys.length - 1]] = value;
|
|
101
|
+
return this;
|
|
102
|
+
};
|
|
103
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface PerformanceConfig {
|
|
2
|
+
enableCaching?: boolean;
|
|
3
|
+
maxCacheSize?: number;
|
|
4
|
+
enableValidation?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function setPerformanceConfig(newConfig: Partial<PerformanceConfig>): void;
|
|
7
|
+
export declare function getPerformanceConfig(): PerformanceConfig;
|
|
8
|
+
declare class LRUCache<K, V> {
|
|
9
|
+
private cache;
|
|
10
|
+
private maxSize;
|
|
11
|
+
constructor(maxSize?: number);
|
|
12
|
+
get(key: K): V | undefined;
|
|
13
|
+
set(key: K, value: V): void;
|
|
14
|
+
clear(): void;
|
|
15
|
+
}
|
|
16
|
+
export declare const cache: LRUCache<unknown, unknown>;
|
|
17
|
+
export declare function withCache<T>(key: string, fn: () => T): T;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cache = void 0;
|
|
4
|
+
exports.setPerformanceConfig = setPerformanceConfig;
|
|
5
|
+
exports.getPerformanceConfig = getPerformanceConfig;
|
|
6
|
+
exports.withCache = withCache;
|
|
7
|
+
const defaultConfig = {
|
|
8
|
+
enableCaching: false,
|
|
9
|
+
maxCacheSize: 100,
|
|
10
|
+
enableValidation: true
|
|
11
|
+
};
|
|
12
|
+
let config = { ...defaultConfig };
|
|
13
|
+
function setPerformanceConfig(newConfig) {
|
|
14
|
+
config = { ...config, ...newConfig };
|
|
15
|
+
}
|
|
16
|
+
function getPerformanceConfig() {
|
|
17
|
+
return { ...config };
|
|
18
|
+
}
|
|
19
|
+
// Simple LRU cache for expensive operations
|
|
20
|
+
class LRUCache {
|
|
21
|
+
constructor(maxSize = 100) {
|
|
22
|
+
this.cache = new Map();
|
|
23
|
+
this.maxSize = maxSize;
|
|
24
|
+
}
|
|
25
|
+
get(key) {
|
|
26
|
+
const value = this.cache.get(key);
|
|
27
|
+
if (value !== undefined) {
|
|
28
|
+
// Move to end (most recently used)
|
|
29
|
+
this.cache.delete(key);
|
|
30
|
+
this.cache.set(key, value);
|
|
31
|
+
}
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
set(key, value) {
|
|
35
|
+
if (this.cache.has(key)) {
|
|
36
|
+
this.cache.delete(key);
|
|
37
|
+
}
|
|
38
|
+
else if (this.cache.size >= this.maxSize) {
|
|
39
|
+
// Remove least recently used (first item)
|
|
40
|
+
const firstKey = this.cache.keys().next().value;
|
|
41
|
+
if (firstKey !== undefined) {
|
|
42
|
+
this.cache.delete(firstKey);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
this.cache.set(key, value);
|
|
46
|
+
}
|
|
47
|
+
clear() {
|
|
48
|
+
this.cache.clear();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.cache = new LRUCache(config.maxCacheSize);
|
|
52
|
+
function withCache(key, fn) {
|
|
53
|
+
if (!config.enableCaching) {
|
|
54
|
+
return fn();
|
|
55
|
+
}
|
|
56
|
+
const cached = exports.cache.get(key);
|
|
57
|
+
if (cached !== undefined) {
|
|
58
|
+
return cached;
|
|
59
|
+
}
|
|
60
|
+
const result = fn();
|
|
61
|
+
exports.cache.set(key, result);
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
@@ -51,4 +51,19 @@ function extendString() {
|
|
|
51
51
|
String.prototype.stripHtml = function () {
|
|
52
52
|
return this.replace(/<[^>]*>/g, '');
|
|
53
53
|
};
|
|
54
|
+
String.prototype.padStart = function (targetLength, padString = ' ') {
|
|
55
|
+
return this.toString().padStart(targetLength, padString);
|
|
56
|
+
};
|
|
57
|
+
String.prototype.padEnd = function (targetLength, padString = ' ') {
|
|
58
|
+
return this.toString().padEnd(targetLength, padString);
|
|
59
|
+
};
|
|
60
|
+
String.prototype.count = function (substring) {
|
|
61
|
+
return (this.match(new RegExp(substring, 'g')) || []).length;
|
|
62
|
+
};
|
|
63
|
+
String.prototype.words = function () {
|
|
64
|
+
return this.trim().split(/\s+/).filter(word => word.length > 0);
|
|
65
|
+
};
|
|
66
|
+
String.prototype.lines = function () {
|
|
67
|
+
return this.split(/\r?\n/);
|
|
68
|
+
};
|
|
54
69
|
}
|
|
@@ -12,6 +12,11 @@ declare global {
|
|
|
12
12
|
isPalindrome(): boolean;
|
|
13
13
|
toTitleCase(): string;
|
|
14
14
|
stripHtml(): string;
|
|
15
|
+
padStart(targetLength: number, padString?: string): string;
|
|
16
|
+
padEnd(targetLength: number, padString?: string): string;
|
|
17
|
+
count(substring: string): number;
|
|
18
|
+
words(): string[];
|
|
19
|
+
lines(): string[];
|
|
15
20
|
}
|
|
16
21
|
interface Array<T> {
|
|
17
22
|
unique(): T[];
|
|
@@ -26,6 +31,12 @@ declare global {
|
|
|
26
31
|
partition(predicate: (item: T) => boolean): [T[], T[]];
|
|
27
32
|
flatten(depth?: number): any[];
|
|
28
33
|
deepFlatten(): any[];
|
|
34
|
+
difference(other: T[]): T[];
|
|
35
|
+
intersection(other: T[]): T[];
|
|
36
|
+
union(other: T[]): T[];
|
|
37
|
+
sample(): T | undefined;
|
|
38
|
+
take(count: number): T[];
|
|
39
|
+
drop(count: number): T[];
|
|
29
40
|
}
|
|
30
41
|
interface Object {
|
|
31
42
|
isEmpty(): boolean;
|
|
@@ -34,6 +45,9 @@ declare global {
|
|
|
34
45
|
deepClone<T>(): T;
|
|
35
46
|
merge(other: Record<string, any>): Record<string, any>;
|
|
36
47
|
deepFreeze<T>(): T;
|
|
48
|
+
hasPath(path: string): boolean;
|
|
49
|
+
getPath(path: string, defaultValue?: any): any;
|
|
50
|
+
setPath(path: string, value: any): any;
|
|
37
51
|
}
|
|
38
52
|
interface Number {
|
|
39
53
|
toPercent(decimals?: number): string;
|
|
@@ -46,6 +60,12 @@ declare global {
|
|
|
46
60
|
toOrdinal(): string;
|
|
47
61
|
toRoman(): string;
|
|
48
62
|
inRange(min: number, max: number): boolean;
|
|
63
|
+
round(decimals?: number): number;
|
|
64
|
+
ceil(decimals?: number): number;
|
|
65
|
+
floor(decimals?: number): number;
|
|
66
|
+
abs(): number;
|
|
67
|
+
sign(): number;
|
|
68
|
+
times(callback: (index: number) => void): void;
|
|
49
69
|
}
|
|
50
70
|
}
|
|
51
71
|
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function validateExtensionInput(value: any, type: string, methodName: string): void;
|
|
2
|
+
export declare function validateArrayInput<T>(arr: T[], methodName: string): void;
|
|
3
|
+
export declare function validateNumberRange(num: number, min: number, max: number, methodName: string): void;
|
|
4
|
+
export declare function validatePositiveInteger(num: number, methodName: string): void;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateExtensionInput = validateExtensionInput;
|
|
4
|
+
exports.validateArrayInput = validateArrayInput;
|
|
5
|
+
exports.validateNumberRange = validateNumberRange;
|
|
6
|
+
exports.validatePositiveInteger = validatePositiveInteger;
|
|
7
|
+
// Validation utilities for extensions
|
|
8
|
+
function validateExtensionInput(value, type, methodName) {
|
|
9
|
+
if (value == null) {
|
|
10
|
+
throw new TypeError(`Cannot call ${methodName} on ${value}`);
|
|
11
|
+
}
|
|
12
|
+
const actualType = typeof value;
|
|
13
|
+
if (actualType !== type) {
|
|
14
|
+
throw new TypeError(`${methodName} can only be called on ${type} values, got ${actualType}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function validateArrayInput(arr, methodName) {
|
|
18
|
+
if (!Array.isArray(arr)) {
|
|
19
|
+
throw new TypeError(`${methodName} can only be called on arrays`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function validateNumberRange(num, min, max, methodName) {
|
|
23
|
+
if (num < min || num > max) {
|
|
24
|
+
throw new RangeError(`${methodName}: number must be between ${min} and ${max}, got ${num}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function validatePositiveInteger(num, methodName) {
|
|
28
|
+
if (!Number.isInteger(num) || num < 0) {
|
|
29
|
+
throw new TypeError(`${methodName}: expected positive integer, got ${num}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function extendArray(): void;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Array prototype extensions
|
|
2
|
+
export function extendArray() {
|
|
3
|
+
Array.prototype.unique = function () {
|
|
4
|
+
return [...new Set(this)];
|
|
5
|
+
};
|
|
6
|
+
Array.prototype.shuffle = function () {
|
|
7
|
+
const arr = [...this];
|
|
8
|
+
for (let i = arr.length - 1; i > 0; i--) {
|
|
9
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
10
|
+
[arr[i], arr[j]] = [arr[j], arr[i]];
|
|
11
|
+
}
|
|
12
|
+
return arr;
|
|
13
|
+
};
|
|
14
|
+
Array.prototype.chunk = function (size) {
|
|
15
|
+
const chunks = [];
|
|
16
|
+
for (let i = 0; i < this.length; i += size) {
|
|
17
|
+
chunks.push(this.slice(i, i + size));
|
|
18
|
+
}
|
|
19
|
+
return chunks;
|
|
20
|
+
};
|
|
21
|
+
Array.prototype.groupBy = function (keyFn) {
|
|
22
|
+
return this.reduce((groups, item) => {
|
|
23
|
+
const key = keyFn(item);
|
|
24
|
+
if (!groups[key])
|
|
25
|
+
groups[key] = [];
|
|
26
|
+
groups[key].push(item);
|
|
27
|
+
return groups;
|
|
28
|
+
}, {});
|
|
29
|
+
};
|
|
30
|
+
Array.prototype.sum = function () {
|
|
31
|
+
return this.reduce((sum, num) => sum + (typeof num === 'number' ? num : 0), 0);
|
|
32
|
+
};
|
|
33
|
+
Array.prototype.average = function () {
|
|
34
|
+
const numbers = this.filter(item => typeof item === 'number');
|
|
35
|
+
return numbers.length > 0 ? numbers.reduce((sum, num) => sum + num, 0) / numbers.length : 0;
|
|
36
|
+
};
|
|
37
|
+
Array.prototype.compact = function () {
|
|
38
|
+
return this.filter(item => item != null && item !== '' && item !== false);
|
|
39
|
+
};
|
|
40
|
+
Array.prototype.pluck = function (key) {
|
|
41
|
+
return this.map(item => item && typeof item === 'object' ? item[key] : undefined).filter(val => val !== undefined);
|
|
42
|
+
};
|
|
43
|
+
Array.prototype.findLast = function (predicate) {
|
|
44
|
+
for (let i = this.length - 1; i >= 0; i--) {
|
|
45
|
+
if (predicate(this[i]))
|
|
46
|
+
return this[i];
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
};
|
|
50
|
+
Array.prototype.partition = function (predicate) {
|
|
51
|
+
const truthy = [];
|
|
52
|
+
const falsy = [];
|
|
53
|
+
this.forEach(item => predicate(item) ? truthy.push(item) : falsy.push(item));
|
|
54
|
+
return [truthy, falsy];
|
|
55
|
+
};
|
|
56
|
+
Array.prototype.flatten = function (depth = 1) {
|
|
57
|
+
return depth > 0 ? this.reduce((acc, val) => acc.concat(Array.isArray(val) ? val.flatten(depth - 1) : val), []) : this.slice();
|
|
58
|
+
};
|
|
59
|
+
Array.prototype.deepFlatten = function () {
|
|
60
|
+
return this.reduce((acc, val) => acc.concat(Array.isArray(val) ? val.deepFlatten() : val), []);
|
|
61
|
+
};
|
|
62
|
+
Array.prototype.difference = function (other) {
|
|
63
|
+
return this.filter(item => !other.includes(item));
|
|
64
|
+
};
|
|
65
|
+
Array.prototype.intersection = function (other) {
|
|
66
|
+
return this.filter(item => other.includes(item));
|
|
67
|
+
};
|
|
68
|
+
Array.prototype.union = function (other) {
|
|
69
|
+
return [...new Set([...this, ...other])];
|
|
70
|
+
};
|
|
71
|
+
Array.prototype.sample = function () {
|
|
72
|
+
return this.length > 0 ? this[Math.floor(Math.random() * this.length)] : undefined;
|
|
73
|
+
};
|
|
74
|
+
Array.prototype.take = function (count) {
|
|
75
|
+
return this.slice(0, Math.max(0, count));
|
|
76
|
+
};
|
|
77
|
+
Array.prototype.drop = function (count) {
|
|
78
|
+
return this.slice(Math.max(0, count));
|
|
79
|
+
};
|
|
80
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { extendString } from './string-extensions';
|
|
2
|
+
import { extendArray } from './array-extensions';
|
|
3
|
+
import { extendObject } from './object-extensions';
|
|
4
|
+
import { extendNumber } from './number-extensions';
|
|
5
|
+
import { setPerformanceConfig, getPerformanceConfig, type PerformanceConfig, withCache } from './performance';
|
|
6
|
+
import './types';
|
|
7
|
+
export { withCache };
|
|
8
|
+
export interface ExtensionOptions {
|
|
9
|
+
string?: boolean;
|
|
10
|
+
array?: boolean;
|
|
11
|
+
object?: boolean;
|
|
12
|
+
number?: boolean;
|
|
13
|
+
performance?: PerformanceConfig;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Initialize JavaScript prototype extensions
|
|
17
|
+
* @param options - Configure which extensions to enable (default: all enabled)
|
|
18
|
+
*/
|
|
19
|
+
export declare function initExtensions(options?: ExtensionOptions): void;
|
|
20
|
+
/**
|
|
21
|
+
* Initialize all extensions (convenience function)
|
|
22
|
+
*/
|
|
23
|
+
export declare function extendAll(): void;
|
|
24
|
+
/**
|
|
25
|
+
* Initialize only specific extensions
|
|
26
|
+
*/
|
|
27
|
+
export declare const extend: {
|
|
28
|
+
string: typeof extendString;
|
|
29
|
+
array: typeof extendArray;
|
|
30
|
+
object: typeof extendObject;
|
|
31
|
+
number: typeof extendNumber;
|
|
32
|
+
};
|
|
33
|
+
export { setPerformanceConfig, getPerformanceConfig, type PerformanceConfig };
|
|
34
|
+
declare const _default: {
|
|
35
|
+
initExtensions: typeof initExtensions;
|
|
36
|
+
extendAll: typeof extendAll;
|
|
37
|
+
extend: {
|
|
38
|
+
string: typeof extendString;
|
|
39
|
+
array: typeof extendArray;
|
|
40
|
+
object: typeof extendObject;
|
|
41
|
+
number: typeof extendNumber;
|
|
42
|
+
};
|
|
43
|
+
setPerformanceConfig: typeof setPerformanceConfig;
|
|
44
|
+
getPerformanceConfig: typeof getPerformanceConfig;
|
|
45
|
+
};
|
|
46
|
+
export default _default;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { extendString } from './string-extensions';
|
|
2
|
+
import { extendArray } from './array-extensions';
|
|
3
|
+
import { extendObject } from './object-extensions';
|
|
4
|
+
import { extendNumber } from './number-extensions';
|
|
5
|
+
import { setPerformanceConfig, getPerformanceConfig, withCache } from './performance';
|
|
6
|
+
import './types';
|
|
7
|
+
// Export withCache for use in extensions
|
|
8
|
+
export { withCache };
|
|
9
|
+
/**
|
|
10
|
+
* Initialize JavaScript prototype extensions
|
|
11
|
+
* @param options - Configure which extensions to enable (default: all enabled)
|
|
12
|
+
*/
|
|
13
|
+
export function initExtensions(options = {}) {
|
|
14
|
+
const { string = true, array = true, object = true, number = true, performance } = options;
|
|
15
|
+
if (performance) {
|
|
16
|
+
setPerformanceConfig(performance);
|
|
17
|
+
}
|
|
18
|
+
if (string)
|
|
19
|
+
extendString();
|
|
20
|
+
if (array)
|
|
21
|
+
extendArray();
|
|
22
|
+
if (object)
|
|
23
|
+
extendObject();
|
|
24
|
+
if (number)
|
|
25
|
+
extendNumber();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Initialize all extensions (convenience function)
|
|
29
|
+
*/
|
|
30
|
+
export function extendAll() {
|
|
31
|
+
initExtensions();
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Initialize only specific extensions
|
|
35
|
+
*/
|
|
36
|
+
export const extend = {
|
|
37
|
+
string: extendString,
|
|
38
|
+
array: extendArray,
|
|
39
|
+
object: extendObject,
|
|
40
|
+
number: extendNumber
|
|
41
|
+
};
|
|
42
|
+
// Export performance utilities
|
|
43
|
+
export { setPerformanceConfig, getPerformanceConfig };
|
|
44
|
+
export default {
|
|
45
|
+
initExtensions,
|
|
46
|
+
extendAll,
|
|
47
|
+
extend,
|
|
48
|
+
setPerformanceConfig,
|
|
49
|
+
getPerformanceConfig
|
|
50
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function extendNumber(): void;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// Number prototype extensions
|
|
2
|
+
import { withCache } from './performance';
|
|
3
|
+
export function extendNumber() {
|
|
4
|
+
Number.prototype.toPercent = function (decimals = 2) {
|
|
5
|
+
return (this.valueOf() * 100).toFixed(decimals) + '%';
|
|
6
|
+
};
|
|
7
|
+
Number.prototype.toCurrency = function (currency = 'USD', locale = 'en-US') {
|
|
8
|
+
return new Intl.NumberFormat(locale, {
|
|
9
|
+
style: 'currency',
|
|
10
|
+
currency: currency
|
|
11
|
+
}).format(this.valueOf());
|
|
12
|
+
};
|
|
13
|
+
Number.prototype.clamp = function (min, max) {
|
|
14
|
+
return Math.min(Math.max(this.valueOf(), min), max);
|
|
15
|
+
};
|
|
16
|
+
Number.prototype.isEven = function () {
|
|
17
|
+
return this.valueOf() % 2 === 0;
|
|
18
|
+
};
|
|
19
|
+
Number.prototype.isOdd = function () {
|
|
20
|
+
return this.valueOf() % 2 !== 0;
|
|
21
|
+
};
|
|
22
|
+
Number.prototype.isPrime = function () {
|
|
23
|
+
const num = this.valueOf();
|
|
24
|
+
return withCache(`prime_${num}`, () => {
|
|
25
|
+
if (num < 2)
|
|
26
|
+
return false;
|
|
27
|
+
for (let i = 2; i <= Math.sqrt(num); i++) {
|
|
28
|
+
if (num % i === 0)
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
return true;
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
Number.prototype.factorial = function () {
|
|
35
|
+
const num = Math.floor(this.valueOf());
|
|
36
|
+
return withCache(`factorial_${num}`, () => {
|
|
37
|
+
if (num < 0)
|
|
38
|
+
return NaN;
|
|
39
|
+
if (num === 0 || num === 1)
|
|
40
|
+
return 1;
|
|
41
|
+
let result = 1;
|
|
42
|
+
for (let i = 2; i <= num; i++) {
|
|
43
|
+
result *= i;
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
Number.prototype.toOrdinal = function () {
|
|
49
|
+
const num = Math.floor(this.valueOf());
|
|
50
|
+
const suffix = ['th', 'st', 'nd', 'rd'];
|
|
51
|
+
const v = num % 100;
|
|
52
|
+
return num + (suffix[(v - 20) % 10] || suffix[v] || suffix[0]);
|
|
53
|
+
};
|
|
54
|
+
Number.prototype.toRoman = function () {
|
|
55
|
+
const num = Math.floor(this.valueOf());
|
|
56
|
+
return withCache(`roman_${num}`, () => {
|
|
57
|
+
if (num <= 0 || num >= 4000)
|
|
58
|
+
return num.toString();
|
|
59
|
+
const values = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
|
|
60
|
+
const symbols = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'];
|
|
61
|
+
let result = '';
|
|
62
|
+
let n = num;
|
|
63
|
+
for (let i = 0; i < values.length; i++) {
|
|
64
|
+
while (n >= values[i]) {
|
|
65
|
+
result += symbols[i];
|
|
66
|
+
n -= values[i];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return result;
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
Number.prototype.inRange = function (min, max) {
|
|
73
|
+
const num = this.valueOf();
|
|
74
|
+
return num >= min && num <= max;
|
|
75
|
+
};
|
|
76
|
+
Number.prototype.round = function (decimals = 0) {
|
|
77
|
+
const factor = Math.pow(10, decimals);
|
|
78
|
+
return Math.round(this.valueOf() * factor) / factor;
|
|
79
|
+
};
|
|
80
|
+
Number.prototype.ceil = function (decimals = 0) {
|
|
81
|
+
const factor = Math.pow(10, decimals);
|
|
82
|
+
return Math.ceil(this.valueOf() * factor) / factor;
|
|
83
|
+
};
|
|
84
|
+
Number.prototype.floor = function (decimals = 0) {
|
|
85
|
+
const factor = Math.pow(10, decimals);
|
|
86
|
+
return Math.floor(this.valueOf() * factor) / factor;
|
|
87
|
+
};
|
|
88
|
+
Number.prototype.abs = function () {
|
|
89
|
+
return Math.abs(this.valueOf());
|
|
90
|
+
};
|
|
91
|
+
Number.prototype.sign = function () {
|
|
92
|
+
return Math.sign(this.valueOf());
|
|
93
|
+
};
|
|
94
|
+
Number.prototype.times = function (callback) {
|
|
95
|
+
const num = Math.floor(this.valueOf());
|
|
96
|
+
for (let i = 0; i < num; i++) {
|
|
97
|
+
callback(i);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function extendObject(): void;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// Object prototype extensions
|
|
2
|
+
import { withCache } from './performance';
|
|
3
|
+
export function extendObject() {
|
|
4
|
+
Object.prototype.isEmpty = function () {
|
|
5
|
+
return Object.keys(this).length === 0;
|
|
6
|
+
};
|
|
7
|
+
Object.prototype.pick = function (keys) {
|
|
8
|
+
const result = {};
|
|
9
|
+
const obj = this;
|
|
10
|
+
keys.forEach(key => {
|
|
11
|
+
if (key in obj) {
|
|
12
|
+
result[key] = obj[key];
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
return result;
|
|
16
|
+
};
|
|
17
|
+
Object.prototype.omit = function (keys) {
|
|
18
|
+
const result = { ...this };
|
|
19
|
+
keys.forEach(key => {
|
|
20
|
+
delete result[key];
|
|
21
|
+
});
|
|
22
|
+
return result;
|
|
23
|
+
};
|
|
24
|
+
Object.prototype.deepClone = function () {
|
|
25
|
+
return withCache(`clone_${JSON.stringify(this)}`, () => {
|
|
26
|
+
if (this === null || typeof this !== 'object')
|
|
27
|
+
return this;
|
|
28
|
+
// Handle Date objects
|
|
29
|
+
if (this instanceof Date)
|
|
30
|
+
return new Date(this.getTime());
|
|
31
|
+
// Handle Array objects
|
|
32
|
+
if (Array.isArray(this)) {
|
|
33
|
+
return this.map(item => {
|
|
34
|
+
if (item && typeof item === 'object' && typeof item.deepClone === 'function') {
|
|
35
|
+
return item.deepClone();
|
|
36
|
+
}
|
|
37
|
+
return item;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
// Handle regular objects
|
|
41
|
+
const cloned = {};
|
|
42
|
+
Object.keys(this).forEach(key => {
|
|
43
|
+
const value = this[key];
|
|
44
|
+
if (value && typeof value === 'object' && typeof value.deepClone === 'function') {
|
|
45
|
+
cloned[key] = value.deepClone();
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
cloned[key] = value;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return cloned;
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
Object.prototype.merge = function (other) {
|
|
55
|
+
return { ...this, ...other };
|
|
56
|
+
};
|
|
57
|
+
Object.prototype.deepFreeze = function () {
|
|
58
|
+
const propNames = Object.getOwnPropertyNames(this);
|
|
59
|
+
for (const name of propNames) {
|
|
60
|
+
const value = this[name];
|
|
61
|
+
if (value && typeof value === 'object') {
|
|
62
|
+
value.deepFreeze();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return Object.freeze(this);
|
|
66
|
+
};
|
|
67
|
+
Object.prototype.hasPath = function (path) {
|
|
68
|
+
const keys = path.split('.');
|
|
69
|
+
let current = this;
|
|
70
|
+
for (const key of keys) {
|
|
71
|
+
if (current == null || !(key in current))
|
|
72
|
+
return false;
|
|
73
|
+
current = current[key];
|
|
74
|
+
}
|
|
75
|
+
return true;
|
|
76
|
+
};
|
|
77
|
+
Object.prototype.getPath = function (path, defaultValue) {
|
|
78
|
+
const keys = path.split('.');
|
|
79
|
+
let current = this;
|
|
80
|
+
for (const key of keys) {
|
|
81
|
+
if (current == null || !(key in current))
|
|
82
|
+
return defaultValue;
|
|
83
|
+
current = current[key];
|
|
84
|
+
}
|
|
85
|
+
return current;
|
|
86
|
+
};
|
|
87
|
+
Object.prototype.setPath = function (path, value) {
|
|
88
|
+
const keys = path.split('.');
|
|
89
|
+
let current = this;
|
|
90
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
91
|
+
const key = keys[i];
|
|
92
|
+
if (!(key in current) || typeof current[key] !== 'object') {
|
|
93
|
+
current[key] = {};
|
|
94
|
+
}
|
|
95
|
+
current = current[key];
|
|
96
|
+
}
|
|
97
|
+
current[keys[keys.length - 1]] = value;
|
|
98
|
+
return this;
|
|
99
|
+
};
|
|
100
|
+
}
|