@bereasoftware/time-guard 2.5.1 → 2.5.3

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 (53) hide show
  1. package/README.en.md +7 -4
  2. package/README.md +7 -4
  3. package/dist/calendars/index.es.js +1 -1
  4. package/dist/plugins/advanced-format.cjs +1 -1
  5. package/dist/plugins/advanced-format.cjs.map +1 -1
  6. package/dist/plugins/advanced-format.es.js +1 -53
  7. package/dist/plugins/advanced-format.es.js.map +1 -1
  8. package/dist/plugins/duration.cjs.map +1 -1
  9. package/dist/plugins/duration.es.js +1 -1
  10. package/dist/plugins/duration.es.js.map +1 -1
  11. package/dist/plugins/relative-time.cjs.map +1 -1
  12. package/dist/plugins/relative-time.es.js +1 -1
  13. package/dist/plugins/relative-time.es.js.map +1 -1
  14. package/dist/time-guard.cjs +3 -1
  15. package/dist/time-guard.cjs.map +1 -1
  16. package/dist/time-guard.es.js +11014 -3948
  17. package/dist/time-guard.es.js.map +1 -1
  18. package/dist/time-guard.iife.js +3 -1
  19. package/dist/time-guard.iife.js.map +1 -1
  20. package/dist/time-guard.umd.js +3 -1
  21. package/dist/time-guard.umd.js.map +1 -1
  22. package/dist/types/calendars/index.d.ts +1 -81
  23. package/dist/types/index.d.ts +1 -20
  24. package/dist/types/locales/index.d.ts +1 -17
  25. package/dist/types/plugins/advanced-format.d.ts +1 -0
  26. package/dist/types/plugins/duration.d.ts +1 -0
  27. package/dist/types/plugins/relative-time.d.ts +1 -0
  28. package/package.json +6 -7
  29. package/dist/types/adapters/temporal.adapter.d.ts +0 -66
  30. package/dist/types/calendars/calendar.manager.d.ts +0 -52
  31. package/dist/types/formatters/date.formatter.d.ts +0 -21
  32. package/dist/types/locales/additional.locale.d.ts +0 -5
  33. package/dist/types/locales/asian.locale.d.ts +0 -9
  34. package/dist/types/locales/english.locale.d.ts +0 -6
  35. package/dist/types/locales/european.locale.d.ts +0 -9
  36. package/dist/types/locales/locale.manager.d.ts +0 -42
  37. package/dist/types/locales/locales-data.d.ts +0 -17
  38. package/dist/types/locales/middle-eastern.locale.d.ts +0 -5
  39. package/dist/types/locales/nordic.locale.d.ts +0 -6
  40. package/dist/types/locales/romance.locale.d.ts +0 -7
  41. package/dist/types/locales/slavic.locale.d.ts +0 -6
  42. package/dist/types/locales/spanish.locale.d.ts +0 -5
  43. package/dist/types/plugins/advanced-format/index.d.ts +0 -47
  44. package/dist/types/plugins/duration/index.d.ts +0 -107
  45. package/dist/types/plugins/duration/types.d.ts +0 -85
  46. package/dist/types/plugins/index.d.ts +0 -10
  47. package/dist/types/plugins/manager.d.ts +0 -58
  48. package/dist/types/plugins/relative-time/index.d.ts +0 -39
  49. package/dist/types/plugins/relative-time/types.d.ts +0 -27
  50. package/dist/types/polyfill-loader.d.ts +0 -6
  51. package/dist/types/time-guard.d.ts +0 -426
  52. package/dist/types/types/index.d.ts +0 -578
  53. package/dist/types/utils/duration-locale.d.ts +0 -33
package/README.en.md CHANGED
@@ -894,8 +894,10 @@ console.log(formatUserDate(date, "ja")); // 水曜日、2024年3月13日 14:30
894
894
  #### Getting Available Locales Programmatically
895
895
 
896
896
  ```typescript
897
+ import { getAvailableLocales } from "@bereasoftware/time-guard";
898
+
897
899
  // Get all available locales
898
- const locales = TimeGuard.getAvailableLocales();
900
+ const locales = getAvailableLocales();
899
901
  // Returns: ['en', 'en-au', 'en-gb', 'en-ca', 'es', 'es-mx', 'es-us', ...]
900
902
 
901
903
  // Filter by prefix
@@ -907,7 +909,7 @@ const asianLocales = locales.filter((l) =>
907
909
 
908
910
  // Create locale selector UI
909
911
  function createLocaleSelector() {
910
- const locales = TimeGuard.getAvailableLocales();
912
+ const locales = getAvailableLocales();
911
913
  return locales.map((locale) => ({
912
914
  code: locale,
913
915
  label: new Intl.DisplayNames("en", { type: "language" }).of(locale),
@@ -1357,7 +1359,8 @@ inNYC.format("YYYY-MM-DD HH:mm:ss Z"); // 2024-03-13 10:30:00 -04:00
1357
1359
  inTokyo.format("YYYY-MM-DD HH:mm:ss Z"); // 2024-03-13 23:30:00 +09:00
1358
1360
 
1359
1361
  // Get all available locales
1360
- TimeGuard.getAvailableLocales(); // Array of 40+ locale codes
1362
+ import { getAvailableLocales } from "@bereasoftware/time-guard";
1363
+ getAvailableLocales(); // Array of 40+ locale codes
1361
1364
  ```
1362
1365
 
1363
1366
  ### 🎨 Format Patterns
@@ -1521,7 +1524,7 @@ time-guard/
1521
1524
  ├── src/
1522
1525
  │ ├── index.ts # Lightweight core (~5KB gzip, EN/ES)
1523
1526
  │ ├── polyfill-loader.ts # Temporal polyfill loader
1524
- │ ├── time-guard.ts # Main class
1527
+ │ ├── index.ts # Main class and entry point
1525
1528
  │ ├── adapters/
1526
1529
  │ │ └── temporal.adapter.ts # Temporal API wrapper
1527
1530
  │ ├── calendars/ # 6 calendar systems
package/README.md CHANGED
@@ -957,8 +957,10 @@ console.log(formatUserDate(date, 'ja')); // 水曜日、2024年3月13日 14:30
957
957
  #### Obtener Locales Disponibles Programáticamente
958
958
 
959
959
  ```typescript
960
+ import { getAvailableLocales } from "@bereasoftware/time-guard";
961
+
960
962
  // Get all available locales
961
- const locales = TimeGuard.getAvailableLocales();
963
+ const locales = getAvailableLocales();
962
964
  // Returns: ['en', 'en-au', 'en-gb', 'en-ca', 'es', 'es-mx', 'es-us', ...]
963
965
 
964
966
  // Filter by prefix
@@ -970,7 +972,7 @@ const asianLocales = locales.filter((l) =>
970
972
 
971
973
  // Create locale selector UI
972
974
  function createLocaleSelector() {
973
- const locales = TimeGuard.getAvailableLocales();
975
+ const locales = getAvailableLocales();
974
976
  return locales.map((locale) => ({
975
977
  code: locale,
976
978
  label: new Intl.DisplayNames('en', { type: 'language' }).of(locale),
@@ -1440,7 +1442,8 @@ inNYC.format('YYYY-MM-DD HH:mm:ss Z'); // 2024-03-13 10:30:00 -04:00
1440
1442
  inTokyo.format('YYYY-MM-DD HH:mm:ss Z'); // 2024-03-13 23:30:00 +09:00
1441
1443
 
1442
1444
  // Get all available locales
1443
- TimeGuard.getAvailableLocales(); // Array of 40+ locale codes
1445
+ import { getAvailableLocales } from "@bereasoftware/time-guard";
1446
+ getAvailableLocales(); // Array of 40+ locale codes
1444
1447
  ```
1445
1448
 
1446
1449
  ### 🎨 Format Patterns
@@ -1705,7 +1708,7 @@ time-guard/
1705
1708
  ├── src/
1706
1709
  │ ├── index.ts # Core ligero (~5KB gzip, EN/ES)
1707
1710
  │ ├── polyfill-loader.ts # Cargador del polyfill Temporal
1708
- │ ├── time-guard.ts # Clase principal
1711
+ │ ├── index.ts # Clase principal y punto de entrada
1709
1712
  │ ├── adapters/
1710
1713
  │ │ └── temporal.adapter.ts # Wrapper del API Temporal
1711
1714
  │ ├── calendars/ # 6 sistemas de calendario
@@ -1,4 +1,4 @@
1
- /*! time-guard v2.5.1 | (c) 2026 Berea-Soft | MIT License | https://github.com/Berea-Soft/time-guard */
1
+ /*! time-guard v2.5.3 | (c) 2026 Berea-Soft | MIT License | https://github.com/Berea-Soft/time-guard */
2
2
  //#region src/calendars/index.ts
