Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@itwin/core-quantity",
"comment": "Return error result when unit labels aren't matched during quantity parsing",
"type": "none"
}
],
"packageName": "@itwin/core-quantity"
}
10 changes: 9 additions & 1 deletion core/quantity/src/Parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,8 @@ export class Parser {
if (unitConversion !== undefined)
return unitConversion;
}
// if there were unique unit labels but not matched to any units, throw an error
if (uniqueUnitLabels.length > 0) throw new QuantityError(QuantityStatus.UnitLabelSuppliedButNotMatched, `The unit label(s) ${uniqueUnitLabels.join(", ")} could not be matched to a known unit.`);
}
return unitConversion;
}
Expand Down Expand Up @@ -613,7 +615,13 @@ export class Parser {
}

const defaultUnit = format.units && format.units.length > 0 ? format.units[0][0] : undefined;
defaultUnitConversion = defaultUnitConversion ? defaultUnitConversion : Parser.getDefaultUnitConversion(tokens, unitsConversions, defaultUnit);
try {
defaultUnitConversion = defaultUnitConversion ? defaultUnitConversion : Parser.getDefaultUnitConversion(tokens, unitsConversions, defaultUnit);
} catch (e) {
// If we failed to get the default unit conversion, we need to return an error.
if (e instanceof QuantityError && e.errorNumber === QuantityStatus.UnitLabelSuppliedButNotMatched)
return { ok: false, error: ParseError.UnitLabelSuppliedButNotMatched };
}

if (format.type === FormatType.Bearing && format.units !== undefined && format.units.length > 0) {
const units = format.units;
Expand Down
28 changes: 28 additions & 0 deletions core/quantity/src/test/Parsing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,34 @@ describe("Synchronous Parsing tests:", async () => {
}
});

it("parse returns a bad value with ParseError.UnitLabelSuppliedButNotMatched", async () => {
const formatDataUnitless = {
formatTraits: ["keepSingleZero", "showUnitLabel"],
precision: 8,
type: "Fractional",
uomSeparator: "",
allowMathematicOperations: true,
};
const formatUnitless = new Format("test");
await formatUnitless.fromJSON(unitsProvider, formatDataUnitless);
const unitlessParserSpec = await ParserSpec.create(formatUnitless, unitsProvider, outUnit, unitsProvider);

const testData = [
"100 INVALIDUNIT",
"50 BADLABEL",
"25.5 UNKNOWNUNIT",
"1.5 NOTFOUND",
"1metera + 123 + 1.65"
];

for (const testEntry of testData) {
const parseResult = Parser.parseQuantityString(testEntry, unitlessParserSpec);
expect(Parser.isParseError(parseResult)).to.be.true;
if (Parser.isParseError(parseResult)) {
expect(parseResult.error).toEqual(ParseError.UnitLabelSuppliedButNotMatched);
}
}
});
it("Parse into length values using custom parse labels", () => {
const testData = [
// if no quantity is provided then the format unit is used to determine unit
Expand Down
9 changes: 9 additions & 0 deletions docs/changehistory/NextVersion.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,12 @@ publish: false
---
# NextVersion

- [NextVersion](#nextversion)
- [@itwin/core-quantity](#itwincore-quantity)
- [Changes](#changes)

## @itwin/core-quantity

### Changes

- **Breaking Change**: Enhanced [Parser]($quantity) error handling to properly propagate `ParseError.UnitLabelSuppliedButNotMatched` when unit labels are provided but cannot be matched to known units. **This change may cause parsing operations that previously succeeded with invalid unit labels to now return error results instead**, providing more accurate feedback and preventing silent failures when parsing quantities with unrecognized unit labels.