Skip to content

Latest commit

 

History

History
368 lines (306 loc) · 9.56 KB

number.md

File metadata and controls

368 lines (306 loc) · 9.56 KB

number

ambient declarations

export function number(rules?: RulesForNumber): NumberSchema;

type RulesForNumber = {
    strictType?: boolean;
    acceptsSpecialFormats?: boolean;
    acceptsFullWidth?: boolean;

    ifUndefined?: number | null;
    ifEmptyString?: number | null;
    ifNull?: number | null;

    integer?: boolean | NUMBER.INTEGER;
    only?: number[];
    minValue?: number | {value: number, adjusts: boolean};
    maxValue?: number | {value: number, adjusts: boolean};

    transform?: (value: number, fail: () => never) => number;
}
type ErrorHandler = (err: ValueSchemaError) => number | null | never;
interface NumberSchema {
    applyTo(value: unknown, onError?: ErrorHandler): number | null
}

applyTo(value[, onError])

Applies schema to value.

If an error occurs, this method calls onError (if specified) or throw ValueSchemaError (otherwise).

// should be OK
assert.strictEqual(
    vs.number().applyTo(-123),
    -123);

// should be adjusted
assert.strictEqual(
    vs.number().applyTo("-123"),
    -123);
assert.strictEqual(
    vs.number().applyTo(true),
    1);
assert.strictEqual(
    vs.number().applyTo(false),
    0);

// should cause error
assert.strictEqual( // catch error by callback function (that returns a value from applyTo() method)
    vs.number().applyTo(
        "abc",
        (err) => 10),
    10);
assert.throws( // ... or try-catch syntax
    () => vs.number().applyTo("abc"),
    {name: "ValueSchemaError", rule: vs.RULE.TYPE});
assert.throws(
    () => vs.number().applyTo("true"),
    {name: "ValueSchemaError", rule: vs.RULE.TYPE});

rules

strictType

Enable strict type check. defaults: false

HANDLE WITH CARE! In URL encoding, all values will be treated as string. Use this method when your system accepts ONLY JSON encoding (application/json)

// should be adjusted
assert.strictEqual(
    vs.number().applyTo("123"),
    123);
assert.strictEqual(
    vs.number().applyTo(true),
    1);

// should cause error
assert.throws(
    () => vs.number({strictType: true}).applyTo("123"),
    {name: "ValueSchemaError", rule: vs.RULE.TYPE});
assert.throws(
    () => vs.number({strictType: true}).applyTo(true),
    {name: "ValueSchemaError", rule: vs.RULE.TYPE});

ifUndefined

Specifies return value when input value is undefined.

NOTE: {ifUndefined: undefined} is NOT equivalent to {}. The former accepts undefined input value (and keeps it as-is), the latter doesn't.

// should be adjusted
assert.strictEqual(
    vs.number({ifUndefined: 1}).applyTo(undefined),
    1);

// should cause error
assert.throws(
    () => vs.number().applyTo(undefined),
    {name: "ValueSchemaError", rule: vs.RULE.UNDEFINED});

// should accept `undefined` value
assert.strictEqual(
    vs.number({ifUndefined: undefined}).applyTo(undefined),
    undefined);

ifNull

Specifies return value when input value is null.

// should be adjusted
assert.strictEqual(
    vs.number({ifNull: 1}).applyTo(null),
    1);

// should cause error
assert.throws(
    () => vs.number().applyTo(null),
    {name: "ValueSchemaError", rule: vs.RULE.NULL});

ifEmptyString

Specifies return value when input value is "".

// should be adjusted
assert.strictEqual(
    vs.number({ifEmptyString: 1}).applyTo(""),
    1);

// should cause error
assert.throws(
    () => vs.number().applyTo(""),
    {name: "ValueSchemaError", rule: vs.RULE.EMPTY_STRING});

acceptsSpecialFormats

Accepts all special number formats; e.g., "1e+2", "0x100", "0o100", "0b100". defaults: false

// should be adjusted
assert.strictEqual(
    vs.number({acceptsSpecialFormats: true}).applyTo("1e+2"),
    100);
assert.strictEqual(
    vs.number({acceptsSpecialFormats: true}).applyTo("0x100"),
    256);
assert.strictEqual(
    vs.number({acceptsSpecialFormats: true}).applyTo("0o100"),
    64);
assert.strictEqual(
    vs.number({acceptsSpecialFormats: true}).applyTo("0b100"),
    4);

// should cause error
assert.throws(
    () => vs.number().applyTo("1e+2"),
    {name: "ValueSchemaError", rule: vs.RULE.TYPE});

acceptsFullWidth

Accepts full-width string; e.g., "1234.5", "1234.5". defaults: false

// should be adjusted
assert.strictEqual(
    vs.number({acceptsFullWidth: true}).applyTo("1234.5"),
    1234.5);

// should cause error
assert.throws(
    () => vs.number().applyTo("1234.5"),
    {name: "ValueSchemaError", rule: vs.RULE.TYPE});

