[jsscripting] Library and Doc updates (#11800)
* [jsscripting] Library and Doc updates This updates the documentation, bumps the NPM version library, and implements conversion of JS date types (js-joda) to Java types Signed-off-by: Dan Cunningham <dan@digitaldan.com>
This commit is contained in:
parent
fcd6ed6e57
commit
fe271e3c4a
@ -1,132 +1,319 @@
|
|||||||
# JavaScript Scripting
|
# JavaScript Scripting
|
||||||
|
|
||||||
This add-on provides support for JavaScript (ECMAScript 2021+) that can be used as a scripting language within automation rules.
|
This add-on provides support for JavaScript (ECMAScript 2021+) that can be used as a scripting language within automation rules.
|
||||||
JavaScript scripts provide access to almost all the functionality in an openHAB runtime environment.
|
|
||||||
|
|
||||||
- [Creating JavaScript Scripts](#creating-javascript-scripts)
|
Also included is [openhab-js](https://github.com/openhab/openhab-js/), a fairly high-level ES6 library to support automation in openHAB. It provides convenient access
|
||||||
- [Logging](#logging)
|
to common openHAB functionality within rules including items, things, actions, logging and more.
|
||||||
- [Core Actions](#core-actions)
|
|
||||||
- [itemRegistry](#itemregistry)
|
|
||||||
- [Event Bus Actions](#event-bus-actions)
|
|
||||||
- [Exec Actions](#exec-actions)
|
|
||||||
- [HTTP Actions](#http-actions)
|
|
||||||
- [Timers](#timers)
|
|
||||||
- [Scripts Actions](#scripts-actions)
|
|
||||||
- [Cloud Notification Actions](#cloud-notification-actions)
|
|
||||||
- [Persistence Extensions](#persistence-extensions)
|
|
||||||
- [Ephemeris Actions](#ephemeris-actions)
|
|
||||||
- [Types and Units](#types-and-units)
|
|
||||||
|
|
||||||
## Creating JavaScript Scripts
|
- [Configuration](#configuration)
|
||||||
|
- [UI Based Rules](#ui-based-rules)
|
||||||
|
- [Scripting Basics](#scripting-basics)
|
||||||
|
- [require](#require)
|
||||||
|
- [console](#console)
|
||||||
|
- [setInterval](#setinterval)
|
||||||
|
- [setTimeout](#settimeout)
|
||||||
|
- [scriptLoaded](#scriptloaded)
|
||||||
|
- [scriptUnLoaded](#scriptunloaded)
|
||||||
|
- [Paths](#paths)
|
||||||
|
- [Standard Library](#standard-library)
|
||||||
|
- [items](#items)
|
||||||
|
- [actions](#actions)
|
||||||
|
- [cache](#cache)
|
||||||
|
- [log](#log)
|
||||||
|
- [time](#time)
|
||||||
|
- [File Based Rules](#file-based-rules)
|
||||||
|
- [JSRule](#jsrule)
|
||||||
|
- [Rule Builder](#rule-builder)
|
||||||
|
|
||||||
When this add-on is installed, JavaScript script actions will be run by this add-on and allow ECMAScript 2021+ features.
|
|
||||||
|
|
||||||
Alternatively, you can create scripts in the `automation/jsr223` configuration directory.
|
## Configuration
|
||||||
If you create an empty file called `test.js`, you will see a log line with information similar to:
|
|
||||||
|
This add-on includes by default the [openhab-js](https://github.com/openhab/openhab-js/) NPM library and exports it's namespaces onto the global namespace. This allows the use of `items`, `actions`, `cache` and other objects without the need to explicitly import using `require()`. This functionality can be disabled for users who prefer to manage their own imports via the add-on configuration options.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## UI Based Rules
|
||||||
|
|
||||||
|
The quickest way to add rules is through the openHAB Web UI.
|
||||||
|
|
||||||
|
Advanced users, or users migrating scripts from existing systems may want to use [File Based Rules](#file-based-rules) for managing rules using files in the user configuration directory.
|
||||||
|
|
||||||
|
### Adding Triggers
|
||||||
|
|
||||||
|
Using the openHAB UI, first create a new rule and set a trigger condition
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Adding Actions
|
||||||
|
|
||||||
|
Select "Add Action" and then select "ECMAScript 262 Edition 11". Its important this is "Edition 11" or higher, earlier versions will not work. This will bring up a empty script editor where you can enter your javascript.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
You can now write rules using standard ES6 Javascript along with the included openHAB [standard library](#standard-library).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
For example, turning a light on:
|
||||||
|
```javascript
|
||||||
|
items.getItem("KitchenLight").sendCommand("ON");
|
||||||
|
console.log("Kitchen Light State", items.getItem("KitchenLight").state);
|
||||||
|
```
|
||||||
|
|
||||||
|
Sending a notification
|
||||||
|
```javascript
|
||||||
|
actions.NotificationAction.sendNotification("romeo@montague.org", "Balcony door is open");
|
||||||
|
```
|
||||||
|
|
||||||
|
Querying the status of a thing
|
||||||
|
```javascript
|
||||||
|
const thingStatusInfo = actions.Things.getThingStatusInfo("zwave:serial_zstick:512");
|
||||||
|
console.log("Thing status",thingStatusInfo.getStatus());
|
||||||
|
```
|
||||||
|
|
||||||
|
See [openhab-js](https://openhab.github.io/openhab-js) for a complete list of functionality
|
||||||
|
|
||||||
|
## Scripting Basics
|
||||||
|
|
||||||
|
The openHAB JSScripting runtime attempts to provide a familiar environment to Javascript developers.
|
||||||
|
|
||||||
|
### Require
|
||||||
|
|
||||||
|
Scripts may include standard NPM based libraries by using CommonJS require. The library search path will look in `automation/js/node_modules` in the user configuration directory.
|
||||||
|
|
||||||
|
### Console
|
||||||
|
|
||||||
|
The JSScripting binding supports the standard `console` object for logging.
|
||||||
|
Script debug logging is enabled by default at the `TRACE` level, but can be configured using the [console logging]({{base}}/administration/logging.html) commands.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
... [INFO ] [.a.m.s.r.i.l.ScriptFileWatcher:150 ] - Loading script 'test.js'
|
log:set DEBUG org.openhab.automation.script
|
||||||
```
|
```
|
||||||
|
|
||||||
To enable debug logging, use the [console logging]({{base}}/administration/logging.html) commands to enable debug logging for the automation functionality:
|
Supported logging functions include:
|
||||||
|
- `console.log(obj1 [, obj2, ..., objN])`
|
||||||
|
- `console.info(obj1 [, obj2, ..., objN])`
|
||||||
|
- `console.warn(obj1 [, obj2, ..., objN])`
|
||||||
|
- `console.error(obj1 [, obj2, ..., objN])`
|
||||||
|
- `console.debug(obj1 [, obj2, ..., objN])`
|
||||||
|
- `console.trace(obj1 [, obj2, ..., objN])`
|
||||||
|
|
||||||
```text
|
where `obj1 ... objN` is a list of JavaScript objects to output. The string representations of each of these objects are appended together in the order listed and output.
|
||||||
log:set DEBUG org.openhab.core.automation
|
|
||||||
|
see https://developer.mozilla.org/en-US/docs/Web/API/console for more information about console logging.
|
||||||
|
|
||||||
|
### setTimeout
|
||||||
|
|
||||||
|
The global setTimeout() method sets a timer which executes a function or specified piece of code once the timer expires.
|
||||||
|
```javascript
|
||||||
|
var timeoutID = setTimeout(function[, delay, arg1, arg2, ...]);
|
||||||
|
var timeoutID = setTimeout(function[, delay]);
|
||||||
```
|
```
|
||||||
|
|
||||||
For more information on the available APIs in scripts see the [JSR223 Scripting]({{base}}/configuration/jsr223.html) documentation.
|
The global `clearTimeout()` method cancels a timeout previously established by calling `setTimeout()`.
|
||||||
|
|
||||||
The following examples show how to access common openHAB functionalities.
|
see https://developer.mozilla.org/en-US/docs/Web/API/setTimeout for more information about setTimeout.
|
||||||
|
|
||||||
## Logging
|
### setInterval
|
||||||
|
|
||||||
As a simple example, the following script logs "Hello, World!".
|
The setInterval() method repeatedly calls a function or executes a code snippet, with a fixed time delay between each call.
|
||||||
Note that `console.log` will usually not work since the output has no terminal to display the text.
|
|
||||||
__Please note:__ Support for `console.log` will likely be added together with a logging API in the [helper library](https://github.com/openhab/openhab-js).
|
|
||||||
The openHAB server uses the [SLF4J](https://www.slf4j.org/) library for logging.
|
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
let logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + this.ruleUID);
|
var intervalID = setInterval(func, [delay, arg1, arg2, ...]);
|
||||||
logger.info('Hello world!');
|
var intervalID = setInterval(function[, delay]);
|
||||||
logger.warn('Successfully logged warning.');
|
|
||||||
logger.error('Successfully logged error.');
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The script uses the [LoggerFactory](https://www.slf4j.org/apidocs/org/slf4j/Logger.html) to obtain a named logger and then logs a message like:
|
The global `clearInterval()` method cancels a timed, repeating action which was previously established by a call to `setInterval()`.
|
||||||
|
|
||||||
```text
|
NOTE: Timers will not be canceled if a script is deleted or modified, it is up to the user to manage timers. See using the [cache](#cache) namespace as well as [ScriptLoaded](#scriptloaded) and [ScriptUnLoaded](#scriptunloaded) for a convenient way of managing persisted objects, such as timers between reloads or deletions of scripts.
|
||||||
... [INFO ] [org.openhab.rule.<ruleId> ] - Hello world!
|
|
||||||
... [WARN ] [org.openhab.rule.<ruleId> ] - Successfully logged warning.
|
|
||||||
... [ERROR] [org.openhab.rule.<ruleId> ] - Successfully logged error.
|
|
||||||
```
|
|
||||||
|
|
||||||
## Core Actions
|
see https://developer.mozilla.org/en-US/docs/Web/API/setInterval for more information about setInterval.
|
||||||
|
|
||||||
The openHAB services, which are pre-included in the integrated JavaScript engine, must explicitely be imported.
|
### ScriptLoaded
|
||||||
|
|
||||||
__Please note:__ The [helper library](https://github.com/openhab/openhab-js) is on the way and will become the preferred API to work with openHAB.
|
For file based scripts, this function will be called if found when the script is loaded.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
let openhab = require('@runtime');
|
scriptLoaded = function () {
|
||||||
|
console.log("script loaded");
|
||||||
|
loadedDate = Date.now();
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### itemRegistry
|
### ScriptUnLoaded
|
||||||
|
|
||||||
|
For file based scripts, this function will be called if found when the script is unloaded.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
let state = openhab.itemRegistry.getItem(itemName).getState();
|
scriptUnloaded = function () {
|
||||||
|
console.log("script unloaded");
|
||||||
|
//clean up rouge timers
|
||||||
|
clearInterval(timer);
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
You can use `toString()` to convert an item's state to string or `toBigDecimal()` to convert to number.
|
### Paths
|
||||||
|
|
||||||
### Event Bus Actions
|
For [file based rules](#file-based-rules), scripts will be loaded from `automation/js` in the user configuration directory.
|
||||||
|
|
||||||
|
NPM libraries will be loaded from `automation/js/node_modules` in the user configuration directory.
|
||||||
|
|
||||||
|
## Standard Library
|
||||||
|
|
||||||
|
Full documentation for the openHAB JavaScript library can be found at [openhab-js](https://openhab.github.io/openhab-js)
|
||||||
|
|
||||||
|
### Items
|
||||||
|
|
||||||
|
The items namespace allows interactions with openHAB items.
|
||||||
|
|
||||||
|
See [openhab-js : items ](https://openhab.github.io/openhab-js/items.html) for full API documentation
|
||||||
|
|
||||||
|
* items : <code>object</code>
|
||||||
|
* .getItem(name, nullIfMissing) ⇒ <code>Item</code>
|
||||||
|
* .getItemsByTag(...tagNames) ⇒ <code>Array.<Item></code>
|
||||||
|
* .createItem(itemName, [itemType], [category], [groups], [label], [tags], [giBaseType], [groupFunction], [itemMetadata])
|
||||||
|
* .addItem(itemName, [itemType], [category], [groups], [label], [tags], [giBaseType], [groupFunction])
|
||||||
|
* .removeItem(itemOrItemName) ⇒ <code>Boolean</code>
|
||||||
|
* .replaceItem(itemName, [itemType], [category], [groups], [label], [tags], [giBaseType], [groupFunction])
|
||||||
|
* .safeItemName(s) ⇒ <code>String</code>
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
openhab.events.sendCommand(itemName, command);
|
const item = items.getItem("KitchenLight");
|
||||||
openhab.events.postUpdate(itemName, state);
|
console.log("Kitchen Light State", item.state);
|
||||||
```
|
```
|
||||||
|
|
||||||
`command` and `state` can be a string `'string'` or a number depending on the item.
|
Calling `getItem(...)` returns an `Item` object with the following properties:
|
||||||
|
|
||||||
### Exec Actions
|
* Item : <code>object</code>
|
||||||
|
* .type ⇒ <code>String</code>
|
||||||
|
* .name ⇒ <code>String</code>
|
||||||
|
* .label ⇒ <code>String</code>
|
||||||
|
* .history ⇒ <code>ItemHistory</code>
|
||||||
|
* .state ⇒ <code>String</code>
|
||||||
|
* .rawState ⇒ <code>HostState</code>
|
||||||
|
* .members ⇒ <code>Array.<Item></code>
|
||||||
|
* .descendents ⇒ <code>Array.<Item></code>
|
||||||
|
* .isUninitialized ⇒ <code>Boolean</code>
|
||||||
|
* .tags ⇒ <code>Array.<String></code>
|
||||||
|
* .getMetadataValue(namespace) ⇒ <code>String</code>
|
||||||
|
* .updateMetadataValue(namespace, value) ⇒ <code>String</code>
|
||||||
|
* .upsertMetadataValue(namespace, value) ⇒ <code>Boolean</code>
|
||||||
|
* .updateMetadataValues(namespaceToValues)
|
||||||
|
* .sendCommand(value)
|
||||||
|
* .sendCommandIfDifferent(value) ⇒ <code>Boolean</code>
|
||||||
|
* .postUpdate(value)
|
||||||
|
* .addGroups(...groupNamesOrItems)
|
||||||
|
* .removeGroups(...groupNamesOrItems)
|
||||||
|
* .addTags(...tagNames)
|
||||||
|
* .removeTags(...tagNames)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const item = items.getItem("KitchenLight");
|
||||||
|
//send a ON command
|
||||||
|
item.sendCommand("ON");
|
||||||
|
//Post an update
|
||||||
|
item.postUpdate("OFF");
|
||||||
|
//Get state
|
||||||
|
console.log("KitchenLight state", item.state)
|
||||||
|
```
|
||||||
|
|
||||||
|
calling `item.history...` returns a ItemHistory object with the following functions:
|
||||||
|
|
||||||
|
Note `serviceId` is optional, if omitted, the default persistance service will be used.
|
||||||
|
|
||||||
|
* ItemHistory : <code>object</code>
|
||||||
|
* .averageSince(timestamp, serviceId) ⇒ <code>Number</code>
|
||||||
|
* .changedSince(timestamp, serviceId) ⇒ <code>Number</code>
|
||||||
|
* .deltaSince(timestamp, serviceId) ⇒ <code>Number</code>
|
||||||
|
* .deviationSince(timestamp, serviceId) ⇒ <code>Number</code>
|
||||||
|
* .evolutionRate(timestamp, serviceId) ⇒ <code>Number</code>
|
||||||
|
* .historicState(timestamp, serviceId) ⇒ <code>state</code>
|
||||||
|
* .lastUpdate(serviceId) ⇒ <code>Date</code>
|
||||||
|
* .latestState(serviceId) ⇒ <code>state</code>
|
||||||
|
* .maximumSince(timestamp,serviceId) ⇒ <code>state</code>
|
||||||
|
* .minimumSince(timestamp,serviceId) ⇒ <code>state</code>
|
||||||
|
* .persist(serviceId)
|
||||||
|
* .previousState(skipEqual,serviceId) ⇒ <code>state</code>
|
||||||
|
* .sumSince(timestamp, serviceId) ⇒ <code>Number</code>
|
||||||
|
* .updatedSince(timestamp, serviceId) ⇒ <code>Boolean</code>
|
||||||
|
* .varianceSince(timestamp,serviceId) ⇒ <code>state</code>
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var yesterday = new Date(new Date().getTime() - (24 * 60 * 60 * 1000));
|
||||||
|
var item = items.getItem("KitchenDimmer");
|
||||||
|
console.log("KitchenDimmer averageSince", item.history.averageSince(yesterday));
|
||||||
|
```
|
||||||
|
|
||||||
|
### Actions
|
||||||
|
|
||||||
|
The actions namespace allows interactions with openHAB actions. The following are a list of standard actions.
|
||||||
|
|
||||||
|
Additional actions provided by user installed addons can be accessed using their common name on the actions name space
|
||||||
|
(example: `actions.Pushsafer.pushsafer(...)`)
|
||||||
|
|
||||||
|
See [openhab-js : actions ](https://openhab.github.io/openhab-js/actions.html) for full API documentation and additional actions.
|
||||||
|
|
||||||
|
#### Audio Actions
|
||||||
|
|
||||||
|
See [openhab-js : actions.Audio ](https://openhab.github.io/openhab-js/actions.html#.Audio) for complete documentation
|
||||||
|
|
||||||
|
### BusEvent
|
||||||
|
|
||||||
|
See [openhab-js : actions.BusEvent ](https://openhab.github.io/openhab-js/actions.html#.BusEvent) for complete documentation
|
||||||
|
|
||||||
|
## Ephemeris Actions
|
||||||
|
|
||||||
|
See [openhab-js : actions.Ephemeris ](https://openhab.github.io/openhab-js/actions.html#.Ephemeris) for complete documentation
|
||||||
|
|
||||||
|
Ephemeris is a way to determine what type of day today or a number of days before or after today is. For example, a way to determine if today is a weekend, a bank holiday, someone’s birthday, trash day, etc.
|
||||||
|
|
||||||
|
Additional information can be found on the [Ephemeris Actions Docs](https://www.openhab.org/docs/configuration/actions.html#ephemeris) as well as the [Ephemeris JavaDoc](https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/ephemeris).
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Example
|
||||||
|
let weekend = actions.Ephemeris.isWeekend();
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Exec Actions
|
||||||
|
|
||||||
|
See [openhab-js : actions.Exec ](https://openhab.github.io/openhab-js/actions.html#.Exec) for complete documentation
|
||||||
|
|
||||||
Execute a command line.
|
Execute a command line.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
openhab.Exec = Java.type('org.openhab.core.model.script.actions.Exec');
|
|
||||||
let Duration = Java.type('java.time.Duration');
|
|
||||||
|
|
||||||
// Execute command line.
|
// Execute command line.
|
||||||
openhab.Exec.executeCommandLine('echo', 'Hello World!');
|
actions.Exec.executeCommandLine('echo', 'Hello World!');
|
||||||
|
|
||||||
// Execute command line with timeout.
|
// Execute command line with timeout.
|
||||||
openhab.Exec.executeCommandLine(Duration.ofSeconds(20), 'echo', 'Hello World!');
|
let Duration = Java.type('java.time.Duration');
|
||||||
|
actions.Exec.executeCommandLine(Duration.ofSeconds(20), 'echo', 'Hello World!');
|
||||||
|
|
||||||
// Get response from command line.
|
// Get response from command line.
|
||||||
let response = openhab.Exec.executeCommandLine('echo', 'Hello World!');
|
let response = actions.Exec.executeCommandLine('echo', 'Hello World!');
|
||||||
|
|
||||||
// Get response from command line with timeout.
|
// Get response from command line with timeout.
|
||||||
response = openhab.Exec.executeCommandLine(Duration.ofSeconds(20), 'echo', 'Hello World!');
|
response = actions.Exec.executeCommandLine(Duration.ofSeconds(20), 'echo', 'Hello World!');
|
||||||
```
|
```
|
||||||
|
|
||||||
### HTTP Actions
|
### HTTP Actions
|
||||||
|
|
||||||
For available actions have a look at the [HTTP Actions Docs](https://www.openhab.org/docs/configuration/actions.html#http-actions).
|
See [openhab-js : actions.HTTP ](https://openhab.github.io/openhab-js/actions.html#.HTTP) for complete documentation
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
openhab.HTTP = Java.type('org.openhab.core.model.script.actions.HTTP');
|
|
||||||
|
|
||||||
// Example GET Request
|
// Example GET Request
|
||||||
var response = openhab.HTTP.sendHttpGetRequest('<url>');
|
var response = actions.HTTP.sendHttpGetRequest('<url>');
|
||||||
```
|
```
|
||||||
|
|
||||||
Replace `<url>` with the request url.
|
Replace `<url>` with the request url.
|
||||||
|
|
||||||
### Timers
|
### ScriptExecution Actions
|
||||||
|
|
||||||
|
See [openhab-js : actions.ScriptExecution ](https://openhab.github.io/openhab-js/actions.html#.ScriptExecution) for complete documentation
|
||||||
|
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
let ZonedDateTime = Java.type('java.time.ZonedDateTime');
|
let now = time.ZonedDateTime.now();
|
||||||
let now = ZonedDateTime.now();
|
|
||||||
openhab.ScriptExecution = Java.type('org.openhab.core.model.script.actions.ScriptExecution');
|
|
||||||
|
|
||||||
// Function to run when the timer goes off.
|
// Function to run when the timer goes off.
|
||||||
function timerOver () {
|
function timerOver () {
|
||||||
@ -134,7 +321,7 @@ function timerOver () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the Timer.
|
// Create the Timer.
|
||||||
this.myTimer = openhab.ScriptExecution.createTimer(now.plusSeconds(10), timerOver);
|
this.myTimer = actions.ScriptExecution.createTimer(now.plusSeconds(10), timerOver);
|
||||||
|
|
||||||
// Cancel the timer.
|
// Cancel the timer.
|
||||||
this.myTimer.cancel();
|
this.myTimer.cancel();
|
||||||
@ -145,106 +332,279 @@ let active = this.myTimer.isActive();
|
|||||||
// Reschedule the timer.
|
// Reschedule the timer.
|
||||||
this.myTimer.reschedule(now.plusSeconds(5));
|
this.myTimer.reschedule(now.plusSeconds(5));
|
||||||
```
|
```
|
||||||
|
### Semantics Actions
|
||||||
|
|
||||||
### Scripts Actions
|
See [openhab-js : actions.Semantics ](https://openhab.github.io/openhab-js/actions.html#.Semantics) for complete documentation
|
||||||
|
|
||||||
Call scripts created in the UI (Settings -> Scripts) with or without parameters.
|
### Things Actions
|
||||||
|
|
||||||
```javascript
|
See [openhab-js : actions.Things ](https://openhab.github.io/openhab-js/actions.html#.Things) for complete documentation
|
||||||
openhab.scriptExtension = Java.type('org.openhab.core.automation.module.script.ScriptExtensionProvider');
|
|
||||||
let bundleContext = Java.type('org.osgi.framework.FrameworkUtil').getBundle(openhab.scriptExtension.class).getBundleContext();
|
|
||||||
openhab.RuleManager = bundleContext.getService(bundleContext.getServiceReference('org.openhab.core.automation.RuleManager'));
|
|
||||||
|
|
||||||
// Simple call.
|
### Voice Actions
|
||||||
openhab.RuleManager.runNow('<scriptToRun>');
|
|
||||||
|
|
||||||
// Advanced call with arguments.
|
See [openhab-js : actions.Voice ](https://openhab.github.io/openhab-js/actions.html#.Voice) for complete documentation
|
||||||
let map = new java.util.HashMap();
|
|
||||||
map.put('identifier1', 'value1');
|
|
||||||
map.put('identifier2', 'value2');
|
|
||||||
// Second argument is whether to consider the conditions, third is a Map<String, Object> (a way to pass data).
|
|
||||||
openhab.RuleManager.runNow('<scriptToRun>', true, map);
|
|
||||||
```
|
|
||||||
|
|
||||||
Replace `<scriptToRun>` with your script's (unique-)id.
|
### Cloud Notification Actions
|
||||||
|
|
||||||
## Cloud Notification Actions
|
(optional action if openhab-cloud is installed)
|
||||||
|
|
||||||
Notification actions may be placed in Rules to send alerts to mobile devices registered with an [openHAB Cloud instance](https://github.com/openhab/openhab-cloud) such as [myopenHAB.org](https://myopenhab.org/).
|
Notification actions may be placed in Rules to send alerts to mobile devices registered with an [openHAB Cloud instance](https://github.com/openhab/openhab-cloud) such as [myopenHAB.org](https://myopenhab.org/).
|
||||||
|
|
||||||
For available actions have a look at the [Cloud Notification Actions Docs](https://www.openhab.org/docs/configuration/actions.html#cloud-notification-actions).
|
For available actions have a look at the [Cloud Notification Actions Docs](https://www.openhab.org/docs/configuration/actions.html#cloud-notification-actions).
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
openhab.NotificationAction = Java.type('org.openhab.io.openhabcloud.NotificationAction')
|
|
||||||
|
|
||||||
// Example
|
// Example
|
||||||
openhab.NotificationAction.sendNotification('<email>', '<message>'); // to a single myopenHAB user identified by e-mail
|
actions.NotificationAction.sendNotification('<email>', '<message>'); // to a single myopenHAB user identified by e-mail
|
||||||
openhab.NotificationAction.sendBroadcastNotification('<message>'); // to all myopenHAB users
|
actions.NotificationAction.sendBroadcastNotification('<message>'); // to all myopenHAB users
|
||||||
```
|
```
|
||||||
|
|
||||||
Replace `<email>` with the e-mail address of the user.
|
Replace `<email>` with the e-mail address of the user.
|
||||||
Replace `<message>` with the notification text.
|
Replace `<message>` with the notification text.
|
||||||
|
|
||||||
## Persistence Extensions
|
### Cache
|
||||||
|
|
||||||
For available commands have a look at [Persistence Extensions in Scripts ans Rules](https://www.openhab.org/docs/configuration/persistence.html#persistence-extensions-in-scripts-and-rules).
|
The cache namespace provides a default cache that can be use to set and retrieve objects that will be persisted between reloads of scripts.
|
||||||
|
|
||||||
For deeper information have a look at the [Persistence Extensions JavaDoc](https://www.openhab.org/javadoc/latest/org/openhab/core/persistence/extensions/persistenceextensions).
|
See [openhab-js : cache ](https://openhab.github.io/openhab-js/cache.html) for full API documentation
|
||||||
|
|
||||||
```javascript
|
* cache : <code>object</code>
|
||||||
openhab.PersistenceExtensions = Java.type('org.openhab.core.persistence.extensions.PersistenceExtensions');
|
* .get(key, defaultSupplier) ⇒ <code>Object | null</code>
|
||||||
let ZonedDateTime = Java.type('java.time.ZonedDateTime');
|
* .put(key, value) ⇒ <code>Previous Object | null</code>
|
||||||
let now = ZonedDateTime.now();
|
* .remove(key) ⇒ <code>Previous Object | null</code>
|
||||||
|
|
||||||
// Example
|
The `defaultSupplier` provided function will return a default value if a specified key is not already associated with a value
|
||||||
var avg = openhab.PersistenceExtensions.averageSince(itemRegistry.getItem('<item>'), now.minusMinutes(5), "influxdb");
|
|
||||||
|
**Example** *(Get a previously set value with a default value (times = 0))*
|
||||||
|
```js
|
||||||
|
let counter = cache.get("counter", () => ({ "times": 0 }));
|
||||||
|
console.log("Count",counter.times++);
|
||||||
```
|
```
|
||||||
|
|
||||||
Replace `<persistence>` with the persistence service to use.
|
**Example** *(Get a previously set object)*
|
||||||
Replace `<item>` with the itemname.
|
```js
|
||||||
|
let counter = cache.get("counter");
|
||||||
|
if(counter == null){
|
||||||
|
counter = {times: 0};
|
||||||
|
cache.put("counter", counter);
|
||||||
|
}
|
||||||
|
console.log("Count",counter.times++);
|
||||||
|
```
|
||||||
|
### Log
|
||||||
|
|
||||||
## Ephemeris Actions
|
By default the JS Scripting binding supports console logging like `console.log()` and `console.debug()` to the openHAB
|
||||||
|
default log. Additionally scripts may create their own native openHAB logs using the log namespace
|
||||||
Ephemeris is a way to determine what type of day today or a number of days before or after today is. For example, a way to determine if today is a weekend, a bank holiday, someone’s birthday, trash day, etc.
|
|
||||||
|
|
||||||
For available actions, have a look at the [Ephemeris Actions Docs](https://www.openhab.org/docs/configuration/actions.html#ephemeris).
|
|
||||||
|
|
||||||
For deeper information have a look at the [Ephemeris JavaDoc](https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/ephemeris).
|
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
openhab.Ephemeris = Java.type('org.openhab.core.model.script.actions.Ephemeris');
|
let logger = log('my_logger');
|
||||||
|
|
||||||
// Example
|
//prints "Hello World!"
|
||||||
let weekend = openhab.Ephemeris.isWeekend();
|
logger.debug("Hello {}!", "world");
|
||||||
```
|
```
|
||||||
|
|
||||||
## Types and Units
|
### Time
|
||||||
|
|
||||||
Import types from openHAB Core for type conversion and more.
|
openHAB internally makes extensive use of the `java.time` package. openHAB-JS exports the excellent [JS-Joda](#https://js-joda.github.io/js-joda/) library via the `time` namespace, which is a native Javascript port of the same API standard used in Java for `java.time`. Anywhere that a native Java `ZonedDateTime` or `Duration` is required, the runtime will automatically convert a JS-Joda `ZonedDateTime` or `Duration` to its Java counterpart.
|
||||||
Import Units from openHAB Core for unit conversion and more.
|
|
||||||
|
Examples:
|
||||||
|
```javascript
|
||||||
|
var now = time.ZonedDateTime.now();
|
||||||
|
var yesterday = time.ZonedDateTime.now().minusHours(24);
|
||||||
|
|
||||||
|
var item = items.getItem("Kitchen");
|
||||||
|
console.log("averageSince", item.history.averageSince(yesterday));
|
||||||
|
```
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
openhab.typeOrUnit = Java.type('org.openhab.core.library.types.typeOrUnit');
|
actions.Exec.executeCommandLine(time.Duration.ofSeconds(20), 'echo', 'Hello World!');
|
||||||
|
|
||||||
// Example
|
|
||||||
openhab.HSBType = Java.type('org.openhab.core.library.types.HSBType');
|
|
||||||
let hsb = openhab.HSBType.fromRGB(4, 6, 9);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Available types are:
|
See [JS-Joda](#https://js-joda.github.io/js-joda/) for more examples and complete API usage.
|
||||||
* `QuantityType`
|
|
||||||
* `StringListType`
|
|
||||||
* `RawType`
|
|
||||||
* `DateTimeType`
|
|
||||||
* `DecimalType`
|
|
||||||
* `HSBType`
|
|
||||||
* `PercentType`
|
|
||||||
* `PointType`
|
|
||||||
* `StringType`
|
|
||||||
|
|
||||||
Available untis are:
|
## File Based Rules
|
||||||
* `SIUnits`
|
|
||||||
* `ImperialUnits`
|
The JSScripting binding will load scripts from `automation/js` in the user configuration directory. The system will automatically reload scripts when changes are detected to files. Local variable state is not persisted among reloads, see using the [cache](#cache) for a connivent way to persist objects.
|
||||||
* `MetricPrefix`
|
|
||||||
* `Units`
|
File based rules can be created in 2 different ways: using [JSRule](#jsrule) or the [Rule Builder](#rule-builder).
|
||||||
* `BinaryPrefix`
|
|
||||||
|
See [openhab-js : rules ](https://openhab.github.io/openhab-js/rules.html) for full API documentation
|
||||||
|
|
||||||
|
### JSRule
|
||||||
|
|
||||||
|
JSRules provides a simple, declarative syntax for defining rules that will be executed based on a trigger condition
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const email = "juliet@capulet.org"
|
||||||
|
|
||||||
|
rules.JSRule({
|
||||||
|
name: "Balcony Lights ON at 5pm",
|
||||||
|
description: "Light will turn on when it's 5:00pm",
|
||||||
|
triggers: [triggers.GenericCronTrigger("0 0 17 * * ?")],
|
||||||
|
execute: data => {
|
||||||
|
items.getItem("BalconyLights").sendCommand("ON");
|
||||||
|
actions.NotificationAction.sendNotification(email, "Balcony lights are ON");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Multiple triggers can be added, some example triggers include:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
triggers.ChannelEventTrigger('astro:sun:local:rise#event', 'START')
|
||||||
|
|
||||||
|
triggers.ItemStateChangeTrigger('my_item', 'OFF', 'ON')
|
||||||
|
|
||||||
|
triggers.ItemStateUpdateTrigger('my_item', 'OFF')
|
||||||
|
|
||||||
|
triggers.ItemCommandTrigger('my_item', 'OFF')
|
||||||
|
|
||||||
|
triggers.GroupStateChangeTrigger('my_group', 'OFF', 'ON')
|
||||||
|
|
||||||
|
triggers.GroupStateUpdateTrigger('my_group', 'OFF')
|
||||||
|
|
||||||
|
triggers.GroupCommandTrigger('my_group', 'OFF')
|
||||||
|
|
||||||
|
triggers.ThingStatusUpdateTrigger('some:thing:uuid','OFFLINE')
|
||||||
|
|
||||||
|
triggers.ThingStatusChangeTrigger('some:thing:uuid','ONLINE','OFFLINE')
|
||||||
|
|
||||||
|
triggers.SystemStartlevelTrigger(40) //Rules loaded
|
||||||
|
|
||||||
|
triggers.SystemStartlevelTrigger(50) //Rule engine started
|
||||||
|
|
||||||
|
triggers.SystemStartlevelTrigger(70) //User interfaces started
|
||||||
|
|
||||||
|
triggers.SystemStartlevelTrigger(80) //Things initialized
|
||||||
|
|
||||||
|
triggers.SystemStartlevelTrigger(100) //Startup Complete
|
||||||
|
|
||||||
|
triggers.GenericCronTrigger('0 30 16 * * ? *')
|
||||||
|
|
||||||
|
triggers.TimeOfDayTrigger('19:00')
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
See [openhab-js : triggers ](https://openhab.github.io/openhab-js/triggers.html) in the API documentation for a full list of all triggers.
|
||||||
|
|
||||||
|
### Rule Builder
|
||||||
|
|
||||||
|
The Rule Builder provides a convenient API to write rules in a high-level, readable style using a builder pattern.
|
||||||
|
|
||||||
|
Rules are started by calling `rules.when()` and can chain together [triggers](#rule-builder-triggers),
|
||||||
|
[conditions](#rule-builder-conditions) and [operations](#rule-builder-operations) in the following pattern:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
rules.when().triggerType()...if().conditionType().then().operationType()...build(name,description);
|
||||||
|
```
|
||||||
|
|
||||||
|
Rule are completed by calling `.build(name,description)` , if name or description are omitted, a generated value will be used.
|
||||||
|
|
||||||
|
A simple example of this would look like:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
rules.when().item("F1_Light").changed().then().send("changed").toItem("F2_Light").build("My Rule", "My First Rule");
|
||||||
|
```
|
||||||
|
|
||||||
|
Operations and conditions can also optionally take functions:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
rules.when().item("F1_light").changed().then(event => {
|
||||||
|
console.log(event);
|
||||||
|
}).build("Test Rule", "My Test Rule");
|
||||||
|
```
|
||||||
|
see [Examples](#rule-builder-examples) for further patterns
|
||||||
|
|
||||||
|
#### Rule Builder Triggers
|
||||||
|
|
||||||
|
* `when()`
|
||||||
|
* `or()`
|
||||||
|
* `.channel(channelName)` Specifies a channel event as a source for the rule to fire.
|
||||||
|
* `.triggered(event)` Trigger on a specific event name
|
||||||
|
* `.cron(cronExpression)` Specifies a cron schedule for the rule to fire.
|
||||||
|
* `.item(itemName)` Specifies an item as the source of changes to trigger a rule.
|
||||||
|
* `.for(duration)`
|
||||||
|
* `.from(state)`
|
||||||
|
* `.to(state)`
|
||||||
|
* `.fromOff()`
|
||||||
|
* `.toOn()`
|
||||||
|
* `.receivedCommand()`
|
||||||
|
* `.receivedUpdate()`
|
||||||
|
* `.memberOf(groupName)`
|
||||||
|
* `.for(duration)`
|
||||||
|
* `.from(state)`
|
||||||
|
* `.to(state)`
|
||||||
|
* `.fromOff()`
|
||||||
|
* `.toOn()`
|
||||||
|
* `.receivedCommand()`
|
||||||
|
* `.receivedUpdate()`
|
||||||
|
* `.system()`
|
||||||
|
* `.ruleEngineStarted()`
|
||||||
|
* `.rulesLoaded()`
|
||||||
|
* `.startupComplete()`
|
||||||
|
* `.thingsInitialized()`
|
||||||
|
* `.userInterfacesStarted()`
|
||||||
|
* `.startLevel(level)`
|
||||||
|
* `.thing(thingName)`
|
||||||
|
* `changed()`
|
||||||
|
* `updated()`
|
||||||
|
* `from(state)`
|
||||||
|
* `to(state)`
|
||||||
|
|
||||||
|
Additionally all the above triggers have the following functions:
|
||||||
|
* `.if()` or `.if(fn)` -> a [rule condition](#rule-builder-conditions)
|
||||||
|
* `.then()` or `.then(fn)` -> a [rule operation](#rule-builder-operations)
|
||||||
|
* `.or()` -> a [rule trigger](#rule-builder-triggers) (chain additional triggers)
|
||||||
|
|
||||||
|
#### Rule Builder Conditions
|
||||||
|
|
||||||
|
* `if(optionalFunction)`
|
||||||
|
* `.stateOfItem(state)`
|
||||||
|
|
||||||
|
#### Rule Builder Operations
|
||||||
|
* `then(optionalFunction)`
|
||||||
|
* `.build(name, description)`
|
||||||
|
* `.copyAndSendState()`
|
||||||
|
* `.copyState()`
|
||||||
|
* `.inGroup(groupName)`
|
||||||
|
* `.postIt()`
|
||||||
|
* `.postUpdate(state)`
|
||||||
|
* `.send(command)`
|
||||||
|
* `.sendIt()`
|
||||||
|
* `.sendOff()`
|
||||||
|
* `.sendOn()`
|
||||||
|
* `.sendToggle()`
|
||||||
|
|
||||||
|
#### Rule Builder Examples
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
//Basic rule, when the BedroomLight1 is changed, run a custom function
|
||||||
|
rules.when().item('BedroomLight1').changed().then(e => {
|
||||||
|
console.log("BedroomLight1 state", e.newState)
|
||||||
|
}.build();
|
||||||
|
|
||||||
|
//turn on the kitchen light at SUNSET
|
||||||
|
rules.when().timeOfDay("SUNSET").then().sendOn().toItem("KitchenLight").build("Sunset Rule","turn on the kitchen light
|
||||||
|
at SUNSET");
|
||||||
|
|
||||||
|
//turn off the kitchen light at 9PM
|
||||||
|
rules.when().cron("0 0 21 * * ?").then().sendOff().toItem("KitchenLight").build("9PM Rule", "turn off the kitchen light
|
||||||
|
at 9PM");
|
||||||
|
|
||||||
|
//set the colour of the hall light to pink at 9PM
|
||||||
|
rules.when().cron("0 0 21 * * ?").then().send("300,100,100").toItem("HallLight").build("Pink Rule", "set the colour of
|
||||||
|
the hall light to pink at 9PM");
|
||||||
|
|
||||||
|
//when the switch S1 status changes to ON, then turn on the HallLight
|
||||||
|
rules.when().item('S1').changed().toOn().then(sendOn().toItem('HallLight')).build("S1 Rule");
|
||||||
|
|
||||||
|
//when the HallLight colour changes pink, if the function fn returns true, then toggle the state of the OutsideLight
|
||||||
|
rules.when().item('HallLight').changed().to("300,100,100").if(fn).then().sendToggle().toItem('OutsideLight').build();
|
||||||
|
|
||||||
|
//and some rules which can be toggled by the items created in the 'gRules' Group:
|
||||||
|
|
||||||
|
//when the HallLight receives a command, send the same command to the KitchenLight
|
||||||
|
rules.when().item('HallLight').receivedCommand().then().sendIt().toItem('KitchenLight').build("Hall Light", "");
|
||||||
|
|
||||||
|
//when the HallLight is updated to ON, make sure that BedroomLight1 is set to the same state as the BedroomLight2
|
||||||
|
rules.when().item('HallLight').receivedUpdate().then().copyState().fromItem('BedroomLight1').toItem('BedroomLight2').build();
|
||||||
|
|
||||||
|
```
|
||||||
|
|||||||
BIN
bundles/org.openhab.automation.jsscripting/docs/rule-config.png
Normal file
BIN
bundles/org.openhab.automation.jsscripting/docs/rule-config.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 154 KiB |
BIN
bundles/org.openhab.automation.jsscripting/docs/rule-engines.png
Normal file
BIN
bundles/org.openhab.automation.jsscripting/docs/rule-engines.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 178 KiB |
BIN
bundles/org.openhab.automation.jsscripting/docs/rule-script.png
Normal file
BIN
bundles/org.openhab.automation.jsscripting/docs/rule-script.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 115 KiB |
BIN
bundles/org.openhab.automation.jsscripting/docs/settings.png
Normal file
BIN
bundles/org.openhab.automation.jsscripting/docs/settings.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 122 KiB |
@ -25,7 +25,7 @@
|
|||||||
<graal.version>21.3.0</graal.version>
|
<graal.version>21.3.0</graal.version>
|
||||||
<asm.version>6.2.1</asm.version>
|
<asm.version>6.2.1</asm.version>
|
||||||
<oh.version>${project.version}</oh.version>
|
<oh.version>${project.version}</oh.version>
|
||||||
<ohjs.version>openhab@1.2.0</ohjs.version>
|
<ohjs.version>openhab@1.2.1</ohjs.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@ -25,6 +25,8 @@ import java.nio.file.OpenOption;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.attribute.FileAttribute;
|
import java.nio.file.attribute.FileAttribute;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -38,6 +40,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
|||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.graalvm.polyglot.Context;
|
import org.graalvm.polyglot.Context;
|
||||||
import org.graalvm.polyglot.Engine;
|
import org.graalvm.polyglot.Engine;
|
||||||
|
import org.graalvm.polyglot.HostAccess;
|
||||||
|
import org.graalvm.polyglot.Value;
|
||||||
import org.openhab.automation.jsscripting.internal.fs.DelegatingFileSystem;
|
import org.openhab.automation.jsscripting.internal.fs.DelegatingFileSystem;
|
||||||
import org.openhab.automation.jsscripting.internal.fs.PrefixedSeekableByteChannel;
|
import org.openhab.automation.jsscripting.internal.fs.PrefixedSeekableByteChannel;
|
||||||
import org.openhab.automation.jsscripting.internal.fs.ReadOnlySeekableByteArrayChannel;
|
import org.openhab.automation.jsscripting.internal.fs.ReadOnlySeekableByteArrayChannel;
|
||||||
@ -77,10 +81,27 @@ public class OpenhabGraalJSScriptEngine extends InvocationInterceptingScriptEngi
|
|||||||
public OpenhabGraalJSScriptEngine(@Nullable String injectionCode) {
|
public OpenhabGraalJSScriptEngine(@Nullable String injectionCode) {
|
||||||
super(null); // delegate depends on fields not yet initialised, so we cannot set it immediately
|
super(null); // delegate depends on fields not yet initialised, so we cannot set it immediately
|
||||||
this.globalScript = GLOBAL_REQUIRE + (injectionCode != null ? injectionCode : "");
|
this.globalScript = GLOBAL_REQUIRE + (injectionCode != null ? injectionCode : "");
|
||||||
|
|
||||||
|
// Custom translate JS Objects - > Java Objects
|
||||||
|
HostAccess hostAccess = HostAccess.newBuilder(HostAccess.ALL)
|
||||||
|
// Translate JS-Joda ZonedDateTime to java.time.ZonedDateTime
|
||||||
|
.targetTypeMapping(Value.class, ZonedDateTime.class, (v) -> v.hasMember("withFixedOffsetZone"), v -> {
|
||||||
|
return ZonedDateTime
|
||||||
|
.parse(v.invokeMember("withFixedOffsetZone").invokeMember("toString").asString());
|
||||||
|
}, HostAccess.TargetMappingPrecedence.LOW)
|
||||||
|
|
||||||
|
// Translate JS-Joda Duration to java.time.Duration
|
||||||
|
.targetTypeMapping(Value.class, Duration.class,
|
||||||
|
// picking two members to check as Duration has many common function names
|
||||||
|
(v) -> v.hasMember("minusDuration") && v.hasMember("toNanos"), v -> {
|
||||||
|
return Duration.ofNanos(v.invokeMember("toNanos").asLong());
|
||||||
|
}, HostAccess.TargetMappingPrecedence.LOW)
|
||||||
|
.build();
|
||||||
|
|
||||||
delegate = GraalJSScriptEngine.create(
|
delegate = GraalJSScriptEngine.create(
|
||||||
Engine.newBuilder().allowExperimentalOptions(true).option("engine.WarnInterpreterOnly", "false")
|
Engine.newBuilder().allowExperimentalOptions(true).option("engine.WarnInterpreterOnly", "false")
|
||||||
.build(),
|
.build(),
|
||||||
Context.newBuilder("js").allowExperimentalOptions(true).allowAllAccess(true)
|
Context.newBuilder("js").allowExperimentalOptions(true).allowAllAccess(true).allowHostAccess(hostAccess)
|
||||||
.option("js.commonjs-require-cwd", JSDependencyTracker.LIB_PATH)
|
.option("js.commonjs-require-cwd", JSDependencyTracker.LIB_PATH)
|
||||||
.option("js.nashorn-compat", "true") // to ease migration
|
.option("js.nashorn-compat", "true") // to ease migration
|
||||||
.option("js.ecmascript-version", "2021") // nashorn compat will enforce es5 compatibility, we
|
.option("js.ecmascript-version", "2021") // nashorn compat will enforce es5 compatibility, we
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user