@itwin/core-quantity 4.8.0-dev.9 → 4.9.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +36 -1
  2. package/lib/cjs/Constants.js.map +1 -1
  3. package/lib/cjs/Exception.js.map +1 -1
  4. package/lib/cjs/Formatter/Format.d.ts +3 -0
  5. package/lib/cjs/Formatter/Format.d.ts.map +1 -1
  6. package/lib/cjs/Formatter/Format.js +8 -0
  7. package/lib/cjs/Formatter/Format.js.map +1 -1
  8. package/lib/cjs/Formatter/FormatEnums.js.map +1 -1
  9. package/lib/cjs/Formatter/Formatter.js.map +1 -1
  10. package/lib/cjs/Formatter/FormatterSpec.js.map +1 -1
  11. package/lib/cjs/Formatter/Interfaces.d.ts +1 -0
  12. package/lib/cjs/Formatter/Interfaces.d.ts.map +1 -1
  13. package/lib/cjs/Formatter/Interfaces.js.map +1 -1
  14. package/lib/cjs/Interfaces.js.map +1 -1
  15. package/lib/cjs/Parser.d.ts +25 -4
  16. package/lib/cjs/Parser.d.ts.map +1 -1
  17. package/lib/cjs/Parser.js +184 -117
  18. package/lib/cjs/Parser.js.map +1 -1
  19. package/lib/cjs/ParserSpec.js.map +1 -1
  20. package/lib/cjs/Quantity.js.map +1 -1
  21. package/lib/cjs/Unit.js.map +1 -1
  22. package/lib/cjs/core-quantity.js.map +1 -1
  23. package/lib/esm/Constants.js.map +1 -1
  24. package/lib/esm/Exception.js.map +1 -1
  25. package/lib/esm/Formatter/Format.d.ts +3 -0
  26. package/lib/esm/Formatter/Format.d.ts.map +1 -1
  27. package/lib/esm/Formatter/Format.js +8 -0
  28. package/lib/esm/Formatter/Format.js.map +1 -1
  29. package/lib/esm/Formatter/FormatEnums.js.map +1 -1
  30. package/lib/esm/Formatter/Formatter.js.map +1 -1
  31. package/lib/esm/Formatter/FormatterSpec.js.map +1 -1
  32. package/lib/esm/Formatter/Interfaces.d.ts +1 -0
  33. package/lib/esm/Formatter/Interfaces.d.ts.map +1 -1
  34. package/lib/esm/Formatter/Interfaces.js.map +1 -1
  35. package/lib/esm/Interfaces.js.map +1 -1
  36. package/lib/esm/Parser.d.ts +25 -4
  37. package/lib/esm/Parser.d.ts.map +1 -1
  38. package/lib/esm/Parser.js +184 -117
  39. package/lib/esm/Parser.js.map +1 -1
  40. package/lib/esm/ParserSpec.js.map +1 -1
  41. package/lib/esm/Quantity.js.map +1 -1
  42. package/lib/esm/Unit.js.map +1 -1
  43. package/lib/esm/core-quantity.js.map +1 -1
  44. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"FormatterSpec.js","sourceRoot":"","sources":["../../../src/Formatter/FormatterSpec.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n* See LICENSE.md in the project root for license terms and full copyright notice.\n*--------------------------------------------------------------------------------------------*/\n/** @packageDocumentation\n * @module Quantity\n */\n\nimport { UnitConversionProps, UnitConversionSpec, UnitProps, UnitsProvider } from \"../Interfaces\";\nimport { Format } from \"./Format\";\nimport { Formatter } from \"./Formatter\";\n\n// cSpell:ignore ZERONORMALIZED, nosign, onlynegative, signalways, negativeparentheses\n// cSpell:ignore trailzeroes, keepsinglezero, zeroempty, keepdecimalpoint, applyrounding, fractiondash, showunitlabel, prependunitlabel, exponentonlynegative\n\n/** 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.\n * Once created the FormatterSpec will be able to format quantity values with synchronous calls.\n * @beta\n */\nexport class FormatterSpec {\n protected _name: string;\n protected _conversions: UnitConversionSpec[] = []; // max four entries\n protected _format: Format;\n protected _persistenceUnit: UnitProps;\n\n /** Constructor\n * @param name The name of a format specification.\n * @param format Defines the output format for the quantity value.\n * @param conversions An array of conversion factors necessary to convert from an input unit to the units specified in the format.\n * @param persistenceUnit The unit the magnitude value is input.\n */\n constructor(name: string, format: Format, conversions?: UnitConversionSpec[], persistenceUnit?: UnitProps) {\n if (!persistenceUnit) {\n if (format.units) {\n const [props] = format.units[0];\n persistenceUnit = props;\n } else {\n throw new Error(\"Formatter Spec needs persistence unit to be specified\");\n }\n }\n\n this._name = name;\n this._format = format;\n this._persistenceUnit = persistenceUnit;\n if (conversions)\n this._conversions = conversions;\n }\n\n public get name(): string { return this._name; }\n /** Returns an array of UnitConversionSpecs, one for each unit that is to be shown in the formatted quantity string. */\n public get unitConversions(): UnitConversionSpec[] { return this._conversions; }\n public get format(): Format { return this._format; }\n public get persistenceUnit(): UnitProps { return this._persistenceUnit; }\n\n /** Get an array of UnitConversionSpecs, one for each unit that is to be shown in the formatted quantity string. */\n public static async getUnitConversions(format: Format, unitsProvider: UnitsProvider, inputUnit?: UnitProps): Promise<UnitConversionSpec[]> {\n const conversions: UnitConversionSpec[] = [];\n let persistenceUnit = inputUnit;\n if (!persistenceUnit) {\n if (format.units) {\n const [props] = format.units[0];\n persistenceUnit = props;\n } else {\n throw new Error(\"Formatter Spec needs persistence unit to be specified\");\n }\n }\n\n if (format.units) {\n let convertFromUnit = inputUnit;\n for (const unit of format.units) {\n let unitConversion: UnitConversionProps;\n if (convertFromUnit) {\n unitConversion = await unitsProvider.getConversion(convertFromUnit, unit[0]);\n } else {\n unitConversion = { factor: 1.0, offset: 0.0 };\n }\n const unitLabel = (unit[1] && unit[1].length > 0) ? unit[1] : unit[0].label;\n const spec = ({ name: unit[0].name, label: unitLabel, conversion: unitConversion, system: unit[0].system }) as UnitConversionSpec;\n\n conversions.push(spec);\n convertFromUnit = unit[0];\n }\n } else {\n // if format is only numeric and a input unit is defined set spec to use the input unit as the format unit\n if (inputUnit) {\n const spec: UnitConversionSpec = { name: inputUnit.name, label: inputUnit.label, system: inputUnit.system, conversion: { factor: 1.0, offset: 0.0 } };\n conversions.push(spec);\n }\n }\n\n return conversions;\n }\n\n /** Static async method to create a FormatSpec given the format and unit of the quantity that will be passed to the Formatter. The input unit will\n * 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\n * async calls to lookup unit definitions.\n * @param name The name of a format specification.\n * @param unitsProvider The units provider is used to look up unit definitions and provide conversion information for converting between units.\n * @param inputUnit The unit the value to be formatted. This unit is often referred to as persistence unit.\n */\n public static async create(name: string, format: Format, unitsProvider: UnitsProvider, inputUnit?: UnitProps): Promise<FormatterSpec> {\n const conversions: UnitConversionSpec[] = await FormatterSpec.getUnitConversions(format, unitsProvider, inputUnit);\n return new FormatterSpec(name, format, conversions, inputUnit);\n }\n\n /** Format a quantity value. */\n public applyFormatting(magnitude: number): string {\n return Formatter.formatQuantity(magnitude, this);\n }\n}\n"]}
