[jsscripting] Fix bugs related to event obj conversion & script wrapping (#19703)

* [jsscripting] Fix onScript is invoked for openhab-js injection from file system

Signed-off-by: Florian Hotze <dev@florianhotze.com>
This commit is contained in:
Florian Hotze
2025-11-23 22:43:42 +01:00
committed by GitHub
parent d57735985f
commit 9bba9d4cd7
2 changed files with 37 additions and 10 deletions
@@ -111,7 +111,7 @@ class DebuggingGraalScriptEngine<T extends ScriptEngine & Invocable & AutoClosea
String identifier = "stack";
if (fileName != null) {
identifier = "file. " + fileName.toString().replaceAll("^.*[/\\\\]", "");
identifier = "file." + fileName.toString().replaceAll("^.*[/\\\\]", "");
} else if (ruleUID != null) {
identifier = "rule." + ruleUID;
} else if (ohEngineIdentifier != null
@@ -112,6 +112,11 @@ public class OpenhabGraalJSScriptEngine
private static final String EVENT_CONVERSION_CODE = "this.event = (typeof this.rules?._getTriggeredData === 'function') ? rules._getTriggeredData(ctx, true) : this.event";
private static final Pattern USE_WRAPPER_DIRECTIVE = Pattern
.compile("^\\s*([\"'])use wrapper(?:=(?<enabled>true|false))?\\1;?\\s*$");
/**
* Pattern to match the header of a JavaScript Immediately Invoked Function Expression (IIFE).
*/
private static final Pattern IIFE_HEADER = Pattern
.compile("^\\s*\\(\\s*(?:function\\s*[\\w$]*\\s*\\([^)]*\\)|\\([^)]*\\)\\s*=>)\\s*\\{?.*$");
private static final String REQUIRE_WRAPPER_NAME = "__wraprequire__";
@@ -346,7 +351,8 @@ public class OpenhabGraalJSScriptEngine
} else {
logger.debug("Evaluating openhab-js injection from the file system for engine '{}' ...",
engineIdentifier);
eval(OPENHAB_JS_INJECTION_CODE);
// use delegate::eval instead of this::eval to avoid invocation of beforeInvocation, onScript, etc.
delegate.eval(OPENHAB_JS_INJECTION_CODE);
}
}
logger.debug("Successfully initialized GraalJS script engine '{}'.", engineIdentifier);
@@ -361,15 +367,9 @@ public class OpenhabGraalJSScriptEngine
return super.onScript(script);
}
String newScript = script;
if (configuration.isEventConversionEnabled()) {
logger.debug("Injecting event conversion code into script for engine '{}'.", engineIdentifier);
newScript = EVENT_CONVERSION_CODE + System.lineSeparator() + newScript;
}
// keep this extendable for more directives by checking the first n lines (n = number of directives)
// keep this extendable for more directives by checking the first n+1 lines (n = number of directives)
// up to two directives: "use strict" (handled by Graal) and "use wrapper"
List<String> header = script.lines().limit(2).toList();
List<String> header = script.lines().limit(3).toList();
boolean useWrapper = isScriptAction()
|| (isScriptCondition() && configuration.isScriptConditionWrapperEnabled());
for (String line : header) {
@@ -390,6 +390,33 @@ public class OpenhabGraalJSScriptEngine
}
}
String newScript = script;
if (configuration.isEventConversionEnabled()) {
int lineNumber = 0;
// if the script contains an IIFE, make sure to inject the event conversion code inside the IIFE
for (int i = 0; i < header.size(); i++) {
if (IIFE_HEADER.matcher(header.get(i)).matches()) {
lineNumber = i + 1;
break;
}
}
logger.debug("Injecting event conversion code into script for engine '{}' after line {} ...",
engineIdentifier, lineNumber);
// inject event conversion code into the script at the given line number
List<String> lines = newScript.lines().toList();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < lines.size(); i++) {
if (i == lineNumber) {
sb.append(EVENT_CONVERSION_CODE);
sb.append(System.lineSeparator());
}
sb.append(lines.get(i));
sb.append(System.lineSeparator());
}
newScript = sb.toString();
}
if (useWrapper) {
logger.debug("Wrapping script for engine '{}' ...", engineIdentifier);
newScript = "(function() {" + System.lineSeparator() + newScript + System.lineSeparator() + "})()";