@jsarc/cooks 0.0.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/README.md +372 -0
- package/cooks.ts +1159 -0
- package/index.ts +274 -0
- package/js/index.js +189 -0
- package/package.json +20 -0
- package/ts/cooks.ts +1159 -0
- package/ts/index.ts +274 -0
- package/tsconfig.json +27 -0
- package/web/cooks.js +920 -0
- package/web/cooks.min.js +1 -0
package/ts/cooks.ts
ADDED
|
@@ -0,0 +1,1159 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
|
|
3
|
+
interface Window {
|
|
4
|
+
default: typeof defaultElementGF;
|
|
5
|
+
Cooks: any;
|
|
6
|
+
Timez: any;
|
|
7
|
+
__bundledModules: any;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface TimezFormatOptions {
|
|
11
|
+
strict?: boolean;
|
|
12
|
+
timezone?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
interface ParseResult {
|
|
17
|
+
year: number;
|
|
18
|
+
month: number;
|
|
19
|
+
day: number;
|
|
20
|
+
hour: number;
|
|
21
|
+
minute: number;
|
|
22
|
+
second: number;
|
|
23
|
+
millisecond: number;
|
|
24
|
+
timezoneOffset?: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
type TimezInput = Date | string | number | typeof Timez | undefined;
|
|
29
|
+
|
|
30
|
+
interface CooksOptions {
|
|
31
|
+
expires?: Date | number;
|
|
32
|
+
path?: string;
|
|
33
|
+
domain?: string;
|
|
34
|
+
secure?: boolean;
|
|
35
|
+
sameSite?: 'strict' | 'lax' | 'none';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
type Serializable =
|
|
40
|
+
| string
|
|
41
|
+
| number
|
|
42
|
+
| boolean
|
|
43
|
+
| Date
|
|
44
|
+
| object
|
|
45
|
+
| Array<any>
|
|
46
|
+
| null
|
|
47
|
+
| undefined;
|
|
48
|
+
|
|
49
|
+
const globalFunct = (function(global: any) {
|
|
50
|
+
'use strict';
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
const NODEENV: 'development' | 'production' | 'debug' = 'development'; // development | debug | production
|
|
54
|
+
|
|
55
|
+
const langs = ['en', 'fr'];
|
|
56
|
+
const langCodes = {
|
|
57
|
+
'fr': 'fr_FR',
|
|
58
|
+
'en': 'en_US',
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const dateTimeFormatInitial = '%Y-%m-%dT%H:%M:%S.%fZ';
|
|
62
|
+
const dateFormatInitial = '%Y-%m-%d';
|
|
63
|
+
const timeFormatInitial = '%H:%M:%S.%fZ';
|
|
64
|
+
|
|
65
|
+
const dateFormatForFile = '%Y%m%d%H%M%S';
|
|
66
|
+
const dateFormat1 = '%Y/%m/%d %H:%M:%S.%fZ';
|
|
67
|
+
const dateFormat2 = '%Y/%m/%d %H:%M:%S';
|
|
68
|
+
const dateFormat3 = '%Y/%m/%d %H:%M';
|
|
69
|
+
const dateFormat4 = '%d/%m/%Y %H:%M:%S GMT%z';
|
|
70
|
+
const dateFormat5 = '%Y/%m/%d';
|
|
71
|
+
const timeFormat1 = '%H:%M:%S.%fZ';
|
|
72
|
+
const timeFormat2 = '%H:%M:%S';
|
|
73
|
+
const timeFormat3 = '%H:%M:%S.%f';
|
|
74
|
+
const pagesPossibles = [5, 10, 15, 25, 50, 100, -1];
|
|
75
|
+
|
|
76
|
+
const regExpForAlphanumeric = /^[\w\s]{1,}/;
|
|
77
|
+
|
|
78
|
+
const tabNumerique = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
|
79
|
+
const tabAlphabetique = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
|
|
80
|
+
const tabAlphabetiqueInsensitive = [...tabAlphabetique, ...tabAlphabetique.map(x => x.toUpperCase())];
|
|
81
|
+
const tabAlphanumerique = [...tabNumerique, ...tabAlphabetique];
|
|
82
|
+
const tabAlphanumeriqueInsensitive = [...tabNumerique, ...tabAlphabetiqueInsensitive];
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class Timez {
|
|
91
|
+
private _date?: Date;
|
|
92
|
+
private static readonly FORMAT_TOKENS: { [key: string]: (timez: Timez) => string | undefined } = {
|
|
93
|
+
'%Y': (t) => t.year()?.toString().padStart(4, '0'),
|
|
94
|
+
'%y': (t) => t.year()?.toString().slice(-2).padStart(2, '0'),
|
|
95
|
+
'%m': (t) => t.month()?.toString().padStart(2, '0'),
|
|
96
|
+
'%d': (t) => t.date()?.toString().padStart(2, '0'),
|
|
97
|
+
'%H': (t) => t.hour()?.toString().padStart(2, '0'),
|
|
98
|
+
'%M': (t) => t.minute()?.toString().padStart(2, '0'),
|
|
99
|
+
'%S': (t) => t.second()?.toString().padStart(2, '0'),
|
|
100
|
+
'%f': (t) => t.millisecond()?.toString().padStart(3, '0'),
|
|
101
|
+
'%z': (t) => {
|
|
102
|
+
const offset = t.utcOffset();
|
|
103
|
+
if (!offset) {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
const sign = offset >= 0 ? '+' : '-';
|
|
107
|
+
const hours = Math.floor(Math.abs(offset) / 60).toString().padStart(2, '0');
|
|
108
|
+
const minutes = (Math.abs(offset) % 60).toString().padStart(2, '0');
|
|
109
|
+
return `${sign}${hours}${minutes}`;
|
|
110
|
+
},
|
|
111
|
+
'%s': (t) => {
|
|
112
|
+
const val = t.valueOf();
|
|
113
|
+
return !!val ? Math.floor(val / 1000).toString() : undefined;
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
static readonly PREDEFINED_FORMATS: { [key: string]: string } = {
|
|
118
|
+
ISO: '%Y-%m-%dT%H:%M:%S.%fZ',
|
|
119
|
+
ISO_DATE: '%Y-%m-%d',
|
|
120
|
+
ISO_TIME: '%H:%M:%S.%fZ',
|
|
121
|
+
COMPACT: '%Y%m%d%H%M%S',
|
|
122
|
+
SLASH_DATETIME: '%Y/%m/%d %H:%M:%S.%fZ',
|
|
123
|
+
SLASH_DATETIME_SEC: '%Y/%m/%d %H:%M:%S',
|
|
124
|
+
SLASH_DATETIME_MIN: '%Y/%m/%d %H:%M',
|
|
125
|
+
EUROPEAN: '%d/%m/%Y %H:%M:%S GMT%z',
|
|
126
|
+
SLASH_DATE: '%Y/%m/%d',
|
|
127
|
+
TIME_MICRO: '%H:%M:%S.%fZ',
|
|
128
|
+
TIME_SEC: '%H:%M:%S',
|
|
129
|
+
CUSTOM_GREETING: '[Bonjour celestin, ][la date actuelle est:: le] %d/%m/%Y [à] %H:%M:%S.%f[Z]',
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
constructor(input?: TimezInput, enableException: boolean = false) {
|
|
133
|
+
if(this.dateChecker(input) === false) {
|
|
134
|
+
this._date = undefined;
|
|
135
|
+
} else {
|
|
136
|
+
if (input instanceof Timez && !!input && !!input?._date) {
|
|
137
|
+
this._date = new Date(input?._date);
|
|
138
|
+
} else if (input instanceof Date) {
|
|
139
|
+
this._date = new Date(input);
|
|
140
|
+
} else if (typeof input === 'string') {
|
|
141
|
+
this._date = Timez.parseString(input, enableException);
|
|
142
|
+
} else if (typeof input === 'number') {
|
|
143
|
+
this._date = new Date(input);
|
|
144
|
+
} else if(
|
|
145
|
+
input === undefined ||
|
|
146
|
+
input === null ||
|
|
147
|
+
(typeof input === 'number' && isNaN(input))
|
|
148
|
+
) {
|
|
149
|
+
this._date = new Date();
|
|
150
|
+
} else {
|
|
151
|
+
this._date = undefined;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
static now(): Timez {
|
|
157
|
+
return new Timez();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
static parse(dateString: any, format?: string): Timez {
|
|
161
|
+
if (
|
|
162
|
+
typeof format === 'string' &&
|
|
163
|
+
format.length > 0 && (
|
|
164
|
+
(
|
|
165
|
+
dateString instanceof Timez &&
|
|
166
|
+
!!dateString &&
|
|
167
|
+
!!dateString?._date
|
|
168
|
+
) ||
|
|
169
|
+
dateString instanceof Date ||
|
|
170
|
+
typeof dateString === 'string' ||
|
|
171
|
+
typeof dateString === 'number' || (
|
|
172
|
+
dateString === undefined ||
|
|
173
|
+
dateString === null ||
|
|
174
|
+
(typeof dateString === 'number' && isNaN(dateString))
|
|
175
|
+
)
|
|
176
|
+
)
|
|
177
|
+
) {
|
|
178
|
+
return Timez.parseWithFormat(dateString, format) || new Timez(dateString);
|
|
179
|
+
}
|
|
180
|
+
return new Timez(dateString);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
static unix(timestamp: number): Timez {
|
|
184
|
+
return new Timez(timestamp * 1000);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
static utc(): Timez {
|
|
188
|
+
const now = new Date();
|
|
189
|
+
return new Timez(Date.UTC(
|
|
190
|
+
now.getUTCFullYear(),
|
|
191
|
+
now.getUTCMonth(),
|
|
192
|
+
now.getUTCDate(),
|
|
193
|
+
now.getUTCHours(),
|
|
194
|
+
now.getUTCMinutes(),
|
|
195
|
+
now.getUTCSeconds(),
|
|
196
|
+
now.getUTCMilliseconds()
|
|
197
|
+
));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
year(): number | undefined {
|
|
201
|
+
return this._date?.getFullYear();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
month(): number | undefined {
|
|
205
|
+
return !!this._date ? this._date.getMonth() + 1 : undefined;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
date(): number | undefined {
|
|
209
|
+
return this._date?.getDate();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
hour(): number | undefined {
|
|
213
|
+
return this._date?.getHours();
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
minute(): number | undefined {
|
|
217
|
+
return this._date?.getMinutes();
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
second(): number | undefined {
|
|
221
|
+
return this._date?.getSeconds();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
millisecond(): number | undefined {
|
|
225
|
+
return this._date?.getMilliseconds();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
day(): number | undefined {
|
|
229
|
+
return this._date?.getDay();
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
add(amount: number, unit: 'years' | 'months' | 'days' | 'hours' | 'minutes' | 'seconds' | 'milliseconds'): Timez {
|
|
233
|
+
if (!this._date) {
|
|
234
|
+
return new Timez(undefined);
|
|
235
|
+
}
|
|
236
|
+
const newDate = new Date(this._date);
|
|
237
|
+
|
|
238
|
+
switch (unit) {
|
|
239
|
+
case 'years':
|
|
240
|
+
newDate.setFullYear(newDate.getFullYear() + amount);
|
|
241
|
+
break;
|
|
242
|
+
case 'months':
|
|
243
|
+
newDate.setMonth(newDate.getMonth() + amount);
|
|
244
|
+
break;
|
|
245
|
+
case 'days':
|
|
246
|
+
newDate.setDate(newDate.getDate() + amount);
|
|
247
|
+
break;
|
|
248
|
+
case 'hours':
|
|
249
|
+
newDate.setHours(newDate.getHours() + amount);
|
|
250
|
+
break;
|
|
251
|
+
case 'minutes':
|
|
252
|
+
newDate.setMinutes(newDate.getMinutes() + amount);
|
|
253
|
+
break;
|
|
254
|
+
case 'seconds':
|
|
255
|
+
newDate.setSeconds(newDate.getSeconds() + amount);
|
|
256
|
+
break;
|
|
257
|
+
case 'milliseconds':
|
|
258
|
+
newDate.setMilliseconds(newDate.getMilliseconds() + amount);
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return new Timez(newDate);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
subtract(amount: number, unit: 'years' | 'months' | 'days' | 'hours' | 'minutes' | 'seconds' | 'milliseconds'): Timez {
|
|
266
|
+
return this.add(-amount, unit);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
startOf(unit: 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second'): Timez {
|
|
270
|
+
if (!this._date) {
|
|
271
|
+
return new Timez(undefined);
|
|
272
|
+
}
|
|
273
|
+
const newDate = new Date(this._date);
|
|
274
|
+
|
|
275
|
+
switch (unit) {
|
|
276
|
+
case 'year':
|
|
277
|
+
newDate.setMonth(0, 1);
|
|
278
|
+
newDate.setHours(0, 0, 0, 0);
|
|
279
|
+
break;
|
|
280
|
+
case 'month':
|
|
281
|
+
newDate.setDate(1);
|
|
282
|
+
newDate.setHours(0, 0, 0, 0);
|
|
283
|
+
break;
|
|
284
|
+
case 'day':
|
|
285
|
+
newDate.setHours(0, 0, 0, 0);
|
|
286
|
+
break;
|
|
287
|
+
case 'hour':
|
|
288
|
+
newDate.setMinutes(0, 0, 0);
|
|
289
|
+
break;
|
|
290
|
+
case 'minute':
|
|
291
|
+
newDate.setSeconds(0, 0);
|
|
292
|
+
break;
|
|
293
|
+
case 'second':
|
|
294
|
+
newDate.setMilliseconds(0);
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return new Timez(newDate);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
endOf(unit: 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second'): Timez {
|
|
302
|
+
const start = this.startOf(unit);
|
|
303
|
+
|
|
304
|
+
switch (unit) {
|
|
305
|
+
case 'year':
|
|
306
|
+
return start.add(1, 'years').subtract(1, 'milliseconds');
|
|
307
|
+
case 'month':
|
|
308
|
+
return start.add(1, 'months').subtract(1, 'milliseconds');
|
|
309
|
+
case 'day':
|
|
310
|
+
return start.add(1, 'days').subtract(1, 'milliseconds');
|
|
311
|
+
case 'hour':
|
|
312
|
+
return start.add(1, 'hours').subtract(1, 'milliseconds');
|
|
313
|
+
case 'minute':
|
|
314
|
+
return start.add(1, 'minutes').subtract(1, 'milliseconds');
|
|
315
|
+
case 'second':
|
|
316
|
+
return start.add(1, 'seconds').subtract(1, 'milliseconds');
|
|
317
|
+
default:
|
|
318
|
+
return start;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
isBefore(other: TimezInput, inclusivity: '()' | '(]' = '()'): boolean {
|
|
323
|
+
const isIncluded = inclusivity[1] === ']';
|
|
324
|
+
const otherTimez = other instanceof Timez ? other : new Timez(other);
|
|
325
|
+
if (!this._date || !otherTimez._date) {
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
return (
|
|
329
|
+
(
|
|
330
|
+
!isIncluded &&
|
|
331
|
+
this._date < otherTimez._date
|
|
332
|
+
) ||
|
|
333
|
+
(
|
|
334
|
+
!!isIncluded &&
|
|
335
|
+
this._date <= otherTimez._date
|
|
336
|
+
)
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
isAfter(other: TimezInput, inclusivity: '()' | '[)' = '()'): boolean {
|
|
341
|
+
const isIncluded = inclusivity[0] === '[';
|
|
342
|
+
const otherTimez = other instanceof Timez ? other : new Timez(other);
|
|
343
|
+
if (!this._date || !otherTimez._date) {
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
return (
|
|
347
|
+
(
|
|
348
|
+
!isIncluded &&
|
|
349
|
+
this._date > otherTimez._date
|
|
350
|
+
) ||
|
|
351
|
+
(
|
|
352
|
+
!!isIncluded &&
|
|
353
|
+
this._date >= otherTimez._date
|
|
354
|
+
)
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
isSame(other: TimezInput, unit?: 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second'): boolean {
|
|
359
|
+
const otherTimez = other instanceof Timez ? other : new Timez(other);
|
|
360
|
+
|
|
361
|
+
if (!unit && this._date && otherTimez._date) {
|
|
362
|
+
return this._date.getTime() === otherTimez._date.getTime();
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const thisStart = !!unit ? this.startOf(unit) : undefined;
|
|
366
|
+
const otherStart = !!unit ? otherTimez.startOf(unit) : undefined;
|
|
367
|
+
|
|
368
|
+
if (!thisStart || !thisStart?._date || !otherStart || !otherStart?._date) {
|
|
369
|
+
return false;
|
|
370
|
+
}
|
|
371
|
+
return thisStart._date.getTime() === otherStart._date.getTime();
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
isBetween(start: TimezInput, end: TimezInput, inclusivity: '()' | '[]' | '(]' | '[)' = '()'): boolean {
|
|
375
|
+
const startTimez: any = start instanceof Timez ? start : new Timez(start);
|
|
376
|
+
const endTimez: any = end instanceof Timez ? end : new Timez(end);
|
|
377
|
+
|
|
378
|
+
const startIncluded = inclusivity[0] === '[';
|
|
379
|
+
const endIncluded = inclusivity[1] === ']';
|
|
380
|
+
|
|
381
|
+
const afterStart = startIncluded ?
|
|
382
|
+
this.isSame(startTimez) || this.isAfter(startTimez) :
|
|
383
|
+
this.isAfter(startTimez);
|
|
384
|
+
|
|
385
|
+
const beforeEnd = endIncluded ?
|
|
386
|
+
this.isSame(endTimez) || this.isBefore(endTimez) :
|
|
387
|
+
this.isBefore(endTimez);
|
|
388
|
+
|
|
389
|
+
return afterStart && beforeEnd;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
format(formatString?: string): string | undefined {
|
|
393
|
+
if (!formatString) {
|
|
394
|
+
return this.toISOString();
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const predefinedFormat = Timez.PREDEFINED_FORMATS[formatString];
|
|
398
|
+
if (predefinedFormat) {
|
|
399
|
+
return this.format(predefinedFormat);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
let result = '';
|
|
403
|
+
let i = 0;
|
|
404
|
+
|
|
405
|
+
while (i < formatString.length) {
|
|
406
|
+
if (formatString[i] === '[') {
|
|
407
|
+
const endIndex = formatString.indexOf(']', i);
|
|
408
|
+
if (endIndex === -1) {
|
|
409
|
+
result += formatString[i];
|
|
410
|
+
i++;
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const literal = formatString.substring(i + 1, endIndex);
|
|
415
|
+
result += literal;
|
|
416
|
+
i = endIndex + 1;
|
|
417
|
+
} else if (formatString[i] === '%' && i + 1 < formatString.length) {
|
|
418
|
+
const token = `%${formatString[i + 1]}`;
|
|
419
|
+
const formatter = Timez.FORMAT_TOKENS[token];
|
|
420
|
+
|
|
421
|
+
if (formatter) {
|
|
422
|
+
result += formatter(this);
|
|
423
|
+
} else {
|
|
424
|
+
result += token;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
i += 2;
|
|
428
|
+
} else {
|
|
429
|
+
result += formatString[i];
|
|
430
|
+
i++;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
return result;
|
|
435
|
+
}
|
|
436
|
+
setTimezone(timezone: string): Timez {
|
|
437
|
+
if (!this._date) {
|
|
438
|
+
return new Timez(undefined);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const currentOffset = this._date.getTimezoneOffset();
|
|
442
|
+
const targetOffset = this.parseTimezoneOffset(timezone);
|
|
443
|
+
|
|
444
|
+
const adjustedDate = new Date(this._date.getTime() + (targetOffset - currentOffset) * 60000);
|
|
445
|
+
return new Timez(adjustedDate);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
utc(): Timez {
|
|
449
|
+
if (!this._date) {
|
|
450
|
+
return new Timez(undefined);
|
|
451
|
+
}
|
|
452
|
+
return new Timez(new Date(Date.UTC(
|
|
453
|
+
this._date.getUTCFullYear(),
|
|
454
|
+
this._date.getUTCMonth(),
|
|
455
|
+
this._date.getUTCDate(),
|
|
456
|
+
this._date.getUTCHours(),
|
|
457
|
+
this._date.getUTCMinutes(),
|
|
458
|
+
this._date.getUTCSeconds(),
|
|
459
|
+
this._date.getUTCMilliseconds()
|
|
460
|
+
)));
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
local(): Timez {
|
|
464
|
+
if (!this._date) {
|
|
465
|
+
return new Timez(undefined);
|
|
466
|
+
}
|
|
467
|
+
return new Timez(new Date(
|
|
468
|
+
this._date.getFullYear(),
|
|
469
|
+
this._date.getMonth(),
|
|
470
|
+
this._date.getDate(),
|
|
471
|
+
this._date.getHours(),
|
|
472
|
+
this._date.getMinutes(),
|
|
473
|
+
this._date.getSeconds(),
|
|
474
|
+
this._date.getMilliseconds()
|
|
475
|
+
));
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
toString(): string | undefined {
|
|
479
|
+
return this._date?.toString();
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
toISOString(): string | undefined {
|
|
483
|
+
return this._date?.toISOString();
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
toDate(): Date | undefined {
|
|
487
|
+
return !!this._date ? new Date(this._date) : undefined;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
valueOf(): number | undefined {
|
|
491
|
+
return this._date?.getTime();
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
unix(): number | undefined {
|
|
495
|
+
return !!this._date ? Math.floor(this._date.getTime() / 1000) : undefined;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
utcOffset(): number | undefined {
|
|
499
|
+
return this._date ? -this._date.getTimezoneOffset() : undefined;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
isCorrect(): boolean {
|
|
503
|
+
return !!this._date && !isNaN(this._date.getTime());
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
timezone(): string | undefined {
|
|
507
|
+
if (!this._date) return undefined;
|
|
508
|
+
|
|
509
|
+
try {
|
|
510
|
+
const formatter = new Intl.DateTimeFormat();
|
|
511
|
+
const timezone = formatter.resolvedOptions().timeZone;
|
|
512
|
+
return timezone || undefined;
|
|
513
|
+
} catch (error) {
|
|
514
|
+
return this.timezoneFromOffset();
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
timezoneAbbr(): string | undefined {
|
|
519
|
+
if (!this._date) return undefined;
|
|
520
|
+
|
|
521
|
+
try {
|
|
522
|
+
const formatter = new Intl.DateTimeFormat('en', {
|
|
523
|
+
timeZoneName: 'short'
|
|
524
|
+
});
|
|
525
|
+
const parts = formatter.formatToParts(this._date);
|
|
526
|
+
const timezonePart = parts.find(part => part.type === 'timeZoneName');
|
|
527
|
+
return timezonePart?.value || undefined;
|
|
528
|
+
} catch (error) {
|
|
529
|
+
return this.timezoneAbbrFromOffset();
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
timezoneName(): string | undefined {
|
|
534
|
+
if (!this._date) return undefined;
|
|
535
|
+
|
|
536
|
+
try {
|
|
537
|
+
const formatter = new Intl.DateTimeFormat('en', {
|
|
538
|
+
timeZoneName: 'long'
|
|
539
|
+
});
|
|
540
|
+
const parts = formatter.formatToParts(this._date);
|
|
541
|
+
const timezonePart = parts.find(part => part.type === 'timeZoneName');
|
|
542
|
+
return timezonePart?.value || undefined;
|
|
543
|
+
} catch (error) {
|
|
544
|
+
return this.timezoneNameFromOffset();
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
timezoneOffsetString(): string | undefined {
|
|
549
|
+
const offset = this.utcOffset();
|
|
550
|
+
if (offset === undefined) return undefined;
|
|
551
|
+
|
|
552
|
+
const sign = offset >= 0 ? '+' : '-';
|
|
553
|
+
const hours = Math.floor(Math.abs(offset) / 60).toString().padStart(2, '0');
|
|
554
|
+
const minutes = (Math.abs(offset) % 60).toString().padStart(2, '0');
|
|
555
|
+
|
|
556
|
+
return `${sign}${hours}:${minutes}`;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
private dateChecker(input: any): boolean {
|
|
562
|
+
return (
|
|
563
|
+
(
|
|
564
|
+
input instanceof Timez &&
|
|
565
|
+
!!input &&
|
|
566
|
+
!!input?._date
|
|
567
|
+
) ||
|
|
568
|
+
input instanceof Date ||
|
|
569
|
+
typeof input === 'string' ||
|
|
570
|
+
typeof input === 'number' || (
|
|
571
|
+
input === undefined ||
|
|
572
|
+
input === null ||
|
|
573
|
+
(typeof input === 'number' && isNaN(input))
|
|
574
|
+
)
|
|
575
|
+
);
|
|
576
|
+
}
|
|
577
|
+
private timezoneFromOffset(): string | undefined {
|
|
578
|
+
const offset = this.utcOffset();
|
|
579
|
+
if (offset === undefined) return undefined;
|
|
580
|
+
|
|
581
|
+
// Mapping basique des offsets vers les timezones IANA
|
|
582
|
+
const offsetToTimezone: { [key: number]: string } = {
|
|
583
|
+
0: 'Etc/UTC',
|
|
584
|
+
60: 'Europe/Paris',
|
|
585
|
+
120: 'Europe/Athens',
|
|
586
|
+
180: 'Europe/Moscow',
|
|
587
|
+
240: 'Asia/Dubai',
|
|
588
|
+
270: 'Asia/Tehran',
|
|
589
|
+
300: 'Asia/Karachi',
|
|
590
|
+
330: 'Asia/Kolkata',
|
|
591
|
+
345: 'Asia/Rangoon',
|
|
592
|
+
360: 'Asia/Dhaka',
|
|
593
|
+
390: 'Asia/Yangon',
|
|
594
|
+
420: 'Asia/Bangkok',
|
|
595
|
+
480: 'Asia/Shanghai',
|
|
596
|
+
525: 'Asia/Kathmandu',
|
|
597
|
+
540: 'Asia/Tokyo',
|
|
598
|
+
570: 'Australia/Adelaide',
|
|
599
|
+
600: 'Australia/Sydney',
|
|
600
|
+
630: 'Australia/Lord_Howe',
|
|
601
|
+
660: 'Pacific/Noumea',
|
|
602
|
+
675: 'Australia/Eucla',
|
|
603
|
+
720: 'Pacific/Auckland',
|
|
604
|
+
780: 'Pacific/Chatham',
|
|
605
|
+
|
|
606
|
+
[-60]: 'Atlantic/Azores',
|
|
607
|
+
[-120]: 'America/Noronha',
|
|
608
|
+
[-180]: 'America/Argentina/Buenos_Aires',
|
|
609
|
+
[-210]: 'America/St_Johns',
|
|
610
|
+
[-240]: 'America/Halifax',
|
|
611
|
+
[-270]: 'America/Caracas',
|
|
612
|
+
[-300]: 'America/New_York',
|
|
613
|
+
[-360]: 'America/Chicago',
|
|
614
|
+
[-420]: 'America/Denver',
|
|
615
|
+
[-480]: 'America/Los_Angeles',
|
|
616
|
+
[-540]: 'America/Anchorage',
|
|
617
|
+
[-600]: 'Pacific/Honolulu',
|
|
618
|
+
[-660]: 'Pacific/Pago_Pago',
|
|
619
|
+
[-720]: 'Pacific/Kiritimati',
|
|
620
|
+
};
|
|
621
|
+
|
|
622
|
+
return offsetToTimezone[offset] || `Etc/GMT${offset >= 0 ? '-' : '+'}${Math.abs(offset) / 60}`;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
private timezoneAbbrFromOffset(): string | undefined {
|
|
626
|
+
const offset = this.utcOffset();
|
|
627
|
+
if (offset === undefined) return undefined;
|
|
628
|
+
|
|
629
|
+
const offsetToAbbr: { [key: number]: string } = {
|
|
630
|
+
0: 'GMT',
|
|
631
|
+
60: 'CET',
|
|
632
|
+
[-300]: 'EST',
|
|
633
|
+
[-360]: 'CST',
|
|
634
|
+
[-420]: 'MST',
|
|
635
|
+
[-480]: 'PST',
|
|
636
|
+
};
|
|
637
|
+
|
|
638
|
+
return offsetToAbbr[offset] || `GMT${offset >= 0 ? '+' : ''}${offset / 60}`;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
private timezoneNameFromOffset(): string | undefined {
|
|
642
|
+
const offset = this.utcOffset();
|
|
643
|
+
if (offset === undefined) return undefined;
|
|
644
|
+
|
|
645
|
+
const offsetToName: { [key: number]: string } = {
|
|
646
|
+
0: 'Greenwich Mean Time',
|
|
647
|
+
60: 'Central European Time',
|
|
648
|
+
[-300]: 'Eastern Standard Time',
|
|
649
|
+
[-360]: 'Central Standard Time',
|
|
650
|
+
[-420]: 'Mountain Standard Time',
|
|
651
|
+
[-480]: 'Pacific Standard Time',
|
|
652
|
+
};
|
|
653
|
+
|
|
654
|
+
return offsetToName[offset] || `GMT${offset >= 0 ? '+' : ''}${offset / 60}`;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// Vérifie si la date est en heure d'été (Daylight Saving Time)
|
|
658
|
+
isDST(): boolean | undefined {
|
|
659
|
+
if (!this._date) return undefined;
|
|
660
|
+
|
|
661
|
+
try {
|
|
662
|
+
const jan = new Date(this._date.getFullYear(), 0, 1);
|
|
663
|
+
const jul = new Date(this._date.getFullYear(), 6, 1);
|
|
664
|
+
|
|
665
|
+
const stdOffset = Math.max(
|
|
666
|
+
jan.getTimezoneOffset(),
|
|
667
|
+
jul.getTimezoneOffset()
|
|
668
|
+
);
|
|
669
|
+
|
|
670
|
+
return this._date.getTimezoneOffset() < stdOffset;
|
|
671
|
+
} catch (error) {
|
|
672
|
+
return undefined;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
private static parseString(dateString: string, enableException: boolean = false): Date | undefined {
|
|
677
|
+
const isoDate = new Date(dateString);
|
|
678
|
+
if (!isNaN(isoDate.getTime())) {
|
|
679
|
+
return isoDate;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
const formats = [
|
|
683
|
+
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\.(\d{3})Z$/,
|
|
684
|
+
/^(\d{4})-(\d{2})-(\d{2})$/,
|
|
685
|
+
/^(\d{4})\/(\d{2})\/(\d{2}) (\d{2}):(\d{2}):(\d{2})$/,
|
|
686
|
+
/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/
|
|
687
|
+
];
|
|
688
|
+
|
|
689
|
+
for (const regex of formats) {
|
|
690
|
+
const match = dateString.match(regex);
|
|
691
|
+
if (match) {
|
|
692
|
+
const components = match.slice(1).map(Number);
|
|
693
|
+
if (regex === formats[0]) {
|
|
694
|
+
// ISO with milliseconds
|
|
695
|
+
return new Date(Date.UTC(components[0], components[1] - 1, components[2], components[3], components[4], components[5], components[6]));
|
|
696
|
+
} else if (regex === formats[1]) {
|
|
697
|
+
// Date only
|
|
698
|
+
return new Date(components[0], components[1] - 1, components[2]);
|
|
699
|
+
} else if (regex === formats[2]) {
|
|
700
|
+
// Slash format
|
|
701
|
+
return new Date(components[0], components[1] - 1, components[2], components[3], components[4], components[5]);
|
|
702
|
+
} else if (regex === formats[3]) {
|
|
703
|
+
// Compact format
|
|
704
|
+
return new Date(components[0], components[1] - 1, components[2], components[3], components[4], components[5]);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
const fallback = new Date(dateString);
|
|
710
|
+
if (!isNaN(fallback.getTime())) {
|
|
711
|
+
return fallback;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
if (!!enableException) {
|
|
715
|
+
throw new Error(`Unable to parse date string: ${dateString}`);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
private static parseWithFormat(value: any, format: string): Timez | undefined {
|
|
720
|
+
if (!value || !format) return undefined;
|
|
721
|
+
|
|
722
|
+
const valueStr = String(value).trim();
|
|
723
|
+
if (!valueStr) return undefined;
|
|
724
|
+
|
|
725
|
+
// Table de mapping des tokens vers les regex et les extracteurs
|
|
726
|
+
const tokenHandlers: { [key: string]: { regex: RegExp, extract: (match: string) => number } } = {
|
|
727
|
+
'Y': {
|
|
728
|
+
regex: /\d{4}/,
|
|
729
|
+
extract: (match) => parseInt(match, 10)
|
|
730
|
+
},
|
|
731
|
+
'y': {
|
|
732
|
+
regex: /\d{2}/,
|
|
733
|
+
extract: (match) => {
|
|
734
|
+
const year = parseInt(match, 10);
|
|
735
|
+
return year >= 70 ? 1900 + year : 2000 + year;
|
|
736
|
+
}
|
|
737
|
+
},
|
|
738
|
+
'm': {
|
|
739
|
+
regex: /\d{1,2}/,
|
|
740
|
+
extract: (match) => parseInt(match, 10)
|
|
741
|
+
},
|
|
742
|
+
'd': {
|
|
743
|
+
regex: /\d{1,2}/,
|
|
744
|
+
extract: (match) => parseInt(match, 10)
|
|
745
|
+
},
|
|
746
|
+
'H': {
|
|
747
|
+
regex: /\d{1,2}/,
|
|
748
|
+
extract: (match) => parseInt(match, 10)
|
|
749
|
+
},
|
|
750
|
+
'M': {
|
|
751
|
+
regex: /\d{1,2}/,
|
|
752
|
+
extract: (match) => parseInt(match, 10)
|
|
753
|
+
},
|
|
754
|
+
'S': {
|
|
755
|
+
regex: /\d{1,2}/,
|
|
756
|
+
extract: (match) => parseInt(match, 10)
|
|
757
|
+
},
|
|
758
|
+
'f': {
|
|
759
|
+
regex: /\d{1,3}/,
|
|
760
|
+
extract: (match) => parseInt(match, 10)
|
|
761
|
+
}
|
|
762
|
+
};
|
|
763
|
+
|
|
764
|
+
const result = {
|
|
765
|
+
year: new Date().getFullYear(),
|
|
766
|
+
month: 1,
|
|
767
|
+
day: 1,
|
|
768
|
+
hour: 0,
|
|
769
|
+
minute: 0,
|
|
770
|
+
second: 0,
|
|
771
|
+
millisecond: 0
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
let valueIndex = 0;
|
|
775
|
+
let formatIndex = 0;
|
|
776
|
+
let inLiteral = false;
|
|
777
|
+
let currentLiteral = '';
|
|
778
|
+
|
|
779
|
+
while (formatIndex < format.length && valueIndex < valueStr.length) {
|
|
780
|
+
const formatChar = format[formatIndex];
|
|
781
|
+
|
|
782
|
+
if (formatChar === '[') {
|
|
783
|
+
// Début d'un littéral
|
|
784
|
+
inLiteral = true;
|
|
785
|
+
currentLiteral = '';
|
|
786
|
+
formatIndex++;
|
|
787
|
+
} else if (formatChar === ']' && inLiteral) {
|
|
788
|
+
// Fin d'un littéral - vérifier qu'il correspond dans la valeur
|
|
789
|
+
if (valueStr.substring(valueIndex, valueIndex + currentLiteral.length) === currentLiteral) {
|
|
790
|
+
valueIndex += currentLiteral.length;
|
|
791
|
+
} else {
|
|
792
|
+
// Littéral non trouvé, échec du parsing
|
|
793
|
+
return undefined;
|
|
794
|
+
}
|
|
795
|
+
inLiteral = false;
|
|
796
|
+
currentLiteral = '';
|
|
797
|
+
formatIndex++;
|
|
798
|
+
} else if (inLiteral) {
|
|
799
|
+
// Accumuler le littéral
|
|
800
|
+
currentLiteral += formatChar;
|
|
801
|
+
formatIndex++;
|
|
802
|
+
} else if (formatChar === '%' && formatIndex + 1 < format.length) {
|
|
803
|
+
// Token de format
|
|
804
|
+
const token = format[formatIndex + 1];
|
|
805
|
+
const handler = tokenHandlers[token];
|
|
806
|
+
|
|
807
|
+
if (handler) {
|
|
808
|
+
// Trouver la partie correspondante dans la valeur
|
|
809
|
+
const remainingValue = valueStr.substring(valueIndex);
|
|
810
|
+
const match = remainingValue.match(handler.regex);
|
|
811
|
+
|
|
812
|
+
if (match && match.index === 0) {
|
|
813
|
+
const matchedValue = match[0];
|
|
814
|
+
const numericValue = handler.extract(matchedValue);
|
|
815
|
+
|
|
816
|
+
// Assigner la valeur au composant correspondant
|
|
817
|
+
switch (token) {
|
|
818
|
+
case 'Y':
|
|
819
|
+
case 'y':
|
|
820
|
+
result.year = numericValue;
|
|
821
|
+
break;
|
|
822
|
+
case 'm':
|
|
823
|
+
result.month = numericValue;
|
|
824
|
+
break;
|
|
825
|
+
case 'd':
|
|
826
|
+
result.day = numericValue;
|
|
827
|
+
break;
|
|
828
|
+
case 'H':
|
|
829
|
+
result.hour = numericValue;
|
|
830
|
+
break;
|
|
831
|
+
case 'M':
|
|
832
|
+
result.minute = numericValue;
|
|
833
|
+
break;
|
|
834
|
+
case 'S':
|
|
835
|
+
result.second = numericValue;
|
|
836
|
+
break;
|
|
837
|
+
case 'f':
|
|
838
|
+
result.millisecond = numericValue;
|
|
839
|
+
break;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
valueIndex += matchedValue.length;
|
|
843
|
+
} else {
|
|
844
|
+
// Token non trouvé, échec du parsing
|
|
845
|
+
return undefined;
|
|
846
|
+
}
|
|
847
|
+
} else {
|
|
848
|
+
// Token non reconnu, avancer d'un caractère
|
|
849
|
+
valueIndex++;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
formatIndex += 2;
|
|
853
|
+
} else {
|
|
854
|
+
// Caractère littéral - doit correspondre exactement
|
|
855
|
+
if (formatChar === valueStr[valueIndex]) {
|
|
856
|
+
valueIndex++;
|
|
857
|
+
formatIndex++;
|
|
858
|
+
} else {
|
|
859
|
+
// Caractère ne correspond pas, échec du parsing
|
|
860
|
+
return undefined;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
// Validation des valeurs
|
|
866
|
+
if (result.month < 1 || result.month > 12) return undefined;
|
|
867
|
+
if (result.day < 1 || result.day > 31) return undefined;
|
|
868
|
+
if (result.hour < 0 || result.hour > 23) return undefined;
|
|
869
|
+
if (result.minute < 0 || result.minute > 59) return undefined;
|
|
870
|
+
if (result.second < 0 || result.second > 59) return undefined;
|
|
871
|
+
if (result.millisecond < 0 || result.millisecond > 999) return undefined;
|
|
872
|
+
|
|
873
|
+
try {
|
|
874
|
+
const date = new Date(
|
|
875
|
+
result.year,
|
|
876
|
+
result.month - 1, // Mois 0-indexed en JS
|
|
877
|
+
result.day,
|
|
878
|
+
result.hour,
|
|
879
|
+
result.minute,
|
|
880
|
+
result.second,
|
|
881
|
+
result.millisecond
|
|
882
|
+
);
|
|
883
|
+
|
|
884
|
+
// Vérifier que la date est valide
|
|
885
|
+
if (isNaN(date.getTime())) {
|
|
886
|
+
return undefined;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
return new Timez(date);
|
|
890
|
+
} catch (error) {
|
|
891
|
+
return undefined;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
private static getTokenLength(token: string): number {
|
|
896
|
+
const tokenLengths: { [key: string]: number } = {
|
|
897
|
+
'Y': 4, // 4 digits pour l'année
|
|
898
|
+
'y': 2, // 2 digits pour l'année
|
|
899
|
+
'm': 2, // 2 digits pour le mois
|
|
900
|
+
'd': 2, // 2 digits pour le jour
|
|
901
|
+
'H': 2, // 2 digits pour l'heure
|
|
902
|
+
'M': 2, // 2 digits pour les minutes
|
|
903
|
+
'S': 2, // 2 digits pour les secondes
|
|
904
|
+
'f': 3, // 3 digits pour les millisecondes
|
|
905
|
+
'z': 5 // ±HHMM pour le timezone
|
|
906
|
+
};
|
|
907
|
+
return tokenLengths[token] || 1;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
private parseTimezoneOffset(timezone: string): number {
|
|
911
|
+
const offsets: { [key: string]: number } = {
|
|
912
|
+
'UTC': 0,
|
|
913
|
+
'EST': -300, // -5 hours
|
|
914
|
+
'EDT': -240, // -4 hours
|
|
915
|
+
'CST': -360, // -6 hours
|
|
916
|
+
'CDT': -300, // -5 hours
|
|
917
|
+
'PST': -480, // -8 hours
|
|
918
|
+
'PDT': -420, // -7 hours
|
|
919
|
+
};
|
|
920
|
+
|
|
921
|
+
if (offsets[timezone.toUpperCase()] !== undefined) {
|
|
922
|
+
return offsets[timezone.toUpperCase()];
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
// Gérer les formats ±HH:MM, ±HHMM, ±HH
|
|
926
|
+
const match = timezone.match(/^([+-])(\d{1,2}):?(\d{2})?$/);
|
|
927
|
+
if (match) {
|
|
928
|
+
const sign = match[1] === '+' ? 1 : -1;
|
|
929
|
+
const hours = parseInt(match[2], 10);
|
|
930
|
+
const minutes = match[3] ? parseInt(match[3], 10) : 0;
|
|
931
|
+
return sign * (hours * 60 + minutes);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
return this._date ? -this._date.getTimezoneOffset() : 0;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
static get FORMATS() {
|
|
938
|
+
return { ...Timez.PREDEFINED_FORMATS };
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
static exposeToGlobal(): void {
|
|
942
|
+
if (typeof window !== 'undefined') {
|
|
943
|
+
(window as any).Timez = Timez;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
if (typeof window !== 'undefined') {
|
|
949
|
+
(window as any).Timez = Timez;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
|
|
953
|
+
|
|
954
|
+
|
|
955
|
+
|
|
956
|
+
|
|
957
|
+
|
|
958
|
+
|
|
959
|
+
|
|
960
|
+
|
|
961
|
+
|
|
962
|
+
class Cooks {
|
|
963
|
+
private static DEFAULT_OPTIONS: CooksOptions = {
|
|
964
|
+
path: '/',
|
|
965
|
+
secure: true,
|
|
966
|
+
sameSite: 'lax' as const
|
|
967
|
+
};
|
|
968
|
+
|
|
969
|
+
public static set<T extends Serializable>(key: string, value: T, options: CooksOptions = {}): void {
|
|
970
|
+
if (!this.isBrowser()) return;
|
|
971
|
+
|
|
972
|
+
try {
|
|
973
|
+
const serializedValue = this.serialize(value);
|
|
974
|
+
const encodedValue = encodeURIComponent(serializedValue);
|
|
975
|
+
const cookieString = this.buildCookieString(key, encodedValue, options);
|
|
976
|
+
|
|
977
|
+
document.cookie = cookieString;
|
|
978
|
+
} catch (error) {
|
|
979
|
+
console.error(`Cooks: Error setting cookie "${key}":`, error);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
public static get<T extends Serializable>(key: string): T | null {
|
|
984
|
+
if (!this.isBrowser()) return null;
|
|
985
|
+
|
|
986
|
+
try {
|
|
987
|
+
const cookies = this.getAllCookies();
|
|
988
|
+
const encodedValue = cookies[key];
|
|
989
|
+
|
|
990
|
+
if (!encodedValue) return null;
|
|
991
|
+
|
|
992
|
+
const decodedValue = decodeURIComponent(encodedValue);
|
|
993
|
+
return this.deserialize<T>(decodedValue);
|
|
994
|
+
} catch (error) {
|
|
995
|
+
console.error(`Cooks: Error getting cookie "${key}":`, error);
|
|
996
|
+
return null;
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
public static remove(key: string, path: string = '/', domain?: string): void {
|
|
1001
|
+
if (!this.isBrowser()) return;
|
|
1002
|
+
|
|
1003
|
+
const options: CooksOptions = {
|
|
1004
|
+
expires: new Date(0),
|
|
1005
|
+
path,
|
|
1006
|
+
domain
|
|
1007
|
+
};
|
|
1008
|
+
|
|
1009
|
+
this.set(key, '', options);
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
public static has(key: string): boolean {
|
|
1013
|
+
return this.get(key) !== null;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
public static keys(): string[] {
|
|
1017
|
+
if (!this.isBrowser()) return [];
|
|
1018
|
+
|
|
1019
|
+
const cookies = this.getAllCookies();
|
|
1020
|
+
return Object.keys(cookies);
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
public static clear(): void {
|
|
1024
|
+
if (!this.isBrowser()) return;
|
|
1025
|
+
|
|
1026
|
+
const cookies = this.getAllCookies();
|
|
1027
|
+
Object.keys(cookies).forEach(key => {
|
|
1028
|
+
this.remove(key);
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
private static serialize(value: Serializable): string {
|
|
1033
|
+
if (value instanceof Date) {
|
|
1034
|
+
return JSON.stringify({
|
|
1035
|
+
__type: 'Date',
|
|
1036
|
+
__value: value.toISOString()
|
|
1037
|
+
});
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
return JSON.stringify(value);
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
private static deserialize<T>(value: string): T {
|
|
1044
|
+
const parsed = JSON.parse(value);
|
|
1045
|
+
|
|
1046
|
+
if (parsed && typeof parsed === 'object' && parsed.__type === 'Date') {
|
|
1047
|
+
return new Date(parsed.__value) as T;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
return parsed as T;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
private static buildCookieString(key: string, value: string, options: CooksOptions): string {
|
|
1054
|
+
const mergedOptions = { ...this.DEFAULT_OPTIONS, ...options };
|
|
1055
|
+
let cookieString = `${key}=${value}`;
|
|
1056
|
+
|
|
1057
|
+
if (mergedOptions.expires !== undefined) {
|
|
1058
|
+
let expirationDate: Date;
|
|
1059
|
+
|
|
1060
|
+
if (typeof mergedOptions.expires === 'number') {
|
|
1061
|
+
const expirationDateInitial = new Timez().add(mergedOptions.expires, 'seconds').toDate();
|
|
1062
|
+
|
|
1063
|
+
if(!!expirationDateInitial) {
|
|
1064
|
+
expirationDate = expirationDateInitial;
|
|
1065
|
+
} else {
|
|
1066
|
+
expirationDate = new Date();
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
} else {
|
|
1070
|
+
|
|
1071
|
+
expirationDate = mergedOptions.expires;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
cookieString += `; expires=${expirationDate.toUTCString()}`;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
if (mergedOptions.path) cookieString += `; path=${mergedOptions.path}`;
|
|
1078
|
+
if (mergedOptions.domain) cookieString += `; domain=${mergedOptions.domain}`;
|
|
1079
|
+
if (mergedOptions.secure) cookieString += `; secure`;
|
|
1080
|
+
if (mergedOptions.sameSite) cookieString += `; samesite=${mergedOptions.sameSite}`;
|
|
1081
|
+
|
|
1082
|
+
if(NODEENV === 'development') {
|
|
1083
|
+
console.log(`Cooks - buildCookieString | cookieString:: `, cookieString);
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
return cookieString;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
private static getAllCookies(): Record<string, string> {
|
|
1090
|
+
return document.cookie
|
|
1091
|
+
.split(';')
|
|
1092
|
+
.reduce((cookies, cookie) => {
|
|
1093
|
+
const [key, value] = cookie.split('=').map(part => part.trim());
|
|
1094
|
+
if (key) {
|
|
1095
|
+
cookies[key] = value || '';
|
|
1096
|
+
}
|
|
1097
|
+
return cookies;
|
|
1098
|
+
}, {} as Record<string, string>);
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
private static isBrowser(): boolean {
|
|
1102
|
+
return typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
1103
|
+
}
|
|
1104
|
+
static exposeToGlobal(): void {
|
|
1105
|
+
if (typeof window !== "undefined") {
|
|
1106
|
+
(window as any).Cooks = Cooks;
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
if (typeof window !== "undefined") {
|
|
1112
|
+
(window as any).Cooks = Cooks;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
|
|
1116
|
+
|
|
1117
|
+
|
|
1118
|
+
const globalFunctModule = {
|
|
1119
|
+
default: Cooks,
|
|
1120
|
+
Cooks: Cooks,
|
|
1121
|
+
};
|
|
1122
|
+
|
|
1123
|
+
|
|
1124
|
+
const __bundledModules = globalFunctModule;
|
|
1125
|
+
|
|
1126
|
+
if (typeof global !== 'undefined') {
|
|
1127
|
+
(global as any).default = Cooks;
|
|
1128
|
+
(global as any).Cooks = Cooks;
|
|
1129
|
+
(global as any).__bundledModules = __bundledModules;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
if (typeof window !== "undefined") {
|
|
1133
|
+
(window as any).default = Cooks;
|
|
1134
|
+
(window as any).Cooks = Cooks;
|
|
1135
|
+
(window as any).__bundledModules = __bundledModules;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
if (typeof exports !== 'undefined') {
|
|
1139
|
+
exports.default = Cooks;
|
|
1140
|
+
exports.Cooks = Cooks;
|
|
1141
|
+
}
|
|
1142
|
+
return globalFunctModule;
|
|
1143
|
+
|
|
1144
|
+
})(typeof global !== 'undefined' ? global :
|
|
1145
|
+
typeof window !== 'undefined' ? window :
|
|
1146
|
+
typeof self !== 'undefined' ? self :
|
|
1147
|
+
typeof globalThis !== 'undefined' ? globalThis :
|
|
1148
|
+
{});
|
|
1149
|
+
|
|
1150
|
+
type CooksElementTypeGF = typeof globalFunct.Cooks;
|
|
1151
|
+
|
|
1152
|
+
type DefaultElementTypeGF = typeof globalFunct.default;
|
|
1153
|
+
|
|
1154
|
+
const CooksElementGF: CooksElementTypeGF = globalFunct.Cooks;
|
|
1155
|
+
|
|
1156
|
+
const defaultElementGF: DefaultElementTypeGF = globalFunct.default;
|
|
1157
|
+
|
|
1158
|
+
|
|
1159
|
+
|