0.0.173 • Published 2 years ago

crs-process-api v0.0.173

Weekly downloads
-
License
ISC
Repository
-
Last release
2 years ago

CRS Process API

Introduction

This library provides a basis to develop process driven application where users and developers use the same API to define features.
It has a dependency on crs-binding.

The goals are:

  1. Extendable data driven api
  2. Allow defining and executing processes using code
  3. Allow defining and executing processes using json

This allows application users to define processes for your system using json and execute them at will.
A process is a sequence of steps that follow up on each other.
The system does not assume sequential execution.

Using the properties:

  1. next_step
  2. pass_step
  3. fail_step

you indicate what the next step must be.

With this system you can perform simple single step actions or scenarios like this.

  1. Get a list of records from the server
  2. Loop through those records and perform a check on each record.
  3. If the condition passes copy that record to an array (result array)
  4. Once you have looped through the records save the result array to file

The idea behind the process api is part of the dynamic application goal.

Executing a process

There are two ways to run a process.

  1. Run the entire process
  2. Run a particular process step

Running the entire process

const process = {...};
await crs.process.run(context, process, item, text, prefixes);
  1. context - object referenced as "$context"
  2. process - object referenced as "$process"
  3. item - object referenced as "$item"
  4. text - object referenced as "$text"
  5. prefixes - object that defines shortcut syntax and reference objects. see prefixes for details.

Running a process step

const process = {...};
await crs.process.runStep(step, context, process);

See the step section for more detail on steps.

You can use a nice shorthand, that is the recommended way of calling a step.

const pageSizeTranslation = await crs.call("translations", "get", { key: "visualization.pageSize" });

pramaters 1. system 2. function on that system 3. args

Target keywords

  1. $context - context object passed to the process
  2. $process - process object passed to the system
  3. $item - item object passed to the system

$item is used when looping through an array and performing actions on the array item.

Step

Each process step has the same basic structure.

{
    type: "console", 
    action: "log", 
    args: {
        ... details
    }
}

Each action has different args that defines the details for that step to execute.
Some process steps need to copy the value of the step to a variable.
The property "target" in args define where that value must be copied too.

Use the target keywords to define the location as required.

...
args: {
    target: "$context.property1"
}

A convention you can use on the process is to have a "data" property where you can save results to during the process execution.

const process = {
    data: {},
    steps: {
        start: { next_step: "doSomething" },
        doSomething: {
            ...
            args: {
                target: "$process.data.value"    
            }           
        }
    }
}

Binding

Default process structure

A process is just an object literal.
Each process has a "steps" property that is also an object literal.
You can decorate the process with additional properties such as:

  1. version
  2. description ...

Each process has a required step called "start".
Start only has one property called "next_step".
The process can't assume what step to start with so "next_step" defines what that starting point is.

const process = {
    steps: {
        start: {
            next_step: "subtract"
        },
        subtract: {
            type: "math",
            action: "subtract",
            args: {
                value1: 10,
                value2: 11,
                target: "$process.result"
            }
        }
    }
}

Common intent

The process engine ships with some basic intent.
Intent is defined on globalThis.crs.intent.

Default intent are:

  1. actions
  2. array
  3. binding
  4. condition
  5. console
  6. data
  7. dom
  8. events
  9. loop
  10. math
  11. module
  12. object
  13. process
  14. random
  15. rest services
  16. string manipulation
  17. system

Each of these has the same functional entry point called "perform".
They all have the same parameters.

  1. step
  2. context
  3. process
  4. item

Extending an intent

For this section lets say we want to add a function to the array intent called "sum".

crs.intent.array.sum = (step, context, process, item) => {
    // perform action
}

There are two helper functions that you need to take note of.

  1. getValue
  2. setValue

getting a value

const value = await crs.process.getValue(step.args.source, context, process, item);

setting a value This is particularly important if you want your step to support writing results to a target.

await crs.process.setValue(step.args.target, result, context, process, item);

Adding your own process action support

