@itwin/rpcinterface-full-stack-tests 5.6.0-dev.8 → 5.7.0-dev.1

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.
@@ -81566,7 +81566,7 @@ class TextStyleSettings {
81566
81566
  listMarker;
81567
81567
  /** The frame settings of the [[TextAnnotation]]. */
81568
81568
  frame;
81569
- /** The margins to surround the document content. */
81569
+ /** Multiplier used to calculate the margins to surround the document content. */
81570
81570
  margins;
81571
81571
  /** The alignment of the text content. */
81572
81572
  justification;
@@ -100347,6 +100347,18 @@ class JsonParser extends _AbstractParser__WEBPACK_IMPORTED_MODULE_2__.AbstractPa
100347
100347
  throw new _Exception__WEBPACK_IMPORTED_MODULE_0__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_0__.ECSchemaStatus.InvalidECJson, `The Format ${this._currentItemFullName} has an invalid 'uomSeparator' attribute. It should be of type 'string'.`);
100348
100348
  if (undefined !== jsonObj.scientificType && typeof (jsonObj.scientificType) !== "string")
100349
100349
  throw new _Exception__WEBPACK_IMPORTED_MODULE_0__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_0__.ECSchemaStatus.InvalidECJson, `The Format ${this._currentItemFullName} has an invalid 'scientificType' attribute. It should be of type 'string'.`);
100350
+ if (undefined !== jsonObj.ratioType && typeof (jsonObj.ratioType) !== "string")
100351
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_0__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_0__.ECSchemaStatus.InvalidECJson, `The Format ${this._currentItemFullName} has an invalid 'ratioType' attribute. It should be of type 'string'.`);
100352
+ if (undefined !== jsonObj.ratioSeparator && typeof (jsonObj.ratioSeparator) !== "string")
100353
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_0__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_0__.ECSchemaStatus.InvalidECJson, `The Format ${this._currentItemFullName} has an invalid 'ratioSeparator' attribute. It should be of type 'string'.`);
100354
+ if (undefined !== jsonObj.ratioFormatType && typeof (jsonObj.ratioFormatType) !== "string")
100355
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_0__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_0__.ECSchemaStatus.InvalidECJson, `The Format ${this._currentItemFullName} has an invalid 'ratioFormatType' attribute. It should be of type 'string'.`);
100356
+ // Validate EC version if ratio properties exist - they require EC version 3.3+
100357
+ if (jsonObj.ratioType !== undefined || jsonObj.ratioSeparator !== undefined || jsonObj.ratioFormatType !== undefined) {
100358
+ if (this._ecSpecVersion === undefined || this._ecSpecVersion.readVersion < 3 || (this._ecSpecVersion.readVersion === 3 && this._ecSpecVersion.writeVersion < 3)) {
100359
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_0__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_0__.ECSchemaStatus.InvalidECJson, `The Format ${this._currentItemFullName} has ratio properties that require EC version 3.3 or newer.`);
100360
+ }
100361
+ }
100350
100362
  if (undefined !== jsonObj.stationOffsetSize && typeof (jsonObj.stationOffsetSize) !== "number")
100351
100363
  throw new _Exception__WEBPACK_IMPORTED_MODULE_0__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_0__.ECSchemaStatus.InvalidECJson, `The Format ${this._currentItemFullName} has an invalid 'stationOffsetSize' attribute. It should be of type 'number'.`);
100352
100364
  if (undefined !== jsonObj.stationSeparator && typeof (jsonObj.stationSeparator) !== "string")
@@ -101060,6 +101072,15 @@ class XmlParser extends _AbstractParser__WEBPACK_IMPORTED_MODULE_5__.AbstractPar
101060
101072
  const thousandSeparator = this.getOptionalAttribute(xmlElement, "thousandSeparator");
101061
101073
  const uomSeparator = this.getOptionalAttribute(xmlElement, "uomSeparator");
101062
101074
  const scientificType = this.getOptionalAttribute(xmlElement, "scientificType");
101075
+ const ratioType = this.getOptionalAttribute(xmlElement, "ratioType");
101076
+ const ratioSeparator = this.getOptionalAttribute(xmlElement, "ratioSeparator");
101077
+ const ratioFormatType = this.getOptionalAttribute(xmlElement, "ratioFormatType");
101078
+ // Validate EC version if ratio properties exist - they require EC version 3.3+
101079
+ if (ratioType !== undefined || ratioSeparator !== undefined || ratioFormatType !== undefined) {
101080
+ if (this._ecSpecVersion === undefined || this._ecSpecVersion.readVersion < 3 || (this._ecSpecVersion.readVersion === 3 && this._ecSpecVersion.writeVersion < 3)) {
101081
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaStatus.InvalidSchemaXML, `The Format ${this._currentItemFullName} has ratio properties that require EC version 3.3 or newer.`);
101082
+ }
101083
+ }
101063
101084
  const stationOffsetSize = this.getOptionalIntAttribute(xmlElement, "stationOffsetSize", `The Format ${this._currentItemFullName} has an invalid 'stationOffsetSize' attribute. It should be a numeric value.`);
101064
101085
  const stationSeparator = this.getOptionalAttribute(xmlElement, "stationSeparator");
101065
101086
  let composite;
@@ -101102,6 +101123,9 @@ class XmlParser extends _AbstractParser__WEBPACK_IMPORTED_MODULE_5__.AbstractPar
101102
101123
  thousandSeparator,
101103
101124
  uomSeparator,
101104
101125
  scientificType,
101126
+ ratioType,
101127
+ ratioSeparator,
101128
+ ratioFormatType,
101105
101129
  stationOffsetSize,
101106
101130
  stationSeparator,
101107
101131
  composite,
