@itwin/core-quantity 3.1.0-dev.8 → 3.2.0-dev.3

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 (34) hide show
  1. package/CHANGELOG.md +17 -1
  2. package/lib/cjs/Exception.d.ts.map +1 -1
  3. package/lib/cjs/Exception.js +1 -0
  4. package/lib/cjs/Exception.js.map +1 -1
  5. package/lib/cjs/Formatter/Format.d.ts +37 -41
  6. package/lib/cjs/Formatter/Format.d.ts.map +1 -1
  7. package/lib/cjs/Formatter/Format.js +117 -341
  8. package/lib/cjs/Formatter/Format.js.map +1 -1
  9. package/lib/cjs/Formatter/FormatEnums.d.ts +46 -1
  10. package/lib/cjs/Formatter/FormatEnums.d.ts.map +1 -1
  11. package/lib/cjs/Formatter/FormatEnums.js +219 -2
  12. package/lib/cjs/Formatter/FormatEnums.js.map +1 -1
  13. package/lib/cjs/Formatter/FormatterSpec.js +1 -1
  14. package/lib/cjs/Formatter/FormatterSpec.js.map +1 -1
  15. package/lib/cjs/Interfaces.d.ts +9 -1
  16. package/lib/cjs/Interfaces.d.ts.map +1 -1
  17. package/lib/cjs/Interfaces.js.map +1 -1
  18. package/lib/esm/Exception.d.ts.map +1 -1
  19. package/lib/esm/Exception.js +2 -1
  20. package/lib/esm/Exception.js.map +1 -1
  21. package/lib/esm/Formatter/Format.d.ts +37 -41
  22. package/lib/esm/Formatter/Format.d.ts.map +1 -1
  23. package/lib/esm/Formatter/Format.js +116 -341
  24. package/lib/esm/Formatter/Format.js.map +1 -1
  25. package/lib/esm/Formatter/FormatEnums.d.ts +46 -1
  26. package/lib/esm/Formatter/FormatEnums.d.ts.map +1 -1
  27. package/lib/esm/Formatter/FormatEnums.js +205 -1
  28. package/lib/esm/Formatter/FormatEnums.js.map +1 -1
  29. package/lib/esm/Formatter/FormatterSpec.js +1 -1
  30. package/lib/esm/Formatter/FormatterSpec.js.map +1 -1
  31. package/lib/esm/Interfaces.d.ts +9 -1
  32. package/lib/esm/Interfaces.d.ts.map +1 -1
  33. package/lib/esm/Interfaces.js.map +1 -1
  34. package/package.json +5 -5
@@ -7,17 +7,14 @@
7
7
  */
8
8
  import { QuantityConstants } from "../Constants";
9
9
  import { QuantityError, QuantityStatus } from "../Exception";
10
- import { DecimalPrecision, FormatTraits, FormatType, FractionalPrecision, ScientificType, ShowSignOption } from "./FormatEnums";
10
+ import { DecimalPrecision, FormatTraits, formatTraitsToArray, FormatType, formatTypeToString, getTraitString, parseFormatTrait, parseFormatType, parsePrecision, parseScientificType, parseShowSignOption, scientificTypeToString, ShowSignOption, showSignOptionToString } from "./FormatEnums";
11
11
  import { isCustomFormatProps } from "./Interfaces";
12
12
  // cSpell:ignore ZERONORMALIZED, nosign, onlynegative, signalways, negativeparentheses
13
13
  // cSpell:ignore trailzeroes, keepsinglezero, zeroempty, keepdecimalpoint, applyrounding, fractiondash, showunitlabel, prependunitlabel, exponentonlynegative
14
- /** A class used to define the specifications for formatting quantity values. This class is typically loaded by reading [[FormatProps]].
14
+ /** A base Format class with shared properties and functionality between quantity and ecschema-metadata Format classes
15
15
  * @beta
16
16
  */