export class MyActions {
    static async perform(step, context, process, item) {
        await this[step.action](step, context, process, item);
    }
    
    static async custom_action(step, context, process, item) {
        // you can access the args of the step on the step parameter
    }
}

crs.intent.myActions = MyActions;

The step can be access as:

stepName: {
    type: "myAction",
    action: "customAction",
    args: {
        ...
    }    
}

Action Intent

crs.intent.action

This intent allows you to execute a function on either

  1. $context
  2. $process
  3. $item
const step = {
    type: "action",
    action: "$context.log",
    args: {
        parameters: ["Hello World"]
    }
}

The target args property will copy the function results to the specified location.
Executing the action will also return you the value of the function you called.

Array Intent

crs.intent.array

This intent provides simple array access.

The default functions are:

  1. add - add a value or object to array
  2. field_to_csv - using an array of objects, export a csv text for a given property on the stored objects.
  3. concat - combine 2 or more arrays into a single array

add step

const step = {
    type: "array",
    action: "add", 
    args: {
        target: "$context.values", 
        value: "Hello World"
    }
}

You can also use this directly.

const values = [];
await crs.intent.array.perform({action: "add", args: {target: values, value: "Hello World"}});

field_to_csv step

There are two scenarios here. 1. Give me a csv where I only use a single field's value and get a string back with those values in csv. 2. I want a csv array for each row in the array build up from a number of fields.

single field example

const step = {
    type: "array",
    action: "field_to_csv",
    args: {
        source: "$context.values",  // what array to use 
        target: "$context.result",  // where to copy the result
        delimiter: ";",             // what delimeter to use
        field: "value"              // what is the property name to use for the values
    }
}

result

"1,2,3"

multi field example

const step = {
    type: "array",
    action: "field_to_csv",
    args: {
        source: "$context.values",  // what array to use 
        target: "$context.result",  // where to copy the result
        delimiter: ";",             // what delimeter to use
        fields: ["value", "code"]   // what is the property name to use for the values
    }
}

result

result

["10;code1", "20;code2", ...]

concat

const step = {
    action: "concat",
    args: {
        sources: ["$context.collection1", "$context.collection2"],
        target: "$context.result"
    }
}

Condition Intent

crs.intent.condition

This intent allows you to perform an "if" statement.
The condition will either pass or fail on you need to indicate what step to take should the condition pass or fail.
To do this you need to define the next step in either:

  1. pass_step - perform this step if the condition passes
  2. fail_step - perform this step if the condition fails

Pass and fail steps need to point to root level objects or a process step object The step for this does not require an action property.

const step = {
    type: "condition",
    args: {
        condition: "$context.value === 10",
    },
    pass_step: "doSomething",
    fail_step: "end"
}

The condition is a standard javascript expression.

Console Intent

crs.intent.console

This intent exposes basic browser console features.
In a standard process I don't think it adds much value but when debugging a process can come in handy.

The actions exposed on this intent are:

  1. log - console.log
  2. error - console.error
  3. warn - console.warn
  4. table - console.table
const step = {
    type: "console",
    action: "log",              // or eror, warn, table
    args: {
        message: "Hello World"  // or $context.value / $process.value / $item.value
    }
}

Loop Intent

crs.intent.loop

This intent allows you to loop through an array and works a little different to the other steps.

const step = {
    type: "loop",
    args: {
        source: "$context.records",
        steps: {
            copy_to_array: {
                type: "array",
                action: "add",
                args: {
                    target: "$context.result",
                    value: "$item"
                }
            }
        }
    }
}

The above example loops through an array found at "$context.records". For each item we copy that array item "$item" to an array at "$context.result".

As you can see in the above example the loop args has a steps property that define what steps to take. These steps execute top down so if you have more than one step, it will execute step 1 then 2 then 3 ... It is at this point where the "$item" comes into play.

If you look at a standard intent entry point:

As part of the loop args you can also define a target property.
When you do that, it will save the current item to that property path.
You can then use it later as a reference for other operations.
For example:

