PROforma is a clinical decision support system (CDSS) language (see Sutton and Fox 2003). PROformajs is a lightweight javascript PROforma engine, written in Javascript.

Getting started

PROformajs is a library intended to be embedded in other applications. The easiest way to get started is by trying the online demonstrator. However, if you are a developer then the REPL can be used to get your hands on the API. With Nodejs (v6+) and Git installed you can first clone the repository, install the dependencies and start it up:

you@yourmachine:~$ git clone https://gitlab.com/openclinical/proformajs.git
you@yourmachine:~$ cd proformajs
you@yourmachine:~$ npm install
you@yourmachine:~$ npm run build
you@yourmachine:~$ npm run repl

> @openclinical/proformajs@0.4.3 repl /home/you/Software/proformajs
> node src/repl.js

PROformajs Copyright (C) 2017 Openclinical CIC
This program comes with ABSOLUTELY NO WARRANTY;
This is free software, and you are welcome to
redistribute it under certain conditions;

This is a Javascript REPL with pre-loaded modules:
* Protocol
* Enactment
* Moment

PROforma>

Protocols and Enactments

Protocols are the design-time representation of guidelines that consist of a tree of tasks and data definitions. Runtime enactments of a protocol are created with the Enactment module which uses the Moment library to handle date and time calculations. The REPL has pre-loaded Protocol, Enactment and Moment modules.

To create a very simple protocol you can create a single demo task. Type

protocol = new Protocol.Task({name: 'demo'})

at the cursor. You should see:

PROforma> protocol = new Protocol.Task({name:'demo'})
Task {
  preCondition: undefined,
  waitCondition: undefined,
  abortCondition: undefined,
  eventTrigger: undefined,
  cycleUntil: undefined,
  name: 'demo',
  caption: undefined,
  description: undefined,
  _parent: undefined,
  meta: undefined,
  optional: false,
  autonomous: false,
  cyclic: false,
  dataDefinitions: []
}

and use that protocol to create a runtime enactment:

PROforma> enactment = new Enactment({start:true, protocol: protocol})
Enactment {
  protocol: Task {
    preCondition: undefined,
    waitCondition: undefined,
    abortCondition: undefined,
    eventTrigger: undefined,
    cycleUntil: undefined,
    name: 'demo',
    caption: undefined,
    description: undefined,
    _parent: undefined,
    meta: undefined,
    optional: false,
    autonomous: false,
    cyclic: false,
    dataDefinitions: []
  },
  options: undefined,
  listeners: {},
  _state: {
    demo: TaskState {
      state: 'in_progress',
      completeable: true,
      cancellable: true,
      index: undefined,
      cycleable: true,
      path: 'demo',
      _enactment: [Circular],
      design: 'demo'
    }
  },
  _data: {},
  _audit: [
    {
      action: 'start',
      timestamp: 2019-08-19T15:51:43.872Z,
      deltas: [Array]
    }
  ],
  _triggers: {},
  tickInterval: undefined,
  stackLimit: 1000
}

The getStatus method shows options available. Ours is a simple protocol and there's only two things that can be done, completing or cancelling the 'demo' task.

PROforma> enactment.getStatus()
{ started: true,
  finished: false,
  completeable: [ 'demo' ],
  cancellable: [ 'demo' ],
  warnings: [],
  requested: {},
  confirmable: {},
  triggers: []
}

Enactment has a chainable interface so completing the task returns the updated enactment which is now finished, as is seen when we chain the getStatus method.

PROforma> enactment.complete('demo').getStatus()
{ started: true, finished: true }

Serialisation

Both protocols and enactments can be serialised to JSON with JSON.stringify and deserialised with a static inflate method, e.g.

PROforma> json = JSON.stringify(protocol)
'{"class":"Task","name":"demo"}'
PROforma> Protocol.inflate(json)
Task {
  preCondition: undefined,
  waitCondition: undefined,
  abortCondition: undefined,
  eventTrigger: undefined,
  cycleUntil: undefined,
  name: 'demo',
  caption: undefined,
  description: undefined,
  _parent: undefined,
  meta: undefined,
  optional: false,
  autonomous: false,
  cyclic: false,
  dataDefinitions: [] }