UNPKG

@itwin/presentation-common

Version:

Common pieces for iModel.js presentation packages

166 lines 7.48 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module Core */ import { Format, FormatterSpec, ParserSpec } from "@itwin/core-quantity"; import { getFormatProps, InvertedUnit, KindOfQuantity, SchemaKey, SchemaMatchType, SchemaUnitProvider, } from "@itwin/ecschema-metadata"; /** * An utility for formatting property values based on `KindOfQuantity` and unit system. * @public */ export class KoqPropertyValueFormatter { _schemaContext; _unitsProvider; _defaultFormats; constructor(_schemaContext, defaultFormats) { this._schemaContext = _schemaContext; this._unitsProvider = new SchemaUnitProvider(_schemaContext); this._defaultFormats = defaultFormats ? Object.entries(defaultFormats).reduce((acc, [phenomenon, unitSystemFormats]) => ({ ...acc, [phenomenon.toUpperCase()]: unitSystemFormats }), {}) : /* c8 ignore next */ undefined; } async format(value, options) { const formatterSpec = await this.getFormatterSpec(options); if (!formatterSpec) { return undefined; } return formatterSpec.applyFormatting(value); } async getFormatterSpec(options) { const formattingProps = await getFormattingProps(this._schemaContext, this._defaultFormats, options); if (!formattingProps) { return undefined; } const { formatProps, persistenceUnitName } = formattingProps; const persistenceUnit = await this._unitsProvider.findUnitByName(persistenceUnitName); const format = await Format.createFromJSON("", this._unitsProvider, formatProps); return FormatterSpec.create("", format, this._unitsProvider, persistenceUnit); } async getParserSpec(options) { const formattingProps = await getFormattingProps(this._schemaContext, this._defaultFormats, options); if (!formattingProps) { return undefined; } const { formatProps, persistenceUnitName } = formattingProps; const persistenceUnit = await this._unitsProvider.findUnitByName(persistenceUnitName); const format = await Format.createFromJSON("", this._unitsProvider, formatProps); return ParserSpec.create(format, this._unitsProvider, persistenceUnit); } } async function getFormattingProps(schemaLocater, defaultFormats, options) { const { koqName, unitSystem } = options; const koq = await getKoq(schemaLocater, koqName); if (!koq) { return undefined; } const persistenceUnit = await koq.persistenceUnit; /* c8 ignore next 3 */ if (!persistenceUnit) { return undefined; } const formatProps = await getKoqFormatProps(koq, persistenceUnit, defaultFormats, unitSystem); if (!formatProps) { return undefined; } return { formatProps, persistenceUnitName: persistenceUnit.fullName }; } async function getKoq(schemaLocater, fullName) { const [schemaName, propKoqName] = fullName.split(":"); const schema = await schemaLocater.getSchema(new SchemaKey(schemaName), SchemaMatchType.Latest); if (!schema) { return undefined; } return schema.getItem(propKoqName, KindOfQuantity); } async function getKoqFormatProps(koq, persistenceUnit, defaultFormats, unitSystem) { const unitSystemMatchers = getUnitSystemGroupMatchers(unitSystem); // use one of KOQ presentation format that matches requested unit system const presentationFormat = await getKoqPresentationFormat(koq, unitSystemMatchers); if (presentationFormat) { return getFormatProps(presentationFormat); } // use one of the formats in default formats map if there is one for matching phenomena and requested unit // system combination if (defaultFormats && unitSystem) { const actualPersistenceUnit = persistenceUnit instanceof InvertedUnit ? /* c8 ignore next */ await persistenceUnit.invertsUnit : persistenceUnit; const phenomenon = await actualPersistenceUnit?.phenomenon; if (phenomenon && defaultFormats[phenomenon.name.toUpperCase()]) { const defaultPhenomenonFormats = defaultFormats[phenomenon.name.toUpperCase()]; for (const defaultUnitSystemFormat of Array.isArray(defaultPhenomenonFormats) ? /* c8 ignore next */ defaultPhenomenonFormats : [defaultPhenomenonFormats]) { if (defaultUnitSystemFormat.unitSystems.includes(unitSystem)) { return defaultUnitSystemFormat.format; } } } } // use persistence unit format if it matches requested unit system and matching presentation format was not found const persistenceUnitSystem = await persistenceUnit.unitSystem; if (persistenceUnitSystem && unitSystemMatchers.some((matcher) => matcher(persistenceUnitSystem))) { return getPersistenceUnitFormatProps(persistenceUnit); } // use default presentation format if persistence unit does not match requested unit system if (koq.defaultPresentationFormat) { return getFormatProps(await koq.defaultPresentationFormat); } return undefined; } async function getKoqPresentationFormat(koq, unitSystemMatchers) { const presentationFormats = koq.presentationFormats; for (const matcher of unitSystemMatchers) { for (const lazyFormat of presentationFormats) { const format = await lazyFormat; const lazyUnit = format.units && format.units[0][0]; /* c8 ignore next 3 */ if (!lazyUnit) { continue; } const unit = await lazyUnit; const currentUnitSystem = await unit.unitSystem; if (currentUnitSystem && matcher(currentUnitSystem)) { return format; } } } return undefined; } function getPersistenceUnitFormatProps(persistenceUnit) { // Same as Format "DefaultRealU" in Formats ecschema return { formatTraits: ["keepSingleZero", "keepDecimalPoint", "showUnitLabel"], precision: 6, type: "Decimal", uomSeparator: " ", decimalSeparator: ".", composite: { units: [ { name: persistenceUnit.fullName, label: persistenceUnit.label, }, ], }, }; } function getUnitSystemGroupMatchers(groupKey) { function createMatcher(name) { const names = Array.isArray(name) ? name : [name]; return (unitSystem) => names.some((n) => n === unitSystem.name.toUpperCase()); } switch (groupKey) { case "imperial": return ["IMPERIAL", "USCUSTOM", "INTERNATIONAL", "FINANCE"].map(createMatcher); case "metric": return [["SI", "METRIC"], "INTERNATIONAL", "FINANCE"].map(createMatcher); case "usCustomary": return ["USCUSTOM", "INTERNATIONAL", "FINANCE"].map(createMatcher); case "usSurvey": return ["USSURVEY", "USCUSTOM", "INTERNATIONAL", "FINANCE"].map(createMatcher); } return []; } //# sourceMappingURL=KoqPropertyValueFormatter.js.map