integer

Limits an input value to integer.

value description
NUMBER.INTEGER.NO (0) / false does not limit to integer
NUMBER.INTEGER.YES (1) / true limits to integer, but does not round
NUMBER.INTEGER.FLOOR (2) rounds towards −∞
NUMBER.INTEGER.FLOOR_RZ (3) rounds towards 0
NUMBER.INTEGER.CEIL (4) rounds towards +∞
NUMBER.INTEGER.CEIL_RI (5) rounds towards ∞
NUMBER.INTEGER.HALF_UP (6) rounds half towards +∞
NUMBER.INTEGER.HALF_UP_RZ (7) rounds half towards 0
NUMBER.INTEGER.HALF_DOWN (8) rounds half towards −∞
NUMBER.INTEGER.HALF_DOWN_RZ (9) rounds half towards 0
// should be adjusted
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.FLOOR}).applyTo(3.14),
    3);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.FLOOR}).applyTo("3.14"),
    3);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.FLOOR}).applyTo(-3.14),
    -4);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.FLOOR_RZ}).applyTo(3.14),
    3);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.FLOOR_RZ}).applyTo(-3.14),
    -3);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.CEIL}).applyTo(3.14),
    4);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.CEIL}).applyTo(-3.14),
    -3);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.CEIL_RI}).applyTo(3.14),
    4);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.CEIL_RI}).applyTo(-3.14),
    -4);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.HALF_UP}).applyTo(3.49),
    3);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.HALF_UP}).applyTo(3.5),
    4);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.HALF_UP}).applyTo(-3.5),
    -3);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.HALF_UP}).applyTo(-3.51),
    -4);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.HALF_UP_RZ}).applyTo(3.49),
    3);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.HALF_UP_RZ}).applyTo(3.5),
    4);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.HALF_UP_RZ}).applyTo(-3.49),
    -3);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.HALF_UP_RZ}).applyTo(-3.5),
    -4);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.HALF_DOWN}).applyTo(3.5),
    3);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.HALF_DOWN}).applyTo(3.51),
    4);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.HALF_DOWN}).applyTo(-3.49),
    -3);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.HALF_DOWN}).applyTo(-3.5),
    -4);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.HALF_DOWN_RZ}).applyTo(3.5),
    3);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.HALF_DOWN_RZ}).applyTo(3.51),
    4);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.HALF_DOWN_RZ}).applyTo(-3.5),
    -3);
assert.strictEqual(
    vs.number({integer: vs.NUMBER.INTEGER.HALF_DOWN_RZ}).applyTo(-3.51),
    -4);

// should cause error
assert.throws(
    () => vs.number({integer: true}).applyTo(3.14),
    {name: "ValueSchemaError", rule: vs.RULE.TYPE});
assert.throws(
    () => vs.number({integer: vs.NUMBER.INTEGER.YES}).applyTo(3.14), // equivalent to "true"
    {name: "ValueSchemaError", rule: vs.RULE.TYPE});

only

Accepts only particular values.

// should be OK
assert.strictEqual(
    vs.number({only: [1, 3, 5]}).applyTo(1),
    1);

// should cause error
assert.throws(
    () => vs.number({only: [1, 3, 5]}).applyTo(2),
    {name: "ValueSchemaError", rule: vs.RULE.ONLY});

minValue

Limits minimum value.

// should be adjusted
assert.strictEqual(
    vs.number({minValue: {value: 1, adjusts: true}}).applyTo(0),
    1);

// should cause errors
assert.throws(
    () => vs.number({minValue: {value: 1, adjusts: false}}).applyTo(0),
    {name: "ValueSchemaError", rule: vs.RULE.MIN_VALUE});
assert.throws(
    () => vs.number({minValue: 1}).applyTo(0), // shorthand of {value: 1, adjusts: false}
    {name: "ValueSchemaError", rule: vs.RULE.MIN_VALUE});

maxValue

Limits maximum value.

// should be adjusted
assert.strictEqual(
    vs.number({maxValue: {value: 100, adjusts: true}}).applyTo(101),
    100);

// should cause errors
assert.throws(
    () => vs.number({maxValue: {value: 100, adjusts: false}}).applyTo(101),
    {name: "ValueSchemaError", rule: vs.RULE.MAX_VALUE});
assert.throws(
    () => vs.number({maxValue: 100}).applyTo(101), // shorthand of {value: 100, adjusts: false}
    {name: "ValueSchemaError", rule: vs.RULE.MAX_VALUE});

transform

Transform input value to another.

fail() causes ValueSchemaError.

// should be adjusted
assert.strictEqual(
    vs.number({transform: value => value * 2}).applyTo("1"),
    2);

// should cause errors
assert.throws(
    () => vs.number({transform: (value, fail) => fail()}).applyTo(0),
    {name: "ValueSchemaError", rule: vs.RULE.TRANSFORM});