3
3
  var e = class {
4
4
  id = "islamic";
@@ -1,2 +1,2 @@
1
- Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});var e=class{name=`advanced-format`;version=`1.0.0`;install(e){let t=e.prototype.format;e.prototype.format=function(e){if(!e||typeof e!=`string`||!/Q|Do|w|W|gggg|GGGG|k{1,2}|X|x|zzz?/.test(e))return t.call(this,e);let n=this.toTemporal(),r=`toPlainDateTime`in n?n.toPlainDateTime():n,i=e=>{let t=[`th`,`st`,`nd`,`rd`],n=e%100;return e+(t[(n-20)%10]||t[n]||t[0])},a=(e,t)=>String(e).padStart(t,`0`),o=e=>{let t=new Date(e.year,0,4),n=new Date(t);n.setDate(t.getDate()-t.getDay()+(t.getDay()===0?-6:1));let r=new Date(e.year,e.month-1,e.day),i=Math.floor((r.getTime()-n.getTime())/(10080*60*1e3))+1;return Math.max(1,i)},s=e=>{let t=Math.ceil((e.day+new Date(e.year,e.month-1,1).getDay())/7);return Math.max(1,t)},c=e=>{let t=new Date(e.year,e.month-1,e.day),n=t.getTime()<new Date(e.year,0,1).getTime()?-1:+(t.getTime()>=new Date(e.year+1,0,1).getTime());return e.year+n},l=e=>{let t=e.month===1&&e.day<4?-1:+(e.month===12&&e.day>28);return e.year+t},u=e.replace(/Q|Do|w|W|gggg|GGGG|k{1,2}|X|x|zzz?/g,e=>{let t=``;switch(e){case`Q`:t=String(Math.ceil(r.month/3));break;case`Do`:t=i(r.day);break;case`W`:case`WW`:t=a(o(r),e===`W`?1:2);break;case`w`:case`ww`:t=a(s(r),e===`w`?1:2);break;case`GGGG`:t=String(c(r));break;case`gggg`:t=String(l(r));break;case`k`:case`kk`:t=a(r.hour===0?24:r.hour,e===`k`?1:2);break;case`X`:t=String(Math.floor(this.valueOf()/1e3));break;case`x`:t=String(this.valueOf());break;case`z`:t=`${this.getTimezoneOffset()}`;break;case`zzz`:t=`${this.getTimezoneOffsetLong()}`;break;default:return e}return`[${t}]`});return t.call(this,u)}}getOrdinal(e){let t=[`th`,`st`,`nd`,`rd`],n=e%100;return e+(t[(n-20)%10]||t[n]||t[0])}padNumber(e,t){return String(e).padStart(t,`0`)}getISOWeek(e){let t=new Date(e.year,0,4),n=new Date(t);n.setDate(t.getDate()-t.getDay()+(t.getDay()===0?-6:1));let r=new Date(e.year,e.month-1,e.day),i=Math.floor((r.getTime()-n.getTime())/(10080*60*1e3))+1;return Math.max(1,i)}getWeekOfYear(e){let t=Math.ceil((e.day+new Date(e.year,e.month-1,1).getDay())/7);return Math.max(1,t)}getISOWeekYear(e){let t=new Date(e.year,e.month-1,e.day),n=t.getTime()<new Date(e.year,0,1).getTime()?-1:+(t.getTime()>=new Date(e.year+1,0,1).getTime());return e.year+n}getWeekYear(e){let t=e.month===1&&e.day<4?-1:+(e.month===12&&e.day>28);return e.year+t}getTimezoneOffset(){try{let e=new Date;return new Intl.DateTimeFormat(`en-US`,{timeZone:`UTC`,timeZoneName:`short`}).formatToParts(e).find(e=>e.type===`timeZoneName`)?.value||`UTC`}catch{return`UTC`}}getTimezoneOffsetLong(){try{let e=new Date;return new Intl.DateTimeFormat(`en-US`,{timeZone:`UTC`,timeZoneName:`long`}).formatToParts(e).find(e=>e.type===`timeZoneName`)?.value||`Coordinated Universal Time`}catch{return`Coordinated Universal Time`}}},t=new e;exports.AdvancedFormatPlugin=e,exports.default=t;
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});var e=class{name=`advanced-format`;version=`1.0.0`;install(e){let t=e.prototype.format;e.prototype.format=function(e){if(!e||typeof e!=`string`||!/Q|Do|w|W|gggg|GGGG|k{1,2}|X|x|zzz?/.test(e))return t.call(this,e);let n=this.toTemporal(),r=`toPlainDateTime`in n?n.toPlainDateTime():n,i=e=>{let t=[`th`,`st`,`nd`,`rd`],n=e%100;return e+(t[(n-20)%10]||t[n]||t[0])},a=(e,t)=>String(e).padStart(t,`0`),o=e=>{let t=new Date(e.year,0,4),n=new Date(t);n.setDate(t.getDate()-t.getDay()+(t.getDay()===0?-6:1));let r=new Date(e.year,e.month-1,e.day),i=Math.floor((r.getTime()-n.getTime())/(10080*60*1e3))+1;return Math.max(1,i)},s=e=>{let t=Math.ceil((e.day+new Date(e.year,e.month-1,1).getDay())/7);return Math.max(1,t)},c=e=>{let t=new Date(e.year,e.month-1,e.day),n=t.getTime()<new Date(e.year,0,1).getTime()?-1:+(t.getTime()>=new Date(e.year+1,0,1).getTime());return e.year+n},l=e=>{let t=e.month===1&&e.day<4?-1:+(e.month===12&&e.day>28);return e.year+t},u=e.replace(/Q|Do|w|W|gggg|GGGG|k{1,2}|X|x|zzz?/g,e=>{let t=``;switch(e){case`Q`:t=String(Math.ceil(r.month/3));break;case`Do`:t=i(r.day);break;case`W`:case`WW`:t=a(o(r),e===`W`?1:2);break;case`w`:case`ww`:t=a(s(r),e===`w`?1:2);break;case`GGGG`:t=String(c(r));break;case`gggg`:t=String(l(r));break;case`k`:case`kk`:t=a(r.hour===0?24:r.hour,e===`k`?1:2);break;case`X`:t=String(Math.floor(this.valueOf()/1e3));break;case`x`:t=String(this.valueOf());break;case`z`:t=`${this.getTimezoneOffset()}`;break;case`zzz`:t=`${this.getTimezoneOffsetLong()}`;break;default:return e}return`[${t}]`});return t.call(this,u)}}},t=new e;exports.AdvancedFormatPlugin=e,exports.default=t;
2
2
  //# sourceMappingURL=advanced-format.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"advanced-format.cjs","names":[],"sources":["../../src/plugins/advanced-format/index.ts"],"sourcesContent":["/**\r\n * TimeGuard Advanced Format Plugin\r\n * Adds advanced format tokens: Q (quarter), Do (ordinal), w (week), etc.\r\n * Follows SOLID principles and extends core formatting capabilities\r\n */\r\n\r\nimport type { ITimeGuardPlugin } from '../../types';\r\nimport type { TimeGuard } from '../../time-guard';\r\nimport type { Temporal } from '@js-temporal/polyfill';\r\n\r\nexport class AdvancedFormatPlugin implements ITimeGuardPlugin {\r\n name = 'advanced-format';\r\n version = '1.0.0';\r\n\r\n /**\r\n * Install plugin into TimeGuard\r\n */\r\n install(TimeGuardClass: typeof TimeGuard): void {\r\n // Store original format method\r\n const originalFormat = TimeGuardClass.prototype.format;\r\n\r\n /**\r\n * Extended format method with advanced tokens\r\n */\r\n (TimeGuardClass.prototype as any).format = function (pattern: string) {\r\n if (!pattern || typeof pattern !== 'string') {\r\n return originalFormat.call(this, pattern);\r\n }\r\n\r\n // Check if pattern contains advanced tokens\r\n if (!/Q|Do|w|W|gggg|GGGG|k{1,2}|X|x|zzz?/.test(pattern)) {\r\n return originalFormat.call(this, pattern);\r\n }\r\n\r\n // Get the underlying Temporal object\r\n const temporal = this.toTemporal();\r\n const temporal_dt =\r\n 'toPlainDateTime' in temporal\r\n ? (temporal as any).toPlainDateTime()\r\n : (temporal as Temporal.PlainDateTime);\r\n \r\n const ordinalFn = (n: number) => {\r\n const suffixes = ['th', 'st', 'nd', 'rd'];\r\n const v = n % 100;\r\n return n + (suffixes[(v - 20) % 10] || suffixes[v] || suffixes[0]);\r\n };\r\n const padFn = (n: number, length: number) => String(n).padStart(length, '0');\r\n const getISOWeek = (temporal: any) => {\r\n const jan4 = new Date(temporal.year, 0, 4);\r\n const week1Start = new Date(jan4);\r\n week1Start.setDate(jan4.getDate() - jan4.getDay() + (jan4.getDay() === 0 ? -6 : 1));\r\n const currentDate = new Date(temporal.year, temporal.month - 1, temporal.day);\r\n const weekNum = Math.floor((currentDate.getTime() - week1Start.getTime()) / (7 * 24 * 60 * 60 * 1000)) + 1;\r\n return Math.max(1, weekNum);\r\n };\r\n const getWeekOfYear = (temporal: any) => {\r\n const weekNum = Math.ceil(((temporal.day + new Date(temporal.year, temporal.month - 1, 1).getDay()) / 7));\r\n return Math.max(1, weekNum);\r\n };\r\n const getISOWeekYear = (temporal: any) => {\r\n const currentDate = new Date(temporal.year, temporal.month - 1, temporal.day);\r\n const yearAdjust = currentDate.getTime() < new Date(temporal.year, 0, 1).getTime() ? -1 : currentDate.getTime() >= new Date(temporal.year + 1, 0, 1).getTime() ? 1 : 0;\r\n return temporal.year + yearAdjust;\r\n };\r\n const getWeekYear = (temporal: any) => {\r\n const yearAdjust = temporal.month === 1 && temporal.day < 4 ? -1 : temporal.month === 12 && temporal.day > 28 ? 1 : 0;\r\n return temporal.year + yearAdjust;\r\n };\r\n\r\n // Replace advanced tokens - wrap results in brackets to protect from standard formatter\r\n let result = pattern.replace(\r\n /Q|Do|w|W|gggg|GGGG|k{1,2}|X|x|zzz?/g,\r\n (match) => {\r\n let replacement = '';\r\n switch (match) {\r\n // Quarter\r\n case 'Q':\r\n replacement = String(Math.ceil((temporal_dt.month) / 3));\r\n break;\r\n\r\n // Ordinal day\r\n case 'Do':\r\n replacement = ordinalFn(temporal_dt.day);\r\n break;\r\n\r\n // Week of year (ISO)\r\n case 'W':\r\n case 'WW':\r\n replacement = padFn(getISOWeek(temporal_dt), match === 'W' ? 1 : 2);\r\n break;\r\n\r\n // Week of year (locale)\r\n case 'w':\r\n case 'ww':\r\n replacement = padFn(getWeekOfYear(temporal_dt), match === 'w' ? 1 : 2);\r\n break;\r\n\r\n // ISO week year\r\n case 'GGGG':\r\n replacement = String(getISOWeekYear(temporal_dt));\r\n break;\r\n\r\n // Week year\r\n case 'gggg':\r\n replacement = String(getWeekYear(temporal_dt));\r\n break;\r\n\r\n // Hour (1-24)\r\n case 'k':\r\n case 'kk':\r\n const hour = temporal_dt.hour === 0 ? 24 : temporal_dt.hour;\r\n replacement = padFn(hour, match === 'k' ? 1 : 2);\r\n break;\r\n\r\n // Unix seconds timestamp\r\n case 'X':\r\n replacement = String(Math.floor(this.valueOf() / 1000));\r\n break;\r\n\r\n // Unix milliseconds timestamp\r\n case 'x':\r\n replacement = String(this.valueOf());\r\n break;\r\n\r\n // Timezone offset\r\n case 'z':\r\n replacement = `${this.getTimezoneOffset()}`;\r\n break;\r\n\r\n case 'zzz':\r\n replacement = `${this.getTimezoneOffsetLong()}`;\r\n break;\r\n\r\n default:\r\n return match;\r\n }\r\n // Wrap in brackets to protect from standard formatter\r\n return `[${replacement}]`;\r\n },\r\n );\r\n\r\n // Apply standard format to the result\r\n return originalFormat.call(this, result);\r\n };\r\n }\r\n\r\n /**\r\n * Get ordinal suffix (1st, 2nd, 3rd, etc.)\r\n */\r\n // @ts-expect-error - Method called dynamically within replace callback\r\n private getOrdinal(n: number): string {\r\n const suffixes = ['th', 'st', 'nd', 'rd'];\r\n const v = n % 100;\r\n return n + (suffixes[(v - 20) % 10] || suffixes[v] || suffixes[0]);\r\n }\r\n\r\n /**\r\n * Pad number with leading zeros\r\n */\r\n // @ts-expect-error - Method called dynamically within replace callback\r\n private padNumber(n: number, length: number): string {\r\n return String(n).padStart(length, '0');\r\n }\r\n\r\n /**\r\n * Get ISO week number\r\n */\r\n // @ts-expect-error - Method called dynamically within replace callback\r\n private getISOWeek(temporal: Temporal.PlainDateTime): number {\r\n // Simple ISO week calculation\r\n const jan4 = new Date(temporal.year, 0, 4);\r\n const week1Start = new Date(jan4);\r\n week1Start.setDate(jan4.getDate() - jan4.getDay() + (jan4.getDay() === 0 ? -6 : 1));\r\n\r\n const currentDate = new Date(temporal.year, temporal.month - 1, temporal.day);\r\n const weekNum = Math.floor(\r\n (currentDate.getTime() - week1Start.getTime()) / (7 * 24 * 60 * 60 * 1000),\r\n ) + 1;\r\n\r\n return Math.max(1, weekNum);\r\n }\r\n\r\n /**\r\n * Get week of year (locale-based)\r\n */\r\n // @ts-expect-error - Method called dynamically within replace callback\r\n private getWeekOfYear(temporal: Temporal.PlainDateTime): number {\r\n const weekNum = Math.ceil(\r\n ((temporal.day + new Date(temporal.year, temporal.month - 1, 1).getDay()) / 7),\r\n );\r\n return Math.max(1, weekNum);\r\n }\r\n\r\n /**\r\n * Get ISO week year\r\n */\r\n // @ts-expect-error - Method called dynamically within replace callback\r\n private getISOWeekYear(temporal: Temporal.PlainDateTime): number {\r\n const currentDate = new Date(temporal.year, temporal.month - 1, temporal.day);\r\n const yearAdjust =\r\n currentDate.getTime() < new Date(temporal.year, 0, 1).getTime()\r\n ? -1\r\n : currentDate.getTime() >= new Date(temporal.year + 1, 0, 1).getTime()\r\n ? 1\r\n : 0;\r\n\r\n return temporal.year + yearAdjust;\r\n }\r\n\r\n /**\r\n * Get week year\r\n */\r\n // @ts-expect-error - Method called dynamically within replace callback\r\n private getWeekYear(temporal: Temporal.PlainDateTime): number {\r\n const yearAdjust =\r\n temporal.month === 1 && temporal.day < 4\r\n ? -1\r\n : temporal.month === 12 && temporal.day > 28\r\n ? 1\r\n : 0;\r\n return temporal.year + yearAdjust;\r\n }\r\n\r\n /**\r\n * Get timezone offset short form\r\n */\r\n // @ts-expect-error - Method called dynamically within replace callback\r\n private getTimezoneOffset(): string {\r\n try {\r\n const now = new Date();\r\n const formatter = new Intl.DateTimeFormat('en-US', {\r\n timeZone: 'UTC',\r\n timeZoneName: 'short',\r\n });\r\n return formatter.formatToParts(now).find(p => p.type === 'timeZoneName')?.value || 'UTC';\r\n } catch {\r\n return 'UTC';\r\n }\r\n }\r\n\r\n /**\r\n * Get timezone offset long form\r\n */\r\n // @ts-expect-error - Method called dynamically within replace callback\r\n private getTimezoneOffsetLong(): string {\r\n try {\r\n const now = new Date();\r\n const formatter = new Intl.DateTimeFormat('en-US', {\r\n timeZone: 'UTC',\r\n timeZoneName: 'long',\r\n });\r\n return formatter.formatToParts(now).find(p => p.type === 'timeZoneName')?.value || 'Coordinated Universal Time';\r\n } catch {\r\n return 'Coordinated Universal Time';\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Create and export default instance\r\n */\r\nexport default new AdvancedFormatPlugin();\r\n"],"mappings":"+FAUA,IAAa,EAAb,KAA8D,CAC5D,KAAO,kBACP,QAAU,QAKV,QAAQ,EAAwC,CAE9C,IAAM,EAAiB,EAAe,UAAU,OAK/C,EAAe,UAAkB,OAAS,SAAU,EAAiB,CAMpE,GALI,CAAC,GAAW,OAAO,GAAY,UAK/B,CAAC,qCAAqC,KAAK,EAAQ,CACrD,OAAO,EAAe,KAAK,KAAM,EAAQ,CAI3C,IAAM,EAAW,KAAK,YAAY,CAC5B,EACJ,oBAAqB,EAChB,EAAiB,iBAAiB,CAClC,EAED,EAAa,GAAc,CAC/B,IAAM,EAAW,CAAC,KAAM,KAAM,KAAM,KAAK,CACnC,EAAI,EAAI,IACd,OAAO,GAAK,GAAU,EAAI,IAAM,KAAO,EAAS,IAAM,EAAS,KAE3D,GAAS,EAAW,IAAmB,OAAO,EAAE,CAAC,SAAS,EAAQ,IAAI,CACtE,EAAc,GAAkB,CACpC,IAAM,EAAO,IAAI,KAAK,EAAS,KAAM,EAAG,EAAE,CACpC,EAAa,IAAI,KAAK,EAAK,CACjC,EAAW,QAAQ,EAAK,SAAS,CAAG,EAAK,QAAQ,EAAI,EAAK,QAAQ,GAAK,EAAI,GAAK,GAAG,CACnF,IAAM,EAAc,IAAI,KAAK,EAAS,KAAM,EAAS,MAAQ,EAAG,EAAS,IAAI,CACvE,EAAU,KAAK,OAAO,EAAY,SAAS,CAAG,EAAW,SAAS,GAAK,MAAc,GAAK,KAAM,CAAG,EACzG,OAAO,KAAK,IAAI,EAAG,EAAQ,EAEvB,EAAiB,GAAkB,CACvC,IAAM,EAAU,KAAK,MAAO,EAAS,IAAM,IAAI,KAAK,EAAS,KAAM,EAAS,MAAQ,EAAG,EAAE,CAAC,QAAQ,EAAI,EAAG,CACzG,OAAO,KAAK,IAAI,EAAG,EAAQ,EAEvB,EAAkB,GAAkB,CACxC,IAAM,EAAc,IAAI,KAAK,EAAS,KAAM,EAAS,MAAQ,EAAG,EAAS,IAAI,CACvE,EAAa,EAAY,SAAS,CAAG,IAAI,KAAK,EAAS,KAAM,EAAG,EAAE,CAAC,SAAS,CAAG,GAAK,IAAY,SAAS,EAAI,IAAI,KAAK,EAAS,KAAO,EAAG,EAAG,EAAE,CAAC,SAAS,EAC9J,OAAO,EAAS,KAAO,GAEnB,EAAe,GAAkB,CACrC,IAAM,EAAa,EAAS,QAAU,GAAK,EAAS,IAAM,EAAI,GAAK,IAAS,QAAU,IAAM,EAAS,IAAM,IAC3G,OAAO,EAAS,KAAO,GAIrB,EAAS,EAAQ,QACnB,sCACC,GAAU,CACT,IAAI,EAAc,GAClB,OAAQ,EAAR,CAEE,IAAK,IACH,EAAc,OAAO,KAAK,KAAM,EAAY,MAAS,EAAE,CAAC,CACxD,MAGF,IAAK,KACH,EAAc,EAAU,EAAY,IAAI,CACxC,MAGF,IAAK,IACL,IAAK,KACH,EAAc,EAAM,EAAW,EAAY,CAAE,IAAU,IAAM,EAAI,EAAE,CACnE,MAGF,IAAK,IACL,IAAK,KACH,EAAc,EAAM,EAAc,EAAY,CAAE,IAAU,IAAM,EAAI,EAAE,CACtE,MAGF,IAAK,OACH,EAAc,OAAO,EAAe,EAAY,CAAC,CACjD,MAGF,IAAK,OACH,EAAc,OAAO,EAAY,EAAY,CAAC,CAC9C,MAGF,IAAK,IACL,IAAK,KAEH,EAAc,EADD,EAAY,OAAS,EAAI,GAAK,EAAY,KAC7B,IAAU,IAAM,EAAI,EAAE,CAChD,MAGF,IAAK,IACH,EAAc,OAAO,KAAK,MAAM,KAAK,SAAS,CAAG,IAAK,CAAC,CACvD,MAGF,IAAK,IACH,EAAc,OAAO,KAAK,SAAS,CAAC,CACpC,MAGF,IAAK,IACH,EAAc,GAAG,KAAK,mBAAmB,GACzC,MAEF,IAAK,MACH,EAAc,GAAG,KAAK,uBAAuB,GAC7C,MAEF,QACE,OAAO,EAGX,MAAO,IAAI,EAAY,IAE1B,CAGD,OAAO,EAAe,KAAK,KAAM,EAAO,EAQ5C,WAAmB,EAAmB,CACpC,IAAM,EAAW,CAAC,KAAM,KAAM,KAAM,KAAK,CACnC,EAAI,EAAI,IACd,OAAO,GAAK,GAAU,EAAI,IAAM,KAAO,EAAS,IAAM,EAAS,IAOjE,UAAkB,EAAW,EAAwB,CACnD,OAAO,OAAO,EAAE,CAAC,SAAS,EAAQ,IAAI,CAOxC,WAAmB,EAA0C,CAE3D,IAAM,EAAO,IAAI,KAAK,EAAS,KAAM,EAAG,EAAE,CACpC,EAAa,IAAI,KAAK,EAAK,CACjC,EAAW,QAAQ,EAAK,SAAS,CAAG,EAAK,QAAQ,EAAI,EAAK,QAAQ,GAAK,EAAI,GAAK,GAAG,CAEnF,IAAM,EAAc,IAAI,KAAK,EAAS,KAAM,EAAS,MAAQ,EAAG,EAAS,IAAI,CACvE,EAAU,KAAK,OAClB,EAAY,SAAS,CAAG,EAAW,SAAS,GAAK,MAAc,GAAK,KACtE,CAAG,EAEJ,OAAO,KAAK,IAAI,EAAG,EAAQ,CAO7B,cAAsB,EAA0C,CAC9D,IAAM,EAAU,KAAK,MACjB,EAAS,IAAM,IAAI,KAAK,EAAS,KAAM,EAAS,MAAQ,EAAG,EAAE,CAAC,QAAQ,EAAI,EAC7E,CACD,OAAO,KAAK,IAAI,EAAG,EAAQ,CAO7B,eAAuB,EAA0C,CAC/D,IAAM,EAAc,IAAI,KAAK,EAAS,KAAM,EAAS,MAAQ,EAAG,EAAS,IAAI,CACvE,EACJ,EAAY,SAAS,CAAG,IAAI,KAAK,EAAS,KAAM,EAAG,EAAE,CAAC,SAAS,CAC3D,GACA,IAAY,SAAS,EAAI,IAAI,KAAK,EAAS,KAAO,EAAG,EAAG,EAAE,CAAC,SAAS,EAI1E,OAAO,EAAS,KAAO,EAOzB,YAAoB,EAA0C,CAC5D,IAAM,EACJ,EAAS,QAAU,GAAK,EAAS,IAAM,EACnC,GACA,IAAS,QAAU,IAAM,EAAS,IAAM,IAG9C,OAAO,EAAS,KAAO,EAOzB,mBAAoC,CAClC,GAAI,CACF,IAAM,EAAM,IAAI,KAKhB,OAJkB,IAAI,KAAK,eAAe,QAAS,CACjD,SAAU,MACV,aAAc,QACf,CAAC,CACe,cAAc,EAAI,CAAC,KAAK,GAAK,EAAE,OAAS,eAAe,EAAE,OAAS,WAC7E,CACN,MAAO,OAQX,uBAAwC,CACtC,GAAI,CACF,IAAM,EAAM,IAAI,KAKhB,OAJkB,IAAI,KAAK,eAAe,QAAS,CACjD,SAAU,MACV,aAAc,OACf,CAAC,CACe,cAAc,EAAI,CAAC,KAAK,GAAK,EAAE,OAAS,eAAe,EAAE,OAAS,kCAC7E,CACN,MAAO,gCAQb,EAAe,IAAI"}