const context = {
    records: [{value: 1}, {value: 2}, {value: 3}],
    result: []
}

const step = {
    type: "loop",
    args: {
        source: "$context.records",
        target: "$context.current",
        steps: {
            copy: {
                type: "array",
                action: "add",
                args: {
                    target: "$context.result",
                    value: "$context.current.value"
                }
            }
        }
    }
};
static async perform(step, context, process, item)

You will notice that three parameters are always passed for access.

  1. context
  2. process
  3. item

In most all cases "item" is not defined.
When executing a process as part of a loop the current array item is the item accessed through "$item".

Math Intent

crs.intent.math

This intent allows for math operations. It exposes basic arithmetic functions but also access to the Math system object for more complex functions.

Basic arithmetic functions are:

  1. add
  2. subtract
  3. multiply
  4. divide
const step = {
    type: "math",
    action: "multiply",
    args: {
        value1: 10,
        value2: 1,
        target: "$process.result"
    }
}

When dealing with add, subract, multiply or divide your args needs two properties.

  1. value1
  2. value2

When using the Math object you need something more dynamic because different functions require different arguments.
For these scenarios you only have a value property of type array.

const step = {
    type: "math",
    action: "max",
    args: {
        value: ["$process.data.max", 90],
        target: "$process.data.max"
    },
    next_step: "do_something"
}

The above example can also be used in a loop to find the max value of a collection.

Module Intent

crs.intent.module

If you are using crs-modules this intent allows you to execute operations exposed by crs-modules.

This intent only exposes three actions but does a little more.

  1. call - call an exported or default function on a defined module
  2. create_class - create an instance of a defined or default exposed class
  3. get_constant - get a constant value defined on that module.

In terms of crs-modules a module is just a javascript file that is registered with a particular key on the module system. Using crs-modules in tandom with crs-process-api is a great way to dynamically extend the api capability.
Since modules only load the files when and if you use it, it is also relatively light weight.

call function step

const step = {
    type: "module",
    action: "call",
    args: {
        module: "utils",
        fnName: "updateMessage",
        parameters: "Hello World",
        target: "$context.result",
        context: "$context"
    }
}

The context property in args here defines what the "this" object in the function call will be.
Under the hood it uses the function.call language feature using the context as the "this" object;

When the function is exported as the default the args parameters change a bit.

args: {
    module: "default-function",
    default: true,
    target: "$context.result",
    context: "$context"
}

Instead of the fnName property, you just need to define that it is the default by setting the "default" property to true. The same concept applies when creating a class.

create class step

const step = {
    type: "module",
    action: "create_class",
    args: {
        module: "class",
        class: "MyClass",
        target: "$context.instance"
    }
}
args: {
    module: "class",
    default: true,
    target: "$context.instance"
}

get constant step

const step = {
    type: "module",
    action: "get_constant",
    args: {
        module: "utils",
        name: "GLOBAL_VALUE",
        target: "$context.instance"
    }
}

Object intent

crs.intent.object

The object intent exposes several utility functions to work with objects.

  1. set - set a property on path with a defined value
  2. get - get the value on a object path
  3. create - create a object literal at a given path
  4. assign - copy the properties from one object to another. uses Object.assign in the background
  5. clone - create a copy of the object.

set step

set_value: {
    type: "object",
    action: "set",
    args: {
        target: "$item.code",
        value: "$item.code.toUpperCase()"
    }
}

You can also set multiple properties and values using the set step

set_value: {
    type: "object",
    action: "set",
    args: {
        target: "$item",
        properties: {
            code: "$item.code.toUpperCase()",
            description: "$item.description"
        }
    }
}

get step

const step = {
    type: "object",
    action: "get",
    args: {
        source: "$context.source",
        target: "$context.result"
    }
}

delete step

const step = {
    type: "object",
    action: "delete",
    args: {
        target: "$context",
        properties: ["property1", "property2"]
    }
}