@@ -102845,7 +102869,7 @@ class SchemaFormatsProvider {
102845
102869
  // If no matching presentation format was found, use persistence unit format if it matches unit system.
102846
102870
  const persistenceUnit = await kindOfQuantity.persistenceUnit;
102847
102871
  const persistenceUnitSystem = await persistenceUnit?.unitSystem;
102848
- if (persistenceUnitSystem && unitSystemMatchers.some((matcher) => matcher(persistenceUnitSystem))) {
102872
+ if (persistenceUnit && persistenceUnitSystem && unitSystemMatchers.some((matcher) => matcher(persistenceUnitSystem))) {
102849
102873
  this._formatsRetrieved.add(itemKey.fullName);
102850
102874
  const props = getPersistenceUnitFormatProps(persistenceUnit);
102851
102875
  return this.convertToFormatDefinition(props, kindOfQuantity);
@@ -105442,6 +105466,7 @@ __webpack_require__.r(__webpack_exports__);
105442
105466
 
105443
105467
 
105444
105468
 
105469
+ const loggingCategory = "ECClass";
105445
105470
  /**
105446
105471
  * A common abstract class for all of the ECClass types.
105447
105472
  * @public @preview
@@ -105496,7 +105521,13 @@ class ECClass extends _SchemaItem__WEBPACK_IMPORTED_MODULE_9__.SchemaItem {
105496
105521
  async getDerivedClasses() {
105497
105522
  const derivedClasses = [];
105498
105523
  for (const derivedClassKey of this.schema.context.classHierarchy.getDerivedClassKeys(this.key)) {
105499
- const derivedClass = await this.schema.context.getSchemaItem(derivedClassKey, ECClass);
105524
+ let derivedClass = await this.schema.getItem(derivedClassKey.name, ECClass); // if the derived class is in the same schema this will get it without going to the context
105525
+ if (derivedClass) {
105526
+ derivedClasses.push(derivedClass);
105527
+ continue;
105528
+ }
105529
+ _itwin_core_bentley__WEBPACK_IMPORTED_MODULE_0__.Logger.logInfo(loggingCategory, `Derived class ${derivedClassKey.name} not found in schema ${this.schema.name}, looking in schema context.`);
105530
+ derivedClass = await this.schema.context.getSchemaItem(derivedClassKey, ECClass);
105500
105531
  if (derivedClass)
105501
105532
  derivedClasses.push(derivedClass);
105502
105533
  }
@@ -105884,18 +105915,56 @@ class ECClass extends _SchemaItem__WEBPACK_IMPORTED_MODULE_9__.SchemaItem {
105884
105915
  */
105885
105916
  async *getAllBaseClasses() {
105886
105917
  for (const baseClassKey of this.schema.context.classHierarchy.getBaseClassKeys(this.key)) {
105887
- const baseClass = await this.schema.lookupItem(baseClassKey, ECClass);
105918
+ const baseClass = await this.getClassFromReferencesRecursively(baseClassKey); // Search in schema ref tree all the way to the top
105888
105919
  if (baseClass)
105889
105920
  yield baseClass;
105890
105921
  }
105891
105922
  }
105923
+ /**
105924
+ * gets a class from this schema or its references recursively using the item key
105925
+ * @param itemKey
105926
+ * @returns ECClass if it could be found, undefined otherwise
105927
+ * @internal
105928
+ */
105929
+ async getClassFromReferencesRecursively(itemKey) {
105930
+ const schemaList = [this.schema];
105931
+ while (schemaList.length > 0) {
105932
+ const currentSchema = schemaList.shift();
105933
+ if (currentSchema.schemaKey.compareByName(itemKey.schemaKey)) {
105934
+ const baseClass = await currentSchema.getItem(itemKey.name, ECClass);
105935
+ schemaList.splice(0); // clear the list
105936
+ return baseClass;
105937
+ }
105938
+ schemaList.push(...currentSchema.references);
105939
+ }
105940
+ return undefined;
105941
+ }
105892
105942
  *getAllBaseClassesSync() {
105893
105943
  for (const baseClassKey of this.schema.context.classHierarchy.getBaseClassKeys(this.key)) {
105894
- const baseClass = this.schema.lookupItemSync(baseClassKey, ECClass);
105944
+ const baseClass = this.getClassFromReferencesRecursivelySync(baseClassKey); // Search in schema ref tree all the way to the top
105895
105945
  if (baseClass)
105896
105946
  yield baseClass;
105897
105947
  }
105898
105948
  }
105949
+ /**
105950
+ * gets a class from this schema or its references recursively using the item key synchronously
105951
+ * @param itemKey
105952
+ * @returns ECClass if it could be found, undefined otherwise
105953
+ * @internal
105954
+ */
105955
+ getClassFromReferencesRecursivelySync(itemKey) {
105956
+ const schemaList = [this.schema];
105957
+ while (schemaList.length > 0) {
105958
+ const currentSchema = schemaList.shift();
105959
+ if (currentSchema.schemaKey.compareByName(itemKey.schemaKey)) {
105960
+ const baseClass = currentSchema.getItemSync(itemKey.name, ECClass);
105961
+ schemaList.splice(0); // clear the list
105962
+ return baseClass;
105963
+ }
105964
+ schemaList.push(...currentSchema.references);
105965
+ }
105966
+ return undefined;
105967
+ }
105899
105968
  /**
105900
105969
  *
105901
105970
  * @param cache
@@ -107031,6 +107100,9 @@ class Format extends _SchemaItem__WEBPACK_IMPORTED_MODULE_5__.SchemaItem {
107031
107100
  get stationSeparator() { return this._base.stationSeparator; }
107032
107101
  get stationOffsetSize() { return this._base.stationOffsetSize; }
107033
107102
  get stationBaseFactor() { return this._base.stationBaseFactor; }
107103
+ get ratioType() { return this._base.ratioType; }
107104
+ get ratioSeparator() { return this._base.ratioSeparator; }
107105
+ get ratioFormatType() { return this._base.ratioFormatType; }
107034
107106
  get formatTraits() { return this._base.formatTraits; }
107035
107107
  get spacer() { return this._base.spacer; }
107036
107108
  get includeZero() { return this._base.includeZero; }
@@ -107052,10 +107124,13 @@ class Format extends _SchemaItem__WEBPACK_IMPORTED_MODULE_5__.SchemaItem {
107052
107124
  addUnit(unit, label) {
107053
107125
  if (undefined === this._units)
107054
107126
  this._units = [];
107055
- else { // Validate that a duplicate is not added.
107056
- for (const existingUnit of this._units) {
107057
- if (unit.fullName.toLowerCase() === existingUnit[0].fullName.toLowerCase())
107058
- throw new _Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaStatus.InvalidECJson, `The Format ${this.fullName} has duplicate units, '${unit.fullName}'.`); // TODO: Validation - this should be a validation error not a hard failure.
107127
+ else {
107128
+ const isDuplicateAllowed = this.type === _itwin_core_quantity__WEBPACK_IMPORTED_MODULE_3__.FormatType.Ratio;
107129
+ if (!isDuplicateAllowed) {
107130
+ for (const existingUnit of this._units) {
107131
+ if (unit.fullName.toLowerCase() === existingUnit[0].fullName.toLowerCase())
107132
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaStatus.InvalidECJson, `The Format ${this.fullName} has duplicate units, '${unit.fullName}'.`); // TODO: Validation - this should be a validation error not a hard failure.
107133
+ }
107059
107134
  }
107060
107135
  }
107061
107136
  this._units.push([unit, label]);
@@ -107080,37 +107155,87 @@ class Format extends _SchemaItem__WEBPACK_IMPORTED_MODULE_5__.SchemaItem {
107080
107155
  if (formatProps.composite.units.length <= 0 || formatProps.composite.units.length > 4)
107081
107156
  throw new _Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaStatus.InvalidECJson, `The Format ${this.fullName} has an invalid 'Composite' attribute. It should have 1-4 units.`);
107082
107157
  }
107158
+ // For Ratio formats: validate that composite is provided
107159
+ if (this.type === _itwin_core_quantity__WEBPACK_IMPORTED_MODULE_3__.FormatType.Ratio) {
107160
+ const hasComposite = undefined !== formatProps.composite && formatProps.composite.units.length > 0;
107161
+ if (!hasComposite) {
107162
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaStatus.InvalidECJson, `The Format ${this.fullName} is 'Ratio' type and must have 'composite' units.`);
107163
+ }
107164
+ }
107083
107165
  }
107084
107166
  fromJSONSync(formatProps) {
107085
107167
  super.fromJSONSync(formatProps);
107086
107168
  this.typecheck(formatProps);
107087
- if (undefined === formatProps.composite)
107088
- return;
107089
- // Units are separated from the rest of the deserialization because of the need to have separate sync and async implementation
107090
- for (const unit of formatProps.composite.units) {
107091
- const newUnit = this.schema.lookupItemSync(unit.name);
107092
- if (undefined === newUnit || (!_Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(newUnit) && !_InvertedUnit__WEBPACK_IMPORTED_MODULE_4__.InvertedUnit.isInvertedUnit(newUnit)))
107093
- throw new _Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaStatus.InvalidECJson, ``);
107094
- if (_Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(newUnit))
107095
- this.addUnit(new _DelayedPromise__WEBPACK_IMPORTED_MODULE_7__.DelayedPromiseWithProps(newUnit.key, async () => newUnit), unit.label);
107096
- else if (_InvertedUnit__WEBPACK_IMPORTED_MODULE_4__.InvertedUnit.isInvertedUnit(newUnit))
107097
- this.addUnit(new _DelayedPromise__WEBPACK_IMPORTED_MODULE_7__.DelayedPromiseWithProps(newUnit.key, async () => newUnit), unit.label);
107169
+ // Process composite units
107170
+ if (undefined !== formatProps.composite) {
107171
+ for (const unit of formatProps.composite.units) {
107172
+ const newUnit = this.schema.lookupItemSync(unit.name);
107173
+ if (undefined === newUnit || (!_Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(newUnit) && !_InvertedUnit__WEBPACK_IMPORTED_MODULE_4__.InvertedUnit.isInvertedUnit(newUnit)))
107174
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaStatus.InvalidECJson, ``);
107175
+ const lazyUnit = _Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(newUnit)
107176
+ ? new _DelayedPromise__WEBPACK_IMPORTED_MODULE_7__.DelayedPromiseWithProps(newUnit.key, async () => newUnit)
107177
+ : new _DelayedPromise__WEBPACK_IMPORTED_MODULE_7__.DelayedPromiseWithProps(newUnit.key, async () => newUnit);
107178
+ this.addUnit(lazyUnit, unit.label);
107179
+ }
107180
+ // For Ratio formats with 2 units: validate both units have the same phenomenon
107181
+ if (this.type === _itwin_core_quantity__WEBPACK_IMPORTED_MODULE_3__.FormatType.Ratio && this._units && this._units.length === 2) {
107182
+ const unit1Item = this.schema.lookupItemSync(this._units[0][0].fullName);
107183
+ const unit2Item = this.schema.lookupItemSync(this._units[1][0].fullName);
107184
+ if (!unit1Item || !unit2Item || (!_Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(unit1Item) && !_InvertedUnit__WEBPACK_IMPORTED_MODULE_4__.InvertedUnit.isInvertedUnit(unit1Item)) || (!_Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(unit2Item) && !_InvertedUnit__WEBPACK_IMPORTED_MODULE_4__.InvertedUnit.isInvertedUnit(unit2Item)))
107185
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaStatus.InvalidECJson, `The Format ${this.fullName} has invalid units.`);
107186
+ const getPhenomenon = (unitItem) => {
107187
+ if (_Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(unitItem)) {
107188
+ return unitItem.phenomenon;
107189
+ }
107190
+ const invertsUnit = unitItem.invertsUnit;
107191
+ if (invertsUnit) {
107192
+ const resolvedUnit = this.schema.lookupItemSync(invertsUnit.fullName);
107193
+ return resolvedUnit && _Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(resolvedUnit) ? resolvedUnit.phenomenon : undefined;
107194
+ }
107195
+ return undefined;
107196
+ };
107197
+ const phenomenon1 = getPhenomenon(unit1Item);
107198
+ const phenomenon2 = getPhenomenon(unit2Item);
107199
+ if (phenomenon1?.fullName !== phenomenon2?.fullName) {
107200
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaStatus.InvalidECJson, `The Format ${this.fullName} has 2-unit composite with different phenomena. Both units must have the same phenomenon.`);
107201
+ }
107202
+ }
107098
107203
  }
107099
107204
  }
107100
107205
  async fromJSON(formatProps) {
107101
107206
  await super.fromJSON(formatProps);
107102
107207
  this.typecheck(formatProps);
107103
- if (undefined === formatProps.composite)
107104
- return;
107105
- // Units are separated from the rest of the deserialization because of the need to have separate sync and async implementation
107106
- for (const unit of formatProps.composite.units) {
107107
- const newUnit = await this.schema.lookupItem(unit.name);
107108
- if (undefined === newUnit || (!_Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(newUnit) && !_InvertedUnit__WEBPACK_IMPORTED_MODULE_4__.InvertedUnit.isInvertedUnit(newUnit)))
107109
- throw new _Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaStatus.InvalidECJson, ``);
107110
- if (_Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(newUnit))
107111
- this.addUnit(new _DelayedPromise__WEBPACK_IMPORTED_MODULE_7__.DelayedPromiseWithProps(newUnit.key, async () => newUnit), unit.label);
107112
- else if (_InvertedUnit__WEBPACK_IMPORTED_MODULE_4__.InvertedUnit.isInvertedUnit(newUnit))
107113
- this.addUnit(new _DelayedPromise__WEBPACK_IMPORTED_MODULE_7__.DelayedPromiseWithProps(newUnit.key, async () => newUnit), unit.label);
107208
+ // Process composite units
107209
+ if (undefined !== formatProps.composite) {
107210
+ for (const unit of formatProps.composite.units) {
107211
+ const newUnit = await this.schema.lookupItem(unit.name);
107212
+ if (undefined === newUnit || (!_Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(newUnit) && !_InvertedUnit__WEBPACK_IMPORTED_MODULE_4__.InvertedUnit.isInvertedUnit(newUnit)))
107213
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaStatus.InvalidECJson, ``);
107214
+ const lazyUnit = _Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(newUnit)
107215
+ ? new _DelayedPromise__WEBPACK_IMPORTED_MODULE_7__.DelayedPromiseWithProps(newUnit.key, async () => newUnit)
107216
+ : new _DelayedPromise__WEBPACK_IMPORTED_MODULE_7__.DelayedPromiseWithProps(newUnit.key, async () => newUnit);
107217
+ this.addUnit(lazyUnit, unit.label);
107218
+ }
107219
+ // For Ratio formats with 2 units: validate both units have the same phenomenon
107220
+ if (this.type === _itwin_core_quantity__WEBPACK_IMPORTED_MODULE_3__.FormatType.Ratio && this._units && this._units.length === 2) {
107221
+ const unit1Item = await this.schema.lookupItem(this._units[0][0].fullName);
107222
+ const unit2Item = await this.schema.lookupItem(this._units[1][0].fullName);
107223
+ if (!unit1Item || !unit2Item || (!_Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(unit1Item) && !_InvertedUnit__WEBPACK_IMPORTED_MODULE_4__.InvertedUnit.isInvertedUnit(unit1Item)) || (!_Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(unit2Item) && !_InvertedUnit__WEBPACK_IMPORTED_MODULE_4__.InvertedUnit.isInvertedUnit(unit2Item)))
107224
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaStatus.InvalidECJson, `The Format ${this.fullName} has invalid units.`);
107225
+ // Helper to extract phenomenon from Unit or InvertedUnit
107226
+ const getPhenomenon = async (unitItem) => {
107227
+ if (_Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(unitItem)) {
107228
+ return unitItem.phenomenon;
107229
+ }
107230
+ const invertsUnit = await unitItem.invertsUnit;
107231
+ return invertsUnit ? invertsUnit.phenomenon : undefined;
107232
+ };
107233
+ const phenomenon1 = await getPhenomenon(unit1Item);
107234
+ const phenomenon2 = await getPhenomenon(unit2Item);
107235
+ if (phenomenon1?.fullName !== phenomenon2?.fullName) {
107236
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaStatus.InvalidECJson, `The Format ${this.fullName} has 2-unit composite with different phenomena. Both units must have the same phenomenon.`);
107237
+ }
107238
+ }
107114
107239
  }
107115
107240
  }
107116
107241
  /**
@@ -107147,6 +107272,15 @@ class Format extends _SchemaItem__WEBPACK_IMPORTED_MODULE_5__.SchemaItem {
107147
107272
  if (" " !== this.stationSeparator)
107148
107273
  schemaJson.stationSeparator = this.stationSeparator;
107149
107274
  }
107275
+ // Only include ratio properties for EC version 3.3+
107276
+ if (_itwin_core_quantity__WEBPACK_IMPORTED_MODULE_3__.FormatType.Ratio === this.type && this.schema.originalECSpecMajorVersion === 3 && this.schema.originalECSpecMinorVersion !== undefined && this.schema.originalECSpecMinorVersion >= 3) {
107277
+ if (undefined !== this.ratioType)
107278
+ schemaJson.ratioType = this.ratioType;
107279
+ if (undefined !== this.ratioSeparator)
107280
+ schemaJson.ratioSeparator = this.ratioSeparator;
107281
+ if (undefined !== this.ratioFormatType)
107282
+ schemaJson.ratioFormatType = this.ratioFormatType;
107283
+ }
107150
107284
  if (undefined === this.units)
107151
107285
  return schemaJson;
107152
107286
  schemaJson.composite = {};
@@ -107178,6 +107312,15 @@ class Format extends _SchemaItem__WEBPACK_IMPORTED_MODULE_5__.SchemaItem {
107178
107312
  itemElement.setAttribute("minWidth", this.minWidth.toString());
107179
107313
  if (undefined !== this.scientificType)
107180
107314
  itemElement.setAttribute("scientificType", this.scientificType);
107315
+ // Only include ratio properties for EC version 3.3+
107316
+ if (this.schema.originalECSpecMajorVersion === 3 && this.schema.originalECSpecMinorVersion !== undefined && this.schema.originalECSpecMinorVersion >= 3) {
107317
+ if (undefined !== this.ratioType)
107318
+ itemElement.setAttribute("ratioType", this.ratioType);
107319
+ if (undefined !== this.ratioSeparator)
107320
+ itemElement.setAttribute("ratioSeparator", this.ratioSeparator);
107321
+ if (undefined !== this.ratioFormatType)
107322
+ itemElement.setAttribute("ratioFormatType", this.ratioFormatType);
107323
+ }
107181
107324
  if (undefined !== this.stationOffsetSize)
107182
107325
  itemElement.setAttribute("stationOffsetSize", this.stationOffsetSize.toString());
107183
107326
  const formatTraits = (0,_itwin_core_quantity__WEBPACK_IMPORTED_MODULE_3__.formatTraitsToArray)(this.formatTraits);
@@ -107924,6 +108067,9 @@ class OverrideFormat {
107924
108067
  get type() { return this.parent.type; }
107925
108068
  get minWidth() { return this.parent.minWidth; }
107926
108069
  get scientificType() { return this.parent.scientificType; }
108070
+ get ratioType() { return this.parent.ratioType; }
108071
+ get ratioSeparator() { return this.parent.ratioSeparator; }
108072
+ get ratioFormatType() { return this.parent.ratioFormatType; }
107927
108073
  get showSignOption() { return this.parent.showSignOption; }
107928
108074
  get decimalSeparator() { return this.parent.decimalSeparator; }
107929
108075
  get thousandSeparator() { return this.parent.thousandSeparator; }
@@ -107948,7 +108094,7 @@ class OverrideFormat {
107948
108094
  for (const [unit, unitLabel] of this._units) {
107949
108095
  const unitSchema = koqSchema.context.getSchemaSync(unit.schemaKey);
107950
108096
  if (unitSchema === undefined)
107951
- throw new _Exception__WEBPACK_IMPORTED_MODULE_3__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_3__.ECSchemaStatus.InvalidECJson, `The unit schema ${unit.schemaKey} is not found in the context.`);
108097
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_3__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_3__.ECSchemaStatus.InvalidECJson, `The unit schema ${unit.schemaKey.toString()} is not found in the context.`);
107952
108098
  fullName += "[";
107953
108099
  fullName += _Deserialization_XmlSerializationUtils__WEBPACK_IMPORTED_MODULE_0__.XmlSerializationUtils.createXmlTypedName(koqSchema, unitSchema, unit.name);
107954
108100
  if (unitLabel !== undefined)
@@ -144794,7 +144940,9 @@ function createMeshArgs(mesh) {
144794
144940
  if (!mesh.triangles || mesh.triangles.isEmpty || mesh.points.length === 0)
144795
144941
  return undefined;
144796
144942
  const texture = mesh.displayParams.textureMapping?.texture;
144797
- const textureMapping = texture && mesh.uvParams.length > 0 ? { texture, uvParams: mesh.uvParams } : undefined;
144943
+ const useConstantLod = mesh.displayParams.textureMapping?.params?.useConstantLod;
144944
+ const constantLodParams = mesh.displayParams.textureMapping?.params?.constantLodParams;
144945
+ const textureMapping = texture && mesh.uvParams.length > 0 ? { texture, uvParams: mesh.uvParams, useConstantLod, constantLodParams } : undefined;
144798
144946
  const colors = new _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.ColorIndex();
144799
144947
  mesh.colorMap.toColorIndex(colors, mesh.colors);
144800
144948
  const features = new _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.FeatureIndex();
@@ -186573,7 +186721,7 @@ function readPnts(stream, dataOffset, pnts) {
186573
186721
  }
186574
186722
  async function decodeDracoPointCloud(buf) {
186575
186723
  try {
186576
- const dracoLoader = (await __webpack_require__.e(/*! import() */ "vendors-common_temp_node_modules_pnpm_loaders_gl_draco_4_3_4_node_modules_loaders_gl_draco_di-40e622").then(__webpack_require__.bind(__webpack_require__, /*! @loaders.gl/draco */ "../../common/temp/node_modules/.pnpm/@loaders.gl+draco@4.3.4/node_modules/@loaders.gl/draco/dist/index.js"))).DracoLoader;
186724
+ const dracoLoader = (await __webpack_require__.e(/*! import() */ "vendors-common_temp_node_modules_pnpm_loaders_gl_draco_4_3_4__loaders_gl_core_4_3_4_node_modu-4c1fc9").then(__webpack_require__.bind(__webpack_require__, /*! @loaders.gl/draco */ "../../common/temp/node_modules/.pnpm/@loaders.gl+draco@4.3.4_@loaders.gl+core@4.3.4/node_modules/@loaders.gl/draco/dist/index.js"))).DracoLoader;
186577
186725
  const mesh = await dracoLoader.parse(buf, {});
186578
186726
  if (mesh.topology !== "point-list")
186579
186727
  return undefined;
@@ -198012,14 +198160,47 @@ class GltfReader {
198012
198160
  }
198013
198161
  }
