@itwin/ecschema-rpcinterface-tests 5.6.0-dev.7 → 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.
@@ -44957,7 +44957,7 @@ class TextStyleSettings {
44957
44957
  listMarker;
44958
44958
  /** The frame settings of the [[TextAnnotation]]. */
44959
44959
  frame;
44960
- /** The margins to surround the document content. */
44960
+ /** Multiplier used to calculate the margins to surround the document content. */
44961
44961
  margins;
44962
44962
  /** The alignment of the text content. */
44963
44963
  justification;
@@ -63738,6 +63738,18 @@ class JsonParser extends _AbstractParser__WEBPACK_IMPORTED_MODULE_2__.AbstractPa
63738
63738
  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'.`);
63739
63739
  if (undefined !== jsonObj.scientificType && typeof (jsonObj.scientificType) !== "string")
63740
63740
  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'.`);
63741
+ if (undefined !== jsonObj.ratioType && typeof (jsonObj.ratioType) !== "string")
63742
+ 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'.`);
63743
+ if (undefined !== jsonObj.ratioSeparator && typeof (jsonObj.ratioSeparator) !== "string")
63744
+ 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'.`);
63745
+ if (undefined !== jsonObj.ratioFormatType && typeof (jsonObj.ratioFormatType) !== "string")
63746
+ 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'.`);
63747
+ // Validate EC version if ratio properties exist - they require EC version 3.3+
63748
+ if (jsonObj.ratioType !== undefined || jsonObj.ratioSeparator !== undefined || jsonObj.ratioFormatType !== undefined) {
63749
+ if (this._ecSpecVersion === undefined || this._ecSpecVersion.readVersion < 3 || (this._ecSpecVersion.readVersion === 3 && this._ecSpecVersion.writeVersion < 3)) {
63750
+ 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.`);
63751
+ }
63752
+ }
63741
63753
  if (undefined !== jsonObj.stationOffsetSize && typeof (jsonObj.stationOffsetSize) !== "number")
63742
63754
  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'.`);
63743
63755
  if (undefined !== jsonObj.stationSeparator && typeof (jsonObj.stationSeparator) !== "string")
@@ -64451,6 +64463,15 @@ class XmlParser extends _AbstractParser__WEBPACK_IMPORTED_MODULE_5__.AbstractPar
64451
64463
  const thousandSeparator = this.getOptionalAttribute(xmlElement, "thousandSeparator");
64452
64464
  const uomSeparator = this.getOptionalAttribute(xmlElement, "uomSeparator");
64453
64465
  const scientificType = this.getOptionalAttribute(xmlElement, "scientificType");
64466
+ const ratioType = this.getOptionalAttribute(xmlElement, "ratioType");
64467
+ const ratioSeparator = this.getOptionalAttribute(xmlElement, "ratioSeparator");
64468
+ const ratioFormatType = this.getOptionalAttribute(xmlElement, "ratioFormatType");
64469
+ // Validate EC version if ratio properties exist - they require EC version 3.3+
64470
+ if (ratioType !== undefined || ratioSeparator !== undefined || ratioFormatType !== undefined) {
64471
+ if (this._ecSpecVersion === undefined || this._ecSpecVersion.readVersion < 3 || (this._ecSpecVersion.readVersion === 3 && this._ecSpecVersion.writeVersion < 3)) {
64472
+ 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.`);
64473
+ }
64474
+ }
64454
64475
  const stationOffsetSize = this.getOptionalIntAttribute(xmlElement, "stationOffsetSize", `The Format ${this._currentItemFullName} has an invalid 'stationOffsetSize' attribute. It should be a numeric value.`);
64455
64476
  const stationSeparator = this.getOptionalAttribute(xmlElement, "stationSeparator");
64456
64477
  let composite;
@@ -64493,6 +64514,9 @@ class XmlParser extends _AbstractParser__WEBPACK_IMPORTED_MODULE_5__.AbstractPar
64493
64514
  thousandSeparator,
64494
64515
  uomSeparator,
64495
64516
  scientificType,
64517
+ ratioType,
64518
+ ratioSeparator,
64519
+ ratioFormatType,
64496
64520
  stationOffsetSize,
64497
64521
  stationSeparator,
64498
64522
  composite,
@@ -66236,7 +66260,7 @@ class SchemaFormatsProvider {
66236
66260
  // If no matching presentation format was found, use persistence unit format if it matches unit system.
66237
66261
  const persistenceUnit = await kindOfQuantity.persistenceUnit;
66238
66262
  const persistenceUnitSystem = await persistenceUnit?.unitSystem;
66239
- if (persistenceUnitSystem && unitSystemMatchers.some((matcher) => matcher(persistenceUnitSystem))) {
66263
+ if (persistenceUnit && persistenceUnitSystem && unitSystemMatchers.some((matcher) => matcher(persistenceUnitSystem))) {
66240
66264
  this._formatsRetrieved.add(itemKey.fullName);
66241
66265
  const props = getPersistenceUnitFormatProps(persistenceUnit);
66242
66266
  return this.convertToFormatDefinition(props, kindOfQuantity);
@@ -68833,6 +68857,7 @@ __webpack_require__.r(__webpack_exports__);
68833
68857
 
68834
68858
 
68835
68859
 
68860
+ const loggingCategory = "ECClass";
68836
68861
  /**
68837
68862
  * A common abstract class for all of the ECClass types.
68838
68863
  * @public @preview
@@ -68887,7 +68912,13 @@ class ECClass extends _SchemaItem__WEBPACK_IMPORTED_MODULE_9__.SchemaItem {
68887
68912
  async getDerivedClasses() {
68888
68913
  const derivedClasses = [];
68889
68914
  for (const derivedClassKey of this.schema.context.classHierarchy.getDerivedClassKeys(this.key)) {
68890
- const derivedClass = await this.schema.context.getSchemaItem(derivedClassKey, ECClass);
68915
+ 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
68916
+ if (derivedClass) {
68917
+ derivedClasses.push(derivedClass);
68918
+ continue;
68919
+ }
68920
+ _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.`);
68921
+ derivedClass = await this.schema.context.getSchemaItem(derivedClassKey, ECClass);
68891
68922
  if (derivedClass)
68892
68923
  derivedClasses.push(derivedClass);
68893
68924
  }
@@ -69275,18 +69306,56 @@ class ECClass extends _SchemaItem__WEBPACK_IMPORTED_MODULE_9__.SchemaItem {
69275
69306
  */
69276
69307
  async *getAllBaseClasses() {
69277
69308
  for (const baseClassKey of this.schema.context.classHierarchy.getBaseClassKeys(this.key)) {
69278
- const baseClass = await this.schema.lookupItem(baseClassKey, ECClass);
69309
+ const baseClass = await this.getClassFromReferencesRecursively(baseClassKey); // Search in schema ref tree all the way to the top
69279
69310
  if (baseClass)
69280
69311
  yield baseClass;
69281
69312
  }
69282
69313
  }
69314
+ /**
69315
+ * gets a class from this schema or its references recursively using the item key
69316
+ * @param itemKey
69317
+ * @returns ECClass if it could be found, undefined otherwise
69318
+ * @internal
69319
+ */
69320
+ async getClassFromReferencesRecursively(itemKey) {
69321
+ const schemaList = [this.schema];
69322
+ while (schemaList.length > 0) {
69323
+ const currentSchema = schemaList.shift();
69324
+ if (currentSchema.schemaKey.compareByName(itemKey.schemaKey)) {
69325
+ const baseClass = await currentSchema.getItem(itemKey.name, ECClass);
69326
+ schemaList.splice(0); // clear the list
69327
+ return baseClass;
69328
+ }
69329
+ schemaList.push(...currentSchema.references);
69330
+ }
69331
+ return undefined;
69332
+ }
69283
69333
  *getAllBaseClassesSync() {
69284
69334
  for (const baseClassKey of this.schema.context.classHierarchy.getBaseClassKeys(this.key)) {
69285
- const baseClass = this.schema.lookupItemSync(baseClassKey, ECClass);
69335
+ const baseClass = this.getClassFromReferencesRecursivelySync(baseClassKey); // Search in schema ref tree all the way to the top
69286
69336
  if (baseClass)
69287
69337
  yield baseClass;
69288
69338
  }
69289
69339
  }
69340
+ /**
69341
+ * gets a class from this schema or its references recursively using the item key synchronously
69342
+ * @param itemKey
69343
+ * @returns ECClass if it could be found, undefined otherwise
69344
+ * @internal
69345
+ */
69346
+ getClassFromReferencesRecursivelySync(itemKey) {
69347
+ const schemaList = [this.schema];
69348
+ while (schemaList.length > 0) {
69349
+ const currentSchema = schemaList.shift();
69350
+ if (currentSchema.schemaKey.compareByName(itemKey.schemaKey)) {
69351
+ const baseClass = currentSchema.getItemSync(itemKey.name, ECClass);
69352
+ schemaList.splice(0); // clear the list
69353
+ return baseClass;
69354
+ }
69355
+ schemaList.push(...currentSchema.references);
69356
+ }
69357
+ return undefined;
69358
+ }
69290
69359
  /**
69291
69360
  *
69292
69361
  * @param cache
@@ -70422,6 +70491,9 @@ class Format extends _SchemaItem__WEBPACK_IMPORTED_MODULE_5__.SchemaItem {
70422
70491
  get stationSeparator() { return this._base.stationSeparator; }
70423
70492
  get stationOffsetSize() { return this._base.stationOffsetSize; }
70424
70493
  get stationBaseFactor() { return this._base.stationBaseFactor; }
70494
+ get ratioType() { return this._base.ratioType; }
70495
+ get ratioSeparator() { return this._base.ratioSeparator; }
70496
+ get ratioFormatType() { return this._base.ratioFormatType; }
70425
70497
  get formatTraits() { return this._base.formatTraits; }
70426
70498
  get spacer() { return this._base.spacer; }
70427
70499
  get includeZero() { return this._base.includeZero; }
@@ -70443,10 +70515,13 @@ class Format extends _SchemaItem__WEBPACK_IMPORTED_MODULE_5__.SchemaItem {
70443
70515
  addUnit(unit, label) {
70444
70516
  if (undefined === this._units)
70445
70517
  this._units = [];
70446
- else { // Validate that a duplicate is not added.
70447
- for (const existingUnit of this._units) {
70448
- if (unit.fullName.toLowerCase() === existingUnit[0].fullName.toLowerCase())
70449
- 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.
70518
+ else {
70519
+ const isDuplicateAllowed = this.type === _itwin_core_quantity__WEBPACK_IMPORTED_MODULE_3__.FormatType.Ratio;
70520
+ if (!isDuplicateAllowed) {
70521
+ for (const existingUnit of this._units) {
70522
+ if (unit.fullName.toLowerCase() === existingUnit[0].fullName.toLowerCase())
70523
+ 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.
70524
+ }
70450
70525
  }
70451
70526
  }
70452
70527
  this._units.push([unit, label]);
@@ -70471,37 +70546,87 @@ class Format extends _SchemaItem__WEBPACK_IMPORTED_MODULE_5__.SchemaItem {
70471
70546
  if (formatProps.composite.units.length <= 0 || formatProps.composite.units.length > 4)
70472
70547
  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.`);
70473
70548
  }
70549
+ // For Ratio formats: validate that composite is provided
70550
+ if (this.type === _itwin_core_quantity__WEBPACK_IMPORTED_MODULE_3__.FormatType.Ratio) {
70551
+ const hasComposite = undefined !== formatProps.composite && formatProps.composite.units.length > 0;
70552
+ if (!hasComposite) {
70553
+ 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.`);
70554
+ }
70555
+ }
70474
70556
  }
70475
70557
  fromJSONSync(formatProps) {
70476
70558
  super.fromJSONSync(formatProps);
70477
70559
  this.typecheck(formatProps);
70478
- if (undefined === formatProps.composite)
70479
- return;
70480
- // Units are separated from the rest of the deserialization because of the need to have separate sync and async implementation
70481
- for (const unit of formatProps.composite.units) {
70482
- const newUnit = this.schema.lookupItemSync(unit.name);
70483
- if (undefined === newUnit || (!_Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(newUnit) && !_InvertedUnit__WEBPACK_IMPORTED_MODULE_4__.InvertedUnit.isInvertedUnit(newUnit)))
70484
- throw new _Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaStatus.InvalidECJson, ``);
70485
- if (_Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(newUnit))
70486
- this.addUnit(new _DelayedPromise__WEBPACK_IMPORTED_MODULE_7__.DelayedPromiseWithProps(newUnit.key, async () => newUnit), unit.label);
70487
- else if (_InvertedUnit__WEBPACK_IMPORTED_MODULE_4__.InvertedUnit.isInvertedUnit(newUnit))
70488
- this.addUnit(new _DelayedPromise__WEBPACK_IMPORTED_MODULE_7__.DelayedPromiseWithProps(newUnit.key, async () => newUnit), unit.label);
70560
+ // Process composite units
70561
+ if (undefined !== formatProps.composite) {
70562
+ for (const unit of formatProps.composite.units) {
70563
+ const newUnit = this.schema.lookupItemSync(unit.name);
70564
+ if (undefined === newUnit || (!_Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(newUnit) && !_InvertedUnit__WEBPACK_IMPORTED_MODULE_4__.InvertedUnit.isInvertedUnit(newUnit)))
70565
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaStatus.InvalidECJson, ``);
70566
+ const lazyUnit = _Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(newUnit)
70567
+ ? new _DelayedPromise__WEBPACK_IMPORTED_MODULE_7__.DelayedPromiseWithProps(newUnit.key, async () => newUnit)
70568
+ : new _DelayedPromise__WEBPACK_IMPORTED_MODULE_7__.DelayedPromiseWithProps(newUnit.key, async () => newUnit);
70569
+ this.addUnit(lazyUnit, unit.label);
70570
+ }
70571
+ // For Ratio formats with 2 units: validate both units have the same phenomenon
70572
+ if (this.type === _itwin_core_quantity__WEBPACK_IMPORTED_MODULE_3__.FormatType.Ratio && this._units && this._units.length === 2) {
70573
+ const unit1Item = this.schema.lookupItemSync(this._units[0][0].fullName);
70574
+ const unit2Item = this.schema.lookupItemSync(this._units[1][0].fullName);
70575
+ 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)))
70576
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaStatus.InvalidECJson, `The Format ${this.fullName} has invalid units.`);
70577
+ const getPhenomenon = (unitItem) => {
70578
+ if (_Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(unitItem)) {
70579
+ return unitItem.phenomenon;
70580
+ }
70581
+ const invertsUnit = unitItem.invertsUnit;
70582
+ if (invertsUnit) {
70583
+ const resolvedUnit = this.schema.lookupItemSync(invertsUnit.fullName);
70584
+ return resolvedUnit && _Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(resolvedUnit) ? resolvedUnit.phenomenon : undefined;
70585
+ }
70586
+ return undefined;
70587
+ };
70588
+ const phenomenon1 = getPhenomenon(unit1Item);
70589
+ const phenomenon2 = getPhenomenon(unit2Item);
70590
+ if (phenomenon1?.fullName !== phenomenon2?.fullName) {
70591
+ 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.`);
70592
+ }
70593
+ }
70489
70594
  }
70490
70595
  }
70491
70596
  async fromJSON(formatProps) {
70492
70597
  await super.fromJSON(formatProps);
70493
70598
  this.typecheck(formatProps);
70494
- if (undefined === formatProps.composite)
70495
- return;
70496
- // Units are separated from the rest of the deserialization because of the need to have separate sync and async implementation
70497
- for (const unit of formatProps.composite.units) {
70498
- const newUnit = await this.schema.lookupItem(unit.name);
70499
- if (undefined === newUnit || (!_Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(newUnit) && !_InvertedUnit__WEBPACK_IMPORTED_MODULE_4__.InvertedUnit.isInvertedUnit(newUnit)))
70500
- throw new _Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaStatus.InvalidECJson, ``);
70501
- if (_Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(newUnit))
70502
- this.addUnit(new _DelayedPromise__WEBPACK_IMPORTED_MODULE_7__.DelayedPromiseWithProps(newUnit.key, async () => newUnit), unit.label);
70503
- else if (_InvertedUnit__WEBPACK_IMPORTED_MODULE_4__.InvertedUnit.isInvertedUnit(newUnit))
70504
- this.addUnit(new _DelayedPromise__WEBPACK_IMPORTED_MODULE_7__.DelayedPromiseWithProps(newUnit.key, async () => newUnit), unit.label);
70599
+ // Process composite units
70600
+ if (undefined !== formatProps.composite) {
70601
+ for (const unit of formatProps.composite.units) {
70602
+ const newUnit = await this.schema.lookupItem(unit.name);
70603
+ if (undefined === newUnit || (!_Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(newUnit) && !_InvertedUnit__WEBPACK_IMPORTED_MODULE_4__.InvertedUnit.isInvertedUnit(newUnit)))
70604
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaStatus.InvalidECJson, ``);
70605
+ const lazyUnit = _Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(newUnit)
70606
+ ? new _DelayedPromise__WEBPACK_IMPORTED_MODULE_7__.DelayedPromiseWithProps(newUnit.key, async () => newUnit)
70607
+ : new _DelayedPromise__WEBPACK_IMPORTED_MODULE_7__.DelayedPromiseWithProps(newUnit.key, async () => newUnit);
70608
+ this.addUnit(lazyUnit, unit.label);
70609
+ }
70610
+ // For Ratio formats with 2 units: validate both units have the same phenomenon
70611
+ if (this.type === _itwin_core_quantity__WEBPACK_IMPORTED_MODULE_3__.FormatType.Ratio && this._units && this._units.length === 2) {
70612
+ const unit1Item = await this.schema.lookupItem(this._units[0][0].fullName);
70613
+ const unit2Item = await this.schema.lookupItem(this._units[1][0].fullName);
70614
+ 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)))
70615
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaError(_Exception__WEBPACK_IMPORTED_MODULE_2__.ECSchemaStatus.InvalidECJson, `The Format ${this.fullName} has invalid units.`);
70616
+ // Helper to extract phenomenon from Unit or InvertedUnit
70617
+ const getPhenomenon = async (unitItem) => {
70618
+ if (_Unit__WEBPACK_IMPORTED_MODULE_6__.Unit.isUnit(unitItem)) {
70619
+ return unitItem.phenomenon;
70620
+ }
70621
+ const invertsUnit = await unitItem.invertsUnit;
70622
+ return invertsUnit ? invertsUnit.phenomenon : undefined;
70623
+ };
70624
+ const phenomenon1 = await getPhenomenon(unit1Item);
70625
+ const phenomenon2 = await getPhenomenon(unit2Item);
70626
+ if (phenomenon1?.fullName !== phenomenon2?.fullName) {
70627
+ 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.`);
70628
+ }
70629
+ }
70505
70630
  }
70506
70631
  }
70507
70632
  /**
@@ -70538,6 +70663,15 @@ class Format extends _SchemaItem__WEBPACK_IMPORTED_MODULE_5__.SchemaItem {
70538
70663
  if (" " !== this.stationSeparator)
70539
70664
  schemaJson.stationSeparator = this.stationSeparator;
70540
70665
  }
70666
+ // Only include ratio properties for EC version 3.3+
70667
+ if (_itwin_core_quantity__WEBPACK_IMPORTED_MODULE_3__.FormatType.Ratio === this.type && this.schema.originalECSpecMajorVersion === 3 && this.schema.originalECSpecMinorVersion !== undefined && this.schema.originalECSpecMinorVersion >= 3) {
70668
+ if (undefined !== this.ratioType)
70669
+ schemaJson.ratioType = this.ratioType;
70670
+ if (undefined !== this.ratioSeparator)
70671
+ schemaJson.ratioSeparator = this.ratioSeparator;
70672
+ if (undefined !== this.ratioFormatType)
70673
+ schemaJson.ratioFormatType = this.ratioFormatType;
70674
+ }
70541
70675
  if (undefined === this.units)
70542
70676
  return schemaJson;
70543
70677
  schemaJson.composite = {};
@@ -70569,6 +70703,15 @@ class Format extends _SchemaItem__WEBPACK_IMPORTED_MODULE_5__.SchemaItem {
70569
70703
  itemElement.setAttribute("minWidth", this.minWidth.toString());
70570
70704
  if (undefined !== this.scientificType)
70571
70705
  itemElement.setAttribute("scientificType", this.scientificType);
70706
+ // Only include ratio properties for EC version 3.3+
70707
+ if (this.schema.originalECSpecMajorVersion === 3 && this.schema.originalECSpecMinorVersion !== undefined && this.schema.originalECSpecMinorVersion >= 3) {
70708
+ if (undefined !== this.ratioType)
70709
+ itemElement.setAttribute("ratioType", this.ratioType);
70710
+ if (undefined !== this.ratioSeparator)
70711
+ itemElement.setAttribute("ratioSeparator", this.ratioSeparator);
70712
+ if (undefined !== this.ratioFormatType)
70713
+ itemElement.setAttribute("ratioFormatType", this.ratioFormatType);
70714
+ }
70572
70715
  if (undefined !== this.stationOffsetSize)
70573
70716
  itemElement.setAttribute("stationOffsetSize", this.stationOffsetSize.toString());
70574
70717
  const formatTraits = (0,_itwin_core_quantity__WEBPACK_IMPORTED_MODULE_3__.formatTraitsToArray)(this.formatTraits);
@@ -71315,6 +71458,9 @@ class OverrideFormat {
71315
71458
  get type() { return this.parent.type; }
71316
71459
  get minWidth() { return this.parent.minWidth; }
71317
71460
  get scientificType() { return this.parent.scientificType; }
71461
+ get ratioType() { return this.parent.ratioType; }
71462
+ get ratioSeparator() { return this.parent.ratioSeparator; }
71463
+ get ratioFormatType() { return this.parent.ratioFormatType; }
71318
71464
  get showSignOption() { return this.parent.showSignOption; }
71319
71465
  get decimalSeparator() { return this.parent.decimalSeparator; }
71320
71466
  get thousandSeparator() { return this.parent.thousandSeparator; }
@@ -71339,7 +71485,7 @@ class OverrideFormat {
71339
71485
  for (const [unit, unitLabel] of this._units) {
71340
71486
  const unitSchema = koqSchema.context.getSchemaSync(unit.schemaKey);
71341
71487
  if (unitSchema === undefined)
71342
- 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.`);
71488
+ 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.`);
71343
71489
  fullName += "[";
71344
71490
  fullName += _Deserialization_XmlSerializationUtils__WEBPACK_IMPORTED_MODULE_0__.XmlSerializationUtils.createXmlTypedName(koqSchema, unitSchema, unit.name);
71345
71491
  if (unitLabel !== undefined)
@@ -88550,6 +88696,10 @@ class IModelApp {
88550
88696
  * @beta
88551
88697
  */
88552
88698
  static applicationLogoCard;
88699
+ /** Applications may implement this method to supply a Logo Card footer which will always be placed last.
88700
+ * @beta
88701
+ */
88702
+ static applicationLogoCardFooter;
88553
88703
  /** Make a new Logo Card. Call this method from your implementation of [[IModelApp.applicationLogoCard]]
88554
88704
  * @param opts Options for Logo Card
88555
88705
  * @beta
@@ -102601,6 +102751,9 @@ class ScreenViewport extends Viewport {
102601
102751
  for (const ref of this.getTileTreeRefs()) {
102602
102752
  promises.push(ref.addAttributions(logos, this));
102603
102753
  }
102754
+ if (undefined !== _IModelApp__WEBPACK_IMPORTED_MODULE_10__.IModelApp.applicationLogoCardFooter) {
102755
+ logos.appendChild(_IModelApp__WEBPACK_IMPORTED_MODULE_10__.IModelApp.applicationLogoCardFooter());
102756
+ }
102604
102757
  await Promise.all(promises);
102605
102758
  ev.stopPropagation();
102606
102759
  };
@@ -108178,7 +108331,9 @@ function createMeshArgs(mesh) {
108178
108331
  if (!mesh.triangles || mesh.triangles.isEmpty || mesh.points.length === 0)
108179
108332
  return undefined;
108180
108333
  const texture = mesh.displayParams.textureMapping?.texture;
108181
- const textureMapping = texture && mesh.uvParams.length > 0 ? { texture, uvParams: mesh.uvParams } : undefined;
108334
+ const useConstantLod = mesh.displayParams.textureMapping?.params?.useConstantLod;
108335
+ const constantLodParams = mesh.displayParams.textureMapping?.params?.constantLodParams;
108336
+ const textureMapping = texture && mesh.uvParams.length > 0 ? { texture, uvParams: mesh.uvParams, useConstantLod, constantLodParams } : undefined;
108182
108337
  const colors = new _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.ColorIndex();
108183
108338
  mesh.colorMap.toColorIndex(colors, mesh.colors);
108184
108339
  const features = new _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.FeatureIndex();
@@ -149957,7 +150112,7 @@ function readPnts(stream, dataOffset, pnts) {
149957
150112
  }
149958
150113
  async function decodeDracoPointCloud(buf) {
149959
150114
  try {
149960
- 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;
150115
+ 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;
149961
150116
  const mesh = await dracoLoader.parse(buf, {});
149962
150117
  if (mesh.topology !== "point-list")
149963
150118
  return undefined;
@@ -161396,14 +161551,47 @@ class GltfReader {
161396
161551
  }
161397
161552
  }
161398
161553
  createDisplayParams(material, hasBakedLighting, isPointPrimitive = false) {
161554
+ let constantLodParamProps;
161555
+ let normalMapUseConstantLod = false;
161556
+ if (!(0,_common_gltf_GltfSchema__WEBPACK_IMPORTED_MODULE_12__.isGltf1Material)(material)) {
161557
+ // NOTE: EXT_textureInfo_constant_lod is not supported for occlusionTexture and metallicRoughnessTexture
161558
+ // Use the same texture fallback logic as extractTextureId
161559
+ const textureInfo = material.pbrMetallicRoughness?.baseColorTexture ?? material.emissiveTexture;
161560
+ const extConstantLod = textureInfo?.extensions?.EXT_textureInfo_constant_lod;
161561
+ const offset = extConstantLod?.offset;
161562
+ extConstantLod ? constantLodParamProps = {
161563
+ repetitions: extConstantLod?.repetitions,
161564
+ offset: offset ? { x: offset[0], y: offset[1] } : undefined,
161565
+ minDistClamp: extConstantLod?.minClampDistance,
161566
+ maxDistClamp: extConstantLod?.maxClampDistance,
161567
+ } : undefined;
161568
+ // Normal map only uses constant LOD if both the base texture and normal texture have the extension
161569
+ normalMapUseConstantLod = extConstantLod !== undefined && material.normalTexture?.extensions?.EXT_textureInfo_constant_lod !== undefined;
161570
+ }
161399
161571
  const isTransparent = this.isMaterialTransparent(material);
161400
161572
  const textureId = this.extractTextureId(material);
161401
161573
  const normalMapId = this.extractNormalMapId(material);
161402
- let textureMapping = (undefined !== textureId || undefined !== normalMapId) ? this.findTextureMapping(textureId, isTransparent, normalMapId) : undefined;
161574
+ let textureMapping = (undefined !== textureId || undefined !== normalMapId) ? this.findTextureMapping(textureId, isTransparent, normalMapId, constantLodParamProps, normalMapUseConstantLod) : undefined;
161403
161575
  const color = colorFromMaterial(material, isTransparent);
161404
161576
  let renderMaterial;
161405
- if (undefined !== textureMapping && undefined !== textureMapping.normalMapParams) {
161406
- const args = { diffuse: { color }, specular: { color: _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.ColorDef.white }, textureMapping };
161577
+ if (undefined !== textureMapping) {
161578
+ // Convert result of findTextureMapping (TextureMapping object) to MaterialTextureMappingProps interface
161579
+ const textureMappingProps = {
161580
+ texture: textureMapping.texture,
161581
+ normalMapParams: textureMapping.normalMapParams,
161582
+ mode: textureMapping.params.mode,
161583
+ transform: textureMapping.params.textureMatrix,
161584
+ weight: textureMapping.params.weight,
161585
+ worldMapping: textureMapping.params.worldMapping,
161586
+ useConstantLod: textureMapping.params.useConstantLod,
161587
+ constantLodProps: textureMapping.params.useConstantLod ? {
161588
+ repetitions: textureMapping.params.constantLodParams.repetitions,
161589
+ offset: textureMapping.params.constantLodParams.offset,
161590
+ minDistClamp: textureMapping.params.constantLodParams.minDistClamp,
161591
+ maxDistClamp: textureMapping.params.constantLodParams.maxDistClamp,
161592
+ } : undefined,
161593
+ };
161594
+ const args = { diffuse: { color }, specular: { color: _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.ColorDef.white }, textureMapping: textureMappingProps };
161407
161595
  renderMaterial = _IModelApp__WEBPACK_IMPORTED_MODULE_3__.IModelApp.renderSystem.createRenderMaterial(args);
161408
161596
  // DisplayParams doesn't want a separate texture mapping if the material already has one.
161409
161597
  textureMapping = undefined;
@@ -161415,7 +161603,30 @@ class GltfReader {
161415
161603
  width = pointStyle.diameter;
161416
161604
  }
161417
161605
  }
161418
- 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);
161606
+ // Process BENTLEY_materials_planar_fill extension
161607
+ let fillFlags = _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.FillFlags.None;
161608
+ if (!(0,_common_gltf_GltfSchema__WEBPACK_IMPORTED_MODULE_12__.isGltf1Material)(material)) {
161609
+ const planarFill = material.extensions?.BENTLEY_materials_planar_fill;
161610
+ if (planarFill) {
161611
+ // Map wireframeFill: 0=NONE (no fill flags), 1=ALWAYS (Always flag), 2=TOGGLE (ByView flag)
161612
+ const wireframeFill = planarFill.wireframeFill ?? 0;
161613
+ if (wireframeFill === 1) {
161614
+ fillFlags |= _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.FillFlags.Always;
161615
+ }
161616
+ else if (wireframeFill === 2) {
161617
+ fillFlags |= _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.FillFlags.ByView;
161618
+ }
161619
+ // Map backgroundFill to Background flag
161620
+ if (planarFill.backgroundFill === true) {
161621
+ fillFlags |= _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.FillFlags.Background;
161622
+ }
161623
+ // Map behind to Behind flag
161624
+ if (planarFill.behind === true) {
161625
+ fillFlags |= _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.FillFlags.Behind;
161626
+ }
161627
+ }
161628
+ }
161629
+ 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);
161419
161630
  }
161420
161631
  readMeshPrimitives(node, featureTable, thisTransform, thisBias, instances) {
161421
161632
  const meshes = [];
@@ -162217,7 +162428,7 @@ class GltfReader {
162217
162428
  if (_itwin_core_bentley__WEBPACK_IMPORTED_MODULE_0__.ProcessDetector.isIEBrowser) {
162218
162429
  throw new Error("Unsupported browser for Draco decoding");
162219
162430
  }
162220
- 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;
162431
+ 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;
162221
162432
  await Promise.all(dracoMeshes.map(async (x) => this.decodeDracoMesh(x, dracoLoader)));
162222
162433
  }
162223
162434
  catch (err) {
@@ -162361,7 +162572,7 @@ class GltfReader {
162361
162572
  });
162362
162573
  return renderTexture ?? false;
162363
162574
  }
162364
- findTextureMapping(id, isTransparent, normalMapId) {
162575
+ findTextureMapping(id, isTransparent, normalMapId, constantLodParamProps, normalMapUseConstantLod = false) {
162365
162576
  if (undefined === id && undefined === normalMapId)
162366
162577
  return undefined;
162367
162578
  let texture;
@@ -162383,16 +162594,18 @@ class GltfReader {
162383
162594
  nMap = {
162384
162595
  normalMap,
162385
162596
  greenUp,
162597
+ useConstantLod: normalMapUseConstantLod,
162386
162598
  };
162387
162599
  }
162388
162600
  else {
162389
162601
  texture = normalMap;
162390
- nMap = { greenUp };
162602
+ nMap = { greenUp, useConstantLod: normalMapUseConstantLod };
162391
162603
  }
162392
162604
  }
162393
162605
  if (!texture)
162394
162606
  return undefined;
162395
- const textureMapping = new _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.TextureMapping(texture, new _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.TextureMapping.Params());
162607
+ const useConstantLod = constantLodParamProps !== undefined;
162608
+ 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 }));
162396
162609
  textureMapping.normalMapParams = nMap;
162397
162610
  return textureMapping;
162398
162611
  }
@@ -162429,7 +162642,7 @@ async function readGltfTemplate(args) {
162429
162642
  }
162430
162643
  /** Produce a [[RenderGraphic]] from a [glTF](https://www.khronos.org/gltf/) asset suitable for use in [view decorations]($docs/learning/frontend/ViewDecorations).
162431
162644
  * @returns a graphic produced from the glTF asset's default scene, or `undefined` if a graphic could not be produced from the asset.
162432
- * The returned graphic also includes the bounding boxes of the glTF model in world and local coordiantes.
162645
+ * The returned graphic also includes the bounding boxes of the glTF model in world and local coordinates.
162433
162646
  * @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.
162434
162647
  * If a particular glTF asset fails to load and/or display properly, please
162435
162648
  * [submit an issue](https://github.com/iTwin/itwinjs-core/issues).
@@ -162457,6 +162670,7 @@ class GltfGraphicsReader extends GltfReader {
162457
162670
  _contentRange;
162458
162671
  _transform;
162459
162672
  _isLeaf;
162673
+ _useViewportRenderMode;
162460
162674
  binaryData; // strictly for tests
162461
162675
  meshes; // strictly for tests
162462
162676
  constructor(props, args) {
@@ -162470,6 +162684,7 @@ class GltfGraphicsReader extends GltfReader {
162470
162684
  this._contentRange = args.contentRange;
162471
162685
  this._transform = args.transform;
162472
162686
  this._isLeaf = true !== args.hasChildren;
162687
+ this._useViewportRenderMode = args.useViewportRenderMode ?? false;
162473
162688
  this.binaryData = props.binaryData;
162474
162689
  const pickableId = args.pickableOptions?.id;
162475
162690
  if (pickableId) {
@@ -162480,7 +162695,8 @@ class GltfGraphicsReader extends GltfReader {
162480
162695
  get viewFlagOverrides() {
162481
162696
  return {
162482
162697
  whiteOnWhiteReversal: false,
162483
- renderMode: _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.RenderMode.SmoothShade,
162698
+ // Don't override renderMode if using viewport's render mode - let the viewport control it.
162699
+ renderMode: this._useViewportRenderMode ? undefined : _itwin_core_common__WEBPACK_IMPORTED_MODULE_2__.RenderMode.SmoothShade,
162484
162700
  };
162485
162701
  }
162486
162702
  get meshElementIdToFeatureIndex() {
@@ -304088,6 +304304,8 @@ class BaseFormat {
304088
304304
  _stationOffsetSize; // required when type is station; positive integer > 0
304089
304305
  _stationBaseFactor; // optional positive integer base factor for station formatting; default is 1
304090
304306
  _ratioType; // required if type is ratio; options: oneToN, NToOne, ValueBased, useGreatestCommonDivisor
304307
+ _ratioFormatType; // defaults to Decimal if not specified
304308
+ _ratioSeparator; // default is ":"; separator character used in ratio formatting
304091
304309
  _azimuthBase; // value always clockwise from north
304092
304310
  _azimuthBaseUnit; // unit for azimuthBase value
304093
304311
  _azimuthCounterClockwise; // if set to true, azimuth values are returned counter-clockwise from base
@@ -304109,6 +304327,10 @@ class BaseFormat {
304109
304327
  set scientificType(scientificType) { this._scientificType = scientificType; }
304110
304328
  get ratioType() { return this._ratioType; }
304111
304329
  set ratioType(ratioType) { this._ratioType = ratioType; }
304330
+ get ratioFormatType() { return this._ratioFormatType; }
304331
+ set ratioFormatType(ratioFormatType) { this._ratioFormatType = ratioFormatType; }
304332
+ get ratioSeparator() { return this._ratioSeparator; }
304333
+ set ratioSeparator(ratioSeparator) { this._ratioSeparator = ratioSeparator; }
304112
304334
  get showSignOption() { return this._showSignOption; }
304113
304335
  set showSignOption(showSignOption) { this._showSignOption = showSignOption; }
304114
304336
  get decimalSeparator() { return this._decimalSeparator; }
@@ -304177,6 +304399,22 @@ class BaseFormat {
304177
304399
  if (undefined === formatProps.ratioType)
304178
304400
  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.`);
304179
304401
  this._ratioType = (0,_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.parseRatioType)(formatProps.ratioType, this.name);
304402
+ if (undefined !== formatProps.ratioSeparator) {
304403
+ if (typeof (formatProps.ratioSeparator) !== "string")
304404
+ 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'.`);
304405
+ if (formatProps.ratioSeparator.length !== 1)
304406
+ 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.`);
304407
+ this._ratioSeparator = formatProps.ratioSeparator;
304408
+ }
304409
+ else {
304410
+ this._ratioSeparator = ":"; // Apply default
304411
+ }
304412
+ if (undefined !== formatProps.ratioFormatType) {
304413
+ this._ratioFormatType = (0,_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.parseRatioFormatType)(formatProps.ratioFormatType, this.name);
304414
+ }
304415
+ else {
304416
+ this._ratioFormatType = _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.RatioFormatType.Decimal; // Apply default
304417
+ }
304180
304418
  }
304181
304419
  if (undefined !== formatProps.roundFactor) { // optional; default is 0.0
304182
304420
  if (typeof (formatProps.roundFactor) !== "number")
@@ -304301,6 +304539,8 @@ class Format extends BaseFormat {
304301
304539
  newFormat._azimuthBaseUnit = this._azimuthBaseUnit;
304302
304540
  newFormat._azimuthCounterClockwise = this._azimuthCounterClockwise;
304303
304541
  newFormat._ratioType = this._ratioType;
304542
+ newFormat._ratioFormatType = this._ratioFormatType;
304543
+ newFormat._ratioSeparator = this._ratioSeparator;
304304
304544
  newFormat._revolutionUnit = this._revolutionUnit;
304305
304545
  newFormat._customProps = this._customProps;
304306
304546
  this._units && (newFormat._units = [...this._units]);
@@ -304361,25 +304601,28 @@ class Format extends BaseFormat {
304361
304601
  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'`);
304362
304602
  }
304363
304603
  if (jsonObj.composite.units.length > 0 && jsonObj.composite.units.length <= 4) { // Composite requires 1-4 units
304364
- for (const nextUnit of jsonObj.composite.units) {
304365
- if (this._units) {
304366
- for (const existingUnit of this._units) {
304367
- const unitObj = existingUnit[0].name;
304368
- if (unitObj.toLowerCase() === nextUnit.unit.name.toLowerCase()) {
304369
- throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvalidJson, `The unit ${unitObj} has a duplicate name.`);
304370
- }
304604
+ const isDuplicateAllowed = this.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Ratio;
304605
+ const seenUnits = new Set();
304606
+ this._units = [];
304607
+ for (const unitSpec of jsonObj.composite.units) {
304608
+ if (!isDuplicateAllowed) {
304609
+ const unitName = unitSpec.unit.name.toLowerCase();
304610
+ const existingName = seenUnits.has(unitName);
304611
+ if (existingName) {
304612
+ 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}'`);
304371
304613
  }
304614
+ seenUnits.add(unitName);
304372
304615
  }
304373
- if (undefined === this._units) {
304374
- this._units = [];
304375
- }
304376
- this._units.push([nextUnit.unit, nextUnit.label]);
304616
+ this._units.push([unitSpec.unit, unitSpec.label]);
304377
304617
  }
304378
304618
  }
304379
304619
  }
304380
304620
  if (undefined === this.units || this.units.length === 0)
304381
304621
  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'`);
304382
304622
  }
304623
+ if (this.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Ratio && (!this._units || this._units.length === 0)) {
304624
+ 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.`);
304625
+ }
304383
304626
  if (this.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Azimuth || this.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Bearing) {
304384
304627
  this._azimuthBaseUnit = jsonObj.azimuthBaseUnit;
304385
304628
  this._revolutionUnit = jsonObj.revolutionUnit;
@@ -304446,6 +304689,8 @@ class Format extends BaseFormat {
304446
304689
  uomSeparator: this.uomSeparator,
304447
304690
  scientificType: this.scientificType ? this.scientificType : undefined,
304448
304691
  ratioType: this.ratioType,
304692
+ ratioFormatType: this.ratioFormatType,
304693
+ ratioSeparator: this.ratioSeparator,
304449
304694
  stationOffsetSize: this.stationOffsetSize,
304450
304695
  stationSeparator: this.stationSeparator,
304451
304696
  stationBaseFactor: this.stationBaseFactor,
@@ -304490,6 +304735,15 @@ async function resolveFormatProps(formatName, unitsProvider, jsonObj) {
304490
304735
  const unit = await resolveCompositeUnit(unitsProvider, entry.name);
304491
304736
  return { unit, label: entry.label };
304492
304737
  }));
304738
+ // For Ratio formats with 2 units: validate both units have the same phenomenon
304739
+ const formatType = (0,_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.parseFormatType)(jsonObj.type, formatName);
304740
+ if (formatType === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Ratio && units.length === 2) {
304741
+ const phenomenon1 = units[0].unit.phenomenon;
304742
+ const phenomenon2 = units[1].unit.phenomenon;
304743
+ if (phenomenon1 !== phenomenon2) {
304744
+ 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}'.`);
304745
+ }
304746
+ }
304493
304747
  }
304494
304748
  let azimuthBaseUnit, revolutionUnit;
304495
304749
  const type = (0,_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.parseFormatType)(jsonObj.type, formatName);
@@ -304530,6 +304784,7 @@ __webpack_require__.r(__webpack_exports__);
304530
304784
  /* harmony export */ FormatTraits: () => (/* binding */ FormatTraits),
304531
304785
  /* harmony export */ FormatType: () => (/* binding */ FormatType),
304532
304786
  /* harmony export */ FractionalPrecision: () => (/* binding */ FractionalPrecision),
304787
+ /* harmony export */ RatioFormatType: () => (/* binding */ RatioFormatType),
304533
304788
  /* harmony export */ RatioType: () => (/* binding */ RatioType),
304534
304789
  /* harmony export */ ScientificType: () => (/* binding */ ScientificType),
304535
304790
  /* harmony export */ ShowSignOption: () => (/* binding */ ShowSignOption),
@@ -304543,6 +304798,7 @@ __webpack_require__.r(__webpack_exports__);
304543
304798
  /* harmony export */ parseFormatType: () => (/* binding */ parseFormatType),
304544
304799
  /* harmony export */ parseFractionalPrecision: () => (/* binding */ parseFractionalPrecision),
304545
304800
  /* harmony export */ parsePrecision: () => (/* binding */ parsePrecision),
304801
+ /* harmony export */ parseRatioFormatType: () => (/* binding */ parseRatioFormatType),
304546
304802
  /* harmony export */ parseRatioType: () => (/* binding */ parseRatioType),
304547
304803
  /* harmony export */ parseScientificType: () => (/* binding */ parseScientificType),
304548
304804
  /* harmony export */ parseShowSignOption: () => (/* binding */ parseShowSignOption),
@@ -304687,6 +304943,16 @@ var RatioType;
304687
304943
  /** 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 */
304688
304944
  RatioType["UseGreatestCommonDivisor"] = "UseGreatestCommonDivisor";
304689
304945
  })(RatioType || (RatioType = {}));
304946
+ /** The format type for the numbers within a ratio.
304947
+ * @beta
304948
+ */
304949
+ var RatioFormatType;
304950
+ (function (RatioFormatType) {
304951
+ /** Decimal display (ie 2.125) */
304952
+ RatioFormatType["Decimal"] = "Decimal";
304953
+ /** Fractional display (ie 2-1/8) */
304954
+ RatioFormatType["Fractional"] = "Fractional";
304955
+ })(RatioFormatType || (RatioFormatType = {}));
304690
304956
  /** Determines how the sign of values are displayed
304691
304957
  * @beta */
304692
304958
  var ShowSignOption;
@@ -304732,6 +304998,18 @@ function parseRatioType(ratioType, formatName) {
304732
304998
  }
304733
304999
  throw new _Exception__WEBPACK_IMPORTED_MODULE_0__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_0__.QuantityStatus.InvalidJson, `The Format ${formatName} has an invalid 'ratioType' attribute.`);
