Working towards JavaScript to write a ruleset

Background

There is interest in allowing a ruleset to be written in JavaScript, as a Node.js module.

This page will explore a way in which this might be done.

Contrived example

Let's assume we want to implement an API to maintain many named counters, as shown here:

/sky/cloud/<ECI>/counting/count?name=<NAME>
/sky/cloud/<ECI>/counting/largeCounts?limit=<LIMIT>
/sky/cloud/<ECI>/counting/countersAt?value=<VALUE>
/sky/cloud/<ECI>/counting/totalCount

/sky/event/<ECI>/none/counting/needed?name=<NAME>
/sky/event/<ECI>/none/counting/one_more?name=<NAME>
/sky/event/<ECI>/none/counting/new_value?name=<NAME>&value=<VALUE>
/sky/event/<ECI>/none/counting/needs_reset?name=<NAME>
/sky/event/<ECI>/none/counting/not_needed?name=<NAME>

The plan is to create and use a single pico to provide the implementation. A channel will be created in the pico, and its channel identifier is represented by <ECI> in the spec. Similarly, a counter name when mentioned in an API call is represented by <NAME> in the spec. Also appearing are <LIMIT> and <VALUE> which stand in for numbers in the spec.

The lifecycle of one of these counters might be as follows:

  1. the need for the counter is felt, a name is chosen, and the API event in line 6 creates it, initialized at zero
  2. there is a need to increment the counter, satisfied by the API event in line 7
  3. the counter needs a new value, which is assigned by the API event in line 8
  4. the counter needs to be reset to zero, API event in line 9
  5. the counter is no longer needed and is removed by the API event in line 10

Meanwhile, we can obtain the current value of a counter using the API query in line 1, get a list of counts larger than a certain limit using the API query in line 3, get a list of counter names that have a specified value using the API query in line 3, and finally, get the total of all counter values using the API query in line 4.

Again, this is not intended as a really useful API, but as an example to guide coding in both KRL and, perhaps, in JavaScript.

KRL implementation

An implementation of a ruleset written in KRL which satisfies this API spec is available at on GitHub.

Possible JavaScript implementation

A JavaScript Node.js module for this example might have a structure like this:

var count = function(args,entityVars){ ... args.name ... };
var largeCounts = function(args,entityVars){ ... args.limit ... };
var countersAt = function(args,entityVars){ ... args.value ... };
var totalCount = function(args,entityVars){ ... entityVars.read("counts") ... };
var rulesetAdded = function(entityVars,actions){ ... entityVars.write("counts",{}) ... };
var rule1 = { select: { domain: "counting", type: "needed",
              rule: function(attrs,entityVars,actions){ ... attrs.name ... entityVars.write("counts",key,0) ... };
...
module.exports = {
  "queries": { count: count, largeCounts: largeCounts, countersAt: countersAt, totalCount: totalCount },
  "hooks": { rulesetInstallation: rulesetAdded },
  "rules": [ rule1, ..., rule5 ]
}

The details are left to be filled in by a Node.js programmer. This shows how entity variables belonging to this ruleset/pico could be read in queries and rules, and written in hooks and rules, using a JS object passed into them, identified here as entityVars. Not shown here are how a rule might contribute actions, nor how they might raise further events.

Registration

When the engine was made aware of the JavaScript module, it would transpile it into a Node.js module compatible with those produced by the krl-compiler for rulesets written in KRL. The author is reminded here of a cartoon showing a mathematician at a chalkboard with a complicated proof, in the middle of which are the words "here a miracle occurs." Seriously, though, this transpilation ought to be doable.

Installation in a pico

When the ruleset is installed in the chosen pico, its rulesetInstallation rule function will be evaluated as part of the chain of events initiated by the installation. This is a suggested shortcut, as an explained hook, rather than requiring a specific rule to react to the wrangler:ruleset_added event, with which KRL programmers are familiar.