198014
198162
  createDisplayParams(material, hasBakedLighting, isPointPrimitive = false) {
198163
+ let constantLodParamProps;
198164
+ let normalMapUseConstantLod = false;
198165
+ if (!(0,_common_gltf_GltfSchema__WEBPACK_IMPORTED_MODULE_12__.isGltf1Material)(material)) {
198166
+ // NOTE: EXT_textureInfo_constant_lod is not supported for occlusionTexture and metallicRoughnessTexture
198167
+ // Use the same texture fallback logic as extractTextureId
198168
+ const textureInfo = material.pbrMetallicRoughness?.baseColorTexture ?? material.emissiveTexture;
198169
+ const extConstantLod = textureInfo?.extensions?.EXT_textureInfo_constant_lod;
198170
+ const offset = extConstantLod?.offset;
198171
+ extConstantLod ? constantLodParamProps = {
198172
+ repetitions: extConstantLod?.repetitions,
198173
+ offset: offset ? { x: offset[0], y: offset[1] } : undefined,
198174
+ minDistClamp: extConstantLod?.minClampDistance,
198175
+ maxDistClamp: extConstantLod?.maxClampDistance,
198176
+ } : undefined;
198177
+ // Normal map only uses constant LOD if both the base texture and normal texture have the extension
198178
+ normalMapUseConstantLod = extConstantLod !== undefined && material.normalTexture?.extensions?.EXT_textureInfo_constant_lod !== undefined;
198179
+ }
198015
198180
  const isTransparent = this.isMaterialTransparent(material);
198016
198181
  const textureId = this.extractTextureId(material);
198017
198182
  const normalMapId = this.extractNormalMapId(material);
198018
- let textureMapping = (undefined !== textureId || undefined !== normalMapId) ? this.findTextureMapping(textureId, isTransparent, normalMapId) : undefined;
198183
+ let textureMapping = (undefined !== textureId || undefined !== normalMapId) ? this.findTextureMapping(textureId, isTransparent, normalMapId, constantLodParamProps, normalMapUseConstantLod) : undefined;
198019
198184
  const color = colorFromMaterial(material, isTransparent);
198020
198185
  let renderMaterial;
198021
- if (undefined !== textureMapping && undefined !== textureMapping.normalMapParams) {
198022
- const args = { diffuse: { color }, specular: { color: _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.ColorDef.white }, textureMapping };
198186
+ if (undefined !== textureMapping) {
198187
+ // Convert result of findTextureMapping (TextureMapping object) to MaterialTextureMappingProps interface
198188
+ const textureMappingProps = {
198189
+ texture: textureMapping.texture,
198190
+ normalMapParams: textureMapping.normalMapParams,
198191
+ mode: textureMapping.params.mode,
198192
+ transform: textureMapping.params.textureMatrix,
198193
+ weight: textureMapping.params.weight,
198194
+ worldMapping: textureMapping.params.worldMapping,
198195
+ useConstantLod: textureMapping.params.useConstantLod,
198196
+ constantLodProps: textureMapping.params.useConstantLod ? {
198197
+ repetitions: textureMapping.params.constantLodParams.repetitions,
198198
+ offset: textureMapping.params.constantLodParams.offset,
198199
+ minDistClamp: textureMapping.params.constantLodParams.minDistClamp,
198200
+ maxDistClamp: textureMapping.params.constantLodParams.maxDistClamp,
198201
+ } : undefined,
198202
+ };
198203
+ const args = { diffuse: { color }, specular: { color: _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.ColorDef.white }, textureMapping: textureMappingProps };
198023
198204
  renderMaterial = _IModelApp__WEBPACK_IMPORTED_MODULE_3__.IModelApp.renderSystem.createRenderMaterial(args);
198024
198205
  // DisplayParams doesn't want a separate texture mapping if the material already has one.
198025
198206
  textureMapping = undefined;
@@ -198031,7 +198212,30 @@ class GltfReader {
198031
198212
  width = pointStyle.diameter;
198032
198213
  }
198033
198214
  }
198034
- return new _common_internal_render_DisplayParams__WEBPACK_IMPORTED_MODULE_8__.DisplayParams(_common_internal_render_DisplayParams__WEBPACK_IMPORTED_MODULE_8__.DisplayParams.Type.Mesh, color, color, width, _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.LinePixels.Solid, _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.FillFlags.None, renderMaterial, undefined, hasBakedLighting, textureMapping);
198215
+ // Process BENTLEY_materials_planar_fill extension
198216
+ let fillFlags = _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.FillFlags.None;
198217
+ if (!(0,_common_gltf_GltfSchema__WEBPACK_IMPORTED_MODULE_12__.isGltf1Material)(material)) {
198218
+ const planarFill = material.extensions?.BENTLEY_materials_planar_fill;
198219
+ if (planarFill) {
198220
+ // Map wireframeFill: 0=NONE (no fill flags), 1=ALWAYS (Always flag), 2=TOGGLE (ByView flag)
198221
+ const wireframeFill = planarFill.wireframeFill ?? 0;
198222
+ if (wireframeFill === 1) {
198223
+ fillFlags |= _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.FillFlags.Always;
198224
+ }
198225
+ else if (wireframeFill === 2) {
198226
+ fillFlags |= _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.FillFlags.ByView;
198227
+ }
198228
+ // Map backgroundFill to Background flag
198229
+ if (planarFill.backgroundFill === true) {
198230
+ fillFlags |= _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.FillFlags.Background;
198231
+ }
198232
+ // Map behind to Behind flag
198233
+ if (planarFill.behind === true) {
198234
+ fillFlags |= _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.FillFlags.Behind;
198235
+ }
198236
+ }
198237
+ }
198238
+ return new _common_internal_render_DisplayParams__WEBPACK_IMPORTED_MODULE_8__.DisplayParams(_common_internal_render_DisplayParams__WEBPACK_IMPORTED_MODULE_8__.DisplayParams.Type.Mesh, color, color, width, _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.LinePixels.Solid, fillFlags, renderMaterial, undefined, hasBakedLighting, textureMapping);
198035
198239
  }
198036
198240
  readMeshPrimitives(node, featureTable, thisTransform, thisBias, instances) {
198037
198241
  const meshes = [];
@@ -198833,7 +199037,7 @@ class GltfReader {
198833
199037
  if (_itwin_core_bentley__WEBPACK_IMPORTED_MODULE_0__.ProcessDetector.isIEBrowser) {
198834
199038
  throw new Error("Unsupported browser for Draco decoding");
198835
199039
  }
198836
- const dracoLoader = (await __webpack_require__.e(/*! import() */ "vendors-common_temp_node_modules_pnpm_loaders_gl_draco_4_3_4_node_modules_loaders_gl_draco_di-40e622").then(__webpack_require__.bind(__webpack_require__, /*! @loaders.gl/draco */ "../../common/temp/node_modules/.pnpm/@loaders.gl+draco@4.3.4/node_modules/@loaders.gl/draco/dist/index.js"))).DracoLoader;
199040
+ const dracoLoader = (await __webpack_require__.e(/*! import() */ "vendors-common_temp_node_modules_pnpm_loaders_gl_draco_4_3_4__loaders_gl_core_4_3_4_node_modu-4c1fc9").then(__webpack_require__.bind(__webpack_require__, /*! @loaders.gl/draco */ "../../common/temp/node_modules/.pnpm/@loaders.gl+draco@4.3.4_@loaders.gl+core@4.3.4/node_modules/@loaders.gl/draco/dist/index.js"))).DracoLoader;
198837
199041
  await Promise.all(dracoMeshes.map(async (x) => this.decodeDracoMesh(x, dracoLoader)));
198838
199042
  }
198839
199043
  catch (err) {
@@ -198977,7 +199181,7 @@ class GltfReader {
198977
199181
  });
198978
199182
  return renderTexture ?? false;
198979
199183
  }
198980
- findTextureMapping(id, isTransparent, normalMapId) {
199184
+ findTextureMapping(id, isTransparent, normalMapId, constantLodParamProps, normalMapUseConstantLod = false) {
198981
199185
  if (undefined === id && undefined === normalMapId)
198982
199186
  return undefined;
198983
199187
  let texture;
@@ -198999,16 +199203,18 @@ class GltfReader {
198999
199203
  nMap = {
199000
199204
  normalMap,
199001
199205
  greenUp,
199206
+ useConstantLod: normalMapUseConstantLod,
199002
199207
  };
199003
199208
  }
199004
199209
  else {
199005
199210
  texture = normalMap;
199006
- nMap = { greenUp };
199211
+ nMap = { greenUp, useConstantLod: normalMapUseConstantLod };
199007
199212
  }
199008
199213
  }
199009
199214
  if (!texture)
199010
199215
  return undefined;
199011
- const textureMapping = new _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.TextureMapping(texture, new _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.TextureMapping.Params());
199216
+ const useConstantLod = constantLodParamProps !== undefined;
199217
+ const textureMapping = new _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.TextureMapping(texture, new _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.TextureMapping.Params({ useConstantLod, constantLodProps: constantLodParamProps }));
199012
199218
  textureMapping.normalMapParams = nMap;
199013
199219
  return textureMapping;
199014
199220
  }
@@ -199045,7 +199251,7 @@ async function readGltfTemplate(args) {
199045
199251
  }
199046
199252
  /** Produce a [[RenderGraphic]] from a [glTF](https://www.khronos.org/gltf/) asset suitable for use in [view decorations]($docs/learning/frontend/ViewDecorations).
199047
199253
  * @returns a graphic produced from the glTF asset's default scene, or `undefined` if a graphic could not be produced from the asset.
199048
- * The returned graphic also includes the bounding boxes of the glTF model in world and local coordiantes.
199254
+ * The returned graphic also includes the bounding boxes of the glTF model in world and local coordinates.
199049
199255
  * @note Support for the full [glTF 2.0 specification](https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html) is currently a work in progress.
199050
199256
  * If a particular glTF asset fails to load and/or display properly, please
199051
199257
  * [submit an issue](https://github.com/iTwin/itwinjs-core/issues).
@@ -199073,6 +199279,7 @@ class GltfGraphicsReader extends GltfReader {
199073
199279
  _contentRange;
199074
199280
  _transform;
199075
199281
  _isLeaf;
199282
+ _useViewportRenderMode;
199076
199283
  binaryData; // strictly for tests
199077
199284
  meshes; // strictly for tests
199078
199285
  constructor(props, args) {
@@ -199086,6 +199293,7 @@ class GltfGraphicsReader extends GltfReader {
199086
199293
  this._contentRange = args.contentRange;
199087
199294
  this._transform = args.transform;
199088
199295
  this._isLeaf = true !== args.hasChildren;
199296
+ this._useViewportRenderMode = args.useViewportRenderMode ?? false;
199089
199297
  this.binaryData = props.binaryData;
199090
199298
  const pickableId = args.pickableOptions?.id;
199091
199299
  if (pickableId) {
@@ -199096,7 +199304,8 @@ class GltfGraphicsReader extends GltfReader {
199096
199304
  get viewFlagOverrides() {
199097
199305
  return {
199098
199306
  whiteOnWhiteReversal: false,
199099
- renderMode: _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.RenderMode.SmoothShade,
199307
+ // Don't override renderMode if using viewport's render mode - let the viewport control it.
199308
+ renderMode: this._useViewportRenderMode ? undefined : _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.RenderMode.SmoothShade,
199100
199309
  };
199101
199310
  }
199102
199311
  get meshElementIdToFeatureIndex() {
@@ -340704,6 +340913,8 @@ class BaseFormat {
340704
340913
  _stationOffsetSize; // required when type is station; positive integer > 0
340705
340914
  _stationBaseFactor; // optional positive integer base factor for station formatting; default is 1
340706
340915
  _ratioType; // required if type is ratio; options: oneToN, NToOne, ValueBased, useGreatestCommonDivisor
340916
+ _ratioFormatType; // defaults to Decimal if not specified
340917
+ _ratioSeparator; // default is ":"; separator character used in ratio formatting
340707
340918
  _azimuthBase; // value always clockwise from north
340708
340919
  _azimuthBaseUnit; // unit for azimuthBase value
340709
340920
  _azimuthCounterClockwise; // if set to true, azimuth values are returned counter-clockwise from base
@@ -340725,6 +340936,10 @@ class BaseFormat {
340725
340936
  set scientificType(scientificType) { this._scientificType = scientificType; }
340726
340937
  get ratioType() { return this._ratioType; }
340727
340938
  set ratioType(ratioType) { this._ratioType = ratioType; }
340939
+ get ratioFormatType() { return this._ratioFormatType; }
340940
+ set ratioFormatType(ratioFormatType) { this._ratioFormatType = ratioFormatType; }
340941
+ get ratioSeparator() { return this._ratioSeparator; }
340942
+ set ratioSeparator(ratioSeparator) { this._ratioSeparator = ratioSeparator; }
340728
340943
  get showSignOption() { return this._showSignOption; }
340729
340944
  set showSignOption(showSignOption) { this._showSignOption = showSignOption; }
340730
340945
  get decimalSeparator() { return this._decimalSeparator; }
@@ -340793,6 +341008,22 @@ class BaseFormat {
340793
341008
  if (undefined === formatProps.ratioType)
340794
341009
  throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvalidJson, `The Format ${this.name} is 'Ratio' type therefore the attribute 'ratioType' is required.`);
340795
341010
  this._ratioType = (0,_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.parseRatioType)(formatProps.ratioType, this.name);
341011
+ if (undefined !== formatProps.ratioSeparator) {
341012
+ if (typeof (formatProps.ratioSeparator) !== "string")
341013
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'ratioSeparator' attribute. It should be of type 'string'.`);
341014
+ if (formatProps.ratioSeparator.length !== 1)
341015
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvalidJson, `The Format ${this.name} has an invalid 'ratioSeparator' attribute. It should be a one character string.`);
341016
+ this._ratioSeparator = formatProps.ratioSeparator;
341017
+ }
341018
+ else {
341019
+ this._ratioSeparator = ":"; // Apply default
341020
+ }
341021
+ if (undefined !== formatProps.ratioFormatType) {
341022
+ this._ratioFormatType = (0,_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.parseRatioFormatType)(formatProps.ratioFormatType, this.name);
341023
+ }
341024
+ else {
341025
+ this._ratioFormatType = _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.RatioFormatType.Decimal; // Apply default
341026
+ }
340796
341027
  }
340797
341028
  if (undefined !== formatProps.roundFactor) { // optional; default is 0.0
340798
341029
  if (typeof (formatProps.roundFactor) !== "number")
@@ -340917,6 +341148,8 @@ class Format extends BaseFormat {
340917
341148
  newFormat._azimuthBaseUnit = this._azimuthBaseUnit;
340918
341149
  newFormat._azimuthCounterClockwise = this._azimuthCounterClockwise;
340919
341150
  newFormat._ratioType = this._ratioType;
341151
+ newFormat._ratioFormatType = this._ratioFormatType;
341152
+ newFormat._ratioSeparator = this._ratioSeparator;
340920
341153
  newFormat._revolutionUnit = this._revolutionUnit;
340921
341154
  newFormat._customProps = this._customProps;
340922
341155
  this._units && (newFormat._units = [...this._units]);
@@ -340977,25 +341210,28 @@ class Format extends BaseFormat {
340977
341210
  throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvalidJson, `The Format ${this.name} has a Composite with an invalid 'units' attribute. It must be of type 'array'`);
340978
341211
  }
340979
341212
  if (jsonObj.composite.units.length > 0 && jsonObj.composite.units.length <= 4) { // Composite requires 1-4 units
340980
- for (const nextUnit of jsonObj.composite.units) {
340981
- if (this._units) {
340982
- for (const existingUnit of this._units) {
340983
- const unitObj = existingUnit[0].name;
340984
- if (unitObj.toLowerCase() === nextUnit.unit.name.toLowerCase()) {
340985
- throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvalidJson, `The unit ${unitObj} has a duplicate name.`);
340986
- }
341213
+ const isDuplicateAllowed = this.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Ratio;
341214
+ const seenUnits = new Set();
341215
+ this._units = [];
341216
+ for (const unitSpec of jsonObj.composite.units) {
341217
+ if (!isDuplicateAllowed) {
341218
+ const unitName = unitSpec.unit.name.toLowerCase();
341219
+ const existingName = seenUnits.has(unitName);
341220
+ if (existingName) {
341221
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvalidJson, `The Format ${this.name} contains duplicate units: '${unitSpec.unit.name}'`);
340987
341222
  }
341223
+ seenUnits.add(unitName);
340988
341224
  }
340989
- if (undefined === this._units) {
340990
- this._units = [];
340991
- }
340992
- this._units.push([nextUnit.unit, nextUnit.label]);
341225
+ this._units.push([unitSpec.unit, unitSpec.label]);
340993
341226
  }
340994
341227
  }
340995
341228
  }
340996
341229
  if (undefined === this.units || this.units.length === 0)
340997
341230
  throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvalidJson, `The Format ${this.name} has a Composite with no valid 'units'`);
340998
341231
  }
341232
+ if (this.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Ratio && (!this._units || this._units.length === 0)) {
341233
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvalidJson, `The Format ${this.name} is 'Ratio' type and must have 'composite' units.`);
341234
+ }
340999
341235
  if (this.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Azimuth || this.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Bearing) {
341000
341236
  this._azimuthBaseUnit = jsonObj.azimuthBaseUnit;
341001
341237
  this._revolutionUnit = jsonObj.revolutionUnit;
@@ -341062,6 +341298,8 @@ class Format extends BaseFormat {
341062
341298
  uomSeparator: this.uomSeparator,
341063
341299
  scientificType: this.scientificType ? this.scientificType : undefined,
341064
341300
  ratioType: this.ratioType,
341301
+ ratioFormatType: this.ratioFormatType,
341302
+ ratioSeparator: this.ratioSeparator,
341065
341303
  stationOffsetSize: this.stationOffsetSize,
341066
341304
  stationSeparator: this.stationSeparator,
341067
341305
  stationBaseFactor: this.stationBaseFactor,
@@ -341106,6 +341344,15 @@ async function resolveFormatProps(formatName, unitsProvider, jsonObj) {
341106
341344
  const unit = await resolveCompositeUnit(unitsProvider, entry.name);
341107
341345
  return { unit, label: entry.label };
341108
341346
  }));
341347
+ // For Ratio formats with 2 units: validate both units have the same phenomenon
341348
+ const formatType = (0,_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.parseFormatType)(jsonObj.type, formatName);
341349
+ if (formatType === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Ratio && units.length === 2) {
341350
+ const phenomenon1 = units[0].unit.phenomenon;
341351
+ const phenomenon2 = units[1].unit.phenomenon;
341352
+ if (phenomenon1 !== phenomenon2) {
341353
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvalidJson, `The Format ${formatName} has 2-unit composite with different phenomena. Both units must have the same phenomenon. Found '${phenomenon1}' and '${phenomenon2}'.`);
341354
+ }
341355
+ }
341109
341356
  }
341110
341357
  let azimuthBaseUnit, revolutionUnit;
341111
341358
  const type = (0,_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.parseFormatType)(jsonObj.type, formatName);
@@ -341146,6 +341393,7 @@ __webpack_require__.r(__webpack_exports__);
341146
341393
  /* harmony export */ FormatTraits: () => (/* binding */ FormatTraits),
341147
341394
  /* harmony export */ FormatType: () => (/* binding */ FormatType),
341148
341395
  /* harmony export */ FractionalPrecision: () => (/* binding */ FractionalPrecision),
341396
+ /* harmony export */ RatioFormatType: () => (/* binding */ RatioFormatType),
341149
341397
  /* harmony export */ RatioType: () => (/* binding */ RatioType),
341150
341398
  /* harmony export */ ScientificType: () => (/* binding */ ScientificType),
341151
341399
  /* harmony export */ ShowSignOption: () => (/* binding */ ShowSignOption),
@@ -341159,6 +341407,7 @@ __webpack_require__.r(__webpack_exports__);
341159
341407
  /* harmony export */ parseFormatType: () => (/* binding */ parseFormatType),
341160
341408
  /* harmony export */ parseFractionalPrecision: () => (/* binding */ parseFractionalPrecision),
341161
341409
  /* harmony export */ parsePrecision: () => (/* binding */ parsePrecision),
341410
+ /* harmony export */ parseRatioFormatType: () => (/* binding */ parseRatioFormatType),
341162
341411
  /* harmony export */ parseRatioType: () => (/* binding */ parseRatioType),
341163
341412
  /* harmony export */ parseScientificType: () => (/* binding */ parseScientificType),
341164
341413
  /* harmony export */ parseShowSignOption: () => (/* binding */ parseShowSignOption),
@@ -341303,6 +341552,16 @@ var RatioType;
341303
341552
  /** scales the input ratio to its simplest integer form using the greatest common divisor (GCD) of the values. e.g. 0.3 turns into 3:10 */
341304
341553
  RatioType["UseGreatestCommonDivisor"] = "UseGreatestCommonDivisor";
341305
341554
  })(RatioType || (RatioType = {}));