304734
305000
  }
305001
+ /** @beta */
305002
+ function parseRatioFormatType(ratioFormatType, formatName) {
305003
+ const normalizedValue = ratioFormatType.toLowerCase();
305004
+ for (const key in RatioFormatType) {
305005
+ if (RatioFormatType.hasOwnProperty(key)) {
305006
+ const enumValue = RatioFormatType[key];
305007
+ if (enumValue.toLowerCase() === normalizedValue)
305008
+ return enumValue;
305009
+ }
305010
+ }
305011
+ throw new _Exception__WEBPACK_IMPORTED_MODULE_0__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_0__.QuantityStatus.InvalidJson, `The Format ${formatName} has an invalid 'ratioFormatType' attribute.`);
305012
+ }
304735
305013
  /** @beta */
304736
305014
  function parseShowSignOption(showSignOption, formatName) {
304737
305015
  switch (showSignOption.toLowerCase()) {
@@ -304893,10 +305171,18 @@ function parsePrecision(precision, type, formatName) {
304893
305171
  case FormatType.Decimal:
304894
305172
  case FormatType.Scientific:
304895
305173
  case FormatType.Station:
304896
- case FormatType.Ratio:
304897
305174
  case FormatType.Bearing:
304898
305175
  case FormatType.Azimuth:
304899
305176
  return parseDecimalPrecision(precision, formatName);
305177
+ case FormatType.Ratio:
305178
+ // Ratio type can use either decimal or fractional precision depending on ratioFormatType
305179
+ // Try decimal first, if it fails, try fractional
305180
+ try {
305181
+ return parseDecimalPrecision(precision, formatName);
305182
+ }
305183
+ catch {
305184
+ return parseFractionalPrecision(precision, formatName);
305185
+ }
304900
305186
  case FormatType.Fractional:
304901
305187
  return parseFractionalPrecision(precision, formatName);
304902
305188
  default:
@@ -304920,8 +305206,9 @@ __webpack_require__.r(__webpack_exports__);
304920
305206
  /* harmony export */ });
304921
305207
  /* harmony import */ var _Constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Constants */ "../../core/quantity/lib/esm/Constants.js");
