@itwin/core-quantity 4.0.0-dev.7 → 4.0.0-dev.72
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/CHANGELOG.md +43 -1
- package/lib/cjs/Constants.d.ts +27 -27
- package/lib/cjs/Constants.js +52 -52
- package/lib/cjs/Constants.js.map +1 -1
- package/lib/cjs/Exception.d.ts +26 -26
- package/lib/cjs/Exception.js +38 -38
- package/lib/cjs/Formatter/Format.d.ts +91 -91
- package/lib/cjs/Formatter/Format.js +328 -329
- package/lib/cjs/Formatter/Format.js.map +1 -1
- package/lib/cjs/Formatter/FormatEnums.d.ts +133 -133
- package/lib/cjs/Formatter/FormatEnums.js +318 -318
- package/lib/cjs/Formatter/Formatter.d.ts +44 -44
- package/lib/cjs/Formatter/Formatter.js +371 -371
- package/lib/cjs/Formatter/Formatter.js.map +1 -1
- package/lib/cjs/Formatter/FormatterSpec.d.ts +39 -39
- package/lib/cjs/Formatter/FormatterSpec.js +101 -101
- package/lib/cjs/Formatter/Interfaces.d.ts +62 -62
- package/lib/cjs/Formatter/Interfaces.js +17 -17
- package/lib/cjs/Interfaces.d.ts +86 -86
- package/lib/cjs/Interfaces.d.ts.map +1 -1
- package/lib/cjs/Interfaces.js +9 -9
- package/lib/cjs/Parser.d.ts +93 -93
- package/lib/cjs/Parser.d.ts.map +1 -1
- package/lib/cjs/Parser.js +592 -592
- package/lib/cjs/Parser.js.map +1 -1
- package/lib/cjs/ParserSpec.d.ts +34 -34
- package/lib/cjs/ParserSpec.js +47 -47
- package/lib/cjs/Quantity.d.ts +27 -27
- package/lib/cjs/Quantity.js +46 -46
- package/lib/cjs/Quantity.js.map +1 -1
- package/lib/cjs/Unit.d.ts +25 -25
- package/lib/cjs/Unit.js +44 -44
- package/lib/cjs/core-quantity.d.ts +19 -19
- package/lib/cjs/core-quantity.js +39 -35
- package/lib/cjs/core-quantity.js.map +1 -1
- package/lib/esm/Constants.d.ts +27 -27
- package/lib/esm/Constants.js +49 -48
- package/lib/esm/Constants.js.map +1 -1
- package/lib/esm/Exception.d.ts +26 -26
- package/lib/esm/Exception.js +34 -34
- package/lib/esm/Formatter/Format.d.ts +91 -91
- package/lib/esm/Formatter/Format.js +323 -324
- package/lib/esm/Formatter/Format.js.map +1 -1
- package/lib/esm/Formatter/FormatEnums.d.ts +133 -133
- package/lib/esm/Formatter/FormatEnums.js +302 -302
- package/lib/esm/Formatter/Formatter.d.ts +44 -44
- package/lib/esm/Formatter/Formatter.js +368 -367
- package/lib/esm/Formatter/Formatter.js.map +1 -1
- package/lib/esm/Formatter/FormatterSpec.d.ts +39 -39
- package/lib/esm/Formatter/FormatterSpec.js +97 -97
- package/lib/esm/Formatter/Interfaces.d.ts +62 -62
- package/lib/esm/Formatter/Interfaces.js +13 -13
- package/lib/esm/Interfaces.d.ts +86 -86
- package/lib/esm/Interfaces.d.ts.map +1 -1
- package/lib/esm/Interfaces.js +8 -8
- package/lib/esm/Parser.d.ts +93 -93
- package/lib/esm/Parser.d.ts.map +1 -1
- package/lib/esm/Parser.js +589 -588
- package/lib/esm/Parser.js.map +1 -1
- package/lib/esm/ParserSpec.d.ts +34 -34
- package/lib/esm/ParserSpec.js +43 -43
- package/lib/esm/Quantity.d.ts +27 -27
- package/lib/esm/Quantity.js +42 -42
- package/lib/esm/Quantity.js.map +1 -1
- package/lib/esm/Unit.d.ts +25 -25
- package/lib/esm/Unit.js +39 -39
- package/lib/esm/core-quantity.d.ts +19 -19
- package/lib/esm/core-quantity.js +23 -23
- package/package.json +11 -11
|
@@ -1,325 +1,324 @@
|
|
|
1
|
-
/*---------------------------------------------------------------------------------------------
|
|
2
|
-
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
3
|
-
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
4
|
-
*--------------------------------------------------------------------------------------------*/
|
|
5
|
-
/** @packageDocumentation
|
|
6
|
-
* @module Quantity
|
|
7
|
-
*/
|
|
8
|
-
import { QuantityConstants } from "../Constants";
|
|
9
|
-
import { QuantityError, QuantityStatus } from "../Exception";
|
|
10
|
-
import { DecimalPrecision, FormatTraits, formatTraitsToArray, FormatType, formatTypeToString, getTraitString, parseFormatTrait, parseFormatType, parsePrecision, parseScientificType, parseShowSignOption, scientificTypeToString, ShowSignOption, showSignOptionToString } from "./FormatEnums";
|
|
11
|
-
import { isCustomFormatProps } from "./Interfaces";
|
|
12
|
-
// cSpell:ignore ZERONORMALIZED, nosign, onlynegative, signalways, negativeparentheses
|
|
13
|
-
// cSpell:ignore trailzeroes, keepsinglezero, zeroempty, keepdecimalpoint, applyrounding, fractiondash, showunitlabel, prependunitlabel, exponentonlynegative
|
|
14
|
-
/** A base Format class with shared properties and functionality between quantity and ecschema-metadata Format classes
|
|
15
|
-
* @beta
|
|
16
|
-
*/
|
|
17
|
-
export class BaseFormat {
|
|
18
|
-
constructor(name) {
|
|
19
|
-
this._name = "";
|
|
20
|
-
this._roundFactor = 0.0;
|
|
21
|
-
this._type = FormatType.Decimal; // required; options are decimal, fractional, scientific, station
|
|
22
|
-
this._precision = DecimalPrecision.Six; // required
|
|
23
|
-
this._showSignOption = ShowSignOption.OnlyNegative; // options: noSign, onlyNegative, signAlways, negativeParentheses
|
|
24
|
-
this._decimalSeparator = QuantityConstants.LocaleSpecificDecimalSeparator;
|
|
25
|
-
this._thousandSeparator = QuantityConstants.LocaleSpecificThousandSeparator;
|
|
26
|
-
this._uomSeparator = " "; // optional; default is " "; defined separator between magnitude and the unit
|
|
27
|
-
this._stationSeparator = "+"; // optional; default is "+"
|
|
28
|
-
this._formatTraits = FormatTraits.Uninitialized;
|
|
29
|
-
this._spacer = " "; // optional; default is " "
|
|
30
|
-
this._includeZero = true; // optional; default is true
|
|
31
|
-
this._name = name;
|
|
32
|
-
}
|
|
33
|
-
get name() { return this._name; }
|
|
34
|
-
get roundFactor() { return this._roundFactor; }
|
|
35
|
-
set roundFactor(roundFactor) { this._roundFactor = roundFactor; }
|
|
36
|
-
get type() { return this._type; }
|
|
37
|
-
set type(formatType) { this._type = formatType; }
|
|
38
|
-
get precision() { return this._precision; }
|
|
39
|
-
set precision(precision) { this._precision = precision; }
|
|
40
|
-
get minWidth() { return this._minWidth; }
|
|
41
|
-
set minWidth(minWidth) { this._minWidth = minWidth; }
|
|
42
|
-
get scientificType() { return this._scientificType; }
|
|
43
|
-
set scientificType(scientificType) { this._scientificType = scientificType; }
|
|
44
|
-
get showSignOption() { return this._showSignOption; }
|
|
45
|
-
set showSignOption(showSignOption) { this._showSignOption = showSignOption; }
|
|
46
|
-
get decimalSeparator() { return this._decimalSeparator; }
|
|
47
|
-
set decimalSeparator(decimalSeparator) { this._decimalSeparator = decimalSeparator; }
|
|
48
|
-
get thousandSeparator() { return this._thousandSeparator; }
|
|
49
|
-
set thousandSeparator(thousandSeparator) { this._thousandSeparator = thousandSeparator; }
|
|
50
|
-
get uomSeparator() { return this._uomSeparator; }
|
|
51
|
-
set uomSeparator(uomSeparator) { this._uomSeparator = uomSeparator; }
|
|
52
|
-
get stationSeparator() { return this._stationSeparator; }
|
|
53
|
-
set stationSeparator(stationSeparator) { this._stationSeparator = stationSeparator; }
|
|
54
|
-
get stationOffsetSize() { return this._stationOffsetSize; }
|
|
55
|
-
set stationOffsetSize(stationOffsetSize) { stationOffsetSize = this._stationOffsetSize = stationOffsetSize; }
|
|
56
|
-
get formatTraits() { return this._formatTraits; }
|
|
57
|
-
set formatTraits(formatTraits) { this._formatTraits = formatTraits; }
|
|
58
|
-
get spacer() { return this._spacer; }
|
|
59
|
-
set spacer(spacer) { this._spacer = spacer
|
|
60
|
-
get includeZero() { return this._includeZero; }
|
|
61
|
-
set includeZero(includeZero) { this._includeZero = includeZero
|
|
62
|
-
/** This method parses input string that is typically extracted for persisted JSON data and validates that the string is a valid FormatType. Throws exception if not valid. */
|
|
63
|
-
parseFormatTraits(formatTraitsFromJson) {
|
|
64
|
-
const formatTraits = (Array.isArray(formatTraitsFromJson)) ? formatTraitsFromJson : formatTraitsFromJson.split(/,|;|\|/);
|
|
65
|
-
formatTraits.forEach((formatTraitsString) => {
|
|
66
|
-
const formatTrait = parseFormatTrait(formatTraitsString, this.name);
|
|
67
|
-
this._formatTraits = this.formatTraits | formatTrait;
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
/** This method returns true if the formatTrait is set in this Format object. */
|
|
71
|
-
hasFormatTraitSet(formatTrait) {
|
|
72
|
-
return (this._formatTraits & formatTrait) === formatTrait;
|
|
73
|
-
}
|
|
74
|
-
loadFormatProperties(formatProps) {
|
|
75
|
-
this._type = parseFormatType(formatProps.type, this.name);
|
|
76
|
-
if (formatProps.precision !== undefined) {
|
|
77
|
-
if (!Number.isInteger(formatProps.precision)) // mut be an integer
|
|
78
|
-
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'precision' attribute. It should be an integer.`);
|
|
79
|
-
this._precision = parsePrecision(formatProps.precision, this._type, this.name);
|
|
80
|
-
}
|
|
81
|
-
if (this.type === FormatType.Scientific) {
|
|
82
|
-
if (undefined === formatProps.scientificType) // if format type is scientific and scientific type is undefined, throw
|
|
83
|
-
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} is 'Scientific' type therefore the attribute 'scientificType' is required.`);
|
|
84
|
-
this._scientificType = parseScientificType(formatProps.scientificType, this.name);
|
|
85
|
-
}
|
|
86
|
-
if (undefined !== formatProps.roundFactor) { // optional; default is 0.0
|
|
87
|
-
if (typeof (formatProps.roundFactor) !== "number")
|
|
88
|
-
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'roundFactor' attribute. It should be of type 'number'.`);
|
|
89
|
-
if (formatProps.roundFactor !== this.roundFactor) // if roundFactor isn't default value of 0.0, reassign roundFactor variable
|
|
90
|
-
this._roundFactor = formatProps.roundFactor;
|
|
91
|
-
}
|
|
92
|
-
if (undefined !== formatProps.minWidth) { // optional
|
|
93
|
-
if (!Number.isInteger(formatProps.minWidth) || formatProps.minWidth < 0) // must be a positive int
|
|
94
|
-
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'minWidth' attribute. It should be a positive integer.`);
|
|
95
|
-
this._minWidth = formatProps.minWidth;
|
|
96
|
-
}
|
|
97
|
-
if (FormatType.Station === this.type) {
|
|
98
|
-
if (undefined === formatProps.stationOffsetSize)
|
|
99
|
-
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} is 'Station' type therefore the attribute 'stationOffsetSize' is required.`);
|
|
100
|
-
if (!Number.isInteger(formatProps.stationOffsetSize) || formatProps.stationOffsetSize < 0) // must be a positive int > 0
|
|
101
|
-
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'stationOffsetSize' attribute. It should be a positive integer.`);
|
|
102
|
-
this._stationOffsetSize = formatProps.stationOffsetSize;
|
|
103
|
-
}
|
|
104
|
-
if (undefined !== formatProps.showSignOption) { // optional; default is "onlyNegative"
|
|
105
|
-
this._showSignOption = parseShowSignOption(formatProps.showSignOption, this.name);
|
|
106
|
-
}
|
|
107
|
-
if (undefined !== formatProps.formatTraits && formatProps.formatTraits.length !== 0) { // FormatTraits is optional
|
|
108
|
-
if (!Array.isArray(formatProps.formatTraits) && typeof (formatProps.formatTraits) !== "string") // must be either an array of strings or a string
|
|
109
|
-
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'formatTraits' attribute. It should be of type 'string' or 'string[]'.`);
|
|
110
|
-
this.parseFormatTraits(formatProps.formatTraits); // check that all of the options for formatTraits are valid. If now, throw
|
|
111
|
-
}
|
|
112
|
-
if (undefined !== formatProps.decimalSeparator) { // optional
|
|
113
|
-
if (typeof (formatProps.decimalSeparator) !== "string") // not a string or not a one character string
|
|
114
|
-
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'decimalSeparator' attribute. It should be of type 'string'.`);
|
|
115
|
-
if (formatProps.decimalSeparator.length > 1)
|
|
116
|
-
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'decimalSeparator' attribute. It should be an empty or one character string.`);
|
|
117
|
-
this._decimalSeparator = formatProps.decimalSeparator;
|
|
118
|
-
}
|
|
119
|
-
if (undefined !== formatProps.thousandSeparator) { // optional
|
|
120
|
-
if (typeof (formatProps.thousandSeparator) !== "string")
|
|
121
|
-
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'thousandSeparator' attribute. It should be of type 'string'.`);
|
|
122
|
-
if (formatProps.thousandSeparator.length > 1)
|
|
123
|
-
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'thousandSeparator' attribute. It should be an empty or one character string.`);
|
|
124
|
-
this._thousandSeparator = formatProps.thousandSeparator;
|
|
125
|
-
}
|
|
126
|
-
if (undefined !== formatProps.uomSeparator) { // optional; default is " "
|
|
127
|
-
if (typeof (formatProps.uomSeparator) !== "string")
|
|
128
|
-
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'uomSeparator' attribute. It should be of type 'string'.`);
|
|
129
|
-
if (formatProps.uomSeparator.length < 0 || formatProps.uomSeparator.length > 1)
|
|
130
|
-
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'uomSeparator' attribute. It should be an empty or one character string.`);
|
|
131
|
-
this._uomSeparator = formatProps.uomSeparator;
|
|
132
|
-
}
|
|
133
|
-
if (undefined !== formatProps.stationSeparator) { // optional; default is "+"
|
|
134
|
-
if (typeof (formatProps.stationSeparator) !== "string")
|
|
135
|
-
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'stationSeparator' attribute. It should be of type 'string'.`);
|
|
136
|
-
if (formatProps.stationSeparator.length > 1)
|
|
137
|
-
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'stationSeparator' attribute. It should be an empty or one character string.`);
|
|
138
|
-
this._stationSeparator = formatProps.stationSeparator;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
/** A class used to define the specifications for formatting quantity values. This class is typically loaded by reading [[FormatProps]].
|
|
143
|
-
* @beta
|
|
144
|
-
*/
|
|
145
|
-
export class Format extends BaseFormat {
|
|
146
|
-
/** Constructor
|
|
147
|
-
* @param name The name of a format specification. TODO: make optional or remove
|
|
148
|
-
*/
|
|
149
|
-
constructor(name) {
|
|
150
|
-
super(name);
|
|
151
|
-
}
|
|
152
|
-
get units() { return this._units; }
|
|
153
|
-
get hasUnits() { return this._units !== undefined && this._units.length > 0; }
|
|
154
|
-
get customProps() { return this._customProps; }
|
|
155
|
-
static isFormatTraitSetInProps(formatProps, trait) {
|
|
156
|
-
if (!formatProps.formatTraits)
|
|
157
|
-
return false;
|
|
158
|
-
const formatTraits = Array.isArray(formatProps.formatTraits) ? formatProps.formatTraits : formatProps.formatTraits.split(/,|;|\|/);
|
|
159
|
-
const traitStr = getTraitString(trait);
|
|
160
|
-
return formatTraits.find((traitEntry) => traitStr === traitEntry) ? true : false;
|
|
161
|
-
}
|
|
162
|
-
async createUnit(unitsProvider, name, label) {
|
|
163
|
-
if (name === undefined || typeof (name) !== "string" || (label !== undefined && typeof (label) !== "string")) // throws if name is undefined or name isn't a string or if label is defined and isn't a string
|
|
164
|
-
throw new QuantityError(QuantityStatus.InvalidJson, `This Composite has a unit with an invalid 'name' or 'label' attribute.`);
|
|
165
|
-
for (const unit of this.units) {
|
|
166
|
-
const unitObj = unit[0].name;
|
|
167
|
-
if (unitObj.toLowerCase() === name.toLowerCase()) // duplicate names are not allowed
|
|
168
|
-
throw new QuantityError(QuantityStatus.InvalidJson, `The unit ${unitObj} has a duplicate name.`);
|
|
169
|
-
}
|
|
170
|
-
const newUnit = await unitsProvider.findUnitByName(name);
|
|
171
|
-
if (!newUnit || !newUnit.isValid)
|
|
172
|
-
throw new QuantityError(QuantityStatus.InvalidJson, `Invalid unit name '${name}'.`);
|
|
173
|
-
this.units.push([newUnit, label]);
|
|
174
|
-
}
|
|
175
|
-
/**
|
|
176
|
-
* Clone Format
|
|
177
|
-
*/
|
|
178
|
-
clone(options) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
newFormat.
|
|
182
|
-
newFormat.
|
|
183
|
-
newFormat.
|
|
184
|
-
newFormat.
|
|
185
|
-
newFormat.
|
|
186
|
-
newFormat.
|
|
187
|
-
newFormat.
|
|
188
|
-
newFormat.
|
|
189
|
-
newFormat.
|
|
190
|
-
newFormat.
|
|
191
|
-
newFormat.
|
|
192
|
-
newFormat.
|
|
193
|
-
newFormat.
|
|
194
|
-
newFormat.
|
|
195
|
-
newFormat.
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
}
|
|
1
|
+
/*---------------------------------------------------------------------------------------------
|
|
2
|
+
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
3
|
+
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
4
|
+
*--------------------------------------------------------------------------------------------*/
|
|
5
|
+
/** @packageDocumentation
|
|
6
|
+
* @module Quantity
|
|
7
|
+
*/
|
|
8
|
+
import { QuantityConstants } from "../Constants";
|
|
9
|
+
import { QuantityError, QuantityStatus } from "../Exception";
|
|
10
|
+
import { DecimalPrecision, FormatTraits, formatTraitsToArray, FormatType, formatTypeToString, getTraitString, parseFormatTrait, parseFormatType, parsePrecision, parseScientificType, parseShowSignOption, scientificTypeToString, ShowSignOption, showSignOptionToString } from "./FormatEnums";
|
|
11
|
+
import { isCustomFormatProps } from "./Interfaces";
|
|
12
|
+
// cSpell:ignore ZERONORMALIZED, nosign, onlynegative, signalways, negativeparentheses
|
|
13
|
+
// cSpell:ignore trailzeroes, keepsinglezero, zeroempty, keepdecimalpoint, applyrounding, fractiondash, showunitlabel, prependunitlabel, exponentonlynegative
|
|
14
|
+
/** A base Format class with shared properties and functionality between quantity and ecschema-metadata Format classes
|
|
15
|
+
* @beta
|
|
16
|
+
*/
|
|
17
|
+
export class BaseFormat {
|
|
18
|
+
constructor(name) {
|
|
19
|
+
this._name = "";
|
|
20
|
+
this._roundFactor = 0.0;
|
|
21
|
+
this._type = FormatType.Decimal; // required; options are decimal, fractional, scientific, station
|
|
22
|
+
this._precision = DecimalPrecision.Six; // required
|
|
23
|
+
this._showSignOption = ShowSignOption.OnlyNegative; // options: noSign, onlyNegative, signAlways, negativeParentheses
|
|
24
|
+
this._decimalSeparator = QuantityConstants.LocaleSpecificDecimalSeparator;
|
|
25
|
+
this._thousandSeparator = QuantityConstants.LocaleSpecificThousandSeparator;
|
|
26
|
+
this._uomSeparator = " "; // optional; default is " "; defined separator between magnitude and the unit
|
|
27
|
+
this._stationSeparator = "+"; // optional; default is "+"
|
|
28
|
+
this._formatTraits = FormatTraits.Uninitialized;
|
|
29
|
+
this._spacer = " "; // optional; default is " "
|
|
30
|
+
this._includeZero = true; // optional; default is true
|
|
31
|
+
this._name = name;
|
|
32
|
+
}
|
|
33
|
+
get name() { return this._name; }
|
|
34
|
+
get roundFactor() { return this._roundFactor; }
|
|
35
|
+
set roundFactor(roundFactor) { this._roundFactor = roundFactor; }
|
|
36
|
+
get type() { return this._type; }
|
|
37
|
+
set type(formatType) { this._type = formatType; }
|
|
38
|
+
get precision() { return this._precision; }
|
|
39
|
+
set precision(precision) { this._precision = precision; }
|
|
40
|
+
get minWidth() { return this._minWidth; }
|
|
41
|
+
set minWidth(minWidth) { this._minWidth = minWidth; }
|
|
42
|
+
get scientificType() { return this._scientificType; }
|
|
43
|
+
set scientificType(scientificType) { this._scientificType = scientificType; }
|
|
44
|
+
get showSignOption() { return this._showSignOption; }
|
|
45
|
+
set showSignOption(showSignOption) { this._showSignOption = showSignOption; }
|
|
46
|
+
get decimalSeparator() { return this._decimalSeparator; }
|
|
47
|
+
set decimalSeparator(decimalSeparator) { this._decimalSeparator = decimalSeparator; }
|
|
48
|
+
get thousandSeparator() { return this._thousandSeparator; }
|
|
49
|
+
set thousandSeparator(thousandSeparator) { this._thousandSeparator = thousandSeparator; }
|
|
50
|
+
get uomSeparator() { return this._uomSeparator; }
|
|
51
|
+
set uomSeparator(uomSeparator) { this._uomSeparator = uomSeparator; }
|
|
52
|
+
get stationSeparator() { return this._stationSeparator; }
|
|
53
|
+
set stationSeparator(stationSeparator) { this._stationSeparator = stationSeparator; }
|
|
54
|
+
get stationOffsetSize() { return this._stationOffsetSize; }
|
|
55
|
+
set stationOffsetSize(stationOffsetSize) { stationOffsetSize = this._stationOffsetSize = stationOffsetSize; }
|
|
56
|
+
get formatTraits() { return this._formatTraits; }
|
|
57
|
+
set formatTraits(formatTraits) { this._formatTraits = formatTraits; }
|
|
58
|
+
get spacer() { return this._spacer; }
|
|
59
|
+
set spacer(spacer) { this._spacer = spacer ?? this._spacer; }
|
|
60
|
+
get includeZero() { return this._includeZero; }
|
|
61
|
+
set includeZero(includeZero) { this._includeZero = includeZero ?? this._includeZero; }
|
|
62
|
+
/** This method parses input string that is typically extracted for persisted JSON data and validates that the string is a valid FormatType. Throws exception if not valid. */
|
|
63
|
+
parseFormatTraits(formatTraitsFromJson) {
|
|
64
|
+
const formatTraits = (Array.isArray(formatTraitsFromJson)) ? formatTraitsFromJson : formatTraitsFromJson.split(/,|;|\|/);
|
|
65
|
+
formatTraits.forEach((formatTraitsString) => {
|
|
66
|
+
const formatTrait = parseFormatTrait(formatTraitsString, this.name);
|
|
67
|
+
this._formatTraits = this.formatTraits | formatTrait;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/** This method returns true if the formatTrait is set in this Format object. */
|
|
71
|
+
hasFormatTraitSet(formatTrait) {
|
|
72
|
+
return (this._formatTraits & formatTrait) === formatTrait;
|
|
73
|
+
}
|
|
74
|
+
loadFormatProperties(formatProps) {
|
|
75
|
+
this._type = parseFormatType(formatProps.type, this.name);
|
|
76
|
+
if (formatProps.precision !== undefined) {
|
|
77
|
+
if (!Number.isInteger(formatProps.precision)) // mut be an integer
|
|
78
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'precision' attribute. It should be an integer.`);
|
|
79
|
+
this._precision = parsePrecision(formatProps.precision, this._type, this.name);
|
|
80
|
+
}
|
|
81
|
+
if (this.type === FormatType.Scientific) {
|
|
82
|
+
if (undefined === formatProps.scientificType) // if format type is scientific and scientific type is undefined, throw
|
|
83
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} is 'Scientific' type therefore the attribute 'scientificType' is required.`);
|
|
84
|
+
this._scientificType = parseScientificType(formatProps.scientificType, this.name);
|
|
85
|
+
}
|
|
86
|
+
if (undefined !== formatProps.roundFactor) { // optional; default is 0.0
|
|
87
|
+
if (typeof (formatProps.roundFactor) !== "number")
|
|
88
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'roundFactor' attribute. It should be of type 'number'.`);
|
|
89
|
+
if (formatProps.roundFactor !== this.roundFactor) // if roundFactor isn't default value of 0.0, reassign roundFactor variable
|
|
90
|
+
this._roundFactor = formatProps.roundFactor;
|
|
91
|
+
}
|
|
92
|
+
if (undefined !== formatProps.minWidth) { // optional
|
|
93
|
+
if (!Number.isInteger(formatProps.minWidth) || formatProps.minWidth < 0) // must be a positive int
|
|
94
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'minWidth' attribute. It should be a positive integer.`);
|
|
95
|
+
this._minWidth = formatProps.minWidth;
|
|
96
|
+
}
|
|
97
|
+
if (FormatType.Station === this.type) {
|
|
98
|
+
if (undefined === formatProps.stationOffsetSize)
|
|
99
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} is 'Station' type therefore the attribute 'stationOffsetSize' is required.`);
|
|
100
|
+
if (!Number.isInteger(formatProps.stationOffsetSize) || formatProps.stationOffsetSize < 0) // must be a positive int > 0
|
|
101
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'stationOffsetSize' attribute. It should be a positive integer.`);
|
|
102
|
+
this._stationOffsetSize = formatProps.stationOffsetSize;
|
|
103
|
+
}
|
|
104
|
+
if (undefined !== formatProps.showSignOption) { // optional; default is "onlyNegative"
|
|
105
|
+
this._showSignOption = parseShowSignOption(formatProps.showSignOption, this.name);
|
|
106
|
+
}
|
|
107
|
+
if (undefined !== formatProps.formatTraits && formatProps.formatTraits.length !== 0) { // FormatTraits is optional
|
|
108
|
+
if (!Array.isArray(formatProps.formatTraits) && typeof (formatProps.formatTraits) !== "string") // must be either an array of strings or a string
|
|
109
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'formatTraits' attribute. It should be of type 'string' or 'string[]'.`);
|
|
110
|
+
this.parseFormatTraits(formatProps.formatTraits); // check that all of the options for formatTraits are valid. If now, throw
|
|
111
|
+
}
|
|
112
|
+
if (undefined !== formatProps.decimalSeparator) { // optional
|
|
113
|
+
if (typeof (formatProps.decimalSeparator) !== "string") // not a string or not a one character string
|
|
114
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'decimalSeparator' attribute. It should be of type 'string'.`);
|
|
115
|
+
if (formatProps.decimalSeparator.length > 1)
|
|
116
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'decimalSeparator' attribute. It should be an empty or one character string.`);
|
|
117
|
+
this._decimalSeparator = formatProps.decimalSeparator;
|
|
118
|
+
}
|
|
119
|
+
if (undefined !== formatProps.thousandSeparator) { // optional
|
|
120
|
+
if (typeof (formatProps.thousandSeparator) !== "string")
|
|
121
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'thousandSeparator' attribute. It should be of type 'string'.`);
|
|
122
|
+
if (formatProps.thousandSeparator.length > 1)
|
|
123
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'thousandSeparator' attribute. It should be an empty or one character string.`);
|
|
124
|
+
this._thousandSeparator = formatProps.thousandSeparator;
|
|
125
|
+
}
|
|
126
|
+
if (undefined !== formatProps.uomSeparator) { // optional; default is " "
|
|
127
|
+
if (typeof (formatProps.uomSeparator) !== "string")
|
|
128
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'uomSeparator' attribute. It should be of type 'string'.`);
|
|
129
|
+
if (formatProps.uomSeparator.length < 0 || formatProps.uomSeparator.length > 1)
|
|
130
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'uomSeparator' attribute. It should be an empty or one character string.`);
|
|
131
|
+
this._uomSeparator = formatProps.uomSeparator;
|
|
132
|
+
}
|
|
133
|
+
if (undefined !== formatProps.stationSeparator) { // optional; default is "+"
|
|
134
|
+
if (typeof (formatProps.stationSeparator) !== "string")
|
|
135
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'stationSeparator' attribute. It should be of type 'string'.`);
|
|
136
|
+
if (formatProps.stationSeparator.length > 1)
|
|
137
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'stationSeparator' attribute. It should be an empty or one character string.`);
|
|
138
|
+
this._stationSeparator = formatProps.stationSeparator;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/** A class used to define the specifications for formatting quantity values. This class is typically loaded by reading [[FormatProps]].
|
|
143
|
+
* @beta
|
|
144
|
+
*/
|
|
145
|
+
export class Format extends BaseFormat {
|
|
146
|
+
/** Constructor
|
|
147
|
+
* @param name The name of a format specification. TODO: make optional or remove
|
|
148
|
+
*/
|
|
149
|
+
constructor(name) {
|
|
150
|
+
super(name);
|
|
151
|
+
}
|
|
152
|
+
get units() { return this._units; }
|
|
153
|
+
get hasUnits() { return this._units !== undefined && this._units.length > 0; }
|
|
154
|
+
get customProps() { return this._customProps; }
|
|
155
|
+
static isFormatTraitSetInProps(formatProps, trait) {
|
|
156
|
+
if (!formatProps.formatTraits)
|
|
157
|
+
return false;
|
|
158
|
+
const formatTraits = Array.isArray(formatProps.formatTraits) ? formatProps.formatTraits : formatProps.formatTraits.split(/,|;|\|/);
|
|
159
|
+
const traitStr = getTraitString(trait);
|
|
160
|
+
return formatTraits.find((traitEntry) => traitStr === traitEntry) ? true : false;
|
|
161
|
+
}
|
|
162
|
+
async createUnit(unitsProvider, name, label) {
|
|
163
|
+
if (name === undefined || typeof (name) !== "string" || (label !== undefined && typeof (label) !== "string")) // throws if name is undefined or name isn't a string or if label is defined and isn't a string
|
|
164
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `This Composite has a unit with an invalid 'name' or 'label' attribute.`);
|
|
165
|
+
for (const unit of this.units) {
|
|
166
|
+
const unitObj = unit[0].name;
|
|
167
|
+
if (unitObj.toLowerCase() === name.toLowerCase()) // duplicate names are not allowed
|
|
168
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The unit ${unitObj} has a duplicate name.`);
|
|
169
|
+
}
|
|
170
|
+
const newUnit = await unitsProvider.findUnitByName(name);
|
|
171
|
+
if (!newUnit || !newUnit.isValid)
|
|
172
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `Invalid unit name '${name}'.`);
|
|
173
|
+
this.units.push([newUnit, label]);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Clone Format
|
|
177
|
+
*/
|
|
178
|
+
clone(options) {
|
|
179
|
+
const newFormat = new Format(this.name);
|
|
180
|
+
newFormat._roundFactor = this._roundFactor;
|
|
181
|
+
newFormat._type = this._type;
|
|
182
|
+
newFormat._precision = this._precision;
|
|
183
|
+
newFormat._minWidth = this._minWidth;
|
|
184
|
+
newFormat._scientificType = this._scientificType;
|
|
185
|
+
newFormat._showSignOption = this._showSignOption;
|
|
186
|
+
newFormat._decimalSeparator = this._decimalSeparator;
|
|
187
|
+
newFormat._thousandSeparator = this._thousandSeparator;
|
|
188
|
+
newFormat._uomSeparator = this._uomSeparator;
|
|
189
|
+
newFormat._stationSeparator = this._stationSeparator;
|
|
190
|
+
newFormat._stationOffsetSize = this._stationOffsetSize;
|
|
191
|
+
newFormat._formatTraits = this._formatTraits;
|
|
192
|
+
newFormat._spacer = this._spacer;
|
|
193
|
+
newFormat._includeZero = this._includeZero;
|
|
194
|
+
newFormat._customProps = this._customProps;
|
|
195
|
+
this._units && (newFormat._units = [...this._units]);
|
|
196
|
+
if (newFormat._units) {
|
|
197
|
+
if (options?.showOnlyPrimaryUnit) {
|
|
198
|
+
if (newFormat._units.length > 1)
|
|
199
|
+
newFormat._units.length = 1;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (undefined !== options?.traits)
|
|
203
|
+
newFormat._formatTraits = options?.traits;
|
|
204
|
+
if (undefined !== options?.type)
|
|
205
|
+
newFormat._type = options.type;
|
|
206
|
+
if (undefined !== options?.precision) {
|
|
207
|
+
// ensure specified precision is valid
|
|
208
|
+
const precision = parsePrecision(options?.precision, newFormat._type, newFormat.name);
|
|
209
|
+
newFormat._precision = precision;
|
|
210
|
+
}
|
|
211
|
+
if (undefined !== options?.primaryUnit) {
|
|
212
|
+
if (options.primaryUnit.unit) {
|
|
213
|
+
const newUnits = new Array();
|
|
214
|
+
newUnits.push([options.primaryUnit.unit, options.primaryUnit.label]);
|
|
215
|
+
newFormat._units = newUnits;
|
|
216
|
+
}
|
|
217
|
+
else if (options.primaryUnit.label && newFormat._units?.length) {
|
|
218
|
+
// update label only
|
|
219
|
+
newFormat._units[0][1] = options.primaryUnit.label;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return newFormat;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Populates this Format with the values from the provided.
|
|
226
|
+
*/
|
|
227
|
+
async fromJSON(unitsProvider, jsonObj) {
|
|
228
|
+
this.loadFormatProperties(jsonObj);
|
|
229
|
+
if (isCustomFormatProps(jsonObj))
|
|
230
|
+
this._customProps = jsonObj.custom;
|
|
231
|
+
if (undefined !== jsonObj.composite) { // optional
|
|
232
|
+
this._units = new Array();
|
|
233
|
+
if (jsonObj.composite.includeZero !== undefined) {
|
|
234
|
+
if (typeof (jsonObj.composite.includeZero) !== "boolean") // includeZero must be a boolean IF it is defined
|
|
235
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has a Composite with an invalid 'includeZero' attribute. It should be of type 'boolean'.`);
|
|
236
|
+
this._includeZero = jsonObj.composite.includeZero;
|
|
237
|
+
}
|
|
238
|
+
if (jsonObj.composite.spacer !== undefined) { // spacer must be a string IF it is defined
|
|
239
|
+
if (typeof (jsonObj.composite.spacer) !== "string")
|
|
240
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has a Composite with an invalid 'spacer' attribute. It must be of type 'string'.`);
|
|
241
|
+
if (jsonObj.composite.spacer.length > 1)
|
|
242
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has a Composite with an invalid 'spacer' attribute. It should be an empty or one character string.`);
|
|
243
|
+
this._spacer = jsonObj.composite.spacer;
|
|
244
|
+
}
|
|
245
|
+
if (jsonObj.composite.units !== undefined) { // if composite is defined, it must be an array with 1-4 units
|
|
246
|
+
if (!Array.isArray(jsonObj.composite.units)) { // must be an array
|
|
247
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has a Composite with an invalid 'units' attribute. It must be of type 'array'`);
|
|
248
|
+
}
|
|
249
|
+
if (jsonObj.composite.units.length > 0 && jsonObj.composite.units.length <= 4) { // Composite requires 1-4 units
|
|
250
|
+
try {
|
|
251
|
+
const createUnitPromises = [];
|
|
252
|
+
for (const unit of jsonObj.composite.units) {
|
|
253
|
+
createUnitPromises.push(this.createUnit(unitsProvider, unit.name, unit.label));
|
|
254
|
+
}
|
|
255
|
+
await Promise.all(createUnitPromises);
|
|
256
|
+
}
|
|
257
|
+
catch (e) {
|
|
258
|
+
throw e;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (undefined === this.units || this.units.length === 0)
|
|
263
|
+
throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has a Composite with no valid 'units'`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/** Create a Format from FormatProps */
|
|
267
|
+
static async createFromJSON(name, unitsProvider, formatProps) {
|
|
268
|
+
const actualFormat = new Format(name);
|
|
269
|
+
await actualFormat.fromJSON(unitsProvider, formatProps);
|
|
270
|
+
return actualFormat;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Returns a JSON object that contain the specification for this Format.
|
|
274
|
+
*/
|
|
275
|
+
toJSON() {
|
|
276
|
+
let composite;
|
|
277
|
+
if (this.units) {
|
|
278
|
+
const units = this.units.map((value) => {
|
|
279
|
+
if (undefined !== value[1])
|
|
280
|
+
return { name: value[0].name, label: value[1] };
|
|
281
|
+
else
|
|
282
|
+
return { name: value[0].name };
|
|
283
|
+
});
|
|
284
|
+
composite = {
|
|
285
|
+
spacer: this.spacer,
|
|
286
|
+
includeZero: this.includeZero,
|
|
287
|
+
units,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
if (this.customProps)
|
|
291
|
+
return {
|
|
292
|
+
type: formatTypeToString(this.type),
|
|
293
|
+
precision: this.precision,
|
|
294
|
+
roundFactor: this.roundFactor,
|
|
295
|
+
minWidth: this.minWidth,
|
|
296
|
+
showSignOption: showSignOptionToString(this.showSignOption),
|
|
297
|
+
formatTraits: formatTraitsToArray(this.formatTraits),
|
|
298
|
+
decimalSeparator: this.decimalSeparator,
|
|
299
|
+
thousandSeparator: this.thousandSeparator,
|
|
300
|
+
uomSeparator: this.uomSeparator,
|
|
301
|
+
scientificType: this.scientificType ? scientificTypeToString(this.scientificType) : undefined,
|
|
302
|
+
stationOffsetSize: this.stationOffsetSize,
|
|
303
|
+
stationSeparator: this.stationSeparator,
|
|
304
|
+
composite,
|
|
305
|
+
custom: this.customProps,
|
|
306
|
+
};
|
|
307
|
+
return {
|
|
308
|
+
type: formatTypeToString(this.type),
|
|
309
|
+
precision: this.precision,
|
|
310
|
+
roundFactor: this.roundFactor,
|
|
311
|
+
minWidth: this.minWidth,
|
|
312
|
+
showSignOption: showSignOptionToString(this.showSignOption),
|
|
313
|
+
formatTraits: formatTraitsToArray(this.formatTraits),
|
|
314
|
+
decimalSeparator: this.decimalSeparator,
|
|
315
|
+
thousandSeparator: this.thousandSeparator,
|
|
316
|
+
uomSeparator: this.uomSeparator,
|
|
317
|
+
scientificType: this.scientificType ? scientificTypeToString(this.scientificType) : undefined,
|
|
318
|
+
stationOffsetSize: this.stationOffsetSize,
|
|
319
|
+
stationSeparator: this.stationSeparator,
|
|
320
|
+
composite,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
}
|
|
325
324
|
//# sourceMappingURL=Format.js.map
|