create step

const step = {
    type: "object",
    action: "clone",
    args: {
        source: "$context.source",
        target: "$context.result"
    }
}

clone step

const step = {
    type: "object",
    action: "clone",
    args: {
        source: "$context.source",
        target: "$context.result",
        fields: ["code"]
    }
}

If you leave the "fields" property out it will clone the entire object.
If you define the "fields" it will create a new object that contains only the fields you defined.

assign step

const step = {
    type: "object",
    action: "assign",
    args: {
        source: "$context.source",
        target: "$context.result",
    }
};

Process intent

crs.intent.process

This intent allows for sub processes.
In other words, running a different process as a step in the current process.
This can go n levels deep.

const step = {
    type: "process",
    action: "sub_process_name", // property name on the process elementsSchema object that you want to execute.
    args: {
        elementsSchema: "schema_registry_key", // id property on the process elementsSchema object. see below
        parameters: {
            value: 10
        },
        target: "$context.result"
    }
}

Take special note on parameters.
You need a way to transfer values between processes.
Parameters is the way that is done. The values defined in the above parameters object will be passed to the sub process as its parameters.

A process defines it's required input using a property called "parameters_def".
parameters_def is also used to define what parameters are required and what default values are if the parameter is not provided.

Use the "target" args parameter to store the result of the sub process.

const process = {
    parameters_def: {
        value1: {type: "number", required: true},
        value2: {type: "number", required: true, default: 0}
    },
    steps: {
        ...
    }
}

"parameters_def" is just a definition and not accessed directly in the process.
Each process that has parameters can be accessed through the "parameters" property created at runtime.

const step = {
    type: "math",
    action: "add",
    args: {
        value1: "$process.parameters.value1",
        value2: "$process.parameters.value2",
        target: "$process.result"
    },
}

A process's "result" must be set on the "result" property of the process object as can be seen above.

An important part of running sub processes is the process elementsSchema registry.

crs.processSchemaRegistry

This object acts as a registry and aggregator of processes.
A elementsSchema is a JSON object that contains one or more processes.

export const processes = {
    id: "loop_sub",
    process1: {   // process called "process1"
        data: {}, // data object on the process for storing values
        steps: {} // steps of the process
    },
    process2: {   // process called "process2"
        data: {}, // data object on the process for storing values
        steps: {} // steps of the process
    }
}

Processes are object properties on the elementsSchema object.
Each elementsSchema object must have a unique id property. The id will be the name used to define what elementsSchema the process is on when executing a process step.

Dom Intent

This allows you to read and write to the dom.

set_attribute

step: {
    type: "dom",
    action: "set_attribute",
    args: {
        query: "#element1",
        attr: "data-value",
        value: 10
    }
}

get_attribute

get_attribute: {
    type: "dom",
    action: "get_attribute",
    args: {
        query: "#element",
        attr: "data-value",
        target: "$process.data.value"
    }
}

set_style

set_style: {
    type: "dom",
    action: "set_style",
    args: {
        query: "#element",
        style: "background",
        value: "#ff0090"
    }
}

get_style

step: {
    type: "dom",
    action: "get_style",
    args: {
        query: "#edtStyle",
        style: "background",
        target: "$binding.styleValue"
    }
}

add_class

step: {
    type: "dom",
    action: "add_class",
    args: {
        query: "#class-target",
        value: "bg_red"
    }
}
step: {
    type: "dom",
    action: "add_class",
    args: {
        query: "#class-target",
        value: ["bg_red", "fg_white"]
    }
}

remove_class

start: {
    type: "dom",
    action: "remove_class",
    args: {
        query: "#class-target",
        value: ["bg_red", "fg_white"]
    }
}

set_text

step: {
    type: "dom",
    action: "set_text",
    args: {
        query: "#element",
        value: "$process.data.value"
    }
}

get_text

step: {
    type: "dom",
    action: "get_text",
    args: {
        query: "#element",
        target: "$context.value"
    }
}

