context.d.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. import { QuickJSDeferredPromise } from "./deferred-promise";
  2. import type { EitherModule } from "./emscripten-types";
  3. import { JSBorrowedCharPointer, JSContextPointer, JSRuntimePointer, JSValueConstPointer, JSValuePointer } from "./types-ffi";
  4. import { Disposable, Lifetime, Scope } from "./lifetime";
  5. import { ModuleMemory } from "./memory";
  6. import { QuickJSModuleCallbacks } from "./module";
  7. import { QuickJSRuntime } from "./runtime";
  8. import { ContextEvalOptions, EitherFFI, JSValue, PromiseExecutor, QuickJSHandle } from "./types";
  9. import { LowLevelJavascriptVm, SuccessOrFail, VmCallResult, VmFunctionImplementation, VmPropertyDescriptor } from "./vm-interface";
  10. /**
  11. * Property key for getting or setting a property on a handle with
  12. * [[QuickJSContext.getProp]], [[QuickJSContext.setProp]], or [[QuickJSContext.defineProp]].
  13. */
  14. export type QuickJSPropertyKey = number | string | QuickJSHandle;
  15. /**
  16. * @private
  17. */
  18. declare class ContextMemory extends ModuleMemory implements Disposable {
  19. readonly owner: QuickJSRuntime;
  20. readonly ctx: Lifetime<JSContextPointer>;
  21. readonly rt: Lifetime<JSRuntimePointer>;
  22. readonly module: EitherModule;
  23. readonly ffi: EitherFFI;
  24. readonly scope: Scope;
  25. /** @private */
  26. constructor(args: {
  27. owner: QuickJSRuntime;
  28. module: EitherModule;
  29. ffi: EitherFFI;
  30. ctx: Lifetime<JSContextPointer>;
  31. rt: Lifetime<JSRuntimePointer>;
  32. ownedLifetimes?: Disposable[];
  33. });
  34. get alive(): boolean;
  35. dispose(): void;
  36. /**
  37. * Track `lifetime` so that it is disposed when this scope is disposed.
  38. */
  39. manage<T extends Disposable>(lifetime: T): T;
  40. copyJSValue: (ptr: JSValuePointer | JSValueConstPointer) => any;
  41. freeJSValue: (ptr: JSValuePointer) => void;
  42. consumeJSCharPointer(ptr: JSBorrowedCharPointer): string;
  43. heapValueHandle(ptr: JSValuePointer): JSValue;
  44. }
  45. /**
  46. * QuickJSContext wraps a QuickJS Javascript context (JSContext*) within a
  47. * runtime. The contexts within the same runtime may exchange objects freely.
  48. * You can think of separate runtimes like different domains in a browser, and
  49. * the contexts within a runtime like the different windows open to the same
  50. * domain. The {@link runtime} references the context's runtime.
  51. *
  52. * This class's methods return {@link QuickJSHandle}, which wrap C pointers (JSValue*).
  53. * It's the caller's responsibility to call `.dispose()` on any
  54. * handles you create to free memory once you're done with the handle.
  55. *
  56. * Use {@link QuickJSRuntime.newContext} or {@link QuickJSWASMModule.newContext}
  57. * to create a new QuickJSContext.
  58. *
  59. * Create QuickJS values inside the interpreter with methods like
  60. * [[newNumber]], [[newString]], [[newArray]], [[newObject]],
  61. * [[newFunction]], and [[newPromise]].
  62. *
  63. * Call [[setProp]] or [[defineProp]] to customize objects. Use those methods
  64. * with [[global]] to expose the values you create to the interior of the
  65. * interpreter, so they can be used in [[evalCode]].
  66. *
  67. * Use [[evalCode]] or [[callFunction]] to execute Javascript inside the VM. If
  68. * you're using asynchronous code inside the QuickJSContext, you may need to also
  69. * call [[executePendingJobs]]. Executing code inside the runtime returns a
  70. * result object representing successful execution or an error. You must dispose
  71. * of any such results to avoid leaking memory inside the VM.
  72. *
  73. * Implement memory and CPU constraints at the runtime level, using [[runtime]].
  74. * See {@link QuickJSRuntime} for more information.
  75. *
  76. */
  77. export declare class QuickJSContext implements LowLevelJavascriptVm<QuickJSHandle>, Disposable {
  78. /**
  79. * The runtime that created this context.
  80. */
  81. readonly runtime: QuickJSRuntime;
  82. /** @private */
  83. protected readonly ctx: Lifetime<JSContextPointer>;
  84. /** @private */
  85. protected readonly rt: Lifetime<JSRuntimePointer>;
  86. /** @private */
  87. protected readonly module: EitherModule;
  88. /** @private */
  89. protected readonly ffi: EitherFFI;
  90. /** @private */
  91. protected memory: ContextMemory;
  92. /** @private */
  93. protected _undefined: QuickJSHandle | undefined;
  94. /** @private */
  95. protected _null: QuickJSHandle | undefined;
  96. /** @private */
  97. protected _false: QuickJSHandle | undefined;
  98. /** @private */
  99. protected _true: QuickJSHandle | undefined;
  100. /** @private */
  101. protected _global: QuickJSHandle | undefined;
  102. /** @private */
  103. protected _BigInt: QuickJSHandle | undefined;
  104. /**
  105. * Use {@link QuickJS.createVm} to create a QuickJSContext instance.
  106. */
  107. constructor(args: {
  108. module: EitherModule;
  109. ffi: EitherFFI;
  110. ctx: Lifetime<JSContextPointer>;
  111. rt: Lifetime<JSRuntimePointer>;
  112. runtime: QuickJSRuntime;
  113. ownedLifetimes?: Disposable[];
  114. callbacks: QuickJSModuleCallbacks;
  115. });
  116. get alive(): boolean;
  117. /**
  118. * Dispose of this VM's underlying resources.
  119. *
  120. * @throws Calling this method without disposing of all created handles
  121. * will result in an error.
  122. */
  123. dispose(): void;
  124. /**
  125. * [`undefined`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined).
  126. */
  127. get undefined(): QuickJSHandle;
  128. /**
  129. * [`null`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null).
  130. */
  131. get null(): QuickJSHandle;
  132. /**
  133. * [`true`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/true).
  134. */
  135. get true(): QuickJSHandle;
  136. /**
  137. * [`false`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/false).
  138. */
  139. get false(): QuickJSHandle;
  140. /**
  141. * [`global`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects).
  142. * A handle to the global object inside the interpreter.
  143. * You can set properties to create global variables.
  144. */
  145. get global(): QuickJSHandle;
  146. /**
  147. * Converts a Javascript number into a QuickJS value.
  148. */
  149. newNumber(num: number): QuickJSHandle;
  150. /**
  151. * Create a QuickJS [string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) value.
  152. */
  153. newString(str: string): QuickJSHandle;
  154. /**
  155. * Create a QuickJS [symbol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) value.
  156. * No two symbols created with this function will be the same value.
  157. */
  158. newUniqueSymbol(description: string | symbol): QuickJSHandle;
  159. /**
  160. * Get a symbol from the [global registry](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol#shared_symbols_in_the_global_symbol_registry) for the given key.
  161. * All symbols created with the same key will be the same value.
  162. */
  163. newSymbolFor(key: string | symbol): QuickJSHandle;
  164. /**
  165. * Create a QuickJS [bigint](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) value.
  166. */
  167. newBigInt(num: bigint): QuickJSHandle;
  168. /**
  169. * `{}`.
  170. * Create a new QuickJS [object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer).
  171. *
  172. * @param prototype - Like [`Object.create`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create).
  173. */
  174. newObject(prototype?: QuickJSHandle): QuickJSHandle;
  175. /**
  176. * `[]`.
  177. * Create a new QuickJS [array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array).
  178. */
  179. newArray(): QuickJSHandle;
  180. /**
  181. * Create a new [[QuickJSDeferredPromise]]. Use `deferred.resolve(handle)` and
  182. * `deferred.reject(handle)` to fulfill the promise handle available at `deferred.handle`.
  183. * Note that you are responsible for calling `deferred.dispose()` to free the underlying
  184. * resources; see the documentation on [[QuickJSDeferredPromise]] for details.
  185. */
  186. newPromise(): QuickJSDeferredPromise;
  187. /**
  188. * Create a new [[QuickJSDeferredPromise]] that resolves when the
  189. * given native Promise<QuickJSHandle> resolves. Rejections will be coerced
  190. * to a QuickJS error.
  191. *
  192. * You can still resolve/reject the created promise "early" using its methods.
  193. */
  194. newPromise(promise: Promise<QuickJSHandle>): QuickJSDeferredPromise;
  195. /**
  196. * Construct a new native Promise<QuickJSHandle>, and then convert it into a
  197. * [[QuickJSDeferredPromise]].
  198. *
  199. * You can still resolve/reject the created promise "early" using its methods.
  200. */
  201. newPromise(newPromiseFn: PromiseExecutor<QuickJSHandle, Error | QuickJSHandle>): QuickJSDeferredPromise;
  202. /**
  203. * Convert a Javascript function into a QuickJS function value.
  204. * See [[VmFunctionImplementation]] for more details.
  205. *
  206. * A [[VmFunctionImplementation]] should not free its arguments or its return
  207. * value. A VmFunctionImplementation should also not retain any references to
  208. * its return value.
  209. *
  210. * To implement an async function, create a promise with [[newPromise]], then
  211. * return the deferred promise handle from `deferred.handle` from your
  212. * function implementation:
  213. *
  214. * ```
  215. * const deferred = vm.newPromise()
  216. * someNativeAsyncFunction().then(deferred.resolve)
  217. * return deferred.handle
  218. * ```
  219. */
  220. newFunction(name: string, fn: VmFunctionImplementation<QuickJSHandle>): QuickJSHandle;
  221. newError(error: {
  222. name: string;
  223. message: string;
  224. }): QuickJSHandle;
  225. newError(message: string): QuickJSHandle;
  226. newError(): QuickJSHandle;
  227. /**
  228. * `typeof` operator. **Not** [standards compliant](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof).
  229. *
  230. * @remarks
  231. * Does not support BigInt values correctly.
  232. */
  233. typeof(handle: QuickJSHandle): string;
  234. /**
  235. * Converts `handle` into a Javascript number.
  236. * @returns `NaN` on error, otherwise a `number`.
  237. */
  238. getNumber(handle: QuickJSHandle): number;
  239. /**
  240. * Converts `handle` to a Javascript string.
  241. */
  242. getString(handle: QuickJSHandle): string;
  243. /**
  244. * Converts `handle` into a Javascript symbol. If the symbol is in the global
  245. * registry in the guest, it will be created with Symbol.for on the host.
  246. */
  247. getSymbol(handle: QuickJSHandle): symbol;
  248. /**
  249. * Converts `handle` to a Javascript bigint.
  250. */
  251. getBigInt(handle: QuickJSHandle): bigint;
  252. /**
  253. * `Promise.resolve(value)`.
  254. * Convert a handle containing a Promise-like value inside the VM into an
  255. * actual promise on the host.
  256. *
  257. * @remarks
  258. * You may need to call [[executePendingJobs]] to ensure that the promise is resolved.
  259. *
  260. * @param promiseLikeHandle - A handle to a Promise-like value with a `.then(onSuccess, onError)` method.
  261. */
  262. resolvePromise(promiseLikeHandle: QuickJSHandle): Promise<VmCallResult<QuickJSHandle>>;
  263. /**
  264. * `handle[key]`.
  265. * Get a property from a JSValue.
  266. *
  267. * @param key - The property may be specified as a JSValue handle, or as a
  268. * Javascript string (which will be converted automatically).
  269. */
  270. getProp(handle: QuickJSHandle, key: QuickJSPropertyKey): QuickJSHandle;
  271. /**
  272. * `handle[key] = value`.
  273. * Set a property on a JSValue.
  274. *
  275. * @remarks
  276. * Note that the QuickJS authors recommend using [[defineProp]] to define new
  277. * properties.
  278. *
  279. * @param key - The property may be specified as a JSValue handle, or as a
  280. * Javascript string or number (which will be converted automatically to a JSValue).
  281. */
  282. setProp(handle: QuickJSHandle, key: QuickJSPropertyKey, value: QuickJSHandle): void;
  283. /**
  284. * [`Object.defineProperty(handle, key, descriptor)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty).
  285. *
  286. * @param key - The property may be specified as a JSValue handle, or as a
  287. * Javascript string or number (which will be converted automatically to a JSValue).
  288. */
  289. defineProp(handle: QuickJSHandle, key: QuickJSPropertyKey, descriptor: VmPropertyDescriptor<QuickJSHandle>): void;
  290. /**
  291. * [`func.call(thisVal, ...args)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call).
  292. * Call a JSValue as a function.
  293. *
  294. * See [[unwrapResult]], which will throw if the function returned an error, or
  295. * return the result handle directly. If evaluation returned a handle containing
  296. * a promise, use [[resolvePromise]] to convert it to a native promise and
  297. * [[executePendingJobs]] to finish evaluating the promise.
  298. *
  299. * @returns A result. If the function threw synchronously, `result.error` be a
  300. * handle to the exception. Otherwise `result.value` will be a handle to the
  301. * value.
  302. */
  303. callFunction(func: QuickJSHandle, thisVal: QuickJSHandle, ...args: QuickJSHandle[]): VmCallResult<QuickJSHandle>;
  304. /**
  305. * Like [`eval(code)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#Description).
  306. * Evaluates the Javascript source `code` in the global scope of this VM.
  307. * When working with async code, you many need to call [[executePendingJobs]]
  308. * to execute callbacks pending after synchronous evaluation returns.
  309. *
  310. * See [[unwrapResult]], which will throw if the function returned an error, or
  311. * return the result handle directly. If evaluation returned a handle containing
  312. * a promise, use [[resolvePromise]] to convert it to a native promise and
  313. * [[executePendingJobs]] to finish evaluating the promise.
  314. *
  315. * *Note*: to protect against infinite loops, provide an interrupt handler to
  316. * [[setInterruptHandler]]. You can use [[shouldInterruptAfterDeadline]] to
  317. * create a time-based deadline.
  318. *
  319. * @returns The last statement's value. If the code threw synchronously,
  320. * `result.error` will be a handle to the exception. If execution was
  321. * interrupted, the error will have name `InternalError` and message
  322. * `interrupted`.
  323. */
  324. evalCode(code: string, filename?: string,
  325. /**
  326. * If no options are passed, a heuristic will be used to detect if `code` is
  327. * an ES module.
  328. *
  329. * See [[EvalFlags]] for number semantics.
  330. */
  331. options?: number | ContextEvalOptions): VmCallResult<QuickJSHandle>;
  332. /**
  333. * Throw an error in the VM, interrupted whatever current execution is in progress when execution resumes.
  334. * @experimental
  335. */
  336. throw(error: Error | QuickJSHandle): any;
  337. /**
  338. * @private
  339. */
  340. protected borrowPropertyKey(key: QuickJSPropertyKey): QuickJSHandle;
  341. /**
  342. * @private
  343. */
  344. getMemory(rt: JSRuntimePointer): ContextMemory;
  345. /**
  346. * Dump a JSValue to Javascript in a best-effort fashion.
  347. * Returns `handle.toString()` if it cannot be serialized to JSON.
  348. */
  349. dump(handle: QuickJSHandle): any;
  350. /**
  351. * Unwrap a SuccessOrFail result such as a [[VmCallResult]] or a
  352. * [[ExecutePendingJobsResult]], where the fail branch contains a handle to a QuickJS error value.
  353. * If the result is a success, returns the value.
  354. * If the result is an error, converts the error to a native object and throws the error.
  355. */
  356. unwrapResult<T>(result: SuccessOrFail<T, QuickJSHandle>): T;
  357. /** @private */
  358. protected fnNextId: number;
  359. /** @private */
  360. protected fnMaps: Map<number, Map<number, VmFunctionImplementation<QuickJSHandle>>>;
  361. /** @private */
  362. protected getFunction(fn_id: number): VmFunctionImplementation<QuickJSHandle> | undefined;
  363. /** @private */
  364. protected setFunction(fn_id: number, handle: VmFunctionImplementation<QuickJSHandle>): Map<number, VmFunctionImplementation<QuickJSHandle>>;
  365. /**
  366. * @hidden
  367. */
  368. private cToHostCallbacks;
  369. private errorToHandle;
  370. }
  371. export {};