1
+ {"version":3,"file":"FormatterSpec.js","sourceRoot":"","sources":["../../../src/Formatter/FormatterSpec.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n/** @packageDocumentation\r\n * @module Quantity\r\n */\r\n\r\nimport { UnitConversionProps, UnitConversionSpec, UnitProps, UnitsProvider } from \"../Interfaces\";\r\nimport { Format } from \"./Format\";\r\nimport { Formatter } from \"./Formatter\";\r\n\r\n// cSpell:ignore ZERONORMALIZED, nosign, onlynegative, signalways, negativeparentheses\r\n// cSpell:ignore trailzeroes, keepsinglezero, zeroempty, keepdecimalpoint, applyrounding, fractiondash, showunitlabel, prependunitlabel, exponentonlynegative\r\n\r\n/** 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.\r\n * Once created the FormatterSpec will be able to format quantity values with synchronous calls.\r\n * @beta\r\n */\r\nexport class FormatterSpec {\r\n protected _name: string;\r\n protected _conversions: UnitConversionSpec[] = []; // max four entries\r\n protected _format: Format;\r\n protected _persistenceUnit: UnitProps;\r\n\r\n /** Constructor\r\n * @param name The name of a format specification.\r\n * @param format Defines the output format for the quantity value.\r\n * @param conversions An array of conversion factors necessary to convert from an input unit to the units specified in the format.\r\n * @param persistenceUnit The unit the magnitude value is input.\r\n */\r\n constructor(name: string, format: Format, conversions?: UnitConversionSpec[], persistenceUnit?: UnitProps) {\r\n if (!persistenceUnit) {\r\n if (format.units) {\r\n const [props] = format.units[0];\r\n persistenceUnit = props;\r\n } else {\r\n throw new Error(\"Formatter Spec needs persistence unit to be specified\");\r\n }\r\n }\r\n\r\n this._name = name;\r\n this._format = format;\r\n this._persistenceUnit = persistenceUnit;\r\n if (conversions)\r\n this._conversions = conversions;\r\n }\r\n\r\n public get name(): string { return this._name; }\r\n /** Returns an array of UnitConversionSpecs, one for each unit that is to be shown in the formatted quantity string. */\r\n public get unitConversions(): UnitConversionSpec[] { return this._conversions; }\r\n public get format(): Format { return this._format; }\r\n public get persistenceUnit(): UnitProps { return this._persistenceUnit; }\r\n\r\n /** Get an array of UnitConversionSpecs, one for each unit that is to be shown in the formatted quantity string. */\r\n public static async getUnitConversions(format: Format, unitsProvider: UnitsProvider, inputUnit?: UnitProps): Promise<UnitConversionSpec[]> {\r\n const conversions: UnitConversionSpec[] = [];\r\n let persistenceUnit = inputUnit;\r\n if (!persistenceUnit) {\r\n if (format.units) {\r\n const [props] = format.units[0];\r\n persistenceUnit = props;\r\n } else {\r\n throw new Error(\"Formatter Spec needs persistence unit to be specified\");\r\n }\r\n }\r\n\r\n if (format.units) {\r\n let convertFromUnit = inputUnit;\r\n for (const unit of format.units) {\r\n let unitConversion: UnitConversionProps;\r\n if (convertFromUnit) {\r\n unitConversion = await unitsProvider.getConversion(convertFromUnit, unit[0]);\r\n } else {\r\n unitConversion = { factor: 1.0, offset: 0.0 };\r\n }\r\n const unitLabel = (unit[1] && unit[1].length > 0) ? unit[1] : unit[0].label;\r\n const spec = ({ name: unit[0].name, label: unitLabel, conversion: unitConversion, system: unit[0].system }) as UnitConversionSpec;\r\n\r\n conversions.push(spec);\r\n convertFromUnit = unit[0];\r\n }\r\n } else {\r\n // if format is only numeric and a input unit is defined set spec to use the input unit as the format unit\r\n if (inputUnit) {\r\n const spec: UnitConversionSpec = { name: inputUnit.name, label: inputUnit.label, system: inputUnit.system, conversion: { factor: 1.0, offset: 0.0 } };\r\n conversions.push(spec);\r\n }\r\n }\r\n\r\n return conversions;\r\n }\r\n\r\n /** Static async method to create a FormatSpec given the format and unit of the quantity that will be passed to the Formatter. The input unit will\r\n * 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\r\n * async calls to lookup unit definitions.\r\n * @param name The name of a format specification.\r\n * @param unitsProvider The units provider is used to look up unit definitions and provide conversion information for converting between units.\r\n * @param inputUnit The unit the value to be formatted. This unit is often referred to as persistence unit.\r\n */\r\n public static async create(name: string, format: Format, unitsProvider: UnitsProvider, inputUnit?: UnitProps): Promise<FormatterSpec> {\r\n const conversions: UnitConversionSpec[] = await FormatterSpec.getUnitConversions(format, unitsProvider, inputUnit);\r\n return new FormatterSpec(name, format, conversions, inputUnit);\r\n }\r\n\r\n /** Format a quantity value. */\r\n public applyFormatting(magnitude: number): string {\r\n return Formatter.formatQuantity(magnitude, this);\r\n }\r\n}\r\n"]}
@@ -19,6 +19,7 @@ export interface FormatProps {
19
19
  readonly scientificType?: string;
20
20
  readonly stationOffsetSize?: number;
21
21
  readonly stationSeparator?: string;
22
+ readonly allowMathematicOperations?: boolean;
22
23
  readonly composite?: {
23
24
  readonly spacer?: string;
24
25
  readonly includeZero?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"Interfaces.d.ts","sourceRoot":"","sources":["../../../src/Formatter/Interfaces.ts"],"names":[],"mappings":"AAIA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEhG;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE;QACnB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;QAC/B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;YACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;YACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;SACzB,CAAC,CAAC;KACJ,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,WAAW;IACpD,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC;CACtB;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,SAAU,WAAW,8BAEpD,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,yEAAyE;IACzE,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,oCAAoC;IACpC,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,4CAA4C;IAC5C,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,uFAAuF;IACvF,SAAS,CAAC,EAAE,gBAAgB,GAAG,mBAAmB,CAAC;IACnD,oDAAoD;IACpD,WAAW,CAAC,EAAE,SAAS,CAAC;CACzB"}
1
+ {"version":3,"file":"Interfaces.d.ts","sourceRoot":"","sources":["../../../src/Formatter/Interfaces.ts"],"names":[],"mappings":"AAIA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEhG;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,yBAAyB,CAAC,EAAE,OAAO,CAAC;IAC7C,QAAQ,CAAC,SAAS,CAAC,EAAE;QACnB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;QAC/B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;YACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;YACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;SACzB,CAAC,CAAC;KACJ,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,WAAW;IACpD,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC;CACtB;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,SAAU,WAAW,8BAEpD,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,yEAAyE;IACzE,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,oCAAoC;IACpC,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,4CAA4C;IAC5C,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,uFAAuF;IACvF,SAAS,CAAC,EAAE,gBAAgB,GAAG,mBAAmB,CAAC;IACnD,oDAAoD;IACpD,WAAW,CAAC,EAAE,SAAS,CAAC;CACzB"}
@@ -1 +1 @@
1
- {"version":3,"file":"Interfaces.js","sourceRoot":"","sources":["../../../src/Formatter/Interfaces.ts"],"names":[],"mappings":";AAAA;;;+FAG+F;AAC/F;;GAEG;;;AAsCH;;GAEG;AACI,MAAM,mBAAmB,GAAG,CAAC,IAAiB,EAA6B,EAAE;IAClF,OAAQ,IAA0B,CAAC,MAAM,KAAK,SAAS,CAAC;AAC1D,CAAC,CAAC;AAFW,QAAA,mBAAmB,uBAE9B","sourcesContent":["/*---------------------------------------------------------------------------------------------\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n* See LICENSE.md in the project root for license terms and full copyright notice.\n*--------------------------------------------------------------------------------------------*/\n/** @packageDocumentation\n * @module Quantity\n */\n\nimport { UnitProps } from \"../Interfaces\";\nimport { DecimalPrecision, FormatTraits, FormatType, FractionalPrecision } from \"./FormatEnums\";\n\n/** This interface defines the persistence format for describing the formatting of quantity values.\n * @beta\n */\nexport interface FormatProps {\n readonly type: string;\n readonly precision?: number;\n readonly roundFactor?: number;\n readonly minWidth?: number;\n readonly showSignOption?: string;\n readonly formatTraits?: string | string[];\n readonly decimalSeparator?: string;\n readonly thousandSeparator?: string;\n readonly uomSeparator?: string;\n readonly scientificType?: string; // conditionally required\n readonly stationOffsetSize?: number; // conditionally required\n readonly stationSeparator?: string;\n readonly composite?: {\n readonly spacer?: string;\n readonly includeZero?: boolean; // not currently used in Native formatter\n readonly units: Array<{\n readonly name: string;\n readonly label?: string;\n }>;\n };\n}\n\n/** This interface is used when supporting Custom Formatters that need more than the standard set of properties.\n * @beta\n */\nexport interface CustomFormatProps extends FormatProps {\n readonly custom: any;\n}\n\n/** CustomFormatProps type guard.\n * @beta\n */\nexport const isCustomFormatProps = (item: FormatProps): item is CustomFormatProps => {\n return (item as CustomFormatProps).custom !== undefined;\n};\n\n/** CloneFormat defines unit and label specification if primary unit is to be set during clone.\n * @beta\n */\nexport interface CloneUnit {\n unit?: UnitProps;\n label?: string;\n}\n\n/** CloneOptions that define modifications that can be made during the cloning of a Format.\n * @beta\n */\nexport interface CloneOptions {\n /** allows composite formats to be converted to only show primary unit */\n showOnlyPrimaryUnit?: boolean;\n /** allow format traits to be set */\n traits?: FormatTraits;\n /** allows new FormatType to be specified */\n type?: FormatType;\n /** allows precision to be set, this will throw if value is not valid for FormatType */\n precision?: DecimalPrecision | FractionalPrecision;\n /** allows primary unit and label to be specified */\n primaryUnit?: CloneUnit;\n}\n"]}
1
+ {"version":3,"file":"Interfaces.js","sourceRoot":"","sources":["../../../src/Formatter/Interfaces.ts"],"names":[],"mappings":";AAAA;;;+FAG+F;AAC/F;;GAEG;;;AAuCH;;GAEG;AACI,MAAM,mBAAmB,GAAG,CAAC,IAAiB,EAA6B,EAAE;IAClF,OAAQ,IAA0B,CAAC,MAAM,KAAK,SAAS,CAAC;AAC1D,CAAC,CAAC;AAFW,QAAA,mBAAmB,uBAE9B","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n/** @packageDocumentation\r\n * @module Quantity\r\n */\r\n\r\nimport { UnitProps } from \"../Interfaces\";\r\nimport { DecimalPrecision, FormatTraits, FormatType, FractionalPrecision } from \"./FormatEnums\";\r\n\r\n/** This interface defines the persistence format for describing the formatting of quantity values.\r\n * @beta\r\n */\r\nexport interface FormatProps {\r\n readonly type: string;\r\n readonly precision?: number;\r\n readonly roundFactor?: number;\r\n readonly minWidth?: number;\r\n readonly showSignOption?: string;\r\n readonly formatTraits?: string | string[];\r\n readonly decimalSeparator?: string;\r\n readonly thousandSeparator?: string;\r\n readonly uomSeparator?: string;\r\n readonly scientificType?: string; // conditionally required\r\n readonly stationOffsetSize?: number; // conditionally required\r\n readonly stationSeparator?: string;\r\n readonly allowMathematicOperations?: boolean;\r\n readonly composite?: {\r\n readonly spacer?: string;\r\n readonly includeZero?: boolean; // not currently used in Native formatter\r\n readonly units: Array<{\r\n readonly name: string;\r\n readonly label?: string;\r\n }>;\r\n };\r\n}\r\n\r\n/** This interface is used when supporting Custom Formatters that need more than the standard set of properties.\r\n * @beta\r\n */\r\nexport interface CustomFormatProps extends FormatProps {\r\n readonly custom: any;\r\n}\r\n\r\n/** CustomFormatProps type guard.\r\n * @beta\r\n */\r\nexport const isCustomFormatProps = (item: FormatProps): item is CustomFormatProps => {\r\n return (item as CustomFormatProps).custom !== undefined;\r\n};\r\n\r\n/** CloneFormat defines unit and label specification if primary unit is to be set during clone.\r\n * @beta\r\n */\r\nexport interface CloneUnit {\r\n unit?: UnitProps;\r\n label?: string;\r\n}\r\n\r\n/** CloneOptions that define modifications that can be made during the cloning of a Format.\r\n * @beta\r\n */\r\nexport interface CloneOptions {\r\n /** allows composite formats to be converted to only show primary unit */\r\n showOnlyPrimaryUnit?: boolean;\r\n /** allow format traits to be set */\r\n traits?: FormatTraits;\r\n /** allows new FormatType to be specified */\r\n type?: FormatType;\r\n /** allows precision to be set, this will throw if value is not valid for FormatType */\r\n precision?: DecimalPrecision | FractionalPrecision;\r\n /** allows primary unit and label to be specified */\r\n primaryUnit?: CloneUnit;\r\n}\r\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"Interfaces.js","sourceRoot":"","sources":["../../src/Interfaces.ts"],"names":[],"mappings":";AAAA;;;+FAG+F;AAC/F;;GAEG","sourcesContent":["/*---------------------------------------------------------------------------------------------\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n* See LICENSE.md in the project root for license terms and full copyright notice.\n*--------------------------------------------------------------------------------------------*/\n/** @packageDocumentation\n * @module Quantity\n */\n\n/** This interface allows a provider to be specified that will define an array of alternate labels for a specific unit.\n * @beta\n */\nexport interface AlternateUnitLabelsProvider {\n getAlternateUnitLabels: (unit: UnitProps) => string[] | undefined;\n}\n\n/** This interface provides basic information about a Unit that is return from a UnitProvider. This info\n * uniquely identifies a unit by its name.\n * @beta\n */\nexport interface UnitProps {\n /** Unique name for unit. */\n readonly name: string;\n /** Default label for unit. */\n readonly label: string;\n /** Unique name of unit phenomenon. Example phenomenon names include 'Units.LENGTH', 'Units.AREA', and 'Units.VOLUME' */\n readonly phenomenon: string;\n /** This is set to true if the Unit is known by the UnitsProvider. */\n readonly isValid: boolean;\n /** Unique system name. Example \"Units.USCUSTOM\",\" Units.METRIC\", \"Units.USSURVEY\", \"Units.IMPERIAL\" */\n readonly system: string;\n}\n\n/** This interface defines the required properties of a Quantity.\n * @beta\n */\nexport interface QuantityProps {\n readonly magnitude: number;\n readonly unit: UnitProps;\n readonly isValid: boolean;\n}\n\n/** Interface that defines how to convert between a specific unit an another in synchronous formatting or parsing processing.\n * @beta\n */\nexport interface UnitConversionSpec {\n /** Unit name that was used to locate the unit by the Unit Provider */\n name: string;\n /** The default label that is used to display unit */\n label: string;\n /** Unit system name, used to when finding preferred parse unit */\n system: string;\n /** the information necessary to convert the unit to a specific display unit */\n conversion: UnitConversionProps;\n /** Labels that may be used to represent the unit in a string that is to be parsed. */\n parseLabels?: string[];\n}\n\n/** This interface defines the properties required to convert a quantity value from one unit to another such as from meters to feet\n * or from Celsius to Fahrenheit.\n * @beta\n */\nexport interface UnitConversionProps {\n factor: number;\n offset: number;\n}\n\n/** Interface that defines potential parse units that may be found in user's string input of a quantity value.\n * @beta\n */\nexport interface PotentialParseUnit {\n unitName: string;\n altLabels?: string[];\n}\n\n/**\n * This interface defines extra properties to be associated with Units from Units Schema by name\n * @alpha\n */\nexport interface UnitExtraData {\n readonly name: string;\n readonly altDisplayLabels: string[];\n}\n\n/** This interface is implemented by the class that is responsible for locating units by name or label and providing conversion values between units.\n * The methods to be implemented are async allowing the UnitsProvider to query the backend when necessary to look up unit definition and conversion rules.\n * @beta\n */\nexport interface UnitsProvider {\n findUnit(unitLabel: string, schemaName?: string, phenomenon?: string, unitSystem?: string): Promise<UnitProps>;\n getUnitsByFamily(phenomenon: string): Promise<UnitProps[]>;\n findUnitByName(unitName: string): Promise<UnitProps>;\n getConversion(fromUnit: UnitProps, toUnit: UnitProps): Promise<UnitConversionProps>;\n}\n\n/**\n * Used to uniquely identify a unit system.\n * @beta\n */\nexport type UnitSystemKey = \"metric\" | \"imperial\" | \"usCustomary\" | \"usSurvey\";\n"]}
1
+ {"version":3,"file":"Interfaces.js","sourceRoot":"","sources":["../../src/Interfaces.ts"],"names":[],"mappings":";AAAA;;;+FAG+F;AAC/F;;GAEG","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n/** @packageDocumentation\r\n * @module Quantity\r\n */\r\n\r\n/** This interface allows a provider to be specified that will define an array of alternate labels for a specific unit.\r\n * @beta\r\n */\r\nexport interface AlternateUnitLabelsProvider {\r\n getAlternateUnitLabels: (unit: UnitProps) => string[] | undefined;\r\n}\r\n\r\n/** This interface provides basic information about a Unit that is return from a UnitProvider. This info\r\n * uniquely identifies a unit by its name.\r\n * @beta\r\n */\r\nexport interface UnitProps {\r\n /** Unique name for unit. */\r\n readonly name: string;\r\n /** Default label for unit. */\r\n readonly label: string;\r\n /** Unique name of unit phenomenon. Example phenomenon names include 'Units.LENGTH', 'Units.AREA', and 'Units.VOLUME' */\r\n readonly phenomenon: string;\r\n /** This is set to true if the Unit is known by the UnitsProvider. */\r\n readonly isValid: boolean;\r\n /** Unique system name. Example \"Units.USCUSTOM\",\" Units.METRIC\", \"Units.USSURVEY\", \"Units.IMPERIAL\" */\r\n readonly system: string;\r\n}\r\n\r\n/** This interface defines the required properties of a Quantity.\r\n * @beta\r\n */\r\nexport interface QuantityProps {\r\n readonly magnitude: number;\r\n readonly unit: UnitProps;\r\n readonly isValid: boolean;\r\n}\r\n\r\n/** Interface that defines how to convert between a specific unit an another in synchronous formatting or parsing processing.\r\n * @beta\r\n */\r\nexport interface UnitConversionSpec {\r\n /** Unit name that was used to locate the unit by the Unit Provider */\r\n name: string;\r\n /** The default label that is used to display unit */\r\n label: string;\r\n /** Unit system name, used to when finding preferred parse unit */\r\n system: string;\r\n /** the information necessary to convert the unit to a specific display unit */\r\n conversion: UnitConversionProps;\r\n /** Labels that may be used to represent the unit in a string that is to be parsed. */\r\n parseLabels?: string[];\r\n}\r\n\r\n/** This interface defines the properties required to convert a quantity value from one unit to another such as from meters to feet\r\n * or from Celsius to Fahrenheit.\r\n * @beta\r\n */\r\nexport interface UnitConversionProps {\r\n factor: number;\r\n offset: number;\r\n}\r\n\r\n/** Interface that defines potential parse units that may be found in user's string input of a quantity value.\r\n * @beta\r\n */\r\nexport interface PotentialParseUnit {\r\n unitName: string;\r\n altLabels?: string[];\r\n}\r\n\r\n/**\r\n * This interface defines extra properties to be associated with Units from Units Schema by name\r\n * @alpha\r\n */\r\nexport interface UnitExtraData {\r\n readonly name: string;\r\n readonly altDisplayLabels: string[];\r\n}\r\n\r\n/** This interface is implemented by the class that is responsible for locating units by name or label and providing conversion values between units.\r\n * The methods to be implemented are async allowing the UnitsProvider to query the backend when necessary to look up unit definition and conversion rules.\r\n * @beta\r\n */\r\nexport interface UnitsProvider {\r\n findUnit(unitLabel: string, schemaName?: string, phenomenon?: string, unitSystem?: string): Promise<UnitProps>;\r\n getUnitsByFamily(phenomenon: string): Promise<UnitProps[]>;\r\n findUnitByName(unitName: string): Promise<UnitProps>;\r\n getConversion(fromUnit: UnitProps, toUnit: UnitProps): Promise<UnitConversionProps>;\r\n}\r\n\r\n/**\r\n * Used to uniquely identify a unit system.\r\n * @beta\r\n */\r\nexport type UnitSystemKey = \"metric\" | \"imperial\" | \"usCustomary\" | \"usSurvey\";\r\n"]}
@@ -13,7 +13,8 @@ export declare enum ParseError {
13
13
  UnitLabelSuppliedButNotMatched = 3,
14
14
  UnknownUnit = 4,
15
15
  UnableToConvertParseTokensToQuantity = 5,
16
- InvalidParserSpec = 6
16
+ InvalidParserSpec = 6,
17
+ MathematicOperationFoundButIsNotAllowed = 7
17
18
  }
