@naman_deep_singh/js-extensions 1.3.3 → 1.4.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.
Files changed (38) hide show
  1. package/README.md +174 -425
  2. package/dist/cjs/array/array-extensions.js +84 -50
  3. package/dist/cjs/core/performance.d.ts +1 -0
  4. package/dist/cjs/core/performance.js +6 -0
  5. package/dist/cjs/core/version.d.ts +1 -0
  6. package/dist/cjs/core/version.js +9 -0
  7. package/dist/cjs/index.d.ts +1 -0
  8. package/dist/cjs/index.js +1 -0
  9. package/dist/cjs/number/number-extensions.js +85 -97
  10. package/dist/cjs/object/object-extensions.js +102 -103
  11. package/dist/cjs/string/string-extensions.js +66 -43
  12. package/dist/cjs/types/global-augmentations.d.ts +1 -0
  13. package/dist/cjs/utils/defineExtension.d.ts +1 -0
  14. package/dist/cjs/utils/defineExtension.js +13 -0
  15. package/dist/cjs/utils/index.d.ts +1 -0
  16. package/dist/cjs/utils/index.js +1 -0
  17. package/dist/esm/array/array-extensions.js +84 -50
  18. package/dist/esm/core/performance.d.ts +1 -0
  19. package/dist/esm/core/performance.js +5 -0
  20. package/dist/esm/core/version.d.ts +1 -0
  21. package/dist/esm/core/version.js +5 -0
  22. package/dist/esm/index.d.ts +1 -0
  23. package/dist/esm/index.js +1 -0
  24. package/dist/esm/number/number-extensions.js +86 -98
  25. package/dist/esm/object/object-extensions.js +102 -103
  26. package/dist/esm/string/string-extensions.js +66 -43
  27. package/dist/esm/types/global-augmentations.d.ts +1 -0
  28. package/dist/esm/utils/defineExtension.d.ts +1 -0
  29. package/dist/esm/utils/defineExtension.js +10 -0
  30. package/dist/esm/utils/index.d.ts +1 -0
  31. package/dist/esm/utils/index.js +1 -0
  32. package/dist/types/core/performance.d.ts +1 -0
  33. package/dist/types/core/version.d.ts +1 -0
  34. package/dist/types/index.d.ts +1 -0
  35. package/dist/types/types/global-augmentations.d.ts +1 -0
  36. package/dist/types/utils/defineExtension.d.ts +1 -0
  37. package/dist/types/utils/index.d.ts +1 -0
  38. package/package.json +8 -4
