@getdashfy/utils 0.1.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/dist/index.js ADDED
@@ -0,0 +1,445 @@
1
+ import { format as format$1, formatDistanceToNow, intervalToDuration, formatDuration } from 'date-fns';
2
+ import * as dateFns from 'date-fns';
3
+ export { dateFns };
4
+ import prettyBytes from 'pretty-bytes';
5
+
6
+ // src/index.ts
7
+
8
+ // src/error/error.ts
9
+ function isErrorWithMessage(error) {
10
+ return typeof error === "object" && error !== null && "message" in error && typeof error.message === "string";
11
+ }
12
+ function toErrorWithMessage(maybeError) {
13
+ if (isErrorWithMessage(maybeError)) {
14
+ return maybeError;
15
+ }
16
+ try {
17
+ return new Error(JSON.stringify(maybeError));
18
+ } catch {
19
+ return new Error(String(maybeError));
20
+ }
21
+ }
22
+ function getErrorMessage(error) {
23
+ return toErrorWithMessage(error).message;
24
+ }
25
+
26
+ // src/format/core.ts
27
+ var defaultLocale;
28
+ function setDefaultLocale(locale) {
29
+ defaultLocale = locale;
30
+ }
31
+ function getDefaultLocale() {
32
+ return defaultLocale;
33
+ }
34
+ function resolveLocale(options) {
35
+ return options?.locale ?? defaultLocale;
36
+ }
37
+ function handleZeroNull(value, options, formatFn) {
38
+ if (value === null || value === void 0) {
39
+ if (options?.nullFormat !== void 0) {
40
+ return options.nullFormat;
41
+ }
42
+ return null;
43
+ }
44
+ if (typeof value === "number" && value === 0 && options?.zeroFormat !== void 0) {
45
+ return options.zeroFormat;
46
+ }
47
+ return formatFn(value);
48
+ }
49
+
50
+ // src/format/bytes.ts
51
+ function formatBytes(value, options) {
52
+ const result = handleZeroNull(value, options, (valueToFormat) => {
53
+ const byteCount = typeof valueToFormat === "bigint" ? Number(valueToFormat) : valueToFormat;
54
+ const locale = resolveLocale(options);
55
+ return prettyBytes(byteCount, {
56
+ binary: options?.binary,
57
+ bits: options?.bits,
58
+ signed: options?.signed,
59
+ locale: locale ? Array.isArray(locale) ? locale[0] : locale : false,
60
+ minimumFractionDigits: options?.minimumFractionDigits,
61
+ maximumFractionDigits: options?.maximumFractionDigits
62
+ });
63
+ });
64
+ const fallbackValue = value === null || value === void 0 ? 0 : typeof value === "bigint" ? Number(value) : value;
65
+ return result ?? prettyBytes(fallbackValue);
66
+ }
67
+ function formatBytesPerSecond(value, options) {
68
+ const result = handleZeroNull(value, options, (valueToFormat) => {
69
+ const byteCount = typeof valueToFormat === "bigint" ? Number(valueToFormat) : valueToFormat;
70
+ const locale = resolveLocale(options);
71
+ return `${prettyBytes(byteCount, {
72
+ binary: options?.binary,
73
+ bits: options?.bits,
74
+ signed: options?.signed,
75
+ locale: locale ? Array.isArray(locale) ? locale[0] : locale : false,
76
+ minimumFractionDigits: options?.minimumFractionDigits,
77
+ maximumFractionDigits: options?.maximumFractionDigits
78
+ })}/s`;
79
+ });
80
+ const fallbackValue = value === null || value === void 0 ? 0 : typeof value === "bigint" ? Number(value) : value;
81
+ return result ?? `${prettyBytes(fallbackValue)}/s`;
82
+ }
83
+
84
+ // src/format/currency.ts
85
+ function formatCurrency(value, options) {
86
+ const result = handleZeroNull(value, options, (valueToFormat) => {
87
+ const locale = resolveLocale(options);
88
+ const formatOptions = {
89
+ style: "currency",
90
+ currency: options?.currency ?? "USD",
91
+ minimumFractionDigits: options?.minimumFractionDigits,
92
+ maximumFractionDigits: options?.maximumFractionDigits ?? 2
93
+ };
94
+ return new Intl.NumberFormat(locale, formatOptions).format(valueToFormat);
95
+ });
96
+ const fallbackResult = new Intl.NumberFormat(resolveLocale(options), {
97
+ style: "currency",
98
+ currency: options?.currency ?? "USD"
99
+ }).format(value);
100
+ return result ?? fallbackResult;
101
+ }
102
+ function formatDate(value, options) {
103
+ const date = value instanceof Date ? value : typeof value === "number" ? new Date(value * 1e3) : new Date(value);
104
+ const pattern = options?.format ?? "MMM d, yyyy";
105
+ return format$1(date, pattern);
106
+ }
107
+ function formatRelativeTime(value, options) {
108
+ const date = value instanceof Date ? value : typeof value === "number" ? new Date(value * 1e3) : new Date(value);
109
+ return formatDistanceToNow(date, { addSuffix: options?.addSuffix ?? true });
110
+ }
111
+
112
+ // src/format/exponential.ts
113
+ function formatExponential(value, options) {
114
+ const result = handleZeroNull(value, options, (valueToFormat) => {
115
+ const locale = resolveLocale(options);
116
+ const formatOptions = {
117
+ notation: "scientific",
118
+ minimumFractionDigits: options?.minimumFractionDigits,
119
+ maximumFractionDigits: options?.maximumFractionDigits ?? 2
120
+ };
121
+ return new Intl.NumberFormat(locale, formatOptions).format(valueToFormat);
122
+ });
123
+ const fallbackResult = new Intl.NumberFormat(resolveLocale(options), {
124
+ notation: "scientific"
125
+ }).format(value);
126
+ return result ?? fallbackResult;
127
+ }
128
+
129
+ // src/format/list.ts
130
+ function formatList(items, options) {
131
+ if (items.length === 0) {
132
+ return "";
133
+ }
134
+ const locale = resolveLocale(options);
135
+ return new Intl.ListFormat(locale, {
136
+ type: options?.type ?? "conjunction",
137
+ style: options?.style ?? "long"
138
+ }).format(items);
139
+ }
140
+
141
+ // src/format/number.ts
142
+ function formatNumber(value, options) {
143
+ const result = handleZeroNull(value, options, (valueToFormat) => {
144
+ const locale = resolveLocale(options);
145
+ const opts = {
146
+ minimumFractionDigits: options?.minimumFractionDigits,
147
+ maximumFractionDigits: options?.maximumFractionDigits ?? (valueToFormat % 1 === 0 ? 0 : 2),
148
+ ...options?.notation && { notation: options.notation },
149
+ ...options?.compactDisplay && { compactDisplay: options.compactDisplay }
150
+ };
151
+ return new Intl.NumberFormat(locale, opts).format(valueToFormat);
152
+ });
153
+ const fallbackResult = new Intl.NumberFormat(resolveLocale(options)).format(value);
154
+ return result ?? fallbackResult;
155
+ }
156
+
157
+ // src/format/ordinal.ts
158
+ function formatOrdinal(value, options) {
159
+ const result = handleZeroNull(value, options, (valueToFormat) => {
160
+ const locale = resolveLocale(options);
161
+ const roundedValue = Math.round(valueToFormat);
162
+ const intl = new Intl.NumberFormat(locale, {
163
+ minimumFractionDigits: options?.minimumFractionDigits,
164
+ maximumFractionDigits: options?.maximumFractionDigits ?? 0
165
+ });
166
+ const ord = typeof Intl.PluralRules !== "undefined" ? new Intl.PluralRules(locale, { type: "ordinal" }).select(roundedValue) : "other";
167
+ const suffixes = {
168
+ one: "st",
169
+ two: "nd",
170
+ few: "rd",
171
+ other: "th"
172
+ };
173
+ return `${intl.format(roundedValue)}${suffixes[ord] ?? "th"}`;
174
+ });
175
+ return result ?? `${value}th`;
176
+ }
177
+
178
+ // src/format/percent.ts
179
+ function formatPercent(value, options) {
180
+ const result = handleZeroNull(value, options, (valueToFormat) => {
181
+ const toFormat = options?.scaleBy100 !== false ? valueToFormat : valueToFormat / 100;
182
+ const locale = resolveLocale(options);
183
+ const opts = {
184
+ style: "percent",
185
+ minimumFractionDigits: options?.minimumFractionDigits,
186
+ maximumFractionDigits: options?.maximumFractionDigits ?? 0
187
+ };
188
+ return new Intl.NumberFormat(locale, opts).format(toFormat);
189
+ });
190
+ const fallbackResult = new Intl.NumberFormat(resolveLocale(options), { style: "percent" }).format(
191
+ value
192
+ );
193
+ return result ?? fallbackResult;
194
+ }
195
+
196
+ // src/format/temperature.ts
197
+ function formatTemperature(value, options) {
198
+ const result = handleZeroNull(value, options, (valueToFormat) => {
199
+ const locale = resolveLocale(options);
200
+ const unit = options?.unit ?? "celsius";
201
+ const maxFrac = options?.maximumFractionDigits ?? 0;
202
+ const minFrac = options?.minimumFractionDigits;
203
+ if (unit === "kelvin") {
204
+ const opts2 = {
205
+ minimumFractionDigits: minFrac,
206
+ maximumFractionDigits: maxFrac
207
+ };
208
+ return `${new Intl.NumberFormat(locale, opts2).format(valueToFormat)} K`;
209
+ }
210
+ const unitKey = unit === "celsius" ? "celsius" : "fahrenheit";
211
+ const opts = {
212
+ style: "unit",
213
+ unit: unitKey,
214
+ minimumFractionDigits: minFrac,
215
+ maximumFractionDigits: maxFrac
216
+ };
217
+ return new Intl.NumberFormat(locale, opts).format(valueToFormat);
218
+ });
219
+ const fallbackResult = new Intl.NumberFormat(resolveLocale(options), {
220
+ style: "unit",
221
+ unit: "celsius"
222
+ }).format(value);
223
+ return result ?? fallbackResult;
224
+ }
225
+ function formatTime(seconds, options) {
226
+ const result = handleZeroNull(seconds, options, (secondsToFormat) => {
227
+ if (options?.style === "long" || options?.style === void 0) {
228
+ const duration = intervalToDuration({ start: 0, end: secondsToFormat * 1e3 });
229
+ const formatted = formatDuration(duration, {
230
+ format: options?.includeSeconds !== false ? ["hours", "minutes", "seconds"] : ["hours", "minutes"]
231
+ });
232
+ return formatted || "0 seconds";
233
+ }
234
+ const h = Math.floor(secondsToFormat / 3600);
235
+ const m = Math.floor((secondsToFormat - h * 3600) / 60);
236
+ const sec = Math.round(secondsToFormat - h * 3600 - m * 60);
237
+ const pad = (value) => value < 10 ? `0${value}` : String(value);
238
+ return `${pad(h)}:${pad(m)}:${pad(sec)}`;
239
+ });
240
+ return result ?? "0:00:00";
241
+ }
242
+ function formatTimeCompact(seconds, options) {
243
+ const result = handleZeroNull(seconds, options, (secondsToFormat) => {
244
+ const days = Math.floor(secondsToFormat / 86400);
245
+ const hours = Math.floor(secondsToFormat % 86400 / 3600);
246
+ const minutes = Math.floor(secondsToFormat % 3600 / 60);
247
+ const parts = [];
248
+ if (days > 0) {
249
+ parts.push(`${days}d`);
250
+ }
251
+ if (hours > 0) {
252
+ parts.push(`${hours}h`);
253
+ }
254
+ if (minutes > 0) {
255
+ parts.push(`${minutes}m`);
256
+ }
257
+ return parts.length > 0 ? parts.join(" ") : "0m";
258
+ });
259
+ return result ?? "0m";
260
+ }
261
+
262
+ // src/format/format.ts
263
+ function format(value, formatString, options) {
264
+ if (value === null || value === void 0) {
265
+ if (options?.nullFormat !== void 0) {
266
+ return options.nullFormat;
267
+ }
268
+ return "";
269
+ }
270
+ const str = formatString.trim().toLowerCase();
271
+ if (str === "ordinal" || str === "0o") {
272
+ return formatOrdinal(Number(value), options);
273
+ }
274
+ if (str === "relative") {
275
+ const date = value instanceof Date ? value : typeof value === "number" ? new Date(value * 1e3) : new Date(value);
276
+ return formatRelativeTime(date, { ...options, addSuffix: true });
277
+ }
278
+ if (str === "list") {
279
+ return formatList(value, options);
280
+ }
281
+ if (str === "exponential" || str === "0.00e+0" || /e[+-]/.test(str)) {
282
+ return formatExponential(Number(value), options);
283
+ }
284
+ if (/\$|currency/.test(str)) {
285
+ const currency = str.includes("\u20AC") ? "EUR" : str.includes("\xA3") ? "GBP" : "USD";
286
+ return formatCurrency(Number(value), { ...options, currency });
287
+ }
288
+ if (/%|percent/.test(str)) {
289
+ const decimals2 = /\.(0+)/.exec(str)?.[1]?.length ?? 0;
290
+ return formatPercent(Number(value), {
291
+ ...options,
292
+ maximumFractionDigits: decimals2
293
+ });
294
+ }
295
+ if (str === "bps" || str.endsWith("/s")) {
296
+ const binary = str.includes("ib");
297
+ return formatBytesPerSecond(typeof value === "bigint" ? value : Number(value), {
298
+ ...options,
299
+ binary
300
+ });
301
+ }
302
+ if (/0\s?i?b|bytes/.test(str)) {
303
+ const binary = str.includes("ib");
304
+ return formatBytes(typeof value === "bigint" ? value : Number(value), {
305
+ ...options,
306
+ binary
307
+ });
308
+ }
309
+ if (str === "uptime" && typeof value === "number") {
310
+ return formatTimeCompact(value, options);
311
+ }
312
+ if ((str === "time" || str === "duration") && typeof value === "number") {
313
+ return formatTime(value, { ...options, style: "long" });
314
+ }
315
+ if (/[:]/.test(str) && typeof value === "number") {
316
+ return formatTime(value, { ...options, style: "short" });
317
+ }
318
+ if (/temp|°|celsius|fahrenheit|kelvin/.test(str)) {
319
+ const unit = str.includes("f") ? "fahrenheit" : str.includes("k") ? "kelvin" : "celsius";
320
+ return formatTemperature(Number(value), { ...options, unit });
321
+ }
322
+ if (/date|short|long|iso/.test(str)) {
323
+ const date = value instanceof Date ? value : typeof value === "number" ? new Date(value * 1e3) : new Date(value);
324
+ if (str === "short") {
325
+ return formatDate(date, { ...options, format: "MMM d" });
326
+ }
327
+ if (str === "long") {
328
+ return formatDate(date, { ...options, format: "MMMM d, yyyy" });
329
+ }
330
+ if (str === "iso") {
331
+ return formatDate(date, { ...options, format: "yyyy-MM-dd'T'HH:mm:ss" });
332
+ }
333
+ return formatDate(date, options);
334
+ }
335
+ const num = typeof value === "number" ? value : typeof value === "bigint" ? Number(value) : Number.parseFloat(String(value));
336
+ if (Number.isNaN(num)) {
337
+ return options?.nullFormat ?? "";
338
+ }
339
+ const decimals = /\.(0+)/.exec(str)?.[1]?.length ?? 0;
340
+ const compact = /a|abbrev/.test(str);
341
+ if (compact) {
342
+ return formatNumber(num, {
343
+ ...options,
344
+ notation: "compact",
345
+ compactDisplay: str.includes(" ") ? "long" : "short",
346
+ maximumFractionDigits: decimals || 1
347
+ });
348
+ }
349
+ return formatNumber(num, {
350
+ ...options,
351
+ minimumFractionDigits: decimals,
352
+ maximumFractionDigits: decimals
353
+ });
354
+ }
355
+
356
+ // src/function/debounce.ts
357
+ function debounce(func, wait) {
358
+ let timeout = null;
359
+ return function executedFunction(...args) {
360
+ const later = () => {
361
+ timeout = null;
362
+ func(...args);
363
+ };
364
+ if (timeout !== null) {
365
+ clearTimeout(timeout);
366
+ }
367
+ timeout = setTimeout(later, wait);
368
+ };
369
+ }
370
+
371
+ // src/object/get.ts
372
+ function get(obj, path) {
373
+ const keys = path.split(".");
374
+ let result = obj;
375
+ for (const key of keys) {
376
+ if (result && typeof result === "object" && key in result) {
377
+ result = result[key];
378
+ } else {
379
+ return void 0;
380
+ }
381
+ }
382
+ return result;
383
+ }
384
+
385
+ // src/platform/env.ts
386
+ var isDevelopment = process.env.NODE_ENV === "development";
387
+ var isProduction = process.env.NODE_ENV === "production";
388
+ var isTest = process.env.NODE_ENV === "test";
389
+
390
+ // src/platform/os.ts
391
+ var isMac = typeof navigator !== "undefined" && navigator.platform.toUpperCase().includes("MAC");
392
+ var modKey = isMac ? "\u2318" : "Ctrl";
393
+
394
+ // src/platform/runtime.ts
395
+ var isClient = typeof window !== "undefined";
396
+ var isServer = typeof window === "undefined";
397
+
398
+ // src/string/stringifyValue.ts
399
+ function stringifyValue(value) {
400
+ if (value === null || value === void 0) {
401
+ return "";
402
+ }
403
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
404
+ return String(value);
405
+ }
406
+ return JSON.stringify(value);
407
+ }
408
+
409
+ // src/string/truncate.ts
410
+ function truncate(str, length) {
411
+ if (str.length <= length) {
412
+ return str;
413
+ }
414
+ return `${str.slice(0, length)}...`;
415
+ }
416
+
417
+ // src/string/valueToDisplayString.ts
418
+ function valueToDisplayString(value) {
419
+ if (value === null) {
420
+ return "null";
421
+ }
422
+ if (value === void 0) {
423
+ return "undefined";
424
+ }
425
+ if (typeof value === "boolean") {
426
+ return value ? "true" : "false";
427
+ }
428
+ if (typeof value === "string") {
429
+ return value;
430
+ }
431
+ if (typeof value === "number") {
432
+ return String(value);
433
+ }
434
+ if (Array.isArray(value)) {
435
+ return `Array(${value.length})`;
436
+ }
437
+ if (typeof value === "object") {
438
+ return `Object(${Object.keys(value).length})`;
439
+ }
440
+ return String(value);
441
+ }
442
+
443
+ export { debounce, format, formatBytes, formatBytesPerSecond, formatCurrency, formatDate, formatExponential, formatList, formatNumber, formatOrdinal, formatPercent, formatRelativeTime, formatTemperature, formatTime, formatTimeCompact, get, getDefaultLocale, getErrorMessage, isClient, isDevelopment, isMac, isProduction, isServer, isTest, modKey, setDefaultLocale, stringifyValue, truncate, valueToDisplayString };
444
+ //# sourceMappingURL=index.js.map
445
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/error/error.ts","../src/format/core.ts","../src/format/bytes.ts","../src/format/currency.ts","../src/format/date.ts","../src/format/exponential.ts","../src/format/list.ts","../src/format/number.ts","../src/format/ordinal.ts","../src/format/percent.ts","../src/format/temperature.ts","../src/format/time.ts","../src/format/format.ts","../src/function/debounce.ts","../src/object/get.ts","../src/platform/env.ts","../src/platform/os.ts","../src/platform/runtime.ts","../src/string/stringifyValue.ts","../src/string/truncate.ts","../src/string/valueToDisplayString.ts"],"names":["dateFnsFormat","opts","decimals"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Type guard and utility functions for safe error message extraction.\n *\n * TypeScript's catch blocks receive `unknown` types, not `Error` types.\n * These utilities provide type-safe ways to extract error messages from any thrown value.\n *\n * @link https://kentcdodds.com/blog/get-a-catch-block-error-message-with-typescript\n */\n\ninterface ErrorWithMessage {\n message: string\n}\n\n/**\n * Type guard to check if a value is an object with a string message property.\n *\n * @param error - The value to check\n * @returns True if the value has a string message property\n */\nfunction isErrorWithMessage(error: unknown): error is ErrorWithMessage {\n return (\n typeof error === 'object' &&\n error !== null &&\n 'message' in error &&\n typeof (error as Record<string, unknown>).message === 'string'\n )\n}\n\n/**\n * Converts any value to an object with a message property.\n *\n * Handles edge cases like circular references and non-serializable objects.\n *\n * @param maybeError - The value to convert\n * @returns An object with a message property\n */\nfunction toErrorWithMessage(maybeError: unknown): ErrorWithMessage {\n if (isErrorWithMessage(maybeError)) {\n return maybeError\n }\n\n try {\n return new Error(JSON.stringify(maybeError))\n } catch {\n // Fallback in case there's an error stringifying the maybeError\n // like with circular references for example.\n return new Error(String(maybeError))\n }\n}\n\n/**\n * Safely extracts an error message from any thrown value.\n *\n * Use this in catch blocks to get a string message regardless of what was thrown.\n *\n * @param error - The caught error (of type unknown)\n * @returns A string error message\n *\n * @example\n * ```ts\n * try {\n * // some code that might throw\n * } catch (error) {\n * const message = getErrorMessage(error)\n * console.error(message)\n * }\n * ```\n */\nexport function getErrorMessage(error: unknown): string {\n return toErrorWithMessage(error).message\n}\n","/**\n * Core utilities shared across format modules.\n */\n\nlet defaultLocale: string | string[] | undefined\n\n/**\n * Set the default locale for all format functions.\n *\n * When a format is called without `locale` in its options, it uses this value.\n * Call at app startup or in tests for consistent output (e.g. `setDefaultLocale('en-US')`).\n *\n * @param locale - BCP 47 locale (e.g. 'en-US'), an array of fallbacks, or `undefined` to use runtime default\n */\nexport function setDefaultLocale(locale: string | string[] | undefined): void {\n defaultLocale = locale\n}\n\n/**\n * Get the current default locale.\n *\n * @returns The default locale, or `undefined` if none is set\n */\nexport function getDefaultLocale(): string | string[] | undefined {\n return defaultLocale\n}\n\n/**\n * Resolve which locale to use for formatting.\n *\n * Uses `options.locale` when present, otherwise falls back to the default locale.\n * Format functions use this before passing locale to Intl APIs.\n *\n * @param options - Format options that may include a `locale` override\n * @returns The locale to use, or `undefined` if neither options nor default are set\n */\nexport function resolveLocale(options?: {\n locale?: string | string[]\n}): string | string[] | undefined {\n return options?.locale ?? defaultLocale\n}\n\n/**\n * Handle zero and null/undefined before delegating to the formatter.\n *\n * - If value is null/undefined: return `nullFormat` when set, otherwise `null`\n * - If value is 0: return `zeroFormat` when set, otherwise format normally\n * - Otherwise: call formatFn with the value\n *\n * @param value - The value to format (may be null or undefined)\n * @param options - Optional `zeroFormat` and `nullFormat` for custom output\n * @param formatFn - The formatter to call when value is valid and non-zero\n * @returns Custom string, `null`, or the formatted value\n *\n * @example\n * ```ts\n * handleZeroNull(100, { zeroFormat: '0' }, (v) => v.toString())\n * // => '100'\n *\n * handleZeroNull(0, { zeroFormat: '0' }, (v) => v.toString())\n * // => '0'\n *\n * handleZeroNull(null, { nullFormat: 'N/A' }, (v) => v.toString())\n * // => 'N/A'\n *\n * handleZeroNull(undefined, { nullFormat: 'N/A' }, (v) => v.toString())\n * // => 'N/A'\n * ```\n */\nexport function handleZeroNull<T>(\n value: T | null | undefined,\n options: { zeroFormat?: string; nullFormat?: string } | undefined,\n formatFn: (valueToFormat: T) => string,\n): string | null {\n if (value === null || value === undefined) {\n if (options?.nullFormat !== undefined) {\n return options.nullFormat\n }\n\n return null\n }\n\n if (typeof value === 'number' && value === 0 && options?.zeroFormat !== undefined) {\n return options.zeroFormat\n }\n\n return formatFn(value as T)\n}\n","import prettyBytes from 'pretty-bytes'\n\nimport { handleZeroNull, resolveLocale } from './core'\nimport type { BytesFormatOptions } from './types'\n\n/**\n * Format a byte count into a human-readable string.\n *\n * @param value - The byte count to format\n * @param options - Optional formatting options\n * @returns A human-readable string representing the byte count\n *\n * @example\n * ```ts\n * formatBytes(1024) // '1.02 kB'\n * formatBytes(1024, { binary: true }) // '1 KiB'\n * formatBytes(8192, { bits: true }) // '8.19 kbit'\n * formatBytes(1024, { locale: 'de-DE' }) // '1,02 kB'\n * ```\n */\nexport function formatBytes(value: number | bigint, options?: BytesFormatOptions): string {\n const result = handleZeroNull(value, options, (valueToFormat) => {\n const byteCount = typeof valueToFormat === 'bigint' ? Number(valueToFormat) : valueToFormat\n const locale = resolveLocale(options)\n\n return prettyBytes(byteCount, {\n binary: options?.binary,\n bits: options?.bits,\n signed: options?.signed,\n locale: locale ? (Array.isArray(locale) ? locale[0] : locale) : false,\n minimumFractionDigits: options?.minimumFractionDigits,\n maximumFractionDigits: options?.maximumFractionDigits,\n })\n })\n\n const fallbackValue =\n value === null || value === undefined ? 0 : typeof value === 'bigint' ? Number(value) : value\n\n return result ?? prettyBytes(fallbackValue)\n}\n\n/**\n * Format a byte-rate value into a human-readable per-second string.\n *\n * @param value - The throughput in bytes per second\n * @param options - Optional formatting options (same as {@link formatBytes})\n * @returns A human-readable string representing the throughput\n *\n * @example\n * ```ts\n * formatBytesPerSecond(1024) // '1.02 kB/s'\n * formatBytesPerSecond(1024, { binary: true }) // '1 KiB/s'\n * formatBytesPerSecond(0) // '0 B/s'\n * ```\n */\nexport function formatBytesPerSecond(value: number | bigint, options?: BytesFormatOptions): string {\n const result = handleZeroNull(value, options, (valueToFormat) => {\n const byteCount = typeof valueToFormat === 'bigint' ? Number(valueToFormat) : valueToFormat\n const locale = resolveLocale(options)\n\n return `${prettyBytes(byteCount, {\n binary: options?.binary,\n bits: options?.bits,\n signed: options?.signed,\n locale: locale ? (Array.isArray(locale) ? locale[0] : locale) : false,\n minimumFractionDigits: options?.minimumFractionDigits,\n maximumFractionDigits: options?.maximumFractionDigits,\n })}/s`\n })\n\n const fallbackValue =\n value === null || value === undefined ? 0 : typeof value === 'bigint' ? Number(value) : value\n\n return result ?? `${prettyBytes(fallbackValue)}/s`\n}\n","import { handleZeroNull, resolveLocale } from './core'\nimport type { CurrencyFormatOptions } from './types'\n\n/**\n * Format a number as currency with the correct symbol and locale-specific formatting.\n *\n * @param value - The numeric value to format\n * @param options - Optional formatting options\n * @returns Formatted string representing the currency value\n *\n * @example\n * ```ts\n * formatCurrency(1234.56) // '$1,234.56'\n * formatCurrency(99.99, { currency: 'EUR' }) // '€99.99'\n * formatCurrency(0, { zeroFormat: 'Free' }) // 'Free'\n * formatCurrency(1234.56, { locale: 'de-DE' }) // '1.234,56 €'\n * ```\n */\nexport function formatCurrency(value: number, options?: CurrencyFormatOptions): string {\n const result = handleZeroNull(value, options, (valueToFormat) => {\n const locale = resolveLocale(options)\n const formatOptions: Intl.NumberFormatOptions = {\n style: 'currency',\n currency: options?.currency ?? 'USD',\n minimumFractionDigits: options?.minimumFractionDigits,\n maximumFractionDigits: options?.maximumFractionDigits ?? 2,\n }\n\n return new Intl.NumberFormat(locale, formatOptions).format(valueToFormat)\n })\n\n const fallbackResult = new Intl.NumberFormat(resolveLocale(options), {\n style: 'currency',\n currency: options?.currency ?? 'USD',\n }).format(value)\n\n return result ?? fallbackResult\n}\n","import { format as dateFnsFormat, formatDistanceToNow } from 'date-fns'\n\nimport type { DateFormatOptions } from './types'\n\n/**\n * Format a date (Date, string, or Unix timestamp in seconds).\n *\n * @param value - Date instance, ISO string, or Unix seconds\n * @param options - Optional formatting options\n * @returns Formatted string per the pattern\n *\n * @example\n * ```ts\n * formatDate(new Date('2025-03-13')) // 'Mar 13, 2025'\n * formatDate('2025-03-13', { format: 'yyyy-MM-dd' }) // '2025-03-13'\n * ```\n */\nexport function formatDate(value: Date | string | number, options?: DateFormatOptions): string {\n const date =\n value instanceof Date\n ? value\n : typeof value === 'number'\n ? new Date(value * 1000)\n : new Date(value)\n const pattern = options?.format ?? 'MMM d, yyyy'\n return dateFnsFormat(date, pattern)\n}\n\n/**\n * Format a date as human-readable relative time.\n *\n * @param value - Date instance, ISO string, or Unix seconds\n * @param options - Optional formatting options\n * @returns Relative string such as \"about 2 hours ago\" or \"in 3 days\"\n *\n * @example\n * ```ts\n * formatRelativeTime(Date.now() / 1000 - 3600) // 'about 1 hour ago'\n * formatRelativeTime(new Date(), { addSuffix: false }) // 'less than a minute'\n * ```\n */\nexport function formatRelativeTime(\n value: Date | string | number,\n options?: DateFormatOptions,\n): string {\n const date =\n value instanceof Date\n ? value\n : typeof value === 'number'\n ? new Date(value * 1000)\n : new Date(value)\n return formatDistanceToNow(date, { addSuffix: options?.addSuffix ?? true })\n}\n","import { handleZeroNull, resolveLocale } from './core'\nimport type { ExponentialFormatOptions } from './types'\n\n/**\n * Format a number in exponential/scientific notation.\n *\n * @param value - The number to format\n * @param options - Optional formatting options\n * @returns Formatted string representing the exponential value\n *\n * @example\n * ```ts\n * formatExponential(1234.56) // '1.23E3'\n * formatExponential(1234.56, { maximumFractionDigits: 0 }) // '1E3'\n * formatExponential(0.00123) // '1.23E-3'\n * formatExponential(1234.56, { locale: 'de-DE' }) // '1,23E3'\n * formatExponential(0, { zeroFormat: '0' }) // '0'\n * ```\n */\nexport function formatExponential(value: number, options?: ExponentialFormatOptions): string {\n const result = handleZeroNull(value, options, (valueToFormat) => {\n const locale = resolveLocale(options)\n const formatOptions: Intl.NumberFormatOptions = {\n notation: 'scientific',\n minimumFractionDigits: options?.minimumFractionDigits,\n maximumFractionDigits: options?.maximumFractionDigits ?? 2,\n }\n\n return new Intl.NumberFormat(locale, formatOptions).format(valueToFormat)\n })\n\n const fallbackResult = new Intl.NumberFormat(resolveLocale(options), {\n notation: 'scientific',\n }).format(value)\n\n return result ?? fallbackResult\n}\n","import { resolveLocale } from './core'\nimport type { ListFormatOptions } from './types'\n\n/**\n * Format a list of strings.\n *\n * @param items - The list of strings to format\n * @param options - Optional formatting options\n * @returns The formatted list\n *\n * @example\n * ```ts\n * formatList(['A', 'B', 'C'])\n * // => 'A, B, and C'\n *\n * formatList(['A', 'B', 'C'], { type: 'disjunction' })\n * // => 'A, B, or C'\n *\n * formatList(['A', 'B', 'C'], { style: 'short' })\n * // => 'A, B, & C'\n *\n * formatList(['A', 'B', 'C'], { style: 'narrow' })\n * // => 'A, B, C'\n * ```\n */\nexport function formatList(items: string[], options?: ListFormatOptions): string {\n if (items.length === 0) {\n return ''\n }\n\n const locale = resolveLocale(options)\n\n return new Intl.ListFormat(locale, {\n type: options?.type ?? 'conjunction',\n style: options?.style ?? 'long',\n }).format(items)\n}\n","import { handleZeroNull, resolveLocale } from './core'\nimport type { NumberFormatOptions } from './types'\n\n/**\n * Format a number with locale-aware thousands separators and optional decimals.\n *\n * @param value - The number to format\n * @param options - Optional formatting options\n * @returns Formatted string representing the number\n *\n * @example\n * ```ts\n * formatNumber(1234.56)\n * // => '1,234.56'\n *\n * formatNumber(1234.56, { maximumFractionDigits: 2 })\n * // => '1,234.56'\n *\n * formatNumber(1234.56, { notation: 'compact' })\n * // => '1.2K'\n *\n * formatNumber(1234.56, { notation: 'compact', compactDisplay: 'long' })\n * // => '1.2 thousand'\n * ```\n */\nexport function formatNumber(value: number, options?: NumberFormatOptions): string {\n const result = handleZeroNull(value, options, (valueToFormat) => {\n const locale = resolveLocale(options)\n const opts: Intl.NumberFormatOptions = {\n minimumFractionDigits: options?.minimumFractionDigits,\n maximumFractionDigits: options?.maximumFractionDigits ?? (valueToFormat % 1 === 0 ? 0 : 2),\n ...(options?.notation && { notation: options.notation }),\n ...(options?.compactDisplay && { compactDisplay: options.compactDisplay }),\n }\n\n return new Intl.NumberFormat(locale, opts).format(valueToFormat)\n })\n\n const fallbackResult = new Intl.NumberFormat(resolveLocale(options)).format(value)\n\n return result ?? fallbackResult\n}\n","import { handleZeroNull, resolveLocale } from './core'\nimport type { OrdinalFormatOptions } from './types'\n\n/**\n * Format a number with ordinal suffix.\n *\n * @param value - The number to format\n * @param options - Optional formatting options\n * @returns Formatted string representing the ordinal value\n *\n * @example\n * ```ts\n * formatOrdinal(1) // '1st'\n * formatOrdinal(2) // '2nd'\n * formatOrdinal(3) // '3rd'\n * ```\n */\nexport function formatOrdinal(value: number, options?: OrdinalFormatOptions): string {\n const result = handleZeroNull(value, options, (valueToFormat) => {\n const locale = resolveLocale(options)\n const roundedValue = Math.round(valueToFormat)\n const intl = new Intl.NumberFormat(locale, {\n minimumFractionDigits: options?.minimumFractionDigits,\n maximumFractionDigits: options?.maximumFractionDigits ?? 0,\n })\n const ord =\n typeof Intl.PluralRules !== 'undefined'\n ? new Intl.PluralRules(locale, { type: 'ordinal' }).select(roundedValue)\n : 'other'\n const suffixes: Record<string, string> = {\n one: 'st',\n two: 'nd',\n few: 'rd',\n other: 'th',\n }\n\n /* v8 ignore next */\n return `${intl.format(roundedValue)}${suffixes[ord] ?? 'th'}`\n })\n\n return result ?? `${value}th`\n}\n","import { handleZeroNull, resolveLocale } from './core'\nimport type { PercentFormatOptions } from './types'\n\n/**\n * Format a number as a percentage.\n *\n * @param value - The number to format\n * @param options - Optional formatting options\n * @returns Formatted string representing the percentage value\n *\n * @example\n * ```ts\n * formatPercent(0.5)\n * // => '50%'\n *\n * formatPercent(0.5, { minimumFractionDigits: 2, maximumFractionDigits: 2 })\n * // => '50.00%'\n *\n * formatPercent(50, { scaleBy100: false })\n * // => '50%' (value already 0–100)\n * ```\n */\nexport function formatPercent(value: number, options?: PercentFormatOptions): string {\n const result = handleZeroNull(value, options, (valueToFormat) => {\n const toFormat = options?.scaleBy100 !== false ? valueToFormat : valueToFormat / 100\n const locale = resolveLocale(options)\n const opts: Intl.NumberFormatOptions = {\n style: 'percent',\n minimumFractionDigits: options?.minimumFractionDigits,\n maximumFractionDigits: options?.maximumFractionDigits ?? 0,\n }\n\n return new Intl.NumberFormat(locale, opts).format(toFormat)\n })\n\n const fallbackResult = new Intl.NumberFormat(resolveLocale(options), { style: 'percent' }).format(\n value,\n )\n\n return result ?? fallbackResult\n}\n","import { handleZeroNull, resolveLocale } from './core'\nimport type { TemperatureFormatOptions } from './types'\n\n/**\n * Format a temperature value.\n *\n * @param value - The temperature value to format\n * @param options - Optional formatting options\n * @returns Formatted string representing the temperature value\n *\n * @example\n * ```ts\n * formatTemperature(25) // '25°C'\n * formatTemperature(77, { unit: 'fahrenheit' }) // '77°F'\n * formatTemperature(273.15, { unit: 'kelvin' }) // '273.15 K'\n * ```\n */\nexport function formatTemperature(value: number, options?: TemperatureFormatOptions): string {\n const result = handleZeroNull(value, options, (valueToFormat) => {\n const locale = resolveLocale(options)\n const unit = options?.unit ?? 'celsius'\n const maxFrac = options?.maximumFractionDigits ?? 0\n const minFrac = options?.minimumFractionDigits\n\n if (unit === 'kelvin') {\n const opts: Intl.NumberFormatOptions = {\n minimumFractionDigits: minFrac,\n maximumFractionDigits: maxFrac,\n }\n\n return `${new Intl.NumberFormat(locale, opts).format(valueToFormat)} K`\n }\n\n const unitKey = unit === 'celsius' ? 'celsius' : 'fahrenheit'\n const opts: Intl.NumberFormatOptions = {\n style: 'unit',\n unit: unitKey,\n minimumFractionDigits: minFrac,\n maximumFractionDigits: maxFrac,\n }\n\n return new Intl.NumberFormat(locale, opts).format(valueToFormat)\n })\n\n const fallbackResult = new Intl.NumberFormat(resolveLocale(options), {\n style: 'unit',\n unit: 'celsius',\n }).format(value)\n\n return result ?? fallbackResult\n}\n","import { formatDuration, intervalToDuration } from 'date-fns'\n\nimport { handleZeroNull } from './core'\nimport type { TimeFormatOptions } from './types'\n\n/**\n * Format a duration in seconds to HH:MM:SS or human-readable string.\n *\n * @param seconds - The duration in seconds to format\n * @param options - Optional formatting options\n * @returns Formatted string representing the time value\n *\n * @example\n * ```ts\n * formatTime(3661, { style: 'short' })\n * // => '01:01:01'\n *\n * formatTime(65, { style: 'long' })\n * // => '1 minute 5 seconds'\n *\n * formatTime(3661, { style: 'long', includeSeconds: false })\n * // => '1 hour 1 minute'\n * ```\n */\nexport function formatTime(seconds: number, options?: TimeFormatOptions): string {\n const result = handleZeroNull(seconds, options, (secondsToFormat) => {\n if (options?.style === 'long' || options?.style === undefined) {\n const duration = intervalToDuration({ start: 0, end: secondsToFormat * 1000 })\n const formatted = formatDuration(duration, {\n format:\n options?.includeSeconds !== false\n ? ['hours', 'minutes', 'seconds']\n : ['hours', 'minutes'],\n })\n\n return formatted || '0 seconds'\n }\n\n const h = Math.floor(secondsToFormat / 3600)\n const m = Math.floor((secondsToFormat - h * 3600) / 60)\n const sec = Math.round(secondsToFormat - h * 3600 - m * 60)\n const pad = (value: number) => (value < 10 ? `0${value}` : String(value))\n\n return `${pad(h)}:${pad(m)}:${pad(sec)}`\n })\n\n return result ?? '0:00:00'\n}\n\n/**\n * Format a duration in seconds into a compact, multi-day-aware string.\n *\n * Drops zero units and joins the remainder with spaces. Useful for uptime\n * fields where space is tight and the long-form `formatTime` is too verbose.\n *\n * @param seconds - The duration in seconds to format\n * @param options - Optional formatting options\n * @returns Formatted string representing the duration\n *\n * @example\n * ```ts\n * formatTimeCompact(3 * 86400 + 5 * 3600 + 12 * 60)\n * // => '3d 5h 12m'\n *\n * formatTimeCompact(45 * 60)\n * // => '45m'\n *\n * formatTimeCompact(0)\n * // => '0m'\n * ```\n */\nexport function formatTimeCompact(seconds: number, options?: TimeFormatOptions): string {\n const result = handleZeroNull(seconds, options, (secondsToFormat) => {\n const days = Math.floor(secondsToFormat / 86400)\n const hours = Math.floor((secondsToFormat % 86400) / 3600)\n const minutes = Math.floor((secondsToFormat % 3600) / 60)\n\n const parts: string[] = []\n\n if (days > 0) {\n parts.push(`${days}d`)\n }\n\n if (hours > 0) {\n parts.push(`${hours}h`)\n }\n\n if (minutes > 0) {\n parts.push(`${minutes}m`)\n }\n\n return parts.length > 0 ? parts.join(' ') : '0m'\n })\n\n return result ?? '0m'\n}\n","import { formatBytes, formatBytesPerSecond } from './bytes'\nimport { formatCurrency } from './currency'\nimport { formatDate, formatRelativeTime } from './date'\nimport { formatExponential } from './exponential'\nimport { formatList } from './list'\nimport { formatNumber } from './number'\nimport { formatOrdinal } from './ordinal'\nimport { formatPercent } from './percent'\nimport { formatTemperature } from './temperature'\nimport { formatTime, formatTimeCompact } from './time'\nimport type { BaseFormatOptions, DateFormatOptions } from './types'\n\n/**\n * Main format function - parses format strings and delegates to the appropriate formatter.\n *\n * @param value - The value to format\n * @param formatString - The format string\n * @param options - Optional formatting options\n * @returns The formatted value\n *\n * @example\n * ```ts\n * format(1000, '0,0')\n * // => '1,000'\n *\n * format(1500000, '0.0a')\n * // => '1.5M'\n *\n * format(new Date(), 'relative')\n * // => 'less than a minute ago'\n * ```\n */\nexport function format(\n value: number | bigint | Date | string | string[] | null | undefined,\n formatString: string,\n options?: BaseFormatOptions,\n): string {\n if (value === null || value === undefined) {\n if (options?.nullFormat !== undefined) {\n return options.nullFormat\n }\n\n return ''\n }\n\n const str = formatString.trim().toLowerCase()\n\n if (str === 'ordinal' || str === '0o') {\n return formatOrdinal(Number(value), options)\n }\n\n if (str === 'relative') {\n const date =\n value instanceof Date\n ? value\n : typeof value === 'number'\n ? new Date(value * 1000)\n : new Date(value as string)\n return formatRelativeTime(date, { ...options, addSuffix: true })\n }\n\n if (str === 'list') {\n return formatList(value as unknown as string[], options)\n }\n\n if (str === 'exponential' || str === '0.00e+0' || /e[+-]/.test(str)) {\n return formatExponential(Number(value), options)\n }\n\n if (/\\$|currency/.test(str)) {\n /* v8 ignore next */\n const currency = str.includes('€') ? 'EUR' : str.includes('£') ? 'GBP' : 'USD'\n return formatCurrency(Number(value), { ...options, currency })\n }\n\n if (/%|percent/.test(str)) {\n const decimals = /\\.(0+)/.exec(str)?.[1]?.length ?? 0\n return formatPercent(Number(value), {\n ...options,\n maximumFractionDigits: decimals,\n })\n }\n\n if (str === 'bps' || str.endsWith('/s')) {\n const binary = str.includes('ib')\n return formatBytesPerSecond(typeof value === 'bigint' ? value : Number(value), {\n ...options,\n binary,\n })\n }\n\n if (/0\\s?i?b|bytes/.test(str)) {\n const binary = str.includes('ib')\n return formatBytes(typeof value === 'bigint' ? value : Number(value), {\n ...options,\n binary,\n })\n }\n\n if (str === 'uptime' && typeof value === 'number') {\n return formatTimeCompact(value, options)\n }\n\n if ((str === 'time' || str === 'duration') && typeof value === 'number') {\n return formatTime(value, { ...options, style: 'long' })\n }\n\n if (/[:]/.test(str) && typeof value === 'number') {\n return formatTime(value, { ...options, style: 'short' })\n }\n\n if (/temp|°|celsius|fahrenheit|kelvin/.test(str)) {\n const unit = str.includes('f') ? 'fahrenheit' : str.includes('k') ? 'kelvin' : 'celsius'\n return formatTemperature(Number(value), { ...options, unit })\n }\n\n if (/date|short|long|iso/.test(str)) {\n const date =\n value instanceof Date\n ? value\n : typeof value === 'number'\n ? new Date(value * 1000)\n : new Date(value as string)\n\n if (str === 'short') {\n return formatDate(date, { ...options, format: 'MMM d' })\n }\n\n if (str === 'long') {\n return formatDate(date, { ...options, format: 'MMMM d, yyyy' })\n }\n\n if (str === 'iso') {\n return formatDate(date, { ...options, format: \"yyyy-MM-dd'T'HH:mm:ss\" })\n }\n\n return formatDate(date, options as DateFormatOptions)\n }\n\n const num =\n typeof value === 'number'\n ? value\n : typeof value === 'bigint'\n ? Number(value)\n : Number.parseFloat(String(value))\n\n if (Number.isNaN(num)) {\n return options?.nullFormat ?? ''\n }\n\n const decimals = /\\.(0+)/.exec(str)?.[1]?.length ?? 0\n const compact = /a|abbrev/.test(str)\n\n if (compact) {\n return formatNumber(num, {\n ...options,\n notation: 'compact',\n compactDisplay: str.includes(' ') ? 'long' : 'short',\n maximumFractionDigits: decimals || 1,\n })\n }\n\n return formatNumber(num, {\n ...options,\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n })\n}\n","/**\n * Creates a debounced function that delays invoking `func` until after `wait` milliseconds.\n *\n * @template T - The type of the function to debounce\n * @param func - The function to debounce\n * @param wait - The number of milliseconds to delay execution\n * @returns A new debounced version of the provided function\n *\n * @example\n * ```ts\n * // Debounce a search function\n * const debouncedSearch = debounce((query: string) => {\n * fetchSearchResults(query)\n * }, 300)\n *\n * // User types \"hello\"\n * debouncedSearch('h') // Waits...\n * debouncedSearch('he') // Cancels previous, waits...\n * debouncedSearch('hel') // Cancels previous, waits...\n * // After 300ms of no calls, executes with 'hel'\n * ```\n *\n * @example\n * ```ts\n * // Debounce window resize handler\n * const debouncedResize = debounce(() => {\n * recalculateLayout()\n * }, 150)\n *\n * window.addEventListener('resize', debouncedResize)\n * ```\n */\nexport function debounce<T extends (...args: unknown[]) => unknown>(\n func: T,\n wait: number,\n): (...args: Parameters<T>) => void {\n let timeout: ReturnType<typeof setTimeout> | null = null\n\n return function executedFunction(...args: Parameters<T>) {\n const later = () => {\n timeout = null\n func(...args)\n }\n\n if (timeout !== null) {\n clearTimeout(timeout)\n }\n\n timeout = setTimeout(later, wait)\n }\n}\n","/**\n * Safely retrieves a nested property value from an object using a dot-notation path.\n *\n * This function provides a safe way to access deeply nested properties without\n * worrying about undefined intermediate values. Similar to lodash's `_.get()`.\n * Returns `undefined` if any part of the path doesn't exist.\n *\n * @param obj - The object to query\n * @param path - The dot-notation path to the property (e.g., 'user.address.city')\n * @returns The value at the path, or `undefined` if not found\n *\n * @example\n * ```ts\n * const user = { name: 'John', address: { city: 'NYC', zip: '10001' } }\n *\n * get(user, 'name')\n * // => 'John'\n * ```\n *\n * @example\n * ```ts\n * get(user, 'address.city')\n * // => 'NYC'\n * ```\n *\n * @example\n * ```ts\n * // Safe access - returns undefined instead of throwing\n * get(user, 'address.country')\n * // => undefined\n * ```\n */\nexport function get(obj: Record<string, unknown>, path: string): unknown {\n const keys = path.split('.')\n let result: unknown = obj\n\n for (const key of keys) {\n if (result && typeof result === 'object' && key in result) {\n result = (result as Record<string, unknown>)[key]\n } else {\n return undefined\n }\n }\n\n return result\n}\n","/** Check if the code is running in development mode. */\nexport const isDevelopment = process.env.NODE_ENV === 'development'\n\n/** Check if the code is running in production mode. */\nexport const isProduction = process.env.NODE_ENV === 'production'\n\n/** Check if the code is running in test mode. */\nexport const isTest = process.env.NODE_ENV === 'test'\n","/**\n * Check if the current platform is macOS.\n */\nexport const isMac =\n typeof navigator !== 'undefined' && navigator.platform.toUpperCase().includes('MAC')\n\n/**\n * Get the modifier key symbol based on the current platform.\n *\n * @returns '⌘' for macOS, 'Ctrl' for other platforms\n *\n * @example\n * ```ts\n * // On macOS\n * `Press ${modKey}+S to save` // => 'Press ⌘+S to save'\n *\n * // On Windows/Linux\n * `Press ${modKey}+S to save` // => 'Press Ctrl+S to save'\n * ```\n */\nexport const modKey = isMac ? '⌘' : 'Ctrl'\n","/** Check if the code is running on the client. */\nexport const isClient = typeof window !== 'undefined'\n\n/** Check if the code is running on the server. */\nexport const isServer = typeof window === 'undefined'\n","/**\n * Converts any value to a string representation (primitives as-is, objects as JSON).\n *\n * @param value - The value to convert to a string\n * @returns A string representation of the value\n *\n * @example\n * ```ts\n * stringifyValue(null)\n * // => ''\n *\n * stringifyValue(undefined)\n * // => ''\n *\n * stringifyValue('hello')\n * // => 'hello'\n *\n * stringifyValue(42)\n * // => '42'\n *\n * stringifyValue(true)\n * // => 'true'\n *\n * stringifyValue({ name: 'John', age: 30 })\n * // => '{\"name\":\"John\",\"age\":30}'\n *\n * stringifyValue([1, 2, 3])\n * // => '[1,2,3]'\n * ```\n */\nexport function stringifyValue(value: unknown): string {\n if (value === null || value === undefined) {\n return ''\n }\n\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n return String(value)\n }\n\n return JSON.stringify(value)\n}\n","/**\n * Truncates a string to a specified length and adds an ellipsis if needed.\n *\n * @param str - The string to truncate\n * @param length - The maximum length before truncation (excluding ellipsis)\n * @returns The truncated string with '...' appended, or the original if short enough\n *\n * @example\n * ```ts\n * truncate('Hello, World!', 5)\n * // => 'Hello...'\n *\n * truncate('Short', 10)\n * // => 'Short'\n *\n * // Perfect for long descriptions in UI\n * const description = 'This is a very long description that needs truncation'\n * truncate(description, 20)\n * // => 'This is a very long ...'\n * ```\n */\nexport function truncate(str: string, length: number): string {\n if (str.length <= length) {\n return str\n }\n\n return `${str.slice(0, length)}...`\n}\n","/**\n * Formats a value into a human-readable display string.\n *\n * @param value - The value to format\n * @returns Formatted string representation for display\n *\n * @example\n * ```ts\n * valueToDisplayString(null) // 'null'\n * valueToDisplayString(undefined) // 'undefined'\n * valueToDisplayString(true) // 'true'\n * valueToDisplayString('hello') // 'hello'\n * valueToDisplayString(42) // '42'\n * valueToDisplayString([1, 2, 3]) // 'Array(3)'\n * valueToDisplayString({ a: 1, b: 2 }) // 'Object(2)'\n * ```\n */\nexport function valueToDisplayString(value: unknown): string {\n if (value === null) {\n return 'null'\n }\n if (value === undefined) {\n return 'undefined'\n }\n if (typeof value === 'boolean') {\n return value ? 'true' : 'false'\n }\n if (typeof value === 'string') {\n return value\n }\n if (typeof value === 'number') {\n return String(value)\n }\n if (Array.isArray(value)) {\n return `Array(${value.length})`\n }\n if (typeof value === 'object') {\n return `Object(${Object.keys(value as Record<string, unknown>).length})`\n }\n // Fallback for symbols, bigint, etc.\n return String(value as string | number | boolean)\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,85 @@
1
+ {
2
+ "name": "@getdashfy/utils",
3
+ "version": "0.1.0",
4
+ "description": "Formatting and utility functions for Dashfy - numbers, currencies, bytes, dates, times, strings, platform detection, and more",
5
+ "keywords": [
6
+ "dashfy",
7
+ "utils",
8
+ "format",
9
+ "bytes",
10
+ "currency",
11
+ "date",
12
+ "exponential",
13
+ "list",
14
+ "number",
15
+ "ordinal",
16
+ "percent",
17
+ "temperature",
18
+ "time",
19
+ "error",
20
+ "function",
21
+ "object",
22
+ "platform",
23
+ "string"
24
+ ],
25
+ "homepage": "https://github.com/dashfy/dashfy#readme",
26
+ "bugs": {
27
+ "url": "https://github.com/dashfy/dashfy/issues"
28
+ },
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git@github.com:dashfy/dashfy.git",
32
+ "directory": "packages/utils"
33
+ },
34
+ "license": "AGPL-3.0-or-later",
35
+ "author": {
36
+ "name": "Breno Polanski",
37
+ "email": "breno@dashfy.dev",
38
+ "url": "https://github.com/brenopolanski"
39
+ },
40
+ "type": "module",
41
+ "exports": {
42
+ ".": {
43
+ "types": "./dist/index.d.ts",
44
+ "import": "./dist/index.js",
45
+ "require": "./dist/index.cjs"
46
+ }
47
+ },
48
+ "main": "./dist/index.cjs",
49
+ "module": "./dist/index.js",
50
+ "types": "./dist/index.d.ts",
51
+ "files": [
52
+ "dist",
53
+ "README.md",
54
+ "LICENSE",
55
+ "CHANGELOG.md"
56
+ ],
57
+ "publishConfig": {
58
+ "access": "public"
59
+ },
60
+ "engines": {
61
+ "node": ">=20.0.0"
62
+ },
63
+ "scripts": {
64
+ "build": "tsup",
65
+ "check:circular": "madge --circular --extensions ts src/",
66
+ "clean": "rm -rf .turbo dist node_modules",
67
+ "dev": "tsup --watch",
68
+ "test": "vitest run",
69
+ "test:coverage": "vitest run --coverage",
70
+ "test:watch": "vitest",
71
+ "typecheck": "tsc --noEmit"
72
+ },
73
+ "dependencies": {
74
+ "date-fns": "^4.1.0",
75
+ "pretty-bytes": "^7.1.0"
76
+ },
77
+ "devDependencies": {
78
+ "@getdashfy/tsconfig": "workspace:*",
79
+ "@types/node": "^25.0.0",
80
+ "@vitest/coverage-v8": "^2.1.9",
81
+ "tsup": "^8.3.5",
82
+ "typescript": "^5.7.2",
83
+ "vitest": "^2.1.8"
84
+ }
85
+ }