17
- export class Format {
18
- /** Constructor
19
- * @param name The name of a format specification. TODO: make optional or remove
20
- */
17
+ export class BaseFormat {
21
18
  constructor(name) {
22
19
  this._name = "";
23
20
  this._roundFactor = 0.0;
@@ -28,280 +25,139 @@ export class Format {
28
25
  this._thousandSeparator = QuantityConstants.LocaleSpecificThousandSeparator;
29
26
  this._uomSeparator = " "; // optional; default is " "; defined separator between magnitude and the unit
30
27
  this._stationSeparator = "+"; // optional; default is "+"
31
- this._formatTraits = 0x0;
28
+ this._formatTraits = FormatTraits.Uninitialized;
32
29
  this._spacer = " "; // optional; default is " "
33
30
  this._includeZero = true; // optional; default is true
34
31
  this._name = name;
35
32
  }
36
33
  get name() { return this._name; }
37
34
  get roundFactor() { return this._roundFactor; }
35
+ set roundFactor(roundFactor) { this._roundFactor = roundFactor; }
38
36
  get type() { return this._type; }
37
+ set type(formatType) { this._type = formatType; }
39
38
  get precision() { return this._precision; }
39
+ set precision(precision) { this._precision = precision; }
40
40
  get minWidth() { return this._minWidth; }
41
+ set minWidth(minWidth) { this._minWidth = minWidth; }
41
42
  get scientificType() { return this._scientificType; }
43
+ set scientificType(scientificType) { this._scientificType = scientificType; }
42
44
  get showSignOption() { return this._showSignOption; }
45
+ set showSignOption(showSignOption) { this._showSignOption = showSignOption; }
43
46
  get decimalSeparator() { return this._decimalSeparator; }
47
+ set decimalSeparator(decimalSeparator) { this._decimalSeparator = decimalSeparator; }
44
48
  get thousandSeparator() { return this._thousandSeparator; }
49
+ set thousandSeparator(thousandSeparator) { this._thousandSeparator = thousandSeparator; }
45
50
  get uomSeparator() { return this._uomSeparator; }
51
+ set uomSeparator(uomSeparator) { this._uomSeparator = uomSeparator; }
46
52
  get stationSeparator() { return this._stationSeparator; }
53
+ set stationSeparator(stationSeparator) { this._stationSeparator = stationSeparator; }
47
54
  get stationOffsetSize() { return this._stationOffsetSize; }
55
+ set stationOffsetSize(stationOffsetSize) { stationOffsetSize = this._stationOffsetSize = stationOffsetSize; }
48
56
  get formatTraits() { return this._formatTraits; }
57
+ set formatTraits(formatTraits) { this._formatTraits = formatTraits; }
49
58
  get spacer() { return this._spacer; }
59
+ set spacer(spacer) { this._spacer = spacer !== null && spacer !== void 0 ? spacer : this._spacer; }
50
60
  get includeZero() { return this._includeZero; }
51
- get units() { return this._units; }
52
- get hasUnits() { return this._units !== undefined && this._units.length > 0; }
53
- get customProps() { return this._customProps; }
54
- // parse and toString methods
55
- static scientificTypeToString(scientificType) {
56
- if (scientificType === ScientificType.Normalized)
57
- return "Normalized";
58
- else
59
- return "ZeroNormalized";
61
+ set includeZero(includeZero) { this._includeZero = includeZero !== null && includeZero !== void 0 ? 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
+ });
60
69
  }
61
- /** This method parses input string that is typically extracted for persisted JSON data and validates that the string is a valid ScientificType. Throws exception if not valid. */
62
- static parseScientificType(scientificType, formatName) {
63
- switch (scientificType.toLowerCase()) {
64
- case "normalized":
65
- return ScientificType.Normalized;
66
- case "zeronormalized":
67
- return ScientificType.ZeroNormalized;
68
- default:
69
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${formatName} has an invalid 'SCIENTIFIC_TYPE' attribute.`);
70
- }
70
+ /** This method returns true if the formatTrait is set in this Format object. */
71
+ hasFormatTraitSet(formatTrait) {
72
+ return (this._formatTraits & formatTrait) === formatTrait;
71
73
  }
72
- /** Method used when generating a JSON object that represents this Format. */
73
- static showSignOptionToString(showSign) {
74
- switch (showSign) {
75
- case ShowSignOption.NegativeParentheses:
76
- return "NegativeParentheses";
77
- case ShowSignOption.NoSign:
78
- return "NoSign";
79
- case ShowSignOption.OnlyNegative:
80
- return "OnlyNegative";
81
- case ShowSignOption.SignAlways:
82
- return "SignAlways";
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);
83
80
  }
84
- }
85
- /** This method parses input string that is typically extracted for persisted JSON data and validates that the string is a valid ShowSignOption. Throws exception if not valid. */
86
- static parseShowSignOption(showSignOption, formatName) {
87
- switch (showSignOption.toLowerCase()) {
88
- case "nosign":
89
- return ShowSignOption.NoSign;
90
- case "onlynegative":
91
- return ShowSignOption.OnlyNegative;
92
- case "signalways":
93
- return ShowSignOption.SignAlways;
94
- case "negativeparentheses":
95
- return ShowSignOption.NegativeParentheses;
96
- default:
97
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${formatName} has an invalid 'showSignOption' attribute.`);
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);
98
85
  }
99
- }
100
- static isFormatTraitSetInProps(formatProps, trait) {
101
- if (!formatProps.formatTraits)
102
- return false;
103
- const formatTraits = Array.isArray(formatProps.formatTraits) ? formatProps.formatTraits : formatProps.formatTraits.split(/,|;|\|/);
104
- const traitStr = Format.getTraitString(trait);
105
- return formatTraits.find((traitEntry) => traitStr === traitEntry) ? true : false;
106
- }
107
- /** Get string used in FormatProps */
108
- static getTraitString(trait) {
109
- switch (trait) {
110
- case FormatTraits.TrailZeroes:
111
- return "trailZeroes";
112
- case FormatTraits.KeepSingleZero:
113
- return "keepSingleZero";
114
- case FormatTraits.ZeroEmpty:
115
- return "zeroEmpty";
116
- case FormatTraits.KeepDecimalPoint:
117
- return "keepDecimalPoint";
118
- case FormatTraits.ApplyRounding:
119
- return "applyRounding";
120
- case FormatTraits.FractionDash:
121
- return "fractionDash";
122
- case FormatTraits.ShowUnitLabel:
123
- return "showUnitLabel";
124
- case FormatTraits.PrependUnitLabel:
125
- return "prependUnitLabel";
126
- case FormatTraits.Use1000Separator:
127
- return "use1000Separator";
128
- case FormatTraits.ExponentOnlyNegative:
129
- default:
130
- return "exponentOnlyNegative";
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;
131
91
  }
132
- }
133
- /** Method used when generating a JSON object that represents this Format. */
134
- static formatTraitsToArray(currentFormatTrait) {
135
- const formatTraitsArr = Array();
136
- if ((currentFormatTrait & FormatTraits.TrailZeroes) === FormatTraits.TrailZeroes)
137
- formatTraitsArr.push(Format.getTraitString(FormatTraits.TrailZeroes));
138
- if ((currentFormatTrait & FormatTraits.KeepSingleZero) === FormatTraits.KeepSingleZero)
139
- formatTraitsArr.push(Format.getTraitString(FormatTraits.KeepSingleZero));
140
- if ((currentFormatTrait & FormatTraits.ZeroEmpty) === FormatTraits.ZeroEmpty)
141
- formatTraitsArr.push(Format.getTraitString(FormatTraits.ZeroEmpty));
142
- if ((currentFormatTrait & FormatTraits.KeepDecimalPoint) === FormatTraits.KeepDecimalPoint)
143
- formatTraitsArr.push(Format.getTraitString(FormatTraits.KeepDecimalPoint));
144
- if ((currentFormatTrait & FormatTraits.ApplyRounding) === FormatTraits.ApplyRounding)
145
- formatTraitsArr.push(Format.getTraitString(FormatTraits.ApplyRounding));
146
- if ((currentFormatTrait & FormatTraits.FractionDash) === FormatTraits.FractionDash)
147
- formatTraitsArr.push(Format.getTraitString(FormatTraits.FractionDash));
148
- if ((currentFormatTrait & FormatTraits.ShowUnitLabel) === FormatTraits.ShowUnitLabel)
149
- formatTraitsArr.push(Format.getTraitString(FormatTraits.ShowUnitLabel));
150
- if ((currentFormatTrait & FormatTraits.PrependUnitLabel) === FormatTraits.PrependUnitLabel)
151
- formatTraitsArr.push(Format.getTraitString(FormatTraits.PrependUnitLabel));
152
- if ((currentFormatTrait & FormatTraits.Use1000Separator) === FormatTraits.Use1000Separator)
153
- formatTraitsArr.push(Format.getTraitString(FormatTraits.Use1000Separator));
154
- // NOTE: the formatter does not current use trait ExponentOnlyNegative
155
- if ((currentFormatTrait & FormatTraits.ExponentOnlyNegative) === FormatTraits.ExponentOnlyNegative)
156
- formatTraitsArr.push(Format.getTraitString(FormatTraits.ExponentOnlyNegative));
157
- return formatTraitsArr;
158
- }
159
- /** This method parses input string that is typically extracted for persisted JSON data and validates that the string is a valid FormatTrait. Throws exception if not valid. */
160
- static parseFormatTrait(stringToCheck, currentFormatTrait) {
161
- switch (stringToCheck.toLowerCase()) {
162
- case "trailzeroes":
163
- return currentFormatTrait | FormatTraits.TrailZeroes;
164
- case "keepsinglezero":
165
- return currentFormatTrait | FormatTraits.KeepSingleZero; // keep single when format type is Decimal
166
- case "zeroempty":
167
- return currentFormatTrait | FormatTraits.ZeroEmpty;
168
- case "keepdecimalpoint":
169
- return currentFormatTrait | FormatTraits.KeepDecimalPoint; // add decimal point when no fractional part and format type is Decimal
170
- case "applyrounding":
171
- return currentFormatTrait | FormatTraits.ApplyRounding;
172
- case "fractiondash":
173
- return currentFormatTrait | FormatTraits.FractionDash;
174
- case "showunitlabel":
175
- return currentFormatTrait | FormatTraits.ShowUnitLabel;
176
- case "prependunitlabel":
177
- return currentFormatTrait | FormatTraits.PrependUnitLabel;
178
- case "use1000separator":
179
- return currentFormatTrait | FormatTraits.Use1000Separator;
180
- case "exponentonlynegative":
181
- return currentFormatTrait | FormatTraits.ExponentOnlyNegative;
182
- default:
183
- throw new QuantityError(QuantityStatus.InvalidJson, `Format has an invalid 'formatTraits' option.`);
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;
184
96
  }
185
- }
186
- /** Get FormatTrait from entry in FormatProps */
187
- static parseFormatTraits(formatTraitsFromJson) {
188
- if (!formatTraitsFromJson)
189
- return undefined;
190
- const formatTraits = Array.isArray(formatTraitsFromJson) ? formatTraitsFromJson : formatTraitsFromJson.split(/,|;|\|/);
191
- let traits = 0;
192
- for (const traitStr of formatTraits) {
193
- traits = Format.parseFormatTrait(traitStr, traits);
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;
194
103
  }
195
- if (0 === traits)
196
- return undefined;
197
- return traits;
198
- }
199
- /** Method used when generating a JSON object that represents this Format. */
200
- static formatTypeToString(type) {
201
- switch (type) {
202
- case FormatType.Decimal:
203
- return "Decimal";
204
- case FormatType.Scientific:
205
- return "Scientific";
206
- case FormatType.Station:
207
- return "Station";
208
- case FormatType.Fractional:
209
- return "Fractional";
104
+ if (undefined !== formatProps.showSignOption) { // optional; default is "onlyNegative"
105
+ this._showSignOption = parseShowSignOption(formatProps.showSignOption, this.name);
210
106
  }
211
- }
212
- /** 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. */
213
- static parseFormatType(jsonObjType, formatName) {
214
- switch (jsonObjType.toLowerCase()) {
215
- case "decimal":
216
- return FormatType.Decimal;
217
- case "scientific":
218
- return FormatType.Scientific;
219
- case "station":
220
- return FormatType.Station;
221
- case "fractional":
222
- return FormatType.Fractional;
223
- default:
224
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${formatName} has an invalid 'type' attribute.`);
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
225
111
  }
226
- }
227
- /** This method validates the input value, that is typically extracted for persisted JSON data, is a valid DecimalPrecision. Throws exception if not valid. */
228
- static parseDecimalPrecision(jsonObjPrecision) {
229
- switch (jsonObjPrecision) {
230
- case 0:
231
- return DecimalPrecision.Zero;
232
- case 1:
233
- return DecimalPrecision.One;
234
- case 2:
235
- return DecimalPrecision.Two;
236
- case 3:
237
- return DecimalPrecision.Three;
238
- case 4:
239
- return DecimalPrecision.Four;
240
- case 5:
241
- return DecimalPrecision.Five;
242
- case 6:
243
- return DecimalPrecision.Six;
244
- case 7:
245
- return DecimalPrecision.Seven;
246
- case 8:
247
- return DecimalPrecision.Eight;
248
- case 9:
249
- return DecimalPrecision.Nine;
250
- case 10:
251
- return DecimalPrecision.Ten;
252
- case 11:
253
- return DecimalPrecision.Eleven;
254
- case 12:
255
- return DecimalPrecision.Twelve;
256
- default:
257
- throw new QuantityError(QuantityStatus.InvalidJson, `The 'precision' attribute must be an integer in the range 0-12.`);
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;
258
118
  }
259
- }
260
- /** This method validates the input value, that is typically extracted for persisted JSON data, is a valid FractionalPrecision. Throws exception if not valid. */
261
- static parseFractionalPrecision(jsonObjPrecision, formatName) {
262
- switch (jsonObjPrecision) {
263
- case 1:
264
- return FractionalPrecision.One;
265
- case 2:
266
- return FractionalPrecision.Two;
267
- case 4:
268
- return FractionalPrecision.Four;
269
- case 8:
270
- return FractionalPrecision.Eight;
271
- case 16:
272
- return FractionalPrecision.Sixteen;
273
- case 32:
274
- return FractionalPrecision.ThirtyTwo;
275
- case 64:
276
- return FractionalPrecision.SixtyFour;
277
- case 128:
278
- return FractionalPrecision.OneHundredTwentyEight;
279
- case 256:
280
- return FractionalPrecision.TwoHundredFiftySix;
281
- default:
282
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${formatName} has an invalid 'precision' attribute.`);
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;
283
125
  }
284
- }
285
- /** This method validates the input value, that is typically extracted for persisted JSON data, is a valid DecimalPrecision or FractionalPrecision. Throws exception if not valid. */
286
- static parsePrecision(precision, formatName, type) {
287
- switch (type) { // type must be decimal, fractional, scientific, or station
288
- case FormatType.Decimal:
289
- case FormatType.Scientific:
290
- case FormatType.Station:
291
- return Format.parseDecimalPrecision(precision);
292
- case FormatType.Fractional:
293
- return Format.parseFractionalPrecision(precision, formatName);
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;
294
139
  }
295
140
  }
