Extendable library for typecasting.
import * as a from 'alwz';
// or
const a = require('alwz');
- See: presets
convert data with presetted converters
a.byte('3'); // 3
a.short(false); // 0
a.int(true); // 1
a.uint(Infinity); // 4294967295
a.long(NaN); // 0
a.long(['1', '2', '3']); // 1 | ['1','2','3'] => '1' => 1
a.array('abc'); // ['abc']
a.array([123, 'abc', {}, Math.max]); // [123, 'abc', {}, Math.max]
- See: utils
construct complex data
ensure an array output
const array = a.utils.array;
const ArrayOfUByte = array(a.ubyte);
ArrayOfUByte([undefined, true, 2.3, '4', Infinity]); // [0, 1, 2, 4, 255]
simplify multidimensional arrays processing
const array = a.utils.array;
const Bytes3dArray = array(array(array(a.byte)));
Bytes3dArray(1); // [[[1]]];
Bytes3dArray([[[null, NaN, 'a'], [true, '2', 3]], [[Infinity]]]); // [[[0, 0, 0], [1, 2, 3]], [[127]]];
create tuples
const tuple = a.utils.tuple;
const PairOfUint = tuple([a.uint, a.uint]);
PairOfUint(['abc', 3.5, 100]); // [0, 3]
const PairOfNumbers = tuple([Number, Number]);
PairOfNumbers(['abc', 3.5, 100]); // [NaN, 3.5]
- See: Converter
create custom converters
extend an existing converter
// make boolean smarter
const bool = a.default.get('boolean')
.clone()
.string(function(v) { // string input processing
if (v === 'true' || v === 'yes') {
return true;
} else if (v === 'false' || v === 'no') {
return false;
} else {
return this.types.number(Number(v));
}
})
.convert;
bool('yes'); // true
bool('no'); // false
bool('false'); // false
parse colon-separated number/string records
const PathArray = a.default.get('array')
.clone()
.string((i) => [...i.matchAll(/\/(\w+)/g)].map((i) => i[1]))
.convert;
const DSV2Tuple = a.utils.tuple(
[String, String, Number, Number, String, PathArray, PathArray],
a.default.get('array')
.clone()
.string((i) => i.split(':'))
.convert
);
const input = 'user:12345:1000:1000:ordinar user:/home/user:/bin/sh';
DSV2Tuple(input); // ['user', '12345', 1000, 1000, 'ordinar user', ['home', 'user'], ['bin', 'sh']];
dynamically select convert function (based on predefined converters)
a.to('int')('24.5'); // 24
a.to('byte')(Infinity); // 127
a.to('bigint')('42.5'); // 42n
registry of predefined converters
// get list of predefined converters
Array.from(a.default.keys()); // ['boolean', 'byte', 'int', 'long', 'double', 'string', ...];
// retrieving with existence check
const Num = a.default.converter('number'); // Converter<number>
const Str = a.default.converter('string'); // Converter<string>
a.default.converter('123'); // Error
// direct retrieving
const Arr = a.default.get('array'); // Converter<Array>
const Unknown = a.default.get('123'); // undefined
- See: is
data type checks
const { is } = a;
is.void(0); // false
is.void(null); // true
is.value(null); // false
is.value(0); // true
is.ubyte(255); // true
is.int(Infinity); // false
is.object(null); // false
is.Iterable(new Set()); // true
boolean.convert('abc'); // true
boolean.convert(Symbol.for('')); // false
boolean.convert([]); // false
boolean.convert([0]); // false
boolean.convert([false, true]); // false
boolean.convert([123]); // true
number.convert(Infinity); // Infinity
number.convert('42'); // 42
number.convert('abc'); // NaN
number.convert(Symbol.for('42')); // 42
number.convert(new Date('1970-01-01T00:00:00.042Z')); // 42
number.convert(['42']); // 42
number.convert([ [ [ 42 ] ] ]); // 42
number.convert(new Date('1970-01-01T00:00:00.999Z')); // 999
|--------|------------------|------------------|
| type | min | max |
|--------|------------------|------------------|
| byte | -128 | 127 |
| short | -32768 | 32767 |
| int | -2147483648 | 2147483647 |
| long | MIN_SAFE_INTEGER | MAX_SAFE_INTEGER |
|--------|------------------|------------------|
| ubyte | 0 | 255 |
| ushort | 0 | 65535 |
| uint | 0 | 4294967295 |
| ulong | 0 | MAX_SAFE_INTEGER |
|--------|------------------|------------------|
int.convert(undefined); // 0
int.convert(null); // 0
int.convert(NaN); // 0
int.convert('abc'); // 0
int.convert(true); // 1
int.convert(42.5); // 42
int.convert('42.5'); // 42
int.convert(['42.5']); // 42
int.convert(Symbol.for('42.5')); // 42
int.convert(new Date('1970-01-01T00:00:00.042Z')); // 42
int.convert(new Date(NaN)); // 0
cast to byte, short (2 bytes), int (4 bytes) or long (8 bytes)
byte.convert(128); // 127
byte.convert(Infinity); // 127
byte.convert(-Infinity); // -128
short.convert(Infinity); // 32767
short.convert(-Infinity); // -32768
int.convert(Infinity); // 2147483647
int.convert(-Infinity); // -2147483648
long.convert(Infinity); // MAX_SAFE_INTEGER
long.convert(-Infinity); // MIN_SAFE_INTEGER
cast to ubyte, ushort (2 bytes), uint (4 bytes) or ulong (8 bytes)
ubyte.convert(-7); // 0
ubyte.convert('a'); // 0
ubyte.convert(Infinity); // 255
ubyte.convert(-Infinity); // 0
ushort.convert(Infinity); // 65535
ushort.convert(-Infinity); // 0
uint.convert(Infinity); // 4294967295
uint.convert(-Infinity); // 0
ulong.convert(Infinity); // MAX_SAFE_INTEGER
ulong.convert(-Infinity); // 0
double.convert('42.5'); // 42.5
double.convert(Infinity); // Number.MAX_VALUE
double.convert(NaN); // 0
bigint.convert(42.5); // 42n
bigint.convert('42'); // 42n
bigint.convert('42.5'); // 0n
bigint.convert(Symbol.for('42')); // 42n
bigint.convert(new Date('1970-01-01T00:00:00.999Z')); // 999n
string.convert(); // ''
string.convert(null); // ''
string.convert(false); // ''
string.convert(true); // ' '
string.convert(42.5); // '42.5'
string.convert([1, 2, 3]); // '1'
string.convert(Symbol.for('42')); // '42'
string.convert(new Date('1970-01-01T00:00:00.999Z')); // '1970-01-01T00:00:00.999Z'
symbol.convert(false); // Symbol('')
symbol.convert(42.5); // Symbol('42.5')
symbol.convert('42.5'); // Symbol('42.5')
symbol.convert([1.5, 2, 3]); // Symbol('1.5')
symbol.convert(new Date('1970-01-01T00:00:00.999Z')); // Symbol('1970-01-01T00:00:00.999Z')
array.convert(); // []
array.convert(null); // []
array.convert(false); // [false]
array.convert(123); // [123]
array.convert('1,2,3'); // ['1,2,3']
array.convert(new Set([1, 2, 3])); // [1, 2, 3]
array.convert(new Map([[1, 2], [3, 4], [5, 6]])); // [[1, 2], [3, 4], [5, 6]]
fn.convert((a, b) => a + b); // (a, b) => a + b
fn.convert(123); // () => 123
date.convert(111); // Date('1970-01-01T00:00:00.111Z')
date.convert([222, 333]); // Date('1970-01-01T00:00:00.222Z')
date.convert('abc'); // Date(NaN)
object.convert(undefined); // {}
object.convert(null); // {}
object.convert(false); // Boolean { false }
object.convert(1); // Number { 1 }
object.convert('2'); // String { 2 }
object.convert([1, '2', 3n]); // [1, '2', 3n]
map.convert([ [true, 1], 2, '3']); // Map { [true, 1] }
weakmap.convert([ [Boolean, 'bool'], [Number, 'num'], [String, 'str'], [true, 1], 2, '3']); // WeakMap { [Boolean, 'bool'], [Number, 'num'], [String, 'str'] }
set.convert([1, '2', 3]); // Set {1, '2', 3}
weakset.convert([Boolean, Number, String, true, 2, '3']); // WeakSet { Boolean, Number, String }
promise.convert(Promise.resolve(1)); // Promise { 1 }
promise.convert(42); // Promise { 42 }
extra utils functions
const { array, tuple, range, variant, object, dictionary } = a.utils;
constrain data to an array elements of a given type
-
conversion
Conversion<any, OUTPUT> item conversion -
initiator
Conversion<any, Array<any>> input data initial conversion (optional, defaultpresets.array.convert
)
const Numbers = array(Number);
Numbers(); // []
Numbers([]); // []
Numbers([true, 2, "3", {}]); // [1, 2, 3, NaN]
sparse arrays behavior
// Be aware of sparse arrays behavior - conversion is not performed for empty items
numArray[1, , 3] // [1, , 3]
Returns Conversion<any, Array<OUTPUT>>
constrain data to a tuple with given types
-
conversions
Array<Conversion<any, any>> tuple elemets conversions -
initiator
Conversion<any, Array<any>> input data initial conversion (optional, defaultpresets.array.convert
)
const NumStrBool = tuple([Number, String, Boolean]);
NumStrBool(); // [NaN, 'undefined', false]
NumStrBool(null); // [NaN, 'undefined', false]
NumStrBool([]); // [NaN, '', false]
NumStrBool('5'); // [5, 'undefined', false]
NumStrBool(['1', '2', '3']); // [1, '2', true]
Returns Conversion<any, Array<any>>
constrain variable value within a given range
-
lower
OUTPUT lower range border (optional, default-Number.MAX_VALUE
) -
upper
OUTPUT upper range border (optional, defaultNumber.MAX_VALUE
) -
fallback
Fallback<OUTPUT> fallback value generator -
conversion
Conversion<any, OUTPUT> input data conversion (optional, defaultpresets.double.convert
)
const range37 = range(3, 7);
range37(1); // 3
range37(5); // 5
range37(9); // 7
const range37WithCustomFallback = range(3, 7, () => -1);
range37WithCustomFallback(1); // -1
range37WithCustomFallback(5); // 5
range37WithCustomFallback(9); // -1
const rangeString = range('k', 'w', undefined, String);
rangeString('a'); // k
rangeString('n'); // n
rangeString('z'); // w
Returns Conversion<any, OUTPUT>
constrain variable to given variants
-
values
Array<OUTPUT> valid values list -
fallback
Fallback<OUTPUT> fallback value generator (optional, default()=>values[0]
) -
conversion
Conversion<any, OUTPUT> input data conversion (optional, defaultpresets.double.convert
)
const oneOf123 = variant([1, 2, 3]);
oneOf123(1); // 1
oneOf123(2); // 2
oneOf123(3); // 3
oneOf123(4); // 1
oneOf123(-5); // 1
const oneOf123WithCustomFallback = variant([1, 2, 3], () => -1);
oneOf123WithCustomFallback(4); // -1
oneOf123Strict([1, 2, 3], () => {
throw new Error('invalid input');
});
oneOf123Strict(4); // throws an Error
const oneOfAB = variant(['a', 'b'], (i) => ['a', 'b'][i], String);
oneOfAB('a'); // 'a'
oneOfAB('b'); // 'b'
oneOfAB(0); // 'a'
oneOfAB(1); // 'b'
Returns Conversion<any, OUTPUT>
cast data into an object with a given schema
-
schema
Record<string, Conversion<any, OUTPUT>> -
conversion
Conversion<any, OUTPUT> input data conversion (optional, defaultpresets.object.convert
)
const obj = object({
a: a.ubyte,
b: array(object({
c: a.int,
d: a.string,
})),
});
obj(undefined); // { a: 0, b: [] }
obj({ a: 999, b: [{ c: 2.5, d: 3 }, null] }); // { a: 255, b: [{ c: 2, d: '3' }, { c: 0, d: '' }] }
Returns Conversion<any, OUTPUT>
cast data into a dictionary
-
conversion
-
initiator
Conversion<any, any> input data conversion (optional, defaultpresets.object.convert
)
const dictOfInt = utils.dictionary(a.int);
dictOfInt(undefined); // { }
dictInt({ a: null, b: true, c: '2', d: [3, 4] }); // { a: 0, b: 1, c: 2, d: 3 }
Returns Conversion<any, Record<(string | number), VALUE>>
guard functions (pattern matching check)
undefined or null
is.void(null) // true
is.void(0) // false
any value except undefined or null
is.value(null) // false
is.value(0) // true
is.boolean(1) // false
is.boolean(true) // true
is.number(NaN) // true
is.number(Infinity) // true
is.number(1) // true
is.number('1') // false
byte, short, int, long
is.int(NaN) // false
is.long(Infinity) // false
is.uint(-1) // false
is.uint(1) // true
is.uint(1.5) // false
double
is.double(NaN) // false
is.double(Infinity) // false
is.double(1.5) // true
any object (null excluded)
is.object(null) // false
is.object({}) // true
can be iterated
is.Iterable(new Map()); // true
is.Iterable([]); // true
is.Iterable({}); // false
converts input data to specific type
- at first checks if conversion is necessary
- then attempts conversion based on the input data type
- searches among registered conversions if no matching type is found
- generates a fallback value if no suitable conversion can be found
-
is
IS<OUTPUT> initial input data type checker(predicate). determines if any conversion is necessary -
fallback
Fallback<OUTPUT> fallback value generator. runs if none of the available conversions are suitable
converter creation
const positive = new Converter(
(input) => typeof input === 'number' && input > 0,
(input) => input === 0 ? 0.1 : 0.2
);
positive
.undefined(() => 0.3)
.boolean((i) => i ? 1 : 0.4)
.number(function(i) {
const result = Math.abs(i)
return this.is(result) ? result : this.fallback(i);
})
.string((i) => positive.convert(Number(i)))
.symbol((i) => positive.convert(Symbol.keyFor(i)))
.bigint((i) => positive.convert(Number(i)))
.register(Array.isArray, (i) => positive.convert(i[0]))
.register((i) => i === null, (i) => 0.5);
positive.convert(1); // 1
positive.convert(0); // 0.1 (fallback)
positive.convert(NaN); // 0.2 (fallback)
positive.convert(undefined); // 0.3 (has own handler)
positive.convert(false); // 0.4 (has own handler)
positive.convert(null); // 0.5 (has own handler)
positive.convert(2n); // 2
positive.convert(-3); // 3
positive.convert('4'); // 4
positive.convert([5, 6]); // 5
conversion with prohibited input types
const converter = new Converter(
(input) => typeof input === 'number',
(input) => {
throw new Error('unknown input data type:' + input);
})
.string((i) => {
throw new Error('string input is forbidden:' + i);
})
.boolean(Number)
.register(Array.isArray, (i) => converter.convert(i[0]));
converter.convert(true); // 1
converter.convert(2); // 2
converter.convert('3'); // Error
converter.convert([4]); // 4
converter.convert(Promise.resolve(5)); // Error
converts data according to saved conversion rules
-
input
any input data
adds conversion function for INPUT
type
-
is
IS<INPUT> input data type checker(predicate), determines if input can be processed byconversion
-
conversion
Conversion<INPUT, OUTPUT>INPUT
toOUTPUT
conversion function
removes conversion for INPUT
type
-
is
IS<INPUT> input type checker(predicate)
set conversion rule for type
if conversion
is defined or unset if undefined
-
name
string one of types (typeof
result) -
conversion
Conversion?
conversion rule setter for undefined
input
-
conversion
Conversion?
conversion rule setter for boolean
input
-
conversion
Conversion?
conversion rule setter for number
input
-
conversion
Conversion?
conversion rule setter for bigint
input
-
conversion
Conversion?
conversion rule setter for string
input
-
conversion
Conversion?
conversion rule setter for symbol
input
-
conversion
Conversion?
const converter = new Converter(
(i) => typeof i === 'number',
() => 0
)
.undefined(() => 1);
const clone = converter
.clone()
.undefined(() => 2);
converter.convert(); // 1
clone.convert(); // 2