jslike 1.4.5 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.js +51 -25
- package/dist/esm/interpreter/index.js +2 -1
- package/dist/esm/interpreter/interpreter.js +85 -26
- package/dist/esm/runtime/execution-controller.js +212 -0
- package/dist/index.cjs +287 -35
- package/dist/index.d.cts +350 -52
- package/dist/index.d.ts +350 -52
- package/dist/index.js +286 -35
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5784,19 +5784,36 @@ var Interpreter = class _Interpreter {
|
|
|
5784
5784
|
this.moduleCache = /* @__PURE__ */ new Map();
|
|
5785
5785
|
this.moduleExports = {};
|
|
5786
5786
|
this.abortSignal = options.abortSignal;
|
|
5787
|
+
this.executionController = options.executionController;
|
|
5787
5788
|
}
|
|
5788
|
-
// Check if execution should be aborted
|
|
5789
|
+
// Check if execution should be aborted (sync version)
|
|
5789
5790
|
checkAbortSignal() {
|
|
5791
|
+
if (this.executionController) {
|
|
5792
|
+
this.executionController._checkAbortSync();
|
|
5793
|
+
return;
|
|
5794
|
+
}
|
|
5790
5795
|
if (this.abortSignal && this.abortSignal.aborted) {
|
|
5791
5796
|
const error = new Error("The operation was aborted");
|
|
5792
5797
|
error.name = "AbortError";
|
|
5793
5798
|
throw error;
|
|
5794
5799
|
}
|
|
5795
5800
|
}
|
|
5801
|
+
// Checkpoint that returns a promise only when controller is present
|
|
5802
|
+
// When no controller, returns null to signal no await needed
|
|
5803
|
+
_getCheckpointPromise(node, env) {
|
|
5804
|
+
if (this.executionController) {
|
|
5805
|
+
this.executionController._setEnv(env);
|
|
5806
|
+
return this.executionController._checkpoint(node);
|
|
5807
|
+
} else {
|
|
5808
|
+
this.checkAbortSignal();
|
|
5809
|
+
return null;
|
|
5810
|
+
}
|
|
5811
|
+
}
|
|
5796
5812
|
// Async evaluation for async functions - handles await expressions
|
|
5797
5813
|
async evaluateAsync(node, env) {
|
|
5798
5814
|
if (!node) return void 0;
|
|
5799
|
-
this.
|
|
5815
|
+
const checkpointPromise = this._getCheckpointPromise(node, env);
|
|
5816
|
+
if (checkpointPromise) await checkpointPromise;
|
|
5800
5817
|
if (node.type === "AwaitExpression") {
|
|
5801
5818
|
const promise = await this.evaluateAsync(node.argument, env);
|
|
5802
5819
|
return await promise;
|
|
@@ -5967,6 +5984,8 @@ var Interpreter = class _Interpreter {
|
|
|
5967
5984
|
await this.evaluateAsync(node.init, forEnv);
|
|
5968
5985
|
}
|
|
5969
5986
|
while (!node.test || await this.evaluateAsync(node.test, forEnv)) {
|
|
5987
|
+
const cp1 = this._getCheckpointPromise(node, forEnv);
|
|
5988
|
+
if (cp1) await cp1;
|
|
5970
5989
|
const result = await this.evaluateAsync(node.body, forEnv);
|
|
5971
5990
|
if (result instanceof BreakSignal) {
|
|
5972
5991
|
break;
|
|
@@ -5992,6 +6011,8 @@ var Interpreter = class _Interpreter {
|
|
|
5992
6011
|
const declarator = node.left.declarations[0];
|
|
5993
6012
|
const isConst = node.left.kind === "const";
|
|
5994
6013
|
for (const value of iterable) {
|
|
6014
|
+
const cp2 = this._getCheckpointPromise(node, forEnv);
|
|
6015
|
+
if (cp2) await cp2;
|
|
5995
6016
|
const iterEnv = forEnv.extend();
|
|
5996
6017
|
if (declarator.id.type === "Identifier") {
|
|
5997
6018
|
iterEnv.define(declarator.id.name, value, isConst);
|
|
@@ -6022,6 +6043,8 @@ var Interpreter = class _Interpreter {
|
|
|
6022
6043
|
const varName = node.left.declarations[0].id.name;
|
|
6023
6044
|
forEnv.define(varName, void 0);
|
|
6024
6045
|
for (const key in obj) {
|
|
6046
|
+
const cp3 = this._getCheckpointPromise(node, forEnv);
|
|
6047
|
+
if (cp3) await cp3;
|
|
6025
6048
|
forEnv.set(varName, key);
|
|
6026
6049
|
const result = await this.evaluateAsync(node.body, forEnv);
|
|
6027
6050
|
if (result instanceof BreakSignal) {
|
|
@@ -6038,6 +6061,8 @@ var Interpreter = class _Interpreter {
|
|
|
6038
6061
|
}
|
|
6039
6062
|
if (node.type === "WhileStatement") {
|
|
6040
6063
|
while (await this.evaluateAsync(node.test, env)) {
|
|
6064
|
+
const cp4 = this._getCheckpointPromise(node, env);
|
|
6065
|
+
if (cp4) await cp4;
|
|
6041
6066
|
const result = await this.evaluateAsync(node.body, env);
|
|
6042
6067
|
if (result instanceof BreakSignal) {
|
|
6043
6068
|
break;
|
|
@@ -6053,6 +6078,8 @@ var Interpreter = class _Interpreter {
|
|
|
6053
6078
|
}
|
|
6054
6079
|
if (node.type === "DoWhileStatement") {
|
|
6055
6080
|
do {
|
|
6081
|
+
const cp5 = this._getCheckpointPromise(node, env);
|
|
6082
|
+
if (cp5) await cp5;
|
|
6056
6083
|
const result = await this.evaluateAsync(node.body, env);
|
|
6057
6084
|
if (result instanceof BreakSignal) {
|
|
6058
6085
|
break;
|
|
@@ -6695,6 +6722,7 @@ var Interpreter = class _Interpreter {
|
|
|
6695
6722
|
callUserFunction(func, args, callingEnv, thisContext = void 0) {
|
|
6696
6723
|
const metadata = func.__metadata || func;
|
|
6697
6724
|
const funcEnv = new Environment(metadata.closure);
|
|
6725
|
+
const funcName = metadata.name || func.name || "anonymous";
|
|
6698
6726
|
if (thisContext !== void 0) {
|
|
6699
6727
|
funcEnv.define("this", thisContext);
|
|
6700
6728
|
}
|
|
@@ -6717,15 +6745,46 @@ var Interpreter = class _Interpreter {
|
|
|
6717
6745
|
}
|
|
6718
6746
|
}
|
|
6719
6747
|
if (metadata.async) {
|
|
6748
|
+
if (this.executionController) {
|
|
6749
|
+
this.executionController._pushCall(funcName);
|
|
6750
|
+
}
|
|
6720
6751
|
return (async () => {
|
|
6752
|
+
try {
|
|
6753
|
+
if (metadata.expression) {
|
|
6754
|
+
const result = await this.evaluateAsync(metadata.body, funcEnv);
|
|
6755
|
+
if (result instanceof ThrowSignal) {
|
|
6756
|
+
throw result.value;
|
|
6757
|
+
}
|
|
6758
|
+
return result;
|
|
6759
|
+
} else {
|
|
6760
|
+
const result = await this.evaluateAsync(metadata.body, funcEnv);
|
|
6761
|
+
if (result instanceof ReturnValue) {
|
|
6762
|
+
return result.value;
|
|
6763
|
+
}
|
|
6764
|
+
if (result instanceof ThrowSignal) {
|
|
6765
|
+
throw result.value;
|
|
6766
|
+
}
|
|
6767
|
+
return void 0;
|
|
6768
|
+
}
|
|
6769
|
+
} finally {
|
|
6770
|
+
if (this.executionController) {
|
|
6771
|
+
this.executionController._popCall();
|
|
6772
|
+
}
|
|
6773
|
+
}
|
|
6774
|
+
})();
|
|
6775
|
+
} else {
|
|
6776
|
+
if (this.executionController) {
|
|
6777
|
+
this.executionController._pushCall(funcName);
|
|
6778
|
+
}
|
|
6779
|
+
try {
|
|
6721
6780
|
if (metadata.expression) {
|
|
6722
|
-
const result =
|
|
6781
|
+
const result = this.evaluate(metadata.body, funcEnv);
|
|
6723
6782
|
if (result instanceof ThrowSignal) {
|
|
6724
6783
|
throw result.value;
|
|
6725
6784
|
}
|
|
6726
6785
|
return result;
|
|
6727
6786
|
} else {
|
|
6728
|
-
const result =
|
|
6787
|
+
const result = this.evaluate(metadata.body, funcEnv);
|
|
6729
6788
|
if (result instanceof ReturnValue) {
|
|
6730
6789
|
return result.value;
|
|
6731
6790
|
}
|
|
@@ -6734,23 +6793,10 @@ var Interpreter = class _Interpreter {
|
|
|
6734
6793
|
}
|
|
6735
6794
|
return void 0;
|
|
6736
6795
|
}
|
|
6737
|
-
}
|
|
6738
|
-
|
|
6739
|
-
|
|
6740
|
-
const result = this.evaluate(metadata.body, funcEnv);
|
|
6741
|
-
if (result instanceof ThrowSignal) {
|
|
6742
|
-
throw result.value;
|
|
6743
|
-
}
|
|
6744
|
-
return result;
|
|
6745
|
-
} else {
|
|
6746
|
-
const result = this.evaluate(metadata.body, funcEnv);
|
|
6747
|
-
if (result instanceof ReturnValue) {
|
|
6748
|
-
return result.value;
|
|
6749
|
-
}
|
|
6750
|
-
if (result instanceof ThrowSignal) {
|
|
6751
|
-
throw result.value;
|
|
6796
|
+
} finally {
|
|
6797
|
+
if (this.executionController) {
|
|
6798
|
+
this.executionController._popCall();
|
|
6752
6799
|
}
|
|
6753
|
-
return void 0;
|
|
6754
6800
|
}
|
|
6755
6801
|
}
|
|
6756
6802
|
}
|
|
@@ -7893,7 +7939,8 @@ var WangInterpreter = class {
|
|
|
7893
7939
|
}
|
|
7894
7940
|
const hasTopLevelReturn = this.hasTopLevelReturn(code);
|
|
7895
7941
|
const options = {
|
|
7896
|
-
moduleResolver: this.moduleResolver
|
|
7942
|
+
moduleResolver: this.moduleResolver,
|
|
7943
|
+
executionController: userOptions.executionController
|
|
7897
7944
|
// sourceType will be auto-detected from code
|
|
7898
7945
|
};
|
|
7899
7946
|
let result;
|
|
@@ -7972,6 +8019,191 @@ var InMemoryModuleResolver = class {
|
|
|
7972
8019
|
}
|
|
7973
8020
|
};
|
|
7974
8021
|
|
|
8022
|
+
// src/runtime/execution-controller.js
|
|
8023
|
+
var ExecutionController = class {
|
|
8024
|
+
constructor() {
|
|
8025
|
+
this.state = "idle";
|
|
8026
|
+
this.pauseRequested = false;
|
|
8027
|
+
this.abortRequested = false;
|
|
8028
|
+
this.stepCount = 0;
|
|
8029
|
+
this.currentNode = null;
|
|
8030
|
+
this.callStack = [];
|
|
8031
|
+
this.currentEnv = null;
|
|
8032
|
+
this._resolveResume = null;
|
|
8033
|
+
}
|
|
8034
|
+
// --- Control methods (called by user) ---
|
|
8035
|
+
/**
|
|
8036
|
+
* Request pause at next checkpoint. Only works during async evaluation.
|
|
8037
|
+
*/
|
|
8038
|
+
pause() {
|
|
8039
|
+
if (this.state === "running") {
|
|
8040
|
+
this.pauseRequested = true;
|
|
8041
|
+
}
|
|
8042
|
+
}
|
|
8043
|
+
/**
|
|
8044
|
+
* Resume execution after pause.
|
|
8045
|
+
*/
|
|
8046
|
+
resume() {
|
|
8047
|
+
if (this.state === "paused" && this._resolveResume) {
|
|
8048
|
+
this.pauseRequested = false;
|
|
8049
|
+
this._resolveResume();
|
|
8050
|
+
this._resolveResume = null;
|
|
8051
|
+
}
|
|
8052
|
+
}
|
|
8053
|
+
/**
|
|
8054
|
+
* Abort execution. Works for both sync and async evaluation.
|
|
8055
|
+
* If paused, will resume and then abort.
|
|
8056
|
+
*/
|
|
8057
|
+
abort() {
|
|
8058
|
+
this.abortRequested = true;
|
|
8059
|
+
if (this._resolveResume) {
|
|
8060
|
+
this._resolveResume();
|
|
8061
|
+
this._resolveResume = null;
|
|
8062
|
+
}
|
|
8063
|
+
}
|
|
8064
|
+
// --- Status (called by user) ---
|
|
8065
|
+
/**
|
|
8066
|
+
* Get current execution status with full debug information.
|
|
8067
|
+
* @returns {Object} Status object with state, stepCount, currentNode, callStack, and variables
|
|
8068
|
+
*/
|
|
8069
|
+
getStatus() {
|
|
8070
|
+
var _a;
|
|
8071
|
+
return {
|
|
8072
|
+
state: this.state,
|
|
8073
|
+
stepCount: this.stepCount,
|
|
8074
|
+
currentNode: ((_a = this.currentNode) == null ? void 0 : _a.type) || null,
|
|
8075
|
+
callStack: [...this.callStack],
|
|
8076
|
+
variables: this._getEnvironmentVariables()
|
|
8077
|
+
};
|
|
8078
|
+
}
|
|
8079
|
+
/**
|
|
8080
|
+
* Check if abort has been requested.
|
|
8081
|
+
* Compatible with AbortSignal interface.
|
|
8082
|
+
*/
|
|
8083
|
+
get aborted() {
|
|
8084
|
+
return this.abortRequested;
|
|
8085
|
+
}
|
|
8086
|
+
// --- Internal methods (called by interpreter) ---
|
|
8087
|
+
/**
|
|
8088
|
+
* Mark execution as started. Called by execute().
|
|
8089
|
+
* @internal
|
|
8090
|
+
*/
|
|
8091
|
+
_start() {
|
|
8092
|
+
this.state = "running";
|
|
8093
|
+
this.stepCount = 0;
|
|
8094
|
+
this.currentNode = null;
|
|
8095
|
+
this.callStack = [];
|
|
8096
|
+
this.pauseRequested = false;
|
|
8097
|
+
}
|
|
8098
|
+
/**
|
|
8099
|
+
* Mark execution as completed. Called by execute().
|
|
8100
|
+
* @internal
|
|
8101
|
+
*/
|
|
8102
|
+
_complete() {
|
|
8103
|
+
this.state = "completed";
|
|
8104
|
+
}
|
|
8105
|
+
/**
|
|
8106
|
+
* Push a function call onto the call stack.
|
|
8107
|
+
* @internal
|
|
8108
|
+
*/
|
|
8109
|
+
_pushCall(name) {
|
|
8110
|
+
this.callStack.push(name);
|
|
8111
|
+
}
|
|
8112
|
+
/**
|
|
8113
|
+
* Pop a function call from the call stack.
|
|
8114
|
+
* @internal
|
|
8115
|
+
*/
|
|
8116
|
+
_popCall() {
|
|
8117
|
+
this.callStack.pop();
|
|
8118
|
+
}
|
|
8119
|
+
/**
|
|
8120
|
+
* Set the current environment for variable introspection.
|
|
8121
|
+
* @internal
|
|
8122
|
+
*/
|
|
8123
|
+
_setEnv(env) {
|
|
8124
|
+
this.currentEnv = env;
|
|
8125
|
+
}
|
|
8126
|
+
/**
|
|
8127
|
+
* Async checkpoint - yields if paused, throws if aborted.
|
|
8128
|
+
* Called at coarse granularity points (loops, function calls).
|
|
8129
|
+
* @internal
|
|
8130
|
+
*/
|
|
8131
|
+
async _checkpoint(node) {
|
|
8132
|
+
this.stepCount++;
|
|
8133
|
+
this.currentNode = node;
|
|
8134
|
+
if (this.abortRequested) {
|
|
8135
|
+
this.state = "aborted";
|
|
8136
|
+
const error = new Error("The operation was aborted");
|
|
8137
|
+
error.name = "AbortError";
|
|
8138
|
+
throw error;
|
|
8139
|
+
}
|
|
8140
|
+
if (this.pauseRequested && this.state === "running") {
|
|
8141
|
+
this.state = "paused";
|
|
8142
|
+
await new Promise((resolve) => {
|
|
8143
|
+
this._resolveResume = resolve;
|
|
8144
|
+
});
|
|
8145
|
+
this.state = "running";
|
|
8146
|
+
if (this.abortRequested) {
|
|
8147
|
+
this.state = "aborted";
|
|
8148
|
+
const error = new Error("The operation was aborted");
|
|
8149
|
+
error.name = "AbortError";
|
|
8150
|
+
throw error;
|
|
8151
|
+
}
|
|
8152
|
+
}
|
|
8153
|
+
}
|
|
8154
|
+
/**
|
|
8155
|
+
* Sync abort check - only throws if aborted, cannot pause.
|
|
8156
|
+
* Used in sync evaluate() path.
|
|
8157
|
+
* @internal
|
|
8158
|
+
*/
|
|
8159
|
+
_checkAbortSync() {
|
|
8160
|
+
if (this.abortRequested) {
|
|
8161
|
+
this.state = "aborted";
|
|
8162
|
+
const error = new Error("The operation was aborted");
|
|
8163
|
+
error.name = "AbortError";
|
|
8164
|
+
throw error;
|
|
8165
|
+
}
|
|
8166
|
+
}
|
|
8167
|
+
/**
|
|
8168
|
+
* Get all variables from current environment chain.
|
|
8169
|
+
* @internal
|
|
8170
|
+
*/
|
|
8171
|
+
_getEnvironmentVariables() {
|
|
8172
|
+
if (!this.currentEnv) return {};
|
|
8173
|
+
const vars = {};
|
|
8174
|
+
let env = this.currentEnv;
|
|
8175
|
+
while (env) {
|
|
8176
|
+
if (env.vars) {
|
|
8177
|
+
for (const [key, value] of env.vars) {
|
|
8178
|
+
if (!(key in vars)) {
|
|
8179
|
+
vars[key] = this._serializeValue(value);
|
|
8180
|
+
}
|
|
8181
|
+
}
|
|
8182
|
+
}
|
|
8183
|
+
env = env.parent;
|
|
8184
|
+
}
|
|
8185
|
+
return vars;
|
|
8186
|
+
}
|
|
8187
|
+
/**
|
|
8188
|
+
* Serialize a value for status reporting.
|
|
8189
|
+
* @internal
|
|
8190
|
+
*/
|
|
8191
|
+
_serializeValue(value) {
|
|
8192
|
+
if (value === void 0) return { type: "undefined" };
|
|
8193
|
+
if (value === null) return { type: "null" };
|
|
8194
|
+
if (typeof value === "function" || value && value.__isFunction) {
|
|
8195
|
+
return { type: "function", name: value.name || "anonymous" };
|
|
8196
|
+
}
|
|
8197
|
+
if (Array.isArray(value)) {
|
|
8198
|
+
return { type: "array", length: value.length };
|
|
8199
|
+
}
|
|
8200
|
+
if (typeof value === "object") {
|
|
8201
|
+
return { type: "object", preview: Object.keys(value).slice(0, 5) };
|
|
8202
|
+
}
|
|
8203
|
+
return { type: typeof value, value };
|
|
8204
|
+
}
|
|
8205
|
+
};
|
|
8206
|
+
|
|
7975
8207
|
// src/index.js
|
|
7976
8208
|
function containsModuleSyntax(code) {
|
|
7977
8209
|
if (/^\s*(import|export)\s+/m.test(code)) {
|
|
@@ -8038,21 +8270,39 @@ function containsTopLevelAwait(node) {
|
|
|
8038
8270
|
return false;
|
|
8039
8271
|
}
|
|
8040
8272
|
async function execute(code, env = null, options = {}) {
|
|
8041
|
-
const
|
|
8042
|
-
if (
|
|
8043
|
-
|
|
8273
|
+
const controller = options.executionController;
|
|
8274
|
+
if (controller) {
|
|
8275
|
+
controller._start();
|
|
8044
8276
|
}
|
|
8045
|
-
|
|
8046
|
-
|
|
8047
|
-
|
|
8048
|
-
|
|
8049
|
-
|
|
8050
|
-
|
|
8051
|
-
|
|
8052
|
-
|
|
8053
|
-
|
|
8054
|
-
|
|
8055
|
-
|
|
8277
|
+
try {
|
|
8278
|
+
const ast = parse4(code, options);
|
|
8279
|
+
if (!env) {
|
|
8280
|
+
env = createGlobalEnvironment(new Environment());
|
|
8281
|
+
}
|
|
8282
|
+
const interpreter = new Interpreter(env, {
|
|
8283
|
+
moduleResolver: options.moduleResolver,
|
|
8284
|
+
abortSignal: options.abortSignal,
|
|
8285
|
+
executionController: controller
|
|
8286
|
+
});
|
|
8287
|
+
const needsAsync = options.sourceType === "module" || containsModuleDeclarations(ast) || containsTopLevelAwait(ast) || controller != null;
|
|
8288
|
+
if (needsAsync) {
|
|
8289
|
+
const result = await interpreter.evaluateAsync(ast, env);
|
|
8290
|
+
if (controller) {
|
|
8291
|
+
controller._complete();
|
|
8292
|
+
}
|
|
8293
|
+
return result instanceof ReturnValue ? result.value : result;
|
|
8294
|
+
} else {
|
|
8295
|
+
const result = interpreter.evaluate(ast, env);
|
|
8296
|
+
if (controller) {
|
|
8297
|
+
controller._complete();
|
|
8298
|
+
}
|
|
8299
|
+
return result instanceof ReturnValue ? result.value : result;
|
|
8300
|
+
}
|
|
8301
|
+
} catch (e) {
|
|
8302
|
+
if (controller && e.name === "AbortError") {
|
|
8303
|
+
controller.state = "aborted";
|
|
8304
|
+
}
|
|
8305
|
+
throw e;
|
|
8056
8306
|
}
|
|
8057
8307
|
}
|
|
8058
8308
|
function createEnvironment() {
|
|
@@ -8089,6 +8339,7 @@ var ModuleResolver = class {
|
|
|
8089
8339
|
};
|
|
8090
8340
|
export {
|
|
8091
8341
|
Environment,
|
|
8342
|
+
ExecutionController,
|
|
8092
8343
|
InMemoryModuleResolver,
|
|
8093
8344
|
Interpreter,
|
|
8094
8345
|
ModuleResolver,
|