296
- verifyFormatTraitsOptions(formatTraitsFromJson) {
297
- const formatTraits = (Array.isArray(formatTraitsFromJson)) ? formatTraitsFromJson : formatTraitsFromJson.split(/,|;|\|/);
298
- formatTraits.forEach((formatTraitsString) => {
299
- this._formatTraits = Format.parseFormatTrait(formatTraitsString, this.formatTraits);
300
- });
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);
301
151
  }
302
- /** This method returns true if the formatTrait is set in this Format object. */
303
- hasFormatTraitSet(formatTrait) {
304
- return (this._formatTraits & formatTrait) === formatTrait;
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;
305
161
  }
306
162
  async createUnit(unitsProvider, name, label) {
307
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
@@ -350,7 +206,7 @@ export class Format {
350
206
  newFormat._type = options.type;
351
207
  if (undefined !== (options === null || options === void 0 ? void 0 : options.precision)) {
352
208
  // ensure specified precision is valid
353
- const precision = Format.parsePrecision(options === null || options === void 0 ? void 0 : options.precision, "clone", newFormat._type);
209
+ const precision = parsePrecision(options === null || options === void 0 ? void 0 : options.precision, newFormat._type, newFormat.name);
354
210
  newFormat._precision = precision;
355
211
  }
356
212
  if (undefined !== (options === null || options === void 0 ? void 0 : options.primaryUnit)) {
@@ -366,94 +222,13 @@ export class Format {
366
222
  }
367
223
  return newFormat;
368
224
  }
369
- loadFormatProperties(jsonObj) {
370
- if (isCustomFormatProps(jsonObj))
371
- this._customProps = jsonObj.custom;
372
- if (undefined === jsonObj.type) // type is required
373
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} does not have the required 'type' attribute.`);
374
- if (typeof (jsonObj.type) !== "string")
375
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'type' attribute. It should be of type 'string'.`);
376
- this._type = Format.parseFormatType(jsonObj.type, this.name);
377
- if (undefined === jsonObj.precision) // precision is required
378
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} does not have the required 'precision' attribute.`);
379
- else if (typeof (jsonObj.precision) !== "number") // must be a number
380
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'precision' attribute. It should be of type 'number'.`);
381
- else if (!Number.isInteger(jsonObj.precision)) // must be an integer
382
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'precision' attribute. It should be an integer.`);
383
- this._precision = Format.parsePrecision(jsonObj.precision, this.name, this._type);
384
- if (this.type === FormatType.Scientific) {
385
- if (undefined === jsonObj.scientificType) // if format type is scientific and scientific type is undefined, throw
386
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has type 'Scientific' therefore attribute 'scientificType' is required.`);
387
- if (typeof (jsonObj.scientificType) !== "string")
388
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'scientificType' attribute. It should be of type 'string'.`);
389
- this._scientificType = Format.parseScientificType(jsonObj.scientificType.toLowerCase(), this.name);
390
- }
391
- if (this.type === FormatType.Station) {
392
- if (undefined === jsonObj.stationOffsetSize)
393
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has type 'Station' therefore attribute 'stationOffsetSize' is required.`);
394
- if (typeof (jsonObj.stationOffsetSize) !== "number")
395
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'stationOffsetSize' attribute. It should be of type 'number'.`);
396
- if (!Number.isInteger(jsonObj.stationOffsetSize) || jsonObj.stationOffsetSize <= 0) // must be a positive int > 0
397
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'stationOffsetSize' attribute. It should be a positive integer.`);
398
- this._stationOffsetSize = jsonObj.stationOffsetSize;
399
- }
400
- if (undefined !== jsonObj.roundFactor) { // optional; default is 0.0
401
- if (typeof (jsonObj.roundFactor) !== "number")
402
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'roundFactor' attribute. It should be of type 'number'.`);
403
- if (jsonObj.roundFactor !== this.roundFactor) // if roundFactor isn't default value of 0.0, reassign roundFactor variable
404
- this._roundFactor = jsonObj.roundFactor;
405
- }
406
- if (undefined !== jsonObj.minWidth) { // optional
407
- if (typeof (jsonObj.minWidth) !== "number")
408
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'minWidth' attribute. It should be of type 'number'.`);
409
- if (!Number.isInteger(jsonObj.minWidth) || jsonObj.minWidth < 0) // must be a positive int
410
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'minWidth' attribute. It should be a positive integer.`);
411
- this._minWidth = jsonObj.minWidth;
412
- }
413
- if (undefined !== jsonObj.showSignOption) { // optional; default is "onlyNegative"
414
- if (typeof (jsonObj.showSignOption) !== "string")
415
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'showSignOption' attribute. It should be of type 'string'.`);
416
- this._showSignOption = Format.parseShowSignOption(jsonObj.showSignOption, this.name);
417
- }
418
- if (undefined !== jsonObj.formatTraits && jsonObj.formatTraits.length !== 0) { // FormatTraits is optional
419
- if (!Array.isArray(jsonObj.formatTraits) && typeof (jsonObj.formatTraits) !== "string") // must be either an array of strings or a string
420
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'formatTraits' attribute. It should be of type 'string' or 'string[]'.`);
421
- this.verifyFormatTraitsOptions(jsonObj.formatTraits); // check that all of the options for formatTraits are valid. If now, throw
422
- }
423
- if (undefined !== jsonObj.decimalSeparator) { // optional
424
- if (typeof (jsonObj.decimalSeparator) !== "string") // not a string or not a one character string
425
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'decimalSeparator' attribute. It should be of type 'string'.`);
426
- if (jsonObj.decimalSeparator.length !== 1)
427
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'decimalSeparator' attribute. It must be a one character string.`);
428
- this._decimalSeparator = jsonObj.decimalSeparator;
429
- }
430
- if (undefined !== jsonObj.thousandSeparator) { // optional
431
- if (typeof (jsonObj.thousandSeparator) !== "string")
432
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'thousandSeparator' attribute. It should be of type 'string'.`);
433
- if (jsonObj.thousandSeparator.length !== 1)
434
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'thousandSeparator' attribute. It must be a one character string.`);
435
- this._thousandSeparator = jsonObj.thousandSeparator;
436
- }
437
- if (undefined !== jsonObj.uomSeparator) { // optional; default is " "
438
- if (typeof (jsonObj.uomSeparator) !== "string")
439
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'uomSeparator' attribute. It should be of type 'string'.`);
440
- if (jsonObj.uomSeparator.length < 0 || jsonObj.uomSeparator.length > 1)
441
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'uomSeparator' attribute. It must be empty or a string with a single character.`);
442
- this._uomSeparator = jsonObj.uomSeparator;
443
- }
444
- if (undefined !== jsonObj.stationSeparator) { // optional; default is "+"
445
- if (typeof (jsonObj.stationSeparator) !== "string")
446
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'stationSeparator' attribute. It should be of type 'string'.`);
447
- if (jsonObj.stationSeparator.length !== 1)
448
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'stationSeparator' attribute. It must be a one character string.`);
449
- this._stationSeparator = jsonObj.stationSeparator;
450
- }
451
- }
452
225
  /**
453
226
  * Populates this Format with the values from the provided.
454
227
  */
455
228
  async fromJSON(unitsProvider, jsonObj) {
456
229
  this.loadFormatProperties(jsonObj);
230
+ if (isCustomFormatProps(jsonObj))
231
+ this._customProps = jsonObj.custom;
457
232
  if (undefined !== jsonObj.composite) { // optional
458
233
  this._units = new Array();
459
234
  if (jsonObj.composite.includeZero !== undefined) {
@@ -464,8 +239,8 @@ export class Format {
464
239
  if (jsonObj.composite.spacer !== undefined) { // spacer must be a string IF it is defined
465
240
  if (typeof (jsonObj.composite.spacer) !== "string")
466
241
  throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has a Composite with an invalid 'spacer' attribute. It must be of type 'string'.`);