1
+ {"version":3,"file":"advanced-format.cjs","names":[],"sources":["../../src/plugins/advanced-format/index.ts"],"sourcesContent":["/**\r\n * TimeGuard Advanced Format Plugin\r\n * Adds advanced format tokens: Q (quarter), Do (ordinal), w (week), etc.\r\n * Follows SOLID principles and extends core formatting capabilities\r\n */\r\n\r\nimport type { ITimeGuardPlugin } from '../../types';\r\nimport type { TimeGuard } from '../../index';\r\nimport { Temporal } from '@js-temporal/polyfill';\r\n\r\nexport class AdvancedFormatPlugin implements ITimeGuardPlugin {\r\n name = 'advanced-format';\r\n version = '1.0.0';\r\n\r\n /**\r\n * Install plugin into TimeGuard\r\n */\r\n install(TimeGuardClass: typeof TimeGuard): void {\r\n // Store original format method\r\n const originalFormat = TimeGuardClass.prototype.format;\r\n\r\n /**\r\n * Extended format method with advanced tokens\r\n */\r\n (TimeGuardClass.prototype as any).format = function (pattern: string) {\r\n if (!pattern || typeof pattern !== 'string') {\r\n return originalFormat.call(this, pattern);\r\n }\r\n\r\n // Check if pattern contains advanced tokens\r\n if (!/Q|Do|w|W|gggg|GGGG|k{1,2}|X|x|zzz?/.test(pattern)) {\r\n return originalFormat.call(this, pattern);\r\n }\r\n\r\n // Get the underlying Temporal object\r\n const temporal = this.toTemporal();\r\n const temporal_dt =\r\n 'toPlainDateTime' in temporal\r\n ? (temporal as any).toPlainDateTime()\r\n : (temporal as Temporal.PlainDateTime);\r\n \r\n const ordinalFn = (n: number) => {\r\n const suffixes = ['th', 'st', 'nd', 'rd'];\r\n const v = n % 100;\r\n return n + (suffixes[(v - 20) % 10] || suffixes[v] || suffixes[0]);\r\n };\r\n const padFn = (n: number, length: number) => String(n).padStart(length, '0');\r\n const getISOWeek = (temporal: any) => {\r\n const jan4 = new Date(temporal.year, 0, 4);\r\n const week1Start = new Date(jan4);\r\n week1Start.setDate(jan4.getDate() - jan4.getDay() + (jan4.getDay() === 0 ? -6 : 1));\r\n const currentDate = new Date(temporal.year, temporal.month - 1, temporal.day);\r\n const weekNum = Math.floor((currentDate.getTime() - week1Start.getTime()) / (7 * 24 * 60 * 60 * 1000)) + 1;\r\n return Math.max(1, weekNum);\r\n };\r\n const getWeekOfYear = (temporal: any) => {\r\n const weekNum = Math.ceil(((temporal.day + new Date(temporal.year, temporal.month - 1, 1).getDay()) / 7));\r\n return Math.max(1, weekNum);\r\n };\r\n const getISOWeekYear = (temporal: any) => {\r\n const currentDate = new Date(temporal.year, temporal.month - 1, temporal.day);\r\n const yearAdjust = currentDate.getTime() < new Date(temporal.year, 0, 1).getTime() ? -1 : currentDate.getTime() >= new Date(temporal.year + 1, 0, 1).getTime() ? 1 : 0;\r\n return temporal.year + yearAdjust;\r\n };\r\n const getWeekYear = (temporal: any) => {\r\n const yearAdjust = temporal.month === 1 && temporal.day < 4 ? -1 : temporal.month === 12 && temporal.day > 28 ? 1 : 0;\r\n return temporal.year + yearAdjust;\r\n };\r\n\r\n // Replace advanced tokens - wrap results in brackets to protect from standard formatter\r\n let result = pattern.replace(\r\n /Q|Do|w|W|gggg|GGGG|k{1,2}|X|x|zzz?/g,\r\n (match) => {\r\n let replacement = '';\r\n switch (match) {\r\n // Quarter\r\n case 'Q':\r\n replacement = String(Math.ceil((temporal_dt.month) / 3));\r\n break;\r\n\r\n // Ordinal day\r\n case 'Do':\r\n replacement = ordinalFn(temporal_dt.day);\r\n break;\r\n\r\n // Week of year (ISO)\r\n case 'W':\r\n case 'WW':\r\n replacement = padFn(getISOWeek(temporal_dt), match === 'W' ? 1 : 2);\r\n break;\r\n\r\n // Week of year (locale)\r\n case 'w':\r\n case 'ww':\r\n replacement = padFn(getWeekOfYear(temporal_dt), match === 'w' ? 1 : 2);\r\n break;\r\n\r\n // ISO week year\r\n case 'GGGG':\r\n replacement = String(getISOWeekYear(temporal_dt));\r\n break;\r\n\r\n // Week year\r\n case 'gggg':\r\n replacement = String(getWeekYear(temporal_dt));\r\n break;\r\n\r\n // Hour (1-24)\r\n case 'k':\r\n case 'kk':\r\n const hour = temporal_dt.hour === 0 ? 24 : temporal_dt.hour;\r\n replacement = padFn(hour, match === 'k' ? 1 : 2);\r\n break;\r\n\r\n // Unix seconds timestamp\r\n case 'X':\r\n replacement = String(Math.floor(this.valueOf() / 1000));\r\n break;\r\n\r\n // Unix milliseconds timestamp\r\n case 'x':\r\n replacement = String(this.valueOf());\r\n break;\r\n\r\n // Timezone offset\r\n case 'z':\r\n replacement = `${this.getTimezoneOffset()}`;\r\n break;\r\n\r\n case 'zzz':\r\n replacement = `${this.getTimezoneOffsetLong()}`;\r\n break;\r\n\r\n default:\r\n return match;\r\n }\r\n // Wrap in brackets to protect from standard formatter\r\n return `[${replacement}]`;\r\n },\r\n );\r\n\r\n // Apply standard format to the result\r\n return originalFormat.call(this, result);\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Create and export default instance\r\n */\r\nexport default new AdvancedFormatPlugin();\r\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- /*! time-guard v2.5.1 | (c) 2026 Berea-Soft | MIT License | https://github.com/Berea-Soft/time-guard */
1
+ /*! time-guard v2.5.3 | (c) 2026 Berea-Soft | MIT License | https://github.com/Berea-Soft/time-guard */
2
2
  //#region src/plugins/advanced-format/index.ts
3
3
  var e = class {
4
4
  name = "advanced-format";
@@ -75,58 +75,6 @@ var e = class {
75
75
  return t.call(this, u);
76
76
  };
77
77
  }
78
- getOrdinal(e) {
79
- let t = [
80
- "th",
81
- "st",
82
- "nd",
83
- "rd"
84
- ], n = e % 100;
85
- return e + (t[(n - 20) % 10] || t[n] || t[0]);
86
- }
87
- padNumber(e, t) {
88
- return String(e).padStart(t, "0");
89
- }
90
- getISOWeek(e) {
91
- let t = new Date(e.year, 0, 4), n = new Date(t);
92
- n.setDate(t.getDate() - t.getDay() + (t.getDay() === 0 ? -6 : 1));
93
- let r = new Date(e.year, e.month - 1, e.day), i = Math.floor((r.getTime() - n.getTime()) / (10080 * 60 * 1e3)) + 1;
94
- return Math.max(1, i);
95
- }
96
- getWeekOfYear(e) {
97
- let t = Math.ceil((e.day + new Date(e.year, e.month - 1, 1).getDay()) / 7);
98
- return Math.max(1, t);
99
- }
100
- getISOWeekYear(e) {
101
- let t = new Date(e.year, e.month - 1, e.day), n = t.getTime() < new Date(e.year, 0, 1).getTime() ? -1 : +(t.getTime() >= new Date(e.year + 1, 0, 1).getTime());
102
- return e.year + n;
103
- }
104
- getWeekYear(e) {
105
- let t = e.month === 1 && e.day < 4 ? -1 : +(e.month === 12 && e.day > 28);
106
- return e.year + t;
107
- }
108
- getTimezoneOffset() {
109
- try {
110
- let e = /* @__PURE__ */ new Date();
111
- return new Intl.DateTimeFormat("en-US", {
112
- timeZone: "UTC",
113
- timeZoneName: "short"
114
- }).formatToParts(e).find((e) => e.type === "timeZoneName")?.value || "UTC";
115
- } catch {
116
- return "UTC";
117
- }
118
- }
119
- getTimezoneOffsetLong() {
120
- try {
121
- let e = /* @__PURE__ */ new Date();
122
- return new Intl.DateTimeFormat("en-US", {
123
- timeZone: "UTC",
124
- timeZoneName: "long"
125
- }).formatToParts(e).find((e) => e.type === "timeZoneName")?.value || "Coordinated Universal Time";
126
- } catch {
127
- return "Coordinated Universal Time";
128
- }
129
- }
130
78
  }, t = new e();
131
79
  //#endregion
132
80
  export { e as AdvancedFormatPlugin, t as default };
@@ -1 +1 @@
1
- {"version":3,"file":"advanced-format.es.js","names":[],"sources":["../../src/plugins/advanced-format/index.ts"],"sourcesContent":["/**\r\n * TimeGuard Advanced Format Plugin\r\n * Adds advanced format tokens: Q (quarter), Do (ordinal), w (week), etc.\r\n * Follows SOLID principles and extends core formatting capabilities\r\n */\r\n\r\nimport type { ITimeGuardPlugin } from '../../types';\r\nimport type { TimeGuard } from '../../time-guard';\r\nimport type { Temporal } from '@js-temporal/polyfill';\r\n\r\nexport class AdvancedFormatPlugin implements ITimeGuardPlugin {\r\n name = 'advanced-format';\r\n version = '1.0.0';\r\n\r\n /**\r\n * Install plugin into TimeGuard\r\n */\r\n install(TimeGuardClass: typeof TimeGuard): void {\r\n // Store original format method\r\n const originalFormat = TimeGuardClass.prototype.format;\r\n\r\n /**\r\n * Extended format method with advanced tokens\r\n */\r\n (TimeGuardClass.prototype as any).format = function (pattern: string) {\r\n if (!pattern || typeof pattern !== 'string') {\r\n return originalFormat.call(this, pattern);\r\n }\r\n\r\n // Check if pattern contains advanced tokens\r\n if (!/Q|Do|w|W|gggg|GGGG|k{1,2}|X|x|zzz?/.test(pattern)) {\r\n return originalFormat.call(this, pattern);\r\n }\r\n\r\n // Get the underlying Temporal object\r\n const temporal = this.toTemporal();\r\n const temporal_dt =\r\n 'toPlainDateTime' in temporal\r\n ? (temporal as any).toPlainDateTime()\r\n : (temporal as Temporal.PlainDateTime);\r\n \r\n const ordinalFn = (n: number) => {\r\n const suffixes = ['th', 'st', 'nd', 'rd'];\r\n const v = n % 100;\r\n return n + (suffixes[(v - 20) % 10] || suffixes[v] || suffixes[0]);\r\n };\r\n const padFn = (n: number, length: number) => String(n).padStart(length, '0');\r\n const getISOWeek = (temporal: any) => {\r\n const jan4 = new Date(temporal.year, 0, 4);\r\n const week1Start = new Date(jan4);\r\n week1Start.setDate(jan4.getDate() - jan4.getDay() + (jan4.getDay() === 0 ? -6 : 1));\r\n const currentDate = new Date(temporal.year, temporal.month - 1, temporal.day);\r\n const weekNum = Math.floor((currentDate.getTime() - week1Start.getTime()) / (7 * 24 * 60 * 60 * 1000)) + 1;\r\n return Math.max(1, weekNum);\r\n };\r\n const getWeekOfYear = (temporal: any) => {\r\n const weekNum = Math.ceil(((temporal.day + new Date(temporal.year, temporal.month - 1, 1).getDay()) / 7));\r\n return Math.max(1, weekNum);\r\n };\r\n const getISOWeekYear = (temporal: any) => {\r\n const currentDate = new Date(temporal.year, temporal.month - 1, temporal.day);\r\n const yearAdjust = currentDate.getTime() < new Date(temporal.year, 0, 1).getTime() ? -1 : currentDate.getTime() >= new Date(temporal.year + 1, 0, 1).getTime() ? 1 : 0;\r\n return temporal.year + yearAdjust;\r\n };\r\n const getWeekYear = (temporal: any) => {\r\n const yearAdjust = temporal.month === 1 && temporal.day < 4 ? -1 : temporal.month === 12 && temporal.day > 28 ? 1 : 0;\r\n return temporal.year + yearAdjust;\r\n };\r\n\r\n // Replace advanced tokens - wrap results in brackets to protect from standard formatter\r\n let result = pattern.replace(\r\n /Q|Do|w|W|gggg|GGGG|k{1,2}|X|x|zzz?/g,\r\n (match) => {\r\n let replacement = '';\r\n switch (match) {\r\n // Quarter\r\n case 'Q':\r\n replacement = String(Math.ceil((temporal_dt.month) / 3));\r\n break;\r\n\r\n // Ordinal day\r\n case 'Do':\r\n replacement = ordinalFn(temporal_dt.day);\r\n break;\r\n\r\n // Week of year (ISO)\r\n case 'W':\r\n case 'WW':\r\n replacement = padFn(getISOWeek(temporal_dt), match === 'W' ? 1 : 2);\r\n break;\r\n\r\n // Week of year (locale)\r\n case 'w':\r\n case 'ww':\r\n replacement = padFn(getWeekOfYear(temporal_dt), match === 'w' ? 1 : 2);\r\n break;\r\n\r\n // ISO week year\r\n case 'GGGG':\r\n replacement = String(getISOWeekYear(temporal_dt));\r\n break;\r\n\r\n // Week year\r\n case 'gggg':\r\n replacement = String(getWeekYear(temporal_dt));\r\n break;\r\n\r\n // Hour (1-24)\r\n case 'k':\r\n case 'kk':\r\n const hour = temporal_dt.hour === 0 ? 24 : temporal_dt.hour;\r\n replacement = padFn(hour, match === 'k' ? 1 : 2);\r\n break;\r\n\r\n // Unix seconds timestamp\r\n case 'X':\r\n replacement = String(Math.floor(this.valueOf() / 1000));\r\n break;\r\n\r\n // Unix milliseconds timestamp\r\n case 'x':\r\n replacement = String(this.valueOf());\r\n break;\r\n\r\n // Timezone offset\r\n case 'z':\r\n replacement = `${this.getTimezoneOffset()}`;\r\n break;\r\n\r\n case 'zzz':\r\n replacement = `${this.getTimezoneOffsetLong()}`;\r\n break;\r\n\r\n default:\r\n return match;\r\n }\r\n // Wrap in brackets to protect from standard formatter\r\n return `[${replacement}]`;\r\n },\r\n );\r\n\r\n // Apply standard format to the result\r\n return originalFormat.call(this, result);\r\n };\r\n }\r\n\r\n /**\r\n * Get ordinal suffix (1st, 2nd, 3rd, etc.)\r\n */\r\n // @ts-expect-error - Method called dynamically within replace callback\r\n private getOrdinal(n: number): string {\r\n const suffixes = ['th', 'st', 'nd', 'rd'];\r\n const v = n % 100;\r\n return n + (suffixes[(v - 20) % 10] || suffixes[v] || suffixes[0]);\r\n }\r\n\r\n /**\r\n * Pad number with leading zeros\r\n */\r\n // @ts-expect-error - Method called dynamically within replace callback\r\n private padNumber(n: number, length: number): string {\r\n return String(n).padStart(length, '0');\r\n }\r\n\r\n /**\r\n * Get ISO week number\r\n */\r\n // @ts-expect-error - Method called dynamically within replace callback\r\n private getISOWeek(temporal: Temporal.PlainDateTime): number {\r\n // Simple ISO week calculation\r\n const jan4 = new Date(temporal.year, 0, 4);\r\n const week1Start = new Date(jan4);\r\n week1Start.setDate(jan4.getDate() - jan4.getDay() + (jan4.getDay() === 0 ? -6 : 1));\r\n\r\n const currentDate = new Date(temporal.year, temporal.month - 1, temporal.day);\r\n const weekNum = Math.floor(\r\n (currentDate.getTime() - week1Start.getTime()) / (7 * 24 * 60 * 60 * 1000),\r\n ) + 1;\r\n\r\n return Math.max(1, weekNum);\r\n }\r\n\r\n /**\r\n * Get week of year (locale-based)\r\n */\r\n // @ts-expect-error - Method called dynamically within replace callback\r\n private getWeekOfYear(temporal: Temporal.PlainDateTime): number {\r\n const weekNum = Math.ceil(\r\n ((temporal.day + new Date(temporal.year, temporal.month - 1, 1).getDay()) / 7),\r\n );\r\n return Math.max(1, weekNum);\r\n }\r\n\r\n /**\r\n * Get ISO week year\r\n */\r\n // @ts-expect-error - Method called dynamically within replace callback\r\n private getISOWeekYear(temporal: Temporal.PlainDateTime): number {\r\n const currentDate = new Date(temporal.year, temporal.month - 1, temporal.day);\r\n const yearAdjust =\r\n currentDate.getTime() < new Date(temporal.year, 0, 1).getTime()\r\n ? -1\r\n : currentDate.getTime() >= new Date(temporal.year + 1, 0, 1).getTime()\r\n ? 1\r\n : 0;\r\n\r\n return temporal.year + yearAdjust;\r\n }\r\n\r\n /**\r\n * Get week year\r\n */\r\n // @ts-expect-error - Method called dynamically within replace callback\r\n private getWeekYear(temporal: Temporal.PlainDateTime): number {\r\n const yearAdjust =\r\n temporal.month === 1 && temporal.day < 4\r\n ? -1\r\n : temporal.month === 12 && temporal.day > 28\r\n ? 1\r\n : 0;\r\n return temporal.year + yearAdjust;\r\n }\r\n\r\n /**\r\n * Get timezone offset short form\r\n */\r\n // @ts-expect-error - Method called dynamically within replace callback\r\n private getTimezoneOffset(): string {\r\n try {\r\n const now = new Date();\r\n const formatter = new Intl.DateTimeFormat('en-US', {\r\n timeZone: 'UTC',\r\n timeZoneName: 'short',\r\n });\r\n return formatter.formatToParts(now).find(p => p.type === 'timeZoneName')?.value || 'UTC';\r\n } catch {\r\n return 'UTC';\r\n }\r\n }\r\n\r\n /**\r\n * Get timezone offset long form\r\n */\r\n // @ts-expect-error - Method called dynamically within replace callback\r\n private getTimezoneOffsetLong(): string {\r\n try {\r\n const now = new Date();\r\n const formatter = new Intl.DateTimeFormat('en-US', {\r\n timeZone: 'UTC',\r\n timeZoneName: 'long',\r\n });\r\n return formatter.formatToParts(now).find(p => p.type === 'timeZoneName')?.value || 'Coordinated Universal Time';\r\n } catch {\r\n return 'Coordinated Universal Time';\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Create and export default instance\r\n */\r\nexport default new AdvancedFormatPlugin();\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"advanced-format.es.js","names":[],"sources":["../../src/plugins/advanced-format/index.ts"],"sourcesContent":["/**\r\n * TimeGuard Advanced Format Plugin\r\n * Adds advanced format tokens: Q (quarter), Do (ordinal), w (week), etc.\r\n * Follows SOLID principles and extends core formatting capabilities\r\n */\r\n\r\nimport type { ITimeGuardPlugin } from '../../types';\r\nimport type { TimeGuard } from '../../index';\r\nimport { Temporal } from '@js-temporal/polyfill';\r\n\r\nexport class AdvancedFormatPlugin implements ITimeGuardPlugin {\r\n name = 'advanced-format';\r\n version = '1.0.0';\r\n\r\n /**\r\n * Install plugin into TimeGuard\r\n */\r\n install(TimeGuardClass: typeof TimeGuard): void {\r\n // Store original format method\r\n const originalFormat = TimeGuardClass.prototype.format;\r\n\r\n /**\r\n * Extended format method with advanced tokens\r\n */\r\n (TimeGuardClass.prototype as any).format = function (pattern: string) {\r\n if (!pattern || typeof pattern !== 'string') {\r\n return originalFormat.call(this, pattern);\r\n }\r\n\r\n // Check if pattern contains advanced tokens\r\n if (!/Q|Do|w|W|gggg|GGGG|k{1,2}|X|x|zzz?/.test(pattern)) {\r\n return originalFormat.call(this, pattern);\r\n }\r\n\r\n // Get the underlying Temporal object\r\n const temporal = this.toTemporal();\r\n const temporal_dt =\r\n 'toPlainDateTime' in temporal\r\n ? (temporal as any).toPlainDateTime()\r\n : (temporal as Temporal.PlainDateTime);\r\n \r\n const ordinalFn = (n: number) => {\r\n const suffixes = ['th', 'st', 'nd', 'rd'];\r\n const v = n % 100;\r\n return n + (suffixes[(v - 20) % 10] || suffixes[v] || suffixes[0]);\r\n };\r\n const padFn = (n: number, length: number) => String(n).padStart(length, '0');\r\n const getISOWeek = (temporal: any) => {\r\n const jan4 = new Date(temporal.year, 0, 4);\r\n const week1Start = new Date(jan4);\r\n week1Start.setDate(jan4.getDate() - jan4.getDay() + (jan4.getDay() === 0 ? -6 : 1));\r\n const currentDate = new Date(temporal.year, temporal.month - 1, temporal.day);\r\n const weekNum = Math.floor((currentDate.getTime() - week1Start.getTime()) / (7 * 24 * 60 * 60 * 1000)) + 1;\r\n return Math.max(1, weekNum);\r\n };\r\n const getWeekOfYear = (temporal: any) => {\r\n const weekNum = Math.ceil(((temporal.day + new Date(temporal.year, temporal.month - 1, 1).getDay()) / 7));\r\n return Math.max(1, weekNum);\r\n };\r\n const getISOWeekYear = (temporal: any) => {\r\n const currentDate = new Date(temporal.year, temporal.month - 1, temporal.day);\r\n const yearAdjust = currentDate.getTime() < new Date(temporal.year, 0, 1).getTime() ? -1 : currentDate.getTime() >= new Date(temporal.year + 1, 0, 1).getTime() ? 1 : 0;\r\n return temporal.year + yearAdjust;\r\n };\r\n const getWeekYear = (temporal: any) => {\r\n const yearAdjust = temporal.month === 1 && temporal.day < 4 ? -1 : temporal.month === 12 && temporal.day > 28 ? 1 : 0;\r\n return temporal.year + yearAdjust;\r\n };\r\n\r\n // Replace advanced tokens - wrap results in brackets to protect from standard formatter\r\n let result = pattern.replace(\r\n /Q|Do|w|W|gggg|GGGG|k{1,2}|X|x|zzz?/g,\r\n (match) => {\r\n let replacement = '';\r\n switch (match) {\r\n // Quarter\r\n case 'Q':\r\n replacement = String(Math.ceil((temporal_dt.month) / 3));\r\n break;\r\n\r\n // Ordinal day\r\n case 'Do':\r\n replacement = ordinalFn(temporal_dt.day);\r\n break;\r\n\r\n // Week of year (ISO)\r\n case 'W':\r\n case 'WW':\r\n replacement = padFn(getISOWeek(temporal_dt), match === 'W' ? 1 : 2);\r\n break;\r\n\r\n // Week of year (locale)\r\n case 'w':\r\n case 'ww':\r\n replacement = padFn(getWeekOfYear(temporal_dt), match === 'w' ? 1 : 2);\r\n break;\r\n\r\n // ISO week year\r\n case 'GGGG':\r\n replacement = String(getISOWeekYear(temporal_dt));\r\n break;\r\n\r\n // Week year\r\n case 'gggg':\r\n replacement = String(getWeekYear(temporal_dt));\r\n break;\r\n\r\n // Hour (1-24)\r\n case 'k':\r\n case 'kk':\r\n const hour = temporal_dt.hour === 0 ? 24 : temporal_dt.hour;\r\n replacement = padFn(hour, match === 'k' ? 1 : 2);\r\n break;\r\n\r\n // Unix seconds timestamp\r\n case 'X':\r\n replacement = String(Math.floor(this.valueOf() / 1000));\r\n break;\r\n\r\n // Unix milliseconds timestamp\r\n case 'x':\r\n replacement = String(this.valueOf());\r\n break;\r\n\r\n // Timezone offset\r\n case 'z':\r\n replacement = `${this.getTimezoneOffset()}`;\r\n break;\r\n\r\n case 'zzz':\r\n replacement = `${this.getTimezoneOffsetLong()}`;\r\n break;\r\n\r\n default:\r\n return match;\r\n }\r\n // Wrap in brackets to protect from standard formatter\r\n return `[${replacement}]`;\r\n },\r\n );\r\n\r\n // Apply standard format to the result\r\n return originalFormat.call(this, result);\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Create and export default instance\r\n */\r\nexport default new AdvancedFormatPlugin();\r\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"duration.cjs","names":[],"sources":["../../src/plugins/duration/index.ts"],"sourcesContent":["/**\r\n * TimeGuard Duration Plugin\r\n * Implements ISO 8601 duration support and time calculations\r\n * Follows SOLID principles and enables advanced duration operations\r\n */\r\n\r\nimport type { ITimeGuardPlugin } from '../../types';\r\nimport type { TimeGuard } from '../../time-guard';\r\nimport type { DurationInput, DurationObject, DurationUnit, IDuration } from './types';\r\n\r\n/**\r\n * Duration class - represents time span following ISO 8601 standard\r\n */\r\nexport class Duration implements IDuration {\r\n private years: number = 0;\r\n private months: number = 0;\r\n private weeks: number = 0;\r\n private days: number = 0;\r\n private hours: number = 0;\r\n private minutes: number = 0;\r\n private seconds: number = 0;\r\n private milliseconds: number = 0;\r\n\r\n constructor(input: DurationInput) {\r\n this.years = input.years || 0;\r\n this.months = input.months || 0;\r\n this.weeks = input.weeks || 0;\r\n this.days = input.days || 0;\r\n this.hours = input.hours || 0;\r\n this.minutes = input.minutes || 0;\r\n this.seconds = input.seconds || 0;\r\n this.milliseconds = input.milliseconds || 0;\r\n }\r\n\r\n /**\r\n * Create Duration from ISO 8601 string\r\n * @example Duration.fromISO(\"P3Y6M4DT12H30M5S\")\r\n */\r\n static fromISO(iso: string): Duration {\r\n const isoRegex = /^(-)?P(?:(\\d+)Y)?(?:(\\d+)M)?(?:(\\d+)W)?(?:(\\d+)D)?(?:T(?:(\\d+)H)?(?:(\\d+)M)?(?:([\\d.]+)S)?)?$/;\r\n const match = iso.match(isoRegex);\r\n\r\n if (!match) {\r\n throw new Error(`Invalid ISO 8601 duration: ${iso}`);\r\n }\r\n\r\n const [, negative, years, months, , days, hours, minutes, seconds] = match;\r\n const multiplier = negative ? -1 : 1;\r\n\r\n return new Duration({\r\n years: parseInt(years || '0', 10) * multiplier,\r\n months: parseInt(months || '0', 10) * multiplier,\r\n days: parseInt(days || '0', 10) * multiplier,\r\n hours: parseInt(hours || '0', 10) * multiplier,\r\n minutes: parseInt(minutes || '0', 10) * multiplier,\r\n seconds: parseFloat(seconds || '0') * multiplier,\r\n });\r\n }\r\n\r\n /**\r\n * Create a Duration between this date and another\r\n */\r\n static between(from: TimeGuard, to: TimeGuard): Duration {\r\n // Calculate (to - from) using since() for proper duration\r\n const fromDT = (from as any).toTemporal();\r\n const toDT = (to as any).toTemporal();\r\n const duration = (toDT as any).since(fromDT);\r\n \r\n return new Duration({\r\n years: duration.years || 0,\r\n months: duration.months || 0,\r\n weeks: 0,\r\n days: duration.days || 0,\r\n hours: duration.hours || 0,\r\n minutes: duration.minutes || 0,\r\n seconds: duration.seconds || 0,\r\n milliseconds: duration.milliseconds || 0,\r\n });\r\n }\r\n\r\n /**\r\n * Create Duration from milliseconds\r\n */\r\n static fromMilliseconds(ms: number): Duration {\r\n const isNegative = ms < 0;\r\n const absMilhs = Math.abs(ms);\r\n\r\n const years = Math.floor(absMilhs / (1000 * 60 * 60 * 24 * 365));\r\n const months = Math.floor((absMilhs % (1000 * 60 * 60 * 24 * 365)) / (1000 * 60 * 60 * 24 * 30));\r\n const days = Math.floor((absMilhs % (1000 * 60 * 60 * 24 * 30)) / (1000 * 60 * 60 * 24));\r\n const hours = Math.floor((absMilhs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));\r\n const minutes = Math.floor((absMilhs % (1000 * 60 * 60)) / (1000 * 60));\r\n const seconds = Math.floor((absMilhs % (1000 * 60)) / 1000);\r\n const milliseconds = Math.floor(absMilhs % 1000);\r\n\r\n const multiplier = isNegative ? -1 : 1;\r\n\r\n return new Duration({\r\n years: years * multiplier,\r\n months: months * multiplier,\r\n days: days * multiplier,\r\n hours: hours * multiplier,\r\n minutes: minutes * multiplier,\r\n seconds: seconds * multiplier,\r\n milliseconds: milliseconds * multiplier,\r\n });\r\n }\r\n\r\n /**\r\n * Get duration in specific unit\r\n */\r\n as(unit: DurationUnit): number {\r\n const ms = this.asMilliseconds();\r\n\r\n const conversions: Record<DurationUnit, number> = {\r\n milliseconds: 1,\r\n seconds: 1000,\r\n minutes: 1000 * 60,\r\n hours: 1000 * 60 * 60,\r\n days: 1000 * 60 * 60 * 24,\r\n weeks: 1000 * 60 * 60 * 24 * 7,\r\n months: 1000 * 60 * 60 * 24 * 30,\r\n years: 1000 * 60 * 60 * 24 * 365,\r\n };\r\n\r\n return ms / conversions[unit];\r\n }\r\n\r\n /**\r\n * Get duration as milliseconds\r\n */\r\n asMilliseconds(): number {\r\n return (\r\n this.years * 1000 * 60 * 60 * 24 * 365 +\r\n this.months * 1000 * 60 * 60 * 24 * 30 +\r\n this.weeks * 1000 * 60 * 60 * 24 * 7 +\r\n this.days * 1000 * 60 * 60 * 24 +\r\n this.hours * 1000 * 60 * 60 +\r\n this.minutes * 1000 * 60 +\r\n this.seconds * 1000 +\r\n this.milliseconds\r\n );\r\n }\r\n\r\n /**\r\n * Get duration as seconds\r\n */\r\n asSeconds(): number {\r\n return this.asMilliseconds() / 1000;\r\n }\r\n\r\n /**\r\n * Get duration as minutes\r\n */\r\n asMinutes(): number {\r\n return this.asSeconds() / 60;\r\n }\r\n\r\n /**\r\n * Get duration as hours\r\n */\r\n asHours(): number {\r\n return this.asMinutes() / 60;\r\n }\r\n\r\n /**\r\n * Get duration as days\r\n */\r\n asDays(): number {\r\n return this.asHours() / 24;\r\n }\r\n\r\n /**\r\n * Get duration as weeks\r\n */\r\n asWeeks(): number {\r\n return this.asDays() / 7;\r\n }\r\n\r\n /**\r\n * Get duration as months\r\n */\r\n asMonths(): number {\r\n return this.asDays() / 30;\r\n }\r\n\r\n /**\r\n * Get duration as years\r\n */\r\n asYears(): number {\r\n return this.asDays() / 365;\r\n }\r\n\r\n /**\r\n * Get all components\r\n */\r\n toObject(): DurationObject {\r\n return {\r\n years: this.years,\r\n months: this.months,\r\n weeks: this.weeks,\r\n days: this.days,\r\n hours: this.hours,\r\n minutes: this.minutes,\r\n seconds: this.seconds,\r\n milliseconds: this.milliseconds,\r\n };\r\n }\r\n\r\n /**\r\n * Get ISO 8601 string representation\r\n * @example \"P3Y6M4DT12H30M5S\"\r\n */\r\n toISO(): string {\r\n\r\n // Date part\r\n let datePart = '';\r\n if (this.years) datePart += `${this.years}Y`;\r\n if (this.months) datePart += `${this.months}M`;\r\n if (this.weeks || this.days) datePart += `${this.weeks * 7 + this.days}D`;\r\n\r\n // Time part\r\n let timePart = '';\r\n if (this.hours) timePart += `${this.hours}H`;\r\n if (this.minutes) timePart += `${this.minutes}M`;\r\n if (this.seconds || this.milliseconds) {\r\n timePart += `${this.seconds + this.milliseconds / 1000}S`;\r\n }\r\n\r\n const sign = this.isNegative() ? '-' : '';\r\n return `${sign}P${datePart}${timePart ? `T${timePart}` : ''}`;\r\n }\r\n\r\n /**\r\n * Get human-readable string\r\n */\r\n humanize(): string {\r\n const parts: string[] = [];\r\n\r\n if (this.years) parts.push(`${Math.abs(this.years)} year${Math.abs(this.years) !== 1 ? 's' : ''}`);\r\n if (this.months) parts.push(`${Math.abs(this.months)} month${Math.abs(this.months) !== 1 ? 's' : ''}`);\r\n if (this.weeks) parts.push(`${Math.abs(this.weeks)} week${Math.abs(this.weeks) !== 1 ? 's' : ''}`);\r\n if (this.days) parts.push(`${Math.abs(this.days)} day${Math.abs(this.days) !== 1 ? 's' : ''}`);\r\n if (this.hours) parts.push(`${Math.abs(this.hours)} hour${Math.abs(this.hours) !== 1 ? 's' : ''}`);\r\n if (this.minutes) parts.push(`${Math.abs(this.minutes)} minute${Math.abs(this.minutes) !== 1 ? 's' : ''}`);\r\n if (this.seconds) parts.push(`${Math.abs(this.seconds)} second${Math.abs(this.seconds) !== 1 ? 's' : ''}`);\r\n if (this.milliseconds) parts.push(`${Math.abs(this.milliseconds)} ms`);\r\n\r\n if (parts.length === 0) return '0 seconds';\r\n\r\n const text = parts.join(', ');\r\n return this.isNegative() ? `-${text}` : text;\r\n }\r\n\r\n /**\r\n * Check if duration is negative\r\n */\r\n isNegative(): boolean {\r\n return (\r\n this.years < 0 ||\r\n this.months < 0 ||\r\n this.weeks < 0 ||\r\n this.days < 0 ||\r\n this.hours < 0 ||\r\n this.minutes < 0 ||\r\n this.seconds < 0 ||\r\n this.milliseconds < 0\r\n );\r\n }\r\n\r\n /**\r\n * Get absolute duration\r\n */\r\n abs(): Duration {\r\n return new Duration({\r\n years: Math.abs(this.years),\r\n months: Math.abs(this.months),\r\n weeks: Math.abs(this.weeks),\r\n days: Math.abs(this.days),\r\n hours: Math.abs(this.hours),\r\n minutes: Math.abs(this.minutes),\r\n seconds: Math.abs(this.seconds),\r\n milliseconds: Math.abs(this.milliseconds),\r\n });\r\n }\r\n\r\n /**\r\n * String representation\r\n */\r\n toString(): string {\r\n return this.toISO();\r\n }\r\n}\r\n\r\n/**\r\n * Duration Plugin\r\n */\r\nexport class DurationPlugin implements ITimeGuardPlugin {\r\n name = 'duration';\r\n version = '1.0.0';\r\n\r\n /**\r\n * Install plugin into TimeGuard\r\n */\r\n install(TimeGuardClass: typeof TimeGuard): void {\r\n /**\r\n * Create a Duration between this date and another\r\n */\r\n (TimeGuardClass.prototype as any).duration = function (other: TimeGuard): Duration {\r\n return Duration.between(this, other);\r\n };\r\n\r\n /**\r\n * Get Duration class for creating custom durations\r\n */\r\n (TimeGuardClass as any).Duration = Duration;\r\n\r\n /**\r\n * Create Duration from ISO 8601 string\r\n */\r\n (TimeGuardClass as any).duration = {\r\n fromISO: (iso: string): Duration => Duration.fromISO(iso),\r\n between: (from: TimeGuard, to: TimeGuard): Duration => Duration.between(from, to),\r\n fromMilliseconds: (ms: number): Duration => Duration.fromMilliseconds(ms),\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Create and export default instance\r\n */\r\nexport const durationPlugin = new DurationPlugin();\r\n\r\nexport default durationPlugin;\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"duration.cjs","names":[],"sources":["../../src/plugins/duration/index.ts"],"sourcesContent":["/**\r\n * TimeGuard Duration Plugin\r\n * Implements ISO 8601 duration support and time calculations\r\n * Follows SOLID principles and enables advanced duration operations\r\n */\r\n\r\nimport type { ITimeGuardPlugin } from '../../types';\r\nimport type { TimeGuard } from '../../index';\r\nimport type { DurationInput, DurationObject, DurationUnit, IDuration } from './types';\r\n\r\n/**\r\n * Duration class - represents time span following ISO 8601 standard\r\n */\r\nexport class Duration implements IDuration {\r\n private years: number = 0;\r\n private months: number = 0;\r\n private weeks: number = 0;\r\n private days: number = 0;\r\n private hours: number = 0;\r\n private minutes: number = 0;\r\n private seconds: number = 0;\r\n private milliseconds: number = 0;\r\n\r\n constructor(input: DurationInput) {\r\n this.years = input.years || 0;\r\n this.months = input.months || 0;\r\n this.weeks = input.weeks || 0;\r\n this.days = input.days || 0;\r\n this.hours = input.hours || 0;\r\n this.minutes = input.minutes || 0;\r\n this.seconds = input.seconds || 0;\r\n this.milliseconds = input.milliseconds || 0;\r\n }\r\n\r\n /**\r\n * Create Duration from ISO 8601 string\r\n * @example Duration.fromISO(\"P3Y6M4DT12H30M5S\")\r\n */\r\n static fromISO(iso: string): Duration {\r\n const isoRegex = /^(-)?P(?:(\\d+)Y)?(?:(\\d+)M)?(?:(\\d+)W)?(?:(\\d+)D)?(?:T(?:(\\d+)H)?(?:(\\d+)M)?(?:([\\d.]+)S)?)?$/;\r\n const match = iso.match(isoRegex);\r\n\r\n if (!match) {\r\n throw new Error(`Invalid ISO 8601 duration: ${iso}`);\r\n }\r\n\r\n const [, negative, years, months, , days, hours, minutes, seconds] = match;\r\n const multiplier = negative ? -1 : 1;\r\n\r\n return new Duration({\r\n years: parseInt(years || '0', 10) * multiplier,\r\n months: parseInt(months || '0', 10) * multiplier,\r\n days: parseInt(days || '0', 10) * multiplier,\r\n hours: parseInt(hours || '0', 10) * multiplier,\r\n minutes: parseInt(minutes || '0', 10) * multiplier,\r\n seconds: parseFloat(seconds || '0') * multiplier,\r\n });\r\n }\r\n\r\n /**\r\n * Create a Duration between this date and another\r\n */\r\n static between(from: TimeGuard, to: TimeGuard): Duration {\r\n // Calculate (to - from) using since() for proper duration\r\n const fromDT = (from as any).toTemporal();\r\n const toDT = (to as any).toTemporal();\r\n const duration = (toDT as any).since(fromDT);\r\n \r\n return new Duration({\r\n years: duration.years || 0,\r\n months: duration.months || 0,\r\n weeks: 0,\r\n days: duration.days || 0,\r\n hours: duration.hours || 0,\r\n minutes: duration.minutes || 0,\r\n seconds: duration.seconds || 0,\r\n milliseconds: duration.milliseconds || 0,\r\n });\r\n }\r\n\r\n /**\r\n * Create Duration from milliseconds\r\n */\r\n static fromMilliseconds(ms: number): Duration {\r\n const isNegative = ms < 0;\r\n const absMilhs = Math.abs(ms);\r\n\r\n const years = Math.floor(absMilhs / (1000 * 60 * 60 * 24 * 365));\r\n const months = Math.floor((absMilhs % (1000 * 60 * 60 * 24 * 365)) / (1000 * 60 * 60 * 24 * 30));\r\n const days = Math.floor((absMilhs % (1000 * 60 * 60 * 24 * 30)) / (1000 * 60 * 60 * 24));\r\n const hours = Math.floor((absMilhs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));\r\n const minutes = Math.floor((absMilhs % (1000 * 60 * 60)) / (1000 * 60));\r\n const seconds = Math.floor((absMilhs % (1000 * 60)) / 1000);\r\n const milliseconds = Math.floor(absMilhs % 1000);\r\n\r\n const multiplier = isNegative ? -1 : 1;\r\n\r\n return new Duration({\r\n years: years * multiplier,\r\n months: months * multiplier,\r\n days: days * multiplier,\r\n hours: hours * multiplier,\r\n minutes: minutes * multiplier,\r\n seconds: seconds * multiplier,\r\n milliseconds: milliseconds * multiplier,\r\n });\r\n }\r\n\r\n /**\r\n * Get duration in specific unit\r\n */\r\n as(unit: DurationUnit): number {\r\n const ms = this.asMilliseconds();\r\n\r\n const conversions: Record<DurationUnit, number> = {\r\n milliseconds: 1,\r\n seconds: 1000,\r\n minutes: 1000 * 60,\r\n hours: 1000 * 60 * 60,\r\n days: 1000 * 60 * 60 * 24,\r\n weeks: 1000 * 60 * 60 * 24 * 7,\r\n months: 1000 * 60 * 60 * 24 * 30,\r\n years: 1000 * 60 * 60 * 24 * 365,\r\n };\r\n\r\n return ms / conversions[unit];\r\n }\r\n\r\n /**\r\n * Get duration as milliseconds\r\n */\r\n asMilliseconds(): number {\r\n return (\r\n this.years * 1000 * 60 * 60 * 24 * 365 +\r\n this.months * 1000 * 60 * 60 * 24 * 30 +\r\n this.weeks * 1000 * 60 * 60 * 24 * 7 +\r\n this.days * 1000 * 60 * 60 * 24 +\r\n this.hours * 1000 * 60 * 60 +\r\n this.minutes * 1000 * 60 +\r\n this.seconds * 1000 +\r\n this.milliseconds\r\n );\r\n }\r\n\r\n /**\r\n * Get duration as seconds\r\n */\r\n asSeconds(): number {\r\n return this.asMilliseconds() / 1000;\r\n }\r\n\r\n /**\r\n * Get duration as minutes\r\n */\r\n asMinutes(): number {\r\n return this.asSeconds() / 60;\r\n }\r\n\r\n /**\r\n * Get duration as hours\r\n */\r\n asHours(): number {\r\n return this.asMinutes() / 60;\r\n }\r\n\r\n /**\r\n * Get duration as days\r\n */\r\n asDays(): number {\r\n return this.asHours() / 24;\r\n }\r\n\r\n /**\r\n * Get duration as weeks\r\n */\r\n asWeeks(): number {\r\n return this.asDays() / 7;\r\n }\r\n\r\n /**\r\n * Get duration as months\r\n */\r\n asMonths(): number {\r\n return this.asDays() / 30;\r\n }\r\n\r\n /**\r\n * Get duration as years\r\n */\r\n asYears(): number {\r\n return this.asDays() / 365;\r\n }\r\n\r\n /**\r\n * Get all components\r\n */\r\n toObject(): DurationObject {\r\n return {\r\n years: this.years,\r\n months: this.months,\r\n weeks: this.weeks,\r\n days: this.days,\r\n hours: this.hours,\r\n minutes: this.minutes,\r\n seconds: this.seconds,\r\n milliseconds: this.milliseconds,\r\n };\r\n }\r\n\r\n /**\r\n * Get ISO 8601 string representation\r\n * @example \"P3Y6M4DT12H30M5S\"\r\n */\r\n toISO(): string {\r\n\r\n // Date part\r\n let datePart = '';\r\n if (this.years) datePart += `${this.years}Y`;\r\n if (this.months) datePart += `${this.months}M`;\r\n if (this.weeks || this.days) datePart += `${this.weeks * 7 + this.days}D`;\r\n\r\n // Time part\r\n let timePart = '';\r\n if (this.hours) timePart += `${this.hours}H`;\r\n if (this.minutes) timePart += `${this.minutes}M`;\r\n if (this.seconds || this.milliseconds) {\r\n timePart += `${this.seconds + this.milliseconds / 1000}S`;\r\n }\r\n\r\n const sign = this.isNegative() ? '-' : '';\r\n return `${sign}P${datePart}${timePart ? `T${timePart}` : ''}`;\r\n }\r\n\r\n /**\r\n * Get human-readable string\r\n */\r\n humanize(): string {\r\n const parts: string[] = [];\r\n\r\n if (this.years) parts.push(`${Math.abs(this.years)} year${Math.abs(this.years) !== 1 ? 's' : ''}`);\r\n if (this.months) parts.push(`${Math.abs(this.months)} month${Math.abs(this.months) !== 1 ? 's' : ''}`);\r\n if (this.weeks) parts.push(`${Math.abs(this.weeks)} week${Math.abs(this.weeks) !== 1 ? 's' : ''}`);\r\n if (this.days) parts.push(`${Math.abs(this.days)} day${Math.abs(this.days) !== 1 ? 's' : ''}`);\r\n if (this.hours) parts.push(`${Math.abs(this.hours)} hour${Math.abs(this.hours) !== 1 ? 's' : ''}`);\r\n if (this.minutes) parts.push(`${Math.abs(this.minutes)} minute${Math.abs(this.minutes) !== 1 ? 's' : ''}`);\r\n if (this.seconds) parts.push(`${Math.abs(this.seconds)} second${Math.abs(this.seconds) !== 1 ? 's' : ''}`);\r\n if (this.milliseconds) parts.push(`${Math.abs(this.milliseconds)} ms`);\r\n\r\n if (parts.length === 0) return '0 seconds';\r\n\r\n const text = parts.join(', ');\r\n return this.isNegative() ? `-${text}` : text;\r\n }\r\n\r\n /**\r\n * Check if duration is negative\r\n */\r\n isNegative(): boolean {\r\n return (\r\n this.years < 0 ||\r\n this.months < 0 ||\r\n this.weeks < 0 ||\r\n this.days < 0 ||\r\n this.hours < 0 ||\r\n this.minutes < 0 ||\r\n this.seconds < 0 ||\r\n this.milliseconds < 0\r\n );\r\n }\r\n\r\n /**\r\n * Get absolute duration\r\n */\r\n abs(): Duration {\r\n return new Duration({\r\n years: Math.abs(this.years),\r\n months: Math.abs(this.months),\r\n weeks: Math.abs(this.weeks),\r\n days: Math.abs(this.days),\r\n hours: Math.abs(this.hours),\r\n minutes: Math.abs(this.minutes),\r\n seconds: Math.abs(this.seconds),\r\n milliseconds: Math.abs(this.milliseconds),\r\n });\r\n }\r\n\r\n /**\r\n * String representation\r\n */\r\n toString(): string {\r\n return this.toISO();\r\n }\r\n}\r\n\r\n/**\r\n * Duration Plugin\r\n */\r\nexport class DurationPlugin implements ITimeGuardPlugin {\r\n name = 'duration';\r\n version = '1.0.0';\r\n\r\n /**\r\n * Install plugin into TimeGuard\r\n */\r\n install(TimeGuardClass: typeof TimeGuard): void {\r\n /**\r\n * Create a Duration between this date and another\r\n */\r\n (TimeGuardClass.prototype as any).duration = function (other: TimeGuard): Duration {\r\n return Duration.between(this, other);\r\n };\r\n\r\n /**\r\n * Get Duration class for creating custom durations\r\n */\r\n (TimeGuardClass as any).Duration = Duration;\r\n\r\n /**\r\n * Create Duration from ISO 8601 string\r\n */\r\n (TimeGuardClass as any).duration = {\r\n fromISO: (iso: string): Duration => Duration.fromISO(iso),\r\n between: (from: TimeGuard, to: TimeGuard): Duration => Duration.between(from, to),\r\n fromMilliseconds: (ms: number): Duration => Duration.fromMilliseconds(ms),\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Create and export default instance\r\n */\r\nexport const durationPlugin = new DurationPlugin();\r\n\r\nexport default durationPlugin;\r\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- /*! time-guard v2.5.1 | (c) 2026 Berea-Soft | MIT License | https://github.com/Berea-Soft/time-guard */
1
+ /*! time-guard v2.5.3 | (c) 2026 Berea-Soft | MIT License | https://github.com/Berea-Soft/time-guard */
2
2
  //#region src/plugins/duration/index.ts
3
3
  var e = class e {
4
4
  years = 0;
@@ -1 +1 @@
1
- {"version":3,"file":"duration.es.js","names":[],"sources":["../../src/plugins/duration/index.ts"],"sourcesContent":["/**\r\n * TimeGuard Duration Plugin\r\n * Implements ISO 8601 duration support and time calculations\r\n * Follows SOLID principles and enables advanced duration operations\r\n */\r\n\r\nimport type { ITimeGuardPlugin } from '../../types';\r\nimport type { TimeGuard } from '../../time-guard';\r\nimport type { DurationInput, DurationObject, DurationUnit, IDuration } from './types';\r\n\r\n/**\r\n * Duration class - represents time span following ISO 8601 standard\r\n */\r\nexport class Duration implements IDuration {\r\n private years: number = 0;\r\n private months: number = 0;\r\n private weeks: number = 0;\r\n private days: number = 0;\r\n private hours: number = 0;\r\n private minutes: number = 0;\r\n private seconds: number = 0;\r\n private milliseconds: number = 0;\r\n\r\n constructor(input: DurationInput) {\r\n this.years = input.years || 0;\r\n this.months = input.months || 0;\r\n this.weeks = input.weeks || 0;\r\n this.days = input.days || 0;\r\n this.hours = input.hours || 0;\r\n this.minutes = input.minutes || 0;\r\n this.seconds = input.seconds || 0;\r\n this.milliseconds = input.milliseconds || 0;\r\n }\r\n\r\n /**\r\n * Create Duration from ISO 8601 string\r\n * @example Duration.fromISO(\"P3Y6M4DT12H30M5S\")\r\n */\r\n static fromISO(iso: string): Duration {\r\n const isoRegex = /^(-)?P(?:(\\d+)Y)?(?:(\\d+)M)?(?:(\\d+)W)?(?:(\\d+)D)?(?:T(?:(\\d+)H)?(?:(\\d+)M)?(?:([\\d.]+)S)?)?$/;\r\n const match = iso.match(isoRegex);\r\n\r\n if (!match) {\r\n throw new Error(`Invalid ISO 8601 duration: ${iso}`);\r\n }\r\n\r\n const [, negative, years, months, , days, hours, minutes, seconds] = match;\r\n const multiplier = negative ? -1 : 1;\r\n\r\n return new Duration({\r\n years: parseInt(years || '0', 10) * multiplier,\r\n months: parseInt(months || '0', 10) * multiplier,\r\n days: parseInt(days || '0', 10) * multiplier,\r\n hours: parseInt(hours || '0', 10) * multiplier,\r\n minutes: parseInt(minutes || '0', 10) * multiplier,\r\n seconds: parseFloat(seconds || '0') * multiplier,\r\n });\r\n }\r\n\r\n /**\r\n * Create a Duration between this date and another\r\n */\r\n static between(from: TimeGuard, to: TimeGuard): Duration {\r\n // Calculate (to - from) using since() for proper duration\r\n const fromDT = (from as any).toTemporal();\r\n const toDT = (to as any).toTemporal();\r\n const duration = (toDT as any).since(fromDT);\r\n \r\n return new Duration({\r\n years: duration.years || 0,\r\n months: duration.months || 0,\r\n weeks: 0,\r\n days: duration.days || 0,\r\n hours: duration.hours || 0,\r\n minutes: duration.minutes || 0,\r\n seconds: duration.seconds || 0,\r\n milliseconds: duration.milliseconds || 0,\r\n });\r\n }\r\n\r\n /**\r\n * Create Duration from milliseconds\r\n */\r\n static fromMilliseconds(ms: number): Duration {\r\n const isNegative = ms < 0;\r\n const absMilhs = Math.abs(ms);\r\n\r\n const years = Math.floor(absMilhs / (1000 * 60 * 60 * 24 * 365));\r\n const months = Math.floor((absMilhs % (1000 * 60 * 60 * 24 * 365)) / (1000 * 60 * 60 * 24 * 30));\r\n const days = Math.floor((absMilhs % (1000 * 60 * 60 * 24 * 30)) / (1000 * 60 * 60 * 24));\r\n const hours = Math.floor((absMilhs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));\r\n const minutes = Math.floor((absMilhs % (1000 * 60 * 60)) / (1000 * 60));\r\n const seconds = Math.floor((absMilhs % (1000 * 60)) / 1000);\r\n const milliseconds = Math.floor(absMilhs % 1000);\r\n\r\n const multiplier = isNegative ? -1 : 1;\r\n\r\n return new Duration({\r\n years: years * multiplier,\r\n months: months * multiplier,\r\n days: days * multiplier,\r\n hours: hours * multiplier,\r\n minutes: minutes * multiplier,\r\n seconds: seconds * multiplier,\r\n milliseconds: milliseconds * multiplier,\r\n });\r\n }\r\n\r\n /**\r\n * Get duration in specific unit\r\n */\r\n as(unit: DurationUnit): number {\r\n const ms = this.asMilliseconds();\r\n\r\n const conversions: Record<DurationUnit, number> = {\r\n milliseconds: 1,\r\n seconds: 1000,\r\n minutes: 1000 * 60,\r\n hours: 1000 * 60 * 60,\r\n days: 1000 * 60 * 60 * 24,\r\n weeks: 1000 * 60 * 60 * 24 * 7,\r\n months: 1000 * 60 * 60 * 24 * 30,\r\n years: 1000 * 60 * 60 * 24 * 365,\r\n };\r\n\r\n return ms / conversions[unit];\r\n }\r\n\r\n /**\r\n * Get duration as milliseconds\r\n */\r\n asMilliseconds(): number {\r\n return (\r\n this.years * 1000 * 60 * 60 * 24 * 365 +\r\n this.months * 1000 * 60 * 60 * 24 * 30 +\r\n this.weeks * 1000 * 60 * 60 * 24 * 7 +\r\n this.days * 1000 * 60 * 60 * 24 +\r\n this.hours * 1000 * 60 * 60 +\r\n this.minutes * 1000 * 60 +\r\n this.seconds * 1000 +\r\n this.milliseconds\r\n );\r\n }\r\n\r\n /**\r\n * Get duration as seconds\r\n */\r\n asSeconds(): number {\r\n return this.asMilliseconds() / 1000;\r\n }\r\n\r\n /**\r\n * Get duration as minutes\r\n */\r\n asMinutes(): number {\r\n return this.asSeconds() / 60;\r\n }\r\n\r\n /**\r\n * Get duration as hours\r\n */\r\n asHours(): number {\r\n return this.asMinutes() / 60;\r\n }\r\n\r\n /**\r\n * Get duration as days\r\n */\r\n asDays(): number {\r\n return this.asHours() / 24;\r\n }\r\n\r\n /**\r\n * Get duration as weeks\r\n */\r\n asWeeks(): number {\r\n return this.asDays() / 7;\r\n }\r\n\r\n /**\r\n * Get duration as months\r\n */\r\n asMonths(): number {\r\n return this.asDays() / 30;\r\n }\r\n\r\n /**\r\n * Get duration as years\r\n */\r\n asYears(): number {\r\n return this.asDays() / 365;\r\n }\r\n\r\n /**\r\n * Get all components\r\n */\r\n toObject(): DurationObject {\r\n return {\r\n years: this.years,\r\n months: this.months,\r\n weeks: this.weeks,\r\n days: this.days,\r\n hours: this.hours,\r\n minutes: this.minutes,\r\n seconds: this.seconds,\r\n milliseconds: this.milliseconds,\r\n };\r\n }\r\n\r\n /**\r\n * Get ISO 8601 string representation\r\n * @example \"P3Y6M4DT12H30M5S\"\r\n */\r\n toISO(): string {\r\n\r\n // Date part\r\n let datePart = '';\r\n if (this.years) datePart += `${this.years}Y`;\r\n if (this.months) datePart += `${this.months}M`;\r\n if (this.weeks || this.days) datePart += `${this.weeks * 7 + this.days}D`;\r\n\r\n // Time part\r\n let timePart = '';\r\n if (this.hours) timePart += `${this.hours}H`;\r\n if (this.minutes) timePart += `${this.minutes}M`;\r\n if (this.seconds || this.milliseconds) {\r\n timePart += `${this.seconds + this.milliseconds / 1000}S`;\r\n }\r\n\r\n const sign = this.isNegative() ? '-' : '';\r\n return `${sign}P${datePart}${timePart ? `T${timePart}` : ''}`;\r\n }\r\n\r\n /**\r\n * Get human-readable string\r\n */\r\n humanize(): string {\r\n const parts: string[] = [];\r\n\r\n if (this.years) parts.push(`${Math.abs(this.years)} year${Math.abs(this.years) !== 1 ? 's' : ''}`);\r\n if (this.months) parts.push(`${Math.abs(this.months)} month${Math.abs(this.months) !== 1 ? 's' : ''}`);\r\n if (this.weeks) parts.push(`${Math.abs(this.weeks)} week${Math.abs(this.weeks) !== 1 ? 's' : ''}`);\r\n if (this.days) parts.push(`${Math.abs(this.days)} day${Math.abs(this.days) !== 1 ? 's' : ''}`);\r\n if (this.hours) parts.push(`${Math.abs(this.hours)} hour${Math.abs(this.hours) !== 1 ? 's' : ''}`);\r\n if (this.minutes) parts.push(`${Math.abs(this.minutes)} minute${Math.abs(this.minutes) !== 1 ? 's' : ''}`);\r\n if (this.seconds) parts.push(`${Math.abs(this.seconds)} second${Math.abs(this.seconds) !== 1 ? 's' : ''}`);\r\n if (this.milliseconds) parts.push(`${Math.abs(this.milliseconds)} ms`);\r\n\r\n if (parts.length === 0) return '0 seconds';\r\n\r\n const text = parts.join(', ');\r\n return this.isNegative() ? `-${text}` : text;\r\n }\r\n\r\n /**\r\n * Check if duration is negative\r\n */\r\n isNegative(): boolean {\r\n return (\r\n this.years < 0 ||\r\n this.months < 0 ||\r\n this.weeks < 0 ||\r\n this.days < 0 ||\r\n this.hours < 0 ||\r\n this.minutes < 0 ||\r\n this.seconds < 0 ||\r\n this.milliseconds < 0\r\n );\r\n }\r\n\r\n /**\r\n * Get absolute duration\r\n */\r\n abs(): Duration {\r\n return new Duration({\r\n years: Math.abs(this.years),\r\n months: Math.abs(this.months),\r\n weeks: Math.abs(this.weeks),\r\n days: Math.abs(this.days),\r\n hours: Math.abs(this.hours),\r\n minutes: Math.abs(this.minutes),\r\n seconds: Math.abs(this.seconds),\r\n milliseconds: Math.abs(this.milliseconds),\r\n });\r\n }\r\n\r\n /**\r\n * String representation\r\n */\r\n toString(): string {\r\n return this.toISO();\r\n }\r\n}\r\n\r\n/**\r\n * Duration Plugin\r\n */\r\nexport class DurationPlugin implements ITimeGuardPlugin {\r\n name = 'duration';\r\n version = '1.0.0';\r\n\r\n /**\r\n * Install plugin into TimeGuard\r\n */\r\n install(TimeGuardClass: typeof TimeGuard): void {\r\n /**\r\n * Create a Duration between this date and another\r\n */\r\n (TimeGuardClass.prototype as any).duration = function (other: TimeGuard): Duration {\r\n return Duration.between(this, other);\r\n };\r\n\r\n /**\r\n * Get Duration class for creating custom durations\r\n */\r\n (TimeGuardClass as any).Duration = Duration;\r\n\r\n /**\r\n * Create Duration from ISO 8601 string\r\n */\r\n (TimeGuardClass as any).duration = {\r\n fromISO: (iso: string): Duration => Duration.fromISO(iso),\r\n between: (from: TimeGuard, to: TimeGuard): Duration => Duration.between(from, to),\r\n fromMilliseconds: (ms: number): Duration => Duration.fromMilliseconds(ms),\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Create and export default instance\r\n */\r\nexport const durationPlugin = new DurationPlugin();\r\n\r\nexport default durationPlugin;\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"duration.es.js","names":[],"sources":["../../src/plugins/duration/index.ts"],"sourcesContent":["/**\r\n * TimeGuard Duration Plugin\r\n * Implements ISO 8601 duration support and time calculations\r\n * Follows SOLID principles and enables advanced duration operations\r\n */\r\n\r\nimport type { ITimeGuardPlugin } from '../../types';\r\nimport type { TimeGuard } from '../../index';\r\nimport type { DurationInput, DurationObject, DurationUnit, IDuration } from './types';\r\n\r\n/**\r\n * Duration class - represents time span following ISO 8601 standard\r\n */\r\nexport class Duration implements IDuration {\r\n private years: number = 0;\r\n private months: number = 0;\r\n private weeks: number = 0;\r\n private days: number = 0;\r\n private hours: number = 0;\r\n private minutes: number = 0;\r\n private seconds: number = 0;\r\n private milliseconds: number = 0;\r\n\r\n constructor(input: DurationInput) {\r\n this.years = input.years || 0;\r\n this.months = input.months || 0;\r\n this.weeks = input.weeks || 0;\r\n this.days = input.days || 0;\r\n this.hours = input.hours || 0;\r\n this.minutes = input.minutes || 0;\r\n this.seconds = input.seconds || 0;\r\n this.milliseconds = input.milliseconds || 0;\r\n }\r\n\r\n /**\r\n * Create Duration from ISO 8601 string\r\n * @example Duration.fromISO(\"P3Y6M4DT12H30M5S\")\r\n */\r\n static fromISO(iso: string): Duration {\r\n const isoRegex = /^(-)?P(?:(\\d+)Y)?(?:(\\d+)M)?(?:(\\d+)W)?(?:(\\d+)D)?(?:T(?:(\\d+)H)?(?:(\\d+)M)?(?:([\\d.]+)S)?)?$/;\r\n const match = iso.match(isoRegex);\r\n\r\n if (!match) {\r\n throw new Error(`Invalid ISO 8601 duration: ${iso}`);\r\n }\r\n\r\n const [, negative, years, months, , days, hours, minutes, seconds] = match;\r\n const multiplier = negative ? -1 : 1;\r\n\r\n return new Duration({\r\n years: parseInt(years || '0', 10) * multiplier,\r\n months: parseInt(months || '0', 10) * multiplier,\r\n days: parseInt(days || '0', 10) * multiplier,\r\n hours: parseInt(hours || '0', 10) * multiplier,\r\n minutes: parseInt(minutes || '0', 10) * multiplier,\r\n seconds: parseFloat(seconds || '0') * multiplier,\r\n });\r\n }\r\n\r\n /**\r\n * Create a Duration between this date and another\r\n */\r\n static between(from: TimeGuard, to: TimeGuard): Duration {\r\n // Calculate (to - from) using since() for proper duration\r\n const fromDT = (from as any).toTemporal();\r\n const toDT = (to as any).toTemporal();\r\n const duration = (toDT as any).since(fromDT);\r\n \r\n return new Duration({\r\n years: duration.years || 0,\r\n months: duration.months || 0,\r\n weeks: 0,\r\n days: duration.days || 0,\r\n hours: duration.hours || 0,\r\n minutes: duration.minutes || 0,\r\n seconds: duration.seconds || 0,\r\n milliseconds: duration.milliseconds || 0,\r\n });\r\n }\r\n\r\n /**\r\n * Create Duration from milliseconds\r\n */\r\n static fromMilliseconds(ms: number): Duration {\r\n const isNegative = ms < 0;\r\n const absMilhs = Math.abs(ms);\r\n\r\n const years = Math.floor(absMilhs / (1000 * 60 * 60 * 24 * 365));\r\n const months = Math.floor((absMilhs % (1000 * 60 * 60 * 24 * 365)) / (1000 * 60 * 60 * 24 * 30));\r\n const days = Math.floor((absMilhs % (1000 * 60 * 60 * 24 * 30)) / (1000 * 60 * 60 * 24));\r\n const hours = Math.floor((absMilhs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));\r\n const minutes = Math.floor((absMilhs % (1000 * 60 * 60)) / (1000 * 60));\r\n const seconds = Math.floor((absMilhs % (1000 * 60)) / 1000);\r\n const milliseconds = Math.floor(absMilhs % 1000);\r\n\r\n const multiplier = isNegative ? -1 : 1;\r\n\r\n return new Duration({\r\n years: years * multiplier,\r\n months: months * multiplier,\r\n days: days * multiplier,\r\n hours: hours * multiplier,\r\n minutes: minutes * multiplier,\r\n seconds: seconds * multiplier,\r\n milliseconds: milliseconds * multiplier,\r\n });\r\n }\r\n\r\n /**\r\n * Get duration in specific unit\r\n */\r\n as(unit: DurationUnit): number {\r\n const ms = this.asMilliseconds();\r\n\r\n const conversions: Record<DurationUnit, number> = {\r\n milliseconds: 1,\r\n seconds: 1000,\r\n minutes: 1000 * 60,\r\n hours: 1000 * 60 * 60,\r\n days: 1000 * 60 * 60 * 24,\r\n weeks: 1000 * 60 * 60 * 24 * 7,\r\n months: 1000 * 60 * 60 * 24 * 30,\r\n years: 1000 * 60 * 60 * 24 * 365,\r\n };\r\n\r\n return ms / conversions[unit];\r\n }\r\n\r\n /**\r\n * Get duration as milliseconds\r\n */\r\n asMilliseconds(): number {\r\n return (\r\n this.years * 1000 * 60 * 60 * 24 * 365 +\r\n this.months * 1000 * 60 * 60 * 24 * 30 +\r\n this.weeks * 1000 * 60 * 60 * 24 * 7 +\r\n this.days * 1000 * 60 * 60 * 24 +\r\n this.hours * 1000 * 60 * 60 +\r\n this.minutes * 1000 * 60 +\r\n this.seconds * 1000 +\r\n this.milliseconds\r\n );\r\n }\r\n\r\n /**\r\n * Get duration as seconds\r\n */\r\n asSeconds(): number {\r\n return this.asMilliseconds() / 1000;\r\n }\r\n\r\n /**\r\n * Get duration as minutes\r\n */\r\n asMinutes(): number {\r\n return this.asSeconds() / 60;\r\n }\r\n\r\n /**\r\n * Get duration as hours\r\n */\r\n asHours(): number {\r\n return this.asMinutes() / 60;\r\n }\r\n\r\n /**\r\n * Get duration as days\r\n */\r\n asDays(): number {\r\n return this.asHours() / 24;\r\n }\r\n\r\n /**\r\n * Get duration as weeks\r\n */\r\n asWeeks(): number {\r\n return this.asDays() / 7;\r\n }\r\n\r\n /**\r\n * Get duration as months\r\n */\r\n asMonths(): number {\r\n return this.asDays() / 30;\r\n }\r\n\r\n /**\r\n * Get duration as years\r\n */\r\n asYears(): number {\r\n return this.asDays() / 365;\r\n }\r\n\r\n /**\r\n * Get all components\r\n */\r\n toObject(): DurationObject {\r\n return {\r\n years: this.years,\r\n months: this.months,\r\n weeks: this.weeks,\r\n days: this.days,\r\n hours: this.hours,\r\n minutes: this.minutes,\r\n seconds: this.seconds,\r\n milliseconds: this.milliseconds,\r\n };\r\n }\r\n\r\n /**\r\n * Get ISO 8601 string representation\r\n * @example \"P3Y6M4DT12H30M5S\"\r\n */\r\n toISO(): string {\r\n\r\n // Date part\r\n let datePart = '';\r\n if (this.years) datePart += `${this.years}Y`;\r\n if (this.months) datePart += `${this.months}M`;\r\n if (this.weeks || this.days) datePart += `${this.weeks * 7 + this.days}D`;\r\n\r\n // Time part\r\n let timePart = '';\r\n if (this.hours) timePart += `${this.hours}H`;\r\n if (this.minutes) timePart += `${this.minutes}M`;\r\n if (this.seconds || this.milliseconds) {\r\n timePart += `${this.seconds + this.milliseconds / 1000}S`;\r\n }\r\n\r\n const sign = this.isNegative() ? '-' : '';\r\n return `${sign}P${datePart}${timePart ? `T${timePart}` : ''}`;\r\n }\r\n\r\n /**\r\n * Get human-readable string\r\n */\r\n humanize(): string {\r\n const parts: string[] = [];\r\n\r\n if (this.years) parts.push(`${Math.abs(this.years)} year${Math.abs(this.years) !== 1 ? 's' : ''}`);\r\n if (this.months) parts.push(`${Math.abs(this.months)} month${Math.abs(this.months) !== 1 ? 's' : ''}`);\r\n if (this.weeks) parts.push(`${Math.abs(this.weeks)} week${Math.abs(this.weeks) !== 1 ? 's' : ''}`);\r\n if (this.days) parts.push(`${Math.abs(this.days)} day${Math.abs(this.days) !== 1 ? 's' : ''}`);\r\n if (this.hours) parts.push(`${Math.abs(this.hours)} hour${Math.abs(this.hours) !== 1 ? 's' : ''}`);\r\n if (this.minutes) parts.push(`${Math.abs(this.minutes)} minute${Math.abs(this.minutes) !== 1 ? 's' : ''}`);\r\n if (this.seconds) parts.push(`${Math.abs(this.seconds)} second${Math.abs(this.seconds) !== 1 ? 's' : ''}`);\r\n if (this.milliseconds) parts.push(`${Math.abs(this.milliseconds)} ms`);\r\n\r\n if (parts.length === 0) return '0 seconds';\r\n\r\n const text = parts.join(', ');\r\n return this.isNegative() ? `-${text}` : text;\r\n }\r\n\r\n /**\r\n * Check if duration is negative\r\n */\r\n isNegative(): boolean {\r\n return (\r\n this.years < 0 ||\r\n this.months < 0 ||\r\n this.weeks < 0 ||\r\n this.days < 0 ||\r\n this.hours < 0 ||\r\n this.minutes < 0 ||\r\n this.seconds < 0 ||\r\n this.milliseconds < 0\r\n );\r\n }\r\n\r\n /**\r\n * Get absolute duration\r\n */\r\n abs(): Duration {\r\n return new Duration({\r\n years: Math.abs(this.years),\r\n months: Math.abs(this.months),\r\n weeks: Math.abs(this.weeks),\r\n days: Math.abs(this.days),\r\n hours: Math.abs(this.hours),\r\n minutes: Math.abs(this.minutes),\r\n seconds: Math.abs(this.seconds),\r\n milliseconds: Math.abs(this.milliseconds),\r\n });\r\n }\r\n\r\n /**\r\n * String representation\r\n */\r\n toString(): string {\r\n return this.toISO();\r\n }\r\n}\r\n\r\n/**\r\n * Duration Plugin\r\n */\r\nexport class DurationPlugin implements ITimeGuardPlugin {\r\n name = 'duration';\r\n version = '1.0.0';\r\n\r\n /**\r\n * Install plugin into TimeGuard\r\n */\r\n install(TimeGuardClass: typeof TimeGuard): void {\r\n /**\r\n * Create a Duration between this date and another\r\n */\r\n (TimeGuardClass.prototype as any).duration = function (other: TimeGuard): Duration {\r\n return Duration.between(this, other);\r\n };\r\n\r\n /**\r\n * Get Duration class for creating custom durations\r\n */\r\n (TimeGuardClass as any).Duration = Duration;\r\n\r\n /**\r\n * Create Duration from ISO 8601 string\r\n */\r\n (TimeGuardClass as any).duration = {\r\n fromISO: (iso: string): Duration => Duration.fromISO(iso),\r\n between: (from: TimeGuard, to: TimeGuard): Duration => Duration.between(from, to),\r\n fromMilliseconds: (ms: number): Duration => Duration.fromMilliseconds(ms),\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Create and export default instance\r\n */\r\nexport const durationPlugin = new DurationPlugin();\r\n\r\nexport default durationPlugin;\r\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"relative-time.cjs","names":[],"sources":["../../src/plugins/relative-time/index.ts"],"sourcesContent":["/**\r\n * TimeGuard Relative Time Plugin\r\n * Adds human-readable time differences (e.g., \"2 hours ago\", \"in 3 days\")\r\n * Follows SOLID principles and Temporal API standards\r\n */\r\n\r\nimport type { ITimeGuardPlugin } from '../../types';\r\nimport type { TimeGuard } from '../../time-guard';\r\nimport type { RelativeTimeConfig, RelativeTimeFormats, RelativeTimeThreshold } from './types';\r\n\r\nconst DEFAULT_THRESHOLDS: RelativeTimeThreshold[] = [\r\n { l: 's', r: 44, d: 'second' },\r\n { l: 'm', r: 89 },\r\n { l: 'mm', r: 44, d: 'minute' },\r\n { l: 'h', r: 89 },\r\n { l: 'hh', r: 21, d: 'hour' },\r\n { l: 'd', r: 35 },\r\n { l: 'dd', r: 25, d: 'day' },\r\n { l: 'M', r: 45 },\r\n { l: 'MM', r: 10, d: 'month' },\r\n { l: 'y', r: 17 },\r\n { l: 'yy', d: 'year' },\r\n];\r\n\r\nconst DEFAULT_FORMATS: RelativeTimeFormats = {\r\n future: 'in %s',\r\n past: '%s ago',\r\n s: 'a few seconds',\r\n m: 'a minute',\r\n mm: '%d minutes',\r\n h: 'an hour',\r\n hh: '%d hours',\r\n d: 'a day',\r\n dd: '%d days',\r\n M: 'a month',\r\n MM: '%d months',\r\n y: 'a year',\r\n yy: '%d years',\r\n};\r\n\r\nexport class RelativeTimePlugin implements ITimeGuardPlugin {\r\n name = 'relative-time';\r\n version = '1.0.0';\r\n \r\n private config: RelativeTimeConfig;\r\n private formats: RelativeTimeFormats;\r\n\r\n constructor(config?: RelativeTimeConfig) {\r\n this.config = {\r\n thresholds: config?.thresholds || DEFAULT_THRESHOLDS,\r\n rounding: config?.rounding || Math.round,\r\n };\r\n this.formats = DEFAULT_FORMATS;\r\n }\r\n\r\n /**\r\n * Install plugin into TimeGuard\r\n */\r\n install(TimeGuardClass: typeof TimeGuard): void {\r\n const plugin = this;\r\n\r\n /**\r\n * Get relative time string (e.g., \"2 hours ago\")\r\n */\r\n (TimeGuardClass.prototype as any).fromNow = function (withoutSuffix?: boolean): string {\r\n return plugin.formatRelativeTime(this, false, withoutSuffix);\r\n };\r\n\r\n /**\r\n * Get future relative time string (e.g., \"in 3 days\")\r\n */\r\n (TimeGuardClass.prototype as any).toNow = function (withoutSuffix?: boolean): string {\r\n return plugin.formatRelativeTime(this, true, withoutSuffix);\r\n };\r\n\r\n /**\r\n * Get human-readable duration\r\n */\r\n (TimeGuardClass.prototype as any).humanize = function (\r\n other?: TimeGuard,\r\n withoutSuffix?: boolean,\r\n ): string {\r\n if (other) {\r\n return plugin.formatRelativeTime(this, other.isAfter(this), withoutSuffix);\r\n }\r\n return plugin.formatRelativeTime(this, false, withoutSuffix);\r\n };\r\n }\r\n\r\n /**\r\n * Format relative time\r\n */\r\n private formatRelativeTime(\r\n date: TimeGuard,\r\n isFuture: boolean,\r\n withoutSuffix?: boolean,\r\n ): string {\r\n const now = (date.constructor as typeof TimeGuard).now();\r\n let diff = now.diff(date, 'millisecond');\r\n const absDiff = Math.abs(diff);\r\n const isFromNow = diff > 0;\r\n const actualIsFuture = isFuture ?? !isFromNow;\r\n\r\n let result = this.getRelativeTimeString(absDiff);\r\n\r\n if (withoutSuffix) {\r\n return result;\r\n }\r\n\r\n const suffix = actualIsFuture ? this.formats.future : this.formats.past;\r\n return suffix.replace('%s', result);\r\n }\r\n\r\n /**\r\n * Get relative time string based on milliseconds\r\n */\r\n private getRelativeTimeString(milliseconds: number): string {\r\n const thresholds = this.config.thresholds || DEFAULT_THRESHOLDS;\r\n const rounding = this.config.rounding || Math.round;\r\n\r\n for (let i = 0; i < thresholds.length; i++) {\r\n const threshold = thresholds[i];\r\n const nextThreshold = i + 1 < thresholds.length ? thresholds[i + 1] : null;\r\n\r\n // Skip if we haven't reached this threshold\r\n if (nextThreshold && threshold.r && milliseconds < threshold.r * 1000) {\r\n continue;\r\n }\r\n\r\n // Convert to appropriate unit\r\n let value: number;\r\n if (threshold.d) {\r\n const unitMs = this.getUnitMilliseconds(threshold.d);\r\n value = rounding(milliseconds / unitMs);\r\n } else {\r\n value = 1;\r\n }\r\n\r\n const label = threshold.l;\r\n const format = (this.formats as any)[label] || label;\r\n\r\n if (typeof format === 'string') {\r\n return format.includes('%d')\r\n ? format.replace('%d', String(value))\r\n : format;\r\n }\r\n\r\n return format;\r\n }\r\n\r\n // Fallback\r\n return `${rounding(milliseconds / 1000)} seconds`;\r\n }\r\n\r\n /**\r\n * Get milliseconds per unit\r\n */\r\n private getUnitMilliseconds(unit: string): number {\r\n const msMap: Record<string, number> = {\r\n second: 1000,\r\n minute: 1000 * 60,\r\n hour: 1000 * 60 * 60,\r\n day: 1000 * 60 * 60 * 24,\r\n month: 1000 * 60 * 60 * 24 * 30,\r\n year: 1000 * 60 * 60 * 24 * 365,\r\n };\r\n return msMap[unit] || 1;\r\n }\r\n\r\n /**\r\n * Set format strings\r\n */\r\n setFormats(formats: Partial<RelativeTimeFormats>): void {\r\n Object.assign(this.formats, formats);\r\n }\r\n\r\n /**\r\n * Get current formats\r\n */\r\n getFormats(): RelativeTimeFormats {\r\n return { ...this.formats };\r\n }\r\n}\r\n\r\n/**\r\n * Create and export default instance\r\n */\r\nexport default new RelativeTimePlugin();\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"relative-time.cjs","names":[],"sources":["../../src/plugins/relative-time/index.ts"],"sourcesContent":["/**\r\n * TimeGuard Relative Time Plugin\r\n * Adds human-readable time differences (e.g., \"2 hours ago\", \"in 3 days\")\r\n * Follows SOLID principles and Temporal API standards\r\n */\r\n\r\nimport type { ITimeGuardPlugin } from '../../types';\r\nimport type { TimeGuard } from '../../index';\r\nimport type { RelativeTimeConfig, RelativeTimeFormats, RelativeTimeThreshold } from './types';\r\n\r\nconst DEFAULT_THRESHOLDS: RelativeTimeThreshold[] = [\r\n { l: 's', r: 44, d: 'second' },\r\n { l: 'm', r: 89 },\r\n { l: 'mm', r: 44, d: 'minute' },\r\n { l: 'h', r: 89 },\r\n { l: 'hh', r: 21, d: 'hour' },\r\n { l: 'd', r: 35 },\r\n { l: 'dd', r: 25, d: 'day' },\r\n { l: 'M', r: 45 },\r\n { l: 'MM', r: 10, d: 'month' },\r\n { l: 'y', r: 17 },\r\n { l: 'yy', d: 'year' },\r\n];\r\n\r\nconst DEFAULT_FORMATS: RelativeTimeFormats = {\r\n future: 'in %s',\r\n past: '%s ago',\r\n s: 'a few seconds',\r\n m: 'a minute',\r\n mm: '%d minutes',\r\n h: 'an hour',\r\n hh: '%d hours',\r\n d: 'a day',\r\n dd: '%d days',\r\n M: 'a month',\r\n MM: '%d months',\r\n y: 'a year',\r\n yy: '%d years',\r\n};\r\n\r\nexport class RelativeTimePlugin implements ITimeGuardPlugin {\r\n name = 'relative-time';\r\n version = '1.0.0';\r\n \r\n private config: RelativeTimeConfig;\r\n private formats: RelativeTimeFormats;\r\n\r\n constructor(config?: RelativeTimeConfig) {\r\n this.config = {\r\n thresholds: config?.thresholds || DEFAULT_THRESHOLDS,\r\n rounding: config?.rounding || Math.round,\r\n };\r\n this.formats = DEFAULT_FORMATS;\r\n }\r\n\r\n /**\r\n * Install plugin into TimeGuard\r\n */\r\n install(TimeGuardClass: typeof TimeGuard): void {\r\n const plugin = this;\r\n\r\n /**\r\n * Get relative time string (e.g., \"2 hours ago\")\r\n */\r\n (TimeGuardClass.prototype as any).fromNow = function (withoutSuffix?: boolean): string {\r\n return plugin.formatRelativeTime(this, false, withoutSuffix);\r\n };\r\n\r\n /**\r\n * Get future relative time string (e.g., \"in 3 days\")\r\n */\r\n (TimeGuardClass.prototype as any).toNow = function (withoutSuffix?: boolean): string {\r\n return plugin.formatRelativeTime(this, true, withoutSuffix);\r\n };\r\n\r\n /**\r\n * Get human-readable duration\r\n */\r\n (TimeGuardClass.prototype as any).humanize = function (\r\n other?: TimeGuard,\r\n withoutSuffix?: boolean,\r\n ): string {\r\n if (other) {\r\n return plugin.formatRelativeTime(this, other.isAfter(this), withoutSuffix);\r\n }\r\n return plugin.formatRelativeTime(this, false, withoutSuffix);\r\n };\r\n }\r\n\r\n /**\r\n * Format relative time\r\n */\r\n private formatRelativeTime(\r\n date: TimeGuard,\r\n isFuture: boolean,\r\n withoutSuffix?: boolean,\r\n ): string {\r\n const now = (date.constructor as typeof TimeGuard).now();\r\n let diff = now.diff(date, 'millisecond');\r\n const absDiff = Math.abs(diff);\r\n const isFromNow = diff > 0;\r\n const actualIsFuture = isFuture ?? !isFromNow;\r\n\r\n let result = this.getRelativeTimeString(absDiff);\r\n\r\n if (withoutSuffix) {\r\n return result;\r\n }\r\n\r\n const suffix = actualIsFuture ? this.formats.future : this.formats.past;\r\n return suffix.replace('%s', result);\r\n }\r\n\r\n /**\r\n * Get relative time string based on milliseconds\r\n */\r\n private getRelativeTimeString(milliseconds: number): string {\r\n const thresholds = this.config.thresholds || DEFAULT_THRESHOLDS;\r\n const rounding = this.config.rounding || Math.round;\r\n\r\n for (let i = 0; i < thresholds.length; i++) {\r\n const threshold = thresholds[i];\r\n const nextThreshold = i + 1 < thresholds.length ? thresholds[i + 1] : null;\r\n\r\n // Skip if we haven't reached this threshold\r\n if (nextThreshold && threshold.r && milliseconds < threshold.r * 1000) {\r\n continue;\r\n }\r\n\r\n // Convert to appropriate unit\r\n let value: number;\r\n if (threshold.d) {\r\n const unitMs = this.getUnitMilliseconds(threshold.d);\r\n value = rounding(milliseconds / unitMs);\r\n } else {\r\n value = 1;\r\n }\r\n\r\n const label = threshold.l;\r\n const format = (this.formats as any)[label] || label;\r\n\r\n if (typeof format === 'string') {\r\n return format.includes('%d')\r\n ? format.replace('%d', String(value))\r\n : format;\r\n }\r\n\r\n return format;\r\n }\r\n\r\n // Fallback\r\n return `${rounding(milliseconds / 1000)} seconds`;\r\n }\r\n\r\n /**\r\n * Get milliseconds per unit\r\n */\r\n private getUnitMilliseconds(unit: string): number {\r\n const msMap: Record<string, number> = {\r\n second: 1000,\r\n minute: 1000 * 60,\r\n hour: 1000 * 60 * 60,\r\n day: 1000 * 60 * 60 * 24,\r\n month: 1000 * 60 * 60 * 24 * 30,\r\n year: 1000 * 60 * 60 * 24 * 365,\r\n };\r\n return msMap[unit] || 1;\r\n }\r\n\r\n /**\r\n * Set format strings\r\n */\r\n setFormats(formats: Partial<RelativeTimeFormats>): void {\r\n Object.assign(this.formats, formats);\r\n }\r\n\r\n /**\r\n * Get current formats\r\n */\r\n getFormats(): RelativeTimeFormats {\r\n return { ...this.formats };\r\n }\r\n}\r\n\r\n/**\r\n * Create and export default instance\r\n */\r\nexport default new RelativeTimePlugin();\r\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- /*! time-guard v2.5.1 | (c) 2026 Berea-Soft | MIT License | https://github.com/Berea-Soft/time-guard */
1
+ /*! time-guard v2.5.3 | (c) 2026 Berea-Soft | MIT License | https://github.com/Berea-Soft/time-guard */
2
2
  //#region src/plugins/relative-time/index.ts
3
3
  var e = [
4
4
  {
@@ -1 +1 @@
1
- {"version":3,"file":"relative-time.es.js","names":[],"sources":["../../src/plugins/relative-time/index.ts"],"sourcesContent":["/**\r\n * TimeGuard Relative Time Plugin\r\n * Adds human-readable time differences (e.g., \"2 hours ago\", \"in 3 days\")\r\n * Follows SOLID principles and Temporal API standards\r\n */\r\n\r\nimport type { ITimeGuardPlugin } from '../../types';\r\nimport type { TimeGuard } from '../../time-guard';\r\nimport type { RelativeTimeConfig, RelativeTimeFormats, RelativeTimeThreshold } from './types';\r\n\r\nconst DEFAULT_THRESHOLDS: RelativeTimeThreshold[] = [\r\n { l: 's', r: 44, d: 'second' },\r\n { l: 'm', r: 89 },\r\n { l: 'mm', r: 44, d: 'minute' },\r\n { l: 'h', r: 89 },\r\n { l: 'hh', r: 21, d: 'hour' },\r\n { l: 'd', r: 35 },\r\n { l: 'dd', r: 25, d: 'day' },\r\n { l: 'M', r: 45 },\r\n { l: 'MM', r: 10, d: 'month' },\r\n { l: 'y', r: 17 },\r\n { l: 'yy', d: 'year' },\r\n];\r\n\r\nconst DEFAULT_FORMATS: RelativeTimeFormats = {\r\n future: 'in %s',\r\n past: '%s ago',\r\n s: 'a few seconds',\r\n m: 'a minute',\r\n mm: '%d minutes',\r\n h: 'an hour',\r\n hh: '%d hours',\r\n d: 'a day',\r\n dd: '%d days',\r\n M: 'a month',\r\n MM: '%d months',\r\n y: 'a year',\r\n yy: '%d years',\r\n};\r\n\r\nexport class RelativeTimePlugin implements ITimeGuardPlugin {\r\n name = 'relative-time';\r\n version = '1.0.0';\r\n \r\n private config: RelativeTimeConfig;\r\n private formats: RelativeTimeFormats;\r\n\r\n constructor(config?: RelativeTimeConfig) {\r\n this.config = {\r\n thresholds: config?.thresholds || DEFAULT_THRESHOLDS,\r\n rounding: config?.rounding || Math.round,\r\n };\r\n this.formats = DEFAULT_FORMATS;\r\n }\r\n\r\n /**\r\n * Install plugin into TimeGuard\r\n */\r\n install(TimeGuardClass: typeof TimeGuard): void {\r\n const plugin = this;\r\n\r\n /**\r\n * Get relative time string (e.g., \"2 hours ago\")\r\n */\r\n (TimeGuardClass.prototype as any).fromNow = function (withoutSuffix?: boolean): string {\r\n return plugin.formatRelativeTime(this, false, withoutSuffix);\r\n };\r\n\r\n /**\r\n * Get future relative time string (e.g., \"in 3 days\")\r\n */\r\n (TimeGuardClass.prototype as any).toNow = function (withoutSuffix?: boolean): string {\r\n return plugin.formatRelativeTime(this, true, withoutSuffix);\r\n };\r\n\r\n /**\r\n * Get human-readable duration\r\n */\r\n (TimeGuardClass.prototype as any).humanize = function (\r\n other?: TimeGuard,\r\n withoutSuffix?: boolean,\r\n ): string {\r\n if (other) {\r\n return plugin.formatRelativeTime(this, other.isAfter(this), withoutSuffix);\r\n }\r\n return plugin.formatRelativeTime(this, false, withoutSuffix);\r\n };\r\n }\r\n\r\n /**\r\n * Format relative time\r\n */\r\n private formatRelativeTime(\r\n date: TimeGuard,\r\n isFuture: boolean,\r\n withoutSuffix?: boolean,\r\n ): string {\r\n const now = (date.constructor as typeof TimeGuard).now();\r\n let diff = now.diff(date, 'millisecond');\r\n const absDiff = Math.abs(diff);\r\n const isFromNow = diff > 0;\r\n const actualIsFuture = isFuture ?? !isFromNow;\r\n\r\n let result = this.getRelativeTimeString(absDiff);\r\n\r\n if (withoutSuffix) {\r\n return result;\r\n }\r\n\r\n const suffix = actualIsFuture ? this.formats.future : this.formats.past;\r\n return suffix.replace('%s', result);\r\n }\r\n\r\n /**\r\n * Get relative time string based on milliseconds\r\n */\r\n private getRelativeTimeString(milliseconds: number): string {\r\n const thresholds = this.config.thresholds || DEFAULT_THRESHOLDS;\r\n const rounding = this.config.rounding || Math.round;\r\n\r\n for (let i = 0; i < thresholds.length; i++) {\r\n const threshold = thresholds[i];\r\n const nextThreshold = i + 1 < thresholds.length ? thresholds[i + 1] : null;\r\n\r\n // Skip if we haven't reached this threshold\r\n if (nextThreshold && threshold.r && milliseconds < threshold.r * 1000) {\r\n continue;\r\n }\r\n\r\n // Convert to appropriate unit\r\n let value: number;\r\n if (threshold.d) {\r\n const unitMs = this.getUnitMilliseconds(threshold.d);\r\n value = rounding(milliseconds / unitMs);\r\n } else {\r\n value = 1;\r\n }\r\n\r\n const label = threshold.l;\r\n const format = (this.formats as any)[label] || label;\r\n\r\n if (typeof format === 'string') {\r\n return format.includes('%d')\r\n ? format.replace('%d', String(value))\r\n : format;\r\n }\r\n\r\n return format;\r\n }\r\n\r\n // Fallback\r\n return `${rounding(milliseconds / 1000)} seconds`;\r\n }\r\n\r\n /**\r\n * Get milliseconds per unit\r\n */\r\n private getUnitMilliseconds(unit: string): number {\r\n const msMap: Record<string, number> = {\r\n second: 1000,\r\n minute: 1000 * 60,\r\n hour: 1000 * 60 * 60,\r\n day: 1000 * 60 * 60 * 24,\r\n month: 1000 * 60 * 60 * 24 * 30,\r\n year: 1000 * 60 * 60 * 24 * 365,\r\n };\r\n return msMap[unit] || 1;\r\n }\r\n\r\n /**\r\n * Set format strings\r\n */\r\n setFormats(formats: Partial<RelativeTimeFormats>): void {\r\n Object.assign(this.formats, formats);\r\n }\r\n\r\n /**\r\n * Get current formats\r\n */\r\n getFormats(): RelativeTimeFormats {\r\n return { ...this.formats };\r\n }\r\n}\r\n\r\n/**\r\n * Create and export default instance\r\n */\r\nexport default new RelativeTimePlugin();\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"relative-time.es.js","names":[],"sources":["../../src/plugins/relative-time/index.ts"],"sourcesContent":["/**\r\n * TimeGuard Relative Time Plugin\r\n * Adds human-readable time differences (e.g., \"2 hours ago\", \"in 3 days\")\r\n * Follows SOLID principles and Temporal API standards\r\n */\r\n\r\nimport type { ITimeGuardPlugin } from '../../types';\r\nimport type { TimeGuard } from '../../index';\r\nimport type { RelativeTimeConfig, RelativeTimeFormats, RelativeTimeThreshold } from './types';\r\n\r\nconst DEFAULT_THRESHOLDS: RelativeTimeThreshold[] = [\r\n { l: 's', r: 44, d: 'second' },\r\n { l: 'm', r: 89 },\r\n { l: 'mm', r: 44, d: 'minute' },\r\n { l: 'h', r: 89 },\r\n { l: 'hh', r: 21, d: 'hour' },\r\n { l: 'd', r: 35 },\r\n { l: 'dd', r: 25, d: 'day' },\r\n { l: 'M', r: 45 },\r\n { l: 'MM', r: 10, d: 'month' },\r\n { l: 'y', r: 17 },\r\n { l: 'yy', d: 'year' },\r\n];\r\n\r\nconst DEFAULT_FORMATS: RelativeTimeFormats = {\r\n future: 'in %s',\r\n past: '%s ago',\r\n s: 'a few seconds',\r\n m: 'a minute',\r\n mm: '%d minutes',\r\n h: 'an hour',\r\n hh: '%d hours',\r\n d: 'a day',\r\n dd: '%d days',\r\n M: 'a month',\r\n MM: '%d months',\r\n y: 'a year',\r\n yy: '%d years',\r\n};\r\n\r\nexport class RelativeTimePlugin implements ITimeGuardPlugin {\r\n name = 'relative-time';\r\n version = '1.0.0';\r\n \r\n private config: RelativeTimeConfig;\r\n private formats: RelativeTimeFormats;\r\n\r\n constructor(config?: RelativeTimeConfig) {\r\n this.config = {\r\n thresholds: config?.thresholds || DEFAULT_THRESHOLDS,\r\n rounding: config?.rounding || Math.round,\r\n };\r\n this.formats = DEFAULT_FORMATS;\r\n }\r\n\r\n /**\r\n * Install plugin into TimeGuard\r\n */\r\n install(TimeGuardClass: typeof TimeGuard): void {\r\n const plugin = this;\r\n\r\n /**\r\n * Get relative time string (e.g., \"2 hours ago\")\r\n */\r\n (TimeGuardClass.prototype as any).fromNow = function (withoutSuffix?: boolean): string {\r\n return plugin.formatRelativeTime(this, false, withoutSuffix);\r\n };\r\n\r\n /**\r\n * Get future relative time string (e.g., \"in 3 days\")\r\n */\r\n (TimeGuardClass.prototype as any).toNow = function (withoutSuffix?: boolean): string {\r\n return plugin.formatRelativeTime(this, true, withoutSuffix);\r\n };\r\n\r\n /**\r\n * Get human-readable duration\r\n */\r\n (TimeGuardClass.prototype as any).humanize = function (\r\n other?: TimeGuard,\r\n withoutSuffix?: boolean,\r\n ): string {\r\n if (other) {\r\n return plugin.formatRelativeTime(this, other.isAfter(this), withoutSuffix);\r\n }\r\n return plugin.formatRelativeTime(this, false, withoutSuffix);\r\n };\r\n }\r\n\r\n /**\r\n * Format relative time\r\n */\r\n private formatRelativeTime(\r\n date: TimeGuard,\r\n isFuture: boolean,\r\n withoutSuffix?: boolean,\r\n ): string {\r\n const now = (date.constructor as typeof TimeGuard).now();\r\n let diff = now.diff(date, 'millisecond');\r\n const absDiff = Math.abs(diff);\r\n const isFromNow = diff > 0;\r\n const actualIsFuture = isFuture ?? !isFromNow;\r\n\r\n let result = this.getRelativeTimeString(absDiff);\r\n\r\n if (withoutSuffix) {\r\n return result;\r\n }\r\n\r\n const suffix = actualIsFuture ? this.formats.future : this.formats.past;\r\n return suffix.replace('%s', result);\r\n }\r\n\r\n /**\r\n * Get relative time string based on milliseconds\r\n */\r\n private getRelativeTimeString(milliseconds: number): string {\r\n const thresholds = this.config.thresholds || DEFAULT_THRESHOLDS;\r\n const rounding = this.config.rounding || Math.round;\r\n\r\n for (let i = 0; i < thresholds.length; i++) {\r\n const threshold = thresholds[i];\r\n const nextThreshold = i + 1 < thresholds.length ? thresholds[i + 1] : null;\r\n\r\n // Skip if we haven't reached this threshold\r\n if (nextThreshold && threshold.r && milliseconds < threshold.r * 1000) {\r\n continue;\r\n }\r\n\r\n // Convert to appropriate unit\r\n let value: number;\r\n if (threshold.d) {\r\n const unitMs = this.getUnitMilliseconds(threshold.d);\r\n value = rounding(milliseconds / unitMs);\r\n } else {\r\n value = 1;\r\n }\r\n\r\n const label = threshold.l;\r\n const format = (this.formats as any)[label] || label;\r\n\r\n if (typeof format === 'string') {\r\n return format.includes('%d')\r\n ? format.replace('%d', String(value))\r\n : format;\r\n }\r\n\r\n return format;\r\n }\r\n\r\n // Fallback\r\n return `${rounding(milliseconds / 1000)} seconds`;\r\n }\r\n\r\n /**\r\n * Get milliseconds per unit\r\n */\r\n private getUnitMilliseconds(unit: string): number {\r\n const msMap: Record<string, number> = {\r\n second: 1000,\r\n minute: 1000 * 60,\r\n hour: 1000 * 60 * 60,\r\n day: 1000 * 60 * 60 * 24,\r\n month: 1000 * 60 * 60 * 24 * 30,\r\n year: 1000 * 60 * 60 * 24 * 365,\r\n };\r\n return msMap[unit] || 1;\r\n }\r\n\r\n /**\r\n * Set format strings\r\n */\r\n setFormats(formats: Partial<RelativeTimeFormats>): void {\r\n Object.assign(this.formats, formats);\r\n }\r\n\r\n /**\r\n * Get current formats\r\n */\r\n getFormats(): RelativeTimeFormats {\r\n return { ...this.formats };\r\n }\r\n}\r\n\r\n/**\r\n * Create and export default instance\r\n */\r\nexport default new RelativeTimePlugin();\r\n"],"mappings":"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"}