@h3ravel/support 0.2.0 → 0.3.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @h3ravel/support
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3ff97bf: refactor: add a shared package to be extended by others to avoid cyclic dependency issues.
8
+
3
9
  ## 0.2.0
4
10
 
5
11
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -19,8 +19,8 @@ var __copyProps = (to, from, except, desc) => {
19
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
20
 
21
21
  // src/index.ts
22
- var index_exports = {};
23
- __export(index_exports, {
22
+ var src_exports = {};
23
+ __export(src_exports, {
24
24
  abbreviate: () => abbreviate,
25
25
  after: () => after,
26
26
  afterLast: () => afterLast,
@@ -46,11 +46,12 @@ __export(index_exports, {
46
46
  toHumanTime: () => toHumanTime,
47
47
  truncate: () => truncate
48
48
  });
49
- module.exports = __toCommonJS(index_exports);
49
+ module.exports = __toCommonJS(src_exports);
50
50
 
51
51
  // src/Helpers/Arr.ts
52
52
  var chunk = /* @__PURE__ */ __name((arr, size = 2) => {
53
- if (size <= 0) throw new Error("Chunk size must be greater than 0");
53
+ if (size <= 0)
54
+ throw new Error("Chunk size must be greater than 0");
54
55
  const chunks = [];
55
56
  for (let i = 0; i < arr.length; i += size) {
56
57
  chunks.push(arr.slice(i, i + size));
@@ -58,7 +59,8 @@ var chunk = /* @__PURE__ */ __name((arr, size = 2) => {
58
59
  return chunks;
59
60
  }, "chunk");
60
61
  var range = /* @__PURE__ */ __name((size, startAt = 0) => {
61
- if (size <= 0 || !Number.isFinite(size)) return [];
62
+ if (size <= 0 || !Number.isFinite(size))
63
+ return [];
62
64
  return Array.from({
63
65
  length: size
64
66
  }, (_, i) => startAt + i);
@@ -66,7 +68,8 @@ var range = /* @__PURE__ */ __name((size, startAt = 0) => {
66
68
 
67
69
  // src/Helpers/Number.ts
68
70
  var abbreviate = /* @__PURE__ */ __name((value, locale = "en-US") => {
69
- if (!value) return "0";
71
+ if (!value)
72
+ return "0";
70
73
  if (value < 1e3) {
71
74
  return new Intl.NumberFormat(locale).format(value);
72
75
  }
@@ -97,7 +100,8 @@ var abbreviate = /* @__PURE__ */ __name((value, locale = "en-US") => {
97
100
  }
98
101
  ];
99
102
  const match = si.find((scale) => value >= scale.v);
100
- if (!match) return new Intl.NumberFormat(locale).format(value);
103
+ if (!match)
104
+ return new Intl.NumberFormat(locale).format(value);
101
105
  const formatted = value / match.v;
102
106
  return new Intl.NumberFormat(locale, {
103
107
  minimumFractionDigits: 0,
@@ -147,8 +151,10 @@ var humanize = /* @__PURE__ */ __name((num, slugify2) => {
147
151
  "ninety"
148
152
  ];
149
153
  const numString = num.toString();
150
- if (num < 0) throw new Error("Negative numbers are not supported.");
151
- if (num === 0) return "zero";
154
+ if (num < 0)
155
+ throw new Error("Negative numbers are not supported.");
156
+ if (num === 0)
157
+ return "zero";
152
158
  if (num < 20) {
153
159
  return ones[num] ?? "";
154
160
  }
@@ -156,13 +162,17 @@ var humanize = /* @__PURE__ */ __name((num, slugify2) => {
156
162
  return tens[numString[0]] + " " + ones[numString[1]];
157
163
  }
158
164
  if (numString.length == 3) {
159
- if (numString[1] === "0" && numString[2] === "0") return ones[numString[0]] + " hundred";
160
- else return ones[numString[0]] + " hundred and " + humanize(+((numString[1] || "") + numString[2]), slugify2);
165
+ if (numString[1] === "0" && numString[2] === "0")
166
+ return ones[numString[0]] + " hundred";
167
+ else
168
+ return ones[numString[0]] + " hundred and " + humanize(+((numString[1] || "") + numString[2]), slugify2);
161
169
  }
162
170
  if (numString.length === 4) {
163
171
  const end = +((numString[1] || "") + numString[2] + numString[3]);
164
- if (end === 0) return ones[numString[0]] + " thousand";
165
- if (end < 100) return ones[numString[0]] + " thousand and " + humanize(end, slugify2);
172
+ if (end === 0)
173
+ return ones[numString[0]] + " thousand";
174
+ if (end < 100)
175
+ return ones[numString[0]] + " thousand and " + humanize(end, slugify2);
166
176
  return ones[numString[0]] + " thousand " + humanize(end, slugify2);
167
177
  }
168
178
  return num;
@@ -199,15 +209,19 @@ var toBytes = /* @__PURE__ */ __name((bytes, decimals = 2, bits = false) => {
199
209
  return `${value} ${sizes[index]}`;
200
210
  }, "toBytes");
201
211
  var toHumanTime = /* @__PURE__ */ __name((seconds = 0, worded = false) => {
202
- if (isNaN(seconds) || seconds < 0) seconds = 0;
212
+ if (isNaN(seconds) || seconds < 0)
213
+ seconds = 0;
203
214
  const hours = Math.floor(seconds / 3600);
204
215
  const minutes = Math.floor(seconds % 3600 / 60);
205
216
  const secs = Math.floor(seconds % 60);
206
217
  if (worded) {
207
218
  const parts = [];
208
- if (hours) parts.push(`${hours}hr`);
209
- if (minutes) parts.push(`${minutes}min`);
210
- if (secs || !hours && !minutes) parts.push(`${secs}sec`);
219
+ if (hours)
220
+ parts.push(`${hours}hr`);
221
+ if (minutes)
222
+ parts.push(`${minutes}min`);
223
+ if (secs || !hours && !minutes)
224
+ parts.push(`${secs}sec`);
211
225
  return parts.join(" ");
212
226
  }
213
227
  const hh = hours > 0 ? `${hours}:` : "";
@@ -255,7 +269,8 @@ var modObj = /* @__PURE__ */ __name((obj, callback) => {
255
269
  ])));
256
270
  }, "modObj");
257
271
  function safeDot(data, key) {
258
- if (!key) return data;
272
+ if (!key)
273
+ return data;
259
274
  return key.split(".").reduce((acc, k) => acc?.[k], data);
260
275
  }
261
276
  __name(safeDot, "safeDot");
@@ -292,32 +307,38 @@ var slugifyKeys = /* @__PURE__ */ __name((obj, only = [], separator = "_") => {
292
307
 
293
308
  // src/Helpers/Str.ts
294
309
  var after = /* @__PURE__ */ __name((value, search) => {
295
- if (!search) return value;
310
+ if (!search)
311
+ return value;
296
312
  const index = value.indexOf(search);
297
313
  return index !== -1 ? value.slice(index + search.length) : value;
298
314
  }, "after");
299
315
  var afterLast = /* @__PURE__ */ __name((value, search) => {
300
- if (!search) return value;
316
+ if (!search)
317
+ return value;
301
318
  const lastIndex = value.lastIndexOf(search);
302
319
  return lastIndex !== -1 ? value.slice(lastIndex + search.length) : value;
303
320
  }, "afterLast");
304
321
  var before = /* @__PURE__ */ __name((value, search) => {
305
- if (!search) return value;
322
+ if (!search)
323
+ return value;
306
324
  const index = value.indexOf(search);
307
325
  return index !== -1 ? value.slice(0, index) : value;
308
326
  }, "before");
309
327
  var beforeLast = /* @__PURE__ */ __name((value, search) => {
310
- if (!search) return value;
328
+ if (!search)
329
+ return value;
311
330
  const lastIndex = value.lastIndexOf(search);
312
331
  return lastIndex !== -1 ? value.slice(0, lastIndex) : value;
313
332
  }, "beforeLast");
314
333
  function capitalize(str) {
315
- if (!str) return "";
334
+ if (!str)
335
+ return "";
316
336
  return str[0].toUpperCase() + str.slice(1);
317
337
  }
318
338
  __name(capitalize, "capitalize");
319
339
  var pluralize = /* @__PURE__ */ __name((word, count) => {
320
- if (count === 1) return word;
340
+ if (count === 1)
341
+ return word;
321
342
  const irregularPlurals = {
322
343
  foot: "feet",
323
344
  child: "children",
@@ -354,7 +375,8 @@ var singularize = /* @__PURE__ */ __name((word) => {
354
375
  men: "man",
355
376
  women: "woman"
356
377
  };
357
- if (word in irregulars) return irregulars[word];
378
+ if (word in irregulars)
379
+ return irregulars[word];
358
380
  if (/ies$/i.test(word) && word.length > 3) {
359
381
  return word.replace(/ies$/i, "y");
360
382
  }
@@ -370,12 +392,15 @@ var slugify = /* @__PURE__ */ __name((str, joiner = "_") => {
370
392
  return str.replace(/([a-z])([A-Z])/g, `$1${joiner}$2`).replace(/[\s\W]+/g, joiner).replace(new RegExp(`${joiner}{2,}`, "g"), joiner).replace(new RegExp(`^${joiner}|${joiner}$`, "g"), "").toLowerCase();
371
393
  }, "slugify");
372
394
  var subString = /* @__PURE__ */ __name((str, len, ellipsis = "...") => {
373
- if (!str) return "";
374
- if (len <= ellipsis.length) return ellipsis;
395
+ if (!str)
396
+ return "";
397
+ if (len <= ellipsis.length)
398
+ return ellipsis;
375
399
  return str.length > len ? str.substring(0, len - ellipsis.length).trimEnd() + ellipsis : str;
376
400
  }, "subString");
377
401
  var substitute = /* @__PURE__ */ __name((str, data = {}, def) => {
378
- if (!str || !data) return void 0;
402
+ if (!str || !data)
403
+ return void 0;
379
404
  const regex = /{\s*([a-zA-Z0-9_.]+)\s*}/g;
380
405
  const flattened = dot(data);
381
406
  const out = str.replace(regex, (_, key) => {
@@ -385,7 +410,8 @@ var substitute = /* @__PURE__ */ __name((str, data = {}, def) => {
385
410
  return out;
386
411
  }, "substitute");
387
412
  var truncate = /* @__PURE__ */ __name((str, len = 20, suffix = "...") => {
388
- if (!str) return "";
413
+ if (!str)
414
+ return "";
389
415
  const clean = str.replace(/<[^>]+>/g, "");
390
416
  const truncated = clean.length > len ? clean.substring(0, len - suffix.length) + suffix : clean;
391
417
  return truncated.replace(/\n/g, " ").replace(new RegExp(`\\s+${suffix.replace(/\./g, "\\.")}$`), suffix);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/Helpers/Arr.ts","../src/Helpers/Number.ts","../src/Helpers/Obj.ts","../src/Helpers/Str.ts"],"sourcesContent":["/**\n * @file Automatically generated by barrelsby.\n */\n\nexport * from './Contracts/ObjContract';\nexport * from './Contracts/StrContract';\nexport * from './Helpers/Arr';\nexport * from './Helpers/Number';\nexport * from './Helpers/Obj';\nexport * from './Helpers/Str';\n","/**\n * Splits an array into chunks of a specified size.\n *\n * @template T - Type of elements in the array\n * @param arr - The input array\n * @param size - Size of each chunk (default: 2)\n * @returns An array of chunks (arrays)\n */\nexport const chunk = <T> (arr: T[], size: number = 2): T[][] => {\n if (size <= 0) throw new Error(\"Chunk size must be greater than 0\")\n\n const chunks: T[][] = []\n\n for (let i = 0; i < arr.length; i += size) {\n chunks.push(arr.slice(i, i + size))\n }\n\n return chunks\n}\n\n\n/**\n * Generates an array of sequential numbers.\n *\n * @param size - Number of elements in the range\n * @param startAt - Starting number (default: 0)\n * @returns An array of numbers from startAt to startAt + size - 1\n */\nexport const range = (size: number, startAt: number = 0): number[] => {\n if (size <= 0 || !Number.isFinite(size)) return []\n\n return Array.from({ length: size }, (_, i) => startAt + i)\n}\n","/**\n * Abbreviates large numbers using SI symbols (K, M, B...) \n * and formats the output according to the given locale.\n *\n * @param value - The number to abbreviate\n * @param locale - Optional locale string (default: \"en-US\")\n * @returns A localized, abbreviated number string\n */\nexport const abbreviate = (value?: number, locale: string = 'en-US'): string => {\n if (!value) return '0'\n\n // Numbers less than 1000 don't need abbreviation\n if (value < 1000) {\n return new Intl.NumberFormat(locale).format(value)\n }\n\n const si = [\n { v: 1e18, s: 'E' },\n { v: 1e15, s: 'P' },\n { v: 1e12, s: 'T' },\n { v: 1e9, s: 'B' },\n { v: 1e6, s: 'M' },\n { v: 1e3, s: 'K' },\n ]\n\n const match = si.find(scale => value >= scale.v)\n if (!match) return new Intl.NumberFormat(locale).format(value)\n\n const formatted = value / match.v\n\n return (\n new Intl.NumberFormat(locale, {\n minimumFractionDigits: 0,\n maximumFractionDigits: 2,\n }).format(formatted) + match.s\n )\n}\n\n/**\n * Concverts a number into human readable string\n *\n * @param num The number to convert\n * @param slugify convert the ouput into a slug using this as a separator\n * @returns\n */\nexport const humanize = (num: number, slugify?: '-' | '_'): string => {\n if (!num) {\n return ''\n }\n\n if (slugify === '-' || slugify === '_') {\n const h = humanize(num)\n return typeof h === 'string' ? h.replace(' ', slugify).toLowerCase() : h\n }\n\n const ones = [\n '',\n 'one',\n 'two',\n 'three',\n 'four',\n 'five',\n 'six',\n 'seven',\n 'eight',\n 'nine',\n 'ten',\n 'eleven',\n 'twelve',\n 'thirteen',\n 'fourteen',\n 'fifteen',\n 'sixteen',\n 'seventeen',\n 'eighteen',\n 'nineteen',\n ]\n const tens = [\n '',\n '',\n 'twenty',\n 'thirty',\n 'forty',\n 'fifty',\n 'sixty',\n 'seventy',\n 'eighty',\n 'ninety',\n ]\n\n const numString: string = num.toString()\n\n if (num < 0) throw new Error('Negative numbers are not supported.')\n\n if (num === 0) return 'zero'\n\n //the case of 1 - 20\n if (num < 20) {\n return ones[num] ?? ''\n }\n\n if (numString.length === 2) {\n return tens[numString[0] as unknown as number] + ' ' + ones[numString[1] as unknown as number]\n }\n\n //100 and more\n if (numString.length == 3) {\n if (numString[1] === '0' && numString[2] === '0')\n return ones[numString[0] as unknown as number] + ' hundred'\n else\n return (\n ones[numString[0] as unknown as number] +\n ' hundred and ' +\n humanize(+((numString[1] || '') + numString[2]), slugify)\n )\n }\n\n if (numString.length === 4) {\n const end = +((numString[1] || '') + numString[2] + numString[3])\n if (end === 0) return ones[numString[0] as unknown as number] + ' thousand'\n if (end < 100)\n return ones[numString[0] as unknown as number] + ' thousand and ' + humanize(end, slugify)\n return ones[numString[0] as unknown as number] + ' thousand ' + humanize(end, slugify)\n }\n\n return num as unknown as string\n}\n\n/**\n * Converts a number of bytes into a human-readable string.\n *\n * @param bytes - The size in bytes to convert\n * @param decimals - Number of decimal places to display (default: 2)\n * @param bits - If true, uses 1000-based (SI) units (B, KB, MB...); \n * otherwise uses 1024-based binary units (Bytes, KiB...)\n * @returns A formatted string with the appropriate unit\n */\nexport const toBytes = (\n bytes?: number,\n decimals: number = 2,\n bits: boolean = false\n): string => {\n if (!bytes || isNaN(bytes)) {\n return bits ? '0 B' : '0 Bytes'\n }\n\n const base = bits ? 1000 : 1024\n const dm = decimals < 0 ? 0 : decimals\n const sizes = bits\n ? ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] // SI units\n : ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'] // Binary units\n\n const index = Math.floor(Math.log(bytes) / Math.log(base))\n\n const value = parseFloat((bytes / Math.pow(base, index)).toFixed(dm))\n return `${value} ${sizes[index]}`\n}\n\n/**\n * Formats a duration (in seconds) into a human-readable string.\n *\n * @param seconds - Duration in seconds\n * @param worded - If true, outputs worded format (e.g., \"1hr 2min 3sec\"),\n * otherwise HH:MM:SS (e.g., \"01:02:03\")\n * @returns A formatted time string\n */\nexport const toHumanTime = (\n seconds: number = 0,\n worded: boolean = false\n): string => {\n // Ensure seconds is a number and not negative\n if (isNaN(seconds) || seconds < 0) seconds = 0\n\n const hours = Math.floor(seconds / 3600)\n const minutes = Math.floor((seconds % 3600) / 60)\n const secs = Math.floor(seconds % 60)\n\n // Worded format → \"1hr 2min 3sec\"\n if (worded) {\n const parts = []\n if (hours) parts.push(`${hours}hr`)\n if (minutes) parts.push(`${minutes}min`)\n if (secs || (!hours && !minutes)) parts.push(`${secs}sec`)\n return parts.join(' ')\n }\n\n // HH:MM:SS format → zero-padded\n const hh = hours > 0 ? `${hours}:` : ''\n const mm = (hours > 0 && minutes < 10 ? `0${minutes}` : minutes) + ':'\n const ss = secs < 10 ? `0${secs}` : secs\n\n return `${hh}${mm}${ss}`\n}\n\n","import { DotFlatten, DotNestedKeys, DotNestedValue, KeysToSnakeCase } from \"../Contracts/ObjContract\"\n\n/**\n * Flattens a nested object into a single-level object\n * with dot-separated keys.\n *\n * Example:\n * doter({\n * user: { name: \"John\", address: { city: \"NY\" } },\n * active: true\n * })\n * \n * Output:\n * {\n * \"user.name\": \"John\",\n * \"user.address.city\": \"NY\",\n * \"active\": true\n * }\n *\n * @template T - The type of the input object\n * @param obj - The nested object to flatten\n * @returns A flattened object with dotted keys and inferred types\n */\nexport const dot = <T extends Record<string, any>> (obj: T): DotFlatten<T> => {\n const result = {} as Record<string, unknown>\n\n /**\n * Internal recursive function to traverse and flatten the object.\n * \n * @param o - Current object to flatten\n * @param prefix - Key path accumulated so far\n */\n const recurse = (o: Record<string, any>, prefix = ''): void => {\n for (const [key, value] of Object.entries(o)) {\n const newKey = prefix ? `${prefix}.${key}` : key\n\n /**\n * Recurse if the value is a plain object\n */\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n recurse(value, newKey)\n } else {\n /**\n * Otherwise, assign directly\n */\n result[newKey] = value\n }\n }\n }\n\n recurse(obj)\n return result as DotFlatten<T>\n}\n\n/**\n * Extracts a subset of properties from an object.\n *\n * @template T - Type of the source object\n * @template K - Keys of T to extract\n * @param obj - The source object\n * @param keys - Array of keys to extract\n * @returns A new object with only the specified keys\n */\nexport const extractProperties = <T extends object, K extends keyof T> (\n obj: T,\n keys: readonly K[] = []\n): Pick<T, K> => {\n return Object.fromEntries(\n keys.map(key => [key, obj[key]])\n ) as Pick<T, K>\n}\n\n/**\n * Safely retrieves a value from an object by key or nested keys.\n *\n * @template T - Type of the source object\n * @param key - Single key or tuple [parentKey, childKey]\n * @param item - The source object\n * @returns The found value as a string or the key itself if not found\n */\nexport const getValue = <\n T extends Record<string, any> // Allow nested objects\n> (\n key: string | [keyof T, keyof T[string]],\n item: T\n): string => {\n if (Array.isArray(key)) {\n const [parent, child] = key\n\n if (child !== undefined) {\n // Access nested property: item[parent][child]\n return (\n String(item?.[parent]?.[child] ??\n item?.[parent] ??\n `${String(parent)}.${String(child)}`)\n )\n }\n\n // Only top-level key\n return String(item?.[parent] ?? parent)\n }\n\n // Single key access\n return String(item?.[key] ?? key)\n}\n\n/**\n * Maps over an object's entries and returns a new object \n * with transformed keys and/or values.\n *\n * @template T - Type of the input object\n * @template R - Type of the new values\n * @param obj - The object to transform\n * @param callback - Function that receives [key, value] and returns [newKey, newValue]\n * @returns A new object with transformed entries\n */\nexport const modObj = <T extends object, R> (\n obj: T,\n callback: (entry: [keyof T & string, T[keyof T]]) => [string, R]\n): Record<string, R> => {\n return Object.fromEntries(\n Object.entries(obj).map(([key, value]) =>\n callback([key as keyof T & string, value as T[keyof T]])\n )\n ) as Record<string, R>\n}\n\n\nexport function safeDot<T extends Record<string, any>> (data: T): T\nexport function safeDot<\n T extends Record<string, any>,\n K extends DotNestedKeys<T>\n> (data: T, key?: K): DotNestedValue<T, K>\nexport function safeDot<\n T extends Record<string, any>,\n K extends DotNestedKeys<T>\n> (data: T, key?: K): any {\n if (!key) return data\n return key.split('.').reduce((acc: any, k) => acc?.[k], data)\n}\n\n/**\n * Sets a nested property on an object using dot notation.\n * \n * @example\n * const obj = {}\n * setNested(obj, 'app.user.name', 'Legacy')\n * console.log(obj)\n * // Output: { app: { user: { name: 'Legacy' } } }\n * \n * @param obj - The target object to modify.\n * @param key - The dot-separated key (e.g., 'app.user.name').\n * @param value - The value to set at the specified path.\n */\nexport const setNested = (\n obj: Record<string, any>,\n key: string,\n value: any\n): void => {\n if (!key.includes('.')) {\n obj[key] = value\n return\n }\n\n const parts = key.split('.')\n let current = obj\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]\n\n /**\n * If we're at the last key, assign the value\n */\n if (i === parts.length - 1) {\n current[part] = value\n } else {\n /**\n * If the key doesn't exist or isn't an object, create it\n */\n if (typeof current[part] !== 'object' || current[part] === null) {\n current[part] = {}\n }\n current = current[part]\n }\n }\n}\n\n/**\n * Converts object keys to a slugified format (e.g., snake_case).\n *\n * @template T - Type of the input object\n * @param obj - The object whose keys will be slugified\n * @param only - Optional array of keys to slugify (others remain unchanged)\n * @param separator - Separator for slugified keys (default: \"_\")\n * @returns A new object with slugified keys\n */\nexport const slugifyKeys = <T extends object> (\n obj: T,\n only: string[] = [],\n separator: string = '_'\n): KeysToSnakeCase<T> => {\n const slugify = (key: string): string =>\n key\n .replace(/([a-z])([A-Z])/g, `$1${separator}$2`) // Handle camelCase\n .replace(/[\\s\\W]+/g, separator) // Replace spaces/symbols\n .replace(new RegExp(`${separator}{2,}`, 'g'), separator) // Remove duplicate separators\n .replace(new RegExp(`^${separator}|${separator}$`, 'g'), '') // Trim edges\n .toLowerCase()\n\n let entries = Object.entries(obj)\n\n // Filter if `only` is provided\n if (only.length) {\n entries = entries.filter(([key]) => only.includes(key))\n }\n\n return Object.fromEntries(\n entries.map(([key, value]) => [slugify(key), value])\n ) as KeysToSnakeCase<T>\n}\n","import { dot } from \"./Obj\"\n\n/**\n * Get the portion of the string after the first occurrence of the given value.\n * \n * @param value \n * @param search \n * @returns \n */\nexport const after = (value: string, search: string): string => {\n if (!search) return value\n const index = value.indexOf(search)\n return index !== -1 ? value.slice(index + search.length) : value\n}\n\n/**\n * Get the portion of the string after the last occurrence of the given value.\n * \n * @param value \n * @param search \n * @returns \n */\nexport const afterLast = (value: string, search: string): string => {\n if (!search) return value\n const lastIndex = value.lastIndexOf(search)\n return lastIndex !== -1 ? value.slice(lastIndex + search.length) : value\n}\n\n/**\n * Get the portion of the string before the first occurrence of the given value.\n * \n * @param value \n * @param search \n * @returns \n */\nexport const before = (value: string, search: string): string => {\n if (!search) return value\n const index = value.indexOf(search)\n return index !== -1 ? value.slice(0, index) : value\n}\n\n/**\n * Get the portion of the string before the last occurrence of the given value.\n * \n * @param value \n * @param search \n * @returns \n */\nexport const beforeLast = (value: string, search: string): string => {\n if (!search) return value\n const lastIndex = value.lastIndexOf(search)\n return lastIndex !== -1 ? value.slice(0, lastIndex) : value\n}\n\n/**\n * Capitalizes the first character of a string.\n *\n * @param str - The input string\n * @returns The string with the first character capitalized\n */\nexport function capitalize (str: string): string {\n if (!str) return '' // Handle empty or undefined strings safely\n return str[0].toUpperCase() + str.slice(1)\n}\n\n\n/**\n * Returns the pluralized form of a word based on the given number.\n *\n * @param word - The word to pluralize\n * @param count - The number determining pluralization\n * @returns Singular if count === 1, otherwise plural form\n */\nexport const pluralize = (word: string, count: number): string => {\n // If count is exactly 1 → singular\n if (count === 1) return word\n\n // Irregular plurals map\n const irregularPlurals: Record<string, string> = {\n foot: 'feet',\n child: 'children',\n mouse: 'mice',\n goose: 'geese',\n person: 'people',\n man: 'men',\n woman: 'women',\n }\n\n // Handle irregular cases first\n if (word in irregularPlurals) {\n return irregularPlurals[word]\n }\n\n // If word ends with consonant + \"y\" → replace \"y\" with \"ies\"\n if (\n word.endsWith('y') &&\n !['a', 'e', 'i', 'o', 'u'].includes(word[word.length - 2]?.toLowerCase() ?? '')\n ) {\n return word.slice(0, -1) + 'ies'\n }\n\n // If word ends in \"s\", \"ss\", \"sh\", \"ch\", \"x\", or \"z\" → add \"es\"\n if (/(s|ss|sh|ch|x|z)$/i.test(word)) {\n return word + 'es'\n }\n\n // Default: just add \"s\"\n return word + 's'\n}\n\n/**\n * Converts a plural English word into its singular form.\n *\n * @param word - The word to singularize\n * @returns The singular form of the word\n */\nexport const singularize = (word: string): string => {\n // Irregular plurals map (reverse of pluralize)\n const irregulars: Record<string, string> = {\n feet: 'foot',\n children: 'child',\n mice: 'mouse',\n geese: 'goose',\n people: 'person',\n men: 'man',\n women: 'woman',\n }\n\n // Handle irregular cases\n if (word in irregulars) return irregulars[word]\n\n // Words ending in \"ies\" → change to \"y\" (e.g., \"bodies\" → \"body\")\n if (/ies$/i.test(word) && word.length > 3) {\n return word.replace(/ies$/i, 'y')\n }\n\n // Words ending in \"es\" after certain consonants → remove \"es\"\n if (/(ches|shes|sses|xes|zes)$/i.test(word)) {\n return word.replace(/es$/i, '')\n }\n\n // Generic case: remove trailing \"s\"\n if (/s$/i.test(word) && word.length > 1) {\n return word.replace(/s$/i, '')\n }\n\n return word\n}\n\n/**\n * Converts a string into a slug format.\n * Handles camelCase, spaces, and non-alphanumeric characters.\n *\n * @param str - The input string to slugify\n * @param joiner - The character used to join words (default: \"_\")\n * @returns A slugified string\n */\nexport const slugify = (str: string, joiner = '_'): string => {\n return str\n // Handle camelCase by adding joiner between lowercase → uppercase\n .replace(/([a-z])([A-Z])/g, `$1${joiner}$2`)\n // Replace spaces and non-alphanumeric characters with joiner\n .replace(/[\\s\\W]+/g, joiner)\n // Remove duplicate joiners\n .replace(new RegExp(`${joiner}{2,}`, 'g'), joiner)\n // Trim joiners from start/end\n .replace(new RegExp(`^${joiner}|${joiner}$`, 'g'), '')\n .toLowerCase()\n}\n\n/**\n * Truncates a string to a specified length and appends an ellipsis if needed.\n *\n * @param str - The input string\n * @param len - Maximum length of the result (including ellipsis)\n * @param ellipsis - String to append if truncated (default: \"...\")\n * @returns The truncated string\n */\nexport const subString = (\n str: string,\n len: number,\n ellipsis: string = '...'\n): string => {\n if (!str) return ''\n if (len <= ellipsis.length) return ellipsis // Avoid negative slicing\n\n return str.length > len\n ? str.substring(0, len - ellipsis.length).trimEnd() + ellipsis\n : str\n}\n\n/**\n * Replaces placeholders in a string with corresponding values from a data object.\n * \n * Example:\n * substitute(\"Hello { user.name }!\", { user: { name: \"John\" } })\n * // \"Hello John!\"\n *\n * @param str - The string containing placeholders wrapped in { } braces.\n * @param data - Object containing values to substitute. Supports nested keys via dot notation.\n * @param def - Default value to use if a key is missing. (Optional)\n * @returns The substituted string or undefined if the input string or data is invalid.\n */\nexport const substitute = (\n str: string,\n data: Record<string, unknown> = {},\n def?: string\n): string | undefined => {\n if (!str || !data) return undefined\n\n // Matches { key } or { nested.key } placeholders\n const regex = /{\\s*([a-zA-Z0-9_.]+)\\s*}/g\n\n // Flatten the data so we can directly access dot notation keys\n const flattened = dot(data)\n\n // Replace each placeholder with its value or the default\n const out = str.replace(regex, (_, key: string) => {\n const value = flattened[key]\n return value !== undefined ? String(value) : def ?? ''\n })\n\n return out\n}\n\n/**\n * Truncates a string to a specified length, removing HTML tags and \n * appending a suffix if the string exceeds the length.\n *\n * @param str - The string to truncate\n * @param len - Maximum length (default: 20)\n * @param suffix - Suffix to append if truncated (default: \"...\")\n * @returns The truncated string\n */\nexport const truncate = (\n str: string,\n len: number = 20,\n suffix: string = '...'\n): string => {\n if (!str) return ''\n\n // Remove any HTML tags\n const clean = str.replace(/<[^>]+>/g, '')\n\n // Determine if we need to truncate\n const truncated =\n clean.length > len\n ? clean.substring(0, len - suffix.length) + suffix\n : clean\n\n // Normalize spaces and line breaks\n return truncated\n .replace(/\\n/g, ' ') // Replace all line breaks\n .replace(new RegExp(`\\\\s+${suffix.replace(/\\./g, '\\\\.')}$`), suffix) // Avoid extra space before suffix\n}\n\n"],"mappings":"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","names":["chunk","arr","size","Error","chunks","i","length","push","slice","range","startAt","Number","isFinite","Array","from","_","abbreviate","value","locale","Intl","NumberFormat","format","si","v","s","match","find","scale","formatted","minimumFractionDigits","maximumFractionDigits","humanize","num","slugify","h","replace","toLowerCase","ones","tens","numString","toString","Error","length","end","toBytes","bytes","decimals","bits","isNaN","base","dm","sizes","index","Math","floor","log","parseFloat","pow","toFixed","toHumanTime","seconds","worded","hours","minutes","secs","parts","push","join","hh","mm","ss","dot","obj","result","recurse","o","prefix","key","value","Object","entries","newKey","Array","isArray","extractProperties","keys","fromEntries","map","getValue","item","parent","child","undefined","String","modObj","callback","safeDot","data","split","reduce","acc","k","setNested","includes","parts","current","i","length","part","slugifyKeys","only","separator","slugify","replace","RegExp","toLowerCase","filter","after","value","search","index","indexOf","slice","length","afterLast","lastIndex","lastIndexOf","before","beforeLast","capitalize","str","toUpperCase","pluralize","word","count","irregularPlurals","foot","child","mouse","goose","person","man","woman","endsWith","includes","toLowerCase","test","singularize","irregulars","feet","children","mice","geese","people","men","women","replace","slugify","joiner","RegExp","subString","len","ellipsis","substring","trimEnd","substitute","data","def","undefined","regex","flattened","dot","out","_","key","String","truncate","suffix","clean","truncated"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/Helpers/Arr.ts","../src/Helpers/Number.ts","../src/Helpers/Obj.ts","../src/Helpers/Str.ts"],"sourcesContent":["/**\n * @file Automatically generated by barrelsby.\n */\n\nexport * from './Contracts/ObjContract';\nexport * from './Contracts/StrContract';\nexport * from './Helpers/Arr';\nexport * from './Helpers/Number';\nexport * from './Helpers/Obj';\nexport * from './Helpers/Str';\n","/**\n * Splits an array into chunks of a specified size.\n *\n * @template T - Type of elements in the array\n * @param arr - The input array\n * @param size - Size of each chunk (default: 2)\n * @returns An array of chunks (arrays)\n */\nexport const chunk = <T> (arr: T[], size: number = 2): T[][] => {\n if (size <= 0) throw new Error(\"Chunk size must be greater than 0\")\n\n const chunks: T[][] = []\n\n for (let i = 0; i < arr.length; i += size) {\n chunks.push(arr.slice(i, i + size))\n }\n\n return chunks\n}\n\n\n/**\n * Generates an array of sequential numbers.\n *\n * @param size - Number of elements in the range\n * @param startAt - Starting number (default: 0)\n * @returns An array of numbers from startAt to startAt + size - 1\n */\nexport const range = (size: number, startAt: number = 0): number[] => {\n if (size <= 0 || !Number.isFinite(size)) return []\n\n return Array.from({ length: size }, (_, i) => startAt + i)\n}\n","/**\n * Abbreviates large numbers using SI symbols (K, M, B...) \n * and formats the output according to the given locale.\n *\n * @param value - The number to abbreviate\n * @param locale - Optional locale string (default: \"en-US\")\n * @returns A localized, abbreviated number string\n */\nexport const abbreviate = (value?: number, locale: string = 'en-US'): string => {\n if (!value) return '0'\n\n // Numbers less than 1000 don't need abbreviation\n if (value < 1000) {\n return new Intl.NumberFormat(locale).format(value)\n }\n\n const si = [\n { v: 1e18, s: 'E' },\n { v: 1e15, s: 'P' },\n { v: 1e12, s: 'T' },\n { v: 1e9, s: 'B' },\n { v: 1e6, s: 'M' },\n { v: 1e3, s: 'K' },\n ]\n\n const match = si.find(scale => value >= scale.v)\n if (!match) return new Intl.NumberFormat(locale).format(value)\n\n const formatted = value / match.v\n\n return (\n new Intl.NumberFormat(locale, {\n minimumFractionDigits: 0,\n maximumFractionDigits: 2,\n }).format(formatted) + match.s\n )\n}\n\n/**\n * Concverts a number into human readable string\n *\n * @param num The number to convert\n * @param slugify convert the ouput into a slug using this as a separator\n * @returns\n */\nexport const humanize = (num: number, slugify?: '-' | '_'): string => {\n if (!num) {\n return ''\n }\n\n if (slugify === '-' || slugify === '_') {\n const h = humanize(num)\n return typeof h === 'string' ? h.replace(' ', slugify).toLowerCase() : h\n }\n\n const ones = [\n '',\n 'one',\n 'two',\n 'three',\n 'four',\n 'five',\n 'six',\n 'seven',\n 'eight',\n 'nine',\n 'ten',\n 'eleven',\n 'twelve',\n 'thirteen',\n 'fourteen',\n 'fifteen',\n 'sixteen',\n 'seventeen',\n 'eighteen',\n 'nineteen',\n ]\n const tens = [\n '',\n '',\n 'twenty',\n 'thirty',\n 'forty',\n 'fifty',\n 'sixty',\n 'seventy',\n 'eighty',\n 'ninety',\n ]\n\n const numString: string = num.toString()\n\n if (num < 0) throw new Error('Negative numbers are not supported.')\n\n if (num === 0) return 'zero'\n\n //the case of 1 - 20\n if (num < 20) {\n return ones[num] ?? ''\n }\n\n if (numString.length === 2) {\n return tens[numString[0] as unknown as number] + ' ' + ones[numString[1] as unknown as number]\n }\n\n //100 and more\n if (numString.length == 3) {\n if (numString[1] === '0' && numString[2] === '0')\n return ones[numString[0] as unknown as number] + ' hundred'\n else\n return (\n ones[numString[0] as unknown as number] +\n ' hundred and ' +\n humanize(+((numString[1] || '') + numString[2]), slugify)\n )\n }\n\n if (numString.length === 4) {\n const end = +((numString[1] || '') + numString[2] + numString[3])\n if (end === 0) return ones[numString[0] as unknown as number] + ' thousand'\n if (end < 100)\n return ones[numString[0] as unknown as number] + ' thousand and ' + humanize(end, slugify)\n return ones[numString[0] as unknown as number] + ' thousand ' + humanize(end, slugify)\n }\n\n return num as unknown as string\n}\n\n/**\n * Converts a number of bytes into a human-readable string.\n *\n * @param bytes - The size in bytes to convert\n * @param decimals - Number of decimal places to display (default: 2)\n * @param bits - If true, uses 1000-based (SI) units (B, KB, MB...); \n * otherwise uses 1024-based binary units (Bytes, KiB...)\n * @returns A formatted string with the appropriate unit\n */\nexport const toBytes = (\n bytes?: number,\n decimals: number = 2,\n bits: boolean = false\n): string => {\n if (!bytes || isNaN(bytes)) {\n return bits ? '0 B' : '0 Bytes'\n }\n\n const base = bits ? 1000 : 1024\n const dm = decimals < 0 ? 0 : decimals\n const sizes = bits\n ? ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] // SI units\n : ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'] // Binary units\n\n const index = Math.floor(Math.log(bytes) / Math.log(base))\n\n const value = parseFloat((bytes / Math.pow(base, index)).toFixed(dm))\n return `${value} ${sizes[index]}`\n}\n\n/**\n * Formats a duration (in seconds) into a human-readable string.\n *\n * @param seconds - Duration in seconds\n * @param worded - If true, outputs worded format (e.g., \"1hr 2min 3sec\"),\n * otherwise HH:MM:SS (e.g., \"01:02:03\")\n * @returns A formatted time string\n */\nexport const toHumanTime = (\n seconds: number = 0,\n worded: boolean = false\n): string => {\n // Ensure seconds is a number and not negative\n if (isNaN(seconds) || seconds < 0) seconds = 0\n\n const hours = Math.floor(seconds / 3600)\n const minutes = Math.floor((seconds % 3600) / 60)\n const secs = Math.floor(seconds % 60)\n\n // Worded format → \"1hr 2min 3sec\"\n if (worded) {\n const parts = []\n if (hours) parts.push(`${hours}hr`)\n if (minutes) parts.push(`${minutes}min`)\n if (secs || (!hours && !minutes)) parts.push(`${secs}sec`)\n return parts.join(' ')\n }\n\n // HH:MM:SS format → zero-padded\n const hh = hours > 0 ? `${hours}:` : ''\n const mm = (hours > 0 && minutes < 10 ? `0${minutes}` : minutes) + ':'\n const ss = secs < 10 ? `0${secs}` : secs\n\n return `${hh}${mm}${ss}`\n}\n\n","import { DotFlatten, DotNestedKeys, DotNestedValue, KeysToSnakeCase } from \"../Contracts/ObjContract\"\n\n/**\n * Flattens a nested object into a single-level object\n * with dot-separated keys.\n *\n * Example:\n * doter({\n * user: { name: \"John\", address: { city: \"NY\" } },\n * active: true\n * })\n * \n * Output:\n * {\n * \"user.name\": \"John\",\n * \"user.address.city\": \"NY\",\n * \"active\": true\n * }\n *\n * @template T - The type of the input object\n * @param obj - The nested object to flatten\n * @returns A flattened object with dotted keys and inferred types\n */\nexport const dot = <T extends Record<string, any>> (obj: T): DotFlatten<T> => {\n const result = {} as Record<string, unknown>\n\n /**\n * Internal recursive function to traverse and flatten the object.\n * \n * @param o - Current object to flatten\n * @param prefix - Key path accumulated so far\n */\n const recurse = (o: Record<string, any>, prefix = ''): void => {\n for (const [key, value] of Object.entries(o)) {\n const newKey = prefix ? `${prefix}.${key}` : key\n\n /**\n * Recurse if the value is a plain object\n */\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n recurse(value, newKey)\n } else {\n /**\n * Otherwise, assign directly\n */\n result[newKey] = value\n }\n }\n }\n\n recurse(obj)\n return result as DotFlatten<T>\n}\n\n/**\n * Extracts a subset of properties from an object.\n *\n * @template T - Type of the source object\n * @template K - Keys of T to extract\n * @param obj - The source object\n * @param keys - Array of keys to extract\n * @returns A new object with only the specified keys\n */\nexport const extractProperties = <T extends object, K extends keyof T> (\n obj: T,\n keys: readonly K[] = []\n): Pick<T, K> => {\n return Object.fromEntries(\n keys.map(key => [key, obj[key]])\n ) as Pick<T, K>\n}\n\n/**\n * Safely retrieves a value from an object by key or nested keys.\n *\n * @template T - Type of the source object\n * @param key - Single key or tuple [parentKey, childKey]\n * @param item - The source object\n * @returns The found value as a string or the key itself if not found\n */\nexport const getValue = <\n T extends Record<string, any> // Allow nested objects\n> (\n key: string | [keyof T, keyof T[string]],\n item: T\n): string => {\n if (Array.isArray(key)) {\n const [parent, child] = key\n\n if (child !== undefined) {\n // Access nested property: item[parent][child]\n return (\n String(item?.[parent]?.[child] ??\n item?.[parent] ??\n `${String(parent)}.${String(child)}`)\n )\n }\n\n // Only top-level key\n return String(item?.[parent] ?? parent)\n }\n\n // Single key access\n return String(item?.[key] ?? key)\n}\n\n/**\n * Maps over an object's entries and returns a new object \n * with transformed keys and/or values.\n *\n * @template T - Type of the input object\n * @template R - Type of the new values\n * @param obj - The object to transform\n * @param callback - Function that receives [key, value] and returns [newKey, newValue]\n * @returns A new object with transformed entries\n */\nexport const modObj = <T extends object, R> (\n obj: T,\n callback: (entry: [keyof T & string, T[keyof T]]) => [string, R]\n): Record<string, R> => {\n return Object.fromEntries(\n Object.entries(obj).map(([key, value]) =>\n callback([key as keyof T & string, value as T[keyof T]])\n )\n ) as Record<string, R>\n}\n\n\nexport function safeDot<T extends Record<string, any>> (data: T): T\nexport function safeDot<\n T extends Record<string, any>,\n K extends DotNestedKeys<T>\n> (data: T, key?: K): DotNestedValue<T, K>\nexport function safeDot<\n T extends Record<string, any>,\n K extends DotNestedKeys<T>\n> (data: T, key?: K): any {\n if (!key) return data\n return key.split('.').reduce((acc: any, k) => acc?.[k], data)\n}\n\n/**\n * Sets a nested property on an object using dot notation.\n * \n * @example\n * const obj = {}\n * setNested(obj, 'app.user.name', 'Legacy')\n * console.log(obj)\n * // Output: { app: { user: { name: 'Legacy' } } }\n * \n * @param obj - The target object to modify.\n * @param key - The dot-separated key (e.g., 'app.user.name').\n * @param value - The value to set at the specified path.\n */\nexport const setNested = (\n obj: Record<string, any>,\n key: string,\n value: any\n): void => {\n if (!key.includes('.')) {\n obj[key] = value\n return\n }\n\n const parts = key.split('.')\n let current = obj\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]\n\n /**\n * If we're at the last key, assign the value\n */\n if (i === parts.length - 1) {\n current[part] = value\n } else {\n /**\n * If the key doesn't exist or isn't an object, create it\n */\n if (typeof current[part] !== 'object' || current[part] === null) {\n current[part] = {}\n }\n current = current[part]\n }\n }\n}\n\n/**\n * Converts object keys to a slugified format (e.g., snake_case).\n *\n * @template T - Type of the input object\n * @param obj - The object whose keys will be slugified\n * @param only - Optional array of keys to slugify (others remain unchanged)\n * @param separator - Separator for slugified keys (default: \"_\")\n * @returns A new object with slugified keys\n */\nexport const slugifyKeys = <T extends object> (\n obj: T,\n only: string[] = [],\n separator: string = '_'\n): KeysToSnakeCase<T> => {\n const slugify = (key: string): string =>\n key\n .replace(/([a-z])([A-Z])/g, `$1${separator}$2`) // Handle camelCase\n .replace(/[\\s\\W]+/g, separator) // Replace spaces/symbols\n .replace(new RegExp(`${separator}{2,}`, 'g'), separator) // Remove duplicate separators\n .replace(new RegExp(`^${separator}|${separator}$`, 'g'), '') // Trim edges\n .toLowerCase()\n\n let entries = Object.entries(obj)\n\n // Filter if `only` is provided\n if (only.length) {\n entries = entries.filter(([key]) => only.includes(key))\n }\n\n return Object.fromEntries(\n entries.map(([key, value]) => [slugify(key), value])\n ) as KeysToSnakeCase<T>\n}\n","import { dot } from \"./Obj\"\n\n/**\n * Get the portion of the string after the first occurrence of the given value.\n * \n * @param value \n * @param search \n * @returns \n */\nexport const after = (value: string, search: string): string => {\n if (!search) return value\n const index = value.indexOf(search)\n return index !== -1 ? value.slice(index + search.length) : value\n}\n\n/**\n * Get the portion of the string after the last occurrence of the given value.\n * \n * @param value \n * @param search \n * @returns \n */\nexport const afterLast = (value: string, search: string): string => {\n if (!search) return value\n const lastIndex = value.lastIndexOf(search)\n return lastIndex !== -1 ? value.slice(lastIndex + search.length) : value\n}\n\n/**\n * Get the portion of the string before the first occurrence of the given value.\n * \n * @param value \n * @param search \n * @returns \n */\nexport const before = (value: string, search: string): string => {\n if (!search) return value\n const index = value.indexOf(search)\n return index !== -1 ? value.slice(0, index) : value\n}\n\n/**\n * Get the portion of the string before the last occurrence of the given value.\n * \n * @param value \n * @param search \n * @returns \n */\nexport const beforeLast = (value: string, search: string): string => {\n if (!search) return value\n const lastIndex = value.lastIndexOf(search)\n return lastIndex !== -1 ? value.slice(0, lastIndex) : value\n}\n\n/**\n * Capitalizes the first character of a string.\n *\n * @param str - The input string\n * @returns The string with the first character capitalized\n */\nexport function capitalize (str: string): string {\n if (!str) return '' // Handle empty or undefined strings safely\n return str[0].toUpperCase() + str.slice(1)\n}\n\n\n/**\n * Returns the pluralized form of a word based on the given number.\n *\n * @param word - The word to pluralize\n * @param count - The number determining pluralization\n * @returns Singular if count === 1, otherwise plural form\n */\nexport const pluralize = (word: string, count: number): string => {\n // If count is exactly 1 → singular\n if (count === 1) return word\n\n // Irregular plurals map\n const irregularPlurals: Record<string, string> = {\n foot: 'feet',\n child: 'children',\n mouse: 'mice',\n goose: 'geese',\n person: 'people',\n man: 'men',\n woman: 'women',\n }\n\n // Handle irregular cases first\n if (word in irregularPlurals) {\n return irregularPlurals[word]\n }\n\n // If word ends with consonant + \"y\" → replace \"y\" with \"ies\"\n if (\n word.endsWith('y') &&\n !['a', 'e', 'i', 'o', 'u'].includes(word[word.length - 2]?.toLowerCase() ?? '')\n ) {\n return word.slice(0, -1) + 'ies'\n }\n\n // If word ends in \"s\", \"ss\", \"sh\", \"ch\", \"x\", or \"z\" → add \"es\"\n if (/(s|ss|sh|ch|x|z)$/i.test(word)) {\n return word + 'es'\n }\n\n // Default: just add \"s\"\n return word + 's'\n}\n\n/**\n * Converts a plural English word into its singular form.\n *\n * @param word - The word to singularize\n * @returns The singular form of the word\n */\nexport const singularize = (word: string): string => {\n // Irregular plurals map (reverse of pluralize)\n const irregulars: Record<string, string> = {\n feet: 'foot',\n children: 'child',\n mice: 'mouse',\n geese: 'goose',\n people: 'person',\n men: 'man',\n women: 'woman',\n }\n\n // Handle irregular cases\n if (word in irregulars) return irregulars[word]\n\n // Words ending in \"ies\" → change to \"y\" (e.g., \"bodies\" → \"body\")\n if (/ies$/i.test(word) && word.length > 3) {\n return word.replace(/ies$/i, 'y')\n }\n\n // Words ending in \"es\" after certain consonants → remove \"es\"\n if (/(ches|shes|sses|xes|zes)$/i.test(word)) {\n return word.replace(/es$/i, '')\n }\n\n // Generic case: remove trailing \"s\"\n if (/s$/i.test(word) && word.length > 1) {\n return word.replace(/s$/i, '')\n }\n\n return word\n}\n\n/**\n * Converts a string into a slug format.\n * Handles camelCase, spaces, and non-alphanumeric characters.\n *\n * @param str - The input string to slugify\n * @param joiner - The character used to join words (default: \"_\")\n * @returns A slugified string\n */\nexport const slugify = (str: string, joiner = '_'): string => {\n return str\n // Handle camelCase by adding joiner between lowercase → uppercase\n .replace(/([a-z])([A-Z])/g, `$1${joiner}$2`)\n // Replace spaces and non-alphanumeric characters with joiner\n .replace(/[\\s\\W]+/g, joiner)\n // Remove duplicate joiners\n .replace(new RegExp(`${joiner}{2,}`, 'g'), joiner)\n // Trim joiners from start/end\n .replace(new RegExp(`^${joiner}|${joiner}$`, 'g'), '')\n .toLowerCase()\n}\n\n/**\n * Truncates a string to a specified length and appends an ellipsis if needed.\n *\n * @param str - The input string\n * @param len - Maximum length of the result (including ellipsis)\n * @param ellipsis - String to append if truncated (default: \"...\")\n * @returns The truncated string\n */\nexport const subString = (\n str: string,\n len: number,\n ellipsis: string = '...'\n): string => {\n if (!str) return ''\n if (len <= ellipsis.length) return ellipsis // Avoid negative slicing\n\n return str.length > len\n ? str.substring(0, len - ellipsis.length).trimEnd() + ellipsis\n : str\n}\n\n/**\n * Replaces placeholders in a string with corresponding values from a data object.\n * \n * Example:\n * substitute(\"Hello { user.name }!\", { user: { name: \"John\" } })\n * // \"Hello John!\"\n *\n * @param str - The string containing placeholders wrapped in { } braces.\n * @param data - Object containing values to substitute. Supports nested keys via dot notation.\n * @param def - Default value to use if a key is missing. (Optional)\n * @returns The substituted string or undefined if the input string or data is invalid.\n */\nexport const substitute = (\n str: string,\n data: Record<string, unknown> = {},\n def?: string\n): string | undefined => {\n if (!str || !data) return undefined\n\n // Matches { key } or { nested.key } placeholders\n const regex = /{\\s*([a-zA-Z0-9_.]+)\\s*}/g\n\n // Flatten the data so we can directly access dot notation keys\n const flattened = dot(data)\n\n // Replace each placeholder with its value or the default\n const out = str.replace(regex, (_, key: string) => {\n const value = flattened[key]\n return value !== undefined ? String(value) : def ?? ''\n })\n\n return out\n}\n\n/**\n * Truncates a string to a specified length, removing HTML tags and \n * appending a suffix if the string exceeds the length.\n *\n * @param str - The string to truncate\n * @param len - Maximum length (default: 20)\n * @param suffix - Suffix to append if truncated (default: \"...\")\n * @returns The truncated string\n */\nexport const truncate = (\n str: string,\n len: number = 20,\n suffix: string = '...'\n): string => {\n if (!str) return ''\n\n // Remove any HTML tags\n const clean = str.replace(/<[^>]+>/g, '')\n\n // Determine if we need to truncate\n const truncated =\n clean.length > len\n ? clean.substring(0, len - suffix.length) + suffix\n : clean\n\n // Normalize spaces and line breaks\n return truncated\n .replace(/\\n/g, ' ') // Replace all line breaks\n .replace(new RegExp(`\\\\s+${suffix.replace(/\\./g, '\\\\.')}$`), suffix) // Avoid extra space before suffix\n}\n\n"],"mappings":"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","names":["chunk","arr","size","Error","chunks","i","length","push","slice","range","startAt","Number","isFinite","Array","from","_","abbreviate","value","locale","Intl","NumberFormat","format","si","v","s","match","find","scale","formatted","minimumFractionDigits","maximumFractionDigits","humanize","num","slugify","h","replace","toLowerCase","ones","tens","numString","toString","Error","length","end","toBytes","bytes","decimals","bits","isNaN","base","dm","sizes","index","Math","floor","log","parseFloat","pow","toFixed","toHumanTime","seconds","worded","hours","minutes","secs","parts","push","join","hh","mm","ss","dot","obj","result","recurse","o","prefix","key","value","Object","entries","newKey","Array","isArray","extractProperties","keys","fromEntries","map","getValue","item","parent","child","undefined","String","modObj","callback","safeDot","data","split","reduce","acc","k","setNested","includes","parts","current","i","length","part","slugifyKeys","only","separator","slugify","replace","RegExp","toLowerCase","filter","after","value","search","index","indexOf","slice","length","afterLast","lastIndex","lastIndexOf","before","beforeLast","capitalize","str","toUpperCase","pluralize","word","count","irregularPlurals","foot","child","mouse","goose","person","man","woman","endsWith","includes","toLowerCase","test","singularize","irregulars","feet","children","mice","geese","people","men","women","replace","slugify","joiner","RegExp","subString","len","ellipsis","substring","trimEnd","substitute","data","def","undefined","regex","flattened","dot","out","_","key","String","truncate","suffix","clean","truncated"]}
package/dist/index.js CHANGED
@@ -3,7 +3,8 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
3
3
 
4
4
  // src/Helpers/Arr.ts
5
5
  var chunk = /* @__PURE__ */ __name((arr, size = 2) => {
6
- if (size <= 0) throw new Error("Chunk size must be greater than 0");
6
+ if (size <= 0)
7
+ throw new Error("Chunk size must be greater than 0");
7
8
  const chunks = [];
8
9
  for (let i = 0; i < arr.length; i += size) {
9
10
  chunks.push(arr.slice(i, i + size));
@@ -11,7 +12,8 @@ var chunk = /* @__PURE__ */ __name((arr, size = 2) => {
11
12
  return chunks;
12
13
  }, "chunk");
13
14
  var range = /* @__PURE__ */ __name((size, startAt = 0) => {
14
- if (size <= 0 || !Number.isFinite(size)) return [];
15
+ if (size <= 0 || !Number.isFinite(size))
16
+ return [];
15
17
  return Array.from({
16
18
  length: size
17
19
  }, (_, i) => startAt + i);
@@ -19,7 +21,8 @@ var range = /* @__PURE__ */ __name((size, startAt = 0) => {
19
21
 
20
22
  // src/Helpers/Number.ts
21
23
  var abbreviate = /* @__PURE__ */ __name((value, locale = "en-US") => {
22
- if (!value) return "0";
24
+ if (!value)
25
+ return "0";
23
26
  if (value < 1e3) {
24
27
  return new Intl.NumberFormat(locale).format(value);
25
28
  }
@@ -50,7 +53,8 @@ var abbreviate = /* @__PURE__ */ __name((value, locale = "en-US") => {
50
53
  }
51
54
  ];
52
55
  const match = si.find((scale) => value >= scale.v);
53
- if (!match) return new Intl.NumberFormat(locale).format(value);
56
+ if (!match)
57
+ return new Intl.NumberFormat(locale).format(value);
54
58
  const formatted = value / match.v;
55
59
  return new Intl.NumberFormat(locale, {
56
60
  minimumFractionDigits: 0,
@@ -100,8 +104,10 @@ var humanize = /* @__PURE__ */ __name((num, slugify2) => {
100
104
  "ninety"
101
105
  ];
102
106
  const numString = num.toString();
103
- if (num < 0) throw new Error("Negative numbers are not supported.");
104
- if (num === 0) return "zero";
107
+ if (num < 0)
108
+ throw new Error("Negative numbers are not supported.");
109
+ if (num === 0)
110
+ return "zero";
105
111
  if (num < 20) {
106
112
  return ones[num] ?? "";
107
113
  }
@@ -109,13 +115,17 @@ var humanize = /* @__PURE__ */ __name((num, slugify2) => {
109
115
  return tens[numString[0]] + " " + ones[numString[1]];
110
116
  }
111
117
  if (numString.length == 3) {
112
- if (numString[1] === "0" && numString[2] === "0") return ones[numString[0]] + " hundred";
113
- else return ones[numString[0]] + " hundred and " + humanize(+((numString[1] || "") + numString[2]), slugify2);
118
+ if (numString[1] === "0" && numString[2] === "0")
119
+ return ones[numString[0]] + " hundred";
120
+ else
121
+ return ones[numString[0]] + " hundred and " + humanize(+((numString[1] || "") + numString[2]), slugify2);
114
122
  }
115
123
  if (numString.length === 4) {
116
124
  const end = +((numString[1] || "") + numString[2] + numString[3]);
117
- if (end === 0) return ones[numString[0]] + " thousand";
118
- if (end < 100) return ones[numString[0]] + " thousand and " + humanize(end, slugify2);
125
+ if (end === 0)
126
+ return ones[numString[0]] + " thousand";
127
+ if (end < 100)
128
+ return ones[numString[0]] + " thousand and " + humanize(end, slugify2);
119
129
  return ones[numString[0]] + " thousand " + humanize(end, slugify2);
120
130
  }
121
131
  return num;
@@ -152,15 +162,19 @@ var toBytes = /* @__PURE__ */ __name((bytes, decimals = 2, bits = false) => {
152
162
  return `${value} ${sizes[index]}`;
153
163
  }, "toBytes");
154
164
  var toHumanTime = /* @__PURE__ */ __name((seconds = 0, worded = false) => {
155
- if (isNaN(seconds) || seconds < 0) seconds = 0;
165
+ if (isNaN(seconds) || seconds < 0)
166
+ seconds = 0;
156
167
  const hours = Math.floor(seconds / 3600);
157
168
  const minutes = Math.floor(seconds % 3600 / 60);
158
169
  const secs = Math.floor(seconds % 60);
159
170
  if (worded) {
160
171
  const parts = [];
161
- if (hours) parts.push(`${hours}hr`);
162
- if (minutes) parts.push(`${minutes}min`);
163
- if (secs || !hours && !minutes) parts.push(`${secs}sec`);
172
+ if (hours)
173
+ parts.push(`${hours}hr`);
174
+ if (minutes)
175
+ parts.push(`${minutes}min`);
176
+ if (secs || !hours && !minutes)
177
+ parts.push(`${secs}sec`);
164
178
  return parts.join(" ");
165
179
  }
166
180
  const hh = hours > 0 ? `${hours}:` : "";
@@ -208,7 +222,8 @@ var modObj = /* @__PURE__ */ __name((obj, callback) => {
208
222
  ])));
209
223
  }, "modObj");
210
224
  function safeDot(data, key) {
211
- if (!key) return data;
225
+ if (!key)
226
+ return data;
212
227
  return key.split(".").reduce((acc, k) => acc?.[k], data);
213
228
  }
214
229
  __name(safeDot, "safeDot");
@@ -245,32 +260,38 @@ var slugifyKeys = /* @__PURE__ */ __name((obj, only = [], separator = "_") => {
245
260
 
246
261
  // src/Helpers/Str.ts
247
262
  var after = /* @__PURE__ */ __name((value, search) => {
248
- if (!search) return value;
263
+ if (!search)
264
+ return value;
249
265
  const index = value.indexOf(search);
250
266
  return index !== -1 ? value.slice(index + search.length) : value;
251
267
  }, "after");
252
268
  var afterLast = /* @__PURE__ */ __name((value, search) => {
253
- if (!search) return value;
269
+ if (!search)
270
+ return value;
254
271
  const lastIndex = value.lastIndexOf(search);
255
272
  return lastIndex !== -1 ? value.slice(lastIndex + search.length) : value;
256
273
  }, "afterLast");
257
274
  var before = /* @__PURE__ */ __name((value, search) => {
258
- if (!search) return value;
275
+ if (!search)
276
+ return value;
259
277
  const index = value.indexOf(search);
260
278
  return index !== -1 ? value.slice(0, index) : value;
261
279
  }, "before");
262
280
  var beforeLast = /* @__PURE__ */ __name((value, search) => {
263
- if (!search) return value;
281
+ if (!search)
282
+ return value;
264
283
  const lastIndex = value.lastIndexOf(search);
265
284
  return lastIndex !== -1 ? value.slice(0, lastIndex) : value;
266
285
  }, "beforeLast");
267
286
  function capitalize(str) {
268
- if (!str) return "";
287
+ if (!str)
288
+ return "";
269
289
  return str[0].toUpperCase() + str.slice(1);
270
290
  }
271
291
  __name(capitalize, "capitalize");
272
292
  var pluralize = /* @__PURE__ */ __name((word, count) => {
273
- if (count === 1) return word;
293
+ if (count === 1)
294
+ return word;
274
295
  const irregularPlurals = {
275
296
  foot: "feet",
276
297
  child: "children",
@@ -307,7 +328,8 @@ var singularize = /* @__PURE__ */ __name((word) => {
307
328
  men: "man",
308
329
  women: "woman"
309
330
  };
310
- if (word in irregulars) return irregulars[word];
331
+ if (word in irregulars)
332
+ return irregulars[word];
311
333
  if (/ies$/i.test(word) && word.length > 3) {
312
334
  return word.replace(/ies$/i, "y");
313
335
  }
@@ -323,12 +345,15 @@ var slugify = /* @__PURE__ */ __name((str, joiner = "_") => {
323
345
  return str.replace(/([a-z])([A-Z])/g, `$1${joiner}$2`).replace(/[\s\W]+/g, joiner).replace(new RegExp(`${joiner}{2,}`, "g"), joiner).replace(new RegExp(`^${joiner}|${joiner}$`, "g"), "").toLowerCase();
324
346
  }, "slugify");
325
347
  var subString = /* @__PURE__ */ __name((str, len, ellipsis = "...") => {
326
- if (!str) return "";
327
- if (len <= ellipsis.length) return ellipsis;
348
+ if (!str)
349
+ return "";
350
+ if (len <= ellipsis.length)
351
+ return ellipsis;
328
352
  return str.length > len ? str.substring(0, len - ellipsis.length).trimEnd() + ellipsis : str;
329
353
  }, "subString");
330
354
  var substitute = /* @__PURE__ */ __name((str, data = {}, def) => {
331
- if (!str || !data) return void 0;
355
+ if (!str || !data)
356
+ return void 0;
332
357
  const regex = /{\s*([a-zA-Z0-9_.]+)\s*}/g;
333
358
  const flattened = dot(data);
334
359
  const out = str.replace(regex, (_, key) => {
@@ -338,7 +363,8 @@ var substitute = /* @__PURE__ */ __name((str, data = {}, def) => {
338
363
  return out;
339
364
  }, "substitute");
340
365
  var truncate = /* @__PURE__ */ __name((str, len = 20, suffix = "...") => {
341
- if (!str) return "";
366
+ if (!str)
367
+ return "";
342
368
  const clean = str.replace(/<[^>]+>/g, "");
343
369
  const truncated = clean.length > len ? clean.substring(0, len - suffix.length) + suffix : clean;
344
370
  return truncated.replace(/\n/g, " ").replace(new RegExp(`\\s+${suffix.replace(/\./g, "\\.")}$`), suffix);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/Helpers/Arr.ts","../src/Helpers/Number.ts","../src/Helpers/Obj.ts","../src/Helpers/Str.ts"],"sourcesContent":["/**\n * Splits an array into chunks of a specified size.\n *\n * @template T - Type of elements in the array\n * @param arr - The input array\n * @param size - Size of each chunk (default: 2)\n * @returns An array of chunks (arrays)\n */\nexport const chunk = <T> (arr: T[], size: number = 2): T[][] => {\n if (size <= 0) throw new Error(\"Chunk size must be greater than 0\")\n\n const chunks: T[][] = []\n\n for (let i = 0; i < arr.length; i += size) {\n chunks.push(arr.slice(i, i + size))\n }\n\n return chunks\n}\n\n\n/**\n * Generates an array of sequential numbers.\n *\n * @param size - Number of elements in the range\n * @param startAt - Starting number (default: 0)\n * @returns An array of numbers from startAt to startAt + size - 1\n */\nexport const range = (size: number, startAt: number = 0): number[] => {\n if (size <= 0 || !Number.isFinite(size)) return []\n\n return Array.from({ length: size }, (_, i) => startAt + i)\n}\n","/**\n * Abbreviates large numbers using SI symbols (K, M, B...) \n * and formats the output according to the given locale.\n *\n * @param value - The number to abbreviate\n * @param locale - Optional locale string (default: \"en-US\")\n * @returns A localized, abbreviated number string\n */\nexport const abbreviate = (value?: number, locale: string = 'en-US'): string => {\n if (!value) return '0'\n\n // Numbers less than 1000 don't need abbreviation\n if (value < 1000) {\n return new Intl.NumberFormat(locale).format(value)\n }\n\n const si = [\n { v: 1e18, s: 'E' },\n { v: 1e15, s: 'P' },\n { v: 1e12, s: 'T' },\n { v: 1e9, s: 'B' },\n { v: 1e6, s: 'M' },\n { v: 1e3, s: 'K' },\n ]\n\n const match = si.find(scale => value >= scale.v)\n if (!match) return new Intl.NumberFormat(locale).format(value)\n\n const formatted = value / match.v\n\n return (\n new Intl.NumberFormat(locale, {\n minimumFractionDigits: 0,\n maximumFractionDigits: 2,\n }).format(formatted) + match.s\n )\n}\n\n/**\n * Concverts a number into human readable string\n *\n * @param num The number to convert\n * @param slugify convert the ouput into a slug using this as a separator\n * @returns\n */\nexport const humanize = (num: number, slugify?: '-' | '_'): string => {\n if (!num) {\n return ''\n }\n\n if (slugify === '-' || slugify === '_') {\n const h = humanize(num)\n return typeof h === 'string' ? h.replace(' ', slugify).toLowerCase() : h\n }\n\n const ones = [\n '',\n 'one',\n 'two',\n 'three',\n 'four',\n 'five',\n 'six',\n 'seven',\n 'eight',\n 'nine',\n 'ten',\n 'eleven',\n 'twelve',\n 'thirteen',\n 'fourteen',\n 'fifteen',\n 'sixteen',\n 'seventeen',\n 'eighteen',\n 'nineteen',\n ]\n const tens = [\n '',\n '',\n 'twenty',\n 'thirty',\n 'forty',\n 'fifty',\n 'sixty',\n 'seventy',\n 'eighty',\n 'ninety',\n ]\n\n const numString: string = num.toString()\n\n if (num < 0) throw new Error('Negative numbers are not supported.')\n\n if (num === 0) return 'zero'\n\n //the case of 1 - 20\n if (num < 20) {\n return ones[num] ?? ''\n }\n\n if (numString.length === 2) {\n return tens[numString[0] as unknown as number] + ' ' + ones[numString[1] as unknown as number]\n }\n\n //100 and more\n if (numString.length == 3) {\n if (numString[1] === '0' && numString[2] === '0')\n return ones[numString[0] as unknown as number] + ' hundred'\n else\n return (\n ones[numString[0] as unknown as number] +\n ' hundred and ' +\n humanize(+((numString[1] || '') + numString[2]), slugify)\n )\n }\n\n if (numString.length === 4) {\n const end = +((numString[1] || '') + numString[2] + numString[3])\n if (end === 0) return ones[numString[0] as unknown as number] + ' thousand'\n if (end < 100)\n return ones[numString[0] as unknown as number] + ' thousand and ' + humanize(end, slugify)\n return ones[numString[0] as unknown as number] + ' thousand ' + humanize(end, slugify)\n }\n\n return num as unknown as string\n}\n\n/**\n * Converts a number of bytes into a human-readable string.\n *\n * @param bytes - The size in bytes to convert\n * @param decimals - Number of decimal places to display (default: 2)\n * @param bits - If true, uses 1000-based (SI) units (B, KB, MB...); \n * otherwise uses 1024-based binary units (Bytes, KiB...)\n * @returns A formatted string with the appropriate unit\n */\nexport const toBytes = (\n bytes?: number,\n decimals: number = 2,\n bits: boolean = false\n): string => {\n if (!bytes || isNaN(bytes)) {\n return bits ? '0 B' : '0 Bytes'\n }\n\n const base = bits ? 1000 : 1024\n const dm = decimals < 0 ? 0 : decimals\n const sizes = bits\n ? ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] // SI units\n : ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'] // Binary units\n\n const index = Math.floor(Math.log(bytes) / Math.log(base))\n\n const value = parseFloat((bytes / Math.pow(base, index)).toFixed(dm))\n return `${value} ${sizes[index]}`\n}\n\n/**\n * Formats a duration (in seconds) into a human-readable string.\n *\n * @param seconds - Duration in seconds\n * @param worded - If true, outputs worded format (e.g., \"1hr 2min 3sec\"),\n * otherwise HH:MM:SS (e.g., \"01:02:03\")\n * @returns A formatted time string\n */\nexport const toHumanTime = (\n seconds: number = 0,\n worded: boolean = false\n): string => {\n // Ensure seconds is a number and not negative\n if (isNaN(seconds) || seconds < 0) seconds = 0\n\n const hours = Math.floor(seconds / 3600)\n const minutes = Math.floor((seconds % 3600) / 60)\n const secs = Math.floor(seconds % 60)\n\n // Worded format → \"1hr 2min 3sec\"\n if (worded) {\n const parts = []\n if (hours) parts.push(`${hours}hr`)\n if (minutes) parts.push(`${minutes}min`)\n if (secs || (!hours && !minutes)) parts.push(`${secs}sec`)\n return parts.join(' ')\n }\n\n // HH:MM:SS format → zero-padded\n const hh = hours > 0 ? `${hours}:` : ''\n const mm = (hours > 0 && minutes < 10 ? `0${minutes}` : minutes) + ':'\n const ss = secs < 10 ? `0${secs}` : secs\n\n return `${hh}${mm}${ss}`\n}\n\n","import { DotFlatten, DotNestedKeys, DotNestedValue, KeysToSnakeCase } from \"../Contracts/ObjContract\"\n\n/**\n * Flattens a nested object into a single-level object\n * with dot-separated keys.\n *\n * Example:\n * doter({\n * user: { name: \"John\", address: { city: \"NY\" } },\n * active: true\n * })\n * \n * Output:\n * {\n * \"user.name\": \"John\",\n * \"user.address.city\": \"NY\",\n * \"active\": true\n * }\n *\n * @template T - The type of the input object\n * @param obj - The nested object to flatten\n * @returns A flattened object with dotted keys and inferred types\n */\nexport const dot = <T extends Record<string, any>> (obj: T): DotFlatten<T> => {\n const result = {} as Record<string, unknown>\n\n /**\n * Internal recursive function to traverse and flatten the object.\n * \n * @param o - Current object to flatten\n * @param prefix - Key path accumulated so far\n */\n const recurse = (o: Record<string, any>, prefix = ''): void => {\n for (const [key, value] of Object.entries(o)) {\n const newKey = prefix ? `${prefix}.${key}` : key\n\n /**\n * Recurse if the value is a plain object\n */\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n recurse(value, newKey)\n } else {\n /**\n * Otherwise, assign directly\n */\n result[newKey] = value\n }\n }\n }\n\n recurse(obj)\n return result as DotFlatten<T>\n}\n\n/**\n * Extracts a subset of properties from an object.\n *\n * @template T - Type of the source object\n * @template K - Keys of T to extract\n * @param obj - The source object\n * @param keys - Array of keys to extract\n * @returns A new object with only the specified keys\n */\nexport const extractProperties = <T extends object, K extends keyof T> (\n obj: T,\n keys: readonly K[] = []\n): Pick<T, K> => {\n return Object.fromEntries(\n keys.map(key => [key, obj[key]])\n ) as Pick<T, K>\n}\n\n/**\n * Safely retrieves a value from an object by key or nested keys.\n *\n * @template T - Type of the source object\n * @param key - Single key or tuple [parentKey, childKey]\n * @param item - The source object\n * @returns The found value as a string or the key itself if not found\n */\nexport const getValue = <\n T extends Record<string, any> // Allow nested objects\n> (\n key: string | [keyof T, keyof T[string]],\n item: T\n): string => {\n if (Array.isArray(key)) {\n const [parent, child] = key\n\n if (child !== undefined) {\n // Access nested property: item[parent][child]\n return (\n String(item?.[parent]?.[child] ??\n item?.[parent] ??\n `${String(parent)}.${String(child)}`)\n )\n }\n\n // Only top-level key\n return String(item?.[parent] ?? parent)\n }\n\n // Single key access\n return String(item?.[key] ?? key)\n}\n\n/**\n * Maps over an object's entries and returns a new object \n * with transformed keys and/or values.\n *\n * @template T - Type of the input object\n * @template R - Type of the new values\n * @param obj - The object to transform\n * @param callback - Function that receives [key, value] and returns [newKey, newValue]\n * @returns A new object with transformed entries\n */\nexport const modObj = <T extends object, R> (\n obj: T,\n callback: (entry: [keyof T & string, T[keyof T]]) => [string, R]\n): Record<string, R> => {\n return Object.fromEntries(\n Object.entries(obj).map(([key, value]) =>\n callback([key as keyof T & string, value as T[keyof T]])\n )\n ) as Record<string, R>\n}\n\n\nexport function safeDot<T extends Record<string, any>> (data: T): T\nexport function safeDot<\n T extends Record<string, any>,\n K extends DotNestedKeys<T>\n> (data: T, key?: K): DotNestedValue<T, K>\nexport function safeDot<\n T extends Record<string, any>,\n K extends DotNestedKeys<T>\n> (data: T, key?: K): any {\n if (!key) return data\n return key.split('.').reduce((acc: any, k) => acc?.[k], data)\n}\n\n/**\n * Sets a nested property on an object using dot notation.\n * \n * @example\n * const obj = {}\n * setNested(obj, 'app.user.name', 'Legacy')\n * console.log(obj)\n * // Output: { app: { user: { name: 'Legacy' } } }\n * \n * @param obj - The target object to modify.\n * @param key - The dot-separated key (e.g., 'app.user.name').\n * @param value - The value to set at the specified path.\n */\nexport const setNested = (\n obj: Record<string, any>,\n key: string,\n value: any\n): void => {\n if (!key.includes('.')) {\n obj[key] = value\n return\n }\n\n const parts = key.split('.')\n let current = obj\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]\n\n /**\n * If we're at the last key, assign the value\n */\n if (i === parts.length - 1) {\n current[part] = value\n } else {\n /**\n * If the key doesn't exist or isn't an object, create it\n */\n if (typeof current[part] !== 'object' || current[part] === null) {\n current[part] = {}\n }\n current = current[part]\n }\n }\n}\n\n/**\n * Converts object keys to a slugified format (e.g., snake_case).\n *\n * @template T - Type of the input object\n * @param obj - The object whose keys will be slugified\n * @param only - Optional array of keys to slugify (others remain unchanged)\n * @param separator - Separator for slugified keys (default: \"_\")\n * @returns A new object with slugified keys\n */\nexport const slugifyKeys = <T extends object> (\n obj: T,\n only: string[] = [],\n separator: string = '_'\n): KeysToSnakeCase<T> => {\n const slugify = (key: string): string =>\n key\n .replace(/([a-z])([A-Z])/g, `$1${separator}$2`) // Handle camelCase\n .replace(/[\\s\\W]+/g, separator) // Replace spaces/symbols\n .replace(new RegExp(`${separator}{2,}`, 'g'), separator) // Remove duplicate separators\n .replace(new RegExp(`^${separator}|${separator}$`, 'g'), '') // Trim edges\n .toLowerCase()\n\n let entries = Object.entries(obj)\n\n // Filter if `only` is provided\n if (only.length) {\n entries = entries.filter(([key]) => only.includes(key))\n }\n\n return Object.fromEntries(\n entries.map(([key, value]) => [slugify(key), value])\n ) as KeysToSnakeCase<T>\n}\n","import { dot } from \"./Obj\"\n\n/**\n * Get the portion of the string after the first occurrence of the given value.\n * \n * @param value \n * @param search \n * @returns \n */\nexport const after = (value: string, search: string): string => {\n if (!search) return value\n const index = value.indexOf(search)\n return index !== -1 ? value.slice(index + search.length) : value\n}\n\n/**\n * Get the portion of the string after the last occurrence of the given value.\n * \n * @param value \n * @param search \n * @returns \n */\nexport const afterLast = (value: string, search: string): string => {\n if (!search) return value\n const lastIndex = value.lastIndexOf(search)\n return lastIndex !== -1 ? value.slice(lastIndex + search.length) : value\n}\n\n/**\n * Get the portion of the string before the first occurrence of the given value.\n * \n * @param value \n * @param search \n * @returns \n */\nexport const before = (value: string, search: string): string => {\n if (!search) return value\n const index = value.indexOf(search)\n return index !== -1 ? value.slice(0, index) : value\n}\n\n/**\n * Get the portion of the string before the last occurrence of the given value.\n * \n * @param value \n * @param search \n * @returns \n */\nexport const beforeLast = (value: string, search: string): string => {\n if (!search) return value\n const lastIndex = value.lastIndexOf(search)\n return lastIndex !== -1 ? value.slice(0, lastIndex) : value\n}\n\n/**\n * Capitalizes the first character of a string.\n *\n * @param str - The input string\n * @returns The string with the first character capitalized\n */\nexport function capitalize (str: string): string {\n if (!str) return '' // Handle empty or undefined strings safely\n return str[0].toUpperCase() + str.slice(1)\n}\n\n\n/**\n * Returns the pluralized form of a word based on the given number.\n *\n * @param word - The word to pluralize\n * @param count - The number determining pluralization\n * @returns Singular if count === 1, otherwise plural form\n */\nexport const pluralize = (word: string, count: number): string => {\n // If count is exactly 1 → singular\n if (count === 1) return word\n\n // Irregular plurals map\n const irregularPlurals: Record<string, string> = {\n foot: 'feet',\n child: 'children',\n mouse: 'mice',\n goose: 'geese',\n person: 'people',\n man: 'men',\n woman: 'women',\n }\n\n // Handle irregular cases first\n if (word in irregularPlurals) {\n return irregularPlurals[word]\n }\n\n // If word ends with consonant + \"y\" → replace \"y\" with \"ies\"\n if (\n word.endsWith('y') &&\n !['a', 'e', 'i', 'o', 'u'].includes(word[word.length - 2]?.toLowerCase() ?? '')\n ) {\n return word.slice(0, -1) + 'ies'\n }\n\n // If word ends in \"s\", \"ss\", \"sh\", \"ch\", \"x\", or \"z\" → add \"es\"\n if (/(s|ss|sh|ch|x|z)$/i.test(word)) {\n return word + 'es'\n }\n\n // Default: just add \"s\"\n return word + 's'\n}\n\n/**\n * Converts a plural English word into its singular form.\n *\n * @param word - The word to singularize\n * @returns The singular form of the word\n */\nexport const singularize = (word: string): string => {\n // Irregular plurals map (reverse of pluralize)\n const irregulars: Record<string, string> = {\n feet: 'foot',\n children: 'child',\n mice: 'mouse',\n geese: 'goose',\n people: 'person',\n men: 'man',\n women: 'woman',\n }\n\n // Handle irregular cases\n if (word in irregulars) return irregulars[word]\n\n // Words ending in \"ies\" → change to \"y\" (e.g., \"bodies\" → \"body\")\n if (/ies$/i.test(word) && word.length > 3) {\n return word.replace(/ies$/i, 'y')\n }\n\n // Words ending in \"es\" after certain consonants → remove \"es\"\n if (/(ches|shes|sses|xes|zes)$/i.test(word)) {\n return word.replace(/es$/i, '')\n }\n\n // Generic case: remove trailing \"s\"\n if (/s$/i.test(word) && word.length > 1) {\n return word.replace(/s$/i, '')\n }\n\n return word\n}\n\n/**\n * Converts a string into a slug format.\n * Handles camelCase, spaces, and non-alphanumeric characters.\n *\n * @param str - The input string to slugify\n * @param joiner - The character used to join words (default: \"_\")\n * @returns A slugified string\n */\nexport const slugify = (str: string, joiner = '_'): string => {\n return str\n // Handle camelCase by adding joiner between lowercase → uppercase\n .replace(/([a-z])([A-Z])/g, `$1${joiner}$2`)\n // Replace spaces and non-alphanumeric characters with joiner\n .replace(/[\\s\\W]+/g, joiner)\n // Remove duplicate joiners\n .replace(new RegExp(`${joiner}{2,}`, 'g'), joiner)\n // Trim joiners from start/end\n .replace(new RegExp(`^${joiner}|${joiner}$`, 'g'), '')\n .toLowerCase()\n}\n\n/**\n * Truncates a string to a specified length and appends an ellipsis if needed.\n *\n * @param str - The input string\n * @param len - Maximum length of the result (including ellipsis)\n * @param ellipsis - String to append if truncated (default: \"...\")\n * @returns The truncated string\n */\nexport const subString = (\n str: string,\n len: number,\n ellipsis: string = '...'\n): string => {\n if (!str) return ''\n if (len <= ellipsis.length) return ellipsis // Avoid negative slicing\n\n return str.length > len\n ? str.substring(0, len - ellipsis.length).trimEnd() + ellipsis\n : str\n}\n\n/**\n * Replaces placeholders in a string with corresponding values from a data object.\n * \n * Example:\n * substitute(\"Hello { user.name }!\", { user: { name: \"John\" } })\n * // \"Hello John!\"\n *\n * @param str - The string containing placeholders wrapped in { } braces.\n * @param data - Object containing values to substitute. Supports nested keys via dot notation.\n * @param def - Default value to use if a key is missing. (Optional)\n * @returns The substituted string or undefined if the input string or data is invalid.\n */\nexport const substitute = (\n str: string,\n data: Record<string, unknown> = {},\n def?: string\n): string | undefined => {\n if (!str || !data) return undefined\n\n // Matches { key } or { nested.key } placeholders\n const regex = /{\\s*([a-zA-Z0-9_.]+)\\s*}/g\n\n // Flatten the data so we can directly access dot notation keys\n const flattened = dot(data)\n\n // Replace each placeholder with its value or the default\n const out = str.replace(regex, (_, key: string) => {\n const value = flattened[key]\n return value !== undefined ? String(value) : def ?? ''\n })\n\n return out\n}\n\n/**\n * Truncates a string to a specified length, removing HTML tags and \n * appending a suffix if the string exceeds the length.\n *\n * @param str - The string to truncate\n * @param len - Maximum length (default: 20)\n * @param suffix - Suffix to append if truncated (default: \"...\")\n * @returns The truncated string\n */\nexport const truncate = (\n str: string,\n len: number = 20,\n suffix: string = '...'\n): string => {\n if (!str) return ''\n\n // Remove any HTML tags\n const clean = str.replace(/<[^>]+>/g, '')\n\n // Determine if we need to truncate\n const truncated =\n clean.length > len\n ? clean.substring(0, len - suffix.length) + suffix\n : clean\n\n // Normalize spaces and line breaks\n return truncated\n .replace(/\\n/g, ' ') // Replace all line breaks\n .replace(new RegExp(`\\\\s+${suffix.replace(/\\./g, '\\\\.')}$`), suffix) // Avoid extra space before suffix\n}\n\n"],"mappings":"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","names":["chunk","arr","size","Error","chunks","i","length","push","slice","range","startAt","Number","isFinite","Array","from","_","abbreviate","value","locale","Intl","NumberFormat","format","si","v","s","match","find","scale","formatted","minimumFractionDigits","maximumFractionDigits","humanize","num","slugify","h","replace","toLowerCase","ones","tens","numString","toString","Error","length","end","toBytes","bytes","decimals","bits","isNaN","base","dm","sizes","index","Math","floor","log","parseFloat","pow","toFixed","toHumanTime","seconds","worded","hours","minutes","secs","parts","push","join","hh","mm","ss","dot","obj","result","recurse","o","prefix","key","value","Object","entries","newKey","Array","isArray","extractProperties","keys","fromEntries","map","getValue","item","parent","child","undefined","String","modObj","callback","safeDot","data","split","reduce","acc","k","setNested","includes","parts","current","i","length","part","slugifyKeys","only","separator","slugify","replace","RegExp","toLowerCase","filter","after","value","search","index","indexOf","slice","length","afterLast","lastIndex","lastIndexOf","before","beforeLast","capitalize","str","toUpperCase","pluralize","word","count","irregularPlurals","foot","child","mouse","goose","person","man","woman","endsWith","includes","toLowerCase","test","singularize","irregulars","feet","children","mice","geese","people","men","women","replace","slugify","joiner","RegExp","subString","len","ellipsis","substring","trimEnd","substitute","data","def","undefined","regex","flattened","dot","out","_","key","String","truncate","suffix","clean","truncated"]}
1
+ {"version":3,"sources":["../src/Helpers/Arr.ts","../src/Helpers/Number.ts","../src/Helpers/Obj.ts","../src/Helpers/Str.ts"],"sourcesContent":["/**\n * Splits an array into chunks of a specified size.\n *\n * @template T - Type of elements in the array\n * @param arr - The input array\n * @param size - Size of each chunk (default: 2)\n * @returns An array of chunks (arrays)\n */\nexport const chunk = <T> (arr: T[], size: number = 2): T[][] => {\n if (size <= 0) throw new Error(\"Chunk size must be greater than 0\")\n\n const chunks: T[][] = []\n\n for (let i = 0; i < arr.length; i += size) {\n chunks.push(arr.slice(i, i + size))\n }\n\n return chunks\n}\n\n\n/**\n * Generates an array of sequential numbers.\n *\n * @param size - Number of elements in the range\n * @param startAt - Starting number (default: 0)\n * @returns An array of numbers from startAt to startAt + size - 1\n */\nexport const range = (size: number, startAt: number = 0): number[] => {\n if (size <= 0 || !Number.isFinite(size)) return []\n\n return Array.from({ length: size }, (_, i) => startAt + i)\n}\n","/**\n * Abbreviates large numbers using SI symbols (K, M, B...) \n * and formats the output according to the given locale.\n *\n * @param value - The number to abbreviate\n * @param locale - Optional locale string (default: \"en-US\")\n * @returns A localized, abbreviated number string\n */\nexport const abbreviate = (value?: number, locale: string = 'en-US'): string => {\n if (!value) return '0'\n\n // Numbers less than 1000 don't need abbreviation\n if (value < 1000) {\n return new Intl.NumberFormat(locale).format(value)\n }\n\n const si = [\n { v: 1e18, s: 'E' },\n { v: 1e15, s: 'P' },\n { v: 1e12, s: 'T' },\n { v: 1e9, s: 'B' },\n { v: 1e6, s: 'M' },\n { v: 1e3, s: 'K' },\n ]\n\n const match = si.find(scale => value >= scale.v)\n if (!match) return new Intl.NumberFormat(locale).format(value)\n\n const formatted = value / match.v\n\n return (\n new Intl.NumberFormat(locale, {\n minimumFractionDigits: 0,\n maximumFractionDigits: 2,\n }).format(formatted) + match.s\n )\n}\n\n/**\n * Concverts a number into human readable string\n *\n * @param num The number to convert\n * @param slugify convert the ouput into a slug using this as a separator\n * @returns\n */\nexport const humanize = (num: number, slugify?: '-' | '_'): string => {\n if (!num) {\n return ''\n }\n\n if (slugify === '-' || slugify === '_') {\n const h = humanize(num)\n return typeof h === 'string' ? h.replace(' ', slugify).toLowerCase() : h\n }\n\n const ones = [\n '',\n 'one',\n 'two',\n 'three',\n 'four',\n 'five',\n 'six',\n 'seven',\n 'eight',\n 'nine',\n 'ten',\n 'eleven',\n 'twelve',\n 'thirteen',\n 'fourteen',\n 'fifteen',\n 'sixteen',\n 'seventeen',\n 'eighteen',\n 'nineteen',\n ]\n const tens = [\n '',\n '',\n 'twenty',\n 'thirty',\n 'forty',\n 'fifty',\n 'sixty',\n 'seventy',\n 'eighty',\n 'ninety',\n ]\n\n const numString: string = num.toString()\n\n if (num < 0) throw new Error('Negative numbers are not supported.')\n\n if (num === 0) return 'zero'\n\n //the case of 1 - 20\n if (num < 20) {\n return ones[num] ?? ''\n }\n\n if (numString.length === 2) {\n return tens[numString[0] as unknown as number] + ' ' + ones[numString[1] as unknown as number]\n }\n\n //100 and more\n if (numString.length == 3) {\n if (numString[1] === '0' && numString[2] === '0')\n return ones[numString[0] as unknown as number] + ' hundred'\n else\n return (\n ones[numString[0] as unknown as number] +\n ' hundred and ' +\n humanize(+((numString[1] || '') + numString[2]), slugify)\n )\n }\n\n if (numString.length === 4) {\n const end = +((numString[1] || '') + numString[2] + numString[3])\n if (end === 0) return ones[numString[0] as unknown as number] + ' thousand'\n if (end < 100)\n return ones[numString[0] as unknown as number] + ' thousand and ' + humanize(end, slugify)\n return ones[numString[0] as unknown as number] + ' thousand ' + humanize(end, slugify)\n }\n\n return num as unknown as string\n}\n\n/**\n * Converts a number of bytes into a human-readable string.\n *\n * @param bytes - The size in bytes to convert\n * @param decimals - Number of decimal places to display (default: 2)\n * @param bits - If true, uses 1000-based (SI) units (B, KB, MB...); \n * otherwise uses 1024-based binary units (Bytes, KiB...)\n * @returns A formatted string with the appropriate unit\n */\nexport const toBytes = (\n bytes?: number,\n decimals: number = 2,\n bits: boolean = false\n): string => {\n if (!bytes || isNaN(bytes)) {\n return bits ? '0 B' : '0 Bytes'\n }\n\n const base = bits ? 1000 : 1024\n const dm = decimals < 0 ? 0 : decimals\n const sizes = bits\n ? ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] // SI units\n : ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'] // Binary units\n\n const index = Math.floor(Math.log(bytes) / Math.log(base))\n\n const value = parseFloat((bytes / Math.pow(base, index)).toFixed(dm))\n return `${value} ${sizes[index]}`\n}\n\n/**\n * Formats a duration (in seconds) into a human-readable string.\n *\n * @param seconds - Duration in seconds\n * @param worded - If true, outputs worded format (e.g., \"1hr 2min 3sec\"),\n * otherwise HH:MM:SS (e.g., \"01:02:03\")\n * @returns A formatted time string\n */\nexport const toHumanTime = (\n seconds: number = 0,\n worded: boolean = false\n): string => {\n // Ensure seconds is a number and not negative\n if (isNaN(seconds) || seconds < 0) seconds = 0\n\n const hours = Math.floor(seconds / 3600)\n const minutes = Math.floor((seconds % 3600) / 60)\n const secs = Math.floor(seconds % 60)\n\n // Worded format → \"1hr 2min 3sec\"\n if (worded) {\n const parts = []\n if (hours) parts.push(`${hours}hr`)\n if (minutes) parts.push(`${minutes}min`)\n if (secs || (!hours && !minutes)) parts.push(`${secs}sec`)\n return parts.join(' ')\n }\n\n // HH:MM:SS format → zero-padded\n const hh = hours > 0 ? `${hours}:` : ''\n const mm = (hours > 0 && minutes < 10 ? `0${minutes}` : minutes) + ':'\n const ss = secs < 10 ? `0${secs}` : secs\n\n return `${hh}${mm}${ss}`\n}\n\n","import { DotFlatten, DotNestedKeys, DotNestedValue, KeysToSnakeCase } from \"../Contracts/ObjContract\"\n\n/**\n * Flattens a nested object into a single-level object\n * with dot-separated keys.\n *\n * Example:\n * doter({\n * user: { name: \"John\", address: { city: \"NY\" } },\n * active: true\n * })\n * \n * Output:\n * {\n * \"user.name\": \"John\",\n * \"user.address.city\": \"NY\",\n * \"active\": true\n * }\n *\n * @template T - The type of the input object\n * @param obj - The nested object to flatten\n * @returns A flattened object with dotted keys and inferred types\n */\nexport const dot = <T extends Record<string, any>> (obj: T): DotFlatten<T> => {\n const result = {} as Record<string, unknown>\n\n /**\n * Internal recursive function to traverse and flatten the object.\n * \n * @param o - Current object to flatten\n * @param prefix - Key path accumulated so far\n */\n const recurse = (o: Record<string, any>, prefix = ''): void => {\n for (const [key, value] of Object.entries(o)) {\n const newKey = prefix ? `${prefix}.${key}` : key\n\n /**\n * Recurse if the value is a plain object\n */\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n recurse(value, newKey)\n } else {\n /**\n * Otherwise, assign directly\n */\n result[newKey] = value\n }\n }\n }\n\n recurse(obj)\n return result as DotFlatten<T>\n}\n\n/**\n * Extracts a subset of properties from an object.\n *\n * @template T - Type of the source object\n * @template K - Keys of T to extract\n * @param obj - The source object\n * @param keys - Array of keys to extract\n * @returns A new object with only the specified keys\n */\nexport const extractProperties = <T extends object, K extends keyof T> (\n obj: T,\n keys: readonly K[] = []\n): Pick<T, K> => {\n return Object.fromEntries(\n keys.map(key => [key, obj[key]])\n ) as Pick<T, K>\n}\n\n/**\n * Safely retrieves a value from an object by key or nested keys.\n *\n * @template T - Type of the source object\n * @param key - Single key or tuple [parentKey, childKey]\n * @param item - The source object\n * @returns The found value as a string or the key itself if not found\n */\nexport const getValue = <\n T extends Record<string, any> // Allow nested objects\n> (\n key: string | [keyof T, keyof T[string]],\n item: T\n): string => {\n if (Array.isArray(key)) {\n const [parent, child] = key\n\n if (child !== undefined) {\n // Access nested property: item[parent][child]\n return (\n String(item?.[parent]?.[child] ??\n item?.[parent] ??\n `${String(parent)}.${String(child)}`)\n )\n }\n\n // Only top-level key\n return String(item?.[parent] ?? parent)\n }\n\n // Single key access\n return String(item?.[key] ?? key)\n}\n\n/**\n * Maps over an object's entries and returns a new object \n * with transformed keys and/or values.\n *\n * @template T - Type of the input object\n * @template R - Type of the new values\n * @param obj - The object to transform\n * @param callback - Function that receives [key, value] and returns [newKey, newValue]\n * @returns A new object with transformed entries\n */\nexport const modObj = <T extends object, R> (\n obj: T,\n callback: (entry: [keyof T & string, T[keyof T]]) => [string, R]\n): Record<string, R> => {\n return Object.fromEntries(\n Object.entries(obj).map(([key, value]) =>\n callback([key as keyof T & string, value as T[keyof T]])\n )\n ) as Record<string, R>\n}\n\n\nexport function safeDot<T extends Record<string, any>> (data: T): T\nexport function safeDot<\n T extends Record<string, any>,\n K extends DotNestedKeys<T>\n> (data: T, key?: K): DotNestedValue<T, K>\nexport function safeDot<\n T extends Record<string, any>,\n K extends DotNestedKeys<T>\n> (data: T, key?: K): any {\n if (!key) return data\n return key.split('.').reduce((acc: any, k) => acc?.[k], data)\n}\n\n/**\n * Sets a nested property on an object using dot notation.\n * \n * @example\n * const obj = {}\n * setNested(obj, 'app.user.name', 'Legacy')\n * console.log(obj)\n * // Output: { app: { user: { name: 'Legacy' } } }\n * \n * @param obj - The target object to modify.\n * @param key - The dot-separated key (e.g., 'app.user.name').\n * @param value - The value to set at the specified path.\n */\nexport const setNested = (\n obj: Record<string, any>,\n key: string,\n value: any\n): void => {\n if (!key.includes('.')) {\n obj[key] = value\n return\n }\n\n const parts = key.split('.')\n let current = obj\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]\n\n /**\n * If we're at the last key, assign the value\n */\n if (i === parts.length - 1) {\n current[part] = value\n } else {\n /**\n * If the key doesn't exist or isn't an object, create it\n */\n if (typeof current[part] !== 'object' || current[part] === null) {\n current[part] = {}\n }\n current = current[part]\n }\n }\n}\n\n/**\n * Converts object keys to a slugified format (e.g., snake_case).\n *\n * @template T - Type of the input object\n * @param obj - The object whose keys will be slugified\n * @param only - Optional array of keys to slugify (others remain unchanged)\n * @param separator - Separator for slugified keys (default: \"_\")\n * @returns A new object with slugified keys\n */\nexport const slugifyKeys = <T extends object> (\n obj: T,\n only: string[] = [],\n separator: string = '_'\n): KeysToSnakeCase<T> => {\n const slugify = (key: string): string =>\n key\n .replace(/([a-z])([A-Z])/g, `$1${separator}$2`) // Handle camelCase\n .replace(/[\\s\\W]+/g, separator) // Replace spaces/symbols\n .replace(new RegExp(`${separator}{2,}`, 'g'), separator) // Remove duplicate separators\n .replace(new RegExp(`^${separator}|${separator}$`, 'g'), '') // Trim edges\n .toLowerCase()\n\n let entries = Object.entries(obj)\n\n // Filter if `only` is provided\n if (only.length) {\n entries = entries.filter(([key]) => only.includes(key))\n }\n\n return Object.fromEntries(\n entries.map(([key, value]) => [slugify(key), value])\n ) as KeysToSnakeCase<T>\n}\n","import { dot } from \"./Obj\"\n\n/**\n * Get the portion of the string after the first occurrence of the given value.\n * \n * @param value \n * @param search \n * @returns \n */\nexport const after = (value: string, search: string): string => {\n if (!search) return value\n const index = value.indexOf(search)\n return index !== -1 ? value.slice(index + search.length) : value\n}\n\n/**\n * Get the portion of the string after the last occurrence of the given value.\n * \n * @param value \n * @param search \n * @returns \n */\nexport const afterLast = (value: string, search: string): string => {\n if (!search) return value\n const lastIndex = value.lastIndexOf(search)\n return lastIndex !== -1 ? value.slice(lastIndex + search.length) : value\n}\n\n/**\n * Get the portion of the string before the first occurrence of the given value.\n * \n * @param value \n * @param search \n * @returns \n */\nexport const before = (value: string, search: string): string => {\n if (!search) return value\n const index = value.indexOf(search)\n return index !== -1 ? value.slice(0, index) : value\n}\n\n/**\n * Get the portion of the string before the last occurrence of the given value.\n * \n * @param value \n * @param search \n * @returns \n */\nexport const beforeLast = (value: string, search: string): string => {\n if (!search) return value\n const lastIndex = value.lastIndexOf(search)\n return lastIndex !== -1 ? value.slice(0, lastIndex) : value\n}\n\n/**\n * Capitalizes the first character of a string.\n *\n * @param str - The input string\n * @returns The string with the first character capitalized\n */\nexport function capitalize (str: string): string {\n if (!str) return '' // Handle empty or undefined strings safely\n return str[0].toUpperCase() + str.slice(1)\n}\n\n\n/**\n * Returns the pluralized form of a word based on the given number.\n *\n * @param word - The word to pluralize\n * @param count - The number determining pluralization\n * @returns Singular if count === 1, otherwise plural form\n */\nexport const pluralize = (word: string, count: number): string => {\n // If count is exactly 1 → singular\n if (count === 1) return word\n\n // Irregular plurals map\n const irregularPlurals: Record<string, string> = {\n foot: 'feet',\n child: 'children',\n mouse: 'mice',\n goose: 'geese',\n person: 'people',\n man: 'men',\n woman: 'women',\n }\n\n // Handle irregular cases first\n if (word in irregularPlurals) {\n return irregularPlurals[word]\n }\n\n // If word ends with consonant + \"y\" → replace \"y\" with \"ies\"\n if (\n word.endsWith('y') &&\n !['a', 'e', 'i', 'o', 'u'].includes(word[word.length - 2]?.toLowerCase() ?? '')\n ) {\n return word.slice(0, -1) + 'ies'\n }\n\n // If word ends in \"s\", \"ss\", \"sh\", \"ch\", \"x\", or \"z\" → add \"es\"\n if (/(s|ss|sh|ch|x|z)$/i.test(word)) {\n return word + 'es'\n }\n\n // Default: just add \"s\"\n return word + 's'\n}\n\n/**\n * Converts a plural English word into its singular form.\n *\n * @param word - The word to singularize\n * @returns The singular form of the word\n */\nexport const singularize = (word: string): string => {\n // Irregular plurals map (reverse of pluralize)\n const irregulars: Record<string, string> = {\n feet: 'foot',\n children: 'child',\n mice: 'mouse',\n geese: 'goose',\n people: 'person',\n men: 'man',\n women: 'woman',\n }\n\n // Handle irregular cases\n if (word in irregulars) return irregulars[word]\n\n // Words ending in \"ies\" → change to \"y\" (e.g., \"bodies\" → \"body\")\n if (/ies$/i.test(word) && word.length > 3) {\n return word.replace(/ies$/i, 'y')\n }\n\n // Words ending in \"es\" after certain consonants → remove \"es\"\n if (/(ches|shes|sses|xes|zes)$/i.test(word)) {\n return word.replace(/es$/i, '')\n }\n\n // Generic case: remove trailing \"s\"\n if (/s$/i.test(word) && word.length > 1) {\n return word.replace(/s$/i, '')\n }\n\n return word\n}\n\n/**\n * Converts a string into a slug format.\n * Handles camelCase, spaces, and non-alphanumeric characters.\n *\n * @param str - The input string to slugify\n * @param joiner - The character used to join words (default: \"_\")\n * @returns A slugified string\n */\nexport const slugify = (str: string, joiner = '_'): string => {\n return str\n // Handle camelCase by adding joiner between lowercase → uppercase\n .replace(/([a-z])([A-Z])/g, `$1${joiner}$2`)\n // Replace spaces and non-alphanumeric characters with joiner\n .replace(/[\\s\\W]+/g, joiner)\n // Remove duplicate joiners\n .replace(new RegExp(`${joiner}{2,}`, 'g'), joiner)\n // Trim joiners from start/end\n .replace(new RegExp(`^${joiner}|${joiner}$`, 'g'), '')\n .toLowerCase()\n}\n\n/**\n * Truncates a string to a specified length and appends an ellipsis if needed.\n *\n * @param str - The input string\n * @param len - Maximum length of the result (including ellipsis)\n * @param ellipsis - String to append if truncated (default: \"...\")\n * @returns The truncated string\n */\nexport const subString = (\n str: string,\n len: number,\n ellipsis: string = '...'\n): string => {\n if (!str) return ''\n if (len <= ellipsis.length) return ellipsis // Avoid negative slicing\n\n return str.length > len\n ? str.substring(0, len - ellipsis.length).trimEnd() + ellipsis\n : str\n}\n\n/**\n * Replaces placeholders in a string with corresponding values from a data object.\n * \n * Example:\n * substitute(\"Hello { user.name }!\", { user: { name: \"John\" } })\n * // \"Hello John!\"\n *\n * @param str - The string containing placeholders wrapped in { } braces.\n * @param data - Object containing values to substitute. Supports nested keys via dot notation.\n * @param def - Default value to use if a key is missing. (Optional)\n * @returns The substituted string or undefined if the input string or data is invalid.\n */\nexport const substitute = (\n str: string,\n data: Record<string, unknown> = {},\n def?: string\n): string | undefined => {\n if (!str || !data) return undefined\n\n // Matches { key } or { nested.key } placeholders\n const regex = /{\\s*([a-zA-Z0-9_.]+)\\s*}/g\n\n // Flatten the data so we can directly access dot notation keys\n const flattened = dot(data)\n\n // Replace each placeholder with its value or the default\n const out = str.replace(regex, (_, key: string) => {\n const value = flattened[key]\n return value !== undefined ? String(value) : def ?? ''\n })\n\n return out\n}\n\n/**\n * Truncates a string to a specified length, removing HTML tags and \n * appending a suffix if the string exceeds the length.\n *\n * @param str - The string to truncate\n * @param len - Maximum length (default: 20)\n * @param suffix - Suffix to append if truncated (default: \"...\")\n * @returns The truncated string\n */\nexport const truncate = (\n str: string,\n len: number = 20,\n suffix: string = '...'\n): string => {\n if (!str) return ''\n\n // Remove any HTML tags\n const clean = str.replace(/<[^>]+>/g, '')\n\n // Determine if we need to truncate\n const truncated =\n clean.length > len\n ? clean.substring(0, len - suffix.length) + suffix\n : clean\n\n // Normalize spaces and line breaks\n return truncated\n .replace(/\\n/g, ' ') // Replace all line breaks\n .replace(new RegExp(`\\\\s+${suffix.replace(/\\./g, '\\\\.')}$`), suffix) // Avoid extra space before suffix\n}\n\n"],"mappings":"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","names":["chunk","arr","size","Error","chunks","i","length","push","slice","range","startAt","Number","isFinite","Array","from","_","abbreviate","value","locale","Intl","NumberFormat","format","si","v","s","match","find","scale","formatted","minimumFractionDigits","maximumFractionDigits","humanize","num","slugify","h","replace","toLowerCase","ones","tens","numString","toString","Error","length","end","toBytes","bytes","decimals","bits","isNaN","base","dm","sizes","index","Math","floor","log","parseFloat","pow","toFixed","toHumanTime","seconds","worded","hours","minutes","secs","parts","push","join","hh","mm","ss","dot","obj","result","recurse","o","prefix","key","value","Object","entries","newKey","Array","isArray","extractProperties","keys","fromEntries","map","getValue","item","parent","child","undefined","String","modObj","callback","safeDot","data","split","reduce","acc","k","setNested","includes","parts","current","i","length","part","slugifyKeys","only","separator","slugify","replace","RegExp","toLowerCase","filter","after","value","search","index","indexOf","slice","length","afterLast","lastIndex","lastIndexOf","before","beforeLast","capitalize","str","toUpperCase","pluralize","word","count","irregularPlurals","foot","child","mouse","goose","person","man","woman","endsWith","includes","toLowerCase","test","singularize","irregulars","feet","children","mice","geese","people","men","women","replace","slugify","joiner","RegExp","subString","len","ellipsis","substring","trimEnd","substitute","data","def","undefined","regex","flattened","dot","out","_","key","String","truncate","suffix","clean","truncated"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@h3ravel/support",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Shared helpers, facades and utilities for H3ravel.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/tsconfig.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "extends": "../tsconfig/tsconfig.json",
2
+ "extends": "../shared/tsconfig.json",
3
3
  "compilerOptions": {
4
4
  "outDir": "dist"
5
5
  },