341555
+ /** The format type for the numbers within a ratio.
341556
+ * @beta
341557
+ */
341558
+ var RatioFormatType;
341559
+ (function (RatioFormatType) {
341560
+ /** Decimal display (ie 2.125) */
341561
+ RatioFormatType["Decimal"] = "Decimal";
341562
+ /** Fractional display (ie 2-1/8) */
341563
+ RatioFormatType["Fractional"] = "Fractional";
341564
+ })(RatioFormatType || (RatioFormatType = {}));
341306
341565
  /** Determines how the sign of values are displayed
341307
341566
  * @beta */
341308
341567
  var ShowSignOption;
@@ -341348,6 +341607,18 @@ function parseRatioType(ratioType, formatName) {
341348
341607
  }
341349
341608
  throw new _Exception__WEBPACK_IMPORTED_MODULE_0__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_0__.QuantityStatus.InvalidJson, `The Format ${formatName} has an invalid 'ratioType' attribute.`);
341350
341609
  }
341610
+ /** @beta */
341611
+ function parseRatioFormatType(ratioFormatType, formatName) {
341612
+ const normalizedValue = ratioFormatType.toLowerCase();
341613
+ for (const key in RatioFormatType) {
341614
+ if (RatioFormatType.hasOwnProperty(key)) {
341615
+ const enumValue = RatioFormatType[key];
341616
+ if (enumValue.toLowerCase() === normalizedValue)
341617
+ return enumValue;
341618
+ }
341619
+ }
341620
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_0__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_0__.QuantityStatus.InvalidJson, `The Format ${formatName} has an invalid 'ratioFormatType' attribute.`);
341621
+ }
341351
341622
  /** @beta */
341352
341623
  function parseShowSignOption(showSignOption, formatName) {
341353
341624
  switch (showSignOption.toLowerCase()) {
@@ -341509,10 +341780,18 @@ function parsePrecision(precision, type, formatName) {
341509
341780
  case FormatType.Decimal:
341510
341781
  case FormatType.Scientific:
341511
341782
  case FormatType.Station:
341512
- case FormatType.Ratio:
341513
341783
  case FormatType.Bearing:
341514
341784
  case FormatType.Azimuth:
341515
341785
  return parseDecimalPrecision(precision, formatName);
341786
+ case FormatType.Ratio:
341787
+ // Ratio type can use either decimal or fractional precision depending on ratioFormatType
341788
+ // Try decimal first, if it fails, try fractional
341789
+ try {
341790
+ return parseDecimalPrecision(precision, formatName);
341791
+ }
341792
+ catch {
341793
+ return parseFractionalPrecision(precision, formatName);
341794
+ }
341516
341795
  case FormatType.Fractional:
341517
341796
  return parseFractionalPrecision(precision, formatName);
341518
341797
  default:
@@ -341536,8 +341815,9 @@ __webpack_require__.r(__webpack_exports__);
341536
341815
  /* harmony export */ });
341537
341816
  /* harmony import */ var _Constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Constants */ "../../core/quantity/lib/esm/Constants.js");
341538
341817
  /* harmony import */ var _Exception__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Exception */ "../../core/quantity/lib/esm/Exception.js");
341539
- /* harmony import */ var _FormatEnums__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./FormatEnums */ "../../core/quantity/lib/esm/Formatter/FormatEnums.js");
341540
- /* harmony import */ var _Quantity__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../Quantity */ "../../core/quantity/lib/esm/Quantity.js");
341818
+ /* harmony import */ var _FormatterSpec__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./FormatterSpec */ "../../core/quantity/lib/esm/Formatter/FormatterSpec.js");
341819
+ /* harmony import */ var _FormatEnums__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./FormatEnums */ "../../core/quantity/lib/esm/Formatter/FormatEnums.js");
341820
+ /* harmony import */ var _Quantity__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../Quantity */ "../../core/quantity/lib/esm/Quantity.js");
341541
341821
  /*---------------------------------------------------------------------------------------------
341542
341822
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
341543
341823
  * See LICENSE.md in the project root for license terms and full copyright notice.
@@ -341549,6 +341829,7 @@ __webpack_require__.r(__webpack_exports__);
341549
341829
 
341550
341830
 
341551
341831
 
341832
+
341552
341833
  /** rounding additive
341553
341834
  * @internal
341554
341835
  */
@@ -341649,7 +341930,7 @@ class Formatter {
341649
341930
  static integerPartToText(wholePart, spec) {
341650
341931
  // build invariant string represent wholePart
341651
341932
  let formattedValue = wholePart.toFixed(0);
341652
- if ((formattedValue.length > 3) && (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.Use1000Separator) && (spec.format.thousandSeparator.length > 0))) {
341933
+ if ((formattedValue.length > 3) && (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.Use1000Separator) && (spec.format.thousandSeparator.length > 0))) {
341653
341934
  let numSeparators = Math.floor(formattedValue.length / 3);
341654
341935
  let groupLength = formattedValue.length % 3;
341655
341936
  if (groupLength === 0) {
@@ -341696,7 +341977,7 @@ class Formatter {
341696
341977
  else {
341697
341978
  componentText = Formatter.formatMagnitude(compositeValue, spec);
341698
341979
  }
341699
- if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.ShowUnitLabel)) {
341980
+ if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.ShowUnitLabel)) {
341700
341981
  componentText = componentText + spec.format.uomSeparator + label;
341701
341982
  }
341702
341983
  return componentText;
@@ -341716,12 +341997,11 @@ class Formatter {
341716
341997
  throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvalidCompositeFormat, `The Format ${spec.format.name} has a invalid unit specification.`);
341717
341998
  if (i > 0 && unitConversion.offset !== 0) // offset should only ever be defined for major unit
341718
341999
  throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvalidCompositeFormat, `The Format ${spec.format.name} has a invalid unit specification.`);