304922
305208
  /* harmony import */ var _Exception__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Exception */ "../../core/quantity/lib/esm/Exception.js");
304923
- /* harmony import */ var _FormatEnums__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./FormatEnums */ "../../core/quantity/lib/esm/Formatter/FormatEnums.js");
304924
- /* harmony import */ var _Quantity__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../Quantity */ "../../core/quantity/lib/esm/Quantity.js");
305209
+ /* harmony import */ var _FormatterSpec__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./FormatterSpec */ "../../core/quantity/lib/esm/Formatter/FormatterSpec.js");
305210
+ /* harmony import */ var _FormatEnums__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./FormatEnums */ "../../core/quantity/lib/esm/Formatter/FormatEnums.js");
305211
+ /* harmony import */ var _Quantity__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../Quantity */ "../../core/quantity/lib/esm/Quantity.js");
304925
305212
  /*---------------------------------------------------------------------------------------------
304926
305213
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
304927
305214
  * See LICENSE.md in the project root for license terms and full copyright notice.
@@ -304933,6 +305220,7 @@ __webpack_require__.r(__webpack_exports__);
304933
305220
 
304934
305221
 
304935
305222
 
305223
+
304936
305224
  /** rounding additive
304937
305225
  * @internal
304938
305226
  */
@@ -305033,7 +305321,7 @@ class Formatter {
305033
305321
  static integerPartToText(wholePart, spec) {
305034
305322
  // build invariant string represent wholePart
305035
305323
  let formattedValue = wholePart.toFixed(0);
305036
- if ((formattedValue.length > 3) && (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.Use1000Separator) && (spec.format.thousandSeparator.length > 0))) {
305324
+ if ((formattedValue.length > 3) && (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.Use1000Separator) && (spec.format.thousandSeparator.length > 0))) {
305037
305325
  let numSeparators = Math.floor(formattedValue.length / 3);
305038
305326
  let groupLength = formattedValue.length % 3;
305039
305327
  if (groupLength === 0) {
@@ -305080,7 +305368,7 @@ class Formatter {
305080
305368
  else {
305081
305369
  componentText = Formatter.formatMagnitude(compositeValue, spec);
305082
305370
  }
305083
- if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.ShowUnitLabel)) {
305371
+ if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.ShowUnitLabel)) {
305084
305372
  componentText = componentText + spec.format.uomSeparator + label;
305085
305373
  }
305086
305374
  return componentText;
@@ -305100,12 +305388,11 @@ class Formatter {
305100
305388
  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.`);
305101
305389
  if (i > 0 && unitConversion.offset !== 0) // offset should only ever be defined for major unit
305102
305390
  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.`);
305103
- let unitValue = 0.0;
305104
- if (spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Ratio) {
305105
- if (1 !== (spec.format.units?.length ?? 0))
305106
- 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.`);
305391
+ // Handle ratio format with composite units
305392
+ if (spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Ratio) {
305393
+ let ratioUnitValue = 0.0;
305107
305394
  try {
305108
- unitValue = (0,_Quantity__WEBPACK_IMPORTED_MODULE_3__.applyConversion)(remainingMagnitude, unitConversion) + this.FPV_MINTHRESHOLD;
305395
+ ratioUnitValue = (0,_Quantity__WEBPACK_IMPORTED_MODULE_4__.applyConversion)(remainingMagnitude, unitConversion) + this.FPV_MINTHRESHOLD;
305109
305396
  }
305110
305397
  catch (e) {
305111
305398
  // The "InvertingZero" error is thrown when the value is zero and the conversion factor is inverted.
@@ -305113,12 +305400,13 @@ class Formatter {
305113
305400
  if (e instanceof _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError && e.errorNumber === _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvertingZero) {
305114
305401
  return { componentText: "1:0", isNegative: false };
305115
305402
  }
305403
+ throw e;
305116
305404
  }
305117
- compositeStrings.push(this.formatRatio(unitValue, spec));
305118
- isNegative = unitValue < 0;
305405
+ compositeStrings.push(this.formatRatio(ratioUnitValue, spec));
305406
+ isNegative = ratioUnitValue < 0;
305119
305407
  continue;
305120
305408
  }
305121
- unitValue = (0,_Quantity__WEBPACK_IMPORTED_MODULE_3__.applyConversion)(remainingMagnitude, unitConversion) + this.FPV_MINTHRESHOLD;
305409
+ let unitValue = (0,_Quantity__WEBPACK_IMPORTED_MODULE_4__.applyConversion)(remainingMagnitude, unitConversion) + this.FPV_MINTHRESHOLD;
305122
305410
  if (0 === i) {
305123
305411
  // Only set isNegative from the first (major) unit conversion
305124
305412
  isNegative = unitValue < 0;
@@ -305126,16 +305414,16 @@ class Formatter {
305126
305414
  // but use higher precision if the format specifies it
305127
305415
  const precisionScale = Math.pow(10, Math.max(8, spec.format.precision));
305128
305416
  unitValue = Math.floor(unitValue * precisionScale + FPV_ROUNDFACTOR) / precisionScale;
305129
- if ((Math.abs(unitValue) < 0.0001) && spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.ZeroEmpty))
305417
+ if ((Math.abs(unitValue) < 0.0001) && spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.ZeroEmpty))
305130
305418
  return { componentText: "", isNegative: false };
305131
305419
  }
305132
305420
  if (i < (spec.format.units?.length ?? 0) - 1) {
305133
305421
  let wholePart = Math.trunc(unitValue);
305134
305422
  // Check if the remaining fractional part will round up to a full unit in the next (smaller) component
305135
- if (spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Fractional && i === spec.unitConversions.length - 2) {
305423
+ if (spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Fractional && i === spec.unitConversions.length - 2) {
305136
305424
  // For the second-to-last unit with fractional formatting, check if rounding causes carry-over
305137
305425
  const fractionalPart = unitValue - wholePart;
305138
- const nextUnitValue = (0,_Quantity__WEBPACK_IMPORTED_MODULE_3__.applyConversion)(fractionalPart, spec.unitConversions[i + 1].conversion);
305426
+ const nextUnitValue = (0,_Quantity__WEBPACK_IMPORTED_MODULE_4__.applyConversion)(fractionalPart, spec.unitConversions[i + 1].conversion);
305139
305427
  // Create a FractionalNumeric to determine what the rounded value would be
305140
305428
  const fn = new FractionalNumeric(Math.abs(nextUnitValue), spec.format.precision, true);
305141
305429
  // If the fractional numeric rounds to a whole unit (integral part increased due to rounding)
@@ -305165,18 +305453,18 @@ class Formatter {
305165
305453
  */
305166
305454
  static formatMagnitude(magnitude, spec) {
305167
305455
  let posMagnitude = Math.abs(magnitude);
305168
- if ((Math.abs(posMagnitude) < 0.0001) && spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.ZeroEmpty))
305456
+ if ((Math.abs(posMagnitude) < 0.0001) && spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.ZeroEmpty))
305169
305457
  return "";
305170
- if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.ApplyRounding))
305458
+ if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.ApplyRounding))
305171
305459
  posMagnitude = Math.abs(Formatter.roundDouble(magnitude, spec.format.roundFactor));
305172
- const isSci = ((posMagnitude > 1.0e12) || spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Scientific);
305173
- 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;
305174
- const isFractional = (!isDecimal && spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Fractional);
305460
+ const isSci = ((posMagnitude > 1.0e12) || spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Scientific);
305461
+ 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;
305462
+ const isFractional = (!isDecimal && spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Fractional);
305175
305463
  /* const usesStops = spec.format.type === FormatType.Station; */
305176
- const isPrecisionZero = spec.format.precision === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.DecimalPrecision.Zero;
305177
- const isKeepSingleZero = spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.KeepSingleZero);
305464
+ const isPrecisionZero = spec.format.precision === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.DecimalPrecision.Zero;
305465
+ const isKeepSingleZero = spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.KeepSingleZero);
305178
305466
  const precisionScale = Math.pow(10.0, spec.format.precision);
305179
- const isKeepTrailingZeroes = spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.TrailZeroes);
305467
+ const isKeepTrailingZeroes = spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.TrailZeroes);
305180
305468
  let expInt = 0.0;
305181
305469
  if (isSci && (posMagnitude !== 0.0)) {
305182
305470
  let exp = Math.log10(posMagnitude);
@@ -305186,10 +305474,10 @@ class Formatter {
305186
305474
  negativeExp = true;
305187
305475
  }
305188
305476
  expInt = Math.floor(exp);
305189
- if (spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Scientific) {
305190
- if (spec.format.scientificType === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.ScientificType.ZeroNormalized && posMagnitude > 1.0)
305477
+ if (spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Scientific) {
305478
+ if (spec.format.scientificType === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.ScientificType.ZeroNormalized && posMagnitude > 1.0)
305191
305479
  expInt += 1.0;
305192
- else if (spec.format.scientificType === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.ScientificType.Normalized && posMagnitude < 1.0)
305480
+ else if (spec.format.scientificType === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.ScientificType.Normalized && posMagnitude < 1.0)
305193
305481
  expInt += 1.0;
305194
305482
  if (negativeExp)
305195
305483
  expInt = -expInt;
@@ -305211,7 +305499,7 @@ class Formatter {
305211
305499
  }
305212
305500
  formattedValue = Formatter.integerPartToText(wholePart, spec);
305213
305501
  if (isPrecisionZero) {
305214
- if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.KeepDecimalPoint) && !isKeepSingleZero)
305502
+ if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.KeepDecimalPoint) && !isKeepSingleZero)
305215
305503
  formattedValue = formattedValue + spec.format.decimalSeparator;
305216
305504
  else if (isKeepSingleZero)
305217
305505
  formattedValue = `${formattedValue + spec.format.decimalSeparator}0`;
@@ -305226,7 +305514,7 @@ class Formatter {
305226
305514
  if (fractionString.length > 0)
305227
305515
  formattedValue = formattedValue + spec.format.decimalSeparator + fractionString;
305228
305516
  else {
305229
- if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.KeepDecimalPoint))
305517
+ if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.KeepDecimalPoint))
305230
305518
  formattedValue = formattedValue + spec.format.decimalSeparator + (isKeepSingleZero ? "0" : "");
305231
305519
  }
305232
305520
  }
@@ -305239,7 +305527,7 @@ class Formatter {
305239
305527
  const fn = new FractionalNumeric(posMagnitude, spec.format.precision, true);
305240
305528
  formattedValue = fn.getIntegralString();
305241
305529
  if (!fn.isZero && fn.hasFractionPart) {
305242
- const wholeFractionSeparator = spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.FractionDash) ? "-" : " ";
305530
+ const wholeFractionSeparator = spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.FractionDash) ? "-" : " ";
305243
305531
  const fractionString = `${fn.getNumeratorString()}/${fn.getDenominatorString()}`;
305244
305532
  formattedValue = formattedValue + wholeFractionSeparator + fractionString;
305245
305533
  }
@@ -305268,7 +305556,7 @@ class Formatter {
305268
305556
  else {
305269
305557
  if (isKeepTrailingZeroes)
305270
305558
  fractionString = spec.format.decimalSeparator + "".padEnd(spec.format.precision, "0");
305271
- else if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.KeepDecimalPoint))
305559
+ else if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.KeepDecimalPoint))
305272
305560
  fractionString = spec.format.decimalSeparator;
305273
305561
  formattedValue = stationString + fractionString;
305274
305562
  }
@@ -305297,21 +305585,21 @@ class Formatter {
305297
305585
  let prefix = "";
305298
305586
  let suffix = "";
305299
305587
  switch (showSignOption) {
305300
- case _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.ShowSignOption.NegativeParentheses:
305588
+ case _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.ShowSignOption.NegativeParentheses:
305301
305589
  if (isNegative) {
305302
305590
  prefix = "(";
305303
305591
  suffix = ")";
305304
305592
  }
305305
305593
  break;
305306
- case _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.ShowSignOption.OnlyNegative:
305307
- if (isNegative && formatType !== _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Bearing && formatType !== _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Azimuth) {
305594
+ case _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.ShowSignOption.OnlyNegative:
305595
+ if (isNegative && formatType !== _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Bearing && formatType !== _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Azimuth) {
305308
305596
  prefix = "-";
305309
305597
  }
305310
305598
  break;
305311
- case _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.ShowSignOption.SignAlways:
305599
+ case _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.ShowSignOption.SignAlways:
305312
305600
  prefix = isNegative ? "-" : "+";
305313
305601
  break;
305314
- case _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.ShowSignOption.NoSign:
305602
+ case _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.ShowSignOption.NoSign:
305315
305603
  default:
305316
305604
  break;
305317
305605
  }
@@ -305327,14 +305615,20 @@ class Formatter {
305327
305615
  let suffix = "";
305328
305616
  let formattedValue = "";
305329
305617
  // Handle bearing/azimuth special formatting
305330
- if (spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Bearing || spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Azimuth) {
305618
+ if (spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Bearing || spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Azimuth) {
305331
305619
  const result = this.processBearingAndAzimuth(magnitude, spec);
305332
305620
  magnitude = result.magnitude;
305333
305621
  prefix = result.prefix ?? "";
305334
305622
  suffix = result.suffix ?? "";
305335
305623
  }
305336
305624
  let formattedMagnitude = "";
305337
- if (spec.format.hasUnits) {
305625
+ if (spec.format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Ratio && spec.unitConversions.length >= 3) {
305626
+ // Handle ratio formatting separately when 2-unit composite provides 3 conversion specs
305627
+ const ratioResult = this.formatRatioQuantity(magnitude, spec);
305628
+ formattedMagnitude = ratioResult.componentText;
305629
+ valueIsNegative = ratioResult.isNegative;
305630
+ }
305631
+ else if (spec.format.hasUnits) {
305338
305632
  const compositeResult = Formatter.formatComposite(magnitude, spec);
305339
305633
  formattedMagnitude = compositeResult.componentText;
305340
305634
  // Override the sign detection with the composite conversion result
@@ -305343,8 +305637,8 @@ class Formatter {
305343
305637
  else {
305344
305638
  // unitless quantity
305345
305639
  formattedMagnitude = Formatter.formatMagnitude(magnitude, spec);
305346
- if (formattedMagnitude.length > 0 && spec.unitConversions.length > 0 && spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.ShowUnitLabel)) {
305347
- if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatTraits.PrependUnitLabel))
305640
+ if (formattedMagnitude.length > 0 && spec.unitConversions.length > 0 && spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.ShowUnitLabel)) {
305641
+ if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.PrependUnitLabel))
305348
305642
  formattedMagnitude = spec.unitConversions[0].label + spec.format.uomSeparator + formattedMagnitude;
305349
305643
  else
305350
305644
  formattedMagnitude = formattedMagnitude + spec.format.uomSeparator + spec.unitConversions[0].label;
@@ -305364,12 +305658,12 @@ class Formatter {
305364
305658
  }
305365
305659
  static processBearingAndAzimuth(magnitude, spec) {
305366
305660
  const type = spec.format.type;
305367
- if (type !== _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Bearing && type !== _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Azimuth)
305661
+ if (type !== _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Bearing && type !== _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Azimuth)
305368
305662
  return { magnitude };
305369
305663
  const revolution = this.getRevolution(spec);
305370
305664
  magnitude = this.normalizeAngle(magnitude, revolution);
305371
305665
  const quarterRevolution = revolution / 4;
305372
- if (type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Bearing) {
305666
+ if (type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Bearing) {
305373
305667
  let quadrant = 0;
305374
305668
  while (magnitude > quarterRevolution) {
305375
305669
  magnitude -= quarterRevolution;
@@ -305396,7 +305690,7 @@ class Formatter {
305396
305690
  if (quadrant === 2 && spec.unitConversions.length > 0) {
305397
305691
  // To determine if value is small, we need to convert it to the smallest unit presented and use the provided precision on it
305398
305692
  const unitConversion = spec.unitConversions[spec.unitConversions.length - 1].conversion;
305399
- const smallestFormattedDelta = (0,_Quantity__WEBPACK_IMPORTED_MODULE_3__.applyConversion)((quarterRevolution - magnitude), unitConversion) + this.FPV_MINTHRESHOLD;
305693
+ const smallestFormattedDelta = (0,_Quantity__WEBPACK_IMPORTED_MODULE_4__.applyConversion)((quarterRevolution - magnitude), unitConversion) + this.FPV_MINTHRESHOLD;
305400
305694
  const precisionScale = Math.pow(10.0, spec.format.precision);
305401
305695
  const floor = Math.floor((smallestFormattedDelta) * precisionScale + FPV_ROUNDFACTOR) / precisionScale;
305402
305696
  if (floor === 0) {
@@ -305405,13 +305699,13 @@ class Formatter {
305405
305699
  }
305406
305700
  return { magnitude, prefix, suffix };
305407
305701
  }
305408
- if (type === _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Azimuth) {
305702
+ if (type === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Azimuth) {
305409
305703
  let azimuthBase = 0; // default base is North
305410
305704
  if (spec.format.azimuthBase !== undefined) {
305411
305705
  if (spec.azimuthBaseConversion === undefined) {
305412
305706
  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.`);
305413
305707
  }
