quickjs-emscripten-sync 1.6.0 → 1.7.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/index.d.ts +27 -8
- package/dist/quickjs-emscripten-sync.mjs +26 -10
- package/dist/quickjs-emscripten-sync.umd.js +2 -2
- package/package.json +2 -2
- package/src/index.test.ts +121 -0
- package/src/index.ts +28 -9
- package/src/vmutil.ts +4 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Intrinsics } from 'quickjs-emscripten';
|
|
1
2
|
import { QuickJSContext } from 'quickjs-emscripten';
|
|
2
3
|
import { QuickJSDeferredPromise } from 'quickjs-emscripten';
|
|
3
4
|
import { QuickJSHandle } from 'quickjs-emscripten';
|
|
@@ -28,22 +29,38 @@ export declare class Arena {
|
|
|
28
29
|
*/
|
|
29
30
|
evalCode<T = any>(code: string): T;
|
|
30
31
|
/**
|
|
31
|
-
* Evaluate ES module code in the VM
|
|
32
|
-
*
|
|
33
|
-
*
|
|
32
|
+
* Evaluate ES module code in the VM and get the module's exports.
|
|
33
|
+
*
|
|
34
|
+
* Requires quickjs-emscripten >= 0.29.0 for export access.
|
|
34
35
|
*
|
|
35
36
|
* @param code - The ES module code to evaluate
|
|
36
37
|
* @param filename - Optional filename for debugging purposes (default: "module.js")
|
|
37
|
-
* @returns
|
|
38
|
+
* @returns The module's exports object, or a Promise resolving to exports if using top-level await
|
|
38
39
|
*
|
|
39
40
|
* @example
|
|
40
41
|
* ```js
|
|
41
|
-
* //
|
|
42
|
-
* arena.
|
|
43
|
-
*
|
|
42
|
+
* // Simple module with exports
|
|
43
|
+
* const exports = arena.evalModule(`
|
|
44
|
+
* export const value = 42;
|
|
45
|
+
* export function greet(name) {
|
|
46
|
+
* return "Hello, " + name;
|
|
47
|
+
* }
|
|
48
|
+
* `);
|
|
49
|
+
* console.log(exports.value); // 42
|
|
50
|
+
* console.log(exports.greet("World")); // "Hello, World"
|
|
51
|
+
*
|
|
52
|
+
* // Module with default export
|
|
53
|
+
* const mod = arena.evalModule('export default function(x) { return x * 2; }');
|
|
54
|
+
* console.log(mod.default(21)); // 42
|
|
55
|
+
*
|
|
56
|
+
* // Module with top-level await
|
|
57
|
+
* const promise = arena.evalModule('export const data = await Promise.resolve(123);');
|
|
58
|
+
* arena.executePendingJobs();
|
|
59
|
+
* const exports = await promise;
|
|
60
|
+
* console.log(exports.data); // 123
|
|
44
61
|
* ```
|
|
45
62
|
*/
|
|
46
|
-
evalModule(code: string, filename?: string):
|
|
63
|
+
evalModule<T = any>(code: string, filename?: string): T | Promise<T>;
|
|
47
64
|
/**
|
|
48
65
|
* Almost same as `vm.executePendingJobs()`, but it converts and re-throws error objects when an error is thrown during evaluation.
|
|
49
66
|
*/
|
|
@@ -216,6 +233,8 @@ export declare const defaultRegisteredObjects: [any, string][];
|
|
|
216
233
|
|
|
217
234
|
export declare function eq(ctx: QuickJSContext, a: QuickJSHandle, b: QuickJSHandle): boolean;
|
|
218
235
|
|
|
236
|
+
export { Intrinsics }
|
|
237
|
+
|
|
219
238
|
export declare function isES2015Class(cls: any): cls is new (...args: any[]) => any;
|
|
220
239
|
|
|
221
240
|
export declare function isHandleObject(ctx: QuickJSContext, h: QuickJSHandle): boolean;
|
|
@@ -85,8 +85,8 @@ const I = [
|
|
|
85
85
|
...Object.getOwnPropertyNames(Symbol).filter((n) => typeof Symbol[n] == "symbol").map((n) => [Symbol[n], `Symbol.${n}`])
|
|
86
86
|
];
|
|
87
87
|
function T(n, e) {
|
|
88
|
-
const t = n.unwrapResult(n.evalCode(e)), r = (
|
|
89
|
-
return r.dispose =
|
|
88
|
+
const t = n.unwrapResult(n.evalCode(e)), r = (o, ...i) => n.unwrapResult(n.callFunction(t, o != null ? o : n.undefined, ...i)), s = () => t.dispose();
|
|
89
|
+
return r.dispose = s, r[Symbol.dispose] = s, r.alive = !0, Object.defineProperty(r, "alive", {
|
|
90
90
|
get: () => t.alive
|
|
91
91
|
}), r;
|
|
92
92
|
}
|
|
@@ -811,24 +811,40 @@ class we {
|
|
|
811
811
|
return this._unwrapResultAndUnmarshal(t);
|
|
812
812
|
}
|
|
813
813
|
/**
|
|
814
|
-
* Evaluate ES module code in the VM
|
|
815
|
-
*
|
|
816
|
-
*
|
|
814
|
+
* Evaluate ES module code in the VM and get the module's exports.
|
|
815
|
+
*
|
|
816
|
+
* Requires quickjs-emscripten >= 0.29.0 for export access.
|
|
817
817
|
*
|
|
818
818
|
* @param code - The ES module code to evaluate
|
|
819
819
|
* @param filename - Optional filename for debugging purposes (default: "module.js")
|
|
820
|
-
* @returns
|
|
820
|
+
* @returns The module's exports object, or a Promise resolving to exports if using top-level await
|
|
821
821
|
*
|
|
822
822
|
* @example
|
|
823
823
|
* ```js
|
|
824
|
-
* //
|
|
825
|
-
* arena.
|
|
826
|
-
*
|
|
824
|
+
* // Simple module with exports
|
|
825
|
+
* const exports = arena.evalModule(`
|
|
826
|
+
* export const value = 42;
|
|
827
|
+
* export function greet(name) {
|
|
828
|
+
* return "Hello, " + name;
|
|
829
|
+
* }
|
|
830
|
+
* `);
|
|
831
|
+
* console.log(exports.value); // 42
|
|
832
|
+
* console.log(exports.greet("World")); // "Hello, World"
|
|
833
|
+
*
|
|
834
|
+
* // Module with default export
|
|
835
|
+
* const mod = arena.evalModule('export default function(x) { return x * 2; }');
|
|
836
|
+
* console.log(mod.default(21)); // 42
|
|
837
|
+
*
|
|
838
|
+
* // Module with top-level await
|
|
839
|
+
* const promise = arena.evalModule('export const data = await Promise.resolve(123);');
|
|
840
|
+
* arena.executePendingJobs();
|
|
841
|
+
* const exports = await promise;
|
|
842
|
+
* console.log(exports.data); // 123
|
|
827
843
|
* ```
|
|
828
844
|
*/
|
|
829
845
|
evalModule(e, t = "module.js") {
|
|
830
846
|
const r = this.context.evalCode(e, t, { type: "module" });
|
|
831
|
-
this._unwrapResultAndUnmarshal(r);
|
|
847
|
+
return this._unwrapResultAndUnmarshal(r);
|
|
832
848
|
}
|
|
833
849
|
/**
|
|
834
850
|
* Almost same as `vm.executePendingJobs()`, but it converts and re-throws error objects when an error is thrown during evaluation.
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
fn.name = name;
|
|
6
6
|
fn.length = length;
|
|
7
7
|
return fn;
|
|
8
|
-
})`))}disposeEx(){this.fnGenerator.dispose(),this.fn.dispose()}}const k=[[Symbol,"Symbol"],[Symbol.prototype,"Symbol.prototype"],[Object,"Object"],[Object.prototype,"Object.prototype"],[Function,"Function"],[Function.prototype,"Function.prototype"],[Boolean,"Boolean"],[Boolean.prototype,"Boolean.prototype"],[Array,"Array"],[Array.prototype,"Array.prototype"],[Error,"Error"],[Error.prototype,"Error.prototype"],[EvalError,"EvalError"],[EvalError.prototype,"EvalError.prototype"],[RangeError,"RangeError"],[RangeError.prototype,"RangeError.prototype"],[ReferenceError,"ReferenceError"],[ReferenceError.prototype,"ReferenceError.prototype"],[SyntaxError,"SyntaxError"],[SyntaxError.prototype,"SyntaxError.prototype"],[TypeError,"TypeError"],[TypeError.prototype,"TypeError.prototype"],[URIError,"URIError"],[URIError.prototype,"URIError.prototype"],...Object.getOwnPropertyNames(Symbol).filter(n=>typeof Symbol[n]=="symbol").map(n=>[Symbol[n],`Symbol.${n}`])];function J(n,e){const t=n.unwrapResult(n.evalCode(e)),r=(
|
|
8
|
+
})`))}disposeEx(){this.fnGenerator.dispose(),this.fn.dispose()}}const k=[[Symbol,"Symbol"],[Symbol.prototype,"Symbol.prototype"],[Object,"Object"],[Object.prototype,"Object.prototype"],[Function,"Function"],[Function.prototype,"Function.prototype"],[Boolean,"Boolean"],[Boolean.prototype,"Boolean.prototype"],[Array,"Array"],[Array.prototype,"Array.prototype"],[Error,"Error"],[Error.prototype,"Error.prototype"],[EvalError,"EvalError"],[EvalError.prototype,"EvalError.prototype"],[RangeError,"RangeError"],[RangeError.prototype,"RangeError.prototype"],[ReferenceError,"ReferenceError"],[ReferenceError.prototype,"ReferenceError.prototype"],[SyntaxError,"SyntaxError"],[SyntaxError.prototype,"SyntaxError.prototype"],[TypeError,"TypeError"],[TypeError.prototype,"TypeError.prototype"],[URIError,"URIError"],[URIError.prototype,"URIError.prototype"],...Object.getOwnPropertyNames(Symbol).filter(n=>typeof Symbol[n]=="symbol").map(n=>[Symbol[n],`Symbol.${n}`])];function J(n,e){const t=n.unwrapResult(n.evalCode(e)),r=(o,...i)=>n.unwrapResult(n.callFunction(t,o!=null?o:n.undefined,...i)),s=()=>t.dispose();return r.dispose=s,r[Symbol.dispose]=s,r.alive=!0,Object.defineProperty(r,"alive",{get:()=>t.alive}),r}function _(n,e,t,...r){const s=J(n,e);try{return s(t,...r)}finally{s.dispose()}}function C(n,e,t){return n.dump(_(n,"Object.is",void 0,e,t))}function W(n,e,t){return n.dump(_(n,"(a, b) => a instanceof b",void 0,e,t))}function F(n,e){return n.dump(_(n,'a => typeof a === "object" && a !== null || typeof a === "function"',void 0,e))}function H(n,e){const t=JSON.stringify(e);return t?_(n,"JSON.parse",void 0,n.newString(t)):n.undefined}function z(n,e){try{return e(n)}finally{for(const t of n)t.alive&&t.dispose()}}function $([n,e],t){try{return t(n)}finally{e&&n.dispose()}}function S(n,e){try{return e(...n.map(t=>t[0]))}finally{for(const[t,r]of n)r&&t.dispose()}}function q(n){return"handle"in n}function L(n){return q(n)?n.handle:n}function Q(n,e,t,r){var o;let s;for(const i of r)if(s=i(e,n),s)break;return s?(o=t(e,s))!=null?o:s:void 0}function V(n,e){return typeof n!="symbol"?void 0:_(e,"d => Symbol(d)",void 0,n.description?e.newString(n.description):e.undefined)}function X(n,e){return n instanceof Date?_(e,"d => new Date(d)",void 0,e.newNumber(n.getTime())):void 0}const Y=[V,X];function N(n){return typeof n=="function"&&/^class\s/.test(Function.prototype.toString.call(n))}function g(n){return typeof n=="function"||typeof n=="object"&&n!==null}function O(n,e){const t=new Set,r=s=>{if(!(!g(s)||t.has(s)||(e==null?void 0:e(s,t))===!1)){if(t.add(s),Array.isArray(s)){for(const o of s)r(o);return}if(typeof s=="object"){const o=Object.getPrototypeOf(s);o&&o!==Object.prototype&&r(o)}for(const o of Object.values(Object.getOwnPropertyDescriptors(s)))"value"in o&&r(o.value),"get"in o&&r(o.get),"set"in o&&r(o.set)}};return r(n),t}function Z(n,e){return O(n,e?(t,r)=>r.size<e:void 0).size}function K(){let n=()=>{},e=()=>{};return{promise:new Promise((r,s)=>{n=r,e=s}),resolve:n,reject:e}}function A(n,e,t,r){const s=n.newObject(),o=(a,u)=>{const p=r(a),l=typeof u.value=="undefined"?void 0:r(u.value),f=typeof u.get=="undefined"?void 0:r(u.get),d=typeof u.set=="undefined"?void 0:r(u.set);n.newObject().consume(h=>{Object.entries(u).forEach(([y,b])=>{const w=y==="value"?l:y==="get"?f:y==="set"?d:b?n.true:n.false;w&&n.setProp(h,y,w)}),n.setProp(s,p,h)})},i=Object.getOwnPropertyDescriptors(e);Object.entries(i).forEach(([a,u])=>o(a,u)),Object.getOwnPropertySymbols(i).forEach(a=>o(a,i[a])),_(n,"Object.defineProperties",void 0,t,s).dispose(),s.dispose()}function x(n,e,t,r,s,o){var u;if(typeof e!="function")return;const i=n.newFunction(e.name,function(...p){const l=r(this),f=p.map(d=>r(d));if(N(e)&&g(l)){const d=new e(...f);return Object.entries(d).forEach(([h,y])=>{n.setProp(this,h,t(y))}),this}return t(o?o(e,l,f):e.apply(l,f))}).consume(p=>_(n,`Cls => {
|
|
9
9
|
const fn = function(...args) { return Cls.apply(this, args); };
|
|
10
10
|
fn.name = Cls.name;
|
|
11
11
|
fn.length = Cls.length;
|
|
@@ -68,4 +68,4 @@
|
|
|
68
68
|
},
|
|
69
69
|
});
|
|
70
70
|
return rec;
|
|
71
|
-
}`,void 0,e,r,l),!0])}function P(n,e){var t;return g(n)&&(t=n[e])!=null?t:n}function R(n,e,t){return U(n,e,t)?[n.getProp(e,t),!0]:[e,!1]}function he(n,e){return g(n)&&!!n[e]}function U(n,e,t){return!!n.dump(_(n,'(a, s) => (a instanceof Promise) || (a instanceof Date) || (typeof a === "object" && a !== null || typeof a === "function") && !!a[s]',void 0,e,t))}class ye{constructor(e,t){c(this,"context");c(this,"_map");c(this,"_registeredMap");c(this,"_registeredMapDispose",new Set);c(this,"_sync",new Set);c(this,"_temporalSync",new Set);c(this,"_symbol",Symbol());c(this,"_symbolHandle");c(this,"_options");c(this,"_isMarshalable",e=>{var r,s;const t=(r=this._options)==null?void 0:r.isMarshalable;return(s=typeof t=="function"?t(this._unwrap(e)):t)!=null?s:"json"});c(this,"_marshalFind",e=>{var s,o,i;const t=this._unwrap(e);return(i=(o=(s=this._registeredMap.get(e))!=null?s:t!==e?this._registeredMap.get(t):void 0)!=null?o:this._map.get(e))!=null?i:t!==e?this._map.get(t):void 0});c(this,"_marshalPre",(e,t,r)=>{var s;if(r!=="json")return(s=this._register(e,L(t),this._map))==null?void 0:s[1]});c(this,"_marshalPreApply",(e,t,r)=>{const s=g(t)?this._unwrap(t):void 0;s&&this._temporalSync.add(s);try{return e.apply(t,r)}finally{s&&this._temporalSync.delete(s)}});c(this,"_marshal",e=>{var s,o;const t=this._registeredMap.get(e);if(t)return[t,!1];const r=E((s=this._wrap(e))!=null?s:e,{ctx:this.context,unmarshal:this._unmarshal,isMarshalable:this._isMarshalable,find:this._marshalFind,pre:this._marshalPre,preApply:this._marshalPreApply,custom:(o=this._options)==null?void 0:o.customMarshaller});return[r,!this._map.hasHandle(r)]});c(this,"_preUnmarshal",(e,t)=>{var r;return(r=this._register(e,t,void 0,!0))==null?void 0:r[0]});c(this,"_unmarshalFind",e=>{var t;return(t=this._registeredMap.getByHandle(e))!=null?t:this._map.getByHandle(e)});c(this,"_unmarshal",e=>{var s;const t=this._registeredMap.getByHandle(e);if(typeof t!="undefined")return t;const[r]=this._wrapHandle(e);return B(r!=null?r:e,{ctx:this.context,marshal:this._marshal,find:this._unmarshalFind,pre:this._preUnmarshal,custom:(s=this._options)==null?void 0:s.customUnmarshaller})});c(this,"_syncMode",e=>{const t=this._unwrap(e);return this._sync.has(t)||this._temporalSync.has(t)?"both":void 0});c(this,"_unwrapIfNotSynced",e=>{const t=this._unwrap(e);return t instanceof Promise||!this._sync.has(t)?t:e});var r;t!=null&&t.compat&&!("runtime"in e)&&(e.runtime={hasPendingJob:()=>e.hasPendingJob(),executePendingJobs:s=>e.executePendingJobs(s)}),this.context=t!=null&&t.experimentalContextEx?v(e):e,this._options=t,this._symbolHandle=e.unwrapResult(e.evalCode("Symbol()")),this._map=new M(e),this._registeredMap=new M(e),this.registerAll((r=t==null?void 0:t.registeredObjects)!=null?r:k)}dispose(){var e,t;this._map.dispose(),this._registeredMap.dispose(),this._symbolHandle.dispose(),(t=(e=this.context).disposeEx)==null||t.call(e)}evalCode(e){const t=this.context.evalCode(e);return this._unwrapResultAndUnmarshal(t)}evalModule(e,t="module.js"){const r=this.context.evalCode(e,t,{type:"module"});this._unwrapResultAndUnmarshal(r)}executePendingJobs(e){const t=this.context.runtime.executePendingJobs(e);if("value"in t)return t.value;throw this._unwrapIfNotSynced(t.error.consume(this._unmarshal))}setMemoryLimit(e){this.context.runtime.setMemoryLimit(e)}setMaxStackSize(e){this.context.runtime.setMaxStackSize(e)}getMemoryUsage(){const e=this.context.runtime.computeMemoryUsage();try{return this.context.dump(e)}finally{e.dispose()}}dumpMemoryUsage(){return this.context.runtime.dumpMemoryUsage()}expose(e){for(const[t,r]of Object.entries(e))$(this._marshal(r),s=>{this.context.setProp(this.context.global,t,s)})}sync(e){const t=this._wrap(e);return typeof t=="undefined"?e:(O(t,r=>{const s=this._unwrap(r);this._sync.add(s)}),t)}register(e,t){if(this._registeredMap.has(e))return;const r=typeof t=="string"?this._unwrapResult(this.context.evalCode(t)):t;C(this.context,r,this.context.undefined)||(typeof t=="string"&&this._registeredMapDispose.add(e),this._registeredMap.set(e,r))}registerAll(e){for(const[t,r]of e)this.register(t,r)}unregister(e,t){this._registeredMap.delete(e,this._registeredMapDispose.has(e)||t),this._registeredMapDispose.delete(e)}unregisterAll(e,t){for(const r of e)this.unregister(r,t)}startSync(e){if(!g(e))return;const t=this._unwrap(e);this._sync.add(t)}endSync(e){this._sync.delete(this._unwrap(e))}_unwrapResult(e){if("value"in e)return e.value;throw this._unwrapIfNotSynced(e.error.consume(this._unmarshal))}_unwrapResultAndUnmarshal(e){if(e)return this._unwrapIfNotSynced(this._unwrapResult(e).consume(this._unmarshal))}_register(e,t,r=this._map,s){if(this._registeredMap.has(e)||this._registeredMap.hasHandle(t))return;let o=this._wrap(e);const[i]=this._wrapHandle(t),a=e instanceof Promise;if(!i||!o&&!a)return;a&&(o=e);const u=this._unwrap(e),[p,l]=this._unwrapHandle(t);if(r.set(o,i,u,p))s&&this._sync.add(u);else throw l&&p.dispose(),new Error("already registered");return[o,i]}_wrap(e){var t;return de(this.context,e,this._symbol,this._symbolHandle,this._marshal,this._syncMode,(t=this._options)==null?void 0:t.isWrappable)}_unwrap(e){return P(e,this._symbol)}_wrapHandle(e){var t;return me(this.context,e,this._symbol,this._symbolHandle,this._unmarshal,this._syncMode,(t=this._options)==null?void 0:t.isHandleWrappable)}_unwrapHandle(e){return R(this.context,e,this._symbolHandle)}}m.Arena=ye,m.VMMap=M,m.call=_,m.complexity=Z,m.consumeAll=z,m.defaultRegisteredObjects=k,m.eq=C,m.isES2015Class=N,m.isHandleObject=F,m.isObject=g,m.json=H,m.marshal=E,m.unmarshal=B,m.walkObject=O,Object.defineProperty(m,Symbol.toStringTag,{value:"Module"})}));
|
|
71
|
+
}`,void 0,e,r,l),!0])}function P(n,e){var t;return g(n)&&(t=n[e])!=null?t:n}function R(n,e,t){return U(n,e,t)?[n.getProp(e,t),!0]:[e,!1]}function he(n,e){return g(n)&&!!n[e]}function U(n,e,t){return!!n.dump(_(n,'(a, s) => (a instanceof Promise) || (a instanceof Date) || (typeof a === "object" && a !== null || typeof a === "function") && !!a[s]',void 0,e,t))}class ye{constructor(e,t){c(this,"context");c(this,"_map");c(this,"_registeredMap");c(this,"_registeredMapDispose",new Set);c(this,"_sync",new Set);c(this,"_temporalSync",new Set);c(this,"_symbol",Symbol());c(this,"_symbolHandle");c(this,"_options");c(this,"_isMarshalable",e=>{var r,s;const t=(r=this._options)==null?void 0:r.isMarshalable;return(s=typeof t=="function"?t(this._unwrap(e)):t)!=null?s:"json"});c(this,"_marshalFind",e=>{var s,o,i;const t=this._unwrap(e);return(i=(o=(s=this._registeredMap.get(e))!=null?s:t!==e?this._registeredMap.get(t):void 0)!=null?o:this._map.get(e))!=null?i:t!==e?this._map.get(t):void 0});c(this,"_marshalPre",(e,t,r)=>{var s;if(r!=="json")return(s=this._register(e,L(t),this._map))==null?void 0:s[1]});c(this,"_marshalPreApply",(e,t,r)=>{const s=g(t)?this._unwrap(t):void 0;s&&this._temporalSync.add(s);try{return e.apply(t,r)}finally{s&&this._temporalSync.delete(s)}});c(this,"_marshal",e=>{var s,o;const t=this._registeredMap.get(e);if(t)return[t,!1];const r=E((s=this._wrap(e))!=null?s:e,{ctx:this.context,unmarshal:this._unmarshal,isMarshalable:this._isMarshalable,find:this._marshalFind,pre:this._marshalPre,preApply:this._marshalPreApply,custom:(o=this._options)==null?void 0:o.customMarshaller});return[r,!this._map.hasHandle(r)]});c(this,"_preUnmarshal",(e,t)=>{var r;return(r=this._register(e,t,void 0,!0))==null?void 0:r[0]});c(this,"_unmarshalFind",e=>{var t;return(t=this._registeredMap.getByHandle(e))!=null?t:this._map.getByHandle(e)});c(this,"_unmarshal",e=>{var s;const t=this._registeredMap.getByHandle(e);if(typeof t!="undefined")return t;const[r]=this._wrapHandle(e);return B(r!=null?r:e,{ctx:this.context,marshal:this._marshal,find:this._unmarshalFind,pre:this._preUnmarshal,custom:(s=this._options)==null?void 0:s.customUnmarshaller})});c(this,"_syncMode",e=>{const t=this._unwrap(e);return this._sync.has(t)||this._temporalSync.has(t)?"both":void 0});c(this,"_unwrapIfNotSynced",e=>{const t=this._unwrap(e);return t instanceof Promise||!this._sync.has(t)?t:e});var r;t!=null&&t.compat&&!("runtime"in e)&&(e.runtime={hasPendingJob:()=>e.hasPendingJob(),executePendingJobs:s=>e.executePendingJobs(s)}),this.context=t!=null&&t.experimentalContextEx?v(e):e,this._options=t,this._symbolHandle=e.unwrapResult(e.evalCode("Symbol()")),this._map=new M(e),this._registeredMap=new M(e),this.registerAll((r=t==null?void 0:t.registeredObjects)!=null?r:k)}dispose(){var e,t;this._map.dispose(),this._registeredMap.dispose(),this._symbolHandle.dispose(),(t=(e=this.context).disposeEx)==null||t.call(e)}evalCode(e){const t=this.context.evalCode(e);return this._unwrapResultAndUnmarshal(t)}evalModule(e,t="module.js"){const r=this.context.evalCode(e,t,{type:"module"});return this._unwrapResultAndUnmarshal(r)}executePendingJobs(e){const t=this.context.runtime.executePendingJobs(e);if("value"in t)return t.value;throw this._unwrapIfNotSynced(t.error.consume(this._unmarshal))}setMemoryLimit(e){this.context.runtime.setMemoryLimit(e)}setMaxStackSize(e){this.context.runtime.setMaxStackSize(e)}getMemoryUsage(){const e=this.context.runtime.computeMemoryUsage();try{return this.context.dump(e)}finally{e.dispose()}}dumpMemoryUsage(){return this.context.runtime.dumpMemoryUsage()}expose(e){for(const[t,r]of Object.entries(e))$(this._marshal(r),s=>{this.context.setProp(this.context.global,t,s)})}sync(e){const t=this._wrap(e);return typeof t=="undefined"?e:(O(t,r=>{const s=this._unwrap(r);this._sync.add(s)}),t)}register(e,t){if(this._registeredMap.has(e))return;const r=typeof t=="string"?this._unwrapResult(this.context.evalCode(t)):t;C(this.context,r,this.context.undefined)||(typeof t=="string"&&this._registeredMapDispose.add(e),this._registeredMap.set(e,r))}registerAll(e){for(const[t,r]of e)this.register(t,r)}unregister(e,t){this._registeredMap.delete(e,this._registeredMapDispose.has(e)||t),this._registeredMapDispose.delete(e)}unregisterAll(e,t){for(const r of e)this.unregister(r,t)}startSync(e){if(!g(e))return;const t=this._unwrap(e);this._sync.add(t)}endSync(e){this._sync.delete(this._unwrap(e))}_unwrapResult(e){if("value"in e)return e.value;throw this._unwrapIfNotSynced(e.error.consume(this._unmarshal))}_unwrapResultAndUnmarshal(e){if(e)return this._unwrapIfNotSynced(this._unwrapResult(e).consume(this._unmarshal))}_register(e,t,r=this._map,s){if(this._registeredMap.has(e)||this._registeredMap.hasHandle(t))return;let o=this._wrap(e);const[i]=this._wrapHandle(t),a=e instanceof Promise;if(!i||!o&&!a)return;a&&(o=e);const u=this._unwrap(e),[p,l]=this._unwrapHandle(t);if(r.set(o,i,u,p))s&&this._sync.add(u);else throw l&&p.dispose(),new Error("already registered");return[o,i]}_wrap(e){var t;return de(this.context,e,this._symbol,this._symbolHandle,this._marshal,this._syncMode,(t=this._options)==null?void 0:t.isWrappable)}_unwrap(e){return P(e,this._symbol)}_wrapHandle(e){var t;return me(this.context,e,this._symbol,this._symbolHandle,this._unmarshal,this._syncMode,(t=this._options)==null?void 0:t.isHandleWrappable)}_unwrapHandle(e){return R(this.context,e,this._symbolHandle)}}m.Arena=ye,m.VMMap=M,m.call=_,m.complexity=Z,m.consumeAll=z,m.defaultRegisteredObjects=k,m.eq=C,m.isES2015Class=N,m.isHandleObject=F,m.isObject=g,m.json=H,m.marshal=E,m.unmarshal=B,m.walkObject=O,Object.defineProperty(m,Symbol.toStringTag,{value:"Module"})}));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "quickjs-emscripten-sync",
|
|
3
3
|
"author": "rot1024",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.7.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"source": "./src/index.ts",
|
|
7
7
|
"main": "./dist/quickjs-emscripten-sync.umd.js",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"eslint": "^8.57.1",
|
|
36
36
|
"eslint-config-reearth": "^0.2.1",
|
|
37
37
|
"prettier": "^2.8.8",
|
|
38
|
-
"quickjs-emscripten": "^0.
|
|
38
|
+
"quickjs-emscripten": "^0.29.0",
|
|
39
39
|
"typescript": "^5.7.2",
|
|
40
40
|
"vite": "^6.0.3",
|
|
41
41
|
"vite-plugin-dts": "^4.3.0",
|
package/src/index.test.ts
CHANGED
|
@@ -715,6 +715,107 @@ describe("evalModule", () => {
|
|
|
715
715
|
arena.dispose();
|
|
716
716
|
ctx.dispose();
|
|
717
717
|
});
|
|
718
|
+
|
|
719
|
+
test("module returns exported values (0.29+)", async () => {
|
|
720
|
+
const ctx = (await getQuickJS()).newContext();
|
|
721
|
+
const arena = new Arena(ctx, { isMarshalable: true });
|
|
722
|
+
|
|
723
|
+
const exports = arena.evalModule(`
|
|
724
|
+
export const value = 42;
|
|
725
|
+
export const message = "Hello";
|
|
726
|
+
export const obj = { a: 1, b: 2 };
|
|
727
|
+
`);
|
|
728
|
+
|
|
729
|
+
expect(exports.value).toBe(42);
|
|
730
|
+
expect(exports.message).toBe("Hello");
|
|
731
|
+
expect(exports.obj).toEqual({ a: 1, b: 2 });
|
|
732
|
+
|
|
733
|
+
arena.dispose();
|
|
734
|
+
ctx.dispose();
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
test("module returns exported functions (0.29+)", async () => {
|
|
738
|
+
const ctx = (await getQuickJS()).newContext();
|
|
739
|
+
const arena = new Arena(ctx, { isMarshalable: true });
|
|
740
|
+
|
|
741
|
+
const exports = arena.evalModule(`
|
|
742
|
+
export function greet(name) {
|
|
743
|
+
return "Hello, " + name;
|
|
744
|
+
}
|
|
745
|
+
export function add(a, b) {
|
|
746
|
+
return a + b;
|
|
747
|
+
}
|
|
748
|
+
`);
|
|
749
|
+
|
|
750
|
+
expect(exports.greet("World")).toBe("Hello, World");
|
|
751
|
+
expect(exports.add(2, 3)).toBe(5);
|
|
752
|
+
|
|
753
|
+
arena.dispose();
|
|
754
|
+
ctx.dispose();
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
test("module with default export (0.29+)", async () => {
|
|
758
|
+
const ctx = (await getQuickJS()).newContext();
|
|
759
|
+
const arena = new Arena(ctx, { isMarshalable: true });
|
|
760
|
+
|
|
761
|
+
const exports = arena.evalModule(`
|
|
762
|
+
export default function(x) {
|
|
763
|
+
return x * 2;
|
|
764
|
+
}
|
|
765
|
+
`);
|
|
766
|
+
|
|
767
|
+
expect(exports.default(21)).toBe(42);
|
|
768
|
+
|
|
769
|
+
arena.dispose();
|
|
770
|
+
ctx.dispose();
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
test("module with class export (0.29+)", async () => {
|
|
774
|
+
const ctx = (await getQuickJS()).newContext();
|
|
775
|
+
const arena = new Arena(ctx, { isMarshalable: true });
|
|
776
|
+
|
|
777
|
+
// Export objects and static methods from a class
|
|
778
|
+
const exports = arena.evalModule(`
|
|
779
|
+
export class Counter {
|
|
780
|
+
static create(initial = 0) {
|
|
781
|
+
return { count: initial };
|
|
782
|
+
}
|
|
783
|
+
static increment(obj) {
|
|
784
|
+
return ++obj.count;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
`);
|
|
788
|
+
|
|
789
|
+
// Static methods can be called from the host
|
|
790
|
+
const counter = exports.Counter.create(10);
|
|
791
|
+
expect(counter.count).toBe(10);
|
|
792
|
+
expect(exports.Counter.increment(counter)).toBe(11);
|
|
793
|
+
expect(counter.count).toBe(11);
|
|
794
|
+
|
|
795
|
+
arena.dispose();
|
|
796
|
+
ctx.dispose();
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
test("module with top-level await (0.29+)", async () => {
|
|
800
|
+
const ctx = (await getQuickJS()).newContext();
|
|
801
|
+
const arena = new Arena(ctx, { isMarshalable: true });
|
|
802
|
+
|
|
803
|
+
const exportsPromise = arena.evalModule(`
|
|
804
|
+
export const data = await Promise.resolve(123);
|
|
805
|
+
export const message = "loaded";
|
|
806
|
+
`);
|
|
807
|
+
|
|
808
|
+
expect(exportsPromise).toBeInstanceOf(Promise);
|
|
809
|
+
|
|
810
|
+
arena.executePendingJobs();
|
|
811
|
+
|
|
812
|
+
const exports = await exportsPromise;
|
|
813
|
+
expect(exports.data).toBe(123);
|
|
814
|
+
expect(exports.message).toBe("loaded");
|
|
815
|
+
|
|
816
|
+
arena.dispose();
|
|
817
|
+
ctx.dispose();
|
|
818
|
+
});
|
|
718
819
|
});
|
|
719
820
|
|
|
720
821
|
describe("memory management", () => {
|
|
@@ -911,3 +1012,23 @@ describe("memory management", () => {
|
|
|
911
1012
|
ctx.dispose();
|
|
912
1013
|
});
|
|
913
1014
|
});
|
|
1015
|
+
|
|
1016
|
+
describe("intrinsics configuration", () => {
|
|
1017
|
+
test("intrinsics can be configured when creating context", async () => {
|
|
1018
|
+
const quickjs = await getQuickJS();
|
|
1019
|
+
const runtime = quickjs.newRuntime();
|
|
1020
|
+
|
|
1021
|
+
// Example: disable eval for sandboxing
|
|
1022
|
+
const ctx = runtime.newContext({ intrinsics: { Eval: false } });
|
|
1023
|
+
const arena = new Arena(ctx, { isMarshalable: true });
|
|
1024
|
+
|
|
1025
|
+
// This test demonstrates that intrinsics are configured at context creation
|
|
1026
|
+
// The actual restrictions would be enforced by quickjs-emscripten
|
|
1027
|
+
expect(arena).toBeDefined();
|
|
1028
|
+
expect(arena.context).toBeDefined();
|
|
1029
|
+
|
|
1030
|
+
arena.dispose();
|
|
1031
|
+
ctx.dispose();
|
|
1032
|
+
runtime.dispose();
|
|
1033
|
+
});
|
|
1034
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
QuickJSContext,
|
|
5
5
|
SuccessOrFail,
|
|
6
6
|
VmCallResult,
|
|
7
|
+
Intrinsics,
|
|
7
8
|
} from "quickjs-emscripten";
|
|
8
9
|
|
|
9
10
|
import { wrapContext, QuickJSContextEx } from "./contextex";
|
|
@@ -31,6 +32,8 @@ export {
|
|
|
31
32
|
consumeAll,
|
|
32
33
|
};
|
|
33
34
|
|
|
35
|
+
export type { Intrinsics };
|
|
36
|
+
|
|
34
37
|
export type Options = {
|
|
35
38
|
/** A callback that returns a boolean value that determines whether an object is marshalled or not. If false, no marshaling will be done and undefined will be passed to the QuickJS VM, otherwise marshaling will be done. By default, all objects will be marshalled. */
|
|
36
39
|
isMarshalable?: boolean | "json" | ((target: any) => boolean | "json");
|
|
@@ -104,24 +107,40 @@ export class Arena {
|
|
|
104
107
|
}
|
|
105
108
|
|
|
106
109
|
/**
|
|
107
|
-
* Evaluate ES module code in the VM
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
+
* Evaluate ES module code in the VM and get the module's exports.
|
|
111
|
+
*
|
|
112
|
+
* Requires quickjs-emscripten >= 0.29.0 for export access.
|
|
110
113
|
*
|
|
111
114
|
* @param code - The ES module code to evaluate
|
|
112
115
|
* @param filename - Optional filename for debugging purposes (default: "module.js")
|
|
113
|
-
* @returns
|
|
116
|
+
* @returns The module's exports object, or a Promise resolving to exports if using top-level await
|
|
114
117
|
*
|
|
115
118
|
* @example
|
|
116
119
|
* ```js
|
|
117
|
-
* //
|
|
118
|
-
* arena.
|
|
119
|
-
*
|
|
120
|
+
* // Simple module with exports
|
|
121
|
+
* const exports = arena.evalModule(`
|
|
122
|
+
* export const value = 42;
|
|
123
|
+
* export function greet(name) {
|
|
124
|
+
* return "Hello, " + name;
|
|
125
|
+
* }
|
|
126
|
+
* `);
|
|
127
|
+
* console.log(exports.value); // 42
|
|
128
|
+
* console.log(exports.greet("World")); // "Hello, World"
|
|
129
|
+
*
|
|
130
|
+
* // Module with default export
|
|
131
|
+
* const mod = arena.evalModule('export default function(x) { return x * 2; }');
|
|
132
|
+
* console.log(mod.default(21)); // 42
|
|
133
|
+
*
|
|
134
|
+
* // Module with top-level await
|
|
135
|
+
* const promise = arena.evalModule('export const data = await Promise.resolve(123);');
|
|
136
|
+
* arena.executePendingJobs();
|
|
137
|
+
* const exports = await promise;
|
|
138
|
+
* console.log(exports.data); // 123
|
|
120
139
|
* ```
|
|
121
140
|
*/
|
|
122
|
-
evalModule(code: string, filename = "module.js"):
|
|
141
|
+
evalModule<T = any>(code: string, filename = "module.js"): T | Promise<T> {
|
|
123
142
|
const handle = this.context.evalCode(code, filename, { type: "module" });
|
|
124
|
-
this._unwrapResultAndUnmarshal(handle);
|
|
143
|
+
return this._unwrapResultAndUnmarshal(handle);
|
|
125
144
|
}
|
|
126
145
|
|
|
127
146
|
/**
|
package/src/vmutil.ts
CHANGED
|
@@ -10,10 +10,12 @@ export function fn(
|
|
|
10
10
|
code: string,
|
|
11
11
|
): ((thisArg: QuickJSHandle | undefined, ...args: QuickJSHandle[]) => QuickJSHandle) & Disposable {
|
|
12
12
|
const handle = ctx.unwrapResult(ctx.evalCode(code));
|
|
13
|
-
const f = (thisArg: QuickJSHandle | undefined, ...args: QuickJSHandle[]): any => {
|
|
13
|
+
const f: any = (thisArg: QuickJSHandle | undefined, ...args: QuickJSHandle[]): any => {
|
|
14
14
|
return ctx.unwrapResult(ctx.callFunction(handle, thisArg ?? ctx.undefined, ...args));
|
|
15
15
|
};
|
|
16
|
-
|
|
16
|
+
const disposeFn = () => handle.dispose();
|
|
17
|
+
f.dispose = disposeFn;
|
|
18
|
+
f[Symbol.dispose] = disposeFn;
|
|
17
19
|
f.alive = true;
|
|
18
20
|
Object.defineProperty(f, "alive", {
|
|
19
21
|
get: () => handle.alive,
|