@valkyriestudios/utils 12.19.0 → 12.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +384 -161
  2. package/array/dedupe.d.ts +0 -2
  3. package/array/groupBy.d.ts +0 -1
  4. package/array/is.d.ts +1 -3
  5. package/array/isNotEmpty.d.ts +1 -3
  6. package/array/join.d.ts +0 -2
  7. package/array/join.js +3 -2
  8. package/array/mapFn.js +1 -1
  9. package/array/mapPrimitive.d.ts +0 -2
  10. package/array/sort.d.ts +0 -2
  11. package/array/split.d.ts +0 -2
  12. package/boolean/is.d.ts +1 -3
  13. package/date/addUTC.d.ts +5 -6
  14. package/date/diff.d.ts +5 -6
  15. package/date/endOfUTC.d.ts +4 -5
  16. package/date/format.d.ts +16 -2
  17. package/date/format.js +175 -73
  18. package/date/index.d.ts +3 -1
  19. package/date/index.js +6 -1
  20. package/date/is.d.ts +1 -3
  21. package/date/isFormat.d.ts +11 -0
  22. package/date/isFormat.js +110 -0
  23. package/date/isLeap.d.ts +7 -0
  24. package/date/isLeap.js +11 -0
  25. package/date/nowUnix.d.ts +0 -2
  26. package/date/nowUnixMs.d.ts +0 -2
  27. package/date/setTimeUTC.d.ts +1 -2
  28. package/date/startOfUTC.d.ts +4 -5
  29. package/date/toUTC.d.ts +1 -3
  30. package/date/toUnix.d.ts +1 -3
  31. package/deep/freeze.d.ts +1 -3
  32. package/deep/get.d.ts +5 -7
  33. package/deep/seal.d.ts +1 -3
  34. package/deep/set.d.ts +0 -1
  35. package/equal.d.ts +2 -4
  36. package/formdata/index.d.ts +2 -1
  37. package/formdata/index.js +3 -1
  38. package/formdata/is.d.ts +1 -3
  39. package/formdata/toObject.d.ts +16 -0
  40. package/formdata/toObject.js +23 -0
  41. package/function/is.d.ts +1 -3
  42. package/function/isAsync.d.ts +1 -3
  43. package/function/noop.d.ts +0 -2
  44. package/function/noop.js +1 -2
  45. package/function/noopresolve.d.ts +0 -2
  46. package/function/noopreturn.d.ts +0 -2
  47. package/function/sleep.d.ts +1 -3
  48. package/hash/fnv1A.d.ts +2 -4
  49. package/hash/fnv1A.js +2 -2
  50. package/hash/guid.d.ts +0 -2
  51. package/index.d.ts +41 -10
  52. package/number/is.d.ts +1 -3
  53. package/number/isAbove.d.ts +2 -4
  54. package/number/isAboveOrEqual.d.ts +2 -4
  55. package/number/isBelow.d.ts +2 -4
  56. package/number/isBelowOrEqual.d.ts +2 -4
  57. package/number/isBetween.d.ts +3 -5
  58. package/number/isBetween.js +4 -6
  59. package/number/isInteger.d.ts +1 -3
  60. package/number/isIntegerAbove.d.ts +2 -4
  61. package/number/isIntegerAboveOrEqual.d.ts +2 -4
  62. package/number/isIntegerBelow.d.ts +2 -4
  63. package/number/isIntegerBelowOrEqual.d.ts +2 -4
  64. package/number/isIntegerBetween.d.ts +3 -5
  65. package/number/isIntegerBetween.js +4 -6
  66. package/number/isNumericalNaN.d.ts +1 -3
  67. package/number/randomBetween.d.ts +2 -4
  68. package/number/randomIntBetween.d.ts +2 -4
  69. package/number/round.d.ts +2 -4
  70. package/number/round.js +5 -3
  71. package/number/toPercentage.d.ts +4 -6
  72. package/object/define.d.ts +0 -2
  73. package/object/is.d.ts +1 -3
  74. package/object/isNotEmpty.d.ts +2 -6
  75. package/object/merge.d.ts +2 -4
  76. package/object/merge.js +2 -3
  77. package/object/pick.d.ts +0 -2
  78. package/object/pick.js +2 -3
  79. package/package.json +1 -1
  80. package/regexp/is.d.ts +1 -3
  81. package/regexp/sanitize.d.ts +1 -3
  82. package/regexp/sanitize.js +2 -1
  83. package/string/humanizeBytes.d.ts +1 -3
  84. package/string/humanizeBytes.js +5 -11
  85. package/string/humanizeNumber.d.ts +2 -4
  86. package/string/humanizeNumber.js +13 -15
  87. package/string/is.d.ts +1 -3
  88. package/string/isBetween.d.ts +4 -6
  89. package/string/isNotEmpty.d.ts +2 -4
  90. package/string/shorten.d.ts +0 -2
  91. package/string/shorten.js +1 -4
