data-context
Version:
Watch data changes in the browser and node.js
869 lines (762 loc) • 32.2 kB
JavaScript
/** Copyright (c) 2024, Manuel Lõhmus (MIT). */
importModules(["data-context"], function (DC) {
var { parse, stringify } = DC;
/***** Init TESTS *********************************************************/
testRunner('Init TESTS ', { skip: false }, (test) => {
// UNDEFINED
test('DC(undefined) ', { skip: false }, (check) => {
return check(DC(undefined)).mustBe(undefined);
});
// NULL
test('DC(null) ', { skip: false }, (check) => {
return check(DC(null)).mustBe(null);
});
// BOOLEAN
test('DC(false) ', { skip: false }, (check) => {
return check(DC(false).valueOf()).mustBe(false);
});
test('DC(true) ', { skip: false }, (check) => {
return check(DC(true).valueOf()).mustBe(true);
});
// NUMBER
test('DC(123) ', { skip: false }, (check) => {
return check(DC(123).valueOf()).mustBe(123);
});
test('DC(-456) ', { skip: false }, (check) => {
return check(DC(-456).valueOf()).mustBe(-456);
});
test('DC(-456) + 123 ', { skip: false }, (check) => {
return check(DC(-456) + 123).mustBe(-333);
});
// STRING
test('DC("") ', { skip: false }, (check) => {
return check(DC("").valueOf()).mustBe("");
});
test('DC("test") ', { skip: false }, (check) => {
return check(DC("test").valueOf()).mustBe("test");
});
test('DC("test") + 123 ', { skip: false }, (check) => {
return check(DC("test") + 123).mustBe("test123");
});
// ARRAY
test('DC([]) ', { skip: false }, (check) => {
return check(DC([]).toString()).mustBe("[" + [].toString() + "]");
});
test('DC(["test"]) ', { skip: false }, (check) => {
return check(DC(["test"]).toString()).mustBe("[\"test\"]");
});
test('DC(["test"]).push(123) ', { skip: false }, (check) => {
var dc = DC(["test"]);
dc.push(123);
return check(dc.toString()).mustBe("[\"test\",123]");
});
// OBJECT;
test('DC({}) ', { skip: false }, (check) => {
return check(Object.keys(DC({})).toString()).mustBe("");
});
test('DC({ key: "val" }) ', { skip: false }, (check) => {
var dc = DC({ key: "val" });
check(Object.keys(dc).toString()).mustBe("key");
return DC.convertPrimitiveTypes
? check(Object.entries(dc).toString()).mustBe("key,\"val\"")
: check(Object.entries(dc).toString()).mustBe("key,val");
});
test('DC({}).key = 123 ', { skip: false }, (check) => {
var dc = DC({});
dc.key = 123;
check(Object.keys(dc).toString()).mustBe("key");
return check(Object.entries(dc).toString()).mustBe("key,123");
});
});
/***** Event Emitter TESTS ************************************************/
testRunner('Event Emitter TESTS ', { skip: false }, (test) => {
test('VALUE set_event ', { skip: false }, (check) => {
var parent = DC({});
var arr = DC([0]);
parent.dc = arr;
parent.on("-set", function (event) {
check(event.newValue).mustBe(123);
check(event.propertyPath.pop()).mustBe("dc");
//check(typeof event.timestamp).mustBe("number");
return true;
}, true);
arr.on("-set", function (event) {
check(event.oldValue + '').mustBe('0');
check(event.newValue).mustBe(123);
check(event.propertyPath.pop() + '').mustBe("0");
//check(typeof event.timestamp).mustBe("number");
return true;
}, true);
arr[0] = 123;
return check(arr[0] + '').mustBe('123');
});
test('OBJECT delete_event ', { skip: false }, (check) => {
var parent = DC({ dc: { number: 123 } });
parent.on("-delete", function (event) {
check(event.oldValue).mustBe(789);
check(event.propertyPath.pop()).mustBe("dc");
//check(typeof event.timestamp).mustBe("number");
event.oldValue = 456;
});
parent.dc.on("-delete", function (event) {
check(event.oldValue).mustBe(123);
check(event.propertyPath.pop()).mustBe("number");
//check(typeof event.timestamp).mustBe("number");
event.oldValue = 789;
});
delete parent.dc.number;
return check(parent.dc.number).mustBe(undefined);
});
test('ARRAY pop ', { skip: false }, (check) => {
var dc = DC([1, 2, 3]);
dc.on("-delete", function (event) {
check(typeof event.oldValue).mustBe("number");
check(typeof parseInt(event.propertyPath.pop())).mustBe("number");
//check(typeof event.timestamp).mustBe("number");
}, true);
check(dc.pop() + "").mustBe("3");
check(dc.pop() + "").mustBe("2");
check(dc.pop() + "").mustBe("1");
return true;
});
test('ARRAY push ', { skip: false }, (check) => {
var dc = DC([]);
dc.on("-set", function (event) {
check(typeof event.newValue.valueOf()).mustBe("number");
check(typeof parseInt(event.propertyPath.pop())).mustBe("number");
//check(typeof event.timestamp).mustBe("number");
}, true);
dc.on("-new", function (event) {
check(typeof event.newValue.valueOf()).mustBe("number");
}, true);
check(dc.push(1) + "").mustBe("1");
check(dc.push(2) + "").mustBe("2");
check(dc.push(3) + "").mustBe("3");
return true;
});
});
/***** Parse TESTS ********************************************************/
testRunner('Parse TESTS ', { skip: false }, (test) => {
test('parse(undefined) ', { skip: false }, (check) => {
return check(parse(undefined)).mustBe(undefined);
});
test('parse(null) ', { skip: false }, (check) => {
return check(parse(null)).mustBe(null);
});
test('parse(0) ', { skip: false }, (check) => {
return check(parse(0)).mustBe(0);
});
test('parse(-0) ', { skip: false }, (check) => {
return check(parse(-0)).mustBe(0);
});
test('parse(0x01) ', { skip: false }, (check) => {
return check(parse(0x01)).mustBe(1);
});
test('parse("") ', { skip: false }, (check) => {
return check(parse("")).mustBe(undefined);
});
test('parse(\'""\')?.valueOf() ', { skip: false }, (check) => {
return check(parse('""')?.valueOf()).mustBe('');
});
test('parse(\'"abc"\')?.valueOf() ', { skip: false }, (check) => {
return check(parse('"abc"')?.valueOf()).mustBe('abc');
});
test('parse(\'"\\uD800"\')?.valueOf() ', { skip: false }, (check) => {
return check(parse('"\uD800"')?.valueOf()).mustBe('\uD800');
});
test('parse(\'null\') ', { skip: false }, (check) => {
return check(parse('null')).mustBe(null);
});
test('parse(\'false\')?.valueOf() ', { skip: false }, (check) => {
return check(parse('false')?.valueOf()).mustBe(false);
});
test('parse(\'true\')?.valueOf() ', { skip: false }, (check) => {
return check(parse('true')?.valueOf()).mustBe(true);
});
test('parse(\'0\')?.valueOf() ', { skip: false }, (check) => {
return check(parse('0')?.valueOf()).mustBe(0);
});
test('parse(\'123\')?.valueOf() ', { skip: false }, (check) => {
return check(parse('123')?.valueOf()).mustBe(123);
});
test('parse(\'-123\')?.valueOf() ', { skip: false }, (check) => {
return check(parse('-123')?.valueOf()).mustBe(-123);
});
test('parse(\'[]\') ', { skip: false }, (check) => {
return check(Array.isArray(parse('[]'))).mustBe(true);
});
test('parse(\'[\n]\') ', { skip: false }, (check) => {
return check(Array.isArray(parse('[\n]'))).mustBe(true);
});
test('parse(\'["abc"]\') ', { skip: false }, (check) => {
return check(Array.isArray(parse('[ "abc" ]'))).mustBe(true);
});
test('parse(\'{}\') ', { skip: false }, (check) => {
var data = parse('{}')?.valueOf();
check(data).mustNotBe(null);
check(typeof data).mustBe("object");
check(Object.keys(data).length).mustBe(0);
return true;
});
test('parse(\'{\n}\') ', { skip: false }, (check) => {
var data = parse('{\n}')?.valueOf();
check(data).mustNotBe(null);
check(typeof data).mustBe("object");
check(Object.keys(data).length).mustBe(0);
return true;
});
test('parse(\'[1]\') ', { skip: false }, (check) => {
var data = parse('[1]');
check(Array.isArray(data)).mustBe(true);
check(data[0]?.valueOf()).mustBe(1);
return true;
});
test('parse(\'{"arr":[1]}\') ', { skip: false }, (check) => {
var data = parse('{"arr":[1]}');
check(Array.isArray(data.arr)).mustBe(true);
check(data.arr[0]?.valueOf()).mustBe(1);
return true;
});
test('parse(\'[{"nr":1}]\') ', { skip: false }, (check) => {
var data = parse('[{"nr":1}]');
check(Array.isArray(data)).mustBe(true);
check(data[0].nr?.valueOf()).mustBe(1);
return true;
});
});
/***** Stringify TESTS ****************************************************/
testRunner('Stringify TESTS ', { skip: false }, (test) => {
test('stringify(undefined) ', { skip: false }, (check) => {
return check(stringify(undefined)).mustBe(undefined);
});
test('stringify(null) ', { skip: false }, (check) => {
return check(stringify(null)).mustBe('null');
});
test('stringify(true) ', { skip: false }, (check) => {
return check(stringify(true)).mustBe('true');
});
test('stringify(false) ', { skip: false }, (check) => {
return check(stringify(false)).mustBe('false');
});
test('stringify(0) ', { skip: false }, (check) => {
return check(stringify(0)).mustBe('0');
});
test('stringify(-0) ', { skip: false }, (check) => {
return check(stringify(-0)).mustBe('0');
});
test('stringify(0.123) ', { skip: false }, (check) => {
return check(stringify(0.123)).mustBe('0.123');
});
test('stringify(-0.123) ', { skip: false }, (check) => {
return check(stringify(-0.123)).mustBe('-0.123');
});
test('stringify(0.0000123) ', { skip: false }, (check) => {
return check(stringify(0.0000123)).mustBe('0.0000123');
});
test('stringify("") ', { skip: false }, (check) => {
return check(stringify("")).mustBe('""');
});
test('stringify("abc") ', { skip: false }, (check) => {
return check(stringify("abc")).mustBe('"abc"');
});
test('stringify("\\uD800") ', { skip: false }, (check) => {
return check(stringify("\uD800")).mustBe('"\uD800"');
});
test('stringify([]) ', { skip: false }, (check) => {
return check(stringify([])).mustBe('[]');
});
test('stringify({}) ', { skip: false }, (check) => {
return check(stringify({})).mustBe('{}');
});
test('stringify([1]) ', { skip: false }, (check) => {
return check(stringify([1])).mustBe('[1]');
});
test('stringify({arr:[1]}) ', { skip: false }, (check) => {
return check(stringify({ arr: [1] })).mustBe('{"arr":[1]}');
});
test('stringify([{nr:1}]) ', { skip: false }, (check) => {
return check(stringify([{ nr: 1 }])).mustBe('[{"nr":1}]');
});
test('stringify(DC(undefined)) ', { skip: false }, (check) => {
return check(stringify(DC(undefined))).mustBe(undefined);
});
test('stringify(DC(null)) ', { skip: false }, (check) => {
return check(stringify(DC(null))).mustBe('null');
});
test('stringify(DC(true)) ', { skip: false }, (check) => {
return check(stringify(DC(true))).mustBe('true');
});
test('stringify(DC(false)) ', { skip: false }, (check) => {
return check(stringify(DC(false))).mustBe('false');
});
test('stringify(DC(0)) ', { skip: false }, (check) => {
return check(stringify(DC(0))).mustBe('0');
});
test('stringify(DC(-0)) ', { skip: false }, (check) => {
return check(stringify(DC(-0))).mustBe('0');
});
test('stringify(DC(0.123)) ', { skip: false }, (check) => {
return check(stringify(DC(0.123))).mustBe('0.123');
});
test('stringify(DC(-0.123)) ', { skip: false }, (check) => {
return check(stringify(DC(-0.123))).mustBe('-0.123');
});
test('stringify(DC(0.0000123)) ', { skip: false }, (check) => {
return check(stringify(DC(0.0000123))).mustBe('0.0000123');
});
test('stringify(DC("")) ', { skip: false }, (check) => {
return check(stringify(DC(""))).mustBe('""');
});
test('stringify(DC("abc")) ', { skip: false }, (check) => {
return check(stringify(DC("abc"))).mustBe('"abc"');
});
test('stringify(DC([])) ', { skip: false }, (check) => {
return check(stringify(DC([]))).mustBe('[]');
});
test('stringify(DC({})) ', { skip: false }, (check) => {
return check(stringify(DC({}))).mustBe('{}');
});
test('stringify(DC([{ nr: 1 }])) ', { skip: false }, (check) => {
return check(stringify(DC([{ nr: 1 }]))).mustBe('[{"nr":1}]');
});
test('stringify(DC({n:1}),replacer) ', { skip: false }, (check) => {
var keys = [], data = stringify(DC({ n: 1 }), function (k, v) {
check(typeof this).mustBe("object");
check(typeof k).mustBe("string");
check(v).mustNotBe(undefined);
keys.push(k); this;
return v;
});
check(keys.toString())
.mustBe(",n")
.done();
});
test('stringify({s:"a",n:1},["n"]) ', { skip: false }, (check) => {
check(stringify(DC({ n: 1 }), ["n"])).mustBe('{"n":1}').done();
});
test('stringify({n:1,o:{toJSON:...}})', { skip: false }, (check) => {
var obj = {
n: 1,
o: {
toJSON: function (k) {
return {};
}
}
};
check(stringify(DC(obj))).mustBe('{"n":1,"o":{}}').done();
});
});
/***** Complex TESTS ******************************************************/
testRunner('Complex TESTS ', { skip: false }, (test) => {
test('parse - stringify //metadata ', { skip: false }, (check) => {
var json = `{
"test": {
"arr": [
123,
"abc"
]
},
"str": "abc"
}`;
var jsme = `/*obj*/
{
/*obj*/
/*{"timestamp":126546199,"delete":true}*/
"test": {
/*array*/
"arr": [
/*number*/
123,
/*string*/
"abc"
]
},
/*abc*/
"str": "abc"
}`;
var obj = parse(jsme, DC);
var jsme2 = stringify(obj, null, 4);
check(jsme2).mustBe(jsme);
var json2 = JSON.stringify(obj, null, 4);
check(json2).mustBe(json)
return true;
});
test('overwriting data ', { skip: false }, (check) => {
var json = `{
"test":{
"arr":[
123,
456,
"abc"
]
},
"str":"abc"
}`;
var dc = DC({ test: { arr: [] }, str: "abc" });
var obj = parse(json, dc);
obj.test.arr.pop();
var result = stringify(obj, null, 4, { modifiedData: true, setUnmodified: true });
check(result).mustBe(`{
"test": {
"arr": [\r\r 0: 123,
1: 456
]
}
}`);
check(stringify(obj, null, 0, { modifiedData: true, setUnmodified: true })).mustBe('{}');
return true;
});
test('overwriting data minify ', { skip: false }, (check) => {
var json = '{"test":{"arr":[123,"abc"]},"str":"abc"}';
var dc = DC({ test: { arr: [] }, str: "abc" });
var obj = parse(json, dc);
var result = stringify(obj, null, "", { modifiedData: true, setUnmodified: true });
check(result).mustBe('{"test":{"arr":[0:123,1:"abc"]}}');
check(stringify(obj, null, "", { modifiedData: true, setUnmodified: true })).mustBe('{}');
return true;
});
test('overwriting array delete dc ', { skip: false }, (check) => {
var json = `{
"arr": [
{ "nr": 1 },
{ "nr": 2 },
{ "nr": 3 },
{ "nr": 4 },
{ "nr": 5 },
{ "nr": 6 },
{ "nr": 7 }
]
}`;
var obj = parse(json, DC);
var arr = obj.arr.splice(0, 4);
var result = stringify(obj, null, 4, { modifiedData: true, setUnmodified: true });
check(result).mustBe(`{
"arr": [\r\r 0: {
"nr": 5
},
1: {
"nr": 6
},
2: {
"nr": 7
}
]
}`);
obj.arr.push(8);
parse(result, obj);
result = stringify(obj, null, 4, { modifiedData: true, setUnmodified: true });
check(result).mustBe(`{
"arr": [\r\r 0: {
"nr": 5
},
1: {
"nr": 6
},
2: {
"nr": 7
}
]
}`);
return true;
});
test('overwriting object delete key ', { skip: false }, (check) => {
var json = `
{
"dc": {
"key0": 0,
"key1": 1,
"key2": 2
}
}
`;
var obj = parse(json, DC);
delete obj.dc.key0;
var result = stringify(obj, null, 4, { modifiedData: true, setUnmodified: true });
check(result).mustBe(`{
"dc": {
"key0":
}
}`);
return true;
});
test('overwriting array ', { skip: false }, (check) => {
var json = `
[
{
"key0": 0
}
]`;
var obj = parse(json, DC);
obj[0].key0 = 1;
var result = obj.stringifyChanges(null, 4);
check(result).mustBe(`[
0: {
"key0": 1
}
]`);
return true;
});
});
});
/**
* Test runner. Function to run unit tests in the console.
* @author Manuel Lõhmus 2024 (MIT License)
* @version 1.1.2
* [2024-12-29] adde d functionality to select tests by ID in the command line arguments (e.g. --testIDs=1 2 3)
* @example `npm test '--'` or `node index.test.js`
* @example `npm test '--' --help` or `node index.test.js --help`
* @example `npm test '--' --testIDs=1 2 3` or `node index.test.js --testIDs=1 2 3`
* @param {string} runnerName Test runner name.
* @param {{skip:boolean}} options Test runner options.
* @param {(test:Test)=>void} cb Callback function to run the unit tests.
* @returns {boolean} If the tests are OK
* @example testRunner('Module name', { skip: false }, function (test) {...});
*
* @callback Test Unit test callback function
* @param {string} testName Test name.
* @param {{skip:boolean,timeout:number}} options Test options. (default: {skip:false,timeout:3000})))
* @param {(check:Check,done:Done)=>void} fn Test function. Function parameters: check, done. `check` is used to check the test result. `done` is used to end the test.
* @returns {void}
* @example test("Test name", {skip:false,timeout:3000}, function(check,done){...});
* @example test("Test name", function(check,done){...});
* @example test("Test name", {skip:checkableObject === undefined}, function(check,done){...});
*
* @callback Check Check function to check the test result.
* @param {string} label Value name.
* @param {any} value Value to check.
* @returns {Validator}
* @example check('name', value).mustBe(true);
* @example check('name', value).mustNotBe(false);
* @example check('name', value).mustBe(true).done();
* @example check('name', value).mustBe(true).mustNotBe(false).done();
*
* @callback Done Callback function to end the test.
* @param {Error} err Error message. If the error message is empty, the test is considered successful.
* @returns {void}
*
* @typedef Validator
* @property {(value:any)=>Validator} mustBe Check if the value is equal to the specified value.
* @property {(value:any)=>Validator} mustNotBe Check if the value is not equal to the specified value.
* @property {(value:any)=>Validator} mustInclude Check if the value is included to the specified value.
* @property {Done} done Callback function to end the test.
*/
function testRunner(runnerName, options, cb) {
this?.process?.on('uncaughtException', function noop() { });
testRunner.testRunnerOK = true;
clearTimeout(testRunner.exitTimeoutID);
var stdout = {},
timeouts = {},
countStarted = 0,
countCompleted = 0,
testsStarted = false,
testRunnerOK = true,
strSKIP = "\t\t[\x1b[100m\x1b[97m SKIP \x1b[0m]",
strTestsERR = "[\x1b[41m\x1b[97m The tests failed! \x1b[0m]",
strTestsDONE = "[\x1b[42m\x1b[97m The tests are done! \x1b[0m]",
{ help, testids } = _arg_options();
if (help || help === '') {
console.log(`
npm test '--' [OPTION1=VALUE1] [OPTION2=VALUE2] ...
or
node index.test.js [OPTION1=VALUE1] [OPTION2=VALUE2] ...
The following options are supported:
--help Display this help
--testIDs Number of the test to run (e.g. node index.test.js --testIDs=1 2 3)
`);
if (this?.process?.argv[1].endsWith(".js")) { exitPressKey(); }
return;
}
if (testids) { testids = testids.split(' ').filter((id) => id); }
//skip all tests
if (options?.skip) {
testsStarted = "SKIP";
if (runnerName) { log(0, "SKIP > ", runnerName, strSKIP); }
testCompleted();
return testRunnerOK;
}
if (runnerName) { log(0, "START > ", runnerName); }
cb(test);
testsStarted = true;
testCompleted();
return testRunnerOK;
function log() {
var line = "";
for (let i = 1; i < arguments.length; i++) {
line += arguments[i];
}
if (stdout[arguments[0]]) {
stdout[arguments[0]] += line + "\n";
}
else {
stdout[arguments[0]] = line + "\n";
}
}
function print_stdout() {
console.log();
console.log(
Object.keys(stdout).reduce((output, value, i) => output += stdout[i], '')
);
}
/**
* Unit test function.
* @type {Test}
*/
function test(testName, options, fn) {
var startTime, endTime,
id = ++countStarted,
testOK = true,
label = " " + id + ".\tTEST > " + testName + "\t",
strOK = "\t[\x1b[42m\x1b[97m OK \x1b[0m]",
strERR = "\t[\x1b[41m\x1b[97m FAILED \x1b[0m] -> ";
//skip
if (options?.skip || testids && !testids.includes(id + '')) {
log(id, label, "\t", strSKIP);
testCompleted();
return;
}
//timeout
timeouts[id] = setTimeout(function () {
done("timeout");
}, options?.timeout || 3000);
startTime = performance.now();
try {
if (fn(check, done)) { done(); }
}
catch (err) { done(err); }
/**
* Callback function to end the test.
* @type {Done}
*/
function done(err = '') {
endTime = performance.now();
if (err) { testRunnerOK = testOK = false; }
if (err || testOK)
log(id, label, ": ", (endTime - startTime).toFixed(2), "ms\t", err ? strERR : strOK, err || "");
if (timeouts[id]) { testCompleted(); }
clearTimeout(timeouts[id]);
delete timeouts[id];
}
/**
* Check function to check the test result.
* @type {Check}
*/
function check(label, value) {
if (arguments.length === 1) { value = label; label = 'returned'; }
if (label === undefined) { label = 'returned'; }
/**
* Selection fuctions to check.
* @type {Validator}
*/
return {
mustBe: function mustBe(mustBe) {
if (value !== mustBe) { done("\x1b[44m\x1b[97m " + label + " \x1b[0m '" + value + "' \x1b[44m\x1b[97m must be \x1b[0m '" + mustBe + "'"); }
return this;
},
mustNotBe: function mustNotBe(mustNotBe) {
if (value === mustNotBe) { done("\x1b[44m\x1b[97m " + label + " \x1b[0m '" + value + "' \x1b[44m\x1b[97m must not be \x1b[0m '" + mustNotBe + "'"); }
return this;
},
mustInclude: function mustInclude(mustInclude) {
if (!value?.includes || !value.includes(mustInclude)) { done("\x1b[44m\x1b[97m " + label + " \x1b[0m '" + value + "' \x1b[44m\x1b[97m must include \x1b[0m '" + mustInclude + "'"); }
return this;
},
done
};
}
}
function testCompleted() {
countCompleted++;
if (!testsStarted || countStarted >= countCompleted) { return; }
if (runnerName) {
if (testsStarted === "SKIP") {
print_stdout();
}
else if (!testRunnerOK) {
log(++countStarted, "END > " + runnerName + "\t" + strTestsERR);
print_stdout();
}
else {
log(++countStarted, "END > ", runnerName, "\t", strTestsDONE);
print_stdout();
}
this?.process?.removeAllListeners('uncaughtException');
if (this?.process?.argv[1].endsWith(".js")) {
exitPressKey();
}
else if (this?.process) {
if (!testRunnerOK) { testRunner.testRunnerOK = false; }
testRunner.exitTimeoutID = setTimeout(function () {
process.exit(testRunner.testRunnerOK ? 0 : 1);
}, 100);
}
}
}
function exitPressKey() {
process.stdin.setRawMode(true);
process.stdin.resume();
process.stdin.on('data', process.exit.bind(process, testRunnerOK ? 0 : 1));
console.log('Press any key to exit');
}
function _arg_options() {
if (!this?.process) { return {}; }
var key;
return process.argv.slice(2).reduce(function (opt, keyVal) {
var [_key, _val] = keyVal.split('=');
_key = (_key + '').trim();
if (_key[0] === '-') {
if (_val === undefined) {
key = _trimKey(_key);
opt[key] = true;
return opt;
}
if (_val[0] !== '-') {
_val = (_val + '').trim();
key = _trimKey(_key);
opt[key] = _val;
}
}
else if (_key) {
opt[key] = typeof opt[key] === 'string' ? opt[key] + ' ' + _key : _key;
}
return opt;
function _trimKey(key) {
if (key[0] === '-') { key = key.slice(1); }
if (key[0] === '-') { key = key.slice(1); }
return key.toLowerCase();
}
}, {});
}
}
/**
* Import modules.
* @param {string[]} importIdentifierArray Modules to import.
* @param {(...importModules:any[]) => void} callback Callback function.
*/
function importModules(importIdentifierArray, callback) {
var thisScope = "undefined" != typeof globalThis
? globalThis
: "undefined" != typeof window
? window
: "undefined" != typeof global
? global : "undefined" != typeof self
? self
: {};
if (!thisScope.modules) { thisScope.modules = {}; }
if (typeof exports === 'object' && typeof module !== 'undefined') {
// CommonJS
if (importIdentifierArray.length) {
importIdentifierArray = importIdentifierArray.map(function (id) { return require(id); });
}
return module.exports = callback.call(thisScope, ...importIdentifierArray);
}
// Browser
waitModules();
function waitModules() {
if (importIdentifierArray.length) {
for (let i = 0; i < importIdentifierArray.length; i++) {
if (!thisScope.modules[importIdentifierArray[i]]) { return setTimeout(waitModules, 10); }
}
}
callback.call(thisScope, ...importIdentifierArray.map(function (id) { return thisScope.modules[id]; }));
}
}