305414
- const azBaseQuantity = new _Quantity__WEBPACK_IMPORTED_MODULE_3__.Quantity(spec.format.azimuthBaseUnit, spec.format.azimuthBase);
305708
+ const azBaseQuantity = new _Quantity__WEBPACK_IMPORTED_MODULE_4__.Quantity(spec.format.azimuthBaseUnit, spec.format.azimuthBase);
305415
305709
  const azBaseConverted = azBaseQuantity.convertTo(spec.persistenceUnit, spec.azimuthBaseConversion);
305416
305710
  if (azBaseConverted === undefined || !azBaseConverted.isValid) {
305417
305711
  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}.`);
@@ -305441,40 +305735,87 @@ class Formatter {
305441
305735
  if (spec.revolutionConversion === undefined) {
305442
305736
  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.`);
305443
305737
  }
305444
- const revolution = new _Quantity__WEBPACK_IMPORTED_MODULE_3__.Quantity(spec.format.revolutionUnit, 1.0);
305738
+ const revolution = new _Quantity__WEBPACK_IMPORTED_MODULE_4__.Quantity(spec.format.revolutionUnit, 1.0);
305445
305739
  const converted = revolution.convertTo(spec.persistenceUnit, spec.revolutionConversion);
305446
305740
  if (converted === undefined || !converted.isValid) {
305447
305741
  throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.UnsupportedUnit, `Failed to convert revolution unit to ${spec.persistenceUnit.name}.`);
