@@ -6,6 +6,7 @@ const Temporal = globalThis.Temporal || require('temporal-polyfill').Temporal;
66const windowsZones = require ( '../windowsZones.json' ) ;
77
88// Ensure polyfill is globally available for downstream modules
9+ // eslint-disable-next-line unicorn/no-global-object-property-assignment -- shared polyfill bootstrap keeps runtime behavior explicit
910globalThis . Temporal ??= Temporal ;
1011
1112// Minimal alias map to emulate the subset of moment.tz.link behavior tests rely on
@@ -16,7 +17,7 @@ const aliasMap = new Map();
1617 * Collapses whitespace, trims the result, and lowercases the value for case-insensitive lookups.
1718 *
1819 * @param {string } label
19- * @returns {string }
20+ * @returns {string } Normalized label
2021 */
2122function normalizeWindowsLabel ( label ) {
2223 return String ( label )
@@ -30,7 +31,7 @@ function normalizeWindowsLabel(label) {
3031 * This lets us resolve the canonical IANA identifier without relying on fuzzy substring matching.
3132 *
3233 * @param {Record<string, {iana: string[]}> } source
33- * @returns {Map<string, {iana: string[]}> }
34+ * @returns {Map<string, {iana: string[]}> } Index map of normalized labels to data
3435 */
3536function buildWindowsLabelIndex ( source ) {
3637 const index = new Map ( ) ;
@@ -68,7 +69,7 @@ const windowsLabelIndex = buildWindowsLabelIndex(windowsZones);
6869 * Resolve a Windows/legacy timezone label to the canonical IANA identifier exported in windowsZones.json.
6970 *
7071 * @param {string } label
71- * @returns {string|null }
72+ * @returns {string|null } IANA zone or null if not found
7273 */
7374function mapWindowsZone ( label ) {
7475 const exact = windowsZones [ label ] ;
@@ -106,7 +107,7 @@ const validIanaCache = new Map();
106107 * Convert textual UTC offsets ("+05:30", "UTC-4", "(UTC+02:00)") into signed minute counts.
107108 *
108109 * @param {string } offset
109- * @returns {number|undefined }
110+ * @returns {number|undefined } Total minutes or undefined if invalid
110111 */
111112function offsetLabelToMinutes ( offset ) {
112113 if ( ! offset ) {
@@ -118,7 +119,7 @@ function offsetLabelToMinutes(offset) {
118119 . replace ( / ^ \( ? (?: u t c | g m t ) \) ? \s * / iv, '' )
119120 . replace ( / \) $ / v, '' )
120121 . trim ( ) ;
121- const match = trimmed . match ( / ^ ( [ + \- ] ) ( \d { 1 , 2 } ) (?: : ? ( \d { 2 } ) ) ? $ / v) ;
122+ const match = / ^ ( [ + \- ] ) ( \d { 1 , 2 } ) (?: : ? ( \d { 2 } ) ) ? $ / v. exec ( trimmed ) ;
122123 if ( ! match ) {
123124 return undefined ;
124125 }
@@ -177,7 +178,7 @@ function minutesToEtcZone(totalMinutes) {
177178 * Interpret a TZID value (IANA, Windows display name, or offset label) and return structured metadata.
178179 *
179180 * @param {string } value
180- * @returns {{original: string|undefined, iana: string|undefined, offset: string|undefined, offsetMinutes: number|undefined, etc: string|undefined} }
181+ * @returns {{original: string|undefined, iana: string|undefined, offset: string|undefined, offsetMinutes: number|undefined, etc: string|undefined} } Resolved timezone metadata
181182 */
182183function resolveTZID ( value ) {
183184 if ( typeof value !== 'string' || value . length === 0 ) {
@@ -247,7 +248,7 @@ function resolveTZID(value) {
247248 *
248249 * @param {Date } date
249250 * @param {{iana?: string, offsetMinutes?: number} } tzInfo
250- * @returns {string|undefined }
251+ * @returns {string|undefined } Formatted wall-time string or undefined if invalid
251252 */
252253function formatDateForRrule ( date , tzInfo = { } ) {
253254 if ( ! ( date instanceof Date ) || Number . isNaN ( date . getTime ( ) ) ) {
@@ -276,7 +277,7 @@ function formatDateForRrule(date, tzInfo = {}) {
276277 *
277278 * @param {Date } date
278279 * @param {string|undefined } tzid
279- * @returns {Date|undefined }
280+ * @returns {Date|undefined } Date with attached timezone metadata
280281 */
281282function attachTz ( date , tzid ) {
282283 if ( ! date || ! tzid ) {
@@ -314,6 +315,8 @@ function guessLocalZone() {
314315 *
315316 * We depend on Node 20+, so `Intl.supportedValuesOf('timeZone')` is guaranteed
316317 * to exist and yields the canonical list without requiring extra guards.
318+ *
319+ * @returns {string[] } Array of IANA timezone names
317320 */
318321function getZoneNames ( ) {
319322 return Intl . supportedValuesOf ( 'timeZone' ) ;
@@ -362,7 +365,7 @@ function parseDateTimeInZone(yyyymmddThhmmss, zone) {
362365 const s = String ( yyyymmddThhmmss ) ;
363366 // Support basic and extended forms
364367 // Try extended first: YYYY-MM-DDTHH:mm:ss
365- let m = s . match ( / ^ ( \d { 4 } ) - ( \d { 2 } ) - ( \d { 2 } ) [ T ] ( \d { 2 } ) : ( \d { 2 } ) (?: : ( \d { 2 } ) ) ? $ / v) ;
368+ let m = / ^ ( \d { 4 } ) - ( \d { 2 } ) - ( \d { 2 } ) [ T ] ( \d { 2 } ) : ( \d { 2 } ) (?: : ( \d { 2 } ) ) ? $ / v. exec ( s ) ;
366369 let fields ;
367370 if ( m ) {
368371 fields = {
@@ -375,7 +378,7 @@ function parseDateTimeInZone(yyyymmddThhmmss, zone) {
375378 } ;
376379 } else {
377380 // Basic form: YYYYMMDDTHHmmss or YYYYMMDDTHHmm
378- m = s . match ( / ^ ( \d { 4 } ) ( \d { 2 } ) ( \d { 2 } ) T ( \d { 2 } ) ( \d { 2 } ) ( \d { 2 } ) ? $ / v) ;
381+ m = / ^ ( \d { 4 } ) ( \d { 2 } ) ( \d { 2 } ) T ( \d { 2 } ) ( \d { 2 } ) ( \d { 2 } ) ? $ / v. exec ( s ) ;
379382 if ( m ) {
380383 fields = {
381384 year : Number ( m [ 1 ] ) ,
@@ -413,10 +416,10 @@ function parseDateTimeInZone(yyyymmddThhmmss, zone) {
413416function parseWithOffset ( yyyymmddThhmmss , offset ) {
414417 // Offset like +hh:mm, -hh:mm, +hhmm, -hhmm, optionally prefixed by UTC/GMT
415418 const s = String ( yyyymmddThhmmss ) ;
416- let m = s . match ( / ^ ( \d { 4 } ) ( \d { 2 } ) ( \d { 2 } ) T ( \d { 2 } ) ( \d { 2 } ) ( \d { 2 } ) ? $ / v) ;
419+ let m = / ^ ( \d { 4 } ) ( \d { 2 } ) ( \d { 2 } ) T ( \d { 2 } ) ( \d { 2 } ) ( \d { 2 } ) ? $ / v. exec ( s ) ;
417420 // Some feeds emit extended ISO `YYYY-MM-DD[T ]HH:mm[:ss]` strings alongside numeric offsets.
418421 // Mirror parseDateTimeInZone by accepting that form too so we don't fall back to local Date semantics.
419- m ||= s . match ( / ^ ( \d { 4 } ) - ( \d { 2 } ) - ( \d { 2 } ) [ T ] ( \d { 2 } ) : ( \d { 2 } ) (?: : ( \d { 2 } ) ) ? $ / v) ;
422+ m ||= / ^ ( \d { 4 } ) - ( \d { 2 } ) - ( \d { 2 } ) [ T ] ( \d { 2 } ) : ( \d { 2 } ) (?: : ( \d { 2 } ) ) ? $ / v. exec ( s ) ;
420423
421424 if ( ! m ) {
422425 return undefined ;
@@ -484,7 +487,7 @@ const vtimezoneIanaCache = new Map();
484487 *
485488 * @param {Array } blocks - Array of STANDARD or DAYLIGHT components (all same type)
486489 * @param {number } refYear - The event year to look up the rule for
487- * @returns {Object| undefined }
490+ * @returns {object | undefined } Applicable observance block or undefined
488491 */
489492function pickApplicableBlock ( blocks , refYear ) {
490493 if ( blocks . length === 0 ) {
@@ -527,10 +530,10 @@ function pickApplicableBlock(blocks, refYear) {
527530 * No reliable representation is available; callers should fall back to
528531 * floating/local time rather than returning a confidently wrong offset.
529532 *
530- * @param {Object } vTimezone - Parsed VTIMEZONE object (from the node-ical parser stack)
533+ * @param {object } vTimezone - Parsed VTIMEZONE object (from the node-ical parser stack)
531534 * @param {number } year - Reference year used to select the applicable observance block
532535 * and to probe the IANA database (DST boundaries can change historically).
533- * @returns {{ iana: string|undefined, offset: string|undefined } }
536+ * @returns {{ iana: string|undefined, offset: string|undefined } } IANA zone and/or fixed offset
534537 */
535538function resolveVTimezoneToIana ( vTimezone , year ) {
536539 if ( ! vTimezone || typeof vTimezone !== 'object' ) {
@@ -540,7 +543,7 @@ function resolveVTimezoneToIana(vTimezone, year) {
540543 // Reject unusable year values before they can corrupt the cache key or cause
541544 // Temporal.Instant.from() to throw on a malformed ISO string.
542545 const yearNumber = Number ( year ) ;
543- if ( ! Number . isFinite ( yearNumber ) || ! Number . isInteger ( yearNumber ) ) {
546+ if ( ! Number . isFinite ( yearNumber ) || ! Number . isSafeInteger ( yearNumber ) ) {
544547 return { iana : undefined , offset : undefined } ;
545548 }
546549
@@ -645,5 +648,5 @@ function isUtcTimezone(tz) {
645648 }
646649
647650 const tzLower = tz . toLowerCase ( ) ;
648- return tzLower === 'etc/utc' || tzLower === 'utc' || tzLower === 'etc/gmt' ;
651+ return [ 'etc/utc' , 'utc' , 'etc/gmt' ] . includes ( tzLower ) ;
649652}
0 commit comments