@@ -1,34 +1,36 @@
1
- // String prototype extensions
1
+ import { defineExtension } from "src/utils";
2
+ let stringExtended = false;
2
3
  export function extendString() {
3
- String.prototype.toCapitalize = function () {
4
+ if (stringExtended)
5
+ return;
6
+ stringExtended = true;
7
+ defineExtension(String.prototype, 'toCapitalize', function () {
4
8
  return this.charAt(0).toUpperCase() + this.slice(1).toLowerCase();
5
- };
6
- String.prototype.toCamelCase = function () {
7
- return this.replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : '');
8
- };
9
- String.prototype.toKebabCase = function () {
9
+ });
10
+ defineExtension(String.prototype, 'toCamelCase', function () {
11
+ return this.replace(/[-_\s]+(.)?/g, (_, char) => (char ? char.toUpperCase() : ''));
12
+ });
13
+ defineExtension(String.prototype, 'toKebabCase', function () {
10
14
  return this.replace(/([a-z])([A-Z])/g, '$1-$2')
11
15
  .replace(/[\s_]+/g, '-')
12
16
  .toLowerCase();
13
- };
14
- String.prototype.toSnakeCase = function () {
17
+ });
18
+ defineExtension(String.prototype, 'toSnakeCase', function () {
15
19
  return this.replace(/([a-z])([A-Z])/g, '$1_$2')
16
20
  .replace(/[\s-]+/g, '_')
17
21
  .toLowerCase();
18
- };
19
- String.prototype.truncate = function (length, suffix = '...') {
22
+ });
23
+ defineExtension(String.prototype, 'truncate', function (length, suffix = '...') {
20
24
  if (!Number.isInteger(length) || length < 0) {
21
25
  throw new TypeError(`truncate: length must be a non-negative integer, got ${length}`);
22
26
  }
23
- return this.length > length
24
- ? this.substring(0, length) + suffix
25
- : this.toString();
26
- };
27
- String.prototype.isEmail = function () {
27
+ return this.length > length ? this.substring(0, length) + suffix : this.toString();
28
+ });
29
+ defineExtension(String.prototype, 'isEmail', function () {
28
30
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
29
31
  return emailRegex.test(this.toString());
30
- };
31
- String.prototype.isUrl = function () {
32
+ });
33
+ defineExtension(String.prototype, 'isUrl', function () {
32
34
  try {
33
35
  new URL(this.toString());
34
36
  return true;
@@ -36,24 +38,24 @@ export function extendString() {
36
38
  catch {
37
39
  return false;
38
40
  }
39
- };
40
- String.prototype.removeWhitespace = function () {
41
+ });
42
+ defineExtension(String.prototype, 'removeWhitespace', function () {
41
43
  return this.replace(/\s+/g, '');
42
- };
43
- String.prototype.reverse = function () {
44
+ });
45
+ defineExtension(String.prototype, 'reverse', function () {
44
46
  return this.split('').reverse().join('');
45
- };
46
- String.prototype.isPalindrome = function () {
47
+ });
48
+ defineExtension(String.prototype, 'isPalindrome', function () {
47
49
  const cleaned = this.toLowerCase().replace(/[^a-z0-9]/g, '');
48
50
  return cleaned === cleaned.split('').reverse().join('');
49
- };
50
- String.prototype.toTitleCase = function () {
51
+ });
52
+ defineExtension(String.prototype, 'toTitleCase', function () {
51
53
  return this.replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase());
52
- };
53
- String.prototype.stripHtml = function () {
54
+ });
55
+ defineExtension(String.prototype, 'stripHtml', function () {
54
56
  return this.replace(/<[^>]*>/g, '');
55
- };
56
- String.prototype.padStart = function (targetLength, padString = ' ') {
57
+ });
58
+ defineExtension(String.prototype, 'padStart', function (targetLength, padString = ' ') {
57
59
  if (!Number.isInteger(targetLength) || targetLength < 0) {
58
60
  throw new TypeError(`padStart: targetLength must be a non-negative integer, got ${targetLength}`);
59
61
  }
@@ -64,8 +66,8 @@ export function extendString() {
64
66
  throw new TypeError('padStart: padString cannot be empty');
65
67
  }
66
68
  return this.toString().padStart(targetLength, padString);
67
- };
68
- String.prototype.padEnd = function (targetLength, padString = ' ') {
69
+ });
70
+ defineExtension(String.prototype, 'padEnd', function (targetLength, padString = ' ') {
69
71
  if (!Number.isInteger(targetLength) || targetLength < 0) {
70
72
  throw new TypeError(`padEnd: targetLength must be a non-negative integer, got ${targetLength}`);
71
73
  }
@@ -76,22 +78,43 @@ export function extendString() {
76
78
  throw new TypeError('padEnd: padString cannot be empty');
77
79
  }
78
80
  return this.toString().padEnd(targetLength, padString);
79
- };
80
- String.prototype.count = function (substring) {
81
+ });
82
+ defineExtension(String.prototype, 'count', function (substring) {
81
83
  if (typeof substring !== 'string') {
82
84
  throw new TypeError(`count: substring must be a string, got ${typeof substring}`);
83
85
  }
84
86
  if (substring === '') {
85
87
  throw new TypeError('count: substring cannot be empty');
86
88
  }
87
- return (this.match(new RegExp(substring, 'g')) || []).length;
88
- };
89
- String.prototype.words = function () {
90
- return this.trim()
91
- .split(/\s+/)
92
- .filter((word) => word.length > 0);
93
- };
94
- String.prototype.lines = function () {
89
+ const escaped = substring.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
90
+ return (this.match(new RegExp(escaped, 'g')) || []).length;
91
+ });
92
+ defineExtension(String.prototype, 'words', function () {
93
+ return this.trim().split(/\s+/).filter((word) => word.length > 0);
94
+ });
95
+ defineExtension(String.prototype, 'lines', function () {
95
96
  return this.split(/\r?\n/);
96
- };
97
+ });
98
+ defineExtension(String.prototype, 'capitalizeWords', function () {
99
+ return this.toString().replace(/\b\w/g, (char) => char.toUpperCase());
100
+ });
101
+ defineExtension(String.prototype, 'reverseWords', function () {
102
+ return this.toString().split(/\s+/).reverse().join(' ');
103
+ });
104
+ defineExtension(String.prototype, 'truncateWords', function (count, suffix = '...') {
105
+ if (!Number.isInteger(count) || count < 0) {
106
+ throw new TypeError(`truncateWords: count must be a non-negative integer, got ${count}`);
107
+ }
108
+ const words = this.toString().split(/\s+/);
109
+ if (words.length <= count)
110
+ return this.toString();
111
+ return words.slice(0, count).join(' ') + suffix;
112
+ });
113
+ defineExtension(String.prototype, 'slugify', function () {
114
+ return this.toString()
115
+ .toLowerCase()
116
+ .replace(/[^\w\s-]/g, '')
117
+ .trim()
118
+ .replace(/[\s_-]+/g, '-');
119
+ });
97
120
  }