305448
305742
  }
305449
305743
  return converted.magnitude;
305450
305744
  }
305745
+ static formatRatioPart(value, spec, side) {
305746
+ const formatType = spec.format.ratioFormatType === "Fractional" ? _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Fractional : _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Decimal;
305747
+ const tempFormat = spec.format.clone({ type: formatType });
305748
+ const tempSpec = new _FormatterSpec__WEBPACK_IMPORTED_MODULE_2__.FormatterSpec(spec.name, tempFormat, spec.unitConversions, spec.persistenceUnit);
305749
+ let formattedValue = this.formatMagnitude(value, tempSpec);
305750
+ // For fractional ratio formatting, suppress leading "0" if the value is purely fractional
305751
+ if (formatType === _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatType.Fractional && formattedValue.startsWith("0 ")) {
305752
+ formattedValue = formattedValue.substring(2); // Remove "0 " prefix
305753
+ }
305754
+ // Add unit label if ShowUnitLabel trait is set
305755
+ // unitConversions[0] = ratio scale factor, [1] = numerator unit, [2] = denominator unit
305756
+ if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.ShowUnitLabel) && spec.unitConversions.length >= 3) {
305757
+ const labelToAdd = side === "numerator" ? spec.unitConversions[1].label : spec.unitConversions[2].label;
305758
+ formattedValue = formattedValue + labelToAdd;
305759
+ }
305760
+ return formattedValue;
305761
+ }
305762
+ /** Format a ratio quantity value (separate from composite formatting) */
305763
+ static formatRatioQuantity(magnitude, spec) {
305764
+ const unitConversion = spec.unitConversions[0].conversion;
305765
+ let unitValue = 0.0;
305766
+ try {
305767
+ unitValue = (0,_Quantity__WEBPACK_IMPORTED_MODULE_4__.applyConversion)(magnitude, unitConversion) + this.FPV_MINTHRESHOLD;
305768
+ }
305769
+ catch (e) {
305770
+ // The "InvertingZero" error is thrown when the value is zero and the conversion factor is inverted.
305771
+ // For ratio, we return "1:0" as the formatted value.
305772
+ if (e instanceof _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError && e.errorNumber === _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvertingZero) {
305773
+ return { componentText: "1:0", isNegative: false };
305774
+ }
305775
+ throw e;
305776
+ }
305777
+ const componentText = this.formatRatio(unitValue, spec);
305778
+ const isNegative = unitValue < 0;
305779
+ return { componentText, isNegative };
305780
+ }
305451
305781
  static formatRatio(magnitude, spec) {
305452
305782
  if (null === spec.format.ratioType)
305453
305783
  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.`);
305454
305784
  const precisionScale = Math.pow(10.0, spec.format.precision);
305785
+ const separator = spec.format.ratioSeparator;
305455
305786
  let reciprocal = 0;
305787
+ // Helper to get unit labels if ShowUnitLabel is set
305788
+ const getUnitLabels = () => {
305789
+ if (spec.format.hasFormatTraitSet(_FormatEnums__WEBPACK_IMPORTED_MODULE_3__.FormatTraits.ShowUnitLabel) && spec.unitConversions.length >= 3) {
305790
+ return { numeratorLabel: spec.unitConversions[1].label, denominatorLabel: spec.unitConversions[2].label };
305791
+ }
305792
+ return { numeratorLabel: "", denominatorLabel: "" };
305793
+ };
305794
+ const { numeratorLabel, denominatorLabel } = getUnitLabels();
305456
305795
  if (magnitude === 0.0)
305457
- return "0:1";
305796
+ return `0${separator}1`;
305458
305797
  else
305459
305798
  reciprocal = 1.0 / magnitude;
305460
305799
  switch (spec.format.ratioType) {
305461
- case _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.RatioType.OneToN:
305462
- return `1:${this.formatMagnitude(reciprocal, spec)}`;
305463
- case _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.RatioType.NToOne:
305464
- return `${this.formatMagnitude(magnitude, spec)}:1`;
305465
- case _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.RatioType.ValueBased:
305466
- if (magnitude > 1.0)
305467
- return `${this.formatMagnitude(magnitude, spec)}:1`;
305468
- else
305469
- return `1:${this.formatMagnitude(reciprocal, spec)}`;
305470
- case _FormatEnums__WEBPACK_IMPORTED_MODULE_2__.RatioType.UseGreatestCommonDivisor:
305800
+ case _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.RatioType.OneToN:
305801
+ return `1${numeratorLabel}${separator}${this.formatRatioPart(reciprocal, spec, "denominator")}`;
305802
+ case _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.RatioType.NToOne:
305803
+ return `${this.formatRatioPart(magnitude, spec, "numerator")}${separator}1${denominatorLabel}`;
305804
+ case _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.RatioType.ValueBased:
305805
+ if (magnitude > 1.0) {
305806
+ return `${this.formatRatioPart(magnitude, spec, "numerator")}${separator}1${denominatorLabel}`;
305807
+ }
305808
+ else {
305809
+ return `1${numeratorLabel}${separator}${this.formatRatioPart(reciprocal, spec, "denominator")}`;
305810
+ }
305811
+ case _FormatEnums__WEBPACK_IMPORTED_MODULE_3__.RatioType.UseGreatestCommonDivisor:
305471
305812
  magnitude = Math.round(magnitude * precisionScale) / precisionScale;
305472
305813
  let numerator = magnitude * precisionScale;
305473
305814
  let denominator = precisionScale;
305474
305815
  const gcd = FractionalNumeric.getGreatestCommonFactor(numerator, denominator);
305475
305816
  numerator /= gcd;
305476
305817
  denominator /= gcd;
305477
- return `${this.formatMagnitude(numerator, spec)}:${this.formatMagnitude(denominator, spec)}`;
305818
+ return `${this.formatRatioPart(numerator, spec, "numerator")}${separator}${this.formatRatioPart(denominator, spec, "denominator")}`;
305478
305819
  default:
305479
305820
  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.`);
