js-awe
Version:
Awesome js utils including - plan: An Asynchronous control flow with a functional taste - Chrono: record and visualize timelines in the console
235 lines (234 loc) • 10.1 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.end = exports.start = exports.Compile = void 0;
const jsUtils_js_1 = require("./jsUtils.js");
const node_util_1 = __importDefault(require("node:util"));
const start = Symbol('start');
exports.start = start;
const end = Symbol('end');
exports.end = end;
const type = new jsUtils_js_1.EnumMap(['OPEN_ARRAY', 'CLOSE_ARRAY', 'NODE', 'UNSYNC']);
class Node {
constructor(node, path, name) {
this.node = node;
this.path = [...path];
this.name = name;
}
[node_util_1.default.inspect.custom]() {
return `typeof node: ${typeof this.node}, path: ${this.path.join('.')} name: ${this.name}`;
}
}
class Nodes {
constructor() {
this.nodes = [];
}
add(node, path) {
const name = this.calculateNodeName(node, path);
if (this.findByName(name))
throw new Error(`Node with name ${name} already exists`);
const newNode = new Node(node, path, name);
this.nodes.push(newNode);
return newNode;
}
findByName(name) {
return this.nodes.find(node => node.name === name);
}
calculateNodeName(node, path) {
let name = '';
if (node.name) {
name = node.name;
}
if (typeof node === 'symbol') {
name = node.toString().replace('(', '_').replace(')', '');
}
if (this.findByName(name))
return `${name}__${path.join('_')}`;
return name;
}
getNodes() {
return this.nodes;
}
}
class Word {
constructor(type, starts, ends, relations) {
this.type = type;
this.starts = starts;
this.ends = ends;
this.relations = relations;
}
[node_util_1.default.inspect.custom]() {
return JSON.stringify(this);
}
toString() {
JSON.stringify(this);
}
setType(type) {
this.type = type;
return this;
}
getRelations() {
return this.relations;
}
sync(word) {
for (const start of this.ends) {
for (const end of word.starts) {
if (start !== end)
this.relations.push([start, end]);
}
}
return new Word(type.NODE, this.starts, word.ends, [...this.relations, ...word.relations,]);
}
static unsync(word1, word2) {
return new Word(type.UNSYNC, [...word1.starts, ...word2.starts], [...word1.ends, ...word2.ends], [...word1.relations, ...word2.relations]);
}
}
function planToTranscript(plan) {
const nodes = new Nodes();
const startNode = nodes.add(start, []);
const transcript = []; //[new Word(type.NODE, [startNode], [startNode], [])]
processPlan(plan, []);
function processPlan(plan, path) {
const pathLevel = path.length;
for (let i = 0, j = 0; i < plan.length; i++) {
if (Array.isArray(plan[i])) {
transcript.push(new Word(type.OPEN_ARRAY));
path.push(i);
processPlan(plan[i], path);
path.pop();
transcript.push(new Word(type.CLOSE_ARRAY));
}
else {
// path[pathLevel] = i
path.push(i);
nodes.add(plan[i], path);
path.pop();
const currentNode = nodes.getNodes().at(-1);
transcript.push(new Word(type.NODE, [currentNode], [currentNode], []));
}
}
}
const endNode = nodes.add(end, []);
const transcriptWithStartAndEnd = [
new Word(type.NODE, [startNode], [startNode], []),
...transcript,
new Word(type.NODE, [endNode], [endNode], [])
];
return { transcript: transcriptWithStartAndEnd, nodes };
}
function compilePrecedenceFirst(transcript) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
let previousTranscriptLength = transcript.length;
while (transcript.length > 1) {
// console.log('Before transccompilePrecedenceFirst: ', transcript.length)
for (let i = 0; transcript[i + 1] !== undefined; i++) { // i < transcript.length - 1
if (transcript[i].type === type.NODE &&
transcript[i + 1].type === type.NODE) {
transcript.splice(i, 2, transcript[i].sync(transcript[i + 1]));
}
if (transcript[i].type === type.UNSYNC &&
transcript[i + 1].type === type.UNSYNC) {
transcript.splice(i, 2, Word.unsync(transcript[i], transcript[i + 1]));
}
if (((_a = transcript[i]) === null || _a === void 0 ? void 0 : _a.type) === type.OPEN_ARRAY &&
(((_b = transcript[i + 1]) === null || _b === void 0 ? void 0 : _b.type) === type.NODE || ((_c = transcript[i + 1]) === null || _c === void 0 ? void 0 : _c.type) === type.UNSYNC) &&
((_d = transcript[i + 2]) === null || _d === void 0 ? void 0 : _d.type) === type.CLOSE_ARRAY) {
transcript.splice(i, 3, transcript[i + 1].setType(type.UNSYNC));
}
if (((_e = transcript[i]) === null || _e === void 0 ? void 0 : _e.type) === type.OPEN_ARRAY &&
((((_f = transcript[i + 1]) === null || _f === void 0 ? void 0 : _f.type) === type.NODE && ((_g = transcript[i + 2]) === null || _g === void 0 ? void 0 : _g.type) === type.UNSYNC) ||
(((_h = transcript[i + 1]) === null || _h === void 0 ? void 0 : _h.type) === type.UNSYNC && ((_j = transcript[i + 2]) === null || _j === void 0 ? void 0 : _j.type) === type.NODE)) &&
((_k = transcript[i + 3]) === null || _k === void 0 ? void 0 : _k.type) === type.CLOSE_ARRAY) {
transcript.splice(i, 4, transcript[i + 1].sync(transcript[i + 2]).setType(type.UNSYNC));
}
if (((_l = transcript[i]) === null || _l === void 0 ? void 0 : _l.type) === type.OPEN_ARRAY &&
((_m = transcript[i + 1]) === null || _m === void 0 ? void 0 : _m.type) === type.UNSYNC &&
((_o = transcript[i + 2]) === null || _o === void 0 ? void 0 : _o.type) === type.NODE) {
transcript.splice(i + 1, 2, transcript[i + 1].sync(transcript[i + 2]));
}
if (((_p = transcript[i]) === null || _p === void 0 ? void 0 : _p.type) === type.NODE &&
((_q = transcript[i + 1]) === null || _q === void 0 ? void 0 : _q.type) === type.UNSYNC &&
((_r = transcript[i + 2]) === null || _r === void 0 ? void 0 : _r.type) === type.NODE) {
transcript.splice(i, 3, transcript[i].sync(transcript[i + 1]).sync(transcript[i + 2]));
}
if (((_s = transcript[i]) === null || _s === void 0 ? void 0 : _s.type) === type.NODE &&
((_t = transcript[i + 1]) === null || _t === void 0 ? void 0 : _t.type) === type.UNSYNC &&
((_u = transcript[i + 2]) === null || _u === void 0 ? void 0 : _u.type) === type.CLOSE_ARRAY) {
transcript.splice(i, 2, transcript[i].sync(transcript[i + 1]));
}
}
// console.log('After transccompilePrecedenceFirst: ', transcript.length)
// console.log('transcript: ', transcript)
if (transcript.length === previousTranscriptLength)
break;
previousTranscriptLength = transcript.length;
}
}
function compilePrecedenceSecond(transcript) {
let previousTranscriptLength = transcript.length;
while (transcript.length > 1) {
// console.log('Before transccompilePrecedenceSecond: ', transcript.length)
for (let i = 0; transcript[i + 1] !== undefined; i++) { // i < transcript.length - 1
if ((transcript[i].type === type.NODE &&
transcript[i + 1].type === type.UNSYNC) || (transcript[i].type === type.UNSYNC &&
transcript[i + 1].type === type.NODE)) {
transcript.splice(i, 2, transcript[i].sync(transcript[i + 1]).setType(type.NODE));
// console.log('After transccompilePrecedenceSecond: ', transcript.length)
// console.log('transcript: ', transcript)
return;
}
}
// console.log('After transccompilePrecedenceSecond: ', transcript.length)
// console.log('transcript: ', transcript)
if (transcript.length === previousTranscriptLength)
break;
previousTranscriptLength = transcript.length;
}
}
class Compile {
constructor(plan) {
const { transcript, nodes } = planToTranscript(plan);
this.nodes = nodes.getNodes();
let i = 0;
while (transcript.length > 1) {
compilePrecedenceFirst(transcript);
compilePrecedenceSecond(transcript);
i++;
}
this.relations = transcript[0].getRelations();
}
toPlantUML() {
let plantUML = '@startuml\n';
plantUML += 'allowmixing\n';
plantUML += '\n';
for (const node of this.nodes) {
plantUML += `${typeof node === 'symbol' ? 'diamond' : 'object'} ${node.name}\n`;
}
plantUML += '\n';
for (const [from, to] of this.relations) {
plantUML += `${from.name} --> ${to.name}\n`;
}
plantUML += '\n';
plantUML += '@enduml\n';
return plantUML;
}
}
exports.Compile = Compile;
// const complexPlanStrings = [
// [[['test1'],[['fetchBulkCurrentAccounts']]], 'test2'],
// ['fetchAccounts',
// ['identity'],
// ['filterSavings', 'pluck_id', 'map_fetchSavingBalance'],
// ['filterLoans', 'pluck_id_2', 'map_fetchLoanBalance']
// ],
// 'format',
// ];
// const complexPlan = traverse(complexPlanStrings, (node, currentPath, parent) => {
// if (typeof node === 'string') return {name:node}
// //return node;
// });
// console.log(
// new Compile(complexPlan).toPlantUML()
// )
;