@thoughtspot/ts-chart-sdk 0.0.2-alpha.24 → 0.0.2-alpha.25
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.
- package/dist/ts-chart-sdk.d.ts +65 -5
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/main/custom-chart-context.d.ts.map +1 -1
- package/lib/main/custom-chart-context.js +3 -1
- package/lib/main/custom-chart-context.js.map +1 -1
- package/lib/types/answer-column.types.d.ts +3 -3
- package/lib/types/answer-column.types.d.ts.map +1 -1
- package/lib/types/answer-column.types.js +3 -3
- package/lib/types/answer-column.types.js.map +1 -1
- package/lib/types/number-formatting.types.d.ts +2 -2
- package/lib/types/number-formatting.types.d.ts.map +1 -1
- package/lib/types/visual-prop.types.d.ts +40 -0
- package/lib/types/visual-prop.types.d.ts.map +1 -1
- package/lib/types/visual-prop.types.js +32 -1
- package/lib/types/visual-prop.types.js.map +1 -1
- package/lib/utils/globalize-Initializer/globalize-utils.d.ts +16 -0
- package/lib/utils/globalize-Initializer/globalize-utils.d.ts.map +1 -0
- package/lib/utils/globalize-Initializer/globalize-utils.js +101 -0
- package/lib/utils/globalize-Initializer/globalize-utils.js.map +1 -0
- package/lib/utils/globalize-Initializer/globalize-utils.spec.d.ts +2 -0
- package/lib/utils/globalize-Initializer/globalize-utils.spec.d.ts.map +1 -0
- package/lib/utils/globalize-Initializer/globalize-utils.spec.js +149 -0
- package/lib/utils/globalize-Initializer/globalize-utils.spec.js.map +1 -0
- package/lib/utils/number-formatting/number-formatting-utils.d.ts +33 -0
- package/lib/utils/number-formatting/number-formatting-utils.d.ts.map +1 -0
- package/lib/utils/number-formatting/number-formatting-utils.js +180 -0
- package/lib/utils/number-formatting/number-formatting-utils.js.map +1 -0
- package/lib/utils/number-formatting/number-formatting-utils.spec.d.ts +2 -0
- package/lib/utils/number-formatting/number-formatting-utils.spec.d.ts.map +1 -0
- package/lib/utils/number-formatting/number-formatting-utils.spec.js +235 -0
- package/lib/utils/number-formatting/number-formatting-utils.spec.js.map +1 -0
- package/lib/utils/number-formatting/number-formatting.d.ts +5 -0
- package/lib/utils/number-formatting/number-formatting.d.ts.map +1 -0
- package/lib/utils/number-formatting/number-formatting.js +131 -0
- package/lib/utils/number-formatting/number-formatting.js.map +1 -0
- package/lib/utils/number-formatting/number-formatting.spec.d.ts +2 -0
- package/lib/utils/number-formatting/number-formatting.spec.d.ts.map +1 -0
- package/lib/utils/number-formatting/number-formatting.spec.js +159 -0
- package/lib/utils/number-formatting/number-formatting.spec.js.map +1 -0
- package/package.json +4 -1
- package/src/index.ts +2 -0
- package/src/main/custom-chart-context.ts +4 -1
- package/src/types/answer-column.types.ts +3 -3
- package/src/types/number-formatting.types.ts +2 -2
- package/src/types/visual-prop.types.ts +86 -0
- package/src/utils/globalize-Initializer/globalize-utils.spec.ts +192 -0
- package/src/utils/globalize-Initializer/globalize-utils.ts +216 -0
- package/src/utils/number-formatting/number-formatting-utils.spec.ts +321 -0
- package/src/utils/number-formatting/number-formatting-utils.ts +288 -0
- package/src/utils/number-formatting/number-formatting.spec.ts +243 -0
- package/src/utils/number-formatting/number-formatting.ts +268 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ColumnFormat,
|
|
3
|
+
CurrencyFormat,
|
|
4
|
+
CurrencyFormatType,
|
|
5
|
+
FormatType,
|
|
6
|
+
} from '../../types/answer-column.types';
|
|
7
|
+
import {
|
|
8
|
+
CategoryType,
|
|
9
|
+
CurrencyFormatConfig,
|
|
10
|
+
NegativeValueFormat,
|
|
11
|
+
NumberFormatConfig,
|
|
12
|
+
Unit,
|
|
13
|
+
} from '../../types/number-formatting.types';
|
|
14
|
+
import * as globalizeUtils from '../globalize-Initializer/globalize-utils';
|
|
15
|
+
import {
|
|
16
|
+
defaultFormatConfig,
|
|
17
|
+
formatNegativeValue,
|
|
18
|
+
formatSpecialDataValue,
|
|
19
|
+
getAutoUnit,
|
|
20
|
+
getLocaleBasedStringFormats,
|
|
21
|
+
getLocaleName,
|
|
22
|
+
mapFormatterConfig,
|
|
23
|
+
PROTO_TO_UNITS,
|
|
24
|
+
setLocaleBasedStringFormats,
|
|
25
|
+
UNITS_TO_DIVIDING_FACTOR,
|
|
26
|
+
} from './number-formatting-utils';
|
|
27
|
+
|
|
28
|
+
describe('formatNegativeValue', () => {
|
|
29
|
+
it('should format with prefix dash', () => {
|
|
30
|
+
const result = formatNegativeValue(
|
|
31
|
+
'100',
|
|
32
|
+
NegativeValueFormat.PrefixDash,
|
|
33
|
+
);
|
|
34
|
+
expect(result).toBe('-100');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should format with suffix dash', () => {
|
|
38
|
+
const result = formatNegativeValue(
|
|
39
|
+
'100',
|
|
40
|
+
NegativeValueFormat.SuffixDash,
|
|
41
|
+
);
|
|
42
|
+
expect(result).toBe('100-');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should format with braces without dash', () => {
|
|
46
|
+
const result = formatNegativeValue(
|
|
47
|
+
'100',
|
|
48
|
+
NegativeValueFormat.BracesNodash,
|
|
49
|
+
);
|
|
50
|
+
expect(result).toBe('(100)');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should default to prefix dash if no format is provided', () => {
|
|
54
|
+
const result = formatNegativeValue('100');
|
|
55
|
+
expect(result).toBe('-100');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should convert a numeric negative format to a string format', () => {
|
|
59
|
+
// Case where negativeFormat is a number
|
|
60
|
+
const negativeFormatNumber = 1; // For example, PrefixDash
|
|
61
|
+
const formattedValue = '100.25'; // some sample value to format
|
|
62
|
+
|
|
63
|
+
// Before mapping, negativeFormat should be a number
|
|
64
|
+
let result = formatNegativeValue(
|
|
65
|
+
formattedValue,
|
|
66
|
+
negativeFormatNumber as number,
|
|
67
|
+
);
|
|
68
|
+
expect(result).toBe('-100.25'); // PrefixDash adds a '-' before the value
|
|
69
|
+
|
|
70
|
+
// Case with a different number for negative format
|
|
71
|
+
const negativeFormatNumber2 = 2; // For example, SuffixDash
|
|
72
|
+
result = formatNegativeValue(formattedValue, negativeFormatNumber2);
|
|
73
|
+
expect(result).toBe('100.25-'); // SuffixDash adds a '-' after the value
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('getAutoUnit', () => {
|
|
78
|
+
it('should return Trillion for values above 1 Trillion', () => {
|
|
79
|
+
const result = getAutoUnit(1e12);
|
|
80
|
+
expect(result).toBe(Unit.Trillion);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should return Billion for values above 1 Billion', () => {
|
|
84
|
+
const result = getAutoUnit(1e9);
|
|
85
|
+
expect(result).toBe(Unit.Billion);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should return Million for values above 1 Million', () => {
|
|
89
|
+
const result = getAutoUnit(1e6);
|
|
90
|
+
expect(result).toBe(Unit.Million);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should return Thousands for values above 1 Thousand', () => {
|
|
94
|
+
const result = getAutoUnit(1e3);
|
|
95
|
+
expect(result).toBe(Unit.Thousands);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should return None for values below 1000', () => {
|
|
99
|
+
const result = getAutoUnit(500);
|
|
100
|
+
expect(result).toBe(Unit.None);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
describe('getLocaleName', () => {
|
|
105
|
+
it('should return default locale if currency format is not ISO_CODE', () => {
|
|
106
|
+
jest.spyOn(
|
|
107
|
+
globalizeUtils,
|
|
108
|
+
'getDefaultCurrencyCode',
|
|
109
|
+
).mockReturnValueOnce('GBP');
|
|
110
|
+
const currencyFormat: CurrencyFormat = {
|
|
111
|
+
type: CurrencyFormatType.USER_LOCALE,
|
|
112
|
+
column: '',
|
|
113
|
+
isoCode: '',
|
|
114
|
+
};
|
|
115
|
+
const result = getLocaleName(currencyFormat);
|
|
116
|
+
expect(result).toBe('GBP'); // Default locale
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should return ISO code if currency format is ISO_CODE', () => {
|
|
120
|
+
const currencyFormat: CurrencyFormat = {
|
|
121
|
+
type: CurrencyFormatType.ISO_CODE,
|
|
122
|
+
column: '',
|
|
123
|
+
isoCode: 'USD',
|
|
124
|
+
};
|
|
125
|
+
const result = getLocaleName(currencyFormat);
|
|
126
|
+
expect(result).toBe('USD');
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe('defaultFormatConfig', () => {
|
|
131
|
+
it('should return custom format config for a pattern', () => {
|
|
132
|
+
const columnFormatConfig: ColumnFormat = {
|
|
133
|
+
type: FormatType.PATTERN,
|
|
134
|
+
pattern: '###,###',
|
|
135
|
+
};
|
|
136
|
+
const result = defaultFormatConfig(columnFormatConfig);
|
|
137
|
+
expect(result.category).toBe(CategoryType.Custom);
|
|
138
|
+
expect(result.customFormatConfig?.format).toBe('###,###');
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('should return currency format config if currencyFormat is defined', () => {
|
|
142
|
+
const columnFormatConfig: ColumnFormat = {
|
|
143
|
+
type: FormatType.CURRENCY,
|
|
144
|
+
currencyFormat: {
|
|
145
|
+
type: CurrencyFormatType.ISO_CODE,
|
|
146
|
+
column: '',
|
|
147
|
+
isoCode: 'USD',
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
const result = defaultFormatConfig(columnFormatConfig);
|
|
151
|
+
expect(result.category).toBe(CategoryType.Currency);
|
|
152
|
+
expect(result.currencyFormatConfig?.locale).toBe('USD');
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should return number format config by default', () => {
|
|
156
|
+
const result = defaultFormatConfig();
|
|
157
|
+
expect(result.category).toBe(CategoryType.Number);
|
|
158
|
+
expect(result.numberFormatConfig?.decimals).toBe(0);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe('mapFormatterConfig', () => {
|
|
163
|
+
it('should return correct formatter config for a number format', () => {
|
|
164
|
+
const absFloatValue = 1000;
|
|
165
|
+
const configDetails: NumberFormatConfig = {
|
|
166
|
+
decimals: 2,
|
|
167
|
+
negativeValueFormat: NegativeValueFormat.PrefixDash,
|
|
168
|
+
removeTrailingZeroes: false,
|
|
169
|
+
toSeparateThousands: true,
|
|
170
|
+
unit: Unit.Million,
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const result = mapFormatterConfig(absFloatValue, configDetails);
|
|
174
|
+
expect(result.unitDetails).toBe(Unit.Million); // Unit: Million
|
|
175
|
+
expect(result.decimalDetails).toBe(2);
|
|
176
|
+
expect(result.shouldRemoveTrailingZeros).toBe(false);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('should return auto unit and decimal precision for large value', () => {
|
|
180
|
+
const absFloatValue = 1e9; // 1 Billion
|
|
181
|
+
const configDetails: NumberFormatConfig = {
|
|
182
|
+
decimals: 0,
|
|
183
|
+
negativeValueFormat: NegativeValueFormat.PrefixDash,
|
|
184
|
+
removeTrailingZeroes: false,
|
|
185
|
+
toSeparateThousands: true,
|
|
186
|
+
unit: Unit.Auto, // Auto
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const result = mapFormatterConfig(absFloatValue, configDetails);
|
|
190
|
+
expect(result.unitDetails).toBe(Unit.Billion);
|
|
191
|
+
expect(result.decimalDetails).toBe(2); // Default decimal precision for auto
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('should return correct config for currency formatting', () => {
|
|
195
|
+
const absFloatValue = 1000;
|
|
196
|
+
const configDetails: CurrencyFormatConfig = {
|
|
197
|
+
decimals: 2,
|
|
198
|
+
locale: 'en',
|
|
199
|
+
removeTrailingZeroes: false,
|
|
200
|
+
toSeparateThousands: true,
|
|
201
|
+
unit: Unit.Auto,
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const result = mapFormatterConfig(absFloatValue, configDetails);
|
|
205
|
+
expect(result.unitDetails).toBe(Unit.Thousands); // Automatically chosen unit
|
|
206
|
+
expect(result.decimalDetails).toBe(2);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('should correctly map valid unit numbers to the corresponding unit', () => {
|
|
210
|
+
const input = { unit: 1 };
|
|
211
|
+
const result = mapFormatterConfig(1000, input);
|
|
212
|
+
|
|
213
|
+
// Assert that the unit has been correctly mapped to the corresponding
|
|
214
|
+
// value in PROTO_TO_UNITS
|
|
215
|
+
expect(result.unitDetails).toBe(PROTO_TO_UNITS[1]);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
describe('formatSpecialDataValue', () => {
|
|
220
|
+
it('should return {Null} for {Null} values', () => {
|
|
221
|
+
const result = formatSpecialDataValue('{Null}');
|
|
222
|
+
expect(result).toBe('{Null}');
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should return {Null} for null values', () => {
|
|
226
|
+
const result = formatSpecialDataValue(null);
|
|
227
|
+
expect(result).toBe('{Null}');
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('should return {Empty} for empty string', () => {
|
|
231
|
+
const result = formatSpecialDataValue('');
|
|
232
|
+
expect(result).toBe('{Empty}');
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it('should return {Null} for undefined values', () => {
|
|
236
|
+
const result = formatSpecialDataValue(undefined);
|
|
237
|
+
expect(result).toBe('{Null}');
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('should return NaN for string "NaN"', () => {
|
|
241
|
+
const result = formatSpecialDataValue(['NaN']);
|
|
242
|
+
expect(result).toBe('NaN');
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('should return {Null} for empty array', () => {
|
|
246
|
+
const result = formatSpecialDataValue([]);
|
|
247
|
+
expect(result).toBe('{Null}');
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('should return Null for array', () => {
|
|
251
|
+
const result = formatSpecialDataValue(['Test']);
|
|
252
|
+
expect(result).toBe(null);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('should return Infinity for string "Infinity"', () => {
|
|
256
|
+
const result = formatSpecialDataValue(['Infinity']);
|
|
257
|
+
expect(result).toBe('Infinity');
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it('should return null for non-special values', () => {
|
|
261
|
+
const result = formatSpecialDataValue('Test');
|
|
262
|
+
expect(result).toBeNull();
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('should return Infinity for Infinity', () => {
|
|
266
|
+
const result = formatSpecialDataValue(Infinity);
|
|
267
|
+
expect(result).toBe('Infinity');
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
describe('Unit constants', () => {
|
|
272
|
+
it('should map unit to correct dividing factor', () => {
|
|
273
|
+
expect(UNITS_TO_DIVIDING_FACTOR[Unit.Thousands]).toBe(1000);
|
|
274
|
+
expect(UNITS_TO_DIVIDING_FACTOR[Unit.Million]).toBe(1000000);
|
|
275
|
+
expect(UNITS_TO_DIVIDING_FACTOR[Unit.Billion]).toBe(1000000000);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('should map proto to correct unit', () => {
|
|
279
|
+
expect(PROTO_TO_UNITS[1]).toBe(Unit.None);
|
|
280
|
+
expect(PROTO_TO_UNITS[2]).toBe(Unit.Thousands);
|
|
281
|
+
expect(PROTO_TO_UNITS[3]).toBe(Unit.Million);
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
describe('Locale String Formats', () => {
|
|
286
|
+
const strings: Record<string, string> = {
|
|
287
|
+
NULL_VALUE_PLACEHOLDER_LABEL: '{Null}',
|
|
288
|
+
EMPTY_VALUE_PLACEHOLDER_LABEL: '{Empty}',
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
it('should return an default object if setLocaleBasedStringFormats is not called', () => {
|
|
292
|
+
const result = getLocaleBasedStringFormats();
|
|
293
|
+
expect(result).toEqual(strings);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('should set and get locale-based string formats correctly', () => {
|
|
297
|
+
const testLocaleStrings = {
|
|
298
|
+
greeting: 'Hello',
|
|
299
|
+
farewell: 'Goodbye',
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
setLocaleBasedStringFormats(testLocaleStrings);
|
|
303
|
+
|
|
304
|
+
const result = getLocaleBasedStringFormats();
|
|
305
|
+
|
|
306
|
+
expect(result).toEqual(testLocaleStrings);
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it('should update the string formats when setLocaleBasedStringFormats is called multiple times', () => {
|
|
310
|
+
const firstSet = { greeting: 'Hola' };
|
|
311
|
+
const secondSet = { greeting: 'Bonjour' };
|
|
312
|
+
|
|
313
|
+
// Set first locale-based string formats
|
|
314
|
+
setLocaleBasedStringFormats(firstSet);
|
|
315
|
+
expect(getLocaleBasedStringFormats()).toEqual(firstSet);
|
|
316
|
+
|
|
317
|
+
// Set second locale-based string formats
|
|
318
|
+
setLocaleBasedStringFormats(secondSet);
|
|
319
|
+
expect(getLocaleBasedStringFormats()).toEqual(secondSet);
|
|
320
|
+
});
|
|
321
|
+
});
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file: Formatting Utils
|
|
3
|
+
*
|
|
4
|
+
* @author Yashvardhan Nehra <yashvardhan.nehra@thoughtspot.com>
|
|
5
|
+
*
|
|
6
|
+
* Copyright: ThoughtSpot Inc. 2024
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import _ from 'lodash';
|
|
10
|
+
import {
|
|
11
|
+
ColumnFormat,
|
|
12
|
+
CurrencyFormat,
|
|
13
|
+
CurrencyFormatType,
|
|
14
|
+
} from '../../types/answer-column.types';
|
|
15
|
+
import { Maybe } from '../../types/common.types';
|
|
16
|
+
import {
|
|
17
|
+
CategoryType,
|
|
18
|
+
CurrencyFormatConfig,
|
|
19
|
+
FormatConfig,
|
|
20
|
+
NegativeValueFormat,
|
|
21
|
+
NumberFormatConfig,
|
|
22
|
+
Unit,
|
|
23
|
+
} from '../../types/number-formatting.types';
|
|
24
|
+
import { getDefaultCurrencyCode } from '../globalize-Initializer/globalize-utils';
|
|
25
|
+
|
|
26
|
+
interface FormatterConfig {
|
|
27
|
+
unitDetails: Unit;
|
|
28
|
+
decimalDetails: number;
|
|
29
|
+
shouldRemoveTrailingZeros: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const PROTO_TO_NEGATIVE_VALUE_FORMAT = {
|
|
33
|
+
1: NegativeValueFormat.PrefixDash,
|
|
34
|
+
2: NegativeValueFormat.SuffixDash,
|
|
35
|
+
3: NegativeValueFormat.BracesNodash,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Constants for unit conversions and suffixes.
|
|
40
|
+
*/
|
|
41
|
+
export const UNITS_TO_DIVIDING_FACTOR: Record<Unit, number> = {
|
|
42
|
+
[Unit.None]: 1,
|
|
43
|
+
[Unit.Thousands]: 1000,
|
|
44
|
+
[Unit.Million]: 1000 * 1000,
|
|
45
|
+
[Unit.Billion]: 1000 * 1000 * 1000,
|
|
46
|
+
[Unit.Trillion]: 1000 * 1000 * 1000 * 1000,
|
|
47
|
+
[Unit.Auto]: 1,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const PROTO_TO_UNITS = {
|
|
51
|
+
1: Unit.None,
|
|
52
|
+
2: Unit.Thousands,
|
|
53
|
+
3: Unit.Million,
|
|
54
|
+
4: Unit.Billion,
|
|
55
|
+
5: Unit.Trillion,
|
|
56
|
+
6: Unit.Auto,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Default strings for placeholders.
|
|
61
|
+
*/
|
|
62
|
+
let strings: Record<string, string> = {
|
|
63
|
+
NULL_VALUE_PLACEHOLDER_LABEL: '{Null}',
|
|
64
|
+
EMPTY_VALUE_PLACEHOLDER_LABEL: '{Empty}',
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const setLocaleBasedStringFormats = (
|
|
68
|
+
tsLocaleBasedStringsFormats?: Record<string, string>,
|
|
69
|
+
) => {
|
|
70
|
+
if (tsLocaleBasedStringsFormats) {
|
|
71
|
+
strings = tsLocaleBasedStringsFormats;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const getLocaleBasedStringFormats = () => strings;
|
|
76
|
+
|
|
77
|
+
export const UNITS_TO_SUFFIX: Record<Unit, string> = {
|
|
78
|
+
[Unit.None]: '',
|
|
79
|
+
[Unit.Thousands]: 'K',
|
|
80
|
+
[Unit.Million]: 'M',
|
|
81
|
+
[Unit.Billion]: 'B',
|
|
82
|
+
[Unit.Trillion]: 'T',
|
|
83
|
+
[Unit.Auto]: '',
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const DEFAULT_DECIMAL_PRECISION = 2;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Formats negative values according to the specified format.
|
|
90
|
+
*
|
|
91
|
+
* @param formattedValue - The formatted value to modify.
|
|
92
|
+
* @param negativeFormat - The desired negative value format.
|
|
93
|
+
* @returns The formatted negative value.
|
|
94
|
+
*/
|
|
95
|
+
export const formatNegativeValue = (
|
|
96
|
+
formattedValue: string,
|
|
97
|
+
negativeFormat?: Maybe<NegativeValueFormat> | number,
|
|
98
|
+
): string => {
|
|
99
|
+
if (typeof negativeFormat === 'number') {
|
|
100
|
+
// eslint-disable-next-line no-param-reassign
|
|
101
|
+
negativeFormat =
|
|
102
|
+
PROTO_TO_NEGATIVE_VALUE_FORMAT[
|
|
103
|
+
negativeFormat as keyof typeof PROTO_TO_NEGATIVE_VALUE_FORMAT
|
|
104
|
+
];
|
|
105
|
+
}
|
|
106
|
+
switch (negativeFormat) {
|
|
107
|
+
case NegativeValueFormat.PrefixDash:
|
|
108
|
+
return `-${formattedValue}`;
|
|
109
|
+
case NegativeValueFormat.SuffixDash:
|
|
110
|
+
return `${formattedValue}-`;
|
|
111
|
+
case NegativeValueFormat.BracesNodash:
|
|
112
|
+
return `(${formattedValue})`;
|
|
113
|
+
default:
|
|
114
|
+
return `-${formattedValue}`;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Determines the appropriate unit for auto-scaling values.
|
|
120
|
+
*
|
|
121
|
+
* @param value - The numeric value to evaluate.
|
|
122
|
+
* @returns The appropriate unit (e.g., Thousand, Million, etc.).
|
|
123
|
+
*/
|
|
124
|
+
export const getAutoUnit = (value: number): Unit => {
|
|
125
|
+
if (value >= UNITS_TO_DIVIDING_FACTOR[Unit.Trillion]) {
|
|
126
|
+
return Unit.Trillion;
|
|
127
|
+
}
|
|
128
|
+
if (value >= UNITS_TO_DIVIDING_FACTOR[Unit.Billion]) {
|
|
129
|
+
return Unit.Billion;
|
|
130
|
+
}
|
|
131
|
+
if (value >= UNITS_TO_DIVIDING_FACTOR[Unit.Million]) {
|
|
132
|
+
return Unit.Million;
|
|
133
|
+
}
|
|
134
|
+
if (value >= UNITS_TO_DIVIDING_FACTOR[Unit.Thousands]) {
|
|
135
|
+
return Unit.Thousands;
|
|
136
|
+
}
|
|
137
|
+
return Unit.None;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Retrieves the locale name based on the provided currency format.
|
|
142
|
+
*
|
|
143
|
+
* @param currencyFormat - The currency format configuration.
|
|
144
|
+
* @returns The locale name as a string.
|
|
145
|
+
*/
|
|
146
|
+
export const getLocaleName = (currencyFormat: CurrencyFormat): string => {
|
|
147
|
+
if (currencyFormat.type === CurrencyFormatType.ISO_CODE) {
|
|
148
|
+
return currencyFormat.isoCode;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const locale = getDefaultCurrencyCode();
|
|
152
|
+
return locale;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Generates a default format configuration based on the column settings.
|
|
157
|
+
*
|
|
158
|
+
* @param columnFormatConfig - The column-specific formatting settings.
|
|
159
|
+
* @returns The default format configuration.
|
|
160
|
+
*/
|
|
161
|
+
export const defaultFormatConfig = (
|
|
162
|
+
columnFormatConfig?: ColumnFormat,
|
|
163
|
+
): FormatConfig => {
|
|
164
|
+
if (columnFormatConfig?.pattern) {
|
|
165
|
+
return {
|
|
166
|
+
__typename: 'FormatConfig',
|
|
167
|
+
category: CategoryType.Custom,
|
|
168
|
+
isCategoryEditable: true,
|
|
169
|
+
customFormatConfig: {
|
|
170
|
+
__typename: 'CustomFormatConfig',
|
|
171
|
+
format: columnFormatConfig?.pattern,
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
if (columnFormatConfig?.currencyFormat) {
|
|
176
|
+
const locale = getLocaleName(columnFormatConfig?.currencyFormat);
|
|
177
|
+
const currencyFormatConfig: CurrencyFormatConfig = {
|
|
178
|
+
__typename: 'CurrencyFormatConfig',
|
|
179
|
+
decimals: 0,
|
|
180
|
+
locale,
|
|
181
|
+
removeTrailingZeroes: false,
|
|
182
|
+
toSeparateThousands: true,
|
|
183
|
+
unit: Unit.Auto,
|
|
184
|
+
};
|
|
185
|
+
const formatConfig: FormatConfig = {
|
|
186
|
+
__typename: 'FormatConfig',
|
|
187
|
+
category: CategoryType.Currency,
|
|
188
|
+
isCategoryEditable: true,
|
|
189
|
+
currencyFormatConfig,
|
|
190
|
+
};
|
|
191
|
+
return formatConfig;
|
|
192
|
+
}
|
|
193
|
+
const numberFormatConfig: NumberFormatConfig = {
|
|
194
|
+
__typename: 'NumberFormatConfig',
|
|
195
|
+
decimals: 0,
|
|
196
|
+
negativeValueFormat: NegativeValueFormat.PrefixDash,
|
|
197
|
+
removeTrailingZeroes: false,
|
|
198
|
+
toSeparateThousands: true,
|
|
199
|
+
unit: Unit.Auto,
|
|
200
|
+
};
|
|
201
|
+
const formatConfig: FormatConfig = {
|
|
202
|
+
__typename: 'FormatConfig',
|
|
203
|
+
category: CategoryType.Number,
|
|
204
|
+
isCategoryEditable: true,
|
|
205
|
+
numberFormatConfig,
|
|
206
|
+
percentageFormatConfig: null,
|
|
207
|
+
};
|
|
208
|
+
return formatConfig;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Maps configuration details to a formatter configuration object.
|
|
213
|
+
*
|
|
214
|
+
* @param absFloatValue - The absolute value of the number being formatted.
|
|
215
|
+
* @param configDetails - The number or currency format configuration.
|
|
216
|
+
* @returns A mapped formatter configuration.
|
|
217
|
+
*/
|
|
218
|
+
export const mapFormatterConfig = (
|
|
219
|
+
absFloatValue: number,
|
|
220
|
+
configDetails: NumberFormatConfig | CurrencyFormatConfig,
|
|
221
|
+
): FormatterConfig => {
|
|
222
|
+
if (typeof configDetails.unit === 'number') {
|
|
223
|
+
// eslint-disable-next-line no-param-reassign
|
|
224
|
+
configDetails.unit =
|
|
225
|
+
PROTO_TO_UNITS[configDetails.unit as keyof typeof PROTO_TO_UNITS];
|
|
226
|
+
}
|
|
227
|
+
const isAutoFormatted = configDetails.unit === Unit.Auto;
|
|
228
|
+
let unitDetails = configDetails.unit || Unit.Auto;
|
|
229
|
+
let decimalDetails = configDetails.decimals || 0;
|
|
230
|
+
|
|
231
|
+
if (isAutoFormatted) {
|
|
232
|
+
unitDetails = getAutoUnit(absFloatValue);
|
|
233
|
+
if (unitDetails !== Unit.None) {
|
|
234
|
+
decimalDetails = DEFAULT_DECIMAL_PRECISION;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const shouldRemoveTrailingZeros =
|
|
238
|
+
configDetails.removeTrailingZeroes || isAutoFormatted;
|
|
239
|
+
return {
|
|
240
|
+
unitDetails,
|
|
241
|
+
decimalDetails,
|
|
242
|
+
shouldRemoveTrailingZeros,
|
|
243
|
+
};
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Handles formatting of special data values (e.g., null, empty, NaN, Infinity).
|
|
248
|
+
*
|
|
249
|
+
* @param value - The value to check and format.
|
|
250
|
+
* @returns A formatted special value or null if not applicable.
|
|
251
|
+
*/
|
|
252
|
+
export function formatSpecialDataValue(value: any) {
|
|
253
|
+
if (
|
|
254
|
+
value === strings.NULL_VALUE_PLACEHOLDER_LABEL ||
|
|
255
|
+
value === strings.EMPTY_VALUE_PLACEHOLDER_LABEL
|
|
256
|
+
) {
|
|
257
|
+
return value;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (value === null || value === undefined) {
|
|
261
|
+
return strings.NULL_VALUE_PLACEHOLDER_LABEL;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (value === Infinity || value === -Infinity || _.isNaN(value)) {
|
|
265
|
+
return value.toString();
|
|
266
|
+
}
|
|
267
|
+
// {Empty} placeholder is set for empty string or no characters
|
|
268
|
+
// other than spaces.
|
|
269
|
+
if (value === '') {
|
|
270
|
+
return strings.EMPTY_VALUE_PLACEHOLDER_LABEL;
|
|
271
|
+
}
|
|
272
|
+
if (value instanceof Array) {
|
|
273
|
+
if (_.isEmpty(value) || _.isNil(value[0])) {
|
|
274
|
+
return strings.NULL_VALUE_PLACEHOLDER_LABEL;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
switch (value[0]) {
|
|
278
|
+
case 'NaN':
|
|
279
|
+
return 'NaN';
|
|
280
|
+
case 'Infinity':
|
|
281
|
+
return 'Infinity';
|
|
282
|
+
default:
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return null;
|
|
288
|
+
}
|