341719
- let unitValue = 0.0;
341720
- if (spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Ratio) {
341721
- if (1 !== (spec.format.units?.length ?? 0))
341722
- throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvalidCompositeFormat, `The Format '${spec.format.name}' with type 'ratio' must have exactly one unit.`);
342000
+ // Handle ratio format with composite units
342001
+ if (spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Ratio) {
342002
+ let ratioUnitValue = 0.0;
341723
342003
  try {
341724
- unitValue = (0,_Quantity__WEBPACK_IMPORTED_MODULE_3__.applyConversion)(remainingMagnitude, unitConversion) + this.FPV_MINTHRESHOLD;
342004
+ ratioUnitValue = (0,_Quantity__WEBPACK_IMPORTED_MODULE_4__.applyConversion)(remainingMagnitude, unitConversion) + this.FPV_MINTHRESHOLD;
341725
342005
  }
341726
342006
  catch (e) {
341727
342007
  // The "InvertingZero" error is thrown when the value is zero and the conversion factor is inverted.
@@ -341729,12 +342009,13 @@ class Formatter {
341729
342009
  if (e instanceof _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError && e.errorNumber === _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvertingZero) {
341730
342010
  return { componentText: "1:0", isNegative: false };
341731
342011
  }
342012
+ throw e;
341732
342013
  }
341733
- compositeStrings.push(this.formatRatio(unitValue, spec));
341734
- isNegative = unitValue < 0;
342014
+ compositeStrings.push(this.formatRatio(ratioUnitValue, spec));
342015
+ isNegative = ratioUnitValue < 0;
341735
342016
  continue;
341736
342017
  }
341737
- unitValue = (0,_Quantity__WEBPACK_IMPORTED_MODULE_3__.applyConversion)(remainingMagnitude, unitConversion) + this.FPV_MINTHRESHOLD;
342018
+ let unitValue = (0,_Quantity__WEBPACK_IMPORTED_MODULE_4__.applyConversion)(remainingMagnitude, unitConversion) + this.FPV_MINTHRESHOLD;
341738
342019
  if (0 === i) {
341739
342020
  // Only set isNegative from the first (major) unit conversion
341740
342021
  isNegative = unitValue < 0;
@@ -341742,16 +342023,16 @@ class Formatter {
341742
342023
  // but use higher precision if the format specifies it
341743
342024
  const precisionScale = Math.pow(10, Math.max(8, spec.format.precision));
341744
342025
  unitValue = Math.floor(unitValue * precisionScale + FPV_ROUNDFACTOR) / precisionScale;
341745
- if ((Math.abs(unitValue) < 0.0001) && spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.ZeroEmpty))
342026
+ if ((Math.abs(unitValue) < 0.0001) && spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.ZeroEmpty))
341746
342027
  return { componentText: "", isNegative: false };
341747
342028
  }
341748
342029
  if (i < (spec.format.units?.length ?? 0) - 1) {
341749
342030
  let wholePart = Math.trunc(unitValue);
341750
342031
  // Check if the remaining fractional part will round up to a full unit in the next (smaller) component
341751
- if (spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Fractional && i === spec.unitConversions.length - 2) {
342032
+ if (spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Fractional && i === spec.unitConversions.length - 2) {
341752
342033
  // For the second-to-last unit with fractional formatting, check if rounding causes carry-over
341753
342034
  const fractionalPart = unitValue - wholePart;
341754
- const nextUnitValue = (0,_Quantity__WEBPACK_IMPORTED_MODULE_3__.applyConversion)(fractionalPart, spec.unitConversions[i + 1].conversion);
342035
+ const nextUnitValue = (0,_Quantity__WEBPACK_IMPORTED_MODULE_4__.applyConversion)(fractionalPart, spec.unitConversions[i + 1].conversion);
341755
342036
  // Create a FractionalNumeric to determine what the rounded value would be
341756
342037
  const fn = new FractionalNumeric(Math.abs(nextUnitValue), spec.format.precision, true);
341757
342038
  // If the fractional numeric rounds to a whole unit (integral part increased due to rounding)
@@ -341781,18 +342062,18 @@ class Formatter {
341781
342062
  */
341782
342063
  static formatMagnitude(magnitude, spec) {
341783
342064
  let posMagnitude = Math.abs(magnitude);
341784
- if ((Math.abs(posMagnitude) < 0.0001) && spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.ZeroEmpty))
342065
+ if ((Math.abs(posMagnitude) < 0.0001) && spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.ZeroEmpty))
341785
342066
  return "";
341786
- if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.ApplyRounding))
342067
+ if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.ApplyRounding))
341787
342068
  posMagnitude = Math.abs(Formatter.roundDouble(magnitude, spec.format.roundFactor));
341788
- const isSci = ((posMagnitude > 1.0e12) || spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Scientific);
341789
- const isDecimal = (isSci || spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Decimal || spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Bearing || spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Azimuth) || spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Ratio;
341790
- const isFractional = (!isDecimal && spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Fractional);
342069
+ const isSci = ((posMagnitude > 1.0e12) || spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Scientific);
342070
+ const isDecimal = (isSci || spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Decimal || spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Bearing || spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Azimuth) || spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Ratio;
342071
+ const isFractional = (!isDecimal && spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Fractional);
341791
342072
  /* const usesStops = spec.format.type === FormatType.Station; */
341792
- const isPrecisionZero = spec.format.precision === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.DecimalPrecision.Zero;
341793
- const isKeepSingleZero = spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.KeepSingleZero);
342073
+ const isPrecisionZero = spec.format.precision === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.DecimalPrecision.Zero;
342074
+ const isKeepSingleZero = spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.KeepSingleZero);
341794
342075
  const precisionScale = Math.pow(10.0, spec.format.precision);
341795
- const isKeepTrailingZeroes = spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.TrailZeroes);
342076
+ const isKeepTrailingZeroes = spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.TrailZeroes);
341796
342077
  let expInt = 0.0;
341797
342078
  if (isSci && (posMagnitude !== 0.0)) {
341798
342079
  let exp = Math.log10(posMagnitude);
@@ -341802,10 +342083,10 @@ class Formatter {
341802
342083
  negativeExp = true;
341803
342084
  }
341804
342085
  expInt = Math.floor(exp);
341805
- if (spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Scientific) {
341806
- if (spec.format.scientificType === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.ScientificType.ZeroNormalized && posMagnitude > 1.0)
342086
+ if (spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Scientific) {
342087
+ if (spec.format.scientificType === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.ScientificType.ZeroNormalized && posMagnitude > 1.0)
341807
342088
  expInt += 1.0;
341808
- else if (spec.format.scientificType === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.ScientificType.Normalized && posMagnitude < 1.0)
342089
+ else if (spec.format.scientificType === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.ScientificType.Normalized && posMagnitude < 1.0)
341809
342090
  expInt += 1.0;
341810
342091
  if (negativeExp)
341811
342092
  expInt = -expInt;
@@ -341827,7 +342108,7 @@ class Formatter {
341827
342108
  }
341828
342109
  formattedValue = Formatter.integerPartToText(wholePart, spec);
341829
342110
  if (isPrecisionZero) {
341830
- if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.KeepDecimalPoint) && !isKeepSingleZero)
342111
+ if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.KeepDecimalPoint) && !isKeepSingleZero)
341831
342112
  formattedValue = formattedValue + spec.format.decimalSeparator;
341832
342113
  else if (isKeepSingleZero)
341833
342114
  formattedValue = `${formattedValue + spec.format.decimalSeparator}0`;
@@ -341842,7 +342123,7 @@ class Formatter {
341842
342123
  if (fractionString.length > 0)
341843
342124
  formattedValue = formattedValue + spec.format.decimalSeparator + fractionString;
341844
342125
  else {
341845
- if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.KeepDecimalPoint))
342126
+ if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.KeepDecimalPoint))
341846
342127
  formattedValue = formattedValue + spec.format.decimalSeparator + (isKeepSingleZero ? "0" : "");
341847
342128
  }
341848
342129
  }
@@ -341855,7 +342136,7 @@ class Formatter {
341855
342136
  const fn = new FractionalNumeric(posMagnitude, spec.format.precision, true);
341856
342137
  formattedValue = fn.getIntegralString();
341857
342138
  if (!fn.isZero && fn.hasFractionPart) {
341858
- const wholeFractionSeparator = spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.FractionDash) ? "-" : " ";
342139
+ const wholeFractionSeparator = spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.FractionDash) ? "-" : " ";
341859
342140
  const fractionString = `${fn.getNumeratorString()}/${fn.getDenominatorString()}`;
341860
342141
  formattedValue = formattedValue + wholeFractionSeparator + fractionString;
341861
342142
  }
@@ -341884,7 +342165,7 @@ class Formatter {
341884
342165
  else {
341885
342166
  if (isKeepTrailingZeroes)
341886
342167
  fractionString = spec.format.decimalSeparator + "".padEnd(spec.format.precision, "0");
341887
- else if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.KeepDecimalPoint))
342168
+ else if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.KeepDecimalPoint))
341888
342169
  fractionString = spec.format.decimalSeparator;
341889
342170
  formattedValue = stationString + fractionString;
341890
342171
  }
