diff --git a/karate-core/pom.xml b/karate-core/pom.xml
index a8d22ca26..7ff65d1a8 100644
--- a/karate-core/pom.xml
+++ b/karate-core/pom.xml
@@ -12,21 +12,14 @@
4.13.1
- 24.0.0
- org.graalvm.js
- js-scriptengine
- ${graal.version}
-
-
- org.graalvm.js
- js-language
- ${graal.version}
- runtime
-
+ io.karatelabs.js
+ karate-js
+ 0.1.0
+
org.thymeleaf
thymeleaf
diff --git a/karate-core/src/main/java/com/intuit/karate/Match.java b/karate-core/src/main/java/com/intuit/karate/Match.java
index 5ae31713f..8c6599657 100644
--- a/karate-core/src/main/java/com/intuit/karate/Match.java
+++ b/karate-core/src/main/java/com/intuit/karate/Match.java
@@ -23,7 +23,7 @@
*/
package com.intuit.karate;
-import com.intuit.karate.graal.JsEngine;
+import com.intuit.karate.js.JsEngine;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap;
diff --git a/karate-core/src/main/java/com/intuit/karate/MatchOperation.java b/karate-core/src/main/java/com/intuit/karate/MatchOperation.java
index 9d972420a..5c4b2f961 100644
--- a/karate-core/src/main/java/com/intuit/karate/MatchOperation.java
+++ b/karate-core/src/main/java/com/intuit/karate/MatchOperation.java
@@ -23,8 +23,7 @@
*/
package com.intuit.karate;
-import com.intuit.karate.graal.JsEngine;
-import com.intuit.karate.graal.JsValue;
+import com.intuit.karate.js.JsEngine;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
@@ -172,7 +171,7 @@ boolean execute() {
context.JS.put("_$", o);
MatchOperation mo = new MatchOperation(context.descend(i), nestedMatchType, new Match.Value(o), expected, matchEachEmptyAllowed);
mo.execute();
- context.JS.bindings.removeMember("_$");
+ context.JS.remove("_$");
if (!mo.pass) {
return fail("match each failed at index " + i);
}
@@ -284,10 +283,10 @@ private boolean macroEqualsExpected(String expStr) {
}
context.JS.put("$", context.root.actual.getValue());
context.JS.put("_", actual.getValue());
- JsValue jv = context.JS.eval(macro);
- context.JS.bindings.removeMember("$");
- context.JS.bindings.removeMember("_");
- MatchOperation mo = new MatchOperation(context, nestedType, actual, new Match.Value(jv.getValue()), matchEachEmptyAllowed);
+ Object jv = context.JS.eval(macro);
+ context.JS.remove("$");
+ context.JS.remove("_");
+ MatchOperation mo = new MatchOperation(context, nestedType, actual, new Match.Value(jv), matchEachEmptyAllowed);
return mo.execute();
} else if (macro.startsWith("[")) {
int closeBracketPos = macro.indexOf(']');
@@ -307,10 +306,12 @@ private boolean macroEqualsExpected(String expStr) {
} else { // #[5] | #[$.foo]
sizeExpr = bracketContents + " == _";
}
- JsValue jv = context.JS.eval(sizeExpr);
- context.JS.bindings.removeMember("$");
- context.JS.bindings.removeMember("_");
- if (!jv.isTrue()) {
+ Object jv = context.JS.eval(sizeExpr);
+ context.JS.remove("$");
+ context.JS.remove("_");
+ if (jv instanceof Boolean && (Boolean) jv) {
+ // all good
+ } else {
return fail("actual array length is " + listSize);
}
}
@@ -331,8 +332,8 @@ private boolean macroEqualsExpected(String expStr) {
Match.Type nestedType = macroToMatchType(true, macro); // match each
int startPos = matchTypeToStartPos(nestedType);
macro = macro.substring(startPos);
- JsValue jv = context.JS.eval(macro);
- MatchOperation mo = new MatchOperation(context, nestedType, actual, new Match.Value(jv.getValue()), matchEachEmptyAllowed);
+ Object jv = context.JS.eval(macro);
+ MatchOperation mo = new MatchOperation(context, nestedType, actual, new Match.Value(jv), matchEachEmptyAllowed);
return mo.execute();
}
}
@@ -391,10 +392,12 @@ private boolean macroEqualsExpected(String expStr) {
if (macro != null && questionPos != -1) {
context.JS.put("$", context.root.actual.getValue());
context.JS.put("_", actual.getValue());
- JsValue jv = context.JS.eval(macro);
- context.JS.bindings.removeMember("$");
- context.JS.bindings.removeMember("_");
- if (!jv.isTrue()) {
+ Object jv = context.JS.eval(macro);
+ context.JS.remove("$");
+ context.JS.remove("_");
+ if (jv instanceof Boolean && (Boolean) jv) {
+ // all good
+ } else {
return fail("evaluated to 'false'");
}
}
diff --git a/karate-core/src/main/java/com/intuit/karate/core/MockHandler.java b/karate-core/src/main/java/com/intuit/karate/core/MockHandler.java
index 829194edc..c4902f08f 100644
--- a/karate-core/src/main/java/com/intuit/karate/core/MockHandler.java
+++ b/karate-core/src/main/java/com/intuit/karate/core/MockHandler.java
@@ -23,31 +23,15 @@
*/
package com.intuit.karate.core;
-import com.intuit.karate.ScenarioActions;
-import com.intuit.karate.Suite;
-import com.intuit.karate.StringUtils;
-import com.intuit.karate.Json;
-import com.intuit.karate.KarateException;
-import com.intuit.karate.graal.JsValue;
-import com.intuit.karate.http.HttpClientFactory;
-import com.intuit.karate.http.HttpUtils;
-import com.intuit.karate.http.Request;
-import com.intuit.karate.http.ResourceType;
-import com.intuit.karate.http.Response;
-import com.intuit.karate.http.ServerHandler;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import java.util.function.BiFunction;
-import java.util.function.Function;
+import com.intuit.karate.*;
+import com.intuit.karate.http.*;
+import io.karatelabs.js.Invokable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.*;
+
/**
- *
* @author pthomas3
*/
public class MockHandler implements ServerHandler {
@@ -99,36 +83,36 @@ public MockHandler(String prefix, List features, Map ar
corsEnabled = corsEnabled || runtime.engine.getConfig().isCorsEnabled();
globals.putAll(runtime.engine.shallowCloneVariables());
runtime.logger.info("mock server initialized: {}", feature);
- scenarioRuntimes.put(feature, runtime);
+ scenarioRuntimes.put(feature, runtime);
});
}
-
+
public Object getVariable(String name) {
if (globals.containsKey(name)) {
Variable v = globals.get(name);
if (v != null) {
- return JsValue.fromJava(v.getValue());
+ return v.getValue();
}
}
return null;
}
- private ScenarioRuntime initRuntime(Feature feature, Map args) {
- FeatureRuntime featureRuntime = FeatureRuntime.of(Suite.forTempUse(HttpClientFactory.DEFAULT), new FeatureCall(feature), args);
+ private ScenarioRuntime initRuntime(Feature feature, Map initArgs) {
+ FeatureRuntime featureRuntime = FeatureRuntime.of(Suite.forTempUse(HttpClientFactory.DEFAULT), new FeatureCall(feature), initArgs);
FeatureSection section = new FeatureSection();
section.setIndex(-1); // TODO util for creating dummy scenario
Scenario dummy = new Scenario(feature, section, -1);
section.setScenario(dummy);
ScenarioRuntime runtime = new ScenarioRuntime(featureRuntime, dummy);
runtime.logger.setLogOnly(true);
- runtime.engine.setVariable(PATH_MATCHES, (Function) this::pathMatches);
- runtime.engine.setVariable(PARAM_EXISTS, (Function) this::paramExists);
- runtime.engine.setVariable(PARAM_VALUE, (Function) this::paramValue);
- runtime.engine.setVariable(METHOD_IS, (Function) this::methodIs);
- runtime.engine.setVariable(TYPE_CONTAINS, (Function) this::typeContains);
- runtime.engine.setVariable(ACCEPT_CONTAINS, (Function) this::acceptContains);
- runtime.engine.setVariable(HEADER_CONTAINS, (BiFunction) this::headerContains);
- runtime.engine.setVariable(BODY_PATH, (Function) this::bodyPath);
+ runtime.engine.setVariable(PATH_MATCHES, (Invokable) args -> this.pathMatches((String) args[0]));
+ runtime.engine.setVariable(PARAM_EXISTS, (Invokable) args -> this.paramExists((String) args[0]));
+ runtime.engine.setVariable(PARAM_VALUE, (Invokable) args-> this.paramValue((String) args[0]));
+ runtime.engine.setVariable(METHOD_IS, (Invokable) args -> this.methodIs((String) args[0]));
+ runtime.engine.setVariable(TYPE_CONTAINS, (Invokable) args -> this.typeContains((String) args[0]));
+ runtime.engine.setVariable(ACCEPT_CONTAINS, (Invokable) args -> this.acceptContains((String) args[0]));
+ runtime.engine.setVariable(HEADER_CONTAINS, (Invokable) args -> this.headerContains((String) args[0], (String) args[1]));
+ runtime.engine.setVariable(BODY_PATH, (Invokable) args -> this.bodyPath((String) args[0]));
runtime.engine.init();
if (feature.isBackgroundPresent()) {
// if we are within a scenario already e.g. karate.start(), preserve context
@@ -146,7 +130,7 @@ private ScenarioRuntime initRuntime(Feature feature, Map args) {
} finally {
ScenarioEngine.set(prevEngine);
}
- }
+ }
return runtime;
}
@@ -176,7 +160,7 @@ public synchronized Response handle(Request req) { // note the [synchronized]
Feature feature = entry.getKey();
ScenarioRuntime runtime = entry.getValue();
// important for graal to work properly
- Thread.currentThread().setContextClassLoader(runtime.featureRuntime.suite.classLoader);
+ Thread.currentThread().setContextClassLoader(runtime.featureRuntime.suite.classLoader);
LOCAL_REQUEST.set(req);
req.processBody();
ScenarioEngine engine = initEngine(runtime, globals, req);
@@ -242,9 +226,9 @@ public synchronized Response handle(Request req) { // note the [synchronized]
}
return new Response(404);
}
-
+
private static ScenarioEngine initEngine(ScenarioRuntime runtime, Map globals, Request req) {
- ScenarioEngine engine = new ScenarioEngine(runtime.engine.getConfig(), runtime, new HashMap(globals), runtime.logger);
+ ScenarioEngine engine = new ScenarioEngine(runtime.engine.getConfig(), runtime, new HashMap(globals), runtime.logger);
engine.init();
engine.setVariable(ScenarioEngine.REQUEST_URL_BASE, req.getUrlBase());
engine.setVariable(ScenarioEngine.REQUEST_PATH, req.getPath());
@@ -363,7 +347,7 @@ public Object bodyPath(String path) {
if (v.isNotPresent()) {
return null;
} else {
- return JsValue.fromJava(v.getValue());
+ return v.getValue();
}
} else {
Json json = Json.of(body);
@@ -373,7 +357,7 @@ public Object bodyPath(String path) {
} catch (Exception e) {
return null;
}
- return JsValue.fromJava(result);
+ return result;
}
}
diff --git a/karate-core/src/main/java/com/intuit/karate/core/ScenarioBridge.java b/karate-core/src/main/java/com/intuit/karate/core/ScenarioBridge.java
index 039adda20..673db08aa 100644
--- a/karate-core/src/main/java/com/intuit/karate/core/ScenarioBridge.java
+++ b/karate-core/src/main/java/com/intuit/karate/core/ScenarioBridge.java
@@ -23,50 +23,22 @@
*/
package com.intuit.karate.core;
-import com.intuit.karate.FileUtils;
-import com.intuit.karate.Json;
-import com.intuit.karate.JsonUtils;
-import com.intuit.karate.KarateException;
-import com.intuit.karate.Logger;
-import com.intuit.karate.Match;
-import com.intuit.karate.MatchStep;
-import com.intuit.karate.PerfContext;
-import com.intuit.karate.StringUtils;
-import com.intuit.karate.XmlUtils;
-import com.intuit.karate.graal.JsEngine;
-import com.intuit.karate.graal.JsFunction;
-import com.intuit.karate.graal.JsLambda;
-import com.intuit.karate.graal.JsList;
-import com.intuit.karate.graal.JsMap;
-import com.intuit.karate.graal.JsValue;
-import com.intuit.karate.http.HttpClient;
-import com.intuit.karate.http.HttpRequest;
-import com.intuit.karate.http.HttpRequestBuilder;
-import com.intuit.karate.http.ResourceType;
-import com.intuit.karate.http.WebSocketClient;
-import com.intuit.karate.http.WebSocketOptions;
+import com.intuit.karate.*;
+import com.intuit.karate.http.*;
+import com.intuit.karate.js.JsEngine;
import com.intuit.karate.shell.Command;
+import io.karatelabs.js.Invokable;
+
import java.io.File;
import java.io.InputStream;
import java.net.URLDecoder;
import java.net.URLEncoder;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
+import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.graalvm.polyglot.Value;
-import org.graalvm.polyglot.proxy.ProxyExecutable;
/**
- *
* @author pthomas3
*/
public class ScenarioBridge implements PerfContext {
@@ -81,77 +53,74 @@ public void abort() {
getEngine().setAborted(true);
}
- public Object append(Value... vals) {
+ public Object append(Object... vals) {
List list = new ArrayList();
- JsList jsList = new JsList(list);
if (vals.length == 0) {
- return jsList;
+ return list;
}
- Value val = vals[0];
- if (val.hasArrayElements()) {
- list.addAll(val.as(List.class));
+ Object val = vals[0];
+ if (val instanceof List) {
+ list.addAll((List) val);
} else {
- list.add(val.as(Object.class));
+ list.add(val);
}
if (vals.length == 1) {
- return jsList;
+ return list;
}
for (int i = 1; i < vals.length; i++) {
- Value v = vals[i];
- if (v.hasArrayElements()) {
- list.addAll(v.as(List.class));
+ Object v = vals[i];
+ if (v instanceof List) {
+ list.addAll((List) v);
} else {
- list.add(v.as(Object.class));
+ list.add(v);
}
}
- return jsList;
+ return list;
}
- private Object appendToInternal(String varName, Value... vals) {
+ private Object appendToInternal(String varName, Object... vals) {
ScenarioEngine engine = getEngine();
Variable var = engine.vars.get(varName);
if (!var.isList()) {
return null;
}
List list = var.getValue();
- for (Value v : vals) {
- if (v.hasArrayElements()) {
- list.addAll(v.as(List.class));
+ for (Object v : vals) {
+ if (v instanceof List) {
+ list.addAll((List) v);
} else {
- Object temp = v.as(Object.class);
- list.add(temp);
+ list.add(v);
}
}
engine.setVariable(varName, list);
- return new JsList(list);
+ return list;
}
- public Object appendTo(Value ref, Value... vals) {
- if (ref.isString()) {
- return appendToInternal(ref.asString(), vals);
+ public Object appendTo(Object ref, Object... vals) {
+ if (ref instanceof String) {
+ return appendToInternal((String) ref, vals);
}
List list;
- if (ref.hasArrayElements()) {
- list = new JsValue(ref).getAsList(); // make sure we unwrap the "original" list
+ if (ref instanceof List) {
+ list = (List) ref;
} else {
list = new ArrayList();
}
- for (Value v : vals) {
- if (v.hasArrayElements()) {
- list.addAll(v.as(List.class));
+ for (Object v : vals) {
+ if (v instanceof List) {
+ list.addAll((List) v);
} else {
- Object temp = v.as(Object.class);
- list.add(temp);
+ list.add(v);
}
}
- return new JsList(list);
+ return list;
}
public Object call(String fileName) {
return call(false, fileName, null);
}
- public Object call(String fileName, Value arg) {
+ public Object call(String fileName, Object arg) {
return call(false, fileName, arg);
}
@@ -159,7 +128,7 @@ public Object call(boolean sharedScope, String fileName) {
return call(sharedScope, fileName, null);
}
- public Object call(boolean sharedScope, String fileName, Value arg) {
+ public Object call(boolean sharedScope, String fileName, Object arg) {
ScenarioEngine engine = getEngine();
Variable called = new Variable(engine.fileReader.readFile(fileName));
Variable result = engine.call(called, arg == null ? null : new Variable(arg), sharedScope);
@@ -168,7 +137,7 @@ public Object call(boolean sharedScope, String fileName, Value arg) {
engine.setVariables(result.getValue());
}
}
- return JsValue.fromJava(result.getValue());
+ return result.getValue();
}
private static Object callSingleResult(ScenarioEngine engine, Object o) throws Exception {
@@ -176,17 +145,14 @@ private static Object callSingleResult(ScenarioEngine engine, Object o) throws E
engine.logger.warn("callSingle() cached result is an exception");
throw (Exception) o;
}
- // clone so that threads see the same data snapshot
- // we also attach js functions
- o = engine.JS.attachAll(o);
- return JsValue.fromJava(o);
+ return o;
}
public Object callSingle(String fileName) throws Exception {
return callSingle(fileName, null);
}
- public Object callSingle(String fileName, Value arg) throws Exception {
+ public Object callSingle(String fileName, Object arg) throws Exception {
ScenarioEngine engine = getEngine();
final Map CACHE = engine.runtime.featureRuntime.suite.callSingleCache;
int minutes = engine.getConfig().getCallSingleCacheMinutes();
@@ -228,7 +194,7 @@ public Object callSingle(String fileName, Value arg) throws Exception {
if (result == null) {
Variable called = new Variable(read(fileName));
Variable argVar;
- if (arg == null || arg.isNull()) {
+ if (arg == null) {
argVar = null;
} else {
argVar = new Variable(arg);
@@ -267,7 +233,7 @@ public Object callonce(String path) {
public Object callonce(boolean sharedScope, String path) {
String exp = "read('" + path + "')";
Variable v = getEngine().call(true, exp, sharedScope);
- return JsValue.fromJava(v.getValue());
+ return v.getValue();
}
@Override
@@ -276,15 +242,15 @@ public void capturePerfEvent(String name, long startTime, long endTime) {
getEngine().capturePerfEvent(event);
}
- public Object compareImage(Object baseline, Object latest, Value... optionsVal) {
- if (optionsVal.length > 0 && !optionsVal[0].hasMembers()) {
+ public Object compareImage(Object baseline, Object latest, Object... optionsVal) {
+ if (optionsVal.length > 0 && !(optionsVal[0] instanceof Map)) {
throw new RuntimeException("invalid image comparison options: expected map");
}
-
Map options = new HashMap<>();
if (optionsVal.length > 0) {
- for (String k : optionsVal[0].getMemberKeys()) {
- options.put(k, optionsVal[0].getMember(k).as(Object.class));
+ Map map = (Map) optionsVal[0];
+ for (String k : map.keySet()) {
+ options.put(k, map.get(k));
}
}
@@ -293,36 +259,37 @@ public Object compareImage(Object baseline, Object latest, Value... optionsVal)
params.put("latest", latest);
params.put("options", options);
- return JsValue.fromJava(getEngine().compareImageInternal(params));
+ return getEngine().compareImageInternal(params);
}
- public void configure(String key, Value value) {
+ public void configure(String key, Object value) {
getEngine().configure(key, new Variable(value));
}
-
+
public Object consume(String type) {
return getEngine().consume(type);
}
- public Object distinct(Value o) {
- if (!o.hasArrayElements()) {
- return JsList.EMPTY;
+ public Object distinct(Object o) {
+ if (!(o instanceof List)) {
+ return new ArrayList<>();
}
- long count = o.getArraySize();
+ List list = (List) o;
+ long count = list.size();
Set