create_element

step: {
    type: "dom",
    action: "create_element",
    args: {
        id: "element1",
        parent: "#container",
        tagName: "div",
        textContent: "Element 1",
        styles: {
            width: "100%"
        },
        classes: ["class1", "class2"]
    }
}

Can also create composites

step: {
    type: "dom",
    action: "create_element",
    args: {
        id: "composite",
        parent: "#container",
        tagName: "div",
        children: [
            {
                id: "cbSelect",
                tagName: "input",
                attributes: {
                    "type": "checkbox",
                    "data-id": "1"
                }
            }
        ]
    }
}

remove_element

step: {
    type: "dom",
    action: "remove_element",
    args: {
        query: "#element"
    }
}

post_message

clone_for_movement

step: {
    type: "dom",
    action: "clone_for_movement",
    args: {
        query: "#clickClone", 
        parent: "#cloneTarget",
        position: {x: 300, y: 0}
    }
}

move_element

step: {
    type: "dom",
    action: "move_element",
    args: {
        query: "#item2",
        target: "#item5",
        position: "after" // "before" || "after"
    }
}

move_down

step: {
    type: "dom",
    action: "move_element_down",
    args: {
        query: "#item2"
    }
}

move_up

step: {
    type: "dom",
    action: "move_element_up",
    args: {
        query: "#item2"
    }
}

show_widget_dialog This step will create a html layer that consists out of two parts.

  1. background div to block input, thus modal.
  2. crs-widget component to contain UI.
step: {
    type: "dom",
    action: "show_widget_dialog",
    args: {
        id: "my-element",
        html: "$template.my_dialog",
        url: "/templates/current_process_ui.html"
    }
}

This uses the crs binding widgets and template manager features.
$template refers to the fact that the HTML is located on crsbinding template manager using the id "my_dialog". If the template has not yet been loaded, use the url as defined to load the template on the template manager and pass back the html.

The html and url properties work hand in hand on this step.

set_widget

step: {
    type: "dom",
    action: "set_widget",
    args: {
        query: "#my-widget"
        html: "$template.my_dialog",
        url: "/templates/current_process_ui.html"
    }
}

The crs-widget component is flexible where you can change the HTML and binding context at any time. This action allows you to do that.

  1. Define what html to show
  2. Define the object that you bind the UI too

In this case we are not creating a new component so we need to pass a selector query on what element to use.

clear_widget

step: {
    type: "dom",
    action: "clear_widget",
    args: {
        query: "#my-widget"
    }
}

This step clears the HTML on the defined crs-widget and unbinds the data.

show_form_dialog

show_dialog: {
    type: "dom",
    action: "show_form_dialog",
    args: {
        id: "input-form-ui",
        html: "$template.process-input-form",
        url: "/templates/input_form.html",
        error_store: "input_validation"
    }
}

This creates two layers.

  1. background to block input
  2. An ui based on the template passed.

There are a number of rules you need to follow.

  1. Your template must contain a form element that contains your inputs for validation reasons.
  2. Your input structure must follow this example.
<label>
    <div>&{labels.age}</div>
    <input value.bind="age" type="number" required min="20" max="60" style="width: 150px">
</label>

The first element is the with a text content. It must also contain an input or a control that follows standard dom validation api.

Here is an example template.

<div style="padding: 1rem; border-radius: 5px; background: #dadada; display: flex; flex-direction: column; justify-content: center; align-items: center">
    <form>
        <label>
            <div>&{labels.firstName}</div>
            <input value.bind="firstName" required style="width: 150px" autofocus>
        </label>

        <label>
            <div>&{labels.lastName}</div>
            <input value.bind="lastName" required style="width: 150px">
        </label>

        <label>
            <div>&{labels.age}</div>
            <input value.bind="age" type="number" required min="20" max="60" style="width: 150px">
        </label>
    </form>

    <div id="errors" class="errors-collection">
        <ul>
            <template for="error of input_validation">
                <li>${error.message}</li>
            </template>
        </ul>
    </div>

    <div>
        <button click.call="fail">&{buttons.cancel}</button>
        <button click.call="pass">&{buttons.ok}</button>
    </div>
