js-awe
Version:
Awesome js utils including - plan: An Asynchronous control flow with a functional taste - Chrono: record and visualize timelines in the console
202 lines (201 loc) • 10 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Compile = exports.plan = void 0;
const fluture_1 = require("fluture");
const ramdaExt_js_1 = require("./ramdaExt.js");
const just_compare_1 = __importDefault(require("just-compare"));
const jsUtils_js_1 = require("./jsUtils.js");
const planExt_js_1 = require("./planExt.js");
Object.defineProperty(exports, "Compile", { enumerable: true, get: function () { return planExt_js_1.Compile; } });
const convertPathToStackPath = path => path.map((el, index) => {
if (index === 0)
return 0;
return parseInt(el, 10);
});
function generateStack(plan) {
let stack = [];
const reviver = (nodeRef, currentPath, parent) => {
if (typeof nodeRef === 'function' && isNaN(parseInt(currentPath.at(-1), 10)) === false)
stack.push({ value: nodeRef, path: convertPathToStackPath(currentPath) });
return undefined;
};
(0, jsUtils_js_1.traverse)(plan, reviver);
stack.push({ value: ramdaExt_js_1.R.identity, path: [1] });
return stack;
}
const isAncestorOf = son => parent => (son === null || son === void 0 ? void 0 : son.length) > (parent === null || parent === void 0 ? void 0 : parent.length) && (0, just_compare_1.default)(parent, son.slice(0, parent.length));
const isSiblingOf = sibling1 => sibling2 => (0, just_compare_1.default)(sibling1 === null || sibling1 === void 0 ? void 0 : sibling1.slice(0, -1), sibling2 === null || sibling2 === void 0 ? void 0 : sibling2.slice(0, -1));
function hasAnyDescendant(stack) {
return path => stack.some(el => path.length < el.path.length &&
(0, just_compare_1.default)(el.path.slice(0, path.length), path));
}
function getDescendants(stack) {
return path => stack.filter(el => path.length < el.path.length &&
(0, just_compare_1.default)(el.path.slice(0, path.length), path));
}
function areRelativeFrom(ancestorInCommon) {
if (ancestorInCommon === undefined || ancestorInCommon.length === 0)
return false;
return familyMember1 => familyMember2 => (0, just_compare_1.default)(ancestorInCommon, familyMember1 === null || familyMember1 === void 0 ? void 0 : familyMember1.slice(0, ancestorInCommon.length)) &&
(0, just_compare_1.default)(ancestorInCommon, familyMember2 === null || familyMember2 === void 0 ? void 0 : familyMember2.slice(0, ancestorInCommon.length));
}
// areRelativeFrom([0,0])([0,0,0,0])([0,0]) //?
const stackSiblingsReducer = (acum, el, index) => {
var _a;
if (isSiblingOf((_a = ramdaExt_js_1.R.last(acum)) === null || _a === void 0 ? void 0 : _a.path)(el.path)) {
acum[acum.length - 1].value = (0, ramdaExt_js_1.pipe)(ramdaExt_js_1.R.last(acum).value, el.value);
}
else {
acum.push(el);
}
return acum;
};
function acumSiblings(stack) {
return stack.reduce(stackSiblingsReducer, []);
}
const stackParallelReducer = function (numberOfThreads) {
let accruingParallel = false;
let stackItemsToParallelize = [];
return (acum, el, index, stack) => {
var _a, _b;
const elParent = el.path.slice(0, -1);
const elGrandparent = elParent === null || elParent === void 0 ? void 0 : elParent.slice(0, -1);
const nextToEl = (_a = stack[index + 1]) === null || _a === void 0 ? void 0 : _a.path;
const nextToElParent = nextToEl === null || nextToEl === void 0 ? void 0 : nextToEl.slice(0, -1);
const nextToElGrandparent = nextToElParent === null || nextToElParent === void 0 ? void 0 : nextToElParent.slice(0, -1);
const previousToEl = (_b = stack[index - 1]) === null || _b === void 0 ? void 0 : _b.path;
const previousToElGrandparent = previousToEl === null || previousToEl === void 0 ? void 0 : previousToEl.slice(0, -2);
let isElToAccrue = el.path.length >= 3 &&
(0, just_compare_1.default)(elGrandparent, nextToElGrandparent) &&
// el is the only child of parent
(0, just_compare_1.default)(getDescendants(stack)(elParent), [el]) &&
// If previous was not accrued we dont want this to be desdendent of the current grandParent unless previous
// is a brother of the parent (function header of subsequent parellel functions).
(accruingParallel ||
isAncestorOf(previousToEl)(elGrandparent) === false ||
(isAncestorOf(previousToEl)(elGrandparent) === true && previousToEl.length < el.path.length));
if (isElToAccrue === true) {
accruingParallel = true;
stackItemsToParallelize.push(el);
}
if (isElToAccrue === false && accruingParallel === true) {
// In cases we stopped because next element is more nested than our current parallelization
// even though it has the grandParent as ancestor, then we need to cancel accruing and
// restore all elements to acum.
if ((nextToEl === null || nextToEl === void 0 ? void 0 : nextToEl.length) > el.path.length && isAncestorOf(nextToEl)(elGrandparent)) {
acum.push(...stackItemsToParallelize);
acum.push(el);
accruingParallel = false;
stackItemsToParallelize = [];
return acum;
}
// Rest of cases we need to follow with parallelization including current element.
stackItemsToParallelize.push(el);
acum.push({
value: (0, ramdaExt_js_1.runFunctionsSyncOrParallel)(numberOfThreads)(ramdaExt_js_1.R.pluck('value', stackItemsToParallelize)),
path: el.path.slice(0, -1)
});
}
if (isElToAccrue === false && accruingParallel === false) {
acum.push(el);
}
if (isElToAccrue === false) {
accruingParallel = false;
stackItemsToParallelize = [];
}
return acum;
};
};
const acumParallel = numberOfThreads => stack => {
return stack.reduce(stackParallelReducer(numberOfThreads), []);
};
const reduceNesting = (stack) => {
let biggerLengthIndex;
let biggerLengthValue = -1;
(0, jsUtils_js_1.repeat)(stack.length).times(index => {
var _a, _b, _c, _d, _e, _f, _g, _h;
if (((_b = (_a = stack[index]) === null || _a === void 0 ? void 0 : _a.path) === null || _b === void 0 ? void 0 : _b.length) > ((_d = (_c = stack[index + 1]) === null || _c === void 0 ? void 0 : _c.path) === null || _d === void 0 ? void 0 : _d.length)) {
if (biggerLengthValue < ((_f = (_e = stack[index]) === null || _e === void 0 ? void 0 : _e.path) === null || _f === void 0 ? void 0 : _f.length)) {
biggerLengthValue = (_h = (_g = stack[index]) === null || _g === void 0 ? void 0 : _g.path) === null || _h === void 0 ? void 0 : _h.length;
biggerLengthIndex = index;
}
}
});
let newStack = stack;
if (biggerLengthIndex !== undefined) {
newStack = [...stack];
newStack[biggerLengthIndex] =
{
value: newStack[biggerLengthIndex].value,
path: newStack[biggerLengthIndex].path.slice(0, -1)
};
}
return newStack;
};
const extractFinalValue = x => { var _a, _b; return (_b = (_a = x[0]) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : x === null || x === void 0 ? void 0 : x.value; };
const lengthStackPrevLessThanCurr = function () {
let prevStack;
return [
function funCond(stack) {
const result = ((stack === null || stack === void 0 ? void 0 : stack.length) < (prevStack === null || prevStack === void 0 ? void 0 : prevStack.length)) || prevStack === undefined;
prevStack = stack;
return result;
},
function ini() {
prevStack = undefined;
}
];
};
function changeFunWithMockupsObj(mockupsObj) {
return stack => {
if (!mockupsObj)
return stack;
return stack.map(({ path, value }) => {
if ((mockupsObj === null || mockupsObj === void 0 ? void 0 : mockupsObj[value.name]) !== undefined) {
if (typeof mockupsObj[value.name] === 'function') {
return {
value: mockupsObj[value.name],
path
};
}
return {
value: () => mockupsObj[value.name],
path
};
}
return { value: value, path };
});
};
}
function plan({ numberOfThreads = Infinity, mockupsObj = {} } = { numberOfThreads: Infinity, mockupsObj: {} }) {
function build(planDef) {
const toExec = (0, ramdaExt_js_1.pipe)(generateStack, changeFunWithMockupsObj(mockupsObj), (0, ramdaExt_js_1.pipeWhile)(stack => stack.length > 1)((0, ramdaExt_js_1.pipeWhile)(...lengthStackPrevLessThanCurr())(acumSiblings, acumParallel(numberOfThreads)), reduceNesting), extractFinalValue)(planDef);
toExec.rebuild = (options) => {
setOptions(options);
return build(planDef);
};
return toExec;
}
function setOptions(options) {
({ numberOfThreads, mockupsObj } = options);
}
function map(fun, mapThreads = numberOfThreads) {
const toReturn = (data) => {
if (Array.isArray(data))
return (0, ramdaExt_js_1.runFunctionsSyncOrParallel)(mapThreads)(data.map(param => fun.bind(fun, param)))();
return [fun(data)];
};
Object.defineProperty(toReturn, 'name', { value: `map_${fun.name}` });
return toReturn;
}
function identity(...args) {
if (args.length > 1)
throw new Error('identity function only accepts one argument');
return args[0];
}
return { build, map, identity };
}
exports.plan = plan;
;