atomic-fns 0.3.3 → 0.3.5

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 (48) hide show
  1. package/README.md +18 -4
  2. package/core/collections/LRUCache.d.ts +22 -1
  3. package/core/collections/LRUCache.js +22 -1
  4. package/core/collections/LRUCache.ts +22 -1
  5. package/core/collections/SortedMap.d.ts +1 -1
  6. package/core/collections/SortedMap.js +1 -1
  7. package/core/collections/SortedMap.ts +1 -1
  8. package/core/collections/SortedSet.d.ts +6 -0
  9. package/core/collections/SortedSet.js +6 -0
  10. package/core/collections/SortedSet.ts +6 -0
  11. package/core/collections/SortedTree.d.ts +3 -3
  12. package/core/collections/SortedTree.js +3 -3
  13. package/core/collections/SortedTree.ts +3 -3
  14. package/core/collections/abc.d.ts +1 -1
  15. package/core/collections/abc.ts +1 -1
  16. package/core/collections/deque.d.ts +55 -48
  17. package/core/collections/deque.js +61 -53
  18. package/core/collections/deque.ts +63 -54
  19. package/core/collections/index.d.ts +2 -0
  20. package/core/collections/index.js +7 -5
  21. package/core/collections/index.ts +7 -5
  22. package/core/functools/index.d.ts +3 -2
  23. package/core/functools/index.ts +8 -3
  24. package/core/globals/index.d.ts +23 -4
  25. package/core/globals/index.js +29 -6
  26. package/core/globals/index.ts +40 -7
  27. package/core/i18n/date/format.d.ts +16 -0
  28. package/core/i18n/date/format.js +307 -0
  29. package/core/i18n/date/format.ts +343 -0
  30. package/core/i18n/date/index.d.ts +224 -0
  31. package/core/i18n/date/index.js +387 -0
  32. package/core/i18n/date/index.ts +471 -0
  33. package/core/i18n/date/test.html +67 -0
  34. package/core/i18n/index.d.ts +7 -0
  35. package/core/i18n/index.js +7 -0
  36. package/core/i18n/index.ts +8 -0
  37. package/core/index.d.ts +1 -0
  38. package/core/index.js +1 -0
  39. package/core/index.ts +1 -0
  40. package/core/operators/index.d.ts +1 -1
  41. package/core/operators/index.js +35 -5
  42. package/core/operators/index.ts +34 -6
  43. package/package.json +11 -11
  44. package/tests/globals.spec.ts +12 -12
  45. package/tsconfig.json +2 -1
  46. package/core/datetime/index.d.ts +0 -45
  47. package/core/datetime/index.js +0 -71
  48. package/core/datetime/index.ts +0 -128