@@ -341913,21 +342194,21 @@ class Formatter {
341913
342194
  let prefix = "";
341914
342195
  let suffix = "";
341915
342196
  switch (showSignOption) {
341916
- case _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.ShowSignOption.NegativeParentheses:
342197
+ case _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.ShowSignOption.NegativeParentheses:
341917
342198
  if (isNegative) {
341918
342199
  prefix = "(";
341919
342200
  suffix = ")";
341920
342201
  }
341921
342202
  break;
341922
- case _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.ShowSignOption.OnlyNegative:
341923
- if (isNegative && formatType !== _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Bearing && formatType !== _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Azimuth) {
342203
+ case _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.ShowSignOption.OnlyNegative:
342204
+ if (isNegative && formatType !== _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Bearing && formatType !== _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Azimuth) {
341924
342205
  prefix = "-";
341925
342206
  }
341926
342207
  break;
341927
- case _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.ShowSignOption.SignAlways:
342208
+ case _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.ShowSignOption.SignAlways:
341928
342209
  prefix = isNegative ? "-" : "+";
341929
342210
  break;
341930
- case _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.ShowSignOption.NoSign:
342211
+ case _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.ShowSignOption.NoSign:
341931
342212
  default:
341932
342213
  break;
341933
342214
  }
@@ -341943,14 +342224,20 @@ class Formatter {
341943
342224
  let suffix = "";
341944
342225
  let formattedValue = "";
341945
342226
  // Handle bearing/azimuth special formatting
341946
- if (spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Bearing || spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Azimuth) {
342227
+ if (spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Bearing || spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Azimuth) {
341947
342228
  const result = this.processBearingAndAzimuth(magnitude, spec);
341948
342229
  magnitude = result.magnitude;
341949
342230
  prefix = result.prefix ?? "";
341950
342231
  suffix = result.suffix ?? "";
341951
342232
  }
341952
342233
  let formattedMagnitude = "";
341953
- if (spec.format.hasUnits) {
342234
+ if (spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Ratio && spec.unitConversions.length >= 3) {
342235
+ // Handle ratio formatting separately when 2-unit composite provides 3 conversion specs
342236
+ const ratioResult = this.formatRatioQuantity(magnitude, spec);
342237
+ formattedMagnitude = ratioResult.componentText;
342238
+ valueIsNegative = ratioResult.isNegative;
342239
+ }
342240
+ else if (spec.format.hasUnits) {
341954
342241
  const compositeResult = Formatter.formatComposite(magnitude, spec);
341955
342242
  formattedMagnitude = compositeResult.componentText;
341956
342243
  // Override the sign detection with the composite conversion result
@@ -341959,8 +342246,8 @@ class Formatter {
341959
342246
  else {
341960
342247
  // unitless quantity
341961
342248
  formattedMagnitude = Formatter.formatMagnitude(magnitude, spec);
341962
- if (formattedMagnitude.length > 0 && spec.unitConversions.length > 0 && spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.ShowUnitLabel)) {
341963
- if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.PrependUnitLabel))
342249
+ if (formattedMagnitude.length > 0 && spec.unitConversions.length > 0 && spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.ShowUnitLabel)) {
342250
+ if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.PrependUnitLabel))
341964
342251
  formattedMagnitude = spec.unitConversions[0].label + spec.format.uomSeparator + formattedMagnitude;
341965
342252
  else
341966
342253
  formattedMagnitude = formattedMagnitude + spec.format.uomSeparator + spec.unitConversions[0].label;
@@ -341980,12 +342267,12 @@ class Formatter {
341980
342267
  }
341981
342268
  static processBearingAndAzimuth(magnitude, spec) {
341982
342269
  const type = spec.format.type;
341983
- if (type !== _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Bearing && type !== _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Azimuth)
342270
+ if (type !== _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Bearing && type !== _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Azimuth)
341984
342271
  return { magnitude };
341985
342272
  const revolution = this.getRevolution(spec);
341986
342273
  magnitude = this.normalizeAngle(magnitude, revolution);
341987
342274
  const quarterRevolution = revolution / 4;
341988
- if (type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Bearing) {
342275
+ if (type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Bearing) {
341989
342276
  let quadrant = 0;
341990
342277
  while (magnitude > quarterRevolution) {
341991
342278
  magnitude -= quarterRevolution;
@@ -342012,7 +342299,7 @@ class Formatter {
342012
342299
  if (quadrant === 2 && spec.unitConversions.length > 0) {
342013
342300
  // To determine if value is small, we need to convert it to the smallest unit presented and use the provided precision on it
342014
342301
  const unitConversion = spec.unitConversions[spec.unitConversions.length - 1].conversion;
342015
- const smallestFormattedDelta = (0,_Quantity__WEBPACK_IMPORTED_MODULE_3__.applyConversion)((quarterRevolution - magnitude), unitConversion) + this.FPV_MINTHRESHOLD;
342302
+ const smallestFormattedDelta = (0,_Quantity__WEBPACK_IMPORTED_MODULE_4__.applyConversion)((quarterRevolution - magnitude), unitConversion) + this.FPV_MINTHRESHOLD;
342016
342303
  const precisionScale = Math.pow(10.0, spec.format.precision);
342017
342304
  const floor = Math.floor((smallestFormattedDelta) * precisionScale + FPV_ROUNDFACTOR) / precisionScale;
342018
342305
  if (floor === 0) {
@@ -342021,13 +342308,13 @@ class Formatter {
342021
342308
  }
342022
342309
  return { magnitude, prefix, suffix };
342023
342310
  }
342024
- if (type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Azimuth) {
342311
+ if (type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Azimuth) {
342025
342312
  let azimuthBase = 0; // default base is North
342026
342313
  if (spec.format.azimuthBase !== undefined) {
342027
342314
  if (spec.azimuthBaseConversion === undefined) {
342028
342315
  throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.MissingRequiredProperty, `Missing azimuth base conversion for interpreting ${spec.name}'s azimuth base.`);
342029
342316
  }
342030
- const azBaseQuantity = new _Quantity__WEBPACK_IMPORTED_MODULE_3__.Quantity(spec.format.azimuthBaseUnit, spec.format.azimuthBase);
342317
+ const azBaseQuantity = new _Quantity__WEBPACK_IMPORTED_MODULE_4__.Quantity(spec.format.azimuthBaseUnit, spec.format.azimuthBase);
342031
342318
  const azBaseConverted = azBaseQuantity.convertTo(spec.persistenceUnit, spec.azimuthBaseConversion);
342032
342319
  if (azBaseConverted === undefined || !azBaseConverted.isValid) {
342033
342320
  throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.UnsupportedUnit, `Failed to convert azimuth base unit to ${spec.persistenceUnit.name}.`);
@@ -342057,40 +342344,87 @@ class Formatter {
342057
342344
  if (spec.revolutionConversion === undefined) {
342058
342345
  throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.MissingRequiredProperty, `Missing revolution unit conversion for calculating ${spec.name}'s revolution.`);
342059
342346
  }
342060
- const revolution = new _Quantity__WEBPACK_IMPORTED_MODULE_3__.Quantity(spec.format.revolutionUnit, 1.0);
342347
+ const revolution = new _Quantity__WEBPACK_IMPORTED_MODULE_4__.Quantity(spec.format.revolutionUnit, 1.0);
342061
342348
  const converted = revolution.convertTo(spec.persistenceUnit, spec.revolutionConversion);
342062
342349
  if (converted === undefined || !converted.isValid) {
342063
342350
  throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.UnsupportedUnit, `Failed to convert revolution unit to ${spec.persistenceUnit.name}.`);
342064
342351
  }
342065
342352
  return converted.magnitude;
342066
342353
  }
342354
+ static formatRatioPart(value, spec, side) {
342355
+ const formatType = spec.format.ratioFormatType === "Fractional" ? _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Fractional : _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Decimal;
342356
+ const tempFormat = spec.format.clone({ type: formatType });
342357
+ const tempSpec = new _FormatterSpec__WEBPACK_IMPORTED_MODULE_2__.FormatterSpec(spec.name, tempFormat, spec.unitConversions, spec.persistenceUnit);
342358
+ let formattedValue = this.formatMagnitude(value, tempSpec);
342359
+ // For fractional ratio formatting, suppress leading "0" if the value is purely fractional
342360
+ if (formatType === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Fractional && formattedValue.startsWith("0 ")) {
342361
+ formattedValue = formattedValue.substring(2); // Remove "0 " prefix
342362
+ }
342363
+ // Add unit label if ShowUnitLabel trait is set
342364
+ // unitConversions[0] = ratio scale factor, [1] = numerator unit, [2] = denominator unit
342365
+ if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.ShowUnitLabel) && spec.unitConversions.length >= 3) {
342366
+ const labelToAdd = side === "numerator" ? spec.unitConversions[1].label : spec.unitConversions[2].label;
342367
+ formattedValue = formattedValue + labelToAdd;
342368
+ }
342369
+ return formattedValue;
342370
+ }
342371
+ /** Format a ratio quantity value (separate from composite formatting) */
342372
+ static formatRatioQuantity(magnitude, spec) {
342373
+ const unitConversion = spec.unitConversions[0].conversion;
342374
+ let unitValue = 0.0;
342375
+ try {
342376
+ unitValue = (0,_Quantity__WEBPACK_IMPORTED_MODULE_4__.applyConversion)(magnitude, unitConversion) + this.FPV_MINTHRESHOLD;
342377
+ }
342378
+ catch (e) {
342379
+ // The "InvertingZero" error is thrown when the value is zero and the conversion factor is inverted.
342380
+ // For ratio, we return "1:0" as the formatted value.
342381
+ if (e instanceof _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError && e.errorNumber === _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvertingZero) {
342382
+ return { componentText: "1:0", isNegative: false };
342383
+ }
342384
+ throw e;
342385
+ }
342386
+ const componentText = this.formatRatio(unitValue, spec);
342387
+ const isNegative = unitValue < 0;
342388
+ return { componentText, isNegative };
342389
+ }
342067
342390
  static formatRatio(magnitude, spec) {
342068
342391
  if (null === spec.format.ratioType)
342069
342392
  throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvalidCompositeFormat, `The Format ${spec.format.name} must have a ratio type specified.`);
342070
342393
  const precisionScale = Math.pow(10.0, spec.format.precision);
342394
+ const separator = spec.format.ratioSeparator;
342071
342395
  let reciprocal = 0;
342396
+ // Helper to get unit labels if ShowUnitLabel is set
342397
+ const getUnitLabels = () => {
342398
+ if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.ShowUnitLabel) && spec.unitConversions.length >= 3) {
342399
+ return { numeratorLabel: spec.unitConversions[1].label, denominatorLabel: spec.unitConversions[2].label };
342400
+ }
342401
+ return { numeratorLabel: "", denominatorLabel: "" };
342402
+ };
342403
+ const { numeratorLabel, denominatorLabel } = getUnitLabels();
342072
342404
  if (magnitude === 0.0)
342073
- return "0:1";
342405
+ return `0${separator}1`;
342074
342406
  else
342075
342407
  reciprocal = 1.0 / magnitude;
342076
342408
  switch (spec.format.ratioType) {
342077
- case _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.RatioType.OneToN:
342078
- return `1:${this.formatMagnitude(reciprocal, spec)}`;
342079
- case _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.RatioType.NToOne:
342080
- return `${this.formatMagnitude(magnitude, spec)}:1`;
342081
- case _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.RatioType.ValueBased:
342082
- if (magnitude > 1.0)
342083
- return `${this.formatMagnitude(magnitude, spec)}:1`;
342084
- else
342085
- return `1:${this.formatMagnitude(reciprocal, spec)}`;
342086
- case _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.RatioType.UseGreatestCommonDivisor:
342409
+ case _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.RatioType.OneToN:
342410
+ return `1${numeratorLabel}${separator}${this.formatRatioPart(reciprocal, spec, "denominator")}`;
342411
+ case _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.RatioType.NToOne:
342412
+ return `${this.formatRatioPart(magnitude, spec, "numerator")}${separator}1${denominatorLabel}`;
342413
+ case _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.RatioType.ValueBased:
342414
+ if (magnitude > 1.0) {
342415
+ return `${this.formatRatioPart(magnitude, spec, "numerator")}${separator}1${denominatorLabel}`;
342416
+ }
342417
+ else {
342418
+ return `1${numeratorLabel}${separator}${this.formatRatioPart(reciprocal, spec, "denominator")}`;
342419
+ }
342420
+ case _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.RatioType.UseGreatestCommonDivisor:
342087
342421
  magnitude = Math.round(magnitude * precisionScale) / precisionScale;
342088
342422
  let numerator = magnitude * precisionScale;
342089
342423
  let denominator = precisionScale;
342090
342424
  const gcd = FractionalNumeric.getGreatestCommonFactor(numerator, denominator);
342091
342425
  numerator /= gcd;
342092
342426
  denominator /= gcd;
342093
- return `${this.formatMagnitude(numerator, spec)}:${this.formatMagnitude(denominator, spec)}`;
342427
+ return `${this.formatRatioPart(numerator, spec, "numerator")}${separator}${this.formatRatioPart(denominator, spec, "denominator")}`;
342094
342428
  default:
342095
342429
  throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvalidCompositeFormat, `The Format ${spec.format.name} has an invalid ratio type specified.`);
342096
342430
  }
@@ -342111,7 +342445,8 @@ __webpack_require__.r(__webpack_exports__);
342111
342445
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
342112
342446
  /* harmony export */ FormatterSpec: () => (/* binding */ FormatterSpec)
342113
342447
  /* harmony export */ });
342114
- /* harmony import */ var _Formatter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Formatter */ "../../core/quantity/lib/esm/Formatter/Formatter.js");
342448
+ /* harmony import */ var _FormatEnums__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./FormatEnums */ "../../core/quantity/lib/esm/Formatter/FormatEnums.js");
342449
+ /* harmony import */ var _Formatter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Formatter */ "../../core/quantity/lib/esm/Formatter/Formatter.js");
342115
342450
  /*---------------------------------------------------------------------------------------------
342116
342451
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
342117
342452
  * See LICENSE.md in the project root for license terms and full copyright notice.
@@ -342120,6 +342455,7 @@ __webpack_require__.r(__webpack_exports__);
342120
342455
  * @module Quantity
342121
342456
  */
342122
342457
 
342458
+
342123
342459
  // cSpell:ignore ZERONORMALIZED, nosign, onlynegative, signalways, negativeparentheses
342124
342460
  // cSpell:ignore trailzeroes, keepsinglezero, zeroempty, keepdecimalpoint, applyrounding, fractiondash, showunitlabel, prependunitlabel, exponentonlynegative
342125
342461
  /** A class that contains both formatting information and the conversion factors necessary to convert from an input unit to the units specified in the format.
@@ -342166,6 +342502,49 @@ class FormatterSpec {
342166
342502
  get persistenceUnit() { return this._persistenceUnit; }
342167
342503
  get azimuthBaseConversion() { return this._azimuthBaseConversion; }
342168
342504
  get revolutionConversion() { return this._revolutionConversion; }
342505
+ /** Build conversion specs for ratio format with 2 composite units (numerator/denominator). */
342506
+ static async getRatioUnitConversions(units, unitsProvider, persistenceUnit) {
342507
+ const conversions = [];
342508
+ const [numeratorUnit, numeratorLabel] = units[0];
342509
+ const [denominatorUnit, denominatorLabel] = units[1];
342510
+ // Compute ratio scale: how many numerator units per denominator unit (e.g., IN:FT = 12)
342511
+ const denominatorToNumerator = await unitsProvider.getConversion(denominatorUnit, numeratorUnit);
342512
+ const displayRatioScale = denominatorToNumerator.factor;
342513
+ // Avoid double-scaling: if persistence unit already encodes the display ratio, use factor 1.
342514
+ // Check by name heuristic (e.g., IN_PER_FT with ratioUnits [IN, FT] → no scaling needed)
342515
+ const persistenceName = persistenceUnit.name.toUpperCase();
342516
+ const numName = numeratorUnit.name.toUpperCase().split(".").pop() ?? "";
342517
+ const denName = denominatorUnit.name.toUpperCase().split(".").pop() ?? "";
342518
+ // Split by word boundaries (underscores, dots) and check for exact token matches
342519
+ const persistenceTokens = persistenceName.split(/[._]/);
342520
+ const isPersistenceMatchingRatio = persistenceTokens.includes(numName) && persistenceTokens.includes(denName);
342521
+ const ratioScaleFactor = isPersistenceMatchingRatio ? 1.0 : displayRatioScale;
342522
+ // First conversion spec: effective ratio unit conversion
342523
+ const ratioConversionSpec = {
342524
+ name: `${numeratorUnit.name}_per_${denominatorUnit.name}`,
342525
+ label: "",
342526
+ system: numeratorUnit.system,
342527
+ conversion: { factor: ratioScaleFactor, offset: 0.0 },
342528
+ };
342529
+ conversions.push(ratioConversionSpec);
342530
+ // Numerator unit for label lookup
342531
+ const numeratorSpec = {
342532
+ name: numeratorUnit.name,
342533
+ label: numeratorLabel?.length ? numeratorLabel : numeratorUnit.label,
342534
+ system: numeratorUnit.system,
342535
+ conversion: { factor: 1.0, offset: 0.0 },
342536
+ };
342537
+ conversions.push(numeratorSpec);
342538
+ // Denominator unit for label lookup
342539
+ const denominatorSpec = {
342540
+ name: denominatorUnit.name,
342541
+ label: denominatorLabel?.length ? denominatorLabel : denominatorUnit.label,
342542
+ system: denominatorUnit.system,
342543
+ conversion: { factor: 1.0, offset: 0.0 },
342544
+ };
342545
+ conversions.push(denominatorSpec);
342546
+ return conversions;
342547
+ }
342169
342548
  /** Get an array of UnitConversionSpecs, one for each unit that is to be shown in the formatted quantity string. */
342170
342549
  static async getUnitConversions(format, unitsProvider, inputUnit) {
342171
342550
  const conversions = [];
@@ -342179,6 +342558,10 @@ class FormatterSpec {
342179
342558
  throw new Error("Formatter Spec needs persistence unit to be specified");
342180
342559
  }
342181
342560
  }
342561
+ // Handle 2-unit composite for ratio formats (scale factors)
342562
+ if (format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_0__.FormatType.Ratio && format.units && format.units.length === 2) {
342563
+ return FormatterSpec.getRatioUnitConversions(format.units, unitsProvider, persistenceUnit);
342564
+ }
342182
342565
  if (format.units) {
342183
342566
  let convertFromUnit = inputUnit;
342184
342567
  for (const unit of format.units) {
@@ -342235,7 +342618,7 @@ class FormatterSpec {
342235
342618
  }
342236
342619
  /** Format a quantity value. */
342237
342620
  applyFormatting(magnitude) {
342238
- return _Formatter__WEBPACK_IMPORTED_MODULE_0__.Formatter.formatQuantity(magnitude, this);
342621
+ return _Formatter__WEBPACK_IMPORTED_MODULE_1__.Formatter.formatQuantity(magnitude, this);
342239
342622
  }
342240
342623
  }
342241
342624
 
@@ -342343,13 +342726,14 @@ var ParseError;
342343
342726
  ParseError[ParseError["BearingPrefixOrSuffixMissing"] = 7] = "BearingPrefixOrSuffixMissing";
342344
342727
  ParseError[ParseError["MathematicOperationFoundButIsNotAllowed"] = 8] = "MathematicOperationFoundButIsNotAllowed";
342345
342728
  ParseError[ParseError["BearingAngleOutOfRange"] = 9] = "BearingAngleOutOfRange";
342729
+ ParseError[ParseError["InvalidMathResult"] = 10] = "InvalidMathResult";
342346
342730
  })(ParseError || (ParseError = {}));