</div>

Note that labels are using standard crsbinding translations expressions.

In the process step you will notice a property under args called "error_store".
The purpose of this property is to define where on the binding context you want to save your validation errors. On the template example you can see where the errors are being rendered. If you don't define a custom property for this the errors will be stored on a property called "errors"

The process will wait for this dialog to close before it continues. It is important that some action on the form calls either pass or fail.

On the step you can define a "pass_step" or "fail_step".
When you call pass the pass step will be executed.
When you call fail, the fail step will be executed.
Either way the dialog will close on it's own.

Executing the pass step will cause an automatic validation check.
If the validation fails, the dialog will not close.
For the dailog to close on the pass, it must successfully validate.

Open new tab

This feature allows you to add a new tab on a defined url.
There are two scenarios.

  1. static url
  2. url with parameters

Static example

google: {
    steps: {
        start: {
            type: "dom",
            action: "open_tab",

            args: {
                url: "http://www.google.com"
            }
        }
    }
},

Parameters example

parameters: {
    steps: {
        start: {
            type: "dom",
            action: "open_tab",

            args: {
                url: "#input/${id}?type='tasks'&typeId='${typeId}'", // http://localhost/#input/1001?type='tasks'&typeId='2000'
                parameters: {
                    id: 1000,
                    typeId: "$context.typeId"
                }
            }
        }
    }
}

The static url is simple enough so lets focus instead on the parameters instead.
Note the url has js string literal markers in the url.

  1. ${id}
  2. ${typeId}

This means, put the parameter with property "id" here and property "typeId" here.
The parameters property defines the properties and values to use.
These properties can be static values. The id property is a example of that.
The property can also use the same source expression as used in other features referencing the prefix syntax. In this case the $context.typeId indicating that we want to use the typeId value defined on the context as the value of ${typeId}

Strings

The string system provides features for working with strings.

  1. inflate
  2. to_array
  3. from_array

inflate

const step = {
    action: "string",
    args: {
        template: "Hello ${value}",
        parameters: {
            value: "World"
        },
        target: "$context.greeting"
    }
}

The url feature above uses this under the hood.
The rules around the parameters applies the same here.
Use the string literal to mark where the value must be placed and define the details in the parameters. The parameter property value being either a static value of based on a prefix.

to_array

let context = {
    value: "Hello There World"
}

const step = {
    type: "string",
    action: "to_array",
    args: {
        source: "$context.value",
        pattern: " ",
        target: "$context.result"
    }
}

results in

["Hello", "There", "World"]

from_array

let context = {
    value: ["Hello", "There", "Array"]
}

const step = {
    type: "string",
    action: "from_array",
    args: {
        source: "$context.value",
        separator: " ",
        target: "$context.result"
    }
}

results in

"Hello There Array"

System

copy_to_clipboard

const step = {
    type: "system",
    action: "copy_to_clipboard",
    args: {
        source: "$context.value",
    }
}

sleep

const step = {
    type: "system",
    action: "sleep",
    args: {
        duration: 1000,
    },
    next_step: "step2"
}

Internally this uses setInterval for the duration specified.

pause

const step = {
    type: "system",
    action: "pause",
    next_step: "close"
}

Pause is for waiting on UI. This means you must provide a binding context to the process that uses pause. During pause a resume function is added to the binding context. See resume for details

resume Normally you will not use resume directly as part of a process because it is waiting at pause. You use pause while waiting for UI input to be done. To resume you need to bind against the resume function.

<button click.call="resume">Close</button>
<button click.call="resume('log')">Log and Close</button>

In the second example we add an alternative next step. In the examples case, "log". This means you can change the flow of the process depending on the UI.

Local Storage

Open Open indexDB database.