305480
305821
  }
@@ -305495,7 +305836,8 @@ __webpack_require__.r(__webpack_exports__);
305495
305836
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
305496
305837
  /* harmony export */ FormatterSpec: () => (/* binding */ FormatterSpec)
305497
305838
  /* harmony export */ });
305498
- /* harmony import */ var _Formatter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Formatter */ "../../core/quantity/lib/esm/Formatter/Formatter.js");
305839
+ /* harmony import */ var _FormatEnums__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./FormatEnums */ "../../core/quantity/lib/esm/Formatter/FormatEnums.js");
305840
+ /* harmony import */ var _Formatter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Formatter */ "../../core/quantity/lib/esm/Formatter/Formatter.js");
305499
305841
  /*---------------------------------------------------------------------------------------------
305500
305842
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
305501
305843
  * See LICENSE.md in the project root for license terms and full copyright notice.
@@ -305504,6 +305846,7 @@ __webpack_require__.r(__webpack_exports__);
305504
305846
  * @module Quantity
305505
305847
  */
305506
305848
 
305849
+
305507
305850
  // cSpell:ignore ZERONORMALIZED, nosign, onlynegative, signalways, negativeparentheses
305508
305851
  // cSpell:ignore trailzeroes, keepsinglezero, zeroempty, keepdecimalpoint, applyrounding, fractiondash, showunitlabel, prependunitlabel, exponentonlynegative