342347
342731
  var Operator;
342348
342732
  (function (Operator) {
342349
342733
  Operator["addition"] = "+";
342350
342734
  Operator["subtraction"] = "-";
342351
342735
  Operator["multiplication"] = "*";
342352
- Operator["division"] = "/"; // unsupported but we recognize it during parsing
342736
+ Operator["division"] = "/";
342353
342737
  })(Operator || (Operator = {}));
342354
342738
  function isOperator(char) {
342355
342739
  if (typeof char === "number") {
@@ -343104,36 +343488,107 @@ class Parser {
343104
343488
  magnitude = this.normalizeAngle(magnitude, revolution);
343105
343489
  return { ok: true, value: magnitude };
343106
343490
  }
343491
+ /**
343492
+ * Parse a ratio part string (numerator or denominator) to extract the numeric value and optional unit label.
343493
+ * This method processes tokens without applying unit conversions, allowing the ratio format
343494
+ * handler to manage conversions at the ratio level.
343495
+ *
343496
+ *
343497
+ * @note Fractions are already handled by parseQuantitySpecification, which converts them to
343498
+ * single numeric tokens (e.g., "1/2" becomes 0.5).
343499
+ *
343500
+ * @param partStr The string to parse, which may contain a number, fraction, or mixed fraction with optional unit label.
343501
+ * @param format The format specification used for token parsing.
343502
+ * @returns An object containing the parsed numeric value and optional unit label. Returns NaN for value if no number is found.
343503
+ */
343504
+ static parseRatioPart(partStr, format) {
343505
+ partStr = partStr.trim();
343506
+ // Parse tokens - fractions are automatically converted to decimal values by parseQuantitySpecification
343507
+ const tempFormat = format.clone({ type: _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Decimal });
343508
+ const tokens = Parser.parseQuantitySpecification(partStr, tempFormat);
343509
+ let value = NaN;
343510
+ let unitLabel;
343511
+ // Pre-process: merge negative operators with following numbers
343512
+ const processedTokens = [];
343513
+ for (let i = 0; i < tokens.length; i++) {
343514
+ const token = tokens[i];
343515
+ if (token.isOperator && i === 0 && token.value === "-" &&
343516
+ i + 1 < tokens.length && tokens[i + 1].isNumber) {
343517
+ // Merge negative sign with number
343518
+ processedTokens.push(new ParseToken(-tokens[i + 1].value));
343519
+ i++; // Skip the number token since we consumed it
343520
+ }
343521
+ else {
343522
+ processedTokens.push(token);
343523
+ }
343524
+ }
343525
+ // Extract numeric value and unit label from processed tokens
343526
+ for (const token of processedTokens) {
343527
+ if (token.isNumber && isNaN(value)) {
343528
+ value = token.value;
343529
+ }
343530
+ else if (token.isString && !token.isOperator) {
343531
+ // String token that's not an operator - treat as unit label
343532
+ unitLabel = token.value;
343533
+ }
343534
+ }
343535
+ return { value, unitLabel };
343536
+ }
343107
343537
  static parseRatioFormat(inString, spec) {
343108
343538
  if (!inString)
343109
343539
  return { ok: false, error: ParseError.NoValueOrUnitFoundInString };
343110
- const parts = inString.split(":");
343540
+ const separator = spec.format.ratioSeparator ?? ":";
343541
+ const parts = inString.split(separator);
343111
343542
  if (parts.length > 2)
343112
343543
  return { ok: false, error: ParseError.UnableToConvertParseTokensToQuantity };
343113
- const numerator = parseFloat(parts[0]);
343114
- let denominator;
343115
- if (parts.length === 1) {
343116
- denominator = 1.0;
343117
- }
343118
- else {
343119
- denominator = parseFloat(parts[1]);
343544
+ // If the string doesn't contain the expected separator but contains other ratio-like separators,
343545
+ // return an error since the wrong separator was used
343546
+ if (parts.length === 1 && !inString.includes(separator)) {
343547
+ // Check if the string contains other common ratio separators
343548
+ const otherSeparators = [":", "=", "/"];
343549
+ for (const otherSep of otherSeparators) {
343550
+ if (otherSep !== separator && inString.includes(otherSep)) {
343551
+ // The string looks like a ratio but uses the wrong separator
343552
+ return { ok: false, error: ParseError.UnableToConvertParseTokensToQuantity };
343553
+ }
343554
+ }
343555
+ // Parse as a regular quantity value (numerator only, denominator = 1)
343556
+ const result = this.parseAndProcessTokens(inString, spec.format, spec.unitConversions);
343557
+ return result;
343120
343558
  }
343121
- if (isNaN(numerator) || isNaN(denominator))
343559
+ // Parse numerator and denominator parts which may include unit labels
343560
+ const numeratorPart = this.parseRatioPart(parts[0], spec.format);
343561
+ const denominatorPart = parts.length === 1 ? { value: 1.0 } : this.parseRatioPart(parts[1], spec.format);
343562
+ if (isNaN(numeratorPart.value) || isNaN(denominatorPart.value))
343122
343563
  return { ok: false, error: ParseError.NoValueOrUnitFoundInString };
343564
+ // Handle 2-unit composite case - simpler conversion using the pre-computed scale factor
343565
+ if (spec.format.units && spec.format.units.length === 2 && spec.unitConversions.length >= 3) {
343566
+ const ratioConvSpec = spec.unitConversions[0];
343567
+ const scaleFactor = ratioConvSpec.conversion.factor;
343568
+ if (denominatorPart.value === 0) {
343569
+ return { ok: false, error: ParseError.InvalidMathResult };
343570
+ }
343571
+ // The ratio value is numerator/denominator in the display units (e.g., 12 for 12"=1')
343572
+ // Divide by scale factor to get persistence unit value (e.g., 12/12 = 1.0)
343573
+ const ratioValue = numeratorPart.value / denominatorPart.value;
343574
+ const convertedValue = ratioValue / scaleFactor;
343575
+ return { ok: true, value: convertedValue };
343576
+ }
343577
+ // Original flow for 1-unit composite - use Quantity.convertTo for proper unit conversion
343123
343578
  const defaultUnit = spec.format.units && spec.format.units.length > 0 ? spec.format.units[0][0] : undefined;
343124
343579
  const unitConversion = defaultUnit ? Parser.tryFindUnitConversion(defaultUnit.label, spec.unitConversions, defaultUnit) : undefined;
343125
343580
  if (!unitConversion) {
343126
343581
  throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.MissingRequiredProperty, `Missing input unit or unit conversion for interpreting ${spec.format.name}.`);
343127
343582
  }
343128
- if (denominator === 0) {
343129
- if (unitConversion.inversion && numerator === 1)
343583
+ if (denominatorPart.value === 0) {
343584
+ if (unitConversion.inversion && numeratorPart.value === 1)
343130
343585
  return { ok: true, value: 0.0 };
343131
343586
  else
343132
- return { ok: false, error: ParseError.MathematicOperationFoundButIsNotAllowed };
343587
+ return { ok: false, error: ParseError.InvalidMathResult };
343133
343588
  }
343134
343589
  let quantity;
343135
343590
  if (spec.format.units && spec.outUnit) {
343136
- quantity = new _Quantity__WEBPACK_IMPORTED_MODULE_3__.Quantity(spec.format.units[0][0], numerator / denominator);
343591
+ quantity = new _Quantity__WEBPACK_IMPORTED_MODULE_3__.Quantity(spec.format.units[0][0], numeratorPart.value / denominatorPart.value);
343137
343592
  }
343138
343593
  else {
343139
343594
  throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.MissingRequiredProperty, "Missing presentation unit or persistence unit for ratio format.");
@@ -343145,7 +343600,7 @@ class Parser {
343145
343600
  catch (err) {
343146
343601
  // for input of "0:N" with reversed unit
343147
343602
  if (err instanceof _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError && err.errorNumber === _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvertingZero) {
343148
- return { ok: false, error: ParseError.MathematicOperationFoundButIsNotAllowed };
343603
+ return { ok: false, error: ParseError.InvalidMathResult };
343149
343604
  }
343150
343605
  }
343151
343606
  if (converted === undefined || !converted.isValid) {
@@ -343271,7 +343726,8 @@ __webpack_require__.r(__webpack_exports__);
343271
343726
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
343272
343727
  /* harmony export */ ParserSpec: () => (/* binding */ ParserSpec)
343273
343728
  /* harmony export */ });
343274
- /* harmony import */ var _Parser__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Parser */ "../../core/quantity/lib/esm/Parser.js");
343729
+ /* harmony import */ var _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Formatter/FormatEnums */ "../../core/quantity/lib/esm/Formatter/FormatEnums.js");
343730
+ /* harmony import */ var _Parser__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Parser */ "../../core/quantity/lib/esm/Parser.js");
343275
343731
  /*---------------------------------------------------------------------------------------------
343276
343732
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
343277
343733
  * See LICENSE.md in the project root for license terms and full copyright notice.
@@ -343280,6 +343736,7 @@ __webpack_require__.r(__webpack_exports__);
343280
343736
  * @module Quantity
343281
343737
  */
343282
343738
 
343739
+
343283
343740
  /** A ParserSpec holds information needed to parse a string into a quantity synchronously.
343284
343741
  * @beta
343285
343742
  */
@@ -343305,6 +343762,51 @@ class ParserSpec {
343305
343762
  get outUnit() { return this._outUnit; }
343306
343763
  get azimuthBaseConversion() { return this._azimuthBaseConversion; }
343307
343764
  get revolutionConversion() { return this._revolutionConversion; }
343765
+ /** Build conversion specs for ratio format with 2 composite units (numerator/denominator). */
343766
+ static async getRatioUnitConversions(units, unitsProvider, outUnit, altUnitLabelsProvider) {
343767
+ const conversions = [];
343768
+ const [numeratorUnit, numeratorLabel] = units[0];
343769
+ const [denominatorUnit, denominatorLabel] = units[1];
343770
+ // Compute ratio scale: how many numerator units per denominator unit (e.g., IN:FT = 12)
343771
+ const denominatorToNumerator = await unitsProvider.getConversion(denominatorUnit, numeratorUnit);
343772
+ const displayRatioScale = denominatorToNumerator.factor;
343773
+ // Avoid double-scaling: if persistence unit already encodes the display ratio, use factor 1.
343774
+ // Check by name heuristic (e.g., IN_PER_FT with ratioUnits [IN, FT] → no scaling needed)
343775
+ const persistenceName = outUnit.name.toUpperCase();
343776
+ const numName = numeratorUnit.name.toUpperCase().split(".").pop() ?? "";
343777
+ const denName = denominatorUnit.name.toUpperCase().split(".").pop() ?? "";
343778
+ // Split by word boundaries (underscores, dots) and check for exact token matches
343779
+ const persistenceTokens = persistenceName.split(/[._]/);
343780
+ const isPersistenceMatchingRatio = persistenceTokens.includes(numName) && persistenceTokens.includes(denName);
343781
+ const ratioScaleFactor = isPersistenceMatchingRatio ? 1.0 : displayRatioScale;
343782
+ // First conversion spec: effective ratio unit conversion
343783
+ const ratioConversionSpec = {
343784
+ name: `${numeratorUnit.name}_per_${denominatorUnit.name}`,
343785
+ label: "",
343786
+ system: numeratorUnit.system,
343787
+ conversion: { factor: ratioScaleFactor, offset: 0.0 },
343788
+ };
343789
+ conversions.push(ratioConversionSpec);
343790
+ // Numerator unit for label lookup
343791
+ const numeratorSpec = {
343792
+ name: numeratorUnit.name,
343793
+ label: numeratorLabel?.length ? numeratorLabel : numeratorUnit.label,
343794
+ system: numeratorUnit.system,
343795
+ conversion: { factor: 1.0, offset: 0.0 },
343796
+ parseLabels: altUnitLabelsProvider?.getAlternateUnitLabels(numeratorUnit),
343797
+ };
343798
+ conversions.push(numeratorSpec);
343799
+ // Denominator unit for label lookup
343800
+ const denominatorSpec = {
343801
+ name: denominatorUnit.name,
343802
+ label: denominatorLabel?.length ? denominatorLabel : denominatorUnit.label,
343803
+ system: denominatorUnit.system,
343804
+ conversion: { factor: 1.0, offset: 0.0 },
343805
+ parseLabels: altUnitLabelsProvider?.getAlternateUnitLabels(denominatorUnit),
343806
+ };
343807
+ conversions.push(denominatorSpec);
343808
+ return conversions;
343809
+ }
343308
343810
  /** Static async method to create a ParserSpec given the format and unit of the quantity that will be passed to the Parser. The input unit will
343309
343811
  * be used to generate conversion information for each unit specified in the Format. This method is async due to the fact that the units provider must make
343310
343812
  * async calls to lookup unit definitions.
@@ -343313,7 +343815,14 @@ class ParserSpec {
343313
343815
  * @param outUnit The unit a value will be formatted to. This unit is often referred to as persistence unit.
343314
343816
  */
343315
343817
  static async create(format, unitsProvider, outUnit, altUnitLabelsProvider) {
343316
- const conversions = await _Parser__WEBPACK_IMPORTED_MODULE_0__.Parser.createUnitConversionSpecsForUnit(unitsProvider, outUnit, altUnitLabelsProvider);
343818
+ let conversions;
343819
+ // For ratio formats with 2 composite units, use private helper method
343820
+ if (format.type === _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_0__.FormatType.Ratio && format.units && format.units.length === 2) {
343821
+ conversions = await ParserSpec.getRatioUnitConversions(format.units, unitsProvider, outUnit, altUnitLabelsProvider);
343822
+ }
343823
+ else {
343824
+ conversions = await _Parser__WEBPACK_IMPORTED_MODULE_1__.Parser.createUnitConversionSpecsForUnit(unitsProvider, outUnit, altUnitLabelsProvider);
343825
+ }
343317
343826
  const spec = new ParserSpec(outUnit, format, conversions);
343318
343827
  if (format.azimuthBaseUnit !== undefined) {
343319
343828
  if (outUnit !== undefined) {
@@ -343335,7 +343844,7 @@ class ParserSpec {
343335
343844
  }
343336
343845
  /** Do the parsing. Done this way to allow Custom Parser Specs to parse custom formatted strings into their quantities. */
343337
343846
  parseToQuantityValue(inString) {
343338
- return _Parser__WEBPACK_IMPORTED_MODULE_0__.Parser.parseQuantityString(inString, this);
343847
+ return _Parser__WEBPACK_IMPORTED_MODULE_1__.Parser.parseQuantityString(inString, this);
343339
343848
  }
343340
343849
  }
343341
343850
 
@@ -343533,6 +344042,7 @@ __webpack_require__.r(__webpack_exports__);
343533
344042
  /* harmony export */ QuantityConstants: () => (/* reexport safe */ _Constants__WEBPACK_IMPORTED_MODULE_0__.QuantityConstants),
343534
344043
  /* harmony export */ QuantityError: () => (/* reexport safe */ _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError),
343535
344044
  /* harmony export */ QuantityStatus: () => (/* reexport safe */ _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus),
344045
+ /* harmony export */ RatioFormatType: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.RatioFormatType),
343536
344046
  /* harmony export */ RatioType: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.RatioType),
343537
344047
  /* harmony export */ ScientificType: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.ScientificType),
343538
344048
  /* harmony export */ ShowSignOption: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.ShowSignOption),
