'use strict' ; import type DataTable from './DataTable.js' ; import type JSON from '../Core/JSON' ; import U from './../Core/Utilities.js' ; const { merge , isNumber } = U ; /**
 * Class to convert between common value types.
 */ class DataConverter { /**
     * Default options
     */ protected static readonly defaultOptions : DataConverter . Options = { dateFormat : '' , alternativeFormat : '' } ; param { DataConverter . Options } options param { DataConverter . ParseDateCallbackFunction } parseDate public constructor ( options ? , parseDate ? ) { let decimalPoint ; this . options = merge ( DataConverter . defaultOptions , options ) ; this . parseDateFn = parseDate ; decimalPoint = this . options . decimalPoint ; if ( decimalPoint !== '.' && decimalPoint !== ',' ) { decimalPoint = void 0 ; } this . decimalRegex = ( decimalPoint && new RegExp ( '^(-?[0-9]+)' + decimalPoint + '([0-9]+)$' ) ) ; } /**
     * Options for the DataConverter.
     */ private options : DataConverter . Options ; /**
     * Custom parsing function used instead of build-in parseDate method.
     */ private parseDateFn : ( DataConverter . ParseDateFunction | undefined ) ; /**
     * Regular expression used in the trim method to change a decimal point.
     */ private decimalRegex : ( RegExp | undefined ) ; name type { Highcharts . Dictionary < Highcharts . DataDateFormatObject > } private dateFormats : Record < string , Highcharts . DataDateFormatObject > = { 'YYYY/mm/dd' : { regex : /^([0-9]{4})[\-\/\.]([0-9]{1,2})[\-\/\.]([0-9]{1,2})$/ , parser : function ( match ) : number { return ( match ? Date . UTC ( + match [ 1 ] , ( match [ 2 ] as any ) - 1 , + match [ 3 ] ) : NaN ) ; } } , 'dd/mm/YYYY' : { regex : /^([0-9]{1,2})[\-\/\.]([0-9]{1,2})[\-\/\.]([0-9]{4})$/ , parser : function ( match ) : number { return ( match ? Date . UTC ( + match [ 3 ] , ( match [ 2 ] as any ) - 1 , + match [ 1 ] ) : NaN ) ; } , alternative : 'mm/dd/YYYY' } , 'mm/dd/YYYY' : { regex : /^([0-9]{1,2})[\-\/\.]([0-9]{1,2})[\-\/\.]([0-9]{4})$/ , parser : function ( match ) : number { return ( match ? Date . UTC ( + match [ 3 ] , ( match [ 1 ] as any ) - 1 , + match [ 2 ] ) : NaN ) ; } } , 'dd/mm/YY' : { regex : /^([0-9]{1,2})[\-\/\.]([0-9]{1,2})[\-\/\.]([0-9]{2})$/ , parser : function ( match ) : number { const d = new Date ( ) ; if ( ! match ) { return NaN ; } let year = + match [ 3 ] ; if ( year > ( d . getFullYear ( ) - 2000 ) ) { year += 1900 ; } else { year += 2000 ; } return Date . UTC ( year , ( match [ 2 ] as any ) - 1 , + match [ 1 ] ) ; } , alternative : 'mm/dd/YY' } , 'mm/dd/YY' : { regex : /^([0-9]{1,2})[\-\/\.]([0-9]{1,2})[\-\/\.]([0-9]{2})$/ , parser : function ( match ) : number { return ( match ? Date . UTC ( + match [ 3 ] + 2000 , ( match [ 1 ] as any ) - 1 , + match [ 2 ] ) : NaN ) ; } } } ; /**
     * Getter for a date format.
     */ public getDateFormat ( ) { return this . options . dateFormat ; } param { DataConverter . Type } value return { boolean } public asBoolean ( value ) { if ( typeof value === 'boolean' ) { return value ; } if ( typeof value === 'string' ) { return value !== '' && value !== '0' && value !== 'false' ; } return ! ! this . asNumber ( value ) ; } param { DataConverter . Type } value return { globalThis . Date } public asDate ( value ) { let timestamp ; if ( typeof value === 'string' ) { timestamp = this . parseDate ( value ) ; } else if ( typeof value === 'number' ) { timestamp = value ; } else if ( value instanceof Date ) { return value ; } else { timestamp = this . parseDate ( this . asString ( value ) ) ; } return new Date ( timestamp ) ; } param { DataConverter . Type } value return { number } public asNumber ( value ) { if ( typeof value === 'number' ) { return value ; } if ( typeof value === 'boolean' ) { return value ? 1 : 0 ; } if ( typeof value === 'string' ) { if ( value . indexOf ( ' ' ) > - 1 ) { value = value . replace ( /\s+/g , '' ) ; } if ( this . decimalRegex ) { value = value . replace ( this . decimalRegex , '$1.$2' ) ; } return parseFloat ( value ) ; } if ( value instanceof Date ) { return value . getDate ( ) ; } if ( value ) { return value . getRowCount ( ) ; } return NaN ; } param { DataConverter . Type } value return { string } public asString ( value ) { return `${ value }` ; } param { string } str param { boolean } inside return { string } public trim ( str , inside ? ) { const converter = this ; if ( typeof str === 'string' ) { str = str . replace ( /^\s+|\s+$/g , '' ) ; if ( inside && /^[0-9\s]+$/ . test ( str ) ) { str = str . replace ( /\s/g , '' ) ; } if ( converter . decimalRegex ) { str = str . replace ( converter . decimalRegex , '$1.$2' ) ; } } return str ; } param { string } value return { 'number' | 'string' | 'Date' } public guessType ( value ) { const converter = this , trimVal = converter . trim ( value ) , trimInsideVal = converter . trim ( value , true ) , floatVal = parseFloat ( trimInsideVal ) ; let result = 'string' , dateVal ; if ( + trimInsideVal === floatVal ) { if ( floatVal > 365 * 24 * 3600 * 1000 ) { result = 'Date' ; } else { result = 'number' ; } } else { if ( trimVal && trimVal . length ) { dateVal = converter . parseDate ( value ) ; } if ( dateVal && isNumber ( dateVal ) ) { result = 'Date' ; } else { result = 'string' ; } } return result ; } param { string } value return { number | string | Date } public asGuessedType ( value ) { const converter = this , typeMap = { 'number' : converter . asNumber , 'Date' : converter . asDate , 'string' : converter . asString } ; return typeMap [ converter . guessType ( value ) ] . call ( converter , value ) ; } function param { string } value param { string } dateFormatProp public parseDate ( value , dateFormatProp ? ) { const converter = this ; let dateFormat = dateFormatProp || converter . options . dateFormat , result = NaN , key , format , match ; if ( converter . parseDateFn ) { result = converter . parseDateFn ( value ) ; } else { if ( ! dateFormat ) { for ( key in converter . dateFormats ) { format = converter . dateFormats [ key ] ; match = value . match ( format . regex ) ; if ( match ) { dateFormat = key ; result = format . parser ( match ) ; break ; } } } else { format = converter . dateFormats [ dateFormat ] ; if ( ! format ) { format = converter . dateFormats [ 'YYYY/mm/dd' ] ; } match = value . match ( format . regex ) ; if ( match ) { result = format . parser ( match ) ; } } if ( ! match ) { match = Date . parse ( value ) ; if ( typeof match === 'object' && match !== null && ( match as any ) . getTime ) { result = ( ( match as any ) . getTime ( ) - ( match as any ) . getTimezoneOffset ( ) * 60000 ) ; } else if ( isNumber ( match ) ) { result = match - ( new Date ( match ) ) . getTimezoneOffset ( ) * 60000 ; if ( value . indexOf ( '2001' ) === - 1 && ( new Date ( result ) ) . getFullYear ( ) === 2001 ) { result = NaN ; } } } } return result ; } private param { Array < string > } data param { number } limit param { boolean } save public deduceDateFormat ( data , limit ? , save ? ) { const parser = this , stable = [ ] , max = [ ] ; let format = 'YYYY/mm/dd' , thing , guessedFormat = [ ] , i = 0 , madeDeduction = false , elem , j ; if ( ! limit || limit > data . length ) { limit = data . length ; } for ( ; i < limit ; i ++ ) { if ( typeof data [ i ] !== 'undefined' && data [ i ] && data [ i ] . length ) { thing = data [ i ] . trim ( ) . replace ( /\//g , ' ' ) . replace ( /\-/g , ' ' ) . replace ( /\./g , ' ' ) . split ( ' ' ) ; guessedFormat = [ '' , '' , '' ] ; for ( j = 0 ; j < thing . length ; j ++ ) { if ( j < guessedFormat . length ) { elem = parseInt ( thing [ j ] , 10 ) ; if ( elem ) { max [ j ] = ( ! max [ j ] || max [ j ] < elem ) ? elem : max [ j ] ; if ( typeof stable [ j ] !== 'undefined' ) { if ( stable [ j ] !== elem ) { stable [ j ] = false ; } } else { stable [ j ] = elem ; } if ( elem > 31 ) { if ( elem < 100 ) { guessedFormat [ j ] = 'YY' ; } else { guessedFormat [ j ] = 'YYYY' ; } } else if ( elem > 12 && elem <= 31 ) { guessedFormat [ j ] = 'dd' ; madeDeduction = true ; } else if ( ! guessedFormat [ j ] . length ) { guessedFormat [ j ] = 'mm' ; } } } } } } if ( madeDeduction ) { for ( j = 0 ; j < stable . length ; j ++ ) { if ( stable [ j ] !== false ) { if ( max [ j ] > 12 && guessedFormat [ j ] !== 'YY' && guessedFormat [ j ] !== 'YYYY' ) { guessedFormat [ j ] = 'YY' ; } } else if ( max [ j ] > 12 && guessedFormat [ j ] === 'mm' ) { guessedFormat [ j ] = 'dd' ; } } if ( guessedFormat . length === 3 && guessedFormat [ 1 ] === 'dd' && guessedFormat [ 2 ] === 'dd' ) { guessedFormat [ 2 ] = 'YY' ; } format = guessedFormat . join ( '/' ) ; } if ( save ) { parser . options . dateFormat = format ; } return format ; } } /**
 * Additionally provided types to describe supported value types.
 */ namespace DataConverter { /**
     * Contains supported types to convert values from and to.
     */ export type Type = ( boolean | null | number | string | DataTable | Date | undefined ) ; /**
     * Internal options for DataConverter.
     */ export interface Options extends JSON . Object { dateFormat ? : string ; alternativeFormat ? : string ; decimalPoint ? : string ; } /**
     * A function to parse string representations of dates
     * into JavaScript timestamps.
     */ export interface ParseDateFunction { ( dateValue ) : number ; } } export default DataConverter ;