305509
305852
  /** 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.
@@ -305550,6 +305893,49 @@ class FormatterSpec {
305550
305893
  get persistenceUnit() { return this._persistenceUnit; }
305551
305894
  get azimuthBaseConversion() { return this._azimuthBaseConversion; }
305552
305895
  get revolutionConversion() { return this._revolutionConversion; }
305896
+ /** Build conversion specs for ratio format with 2 composite units (numerator/denominator). */
305897
+ static async getRatioUnitConversions(units, unitsProvider, persistenceUnit) {
305898
+ const conversions = [];
305899
+ const [numeratorUnit, numeratorLabel] = units[0];
305900
+ const [denominatorUnit, denominatorLabel] = units[1];
305901
+ // Compute ratio scale: how many numerator units per denominator unit (e.g., IN:FT = 12)
305902
+ const denominatorToNumerator = await unitsProvider.getConversion(denominatorUnit, numeratorUnit);
305903
+ const displayRatioScale = denominatorToNumerator.factor;
305904
+ // Avoid double-scaling: if persistence unit already encodes the display ratio, use factor 1.
305905
+ // Check by name heuristic (e.g., IN_PER_FT with ratioUnits [IN, FT] → no scaling needed)
305906
+ const persistenceName = persistenceUnit.name.toUpperCase();
305907
+ const numName = numeratorUnit.name.toUpperCase().split(".").pop() ?? "";
305908
+ const denName = denominatorUnit.name.toUpperCase().split(".").pop() ?? "";
305909
+ // Split by word boundaries (underscores, dots) and check for exact token matches
305910
+ const persistenceTokens = persistenceName.split(/[._]/);
305911
+ const isPersistenceMatchingRatio = persistenceTokens.includes(numName) && persistenceTokens.includes(denName);
305912
+ const ratioScaleFactor = isPersistenceMatchingRatio ? 1.0 : displayRatioScale;
305913
+ // First conversion spec: effective ratio unit conversion
305914
+ const ratioConversionSpec = {
305915
+ name: `${numeratorUnit.name}_per_${denominatorUnit.name}`,
305916
+ label: "",
305917
+ system: numeratorUnit.system,
305918
+ conversion: { factor: ratioScaleFactor, offset: 0.0 },
305919
+ };
305920
+ conversions.push(ratioConversionSpec);
305921
+ // Numerator unit for label lookup
305922
+ const numeratorSpec = {
305923
+ name: numeratorUnit.name,
305924
+ label: numeratorLabel?.length ? numeratorLabel : numeratorUnit.label,
305925
+ system: numeratorUnit.system,
305926
+ conversion: { factor: 1.0, offset: 0.0 },
305927
+ };
305928
+ conversions.push(numeratorSpec);
305929
+ // Denominator unit for label lookup
305930
+ const denominatorSpec = {
305931
+ name: denominatorUnit.name,
305932
+ label: denominatorLabel?.length ? denominatorLabel : denominatorUnit.label,
305933
+ system: denominatorUnit.system,
305934
+ conversion: { factor: 1.0, offset: 0.0 },
305935
+ };
305936
+ conversions.push(denominatorSpec);
305937
+ return conversions;
305938
+ }
305553
305939
  /** Get an array of UnitConversionSpecs, one for each unit that is to be shown in the formatted quantity string. */
305554
305940
  static async getUnitConversions(format, unitsProvider, inputUnit) {
305555
305941
  const conversions = [];
@@ -305563,6 +305949,10 @@ class FormatterSpec {
305563
305949
  throw new Error("Formatter Spec needs persistence unit to be specified");
305564
305950
  }
305565
305951
  }
305952
+ // Handle 2-unit composite for ratio formats (scale factors)
305953
+ if (format.type === _FormatEnums__WEBPACK_IMPORTED_MODULE_0__.FormatType.Ratio && format.units && format.units.length === 2) {
305954
+ return FormatterSpec.getRatioUnitConversions(format.units, unitsProvider, persistenceUnit);
305955
+ }
305566
305956
  if (format.units) {
305567
305957
  let convertFromUnit = inputUnit;
305568
305958
  for (const unit of format.units) {
@@ -305619,7 +306009,7 @@ class FormatterSpec {
305619
306009
  }
305620
306010
  /** Format a quantity value. */
305621
306011
  applyFormatting(magnitude) {
305622
- return _Formatter__WEBPACK_IMPORTED_MODULE_0__.Formatter.formatQuantity(magnitude, this);
306012
+ return _Formatter__WEBPACK_IMPORTED_MODULE_1__.Formatter.formatQuantity(magnitude, this);
305623
306013
  }
305624
306014
  }
305625
306015
 
@@ -305727,13 +306117,14 @@ var ParseError;
305727
306117
  ParseError[ParseError["BearingPrefixOrSuffixMissing"] = 7] = "BearingPrefixOrSuffixMissing";
305728
306118
  ParseError[ParseError["MathematicOperationFoundButIsNotAllowed"] = 8] = "MathematicOperationFoundButIsNotAllowed";
305729
306119
  ParseError[ParseError["BearingAngleOutOfRange"] = 9] = "BearingAngleOutOfRange";
306120
+ ParseError[ParseError["InvalidMathResult"] = 10] = "InvalidMathResult";
305730
306121
  })(ParseError || (ParseError = {}));
305731
306122
  var Operator;
305732
306123
  (function (Operator) {
305733
306124
  Operator["addition"] = "+";
305734
306125
  Operator["subtraction"] = "-";
305735
306126
  Operator["multiplication"] = "*";
305736
- Operator["division"] = "/"; // unsupported but we recognize it during parsing
306127
+ Operator["division"] = "/";
305737
306128
  })(Operator || (Operator = {}));