package/array/dedupe.d.ts CHANGED
@@ -9,8 +9,6 @@ type DedupeOptions<T> = {
9
9
  *
10
10
  * @param {Array} val - Array to dedupe
11
11
  * @param {DedupeOptions?} opts - Dedupe options
12
- *
13
- * @returns Deduped array
14
12
  */
15
13
  declare function dedupe<T>(val: T[], opts?: DedupeOptions<T>): T[];
16
14
  export { dedupe, dedupe as default };
@@ -17,7 +17,6 @@ type Handler<T> = (val: T) => string | number | boolean;
17
17
  *
18
18
  * @param {T[]} arr - Array to group
19
19
  * @param {Handler<T>|keyof T} handler - String or a function, determines what to group by
20
- * @returns {Record<string, T[]>}
21
20
  */
22
21
  declare function groupBy<T extends Record<string, any>>(arr: T[], handler: Handler<T> | keyof T): Record<string, T[]>;
23
22
  export { groupBy, groupBy as default };
package/array/is.d.ts CHANGED
@@ -1,9 +1,7 @@
1
1
  /**
2
2
  * Check whether or not a provided value is an array
3
3
  *
4
- * @param val - Value to verify
5
- *
6
- * @returns Whether or not the value is an array
4
+ * @param {unknown} val - Value to verify
7
5
  */
8
6
  declare function isArray(val: unknown): val is unknown[];
9
7
  export { isArray, isArray as default };
@@ -1,9 +1,7 @@
1
1
  /**
2
2
  * Check whether or not a provided value is an array with content
3
3
  *
4
- * @param val - Value to verify
5
- *
6
- * @returns Whether or not the value is an array with content
4
+ * @param {unknown} val - Value to verify
7
5
  */
8
6
  declare function isNotEmptyArray(val: unknown): val is unknown[];
9
7
  export { isNotEmptyArray, isNotEmptyArray as default };
package/array/join.d.ts CHANGED
@@ -35,8 +35,6 @@ interface joinOptions {
35
35
  *
36
36
  * @param {unknown[]} val - Array of values to join
37
37
  * @param {joinOptions?} opts - Join options
38
- *
39
- * @returns Joined array as string
40
38
  */
41
39
  declare function join(val: unknown[], opts?: joinOptions): string;
42
40
  export { join, join as default };
package/array/join.js CHANGED
@@ -4,6 +4,7 @@ exports.join = join;
4
4
  exports.default = join;
5
5
  const round_1 = require("../number/round");
6
6
  const isIntegerAboveOrEqual_1 = require("../number/isIntegerAboveOrEqual");
7
+ const SPACE_RGX = /(\s){2,}/g;
7
8
  function join(val, opts) {
8
9
  if (!Array.isArray(val) || !val.length)
9
10
  return '';
@@ -18,11 +19,11 @@ function join(val, opts) {
18
19
  const el = val[i];
19
20
  if (typeof el === 'string' && el.trim().length) {
20
21
  const trimmed = VALTRIM ? el.trim() : el;
21
- result = `${result}${hasVal ? DELIM : ''}${INNERTRIM ? trimmed.replace(/(\s){2,}/g, ' ') : trimmed}`;
22
+ result = result + (hasVal ? DELIM : '') + (INNERTRIM ? trimmed.replace(SPACE_RGX, ' ') : trimmed);
22
23
  hasVal = true;
23
24
  }
24
25
  else if (Number.isFinite(el)) {
25
- result = `${result}${hasVal ? DELIM : ''}${VALROUND !== false ? (0, round_1.round)(el, VALROUND) : el}`;
26
+ result = result + (hasVal ? DELIM : '') + (VALROUND !== false ? (0, round_1.round)(el, VALROUND) : el);
26
27
  hasVal = true;
27
28
  }
28
29
  }
package/array/mapFn.js CHANGED
@@ -16,7 +16,7 @@ function mapFn(arr, fn, opts) {
16
16
  hash = fn(el);
17
17
  if (!Number.isFinite(hash) && !(typeof hash === 'string' && hash.trim().length))
18
18
  continue;
19
- hash = `${hash}`;
19
+ hash = hash + '';
20
20
  map[hash] = MERGE && map[hash] !== undefined ? { ...map[hash], ...el } : el;
21
21
  }
22
22
  return map;
@@ -31,8 +31,6 @@ type mapReturn = Record<string, string | number>;
31
31
  *
32
32
  * @param {unknown[]} val - Array to map
33
33
  * @param {mapOptions?} opts - Options object to override built-in defaults
34
- *
35
- * @returns {mapReturn} KV-Map object
36
34
  */
37
35
  declare function mapPrimitive(arr: unknown[], opts?: mapOptions): mapReturn;
38
36
  export { mapPrimitive, mapPrimitive as default };
package/array/sort.d.ts CHANGED
@@ -54,8 +54,6 @@ type sortByFunction = (el: Record<string, any>) => string;
54
54
  * @param {string|sortByFunction} by - Either a string (key) or a function
55
55
  * @param {'desc'|'asc'} dir - (default='asc') Direction to sort in (asc or desc)
56
56
  * @param {sortOptions} opts - Sort options
57
- *
58
- * @returns Sorted array
59
57
  * @throws {Error}
60
58
  */
61
59
  declare function sort<T extends {
package/array/split.d.ts CHANGED
@@ -12,8 +12,6 @@ type SplitOptions<T> = {
12
12
  * @param {Array} val - Array to split
13
13
  * @param {number} size - Size of batches
14
14
  * @param {SplitOptions?} opts - Split options
15
- *
16
- * @returns Split batches
17
15
  */
18
16
  declare function split<T>(arr: T[], size: number, opts?: SplitOptions<T>): T[][];
19
17
  export { split, split as default };
package/boolean/is.d.ts CHANGED
@@ -1,9 +1,7 @@
1
1
  /**
2
2
  * Check whether or not a provided value is a boolean
3
3
  *
4
- * @param val - Value to verify
5
- *
6
- * @returns Whether or not the value is a boolean
4
+ * @param {unknown} val - Value to verify
7
5
  */
8
6
  declare function isBoolean(val: unknown): val is boolean;
9
7
  export { isBoolean, isBoolean as default };
package/date/addUTC.d.ts CHANGED
@@ -1,11 +1,10 @@
1
+ export type AddUTCKey = 'years' | 'year' | 'months' | 'month' | 'days' | 'day' | 'hours' | 'hour' | 'minutes' | 'minute' | 'seconds' | 'second' | 'milliseconds' | 'millisecond';
1
2
  /**
2
3
  * Adds the provided amount of a specific key to the provided date
3
4
  *
4
- * @param val - Date to set to end of
5
- * @param amount - (default=0) Amount of key to add
6
- * @param key - (default='millisecond') Key to set
7
- *
8
- * @returns New date with provided amount of key added
5
+ * @param {Date} val - Date to set to end of
6
+ * @param {number} amount - (default=0) Amount of key to add
7
+ * @param {AddUTCKey} key - (default='millisecond') Key to set
9
8
  */
10
- declare function addUTC(val: Date, amt?: number, key?: 'years' | 'year' | 'months' | 'month' | 'days' | 'day' | 'hours' | 'hour' | 'minutes' | 'minute' | 'seconds' | 'second' | 'milliseconds' | 'millisecond'): Date;
9
+ declare function addUTC(val: Date, amt?: number, key?: AddUTCKey): Date;
11
10
  export { addUTC, addUTC as default };
package/date/diff.d.ts CHANGED
@@ -1,11 +1,10 @@
1
+ export type DiffKey = 'week' | 'weeks' | 'day' | 'days' | 'hour' | 'hours' | 'minute' | 'minutes' | 'second' | 'seconds' | 'millisecond' | 'milliseconds';
1
2
  /**
2
3
  * Compute the diff between two dates in the provided key
3
4
  *
4
- * @param val_a - Date to diff against
5
- * @param val_b - Date to diff with
6
- * @param key - (default='millisecond') Key to diff in
7
- *
8
- * @returns Numerical diff between two dates
5
+ * @param {Date} val_a - Date to diff against
6
+ * @param {Date} val_b - Date to diff with
7
+ * @param {DiffKey} key - (default='millisecond') Key to diff in
9
8
  */
10
- declare function diff(val_a: Date, val_b: Date, key?: 'week' | 'weeks' | 'day' | 'days' | 'hour' | 'hours' | 'minute' | 'minutes' | 'second' | 'seconds' | 'millisecond' | 'milliseconds'): number;
9
+ declare function diff(val_a: Date, val_b: Date, key?: DiffKey): number;
11
10
  export { diff, diff as default };
@@ -1,10 +1,9 @@
1
+ export type EndOfUTCKey = 'year' | 'quarter' | 'month' | 'week' | 'week_sun' | 'week_mon' | 'week_tue' | 'week_wed' | 'week_thu' | 'week_fri' | 'week_sat' | 'day' | 'hour' | 'minute' | 'second' | 'millisecond';
1
2
  /**
2
3
  * Sets the provided date to end of UTC of provided key
3
4
  *
4
- * @param val - Date to set to end of
5
- * @param key - (default='millisecond') Key to set
6
- *
7
- * @returns New date set to end of key
5
+ * @param {Date} val - Date to set to end of
6
+ * @param {EndOfUTCKey} key - (default='millisecond') Key to set
8
7
  */
9
- declare function endOfUTC(val: Date, key?: 'year' | 'quarter' | 'month' | 'week' | 'week_sun' | 'week_mon' | 'week_tue' | 'week_wed' | 'week_thu' | 'week_fri' | 'week_sat' | 'day' | 'hour' | 'minute' | 'second' | 'millisecond'): Date;
8
+ declare function endOfUTC(val: Date, key?: EndOfUTCKey): Date;
10
9
  export { endOfUTC, endOfUTC as default };
package/date/format.d.ts CHANGED
@@ -1,3 +1,9 @@
1
+ declare const WEEK_STARTS: {
2
+ readonly mon: "mon";
3
+ readonly sun: "sun";
4
+ readonly sat: "sat";
5
+ };
6
+ export type WEEK_START = keyof typeof WEEK_STARTS;
1
7
  /**
2
8
  * Formats the provided date according to a specific spec
3
9
  *
@@ -5,8 +11,16 @@
5
11
  * @param {string} spec - Spec to format the date to
6
12
  * @param {string} locale - Locale to format the date in (only used in certain tokens such as dddd and MMMM)
7
13
  * @param {string} zone - (default=current timezone) Pass the timezone to convert into. If not passed no conversion will happen
8
- * @returns {string} Formatted date as string
14
+ * @param {string} sow - (default='mon') Start of week (only useful when working with the 'W' and 'w' tokens for week numbers
9
15
  * @throws {TypeError} When provided invalid payload
10
16
  */
11
- declare function format(val: Date, spec: string, locale?: string, zone?: string): string;
17
+ declare function format(val: Date, spec: string, locale?: string, zone?: string, sow?: WEEK_START): string;
18
+ declare namespace format {
19
+ var getLocale: () => string;
20
+ var setLocale: (locale: string) => void;
21
+ var getZone: () => string;
22
+ var setZone: (zone: string) => void;
23
+ var getStartOfWeek: () => "mon" | "sun" | "sat";
24
+ var setStartOfWeek: (sow: WEEK_START) => void;
25
+ }
12
26
  export { format, format as default };
package/date/format.js CHANGED
@@ -3,8 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.format = format;
4
4
  exports.default = format;
5
5
  const is_1 = require("./is");
6
- const DEFAULT_LOCALE = 'en-US';
6
+ const WEEK_STARTS = {
7
+ mon: 'mon',
8
+ sun: 'sun',
9
+ sat: 'sat',
10
+ };
11
+ let DEFAULT_LOCALE = 'en-US';
7
12
  let DEFAULT_TZ = 'UTC';
13
+ let DEFAULT_SOW = 'mon';
8
14
  try {
9
15
  DEFAULT_TZ = Intl.DateTimeFormat().resolvedOptions().timeZone;
10
16
  }
@@ -14,37 +20,61 @@ finally {
14
20
  if (typeof DEFAULT_TZ !== 'string')
15
21
  DEFAULT_TZ = 'UTC';
16
22
  }
17
- const escape_rgx = /\[[\s\S]+?]/g;
18
- const intl_formatters = new Map();
19
- const spec_cache = new Map();
20
- const zone_offset_cache = new Map();
21
- function DOY(d) {
22
- return ((d - new Date(d.getFullYear(), 0, 0)) / 86400000) | 0;
23
+ const ESCAPE_RGX = /\[[\s\S]+?]/g;
24
+ const intl_formatters = Object.create(null);
25
+ const spec_cache = Object.create(null);
26
+ const zone_offset_cache = Object.create(null);
27
+ function WeekNr(d, sow) {
28
+ const date = new Date(d.valueOf());
29
+ switch (sow) {
30
+ case 'sun':
31
+ case 'sat': {
32
+ const OFFSET = sow === 'sat' ? 1 : 0;
33
+ const jan1 = new Date(Date.UTC(date.getUTCFullYear(), 0, 1));
34
+ const near = new Date(date.getTime() - (((date.getDay() + OFFSET) % 7) * 86400000));
35
+ const first = new Date(jan1.getTime() - (((jan1.getDay() + OFFSET) % 7) * 86400000));
36
+ return 1 + Math.floor((near.valueOf() - first.valueOf()) / 604800000);
37
+ }
38
+ default: {
39
+ date.setDate(date.getDate() - ((d.getDay() + 6) % 7) + 3);
40
+ const date_thu = date.valueOf();
41
+ date.setMonth(0, 1);
42
+ if (date.getDay() !== 4)
43
+ date.setMonth(0, (1 + ((4 - date.getDay()) + 7)) % 7);
44
+ return 1 + Math.ceil((date_thu - date.valueOf()) / 604800000);
45
+ }
46
+ }
23
47
  }
24
- function toZone(date, zone) {
25
- const ckey = `${zone}:${date.getUTCFullYear()}${DOY(date)}`;
26
- if (zone_offset_cache.has(ckey))
27
- return new Date(date.getTime() + zone_offset_cache.get(ckey));
28
- const client_time = date.getTime();
29
- let zone_time = false;
48
+ function toZone(d, zone) {
49
+ const year = d.getUTCFullYear();
50
+ const month = d.getUTCMonth();
51
+ const day = d.getUTCDate();
52
+ const time = d.getTime();
53
+ const daysInMonths = [31, (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
54
+ let doy = day;
55
+ for (let i = 0; i <= month; i++)
56
+ doy += daysInMonths[i];
57
+ const ckey = zone + ':' + year + ':' + doy;
58
+ if (zone_offset_cache[ckey] !== undefined)
59
+ return new Date(time + zone_offset_cache[ckey]);
60
+ let zone_time = null;
30
61
  try {
31
- zone_time = new Date(date.toLocaleString(DEFAULT_LOCALE, { timeZone: zone })).getTime();
62
+ zone_time = new Date(d.toLocaleString(DEFAULT_LOCALE, { timeZone: zone })).getTime();
32
63
  }
33
64
  catch (err) {
34
- }
35
- if (!Number.isInteger(zone_time))
36
65
  throw new Error(`format: Invalid zone passed - ${zone}`);
37
- const offset = zone_time - client_time;
38
- zone_offset_cache.set(ckey, offset);
39
- return new Date(client_time + offset);
66
+ }
67
+ const offset = zone_time - time;
68
+ zone_offset_cache[ckey] = offset;
69
+ return new Date(time + offset);
40
70
  }
41
71
  function runIntl(loc, token, props, val) {
42
- const hash = `${loc}:${token}`;
43
- let formatter = intl_formatters.get(hash);
72
+ const hash = loc + ':' + token;
73
+ let formatter = intl_formatters[hash];
44
74
  if (!formatter) {
45
75
  try {
46
76
  formatter = new Intl.DateTimeFormat(loc, props);
47
- intl_formatters.set(hash, formatter);
77
+ intl_formatters[hash] = formatter;
48
78
  }
49
79
  catch (err) {
50
80
  throw new Error(`format: Failed to run conversion for ${token} with locale ${loc}`);
@@ -57,21 +87,51 @@ const Tokens = [
57
87
  ['Q', d => ((d.getMonth() + 3) / 3) | 0],
58
88
  ['MMMM', (d, loc) => runIntl(loc, 'MMMM', { month: 'long' }, d)],
59
89
  ['MMM', (d, loc) => runIntl(loc, 'MMM', { month: 'short' }, d)],
60
- ['MM', d => `${d.getMonth() + 1}`.padStart(2, '0')],
90
+ ['MM', d => {
91
+ const val = d.getMonth() + 1;
92
+ return (val < 10 ? '0' : '') + val;
93
+ }],
61
94
  ['M', d => d.getMonth() + 1],
62
- ['DD', d => `${d.getDate()}`.padStart(2, '0')],
95
+ ['WW', (d, loc, sow) => {
96
+ const val = WeekNr(d, sow);
97
+ return (val < 10 ? '0' : '') + val;
98
+ }],
99
+ ['W', (d, loc, sow) => WeekNr(d, sow)],
100
+ ['DD', d => {
101
+ const val = d.getDate();
102
+ return (val < 10 ? '0' : '') + val;
103
+ }],
63
104
  ['D', d => d.getDate()],
64
105
  ['dddd', (d, loc) => runIntl(loc, 'dddd', { weekday: 'long' }, d)],
65
106
  ['ddd', (d, loc) => runIntl(loc, 'ddd', { weekday: 'short' }, d)],
66
- ['HH', d => `${d.getHours()}`.padStart(2, '0')],
107
+ ['HH', d => {
108
+ const val = d.getHours();
109
+ return (val < 10 ? '0' : '') + val;
110
+ }],
67
111
  ['H', d => d.getHours()],
68
- ['hh', d => `${((d.getHours() + 11) % 12) + 1}`.padStart(2, '0')],
112
+ ['hh', d => {
113
+ const val = ((d.getHours() + 11) % 12) + 1;
114
+ return (val < 10 ? '0' : '') + val;
115
+ }],
69
116
  ['h', d => ((d.getHours() + 11) % 12) + 1],
70
- ['mm', d => `${d.getMinutes()}`.padStart(2, '0')],
117
+ ['mm', d => {
118
+ const val = d.getMinutes();
119
+ return (val < 10 ? '0' : '') + val;
120
+ }],
71
121
  ['m', d => d.getMinutes()],
72
- ['ss', d => `${d.getSeconds()}`.padStart(2, '0')],
122
+ ['ss', d => {
123
+ const val = d.getSeconds();
124
+ return (val < 10 ? '0' : '') + val;
125
+ }],
73
126
  ['s', d => d.getSeconds()],
74
- ['SSS', d => `${d.getMilliseconds()}`.padStart(3, '0')],
127
+ ['SSS', d => {
128
+ const val = d.getMilliseconds();
129
+ return val < 10
130
+ ? '00' + val
131
+ : val < 100
132
+ ? '0' + val
133
+ : val;
134
+ }],
75
135
  ['A', d => d.getHours() < 12 ? 'AM' : 'PM'],
76
136
  ['a', d => d.getHours() < 12 ? 'am' : 'pm'],
77
137
  ['l', (d, loc) => runIntl(loc, 'l', { dateStyle: 'short' }, d)],
@@ -79,58 +139,100 @@ const Tokens = [
79
139
  ['t', (d, loc) => runIntl(loc, 't', { timeStyle: 'short' }, d)],
80
140
  ['T', (d, loc) => runIntl(loc, 'T', { timeStyle: 'medium' }, d)],
81
141
  ]
82
- .sort((a, b) => a[0].length > b[0].length ? -1 : 1)
83
- .map((el) => [el[0], new RegExp(el[0], 'g'), el[1]]);
142
+ .map(el => [el[0], el[1], el[0].length])
143
+ .sort((a, b) => a[0].length > b[0].length ? -1 : 1);
84
144
  function getSpecChain(spec) {
85
- let spec_chain = spec_cache.get(spec);
86
- if (spec_chain)
87
- return spec_chain;
88
- spec_chain = [];
89
- let cursor;
90
- let spec_cursor = spec;
145
+ if (spec_cache[spec] !== undefined)
146
+ return spec_cache[spec];
147
+ let base = spec;
148
+ const repl = [];
149
+ let repl_len = 0;
150
+ if (base.indexOf('[') >= 0) {
151
+ base = base.replace(ESCAPE_RGX, match => {
152
+ const escape_token = '$R' + repl_len++ + '$';
153
+ repl.push([escape_token, match.slice(1, -1)]);
154
+ return escape_token;
155
+ });
156
+ }
157
+ const chain = [];
158
+ const matched_positions = new Set();
91
159
  for (let i = 0; i < Tokens.length; i++) {
92
- cursor = Tokens[i];
93
- if (spec_cursor.indexOf(cursor[0]) < 0)
94
- continue;
95
- spec_chain.push(cursor);
96
- spec_cursor = spec_cursor.replace(cursor[1], '');
160
+ const [token] = Tokens[i];
161
+ let pos = base.indexOf(token);
162
+ const token_len = token.length;
163
+ while (pos !== -1) {
164
+ if (!matched_positions.has(pos)) {
165
+ chain.push(Tokens[i]);
166
+ for (let j = 0; j < token_len; j++) {
167
+ matched_positions.add(pos + j);
168
+ }
169
+ }
170
+ pos = base.indexOf(token, pos + 1);
171
+ }
97
172
  }
98
- if (spec_chain.length === 0)
99
- return false;
100
- spec_cache.set(spec, spec_chain);
101
- return spec_chain;
173
+ const chain_len = chain.length;
174
+ const result = chain_len ? { base, chain, chain_len, repl, repl_len } : null;
175
+ spec_cache[spec] = result;
176
+ return result;
102
177
  }
103
- function format(val, spec, locale = DEFAULT_LOCALE, zone = DEFAULT_TZ) {
178
+ function format(val, spec, locale = DEFAULT_LOCALE, zone = DEFAULT_TZ, sow = DEFAULT_SOW) {
104
179
  if (!(0, is_1.isDate)(val))
105
180
  throw new TypeError('format: val must be a Date');
106
- if (typeof spec !== 'string' || !spec.trim().length)
107
- throw new TypeError('format: spec must be a non-empty string');
108
- if (typeof locale !== 'string' || !locale.trim().length)
109
- throw new TypeError('format: locale must be a non-empty string');
110
- if (typeof zone !== 'string' || !zone.trim().length)
111
- throw new TypeError('format: zone must be a non-empty string');
112
- let formatted_string = spec;
113
- const escaped_acc = [];
114
- if (formatted_string.indexOf('[') >= 0) {
115
- formatted_string = formatted_string.replace(escape_rgx, match => {
116
- const escape_token = `$R${escaped_acc.length}$`;
117
- escaped_acc.push([escape_token, match.replace('[', '').replace(']', '')]);
118
- return escape_token;
119
- });
120
- }
121
- const spec_chain = getSpecChain(formatted_string);
122
- if (!spec_chain)
181
+ if (typeof spec !== 'string')
182
+ throw new TypeError('format: spec must be a string');
183
+ if (typeof locale !== 'string')
184
+ throw new TypeError('format: locale must be a string');
185
+ if (typeof zone !== 'string')
186
+ throw new TypeError('format: zone must be a string');
187
+ const n_spec = getSpecChain(spec);
188
+ if (!n_spec)
123
189
  return val.toISOString();
124
190
  const d = toZone(val, zone);
125
- for (let i = 0; i < spec_chain.length; i++) {
126
- const el = spec_chain[i];
127
- formatted_string = formatted_string.replace(el[1], el[2](d, locale));
128
- }
129
- if (escaped_acc.length) {
130
- for (let i = 0; i < escaped_acc.length; i++) {
131
- const escape_token = escaped_acc[i];
132
- formatted_string = formatted_string.replace(escape_token[0], escape_token[1]);
191
+ let base = n_spec.base;
192
+ const { chain_len, chain, repl_len, repl } = n_spec;
193
+ for (let i = 0; i < chain_len; i++) {
194
+ let pos = base.indexOf(chain[i][0]);
195
+ const formatted_val = chain[i][1](d, locale, sow);
196
+ while (pos !== -1) {
197
+ base = base.slice(0, pos) +
198
+ formatted_val +
199
+ base.slice(pos + chain[i][2]);
200
+ pos = base.indexOf(chain[i][0], pos + chain[i][2]);
133
201
  }
134
202
  }
135
- return formatted_string;
203
+ for (let i = 0; i < repl_len; i++) {
204
+ base = base.replace(repl[i][0], repl[i][1]);
205
+ }
206
+ return base;
136
207
  }
208
+ format.getLocale = function () {
209
+ return DEFAULT_LOCALE;
210
+ };
211
+ format.setLocale = function (locale) {
212
+ if (typeof locale !== 'string' || !locale.trim().length)
213
+ throw new Error('format/setLocale: locale should be a string');
214
+ DEFAULT_LOCALE = locale.trim();
215
+ };
216
+ format.getZone = function () {
217
+ return DEFAULT_TZ;
218
+ };
219
+ format.setZone = function (zone) {
220
+ if (typeof zone !== 'string')
221
+ throw new Error('format/setZone: zone should be a string');
222
+ try {
223
+ new Intl.DateTimeFormat('en-US', { timeZone: zone });
224
+ DEFAULT_TZ = zone;
225
+ }
226
+ catch {
227
+ throw new Error(`format/setZone: '${zone}' is not a valid zone`);
228
+ }
229
+ };
230
+ format.getStartOfWeek = function () {
231
+ return DEFAULT_SOW;
232
+ };
233
+ format.setStartOfWeek = function (sow) {
234
+ if (typeof sow !== 'string' ||
235
+ !Object.values(WEEK_STARTS).includes(sow))
236
+ throw new Error('format/setStartOfWeek: sow should be a valid start of week');
237
+ DEFAULT_SOW = sow;
238
+ };
package/date/index.d.ts CHANGED
@@ -2,11 +2,13 @@ import { addUTC } from './addUTC';
2
2
  import { diff } from './diff';
3
3
  import { endOfUTC } from './endOfUTC';
4
4
  import { format } from './format';
5
+ import { isDateFormat } from './isFormat';
5
6
  import { isDate } from './is';
7
+ import { isLeap } from './isLeap';
6
8
  import { nowUnix } from './nowUnix';
7
9
  import { nowUnixMs } from './nowUnixMs';
8
10
  import { setTimeUTC } from './setTimeUTC';
9
11
  import { startOfUTC } from './startOfUTC';
10
12
  import { toUnix } from './toUnix';
11
13
  import { toUTC } from './toUTC';
12
- export { addUTC, diff, endOfUTC, format, isDate, isDate as is, nowUnix, nowUnixMs, setTimeUTC, startOfUTC, toUnix, toUTC };
14
+ export { addUTC, diff, endOfUTC, format, isDateFormat as isFormat, isDateFormat, isDate, isDate as is, isLeap, nowUnix, nowUnixMs, setTimeUTC, startOfUTC, toUnix, toUTC };
package/date/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.toUTC = exports.toUnix = exports.startOfUTC = exports.setTimeUTC = exports.nowUnixMs = exports.nowUnix = exports.is = exports.isDate = exports.format = exports.endOfUTC = exports.diff = exports.addUTC = void 0;
3
+ exports.toUTC = exports.toUnix = exports.startOfUTC = exports.setTimeUTC = exports.nowUnixMs = exports.nowUnix = exports.isLeap = exports.is = exports.isDate = exports.isDateFormat = exports.isFormat = exports.format = exports.endOfUTC = exports.diff = exports.addUTC = void 0;
4
4
  const addUTC_1 = require("./addUTC");
5
5
  Object.defineProperty(exports, "addUTC", { enumerable: true, get: function () { return addUTC_1.addUTC; } });
6
6
  const diff_1 = require("./diff");
@@ -9,9 +9,14 @@ const endOfUTC_1 = require("./endOfUTC");
9
9
  Object.defineProperty(exports, "endOfUTC", { enumerable: true, get: function () { return endOfUTC_1.endOfUTC; } });
10
10
  const format_1 = require("./format");
11
11
  Object.defineProperty(exports, "format", { enumerable: true, get: function () { return format_1.format; } });
12
+ const isFormat_1 = require("./isFormat");
13
+ Object.defineProperty(exports, "isFormat", { enumerable: true, get: function () { return isFormat_1.isDateFormat; } });
14
+ Object.defineProperty(exports, "isDateFormat", { enumerable: true, get: function () { return isFormat_1.isDateFormat; } });
12
15
  const is_1 = require("./is");
13
16
  Object.defineProperty(exports, "isDate", { enumerable: true, get: function () { return is_1.isDate; } });
14
17
  Object.defineProperty(exports, "is", { enumerable: true, get: function () { return is_1.isDate; } });
18
+ const isLeap_1 = require("./isLeap");
19
+ Object.defineProperty(exports, "isLeap", { enumerable: true, get: function () { return isLeap_1.isLeap; } });
15
20
  const nowUnix_1 = require("./nowUnix");
16
21
  Object.defineProperty(exports, "nowUnix", { enumerable: true, get: function () { return nowUnix_1.nowUnix; } });
17
22
  const nowUnixMs_1 = require("./nowUnixMs");
package/date/is.d.ts CHANGED
@@ -1,9 +1,7 @@
1
1
  /**
2
2
  * Check whether or not a provided value is a Date
3
3
  *
4
- * @param val - Value to verify
5
- *
6
- * @returns Whether or not the value is a Date
4
+ * @param {unknown} val - Value to verify
7
5
  */
8
6
  declare function isDate(val: unknown): val is Date;
9
7
  export { isDate, isDate as default };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Checks if a given string is in a particular format
3
+ * Eg:
4
+ * isDateFormat('2024-02-09', 'YYYY-MM-DD'); // true
5
+ * isDateFormat('2024-02-09T14:30', 'YYYY-MM-DD'); // false
6
+ *
7
+ * @param {unknown} input - String to format (eg: '2024-08-01')
8
+ * @param {string} spec - Spec to validate (Eg: 'YYYY-MM-DD')
9
+ */
10
+ declare function isDateFormat(input: unknown, spec: string): input is string;
11
+ export { isDateFormat, isDateFormat as default };