const step = {
    type: "db",
    action: "open",
    args: {
        db: "test_db",
        version: 1,
        tables: {
            people: {
                parameters: {
                    keyPath: "id",
                    autoIncrement: true
                },
                indexes: {
                    id: { unique: true }
                }
            }
        }
    }
}

The table section is just objects where the property is the name of the table.
The parameters section contains standard indexDB properties

delete

const step = {
    type: "db",
    action: "delete",
    args: {
        db: "test_db"
    }
}

set_record Save a new record or update an existing one if the keys match.

const step = {
    type: "db",
    action: "set_record",
    args: {
        db: "test_db",
        table: "people",
        record: {
            firstName : "John",
            lastName : "Smith"
        }
    }
}

The record property can use the usual context prefixes. e.g. "$context.record"

add_records

const step = {
    type: "db",
    action: "add_records",
    args: {
        db: "test_db",
        table: "people",
        records: "$context.records" // can also use an array of objects
    }
});

delete_record

const step = {
    type: "db",
    action: "add_records",
    args: {
        db: "test_db",
        table: "people",
        key: 1  // key value on key defined during creation of table.
    }
};

clear_table Remove all the content from a table

const step = {
    type: "db",
    action: "clear_table",
    args: {
        db: "test_db",
        table: "people"
    }
};

get_record

const step = {
    type: "db",
    action: "clear_table",
    args: {
        db: "test_db",
        table: "people",
        key: 1
    }
};

get_all Get all the records for a given table

const step = {
    type: "db",
    action: "clear_table",
    args: {
        db: "test_db",
        table: "people"
    }
};

Local Storage

set_value

const step = {
    type: "storage",
    action: "set_value",
    args: {
        key: "name",
        value: "John Doe"
    }
};

Value may not be an object.

get_value

const step = {
    type: "storage",
    action: "set_value",
    args: {
        key: "name"
    }
};

set_object

const step = {
    type: "storage",
    action: "set_value",
    args: {
        key: "name"
    }
};

This uses json in the background so must be something that can be pared using JSON.

get_object

const step = {
    type: "storage",
    action: "get_object",
    args: {
        key: "person"
    }
};

This uses json in the background so must be something that can be pared using JSON.

Random

SchemaRegistry

crs.processSchemaRegistry

This only has two public functions:

  1. add
  2. remove

processSchemaRegistry stores process objects on a private object called _schemas.
The id of the elementsSchema defines the property name on _schemas.

If you want to execute a process on the registry, you need to use event aggregation.

const step = {
    action: "process1",
    args: {
        elementsSchema: "loop_sub"
    }  
}

await crsbinding.events.emitter.emit("run-process", {
    step: step,             // define what elementsSchema and process to run
    context: context,       // what object to use as $context
    process: process,       // what object to use as $process
    item: item,             // what object to use as $item
    parameters: parameters  // parameters to use in the process you are calling.
});

Hooks

There are several hooks that you need to take note of.

  1. fetch - used to fetch profiles from remote locations when it is not registered on the processSchemaRegistry
  2. onError - used to handle error messages from the process.
crs.process.fetch = (step) => { return ... fetch code };
crs.process.onError = (error) => { console.error(error) };

prefixes

When you run a process you can pass in an prefixes object as one of the parameters.
prefixes help you define shortcuts to use in your getValue.

prefix example

{
  "$variables": "$context.elementsSchema.variables"
}

In this example, if you reference the value "$variables.property" it will look for the property value on the path "$context.elementsSchema.variables.property"

As you can see it provides you with a convenient way to shorten some expressions.
The value does however not have to be a path.
If the prefix has a object attached to it, the getValue operation will instead return you that object.

Internally there the following prefixes exist.

  1. "$text": refers to "$process.text" (one of the objects you sent in during the run process, else undefined)
  2. "$data": refers to "$process.data"
  3. "$parameters": refers to "$process.parameters"
  4. "$bId": refers to "$process.parameters.bId"

You can also define the prefixes in the process for process specific things.