305738
306129
  function isOperator(char) {
305739
306130
  if (typeof char === "number") {
@@ -306488,36 +306879,107 @@ class Parser {
306488
306879
  magnitude = this.normalizeAngle(magnitude, revolution);
306489
306880
  return { ok: true, value: magnitude };
306490
306881
  }
306882
+ /**
306883
+ * Parse a ratio part string (numerator or denominator) to extract the numeric value and optional unit label.
306884
+ * This method processes tokens without applying unit conversions, allowing the ratio format
306885
+ * handler to manage conversions at the ratio level.
306886
+ *
306887
+ *
306888
+ * @note Fractions are already handled by parseQuantitySpecification, which converts them to
306889
+ * single numeric tokens (e.g., "1/2" becomes 0.5).
306890
+ *
306891
+ * @param partStr The string to parse, which may contain a number, fraction, or mixed fraction with optional unit label.
306892
+ * @param format The format specification used for token parsing.
306893
+ * @returns An object containing the parsed numeric value and optional unit label. Returns NaN for value if no number is found.
306894
+ */
306895
+ static parseRatioPart(partStr, format) {
306896
+ partStr = partStr.trim();
306897
+ // Parse tokens - fractions are automatically converted to decimal values by parseQuantitySpecification
306898
+ const tempFormat = format.clone({ type: _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_2__.FormatType.Decimal });
306899
+ const tokens = Parser.parseQuantitySpecification(partStr, tempFormat);
306900
+ let value = NaN;
306901
+ let unitLabel;
306902
+ // Pre-process: merge negative operators with following numbers
306903
+ const processedTokens = [];
306904
+ for (let i = 0; i < tokens.length; i++) {
306905
+ const token = tokens[i];
306906
+ if (token.isOperator && i === 0 && token.value === "-" &&
306907
+ i + 1 < tokens.length && tokens[i + 1].isNumber) {
306908
+ // Merge negative sign with number
306909
+ processedTokens.push(new ParseToken(-tokens[i + 1].value));
306910
+ i++; // Skip the number token since we consumed it
306911
+ }
306912
+ else {
306913
+ processedTokens.push(token);
306914
+ }
306915
+ }
306916
+ // Extract numeric value and unit label from processed tokens
306917
+ for (const token of processedTokens) {
306918
+ if (token.isNumber && isNaN(value)) {
306919
+ value = token.value;
306920
+ }
306921
+ else if (token.isString && !token.isOperator) {
306922
+ // String token that's not an operator - treat as unit label
306923
+ unitLabel = token.value;
306924
+ }
306925
+ }
306926
+ return { value, unitLabel };
306927
+ }
306491
306928
  static parseRatioFormat(inString, spec) {
306492
306929
  if (!inString)
306493
306930
  return { ok: false, error: ParseError.NoValueOrUnitFoundInString };
306494
- const parts = inString.split(":");
306931
+ const separator = spec.format.ratioSeparator ?? ":";
306932
+ const parts = inString.split(separator);
306495
306933
  if (parts.length > 2)
306496
306934
  return { ok: false, error: ParseError.UnableToConvertParseTokensToQuantity };
306497
- const numerator = parseFloat(parts[0]);
306498
- let denominator;
306499
- if (parts.length === 1) {
306500
- denominator = 1.0;
306501
- }
306502
- else {
306503
- denominator = parseFloat(parts[1]);
306935
+ // If the string doesn't contain the expected separator but contains other ratio-like separators,
306936
+ // return an error since the wrong separator was used
306937
+ if (parts.length === 1 && !inString.includes(separator)) {
306938
+ // Check if the string contains other common ratio separators
306939
+ const otherSeparators = [":", "=", "/"];
306940
+ for (const otherSep of otherSeparators) {
306941
+ if (otherSep !== separator && inString.includes(otherSep)) {
306942
+ // The string looks like a ratio but uses the wrong separator
306943
+ return { ok: false, error: ParseError.UnableToConvertParseTokensToQuantity };
306944
+ }
306945
+ }
306946
+ // Parse as a regular quantity value (numerator only, denominator = 1)
306947
+ const result = this.parseAndProcessTokens(inString, spec.format, spec.unitConversions);
306948
+ return result;
306504
306949
  }
306505
- if (isNaN(numerator) || isNaN(denominator))
306950
+ // Parse numerator and denominator parts which may include unit labels
306951
+ const numeratorPart = this.parseRatioPart(parts[0], spec.format);
306952
+ const denominatorPart = parts.length === 1 ? { value: 1.0 } : this.parseRatioPart(parts[1], spec.format);
306953
+ if (isNaN(numeratorPart.value) || isNaN(denominatorPart.value))
306506
306954
  return { ok: false, error: ParseError.NoValueOrUnitFoundInString };
306955
+ // Handle 2-unit composite case - simpler conversion using the pre-computed scale factor
306956
+ if (spec.format.units && spec.format.units.length === 2 && spec.unitConversions.length >= 3) {
306957
+ const ratioConvSpec = spec.unitConversions[0];
306958
+ const scaleFactor = ratioConvSpec.conversion.factor;
306959
+ if (denominatorPart.value === 0) {
306960
+ return { ok: false, error: ParseError.InvalidMathResult };
306961
+ }
306962
+ // The ratio value is numerator/denominator in the display units (e.g., 12 for 12"=1')
306963
+ // Divide by scale factor to get persistence unit value (e.g., 12/12 = 1.0)
306964
+ const ratioValue = numeratorPart.value / denominatorPart.value;
306965
+ const convertedValue = ratioValue / scaleFactor;
306966
+ return { ok: true, value: convertedValue };
306967
+ }
306968
+ // Original flow for 1-unit composite - use Quantity.convertTo for proper unit conversion
306507
306969
  const defaultUnit = spec.format.units && spec.format.units.length > 0 ? spec.format.units[0][0] : undefined;
306508
306970
  const unitConversion = defaultUnit ? Parser.tryFindUnitConversion(defaultUnit.label, spec.unitConversions, defaultUnit) : undefined;
306509
306971
  if (!unitConversion) {
306510
306972
  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}.`);
306511
306973
  }
306512
- if (denominator === 0) {
306513
- if (unitConversion.inversion && numerator === 1)
306974
+ if (denominatorPart.value === 0) {
306975
+ if (unitConversion.inversion && numeratorPart.value === 1)
306514
306976
  return { ok: true, value: 0.0 };
306515
306977
  else
306516
- return { ok: false, error: ParseError.MathematicOperationFoundButIsNotAllowed };
306978
+ return { ok: false, error: ParseError.InvalidMathResult };
306517
306979
  }
306518
306980
  let quantity;
306519
306981
  if (spec.format.units && spec.outUnit) {
306520
- quantity = new _Quantity__WEBPACK_IMPORTED_MODULE_3__.Quantity(spec.format.units[0][0], numerator / denominator);
306982
+ quantity = new _Quantity__WEBPACK_IMPORTED_MODULE_3__.Quantity(spec.format.units[0][0], numeratorPart.value / denominatorPart.value);
306521
306983
  }
306522
306984
  else {
306523
306985
  throw new _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError(_Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.MissingRequiredProperty, "Missing presentation unit or persistence unit for ratio format.");
@@ -306529,7 +306991,7 @@ class Parser {
306529
306991
  catch (err) {
306530
306992
  // for input of "0:N" with reversed unit
306531
306993
  if (err instanceof _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError && err.errorNumber === _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus.InvertingZero) {
306532
- return { ok: false, error: ParseError.MathematicOperationFoundButIsNotAllowed };
306994
+ return { ok: false, error: ParseError.InvalidMathResult };
306533
306995
  }
306534
306996
  }
306535
306997
  if (converted === undefined || !converted.isValid) {
@@ -306655,7 +307117,8 @@ __webpack_require__.r(__webpack_exports__);
306655
307117
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
306656
307118
  /* harmony export */ ParserSpec: () => (/* binding */ ParserSpec)
306657
307119
  /* harmony export */ });
306658
- /* harmony import */ var _Parser__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Parser */ "../../core/quantity/lib/esm/Parser.js");
307120
+ /* harmony import */ var _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Formatter/FormatEnums */ "../../core/quantity/lib/esm/Formatter/FormatEnums.js");
307121
+ /* harmony import */ var _Parser__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Parser */ "../../core/quantity/lib/esm/Parser.js");
306659
307122
  /*---------------------------------------------------------------------------------------------
306660
307123
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
306661
307124
  * See LICENSE.md in the project root for license terms and full copyright notice.
@@ -306664,6 +307127,7 @@ __webpack_require__.r(__webpack_exports__);
306664
307127
  * @module Quantity
306665
307128
  */
306666
307129
 
307130
+
306667
307131
  /** A ParserSpec holds information needed to parse a string into a quantity synchronously.
306668
307132
  * @beta
306669
307133
  */
@@ -306689,6 +307153,51 @@ class ParserSpec {
306689
307153
  get outUnit() { return this._outUnit; }
306690
307154
  get azimuthBaseConversion() { return this._azimuthBaseConversion; }
306691
307155
  get revolutionConversion() { return this._revolutionConversion; }
307156
+ /** Build conversion specs for ratio format with 2 composite units (numerator/denominator). */
307157
+ static async getRatioUnitConversions(units, unitsProvider, outUnit, altUnitLabelsProvider) {
307158
+ const conversions = [];
307159
+ const [numeratorUnit, numeratorLabel] = units[0];
307160
+ const [denominatorUnit, denominatorLabel] = units[1];
307161
+ // Compute ratio scale: how many numerator units per denominator unit (e.g., IN:FT = 12)
307162
+ const denominatorToNumerator = await unitsProvider.getConversion(denominatorUnit, numeratorUnit);
307163
+ const displayRatioScale = denominatorToNumerator.factor;
307164
+ // Avoid double-scaling: if persistence unit already encodes the display ratio, use factor 1.
307165
+ // Check by name heuristic (e.g., IN_PER_FT with ratioUnits [IN, FT] → no scaling needed)
307166
+ const persistenceName = outUnit.name.toUpperCase();
307167
+ const numName = numeratorUnit.name.toUpperCase().split(".").pop() ?? "";
307168
+ const denName = denominatorUnit.name.toUpperCase().split(".").pop() ?? "";
307169
+ // Split by word boundaries (underscores, dots) and check for exact token matches
307170
+ const persistenceTokens = persistenceName.split(/[._]/);
307171
+ const isPersistenceMatchingRatio = persistenceTokens.includes(numName) && persistenceTokens.includes(denName);
307172
+ const ratioScaleFactor = isPersistenceMatchingRatio ? 1.0 : displayRatioScale;
307173
+ // First conversion spec: effective ratio unit conversion
307174
+ const ratioConversionSpec = {
307175
+ name: `${numeratorUnit.name}_per_${denominatorUnit.name}`,
307176
+ label: "",
307177
+ system: numeratorUnit.system,
307178
+ conversion: { factor: ratioScaleFactor, offset: 0.0 },
307179
+ };
307180
+ conversions.push(ratioConversionSpec);
307181
+ // Numerator unit for label lookup
307182
+ const numeratorSpec = {
307183
+ name: numeratorUnit.name,
307184
+ label: numeratorLabel?.length ? numeratorLabel : numeratorUnit.label,
307185
+ system: numeratorUnit.system,
307186
+ conversion: { factor: 1.0, offset: 0.0 },
307187
+ parseLabels: altUnitLabelsProvider?.getAlternateUnitLabels(numeratorUnit),
307188
+ };
307189
+ conversions.push(numeratorSpec);
307190
+ // Denominator unit for label lookup
307191
+ const denominatorSpec = {
307192
+ name: denominatorUnit.name,
307193
+ label: denominatorLabel?.length ? denominatorLabel : denominatorUnit.label,
307194
+ system: denominatorUnit.system,
307195
+ conversion: { factor: 1.0, offset: 0.0 },
307196
+ parseLabels: altUnitLabelsProvider?.getAlternateUnitLabels(denominatorUnit),
307197
+ };
307198
+ conversions.push(denominatorSpec);
307199
+ return conversions;
307200
+ }
306692
307201
  /** 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
306693
307202
  * 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
306694
307203
  * async calls to lookup unit definitions.
@@ -306697,7 +307206,14 @@ class ParserSpec {
306697
307206
  * @param outUnit The unit a value will be formatted to. This unit is often referred to as persistence unit.
306698
307207
  */
306699
307208
  static async create(format, unitsProvider, outUnit, altUnitLabelsProvider) {
306700
- const conversions = await _Parser__WEBPACK_IMPORTED_MODULE_0__.Parser.createUnitConversionSpecsForUnit(unitsProvider, outUnit, altUnitLabelsProvider);
307209
+ let conversions;
307210
+ // For ratio formats with 2 composite units, use private helper method
307211
+ if (format.type === _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_0__.FormatType.Ratio && format.units && format.units.length === 2) {
307212
+ conversions = await ParserSpec.getRatioUnitConversions(format.units, unitsProvider, outUnit, altUnitLabelsProvider);
307213
+ }
307214
+ else {
307215
+ conversions = await _Parser__WEBPACK_IMPORTED_MODULE_1__.Parser.createUnitConversionSpecsForUnit(unitsProvider, outUnit, altUnitLabelsProvider);
307216
+ }
306701
307217
  const spec = new ParserSpec(outUnit, format, conversions);
306702
307218
  if (format.azimuthBaseUnit !== undefined) {
306703
307219
  if (outUnit !== undefined) {
@@ -306719,7 +307235,7 @@ class ParserSpec {
306719
307235
  }
306720
307236
  /** Do the parsing. Done this way to allow Custom Parser Specs to parse custom formatted strings into their quantities. */
306721
307237
  parseToQuantityValue(inString) {
306722
- return _Parser__WEBPACK_IMPORTED_MODULE_0__.Parser.parseQuantityString(inString, this);
307238
+ return _Parser__WEBPACK_IMPORTED_MODULE_1__.Parser.parseQuantityString(inString, this);
306723
307239
  }
306724
307240
  }
306725
307241
 
@@ -306917,6 +307433,7 @@ __webpack_require__.r(__webpack_exports__);
306917
307433
  /* harmony export */ QuantityConstants: () => (/* reexport safe */ _Constants__WEBPACK_IMPORTED_MODULE_0__.QuantityConstants),
306918
307434
  /* harmony export */ QuantityError: () => (/* reexport safe */ _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityError),
306919
307435
  /* harmony export */ QuantityStatus: () => (/* reexport safe */ _Exception__WEBPACK_IMPORTED_MODULE_1__.QuantityStatus),
307436
+ /* harmony export */ RatioFormatType: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.RatioFormatType),
306920
307437
  /* harmony export */ RatioType: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.RatioType),
306921
307438
  /* harmony export */ ScientificType: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.ScientificType),
306922
307439
  /* harmony export */ ShowSignOption: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.ShowSignOption),
@@ -306935,6 +307452,7 @@ __webpack_require__.r(__webpack_exports__);
306935
307452
  /* harmony export */ parseFormatType: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.parseFormatType),
306936
307453
  /* harmony export */ parseFractionalPrecision: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.parseFractionalPrecision),
306937
307454
  /* harmony export */ parsePrecision: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.parsePrecision),
307455
+ /* harmony export */ parseRatioFormatType: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.parseRatioFormatType),
306938
307456
  /* harmony export */ parseRatioType: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.parseRatioType),
306939
307457
  /* harmony export */ parseScientificType: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.parseScientificType),
306940
307458
  /* harmony export */ parseShowSignOption: () => (/* reexport safe */ _Formatter_FormatEnums__WEBPACK_IMPORTED_MODULE_9__.parseShowSignOption),
@@ -320644,7 +321162,7 @@ var loadLanguages = instance.loadLanguages;
320644
321162
  /***/ ((module) => {
320645
321163
 
320646
321164
  "use strict";
320647
- module.exports = /*#__PURE__*/JSON.parse('{"name":"@itwin/core-frontend","version":"5.6.0-dev.7","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"}}');
321165
+ 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"}}');
320648
321166
 
320649
321167
  /***/ })
320650
321168