@@ -343551,6 +344061,7 @@ __webpack_require__.r(__webpack_exports__);
343551
344061
  /* harmony export */ parseFormatType: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.parseFormatType),
343552
344062
  /* harmony export */ parseFractionalPrecision: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.parseFractionalPrecision),
343553
344063
  /* harmony export */ parsePrecision: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.parsePrecision),
344064
+ /* harmony export */ parseRatioFormatType: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.parseRatioFormatType),
343554
344065
  /* harmony export */ parseRatioType: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.parseRatioType),
343555
344066
  /* harmony export */ parseScientificType: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.parseScientificType),
343556
344067
  /* harmony export */ parseShowSignOption: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.parseShowSignOption),
@@ -344510,7 +345021,7 @@ class TestContext {
344510
345021
  this.initializeRpcInterfaces({ title: this.settings.Backend.name, version: this.settings.Backend.version });
344511
345022
  const iModelClient = new imodels_client_management_1.IModelsClient({ api: { baseUrl: `https://${process.env.IMJS_URL_PREFIX ?? ""}api.bentley.com/imodels` } });
344512
345023
  await core_frontend_1.NoRenderApp.startup({
344513
- applicationVersion: "5.6.0-dev.8",
345024
+ applicationVersion: "5.7.0-dev.1",
344514
345025
  applicationId: this.settings.gprid,
344515
345026
  authorizationClient: new frontend_1.TestFrontendAuthorizationClient(this.serviceAuthToken),
344516
345027
  hubAccess: new imodels_access_frontend_1.FrontendIModelsAccess(iModelClient),
@@ -371203,7 +371714,7 @@ var loadLanguages = instance.loadLanguages;
371203
371714
  /***/ ((module) => {
371204
371715
 
371205
371716
  "use strict";
371206
- module.exports = /*#__PURE__*/JSON.parse('{"name":"@itwin/core-frontend","version":"5.6.0-dev.8","description":"iTwin.js frontend components","main":"lib/cjs/core-frontend.js","module":"lib/esm/core-frontend.js","typings":"lib/cjs/core-frontend","license":"MIT","scripts":{"build":"npm run -s copy:public && npm run -s build:cjs && npm run -s build:esm && npm run -s webpackWorkers && npm run -s copy:workers && npm run -s copy:draco","build:cjs":"npm run -s copy:js:cjs && tsc 1>&2 --outDir lib/cjs","build:esm":"npm run -s copy:js:esm && tsc 1>&2 --module ES2022 --outDir lib/esm","clean":"rimraf -g lib .rush/temp/package-deps*.json","copy:public":"cpx \\"./src/public/**/*\\" ./lib/public","copy:js:cjs":"cpx \\"./src/**/*.js\\" ./lib/cjs","copy:js:esm":"cpx \\"./src/**/*.js\\" ./lib/esm","copy:workers":"cpx \\"./lib/workers/webpack/parse-imdl-worker.js\\" ./lib/public/scripts","copy:draco":"cpx \\"./node_modules/@loaders.gl/draco/dist/libs/*\\" ./lib/public/scripts","docs":"betools docs --json=../../generated-docs/core/core-frontend/file.json --tsIndexFile=./core-frontend.ts --onlyJson --excludes=webgl/**/*,**/map/*.d.ts,**/tile/*.d.ts,**/*-css.ts","extract-api":"betools extract-api --entry=core-frontend && npm run extract-extension-api","extract-extension-api":"eslint --no-inline-config -c extraction.eslint.config.js \\"./src/**/*.ts\\" 1>&2","lint":"eslint \\"./src/**/*.ts\\" 1>&2","lint-fix":"eslint --fix -f visualstudio \\"./src/**/*.ts\\" 1>&2","lint-deprecation":"eslint --fix -f visualstudio --no-inline-config -c ../../common/config/eslint/eslint.config.deprecation-policy.js \\"./src/**/*.ts\\"","pseudolocalize":"betools pseudolocalize --englishDir ./src/public/locales/en --out ./public/locales/en-PSEUDO","test":"npm run webpackTestWorker && vitest --run","cover":"npm run webpackTestWorker && vitest --run","webpackTests":"webpack --config ./src/test/utils/webpack.config.js 1>&2 && npm run -s webpackTestWorker","webpackTestWorker":"webpack --config ./src/test/worker/webpack.config.js 1>&2 && cpx \\"./lib/test/test-worker.js\\" ./lib/test","webpackWorkers":"webpack --config ./src/workers/ImdlParser/webpack.config.js 1>&2"},"repository":{"type":"git","url":"https://github.com/iTwin/itwinjs-core.git","directory":"core/frontend"},"keywords":["Bentley","BIM","iModel","digital-twin","iTwin"],"author":{"name":"Bentley Systems, Inc.","url":"http://www.bentley.com"},"peerDependencies":{"@itwin/appui-abstract":"workspace:*","@itwin/core-bentley":"workspace:*","@itwin/core-common":"workspace:*","@itwin/core-geometry":"workspace:*","@itwin/core-orbitgt":"workspace:*","@itwin/core-quantity":"workspace:*","@itwin/ecschema-metadata":"workspace:*","@itwin/ecschema-rpcinterface-common":"workspace:*"},"//devDependencies":["NOTE: All peerDependencies should also be listed as devDependencies since peerDependencies are not considered by npm install","NOTE: All tools used by scripts in this package must be listed as devDependencies"],"devDependencies":{"@itwin/appui-abstract":"workspace:*","@itwin/build-tools":"workspace:*","@itwin/core-bentley":"workspace:*","@itwin/core-common":"workspace:*","@itwin/core-geometry":"workspace:*","@itwin/core-orbitgt":"workspace:*","@itwin/core-quantity":"workspace:*","@itwin/ecschema-metadata":"workspace:*","@itwin/ecschema-rpcinterface-common":"workspace:*","@itwin/object-storage-core":"^3.0.4","@itwin/eslint-plugin":"5.2.2-dev.2","@types/chai-as-promised":"^7","@types/draco3d":"^1.4.10","@types/sinon":"^17.0.2","@vitest/browser":"^3.0.6","@vitest/coverage-v8":"^3.0.6","cpx2":"^8.0.0","eslint":"^9.31.0","glob":"^10.5.0","playwright":"~1.56.1","rimraf":"^6.0.1","sinon":"^17.0.2","source-map-loader":"^5.0.0","typescript":"~5.6.2","typemoq":"^2.1.0","vitest":"^3.0.6","vite-multiple-assets":"^1.3.1","vite-plugin-static-copy":"2.2.0","webpack":"^5.97.1"},"//dependencies":["NOTE: these dependencies should be only for things that DO NOT APPEAR IN THE API","NOTE: core-frontend should remain UI technology agnostic, so no react/angular dependencies are allowed"],"dependencies":{"@itwin/core-i18n":"workspace:*","@itwin/webgl-compatibility":"workspace:*","@loaders.gl/draco":"^4.3.4","fuse.js":"^3.3.0","wms-capabilities":"0.4.0"}}');
371717
+ module.exports = /*#__PURE__*/JSON.parse('{"name":"@itwin/core-frontend","version":"5.7.0-dev.1","description":"iTwin.js frontend components","main":"lib/cjs/core-frontend.js","module":"lib/esm/core-frontend.js","typings":"lib/cjs/core-frontend","license":"MIT","scripts":{"build":"npm run -s copy:public && npm run -s build:cjs && npm run -s build:esm && npm run -s webpackWorkers && npm run -s copy:workers && npm run -s copy:draco","build:cjs":"npm run -s copy:js:cjs && tsc 1>&2 --outDir lib/cjs","build:esm":"npm run -s copy:js:esm && tsc 1>&2 --module ES2022 --outDir lib/esm","clean":"rimraf -g lib .rush/temp/package-deps*.json","copy:public":"cpx \\"./src/public/**/*\\" ./lib/public","copy:js:cjs":"cpx \\"./src/**/*.js\\" ./lib/cjs","copy:js:esm":"cpx \\"./src/**/*.js\\" ./lib/esm","copy:workers":"cpx \\"./lib/workers/webpack/parse-imdl-worker.js\\" ./lib/public/scripts","copy:draco":"cpx \\"./node_modules/@loaders.gl/draco/dist/libs/*\\" ./lib/public/scripts","docs":"betools docs --json=../../generated-docs/core/core-frontend/file.json --tsIndexFile=./core-frontend.ts --onlyJson --excludes=webgl/**/*,**/map/*.d.ts,**/tile/*.d.ts,**/*-css.ts","extract-api":"betools extract-api --entry=core-frontend && npm run extract-extension-api","extract-extension-api":"eslint --no-inline-config -c extraction.eslint.config.js \\"./src/**/*.ts\\" 1>&2","lint":"eslint \\"./src/**/*.ts\\" 1>&2","lint-fix":"eslint --fix -f visualstudio \\"./src/**/*.ts\\" 1>&2","lint-deprecation":"eslint --fix -f visualstudio --no-inline-config -c ../../common/config/eslint/eslint.config.deprecation-policy.js \\"./src/**/*.ts\\"","pseudolocalize":"betools pseudolocalize --englishDir ./src/public/locales/en --out ./public/locales/en-PSEUDO","test":"npm run webpackTestWorker && vitest --run","cover":"npm run webpackTestWorker && vitest --run","webpackTests":"webpack --config ./src/test/utils/webpack.config.js 1>&2 && npm run -s webpackTestWorker","webpackTestWorker":"webpack --config ./src/test/worker/webpack.config.js 1>&2 && cpx \\"./lib/test/test-worker.js\\" ./lib/test","webpackWorkers":"webpack --config ./src/workers/ImdlParser/webpack.config.js 1>&2"},"repository":{"type":"git","url":"https://github.com/iTwin/itwinjs-core.git","directory":"core/frontend"},"keywords":["Bentley","BIM","iModel","digital-twin","iTwin"],"author":{"name":"Bentley Systems, Inc.","url":"http://www.bentley.com"},"peerDependencies":{"@itwin/appui-abstract":"workspace:*","@itwin/core-bentley":"workspace:*","@itwin/core-common":"workspace:*","@itwin/core-geometry":"workspace:*","@itwin/core-orbitgt":"workspace:*","@itwin/core-quantity":"workspace:*","@itwin/ecschema-metadata":"workspace:*","@itwin/ecschema-rpcinterface-common":"workspace:*"},"//devDependencies":["NOTE: All peerDependencies should also be listed as devDependencies since peerDependencies are not considered by npm install","NOTE: All tools used by scripts in this package must be listed as devDependencies"],"devDependencies":{"@itwin/appui-abstract":"workspace:*","@itwin/build-tools":"workspace:*","@itwin/core-bentley":"workspace:*","@itwin/core-common":"workspace:*","@itwin/core-geometry":"workspace:*","@itwin/core-orbitgt":"workspace:*","@itwin/core-quantity":"workspace:*","@itwin/ecschema-metadata":"workspace:*","@itwin/ecschema-rpcinterface-common":"workspace:*","@itwin/object-storage-core":"^3.0.4","@itwin/eslint-plugin":"^6.0.0","@types/chai-as-promised":"^7","@types/draco3d":"^1.4.10","@types/sinon":"^17.0.2","@vitest/browser":"^3.0.6","@vitest/coverage-v8":"^3.0.6","cpx2":"^8.0.0","eslint":"^9.31.0","glob":"^10.5.0","playwright":"~1.56.1","rimraf":"^6.0.1","sinon":"^17.0.2","source-map-loader":"^5.0.0","typescript":"~5.6.2","typemoq":"^2.1.0","vitest":"^3.0.6","vite-multiple-assets":"^1.3.1","vite-plugin-static-copy":"2.2.0","webpack":"^5.97.1"},"//dependencies":["NOTE: these dependencies should be only for things that DO NOT APPEAR IN THE API","NOTE: core-frontend should remain UI technology agnostic, so no react/angular dependencies are allowed"],"dependencies":{"@itwin/core-i18n":"workspace:*","@itwin/webgl-compatibility":"workspace:*","@loaders.gl/core":"^4.3.4","@loaders.gl/draco":"^4.3.4","fuse.js":"^3.3.0","wms-capabilities":"0.4.0"}}');
371207
371718
 
371208
371719
  /***/ }),
371209
371720