18
19
  /** Parse error result from [[Parser.parseToQuantityValue]] or [[Parser.parseToQuantityValue]].
19
20
  * @beta
@@ -33,6 +34,10 @@ export interface ParsedQuantity {
33
34
  /** The magnitude of the parsed quantity. */
34
35
  value: number;
35
36
  }
37
+ declare enum Operator {
38
+ addition = "+",
39
+ subtraction = "-"
40
+ }
36
41
  /**
37
42
  * Defines Results of parsing a string input by a user into its desired value type
38
43
  * @beta
@@ -42,8 +47,9 @@ export type QuantityParseResult = ParsedQuantity | ParseQuantityError;
42
47
  * @beta
43
48
  */
44
49
  declare class ParseToken {
45
- value: number | string;
46
- constructor(value: string | number);
50
+ value: number | string | Operator;
51
+ isOperator: boolean;
52
+ constructor(value: string | number | Operator);
47
53
  get isString(): boolean;
48
54
  get isNumber(): boolean;
49
55
  }
@@ -62,7 +68,15 @@ export declare class Parser {
62
68
  * @param quantitySpecification The quantity string to ba parsed.
63
69
  */
64
70
  static parseQuantitySpecification(quantitySpecification: string, format: Format): ParseToken[];
71
+ private static isMathematicOperation;
65
72
  private static lookupUnitByLabel;
73
+ /**
74
+ * Get the output unit and all the conversion specs required to parse a given list of tokens.
75
+ */
76
+ private static getRequiredUnitsConversionsToParseTokens;
77
+ /**
78
+ * Get the units information asynchronously, then convert the tokens into quantity using the synchronous tokens -> value.
79
+ */
66
80
  private static createQuantityFromParseTokens;
67
81
  /** Async method to generate a Quantity given a string that represents a quantity value and likely a unit label.
68
82
  * @param inString A string that contains text represent a quantity.
@@ -72,11 +86,18 @@ export declare class Parser {
72
86
  static parseIntoQuantity(inString: string, format: Format, unitsProvider: UnitsProvider, altUnitLabelsProvider?: AlternateUnitLabelsProvider): Promise<QuantityProps>;
73
87
  /** method to get the Unit Conversion given a unit label */
74
88
  private static tryFindUnitConversion;
89
+ /**
90
+ * Get what the unit conversion is for a unitless value.
91
+ */
92
+ private static getDefaultUnitConversion;
93
+ private static getNextTokenPair;
94
+ /**
95
+ * Accumulate the given list of tokens into a single quantity value. Formatting the tokens along the way.
96
+ */
75
97
  private static getQuantityValueFromParseTokens;
76
98
  /** Method to generate a Quantity given a string that represents a quantity value.
77
99
  * @param inString A string that contains text represent a quantity.
78
100
  * @param parserSpec unit label if not explicitly defined by user. Must have matching entry in supplied array of unitsConversions.
79
- * @param defaultValue default value to return if parsing is un successful
80
101
  */
81
102
  static parseQuantityString(inString: string, parserSpec: ParserSpec): QuantityParseResult;
82
103
  /** Method to generate a Quantity given a string that represents a quantity value and likely a unit label.
@@ -1 +1 @@
1
- {"version":3,"file":"Parser.d.ts","sourceRoot":"","sources":["../../src/Parser.ts"],"names":[],"mappings":"AAIA;;GAEG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,EAAE,2BAA2B,EAAE,kBAAkB,EAAE,aAAa,EAAuB,kBAAkB,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjK,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C;;GAEG;AACH,oBAAY,UAAU;IACpB,2BAA2B,IAAI;IAC/B,0BAA0B,IAAA;IAC1B,8BAA8B,IAAA;IAC9B,WAAW,IAAA;IACX,oCAAoC,IAAA;IACpC,iBAAiB,IAAA;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,uDAAuD;IACvD,EAAE,EAAE,KAAK,CAAC;IACV,uDAAuD;IACvD,KAAK,EAAE,UAAU,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,uDAAuD;IACvD,EAAE,EAAE,IAAI,CAAC;IACT,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,cAAc,GAAG,kBAAkB,CAAC;AAEtE;;GAEG;AACH,cAAM,UAAU;IACP,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;gBAElB,KAAK,EAAE,MAAM,GAAG,MAAM;IAOlC,IAAW,QAAQ,IAAI,OAAO,CAA2C;IACzE,IAAW,QAAQ,IAAI,OAAO,CAA2C;CAC1E;AA+BD;;GAEG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAC,IAAI,CAAS;WAEd,gBAAgB,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI,IAAI,cAAc;WAInE,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI,IAAI,kBAAkB;IAIjF,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAoBzC,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAyChC,OAAO,CAAC,MAAM,CAAC,OAAO;IAItB,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAIxC;;OAEG;WACW,0BAA0B,CAAC,qBAAqB,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,EAAE;mBA6IhF,iBAAiB;mBA6BjB,6BAA6B;IAkElD;;;;OAIG;WACiB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,qBAAqB,CAAC,EAAE,2BAA2B,GAAG,OAAO,CAAC,aAAa,CAAC;IAQlL,2DAA2D;IAC3D,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAyCpC,OAAO,CAAC,MAAM,CAAC,+BAA+B;IAmE9C;;;;OAIG;WACW,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,mBAAmB;IAIhG;;;;OAIG;WACW,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,GAAG,mBAAmB;IA+BjI,+HAA+H;WAC3G,gCAAgC,CAAC,aAAa,EAAE,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,qBAAqB,CAAC,EAAE,2BAA2B,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IA4B1L,+HAA+H;WAC3G,yBAAyB,CAAC,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,EAAE,qBAAqB,CAAC,EAAE,2BAA2B,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;CAgDhO"}
1
+ {"version":3,"file":"Parser.d.ts","sourceRoot":"","sources":["../../src/Parser.ts"],"names":[],"mappings":"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"}
package/lib/cjs/Parser.js CHANGED
@@ -22,18 +22,35 @@ var ParseError;
22
22
  ParseError[ParseError["UnknownUnit"] = 4] = "UnknownUnit";
23
23
  ParseError[ParseError["UnableToConvertParseTokensToQuantity"] = 5] = "UnableToConvertParseTokensToQuantity";
24
24
  ParseError[ParseError["InvalidParserSpec"] = 6] = "InvalidParserSpec";
25
+ ParseError[ParseError["MathematicOperationFoundButIsNotAllowed"] = 7] = "MathematicOperationFoundButIsNotAllowed";
25
26
  })(ParseError || (exports.ParseError = ParseError = {}));
27
+ var Operator;
28
+ (function (Operator) {
29
+ Operator["addition"] = "+";
30
+ Operator["subtraction"] = "-";
31
+ })(Operator || (Operator = {}));
32
+ function isOperator(char) {
33
+ if (typeof char === "number") {
34
+ // Convert the charcode to string.
35
+ char = String.fromCharCode(char);
36
+ }
37
+ return Object.values(Operator).includes(char);
38
+ }
26
39
  /** A ParseToken holds either a numeric or string token extracted from a string that represents a quantity value.
27
40
  * @beta
28
41
  */
29
42
  class ParseToken {
30
43
  constructor(value) {
31
- if (typeof value === "string")
44
+ this.isOperator = false;
45
+ if (typeof value === "string") {
32
46
  this.value = value.trim();
33
- else
47
+ this.isOperator = isOperator(this.value);
48
+ }
49
+ else {
34
50
  this.value = value;
51
+ }
35
52
  }
36
- get isString() { return typeof this.value === "string"; }
53
+ get isString() { return !this.isOperator && typeof this.value === "string"; }
37
54
  get isNumber() { return typeof this.value === "number"; }
38
55
  }
39
56
  /** A ScientificToken holds an index and string representing the exponent.
@@ -140,6 +157,7 @@ class Parser {
140
157
  let processingNumber = false;
141
158
  let wipToken = "";
142
159
  let signToken = "";
160
+ let isStationSeparatorAdded = false;
143
161
  let uomSeparatorToIgnore = 0;
144
162
  let fractionDashCode = 0;
145
163
  const skipCodes = [format.thousandSeparator.charCodeAt(0)];
@@ -225,9 +243,17 @@ class Parser {
225
243
  }
226
244
  }
227
245
  }
228
- // ignore any codes in skipCodes
229
- if (skipCodes.findIndex((ref) => ref === charCode) !== -1)
246
+ if (format.type === FormatEnums_1.FormatType.Station && charCode === format.stationSeparator.charCodeAt(0)) {
247
+ if (!isStationSeparatorAdded) {
248
+ isStationSeparatorAdded = true;
249
+ continue;
250
+ }
251
+ isStationSeparatorAdded = false;
252
+ }
253
+ else if (skipCodes.findIndex((ref) => ref === charCode) !== -1) {
254
+ // ignore any codes in skipCodes
230
255
  continue;
256
+ }
231
257
  if (signToken.length > 0) {
232
258
  wipToken = signToken + wipToken;
233
259
  signToken = "";
@@ -235,12 +261,24 @@ class Parser {
235
261
  tokens.push(new ParseToken(parseFloat(wipToken)));
236
262
  wipToken = (i < str.length) ? str[i] : "";
237
263
  processingNumber = false;
264
+ if (wipToken.length === 1 && isOperator(wipToken)) {
265
+ tokens.push(new ParseToken(wipToken)); // Push operator token.
266
+ wipToken = "";
267
+ }
238
268
  }
239
269
  else {
240
270
  // not processing a number
241
- if ((charCode === Constants_1.QuantityConstants.CHAR_PLUS || charCode === Constants_1.QuantityConstants.CHAR_MINUS)) {
242
- if (0 === tokens.length) // sign token only needed for left most value
243
- signToken = str[i];
271
+ if (isOperator(charCode)) {
272
+ if (wipToken.length > 0) {
273
+ // There is a token is progress, process it now, before adding the new operator token.
274
+ tokens.push(new ParseToken(wipToken));
275
+ wipToken = "";
276
+ }
277
+ tokens.push(new ParseToken(str[i])); // Push an Operator Token in the list.
278
+ continue;
279
+ }
280
+ if (wipToken.length === 0 && charCode === Constants_1.QuantityConstants.CHAR_SPACE) {
281
+ // Dont add space when the wip token is empty.
244
282
  continue;
245
283
  }
246
284
  wipToken = wipToken.concat(str[i]);
@@ -261,6 +299,17 @@ class Parser {
261
299
  }
262
300
  return tokens;
263
301
  }
302
+ static isMathematicOperation(tokens) {
303
+ if (tokens.length > 1) {
304
+ // The loop starts at one because the first token can be a operator without it being maths. Ex: "-5FT"
305
+ for (let i = 1; i < tokens.length; i++) {
306
+ if (tokens[i].isOperator)
307
+ // Operator found, it's a math operation.
308
+ return true;
309
+ }
310
+ }
311
+ return false;
312
+ }
264
313
  static async lookupUnitByLabel(unitLabel, format, unitsProvider, altUnitLabelsProvider) {
265
314
  const defaultUnit = format.units && format.units.length > 0 ? format.units[0][0] : undefined;
266
315
  const labelToFind = unitLabel.toLowerCase();
@@ -285,69 +334,53 @@ class Parser {
285
334
  foundUnit = await unitsProvider.findUnit(unitLabel, defaultUnit ? defaultUnit.phenomenon : undefined);
286
335
  return foundUnit;
287
336
  }
288
- static async createQuantityFromParseTokens(tokens, format, unitsProvider, altUnitLabelsProvider) {
289
- let defaultUnit = format.units && format.units.length > 0 ? format.units[0][0] : undefined;
290
- // common case where single value is supplied
291
- if (tokens.length === 1) {
292
- if (tokens[0].isNumber) {
293
- return new Quantity_1.Quantity(defaultUnit, tokens[0].value);
337
+ /**
338
+ * Get the output unit and all the conversion specs required to parse a given list of tokens.
339
+ */
340
+ static async getRequiredUnitsConversionsToParseTokens(tokens, format, unitsProvider, altUnitLabelsProvider) {
341
+ let outUnit = (format.units && format.units.length > 0 ? format.units[0][0] : undefined);
342
+ const unitConversions = [];
343
+ const uniqueUnitLabels = [...new Set(tokens.filter((token) => token.isString).map((token) => token.value))];
344
+ for (const label of uniqueUnitLabels) {
345
+ const unitProps = await this.lookupUnitByLabel(label, format, unitsProvider, altUnitLabelsProvider);
346
+ if (!outUnit) {
347
+ // No default unit, assume that the first unit found is the desired output unit.
348
+ outUnit = unitProps;
294
349
  }
295
- else {
296
- const unit = await this.lookupUnitByLabel(tokens[0].value, format, unitsProvider, altUnitLabelsProvider);
297
- return new Quantity_1.Quantity(unit);
350
+ let spec = unitConversions.find((specB) => specB.name === unitProps.name);
351
+ if (spec) {
352
+ // Already in the list, just add the label.
353
+ spec.parseLabels?.push(label.toLocaleLowerCase());
298
354
  }
299
- }
300
- // common case where single value and single label are supplied
301
- if (tokens.length === 2) {
302
- // unit specification comes before value (like currency)
303
- if (tokens[1].isNumber && tokens[0].isString) {
304
- tokens = [tokens[1], tokens[0]];
305
- }
306
- if (tokens[0].isNumber && tokens[1].isString) {
307
- const unit = await this.lookupUnitByLabel(tokens[1].value, format, unitsProvider, altUnitLabelsProvider);
308
- if (undefined === defaultUnit)
309
- defaultUnit = unit;
310
- if (defaultUnit && defaultUnit.name === unit.name) {
311
- return new Quantity_1.Quantity(defaultUnit, tokens[0].value);
312
- }
313
- else if (defaultUnit) {
314
- const conversion = await unitsProvider.getConversion(unit, defaultUnit);
315
- const mag = ((tokens[0].value * conversion.factor)) + conversion.offset;
316
- return new Quantity_1.Quantity(defaultUnit, mag);
355
+ else {
356
+ // Add new conversion to the list.
357
+ const conversion = await unitsProvider.getConversion(unitProps, outUnit);
358
+ if (conversion) {
359
+ spec = {
360
+ conversion,
361
+ label: unitProps.label,
362
+ system: unitProps.system,
363
+ name: unitProps.name,
364
+ parseLabels: [label.toLocaleLowerCase()],
365
+ };
366
+ unitConversions.push(spec);
317
367
  }
318
368
  }
319
369
  }
320
- // common case where there are multiple value/label pairs
321
- if (tokens.length % 2 === 0) {
322
- let mag = 0.0;
323
- for (let i = 0; i < tokens.length; i = i + 2) {
324
- if (tokens[i].isNumber && tokens[i + 1].isString) {
325
- const value = tokens[i].value;
326
- const unit = await this.lookupUnitByLabel(tokens[i + 1].value, format, unitsProvider, altUnitLabelsProvider);
327
- if (undefined === defaultUnit)
328
- defaultUnit = unit;
329
- if (0 === i) {
330
- if (defaultUnit.name === unit.name)
331
- mag = value;
332
- else {
333
- const conversion = await unitsProvider.getConversion(unit, defaultUnit);
334
- mag = ((value * conversion.factor)) + conversion.offset;
335
- }
336
- }
337
- else {
338
- if (defaultUnit) {
339
- const conversion = await unitsProvider.getConversion(unit, defaultUnit);
340
- if (mag < 0.0)
341
- mag = mag - ((value * conversion.factor)) + conversion.offset;
342
- else
343
- mag = mag + ((value * conversion.factor)) + conversion.offset;
344
- }
345
- }
346
- }
370
+ return { outUnit, specs: unitConversions };
371
+ }
372
+ /**
373
+ * Get the units information asynchronously, then convert the tokens into quantity using the synchronous tokens -> value.
374
+ */
375
+ static async createQuantityFromParseTokens(tokens, format, unitsProvider, altUnitLabelsProvider) {
376
+ const unitConversionInfos = await this.getRequiredUnitsConversionsToParseTokens(tokens, format, unitsProvider, altUnitLabelsProvider);
377
+ if (unitConversionInfos.outUnit) {
378
+ const value = Parser.getQuantityValueFromParseTokens(tokens, format, unitConversionInfos.specs, await unitsProvider.getConversion(unitConversionInfos.outUnit, unitConversionInfos.outUnit));
379
+ if (value.ok) {
380
+ return new Quantity_1.Quantity(unitConversionInfos.outUnit, value.value);
347
381
  }
348
- return new Quantity_1.Quantity(defaultUnit, mag);
349
382
  }
350
- return new Quantity_1.Quantity(defaultUnit);
383
+ return new Quantity_1.Quantity();
351
384
  }
352
385
  /** Async method to generate a Quantity given a string that represents a quantity value and likely a unit label.
353
386
  * @param inString A string that contains text represent a quantity.
@@ -356,7 +389,7 @@ class Parser {
356
389
  */
357
390
  static async parseIntoQuantity(inString, format, unitsProvider, altUnitLabelsProvider) {
358
391
  const tokens = Parser.parseQuantitySpecification(inString, format);
359
- if (tokens.length === 0)
392
+ if (tokens.length === 0 || (!format.allowMathematicOperations && Parser.isMathematicOperation(tokens)))
360
393
  return new Quantity_1.Quantity();
361
394
  return Parser.createQuantityFromParseTokens(tokens, format, unitsProvider, altUnitLabelsProvider);
362
395
  }
@@ -399,75 +432,106 @@ class Parser {
399
432
  }
400
433
  return undefined;
401
434
  }
402
- static getQuantityValueFromParseTokens(tokens, format, unitsConversions) {
403
- const defaultUnit = format.units && format.units.length > 0 ? format.units[0][0] : undefined;
404
- // common case where single value is supplied
405
- if (tokens.length === 1) {
406
- if (tokens[0].isNumber) {
407
- if (defaultUnit) {
408
- const conversion = Parser.tryFindUnitConversion(defaultUnit.label, unitsConversions, defaultUnit);
409
- if (conversion) {
410
- const value = tokens[0].value * conversion.factor + conversion.offset;
411
- return { ok: true, value };
412
- }
413
- }
414
- else {
415
- // if no conversion or no defaultUnit, just return parsed number
416
- return { ok: true, value: tokens[0].value };
417
- }
435
+ /**
436
+ * Get what the unit conversion is for a unitless value.
437
+ */
438
+ static getDefaultUnitConversion(tokens, unitsConversions, defaultUnit) {
439
+ let unitConversion = defaultUnit ? Parser.tryFindUnitConversion(defaultUnit.label, unitsConversions, defaultUnit) : undefined;
440
+ if (!unitConversion) {
441
+ // No default unit conversion, take the first valid unit.
442
+ const uniqueUnitLabels = [...new Set(tokens.filter((token) => token.isString).map((token) => token.value))];
443
+ for (const label of uniqueUnitLabels) {
444
+ unitConversion = Parser.tryFindUnitConversion(label, unitsConversions, defaultUnit);
445
+ if (unitConversion !== undefined)
446
+ return unitConversion;
447
+ }
448
+ }
449
+ return unitConversion;
450
+ }
451
+ // Get the next token pair to parse into a quantity.
452
+ static getNextTokenPair(index, tokens) {
453
+ if (index >= tokens.length)
454
+ return;
455
+ // 6 possible combination of token pair.
456
+ // Stringified to ease comparison later.
457
+ const validCombinations = [
458
+ JSON.stringify(["string"]), // ['FT']
459
+ JSON.stringify(["string", "number"]), // ['$', 5] unit specification comes before value (like currency)
460
+ JSON.stringify(["number"]), // [5]
461
+ JSON.stringify(["number", "string"]), // [5, 'FT']
462
+ JSON.stringify(["operator", "number"]), // ['-', 5]
463
+ JSON.stringify(["operator", "number", "string"]), // ['-', 5, 'FT']
464
+ ];
465
+ // Push up to 3 tokens in the list, if the length allows it.
466
+ const maxNbrTokensInThePair = Math.min(tokens.length - index, 3);
467
+ const tokenPair = tokens.slice(index, index + maxNbrTokensInThePair);
468
+ const currentCombination = tokenPair.map((token) => token.isOperator ? "operator" : (token.isNumber ? "number" : "string"));
469
+ // Check if the token pair is valid. If not, try again by removing the last token util empty.
470
+ // Ex: ['5', 'FT', '7'] invalid => ['5', 'FT'] valid returned
471
+ for (let i = currentCombination.length - 1; i >= 0; i--) {
472
+ if (validCombinations.includes(JSON.stringify(currentCombination))) {
473
+ break;
418
474
  }
419
475
  else {
420
- // only the unit label was specified so assume magnitude of 1
421
- const conversion = Parser.tryFindUnitConversion(tokens[0].value, unitsConversions, defaultUnit);
422
- if (undefined !== conversion)
423
- return { ok: true, value: conversion.factor + conversion.offset };
424
- else
425
- return { ok: false, error: ParseError.NoValueOrUnitFoundInString };
476
+ currentCombination.pop();
477
+ tokenPair.pop();
426
478
  }
427
479
  }
428
- // common case where single value and single label are supplied
429
- if (tokens.length === 2) {
480
+ return tokenPair.length > 0 ? tokenPair : undefined;
481
+ }
482
+ /**
483
+ * Accumulate the given list of tokens into a single quantity value. Formatting the tokens along the way.
484
+ */
485
+ static getQuantityValueFromParseTokens(tokens, format, unitsConversions, defaultUnitConversion) {
486
+ const defaultUnit = format.units && format.units.length > 0 ? format.units[0][0] : undefined;
487
+ defaultUnitConversion = defaultUnitConversion ? defaultUnitConversion : Parser.getDefaultUnitConversion(tokens, unitsConversions, defaultUnit);
488
+ let tokenPair;
489
+ let increment = 1;
490
+ let mag = 0.0;
491
+ // The sign is saved outside from the loop for cases like this. '-1m 50cm 10mm + 2m 30cm 40mm' => -1.51m + 2.34m
492
+ let sign = 1;
493
+ for (let i = 0; i < tokens.length; i = i + increment) {
494
+ tokenPair = this.getNextTokenPair(i, tokens);
495
+ if (!tokenPair || tokenPair.length === 0) {
496
+ return { ok: false, error: ParseError.UnableToConvertParseTokensToQuantity };
497
+ }
498
+ increment = tokenPair.length;
499
+ // Keep the sign so its applied to the next tokens.
500
+ if (tokenPair[0].isOperator) {
501
+ sign = tokenPair[0].value === Operator.addition ? 1 : -1;
502
+ tokenPair.shift();
503
+ }
430
504
  // unit specification comes before value (like currency)
431
- if (tokens[1].isNumber && tokens[0].isString) {
432
- tokens = [tokens[1], tokens[0]];
505
+ if (tokenPair.length === 2 && tokenPair[0].isString) {
506
+ // Invert it so the currency sign comes second.
507
+ tokenPair = [tokenPair[1], tokenPair[0]];
433
508
  }
434
- if (tokens[0].isNumber && tokens[1].isString) {
435
- let conversion = Parser.tryFindUnitConversion(tokens[1].value, unitsConversions, defaultUnit);
436
- // if no conversion, ignore value in second token. If we have defaultUnit, use it.
437
- if (!conversion && defaultUnit) {
438
- conversion = Parser.tryFindUnitConversion(defaultUnit.label, unitsConversions, defaultUnit);
509
+ if (tokenPair[0].isNumber) {
510
+ let value = sign * tokenPair[0].value;
511
+ let conversion;
512
+ if (tokenPair.length === 2 && tokenPair[1].isString) {
513
+ conversion = Parser.tryFindUnitConversion(tokenPair[1].value, unitsConversions, defaultUnit);
439
514
  }
515
+ conversion = conversion ? conversion : defaultUnitConversion;
440
516
  if (conversion) {
441
- const value = tokens[0].value * conversion.factor + conversion.offset;
442
- return { ok: true, value };
517
+ value = (value * conversion.factor) + conversion.offset;
443
518
  }
444
- // if no conversion, just return parsed number and ignore value in second token
445
- return { ok: true, value: tokens[0].value };
519
+ mag = mag + value;
446
520
  }
447
- }
448
- // common case where there are multiple value/label pairs
449
- if (tokens.length % 2 === 0) {
450
- let mag = 0.0;
451
- for (let i = 0; i < tokens.length; i = i + 2) {
452
- if (tokens[i].isNumber && tokens[i + 1].isString) {
453
- const value = tokens[i].value;
454
- const conversion = Parser.tryFindUnitConversion(tokens[i + 1].value, unitsConversions, defaultUnit);
455
- if (conversion) {
456
- if (mag < 0.0)
457
- mag = mag - ((value * conversion.factor)) + conversion.offset;
458
- else
459
- mag = mag + ((value * conversion.factor)) + conversion.offset;
460
- }
521
+ else {
522
+ // only the unit label was specified so assume magnitude of 0
523
+ const conversion = Parser.tryFindUnitConversion(tokenPair[0].value, unitsConversions, defaultUnit);
524
+ if (conversion === undefined) {
525
+ // Unknown unit label
526
+ return { ok: false, error: ParseError.NoValueOrUnitFoundInString };
461
527
  }
462
528
  }
463
- return { ok: true, value: mag };
464
529
  }
465
- return { ok: false, error: ParseError.UnableToConvertParseTokensToQuantity };
530
+ return { ok: true, value: mag };
466
531
  }
467
532
  /** Method to generate a Quantity given a string that represents a quantity value.
468
533
  * @param inString A string that contains text represent a quantity.
469
534
  * @param parserSpec unit label if not explicitly defined by user. Must have matching entry in supplied array of unitsConversions.
470
- * @param defaultValue default value to return if parsing is un successful
471
535
  */
472
536
  static parseQuantityString(inString, parserSpec) {
473
537
  return Parser.parseToQuantityValue(inString, parserSpec.format, parserSpec.unitConversions);
@@ -493,6 +557,9 @@ class Parser {
493
557
  const tokens = Parser.parseQuantitySpecification(inString, format);
494
558
  if (tokens.length === 0)
495
559
  return { ok: false, error: ParseError.UnableToGenerateParseTokens };
560
+ if (!format.allowMathematicOperations && Parser.isMathematicOperation(tokens)) {
561
+ return { ok: false, error: ParseError.MathematicOperationFoundButIsNotAllowed };
562
+ }
496
563
  if (Parser._log) {
497
564
  // eslint-disable-next-line no-console
498
565
  console.log(`Parse tokens`);