import { TZ } from '@phensley/timezone' ; import { lineWrap , Code , HEADER , NOLINT_MAXLINE } from './util' ; import chalk from 'chalk' ; class IdArray { readonly array : string [ ] = [ ] ; private index : any = { } ; private sequence : number = 0 ; add ( key ) { let id = this . index [ key ] ; if ( id === undefined ) { id = this . sequence ++ ; this . index [ key ] = id ; this . array . push ( key ) ; } return id ; } } interface Metazones { zoneindex : string ; metazoneids : string ; index : string ; offsets : string ; untils : string ; } const IGNORED_ZONES = new Set < string > ( [ 'Etc/GMT+1' , 'Etc/GMT+2' , 'Etc/GMT+3' , 'Etc/GMT+4' , 'Etc/GMT+5' , 'Etc/GMT+6' , 'Etc/GMT+7' , 'Etc/GMT+8' , 'Etc/GMT+9' , 'Etc/GMT+10' , 'Etc/GMT+11' , 'Etc/GMT+12' , 'Etc/GMT-1' , 'Etc/GMT-2' , 'Etc/GMT-3' , 'Etc/GMT-4' , 'Etc/GMT-5' , 'Etc/GMT-6' , 'Etc/GMT-7' , 'Etc/GMT-8' , 'Etc/GMT-9' , 'Etc/GMT-10' , 'Etc/GMT-11' , 'Etc/GMT-12' , 'Etc/GMT-13' , 'Etc/GMT-14' , ] ) ; const base36 = ( n ) => n . toString ( 36 ) ; const buildMetaZones2 = ( data ) : Metazones => { const metazoneIndex = new IdArray ( ) ; const offsets = [ ] ; const untils = [ ] ; const index = [ ] ; const zonemap = new Map < number , number > ( ) ; const zoneids = TZ . zoneIds ( ) ; Object . keys ( data ) . forEach ( ( id , mi ) => { let zi = zoneids . indexOf ( id ) ; if ( zi === - 1 ) { const zid = TZ . resolveId ( id ) ; if ( zid === undefined ) { throw new Error ( `${ chalk . red ( 'Error' ) } tzdb / cldr mismatch. zone id failed ${ id }` ) ; } zi = zoneids . indexOf ( zid ) ; } zonemap . set ( zi , mi ) ; } ) ; const zoneindex = [ ] ; zoneids . forEach ( ( id , zi ) => { let mi = zonemap . get ( zi ) ; if ( mi === undefined ) { if ( id === 'Etc/UTC' ) { zi = zoneids . indexOf ( 'Etc/GMT' ) ; mi = zonemap . get ( zi ) ; } else if ( ! IGNORED_ZONES . has ( id ) ) { console . log ( `${ chalk . red ( 'Warning' ) }: ${ id } has no metazone` ) ; } } zoneindex . push ( mi === undefined ? - 1 : mi ) ; } ) ; Object . keys ( data ) . forEach ( ( id ) => { const start = offsets . length ; const ranges = data [ id ] . reverse ( ) ; ranges . forEach ( ( range ) => { const [ mzid , from ] = range ; const offset = metazoneIndex . add ( mzid ) ; offsets . push ( offset ) ; untils . push ( from === - 1 ? from : from / 1000 ) ; } ) ; const end = offsets . length ; index . push ( start ) ; index . push ( end ) ; } ) ; return { zoneindex : zoneindex . map ( base36 ) . join ( ' ' ) , metazoneids : metazoneIndex . array . join ( ' ' ) , index : index . map ( base36 ) . join ( ' ' ) , offsets : offsets . map ( base36 ) . join ( ' ' ) , untils : untils . map ( base36 ) . join ( ' ' ) , } ; } ; const buildStableIdMapping = ( data ) : string => { const tzids = TZ . zoneIds ( ) ; const stableids = data . timeZoneIds ; const res = [ ] ; for ( const stableid of stableids ) { const resolved = TZ . resolveId ( stableid ) ; if ( resolved === undefined || stableid === resolved ) { continue ; } const i = tzids . indexOf ( resolved ) ; res . push ( `${ i }:${ stableid }` ) ; } return res . join ( '|' ) ; } ; /**
 * Construct timezone source.
 */ export const getZones = ( data ) : Code [ ] => { const result = [ ] ; const metazonedata = buildMetaZones2 ( data . metaZoneRanges ) ; const stableidmap = buildStableIdMapping ( data ) ; let code = NOLINT_MAXLINE + HEADER ; code += `export const metazoneData = {\n` ; code += `  // mapping of time zone's array index to metazone's array index\n` ; code += `  zoneindex: '${ metazonedata . zoneindex }',\n\n` ; code += `  // array of metazone ids\n` ; code += `  metazoneids: '${ metazonedata . metazoneids }'.split(' '),\n\n` ; code += `  // array of start/end slice indices into offsets and untils arrays\n` ; code += `  index: '${ metazonedata . index }',\n\n` ; code += `  // offset indicating which metazone id to use at a given until\n` ; code += `  offsets: '${ metazonedata . offsets }',\n` ; code += `  // until timestamps\n` ; code += `  untils: '${ metazonedata . untils }',\n` ; code += `  // mapping of tzdb id back to cldr stable id used for schema lookups\n` ; code += `  stableids: '${ stableidmap }'\n` ; code += `};\n` ; result . push ( Code . core ( [ 'systems' , 'calendars' , 'autogen.zonedata.ts' ] , code ) ) ; code = NOLINT_MAXLINE + HEADER ; code += "import { MetaZoneType } from '@phensley/cldr-types';\n\n" ; code += '/** @public */\n' ; code += `export const TimeZoneStableIds: string[] = ('` ; code += data . timeZoneIds . join ( ' ' ) ; code += `').split(' ');\n\n` ; code += '/** @public */\n' ; code += `export const MetaZoneValues: MetaZoneType[] = ('` ; code += data . metaZoneIds . join ( ' ' ) ; code += `').split(' ') as MetaZoneType[];\n` ; result . push ( Code . core ( [ 'schema' , 'schema' , 'autogen.timezones.ts' ] , code ) ) ; code = NOLINT_MAXLINE + HEADER ; const metaZoneType = lineWrap ( 60 , ' | ' , data . metaZoneIds . map ( ( k ) => `'${ k }'` ) ) ; code += '/** @public */\n' ; code += `export type MetaZoneType = ${ metaZoneType };\n` ; result . push ( Code . types ( [ 'autogen.timezones.ts' ] , code ) ) ; return result ; } ;