467
- if (jsonObj.composite.spacer.length < 0 || jsonObj.composite.spacer.length > 1)
468
- throw new QuantityError(QuantityStatus.InvalidJson, `The Format ${this.name} has a Composite with an invalid 'spacer' attribute. It must be empty or a string with a single character.`);
242
+ if (jsonObj.composite.spacer.length > 1)
243
+ 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.`);
469
244
  this._spacer = jsonObj.composite.spacer;
470
245
  }
471
246
  if (jsonObj.composite.units !== undefined) { // if composite is defined, it must be an array with 1-4 units
@@ -515,32 +290,32 @@ export class Format {
515
290
  }
516
291
  if (this.customProps)
517
292
  return {
518
- type: Format.formatTypeToString(this.type),
293
+ type: formatTypeToString(this.type),
519
294
  precision: this.precision,
520
295
  roundFactor: this.roundFactor,
521
296
  minWidth: this.minWidth,
522
- showSignOption: Format.showSignOptionToString(this.showSignOption),
523
- formatTraits: Format.formatTraitsToArray(this.formatTraits),
297
+ showSignOption: showSignOptionToString(this.showSignOption),
298
+ formatTraits: formatTraitsToArray(this.formatTraits),
524
299
  decimalSeparator: this.decimalSeparator,
525
300
  thousandSeparator: this.thousandSeparator,
526
301
  uomSeparator: this.uomSeparator,
527
- scientificType: this.scientificType ? Format.scientificTypeToString(this.scientificType) : undefined,
302
+ scientificType: this.scientificType ? scientificTypeToString(this.scientificType) : undefined,
528
303
  stationOffsetSize: this.stationOffsetSize,
529
304
  stationSeparator: this.stationSeparator,
530
305
  composite,
531
306
  custom: this.customProps,
532
307
  };
533
308
  return {
534
- type: Format.formatTypeToString(this.type),
309
+ type: formatTypeToString(this.type),
535
310
  precision: this.precision,
536
311
  roundFactor: this.roundFactor,
537
312
  minWidth: this.minWidth,
538
- showSignOption: Format.showSignOptionToString(this.showSignOption),
539
- formatTraits: Format.formatTraitsToArray(this.formatTraits),
313
+ showSignOption: showSignOptionToString(this.showSignOption),
314
+ formatTraits: formatTraitsToArray(this.formatTraits),
540
315
  decimalSeparator: this.decimalSeparator,
541
316
  thousandSeparator: this.thousandSeparator,
542
317
  uomSeparator: this.uomSeparator,
543
- scientificType: this.scientificType ? Format.scientificTypeToString(this.scientificType) : undefined,
318
+ scientificType: this.scientificType ? scientificTypeToString(this.scientificType) : undefined,
544
319
  stationOffsetSize: this.stationOffsetSize,
545
320
  stationSeparator: this.stationSeparator,
546
321
  composite,