@@ -0,0 +1,471 @@
1
+ import { isObject } from '../../globals/index.js'
2
+ import { format, getDate } from './format.js'
3
+
4
+ let globalOptions
5
+
6
+ const systemOptions = () => {
7
+ if (!globalOptions) globalOptions = Intl.DateTimeFormat().resolvedOptions()
8
+ return globalOptions
9
+ }
10
+
11
+ const FORMAT_DEFAULT = 'YYYY-MM-DDTHH:mm:ssZ'
12
+
13
+ const INVALID_DATE_STRING = 'Invalid Date'
14
+
15
+ export type DateParts = {
16
+ year?: number
17
+ month?: number
18
+ day?: number
19
+ hour?: number
20
+ minute?: number
21
+ second?: number
22
+ millisecond?: number
23
+ }
24
+
25
+ type DateLike = number | string | Date | DateParts
26
+
27
+ /**
28
+ * Creates a date tied to a given locale (default system locale) which can be formatted in that locale's language using the native {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl Intl Apis} directly or using a formatting string compatible with `strftime`.
29
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl Intl Apis}
30
+ * @see {@link https://strftime.org/ strftime format}
31
+ */
32
+ export class IntlDate {
33
+ private self: Date
34
+ readonly year: number
35
+ readonly M: number
36
+ readonly day: number
37
+ readonly weekDay: number
38
+ readonly hour: number
39
+ readonly minute: number
40
+ readonly second: number
41
+ readonly millisecond: number
42
+ readonly locale: string
43
+
44
+ /** Returns the current UTC date and time. */
45
+ static UTC(obj: DateLike = {}) {
46
+ return new IntlDate(obj, { utc: true })
47
+ }
48
+
49
+ /** Returns the current local date and time.*/
50
+ static now() {
51
+ return new IntlDate()
52
+ }
53
+
54
+ /**
55
+ * Creates a new `IntlDate` tied to the specified locale (default is system locale).
56
+ * **Note:** The allowed values for `month` start at 1, which is different from legacy `Date`
57
+ * @param {DateLike | IntlDate} obj The date value (default is now)
58
+ * @param {{locale?: string, utc?: boolean}} opts
59
+ * @returns
60
+ */
61
+ constructor(obj?: DateLike | IntlDate, { locale, utc }: any = {}) {
62
+ // Set the default DateTime locale
63
+ this.locale = locale || systemOptions().locale
64
+ if (obj instanceof IntlDate) obj = obj.self
65
+
66
+ if (typeof obj === 'string' || typeof obj === 'number' || obj instanceof Date) {
67
+ this.self = getDate(obj, utc)
68
+ } else if (isObject(obj)) {
69
+ let { year, month, day, hour, minute, second, millisecond } = obj
70
+ // NOTE month is from 1-12, not from 0-11
71
+ if (typeof month === 'number') month -= 1
72
+ if (utc) {
73
+ // from UTC to current
74
+ this.self = new Date(Date.UTC(year!, month!, day, hour, minute, second, millisecond))
75
+ } else {
76
+ this.self = new Date(year!, month!, day, hour, minute, second, millisecond)
77
+ }
78
+ } else {
79
+ this.self = new Date()
80
+ }
81
+
82
+ this.year = this.self.getFullYear()
83
+ this.M = this.self.getMonth()
84
+ this.weekDay = this.self.getDay()
85
+ this.day = this.self.getDate()
86
+ this.hour = this.self.getHours()
87
+ this.minute = this.self.getMinutes()
88
+ this.second = this.self.getSeconds()
89
+ this.millisecond = this.self.getMilliseconds()
90
+ return this
91
+ }
92
+
93
+ isValid() {
94
+ return this.self.toString() !== INVALID_DATE_STRING
95
+ }
96
+
97
+ /** Get the this date's month as a number from 1-12. */
98
+ get month() {
99
+ return this.M + 1
100
+ }
101
+
102
+ /** Get the number of days in this date's month. */
103
+ daysInMonth() {
104
+ return daysInMonth(this.year, this.M)
105
+ }
106
+
107
+ /** Get the number of days in this date's year. */
108
+ daysInYear() {
109
+ return daysInYear(this.year)
110
+ }
111
+
112
+ /** Returns `true` if this date's year is a leap year, otherwise `false`. */
113
+ isLeapYear() {
114
+ return isLeapYear(this.year)
115
+ }
116
+
117
+ /** Gets the number of weeks according to locale in the current moment's year. */
118
+ weeksInYear() {
119
+ return weeksInYear(this.year)
120
+ }
121
+
122
+ /**
123
+ * Returns a localized string representation of this date.
124
+ * @param {Intl.DateTimeFormatOptions} opts The options to use for the format
125
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat Intl.DateTimeFormat()}
126
+ */
127
+ toString(opts?: Intl.DateTimeFormatOptions) {
128
+ return this.self.toLocaleDateString(this.locale, opts)
129
+ }
130
+
131
+ /**
132
+ * Returns a localized string representation of this date, according to the given format string. Format codes use the same specification as C / Python's strftime().
133
+ * @param {string} str The format string to use
134
+ * @see {@link https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes Format Codes}
135
+ * @example
136
+ ```js
137
+ new IntlDate().format('%m/%d/%y') // '10/31/2022'
138
+ ```
139
+ */
140
+ format(str: string) {
141
+ return format(str, this.self, this.locale)
142
+ }
143
+
144
+ /**
145
+ * Returns a new copy of the native `Date` object used by this instance.
146
+ * @returns {Date} A new `Date` object
147
+ */
148
+ toDate() {
149
+ return new Date(this.isValid() ? this.self : NaN)
150
+ }
151
+
152
+ /**
153
+ * Returns the timestamp representing the UTC equivalent of this date.
154
+ * @returns {number} The UTC timestamp of this date.
155
+ */
156
+ toUTC() {
157
+ return dateToUTC(this.self)
158
+ }
159
+
160
+ /**
161
+ * Returns the number of seconds since the Unix Epoch (January 1, 1970 UTC).
162
+ * @see {@link IntlDate.timestamp}
163
+ * @see {@link IntlDate.unix}
164
+ * @example
165
+ ```js
166
+ new IntlDate().toSeconds() // 1318874398
167
+ ```
168
+ */
169
+ toSeconds() {
170
+ return Math.trunc(this.valueOf() / 1000)
171
+ }
172
+
173
+ /**
174
+ * Returns the number of seconds since the Unix Epoch (January 1, 1970 UTC).
175
+ * @see {@link IntlDate.toSeconds}
176
+ * @see {@link IntlDate.unix}
177
+ * @example
178
+ ```js
179
+ new IntlDate().timestamp() // 1318874398
180
+ ```
181
+ */
182
+ timestamp() {
183
+ return this.toSeconds()
184
+ }
185
+
186
+ /**
187
+ * Returns the number of seconds since the Unix Epoch (January 1, 1970 UTC).
188
+ * @see {@link IntlDate.toSeconds}
189
+ * @see {@link IntlDate.timestamp}
190
+ * @example
191
+ ```js
192
+ new IntlDate().unix() // 1318874398
193
+ ```
194
+ */
195
+ unix() {
196
+ return this.toSeconds()
197
+ }
198
+
199
+ /** Formats a string to the ISO8601 standard.
200
+ * @example
201
+ ```js
202
+ new IntlDate().toISOString() // '2022-10-31T22:44:30.652Z'
203
+ ```
204
+ */
205
+ toISOString() {
206
+ return this.self.toISOString()
207
+ }
208
+
209
+ /** Returns the date part formatted as ISO8601.
210
+ * @example
211
+ ```js
212
+ new IntlDate().toISODate() // '2022-10-31'
213
+ ```
214
+ */
215
+ toISODate() {
216
+ return this.self.toISOString().slice(0, 10)
217
+ }
218
+
219
+ /** Returns the time part formatted as ISO8601.
220
+ * @example
221
+ ```js
222
+ new IntlDate().toISOTime() // 'T22:44:30.652Z'
223
+ ```
224
+ */
225
+ toISOTime() {
226
+ return this.self.toISOString().slice(11)
227
+ }
228
+
229
+ /**
230
+ * Returns an object containing year, month, day-of-month, hours, minutes, seconds, milliseconds.
231
+ * @returns {Object} An object like `{year, month, date, hours, minutes, seconds, ms}`
232
+ */
233
+ toObject(): DateParts {
234
+ return {
235
+ year: this.year,
236
+ month: this.month,
237
+ day: this.day,
238
+ hour: this.hour,
239
+ minute: this.M,
240
+ second: this.second,
241
+ millisecond: this.millisecond
242
+ }
243
+ }
244
+
245
+ /** Returns the number of milliseconds since the Unix Epoch (January 1, 1970 UTC) */
246
+ valueOf() {
247
+ return this.isValid() ? this.self.getTime() : NaN
248
+ }
249
+
250
+ /** Returns the timezone string name */
251
+ zoneName() {
252
+ return this.format('%Z')
253
+ }
254
+
255
+ /** Returns the timezone GMT offset name */
256
+ offset() {
257
+ return this.format('%z')
258
+ }
259
+
260
+ /**
261
+ * Check if this date is before another date. The other value will be parsed as an `IntlDate` if not already so.
262
+ * @param {string | number | Object | Date | IntlDate} other Another date or date like object
263
+ * @returns {boolean} Returns `true` if this date is before the given value
264
+ */
265
+ isBefore(other: DateLike | IntlDate) {
266
+ if (!this.isValid()) return false
267
+
268
+ if (other instanceof IntlDate) {
269
+ return this.valueOf() < other.valueOf()
270
+ }
271
+
272
+ return this.valueOf() < new IntlDate(other).valueOf()
273
+ }
274
+
275
+ /**
276
+ * Check if this date is strictly after the given `start` and before `stop` dates. The values will be parsed as an `IntlDate` if not already so.
277
+ * @param {string | number | Object | Date | IntlDate} start The smaller date
278
+ * @param {string | number | Object | Date | IntlDate} stop The larger date
279
+ * @returns {boolean} Returns `true` if this date is greater than `start` and less than `stop`.
280
+ */
281
+ isBetween(start: DateLike | IntlDate, stop: DateLike | IntlDate) {
282
+ return this.isAfter(start) && this.isBefore(stop)
283
+ }
284
+
285
+ /**
286
+ * Check if this date is after another date. The other value will be parsed as an `IntlDate` if not already so.
287
+ * @param {string | number | DateParts | Date | IntlDate} other Another date or date like object
288
+ * @returns {boolean} Returns `true` if this date is after the given value
289
+ */
290
+ isAfter(other: DateLike | IntlDate) {
291
+ if (!this.isValid()) return false
292
+
293
+ if (other instanceof IntlDate) {
294
+ return this.valueOf() > other.valueOf()
295
+ }
296
+
297
+ return this.valueOf() > new IntlDate(other).valueOf()
298
+ }
299
+
300
+ /**
301
+ * Check if this date is the same as `other`.
302
+ * @param other Another date object
303
+ * @returns {boolean} Returns `true` if this date is the same as other
304
+ */
305
+ isSame(other: Date | IntlDate) {
306
+ if (other instanceof IntlDate) {
307
+ return (
308
+ this.isValid() &&
309
+ other.isValid() &&
310
+ this.valueOf() === other.valueOf() &&
311
+ this.locale === other.locale
312
+ )
313
+ }
314
+ return this.valueOf() === other.valueOf()
315
+ }
316
+
317
+ /**
318
+ * Returns the minimum (most distant past) of the given date values.
319
+ * @param {Array<Date | IntlDate>} dates
320
+ * @returns {Date | IntlDate} The smallest date of `dates`
321
+ * @see {@link minDate}
322
+ */
323
+ static min(...dates: Array<Date | IntlDate>) {
324
+ return minDate(...dates)
325
+ }
326
+
327
+ /**
328
+ * Returns the maximum (most distant future) of the given date values.
329
+ * @param {Array<Date | IntlDate>} dates
330
+ * @returns {Date | IntlDate} The largest date of `dates`
331
+ * @see {@link maxDate}
332
+ */
333
+ static max(...dates: Array<Date | IntlDate>) {
334
+ return maxDate(...dates)
335
+ }
336
+
337
+ lt(other: Date | IntlDate) {
338
+ return this.isBefore(other)
339
+ }
340
+
341
+ eq(other: Date | IntlDate) {
342
+ return this.isSame(other)
343
+ }
344
+
345
+ compare(other: Date | IntlDate) {
346
+ if (this.isBefore(other)) return -1
347
+ if (this.isAfter(other)) return 1
348
+ return 0
349
+ }
350
+
351
+ // TODO:
352
+ // Display
353
+ // Time from now
354
+ // Time from X
355
+ // Difference
356
+
357
+ // Parsing
358
+ // Parse String + Date Format
359
+ // Parse String + Time Format
360
+ // Parse String + Format + locale
361
+
362
+ // Manipulate
363
+ // Add
364
+ // Subtract
365
+ // Start of Time
366
+ // End of Time
367
+ }
368
+
369
+ /**
370
+ * Converts the given date to a UTC timestamp.
371
+ * @param {Date} date
372
+ * @returns {number} The milliseconds between the specified date and the UTC Epoch date.
373
+ */
374
+ export function dateToUTC(date: Date) {
375
+ return Date.UTC(
376
+ date.getUTCFullYear(),
377
+ date.getUTCMonth(),
378
+ date.getUTCDate(),
379
+ date.getUTCHours(),
380
+ date.getUTCMinutes(),
381
+ date.getUTCSeconds(),
382
+ date.getUTCMilliseconds()
383
+ )
384
+ }
385
+
386
+ /**
387
+ * Returns the minimum (most distant past) of the given date values.
388
+ * @param {Array<Date | IntlDate>} dates
389
+ * @returns {Date | IntlDate} The smallest date of `dates`
390
+ */
391
+ export function minDate(...dates: Array<Date | IntlDate>) {
392
+ let result = dates[0]
393
+ for (let i = 1; i < dates.length; i++) {
394
+ if (dates[i].valueOf() < result.valueOf()) {
395
+ result = dates[i]
396
+ }
397
+ }
398
+ return result
399
+ }
400
+
401
+ /**
402
+ * Returns the maximum (most distant future) of the given date values.
403
+ * @param {Array<Date | IntlDate>} dates
404
+ * @returns {Date | IntlDate} The largest date of `dates`
405
+ */
406
+ export function maxDate(...dates: Array<Date | IntlDate>) {
407
+ let result = dates[0]
408
+ for (let i = 1; i < dates.length; i++) {
409
+ if (dates[i].valueOf() > result.valueOf()) {
410
+ result = dates[i]
411
+ }
412
+ }
413
+ return result
414
+ }
415
+
416
+ /**
417
+ * Returns `true` if the year is a leap year, otherwise `false`.
418
+ * @param year The date year
419
+ * @returns {boolean} `true` if is a leap year
420
+ */
421
+ export function isLeapYear(year: number) {
422
+ return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)
423
+ }
424
+
425
+ /**
426
+ * Get the number of days in the given year.
427
+ * @param year The date year
428
+ * @returns {number} Number of days in year
429
+ */
430
+ export function daysInYear(year: number) {
431
+ return isLeapYear(year) ? 366 : 365
432
+ }
433
+
434
+ /**
435
+ * Get the number of days in the given month and year.
436
+ * @param year The date year
437
+ * @param month The date month
438
+ * @returns {number} Number of days in month
439
+ */
440
+ export function daysInMonth(year: number, month: number) {
441
+ const modMonth = floorMod(month - 1, 12) + 1,
442
+ modYear = year + (month - modMonth) / 12
443
+
444
+ if (modMonth === 2) {
445
+ return isLeapYear(modYear) ? 29 : 28
446
+ } else {
447
+ return [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][modMonth - 1]
448
+ }
449
+ }
450
+
451
+ /**
452
+ * Gets the number of weeks according to locale in the current moment's year.
453
+ * @param {number} weekYear The the date year
454
+ * @returns {number}
455
+ */
456
+ export function weeksInYear(weekYear: number) {
457
+ const p1 =
458
+ (weekYear +
459
+ Math.floor(weekYear / 4) -
460
+ Math.floor(weekYear / 100) +
461
+ Math.floor(weekYear / 400)) %
462
+ 7,
463
+ last = weekYear - 1,
464
+ p2 = (last + Math.floor(last / 4) - Math.floor(last / 100) + Math.floor(last / 400)) % 7
465
+ return p1 === 4 || p2 === 3 ? 53 : 52
466
+ }
467
+
468
+ // x % n but takes the sign of n instead of x
469
+ function floorMod(x: number, n: number) {
470
+ return x - n * Math.floor(x / n)
471
+ }
@@ -0,0 +1,67 @@
1
+ <script type="module">
2
+ import { IntlDate } from './index.js'
3
+ window.IntlDate = IntlDate
4
+
5
+ let d = new IntlDate('', { locale: 'en' })
6
+ console.log('toString', d.toString())
7
+
8
+ console.log('%A', d.format('%A'))
9
+ console.log('%a', d.format('%a'))
10
+
11
+ console.log('%%d', d.format('%d'))
12
+ console.log('%-d', d.format('%-d'))
13
+
14
+ console.log('%m', d.format('%m'))
15
+ console.log('%-m', d.format('%-m'))
16
+ console.log('%B', d.format('%B'))
17
+ console.log('%b', d.format('%b'))
18
+ console.log('%bb', d.format('%bb'))
19
+
20
+ console.log('%Y', d.format('%Y'))
21
+ console.log('%y', d.format('%y'))
22
+
23
+ console.log('%N', d.format('%N'))
24
+ console.log('%n', d.format('%n'))
25
+
26
+ console.log('%I', d.format('%I'))
27
+ console.log('%-I', d.format('%-I'))
28
+ console.log('%H', d.format('%H'))
29
+ console.log('%-H', d.format('%-H'))
30
+ console.log('%K', d.format('%K'))
31
+ console.log('%k', d.format('%k'))
32
+
33
+ console.log('%M', d.format('%M'))
34
+ console.log('%-M', d.format('%-M'))
35
+
36
+ console.log('%S', d.format('%S'))
37
+ console.log('%-S', d.format('%-S'))
38
+
39
+ console.log('%P', d.format('%P'))
40
+ console.log('%p', d.format('%p'))
41
+ console.log('%pp', d.format('%pp'))
42
+
43
+ console.log('%Z', d.format('%Z'))
44
+ console.log('%-Z', d.format('%-Z'))
45
+ console.log('%z', d.format('%z'))
46
+ console.log('%-z', d.format('%-z'))
47
+ console.log('%ZZ', d.format('%ZZ'))
48
+ console.log('%-ZZ', d.format('%-ZZ'))
49
+
50
+ console.log(d.format('%A, %d/%m/%y'))
51
+ console.log(d.format('%y-%m-%d, %A'))
52
+ console.log(d.format('%y %B %d %A %I:%M:%S %P'))
53
+ console.log(d.format('%y %B %d %A %-I:%-M:%-S %p'))
54
+ console.log(d.format('%y %b %d %a %H:%M:%S'))
55
+ console.log(d.format('%y %b %d %a %-H:%-M:%S'))
56
+ console.log(d.format('%y %b %d %a %K:%M:%S %P')) // %p shows on 12h clock
57
+ console.log(d.format('%y %b %d %a %k:%-M:%S %p')) // %p No effect on 24h
58
+ console.log(d.format('%a, %b %d, %y %N, %K:%M:%S %P'))
59
+ console.log(d.format('%a, %b %d, %y %n, %K:%M:%S %P'))
60
+ console.log(d.format('%a, %b %d, %y %k:%M:%S %P')) // %p No effect on 24h
61
+ console.log(d.format('%y %b %d %a %-I:%M:%S %P %Z'))
62
+ console.log(d.format('%y %b %d %a %-I:%M:%S %P %-Z'))
63
+ console.log(d.format('%y %b %d %a %-I:%M:%S %P %z'))
64
+ console.log(d.format('%y %b %d %a %-I:%M:%S %P %-z'))
65
+ console.log(d.format('%y %b %d %a %-I:%M:%S %P %ZZ'))
66
+ console.log(d.format('%a, %b %d, %y %-I:%M:%S %-ZZ'))
67
+ </script>
@@ -0,0 +1,7 @@
1
+ /**
2
+ * This module includes functions and classes to handle internationalization of dates and currencies.
3
+ *
4
+ * @module i18n
5
+ */
6
+ export * from './date/index.js';
7
+ export * from './date/format.js';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * This module includes functions and classes to handle internationalization of dates and currencies.
3
+ *
4
+ * @module i18n
5
+ */
6
+ export * from './date/index.js';
7
+ export * from './date/format.js';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * This module includes functions and classes to handle internationalization of dates and currencies.
3
+ *
4
+ * @module i18n
5
+ */
6
+
7
+ export * from './date/index.js'
8
+ export * from './date/format.js'
package/core/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './collections/index.js';
2
2
  export * from './functools/index.js';
