mirror of
https://github.com/trezor/trezor-suite.git
synced 2026-03-21 22:57:17 +01:00
fix(schema-utils): add autocast string -> number
This commit is contained in:
committed by
Tomáš Martykán
parent
23b664a894
commit
aaa0cd7846
@@ -5,6 +5,7 @@ import { Mixin } from 'ts-mixer';
|
||||
|
||||
import { ArrayBufferBuilder, BufferBuilder, KeyofEnumBuilder, UintBuilder } from './custom-types';
|
||||
import { InvalidParameter } from './errors';
|
||||
import { setDeepValue } from './utils';
|
||||
|
||||
class CustomTypeBuilder extends Mixin(
|
||||
JavaScriptTypeBuilder,
|
||||
@@ -69,6 +70,17 @@ export function Assert<T extends TSchema>(schema: T, value: unknown): asserts va
|
||||
} else if (error.type === ValueErrorType.Union) {
|
||||
// Drill down into the union
|
||||
FindErrorInUnion(error);
|
||||
} else if (error.type === ValueErrorType.Number && typeof error.value === 'string') {
|
||||
// String instead of number, try to autocast
|
||||
const currentValue = error.value;
|
||||
const parsedNumber = Number(currentValue);
|
||||
if (!Number.isNaN(parsedNumber) && currentValue === parsedNumber.toString()) {
|
||||
// Autocast successful
|
||||
const pathParts = error.path.slice(1).split('/');
|
||||
setDeepValue(value, pathParts, parsedNumber);
|
||||
} else {
|
||||
throw new InvalidParameter(error.message, error.path, error.type, error.value);
|
||||
}
|
||||
} else {
|
||||
throw new InvalidParameter(error.message, error.path, error.type, error.value);
|
||||
}
|
||||
|
||||
15
packages/schema-utils/src/utils.ts
Normal file
15
packages/schema-utils/src/utils.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Sets a value in an object by a path
|
||||
* From https://stackoverflow.com/a/53762921
|
||||
* @param obj object to set value in
|
||||
* @param param path to the value
|
||||
* @param value value to set
|
||||
*/
|
||||
export function setDeepValue(obj: any, [prop, ...path]: string[], value: any) {
|
||||
if (!path.length) {
|
||||
obj[prop] = value;
|
||||
} else {
|
||||
if (!(prop in obj)) obj[prop] = {};
|
||||
setDeepValue(obj[prop], path, value);
|
||||
}
|
||||
}
|
||||
23
packages/schema-utils/tests/number-autocast.test.ts
Normal file
23
packages/schema-utils/tests/number-autocast.test.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Type, Assert } from '../src';
|
||||
|
||||
describe('number-autocast', () => {
|
||||
it('should string to number if needed', () => {
|
||||
const schema = Type.Object({
|
||||
number: Type.Number(),
|
||||
nested: Type.Object({
|
||||
number: Type.Number(),
|
||||
}),
|
||||
});
|
||||
|
||||
const input = {
|
||||
number: '1',
|
||||
nested: {
|
||||
number: '1',
|
||||
},
|
||||
};
|
||||
|
||||
Assert(schema, input);
|
||||
expect(input.number).toEqual(1);
|
||||
expect(input.nested.number).toEqual(1);
|
||||
});
|
||||
});
|
||||
21
packages/schema-utils/tests/utils.test.ts
Normal file
21
packages/schema-utils/tests/utils.test.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { setDeepValue } from '../src/utils';
|
||||
|
||||
describe('setDeepValue', () => {
|
||||
it('sets a deep value in an object', () => {
|
||||
const obj = {};
|
||||
setDeepValue(obj, ['a', 'b', 'c'], 123);
|
||||
expect(obj).toEqual({ a: { b: { c: 123 } } });
|
||||
});
|
||||
|
||||
it('overwrites existing values', () => {
|
||||
const obj = { a: { b: { c: 123 } } };
|
||||
setDeepValue(obj, ['a', 'b', 'c'], 456);
|
||||
expect(obj).toEqual({ a: { b: { c: 456 } } });
|
||||
});
|
||||
|
||||
it('creates intermediate objects if necessary', () => {
|
||||
const obj = {};
|
||||
setDeepValue(obj, ['a', 'b', 'c'], 123);
|
||||
expect(obj).toEqual({ a: { b: { c: 123 } } });
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user