@@ -26,6 +26,7 @@ declare global {
26
26
  sum(): number;
27
27
  average(): number;
28
28
  compact(): T[];
29
+ compactTruthy(): T[];
29
30
  pluck<K extends keyof T>(key: K): T[K][];
30
31
  findLast(predicate: (item: T) => boolean): T | undefined;
31
32
  partition(predicate: (item: T) => boolean): [T[], T[]];
@@ -0,0 +1 @@
1
+ export declare function defineExtension<T extends object>(prototype: T, name: string, fn: Function): void;
@@ -0,0 +1,10 @@
1
+ export function defineExtension(prototype, name, fn) {
2
+ if (!Object.prototype.hasOwnProperty.call(prototype, name)) {
3
+ Object.defineProperty(prototype, name, {
4
+ value: fn,
5
+ writable: false,
6
+ configurable: false,
7
+ enumerable: false,
8
+ });
9
+ }
10
+ }
@@ -1,2 +1,3 @@
1
1
  export * from './config';
2
2
  export * from './helpers';
3
+ export * from './defineExtension';
@@ -1,3 +1,4 @@
1
1
  // Re-export all utilities
2
2
  export * from './config';
3
3
  export * from './helpers';
4
+ export * from './defineExtension';
@@ -13,4 +13,5 @@ export declare class LRUCache<K, V> {
13
13
  set(key: K, value: V): void;
14
14
  clear(): void;
15
15
  }
16
+ export declare function makeInternalCacheKey(domain: string, key: string | number): string;
16
17
  export declare function withCache<T>(key: string, fn: () => T): T;
@@ -0,0 +1 @@
1
+ export declare const getPackageVersion: () => string;
@@ -21,6 +21,7 @@ export declare function initializeExtensions(options?: ExtensionOptions): void;
21
21
  */
22
22
  export { extendAll };
23
23
  /**
24
+ * Selective prototype extension helpers
24
25
  * Initialize only specific extensions
25
26
  */
26
27
  export declare const extend: {
@@ -26,6 +26,7 @@ declare global {
26
26
  sum(): number;
27
27
  average(): number;
28
28
  compact(): T[];
29
+ compactTruthy(): T[];
29
30
  pluck<K extends keyof T>(key: K): T[K][];
30
31
  findLast(predicate: (item: T) => boolean): T | undefined;
31
32
  partition(predicate: (item: T) => boolean): [T[], T[]];
@@ -0,0 +1 @@
1
+ export declare function defineExtension<T extends object>(prototype: T, name: string, fn: Function): void;
@@ -1,2 +1,3 @@
1
1
  export * from './config';
2
2
  export * from './helpers';
3
+ export * from './defineExtension';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naman_deep_singh/js-extensions",
3
- "version": "1.3.3",
3
+ "version": "1.4.0",
4
4
  "description": "Universal JavaScript prototype extensions for common development utilities",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
@@ -31,12 +31,16 @@
31
31
  "author": "Naman Deep Singh",
32
32
  "license": "ISC",
33
33
  "devDependencies": {
34
- "typescript": "^5.9.3",
35
- "rimraf": "^5.0.5"
34
+ "rimraf": "^5.0.5",
35
+ "typescript": "^5.9.3"
36
+ },
37
+ "dependencies": {
38
+ "@types/node": "^25.0.1"
36
39
  },
37
40
  "scripts": {
38
41
  "build": "pnpm run build:types && tsc -p tsconfig.cjs.json && tsc -p tsconfig.esm.json",
39
42
  "build:types": "tsc -p tsconfig.base.json --emitDeclarationOnly --outDir dist/types",
40
- "clean": "rimraf dist"
43
+ "clean": "rimraf dist",
44
+ "clean:js": "find src -type f -name \"*.js\" -delete"
41
45
  }
42
46
  }