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.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
var src_exports = {};
|
|
21
21
|
__export(src_exports, {
|
|
22
22
|
Environment: () => Environment,
|
|
23
|
+
ExecutionController: () => ExecutionController,
|
|
23
24
|
InMemoryModuleResolver: () => InMemoryModuleResolver,
|
|
24
25
|
Interpreter: () => Interpreter,
|
|
25
26
|
ModuleResolver: () => ModuleResolver,
|
|
@@ -5817,19 +5818,36 @@ var Interpreter = class _Interpreter {
|
|
|
5817
5818
|
this.moduleCache = /* @__PURE__ */ new Map();
|
|
5818
5819
|
this.moduleExports = {};
|
|
5819
5820
|
this.abortSignal = options.abortSignal;
|
|
5821
|
+
this.executionController = options.executionController;
|
|
5820
5822
|
}
|
|
5821
|
-
// Check if execution should be aborted
|
|
5823
|
+
// Check if execution should be aborted (sync version)
|
|
5822
5824
|
checkAbortSignal() {
|
|
5825
|
+
if (this.executionController) {
|
|
5826
|
+
this.executionController._checkAbortSync();
|
|
5827
|
+
return;
|
|
5828
|
+
}
|
|
5823
5829
|
if (this.abortSignal && this.abortSignal.aborted) {
|
|
5824
5830
|
const error = new Error("The operation was aborted");
|
|
5825
5831
|
error.name = "AbortError";
|
|
5826
5832
|
throw error;
|
|
5827
5833
|
}
|
|
5828
5834
|
}
|
|
5835
|
+
// Checkpoint that returns a promise only when controller is present
|
|
5836
|
+
// When no controller, returns null to signal no await needed
|
|
5837
|
+
_getCheckpointPromise(node, env) {
|
|
5838
|
+
if (this.executionController) {
|
|
5839
|
+
this.executionController._setEnv(env);
|
|
5840
|
+
return this.executionController._checkpoint(node);
|
|
5841
|
+
} else {
|
|
5842
|
+
this.checkAbortSignal();
|
|
5843
|
+
return null;
|
|
5844
|
+
}
|
|
5845
|
+
}
|
|
5829
5846
|
// Async evaluation for async functions - handles await expressions
|
|
5830
5847
|
async evaluateAsync(node, env) {
|
|
5831
5848
|
if (!node) return void 0;
|
|
5832
|
-
this.
|
|
5849
|
+
const checkpointPromise = this._getCheckpointPromise(node, env);
|
|
5850
|
+
if (checkpointPromise) await checkpointPromise;
|
|
5833
5851
|
if (node.type === "AwaitExpression") {
|
|
5834
5852
|
const promise = await this.evaluateAsync(node.argument, env);
|
|
5835
5853
|
return await promise;
|
|
@@ -6000,6 +6018,8 @@ var Interpreter = class _Interpreter {
|
|
|
6000
6018
|
await this.evaluateAsync(node.init, forEnv);
|
|
6001
6019
|
}
|
|
6002
6020
|
while (!node.test || await this.evaluateAsync(node.test, forEnv)) {
|
|
6021
|
+
const cp1 = this._getCheckpointPromise(node, forEnv);
|
|
6022
|
+
if (cp1) await cp1;
|
|
6003
6023
|
const result = await this.evaluateAsync(node.body, forEnv);
|
|
6004
6024
|
if (result instanceof BreakSignal) {
|
|
6005
6025
|
break;
|
|
@@ -6025,6 +6045,8 @@ var Interpreter = class _Interpreter {
|
|
|
6025
6045
|
const declarator = node.left.declarations[0];
|
|
6026
6046
|
const isConst = node.left.kind === "const";
|
|
6027
6047
|
for (const value of iterable) {
|
|
6048
|
+
const cp2 = this._getCheckpointPromise(node, forEnv);
|
|
6049
|
+
if (cp2) await cp2;
|
|
6028
6050
|
const iterEnv = forEnv.extend();
|
|
6029
6051
|
if (declarator.id.type === "Identifier") {
|
|
6030
6052
|
iterEnv.define(declarator.id.name, value, isConst);
|
|
@@ -6055,6 +6077,8 @@ var Interpreter = class _Interpreter {
|
|
|
6055
6077
|
const varName = node.left.declarations[0].id.name;
|
|
6056
6078
|
forEnv.define(varName, void 0);
|
|
6057
6079
|
for (const key in obj) {
|
|
6080
|
+
const cp3 = this._getCheckpointPromise(node, forEnv);
|
|
6081
|
+
if (cp3) await cp3;
|
|
6058
6082
|
forEnv.set(varName, key);
|
|
6059
6083
|
const result = await this.evaluateAsync(node.body, forEnv);
|
|
6060
6084
|
if (result instanceof BreakSignal) {
|
|
@@ -6071,6 +6095,8 @@ var Interpreter = class _Interpreter {
|
|
|
6071
6095
|
}
|
|
6072
6096
|
if (node.type === "WhileStatement") {
|
|
6073
6097
|
while (await this.evaluateAsync(node.test, env)) {
|
|
6098
|
+
const cp4 = this._getCheckpointPromise(node, env);
|
|
6099
|
+
if (cp4) await cp4;
|
|
6074
6100
|
const result = await this.evaluateAsync(node.body, env);
|
|
6075
6101
|
if (result instanceof BreakSignal) {
|
|
6076
6102
|
break;
|
|
@@ -6086,6 +6112,8 @@ var Interpreter = class _Interpreter {
|
|
|
6086
6112
|
}
|
|
6087
6113
|
if (node.type === "DoWhileStatement") {
|
|
6088
6114
|
do {
|
|
6115
|
+
const cp5 = this._getCheckpointPromise(node, env);
|
|
6116
|
+
if (cp5) await cp5;
|
|
6089
6117
|
const result = await this.evaluateAsync(node.body, env);
|
|
6090
6118
|
if (result instanceof BreakSignal) {
|
|
6091
6119
|
break;
|
|
@@ -6728,6 +6756,7 @@ var Interpreter = class _Interpreter {
|
|
|
6728
6756
|
callUserFunction(func, args, callingEnv, thisContext = void 0) {
|
|
6729
6757
|
const metadata = func.__metadata || func;
|
|
6730
6758
|
const funcEnv = new Environment(metadata.closure);
|
|
6759
|
+
const funcName = metadata.name || func.name || "anonymous";
|
|
6731
6760
|
if (thisContext !== void 0) {
|
|
6732
6761
|
funcEnv.define("this", thisContext);
|
|
6733
6762
|
}
|
|
@@ -6750,15 +6779,46 @@ var Interpreter = class _Interpreter {
|
|
|
6750
6779
|
}
|
|
6751
6780
|
}
|
|
6752
6781
|
if (metadata.async) {
|
|
6782
|
+
if (this.executionController) {
|
|
6783
|
+
this.executionController._pushCall(funcName);
|
|
6784
|
+
}
|
|
6753
6785
|
return (async () => {
|
|
6786
|
+
try {
|
|
6787
|
+
if (metadata.expression) {
|
|
6788
|
+
const result = await this.evaluateAsync(metadata.body, funcEnv);
|
|
6789
|
+
if (result instanceof ThrowSignal) {
|
|
6790
|
+
throw result.value;
|
|
6791
|
+
}
|
|
6792
|
+
return result;
|
|
6793
|
+
} else {
|
|
6794
|
+
const result = await this.evaluateAsync(metadata.body, funcEnv);
|
|
6795
|
+
if (result instanceof ReturnValue) {
|
|
6796
|
+
return result.value;
|
|
6797
|
+
}
|
|
6798
|
+
if (result instanceof ThrowSignal) {
|
|
6799
|
+
throw result.value;
|
|
6800
|
+
}
|
|
6801
|
+
return void 0;
|
|
6802
|
+
}
|
|
6803
|
+
} finally {
|
|
6804
|
+
if (this.executionController) {
|
|
6805
|
+
this.executionController._popCall();
|
|
6806
|
+
}
|
|
6807
|
+
}
|
|
6808
|
+
})();
|
|
6809
|
+
} else {
|
|
6810
|
+
if (this.executionController) {
|
|
6811
|
+
this.executionController._pushCall(funcName);
|
|
6812
|
+
}
|
|
6813
|
+
try {
|
|
6754
6814
|
if (metadata.expression) {
|
|
6755
|
-
const result =
|
|
6815
|
+
const result = this.evaluate(metadata.body, funcEnv);
|
|
6756
6816
|
if (result instanceof ThrowSignal) {
|
|
6757
6817
|
throw result.value;
|
|
6758
6818
|
}
|
|
6759
6819
|
return result;
|
|
6760
6820
|
} else {
|
|
6761
|
-
const result =
|
|
6821
|
+
const result = this.evaluate(metadata.body, funcEnv);
|
|
6762
6822
|
if (result instanceof ReturnValue) {
|
|
6763
6823
|
return result.value;
|
|
6764
6824
|
}
|
|
@@ -6767,23 +6827,10 @@ var Interpreter = class _Interpreter {
|
|
|
6767
6827
|
}
|
|
6768
6828
|
return void 0;
|
|
6769
6829
|
}
|
|
6770
|
-
}
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
const result = this.evaluate(metadata.body, funcEnv);
|
|
6774
|
-
if (result instanceof ThrowSignal) {
|
|
6775
|
-
throw result.value;
|
|
6776
|
-
}
|
|
6777
|
-
return result;
|
|
6778
|
-
} else {
|
|
6779
|
-
const result = this.evaluate(metadata.body, funcEnv);
|
|
6780
|
-
if (result instanceof ReturnValue) {
|
|
6781
|
-
return result.value;
|
|
6782
|
-
}
|
|
6783
|
-
if (result instanceof ThrowSignal) {
|
|
6784
|
-
throw result.value;
|
|
6830
|
+
} finally {
|
|
6831
|
+
if (this.executionController) {
|
|
6832
|
+
this.executionController._popCall();
|
|
6785
6833
|
}
|
|
6786
|
-
return void 0;
|
|
6787
6834
|
}
|
|
6788
6835
|
}
|
|
6789
6836
|
}
|
|
@@ -7926,7 +7973,8 @@ var WangInterpreter = class {
|
|
|
7926
7973
|
}
|
|
7927
7974
|
const hasTopLevelReturn = this.hasTopLevelReturn(code);
|
|
7928
7975
|
const options = {
|
|
7929
|
-
moduleResolver: this.moduleResolver
|
|
7976
|
+
moduleResolver: this.moduleResolver,
|
|
7977
|
+
executionController: userOptions.executionController
|
|
7930
7978
|
// sourceType will be auto-detected from code
|
|
7931
7979
|
};
|
|
7932
7980
|
let result;
|
|
@@ -8005,6 +8053,191 @@ var InMemoryModuleResolver = class {
|
|
|
8005
8053
|
}
|
|
8006
8054
|
};
|
|
8007
8055
|
|
|
8056
|
+
// src/runtime/execution-controller.js
|
|
8057
|
+
var ExecutionController = class {
|
|
8058
|
+
constructor() {
|
|
8059
|
+
this.state = "idle";
|
|
8060
|
+
this.pauseRequested = false;
|
|
8061
|
+
this.abortRequested = false;
|
|
8062
|
+
this.stepCount = 0;
|
|
8063
|
+
this.currentNode = null;
|
|
8064
|
+
this.callStack = [];
|
|
8065
|
+
this.currentEnv = null;
|
|
8066
|
+
this._resolveResume = null;
|
|
8067
|
+
}
|
|
8068
|
+
// --- Control methods (called by user) ---
|
|
8069
|
+
/**
|
|
8070
|
+
* Request pause at next checkpoint. Only works during async evaluation.
|
|
8071
|
+
*/
|
|
8072
|
+
pause() {
|
|
8073
|
+
if (this.state === "running") {
|
|
8074
|
+
this.pauseRequested = true;
|
|
8075
|
+
}
|
|
8076
|
+
}
|
|
8077
|
+
/**
|
|
8078
|
+
* Resume execution after pause.
|
|
8079
|
+
*/
|
|
8080
|
+
resume() {
|
|
8081
|
+
if (this.state === "paused" && this._resolveResume) {
|
|
8082
|
+
this.pauseRequested = false;
|
|
8083
|
+
this._resolveResume();
|
|
8084
|
+
this._resolveResume = null;
|
|
8085
|
+
}
|
|
8086
|
+
}
|
|
8087
|
+
/**
|
|
8088
|
+
* Abort execution. Works for both sync and async evaluation.
|
|
8089
|
+
* If paused, will resume and then abort.
|
|
8090
|
+
*/
|
|
8091
|
+
abort() {
|
|
8092
|
+
this.abortRequested = true;
|
|
8093
|
+
if (this._resolveResume) {
|
|
8094
|
+
this._resolveResume();
|
|
8095
|
+
this._resolveResume = null;
|
|
8096
|
+
}
|
|
8097
|
+
}
|
|
8098
|
+
// --- Status (called by user) ---
|
|
8099
|
+
/**
|
|
8100
|
+
* Get current execution status with full debug information.
|
|
8101
|
+
* @returns {Object} Status object with state, stepCount, currentNode, callStack, and variables
|
|
8102
|
+
*/
|
|
8103
|
+
getStatus() {
|
|
8104
|
+
var _a;
|
|
8105
|
+
return {
|
|
8106
|
+
state: this.state,
|
|
8107
|
+
stepCount: this.stepCount,
|
|
8108
|
+
currentNode: ((_a = this.currentNode) == null ? void 0 : _a.type) || null,
|
|
8109
|
+
callStack: [...this.callStack],
|
|
8110
|
+
variables: this._getEnvironmentVariables()
|
|
8111
|
+
};
|
|
8112
|
+
}
|
|
8113
|
+
/**
|
|
8114
|
+
* Check if abort has been requested.
|
|
8115
|
+
* Compatible with AbortSignal interface.
|
|
8116
|
+
*/
|
|
8117
|
+
get aborted() {
|
|
8118
|
+
return this.abortRequested;
|
|
8119
|
+
}
|
|
8120
|
+
// --- Internal methods (called by interpreter) ---
|
|
8121
|
+
/**
|
|
8122
|
+
* Mark execution as started. Called by execute().
|
|
8123
|
+
* @internal
|
|
8124
|
+
*/
|
|
8125
|
+
_start() {
|
|
8126
|
+
this.state = "running";
|
|
8127
|
+
this.stepCount = 0;
|
|
8128
|
+
this.currentNode = null;
|
|
8129
|
+
this.callStack = [];
|
|
8130
|
+
this.pauseRequested = false;
|
|
8131
|
+
}
|
|
8132
|
+
/**
|
|
8133
|
+
* Mark execution as completed. Called by execute().
|
|
8134
|
+
* @internal
|
|
8135
|
+
*/
|
|
8136
|
+
_complete() {
|
|
8137
|
+
this.state = "completed";
|
|
8138
|
+
}
|
|
8139
|
+
/**
|
|
8140
|
+
* Push a function call onto the call stack.
|
|
8141
|
+
* @internal
|
|
8142
|
+
*/
|
|
8143
|
+
_pushCall(name) {
|
|
8144
|
+
this.callStack.push(name);
|
|
8145
|
+
}
|
|
8146
|
+
/**
|
|
8147
|
+
* Pop a function call from the call stack.
|
|
8148
|
+
* @internal
|
|
8149
|
+
*/
|
|
8150
|
+
_popCall() {
|
|
8151
|
+
this.callStack.pop();
|
|
8152
|
+
}
|
|
8153
|
+
/**
|
|
8154
|
+
* Set the current environment for variable introspection.
|
|
8155
|
+
* @internal
|
|
8156
|
+
*/
|
|
8157
|
+
_setEnv(env) {
|
|
8158
|
+
this.currentEnv = env;
|
|
8159
|
+
}
|
|
8160
|
+
/**
|
|
8161
|
+
* Async checkpoint - yields if paused, throws if aborted.
|
|
8162
|
+
* Called at coarse granularity points (loops, function calls).
|
|
8163
|
+
* @internal
|
|
8164
|
+
*/
|
|
8165
|
+
async _checkpoint(node) {
|
|
8166
|
+
this.stepCount++;
|
|
8167
|
+
this.currentNode = node;
|
|
8168
|
+
if (this.abortRequested) {
|
|
8169
|
+
this.state = "aborted";
|
|
8170
|
+
const error = new Error("The operation was aborted");
|
|
8171
|
+
error.name = "AbortError";
|
|
8172
|
+
throw error;
|
|
8173
|
+
}
|
|
8174
|
+
if (this.pauseRequested && this.state === "running") {
|
|
8175
|
+
this.state = "paused";
|
|
8176
|
+
await new Promise((resolve) => {
|
|
8177
|
+
this._resolveResume = resolve;
|
|
8178
|
+
});
|
|
8179
|
+
this.state = "running";
|
|
8180
|
+
if (this.abortRequested) {
|
|
8181
|
+
this.state = "aborted";
|
|
8182
|
+
const error = new Error("The operation was aborted");
|
|
8183
|
+
error.name = "AbortError";
|
|
8184
|
+
throw error;
|
|
8185
|
+
}
|
|
8186
|
+
}
|
|
8187
|
+
}
|
|
8188
|
+
/**
|
|
8189
|
+
* Sync abort check - only throws if aborted, cannot pause.
|
|
8190
|
+
* Used in sync evaluate() path.
|
|
8191
|
+
* @internal
|
|
8192
|
+
*/
|
|
8193
|
+
_checkAbortSync() {
|
|
8194
|
+
if (this.abortRequested) {
|
|
8195
|
+
this.state = "aborted";
|
|
8196
|
+
const error = new Error("The operation was aborted");
|
|
8197
|
+
error.name = "AbortError";
|
|
8198
|
+
throw error;
|
|
8199
|
+
}
|
|
8200
|
+
}
|
|
8201
|
+
/**
|
|
8202
|
+
* Get all variables from current environment chain.
|
|
8203
|
+
* @internal
|
|
8204
|
+
*/
|
|
8205
|
+
_getEnvironmentVariables() {
|
|
8206
|
+
if (!this.currentEnv) return {};
|
|
8207
|
+
const vars = {};
|
|
8208
|
+
let env = this.currentEnv;
|
|
8209
|
+
while (env) {
|
|
8210
|
+
if (env.vars) {
|
|
8211
|
+
for (const [key, value] of env.vars) {
|
|
8212
|
+
if (!(key in vars)) {
|
|
8213
|
+
vars[key] = this._serializeValue(value);
|
|
8214
|
+
}
|
|
8215
|
+
}
|
|
8216
|
+
}
|
|
8217
|
+
env = env.parent;
|
|
8218
|
+
}
|
|
8219
|
+
return vars;
|
|
8220
|
+
}
|
|
8221
|
+
/**
|
|
8222
|
+
* Serialize a value for status reporting.
|
|
8223
|
+
* @internal
|
|
8224
|
+
*/
|
|
8225
|
+
_serializeValue(value) {
|
|
8226
|
+
if (value === void 0) return { type: "undefined" };
|
|
8227
|
+
if (value === null) return { type: "null" };
|
|
8228
|
+
if (typeof value === "function" || value && value.__isFunction) {
|
|
8229
|
+
return { type: "function", name: value.name || "anonymous" };
|
|
8230
|
+
}
|
|
8231
|
+
if (Array.isArray(value)) {
|
|
8232
|
+
return { type: "array", length: value.length };
|
|
8233
|
+
}
|
|
8234
|
+
if (typeof value === "object") {
|
|
8235
|
+
return { type: "object", preview: Object.keys(value).slice(0, 5) };
|
|
8236
|
+
}
|
|
8237
|
+
return { type: typeof value, value };
|
|
8238
|
+
}
|
|
8239
|
+
};
|
|
8240
|
+
|
|
8008
8241
|
// src/index.js
|
|
8009
8242
|
function containsModuleSyntax(code) {
|
|
8010
8243
|
if (/^\s*(import|export)\s+/m.test(code)) {
|
|
@@ -8071,21 +8304,39 @@ function containsTopLevelAwait(node) {
|
|
|
8071
8304
|
return false;
|
|
8072
8305
|
}
|
|
8073
8306
|
async function execute(code, env = null, options = {}) {
|
|
8074
|
-
const
|
|
8075
|
-
if (
|
|
8076
|
-
|
|
8307
|
+
const controller = options.executionController;
|
|
8308
|
+
if (controller) {
|
|
8309
|
+
controller._start();
|
|
8077
8310
|
}
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
|
|
8086
|
-
|
|
8087
|
-
|
|
8088
|
-
|
|
8311
|
+
try {
|
|
8312
|
+
const ast = parse4(code, options);
|
|
8313
|
+
if (!env) {
|
|
8314
|
+
env = createGlobalEnvironment(new Environment());
|
|
8315
|
+
}
|
|
8316
|
+
const interpreter = new Interpreter(env, {
|
|
8317
|
+
moduleResolver: options.moduleResolver,
|
|
8318
|
+
abortSignal: options.abortSignal,
|
|
8319
|
+
executionController: controller
|
|
8320
|
+
});
|
|
8321
|
+
const needsAsync = options.sourceType === "module" || containsModuleDeclarations(ast) || containsTopLevelAwait(ast) || controller != null;
|
|
8322
|
+
if (needsAsync) {
|
|
8323
|
+
const result = await interpreter.evaluateAsync(ast, env);
|
|
8324
|
+
if (controller) {
|
|
8325
|
+
controller._complete();
|
|
8326
|
+
}
|
|
8327
|
+
return result instanceof ReturnValue ? result.value : result;
|
|
8328
|
+
} else {
|
|
8329
|
+
const result = interpreter.evaluate(ast, env);
|
|
8330
|
+
if (controller) {
|
|
8331
|
+
controller._complete();
|
|
8332
|
+
}
|
|
8333
|
+
return result instanceof ReturnValue ? result.value : result;
|
|
8334
|
+
}
|
|
8335
|
+
} catch (e) {
|
|
8336
|
+
if (controller && e.name === "AbortError") {
|
|
8337
|
+
controller.state = "aborted";
|
|
8338
|
+
}
|
|
8339
|
+
throw e;
|
|
8089
8340
|
}
|
|
8090
8341
|
}
|
|
8091
8342
|
function createEnvironment() {
|
|
@@ -8123,6 +8374,7 @@ var ModuleResolver = class {
|
|
|
8123
8374
|
// Annotate the CommonJS export names for ESM import in node:
|
|
8124
8375
|
0 && (module.exports = {
|
|
8125
8376
|
Environment,
|
|
8377
|
+
ExecutionController,
|
|
8126
8378
|
InMemoryModuleResolver,
|
|
8127
8379
|
Interpreter,
|
|
8128
8380
|
ModuleResolver,
|