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
create specific converters
const even = new a.Converter(
(input) => typeof input === 'number' && input % 2 === 0, // initial input check
(input) => Number(input) % 2 === 0 ? Number(input) : 0 // fallback value generator
);
even
.undefined(() => -2)
.boolean((input) => input ? -4 : -6)
.number(function(input) {
const result = Math.trunc(Math.abs(input || 0) / 2) * 2;
return this.is(result) ? result : this.fallback(input);
})
.string((input) => even.convert(Number(input)))
.register(Array.isArray, (input) => even.convert(input[0])); // take first and try again
even.convert(8); // 8
even.convert(undefined); // -2
even.convert(true); // -4
even.convert(false); // -6
even.convert(NaN); // 0
even.convert(11); // 10
even.convert('15'); // 14
even.convert([17, 18, 19]); // 16
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
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 }
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<T> initial input data type checker(predicate). determines if any conversion is necessary -
fallback
Fallback<T> 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, T>INPUT
toT
conversion function
removes conversion for INPUT
type
-
is
IS<INPUT> input type checker(predicate)
conversion rule setter for undefined
input
conversion
conversion rule setter for boolean
input
conversion
conversion rule setter for number
input
conversion
conversion rule setter for bigint
input
conversion
conversion rule setter for string
input
conversion
conversion rule setter for symbol
input
conversion
const converter = new Converter(
(i) => typeof i === 'number',
() => 0
)
.undefined(() => 1);
const clone = converter
.clone()
.undefined(() => 2);
converter.convert(); // 1
clone.convert(); // 2
extra utils functions
const { array, tuple } = a.utils;
constrain data to an array elements of a given type
-
conversion
Conversion<any, T> item conversion -
initiator
Conversion<any, Array<any>> input data initial conversion (optional, defaultpresets.array.convert
)
const numArray = array(Number);
numArray(); // []
numArray([]); // []
numArray([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<T>>
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 tupleNumStrBool = tuple([Number, String, Boolean]);
tupleNumStrBool(); // [NaN, 'undefined', false]
tupleNumStrBool(null); // [NaN, 'undefined', false]
tupleNumStrBool([]); // [NaN, '', false]
tupleNumStrBool('5'); // [5, 'undefined', false]
tupleNumStrBool(['1', '2', '3']); // [1, '2', true]
Returns Conversion<any, Array<any>>
constrain variable value within a given range
-
lower
T lower range border (optional, default-Number.MAX_VALUE
) -
upper
T upper range border (optional, defaultNumber.MAX_VALUE
) -
fallback
Fallback<T> fallback value generator -
conversion
Conversion<any, T> 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, T>
constrain variable to given variants
-
values
Array<T> valid values list -
fallback
Fallback<T> fallback value generator (optional, default()=>values[0]
) -
conversion
Conversion<any, T> input data conversion (optional, defaultpresets.double.convert
)
const var123 = variant([1, 2, 3]);
var123(1); // 1
var123(2); // 2
var123(3); // 3
var123(4); // 1
var123(-5); // 1
const var123WithCustomFallback = variant([1, 2, 3], () => -1);
var123WithCustomFallback(4); // -1
var123WithStrictFallback([1, 2, 3], () => {
throw new Error('invalid input');
});
var123WithStrictFallback(4); // throws an Error
const varABC = variant(['a', 'b'], (i) => ['a', 'b'][i], String);
varABC('a'); // 'a'
varABC('b'); // 'b'
varABC(0); // 'a'
varABC(1); // 'b'
Returns Conversion<any, T>
cast data into an object with a given schema
-
schema
Record<string, Conversion<any, T>> -
conversion
Conversion<any, T> input data conversion (optional, defaultpresets.object.convert
)
const objABC = utils.object({
a: a.ubyte,
b: utils.array(utils.object({
c: a.int,
d: utils.array(a.string),
})),
});
objABC(undefined); // { a: 0, b: [] }
objABC({ a: 999, b: [{ c: 2.5, d: 3 }, null] }); // { a: 255, b: [{ c: 2, d: ['3'] }, { c: 0, d: [] }] }
Returns Conversion<any, T>