Context & Event Aggregator

Using Node.js' EventEmitter to handle events

import {EventEmitter} from "events";
import {task, TaskContext} from "natron-core";

Creating a Custom Context

class CustomContext extends TaskContext {

  log(opts, ...args) {
    let lvl = this.stack.length - 1;
    args.unshift(opts && opts.ico || " ");
    if (lvl) {
      let indent = " ".repeat(lvl * 2 - 1);
      args.unshift(indent);
    }
    return console.log(...args);
  }
}

Listening for Events

start ... e = {task, context}
finish ... e = {task, context, value}

let ea = new EventEmitter();

ea.on("start", (e) => {
  let {task, context} = e;
  let name = task.name || getAnonymousName(e);
  context.log({ico: "⇢"}, name);
});

ea.on("finish", (e) => {
  let {task, context} = e;
  let name = task.name || getAnonymousName(e);
  context.log({ico: "⇠"}, name);
});

getAnonymousName

let un = new WeakMap();

function getAnonymousName(e) {
  let name = un.get(e);
  if (!name) {
    name = `<task_${(Math.random() * 1e2)|0}>`;
    un.set(e, name);
  }
  return name;
}

Defining Tasks

t: a => (a || b) => b

function a(val, ico = "a") {
  if (val instanceof Array) {
    val = `[${val.join(", ")}]`;
  }
  this.log({ico}, "val", "=", val);
  return `(${val}<${ico}>)`;
}

function b(val) {
  return a.call(this, val, "b");
}

let t = task([a, [[a, b]], b], {
  name: "ab-task",
  options: {pipe: true},
});

Run

let context = new CustomContext({
  args: ["foo"],
  eventAggregator: ea,
});

(t.runWithContext(context)
  .then((val) => {
    console.log("val", "=", val);
  })
);

Output

⇢ ab-task
  ⇢ a
  a val = foo
  ⇠ a
  ⇢ <task_42>
    ⇢ a
    ⇢ b
    a val = (foo<a>)
    b val = (foo<a>)
    ⇠ a
    ⇠ b
  ⇠ <task_42>
  ⇢ b
  b val = [((foo<a>)<a>), ((foo<a>)<b>)]
  ⇠ b
⇠ ab-task
val = ([((foo<a>)<a>), ((foo<a>)<b>)]<b>)