prefixes: {
    "$currentStep": "$process.data.currentStep",
    "$currentClone": "$process.data.currentClone"
}

text

Text is used to pass translation data to the process. Inside the process you reference the value as "$text.property". The translation is an object literal with properties.

await crs.process.run(context, process, null, {property: "Hello World"});
0.0.168

2 years ago

0.0.165

2 years ago

0.0.173

2 years ago

0.0.172

2 years ago

0.0.159

2 years ago

0.0.158

2 years ago

0.0.153

2 years ago

0.0.152

2 years ago

0.0.151

2 years ago

0.0.150

2 years ago

0.0.157

2 years ago

0.0.156

2 years ago

0.0.155

2 years ago

0.0.164

2 years ago

0.0.162

2 years ago

0.0.161

2 years ago

0.0.149

2 years ago

0.0.147

2 years ago

0.0.146

2 years ago

0.0.138

2 years ago

0.0.137

2 years ago

0.0.136

2 years ago

0.0.142

2 years ago

0.0.141

2 years ago

0.0.140

2 years ago

0.0.145

2 years ago

0.0.144

2 years ago

0.0.128

2 years ago

0.0.127

2 years ago

0.0.126

2 years ago

0.0.125

2 years ago

0.0.129

2 years ago

0.0.124

2 years ago

0.0.122

2 years ago

0.0.131

2 years ago

0.0.130

2 years ago

0.0.134

2 years ago

0.0.133

2 years ago

0.0.132

2 years ago

0.0.120

2 years ago

0.0.121

2 years ago

0.0.117

2 years ago

0.0.84

2 years ago

0.0.116

2 years ago

0.0.85

2 years ago

0.0.41

2 years ago

0.0.115

2 years ago

0.0.86

2 years ago

0.0.114

2 years ago

0.0.88

2 years ago

0.0.44

2 years ago

0.0.89

2 years ago

0.0.119

2 years ago

0.0.113

2 years ago

0.0.80

2 years ago

0.0.112

2 years ago

0.0.82

2 years ago

0.0.83

2 years ago

0.0.37

2 years ago

0.0.38

2 years ago

0.0.39

2 years ago

0.0.30

2 years ago

0.0.75

2 years ago

0.0.31

2 years ago

0.0.76

2 years ago

0.0.32

2 years ago

0.0.34

2 years ago

0.0.35

2 years ago

0.0.36

2 years ago

0.0.70

2 years ago

0.0.71

2 years ago

0.0.72

2 years ago

0.0.29

2 years ago

0.0.62

2 years ago

0.0.63

2 years ago

0.0.64

2 years ago

0.0.65

2 years ago

0.0.66

2 years ago

0.0.67

2 years ago

0.0.68

2 years ago

0.0.69

2 years ago

0.0.60

2 years ago

0.0.59

2 years ago

0.0.106

2 years ago

0.0.105

2 years ago

0.0.96

2 years ago

0.0.52

2 years ago

0.0.104

2 years ago

0.0.97

2 years ago

0.0.53

2 years ago

0.0.103

2 years ago

0.0.98

2 years ago

0.0.54

2 years ago

0.0.99

2 years ago

0.0.55

2 years ago

0.0.109

2 years ago

0.0.56

2 years ago

0.0.108

2 years ago

0.0.57

2 years ago

0.0.107

2 years ago

0.0.58

2 years ago

0.0.90

2 years ago

0.0.102

2 years ago

0.0.91

2 years ago

0.0.101

2 years ago

0.0.92

2 years ago

0.0.100

2 years ago

0.0.93

2 years ago

0.0.94

2 years ago

0.0.20

2 years ago

0.0.22

2 years ago

0.0.23

2 years ago

0.0.24

2 years ago

0.0.25

2 years ago

0.0.26

2 years ago

0.0.19

2 years ago

0.0.14

3 years ago

0.0.12

3 years ago

0.0.11

3 years ago

0.0.10

3 years ago