@thoughtspot/ts-chart-sdk 0.0.2-alpha.9 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/README.md +126 -50
  2. package/dist/ts-chart-sdk.d.ts +330 -32
  3. package/lib/index.d.ts +3 -0
  4. package/lib/index.d.ts.map +1 -1
  5. package/lib/index.js +3 -0
  6. package/lib/index.js.map +1 -1
  7. package/lib/main/custom-chart-context.d.ts +17 -4
  8. package/lib/main/custom-chart-context.d.ts.map +1 -1
  9. package/lib/main/custom-chart-context.js +46 -16
  10. package/lib/main/custom-chart-context.js.map +1 -1
  11. package/lib/main/custom-chart-context.spec.js +302 -4
  12. package/lib/main/custom-chart-context.spec.js.map +1 -1
  13. package/lib/main/logger.d.ts +13 -0
  14. package/lib/main/logger.d.ts.map +1 -0
  15. package/lib/main/logger.js +64 -0
  16. package/lib/main/logger.js.map +1 -0
  17. package/lib/main/logger.spec.d.ts +2 -0
  18. package/lib/main/logger.spec.d.ts.map +1 -0
  19. package/lib/main/logger.spec.js +88 -0
  20. package/lib/main/logger.spec.js.map +1 -0
  21. package/lib/main/util.d.ts +2 -0
  22. package/lib/main/util.d.ts.map +1 -1
  23. package/lib/main/util.js +11 -0
  24. package/lib/main/util.js.map +1 -1
  25. package/lib/main/util.spec.d.ts +2 -0
  26. package/lib/main/util.spec.d.ts.map +1 -0
  27. package/lib/main/util.spec.js +73 -0
  28. package/lib/main/util.spec.js.map +1 -0
  29. package/lib/react/use-custom-chart-context.d.ts.map +1 -1
  30. package/lib/react/use-custom-chart-context.js +3 -1
  31. package/lib/react/use-custom-chart-context.js.map +1 -1
  32. package/lib/react/use-custom-chart-context.spec.js +0 -1
  33. package/lib/react/use-custom-chart-context.spec.js.map +1 -1
  34. package/lib/react/use-custom-chart-context.util.d.ts.map +1 -1
  35. package/lib/react/use-custom-chart-context.util.js +5 -3
  36. package/lib/react/use-custom-chart-context.util.js.map +1 -1
  37. package/lib/types/answer-column.types.d.ts +7 -4
  38. package/lib/types/answer-column.types.d.ts.map +1 -1
  39. package/lib/types/answer-column.types.js +3 -3
  40. package/lib/types/answer-column.types.js.map +1 -1
  41. package/lib/types/chart-to-ts-event.types.d.ts +2 -0
  42. package/lib/types/chart-to-ts-event.types.d.ts.map +1 -1
  43. package/lib/types/chart-to-ts-event.types.js +1 -0
  44. package/lib/types/chart-to-ts-event.types.js.map +1 -1
  45. package/lib/types/common.types.d.ts +65 -6
  46. package/lib/types/common.types.d.ts.map +1 -1
  47. package/lib/types/common.types.js.map +1 -1
  48. package/lib/types/conditional-formatting.types.d.ts +1 -16
  49. package/lib/types/conditional-formatting.types.d.ts.map +1 -1
  50. package/lib/types/conditional-formatting.types.js.map +1 -1
  51. package/lib/types/configurator.types.d.ts +1 -1
  52. package/lib/types/configurator.types.d.ts.map +1 -1
  53. package/lib/types/number-formatting.types.d.ts +55 -0
  54. package/lib/types/number-formatting.types.d.ts.map +1 -0
  55. package/lib/types/number-formatting.types.js +23 -0
  56. package/lib/types/number-formatting.types.js.map +1 -0
  57. package/lib/types/ts-to-chart-event.types.d.ts +20 -6
  58. package/lib/types/ts-to-chart-event.types.d.ts.map +1 -1
  59. package/lib/types/ts-to-chart-event.types.js +1 -0
  60. package/lib/types/ts-to-chart-event.types.js.map +1 -1
  61. package/lib/types/visual-prop.types.d.ts +71 -3
  62. package/lib/types/visual-prop.types.d.ts.map +1 -1
  63. package/lib/types/visual-prop.types.js +32 -1
  64. package/lib/types/visual-prop.types.js.map +1 -1
  65. package/lib/utils/date-formatting.d.ts +85 -1
  66. package/lib/utils/date-formatting.d.ts.map +1 -1
  67. package/lib/utils/date-formatting.js +344 -9
  68. package/lib/utils/date-formatting.js.map +1 -1
  69. package/lib/utils/date-formatting.spec.js +301 -31
  70. package/lib/utils/date-formatting.spec.js.map +1 -1
  71. package/lib/utils/date-utils.d.ts +6 -0
  72. package/lib/utils/date-utils.d.ts.map +1 -0
  73. package/lib/utils/date-utils.js +20 -0
  74. package/lib/utils/date-utils.js.map +1 -0
  75. package/lib/utils/date-utils.spec.d.ts +2 -0
  76. package/lib/utils/date-utils.spec.d.ts.map +1 -0
  77. package/lib/utils/date-utils.spec.js +63 -0
  78. package/lib/utils/date-utils.spec.js.map +1 -0
  79. package/lib/utils/formatting-util.d.ts +10 -0
  80. package/lib/utils/formatting-util.d.ts.map +1 -0
  81. package/lib/utils/formatting-util.js +78 -0
  82. package/lib/utils/formatting-util.js.map +1 -0
  83. package/lib/utils/formatting-util.spec.d.ts +2 -0
  84. package/lib/utils/formatting-util.spec.d.ts.map +1 -0
  85. package/lib/utils/formatting-util.spec.js +247 -0
  86. package/lib/utils/formatting-util.spec.js.map +1 -0
  87. package/lib/utils/globalize-Initializer/globalize-utils.d.ts +16 -0
  88. package/lib/utils/globalize-Initializer/globalize-utils.d.ts.map +1 -0
  89. package/lib/utils/globalize-Initializer/globalize-utils.js +101 -0
  90. package/lib/utils/globalize-Initializer/globalize-utils.js.map +1 -0
  91. package/lib/utils/globalize-Initializer/globalize-utils.spec.d.ts +2 -0
  92. package/lib/utils/globalize-Initializer/globalize-utils.spec.d.ts.map +1 -0
  93. package/lib/utils/globalize-Initializer/globalize-utils.spec.js +149 -0
  94. package/lib/utils/globalize-Initializer/globalize-utils.spec.js.map +1 -0
  95. package/lib/utils/number-formatting/number-formatting-utils.d.ts +20 -0
  96. package/lib/utils/number-formatting/number-formatting-utils.d.ts.map +1 -0
  97. package/lib/utils/number-formatting/number-formatting-utils.js +159 -0
  98. package/lib/utils/number-formatting/number-formatting-utils.js.map +1 -0
  99. package/lib/utils/number-formatting/number-formatting-utils.spec.d.ts +2 -0
  100. package/lib/utils/number-formatting/number-formatting-utils.spec.d.ts.map +1 -0
  101. package/lib/utils/number-formatting/number-formatting-utils.spec.js +221 -0
  102. package/lib/utils/number-formatting/number-formatting-utils.spec.js.map +1 -0
  103. package/lib/utils/number-formatting/number-formatting.d.ts +5 -0
  104. package/lib/utils/number-formatting/number-formatting.d.ts.map +1 -0
  105. package/lib/utils/number-formatting/number-formatting.js +128 -0
  106. package/lib/utils/number-formatting/number-formatting.js.map +1 -0
  107. package/lib/utils/number-formatting/number-formatting.spec.d.ts +2 -0
  108. package/lib/utils/number-formatting/number-formatting.spec.d.ts.map +1 -0
  109. package/lib/utils/number-formatting/number-formatting.spec.js +159 -0
  110. package/lib/utils/number-formatting/number-formatting.spec.js.map +1 -0
  111. package/package.json +4 -1
  112. package/src/index.ts +3 -0
  113. package/src/main/custom-chart-context.spec.ts +356 -6
  114. package/src/main/custom-chart-context.ts +205 -16
  115. package/src/main/logger.spec.ts +114 -0
  116. package/src/main/logger.ts +97 -0
  117. package/src/main/util.spec.ts +94 -0
  118. package/src/main/util.ts +20 -0
  119. package/src/react/use-custom-chart-context.spec.tsx +0 -1
  120. package/src/react/use-custom-chart-context.tsx +4 -1
  121. package/src/react/use-custom-chart-context.util.ts +6 -3
  122. package/src/types/answer-column.types.ts +9 -6
  123. package/src/types/chart-to-ts-event.types.ts +7 -0
  124. package/src/types/common.types.ts +100 -10
  125. package/src/types/conditional-formatting.types.ts +2 -17
  126. package/src/types/configurator.types.ts +1 -1
  127. package/src/types/number-formatting.types.ts +80 -0
  128. package/src/types/ts-to-chart-event.types.ts +63 -5
  129. package/src/types/visual-prop.types.ts +197 -3
  130. package/src/utils/date-formatting.spec.ts +375 -32
  131. package/src/utils/date-formatting.ts +587 -14
  132. package/src/utils/date-utils.spec.ts +93 -0
  133. package/src/utils/date-utils.ts +69 -0
  134. package/src/utils/formatting-util.spec.ts +312 -0
  135. package/src/utils/formatting-util.ts +234 -0
  136. package/src/utils/globalize-Initializer/globalize-utils.spec.ts +192 -0
  137. package/src/utils/globalize-Initializer/globalize-utils.ts +216 -0
  138. package/src/utils/number-formatting/number-formatting-utils.spec.ts +296 -0
  139. package/src/utils/number-formatting/number-formatting-utils.ts +260 -0
  140. package/src/utils/number-formatting/number-formatting.spec.ts +243 -0
  141. package/src/utils/number-formatting/number-formatting.ts +264 -0