3
3
  export * from './globals/index.js';
4
+ export * from './i18n/index.js';
4
5
  export * from './itertools/index.js';
5
6
  export * from './math/index.js';
6
7
  export * from './operators/index.js';
package/core/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './collections/index.js';
2
2
  export * from './functools/index.js';
3
3
  export * from './globals/index.js';
4
+ export * from './i18n/index.js';
4
5
  export * from './itertools/index.js';
5
6
  export * from './math/index.js';
6
7
  export * from './operators/index.js';
package/core/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './collections/index.js'
2
2
  export * from './functools/index.js'
3
3
  export * from './globals/index.js'
4
+ export * from './i18n/index.js'
4
5
  export * from './itertools/index.js'
5
6
  export * from './math/index.js'
6
7
  export * from './operators/index.js'
@@ -145,4 +145,4 @@ export declare function shallowEqual(obj: any, other: any): boolean;
145
145
  * @param other
146
146
  * @returns `true` if the objects are considered equal.
147
147
  */
148
- export declare function deepEqual(obj: any, other: any, checker?: typeof eq): boolean;
148
+ export declare function deepEqual(obj: any, other: any, checker?: typeof eq, seen?: WeakSet<object>): boolean;
@@ -57,7 +57,7 @@ export function compare(x, y) {
57
57
  * @returns {boolean} `true` if `x` and `y` are equal or `false` otherwise.
58
58
  */
59
59
  export function eq(x, y) {
60
- return x === y || call(x, 'eq', y) != null;
60
+ return Object.is(x, y) || call(x, 'eq', y) != null;
61
61
  }
62
62
  /**
63
63
  * Compares two values to check if `x` is strictly less than `y`. If `x` is an object with a `lt` method, it returns `x.lt(y)`.
@@ -237,11 +237,15 @@ export function shallowEqual(obj, other) {
237
237
  * @param other
238
238
  * @returns `true` if the objects are considered equal.
239
239
  */
240
- export function deepEqual(obj, other, checker = eq) {
240
+ export function deepEqual(obj, other, checker = eq, seen = new WeakSet()) {
241
241
  if (checker(obj, other))
242
242
  return true;
243
243
  if (!obj || !other)
244
244
  return false;
245
+ if (obj.prototype !== other.prototype)
246
+ return false;
247
+ if (seen.has(obj) && seen.has(other))
248
+ return false;
245
249
  if (Array.isArray(obj)) {
246
250
  // compare the arrays
247
251
  if (obj.length !== other.length)
@@ -253,15 +257,41 @@ export function deepEqual(obj, other, checker = eq) {
253
257
  }
254
258
  return true;
255
259
  }
256
- else if (isObject(obj)) {
257
- // compare the object keys
260
+ if (obj instanceof Set) {
261
+ if (obj.size !== other.size)
262
+ return false;
263
+ for (const value of obj.values()) {
264
+ if (!other.has(value))
265
+ return false;
266
+ }
267
+ return true;
268
+ }
269
+ if (obj instanceof Map) {
270
+ // compare keys and values
271
+ if (obj.size !== other.size)
272
+ return false;
273
+ seen.add(obj);
274
+ seen.add(other);
275
+ for (const key of obj.keys()) {
276
+ if (!other.has(key))
277
+ return false;
278
+ if (!deepEqual(obj.get(key), other.get(key), checker, seen)) {
279
+ return false;
280
+ }
281
+ }
282
+ return true;
283
+ }
284
+ if (isObject(obj)) {
285
+ // compare the object own enumerable keys
258
286
  const objKeys = Object.keys(obj);
259
287
  const otherKeys = Object.keys(other);
260
288
  if (objKeys.length !== otherKeys.length)
261
289
  return false;
290
+ seen.add(obj);
291
+ seen.add(other);
262
292
  for (const key of objKeys) {
263
293
  if (!Object.prototype.hasOwnProperty.call(other, key) ||
264
- !deepEqual(obj[key], other[key], checker)) {
294
+ !deepEqual(obj[key], other[key], checker, seen)) {
265
295
  return false;
266
296
  }
267
297
  }