// import { ConnectionType } from "./package/connector/connection_type.js";
// import { Connector } from "./package/connector/connector.js";
// import { ConnectorType } from "./package/connector/connector_type.js";
/**
* @param {number} waitSecs
*/
export const pause = waitSecs => new Promise(res => setTimeout(res, waitSecs * 1000));
/**
* @param {Array<number>} nrs
* @returns {number}
*/
export const sum = nrs => nrs.reduce((a, b) => a + b, 0);
export const eqArr = (arr1, arr2) => {
// compare lengths - can save a lot of time
if (arr1.length !== arr2.length) {
return false;
}
for (const i = 0, l=arr1.length; i < l; i++) {
// Check if we have nested arrays
if (arr1[i] instanceof Array && arr2[i] instanceof Array) {
// recurse into the nested arrays
if (!eqArr( arr1[i], arr2[i])) {
return false;
}
}
else if (arr1[i] !== arr2[i]) {
// Warning - two different object instances will never be equal: {x:20} != {x:20}
return false;
}
}
return true;
}
/**
* @param {Array<String>} keys
* @param {Object} obj
*/
export const omit = (keys, obj) =>
keys.reduce(
(a, e) => {
const { [e]: omit, ...rest } = a;
return rest;
},
obj
)
/**
* @param {Array<String>} keys
* @param {Object} obj
*/
export const pick = (keys, obj) =>
keys.reduce(
(newObj, k) =>
k in obj ? Object.assign(newObj, { [k]: obj[k] }) : newObj
, {}
);
export const unique = (value, index, self) =>
self.indexOf(value) === index
export const makeImage = ( width, height, src ) => {
const img = new Image(128,128);
img.src = src;
return img
};
/**
* @param {Object} instructions
* @param {Object} instructions.from - source object
* @param {Object} instructions.into - target object (is modified)
* @param {Array<string>} [instructions.required]
* @param {Array<string>} [instructions.optional]
*/
export const copyProps = function ({ from, /* out */ into, required = [], optional = [] }) {
const copiedProps = [];
for (let prop of required || []) {
if (from[prop] === undefined) {
throw new Error(`Missing property "${prop}"`)
}
into[prop] = from[prop];
copiedProps.push(prop);
}
for (let prop of optional || []) {
if (from[prop] !== undefined) {
into[prop] = from[prop];
copiedProps.push(prop);
}
}
return copiedProps;
}
// Safari doesn't understand lookahead
// export const UUIDRegex = new RegExp(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i);
// export const semverRegex = new RegExp(/(?<=^v?|\sv?)(?:(?:0|[1-9]\d*)\.){2}(?:0|[1-9]\d*)(?:-(?:0|[1-9]\d*|[\da-z-]*[a-z-][\da-z-]*)(?:\.(?:0|[1-9]\d*|[\da-z-]*[a-z-][\da-z-]*))*)?(?:\+[\da-z-]+(?:\.[\da-z-]+)*)?\b/gi);
export const UUIDRegex = new RegExp(/^(?:\{[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\}|[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12})$/i);
export const URLRegex = new RegExp(/[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)?/gi);
export const semverRegex = new RegExp(/ ^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+)?$\b/gi);
export const getAssigningComponent = obj => obj.positionedMesh || obj.positionedMeshGroup || obj.blockInstance;
/**
* @link https://stackoverflow.com/questions/40922531/how-to-check-if-a-javascript-function-is-a-constructor
* @param {Object} obj
*/
function isConstructor(obj) {
return !!obj.prototype && !!obj.prototype.constructor.name;
}
/**
* @param {Object} objToCheck - object to check
* @param {Object} requiredProps
* @param {Object} optionalProps
*/
export const checkPropTypes = function (objToCheck, requiredProps = {}, optionalProps = {}) {
const check = (prop, val, shouldBe) => {
let errMsg = null;
let os;
if (typeof shouldBe === 'object' && shouldBe.msg) { // check for .test interferes with the regex types
os = shouldBe;
errMsg = shouldBe.msg || null;
shouldBe = shouldBe.test;
// dirty? yes
}
if (typeof (shouldBe) === 'string') {
if (typeof (val) !== shouldBe) {
throw new Error(`Property [${prop}] is a ${typeof (val)} not a ${shouldBe}. ${errMsg ? errMsg : ''}`);
}
}
else if (shouldBe instanceof RegExp) {
if (!val.match(shouldBe)) {
throw new Error(`Property [${prop}] format is incorrect. ${errMsg ? errMsg : ''}`);
}
}
else if (typeof (shouldBe) === 'function' && !isConstructor(shouldBe)) {
// try {
const checkResult = shouldBe(val);
if (checkResult !== true) {
// value "${val}"
throw new Error(`Invalid property [${prop}]. ${typeof (checkResult) === 'string' ? checkResult : ''} ${errMsg ? errMsg : 'a ' + errMsg}`);
}
// }
// catch ( err ) {
// console.error( err)
// console.error( prop, val, shouldBe)
// throw err
// }
}
else if (typeof (shouldBe) === 'function') {
if (!(val instanceof shouldBe)) {
throw new Error(`Property [${prop}] is a ${val.constructor.name} not a ${shouldBe.name || shouldBe}. ${errMsg ? errMsg : ''}`);
}
}
else {
console.error(shouldBe);
throw new Error('Unknown check type ');
}
}
for (let [prop, shouldBe] of Object.entries(requiredProps)) {
const val = objToCheck[prop];
if (val === undefined) {
throw new Error(`Required property [${prop}] is undefined in keys [${Object.keys(objToCheck).join(', ')}]`);
}
// console.log( shouldBe )
if (Array.isArray(shouldBe)) {
shouldBe.forEach(subSB => check(prop, val, subSB));
}
else {
check(prop, val, shouldBe);
}
}
for (let [prop, shouldBe] of Object.entries(optionalProps)) {
const val = objToCheck[prop];
if (val !== undefined) {
if (Array.isArray(shouldBe)) {
shouldBe.forEach(subSB => check(prop, val, subSB));
}
else {
check(prop, val, shouldBe);
}
}
}
return true;
};
/**
* Builds a map that indexes potential connection mates per connector type
* @param {Object} connectionComponents
* @param {Array<ConnectionType>} connectionComponents.connectionTypes
* @param {Array<ConnectorType>} connectionComponents.connectorTypes
* @param {Array<Connector>} connectionComponents.connectors
* @returns {Map<ConnectorType,Object>}
*/
export const buildMateMap = ({ connectionTypes, connectorTypes, connectors }) => {
// console.log( 'BMM', connectorTypes)
const map = new Map();
for (let ctrType of connectorTypes) {
const ctMap = {};
ctMap.connectionTypes = connectionTypes.filter(cnt => cnt.settings.connectorTypes.includes(ctrType));
ctMap.connectorTypes = [];
for (let relCnnType of ctMap.connectionTypes) {
// the ConnectionType can specify the same ConnectorType twice,
// in this case it can connect to itself. This is why .filter
// cannot be used here, the relCnnType is found in the array
// and the other value is taken as mate, regardless of its type
const types = relCnnType.settings.connectorTypes;
const mateType = types[0] === ctrType ? types[1] : types[0];
if (ctMap.connectorTypes.indexOf(mateType) === -1) {
ctMap.connectorTypes.push(mateType);
}
}
ctMap.connectors = connectors.filter(cn =>
ctMap.connectorTypes.includes(cn.type)
);
map.set(ctrType, ctMap);
}
return map;
}
export const ucFirst = str =>
str.charAt(0).toUpperCase() + str.slice(1);