@@ -8,6 +8,7 @@
8
8
 
9
9
  import _ from 'lodash';
10
10
  import { DateTime } from 'luxon';
11
+ import { create } from '../main/logger';
11
12
  import {
12
13
  ChartColumn,
13
14
  ColumnTimeBucket,
@@ -15,6 +16,8 @@ import {
15
16
  DataType,
16
17
  } from '../types/answer-column.types';
17
18
 
19
+ const logger = create('DateFormattingUtilsSdk');
20
+
18
21
  export interface CustomCalendarDate {
19
22
  v: {
20
23
  s: number;
@@ -23,15 +26,184 @@ export interface CustomCalendarDate {
23
26
  d: string;
24
27
  }
25
28
 
29
+ export const dateFormatPresets = {
30
+ DATE_SHORT: 'DATE_SHORT',
31
+ DATE_SHORT_WITH_HOUR: 'DATE_SHORT_WITH_HOUR',
32
+ DATE_SHORT_WITH_HOUR_WITHOUT_YEAR: 'DATE_SHORT_WITH_HOUR_WITHOUT_YEAR',
33
+ DATETIME_SHORT: 'DATETIME_SHORT',
34
+ DATETIME_SHORT_WITHOUT_YEAR: 'DATETIME_SHORT_WITHOUT_YEAR',
35
+ DATETIME_SHORT_WITH_SECONDS: 'DATETIME_SHORT_WITH_SECONDS',
36
+ DATETIME_SHORT_WITH_MILLIS: 'DATETIME_SHORT_WITH_MILLIS',
37
+ MONTH_WITH_YEAR: 'MONTH_WITH_YEAR',
38
+ QUARTER_WITH_YEAR: 'QUARTER_WITH_YEAR',
39
+ QUARTER_WITH_2_DIGIT_YEAR: 'QUARTER_WITH_2_DIGIT_YEAR',
40
+ DEFAULT_TIME_FORMAT: 'DEFAULT_TIME_FORMAT',
41
+ TIME_24_WITH_SECONDS: 'TIME_24_WITH_SECONDS',
42
+ DATE_SHORT_2_DIGIT_YEAR: 'DATE_SHORT_2_DIGIT_YEAR',
43
+ DATETIME_24_SHORT_WITHOUT_YEAR: 'DATETIME_24_SHORT_WITHOUT_YEAR',
44
+ DATETIME_24_SHORT: 'DATETIME_24_SHORT',
45
+ DATETIME_SHORT_WITH_SECONDS_WITHOUT_YEAR:
46
+ 'DATETIME_SHORT_WITH_SECONDS_WITHOUT_YEAR',
47
+ DATETIME_SHORT_WITH_MILLIS_WITHOUT_YEAR:
48
+ 'DATETIME_SHORT_WITH_MILLIS_WITHOUT_YEAR',
49
+ DATETIME_24_SHORT_WITH_MILLIS_WITHOUT_YEAR:
50
+ 'DATETIME_24_SHORT_WITH_MILLIS_WITHOUT_YEAR',
51
+ DATETIME_24_SHORT_WITH_MILLIS: 'DATETIME_24_SHORT_WITH_MILLIS',
52
+ MONTH_WITH_DAY_AND_YEAR: 'MONTH_WITH_DAY_AND_YEAR',
53
+ MONTH_WITH_2_DIGIT_YEAR: 'MONTH_WITH_2_DIGIT_YEAR',
54
+ DAY_WITH_MONTH_NUM: 'DAY_WITH_MONTH_NUM',
55
+ DATE_SHORT_WITH_HOUR_24_WITHOUT_YEAR:
56
+ 'DATE_SHORT_WITH_HOUR_24_WITHOUT_YEAR',
57
+ DATE_SHORT_WITH_HOUR_24: 'DATE_SHORT_WITH_HOUR_24',
58
+ QUARTER: 'QUARTER',
59
+ MONTH_ONLY: 'MONTH_ONLY',
60
+ DATETIME_WITH_SHORT_OFFSET: 'DATETIME_WITH_SHORT_OFFSET',
61
+ };
62
+ const yearlessFormats = {
63
+ DATE_SHORT: 'DAY_WITH_MONTH',
64
+ DATE_SHORT_WITH_HOUR: 'DATE_SHORT_WITH_HOUR_WITHOUT_YEAR',
65
+ DATETIME_SHORT: 'DATETIME_SHORT_WITHOUT_YEAR',
66
+ DATETIME_SHORT_WITH_SECONDS: 'DATETIME_SHORT_WITH_SECONDS_WITHOUT_YEAR',
67
+ DATETIME_SHORT_WITH_MILLIS: 'DATETIME_SHORT_WITH_MILLIS_WITHOUT_YEAR',
68
+ MONTH_WITH_YEAR: 'MONTH_ONLY',
69
+ QUARTER_WITH_YEAR: 'QUARTER',
70
+ QUARTER_WITH_2_DIGIT_YEAR: 'QUARTER',
71
+ DATE_SHORT_2_DIGIT_YEAR: 'DAY_WITH_MONTH',
72
+ DATETIME_24_SHORT: 'DATETIME_24_SHORT_WITHOUT_YEAR',
73
+ DATETIME_24_SHORT_WITH_MILLIS: 'DATETIME_24_SHORT_WITH_MILLIS_WITHOUT_YEAR',
74
+ MONTH_WITH_DAY_AND_YEAR: 'DAY_WITH_MONTH',
75
+ MONTH_WITH_2_DIGIT_YEAR: 'DAY_WITH_MONTH',
76
+ DATE_SHORT_WITH_HOUR_24: 'DATE_SHORT_WITH_HOUR_24_WITHOUT_YEAR',
77
+ };
78
+
79
+ export const dateNumTypes = {
80
+ DATE_NUM_ABS_DAY: 'DATE_NUM_ABS_DAY',
81
+ DATE_NUM_ABS_MONTH: 'DATE_NUM_ABS_MONTH',
82
+ DATE_NUM_ABS_QUARTER: 'DATE_NUM_ABS_QUARTER',
83
+ DATE_NUM_ABS_YEAR: 'DATE_NUM_ABS_YEAR',
84
+ DATE_NUM_DAY_IN_MONTH: 'DATE_NUM_DAY_IN_MONTH',
85
+ DATE_NUM_DAY_IN_QUARTER: 'DATE_NUM_DAY_IN_QUARTER',
86
+ DATE_NUM_DAY_IN_YEAR: 'DATE_NUM_DAY_IN_YEAR',
87
+ DATE_NUM_DAY_OF_WEEK: 'DATE_NUM_DAY_OF_WEEK',
88
+ DATE_NUM_MONTH_IN_QUARTER: 'DATE_NUM_MONTH_IN_QUARTER',
89
+ DATE_NUM_MONTH_IN_YEAR: 'DATE_NUM_MONTH_IN_YEAR',
90
+ DATE_NUM_QUARTER_IN_YEAR: 'DATE_NUM_QUARTER_IN_YEAR',
91
+ DATE_NUM_WEEK_IN_YEAR: 'DATE_NUM_WEEK_IN_YEAR',
92
+ DATE_NUM_WEEK_IN_QUARTER: 'DATE_NUM_WEEK_IN_QUARTER',
93
+ DATE_NUM_WEEK_IN_MONTH: 'DATE_NUM_WEEK_IN_MONTH',
94
+ DATE_NUM_HOUR_IN_DAY: 'DATE_NUM_HOUR_IN_DAY',
95
+ };
96
+
97
+ const weekdays = [
98
+ 'Sunday',
99
+ 'Monday',
100
+ 'Tuesday',
101
+ 'Wednesday',
102
+ 'Thursday',
103
+ 'Friday',
104
+ 'Saturday',
105
+ ];
106
+
107
+ const months = [
108
+ 'January',
109
+ 'February',
110
+ 'March',
111
+ 'April',
112
+ 'May',
113
+ 'June',
114
+ 'July',
115
+ 'August',
116
+ 'September',
117
+ 'October',
118
+ 'November',
119
+ 'December',
120
+ ];
121
+
122
+ export const bucketizationToDatePreset = {
123
+ HOURLY: dateFormatPresets.DATE_SHORT_WITH_HOUR, // hourly
124
+ DAILY: dateFormatPresets.DATE_SHORT, // daily
125
+ WEEKLY: dateFormatPresets.DATE_SHORT, // weekly
126
+ MONTHLY: dateFormatPresets.MONTH_WITH_YEAR,
127
+ QUARTERLY: dateFormatPresets.QUARTER_WITH_YEAR, // quarterly
128
+ YEARLY: 'yyyy', // yearly
129
+ };
130
+ const dateFormatPresetsToLuxonPresets = {
131
+ [dateFormatPresets.TIME_24_WITH_SECONDS]: DateTime.TIME_24_WITH_SECONDS,
132
+ };
133
+
134
+ export const timeBuckets = {
135
+ NO_BUCKET: 'ms',
136
+ HOURLY: 'h',
137
+ DAILY: 'd',
138
+ WEEKLY: 'w',
139
+ MONTHLY: 'M',
140
+ QUARTERLY: 'Q',
141
+ YEARLY: 'y',
142
+ DAY_OF_WEEK: 'dow',
143
+ DAY_OF_MONTH: 'dom',
144
+ DAY_OF_QUARTER: 'doq',
145
+ DAY_OF_YEAR: 'doy',
146
+ WEEK_OF_MONTH: 'wom',
147
+ WEEK_OF_QUARTER: 'woq',
148
+ WEEK_OF_YEAR: 'woy',
149
+ MONTH_OF_QUARTER: 'moq',
150
+ MONTH_OF_YEAR: 'moy',
151
+ QUARTER_OF_YEAR: 'qoy',
152
+ };
153
+
154
+ const DEFAULT_QUARTER_START_MONTH = 1;
155
+
156
+ /**
157
+ * Checks if a specified column has a data type of 'DATE' or 'DATE_TIME'.
158
+ *
159
+ * @param col - The column to check, represented as a `ChartColumn`.
160
+ * @returns True if the column's data type is either 'DATE' or 'DATE_TIME'; otherwise, false.
161
+ */
162
+
26
163
  export const isDateColumn = (col: ChartColumn) =>
27
164
  DataType[col.dataType] === 'DATE' || DataType[col.dataType] === 'DATE_TIME';
28
165
 
166
+ /**
167
+ * Determines if a specified column is of type 'ATTRIBUTE'.
168
+ *
169
+ * @param col - The column to check, represented as a `ChartColumn`.
170
+ * @returns True if the column's type is `ATTRIBUTE`; otherwise, false.
171
+ */
172
+
29
173
  export const isAttribute = (col: ChartColumn) =>
30
174
  col.type === ColumnType.ATTRIBUTE;
31
175
 
176
+ /**
177
+ * Checks if a specified column has a data type of 'DATE_TIME'.
178
+ *
179
+ * @param col - The column to check, represented as a `ChartColumn`.
180
+ * @returns True if the column's data type is `DATE_TIME`; otherwise, false.
181
+ */
182
+
183
+ export const isDateTimeColumn = (col: ChartColumn) =>
184
+ DataType[col.dataType] === 'DATE_TIME';
185
+
186
+ /**
187
+ * Retrieves the custom calendar GUID associated with a specified column.
188
+ *
189
+ * @param col - The column from which to retrieve the calendar GUID, represented as a `ChartColumn`.
190
+ * @returns The custom calendar GUID of the column, or undefined if not available.
191
+ */
32
192
  export const getCustomCalendarGuidFromColumn = (col: ChartColumn) =>
33
193
  col.calenderGuid;
34
194
 
195
+ /**
196
+ * Determines if a specified column's time bucket is one of the predefined numeric time buckets.
197
+ *
198
+ * This function checks if the column's `timeBucket` is one of the following:
199
+ * `HOUR_OF_DAY`, `DAY_OF_WEEK`, `DAY_OF_MONTH`, `DAY_OF_QUARTER`, `DAY_OF_YEAR`,
200
+ * `WEEK_OF_MONTH`, `WEEK_OF_QUARTER`, `WEEK_OF_YEAR`, `MONTH_OF_QUARTER`,
201
+ * `MONTH_OF_YEAR`, or `QUARTER_OF_YEAR`.
202
+ *
203
+ * @param col - The column to check, represented as a `ChartColumn`.
204
+ * @returns True if the column's time bucket is one of the specified date-related numeric time buckets; otherwise, false.
205
+ */
206
+
35
207
  const isDateNumTimeBucket = (col: ChartColumn): boolean => {
36
208
  return [
37
209
  ColumnTimeBucket.HOUR_OF_DAY,
@@ -47,17 +219,83 @@ const isDateNumTimeBucket = (col: ChartColumn): boolean => {
47
219
  ColumnTimeBucket.QUARTER_OF_YEAR,
48
220
  ].includes(col.timeBucket);
49
221
  };
222
+
223
+ /**
224
+ * Determines if a specified column is both an attribute and has a date-related numeric time bucket.
225
+ *
226
+ * This function checks if the column is of type `ATTRIBUTE` and has a time bucket that is one of
227
+ * the predefined date-related numeric time buckets, as determined by `isDateNumTimeBucket`.
228
+ *
229
+ * @param col - The column to check, represented as a `ChartColumn`.
230
+ * @returns True if the column is an attribute and has a date-related numeric time bucket; otherwise, false.
231
+ */
232
+
50
233
  export const isDateNumColumn = (col: ChartColumn): boolean => {
51
234
  return isAttribute(col) && isDateNumTimeBucket(col);
52
235
  };
53
236
 
237
+ /**
238
+ * Determines if a specified column belongs to the "date family," meaning it is either a date column
239
+ * or a date-related numeric column.
240
+ *
241
+ * This function checks if the column is a date column, as determined by `isDateColumn`, or a
242
+ * date-related numeric column, as determined by `isDateNumColumn`.
243
+ *
244
+ * @param col - The column to check, represented as a `ChartColumn`.
245
+ * @returns True if the column is either a date column or a date-related numeric column; otherwise, false.
246
+ */
247
+
54
248
  export const isDateFamilyColumn = (col: ChartColumn): boolean => {
55
249
  return isDateColumn(col) || isDateNumColumn(col);
56
250
  };
57
251
 
252
+ /**
253
+ * Checks if a specified column has a data type of 'TIME'.
254
+ *
255
+ * @param col - The column to check, represented as a `ChartColumn`.
256
+ * @returns True if the column's data type is `TIME`; otherwise, false.
257
+ */
258
+
58
259
  export const isTimeColumn = (col: ChartColumn) => {
59
260
  return DataType[col.dataType] === 'TIME';
60
261
  };
262
+ /**
263
+ * Retrieves the effective date numeric data type based on the column's time bucket.
264
+ *
265
+ * This function maps a column's `timeBucket` to a corresponding date numeric data type, such as
266
+ * `DATE_NUM_DAY_OF_WEEK`, `DATE_NUM_DAY_IN_MONTH`, etc. If the `timeBucket` does not match any
267
+ * predefined value, the function returns `undefined`.
268
+ *
269
+ * @param col - The column to check, represented as a `ChartColumn`.
270
+ * @returns The corresponding date numeric data type, or `undefined` if the `timeBucket` is not recognized.
271
+ */
272
+
273
+ export const getEffectiveDateNumDataType = (col: ChartColumn) => {
274
+ switch (col.timeBucket) {
275
+ case ColumnTimeBucket.DAY_OF_WEEK:
276
+ return dateNumTypes.DATE_NUM_DAY_OF_WEEK;
277
+ case ColumnTimeBucket.DAY_OF_MONTH:
278
+ return dateNumTypes.DATE_NUM_DAY_IN_MONTH;
279
+ case ColumnTimeBucket.DAY_OF_QUARTER:
280
+ return dateNumTypes.DATE_NUM_DAY_IN_QUARTER;
281
+ case ColumnTimeBucket.DAY_OF_YEAR:
282
+ return dateNumTypes.DATE_NUM_DAY_IN_YEAR;
283
+ case ColumnTimeBucket.WEEK_OF_MONTH:
284
+ return dateNumTypes.DATE_NUM_WEEK_IN_MONTH;
285
+ case ColumnTimeBucket.WEEK_OF_QUARTER:
286
+ return dateNumTypes.DATE_NUM_WEEK_IN_QUARTER;
287
+ case ColumnTimeBucket.WEEK_OF_YEAR:
288
+ return dateNumTypes.DATE_NUM_WEEK_IN_YEAR;
289
+ case ColumnTimeBucket.MONTH_OF_QUARTER:
290
+ return dateNumTypes.DATE_NUM_MONTH_IN_QUARTER;
291
+ case ColumnTimeBucket.MONTH_OF_YEAR:
292
+ return dateNumTypes.DATE_NUM_MONTH_IN_YEAR;
293
+ case ColumnTimeBucket.QUARTER_OF_YEAR:
294
+ return dateNumTypes.DATE_NUM_QUARTER_IN_YEAR;
295
+ default:
296
+ return undefined;
297
+ }
298
+ };
61
299
 
62
300
  /**
63
301
  * Determines if the given column has a custom calendar.
@@ -81,6 +319,24 @@ export function getStartEpoch(date: CustomCalendarDate): number | null {
81
319
  return null;
82
320
  }
83
321
 
322
+ export const assignQuarterValueToString = (
323
+ quarter_of_year: any,
324
+ value: any,
325
+ ) => {
326
+ return quarter_of_year.replace(/\{.*?\}/, value);
327
+ };
328
+
329
+ export function getMonthOfYear(
330
+ num: any,
331
+ quarterStartMonth: any,
332
+ monthOfYear: any,
333
+ ) {
334
+ let monthNum = num + quarterStartMonth - 1;
335
+ monthNum = monthNum > 12 ? monthNum - 12 : monthNum;
336
+
337
+ return monthOfYear[months[monthNum - 1]]; // -1 as monthNum is 1 indexed
338
+ }
339
+
84
340
  export function getDisplayString(date: CustomCalendarDate): string | null {
85
341
  if (_.has(date, 'd')) {
86
342
  return date.d;
@@ -88,22 +344,339 @@ export function getDisplayString(date: CustomCalendarDate): string | null {
88
344
  return null;
89
345
  }
90
346
 
347
+ export const useQuarterStart = (luxonDate: any, quarterStartMonth: any) => {
348
+ const newLuxonDate = luxonDate;
349
+ newLuxonDate.quarterStartMonth = quarterStartMonth;
350
+ return newLuxonDate;
351
+ };
352
+
353
+ export const getCustomCalendarValueFromEpoch = (
354
+ col: ChartColumn,
355
+ dateEpoch: number,
356
+ displayToCustomCalendarValueMap: any,
357
+ ) => {
358
+ if (
359
+ hasCustomCalendar(col) &&
360
+ _.has(displayToCustomCalendarValueMap, dateEpoch)
361
+ ) {
362
+ return displayToCustomCalendarValueMap[dateEpoch];
363
+ }
364
+ return null;
365
+ };
366
+ const parseDate = (dateString: string, format: string, options: any) => {
367
+ return DateTime.fromFormat(
368
+ dateString,
369
+ options.tsLocaleBasedDateFormats[format] || format,
370
+ ).toJSDate();
371
+ };
372
+
373
+ export function getSpecialFormatData(value: string | number, options: any) {
374
+ if (
375
+ value ===
376
+ options.tsLocaleBasedStringsFormats.null_value_placeholder_label ||
377
+ value ===
378
+ options.tsLocaleBasedStringsFormats.empty_value_placeholder_label
379
+ ) {
380
+ return value;
381
+ }
382
+
383
+ if (value === options.tsDateConstants.special_value_unavailable) {
384
+ return options.tsLocaleBasedStringsFormats
385
+ .unavailabe_column_sample_value;
386
+ }
387
+
388
+ // This (==) checks for both null and undefined
389
+ if (value === null || value === undefined) {
390
+ return options.tsLocaleBasedStringsFormats.null_value_placeholder_label;
391
+ }
392
+ // {Empty} placeholder is set for empty string or no characters
393
+ // other than spaces.
394
+ if (value === '') {
395
+ return options.tsLocaleBasedStringsFormats
396
+ .empty_value_placeholder_label;
397
+ }
398
+ return null;
399
+ }
400
+
401
+ export function sanitizeDate(
402
+ inputDate: string | number,
403
+ format: string,
404
+ options: any,
405
+ ) {
406
+ const specialVal = getSpecialFormatData(inputDate, options);
407
+ if (specialVal) {
408
+ return specialVal;
409
+ }
410
+ if (typeof inputDate === 'string') {
411
+ if (!_.isNaN(Number(inputDate))) {
412
+ return parseInt(inputDate, 10);
413
+ }
414
+ return parseDate(inputDate, format, options);
415
+ }
416
+ return inputDate;
417
+ }
418
+
91
419
  /**
92
- * Formats the date value based on the column's properties and custom calendar settings.
93
- *
94
- * @param dataValue - The date value to format.
95
- * @param col - The chart column.
96
- * @returns The formatted date string.
420
+ * Get the formatted date based on the format tokens
421
+ * @param {number} epochMillis
422
+ * @param {string} format: use dateFormatPresets to get localized formatted date
423
+ * or pass the format pattern for non localized results
424
+ * @returns {string}
97
425
  */
98
- export function dateFormatter(dataValue: any, col: ChartColumn) {
99
- if (hasCustomCalendar(col)) {
100
- if (getDisplayString(dataValue)) {
101
- return getDisplayString(dataValue);
426
+ export const formatDateTime = (
427
+ epochMillis: number,
428
+ format: string,
429
+ useSystemCalendar?: boolean,
430
+ options?: any,
431
+ ) => {
432
+ let newFormat = format;
433
+ let luxonDate;
434
+ try {
435
+ luxonDate = DateTime.fromMillis(epochMillis * 1000);
436
+ } catch (e) {
437
+ return 'Invalid Date';
438
+ }
439
+ if (options.tsLocaleBasedDateFormats[newFormat]) {
440
+ if (_.get(options, 'omitYear')) {
441
+ if (yearlessFormats[newFormat as keyof typeof yearlessFormats]) {
442
+ newFormat =
443
+ yearlessFormats[newFormat as keyof typeof yearlessFormats];
444
+ }
102
445
  }
103
- const startEpoch = getStartEpoch(dataValue);
104
- return startEpoch !== null
105
- ? DateTime.fromMillis(startEpoch * 1000).toFormat('dd-MM-yyyy')
106
- : null;
446
+ newFormat = options.tsLocaleBasedDateFormats[newFormat];
447
+ }
448
+ const customCalendarOverridesFiscalOffset = _.get(
449
+ options,
450
+ 'customCalendarOverridesFiscalOffset',
451
+ );
452
+ // if format preset is a luxon preset
453
+ if (!newFormat || dateFormatPresetsToLuxonPresets[newFormat]) {
454
+ // Note: this will not add FY to the year in case of custom
455
+ // quarterStartMonth but the year would be the correct fiscal year
456
+ return luxonDate.toLocaleString(
457
+ dateFormatPresetsToLuxonPresets[newFormat],
458
+ );
459
+ }
460
+ // qqq is not supported in luxon
461
+ newFormat = newFormat.replace(/qqq/, "'Q'q");
462
+ // support YYYY and YY
463
+ newFormat = newFormat.replace(/(YYYY|YY)/, _.lowerCase);
464
+ const quarterStartMonth = options.quarterStartMonth;
465
+ if (
466
+ quarterStartMonth > 1 &&
467
+ !useSystemCalendar &&
468
+ !customCalendarOverridesFiscalOffset
469
+ ) {
470
+ newFormat = newFormat.replace(/[yyyy||yy]/, "'FY' $&");
471
+ }
472
+ return useQuarterStart(
473
+ luxonDate,
474
+ useSystemCalendar ? DEFAULT_QUARTER_START_MONTH : quarterStartMonth,
475
+ ).toFormat(newFormat);
476
+ };
477
+
478
+ function getDayOfWeek(num: any, weekOfDay: any) {
479
+ const new_num = num % 7;
480
+ return weekOfDay[weekdays[new_num]];
481
+ }
482
+ /**
483
+ * Converts a number or string into its corresponding ordinal suffixed value.
484
+ *
485
+ * This function takes a number (or string that can be parsed as a number) and returns it as a
486
+ * string with the appropriate ordinal suffix (`st`, `nd`, `rd`, or `th`). The function accounts for
487
+ * exceptions in English grammar, such as 11th, 12th, and 13th, which do not follow the standard
488
+ * suffix rules.
489
+ *
490
+ * @param i - The number (or string) to convert into an ordinal suffixed value.
491
+ * @returns A string representing the number with its ordinal suffix (e.g., "1st", "2nd", "3rd", "4th").
492
+ */
493
+ export function getOrdinalSuffixedValue(i: number | string): string {
494
+ let ni = i;
495
+ // eslint-disable-next-line radix
496
+ ni = parseInt(ni.toString());
497
+ const j = ni % 10;
498
+ const k = ni % 100;
499
+ // eslint-disable-next-line eqeqeq
500
+ if (j == 1 && k != 11) {
501
+ return `${ni}st`;
502
+ }
503
+ // eslint-disable-next-line eqeqeq
504
+ if (j == 2 && k != 12) {
505
+ return `${ni}nd`;
506
+ }
507
+ // eslint-disable-next-line eqeqeq
508
+ if (j == 3 && k != 13) {
509
+ return `${ni}rd`;
510
+ }
511
+ return `${ni}th`;
512
+ }
513
+ /**
514
+ * Formats a date-related numeric value based on its effective data type, a given format pattern,
515
+ * and options.
516
+ *
517
+ * This function is used to format date-related numeric values (such as days of the month, weeks of
518
+ * the year, or hours of the day) according to the specified `effectiveDataType`, `formatPattern`,
519
+ * and other options. It supports custom formatting for various date-related values and can handle
520
+ * special cases like null values.
521
+ *
522
+ * @param effectiveDataType - The effective data type to format, which determines how the value will be interpreted
523
+ * (e.g., `DATE_NUM_ABS_DAY`, `DATE_NUM_DAY_IN_MONTH`).
524
+ * @param value - The numeric value (or string) to format. This value is typically a date-related number.
525
+ * @param formatPattern - The pattern to use for formatting the value (e.g., for day or month formatting).
526
+ * @param options - An object containing various formatting options, such as locale-based string formats, date constants,
527
+ * and settings for the quarter start month and special value handling.
528
+ *
529
+ * @returns A string representing the formatted date-related numeric value, or a placeholder if the value is null.
530
+ *
531
+ * @example
532
+ * // Example usage
533
+ * const formattedDate = formatDateNum(
534
+ * dateNumTypes.DATE_NUM_DAY_IN_MONTH,
535
+ * 15,
536
+ * 'm',
537
+ * options // get from {@link generateMapOptions}
538
+ * );
539
+ * console.log(formattedDate); // Output could be '15th day of month' depending on the format
540
+ */
541
+
542
+ export function formatDateNum(
543
+ effectiveDataType: string | undefined,
544
+ value: number | string,
545
+ formatPattern: string,
546
+ options: any,
547
+ ) {
548
+ let newValue = value;
549
+ if (_.isString(newValue)) {
550
+ // eslint-disable-next-line radix
551
+ newValue = parseInt(value.toString());
552
+ }
553
+
554
+ if (!value && value !== 0) {
555
+ return options.tsLocaleBasedStringsFormats.null_value_placeholder_label;
556
+ }
557
+ const specialVal = getSpecialFormatData(value, options);
558
+ if (specialVal) {
559
+ return specialVal;
560
+ }
561
+ switch (effectiveDataType) {
562
+ case dateNumTypes.DATE_NUM_ABS_DAY:
563
+ case dateNumTypes.DATE_NUM_ABS_MONTH:
564
+ case dateNumTypes.DATE_NUM_ABS_QUARTER:
565
+ case dateNumTypes.DATE_NUM_ABS_YEAR:
566
+ return `${value}`;
567
+ case dateNumTypes.DATE_NUM_DAY_IN_MONTH:
568
+ return formatPattern === options.tsDateConstants.day_in_month_format
569
+ ? `${value}`
570
+ : `${getOrdinalSuffixedValue(value)} day of month`;
571
+ case dateNumTypes.DATE_NUM_DAY_IN_QUARTER:
572
+ return formatPattern ===
573
+ options.tsDateConstants.day_in_quarter_format
574
+ ? `${value}`
575
+ : `${getOrdinalSuffixedValue(value)} day of quarter`;
576
+ case dateNumTypes.DATE_NUM_DAY_IN_YEAR:
577
+ return formatPattern === options.tsDateConstants.day_in_year_format
578
+ ? `${value}`
579
+ : `${getOrdinalSuffixedValue(value)} day of year`;
580
+ case dateNumTypes.DATE_NUM_DAY_OF_WEEK:
581
+ return formatPattern === options.tsDateConstants.day_of_week_format
582
+ ? // eslint-disable-next-line @typescript-eslint/no-use-before-define
583
+ getDayOfWeek(
584
+ value,
585
+ options.tsLocaleBasedStringsFormats.weekOfDay,
586
+ )
587
+ : `${value}`;
588
+ case dateNumTypes.DATE_NUM_MONTH_IN_QUARTER:
589
+ return formatPattern ===
590
+ options.tsDateConstants.month_in_quarter_format
591
+ ? `${value}`
592
+ : `${getOrdinalSuffixedValue(value)} month of quarter`;
593
+ case dateNumTypes.DATE_NUM_MONTH_IN_YEAR:
594
+ return formatPattern ===
595
+ options.tsDateConstants.month_in_year_format
596
+ ? // eslint-disable-next-line @typescript-eslint/no-use-before-define
597
+ getMonthOfYear(
598
+ value,
599
+ options.quarterStartMonth,
600
+ options.tsLocaleBasedStringsFormats.monthOfYear,
601
+ )
602
+ : `${value}`;
603
+ case dateNumTypes.DATE_NUM_QUARTER_IN_YEAR:
604
+ // Falcon returns quarter as 1 indexed, which is passed on by
605
+ // callosum to blink, so we can use value instead of value + 1.
606
+ return assignQuarterValueToString(
607
+ options.tsLocaleBasedStringsFormats.quarter_of_year,
608
+ value,
609
+ );
610
+ case dateNumTypes.DATE_NUM_WEEK_IN_YEAR:
611
+ // +1 to value as Falcon values start with 0.
612
+ return formatPattern === options.tsDateConstants.week_in_year_format
613
+ ? `${value}`
614
+ : `${getOrdinalSuffixedValue(value)} week of year`;
615
+ case dateNumTypes.DATE_NUM_WEEK_IN_QUARTER:
616
+ case dateNumTypes.DATE_NUM_WEEK_IN_MONTH:
617
+ return `${value}`;
618
+ case dateNumTypes.DATE_NUM_HOUR_IN_DAY:
619
+ return `${value}`;
620
+ default:
621
+ logger.log(
622
+ 'unknown effectiveDataType for date num',
623
+ effectiveDataType,
624
+ );
625
+ return value;
626
+ }
627
+ }
628
+
629
+ /**
630
+ *
631
+ * @param {number|string} inputDate Can be either a parseable format of date or an epoch value.
632
+ * @param {string} format a dateFormatPresets or a format pattern string.
633
+ * @param {boolean} useSystemCalendar If any custom calendar setting (e.g. quarterStartMonth)
634
+ * is to be ignored.
635
+ * @return {string} Returns the formatted date per the format.
636
+ */
637
+ export function formatDate(
638
+ inputDate: number | string,
639
+ format: string,
640
+ useSystemCalendar: boolean,
641
+ options: any,
642
+ ): string {
643
+ let formatPattern = format;
644
+ let newInputDate: any = inputDate;
645
+ if (newInputDate === undefined || newInputDate === null) {
646
+ return options.tsLocaleBasedStringsFormats.null_value_placeholder_label;
647
+ }
648
+ if (!formatPattern) {
649
+ formatPattern = dateFormatPresets.DATE_SHORT;
650
+ }
651
+ if (
652
+ newInputDate ===
653
+ options.tsLocaleBasedStringsFormats.null_value_placeholder_label ||
654
+ newInputDate ===
655
+ options.tsLocaleBasedStringsFormats.empty_value_placeholder_label ||
656
+ newInputDate ===
657
+ options.tsLocaleBasedStringsFormats.other_value_placeholder_label
658
+ ) {
659
+ return newInputDate;
660
+ }
661
+ newInputDate = sanitizeDate(newInputDate, formatPattern, options);
662
+ if (_.isNaN(newInputDate)) {
663
+ return options.tsLocaleBasedStringsFormats.null_value_placeholder_label;
664
+ }
665
+ let epochMillis = newInputDate;
666
+ if (_.isDate(epochMillis)) {
667
+ epochMillis = newInputDate.getTime();
668
+ }
669
+ if (!_.isNumber(epochMillis)) {
670
+ logger.log(
671
+ 'formatDate could not convert input date to a timestamp',
672
+ inputDate,
673
+ );
674
+ return `${inputDate}`;
107
675
  }
108
- return DateTime.fromMillis(dataValue * 1000).toFormat('dd-MM-yyyy');
676
+ return formatDateTime(
677
+ epochMillis,
678
+ formatPattern,
679
+ useSystemCalendar,
680
+ options,
681
+ );
109
682
  }