first commit
This commit is contained in:
21
node_modules/@tootallnate/quickjs-emscripten/LICENSE
generated
vendored
Normal file
21
node_modules/@tootallnate/quickjs-emscripten/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
quickjs-emscripten copyright (c) 2019 Jake Teton-Landis
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
597
node_modules/@tootallnate/quickjs-emscripten/README.md
generated
vendored
Normal file
597
node_modules/@tootallnate/quickjs-emscripten/README.md
generated
vendored
Normal file
@@ -0,0 +1,597 @@
|
||||
# quickjs-emscripten
|
||||
|
||||
Javascript/Typescript bindings for QuickJS, a modern Javascript interpreter,
|
||||
compiled to WebAssembly.
|
||||
|
||||
- Safely evaluate untrusted Javascript (up to ES2020).
|
||||
- Create and manipulate values inside the QuickJS runtime ([more][values]).
|
||||
- Expose host functions to the QuickJS runtime ([more][functions]).
|
||||
- Execute synchronous code that uses asynchronous functions, with [asyncify][asyncify].
|
||||
|
||||
[Github] | [NPM] | [API Documentation][api] | [Examples][tests]
|
||||
|
||||
```typescript
|
||||
import { getQuickJS } from "quickjs-emscripten"
|
||||
|
||||
async function main() {
|
||||
const QuickJS = await getQuickJS()
|
||||
const vm = QuickJS.newContext()
|
||||
|
||||
const world = vm.newString("world")
|
||||
vm.setProp(vm.global, "NAME", world)
|
||||
world.dispose()
|
||||
|
||||
const result = vm.evalCode(`"Hello " + NAME + "!"`)
|
||||
if (result.error) {
|
||||
console.log("Execution failed:", vm.dump(result.error))
|
||||
result.error.dispose()
|
||||
} else {
|
||||
console.log("Success:", vm.dump(result.value))
|
||||
result.value.dispose()
|
||||
}
|
||||
|
||||
vm.dispose()
|
||||
}
|
||||
|
||||
main()
|
||||
```
|
||||
|
||||
[github]: https://github.com/justjake/quickjs-emscripten
|
||||
[npm]: https://www.npmjs.com/package/quickjs-emscripten
|
||||
[api]: https://github.com/justjake/quickjs-emscripten/blob/main/doc/modules.md
|
||||
[tests]: https://github.com/justjake/quickjs-emscripten/blob/main/ts/quickjs.test.ts
|
||||
[values]: #interfacing-with-the-interpreter
|
||||
[asyncify]: #asyncify
|
||||
[functions]: #exposing-apis
|
||||
|
||||
## Usage
|
||||
|
||||
Install from `npm`: `npm install --save quickjs-emscripten` or `yarn add quickjs-emscripten`.
|
||||
|
||||
The root entrypoint of this library is the `getQuickJS` function, which returns
|
||||
a promise that resolves to a [QuickJS singleton](./doc/classes/quickjs.md) when
|
||||
the QuickJS WASM module is ready.
|
||||
|
||||
Once `getQuickJS` has been awaited at least once, you also can use the `getQuickJSSync`
|
||||
function to directly access the singleton engine in your synchronous code.
|
||||
|
||||
### Safely evaluate Javascript code
|
||||
|
||||
See [QuickJS.evalCode](https://github.com/justjake/quickjs-emscripten/blob/main/doc/classes/quickjs.md#evalcode)
|
||||
|
||||
```typescript
|
||||
import { getQuickJS, shouldInterruptAfterDeadline } from "quickjs-emscripten"
|
||||
|
||||
getQuickJS().then((QuickJS) => {
|
||||
const result = QuickJS.evalCode("1 + 1", {
|
||||
shouldInterrupt: shouldInterruptAfterDeadline(Date.now() + 1000),
|
||||
memoryLimitBytes: 1024 * 1024,
|
||||
})
|
||||
console.log(result)
|
||||
})
|
||||
```
|
||||
|
||||
### Interfacing with the interpreter
|
||||
|
||||
You can use [QuickJSContext](https://github.com/justjake/quickjs-emscripten/blob/main/doc/classes/QuickJSContext.md)
|
||||
to build a scripting environment by modifying globals and exposing functions
|
||||
into the QuickJS interpreter.
|
||||
|
||||
Each `QuickJSContext` instance has its own environment -- globals, built-in
|
||||
classes -- and actions from one context won't leak into other contexts or
|
||||
runtimes (with one exception, see [Asyncify][asyncify]).
|
||||
|
||||
Every context is created inside a
|
||||
[QuickJSRuntime](https://github.com/justjake/quickjs-emscripten/blob/main/doc/classes/QuickJSRuntime.md).
|
||||
A runtime represents a Javascript heap, and you can even share values between
|
||||
contexts in the same runtime.
|
||||
|
||||
```typescript
|
||||
const vm = QuickJS.newContext()
|
||||
let state = 0
|
||||
|
||||
const fnHandle = vm.newFunction("nextId", () => {
|
||||
return vm.newNumber(++state)
|
||||
})
|
||||
|
||||
vm.setProp(vm.global, "nextId", fnHandle)
|
||||
fnHandle.dispose()
|
||||
|
||||
const nextId = vm.unwrapResult(vm.evalCode(`nextId(); nextId(); nextId()`))
|
||||
console.log("vm result:", vm.getNumber(nextId), "native state:", state)
|
||||
|
||||
nextId.dispose()
|
||||
vm.dispose()
|
||||
```
|
||||
|
||||
When you create a context from a top-level API like in the example above,
|
||||
instead of by calling `runtime.newContext()`, a runtime is automatically created
|
||||
for the lifetime of the context, and disposed of when you dispose the context.
|
||||
|
||||
#### Runtime
|
||||
|
||||
The runtime has APIs for CPU and memory limits that apply to all contexts within
|
||||
the runtime in aggregate. You can also use the runtime to configure EcmaScript
|
||||
module loading.
|
||||
|
||||
```typescript
|
||||
const runtime = QuickJS.newRuntime()
|
||||
// "Should be enough for everyone" -- attributed to B. Gates
|
||||
runtime.setMemoryLimit(1024 * 640)
|
||||
// Limit stack size
|
||||
runtime.setMaxStackSize(1024 * 320)
|
||||
// Interrupt computation after 1024 calls to the interrupt handler
|
||||
let interruptCycles = 0
|
||||
runtime.setInterruptHandler(() => ++interruptCycles > 1024)
|
||||
// Toy module system that always returns the module name
|
||||
// as the default export
|
||||
runtime.setModuleLoader((moduleName) => `export default '${moduleName}'`)
|
||||
const context = runtime.newContext()
|
||||
const ok = context.evalCode(`
|
||||
import fooName from './foo.js'
|
||||
globalThis.result = fooName
|
||||
`)
|
||||
context.unwrapResult(ok).dispose()
|
||||
// logs "foo.js"
|
||||
console.log(context.getProp(context.global, "result").consume(context.dump))
|
||||
context.dispose()
|
||||
runtime.dispose()
|
||||
```
|
||||
|
||||
### Memory Management
|
||||
|
||||
Many methods in this library return handles to memory allocated inside the
|
||||
WebAssembly heap. These types cannot be garbage-collected as usual in
|
||||
Javascript. Instead, you must manually manage their memory by calling a
|
||||
`.dispose()` method to free the underlying resources. Once a handle has been
|
||||
disposed, it cannot be used anymore. Note that in the example above, we call
|
||||
`.dispose()` on each handle once it is no longer needed.
|
||||
|
||||
Calling `QuickJSContext.dispose()` will throw a RuntimeError if you've forgotten to
|
||||
dispose any handles associated with that VM, so it's good practice to create a
|
||||
new VM instance for each of your tests, and to call `vm.dispose()` at the end
|
||||
of every test.
|
||||
|
||||
```typescript
|
||||
const vm = QuickJS.newContext()
|
||||
const numberHandle = vm.newNumber(42)
|
||||
// Note: numberHandle not disposed, so it leaks memory.
|
||||
vm.dispose()
|
||||
// throws RuntimeError: abort(Assertion failed: list_empty(&rt->gc_obj_list), at: quickjs/quickjs.c,1963,JS_FreeRuntime)
|
||||
```
|
||||
|
||||
Here are some strategies to reduce the toil of calling `.dispose()` on each
|
||||
handle you create:
|
||||
|
||||
#### Scope
|
||||
|
||||
A
|
||||
[`Scope`](https://github.com/justjake/quickjs-emscripten/blob/main/doc/classes/scope.md#class-scope)
|
||||
instance manages a set of disposables and calls their `.dispose()`
|
||||
method in the reverse order in which they're added to the scope. Here's the
|
||||
"Interfacing with the interpreter" example re-written using `Scope`:
|
||||
|
||||
```typescript
|
||||
Scope.withScope((scope) => {
|
||||
const vm = scope.manage(QuickJS.newContext())
|
||||
let state = 0
|
||||
|
||||
const fnHandle = scope.manage(
|
||||
vm.newFunction("nextId", () => {
|
||||
return vm.newNumber(++state)
|
||||
})
|
||||
)
|
||||
|
||||
vm.setProp(vm.global, "nextId", fnHandle)
|
||||
|
||||
const nextId = scope.manage(vm.unwrapResult(vm.evalCode(`nextId(); nextId(); nextId()`)))
|
||||
console.log("vm result:", vm.getNumber(nextId), "native state:", state)
|
||||
|
||||
// When the withScope block exits, it calls scope.dispose(), which in turn calls
|
||||
// the .dispose() methods of all the disposables managed by the scope.
|
||||
})
|
||||
```
|
||||
|
||||
You can also create `Scope` instances with `new Scope()` if you want to manage
|
||||
calling `scope.dispose()` yourself.
|
||||
|
||||
#### `Lifetime.consume(fn)`
|
||||
|
||||
[`Lifetime.consume`](https://github.com/justjake/quickjs-emscripten/blob/main/doc/classes/lifetime.md#consume)
|
||||
is sugar for the common pattern of using a handle and then
|
||||
immediately disposing of it. `Lifetime.consume` takes a `map` function that
|
||||
produces a result of any type. The `map` fuction is called with the handle,
|
||||
then the handle is disposed, then the result is returned.
|
||||
|
||||
Here's the "Interfacing with interpreter" example re-written using `.consume()`:
|
||||
|
||||
```typescript
|
||||
const vm = QuickJS.newContext()
|
||||
let state = 0
|
||||
|
||||
vm.newFunction("nextId", () => {
|
||||
return vm.newNumber(++state)
|
||||
}).consume((fnHandle) => vm.setProp(vm.global, "nextId", fnHandle))
|
||||
|
||||
vm.unwrapResult(vm.evalCode(`nextId(); nextId(); nextId()`)).consume((nextId) =>
|
||||
console.log("vm result:", vm.getNumber(nextId), "native state:", state)
|
||||
)
|
||||
|
||||
vm.dispose()
|
||||
```
|
||||
|
||||
Generally working with `Scope` leads to more straight-forward code, but
|
||||
`Lifetime.consume` can be handy sugar as part of a method call chain.
|
||||
|
||||
### Exposing APIs
|
||||
|
||||
To add APIs inside the QuickJS environment, you'll need to create objects to
|
||||
define the shape of your API, and add properties and functions to those objects
|
||||
to allow code inside QuickJS to call code on the host.
|
||||
|
||||
By default, no host functionality is exposed to code running inside QuickJS.
|
||||
|
||||
```typescript
|
||||
const vm = QuickJS.newContext()
|
||||
// `console.log`
|
||||
const logHandle = vm.newFunction("log", (...args) => {
|
||||
const nativeArgs = args.map(vm.dump)
|
||||
console.log("QuickJS:", ...nativeArgs)
|
||||
})
|
||||
// Partially implement `console` object
|
||||
const consoleHandle = vm.newObject()
|
||||
vm.setProp(consoleHandle, "log", logHandle)
|
||||
vm.setProp(vm.global, "console", consoleHandle)
|
||||
consoleHandle.dispose()
|
||||
logHandle.dispose()
|
||||
|
||||
vm.unwrapResult(vm.evalCode(`console.log("Hello from QuickJS!")`)).dispose()
|
||||
```
|
||||
|
||||
#### Promises
|
||||
|
||||
To expose an asynchronous function that _returns a promise_ to callers within
|
||||
QuickJS, your function can return the handle of a `QuickJSDeferredPromise`
|
||||
created via `context.newPromise()`.
|
||||
|
||||
When you resolve a `QuickJSDeferredPromise` -- and generally whenever async
|
||||
behavior completes for the VM -- pending listeners inside QuickJS may not
|
||||
execute immediately. Your code needs to explicitly call
|
||||
`runtime.executePendingJobs()` to resume execution inside QuickJS. This API
|
||||
gives your code maximum control to _schedule_ when QuickJS will block the host's
|
||||
event loop by resuming execution.
|
||||
|
||||
To work with QuickJS handles that contain a promise inside the environment, you
|
||||
can convert the QuickJSHandle into a native promise using
|
||||
`context.resolvePromise()`. Take care with this API to avoid 'deadlocks' where
|
||||
the host awaits a guest promise, but the guest cannot make progress until the
|
||||
host calls `runtime.executePendingJobs()`. The simplest way to avoid this kind
|
||||
of deadlock is to always schedule `executePendingJobs` after any promise is
|
||||
settled.
|
||||
|
||||
```typescript
|
||||
const vm = QuickJS.newContext()
|
||||
const fakeFileSystem = new Map([["example.txt", "Example file content"]])
|
||||
|
||||
// Function that simulates reading data asynchronously
|
||||
const readFileHandle = vm.newFunction("readFile", (pathHandle) => {
|
||||
const path = vm.getString(pathHandle)
|
||||
const promise = vm.newPromise()
|
||||
setTimeout(() => {
|
||||
const content = fakeFileSystem.get(path)
|
||||
promise.resolve(vm.newString(content || ""))
|
||||
}, 100)
|
||||
// IMPORTANT: Once you resolve an async action inside QuickJS,
|
||||
// call runtime.executePendingJobs() to run any code that was
|
||||
// waiting on the promise or callback.
|
||||
promise.settled.then(vm.runtime.executePendingJobs)
|
||||
return promise.handle
|
||||
})
|
||||
readFileHandle.consume((handle) => vm.setProp(vm.global, "readFile", handle))
|
||||
|
||||
// Evaluate code that uses `readFile`, which returns a promise
|
||||
const result = vm.evalCode(`(async () => {
|
||||
const content = await readFile('example.txt')
|
||||
return content.toUpperCase()
|
||||
})()`)
|
||||
const promiseHandle = vm.unwrapResult(result)
|
||||
|
||||
// Convert the promise handle into a native promise and await it.
|
||||
// If code like this deadlocks, make sure you are calling
|
||||
// runtime.executePendingJobs appropriately.
|
||||
const resolvedResult = await vm.resolvePromise(promiseHandle)
|
||||
promiseHandle.dispose()
|
||||
const resolvedHandle = vm.unwrapResult(resolvedResult)
|
||||
console.log("Result:", vm.getString(resolvedHandle))
|
||||
resolvedHandle.dispose()
|
||||
```
|
||||
|
||||
#### Asyncify
|
||||
|
||||
Sometimes, we want to create a function that's synchronous from the perspective
|
||||
of QuickJS, but prefer to implement that function _asynchronously_ in your host
|
||||
code. The most obvious use-case is for EcmaScript module loading. The underlying
|
||||
QuickJS C library expects the module loader function to return synchronously,
|
||||
but loading data synchronously in the browser or server is somewhere between "a
|
||||
bad idea" and "impossible". QuickJS also doesn't expose an API to "pause" the
|
||||
execution of a runtime, and adding such an API is tricky due to the VM's
|
||||
implementation.
|
||||
|
||||
As a work-around, we provide an alternate build of QuickJS processed by
|
||||
Emscripten/Binaryen's [ASYNCIFY](https://emscripten.org/docs/porting/asyncify.html)
|
||||
compiler transform. Here's how Emscripten's documentation describes Asyncify:
|
||||
|
||||
> Asyncify lets synchronous C or C++ code interact with asynchronous \[host] JavaScript. This allows things like:
|
||||
>
|
||||
> - A synchronous call in C that yields to the event loop, which allows browser events to be handled.
|
||||
>
|
||||
> - A synchronous call in C that waits for an asynchronous operation in \[host] JS to complete.
|
||||
>
|
||||
> Asyncify automatically transforms ... code into a form that can be paused and
|
||||
> resumed ..., so that it is asynchronous (hence the name “Asyncify”) even though
|
||||
> \[it is written] in a normal synchronous way.
|
||||
|
||||
This means we can suspend an _entire WebAssembly module_ (which could contain
|
||||
multiple runtimes and contexts) while our host Javascript loads data
|
||||
asynchronously, and then resume execution once the data load completes. This is
|
||||
a very handy superpower, but it comes with a couple of major limitations:
|
||||
|
||||
1. _An asyncified WebAssembly module can only suspend to wait for a single
|
||||
asynchronous call at a time_. You may call back into a suspended WebAssembly
|
||||
module eg. to create a QuickJS value to return a result, but the system will
|
||||
crash if this call tries to suspend again. Take a look at Emscripten's documentation
|
||||
on [reentrancy](https://emscripten.org/docs/porting/asyncify.html#reentrancy).
|
||||
|
||||
2. _Asyncified code is bigger and runs slower_. The asyncified build of
|
||||
Quickjs-emscripten library is 1M, 2x larger than the 500K of the default
|
||||
version. There may be room for further
|
||||
[optimization](https://emscripten.org/docs/porting/asyncify.html#optimizing)
|
||||
Of our build in the future.
|
||||
|
||||
To use asyncify features, use the following functions:
|
||||
|
||||
- [newAsyncRuntime][]: create a runtime inside a new WebAssembly module.
|
||||
- [newAsyncContext][]: create runtime and context together inside a new
|
||||
WebAssembly module.
|
||||
- [newQuickJSAsyncWASMModule][]: create an empty WebAssembly module.
|
||||
|
||||
[newasyncruntime]: https://github.com/justjake/quickjs-emscripten/blob/main/doc/modules.md#newasyncruntime
|
||||
[newasynccontext]: https://github.com/justjake/quickjs-emscripten/blob/main/doc/modules.md#newasynccontext
|
||||
[newquickjsasyncwasmmodule]: https://github.com/justjake/quickjs-emscripten/blob/main/doc/modules.md#newquickjsasyncwasmmodule
|
||||
|
||||
These functions are asynchronous because they always create a new underlying
|
||||
WebAssembly module so that each instance can suspend and resume independently,
|
||||
and instantiating a WebAssembly module is an async operation. This also adds
|
||||
substantial overhead compared to creating a runtime or context inside an
|
||||
existing module; if you only need to wait for a single async action at a time,
|
||||
you can create a single top-level module and create runtimes or contexts inside
|
||||
of it.
|
||||
|
||||
##### Async module loader
|
||||
|
||||
Here's an example of valuating a script that loads React asynchronously as an ES
|
||||
module. In our example, we're loading from the filesystem for reproducibility,
|
||||
but you can use this technique to load using `fetch`.
|
||||
|
||||
```typescript
|
||||
const module = await newQuickJSAsyncWASMModule()
|
||||
const runtime = module.newRuntime()
|
||||
const path = await import("path")
|
||||
const { promises: fs } = await import("fs")
|
||||
|
||||
const importsPath = path.join(__dirname, "../examples/imports") + "/"
|
||||
// Module loaders can return promises.
|
||||
// Execution will suspend until the promise resolves.
|
||||
runtime.setModuleLoader((moduleName) => {
|
||||
const modulePath = path.join(importsPath, moduleName)
|
||||
if (!modulePath.startsWith(importsPath)) {
|
||||
throw new Error("out of bounds")
|
||||
}
|
||||
console.log("loading", moduleName, "from", modulePath)
|
||||
return fs.readFile(modulePath, "utf-8")
|
||||
})
|
||||
|
||||
// evalCodeAsync is required when execution may suspend.
|
||||
const context = runtime.newContext()
|
||||
const result = await context.evalCodeAsync(`
|
||||
import * as React from 'esm.sh/react@17'
|
||||
import * as ReactDOMServer from 'esm.sh/react-dom@17/server'
|
||||
const e = React.createElement
|
||||
globalThis.html = ReactDOMServer.renderToStaticMarkup(
|
||||
e('div', null, e('strong', null, 'Hello world!'))
|
||||
)
|
||||
`)
|
||||
context.unwrapResult(result).dispose()
|
||||
const html = context.getProp(context.global, "html").consume(context.getString)
|
||||
console.log(html) // <div><strong>Hello world!</strong></div>
|
||||
```
|
||||
|
||||
##### Async on host, sync in QuickJS
|
||||
|
||||
Here's an example of turning an async function into a sync function inside the
|
||||
VM.
|
||||
|
||||
```typescript
|
||||
const context = await newAsyncContext()
|
||||
const path = await import("path")
|
||||
const { promises: fs } = await import("fs")
|
||||
|
||||
const importsPath = path.join(__dirname, "../examples/imports") + "/"
|
||||
const readFileHandle = context.newAsyncifiedFunction("readFile", async (pathHandle) => {
|
||||
const pathString = path.join(importsPath, context.getString(pathHandle))
|
||||
if (!pathString.startsWith(importsPath)) {
|
||||
throw new Error("out of bounds")
|
||||
}
|
||||
const data = await fs.readFile(pathString, "utf-8")
|
||||
return context.newString(data)
|
||||
})
|
||||
readFileHandle.consume((fn) => context.setProp(context.global, "readFile", fn))
|
||||
|
||||
// evalCodeAsync is required when execution may suspend.
|
||||
const result = await context.evalCodeAsync(`
|
||||
// Not a promise! Sync! vvvvvvvvvvvvvvvvvvvv
|
||||
const data = JSON.parse(readFile('data.json'))
|
||||
data.map(x => x.toUpperCase()).join(' ')
|
||||
`)
|
||||
const upperCaseData = context.unwrapResult(result).consume(context.getString)
|
||||
console.log(upperCaseData) // 'VERY USEFUL DATA'
|
||||
```
|
||||
|
||||
### Testing your code
|
||||
|
||||
This library is complicated to use, so please consider automated testing your
|
||||
implementation. We highly writing your test suite to run with both the "release"
|
||||
build variant of quickjs-emscripten, and also the [DEBUG_SYNC] build variant.
|
||||
The debug sync build variant has extra instrumentation code for detecting memory
|
||||
leaks.
|
||||
|
||||
The class [TestQuickJSWASMModule] exposes the memory leak detection API, although
|
||||
this API is only accurate when using `DEBUG_SYNC` variant.
|
||||
|
||||
```typescript
|
||||
// Define your test suite in a function, so that you can test against
|
||||
// different module loaders.
|
||||
function myTests(moduleLoader: () => Promise<QuickJSWASMModule>) {
|
||||
let QuickJS: TestQuickJSWASMModule
|
||||
beforeEach(async () => {
|
||||
// Get a unique TestQuickJSWASMModule instance for each test.
|
||||
const wasmModule = await moduleLoader()
|
||||
QuickJS = new TestQuickJSWASMModule(wasmModule)
|
||||
})
|
||||
afterEach(() => {
|
||||
// Assert that the test disposed all handles. The DEBUG_SYNC build
|
||||
// variant will show detailed traces for each leak.
|
||||
QuickJS.assertNoMemoryAllocated()
|
||||
})
|
||||
|
||||
it("works well", () => {
|
||||
// TODO: write a test using QuickJS
|
||||
const context = QuickJS.newContext()
|
||||
context.unwrapResult(context.evalCode("1 + 1")).dispose()
|
||||
context.dispose()
|
||||
})
|
||||
}
|
||||
|
||||
// Run the test suite against a matrix of module loaders.
|
||||
describe("Check for memory leaks with QuickJS DEBUG build", () => {
|
||||
const moduleLoader = memoizePromiseFactory(() => newQuickJSWASMModule(DEBUG_SYNC))
|
||||
myTests(moduleLoader)
|
||||
})
|
||||
|
||||
describe("Realistic test with QuickJS RELEASE build", () => {
|
||||
myTests(getQuickJS)
|
||||
})
|
||||
```
|
||||
|
||||
For more testing examples, please explore the typescript source of [quickjs-emscripten][ts] repository.
|
||||
|
||||
[ts]: https://github.com/justjake/quickjs-emscripten/blob/main/ts
|
||||
[debug_sync]: https://github.com/justjake/quickjs-emscripten/blob/main/doc/modules.md#debug_sync
|
||||
[testquickjswasmmodule]: https://github.com/justjake/quickjs-emscripten/blob/main/doc/classes/TestQuickJSWASMModule.md
|
||||
|
||||
### Debugging
|
||||
|
||||
- Switch to a DEBUG build variant of the WebAssembly module to see debug log messages from the C part of this library.
|
||||
- Set `process.env.QTS_DEBUG` to see debug log messages from the Javascript part of this library.
|
||||
|
||||
### More Documentation
|
||||
|
||||
[Github] | [NPM] | [API Documentation][api] | [Examples][tests]
|
||||
|
||||
## Background
|
||||
|
||||
This was inspired by seeing https://github.com/maple3142/duktape-eval
|
||||
[on Hacker News](https://news.ycombinator.com/item?id=21946565) and Figma's
|
||||
blogposts about using building a Javascript plugin runtime:
|
||||
|
||||
- [How Figma built the Figma plugin system](https://www.figma.com/blog/how-we-built-the-figma-plugin-system/): Describes the LowLevelJavascriptVm interface.
|
||||
- [An update on plugin security](https://www.figma.com/blog/an-update-on-plugin-security/): Figma switches to QuickJS.
|
||||
|
||||
## Status & Roadmap
|
||||
|
||||
**Stability**: Because the version number of this project is below `1.0.0`,
|
||||
\*expect occasional breaking API changes.
|
||||
|
||||
**Security**: This project makes every effort to be secure, but has not been
|
||||
audited. Please use with care in production settings.
|
||||
|
||||
**Roadmap**: I work on this project in my free time, for fun. Here's I'm
|
||||
thinking comes next. Last updated 2022-03-18.
|
||||
|
||||
1. Further work on module loading APIs:
|
||||
|
||||
- Create modules via Javascript, instead of source text.
|
||||
- Scan source text for imports, for ahead of time or concurrent loading.
|
||||
(This is possible with third-party tools, so lower priority.)
|
||||
|
||||
2. Higher-level tools for reading QuickJS values:
|
||||
|
||||
- Type guard functions: `context.isArray(handle)`, `context.isPromise(handle)`, etc.
|
||||
- Iteration utilities: `context.getIterable(handle)`, `context.iterateObjectEntries(handle)`.
|
||||
This better supports user-level code to deserialize complex handle objects.
|
||||
|
||||
3. Higher-level tools for creating QuickJS values:
|
||||
|
||||
- Devise a way to avoid needing to mess around with handles when setting up
|
||||
the environment.
|
||||
- Consider integrating
|
||||
[quickjs-emscripten-sync](https://github.com/reearth/quickjs-emscripten-sync)
|
||||
for automatic translation.
|
||||
- Consider class-based or interface-type-based marshalling.
|
||||
|
||||
4. EcmaScript Modules / WebAssembly files / Deno support. This requires me to
|
||||
learn a lot of new things, but should be interesting for modern browser usage.
|
||||
|
||||
5. SQLite integration.
|
||||
|
||||
## Related
|
||||
|
||||
- Duktape wrapped in Wasm: https://github.com/maple3142/duktape-eval/blob/main/src/Makefile
|
||||
- QuickJS wrapped in C++: https://github.com/ftk/quickjspp
|
||||
|
||||
## Developing
|
||||
|
||||
This library is implemented in two languages: C (compiled to WASM with
|
||||
Emscripten), and Typescript.
|
||||
|
||||
### The C parts
|
||||
|
||||
The ./c directory contains C code that wraps the QuickJS C library (in ./quickjs).
|
||||
Public functions (those starting with `QTS_`) in ./c/interface.c are
|
||||
automatically exported to native code (via a generated header) and to
|
||||
Typescript (via a generated FFI class). See ./generate.ts for how this works.
|
||||
|
||||
The C code builds as both with `emscripten` (using `emcc`), to produce WASM (or
|
||||
ASM.js) and with `clang`. Build outputs are checked in, so you can iterate on
|
||||
the Javascript parts of the library without setting up the Emscripten toolchain.
|
||||
|
||||
Intermediate object files from QuickJS end up in ./build/quickjs/.
|
||||
|
||||
This project uses `emscripten 3.1.32`.
|
||||
|
||||
- On ARM64, you should install `emscripten` on your machine. For example on macOS, `brew install emscripten`.
|
||||
- If _the correct version of emcc_ is not in your PATH, compilation falls back to using Docker.
|
||||
On ARM64, this is 10-50x slower than native compilation, but it's just fine on x64.
|
||||
|
||||
Related NPM scripts:
|
||||
|
||||
- `yarn update-quickjs` will sync the ./quickjs folder with a
|
||||
github repo tracking the upstream QuickJS.
|
||||
- `yarn make-debug` will rebuild C outputs into ./build/wrapper
|
||||
- `yarn make-release` will rebuild C outputs in release mode, which is the mode
|
||||
that should be checked into the repo.
|
||||
|
||||
### The Typescript parts
|
||||
|
||||
The ./ts directory contains Typescript types and wraps the generated Emscripten
|
||||
FFI in a more usable interface.
|
||||
|
||||
You'll need `node` and `yarn`. Install dependencies with `yarn install`.
|
||||
|
||||
- `yarn build` produces ./dist.
|
||||
- `yarn test` runs the tests.
|
||||
- `yarn test --watch` watches for changes and re-runs the tests.
|
||||
|
||||
### Yarn updates
|
||||
|
||||
Just run `yarn set version from sources` to upgrade the Yarn release.
|
||||
819
node_modules/@tootallnate/quickjs-emscripten/c/interface.c
generated
vendored
Normal file
819
node_modules/@tootallnate/quickjs-emscripten/c/interface.c
generated
vendored
Normal file
@@ -0,0 +1,819 @@
|
||||
/**
|
||||
* interface.c
|
||||
*
|
||||
* We primarily use JSValue* (pointer to JSValue) when communicating with the
|
||||
* host javascript environment, because pointers are trivial to use for calls
|
||||
* into emscripten because they're just a number!
|
||||
*
|
||||
* As with the quickjs.h API, a JSValueConst* value is "borrowed" and should
|
||||
* not be freed. A JSValue* is "owned" and should be freed by the owner.
|
||||
*
|
||||
* Functions starting with "QTS_" are exported by generate.ts to:
|
||||
* - interface.h for native C code.
|
||||
* - ffi.ts for emscripten.
|
||||
*
|
||||
* We support building the following build outputs:
|
||||
*
|
||||
* ## 1. Native machine code
|
||||
* For internal development testing purposes.
|
||||
*
|
||||
* ## 2. WASM via Emscripten
|
||||
* For general production use.
|
||||
*
|
||||
* ## 3. Experimental: Asyncified WASM via Emscripten with -s ASYNCIFY=1.
|
||||
* This variant supports treating async host Javascript calls as synchronous
|
||||
* from the perspective of the WASM c code.
|
||||
*
|
||||
* The way this works is described here:
|
||||
* https://emscripten.org/docs/porting/asyncify.html
|
||||
*
|
||||
* In this variant, any call into our C code could return a promise if it ended
|
||||
* up suspended. We mark the methods we suspect might suspend due to users' code
|
||||
* as returning MaybeAsync(T). This information is ignored for the regular
|
||||
* build.
|
||||
*/
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten.h>
|
||||
#endif
|
||||
|
||||
#include <math.h> // For NAN
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef QTS_SANITIZE_LEAK
|
||||
#include <sanitizer/lsan_interface.h>
|
||||
#endif
|
||||
|
||||
#include "../quickjs/cutils.h"
|
||||
#include "../quickjs/quickjs-libc.h"
|
||||
#include "../quickjs/quickjs.h"
|
||||
|
||||
#define PKG "quickjs-emscripten: "
|
||||
|
||||
#ifdef QTS_DEBUG_MODE
|
||||
#define QTS_DEBUG(msg) qts_log(msg);
|
||||
#define QTS_DUMP(value) qts_dump(ctx, value);
|
||||
#else
|
||||
#define QTS_DEBUG(msg) ;
|
||||
#define QTS_DUMP(value) ;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Signal to our FFI code generator that this string argument should be passed as a pointer
|
||||
* allocated by the caller on the heap, not a JS string on the stack.
|
||||
* https://github.com/emscripten-core/emscripten/issues/6860#issuecomment-405818401
|
||||
*/
|
||||
#define BorrowedHeapChar const char
|
||||
#define OwnedHeapChar char
|
||||
#define JSBorrowedChar const char
|
||||
|
||||
/**
|
||||
* Signal to our FFI code generator that this function should be called
|
||||
* asynchronously when compiled with ASYNCIFY.
|
||||
*/
|
||||
#define MaybeAsync(T) T
|
||||
|
||||
/**
|
||||
* Signal to our FFI code generator that this function is only available in
|
||||
* ASYNCIFY builds.
|
||||
*/
|
||||
#define AsyncifyOnly(T) T
|
||||
|
||||
#define JSVoid void
|
||||
|
||||
#define EvalFlags int
|
||||
#define EvalDetectModule int
|
||||
|
||||
void qts_log(char *msg) {
|
||||
fputs(PKG, stderr);
|
||||
fputs(msg, stderr);
|
||||
fputs("\n", stderr);
|
||||
}
|
||||
|
||||
void qts_dump(JSContext *ctx, JSValueConst value) {
|
||||
const char *str = JS_ToCString(ctx, value);
|
||||
if (!str) {
|
||||
QTS_DEBUG("QTS_DUMP: can't dump");
|
||||
return;
|
||||
}
|
||||
fputs(str, stderr);
|
||||
JS_FreeCString(ctx, str);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void copy_prop_if_needed(JSContext *ctx, JSValueConst dest, JSValueConst src, const char *prop_name) {
|
||||
JSAtom prop_atom = JS_NewAtom(ctx, prop_name);
|
||||
JSValue dest_prop = JS_GetProperty(ctx, dest, prop_atom);
|
||||
if (JS_IsUndefined(dest_prop)) {
|
||||
JSValue src_prop = JS_GetProperty(ctx, src, prop_atom);
|
||||
if (!JS_IsUndefined(src_prop) && !JS_IsException(src_prop)) {
|
||||
JS_SetProperty(ctx, dest, prop_atom, src_prop);
|
||||
}
|
||||
} else {
|
||||
JS_FreeValue(ctx, dest_prop);
|
||||
}
|
||||
JS_FreeAtom(ctx, prop_atom);
|
||||
}
|
||||
|
||||
JSValue *jsvalue_to_heap(JSValueConst value) {
|
||||
JSValue *result = malloc(sizeof(JSValue));
|
||||
if (result) {
|
||||
// Could be better optimized, but at -0z / -ftlo, it
|
||||
// appears to produce the same binary code as a memcpy.
|
||||
*result = value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
JSValue *QTS_Throw(JSContext *ctx, JSValueConst *error) {
|
||||
JSValue copy = JS_DupValue(ctx, *error);
|
||||
return jsvalue_to_heap(JS_Throw(ctx, copy));
|
||||
}
|
||||
|
||||
JSValue *QTS_NewError(JSContext *ctx) {
|
||||
return jsvalue_to_heap(JS_NewError(ctx));
|
||||
}
|
||||
|
||||
/**
|
||||
* Limits.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Memory limit. Set to -1 to disable.
|
||||
*/
|
||||
void QTS_RuntimeSetMemoryLimit(JSRuntime *rt, size_t limit) {
|
||||
JS_SetMemoryLimit(rt, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Memory diagnostics
|
||||
*/
|
||||
|
||||
JSValue *QTS_RuntimeComputeMemoryUsage(JSRuntime *rt, JSContext *ctx) {
|
||||
JSMemoryUsage s;
|
||||
JS_ComputeMemoryUsage(rt, &s);
|
||||
|
||||
// Note that we're going to allocate more memory just to report the memory usage.
|
||||
// A more sound approach would be to bind JSMemoryUsage struct directly - but that's
|
||||
// a lot of work. This should be okay in the mean time.
|
||||
JSValue result = JS_NewObject(ctx);
|
||||
|
||||
// Manually generated via editor-fu from JSMemoryUsage struct definition in quickjs.h
|
||||
JS_SetPropertyStr(ctx, result, "malloc_limit", JS_NewInt64(ctx, s.malloc_limit));
|
||||
JS_SetPropertyStr(ctx, result, "memory_used_size", JS_NewInt64(ctx, s.memory_used_size));
|
||||
JS_SetPropertyStr(ctx, result, "malloc_count", JS_NewInt64(ctx, s.malloc_count));
|
||||
JS_SetPropertyStr(ctx, result, "memory_used_count", JS_NewInt64(ctx, s.memory_used_count));
|
||||
JS_SetPropertyStr(ctx, result, "atom_count", JS_NewInt64(ctx, s.atom_count));
|
||||
JS_SetPropertyStr(ctx, result, "atom_size", JS_NewInt64(ctx, s.atom_size));
|
||||
JS_SetPropertyStr(ctx, result, "str_count", JS_NewInt64(ctx, s.str_count));
|
||||
JS_SetPropertyStr(ctx, result, "str_size", JS_NewInt64(ctx, s.str_size));
|
||||
JS_SetPropertyStr(ctx, result, "obj_count", JS_NewInt64(ctx, s.obj_count));
|
||||
JS_SetPropertyStr(ctx, result, "obj_size", JS_NewInt64(ctx, s.obj_size));
|
||||
JS_SetPropertyStr(ctx, result, "prop_count", JS_NewInt64(ctx, s.prop_count));
|
||||
JS_SetPropertyStr(ctx, result, "prop_size", JS_NewInt64(ctx, s.prop_size));
|
||||
JS_SetPropertyStr(ctx, result, "shape_count", JS_NewInt64(ctx, s.shape_count));
|
||||
JS_SetPropertyStr(ctx, result, "shape_size", JS_NewInt64(ctx, s.shape_size));
|
||||
JS_SetPropertyStr(ctx, result, "js_func_count", JS_NewInt64(ctx, s.js_func_count));
|
||||
JS_SetPropertyStr(ctx, result, "js_func_size", JS_NewInt64(ctx, s.js_func_size));
|
||||
JS_SetPropertyStr(ctx, result, "js_func_code_size", JS_NewInt64(ctx, s.js_func_code_size));
|
||||
JS_SetPropertyStr(ctx, result, "js_func_pc2line_count", JS_NewInt64(ctx, s.js_func_pc2line_count));
|
||||
JS_SetPropertyStr(ctx, result, "js_func_pc2line_size", JS_NewInt64(ctx, s.js_func_pc2line_size));
|
||||
JS_SetPropertyStr(ctx, result, "c_func_count", JS_NewInt64(ctx, s.c_func_count));
|
||||
JS_SetPropertyStr(ctx, result, "array_count", JS_NewInt64(ctx, s.array_count));
|
||||
JS_SetPropertyStr(ctx, result, "fast_array_count", JS_NewInt64(ctx, s.fast_array_count));
|
||||
JS_SetPropertyStr(ctx, result, "fast_array_elements", JS_NewInt64(ctx, s.fast_array_elements));
|
||||
JS_SetPropertyStr(ctx, result, "binary_object_count", JS_NewInt64(ctx, s.binary_object_count));
|
||||
JS_SetPropertyStr(ctx, result, "binary_object_size", JS_NewInt64(ctx, s.binary_object_size));
|
||||
|
||||
return jsvalue_to_heap(result);
|
||||
}
|
||||
|
||||
OwnedHeapChar *QTS_RuntimeDumpMemoryUsage(JSRuntime *rt) {
|
||||
char *result = malloc(sizeof(char) * 1024);
|
||||
FILE *memfile = fmemopen(result, 1024, "w");
|
||||
JSMemoryUsage s;
|
||||
JS_ComputeMemoryUsage(rt, &s);
|
||||
JS_DumpMemoryUsage(memfile, &s, rt);
|
||||
fclose(memfile);
|
||||
return result;
|
||||
}
|
||||
|
||||
int QTS_RecoverableLeakCheck() {
|
||||
#ifdef QTS_SANITIZE_LEAK
|
||||
return __lsan_do_recoverable_leak_check();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int QTS_BuildIsSanitizeLeak() {
|
||||
#ifdef QTS_SANITIZE_LEAK
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef QTS_ASYNCIFY
|
||||
EM_JS(void, set_asyncify_stack_size, (size_t size), {
|
||||
Asyncify.StackSize = size || 81920;
|
||||
});
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Set the stack size limit, in bytes. Set to 0 to disable.
|
||||
*/
|
||||
void QTS_RuntimeSetMaxStackSize(JSRuntime *rt, size_t stack_size) {
|
||||
#ifdef QTS_ASYNCIFY
|
||||
set_asyncify_stack_size(stack_size);
|
||||
#endif
|
||||
JS_SetMaxStackSize(rt, stack_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constant pointers. Because we always use JSValue* from the host Javascript environment,
|
||||
* we need helper fuctions to return pointers to these constants.
|
||||
*/
|
||||
|
||||
JSValueConst QTS_Undefined = JS_UNDEFINED;
|
||||
JSValueConst *QTS_GetUndefined() {
|
||||
return &QTS_Undefined;
|
||||
}
|
||||
|
||||
JSValueConst QTS_Null = JS_NULL;
|
||||
JSValueConst *QTS_GetNull() {
|
||||
return &QTS_Null;
|
||||
}
|
||||
|
||||
JSValueConst QTS_False = JS_FALSE;
|
||||
JSValueConst *QTS_GetFalse() {
|
||||
return &QTS_False;
|
||||
}
|
||||
|
||||
JSValueConst QTS_True = JS_TRUE;
|
||||
JSValueConst *QTS_GetTrue() {
|
||||
return &QTS_True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard FFI functions
|
||||
*/
|
||||
|
||||
JSRuntime *QTS_NewRuntime() {
|
||||
return JS_NewRuntime();
|
||||
}
|
||||
|
||||
void QTS_FreeRuntime(JSRuntime *rt) {
|
||||
JS_FreeRuntime(rt);
|
||||
}
|
||||
|
||||
JSContext *QTS_NewContext(JSRuntime *rt) {
|
||||
return JS_NewContext(rt);
|
||||
}
|
||||
|
||||
void QTS_FreeContext(JSContext *ctx) {
|
||||
JS_FreeContext(ctx);
|
||||
}
|
||||
|
||||
void QTS_FreeValuePointer(JSContext *ctx, JSValue *value) {
|
||||
JS_FreeValue(ctx, *value);
|
||||
free(value);
|
||||
}
|
||||
|
||||
void QTS_FreeValuePointerRuntime(JSRuntime *rt, JSValue *value) {
|
||||
JS_FreeValueRT(rt, *value);
|
||||
free(value);
|
||||
}
|
||||
|
||||
void QTS_FreeVoidPointer(JSContext *ctx, JSVoid *ptr) {
|
||||
js_free(ctx, ptr);
|
||||
}
|
||||
|
||||
void QTS_FreeCString(JSContext *ctx, JSBorrowedChar *str) {
|
||||
JS_FreeCString(ctx, str);
|
||||
}
|
||||
|
||||
JSValue *QTS_DupValuePointer(JSContext *ctx, JSValueConst *val) {
|
||||
return jsvalue_to_heap(JS_DupValue(ctx, *val));
|
||||
}
|
||||
|
||||
JSValue *QTS_NewObject(JSContext *ctx) {
|
||||
return jsvalue_to_heap(JS_NewObject(ctx));
|
||||
}
|
||||
|
||||
JSValue *QTS_NewObjectProto(JSContext *ctx, JSValueConst *proto) {
|
||||
return jsvalue_to_heap(JS_NewObjectProto(ctx, *proto));
|
||||
}
|
||||
|
||||
JSValue *QTS_NewArray(JSContext *ctx) {
|
||||
return jsvalue_to_heap(JS_NewArray(ctx));
|
||||
}
|
||||
|
||||
JSValue *QTS_NewFloat64(JSContext *ctx, double num) {
|
||||
return jsvalue_to_heap(JS_NewFloat64(ctx, num));
|
||||
}
|
||||
|
||||
double QTS_GetFloat64(JSContext *ctx, JSValueConst *value) {
|
||||
double result = NAN;
|
||||
JS_ToFloat64(ctx, &result, *value);
|
||||
return result;
|
||||
}
|
||||
|
||||
JSValue *QTS_NewString(JSContext *ctx, BorrowedHeapChar *string) {
|
||||
return jsvalue_to_heap(JS_NewString(ctx, string));
|
||||
}
|
||||
|
||||
JSBorrowedChar *QTS_GetString(JSContext *ctx, JSValueConst *value) {
|
||||
return JS_ToCString(ctx, *value);
|
||||
}
|
||||
|
||||
JSValue qts_get_symbol_key(JSContext *ctx, JSValueConst *value) {
|
||||
JSValue global = JS_GetGlobalObject(ctx);
|
||||
JSValue Symbol = JS_GetPropertyStr(ctx, global, "Symbol");
|
||||
JS_FreeValue(ctx, global);
|
||||
|
||||
JSValue Symbol_keyFor = JS_GetPropertyStr(ctx, Symbol, "keyFor");
|
||||
JSValue key = JS_Call(ctx, Symbol_keyFor, Symbol, 1, value);
|
||||
JS_FreeValue(ctx, Symbol_keyFor);
|
||||
JS_FreeValue(ctx, Symbol);
|
||||
return key;
|
||||
}
|
||||
|
||||
JSValue *QTS_NewSymbol(JSContext *ctx, BorrowedHeapChar *description, int isGlobal) {
|
||||
JSValue global = JS_GetGlobalObject(ctx);
|
||||
JSValue Symbol = JS_GetPropertyStr(ctx, global, "Symbol");
|
||||
JS_FreeValue(ctx, global);
|
||||
JSValue descriptionValue = JS_NewString(ctx, description);
|
||||
JSValue symbol;
|
||||
|
||||
if (isGlobal != 0) {
|
||||
JSValue Symbol_for = JS_GetPropertyStr(ctx, Symbol, "for");
|
||||
symbol = JS_Call(ctx, Symbol_for, Symbol, 1, &descriptionValue);
|
||||
JS_FreeValue(ctx, descriptionValue);
|
||||
JS_FreeValue(ctx, Symbol_for);
|
||||
JS_FreeValue(ctx, Symbol);
|
||||
return jsvalue_to_heap(symbol);
|
||||
}
|
||||
|
||||
symbol = JS_Call(ctx, Symbol, JS_UNDEFINED, 1, &descriptionValue);
|
||||
JS_FreeValue(ctx, descriptionValue);
|
||||
JS_FreeValue(ctx, Symbol);
|
||||
|
||||
return jsvalue_to_heap(symbol);
|
||||
}
|
||||
|
||||
MaybeAsync(JSBorrowedChar *) QTS_GetSymbolDescriptionOrKey(JSContext *ctx, JSValueConst *value) {
|
||||
JSBorrowedChar *result;
|
||||
|
||||
JSValue key = qts_get_symbol_key(ctx, value);
|
||||
if (!JS_IsUndefined(key)) {
|
||||
result = JS_ToCString(ctx, key);
|
||||
JS_FreeValue(ctx, key);
|
||||
return result;
|
||||
}
|
||||
|
||||
JSValue description = JS_GetPropertyStr(ctx, *value, "description");
|
||||
result = JS_ToCString(ctx, description);
|
||||
JS_FreeValue(ctx, description);
|
||||
return result;
|
||||
}
|
||||
|
||||
int QTS_IsGlobalSymbol(JSContext *ctx, JSValueConst *value) {
|
||||
JSValue key = qts_get_symbol_key(ctx, value);
|
||||
int undefined = JS_IsUndefined(key);
|
||||
JS_FreeValue(ctx, key);
|
||||
|
||||
if (undefined) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int QTS_IsJobPending(JSRuntime *rt) {
|
||||
return JS_IsJobPending(rt);
|
||||
}
|
||||
|
||||
/*
|
||||
runs pending jobs (Promises/async functions) until it encounters
|
||||
an exception or it executed the passed maxJobsToExecute jobs.
|
||||
|
||||
Passing a negative value will run the loop until there are no more
|
||||
pending jobs or an exception happened
|
||||
|
||||
Returns the executed number of jobs or the exception encountered
|
||||
*/
|
||||
MaybeAsync(JSValue *) QTS_ExecutePendingJob(JSRuntime *rt, int maxJobsToExecute, JSContext **lastJobContext) {
|
||||
JSContext *pctx;
|
||||
int status = 1;
|
||||
int executed = 0;
|
||||
while (executed != maxJobsToExecute && status == 1) {
|
||||
status = JS_ExecutePendingJob(rt, &pctx);
|
||||
if (status == -1) {
|
||||
*lastJobContext = pctx;
|
||||
return jsvalue_to_heap(JS_GetException(pctx));
|
||||
} else if (status == 1) {
|
||||
*lastJobContext = pctx;
|
||||
executed++;
|
||||
}
|
||||
}
|
||||
#ifdef QTS_DEBUG_MODE
|
||||
char msg[500];
|
||||
sprintf(msg, "QTS_ExecutePendingJob(executed: %d, pctx: %p, lastJobExecuted: %p)", executed, pctx, *lastJobContext);
|
||||
QTS_DEBUG(msg)
|
||||
#endif
|
||||
return jsvalue_to_heap(JS_NewFloat64(pctx, executed));
|
||||
}
|
||||
|
||||
MaybeAsync(JSValue *) QTS_GetProp(JSContext *ctx, JSValueConst *this_val, JSValueConst *prop_name) {
|
||||
JSAtom prop_atom = JS_ValueToAtom(ctx, *prop_name);
|
||||
JSValue prop_val = JS_GetProperty(ctx, *this_val, prop_atom);
|
||||
JS_FreeAtom(ctx, prop_atom);
|
||||
return jsvalue_to_heap(prop_val);
|
||||
}
|
||||
|
||||
MaybeAsync(void) QTS_SetProp(JSContext *ctx, JSValueConst *this_val, JSValueConst *prop_name, JSValueConst *prop_value) {
|
||||
JSAtom prop_atom = JS_ValueToAtom(ctx, *prop_name);
|
||||
JSValue extra_prop_value = JS_DupValue(ctx, *prop_value);
|
||||
// TODO: should we use DefineProperty internally if this object doesn't have the property yet?
|
||||
JS_SetProperty(ctx, *this_val, prop_atom, extra_prop_value); // consumes extra_prop_value
|
||||
JS_FreeAtom(ctx, prop_atom);
|
||||
}
|
||||
|
||||
void QTS_DefineProp(JSContext *ctx, JSValueConst *this_val, JSValueConst *prop_name, JSValueConst *prop_value, JSValueConst *get, JSValueConst *set, bool configurable, bool enumerable, bool has_value) {
|
||||
JSAtom prop_atom = JS_ValueToAtom(ctx, *prop_name);
|
||||
|
||||
int flags = 0;
|
||||
if (configurable) {
|
||||
flags = flags | JS_PROP_CONFIGURABLE;
|
||||
if (has_value) {
|
||||
flags = flags | JS_PROP_HAS_CONFIGURABLE;
|
||||
}
|
||||
}
|
||||
if (enumerable) {
|
||||
flags = flags | JS_PROP_ENUMERABLE;
|
||||
if (has_value) {
|
||||
flags = flags | JS_PROP_HAS_ENUMERABLE;
|
||||
}
|
||||
}
|
||||
if (!JS_IsUndefined(*get)) {
|
||||
flags = flags | JS_PROP_HAS_GET;
|
||||
}
|
||||
if (!JS_IsUndefined(*set)) {
|
||||
flags = flags | JS_PROP_HAS_SET;
|
||||
}
|
||||
if (has_value) {
|
||||
flags = flags | JS_PROP_HAS_VALUE;
|
||||
}
|
||||
|
||||
JS_DefineProperty(ctx, *this_val, prop_atom, *prop_value, *get, *set, flags);
|
||||
JS_FreeAtom(ctx, prop_atom);
|
||||
}
|
||||
|
||||
MaybeAsync(JSValue *) QTS_Call(JSContext *ctx, JSValueConst *func_obj, JSValueConst *this_obj, int argc, JSValueConst **argv_ptrs) {
|
||||
// convert array of pointers to array of values
|
||||
JSValueConst argv[argc];
|
||||
int i;
|
||||
for (i = 0; i < argc; i++) {
|
||||
argv[i] = *(argv_ptrs[i]);
|
||||
}
|
||||
|
||||
return jsvalue_to_heap(JS_Call(ctx, *func_obj, *this_obj, argc, argv));
|
||||
}
|
||||
|
||||
/**
|
||||
* If maybe_exception is an exception, get the error.
|
||||
* Otherwise, return NULL.
|
||||
*/
|
||||
JSValue *QTS_ResolveException(JSContext *ctx, JSValue *maybe_exception) {
|
||||
if (JS_IsException(*maybe_exception)) {
|
||||
return jsvalue_to_heap(JS_GetException(ctx));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MaybeAsync(JSBorrowedChar *) QTS_Dump(JSContext *ctx, JSValueConst *obj) {
|
||||
JSValue obj_json_value = JS_JSONStringify(ctx, *obj, JS_UNDEFINED, JS_UNDEFINED);
|
||||
if (!JS_IsException(obj_json_value)) {
|
||||
const char *obj_json_chars = JS_ToCString(ctx, obj_json_value);
|
||||
JS_FreeValue(ctx, obj_json_value);
|
||||
if (obj_json_chars != NULL) {
|
||||
JSValue enumerable_props = JS_ParseJSON(ctx, obj_json_chars, strlen(obj_json_chars), "<dump>");
|
||||
JS_FreeCString(ctx, obj_json_chars);
|
||||
if (!JS_IsException(enumerable_props)) {
|
||||
// Copy common non-enumerable props for different object types.
|
||||
// Errors:
|
||||
copy_prop_if_needed(ctx, enumerable_props, *obj, "name");
|
||||
copy_prop_if_needed(ctx, enumerable_props, *obj, "message");
|
||||
copy_prop_if_needed(ctx, enumerable_props, *obj, "stack");
|
||||
|
||||
// Serialize again.
|
||||
JSValue enumerable_json = JS_JSONStringify(ctx, enumerable_props, JS_UNDEFINED, JS_UNDEFINED);
|
||||
JS_FreeValue(ctx, enumerable_props);
|
||||
|
||||
JSBorrowedChar *result = QTS_GetString(ctx, &enumerable_json);
|
||||
JS_FreeValue(ctx, enumerable_json);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef QTS_DEBUG_MODE
|
||||
qts_log("Error dumping JSON:");
|
||||
js_std_dump_error(ctx);
|
||||
#endif
|
||||
|
||||
// Fallback: convert to string
|
||||
return QTS_GetString(ctx, obj);
|
||||
}
|
||||
|
||||
MaybeAsync(JSValue *) QTS_Eval(JSContext *ctx, BorrowedHeapChar *js_code, const char *filename, EvalDetectModule detectModule, EvalFlags evalFlags) {
|
||||
size_t js_code_len = strlen(js_code);
|
||||
|
||||
if (detectModule) {
|
||||
if (JS_DetectModule((const char *)js_code, js_code_len)) {
|
||||
QTS_DEBUG("QTS_Eval: Detected module = true");
|
||||
evalFlags |= JS_EVAL_TYPE_MODULE;
|
||||
} else {
|
||||
QTS_DEBUG("QTS_Eval: Detected module = false");
|
||||
}
|
||||
} else {
|
||||
QTS_DEBUG("QTS_Eval: do not detect module");
|
||||
}
|
||||
|
||||
return jsvalue_to_heap(JS_Eval(ctx, js_code, strlen(js_code), filename, evalFlags));
|
||||
}
|
||||
|
||||
OwnedHeapChar *QTS_Typeof(JSContext *ctx, JSValueConst *value) {
|
||||
const char *result = "unknown";
|
||||
uint32_t tag = JS_VALUE_GET_TAG(*value);
|
||||
|
||||
if (JS_IsNumber(*value)) {
|
||||
result = "number";
|
||||
} else if (JS_IsBigInt(ctx, *value)) {
|
||||
result = "bigint";
|
||||
} else if (JS_IsBigFloat(*value)) {
|
||||
result = "bigfloat";
|
||||
} else if (JS_IsBigDecimal(*value)) {
|
||||
result = "bigdecimal";
|
||||
} else if (JS_IsFunction(ctx, *value)) {
|
||||
result = "function";
|
||||
} else if (JS_IsBool(*value)) {
|
||||
result = "boolean";
|
||||
} else if (JS_IsNull(*value)) {
|
||||
result = "object";
|
||||
} else if (JS_IsUndefined(*value)) {
|
||||
result = "undefined";
|
||||
} else if (JS_IsUninitialized(*value)) {
|
||||
result = "undefined";
|
||||
} else if (JS_IsString(*value)) {
|
||||
result = "string";
|
||||
} else if (JS_IsSymbol(*value)) {
|
||||
result = "symbol";
|
||||
} else if (JS_IsObject(*value)) {
|
||||
result = "object";
|
||||
}
|
||||
|
||||
char *out = strdup(result);
|
||||
return out;
|
||||
}
|
||||
|
||||
JSValue *QTS_GetGlobalObject(JSContext *ctx) {
|
||||
return jsvalue_to_heap(JS_GetGlobalObject(ctx));
|
||||
}
|
||||
|
||||
JSValue *QTS_NewPromiseCapability(JSContext *ctx, JSValue **resolve_funcs_out) {
|
||||
JSValue resolve_funcs[2];
|
||||
JSValue promise = JS_NewPromiseCapability(ctx, resolve_funcs);
|
||||
resolve_funcs_out[0] = jsvalue_to_heap(resolve_funcs[0]);
|
||||
resolve_funcs_out[1] = jsvalue_to_heap(resolve_funcs[1]);
|
||||
return jsvalue_to_heap(promise);
|
||||
}
|
||||
|
||||
void QTS_TestStringArg(const char *string) {
|
||||
// pass
|
||||
}
|
||||
|
||||
int QTS_BuildIsDebug() {
|
||||
#ifdef QTS_DEBUG_MODE
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int QTS_BuildIsAsyncify() {
|
||||
#ifdef QTS_ASYNCIFY
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Module loading helpers
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// C -> Host Callbacks
|
||||
// Note: inside EM_JS, we need to use ['...'] subscript syntax for accessing JS
|
||||
// objects, because in optimized builds, Closure compiler will mangle all the
|
||||
// names.
|
||||
|
||||
// -------------------
|
||||
// function: C -> Host
|
||||
#ifdef __EMSCRIPTEN__
|
||||
EM_JS(MaybeAsync(JSValue *), qts_host_call_function, (JSContext * ctx, JSValueConst *this_ptr, int argc, JSValueConst *argv, uint32_t magic_func_id), {
|
||||
#ifdef QTS_ASYNCIFY
|
||||
const asyncify = {['handleSleep'] : Asyncify.handleSleep};
|
||||
#else
|
||||
const asyncify = undefined;
|
||||
#endif
|
||||
return Module['callbacks']['callFunction'](asyncify, ctx, this_ptr, argc, argv, magic_func_id);
|
||||
});
|
||||
#endif
|
||||
|
||||
// Function: QuickJS -> C
|
||||
JSValue qts_call_function(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic) {
|
||||
JSValue *result_ptr = qts_host_call_function(ctx, &this_val, argc, argv, magic);
|
||||
if (result_ptr == NULL) {
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
JSValue result = *result_ptr;
|
||||
free(result_ptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Function: Host -> QuickJS
|
||||
JSValue *QTS_NewFunction(JSContext *ctx, uint32_t func_id, const char *name) {
|
||||
#ifdef QTS_DEBUG_MODE
|
||||
char msg[500];
|
||||
sprintf(msg, "new_function(name: %s, magic: %d)", name, func_id);
|
||||
QTS_DEBUG(msg)
|
||||
#endif
|
||||
JSValue func_obj = JS_NewCFunctionMagic(
|
||||
/* context */ ctx,
|
||||
/* JSCFunctionMagic* */ &qts_call_function,
|
||||
/* name */ name,
|
||||
/* min argc */ 0,
|
||||
/* function type */ JS_CFUNC_generic_magic,
|
||||
/* magic: fn id */ func_id);
|
||||
return jsvalue_to_heap(func_obj);
|
||||
}
|
||||
|
||||
JSValueConst *QTS_ArgvGetJSValueConstPointer(JSValueConst *argv, int index) {
|
||||
return &argv[index];
|
||||
}
|
||||
|
||||
// --------------------
|
||||
// interrupt: C -> Host
|
||||
#ifdef __EMSCRIPTEN__
|
||||
EM_JS(int, qts_host_interrupt_handler, (JSRuntime * rt), {
|
||||
// Async not supported here.
|
||||
// #ifdef QTS_ASYNCIFY
|
||||
// const asyncify = Asyncify;
|
||||
// #else
|
||||
const asyncify = undefined;
|
||||
// #endif
|
||||
return Module['callbacks']['shouldInterrupt'](asyncify, rt);
|
||||
});
|
||||
#endif
|
||||
|
||||
// interrupt: QuickJS -> C
|
||||
int qts_interrupt_handler(JSRuntime *rt, void *_unused) {
|
||||
return qts_host_interrupt_handler(rt);
|
||||
}
|
||||
|
||||
// interrupt: Host -> QuickJS
|
||||
void QTS_RuntimeEnableInterruptHandler(JSRuntime *rt) {
|
||||
JS_SetInterruptHandler(rt, &qts_interrupt_handler, NULL);
|
||||
}
|
||||
|
||||
void QTS_RuntimeDisableInterruptHandler(JSRuntime *rt) {
|
||||
JS_SetInterruptHandler(rt, NULL, NULL);
|
||||
}
|
||||
|
||||
// --------------------
|
||||
// load module: C -> Host
|
||||
// TODO: a future version can support host returning JSModuleDef* directly;
|
||||
// for now we only support loading module source code.
|
||||
|
||||
/*
|
||||
The module loading model under ASYNCIFY is convoluted. We need to make sure we
|
||||
never have an async request running concurrently for loading modules.
|
||||
|
||||
The first implemenation looked like this:
|
||||
|
||||
C HOST SUSPENDED
|
||||
qts_host_load_module(name) ------> false
|
||||
call rt.loadModule(name) false
|
||||
Start async load module false
|
||||
Suspend C true
|
||||
Async load complete true
|
||||
< --------------- QTS_CompileModule(source) true
|
||||
QTS_Eval(source, COMPILE_ONLY) true
|
||||
Loaded module has import true
|
||||
qts_host_load_module(dep) -------> true
|
||||
call rt.loadModule(dep) true
|
||||
Start async load module true
|
||||
ALREADY SUSPENDED, CRASH
|
||||
|
||||
We can solve this in two different ways:
|
||||
|
||||
1. Return to C as soon as we async load the module source.
|
||||
That way, we unsuspend before calling QTS_CompileModule.
|
||||
2. Once we load the module, use a new API to detect and async
|
||||
load the module's downstream dependencies. This way
|
||||
they're loaded synchronously so we don't need to suspend "again".
|
||||
|
||||
Probably we could optimize (2) to make it more performant, eg with parallel
|
||||
loading, but (1) seems much easier to implement in the sort run.
|
||||
*/
|
||||
|
||||
JSModuleDef *qts_compile_module(JSContext *ctx, const char *module_name, BorrowedHeapChar *module_body) {
|
||||
#ifdef QTS_DEBUG_MODE
|
||||
char msg[500];
|
||||
sprintf(msg, "QTS_CompileModule(ctx: %p, name: %s, bodyLength: %lu)", ctx, module_name, strlen(module_body));
|
||||
QTS_DEBUG(msg)
|
||||
#endif
|
||||
JSValue func_val = JS_Eval(ctx, module_body, strlen(module_body), module_name, JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
|
||||
if (JS_IsException(func_val)) {
|
||||
return NULL;
|
||||
}
|
||||
// TODO: Is exception ok?
|
||||
// TODO: set import.meta?
|
||||
JSModuleDef *module = JS_VALUE_GET_PTR(func_val);
|
||||
JS_FreeValue(ctx, func_val);
|
||||
return module;
|
||||
}
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
EM_JS(MaybeAsync(char *), qts_host_load_module_source, (JSRuntime * rt, JSContext *ctx, const char *module_name), {
|
||||
#ifdef QTS_ASYNCIFY
|
||||
const asyncify = {['handleSleep'] : Asyncify.handleSleep};
|
||||
#else
|
||||
const asyncify = undefined;
|
||||
#endif
|
||||
// https://emscripten.org/docs/api_reference/preamble.js.html#UTF8ToString
|
||||
const moduleNameString = UTF8ToString(module_name);
|
||||
return Module['callbacks']['loadModuleSource'](asyncify, rt, ctx, moduleNameString);
|
||||
});
|
||||
|
||||
EM_JS(MaybeAsync(char *), qts_host_normalize_module, (JSRuntime * rt, JSContext *ctx, const char *module_base_name, const char *module_name), {
|
||||
#ifdef QTS_ASYNCIFY
|
||||
const asyncify = {['handleSleep'] : Asyncify.handleSleep};
|
||||
#else
|
||||
const asyncify = undefined;
|
||||
#endif
|
||||
// https://emscripten.org/docs/api_reference/preamble.js.html#UTF8ToString
|
||||
const moduleBaseNameString = UTF8ToString(module_base_name);
|
||||
const moduleNameString = UTF8ToString(module_name);
|
||||
return Module['callbacks']['normalizeModule'](asyncify, rt, ctx, moduleBaseNameString, moduleNameString);
|
||||
});
|
||||
#endif
|
||||
|
||||
// load module: QuickJS -> C
|
||||
// See js_module_loader in quickjs/quickjs-libc.c:567
|
||||
JSModuleDef *qts_load_module(JSContext *ctx, const char *module_name, void *_unused) {
|
||||
JSRuntime *rt = JS_GetRuntime(ctx);
|
||||
#ifdef QTS_DEBUG_MODE
|
||||
char msg[500];
|
||||
sprintf(msg, "qts_load_module(rt: %p, ctx: %p, name: %s)", rt, ctx, module_name);
|
||||
QTS_DEBUG(msg)
|
||||
#endif
|
||||
char *module_source = qts_host_load_module_source(rt, ctx, module_name);
|
||||
if (module_source == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JSModuleDef *module = qts_compile_module(ctx, module_name, module_source);
|
||||
free(module_source);
|
||||
return module;
|
||||
}
|
||||
|
||||
char *qts_normalize_module(JSContext *ctx, const char *module_base_name, const char *module_name, void *_unused) {
|
||||
JSRuntime *rt = JS_GetRuntime(ctx);
|
||||
#ifdef QTS_DEBUG_MODE
|
||||
char msg[500];
|
||||
sprintf(msg, "qts_normalize_module(rt: %p, ctx: %p, base_name: %s, name: %s)", rt, ctx, module_base_name, module_name);
|
||||
QTS_DEBUG(msg)
|
||||
#endif
|
||||
char *em_module_name = qts_host_normalize_module(rt, ctx, module_base_name, module_name);
|
||||
char *js_module_name = js_strdup(ctx, em_module_name);
|
||||
free(em_module_name);
|
||||
return js_module_name;
|
||||
}
|
||||
|
||||
// Load module: Host -> QuickJS
|
||||
void QTS_RuntimeEnableModuleLoader(JSRuntime *rt, int use_custom_normalize) {
|
||||
JSModuleNormalizeFunc *module_normalize = NULL; /* use default name normalizer */
|
||||
if (use_custom_normalize) {
|
||||
module_normalize = &qts_normalize_module;
|
||||
}
|
||||
JS_SetModuleLoaderFunc(rt, module_normalize, &qts_load_module, NULL);
|
||||
}
|
||||
|
||||
void QTS_RuntimeDisableModuleLoader(JSRuntime *rt) {
|
||||
JS_SetModuleLoaderFunc(rt, NULL, NULL, NULL);
|
||||
}
|
||||
24
node_modules/@tootallnate/quickjs-emscripten/dist/asyncify-helpers.d.ts
generated
vendored
Normal file
24
node_modules/@tootallnate/quickjs-emscripten/dist/asyncify-helpers.d.ts
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
declare function awaitYield<T>(value: T | Promise<T>): Generator<T | Promise<T>, T, T>;
|
||||
declare function awaitYieldOf<T, Yielded>(generator: Generator<Yielded | Promise<Yielded>, T, Yielded>): Generator<T | Promise<T>, T, T>;
|
||||
export type AwaitYield = typeof awaitYield & {
|
||||
of: typeof awaitYieldOf;
|
||||
};
|
||||
/**
|
||||
* Create a function that may or may not be async, using a generator
|
||||
*
|
||||
* Within the generator, call `yield* awaited(maybePromise)` to await a value
|
||||
* that may or may not be a promise.
|
||||
*
|
||||
* If the inner function never yields a promise, it will return synchronously.
|
||||
*/
|
||||
export declare function maybeAsyncFn<
|
||||
/** Function arguments */
|
||||
Args extends any[], This,
|
||||
/** Function return type */
|
||||
Return,
|
||||
/** Yields to unwrap */
|
||||
Yielded>(that: This, fn: (this: This, awaited: AwaitYield, ...args: Args) => Generator<Yielded | Promise<Yielded>, Return, Yielded>): (...args: Args) => Return | Promise<Return>;
|
||||
export type MaybeAsyncBlock<Return, This, Yielded, Args extends any[] = []> = (this: This, awaited: AwaitYield, ...args: Args) => Generator<Yielded | Promise<Yielded>, Return, Yielded>;
|
||||
export declare function maybeAsync<Return, This, Yielded>(that: This, startGenerator: (this: This, await: AwaitYield) => Generator<Yielded | Promise<Yielded>, Return, Yielded>): Return | Promise<Return>;
|
||||
export declare function awaitEachYieldedPromise<Yielded, Returned>(gen: Generator<Yielded | Promise<Yielded>, Returned, Yielded>): Returned | Promise<Returned>;
|
||||
export {};
|
||||
53
node_modules/@tootallnate/quickjs-emscripten/dist/asyncify-helpers.js
generated
vendored
Normal file
53
node_modules/@tootallnate/quickjs-emscripten/dist/asyncify-helpers.js
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.awaitEachYieldedPromise = exports.maybeAsync = exports.maybeAsyncFn = void 0;
|
||||
function* awaitYield(value) {
|
||||
return (yield value);
|
||||
}
|
||||
function awaitYieldOf(generator) {
|
||||
return awaitYield(awaitEachYieldedPromise(generator));
|
||||
}
|
||||
const AwaitYield = awaitYield;
|
||||
AwaitYield.of = awaitYieldOf;
|
||||
/**
|
||||
* Create a function that may or may not be async, using a generator
|
||||
*
|
||||
* Within the generator, call `yield* awaited(maybePromise)` to await a value
|
||||
* that may or may not be a promise.
|
||||
*
|
||||
* If the inner function never yields a promise, it will return synchronously.
|
||||
*/
|
||||
function maybeAsyncFn(that, fn) {
|
||||
return (...args) => {
|
||||
const generator = fn.call(that, AwaitYield, ...args);
|
||||
return awaitEachYieldedPromise(generator);
|
||||
};
|
||||
}
|
||||
exports.maybeAsyncFn = maybeAsyncFn;
|
||||
class Example {
|
||||
constructor() {
|
||||
this.maybeAsyncMethod = maybeAsyncFn(this, function* (awaited, a) {
|
||||
yield* awaited(new Promise((resolve) => setTimeout(resolve, a)));
|
||||
return 5;
|
||||
});
|
||||
}
|
||||
}
|
||||
function maybeAsync(that, startGenerator) {
|
||||
const generator = startGenerator.call(that, AwaitYield);
|
||||
return awaitEachYieldedPromise(generator);
|
||||
}
|
||||
exports.maybeAsync = maybeAsync;
|
||||
function awaitEachYieldedPromise(gen) {
|
||||
function handleNextStep(step) {
|
||||
if (step.done) {
|
||||
return step.value;
|
||||
}
|
||||
if (step.value instanceof Promise) {
|
||||
return step.value.then((value) => handleNextStep(gen.next(value)), (error) => handleNextStep(gen.throw(error)));
|
||||
}
|
||||
return handleNextStep(gen.next(step.value));
|
||||
}
|
||||
return handleNextStep(gen.next());
|
||||
}
|
||||
exports.awaitEachYieldedPromise = awaitEachYieldedPromise;
|
||||
//# sourceMappingURL=asyncify-helpers.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/asyncify-helpers.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/asyncify-helpers.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"asyncify-helpers.js","sourceRoot":"","sources":["../ts/asyncify-helpers.ts"],"names":[],"mappings":";;;AAAA,QAAQ,CAAC,CAAC,UAAU,CAAI,KAAqB;IAC3C,OAAO,CAAC,MAAM,KAAK,CAAM,CAAA;AAC3B,CAAC;AAED,SAAS,YAAY,CACnB,SAA4D;IAE5D,OAAO,UAAU,CAAC,uBAAuB,CAAC,SAAS,CAAC,CAAC,CAAA;AACvD,CAAC;AAMD,MAAM,UAAU,GAAe,UAAwB,CAAA;AACvD,UAAU,CAAC,EAAE,GAAG,YAAY,CAAA;AAE5B;;;;;;;GAOG;AACH,SAAgB,YAAY,CAS1B,IAAU,EACV,EAI2D;IAE3D,OAAO,CAAC,GAAG,IAAU,EAAE,EAAE;QACvB,MAAM,SAAS,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,CAAA;QACpD,OAAO,uBAAuB,CAAC,SAAS,CAAC,CAAA;IAC3C,CAAC,CAAA;AACH,CAAC;AApBD,oCAoBC;AAED,MAAM,OAAO;IAAb;QACU,qBAAgB,GAAG,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAS;YACzE,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;YAChE,OAAO,CAAC,CAAA;QACV,CAAC,CAAC,CAAA;IACJ,CAAC;CAAA;AAQD,SAAgB,UAAU,CACxB,IAAU,EACV,cAG2D;IAE3D,MAAM,SAAS,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;IACvD,OAAO,uBAAuB,CAAC,SAAS,CAAC,CAAA;AAC3C,CAAC;AATD,gCASC;AAED,SAAgB,uBAAuB,CACrC,GAA6D;IAI7D,SAAS,cAAc,CAAC,IAAgB;QACtC,IAAI,IAAI,CAAC,IAAI,EAAE;YACb,OAAO,IAAI,CAAC,KAAK,CAAA;SAClB;QAED,IAAI,IAAI,CAAC,KAAK,YAAY,OAAO,EAAE;YACjC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CACpB,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAC1C,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAC5C,CAAA;SACF;QAED,OAAO,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;IAC7C,CAAC;IAED,OAAO,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;AACnC,CAAC;AArBD,0DAqBC","sourcesContent":["function* awaitYield<T>(value: T | Promise<T>) {\n return (yield value) as T\n}\n\nfunction awaitYieldOf<T, Yielded>(\n generator: Generator<Yielded | Promise<Yielded>, T, Yielded>\n): Generator<T | Promise<T>, T, T> {\n return awaitYield(awaitEachYieldedPromise(generator))\n}\n\nexport type AwaitYield = typeof awaitYield & {\n of: typeof awaitYieldOf\n}\n\nconst AwaitYield: AwaitYield = awaitYield as AwaitYield\nAwaitYield.of = awaitYieldOf\n\n/**\n * Create a function that may or may not be async, using a generator\n *\n * Within the generator, call `yield* awaited(maybePromise)` to await a value\n * that may or may not be a promise.\n *\n * If the inner function never yields a promise, it will return synchronously.\n */\nexport function maybeAsyncFn<\n /** Function arguments */\n Args extends any[],\n This,\n /** Function return type */\n Return,\n /** Yields to unwrap */\n Yielded\n>(\n that: This,\n fn: (\n this: This,\n awaited: AwaitYield,\n ...args: Args\n ) => Generator<Yielded | Promise<Yielded>, Return, Yielded>\n): (...args: Args) => Return | Promise<Return> {\n return (...args: Args) => {\n const generator = fn.call(that, AwaitYield, ...args)\n return awaitEachYieldedPromise(generator)\n }\n}\n\nclass Example {\n private maybeAsyncMethod = maybeAsyncFn(this, function* (awaited, a: number) {\n yield* awaited(new Promise((resolve) => setTimeout(resolve, a)))\n return 5\n })\n}\n\nexport type MaybeAsyncBlock<Return, This, Yielded, Args extends any[] = []> = (\n this: This,\n awaited: AwaitYield,\n ...args: Args\n) => Generator<Yielded | Promise<Yielded>, Return, Yielded>\n\nexport function maybeAsync<Return, This, Yielded>(\n that: This,\n startGenerator: (\n this: This,\n await: AwaitYield\n ) => Generator<Yielded | Promise<Yielded>, Return, Yielded>\n): Return | Promise<Return> {\n const generator = startGenerator.call(that, AwaitYield)\n return awaitEachYieldedPromise(generator)\n}\n\nexport function awaitEachYieldedPromise<Yielded, Returned>(\n gen: Generator<Yielded | Promise<Yielded>, Returned, Yielded>\n): Returned | Promise<Returned> {\n type NextResult = ReturnType<typeof gen.next>\n\n function handleNextStep(step: NextResult): Returned | Promise<Returned> {\n if (step.done) {\n return step.value\n }\n\n if (step.value instanceof Promise) {\n return step.value.then(\n (value) => handleNextStep(gen.next(value)),\n (error) => handleNextStep(gen.throw(error))\n )\n }\n\n return handleNextStep(gen.next(step.value))\n }\n\n return handleNextStep(gen.next())\n}\n"]}
|
||||
48
node_modules/@tootallnate/quickjs-emscripten/dist/context-asyncify.d.ts
generated
vendored
Normal file
48
node_modules/@tootallnate/quickjs-emscripten/dist/context-asyncify.d.ts
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
import { QuickJSContext } from "./context";
|
||||
import { QuickJSAsyncEmscriptenModule } from "./emscripten-types";
|
||||
import { QuickJSAsyncFFI } from "./variants";
|
||||
import { JSRuntimePointer } from "./types-ffi";
|
||||
import { Lifetime } from "./lifetime";
|
||||
import { QuickJSModuleCallbacks } from "./module";
|
||||
import { QuickJSAsyncRuntime } from "./runtime-asyncify";
|
||||
import { ContextEvalOptions, QuickJSHandle } from "./types";
|
||||
import { VmCallResult } from "./vm-interface";
|
||||
export type AsyncFunctionImplementation = (this: QuickJSHandle, ...args: QuickJSHandle[]) => Promise<QuickJSHandle | VmCallResult<QuickJSHandle> | void>;
|
||||
/**
|
||||
* Asyncified version of [[QuickJSContext]].
|
||||
*
|
||||
* *Asyncify* allows normally synchronous code to wait for asynchronous Promises
|
||||
* or callbacks. The asyncified version of QuickJSContext can wait for async
|
||||
* host functions as though they were synchronous.
|
||||
*/
|
||||
export declare class QuickJSAsyncContext extends QuickJSContext {
|
||||
runtime: QuickJSAsyncRuntime;
|
||||
/** @private */
|
||||
protected module: QuickJSAsyncEmscriptenModule;
|
||||
/** @private */
|
||||
protected ffi: QuickJSAsyncFFI;
|
||||
/** @private */
|
||||
protected rt: Lifetime<JSRuntimePointer>;
|
||||
/** @private */
|
||||
protected callbacks: QuickJSModuleCallbacks;
|
||||
/**
|
||||
* Asyncified version of [[evalCode]].
|
||||
*/
|
||||
evalCodeAsync(code: string, filename?: string,
|
||||
/** See [[EvalFlags]] for number semantics */
|
||||
options?: number | ContextEvalOptions): Promise<VmCallResult<QuickJSHandle>>;
|
||||
/**
|
||||
* Similar to [[newFunction]].
|
||||
* Convert an async host Javascript function into a synchronous QuickJS function value.
|
||||
*
|
||||
* Whenever QuickJS calls this function, the VM's stack will be unwound while
|
||||
* waiting the async function to complete, and then restored when the returned
|
||||
* promise resolves.
|
||||
*
|
||||
* Asyncified functions must never call other asyncified functions or
|
||||
* `import`, even indirectly, because the stack cannot be unwound twice.
|
||||
*
|
||||
* See [Emscripten's docs on Asyncify](https://emscripten.org/docs/porting/asyncify.html).
|
||||
*/
|
||||
newAsyncifiedFunction(name: string, fn: AsyncFunctionImplementation): QuickJSHandle;
|
||||
}
|
||||
58
node_modules/@tootallnate/quickjs-emscripten/dist/context-asyncify.js
generated
vendored
Normal file
58
node_modules/@tootallnate/quickjs-emscripten/dist/context-asyncify.js
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.QuickJSAsyncContext = void 0;
|
||||
const context_1 = require("./context");
|
||||
const debug_1 = require("./debug");
|
||||
const types_1 = require("./types");
|
||||
/**
|
||||
* Asyncified version of [[QuickJSContext]].
|
||||
*
|
||||
* *Asyncify* allows normally synchronous code to wait for asynchronous Promises
|
||||
* or callbacks. The asyncified version of QuickJSContext can wait for async
|
||||
* host functions as though they were synchronous.
|
||||
*/
|
||||
class QuickJSAsyncContext extends context_1.QuickJSContext {
|
||||
/**
|
||||
* Asyncified version of [[evalCode]].
|
||||
*/
|
||||
async evalCodeAsync(code, filename = "eval.js",
|
||||
/** See [[EvalFlags]] for number semantics */
|
||||
options) {
|
||||
const detectModule = (options === undefined ? 1 : 0);
|
||||
const flags = (0, types_1.evalOptionsToFlags)(options);
|
||||
let resultPtr = 0;
|
||||
try {
|
||||
resultPtr = await this.memory
|
||||
.newHeapCharPointer(code)
|
||||
.consume((charHandle) => this.ffi.QTS_Eval_MaybeAsync(this.ctx.value, charHandle.value, filename, detectModule, flags));
|
||||
}
|
||||
catch (error) {
|
||||
(0, debug_1.debugLog)("QTS_Eval_MaybeAsync threw", error);
|
||||
throw error;
|
||||
}
|
||||
const errorPtr = this.ffi.QTS_ResolveException(this.ctx.value, resultPtr);
|
||||
if (errorPtr) {
|
||||
this.ffi.QTS_FreeValuePointer(this.ctx.value, resultPtr);
|
||||
return { error: this.memory.heapValueHandle(errorPtr) };
|
||||
}
|
||||
return { value: this.memory.heapValueHandle(resultPtr) };
|
||||
}
|
||||
/**
|
||||
* Similar to [[newFunction]].
|
||||
* Convert an async host Javascript function into a synchronous QuickJS function value.
|
||||
*
|
||||
* Whenever QuickJS calls this function, the VM's stack will be unwound while
|
||||
* waiting the async function to complete, and then restored when the returned
|
||||
* promise resolves.
|
||||
*
|
||||
* Asyncified functions must never call other asyncified functions or
|
||||
* `import`, even indirectly, because the stack cannot be unwound twice.
|
||||
*
|
||||
* See [Emscripten's docs on Asyncify](https://emscripten.org/docs/porting/asyncify.html).
|
||||
*/
|
||||
newAsyncifiedFunction(name, fn) {
|
||||
return this.newFunction(name, fn);
|
||||
}
|
||||
}
|
||||
exports.QuickJSAsyncContext = QuickJSAsyncContext;
|
||||
//# sourceMappingURL=context-asyncify.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/context-asyncify.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/context-asyncify.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"context-asyncify.js","sourceRoot":"","sources":["../ts/context-asyncify.ts"],"names":[],"mappings":";;;AAAA,uCAA0C;AAC1C,mCAAkC;AAOlC,mCAA+E;AAQ/E;;;;;;GAMG;AACH,MAAa,mBAAoB,SAAQ,wBAAc;IAWrD;;OAEG;IACH,KAAK,CAAC,aAAa,CACjB,IAAY,EACZ,WAAmB,SAAS;IAC5B,6CAA6C;IAC7C,OAAqC;QAErC,MAAM,YAAY,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAqB,CAAA;QACxE,MAAM,KAAK,GAAG,IAAA,0BAAkB,EAAC,OAAO,CAAc,CAAA;QACtD,IAAI,SAAS,GAAG,CAAmB,CAAA;QACnC,IAAI;YACF,SAAS,GAAG,MAAM,IAAI,CAAC,MAAM;iBAC1B,kBAAkB,CAAC,IAAI,CAAC;iBACxB,OAAO,CAAC,CAAC,UAAU,EAAE,EAAE,CACtB,IAAI,CAAC,GAAG,CAAC,mBAAmB,CAC1B,IAAI,CAAC,GAAG,CAAC,KAAK,EACd,UAAU,CAAC,KAAK,EAChB,QAAQ,EACR,YAAY,EACZ,KAAK,CACN,CACF,CAAA;SACJ;QAAC,OAAO,KAAK,EAAE;YACd,IAAA,gBAAQ,EAAC,2BAA2B,EAAE,KAAK,CAAC,CAAA;YAC5C,MAAM,KAAK,CAAA;SACZ;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;QACzE,IAAI,QAAQ,EAAE;YACZ,IAAI,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;YACxD,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAA;SACxD;QACD,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,SAAS,CAAC,EAAE,CAAA;IAC1D,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,qBAAqB,CAAC,IAAY,EAAE,EAA+B;QACjE,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAS,CAAC,CAAA;IAC1C,CAAC;CACF;AA/DD,kDA+DC","sourcesContent":["import { QuickJSContext } from \"./context\"\nimport { debugLog } from \"./debug\"\nimport { QuickJSAsyncEmscriptenModule } from \"./emscripten-types\"\nimport { QuickJSAsyncFFI } from \"./variants\"\nimport { EvalDetectModule, EvalFlags, JSRuntimePointer, JSValuePointer } from \"./types-ffi\"\nimport { Lifetime } from \"./lifetime\"\nimport { QuickJSModuleCallbacks } from \"./module\"\nimport { QuickJSAsyncRuntime } from \"./runtime-asyncify\"\nimport { ContextEvalOptions, evalOptionsToFlags, QuickJSHandle } from \"./types\"\nimport { VmCallResult } from \"./vm-interface\"\n\nexport type AsyncFunctionImplementation = (\n this: QuickJSHandle,\n ...args: QuickJSHandle[]\n) => Promise<QuickJSHandle | VmCallResult<QuickJSHandle> | void>\n\n/**\n * Asyncified version of [[QuickJSContext]].\n *\n * *Asyncify* allows normally synchronous code to wait for asynchronous Promises\n * or callbacks. The asyncified version of QuickJSContext can wait for async\n * host functions as though they were synchronous.\n */\nexport class QuickJSAsyncContext extends QuickJSContext {\n public declare runtime: QuickJSAsyncRuntime\n /** @private */\n protected declare module: QuickJSAsyncEmscriptenModule\n /** @private */\n protected declare ffi: QuickJSAsyncFFI\n /** @private */\n protected declare rt: Lifetime<JSRuntimePointer>\n /** @private */\n protected declare callbacks: QuickJSModuleCallbacks\n\n /**\n * Asyncified version of [[evalCode]].\n */\n async evalCodeAsync(\n code: string,\n filename: string = \"eval.js\",\n /** See [[EvalFlags]] for number semantics */\n options?: number | ContextEvalOptions\n ): Promise<VmCallResult<QuickJSHandle>> {\n const detectModule = (options === undefined ? 1 : 0) as EvalDetectModule\n const flags = evalOptionsToFlags(options) as EvalFlags\n let resultPtr = 0 as JSValuePointer\n try {\n resultPtr = await this.memory\n .newHeapCharPointer(code)\n .consume((charHandle) =>\n this.ffi.QTS_Eval_MaybeAsync(\n this.ctx.value,\n charHandle.value,\n filename,\n detectModule,\n flags\n )\n )\n } catch (error) {\n debugLog(\"QTS_Eval_MaybeAsync threw\", error)\n throw error\n }\n const errorPtr = this.ffi.QTS_ResolveException(this.ctx.value, resultPtr)\n if (errorPtr) {\n this.ffi.QTS_FreeValuePointer(this.ctx.value, resultPtr)\n return { error: this.memory.heapValueHandle(errorPtr) }\n }\n return { value: this.memory.heapValueHandle(resultPtr) }\n }\n\n /**\n * Similar to [[newFunction]].\n * Convert an async host Javascript function into a synchronous QuickJS function value.\n *\n * Whenever QuickJS calls this function, the VM's stack will be unwound while\n * waiting the async function to complete, and then restored when the returned\n * promise resolves.\n *\n * Asyncified functions must never call other asyncified functions or\n * `import`, even indirectly, because the stack cannot be unwound twice.\n *\n * See [Emscripten's docs on Asyncify](https://emscripten.org/docs/porting/asyncify.html).\n */\n newAsyncifiedFunction(name: string, fn: AsyncFunctionImplementation): QuickJSHandle {\n return this.newFunction(name, fn as any)\n }\n}\n"]}
|
||||
371
node_modules/@tootallnate/quickjs-emscripten/dist/context.d.ts
generated
vendored
Normal file
371
node_modules/@tootallnate/quickjs-emscripten/dist/context.d.ts
generated
vendored
Normal file
@@ -0,0 +1,371 @@
|
||||
import { QuickJSDeferredPromise } from "./deferred-promise";
|
||||
import type { EitherModule } from "./emscripten-types";
|
||||
import { JSBorrowedCharPointer, JSContextPointer, JSRuntimePointer, JSValueConstPointer, JSValuePointer } from "./types-ffi";
|
||||
import { Disposable, Lifetime, Scope } from "./lifetime";
|
||||
import { ModuleMemory } from "./memory";
|
||||
import { QuickJSModuleCallbacks } from "./module";
|
||||
import { QuickJSRuntime } from "./runtime";
|
||||
import { ContextEvalOptions, EitherFFI, JSValue, PromiseExecutor, QuickJSHandle } from "./types";
|
||||
import { LowLevelJavascriptVm, SuccessOrFail, VmCallResult, VmFunctionImplementation, VmPropertyDescriptor } from "./vm-interface";
|
||||
/**
|
||||
* Property key for getting or setting a property on a handle with
|
||||
* [[QuickJSContext.getProp]], [[QuickJSContext.setProp]], or [[QuickJSContext.defineProp]].
|
||||
*/
|
||||
export type QuickJSPropertyKey = number | string | QuickJSHandle;
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
declare class ContextMemory extends ModuleMemory implements Disposable {
|
||||
readonly owner: QuickJSRuntime;
|
||||
readonly ctx: Lifetime<JSContextPointer>;
|
||||
readonly rt: Lifetime<JSRuntimePointer>;
|
||||
readonly module: EitherModule;
|
||||
readonly ffi: EitherFFI;
|
||||
readonly scope: Scope;
|
||||
/** @private */
|
||||
constructor(args: {
|
||||
owner: QuickJSRuntime;
|
||||
module: EitherModule;
|
||||
ffi: EitherFFI;
|
||||
ctx: Lifetime<JSContextPointer>;
|
||||
rt: Lifetime<JSRuntimePointer>;
|
||||
ownedLifetimes?: Disposable[];
|
||||
});
|
||||
get alive(): boolean;
|
||||
dispose(): void;
|
||||
/**
|
||||
* Track `lifetime` so that it is disposed when this scope is disposed.
|
||||
*/
|
||||
manage<T extends Disposable>(lifetime: T): T;
|
||||
copyJSValue: (ptr: JSValuePointer | JSValueConstPointer) => any;
|
||||
freeJSValue: (ptr: JSValuePointer) => void;
|
||||
consumeJSCharPointer(ptr: JSBorrowedCharPointer): string;
|
||||
heapValueHandle(ptr: JSValuePointer): JSValue;
|
||||
}
|
||||
/**
|
||||
* QuickJSContext wraps a QuickJS Javascript context (JSContext*) within a
|
||||
* runtime. The contexts within the same runtime may exchange objects freely.
|
||||
* You can think of separate runtimes like different domains in a browser, and
|
||||
* the contexts within a runtime like the different windows open to the same
|
||||
* domain. The {@link runtime} references the context's runtime.
|
||||
*
|
||||
* This class's methods return {@link QuickJSHandle}, which wrap C pointers (JSValue*).
|
||||
* It's the caller's responsibility to call `.dispose()` on any
|
||||
* handles you create to free memory once you're done with the handle.
|
||||
*
|
||||
* Use {@link QuickJSRuntime.newContext} or {@link QuickJSWASMModule.newContext}
|
||||
* to create a new QuickJSContext.
|
||||
*
|
||||
* Create QuickJS values inside the interpreter with methods like
|
||||
* [[newNumber]], [[newString]], [[newArray]], [[newObject]],
|
||||
* [[newFunction]], and [[newPromise]].
|
||||
*
|
||||
* Call [[setProp]] or [[defineProp]] to customize objects. Use those methods
|
||||
* with [[global]] to expose the values you create to the interior of the
|
||||
* interpreter, so they can be used in [[evalCode]].
|
||||
*
|
||||
* Use [[evalCode]] or [[callFunction]] to execute Javascript inside the VM. If
|
||||
* you're using asynchronous code inside the QuickJSContext, you may need to also
|
||||
* call [[executePendingJobs]]. Executing code inside the runtime returns a
|
||||
* result object representing successful execution or an error. You must dispose
|
||||
* of any such results to avoid leaking memory inside the VM.
|
||||
*
|
||||
* Implement memory and CPU constraints at the runtime level, using [[runtime]].
|
||||
* See {@link QuickJSRuntime} for more information.
|
||||
*
|
||||
*/
|
||||
export declare class QuickJSContext implements LowLevelJavascriptVm<QuickJSHandle>, Disposable {
|
||||
/**
|
||||
* The runtime that created this context.
|
||||
*/
|
||||
readonly runtime: QuickJSRuntime;
|
||||
/** @private */
|
||||
protected readonly ctx: Lifetime<JSContextPointer>;
|
||||
/** @private */
|
||||
protected readonly rt: Lifetime<JSRuntimePointer>;
|
||||
/** @private */
|
||||
protected readonly module: EitherModule;
|
||||
/** @private */
|
||||
protected readonly ffi: EitherFFI;
|
||||
/** @private */
|
||||
protected memory: ContextMemory;
|
||||
/** @private */
|
||||
protected _undefined: QuickJSHandle | undefined;
|
||||
/** @private */
|
||||
protected _null: QuickJSHandle | undefined;
|
||||
/** @private */
|
||||
protected _false: QuickJSHandle | undefined;
|
||||
/** @private */
|
||||
protected _true: QuickJSHandle | undefined;
|
||||
/** @private */
|
||||
protected _global: QuickJSHandle | undefined;
|
||||
/** @private */
|
||||
protected _BigInt: QuickJSHandle | undefined;
|
||||
/**
|
||||
* Use {@link QuickJS.createVm} to create a QuickJSContext instance.
|
||||
*/
|
||||
constructor(args: {
|
||||
module: EitherModule;
|
||||
ffi: EitherFFI;
|
||||
ctx: Lifetime<JSContextPointer>;
|
||||
rt: Lifetime<JSRuntimePointer>;
|
||||
runtime: QuickJSRuntime;
|
||||
ownedLifetimes?: Disposable[];
|
||||
callbacks: QuickJSModuleCallbacks;
|
||||
});
|
||||
get alive(): boolean;
|
||||
/**
|
||||
* Dispose of this VM's underlying resources.
|
||||
*
|
||||
* @throws Calling this method without disposing of all created handles
|
||||
* will result in an error.
|
||||
*/
|
||||
dispose(): void;
|
||||
/**
|
||||
* [`undefined`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined).
|
||||
*/
|
||||
get undefined(): QuickJSHandle;
|
||||
/**
|
||||
* [`null`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null).
|
||||
*/
|
||||
get null(): QuickJSHandle;
|
||||
/**
|
||||
* [`true`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/true).
|
||||
*/
|
||||
get true(): QuickJSHandle;
|
||||
/**
|
||||
* [`false`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/false).
|
||||
*/
|
||||
get false(): QuickJSHandle;
|
||||
/**
|
||||
* [`global`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects).
|
||||
* A handle to the global object inside the interpreter.
|
||||
* You can set properties to create global variables.
|
||||
*/
|
||||
get global(): QuickJSHandle;
|
||||
/**
|
||||
* Converts a Javascript number into a QuickJS value.
|
||||
*/
|
||||
newNumber(num: number): QuickJSHandle;
|
||||
/**
|
||||
* Create a QuickJS [string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) value.
|
||||
*/
|
||||
newString(str: string): QuickJSHandle;
|
||||
/**
|
||||
* Create a QuickJS [symbol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) value.
|
||||
* No two symbols created with this function will be the same value.
|
||||
*/
|
||||
newUniqueSymbol(description: string | symbol): QuickJSHandle;
|
||||
/**
|
||||
* 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.
|
||||
* All symbols created with the same key will be the same value.
|
||||
*/
|
||||
newSymbolFor(key: string | symbol): QuickJSHandle;
|
||||
/**
|
||||
* Create a QuickJS [bigint](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) value.
|
||||
*/
|
||||
newBigInt(num: bigint): QuickJSHandle;
|
||||
/**
|
||||
* `{}`.
|
||||
* Create a new QuickJS [object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer).
|
||||
*
|
||||
* @param prototype - Like [`Object.create`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create).
|
||||
*/
|
||||
newObject(prototype?: QuickJSHandle): QuickJSHandle;
|
||||
/**
|
||||
* `[]`.
|
||||
* Create a new QuickJS [array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array).
|
||||
*/
|
||||
newArray(): QuickJSHandle;
|
||||
/**
|
||||
* Create a new [[QuickJSDeferredPromise]]. Use `deferred.resolve(handle)` and
|
||||
* `deferred.reject(handle)` to fulfill the promise handle available at `deferred.handle`.
|
||||
* Note that you are responsible for calling `deferred.dispose()` to free the underlying
|
||||
* resources; see the documentation on [[QuickJSDeferredPromise]] for details.
|
||||
*/
|
||||
newPromise(): QuickJSDeferredPromise;
|
||||
/**
|
||||
* Create a new [[QuickJSDeferredPromise]] that resolves when the
|
||||
* given native Promise<QuickJSHandle> resolves. Rejections will be coerced
|
||||
* to a QuickJS error.
|
||||
*
|
||||
* You can still resolve/reject the created promise "early" using its methods.
|
||||
*/
|
||||
newPromise(promise: Promise<QuickJSHandle>): QuickJSDeferredPromise;
|
||||
/**
|
||||
* Construct a new native Promise<QuickJSHandle>, and then convert it into a
|
||||
* [[QuickJSDeferredPromise]].
|
||||
*
|
||||
* You can still resolve/reject the created promise "early" using its methods.
|
||||
*/
|
||||
newPromise(newPromiseFn: PromiseExecutor<QuickJSHandle, Error | QuickJSHandle>): QuickJSDeferredPromise;
|
||||
/**
|
||||
* Convert a Javascript function into a QuickJS function value.
|
||||
* See [[VmFunctionImplementation]] for more details.
|
||||
*
|
||||
* A [[VmFunctionImplementation]] should not free its arguments or its return
|
||||
* value. A VmFunctionImplementation should also not retain any references to
|
||||
* its return value.
|
||||
*
|
||||
* To implement an async function, create a promise with [[newPromise]], then
|
||||
* return the deferred promise handle from `deferred.handle` from your
|
||||
* function implementation:
|
||||
*
|
||||
* ```
|
||||
* const deferred = vm.newPromise()
|
||||
* someNativeAsyncFunction().then(deferred.resolve)
|
||||
* return deferred.handle
|
||||
* ```
|
||||
*/
|
||||
newFunction(name: string, fn: VmFunctionImplementation<QuickJSHandle>): QuickJSHandle;
|
||||
newError(error: {
|
||||
name: string;
|
||||
message: string;
|
||||
}): QuickJSHandle;
|
||||
newError(message: string): QuickJSHandle;
|
||||
newError(): QuickJSHandle;
|
||||
/**
|
||||
* `typeof` operator. **Not** [standards compliant](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof).
|
||||
*
|
||||
* @remarks
|
||||
* Does not support BigInt values correctly.
|
||||
*/
|
||||
typeof(handle: QuickJSHandle): string;
|
||||
/**
|
||||
* Converts `handle` into a Javascript number.
|
||||
* @returns `NaN` on error, otherwise a `number`.
|
||||
*/
|
||||
getNumber(handle: QuickJSHandle): number;
|
||||
/**
|
||||
* Converts `handle` to a Javascript string.
|
||||
*/
|
||||
getString(handle: QuickJSHandle): string;
|
||||
/**
|
||||
* Converts `handle` into a Javascript symbol. If the symbol is in the global
|
||||
* registry in the guest, it will be created with Symbol.for on the host.
|
||||
*/
|
||||
getSymbol(handle: QuickJSHandle): symbol;
|
||||
/**
|
||||
* Converts `handle` to a Javascript bigint.
|
||||
*/
|
||||
getBigInt(handle: QuickJSHandle): bigint;
|
||||
/**
|
||||
* `Promise.resolve(value)`.
|
||||
* Convert a handle containing a Promise-like value inside the VM into an
|
||||
* actual promise on the host.
|
||||
*
|
||||
* @remarks
|
||||
* You may need to call [[executePendingJobs]] to ensure that the promise is resolved.
|
||||
*
|
||||
* @param promiseLikeHandle - A handle to a Promise-like value with a `.then(onSuccess, onError)` method.
|
||||
*/
|
||||
resolvePromise(promiseLikeHandle: QuickJSHandle): Promise<VmCallResult<QuickJSHandle>>;
|
||||
/**
|
||||
* `handle[key]`.
|
||||
* Get a property from a JSValue.
|
||||
*
|
||||
* @param key - The property may be specified as a JSValue handle, or as a
|
||||
* Javascript string (which will be converted automatically).
|
||||
*/
|
||||
getProp(handle: QuickJSHandle, key: QuickJSPropertyKey): QuickJSHandle;
|
||||
/**
|
||||
* `handle[key] = value`.
|
||||
* Set a property on a JSValue.
|
||||
*
|
||||
* @remarks
|
||||
* Note that the QuickJS authors recommend using [[defineProp]] to define new
|
||||
* properties.
|
||||
*
|
||||
* @param key - The property may be specified as a JSValue handle, or as a
|
||||
* Javascript string or number (which will be converted automatically to a JSValue).
|
||||
*/
|
||||
setProp(handle: QuickJSHandle, key: QuickJSPropertyKey, value: QuickJSHandle): void;
|
||||
/**
|
||||
* [`Object.defineProperty(handle, key, descriptor)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty).
|
||||
*
|
||||
* @param key - The property may be specified as a JSValue handle, or as a
|
||||
* Javascript string or number (which will be converted automatically to a JSValue).
|
||||
*/
|
||||
defineProp(handle: QuickJSHandle, key: QuickJSPropertyKey, descriptor: VmPropertyDescriptor<QuickJSHandle>): void;
|
||||
/**
|
||||
* [`func.call(thisVal, ...args)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call).
|
||||
* Call a JSValue as a function.
|
||||
*
|
||||
* See [[unwrapResult]], which will throw if the function returned an error, or
|
||||
* return the result handle directly. If evaluation returned a handle containing
|
||||
* a promise, use [[resolvePromise]] to convert it to a native promise and
|
||||
* [[executePendingJobs]] to finish evaluating the promise.
|
||||
*
|
||||
* @returns A result. If the function threw synchronously, `result.error` be a
|
||||
* handle to the exception. Otherwise `result.value` will be a handle to the
|
||||
* value.
|
||||
*/
|
||||
callFunction(func: QuickJSHandle, thisVal: QuickJSHandle, ...args: QuickJSHandle[]): VmCallResult<QuickJSHandle>;
|
||||
/**
|
||||
* Like [`eval(code)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#Description).
|
||||
* Evaluates the Javascript source `code` in the global scope of this VM.
|
||||
* When working with async code, you many need to call [[executePendingJobs]]
|
||||
* to execute callbacks pending after synchronous evaluation returns.
|
||||
*
|
||||
* See [[unwrapResult]], which will throw if the function returned an error, or
|
||||
* return the result handle directly. If evaluation returned a handle containing
|
||||
* a promise, use [[resolvePromise]] to convert it to a native promise and
|
||||
* [[executePendingJobs]] to finish evaluating the promise.
|
||||
*
|
||||
* *Note*: to protect against infinite loops, provide an interrupt handler to
|
||||
* [[setInterruptHandler]]. You can use [[shouldInterruptAfterDeadline]] to
|
||||
* create a time-based deadline.
|
||||
*
|
||||
* @returns The last statement's value. If the code threw synchronously,
|
||||
* `result.error` will be a handle to the exception. If execution was
|
||||
* interrupted, the error will have name `InternalError` and message
|
||||
* `interrupted`.
|
||||
*/
|
||||
evalCode(code: string, filename?: string,
|
||||
/**
|
||||
* If no options are passed, a heuristic will be used to detect if `code` is
|
||||
* an ES module.
|
||||
*
|
||||
* See [[EvalFlags]] for number semantics.
|
||||
*/
|
||||
options?: number | ContextEvalOptions): VmCallResult<QuickJSHandle>;
|
||||
/**
|
||||
* Throw an error in the VM, interrupted whatever current execution is in progress when execution resumes.
|
||||
* @experimental
|
||||
*/
|
||||
throw(error: Error | QuickJSHandle): any;
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
protected borrowPropertyKey(key: QuickJSPropertyKey): QuickJSHandle;
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
getMemory(rt: JSRuntimePointer): ContextMemory;
|
||||
/**
|
||||
* Dump a JSValue to Javascript in a best-effort fashion.
|
||||
* Returns `handle.toString()` if it cannot be serialized to JSON.
|
||||
*/
|
||||
dump(handle: QuickJSHandle): any;
|
||||
/**
|
||||
* Unwrap a SuccessOrFail result such as a [[VmCallResult]] or a
|
||||
* [[ExecutePendingJobsResult]], where the fail branch contains a handle to a QuickJS error value.
|
||||
* If the result is a success, returns the value.
|
||||
* If the result is an error, converts the error to a native object and throws the error.
|
||||
*/
|
||||
unwrapResult<T>(result: SuccessOrFail<T, QuickJSHandle>): T;
|
||||
/** @private */
|
||||
protected fnNextId: number;
|
||||
/** @private */
|
||||
protected fnMaps: Map<number, Map<number, VmFunctionImplementation<QuickJSHandle>>>;
|
||||
/** @private */
|
||||
protected getFunction(fn_id: number): VmFunctionImplementation<QuickJSHandle> | undefined;
|
||||
/** @private */
|
||||
protected setFunction(fn_id: number, handle: VmFunctionImplementation<QuickJSHandle>): Map<number, VmFunctionImplementation<QuickJSHandle>>;
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
private cToHostCallbacks;
|
||||
private errorToHandle;
|
||||
}
|
||||
export {};
|
||||
691
node_modules/@tootallnate/quickjs-emscripten/dist/context.js
generated
vendored
Normal file
691
node_modules/@tootallnate/quickjs-emscripten/dist/context.js
generated
vendored
Normal file
@@ -0,0 +1,691 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.QuickJSContext = void 0;
|
||||
const debug_1 = require("./debug");
|
||||
const deferred_promise_1 = require("./deferred-promise");
|
||||
const errors_1 = require("./errors");
|
||||
const lifetime_1 = require("./lifetime");
|
||||
const memory_1 = require("./memory");
|
||||
const types_1 = require("./types");
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
class ContextMemory extends memory_1.ModuleMemory {
|
||||
/** @private */
|
||||
constructor(args) {
|
||||
super(args.module);
|
||||
this.scope = new lifetime_1.Scope();
|
||||
this.copyJSValue = (ptr) => {
|
||||
return this.ffi.QTS_DupValuePointer(this.ctx.value, ptr);
|
||||
};
|
||||
this.freeJSValue = (ptr) => {
|
||||
this.ffi.QTS_FreeValuePointer(this.ctx.value, ptr);
|
||||
};
|
||||
args.ownedLifetimes?.forEach((lifetime) => this.scope.manage(lifetime));
|
||||
this.owner = args.owner;
|
||||
this.module = args.module;
|
||||
this.ffi = args.ffi;
|
||||
this.rt = args.rt;
|
||||
this.ctx = this.scope.manage(args.ctx);
|
||||
}
|
||||
get alive() {
|
||||
return this.scope.alive;
|
||||
}
|
||||
dispose() {
|
||||
return this.scope.dispose();
|
||||
}
|
||||
/**
|
||||
* Track `lifetime` so that it is disposed when this scope is disposed.
|
||||
*/
|
||||
manage(lifetime) {
|
||||
return this.scope.manage(lifetime);
|
||||
}
|
||||
consumeJSCharPointer(ptr) {
|
||||
const str = this.module.UTF8ToString(ptr);
|
||||
this.ffi.QTS_FreeCString(this.ctx.value, ptr);
|
||||
return str;
|
||||
}
|
||||
heapValueHandle(ptr) {
|
||||
return new lifetime_1.Lifetime(ptr, this.copyJSValue, this.freeJSValue, this.owner);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* QuickJSContext wraps a QuickJS Javascript context (JSContext*) within a
|
||||
* runtime. The contexts within the same runtime may exchange objects freely.
|
||||
* You can think of separate runtimes like different domains in a browser, and
|
||||
* the contexts within a runtime like the different windows open to the same
|
||||
* domain. The {@link runtime} references the context's runtime.
|
||||
*
|
||||
* This class's methods return {@link QuickJSHandle}, which wrap C pointers (JSValue*).
|
||||
* It's the caller's responsibility to call `.dispose()` on any
|
||||
* handles you create to free memory once you're done with the handle.
|
||||
*
|
||||
* Use {@link QuickJSRuntime.newContext} or {@link QuickJSWASMModule.newContext}
|
||||
* to create a new QuickJSContext.
|
||||
*
|
||||
* Create QuickJS values inside the interpreter with methods like
|
||||
* [[newNumber]], [[newString]], [[newArray]], [[newObject]],
|
||||
* [[newFunction]], and [[newPromise]].
|
||||
*
|
||||
* Call [[setProp]] or [[defineProp]] to customize objects. Use those methods
|
||||
* with [[global]] to expose the values you create to the interior of the
|
||||
* interpreter, so they can be used in [[evalCode]].
|
||||
*
|
||||
* Use [[evalCode]] or [[callFunction]] to execute Javascript inside the VM. If
|
||||
* you're using asynchronous code inside the QuickJSContext, you may need to also
|
||||
* call [[executePendingJobs]]. Executing code inside the runtime returns a
|
||||
* result object representing successful execution or an error. You must dispose
|
||||
* of any such results to avoid leaking memory inside the VM.
|
||||
*
|
||||
* Implement memory and CPU constraints at the runtime level, using [[runtime]].
|
||||
* See {@link QuickJSRuntime} for more information.
|
||||
*
|
||||
*/
|
||||
// TODO: Manage own callback registration
|
||||
class QuickJSContext {
|
||||
/**
|
||||
* Use {@link QuickJS.createVm} to create a QuickJSContext instance.
|
||||
*/
|
||||
constructor(args) {
|
||||
/** @private */
|
||||
this._undefined = undefined;
|
||||
/** @private */
|
||||
this._null = undefined;
|
||||
/** @private */
|
||||
this._false = undefined;
|
||||
/** @private */
|
||||
this._true = undefined;
|
||||
/** @private */
|
||||
this._global = undefined;
|
||||
/** @private */
|
||||
this._BigInt = undefined;
|
||||
/** @private */
|
||||
this.fnNextId = -32768; // min value of signed 16bit int used by Quickjs
|
||||
/** @private */
|
||||
this.fnMaps = new Map();
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
this.cToHostCallbacks = {
|
||||
callFunction: (ctx, this_ptr, argc, argv, fn_id) => {
|
||||
if (ctx !== this.ctx.value) {
|
||||
throw new Error("QuickJSContext instance received C -> JS call with mismatched ctx");
|
||||
}
|
||||
const fn = this.getFunction(fn_id);
|
||||
if (!fn) {
|
||||
// this "throw" is not catch-able from the TS side. could we somehow handle this higher up?
|
||||
throw new Error(`QuickJSContext had no callback with id ${fn_id}`);
|
||||
}
|
||||
return lifetime_1.Scope.withScopeMaybeAsync(this, function* (awaited, scope) {
|
||||
const thisHandle = scope.manage(new lifetime_1.WeakLifetime(this_ptr, this.memory.copyJSValue, this.memory.freeJSValue, this.runtime));
|
||||
const argHandles = new Array(argc);
|
||||
for (let i = 0; i < argc; i++) {
|
||||
const ptr = this.ffi.QTS_ArgvGetJSValueConstPointer(argv, i);
|
||||
argHandles[i] = scope.manage(new lifetime_1.WeakLifetime(ptr, this.memory.copyJSValue, this.memory.freeJSValue, this.runtime));
|
||||
}
|
||||
try {
|
||||
const result = yield* awaited(fn.apply(thisHandle, argHandles));
|
||||
if (result) {
|
||||
if ("error" in result && result.error) {
|
||||
(0, debug_1.debugLog)("throw error", result.error);
|
||||
throw result.error;
|
||||
}
|
||||
const handle = scope.manage(result instanceof lifetime_1.Lifetime ? result : result.value);
|
||||
return this.ffi.QTS_DupValuePointer(this.ctx.value, handle.value);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
catch (error) {
|
||||
return this.errorToHandle(error).consume((errorHandle) => this.ffi.QTS_Throw(this.ctx.value, errorHandle.value));
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
this.runtime = args.runtime;
|
||||
this.module = args.module;
|
||||
this.ffi = args.ffi;
|
||||
this.rt = args.rt;
|
||||
this.ctx = args.ctx;
|
||||
this.memory = new ContextMemory({
|
||||
...args,
|
||||
owner: this.runtime,
|
||||
});
|
||||
args.callbacks.setContextCallbacks(this.ctx.value, this.cToHostCallbacks);
|
||||
this.dump = this.dump.bind(this);
|
||||
this.getString = this.getString.bind(this);
|
||||
this.getNumber = this.getNumber.bind(this);
|
||||
this.resolvePromise = this.resolvePromise.bind(this);
|
||||
}
|
||||
// @implement Disposable ----------------------------------------------------
|
||||
get alive() {
|
||||
return this.memory.alive;
|
||||
}
|
||||
/**
|
||||
* Dispose of this VM's underlying resources.
|
||||
*
|
||||
* @throws Calling this method without disposing of all created handles
|
||||
* will result in an error.
|
||||
*/
|
||||
dispose() {
|
||||
this.memory.dispose();
|
||||
}
|
||||
// Globals ------------------------------------------------------------------
|
||||
/**
|
||||
* [`undefined`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined).
|
||||
*/
|
||||
get undefined() {
|
||||
if (this._undefined) {
|
||||
return this._undefined;
|
||||
}
|
||||
// Undefined is a constant, immutable value in QuickJS.
|
||||
const ptr = this.ffi.QTS_GetUndefined();
|
||||
return (this._undefined = new lifetime_1.StaticLifetime(ptr));
|
||||
}
|
||||
/**
|
||||
* [`null`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null).
|
||||
*/
|
||||
get null() {
|
||||
if (this._null) {
|
||||
return this._null;
|
||||
}
|
||||
// Null is a constant, immutable value in QuickJS.
|
||||
const ptr = this.ffi.QTS_GetNull();
|
||||
return (this._null = new lifetime_1.StaticLifetime(ptr));
|
||||
}
|
||||
/**
|
||||
* [`true`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/true).
|
||||
*/
|
||||
get true() {
|
||||
if (this._true) {
|
||||
return this._true;
|
||||
}
|
||||
// True is a constant, immutable value in QuickJS.
|
||||
const ptr = this.ffi.QTS_GetTrue();
|
||||
return (this._true = new lifetime_1.StaticLifetime(ptr));
|
||||
}
|
||||
/**
|
||||
* [`false`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/false).
|
||||
*/
|
||||
get false() {
|
||||
if (this._false) {
|
||||
return this._false;
|
||||
}
|
||||
// False is a constant, immutable value in QuickJS.
|
||||
const ptr = this.ffi.QTS_GetFalse();
|
||||
return (this._false = new lifetime_1.StaticLifetime(ptr));
|
||||
}
|
||||
/**
|
||||
* [`global`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects).
|
||||
* A handle to the global object inside the interpreter.
|
||||
* You can set properties to create global variables.
|
||||
*/
|
||||
get global() {
|
||||
if (this._global) {
|
||||
return this._global;
|
||||
}
|
||||
// The global is a JSValue, but since it's lifetime is as long as the VM's,
|
||||
// we should manage it.
|
||||
const ptr = this.ffi.QTS_GetGlobalObject(this.ctx.value);
|
||||
// Automatically clean up this reference when we dispose
|
||||
this.memory.manage(this.memory.heapValueHandle(ptr));
|
||||
// This isn't technically a static lifetime, but since it has the same
|
||||
// lifetime as the VM, it's okay to fake one since when the VM is
|
||||
// disposed, no other functions will accept the value.
|
||||
this._global = new lifetime_1.StaticLifetime(ptr, this.runtime);
|
||||
return this._global;
|
||||
}
|
||||
// New values ---------------------------------------------------------------
|
||||
/**
|
||||
* Converts a Javascript number into a QuickJS value.
|
||||
*/
|
||||
newNumber(num) {
|
||||
return this.memory.heapValueHandle(this.ffi.QTS_NewFloat64(this.ctx.value, num));
|
||||
}
|
||||
/**
|
||||
* Create a QuickJS [string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) value.
|
||||
*/
|
||||
newString(str) {
|
||||
const ptr = this.memory
|
||||
.newHeapCharPointer(str)
|
||||
.consume((charHandle) => this.ffi.QTS_NewString(this.ctx.value, charHandle.value));
|
||||
return this.memory.heapValueHandle(ptr);
|
||||
}
|
||||
/**
|
||||
* Create a QuickJS [symbol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) value.
|
||||
* No two symbols created with this function will be the same value.
|
||||
*/
|
||||
newUniqueSymbol(description) {
|
||||
const key = (typeof description === "symbol" ? description.description : description) ?? "";
|
||||
const ptr = this.memory
|
||||
.newHeapCharPointer(key)
|
||||
.consume((charHandle) => this.ffi.QTS_NewSymbol(this.ctx.value, charHandle.value, 0));
|
||||
return this.memory.heapValueHandle(ptr);
|
||||
}
|
||||
/**
|
||||
* 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.
|
||||
* All symbols created with the same key will be the same value.
|
||||
*/
|
||||
newSymbolFor(key) {
|
||||
const description = (typeof key === "symbol" ? key.description : key) ?? "";
|
||||
const ptr = this.memory
|
||||
.newHeapCharPointer(description)
|
||||
.consume((charHandle) => this.ffi.QTS_NewSymbol(this.ctx.value, charHandle.value, 1));
|
||||
return this.memory.heapValueHandle(ptr);
|
||||
}
|
||||
/**
|
||||
* Create a QuickJS [bigint](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) value.
|
||||
*/
|
||||
newBigInt(num) {
|
||||
if (!this._BigInt) {
|
||||
const bigIntHandle = this.getProp(this.global, "BigInt");
|
||||
this.memory.manage(bigIntHandle);
|
||||
this._BigInt = new lifetime_1.StaticLifetime(bigIntHandle.value, this.runtime);
|
||||
}
|
||||
const bigIntHandle = this._BigInt;
|
||||
const asString = String(num);
|
||||
return this.newString(asString).consume((handle) => this.unwrapResult(this.callFunction(bigIntHandle, this.undefined, handle)));
|
||||
}
|
||||
/**
|
||||
* `{}`.
|
||||
* Create a new QuickJS [object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer).
|
||||
*
|
||||
* @param prototype - Like [`Object.create`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create).
|
||||
*/
|
||||
newObject(prototype) {
|
||||
if (prototype) {
|
||||
this.runtime.assertOwned(prototype);
|
||||
}
|
||||
const ptr = prototype
|
||||
? this.ffi.QTS_NewObjectProto(this.ctx.value, prototype.value)
|
||||
: this.ffi.QTS_NewObject(this.ctx.value);
|
||||
return this.memory.heapValueHandle(ptr);
|
||||
}
|
||||
/**
|
||||
* `[]`.
|
||||
* Create a new QuickJS [array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array).
|
||||
*/
|
||||
newArray() {
|
||||
const ptr = this.ffi.QTS_NewArray(this.ctx.value);
|
||||
return this.memory.heapValueHandle(ptr);
|
||||
}
|
||||
newPromise(value) {
|
||||
const deferredPromise = lifetime_1.Scope.withScope((scope) => {
|
||||
const mutablePointerArray = scope.manage(this.memory.newMutablePointerArray(2));
|
||||
const promisePtr = this.ffi.QTS_NewPromiseCapability(this.ctx.value, mutablePointerArray.value.ptr);
|
||||
const promiseHandle = this.memory.heapValueHandle(promisePtr);
|
||||
const [resolveHandle, rejectHandle] = Array.from(mutablePointerArray.value.typedArray).map((jsvaluePtr) => this.memory.heapValueHandle(jsvaluePtr));
|
||||
return new deferred_promise_1.QuickJSDeferredPromise({
|
||||
context: this,
|
||||
promiseHandle,
|
||||
resolveHandle,
|
||||
rejectHandle,
|
||||
});
|
||||
});
|
||||
if (value && typeof value === "function") {
|
||||
value = new Promise(value);
|
||||
}
|
||||
if (value) {
|
||||
Promise.resolve(value).then(deferredPromise.resolve, (error) => error instanceof lifetime_1.Lifetime
|
||||
? deferredPromise.reject(error)
|
||||
: this.newError(error).consume(deferredPromise.reject));
|
||||
}
|
||||
return deferredPromise;
|
||||
}
|
||||
/**
|
||||
* Convert a Javascript function into a QuickJS function value.
|
||||
* See [[VmFunctionImplementation]] for more details.
|
||||
*
|
||||
* A [[VmFunctionImplementation]] should not free its arguments or its return
|
||||
* value. A VmFunctionImplementation should also not retain any references to
|
||||
* its return value.
|
||||
*
|
||||
* To implement an async function, create a promise with [[newPromise]], then
|
||||
* return the deferred promise handle from `deferred.handle` from your
|
||||
* function implementation:
|
||||
*
|
||||
* ```
|
||||
* const deferred = vm.newPromise()
|
||||
* someNativeAsyncFunction().then(deferred.resolve)
|
||||
* return deferred.handle
|
||||
* ```
|
||||
*/
|
||||
newFunction(name, fn) {
|
||||
const fnId = ++this.fnNextId;
|
||||
this.setFunction(fnId, fn);
|
||||
return this.memory.heapValueHandle(this.ffi.QTS_NewFunction(this.ctx.value, fnId, name));
|
||||
}
|
||||
newError(error) {
|
||||
const errorHandle = this.memory.heapValueHandle(this.ffi.QTS_NewError(this.ctx.value));
|
||||
if (error && typeof error === "object") {
|
||||
if (error.name !== undefined) {
|
||||
this.newString(error.name).consume((handle) => this.setProp(errorHandle, "name", handle));
|
||||
}
|
||||
if (error.message !== undefined) {
|
||||
this.newString(error.message).consume((handle) => this.setProp(errorHandle, "message", handle));
|
||||
}
|
||||
}
|
||||
else if (typeof error === "string") {
|
||||
this.newString(error).consume((handle) => this.setProp(errorHandle, "message", handle));
|
||||
}
|
||||
else if (error !== undefined) {
|
||||
// This isn't supported in the type signature but maybe it will make life easier.
|
||||
this.newString(String(error)).consume((handle) => this.setProp(errorHandle, "message", handle));
|
||||
}
|
||||
return errorHandle;
|
||||
}
|
||||
// Read values --------------------------------------------------------------
|
||||
/**
|
||||
* `typeof` operator. **Not** [standards compliant](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof).
|
||||
*
|
||||
* @remarks
|
||||
* Does not support BigInt values correctly.
|
||||
*/
|
||||
typeof(handle) {
|
||||
this.runtime.assertOwned(handle);
|
||||
return this.memory.consumeHeapCharPointer(this.ffi.QTS_Typeof(this.ctx.value, handle.value));
|
||||
}
|
||||
/**
|
||||
* Converts `handle` into a Javascript number.
|
||||
* @returns `NaN` on error, otherwise a `number`.
|
||||
*/
|
||||
getNumber(handle) {
|
||||
this.runtime.assertOwned(handle);
|
||||
return this.ffi.QTS_GetFloat64(this.ctx.value, handle.value);
|
||||
}
|
||||
/**
|
||||
* Converts `handle` to a Javascript string.
|
||||
*/
|
||||
getString(handle) {
|
||||
this.runtime.assertOwned(handle);
|
||||
return this.memory.consumeJSCharPointer(this.ffi.QTS_GetString(this.ctx.value, handle.value));
|
||||
}
|
||||
/**
|
||||
* Converts `handle` into a Javascript symbol. If the symbol is in the global
|
||||
* registry in the guest, it will be created with Symbol.for on the host.
|
||||
*/
|
||||
getSymbol(handle) {
|
||||
this.runtime.assertOwned(handle);
|
||||
const key = this.memory.consumeJSCharPointer(this.ffi.QTS_GetSymbolDescriptionOrKey(this.ctx.value, handle.value));
|
||||
const isGlobal = this.ffi.QTS_IsGlobalSymbol(this.ctx.value, handle.value);
|
||||
return isGlobal ? Symbol.for(key) : Symbol(key);
|
||||
}
|
||||
/**
|
||||
* Converts `handle` to a Javascript bigint.
|
||||
*/
|
||||
getBigInt(handle) {
|
||||
this.runtime.assertOwned(handle);
|
||||
const asString = this.getString(handle);
|
||||
return BigInt(asString);
|
||||
}
|
||||
/**
|
||||
* `Promise.resolve(value)`.
|
||||
* Convert a handle containing a Promise-like value inside the VM into an
|
||||
* actual promise on the host.
|
||||
*
|
||||
* @remarks
|
||||
* You may need to call [[executePendingJobs]] to ensure that the promise is resolved.
|
||||
*
|
||||
* @param promiseLikeHandle - A handle to a Promise-like value with a `.then(onSuccess, onError)` method.
|
||||
*/
|
||||
resolvePromise(promiseLikeHandle) {
|
||||
this.runtime.assertOwned(promiseLikeHandle);
|
||||
const vmResolveResult = lifetime_1.Scope.withScope((scope) => {
|
||||
const vmPromise = scope.manage(this.getProp(this.global, "Promise"));
|
||||
const vmPromiseResolve = scope.manage(this.getProp(vmPromise, "resolve"));
|
||||
return this.callFunction(vmPromiseResolve, vmPromise, promiseLikeHandle);
|
||||
});
|
||||
if (vmResolveResult.error) {
|
||||
return Promise.resolve(vmResolveResult);
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
lifetime_1.Scope.withScope((scope) => {
|
||||
const resolveHandle = scope.manage(this.newFunction("resolve", (value) => {
|
||||
resolve({ value: value && value.dup() });
|
||||
}));
|
||||
const rejectHandle = scope.manage(this.newFunction("reject", (error) => {
|
||||
resolve({ error: error && error.dup() });
|
||||
}));
|
||||
const promiseHandle = scope.manage(vmResolveResult.value);
|
||||
const promiseThenHandle = scope.manage(this.getProp(promiseHandle, "then"));
|
||||
this.unwrapResult(this.callFunction(promiseThenHandle, promiseHandle, resolveHandle, rejectHandle)).dispose();
|
||||
});
|
||||
});
|
||||
}
|
||||
// Properties ---------------------------------------------------------------
|
||||
/**
|
||||
* `handle[key]`.
|
||||
* Get a property from a JSValue.
|
||||
*
|
||||
* @param key - The property may be specified as a JSValue handle, or as a
|
||||
* Javascript string (which will be converted automatically).
|
||||
*/
|
||||
getProp(handle, key) {
|
||||
this.runtime.assertOwned(handle);
|
||||
const ptr = this.borrowPropertyKey(key).consume((quickJSKey) => this.ffi.QTS_GetProp(this.ctx.value, handle.value, quickJSKey.value));
|
||||
const result = this.memory.heapValueHandle(ptr);
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* `handle[key] = value`.
|
||||
* Set a property on a JSValue.
|
||||
*
|
||||
* @remarks
|
||||
* Note that the QuickJS authors recommend using [[defineProp]] to define new
|
||||
* properties.
|
||||
*
|
||||
* @param key - The property may be specified as a JSValue handle, or as a
|
||||
* Javascript string or number (which will be converted automatically to a JSValue).
|
||||
*/
|
||||
setProp(handle, key, value) {
|
||||
this.runtime.assertOwned(handle);
|
||||
// free newly allocated value if key was a string or number. No-op if string was already
|
||||
// a QuickJS handle.
|
||||
this.borrowPropertyKey(key).consume((quickJSKey) => this.ffi.QTS_SetProp(this.ctx.value, handle.value, quickJSKey.value, value.value));
|
||||
}
|
||||
/**
|
||||
* [`Object.defineProperty(handle, key, descriptor)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty).
|
||||
*
|
||||
* @param key - The property may be specified as a JSValue handle, or as a
|
||||
* Javascript string or number (which will be converted automatically to a JSValue).
|
||||
*/
|
||||
defineProp(handle, key, descriptor) {
|
||||
this.runtime.assertOwned(handle);
|
||||
lifetime_1.Scope.withScope((scope) => {
|
||||
const quickJSKey = scope.manage(this.borrowPropertyKey(key));
|
||||
const value = descriptor.value || this.undefined;
|
||||
const configurable = Boolean(descriptor.configurable);
|
||||
const enumerable = Boolean(descriptor.enumerable);
|
||||
const hasValue = Boolean(descriptor.value);
|
||||
const get = descriptor.get
|
||||
? scope.manage(this.newFunction(descriptor.get.name, descriptor.get))
|
||||
: this.undefined;
|
||||
const set = descriptor.set
|
||||
? scope.manage(this.newFunction(descriptor.set.name, descriptor.set))
|
||||
: this.undefined;
|
||||
this.ffi.QTS_DefineProp(this.ctx.value, handle.value, quickJSKey.value, value.value, get.value, set.value, configurable, enumerable, hasValue);
|
||||
});
|
||||
}
|
||||
// Evaluation ---------------------------------------------------------------
|
||||
/**
|
||||
* [`func.call(thisVal, ...args)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call).
|
||||
* Call a JSValue as a function.
|
||||
*
|
||||
* See [[unwrapResult]], which will throw if the function returned an error, or
|
||||
* return the result handle directly. If evaluation returned a handle containing
|
||||
* a promise, use [[resolvePromise]] to convert it to a native promise and
|
||||
* [[executePendingJobs]] to finish evaluating the promise.
|
||||
*
|
||||
* @returns A result. If the function threw synchronously, `result.error` be a
|
||||
* handle to the exception. Otherwise `result.value` will be a handle to the
|
||||
* value.
|
||||
*/
|
||||
callFunction(func, thisVal, ...args) {
|
||||
this.runtime.assertOwned(func);
|
||||
const resultPtr = this.memory
|
||||
.toPointerArray(args)
|
||||
.consume((argsArrayPtr) => this.ffi.QTS_Call(this.ctx.value, func.value, thisVal.value, args.length, argsArrayPtr.value));
|
||||
const errorPtr = this.ffi.QTS_ResolveException(this.ctx.value, resultPtr);
|
||||
if (errorPtr) {
|
||||
this.ffi.QTS_FreeValuePointer(this.ctx.value, resultPtr);
|
||||
return { error: this.memory.heapValueHandle(errorPtr) };
|
||||
}
|
||||
return { value: this.memory.heapValueHandle(resultPtr) };
|
||||
}
|
||||
/**
|
||||
* Like [`eval(code)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#Description).
|
||||
* Evaluates the Javascript source `code` in the global scope of this VM.
|
||||
* When working with async code, you many need to call [[executePendingJobs]]
|
||||
* to execute callbacks pending after synchronous evaluation returns.
|
||||
*
|
||||
* See [[unwrapResult]], which will throw if the function returned an error, or
|
||||
* return the result handle directly. If evaluation returned a handle containing
|
||||
* a promise, use [[resolvePromise]] to convert it to a native promise and
|
||||
* [[executePendingJobs]] to finish evaluating the promise.
|
||||
*
|
||||
* *Note*: to protect against infinite loops, provide an interrupt handler to
|
||||
* [[setInterruptHandler]]. You can use [[shouldInterruptAfterDeadline]] to
|
||||
* create a time-based deadline.
|
||||
*
|
||||
* @returns The last statement's value. If the code threw synchronously,
|
||||
* `result.error` will be a handle to the exception. If execution was
|
||||
* interrupted, the error will have name `InternalError` and message
|
||||
* `interrupted`.
|
||||
*/
|
||||
evalCode(code, filename = "eval.js",
|
||||
/**
|
||||
* If no options are passed, a heuristic will be used to detect if `code` is
|
||||
* an ES module.
|
||||
*
|
||||
* See [[EvalFlags]] for number semantics.
|
||||
*/
|
||||
options) {
|
||||
const detectModule = (options === undefined ? 1 : 0);
|
||||
const flags = (0, types_1.evalOptionsToFlags)(options);
|
||||
const resultPtr = this.memory
|
||||
.newHeapCharPointer(code)
|
||||
.consume((charHandle) => this.ffi.QTS_Eval(this.ctx.value, charHandle.value, filename, detectModule, flags));
|
||||
const errorPtr = this.ffi.QTS_ResolveException(this.ctx.value, resultPtr);
|
||||
if (errorPtr) {
|
||||
this.ffi.QTS_FreeValuePointer(this.ctx.value, resultPtr);
|
||||
return { error: this.memory.heapValueHandle(errorPtr) };
|
||||
}
|
||||
return { value: this.memory.heapValueHandle(resultPtr) };
|
||||
}
|
||||
/**
|
||||
* Throw an error in the VM, interrupted whatever current execution is in progress when execution resumes.
|
||||
* @experimental
|
||||
*/
|
||||
throw(error) {
|
||||
return this.errorToHandle(error).consume((handle) => this.ffi.QTS_Throw(this.ctx.value, handle.value));
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
borrowPropertyKey(key) {
|
||||
if (typeof key === "number") {
|
||||
return this.newNumber(key);
|
||||
}
|
||||
if (typeof key === "string") {
|
||||
return this.newString(key);
|
||||
}
|
||||
// key is already a JSValue, but we're borrowing it. Return a static handle
|
||||
// for internal use only.
|
||||
return new lifetime_1.StaticLifetime(key.value, this.runtime);
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
getMemory(rt) {
|
||||
if (rt === this.rt.value) {
|
||||
return this.memory;
|
||||
}
|
||||
else {
|
||||
throw new Error("Private API. Cannot get memory from a different runtime");
|
||||
}
|
||||
}
|
||||
// Utilities ----------------------------------------------------------------
|
||||
/**
|
||||
* Dump a JSValue to Javascript in a best-effort fashion.
|
||||
* Returns `handle.toString()` if it cannot be serialized to JSON.
|
||||
*/
|
||||
dump(handle) {
|
||||
this.runtime.assertOwned(handle);
|
||||
const type = this.typeof(handle);
|
||||
if (type === "string") {
|
||||
return this.getString(handle);
|
||||
}
|
||||
else if (type === "number") {
|
||||
return this.getNumber(handle);
|
||||
}
|
||||
else if (type === "bigint") {
|
||||
return this.getBigInt(handle);
|
||||
}
|
||||
else if (type === "undefined") {
|
||||
return undefined;
|
||||
}
|
||||
else if (type === "symbol") {
|
||||
return this.getSymbol(handle);
|
||||
}
|
||||
const str = this.memory.consumeJSCharPointer(this.ffi.QTS_Dump(this.ctx.value, handle.value));
|
||||
try {
|
||||
return JSON.parse(str);
|
||||
}
|
||||
catch (err) {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Unwrap a SuccessOrFail result such as a [[VmCallResult]] or a
|
||||
* [[ExecutePendingJobsResult]], where the fail branch contains a handle to a QuickJS error value.
|
||||
* If the result is a success, returns the value.
|
||||
* If the result is an error, converts the error to a native object and throws the error.
|
||||
*/
|
||||
unwrapResult(result) {
|
||||
if (result.error) {
|
||||
const context = "context" in result.error ? result.error.context : this;
|
||||
const cause = result.error.consume((error) => this.dump(error));
|
||||
if (cause && typeof cause === "object" && typeof cause.message === "string") {
|
||||
const { message, name, stack } = cause;
|
||||
const exception = new errors_1.QuickJSUnwrapError("");
|
||||
const hostStack = exception.stack;
|
||||
if (typeof name === "string") {
|
||||
exception.name = cause.name;
|
||||
}
|
||||
if (typeof stack === "string") {
|
||||
exception.stack = `${name}: ${message}\n${cause.stack}Host: ${hostStack}`;
|
||||
}
|
||||
Object.assign(exception, { cause, context, message });
|
||||
throw exception;
|
||||
}
|
||||
throw new errors_1.QuickJSUnwrapError(cause, context);
|
||||
}
|
||||
return result.value;
|
||||
}
|
||||
/** @private */
|
||||
getFunction(fn_id) {
|
||||
const map_id = fn_id >> 8;
|
||||
const fnMap = this.fnMaps.get(map_id);
|
||||
if (!fnMap) {
|
||||
return undefined;
|
||||
}
|
||||
return fnMap.get(fn_id);
|
||||
}
|
||||
/** @private */
|
||||
setFunction(fn_id, handle) {
|
||||
const map_id = fn_id >> 8;
|
||||
let fnMap = this.fnMaps.get(map_id);
|
||||
if (!fnMap) {
|
||||
fnMap = new Map();
|
||||
this.fnMaps.set(map_id, fnMap);
|
||||
}
|
||||
return fnMap.set(fn_id, handle);
|
||||
}
|
||||
errorToHandle(error) {
|
||||
if (error instanceof lifetime_1.Lifetime) {
|
||||
return error;
|
||||
}
|
||||
return this.newError(error);
|
||||
}
|
||||
}
|
||||
exports.QuickJSContext = QuickJSContext;
|
||||
//# sourceMappingURL=context.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/context.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/context.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
5
node_modules/@tootallnate/quickjs-emscripten/dist/debug.d.ts
generated
vendored
Normal file
5
node_modules/@tootallnate/quickjs-emscripten/dist/debug.d.ts
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
export declare const QTS_DEBUG: boolean;
|
||||
export declare let debugLog: {
|
||||
(...data: any[]): void;
|
||||
(message?: any, ...optionalParams: any[]): void;
|
||||
};
|
||||
6
node_modules/@tootallnate/quickjs-emscripten/dist/debug.js
generated
vendored
Normal file
6
node_modules/@tootallnate/quickjs-emscripten/dist/debug.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.debugLog = exports.QTS_DEBUG = void 0;
|
||||
exports.QTS_DEBUG = false || Boolean(typeof process === "object" && process.env.QTS_DEBUG);
|
||||
exports.debugLog = exports.QTS_DEBUG ? console.log.bind(console) : () => { };
|
||||
//# sourceMappingURL=debug.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/debug.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/debug.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"debug.js","sourceRoot":"","sources":["../ts/debug.ts"],"names":[],"mappings":";;;AAAa,QAAA,SAAS,GAAG,KAAK,IAAI,OAAO,CAAC,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;AACpF,QAAA,QAAQ,GAAG,iBAAS,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAE,CAAC,CAAA","sourcesContent":["export const QTS_DEBUG = false || Boolean(typeof process === \"object\" && process.env.QTS_DEBUG)\nexport let debugLog = QTS_DEBUG ? console.log.bind(console) : () => {}\n"]}
|
||||
75
node_modules/@tootallnate/quickjs-emscripten/dist/deferred-promise.d.ts
generated
vendored
Normal file
75
node_modules/@tootallnate/quickjs-emscripten/dist/deferred-promise.d.ts
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
import type { Disposable } from "./lifetime";
|
||||
import type { QuickJSHandle } from "./types";
|
||||
import type { QuickJSRuntime } from "./runtime";
|
||||
import type { QuickJSContext } from "./context";
|
||||
export type { PromiseExecutor } from "./types";
|
||||
/**
|
||||
* QuickJSDeferredPromise wraps a QuickJS promise [[handle]] and allows
|
||||
* [[resolve]]ing or [[reject]]ing that promise. Use it to bridge asynchronous
|
||||
* code on the host to APIs inside a QuickJSContext.
|
||||
*
|
||||
* Managing the lifetime of promises is tricky. There are three
|
||||
* [[QuickJSHandle]]s inside of each deferred promise object: (1) the promise
|
||||
* itself, (2) the `resolve` callback, and (3) the `reject` callback.
|
||||
*
|
||||
* - If the promise will be fulfilled before the end of it's [[owner]]'s lifetime,
|
||||
* the only cleanup necessary is `deferred.handle.dispose()`, because
|
||||
* calling [[resolve]] or [[reject]] will dispose of both callbacks automatically.
|
||||
*
|
||||
* - As the return value of a [[VmFunctionImplementation]], return [[handle]],
|
||||
* and ensure that either [[resolve]] or [[reject]] will be called. No other
|
||||
* clean-up is necessary.
|
||||
*
|
||||
* - In other cases, call [[dispose]], which will dispose [[handle]] as well as the
|
||||
* QuickJS handles that back [[resolve]] and [[reject]]. For this object,
|
||||
* [[dispose]] is idempotent.
|
||||
*/
|
||||
export declare class QuickJSDeferredPromise implements Disposable {
|
||||
owner: QuickJSRuntime;
|
||||
context: QuickJSContext;
|
||||
/**
|
||||
* A handle of the Promise instance inside the QuickJSContext.
|
||||
* You must dispose [[handle]] or the entire QuickJSDeferredPromise once you
|
||||
* are finished with it.
|
||||
*/
|
||||
handle: QuickJSHandle;
|
||||
/**
|
||||
* A native promise that will resolve once this deferred is settled.
|
||||
*/
|
||||
settled: Promise<void>;
|
||||
private resolveHandle;
|
||||
private rejectHandle;
|
||||
private onSettled;
|
||||
/**
|
||||
* Use [[QuickJSContext.newPromise]] to create a new promise instead of calling
|
||||
* this constructor directly.
|
||||
* @unstable
|
||||
*/
|
||||
constructor(args: {
|
||||
context: QuickJSContext;
|
||||
promiseHandle: QuickJSHandle;
|
||||
resolveHandle: QuickJSHandle;
|
||||
rejectHandle: QuickJSHandle;
|
||||
});
|
||||
/**
|
||||
* Resolve [[handle]] with the given value, if any.
|
||||
* Calling this method after calling [[dispose]] is a no-op.
|
||||
*
|
||||
* Note that after resolving a promise, you may need to call
|
||||
* [[QuickJSContext.executePendingJobs]] to propagate the result to the promise's
|
||||
* callbacks.
|
||||
*/
|
||||
resolve: (value?: QuickJSHandle) => void;
|
||||
/**
|
||||
* Reject [[handle]] with the given value, if any.
|
||||
* Calling this method after calling [[dispose]] is a no-op.
|
||||
*
|
||||
* Note that after rejecting a promise, you may need to call
|
||||
* [[QuickJSContext.executePendingJobs]] to propagate the result to the promise's
|
||||
* callbacks.
|
||||
*/
|
||||
reject: (value?: QuickJSHandle) => void;
|
||||
get alive(): boolean;
|
||||
dispose: () => void;
|
||||
private disposeResolvers;
|
||||
}
|
||||
96
node_modules/@tootallnate/quickjs-emscripten/dist/deferred-promise.js
generated
vendored
Normal file
96
node_modules/@tootallnate/quickjs-emscripten/dist/deferred-promise.js
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.QuickJSDeferredPromise = void 0;
|
||||
/**
|
||||
* QuickJSDeferredPromise wraps a QuickJS promise [[handle]] and allows
|
||||
* [[resolve]]ing or [[reject]]ing that promise. Use it to bridge asynchronous
|
||||
* code on the host to APIs inside a QuickJSContext.
|
||||
*
|
||||
* Managing the lifetime of promises is tricky. There are three
|
||||
* [[QuickJSHandle]]s inside of each deferred promise object: (1) the promise
|
||||
* itself, (2) the `resolve` callback, and (3) the `reject` callback.
|
||||
*
|
||||
* - If the promise will be fulfilled before the end of it's [[owner]]'s lifetime,
|
||||
* the only cleanup necessary is `deferred.handle.dispose()`, because
|
||||
* calling [[resolve]] or [[reject]] will dispose of both callbacks automatically.
|
||||
*
|
||||
* - As the return value of a [[VmFunctionImplementation]], return [[handle]],
|
||||
* and ensure that either [[resolve]] or [[reject]] will be called. No other
|
||||
* clean-up is necessary.
|
||||
*
|
||||
* - In other cases, call [[dispose]], which will dispose [[handle]] as well as the
|
||||
* QuickJS handles that back [[resolve]] and [[reject]]. For this object,
|
||||
* [[dispose]] is idempotent.
|
||||
*/
|
||||
class QuickJSDeferredPromise {
|
||||
/**
|
||||
* Use [[QuickJSContext.newPromise]] to create a new promise instead of calling
|
||||
* this constructor directly.
|
||||
* @unstable
|
||||
*/
|
||||
constructor(args) {
|
||||
/**
|
||||
* Resolve [[handle]] with the given value, if any.
|
||||
* Calling this method after calling [[dispose]] is a no-op.
|
||||
*
|
||||
* Note that after resolving a promise, you may need to call
|
||||
* [[QuickJSContext.executePendingJobs]] to propagate the result to the promise's
|
||||
* callbacks.
|
||||
*/
|
||||
this.resolve = (value) => {
|
||||
if (!this.resolveHandle.alive) {
|
||||
return;
|
||||
}
|
||||
this.context
|
||||
.unwrapResult(this.context.callFunction(this.resolveHandle, this.context.undefined, value || this.context.undefined))
|
||||
.dispose();
|
||||
this.disposeResolvers();
|
||||
this.onSettled();
|
||||
};
|
||||
/**
|
||||
* Reject [[handle]] with the given value, if any.
|
||||
* Calling this method after calling [[dispose]] is a no-op.
|
||||
*
|
||||
* Note that after rejecting a promise, you may need to call
|
||||
* [[QuickJSContext.executePendingJobs]] to propagate the result to the promise's
|
||||
* callbacks.
|
||||
*/
|
||||
this.reject = (value) => {
|
||||
if (!this.rejectHandle.alive) {
|
||||
return;
|
||||
}
|
||||
this.context
|
||||
.unwrapResult(this.context.callFunction(this.rejectHandle, this.context.undefined, value || this.context.undefined))
|
||||
.dispose();
|
||||
this.disposeResolvers();
|
||||
this.onSettled();
|
||||
};
|
||||
this.dispose = () => {
|
||||
if (this.handle.alive) {
|
||||
this.handle.dispose();
|
||||
}
|
||||
this.disposeResolvers();
|
||||
};
|
||||
this.context = args.context;
|
||||
this.owner = args.context.runtime;
|
||||
this.handle = args.promiseHandle;
|
||||
this.settled = new Promise((resolve) => {
|
||||
this.onSettled = resolve;
|
||||
});
|
||||
this.resolveHandle = args.resolveHandle;
|
||||
this.rejectHandle = args.rejectHandle;
|
||||
}
|
||||
get alive() {
|
||||
return this.handle.alive || this.resolveHandle.alive || this.rejectHandle.alive;
|
||||
}
|
||||
disposeResolvers() {
|
||||
if (this.resolveHandle.alive) {
|
||||
this.resolveHandle.dispose();
|
||||
}
|
||||
if (this.rejectHandle.alive) {
|
||||
this.rejectHandle.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.QuickJSDeferredPromise = QuickJSDeferredPromise;
|
||||
//# sourceMappingURL=deferred-promise.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/deferred-promise.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/deferred-promise.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
97
node_modules/@tootallnate/quickjs-emscripten/dist/emscripten-types.d.ts
generated
vendored
Normal file
97
node_modules/@tootallnate/quickjs-emscripten/dist/emscripten-types.d.ts
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
import { BorrowedHeapCharPointer, JSContextPointer, JSRuntimePointer, JSValueConstPointer, JSValuePointer, OwnedHeapCharPointer } from "./types-ffi";
|
||||
declare namespace Emscripten {
|
||||
interface FileSystemType {
|
||||
}
|
||||
type EnvironmentType = "WEB" | "NODE" | "SHELL" | "WORKER";
|
||||
type ValueType = "number" | "string" | "array" | "boolean";
|
||||
type TypeCompatibleWithC = number | string | any[] | boolean;
|
||||
type WebAssemblyImports = Array<{
|
||||
name: string;
|
||||
kind: string;
|
||||
}>;
|
||||
type WebAssemblyExports = Array<{
|
||||
module: string;
|
||||
name: string;
|
||||
kind: string;
|
||||
}>;
|
||||
interface CCallOpts {
|
||||
async?: boolean;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Typings for the features we use to interface with our Emscripten build of
|
||||
* QuickJS.
|
||||
*/
|
||||
interface EmscriptenModule {
|
||||
/**
|
||||
* Write JS `str` to HeapChar pointer.
|
||||
* https://emscripten.org/docs/api_reference/preamble.js.html#stringToUTF8
|
||||
*/
|
||||
stringToUTF8(str: string, outPtr: OwnedHeapCharPointer, maxBytesToRead?: number): void;
|
||||
/**
|
||||
* HeapChar to JS string.
|
||||
* https://emscripten.org/docs/api_reference/preamble.js.html#UTF8ToString
|
||||
*/
|
||||
UTF8ToString(ptr: BorrowedHeapCharPointer, maxBytesToRead?: number): string;
|
||||
lengthBytesUTF8(str: string): number;
|
||||
_malloc(size: number): number;
|
||||
_free(ptr: number): void;
|
||||
cwrap(ident: string, returnType: Emscripten.ValueType | null, argTypes: Emscripten.ValueType[], opts?: Emscripten.CCallOpts): (...args: any[]) => any;
|
||||
HEAP8: Int8Array;
|
||||
HEAP16: Int16Array;
|
||||
HEAP32: Int32Array;
|
||||
HEAPU8: Uint8Array;
|
||||
HEAPU16: Uint16Array;
|
||||
HEAPU32: Uint32Array;
|
||||
HEAPF32: Float32Array;
|
||||
HEAPF64: Float64Array;
|
||||
TOTAL_STACK: number;
|
||||
TOTAL_MEMORY: number;
|
||||
FAST_MEMORY: number;
|
||||
}
|
||||
declare const AsyncifySleepReturnValue: unique symbol;
|
||||
/** @private */
|
||||
export type AsyncifySleepResult<T> = T & typeof AsyncifySleepReturnValue;
|
||||
/**
|
||||
* Allows us to optionally suspend the Emscripten runtime to wait for a promise.
|
||||
* https://emscripten.org/docs/porting/asyncify.html#ways-to-use-async-apis-in-older-engines
|
||||
* ```
|
||||
* EM_JS(int, do_fetch, (), {
|
||||
* return Asyncify.handleSleep(function (wakeUp) {
|
||||
* out("waiting for a fetch");
|
||||
* fetch("a.html").then(function (response) {
|
||||
* out("got the fetch response");
|
||||
* // (normally you would do something with the fetch here)
|
||||
* wakeUp(42);
|
||||
* });
|
||||
* });
|
||||
* });
|
||||
* ```
|
||||
* @private
|
||||
*/
|
||||
export interface Asyncify {
|
||||
handleSleep<T>(maybeAsyncFn: (wakeUp: (result: T) => void) => void): AsyncifySleepResult<T>;
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
export interface EmscriptenModuleCallbacks {
|
||||
callFunction: (asyncify: Asyncify | undefined, ctx: JSContextPointer, this_ptr: JSValueConstPointer, argc: number, argv: JSValueConstPointer, fn_id: number) => JSValuePointer | AsyncifySleepResult<JSValuePointer>;
|
||||
loadModuleSource: (asyncify: Asyncify | undefined, rt: JSRuntimePointer, ctx: JSContextPointer, module_name: string) => BorrowedHeapCharPointer | AsyncifySleepResult<BorrowedHeapCharPointer>;
|
||||
normalizeModule: (asyncify: Asyncify | undefined, rt: JSRuntimePointer, ctx: JSContextPointer, module_base_name: string, module_name: string) => BorrowedHeapCharPointer | AsyncifySleepResult<BorrowedHeapCharPointer>;
|
||||
shouldInterrupt: (asyncify: Asyncify | undefined, rt: JSRuntimePointer) => 0 | 1 | AsyncifySleepResult<0 | 1>;
|
||||
}
|
||||
export interface QuickJSEmscriptenModule extends EmscriptenModule {
|
||||
type: "sync";
|
||||
callbacks: EmscriptenModuleCallbacks;
|
||||
}
|
||||
export interface QuickJSAsyncEmscriptenModule extends EmscriptenModule {
|
||||
/** @todo Implement this field */
|
||||
type: "async";
|
||||
callbacks: EmscriptenModuleCallbacks;
|
||||
}
|
||||
export type EitherModule = QuickJSEmscriptenModule | QuickJSAsyncEmscriptenModule;
|
||||
export interface EmscriptenModuleLoader<T extends EmscriptenModule> {
|
||||
(): Promise<T>;
|
||||
}
|
||||
export {};
|
||||
15
node_modules/@tootallnate/quickjs-emscripten/dist/emscripten-types.js
generated
vendored
Normal file
15
node_modules/@tootallnate/quickjs-emscripten/dist/emscripten-types.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
// This is a subset of the Emscripten type definitions from @types/emscripten
|
||||
// Project: http://kripken.github.io/emscripten-site/index.html
|
||||
// Definitions by: Kensuke Matsuzaki <https://github.com/zakki>
|
||||
// Periklis Tsirakidis <https://github.com/periklis>
|
||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||
//
|
||||
// quickjs-emscripten doesn't use the full EmscriptenModule type from @types/emscripten because:
|
||||
//
|
||||
// - the upstream types define many properties that don't exist on our module due
|
||||
// to our build settings
|
||||
// - some upstream types reference web-only ambient types like WebGL stuff, which
|
||||
// we don't use.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
//# sourceMappingURL=emscripten-types.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/emscripten-types.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/emscripten-types.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
28
node_modules/@tootallnate/quickjs-emscripten/dist/errors.d.ts
generated
vendored
Normal file
28
node_modules/@tootallnate/quickjs-emscripten/dist/errors.d.ts
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
import type { QuickJSContext } from "./context";
|
||||
/**
|
||||
* Error thrown if [[QuickJSContext.unwrapResult]] unwraps an error value that isn't an object.
|
||||
*/
|
||||
export declare class QuickJSUnwrapError extends Error {
|
||||
cause: unknown;
|
||||
context?: QuickJSContext | undefined;
|
||||
name: string;
|
||||
constructor(cause: unknown, context?: QuickJSContext | undefined);
|
||||
}
|
||||
export declare class QuickJSWrongOwner extends Error {
|
||||
name: string;
|
||||
}
|
||||
export declare class QuickJSUseAfterFree extends Error {
|
||||
name: string;
|
||||
}
|
||||
export declare class QuickJSNotImplemented extends Error {
|
||||
name: string;
|
||||
}
|
||||
export declare class QuickJSAsyncifyError extends Error {
|
||||
name: string;
|
||||
}
|
||||
export declare class QuickJSAsyncifySuspended extends Error {
|
||||
name: string;
|
||||
}
|
||||
export declare class QuickJSMemoryLeakDetected extends Error {
|
||||
name: string;
|
||||
}
|
||||
58
node_modules/@tootallnate/quickjs-emscripten/dist/errors.js
generated
vendored
Normal file
58
node_modules/@tootallnate/quickjs-emscripten/dist/errors.js
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.QuickJSMemoryLeakDetected = exports.QuickJSAsyncifySuspended = exports.QuickJSAsyncifyError = exports.QuickJSNotImplemented = exports.QuickJSUseAfterFree = exports.QuickJSWrongOwner = exports.QuickJSUnwrapError = void 0;
|
||||
/**
|
||||
* Error thrown if [[QuickJSContext.unwrapResult]] unwraps an error value that isn't an object.
|
||||
*/
|
||||
class QuickJSUnwrapError extends Error {
|
||||
constructor(cause, context) {
|
||||
super(String(cause));
|
||||
this.cause = cause;
|
||||
this.context = context;
|
||||
this.name = "QuickJSUnwrapError";
|
||||
}
|
||||
}
|
||||
exports.QuickJSUnwrapError = QuickJSUnwrapError;
|
||||
class QuickJSWrongOwner extends Error {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.name = "QuickJSWrongOwner";
|
||||
}
|
||||
}
|
||||
exports.QuickJSWrongOwner = QuickJSWrongOwner;
|
||||
class QuickJSUseAfterFree extends Error {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.name = "QuickJSUseAfterFree";
|
||||
}
|
||||
}
|
||||
exports.QuickJSUseAfterFree = QuickJSUseAfterFree;
|
||||
class QuickJSNotImplemented extends Error {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.name = "QuickJSNotImplemented";
|
||||
}
|
||||
}
|
||||
exports.QuickJSNotImplemented = QuickJSNotImplemented;
|
||||
class QuickJSAsyncifyError extends Error {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.name = "QuickJSAsyncifyError";
|
||||
}
|
||||
}
|
||||
exports.QuickJSAsyncifyError = QuickJSAsyncifyError;
|
||||
class QuickJSAsyncifySuspended extends Error {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.name = "QuickJSAsyncifySuspended";
|
||||
}
|
||||
}
|
||||
exports.QuickJSAsyncifySuspended = QuickJSAsyncifySuspended;
|
||||
class QuickJSMemoryLeakDetected extends Error {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.name = "QuickJSMemoryLeakDetected";
|
||||
}
|
||||
}
|
||||
exports.QuickJSMemoryLeakDetected = QuickJSMemoryLeakDetected;
|
||||
//# sourceMappingURL=errors.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/errors.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/errors.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../ts/errors.ts"],"names":[],"mappings":";;;AAEA;;GAEG;AACH,MAAa,kBAAmB,SAAQ,KAAK;IAE3C,YAAmB,KAAc,EAAS,OAAwB;QAChE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;QADH,UAAK,GAAL,KAAK,CAAS;QAAS,YAAO,GAAP,OAAO,CAAiB;QADlE,SAAI,GAAG,oBAAoB,CAAA;IAG3B,CAAC;CACF;AALD,gDAKC;AAED,MAAa,iBAAkB,SAAQ,KAAK;IAA5C;;QACE,SAAI,GAAG,mBAAmB,CAAA;IAC5B,CAAC;CAAA;AAFD,8CAEC;AAED,MAAa,mBAAoB,SAAQ,KAAK;IAA9C;;QACE,SAAI,GAAG,qBAAqB,CAAA;IAC9B,CAAC;CAAA;AAFD,kDAEC;AAED,MAAa,qBAAsB,SAAQ,KAAK;IAAhD;;QACE,SAAI,GAAG,uBAAuB,CAAA;IAChC,CAAC;CAAA;AAFD,sDAEC;AAED,MAAa,oBAAqB,SAAQ,KAAK;IAA/C;;QACE,SAAI,GAAG,sBAAsB,CAAA;IAC/B,CAAC;CAAA;AAFD,oDAEC;AAED,MAAa,wBAAyB,SAAQ,KAAK;IAAnD;;QACE,SAAI,GAAG,0BAA0B,CAAA;IACnC,CAAC;CAAA;AAFD,4DAEC;AAED,MAAa,yBAA0B,SAAQ,KAAK;IAApD;;QACE,SAAI,GAAG,2BAA2B,CAAA;IACpC,CAAC;CAAA;AAFD,8DAEC","sourcesContent":["import type { QuickJSContext } from \"./context\"\n\n/**\n * Error thrown if [[QuickJSContext.unwrapResult]] unwraps an error value that isn't an object.\n */\nexport class QuickJSUnwrapError extends Error {\n name = \"QuickJSUnwrapError\"\n constructor(public cause: unknown, public context?: QuickJSContext) {\n super(String(cause))\n }\n}\n\nexport class QuickJSWrongOwner extends Error {\n name = \"QuickJSWrongOwner\"\n}\n\nexport class QuickJSUseAfterFree extends Error {\n name = \"QuickJSUseAfterFree\"\n}\n\nexport class QuickJSNotImplemented extends Error {\n name = \"QuickJSNotImplemented\"\n}\n\nexport class QuickJSAsyncifyError extends Error {\n name = \"QuickJSAsyncifyError\"\n}\n\nexport class QuickJSAsyncifySuspended extends Error {\n name = \"QuickJSAsyncifySuspended\"\n}\n\nexport class QuickJSMemoryLeakDetected extends Error {\n name = \"QuickJSMemoryLeakDetected\"\n}\n"]}
|
||||
9
node_modules/@tootallnate/quickjs-emscripten/dist/esmHelpers.d.ts
generated
vendored
Normal file
9
node_modules/@tootallnate/quickjs-emscripten/dist/esmHelpers.d.ts
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/** Typescript thinks import('...js/.d.ts') needs mod.default.default */
|
||||
declare function fakeUnwrapDefault<T>(mod: {
|
||||
default: T;
|
||||
}): T;
|
||||
/** Typescript thinks import('...ts') doesn't need mod.default.default, but does */
|
||||
declare function actualUnwrapDefault<T>(mod: T): T;
|
||||
export declare const unwrapTypescript: typeof actualUnwrapDefault;
|
||||
export declare const unwrapJavascript: typeof fakeUnwrapDefault;
|
||||
export {};
|
||||
19
node_modules/@tootallnate/quickjs-emscripten/dist/esmHelpers.js
generated
vendored
Normal file
19
node_modules/@tootallnate/quickjs-emscripten/dist/esmHelpers.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.unwrapJavascript = exports.unwrapTypescript = void 0;
|
||||
/** Typescript thinks import('...js/.d.ts') needs mod.default.default */
|
||||
function fakeUnwrapDefault(mod) {
|
||||
// console.log("fakeUnwrapDefault", mod)
|
||||
return mod.default;
|
||||
}
|
||||
/** Typescript thinks import('...ts') doesn't need mod.default.default, but does */
|
||||
function actualUnwrapDefault(mod) {
|
||||
// console.log("actualUnwrapDefault", mod)
|
||||
const maybeUnwrap = mod.default;
|
||||
return maybeUnwrap ?? mod;
|
||||
}
|
||||
// I'm not sure if this behavior is needed in all runtimes,
|
||||
// or just for mocha + ts-node.
|
||||
exports.unwrapTypescript = actualUnwrapDefault;
|
||||
exports.unwrapJavascript = fakeUnwrapDefault;
|
||||
//# sourceMappingURL=esmHelpers.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/esmHelpers.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/esmHelpers.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"esmHelpers.js","sourceRoot":"","sources":["../ts/esmHelpers.ts"],"names":[],"mappings":";;;AAAA,wEAAwE;AACxE,SAAS,iBAAiB,CAAI,GAAmB;IAC/C,wCAAwC;IACxC,OAAO,GAAG,CAAC,OAAY,CAAA;AACzB,CAAC;AAED,mFAAmF;AACnF,SAAS,mBAAmB,CAAI,GAAM;IACpC,0CAA0C;IAC1C,MAAM,WAAW,GAAI,GAAW,CAAC,OAAO,CAAA;IACxC,OAAO,WAAW,IAAI,GAAG,CAAA;AAC3B,CAAC;AAED,2DAA2D;AAC3D,+BAA+B;AAClB,QAAA,gBAAgB,GAAG,mBAAmB,CAAA;AACtC,QAAA,gBAAgB,GAAG,iBAAiB,CAAA","sourcesContent":["/** Typescript thinks import('...js/.d.ts') needs mod.default.default */\nfunction fakeUnwrapDefault<T>(mod: { default: T }): T {\n // console.log(\"fakeUnwrapDefault\", mod)\n return mod.default as T\n}\n\n/** Typescript thinks import('...ts') doesn't need mod.default.default, but does */\nfunction actualUnwrapDefault<T>(mod: T): T {\n // console.log(\"actualUnwrapDefault\", mod)\n const maybeUnwrap = (mod as any).default\n return maybeUnwrap ?? mod\n}\n\n// I'm not sure if this behavior is needed in all runtimes,\n// or just for mocha + ts-node.\nexport const unwrapTypescript = actualUnwrapDefault\nexport const unwrapJavascript = fakeUnwrapDefault\n"]}
|
||||
5
node_modules/@tootallnate/quickjs-emscripten/dist/generated/emscripten-module.WASM_RELEASE_SYNC.d.ts
generated
vendored
Normal file
5
node_modules/@tootallnate/quickjs-emscripten/dist/generated/emscripten-module.WASM_RELEASE_SYNC.d.ts
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
export = QuickJSRaw;
|
||||
declare function QuickJSRaw(QuickJSRaw?: {}): any;
|
||||
declare namespace QuickJSRaw {
|
||||
export { QuickJSRaw };
|
||||
}
|
||||
387
node_modules/@tootallnate/quickjs-emscripten/dist/generated/emscripten-module.WASM_RELEASE_SYNC.js
generated
vendored
Normal file
387
node_modules/@tootallnate/quickjs-emscripten/dist/generated/emscripten-module.WASM_RELEASE_SYNC.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/@tootallnate/quickjs-emscripten/dist/generated/emscripten-module.WASM_RELEASE_SYNC.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/generated/emscripten-module.WASM_RELEASE_SYNC.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
67
node_modules/@tootallnate/quickjs-emscripten/dist/generated/ffi.WASM_RELEASE_SYNC.d.ts
generated
vendored
Normal file
67
node_modules/@tootallnate/quickjs-emscripten/dist/generated/ffi.WASM_RELEASE_SYNC.d.ts
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
import { QuickJSEmscriptenModule } from "../emscripten-types";
|
||||
import { JSRuntimePointer, JSContextPointer, JSContextPointerPointer, JSValuePointer, JSValueConstPointer, JSValuePointerPointer, JSValueConstPointerPointer, BorrowedHeapCharPointer, OwnedHeapCharPointer, JSBorrowedCharPointer, JSVoidPointer, EvalFlags, EvalDetectModule } from "../types-ffi";
|
||||
/**
|
||||
* Low-level FFI bindings to QuickJS's Emscripten module.
|
||||
* See instead [[QuickJSContext]], the public Javascript interface exposed by this
|
||||
* library.
|
||||
*
|
||||
* @unstable The FFI interface is considered private and may change.
|
||||
*/
|
||||
export declare class QuickJSFFI {
|
||||
private module;
|
||||
constructor(module: QuickJSEmscriptenModule);
|
||||
/** Set at compile time. */
|
||||
readonly DEBUG = false;
|
||||
QTS_Throw: (ctx: JSContextPointer, error: JSValuePointer | JSValueConstPointer) => JSValuePointer;
|
||||
QTS_NewError: (ctx: JSContextPointer) => JSValuePointer;
|
||||
QTS_RuntimeSetMemoryLimit: (rt: JSRuntimePointer, limit: number) => void;
|
||||
QTS_RuntimeComputeMemoryUsage: (rt: JSRuntimePointer, ctx: JSContextPointer) => JSValuePointer;
|
||||
QTS_RuntimeDumpMemoryUsage: (rt: JSRuntimePointer) => OwnedHeapCharPointer;
|
||||
QTS_RecoverableLeakCheck: () => number;
|
||||
QTS_BuildIsSanitizeLeak: () => number;
|
||||
QTS_RuntimeSetMaxStackSize: (rt: JSRuntimePointer, stack_size: number) => void;
|
||||
QTS_GetUndefined: () => JSValueConstPointer;
|
||||
QTS_GetNull: () => JSValueConstPointer;
|
||||
QTS_GetFalse: () => JSValueConstPointer;
|
||||
QTS_GetTrue: () => JSValueConstPointer;
|
||||
QTS_NewRuntime: () => JSRuntimePointer;
|
||||
QTS_FreeRuntime: (rt: JSRuntimePointer) => void;
|
||||
QTS_NewContext: (rt: JSRuntimePointer) => JSContextPointer;
|
||||
QTS_FreeContext: (ctx: JSContextPointer) => void;
|
||||
QTS_FreeValuePointer: (ctx: JSContextPointer, value: JSValuePointer) => void;
|
||||
QTS_FreeValuePointerRuntime: (rt: JSRuntimePointer, value: JSValuePointer) => void;
|
||||
QTS_FreeVoidPointer: (ctx: JSContextPointer, ptr: JSVoidPointer) => void;
|
||||
QTS_FreeCString: (ctx: JSContextPointer, str: JSBorrowedCharPointer) => void;
|
||||
QTS_DupValuePointer: (ctx: JSContextPointer, val: JSValuePointer | JSValueConstPointer) => JSValuePointer;
|
||||
QTS_NewObject: (ctx: JSContextPointer) => JSValuePointer;
|
||||
QTS_NewObjectProto: (ctx: JSContextPointer, proto: JSValuePointer | JSValueConstPointer) => JSValuePointer;
|
||||
QTS_NewArray: (ctx: JSContextPointer) => JSValuePointer;
|
||||
QTS_NewFloat64: (ctx: JSContextPointer, num: number) => JSValuePointer;
|
||||
QTS_GetFloat64: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number;
|
||||
QTS_NewString: (ctx: JSContextPointer, string: BorrowedHeapCharPointer) => JSValuePointer;
|
||||
QTS_GetString: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => JSBorrowedCharPointer;
|
||||
QTS_NewSymbol: (ctx: JSContextPointer, description: BorrowedHeapCharPointer, isGlobal: number) => JSValuePointer;
|
||||
QTS_GetSymbolDescriptionOrKey: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => JSBorrowedCharPointer;
|
||||
QTS_IsGlobalSymbol: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => number;
|
||||
QTS_IsJobPending: (rt: JSRuntimePointer) => number;
|
||||
QTS_ExecutePendingJob: (rt: JSRuntimePointer, maxJobsToExecute: number, lastJobContext: JSContextPointerPointer) => JSValuePointer;
|
||||
QTS_GetProp: (ctx: JSContextPointer, this_val: JSValuePointer | JSValueConstPointer, prop_name: JSValuePointer | JSValueConstPointer) => JSValuePointer;
|
||||
QTS_SetProp: (ctx: JSContextPointer, this_val: JSValuePointer | JSValueConstPointer, prop_name: JSValuePointer | JSValueConstPointer, prop_value: JSValuePointer | JSValueConstPointer) => void;
|
||||
QTS_DefineProp: (ctx: JSContextPointer, this_val: JSValuePointer | JSValueConstPointer, prop_name: JSValuePointer | JSValueConstPointer, prop_value: JSValuePointer | JSValueConstPointer, get: JSValuePointer | JSValueConstPointer, set: JSValuePointer | JSValueConstPointer, configurable: boolean, enumerable: boolean, has_value: boolean) => void;
|
||||
QTS_Call: (ctx: JSContextPointer, func_obj: JSValuePointer | JSValueConstPointer, this_obj: JSValuePointer | JSValueConstPointer, argc: number, argv_ptrs: JSValueConstPointerPointer) => JSValuePointer;
|
||||
QTS_ResolveException: (ctx: JSContextPointer, maybe_exception: JSValuePointer) => JSValuePointer;
|
||||
QTS_Dump: (ctx: JSContextPointer, obj: JSValuePointer | JSValueConstPointer) => JSBorrowedCharPointer;
|
||||
QTS_Eval: (ctx: JSContextPointer, js_code: BorrowedHeapCharPointer, filename: string, detectModule: EvalDetectModule, evalFlags: EvalFlags) => JSValuePointer;
|
||||
QTS_Typeof: (ctx: JSContextPointer, value: JSValuePointer | JSValueConstPointer) => OwnedHeapCharPointer;
|
||||
QTS_GetGlobalObject: (ctx: JSContextPointer) => JSValuePointer;
|
||||
QTS_NewPromiseCapability: (ctx: JSContextPointer, resolve_funcs_out: JSValuePointerPointer) => JSValuePointer;
|
||||
QTS_TestStringArg: (string: string) => void;
|
||||
QTS_BuildIsDebug: () => number;
|
||||
QTS_BuildIsAsyncify: () => number;
|
||||
QTS_NewFunction: (ctx: JSContextPointer, func_id: number, name: string) => JSValuePointer;
|
||||
QTS_ArgvGetJSValueConstPointer: (argv: JSValuePointer | JSValueConstPointer, index: number) => JSValueConstPointer;
|
||||
QTS_RuntimeEnableInterruptHandler: (rt: JSRuntimePointer) => void;
|
||||
QTS_RuntimeDisableInterruptHandler: (rt: JSRuntimePointer) => void;
|
||||
QTS_RuntimeEnableModuleLoader: (rt: JSRuntimePointer, use_custom_normalize: number) => void;
|
||||
QTS_RuntimeDisableModuleLoader: (rt: JSRuntimePointer) => void;
|
||||
}
|
||||
71
node_modules/@tootallnate/quickjs-emscripten/dist/generated/ffi.WASM_RELEASE_SYNC.js
generated
vendored
Normal file
71
node_modules/@tootallnate/quickjs-emscripten/dist/generated/ffi.WASM_RELEASE_SYNC.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.QuickJSFFI = void 0;
|
||||
/**
|
||||
* Low-level FFI bindings to QuickJS's Emscripten module.
|
||||
* See instead [[QuickJSContext]], the public Javascript interface exposed by this
|
||||
* library.
|
||||
*
|
||||
* @unstable The FFI interface is considered private and may change.
|
||||
*/
|
||||
class QuickJSFFI {
|
||||
constructor(module) {
|
||||
this.module = module;
|
||||
/** Set at compile time. */
|
||||
this.DEBUG = false;
|
||||
this.QTS_Throw = this.module.cwrap("QTS_Throw", "number", ["number", "number"]);
|
||||
this.QTS_NewError = this.module.cwrap("QTS_NewError", "number", ["number"]);
|
||||
this.QTS_RuntimeSetMemoryLimit = this.module.cwrap("QTS_RuntimeSetMemoryLimit", null, ["number", "number"]);
|
||||
this.QTS_RuntimeComputeMemoryUsage = this.module.cwrap("QTS_RuntimeComputeMemoryUsage", "number", ["number", "number"]);
|
||||
this.QTS_RuntimeDumpMemoryUsage = this.module.cwrap("QTS_RuntimeDumpMemoryUsage", "number", ["number"]);
|
||||
this.QTS_RecoverableLeakCheck = this.module.cwrap("QTS_RecoverableLeakCheck", "number", []);
|
||||
this.QTS_BuildIsSanitizeLeak = this.module.cwrap("QTS_BuildIsSanitizeLeak", "number", []);
|
||||
this.QTS_RuntimeSetMaxStackSize = this.module.cwrap("QTS_RuntimeSetMaxStackSize", null, ["number", "number"]);
|
||||
this.QTS_GetUndefined = this.module.cwrap("QTS_GetUndefined", "number", []);
|
||||
this.QTS_GetNull = this.module.cwrap("QTS_GetNull", "number", []);
|
||||
this.QTS_GetFalse = this.module.cwrap("QTS_GetFalse", "number", []);
|
||||
this.QTS_GetTrue = this.module.cwrap("QTS_GetTrue", "number", []);
|
||||
this.QTS_NewRuntime = this.module.cwrap("QTS_NewRuntime", "number", []);
|
||||
this.QTS_FreeRuntime = this.module.cwrap("QTS_FreeRuntime", null, ["number"]);
|
||||
this.QTS_NewContext = this.module.cwrap("QTS_NewContext", "number", ["number"]);
|
||||
this.QTS_FreeContext = this.module.cwrap("QTS_FreeContext", null, ["number"]);
|
||||
this.QTS_FreeValuePointer = this.module.cwrap("QTS_FreeValuePointer", null, ["number", "number"]);
|
||||
this.QTS_FreeValuePointerRuntime = this.module.cwrap("QTS_FreeValuePointerRuntime", null, ["number", "number"]);
|
||||
this.QTS_FreeVoidPointer = this.module.cwrap("QTS_FreeVoidPointer", null, ["number", "number"]);
|
||||
this.QTS_FreeCString = this.module.cwrap("QTS_FreeCString", null, ["number", "number"]);
|
||||
this.QTS_DupValuePointer = this.module.cwrap("QTS_DupValuePointer", "number", ["number", "number"]);
|
||||
this.QTS_NewObject = this.module.cwrap("QTS_NewObject", "number", ["number"]);
|
||||
this.QTS_NewObjectProto = this.module.cwrap("QTS_NewObjectProto", "number", ["number", "number"]);
|
||||
this.QTS_NewArray = this.module.cwrap("QTS_NewArray", "number", ["number"]);
|
||||
this.QTS_NewFloat64 = this.module.cwrap("QTS_NewFloat64", "number", ["number", "number"]);
|
||||
this.QTS_GetFloat64 = this.module.cwrap("QTS_GetFloat64", "number", ["number", "number"]);
|
||||
this.QTS_NewString = this.module.cwrap("QTS_NewString", "number", ["number", "number"]);
|
||||
this.QTS_GetString = this.module.cwrap("QTS_GetString", "number", ["number", "number"]);
|
||||
this.QTS_NewSymbol = this.module.cwrap("QTS_NewSymbol", "number", ["number", "number", "number"]);
|
||||
this.QTS_GetSymbolDescriptionOrKey = this.module.cwrap("QTS_GetSymbolDescriptionOrKey", "number", ["number", "number"]);
|
||||
this.QTS_IsGlobalSymbol = this.module.cwrap("QTS_IsGlobalSymbol", "number", ["number", "number"]);
|
||||
this.QTS_IsJobPending = this.module.cwrap("QTS_IsJobPending", "number", ["number"]);
|
||||
this.QTS_ExecutePendingJob = this.module.cwrap("QTS_ExecutePendingJob", "number", ["number", "number", "number"]);
|
||||
this.QTS_GetProp = this.module.cwrap("QTS_GetProp", "number", ["number", "number", "number"]);
|
||||
this.QTS_SetProp = this.module.cwrap("QTS_SetProp", null, ["number", "number", "number", "number"]);
|
||||
this.QTS_DefineProp = this.module.cwrap("QTS_DefineProp", null, ["number", "number", "number", "number", "number", "number", "boolean", "boolean", "boolean"]);
|
||||
this.QTS_Call = this.module.cwrap("QTS_Call", "number", ["number", "number", "number", "number", "number"]);
|
||||
this.QTS_ResolveException = this.module.cwrap("QTS_ResolveException", "number", ["number", "number"]);
|
||||
this.QTS_Dump = this.module.cwrap("QTS_Dump", "number", ["number", "number"]);
|
||||
this.QTS_Eval = this.module.cwrap("QTS_Eval", "number", ["number", "number", "string", "number", "number"]);
|
||||
this.QTS_Typeof = this.module.cwrap("QTS_Typeof", "number", ["number", "number"]);
|
||||
this.QTS_GetGlobalObject = this.module.cwrap("QTS_GetGlobalObject", "number", ["number"]);
|
||||
this.QTS_NewPromiseCapability = this.module.cwrap("QTS_NewPromiseCapability", "number", ["number", "number"]);
|
||||
this.QTS_TestStringArg = this.module.cwrap("QTS_TestStringArg", null, ["string"]);
|
||||
this.QTS_BuildIsDebug = this.module.cwrap("QTS_BuildIsDebug", "number", []);
|
||||
this.QTS_BuildIsAsyncify = this.module.cwrap("QTS_BuildIsAsyncify", "number", []);
|
||||
this.QTS_NewFunction = this.module.cwrap("QTS_NewFunction", "number", ["number", "number", "string"]);
|
||||
this.QTS_ArgvGetJSValueConstPointer = this.module.cwrap("QTS_ArgvGetJSValueConstPointer", "number", ["number", "number"]);
|
||||
this.QTS_RuntimeEnableInterruptHandler = this.module.cwrap("QTS_RuntimeEnableInterruptHandler", null, ["number"]);
|
||||
this.QTS_RuntimeDisableInterruptHandler = this.module.cwrap("QTS_RuntimeDisableInterruptHandler", null, ["number"]);
|
||||
this.QTS_RuntimeEnableModuleLoader = this.module.cwrap("QTS_RuntimeEnableModuleLoader", null, ["number", "number"]);
|
||||
this.QTS_RuntimeDisableModuleLoader = this.module.cwrap("QTS_RuntimeDisableModuleLoader", null, ["number"]);
|
||||
}
|
||||
}
|
||||
exports.QuickJSFFI = QuickJSFFI;
|
||||
//# sourceMappingURL=ffi.WASM_RELEASE_SYNC.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/generated/ffi.WASM_RELEASE_SYNC.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/generated/ffi.WASM_RELEASE_SYNC.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
75
node_modules/@tootallnate/quickjs-emscripten/dist/index.d.ts
generated
vendored
Normal file
75
node_modules/@tootallnate/quickjs-emscripten/dist/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
import type { QuickJSWASMModule } from "./module";
|
||||
import type { QuickJSRuntime, InterruptHandler } from "./runtime";
|
||||
import type { QuickJSContext } from "./context";
|
||||
export type { QuickJSWASMModule, QuickJSContext, QuickJSRuntime };
|
||||
import type { QuickJSAsyncWASMModule } from "./module-asyncify";
|
||||
import type { QuickJSAsyncRuntime } from "./runtime-asyncify";
|
||||
import type { QuickJSAsyncContext, AsyncFunctionImplementation } from "./context-asyncify";
|
||||
import { AsyncRuntimeOptions, ContextOptions } from "./types";
|
||||
export type { QuickJSAsyncContext, QuickJSAsyncRuntime, QuickJSAsyncWASMModule, AsyncFunctionImplementation, };
|
||||
import { newQuickJSWASMModule, newQuickJSAsyncWASMModule, DEBUG_ASYNC, DEBUG_SYNC, RELEASE_ASYNC, RELEASE_SYNC, SyncBuildVariant, AsyncBuildVariant } from "./variants";
|
||||
export { newQuickJSWASMModule, newQuickJSAsyncWASMModule, DEBUG_ASYNC, DEBUG_SYNC, RELEASE_ASYNC, RELEASE_SYNC, SyncBuildVariant, AsyncBuildVariant, };
|
||||
export * from "./vm-interface";
|
||||
export * from "./lifetime";
|
||||
/** Collects the informative errors this library may throw. */
|
||||
export * as errors from "./errors";
|
||||
export * from "./deferred-promise";
|
||||
export * from "./module-test";
|
||||
export type { StaticJSValue, JSValueConst, JSValue, QuickJSHandle, ContextOptions, ContextEvalOptions, RuntimeOptions, AsyncRuntimeOptions, RuntimeOptionsBase, JSModuleLoader, JSModuleLoadResult, JSModuleLoaderAsync, JSModuleLoadSuccess, JSModuleLoadFailure, JSModuleNormalizer, JSModuleNormalizerAsync, JSModuleNormalizeResult, JSModuleNormalizeFailure, JSModuleNormalizeSuccess, } from "./types";
|
||||
export type { ModuleEvalOptions } from "./module";
|
||||
export type { InterruptHandler, ExecutePendingJobsResult } from "./runtime";
|
||||
export type { QuickJSPropertyKey } from "./context";
|
||||
/**
|
||||
* Get a shared singleton {@link QuickJSWASMModule}. Use this to evaluate code
|
||||
* or create Javascript environments.
|
||||
*
|
||||
* This is the top-level entrypoint for the quickjs-emscripten library.
|
||||
*
|
||||
* If you need strictest possible isolation guarantees, you may create a
|
||||
* separate {@link QuickJSWASMModule} via {@link newQuickJSWASMModule}.
|
||||
*
|
||||
* To work with the asyncified version of this library, see these functions:
|
||||
*
|
||||
* - {@link newAsyncRuntime}.
|
||||
* - {@link newAsyncContext}.
|
||||
* - {@link newQuickJSAsyncWASMModule}.
|
||||
*/
|
||||
export declare function getQuickJS(): Promise<QuickJSWASMModule>;
|
||||
/**
|
||||
* Provides synchronous access to the shared {@link QuickJSWASMModule} instance returned by {@link getQuickJS}, as long as
|
||||
* least once.
|
||||
* @throws If called before `getQuickJS` resolves.
|
||||
*/
|
||||
export declare function getQuickJSSync(): QuickJSWASMModule;
|
||||
/**
|
||||
* Create a new [[QuickJSAsyncRuntime]] in a separate WebAssembly module.
|
||||
*
|
||||
* Each runtime is isolated in a separate WebAssembly module, so that errors in
|
||||
* one runtime cannot contaminate another runtime, and each runtime can execute
|
||||
* an asynchronous action without conflicts.
|
||||
*
|
||||
* Note that there is a hard limit on the number of WebAssembly modules in older
|
||||
* versions of v8:
|
||||
* https://bugs.chromium.org/p/v8/issues/detail?id=12076
|
||||
*/
|
||||
export declare function newAsyncRuntime(options?: AsyncRuntimeOptions): Promise<QuickJSAsyncRuntime>;
|
||||
/**
|
||||
* Create a new [[QuickJSAsyncContext]] (with an associated runtime) in an
|
||||
* separate WebAssembly module.
|
||||
*
|
||||
* Each context is isolated in a separate WebAssembly module, so that errors in
|
||||
* one runtime cannot contaminate another runtime, and each runtime can execute
|
||||
* an asynchronous action without conflicts.
|
||||
*
|
||||
* Note that there is a hard limit on the number of WebAssembly modules in older
|
||||
* versions of v8:
|
||||
* https://bugs.chromium.org/p/v8/issues/detail?id=12076
|
||||
*/
|
||||
export declare function newAsyncContext(options?: ContextOptions): Promise<QuickJSAsyncContext>;
|
||||
/**
|
||||
* Returns an interrupt handler that interrupts Javascript execution after a deadline time.
|
||||
*
|
||||
* @param deadline - Interrupt execution if it's still running after this time.
|
||||
* Number values are compared against `Date.now()`
|
||||
*/
|
||||
export declare function shouldInterruptAfterDeadline(deadline: Date | number): InterruptHandler;
|
||||
128
node_modules/@tootallnate/quickjs-emscripten/dist/index.js
generated
vendored
Normal file
128
node_modules/@tootallnate/quickjs-emscripten/dist/index.js
generated
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.shouldInterruptAfterDeadline = exports.newAsyncContext = exports.newAsyncRuntime = exports.getQuickJSSync = exports.getQuickJS = exports.errors = exports.RELEASE_SYNC = exports.RELEASE_ASYNC = exports.DEBUG_SYNC = exports.DEBUG_ASYNC = exports.newQuickJSAsyncWASMModule = exports.newQuickJSWASMModule = void 0;
|
||||
// Build variants
|
||||
const variants_1 = require("./variants");
|
||||
Object.defineProperty(exports, "newQuickJSWASMModule", { enumerable: true, get: function () { return variants_1.newQuickJSWASMModule; } });
|
||||
Object.defineProperty(exports, "newQuickJSAsyncWASMModule", { enumerable: true, get: function () { return variants_1.newQuickJSAsyncWASMModule; } });
|
||||
Object.defineProperty(exports, "DEBUG_ASYNC", { enumerable: true, get: function () { return variants_1.DEBUG_ASYNC; } });
|
||||
Object.defineProperty(exports, "DEBUG_SYNC", { enumerable: true, get: function () { return variants_1.DEBUG_SYNC; } });
|
||||
Object.defineProperty(exports, "RELEASE_ASYNC", { enumerable: true, get: function () { return variants_1.RELEASE_ASYNC; } });
|
||||
Object.defineProperty(exports, "RELEASE_SYNC", { enumerable: true, get: function () { return variants_1.RELEASE_SYNC; } });
|
||||
// Export helpers
|
||||
__exportStar(require("./vm-interface"), exports);
|
||||
__exportStar(require("./lifetime"), exports);
|
||||
/** Collects the informative errors this library may throw. */
|
||||
exports.errors = __importStar(require("./errors"));
|
||||
__exportStar(require("./deferred-promise"), exports);
|
||||
__exportStar(require("./module-test"), exports);
|
||||
let singleton = undefined;
|
||||
let singletonPromise = undefined;
|
||||
/**
|
||||
* Get a shared singleton {@link QuickJSWASMModule}. Use this to evaluate code
|
||||
* or create Javascript environments.
|
||||
*
|
||||
* This is the top-level entrypoint for the quickjs-emscripten library.
|
||||
*
|
||||
* If you need strictest possible isolation guarantees, you may create a
|
||||
* separate {@link QuickJSWASMModule} via {@link newQuickJSWASMModule}.
|
||||
*
|
||||
* To work with the asyncified version of this library, see these functions:
|
||||
*
|
||||
* - {@link newAsyncRuntime}.
|
||||
* - {@link newAsyncContext}.
|
||||
* - {@link newQuickJSAsyncWASMModule}.
|
||||
*/
|
||||
async function getQuickJS() {
|
||||
singletonPromise ?? (singletonPromise = (0, variants_1.newQuickJSWASMModule)().then((instance) => {
|
||||
singleton = instance;
|
||||
return instance;
|
||||
}));
|
||||
return await singletonPromise;
|
||||
}
|
||||
exports.getQuickJS = getQuickJS;
|
||||
/**
|
||||
* Provides synchronous access to the shared {@link QuickJSWASMModule} instance returned by {@link getQuickJS}, as long as
|
||||
* least once.
|
||||
* @throws If called before `getQuickJS` resolves.
|
||||
*/
|
||||
function getQuickJSSync() {
|
||||
if (!singleton) {
|
||||
throw new Error("QuickJS not initialized. Await getQuickJS() at least once.");
|
||||
}
|
||||
return singleton;
|
||||
}
|
||||
exports.getQuickJSSync = getQuickJSSync;
|
||||
/**
|
||||
* Create a new [[QuickJSAsyncRuntime]] in a separate WebAssembly module.
|
||||
*
|
||||
* Each runtime is isolated in a separate WebAssembly module, so that errors in
|
||||
* one runtime cannot contaminate another runtime, and each runtime can execute
|
||||
* an asynchronous action without conflicts.
|
||||
*
|
||||
* Note that there is a hard limit on the number of WebAssembly modules in older
|
||||
* versions of v8:
|
||||
* https://bugs.chromium.org/p/v8/issues/detail?id=12076
|
||||
*/
|
||||
async function newAsyncRuntime(options) {
|
||||
const module = await (0, variants_1.newQuickJSAsyncWASMModule)();
|
||||
return module.newRuntime(options);
|
||||
}
|
||||
exports.newAsyncRuntime = newAsyncRuntime;
|
||||
/**
|
||||
* Create a new [[QuickJSAsyncContext]] (with an associated runtime) in an
|
||||
* separate WebAssembly module.
|
||||
*
|
||||
* Each context is isolated in a separate WebAssembly module, so that errors in
|
||||
* one runtime cannot contaminate another runtime, and each runtime can execute
|
||||
* an asynchronous action without conflicts.
|
||||
*
|
||||
* Note that there is a hard limit on the number of WebAssembly modules in older
|
||||
* versions of v8:
|
||||
* https://bugs.chromium.org/p/v8/issues/detail?id=12076
|
||||
*/
|
||||
async function newAsyncContext(options) {
|
||||
const module = await (0, variants_1.newQuickJSAsyncWASMModule)();
|
||||
return module.newContext(options);
|
||||
}
|
||||
exports.newAsyncContext = newAsyncContext;
|
||||
/**
|
||||
* Returns an interrupt handler that interrupts Javascript execution after a deadline time.
|
||||
*
|
||||
* @param deadline - Interrupt execution if it's still running after this time.
|
||||
* Number values are compared against `Date.now()`
|
||||
*/
|
||||
function shouldInterruptAfterDeadline(deadline) {
|
||||
const deadlineAsNumber = typeof deadline === "number" ? deadline : deadline.getTime();
|
||||
return function () {
|
||||
return Date.now() > deadlineAsNumber;
|
||||
};
|
||||
}
|
||||
exports.shouldInterruptAfterDeadline = shouldInterruptAfterDeadline;
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/index.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/index.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
115
node_modules/@tootallnate/quickjs-emscripten/dist/lifetime.d.ts
generated
vendored
Normal file
115
node_modules/@tootallnate/quickjs-emscripten/dist/lifetime.d.ts
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
import { MaybeAsyncBlock } from "./asyncify-helpers";
|
||||
import type { QuickJSHandle } from "./types";
|
||||
/**
|
||||
* An object that can be disposed.
|
||||
* [[Lifetime]] is the canonical implementation of Disposable.
|
||||
* Use [[Scope]] to manage cleaning up multiple disposables.
|
||||
*/
|
||||
export interface Disposable {
|
||||
/**
|
||||
* Dispose of the underlying resources used by this object.
|
||||
*/
|
||||
dispose(): void;
|
||||
/**
|
||||
* @returns true if the object is alive
|
||||
* @returns false after the object has been [[dispose]]d
|
||||
*/
|
||||
alive: boolean;
|
||||
}
|
||||
/**
|
||||
* A lifetime prevents access to a value after the lifetime has been
|
||||
* [[dispose]]ed.
|
||||
*
|
||||
* Typically, quickjs-emscripten uses Lifetimes to protect C memory pointers.
|
||||
*/
|
||||
export declare class Lifetime<T, TCopy = never, Owner = never> implements Disposable {
|
||||
protected readonly _value: T;
|
||||
protected readonly copier?: ((value: T | TCopy) => TCopy) | undefined;
|
||||
protected readonly disposer?: ((value: T | TCopy) => void) | undefined;
|
||||
protected readonly _owner?: Owner | undefined;
|
||||
protected _alive: boolean;
|
||||
protected _constructorStack: string | undefined;
|
||||
/**
|
||||
* When the Lifetime is disposed, it will call `disposer(_value)`. Use the
|
||||
* disposer function to implement whatever cleanup needs to happen at the end
|
||||
* of `value`'s lifetime.
|
||||
*
|
||||
* `_owner` is not used or controlled by the lifetime. It's just metadata for
|
||||
* the creator.
|
||||
*/
|
||||
constructor(_value: T, copier?: ((value: T | TCopy) => TCopy) | undefined, disposer?: ((value: T | TCopy) => void) | undefined, _owner?: Owner | undefined);
|
||||
get alive(): boolean;
|
||||
/**
|
||||
* The value this Lifetime protects. You must never retain the value - it
|
||||
* may become invalid, leading to memory errors.
|
||||
*
|
||||
* @throws If the lifetime has been [[dispose]]d already.
|
||||
*/
|
||||
get value(): T;
|
||||
get owner(): Owner | undefined;
|
||||
get dupable(): boolean;
|
||||
/**
|
||||
* Create a new handle pointing to the same [[value]].
|
||||
*/
|
||||
dup(): Lifetime<TCopy, TCopy, Owner>;
|
||||
/**
|
||||
* Call `map` with this lifetime, then dispose the lifetime.
|
||||
* @return the result of `map(this)`.
|
||||
*/
|
||||
consume<O>(map: (lifetime: this) => O): O;
|
||||
consume<O>(map: (lifetime: QuickJSHandle) => O): O;
|
||||
/**
|
||||
* Dispose of [[value]] and perform cleanup.
|
||||
*/
|
||||
dispose(): void;
|
||||
private assertAlive;
|
||||
}
|
||||
/**
|
||||
* A Lifetime that lives forever. Used for constants.
|
||||
*/
|
||||
export declare class StaticLifetime<T, Owner = never> extends Lifetime<T, T, Owner> {
|
||||
constructor(value: T, owner?: Owner);
|
||||
get dupable(): boolean;
|
||||
dup(): this;
|
||||
dispose(): void;
|
||||
}
|
||||
/**
|
||||
* A Lifetime that does not own its `value`. A WeakLifetime never calls its
|
||||
* `disposer` function, but can be `dup`ed to produce regular lifetimes that
|
||||
* do.
|
||||
*
|
||||
* Used for function arguments.
|
||||
*/
|
||||
export declare class WeakLifetime<T, TCopy = never, Owner = never> extends Lifetime<T, TCopy, Owner> {
|
||||
constructor(value: T, copier?: (value: T | TCopy) => TCopy, disposer?: (value: TCopy) => void, owner?: Owner);
|
||||
dispose(): void;
|
||||
}
|
||||
/**
|
||||
* Scope helps reduce the burden of manually tracking and disposing of
|
||||
* Lifetimes. See [[withScope]]. and [[withScopeAsync]].
|
||||
*/
|
||||
export declare class Scope implements Disposable {
|
||||
/**
|
||||
* Run `block` with a new Scope instance that will be disposed after the block returns.
|
||||
* Inside `block`, call `scope.manage` on each lifetime you create to have the lifetime
|
||||
* automatically disposed after the block returns.
|
||||
*
|
||||
* @warning Do not use with async functions. Instead, use [[withScopeAsync]].
|
||||
*/
|
||||
static withScope<R>(block: (scope: Scope) => R): R;
|
||||
static withScopeMaybeAsync<Return, This, Yielded>(_this: This, block: MaybeAsyncBlock<Return, This, Yielded, [Scope]>): Return | Promise<Return>;
|
||||
/**
|
||||
* Run `block` with a new Scope instance that will be disposed after the
|
||||
* block's returned promise settles. Inside `block`, call `scope.manage` on each
|
||||
* lifetime you create to have the lifetime automatically disposed after the
|
||||
* block returns.
|
||||
*/
|
||||
static withScopeAsync<R>(block: (scope: Scope) => Promise<R>): Promise<R>;
|
||||
private _disposables;
|
||||
/**
|
||||
* Track `lifetime` so that it is disposed when this scope is disposed.
|
||||
*/
|
||||
manage<T extends Disposable>(lifetime: T): T;
|
||||
get alive(): boolean;
|
||||
dispose(): void;
|
||||
}
|
||||
227
node_modules/@tootallnate/quickjs-emscripten/dist/lifetime.js
generated
vendored
Normal file
227
node_modules/@tootallnate/quickjs-emscripten/dist/lifetime.js
generated
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Scope = exports.WeakLifetime = exports.StaticLifetime = exports.Lifetime = void 0;
|
||||
const asyncify_helpers_1 = require("./asyncify-helpers");
|
||||
const debug_1 = require("./debug");
|
||||
const errors_1 = require("./errors");
|
||||
/**
|
||||
* A lifetime prevents access to a value after the lifetime has been
|
||||
* [[dispose]]ed.
|
||||
*
|
||||
* Typically, quickjs-emscripten uses Lifetimes to protect C memory pointers.
|
||||
*/
|
||||
class Lifetime {
|
||||
/**
|
||||
* When the Lifetime is disposed, it will call `disposer(_value)`. Use the
|
||||
* disposer function to implement whatever cleanup needs to happen at the end
|
||||
* of `value`'s lifetime.
|
||||
*
|
||||
* `_owner` is not used or controlled by the lifetime. It's just metadata for
|
||||
* the creator.
|
||||
*/
|
||||
constructor(_value, copier, disposer, _owner) {
|
||||
this._value = _value;
|
||||
this.copier = copier;
|
||||
this.disposer = disposer;
|
||||
this._owner = _owner;
|
||||
this._alive = true;
|
||||
this._constructorStack = debug_1.QTS_DEBUG ? new Error("Lifetime constructed").stack : undefined;
|
||||
}
|
||||
get alive() {
|
||||
return this._alive;
|
||||
}
|
||||
/**
|
||||
* The value this Lifetime protects. You must never retain the value - it
|
||||
* may become invalid, leading to memory errors.
|
||||
*
|
||||
* @throws If the lifetime has been [[dispose]]d already.
|
||||
*/
|
||||
get value() {
|
||||
this.assertAlive();
|
||||
return this._value;
|
||||
}
|
||||
get owner() {
|
||||
return this._owner;
|
||||
}
|
||||
get dupable() {
|
||||
return !!this.copier;
|
||||
}
|
||||
/**
|
||||
* Create a new handle pointing to the same [[value]].
|
||||
*/
|
||||
dup() {
|
||||
this.assertAlive();
|
||||
if (!this.copier) {
|
||||
throw new Error("Non-dupable lifetime");
|
||||
}
|
||||
return new Lifetime(this.copier(this._value), this.copier, this.disposer, this._owner);
|
||||
}
|
||||
consume(map) {
|
||||
this.assertAlive();
|
||||
const result = map(this);
|
||||
this.dispose();
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Dispose of [[value]] and perform cleanup.
|
||||
*/
|
||||
dispose() {
|
||||
this.assertAlive();
|
||||
if (this.disposer) {
|
||||
this.disposer(this._value);
|
||||
}
|
||||
this._alive = false;
|
||||
}
|
||||
assertAlive() {
|
||||
if (!this.alive) {
|
||||
if (this._constructorStack) {
|
||||
throw new errors_1.QuickJSUseAfterFree(`Lifetime not alive\n${this._constructorStack}\nLifetime used`);
|
||||
}
|
||||
throw new errors_1.QuickJSUseAfterFree("Lifetime not alive");
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.Lifetime = Lifetime;
|
||||
/**
|
||||
* A Lifetime that lives forever. Used for constants.
|
||||
*/
|
||||
class StaticLifetime extends Lifetime {
|
||||
constructor(value, owner) {
|
||||
super(value, undefined, undefined, owner);
|
||||
}
|
||||
// Static lifetime doesn't need a copier to be copiable
|
||||
get dupable() {
|
||||
return true;
|
||||
}
|
||||
// Copy returns the same instance.
|
||||
dup() {
|
||||
return this;
|
||||
}
|
||||
// Dispose does nothing.
|
||||
dispose() { }
|
||||
}
|
||||
exports.StaticLifetime = StaticLifetime;
|
||||
/**
|
||||
* A Lifetime that does not own its `value`. A WeakLifetime never calls its
|
||||
* `disposer` function, but can be `dup`ed to produce regular lifetimes that
|
||||
* do.
|
||||
*
|
||||
* Used for function arguments.
|
||||
*/
|
||||
class WeakLifetime extends Lifetime {
|
||||
constructor(value, copier, disposer, owner) {
|
||||
// We don't care if the disposer doesn't support freeing T
|
||||
super(value, copier, disposer, owner);
|
||||
}
|
||||
dispose() {
|
||||
this._alive = false;
|
||||
}
|
||||
}
|
||||
exports.WeakLifetime = WeakLifetime;
|
||||
function scopeFinally(scope, blockError) {
|
||||
// console.log('scopeFinally', scope, blockError)
|
||||
let disposeError;
|
||||
try {
|
||||
scope.dispose();
|
||||
}
|
||||
catch (error) {
|
||||
disposeError = error;
|
||||
}
|
||||
if (blockError && disposeError) {
|
||||
Object.assign(blockError, {
|
||||
message: `${blockError.message}\n Then, failed to dispose scope: ${disposeError.message}`,
|
||||
disposeError,
|
||||
});
|
||||
throw blockError;
|
||||
}
|
||||
if (blockError || disposeError) {
|
||||
throw blockError || disposeError;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Scope helps reduce the burden of manually tracking and disposing of
|
||||
* Lifetimes. See [[withScope]]. and [[withScopeAsync]].
|
||||
*/
|
||||
class Scope {
|
||||
constructor() {
|
||||
this._disposables = new Lifetime(new Set());
|
||||
}
|
||||
/**
|
||||
* Run `block` with a new Scope instance that will be disposed after the block returns.
|
||||
* Inside `block`, call `scope.manage` on each lifetime you create to have the lifetime
|
||||
* automatically disposed after the block returns.
|
||||
*
|
||||
* @warning Do not use with async functions. Instead, use [[withScopeAsync]].
|
||||
*/
|
||||
static withScope(block) {
|
||||
const scope = new Scope();
|
||||
let blockError;
|
||||
try {
|
||||
return block(scope);
|
||||
}
|
||||
catch (error) {
|
||||
blockError = error;
|
||||
throw error;
|
||||
}
|
||||
finally {
|
||||
scopeFinally(scope, blockError);
|
||||
}
|
||||
}
|
||||
static withScopeMaybeAsync(_this, block) {
|
||||
return (0, asyncify_helpers_1.maybeAsync)(undefined, function* (awaited) {
|
||||
const scope = new Scope();
|
||||
let blockError;
|
||||
try {
|
||||
return yield* awaited.of(block.call(_this, awaited, scope));
|
||||
}
|
||||
catch (error) {
|
||||
blockError = error;
|
||||
throw error;
|
||||
}
|
||||
finally {
|
||||
scopeFinally(scope, blockError);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Run `block` with a new Scope instance that will be disposed after the
|
||||
* block's returned promise settles. Inside `block`, call `scope.manage` on each
|
||||
* lifetime you create to have the lifetime automatically disposed after the
|
||||
* block returns.
|
||||
*/
|
||||
static async withScopeAsync(block) {
|
||||
const scope = new Scope();
|
||||
let blockError;
|
||||
try {
|
||||
return await block(scope);
|
||||
}
|
||||
catch (error) {
|
||||
blockError = error;
|
||||
throw error;
|
||||
}
|
||||
finally {
|
||||
scopeFinally(scope, blockError);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Track `lifetime` so that it is disposed when this scope is disposed.
|
||||
*/
|
||||
manage(lifetime) {
|
||||
this._disposables.value.add(lifetime);
|
||||
return lifetime;
|
||||
}
|
||||
get alive() {
|
||||
return this._disposables.alive;
|
||||
}
|
||||
dispose() {
|
||||
const lifetimes = Array.from(this._disposables.value.values()).reverse();
|
||||
for (const lifetime of lifetimes) {
|
||||
if (lifetime.alive) {
|
||||
lifetime.dispose();
|
||||
}
|
||||
}
|
||||
this._disposables.dispose();
|
||||
}
|
||||
}
|
||||
exports.Scope = Scope;
|
||||
//# sourceMappingURL=lifetime.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/lifetime.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/lifetime.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
18
node_modules/@tootallnate/quickjs-emscripten/dist/memory.d.ts
generated
vendored
Normal file
18
node_modules/@tootallnate/quickjs-emscripten/dist/memory.d.ts
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import { EitherModule } from "./emscripten-types";
|
||||
import { OwnedHeapCharPointer, JSContextPointerPointer, JSValueConstPointerPointer, JSValuePointerPointer } from "./types-ffi";
|
||||
import { Lifetime } from "./lifetime";
|
||||
import { QuickJSHandle } from "./types";
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
export declare class ModuleMemory {
|
||||
module: EitherModule;
|
||||
constructor(module: EitherModule);
|
||||
toPointerArray(handleArray: QuickJSHandle[]): Lifetime<JSValueConstPointerPointer>;
|
||||
newMutablePointerArray<T extends JSContextPointerPointer | JSValuePointerPointer>(length: number): Lifetime<{
|
||||
typedArray: Int32Array;
|
||||
ptr: T;
|
||||
}>;
|
||||
newHeapCharPointer(string: string): Lifetime<OwnedHeapCharPointer>;
|
||||
consumeHeapCharPointer(ptr: OwnedHeapCharPointer): string;
|
||||
}
|
||||
41
node_modules/@tootallnate/quickjs-emscripten/dist/memory.js
generated
vendored
Normal file
41
node_modules/@tootallnate/quickjs-emscripten/dist/memory.js
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ModuleMemory = void 0;
|
||||
const lifetime_1 = require("./lifetime");
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
class ModuleMemory {
|
||||
constructor(module) {
|
||||
this.module = module;
|
||||
}
|
||||
toPointerArray(handleArray) {
|
||||
const typedArray = new Int32Array(handleArray.map((handle) => handle.value));
|
||||
const numBytes = typedArray.length * typedArray.BYTES_PER_ELEMENT;
|
||||
const ptr = this.module._malloc(numBytes);
|
||||
var heapBytes = new Uint8Array(this.module.HEAPU8.buffer, ptr, numBytes);
|
||||
heapBytes.set(new Uint8Array(typedArray.buffer));
|
||||
return new lifetime_1.Lifetime(ptr, undefined, (ptr) => this.module._free(ptr));
|
||||
}
|
||||
newMutablePointerArray(length) {
|
||||
const zeros = new Int32Array(new Array(length).fill(0));
|
||||
const numBytes = zeros.length * zeros.BYTES_PER_ELEMENT;
|
||||
const ptr = this.module._malloc(numBytes);
|
||||
const typedArray = new Int32Array(this.module.HEAPU8.buffer, ptr, length);
|
||||
typedArray.set(zeros);
|
||||
return new lifetime_1.Lifetime({ typedArray, ptr }, undefined, (value) => this.module._free(value.ptr));
|
||||
}
|
||||
newHeapCharPointer(string) {
|
||||
const numBytes = this.module.lengthBytesUTF8(string) + 1;
|
||||
const ptr = this.module._malloc(numBytes);
|
||||
this.module.stringToUTF8(string, ptr, numBytes);
|
||||
return new lifetime_1.Lifetime(ptr, undefined, (value) => this.module._free(value));
|
||||
}
|
||||
consumeHeapCharPointer(ptr) {
|
||||
const str = this.module.UTF8ToString(ptr);
|
||||
this.module._free(ptr);
|
||||
return str;
|
||||
}
|
||||
}
|
||||
exports.ModuleMemory = ModuleMemory;
|
||||
//# sourceMappingURL=memory.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/memory.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/memory.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../ts/memory.ts"],"names":[],"mappings":";;;AAOA,yCAAqC;AAGrC;;GAEG;AACH,MAAa,YAAY;IACvB,YAAmB,MAAoB;QAApB,WAAM,GAAN,MAAM,CAAc;IAAG,CAAC;IAE3C,cAAc,CAAC,WAA4B;QACzC,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;QAC5E,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,GAAG,UAAU,CAAC,iBAAiB,CAAA;QACjE,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAA+B,CAAA;QACvE,IAAI,SAAS,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAA;QACxE,SAAS,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAA;QAChD,OAAO,IAAI,mBAAQ,CAAC,GAAG,EAAE,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAA;IACtE,CAAC;IAED,sBAAsB,CACpB,MAAc;QAEd,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;QACvD,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,iBAAiB,CAAA;QACvD,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAM,CAAA;QAC9C,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAA;QACzE,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACrB,OAAO,IAAI,mBAAQ,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAA;IAC9F,CAAC;IAED,kBAAkB,CAAC,MAAc;QAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QACxD,MAAM,GAAG,GAAyB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAyB,CAAA;QACvF,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAA;QAC/C,OAAO,IAAI,mBAAQ,CAAC,GAAG,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAA;IAC1E,CAAC;IAED,sBAAsB,CAAC,GAAyB;QAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAA;QACzC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QACtB,OAAO,GAAG,CAAA;IACZ,CAAC;CACF;AAnCD,oCAmCC","sourcesContent":["import { EitherModule } from \"./emscripten-types\"\nimport {\n OwnedHeapCharPointer,\n JSContextPointerPointer,\n JSValueConstPointerPointer,\n JSValuePointerPointer,\n} from \"./types-ffi\"\nimport { Lifetime } from \"./lifetime\"\nimport { EitherFFI, QuickJSHandle } from \"./types\"\n\n/**\n * @private\n */\nexport class ModuleMemory {\n constructor(public module: EitherModule) {}\n\n toPointerArray(handleArray: QuickJSHandle[]): Lifetime<JSValueConstPointerPointer> {\n const typedArray = new Int32Array(handleArray.map((handle) => handle.value))\n const numBytes = typedArray.length * typedArray.BYTES_PER_ELEMENT\n const ptr = this.module._malloc(numBytes) as JSValueConstPointerPointer\n var heapBytes = new Uint8Array(this.module.HEAPU8.buffer, ptr, numBytes)\n heapBytes.set(new Uint8Array(typedArray.buffer))\n return new Lifetime(ptr, undefined, (ptr) => this.module._free(ptr))\n }\n\n newMutablePointerArray<T extends JSContextPointerPointer | JSValuePointerPointer>(\n length: number\n ): Lifetime<{ typedArray: Int32Array; ptr: T }> {\n const zeros = new Int32Array(new Array(length).fill(0))\n const numBytes = zeros.length * zeros.BYTES_PER_ELEMENT\n const ptr = this.module._malloc(numBytes) as T\n const typedArray = new Int32Array(this.module.HEAPU8.buffer, ptr, length)\n typedArray.set(zeros)\n return new Lifetime({ typedArray, ptr }, undefined, (value) => this.module._free(value.ptr))\n }\n\n newHeapCharPointer(string: string): Lifetime<OwnedHeapCharPointer> {\n const numBytes = this.module.lengthBytesUTF8(string) + 1\n const ptr: OwnedHeapCharPointer = this.module._malloc(numBytes) as OwnedHeapCharPointer\n this.module.stringToUTF8(string, ptr, numBytes)\n return new Lifetime(ptr, undefined, (value) => this.module._free(value))\n }\n\n consumeHeapCharPointer(ptr: OwnedHeapCharPointer): string {\n const str = this.module.UTF8ToString(ptr)\n this.module._free(ptr)\n return str\n }\n}\n"]}
|
||||
53
node_modules/@tootallnate/quickjs-emscripten/dist/module-asyncify.d.ts
generated
vendored
Normal file
53
node_modules/@tootallnate/quickjs-emscripten/dist/module-asyncify.d.ts
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
import { QuickJSAsyncContext } from "./context-asyncify";
|
||||
import { QuickJSAsyncEmscriptenModule } from "./emscripten-types";
|
||||
import { QuickJSAsyncFFI } from "./variants";
|
||||
import { ModuleEvalOptions, QuickJSWASMModule } from "./module";
|
||||
import { QuickJSAsyncRuntime } from "./runtime-asyncify";
|
||||
import { AsyncRuntimeOptions, ContextOptions } from "./types";
|
||||
/**
|
||||
* Asyncified version of [[QuickJSWASMModule]].
|
||||
*
|
||||
* Due to limitations of Emscripten's ASYNCIFY process, only a single async
|
||||
* function call can happen at a time across the entire WebAssembly module.
|
||||
*
|
||||
* That means that all runtimes, contexts, functions, etc created inside this
|
||||
* WebAssembly are limited to a single concurrent async action.
|
||||
* **Multiple concurrent async actions is an error.**
|
||||
*
|
||||
* To allow for multiple concurrent async actions, you must create multiple WebAssembly
|
||||
* modules.
|
||||
*/
|
||||
export declare class QuickJSAsyncWASMModule extends QuickJSWASMModule {
|
||||
/** @private */
|
||||
protected ffi: QuickJSAsyncFFI;
|
||||
/** @private */
|
||||
protected module: QuickJSAsyncEmscriptenModule;
|
||||
/** @private */
|
||||
constructor(module: QuickJSAsyncEmscriptenModule, ffi: QuickJSAsyncFFI);
|
||||
/**
|
||||
* Create a new async runtime inside this WebAssembly module. All runtimes inside a
|
||||
* module are limited to a single async call at a time. For multiple
|
||||
* concurrent async actions, create multiple WebAssembly modules.
|
||||
*/
|
||||
newRuntime(options?: AsyncRuntimeOptions): QuickJSAsyncRuntime;
|
||||
/**
|
||||
* A simplified API to create a new [[QuickJSRuntime]] and a
|
||||
* [[QuickJSContext]] inside that runtime at the same time. The runtime will
|
||||
* be disposed when the context is disposed.
|
||||
*/
|
||||
newContext(options?: ContextOptions): QuickJSAsyncContext;
|
||||
/** Synchronous evalCode is not supported. */
|
||||
evalCode(): never;
|
||||
/**
|
||||
* One-off evaluate code without needing to create a [[QuickJSRuntimeAsync]] or
|
||||
* [[QuickJSContextSync]] explicitly.
|
||||
*
|
||||
* This version allows for asynchronous Ecmascript module loading.
|
||||
*
|
||||
* Note that only a single async action can occur at a time inside the entire WebAssembly module.
|
||||
* **Multiple concurrent async actions is an error.**
|
||||
*
|
||||
* See the documentation for [[QuickJSWASMModule.evalCode]] for more details.
|
||||
*/
|
||||
evalCodeAsync(code: string, options: ModuleEvalOptions): Promise<unknown>;
|
||||
}
|
||||
97
node_modules/@tootallnate/quickjs-emscripten/dist/module-asyncify.js
generated
vendored
Normal file
97
node_modules/@tootallnate/quickjs-emscripten/dist/module-asyncify.js
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.QuickJSAsyncWASMModule = void 0;
|
||||
const errors_1 = require("./errors");
|
||||
const lifetime_1 = require("./lifetime");
|
||||
const module_1 = require("./module");
|
||||
const runtime_asyncify_1 = require("./runtime-asyncify");
|
||||
/**
|
||||
* Asyncified version of [[QuickJSWASMModule]].
|
||||
*
|
||||
* Due to limitations of Emscripten's ASYNCIFY process, only a single async
|
||||
* function call can happen at a time across the entire WebAssembly module.
|
||||
*
|
||||
* That means that all runtimes, contexts, functions, etc created inside this
|
||||
* WebAssembly are limited to a single concurrent async action.
|
||||
* **Multiple concurrent async actions is an error.**
|
||||
*
|
||||
* To allow for multiple concurrent async actions, you must create multiple WebAssembly
|
||||
* modules.
|
||||
*/
|
||||
class QuickJSAsyncWASMModule extends module_1.QuickJSWASMModule {
|
||||
/** @private */
|
||||
constructor(module, ffi) {
|
||||
super(module, ffi);
|
||||
this.ffi = ffi;
|
||||
this.module = module;
|
||||
}
|
||||
/**
|
||||
* Create a new async runtime inside this WebAssembly module. All runtimes inside a
|
||||
* module are limited to a single async call at a time. For multiple
|
||||
* concurrent async actions, create multiple WebAssembly modules.
|
||||
*/
|
||||
newRuntime(options = {}) {
|
||||
const rt = new lifetime_1.Lifetime(this.ffi.QTS_NewRuntime(), undefined, (rt_ptr) => {
|
||||
this.callbacks.deleteRuntime(rt_ptr);
|
||||
this.ffi.QTS_FreeRuntime(rt_ptr);
|
||||
});
|
||||
const runtime = new runtime_asyncify_1.QuickJSAsyncRuntime({
|
||||
module: this.module,
|
||||
ffi: this.ffi,
|
||||
rt,
|
||||
callbacks: this.callbacks,
|
||||
});
|
||||
(0, module_1.applyBaseRuntimeOptions)(runtime, options);
|
||||
if (options.moduleLoader) {
|
||||
runtime.setModuleLoader(options.moduleLoader);
|
||||
}
|
||||
return runtime;
|
||||
}
|
||||
/**
|
||||
* A simplified API to create a new [[QuickJSRuntime]] and a
|
||||
* [[QuickJSContext]] inside that runtime at the same time. The runtime will
|
||||
* be disposed when the context is disposed.
|
||||
*/
|
||||
newContext(options = {}) {
|
||||
const runtime = this.newRuntime();
|
||||
const lifetimes = options.ownedLifetimes ? options.ownedLifetimes.concat([runtime]) : [runtime];
|
||||
const context = runtime.newContext({ ...options, ownedLifetimes: lifetimes });
|
||||
runtime.context = context;
|
||||
return context;
|
||||
}
|
||||
/** Synchronous evalCode is not supported. */
|
||||
evalCode() {
|
||||
throw new errors_1.QuickJSNotImplemented("QuickJSWASMModuleAsyncify.evalCode: use evalCodeAsync instead");
|
||||
}
|
||||
/**
|
||||
* One-off evaluate code without needing to create a [[QuickJSRuntimeAsync]] or
|
||||
* [[QuickJSContextSync]] explicitly.
|
||||
*
|
||||
* This version allows for asynchronous Ecmascript module loading.
|
||||
*
|
||||
* Note that only a single async action can occur at a time inside the entire WebAssembly module.
|
||||
* **Multiple concurrent async actions is an error.**
|
||||
*
|
||||
* See the documentation for [[QuickJSWASMModule.evalCode]] for more details.
|
||||
*/
|
||||
evalCodeAsync(code, options) {
|
||||
// TODO: we should really figure out generator for the Promise monad...
|
||||
return lifetime_1.Scope.withScopeAsync(async (scope) => {
|
||||
const vm = scope.manage(this.newContext());
|
||||
(0, module_1.applyModuleEvalRuntimeOptions)(vm.runtime, options);
|
||||
const result = await vm.evalCodeAsync(code, "eval.js");
|
||||
if (options.memoryLimitBytes !== undefined) {
|
||||
// Remove memory limit so we can dump the result without exceeding it.
|
||||
vm.runtime.setMemoryLimit(-1);
|
||||
}
|
||||
if (result.error) {
|
||||
const error = vm.dump(scope.manage(result.error));
|
||||
throw error;
|
||||
}
|
||||
const value = vm.dump(scope.manage(result.value));
|
||||
return value;
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.QuickJSAsyncWASMModule = QuickJSAsyncWASMModule;
|
||||
//# sourceMappingURL=module-asyncify.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/module-asyncify.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/module-asyncify.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
27
node_modules/@tootallnate/quickjs-emscripten/dist/module-test.d.ts
generated
vendored
Normal file
27
node_modules/@tootallnate/quickjs-emscripten/dist/module-test.d.ts
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
import type { QuickJSContext } from "./context";
|
||||
import type { ModuleEvalOptions, QuickJSWASMModule } from "./module";
|
||||
import type { QuickJSRuntime } from "./runtime";
|
||||
import type { ContextOptions, RuntimeOptions } from "./types";
|
||||
/**
|
||||
* A test wrapper of [[QuickJSWASMModule]] that keeps a reference to each
|
||||
* context or runtime created.
|
||||
*
|
||||
* Call [[disposeAll]] to reset these sets and calls `dispose` on any left alive
|
||||
* (which may throw an error).
|
||||
*
|
||||
* Call [[assertNoMemoryAllocated]] at the end of a test, when you expect that you've
|
||||
* freed all the memory you've ever allocated.
|
||||
*/
|
||||
export declare class TestQuickJSWASMModule implements Pick<QuickJSWASMModule, keyof QuickJSWASMModule> {
|
||||
private parent;
|
||||
contexts: Set<QuickJSContext>;
|
||||
runtimes: Set<QuickJSRuntime>;
|
||||
constructor(parent: QuickJSWASMModule);
|
||||
newRuntime(options?: RuntimeOptions): QuickJSRuntime;
|
||||
newContext(options?: ContextOptions): QuickJSContext;
|
||||
evalCode(code: string, options?: ModuleEvalOptions): unknown;
|
||||
disposeAll(): void;
|
||||
assertNoMemoryAllocated(): void;
|
||||
/** @private */
|
||||
getFFI(): any;
|
||||
}
|
||||
77
node_modules/@tootallnate/quickjs-emscripten/dist/module-test.js
generated
vendored
Normal file
77
node_modules/@tootallnate/quickjs-emscripten/dist/module-test.js
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.TestQuickJSWASMModule = void 0;
|
||||
const errors_1 = require("./errors");
|
||||
const lifetime_1 = require("./lifetime");
|
||||
/**
|
||||
* A test wrapper of [[QuickJSWASMModule]] that keeps a reference to each
|
||||
* context or runtime created.
|
||||
*
|
||||
* Call [[disposeAll]] to reset these sets and calls `dispose` on any left alive
|
||||
* (which may throw an error).
|
||||
*
|
||||
* Call [[assertNoMemoryAllocated]] at the end of a test, when you expect that you've
|
||||
* freed all the memory you've ever allocated.
|
||||
*/
|
||||
class TestQuickJSWASMModule {
|
||||
constructor(parent) {
|
||||
this.parent = parent;
|
||||
this.contexts = new Set();
|
||||
this.runtimes = new Set();
|
||||
}
|
||||
newRuntime(options) {
|
||||
const runtime = this.parent.newRuntime({
|
||||
...options,
|
||||
ownedLifetimes: [
|
||||
new lifetime_1.Lifetime(undefined, undefined, () => this.runtimes.delete(runtime)),
|
||||
...(options?.ownedLifetimes ?? []),
|
||||
],
|
||||
});
|
||||
this.runtimes.add(runtime);
|
||||
return runtime;
|
||||
}
|
||||
newContext(options) {
|
||||
const context = this.parent.newContext({
|
||||
...options,
|
||||
ownedLifetimes: [
|
||||
new lifetime_1.Lifetime(undefined, undefined, () => this.contexts.delete(context)),
|
||||
...(options?.ownedLifetimes ?? []),
|
||||
],
|
||||
});
|
||||
this.contexts.add(context);
|
||||
return context;
|
||||
}
|
||||
evalCode(code, options) {
|
||||
return this.parent.evalCode(code, options);
|
||||
}
|
||||
disposeAll() {
|
||||
const allDisposables = [...this.contexts, ...this.runtimes];
|
||||
this.runtimes.clear();
|
||||
this.contexts.clear();
|
||||
allDisposables.forEach((d) => {
|
||||
if (d.alive) {
|
||||
d.dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
assertNoMemoryAllocated() {
|
||||
const leaksDetected = this.getFFI().QTS_RecoverableLeakCheck();
|
||||
if (leaksDetected) {
|
||||
// Note: this is currently only available when building from source
|
||||
// with debug builds.
|
||||
throw new errors_1.QuickJSMemoryLeakDetected("Leak sanitizer detected un-freed memory");
|
||||
}
|
||||
if (this.contexts.size > 0) {
|
||||
throw new errors_1.QuickJSMemoryLeakDetected(`${this.contexts.size} contexts leaked`);
|
||||
}
|
||||
if (this.runtimes.size > 0) {
|
||||
throw new errors_1.QuickJSMemoryLeakDetected(`${this.runtimes.size} runtimes leaked`);
|
||||
}
|
||||
}
|
||||
/** @private */
|
||||
getFFI() {
|
||||
return this.parent.getFFI();
|
||||
}
|
||||
}
|
||||
exports.TestQuickJSWASMModule = TestQuickJSWASMModule;
|
||||
//# sourceMappingURL=module-test.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/module-test.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/module-test.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"module-test.js","sourceRoot":"","sources":["../ts/module-test.ts"],"names":[],"mappings":";;;AAIA,qCAAoD;AACpD,yCAAqC;AAErC;;;;;;;;;GASG;AACH,MAAa,qBAAqB;IAGhC,YAAoB,MAAyB;QAAzB,WAAM,GAAN,MAAM,CAAmB;QAF7C,aAAQ,GAAG,IAAI,GAAG,EAAkB,CAAA;QACpC,aAAQ,GAAG,IAAI,GAAG,EAAkB,CAAA;IACY,CAAC;IAEjD,UAAU,CAAC,OAAwB;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;YACrC,GAAG,OAAO;YACV,cAAc,EAAE;gBACd,IAAI,mBAAQ,CAAC,SAAS,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBACvE,GAAG,CAAC,OAAO,EAAE,cAAc,IAAI,EAAE,CAAC;aACnC;SACF,CAAC,CAAA;QACF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QAC1B,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,UAAU,CAAC,OAAwB;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;YACrC,GAAG,OAAO;YACV,cAAc,EAAE;gBACd,IAAI,mBAAQ,CAAC,SAAS,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBACvE,GAAG,CAAC,OAAO,EAAE,cAAc,IAAI,EAAE,CAAC;aACnC;SACF,CAAC,CAAA;QACF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QAC1B,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,QAAQ,CAAC,IAAY,EAAE,OAA2B;QAChD,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IAC5C,CAAC;IAED,UAAU;QACR,MAAM,cAAc,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAA;QAC3D,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAA;QACrB,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAA;QACrB,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;YAC3B,IAAI,CAAC,CAAC,KAAK,EAAE;gBACX,CAAC,CAAC,OAAO,EAAE,CAAA;aACZ;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,uBAAuB;QACrB,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,wBAAwB,EAAE,CAAA;QAC9D,IAAI,aAAa,EAAE;YACjB,mEAAmE;YACnE,qBAAqB;YACrB,MAAM,IAAI,kCAAyB,CAAC,yCAAyC,CAAC,CAAA;SAC/E;QAED,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,EAAE;YAC1B,MAAM,IAAI,kCAAyB,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,kBAAkB,CAAC,CAAA;SAC7E;QAED,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,EAAE;YAC1B,MAAM,IAAI,kCAAyB,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,kBAAkB,CAAC,CAAA;SAC7E;IACH,CAAC;IAED,eAAe;IACf,MAAM;QACJ,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAA;IAC7B,CAAC;CACF;AAjED,sDAiEC","sourcesContent":["import type { QuickJSContext } from \"./context\"\nimport type { ModuleEvalOptions, QuickJSWASMModule } from \"./module\"\nimport type { QuickJSRuntime } from \"./runtime\"\nimport type { ContextOptions, RuntimeOptions } from \"./types\"\nimport { QuickJSMemoryLeakDetected } from \"./errors\"\nimport { Lifetime } from \"./lifetime\"\n\n/**\n * A test wrapper of [[QuickJSWASMModule]] that keeps a reference to each\n * context or runtime created.\n *\n * Call [[disposeAll]] to reset these sets and calls `dispose` on any left alive\n * (which may throw an error).\n *\n * Call [[assertNoMemoryAllocated]] at the end of a test, when you expect that you've\n * freed all the memory you've ever allocated.\n */\nexport class TestQuickJSWASMModule implements Pick<QuickJSWASMModule, keyof QuickJSWASMModule> {\n contexts = new Set<QuickJSContext>()\n runtimes = new Set<QuickJSRuntime>()\n constructor(private parent: QuickJSWASMModule) {}\n\n newRuntime(options?: RuntimeOptions): QuickJSRuntime {\n const runtime = this.parent.newRuntime({\n ...options,\n ownedLifetimes: [\n new Lifetime(undefined, undefined, () => this.runtimes.delete(runtime)),\n ...(options?.ownedLifetimes ?? []),\n ],\n })\n this.runtimes.add(runtime)\n return runtime\n }\n\n newContext(options?: ContextOptions): QuickJSContext {\n const context = this.parent.newContext({\n ...options,\n ownedLifetimes: [\n new Lifetime(undefined, undefined, () => this.contexts.delete(context)),\n ...(options?.ownedLifetimes ?? []),\n ],\n })\n this.contexts.add(context)\n return context\n }\n\n evalCode(code: string, options?: ModuleEvalOptions): unknown {\n return this.parent.evalCode(code, options)\n }\n\n disposeAll() {\n const allDisposables = [...this.contexts, ...this.runtimes]\n this.runtimes.clear()\n this.contexts.clear()\n allDisposables.forEach((d) => {\n if (d.alive) {\n d.dispose()\n }\n })\n }\n\n assertNoMemoryAllocated() {\n const leaksDetected = this.getFFI().QTS_RecoverableLeakCheck()\n if (leaksDetected) {\n // Note: this is currently only available when building from source\n // with debug builds.\n throw new QuickJSMemoryLeakDetected(\"Leak sanitizer detected un-freed memory\")\n }\n\n if (this.contexts.size > 0) {\n throw new QuickJSMemoryLeakDetected(`${this.contexts.size} contexts leaked`)\n }\n\n if (this.runtimes.size > 0) {\n throw new QuickJSMemoryLeakDetected(`${this.runtimes.size} runtimes leaked`)\n }\n }\n\n /** @private */\n getFFI() {\n return this.parent.getFFI()\n }\n}\n"]}
|
||||
152
node_modules/@tootallnate/quickjs-emscripten/dist/module.d.ts
generated
vendored
Normal file
152
node_modules/@tootallnate/quickjs-emscripten/dist/module.d.ts
generated
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
import { QuickJSContext } from "./context";
|
||||
import { Asyncify, AsyncifySleepResult, EitherModule, EmscriptenModuleCallbacks } from "./emscripten-types";
|
||||
import { JSContextPointer, JSRuntimePointer } from "./types-ffi";
|
||||
import { InterruptHandler, QuickJSRuntime } from "./runtime";
|
||||
import { ContextOptions, EitherFFI, JSModuleLoader, RuntimeOptions, RuntimeOptionsBase } from "./types";
|
||||
type EmscriptenCallback<BaseArgs extends any[], Result> = (...args: [Asyncify | undefined, ...BaseArgs]) => Result | AsyncifySleepResult<Result>;
|
||||
type MaybeAsyncEmscriptenCallback<T extends EmscriptenCallback<any, any>> = T extends EmscriptenCallback<infer Args, infer Result> ? (...args: Args) => Result | Promise<Result> : never;
|
||||
type MaybeAsyncEmscriptenCallbacks = {
|
||||
[K in keyof EmscriptenModuleCallbacks]: MaybeAsyncEmscriptenCallback<EmscriptenModuleCallbacks[K]>;
|
||||
};
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
export interface ContextCallbacks {
|
||||
callFunction: MaybeAsyncEmscriptenCallbacks["callFunction"];
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
export interface RuntimeCallbacks {
|
||||
shouldInterrupt: MaybeAsyncEmscriptenCallbacks["shouldInterrupt"];
|
||||
loadModuleSource: MaybeAsyncEmscriptenCallbacks["loadModuleSource"];
|
||||
normalizeModule: MaybeAsyncEmscriptenCallbacks["normalizeModule"];
|
||||
}
|
||||
/**
|
||||
* Options for [[QuickJSWASMModule.evalCode]].
|
||||
*/
|
||||
export interface ModuleEvalOptions {
|
||||
/**
|
||||
* Interrupt evaluation if `shouldInterrupt` returns `true`.
|
||||
* See [[shouldInterruptAfterDeadline]].
|
||||
*/
|
||||
shouldInterrupt?: InterruptHandler;
|
||||
/**
|
||||
* Memory limit, in bytes, of WebAssembly heap memory used by the QuickJS VM.
|
||||
*/
|
||||
memoryLimitBytes?: number;
|
||||
/**
|
||||
* Stack size limit for this vm, in bytes
|
||||
* To remove the limit, set to `0`.
|
||||
*/
|
||||
maxStackSizeBytes?: number;
|
||||
/**
|
||||
* Module loader for any `import` statements or expressions.
|
||||
*/
|
||||
moduleLoader?: JSModuleLoader;
|
||||
}
|
||||
/**
|
||||
* We use static functions per module to dispatch runtime or context calls from
|
||||
* C to the host. This class manages the indirection from a specific runtime or
|
||||
* context pointer to the appropriate callback handler.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
export declare class QuickJSModuleCallbacks {
|
||||
private module;
|
||||
private contextCallbacks;
|
||||
private runtimeCallbacks;
|
||||
constructor(module: EitherModule);
|
||||
setRuntimeCallbacks(rt: JSRuntimePointer, callbacks: RuntimeCallbacks): void;
|
||||
deleteRuntime(rt: JSRuntimePointer): void;
|
||||
setContextCallbacks(ctx: JSContextPointer, callbacks: ContextCallbacks): void;
|
||||
deleteContext(ctx: JSContextPointer): void;
|
||||
private suspendedCount;
|
||||
private suspended;
|
||||
private handleAsyncify;
|
||||
private cToHostCallbacks;
|
||||
}
|
||||
/**
|
||||
* Process RuntimeOptions and apply them to a QuickJSRuntime.
|
||||
* @private
|
||||
*/
|
||||
export declare function applyBaseRuntimeOptions(runtime: QuickJSRuntime, options: RuntimeOptionsBase): void;
|
||||
/**
|
||||
* Process ModuleEvalOptions and apply them to a QuickJSRuntime.
|
||||
* @private
|
||||
*/
|
||||
export declare function applyModuleEvalRuntimeOptions<T extends QuickJSRuntime>(runtime: T, options: ModuleEvalOptions): void;
|
||||
/**
|
||||
* This class presents a Javascript interface to QuickJS, a Javascript interpreter
|
||||
* that supports EcmaScript 2020 (ES2020).
|
||||
*
|
||||
* It wraps a single WebAssembly module containing the QuickJS library and
|
||||
* associated helper C code. WebAssembly modules are completely isolated from
|
||||
* each other by the host's WebAssembly runtime. Separate WebAssembly modules
|
||||
* have the most isolation guarantees possible with this library.
|
||||
*
|
||||
* The simplest way to start running code is {@link evalCode}. This shortcut
|
||||
* method will evaluate Javascript safely and return the result as a native
|
||||
* Javascript value.
|
||||
*
|
||||
* For more control over the execution environment, or to interact with values
|
||||
* inside QuickJS, create a context with {@link newContext} or a runtime with
|
||||
* {@link newRuntime}.
|
||||
*/
|
||||
export declare class QuickJSWASMModule {
|
||||
/** @private */
|
||||
protected ffi: EitherFFI;
|
||||
/** @private */
|
||||
protected callbacks: QuickJSModuleCallbacks;
|
||||
/** @private */
|
||||
protected module: EitherModule;
|
||||
/** @private */
|
||||
constructor(module: EitherModule, ffi: EitherFFI);
|
||||
/**
|
||||
* Create a runtime.
|
||||
* Use the runtime to set limits on CPU and memory usage and configure module
|
||||
* loading for one or more [[QuickJSContext]]s inside the runtime.
|
||||
*/
|
||||
newRuntime(options?: RuntimeOptions): QuickJSRuntime;
|
||||
/**
|
||||
* A simplified API to create a new [[QuickJSRuntime]] and a
|
||||
* [[QuickJSContext]] inside that runtime at the same time. The runtime will
|
||||
* be disposed when the context is disposed.
|
||||
*/
|
||||
newContext(options?: ContextOptions): QuickJSContext;
|
||||
/**
|
||||
* One-off evaluate code without needing to create a [[QuickJSRuntime]] or
|
||||
* [[QuickJSContext]] explicitly.
|
||||
*
|
||||
* To protect against infinite loops, use the `shouldInterrupt` option. The
|
||||
* [[shouldInterruptAfterDeadline]] function will create a time-based deadline.
|
||||
*
|
||||
* If you need more control over how the code executes, create a
|
||||
* [[QuickJSRuntime]] (with [[newRuntime]]) or a [[QuickJSContext]] (with
|
||||
* [[newContext]] or [[QuickJSRuntime.newContext]]), and use its
|
||||
* [[QuickJSContext.evalCode]] method.
|
||||
*
|
||||
* Asynchronous callbacks may not run during the first call to `evalCode`. If
|
||||
* you need to work with async code inside QuickJS, create a runtime and use
|
||||
* [[QuickJSRuntime.executePendingJobs]].
|
||||
*
|
||||
* @returns The result is coerced to a native Javascript value using JSON
|
||||
* serialization, so properties and values unsupported by JSON will be dropped.
|
||||
*
|
||||
* @throws If `code` throws during evaluation, the exception will be
|
||||
* converted into a native Javascript value and thrown.
|
||||
*
|
||||
* @throws if `options.shouldInterrupt` interrupted execution, will throw a Error
|
||||
* with name `"InternalError"` and message `"interrupted"`.
|
||||
*/
|
||||
evalCode(code: string, options?: ModuleEvalOptions): unknown;
|
||||
/**
|
||||
* Get a low-level interface to the QuickJS functions in this WebAssembly
|
||||
* module.
|
||||
* @experimental
|
||||
* @unstable No warranty is provided with this API. It could change at any time.
|
||||
* @private
|
||||
*/
|
||||
getFFI(): EitherFFI;
|
||||
}
|
||||
export {};
|
||||
302
node_modules/@tootallnate/quickjs-emscripten/dist/module.js
generated
vendored
Normal file
302
node_modules/@tootallnate/quickjs-emscripten/dist/module.js
generated
vendored
Normal file
@@ -0,0 +1,302 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.QuickJSWASMModule = exports.applyModuleEvalRuntimeOptions = exports.applyBaseRuntimeOptions = exports.QuickJSModuleCallbacks = void 0;
|
||||
const debug_1 = require("./debug");
|
||||
const errors_1 = require("./errors");
|
||||
const lifetime_1 = require("./lifetime");
|
||||
const runtime_1 = require("./runtime");
|
||||
const types_1 = require("./types");
|
||||
class QuickJSEmscriptenModuleCallbacks {
|
||||
constructor(args) {
|
||||
this.callFunction = args.callFunction;
|
||||
this.shouldInterrupt = args.shouldInterrupt;
|
||||
this.loadModuleSource = args.loadModuleSource;
|
||||
this.normalizeModule = args.normalizeModule;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* We use static functions per module to dispatch runtime or context calls from
|
||||
* C to the host. This class manages the indirection from a specific runtime or
|
||||
* context pointer to the appropriate callback handler.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
class QuickJSModuleCallbacks {
|
||||
constructor(module) {
|
||||
this.contextCallbacks = new Map();
|
||||
this.runtimeCallbacks = new Map();
|
||||
this.suspendedCount = 0;
|
||||
this.cToHostCallbacks = new QuickJSEmscriptenModuleCallbacks({
|
||||
callFunction: (asyncify, ctx, this_ptr, argc, argv, fn_id) => this.handleAsyncify(asyncify, () => {
|
||||
try {
|
||||
const vm = this.contextCallbacks.get(ctx);
|
||||
if (!vm) {
|
||||
throw new Error(`QuickJSContext(ctx = ${ctx}) not found for C function call "${fn_id}"`);
|
||||
}
|
||||
return vm.callFunction(ctx, this_ptr, argc, argv, fn_id);
|
||||
}
|
||||
catch (error) {
|
||||
console.error("[C to host error: returning null]", error);
|
||||
return 0;
|
||||
}
|
||||
}),
|
||||
shouldInterrupt: (asyncify, rt) => this.handleAsyncify(asyncify, () => {
|
||||
try {
|
||||
const vm = this.runtimeCallbacks.get(rt);
|
||||
if (!vm) {
|
||||
throw new Error(`QuickJSRuntime(rt = ${rt}) not found for C interrupt`);
|
||||
}
|
||||
return vm.shouldInterrupt(rt);
|
||||
}
|
||||
catch (error) {
|
||||
console.error("[C to host interrupt: returning error]", error);
|
||||
return 1;
|
||||
}
|
||||
}),
|
||||
loadModuleSource: (asyncify, rt, ctx, moduleName) => this.handleAsyncify(asyncify, () => {
|
||||
try {
|
||||
const runtimeCallbacks = this.runtimeCallbacks.get(rt);
|
||||
if (!runtimeCallbacks) {
|
||||
throw new Error(`QuickJSRuntime(rt = ${rt}) not found for C module loader`);
|
||||
}
|
||||
const loadModule = runtimeCallbacks.loadModuleSource;
|
||||
if (!loadModule) {
|
||||
throw new Error(`QuickJSRuntime(rt = ${rt}) does not support module loading`);
|
||||
}
|
||||
return loadModule(rt, ctx, moduleName);
|
||||
}
|
||||
catch (error) {
|
||||
console.error("[C to host module loader error: returning null]", error);
|
||||
return 0;
|
||||
}
|
||||
}),
|
||||
normalizeModule: (asyncify, rt, ctx, moduleBaseName, moduleName) => this.handleAsyncify(asyncify, () => {
|
||||
try {
|
||||
const runtimeCallbacks = this.runtimeCallbacks.get(rt);
|
||||
if (!runtimeCallbacks) {
|
||||
throw new Error(`QuickJSRuntime(rt = ${rt}) not found for C module loader`);
|
||||
}
|
||||
const normalizeModule = runtimeCallbacks.normalizeModule;
|
||||
if (!normalizeModule) {
|
||||
throw new Error(`QuickJSRuntime(rt = ${rt}) does not support module loading`);
|
||||
}
|
||||
return normalizeModule(rt, ctx, moduleBaseName, moduleName);
|
||||
}
|
||||
catch (error) {
|
||||
console.error("[C to host module loader error: returning null]", error);
|
||||
return 0;
|
||||
}
|
||||
}),
|
||||
});
|
||||
this.module = module;
|
||||
this.module.callbacks = this.cToHostCallbacks;
|
||||
}
|
||||
setRuntimeCallbacks(rt, callbacks) {
|
||||
this.runtimeCallbacks.set(rt, callbacks);
|
||||
}
|
||||
deleteRuntime(rt) {
|
||||
this.runtimeCallbacks.delete(rt);
|
||||
}
|
||||
setContextCallbacks(ctx, callbacks) {
|
||||
this.contextCallbacks.set(ctx, callbacks);
|
||||
}
|
||||
deleteContext(ctx) {
|
||||
this.contextCallbacks.delete(ctx);
|
||||
}
|
||||
handleAsyncify(asyncify, fn) {
|
||||
if (asyncify) {
|
||||
// We must always call asyncify.handleSync around our function.
|
||||
// This allows asyncify to resume suspended execution on the second call.
|
||||
// Asyncify internally can detect sync behavior, and avoid suspending.
|
||||
return asyncify.handleSleep((done) => {
|
||||
try {
|
||||
const result = fn();
|
||||
if (!(result instanceof Promise)) {
|
||||
(0, debug_1.debugLog)("asyncify.handleSleep: not suspending:", result);
|
||||
done(result);
|
||||
return;
|
||||
}
|
||||
// Is promise, we intend to suspend.
|
||||
if (this.suspended) {
|
||||
throw new errors_1.QuickJSAsyncifyError(`Already suspended at: ${this.suspended.stack}\nAttempted to suspend at:`);
|
||||
}
|
||||
else {
|
||||
this.suspended = new errors_1.QuickJSAsyncifySuspended(`(${this.suspendedCount++})`);
|
||||
(0, debug_1.debugLog)("asyncify.handleSleep: suspending:", this.suspended);
|
||||
}
|
||||
result.then((resolvedResult) => {
|
||||
this.suspended = undefined;
|
||||
(0, debug_1.debugLog)("asyncify.handleSleep: resolved:", resolvedResult);
|
||||
done(resolvedResult);
|
||||
}, (error) => {
|
||||
(0, debug_1.debugLog)("asyncify.handleSleep: rejected:", error);
|
||||
console.error("QuickJS: cannot handle error in suspended function", error);
|
||||
this.suspended = undefined;
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
(0, debug_1.debugLog)("asyncify.handleSleep: error:", error);
|
||||
this.suspended = undefined;
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
// No asyncify - we should never return a promise.
|
||||
const value = fn();
|
||||
if (value instanceof Promise) {
|
||||
throw new Error("Promise return value not supported in non-asyncify context.");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
exports.QuickJSModuleCallbacks = QuickJSModuleCallbacks;
|
||||
/**
|
||||
* Process RuntimeOptions and apply them to a QuickJSRuntime.
|
||||
* @private
|
||||
*/
|
||||
function applyBaseRuntimeOptions(runtime, options) {
|
||||
if (options.interruptHandler) {
|
||||
runtime.setInterruptHandler(options.interruptHandler);
|
||||
}
|
||||
if (options.maxStackSizeBytes !== undefined) {
|
||||
runtime.setMaxStackSize(options.maxStackSizeBytes);
|
||||
}
|
||||
if (options.memoryLimitBytes !== undefined) {
|
||||
runtime.setMemoryLimit(options.memoryLimitBytes);
|
||||
}
|
||||
}
|
||||
exports.applyBaseRuntimeOptions = applyBaseRuntimeOptions;
|
||||
/**
|
||||
* Process ModuleEvalOptions and apply them to a QuickJSRuntime.
|
||||
* @private
|
||||
*/
|
||||
function applyModuleEvalRuntimeOptions(runtime, options) {
|
||||
if (options.moduleLoader) {
|
||||
runtime.setModuleLoader(options.moduleLoader);
|
||||
}
|
||||
if (options.shouldInterrupt) {
|
||||
runtime.setInterruptHandler(options.shouldInterrupt);
|
||||
}
|
||||
if (options.memoryLimitBytes !== undefined) {
|
||||
runtime.setMemoryLimit(options.memoryLimitBytes);
|
||||
}
|
||||
if (options.maxStackSizeBytes !== undefined) {
|
||||
runtime.setMaxStackSize(options.maxStackSizeBytes);
|
||||
}
|
||||
}
|
||||
exports.applyModuleEvalRuntimeOptions = applyModuleEvalRuntimeOptions;
|
||||
/**
|
||||
* This class presents a Javascript interface to QuickJS, a Javascript interpreter
|
||||
* that supports EcmaScript 2020 (ES2020).
|
||||
*
|
||||
* It wraps a single WebAssembly module containing the QuickJS library and
|
||||
* associated helper C code. WebAssembly modules are completely isolated from
|
||||
* each other by the host's WebAssembly runtime. Separate WebAssembly modules
|
||||
* have the most isolation guarantees possible with this library.
|
||||
*
|
||||
* The simplest way to start running code is {@link evalCode}. This shortcut
|
||||
* method will evaluate Javascript safely and return the result as a native
|
||||
* Javascript value.
|
||||
*
|
||||
* For more control over the execution environment, or to interact with values
|
||||
* inside QuickJS, create a context with {@link newContext} or a runtime with
|
||||
* {@link newRuntime}.
|
||||
*/
|
||||
class QuickJSWASMModule {
|
||||
/** @private */
|
||||
constructor(module, ffi) {
|
||||
this.module = module;
|
||||
this.ffi = ffi;
|
||||
this.callbacks = new QuickJSModuleCallbacks(module);
|
||||
}
|
||||
/**
|
||||
* Create a runtime.
|
||||
* Use the runtime to set limits on CPU and memory usage and configure module
|
||||
* loading for one or more [[QuickJSContext]]s inside the runtime.
|
||||
*/
|
||||
newRuntime(options = {}) {
|
||||
const rt = new lifetime_1.Lifetime(this.ffi.QTS_NewRuntime(), undefined, (rt_ptr) => {
|
||||
this.callbacks.deleteRuntime(rt_ptr);
|
||||
this.ffi.QTS_FreeRuntime(rt_ptr);
|
||||
});
|
||||
const runtime = new runtime_1.QuickJSRuntime({
|
||||
module: this.module,
|
||||
callbacks: this.callbacks,
|
||||
ffi: this.ffi,
|
||||
rt,
|
||||
});
|
||||
applyBaseRuntimeOptions(runtime, options);
|
||||
if (options.moduleLoader) {
|
||||
runtime.setModuleLoader(options.moduleLoader);
|
||||
}
|
||||
return runtime;
|
||||
}
|
||||
/**
|
||||
* A simplified API to create a new [[QuickJSRuntime]] and a
|
||||
* [[QuickJSContext]] inside that runtime at the same time. The runtime will
|
||||
* be disposed when the context is disposed.
|
||||
*/
|
||||
newContext(options = {}) {
|
||||
const runtime = this.newRuntime();
|
||||
const context = runtime.newContext({
|
||||
...options,
|
||||
ownedLifetimes: (0, types_1.concat)(runtime, options.ownedLifetimes),
|
||||
});
|
||||
runtime.context = context;
|
||||
return context;
|
||||
}
|
||||
/**
|
||||
* One-off evaluate code without needing to create a [[QuickJSRuntime]] or
|
||||
* [[QuickJSContext]] explicitly.
|
||||
*
|
||||
* To protect against infinite loops, use the `shouldInterrupt` option. The
|
||||
* [[shouldInterruptAfterDeadline]] function will create a time-based deadline.
|
||||
*
|
||||
* If you need more control over how the code executes, create a
|
||||
* [[QuickJSRuntime]] (with [[newRuntime]]) or a [[QuickJSContext]] (with
|
||||
* [[newContext]] or [[QuickJSRuntime.newContext]]), and use its
|
||||
* [[QuickJSContext.evalCode]] method.
|
||||
*
|
||||
* Asynchronous callbacks may not run during the first call to `evalCode`. If
|
||||
* you need to work with async code inside QuickJS, create a runtime and use
|
||||
* [[QuickJSRuntime.executePendingJobs]].
|
||||
*
|
||||
* @returns The result is coerced to a native Javascript value using JSON
|
||||
* serialization, so properties and values unsupported by JSON will be dropped.
|
||||
*
|
||||
* @throws If `code` throws during evaluation, the exception will be
|
||||
* converted into a native Javascript value and thrown.
|
||||
*
|
||||
* @throws if `options.shouldInterrupt` interrupted execution, will throw a Error
|
||||
* with name `"InternalError"` and message `"interrupted"`.
|
||||
*/
|
||||
evalCode(code, options = {}) {
|
||||
return lifetime_1.Scope.withScope((scope) => {
|
||||
const vm = scope.manage(this.newContext());
|
||||
applyModuleEvalRuntimeOptions(vm.runtime, options);
|
||||
const result = vm.evalCode(code, "eval.js");
|
||||
if (options.memoryLimitBytes !== undefined) {
|
||||
// Remove memory limit so we can dump the result without exceeding it.
|
||||
vm.runtime.setMemoryLimit(-1);
|
||||
}
|
||||
if (result.error) {
|
||||
const error = vm.dump(scope.manage(result.error));
|
||||
throw error;
|
||||
}
|
||||
const value = vm.dump(scope.manage(result.value));
|
||||
return value;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Get a low-level interface to the QuickJS functions in this WebAssembly
|
||||
* module.
|
||||
* @experimental
|
||||
* @unstable No warranty is provided with this API. It could change at any time.
|
||||
* @private
|
||||
*/
|
||||
getFFI() {
|
||||
return this.ffi;
|
||||
}
|
||||
}
|
||||
exports.QuickJSWASMModule = QuickJSWASMModule;
|
||||
//# sourceMappingURL=module.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/module.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/module.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
38
node_modules/@tootallnate/quickjs-emscripten/dist/runtime-asyncify.d.ts
generated
vendored
Normal file
38
node_modules/@tootallnate/quickjs-emscripten/dist/runtime-asyncify.d.ts
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
import { Lifetime } from ".";
|
||||
import { QuickJSAsyncContext } from "./context-asyncify";
|
||||
import { QuickJSAsyncEmscriptenModule } from "./emscripten-types";
|
||||
import { QuickJSAsyncFFI } from "./variants";
|
||||
import { JSContextPointer, JSRuntimePointer } from "./types-ffi";
|
||||
import { QuickJSModuleCallbacks } from "./module";
|
||||
import { QuickJSRuntime } from "./runtime";
|
||||
import { ContextOptions, JSModuleLoaderAsync, JSModuleNormalizerAsync } from "./types";
|
||||
export declare class QuickJSAsyncRuntime extends QuickJSRuntime {
|
||||
context: QuickJSAsyncContext | undefined;
|
||||
/** @private */
|
||||
protected module: QuickJSAsyncEmscriptenModule;
|
||||
/** @private */
|
||||
protected ffi: QuickJSAsyncFFI;
|
||||
/** @private */
|
||||
protected rt: Lifetime<JSRuntimePointer>;
|
||||
/** @private */
|
||||
protected callbacks: QuickJSModuleCallbacks;
|
||||
/** @private */
|
||||
protected contextMap: Map<JSContextPointer, QuickJSAsyncContext>;
|
||||
/** @private */
|
||||
constructor(args: {
|
||||
module: QuickJSAsyncEmscriptenModule;
|
||||
ffi: QuickJSAsyncFFI;
|
||||
rt: Lifetime<JSRuntimePointer>;
|
||||
callbacks: QuickJSModuleCallbacks;
|
||||
});
|
||||
newContext(options?: ContextOptions): QuickJSAsyncContext;
|
||||
setModuleLoader(moduleLoader: JSModuleLoaderAsync, moduleNormalizer?: JSModuleNormalizerAsync): void;
|
||||
/**
|
||||
* Set the max stack size for this runtime in bytes.
|
||||
* To remove the limit, set to `0`.
|
||||
*
|
||||
* Setting this limit also adjusts the global `ASYNCIFY_STACK_SIZE` for the entire {@link QuickJSAsyncWASMModule}.
|
||||
* See the [pull request](https://github.com/justjake/quickjs-emscripten/pull/114) for more details.
|
||||
*/
|
||||
setMaxStackSize(stackSize: number): void;
|
||||
}
|
||||
49
node_modules/@tootallnate/quickjs-emscripten/dist/runtime-asyncify.js
generated
vendored
Normal file
49
node_modules/@tootallnate/quickjs-emscripten/dist/runtime-asyncify.js
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.QuickJSAsyncRuntime = void 0;
|
||||
const _1 = require(".");
|
||||
const context_asyncify_1 = require("./context-asyncify");
|
||||
const runtime_1 = require("./runtime");
|
||||
const types_1 = require("./types");
|
||||
class QuickJSAsyncRuntime extends runtime_1.QuickJSRuntime {
|
||||
/** @private */
|
||||
constructor(args) {
|
||||
super(args);
|
||||
}
|
||||
newContext(options = {}) {
|
||||
if (options.intrinsics && options.intrinsics !== types_1.DefaultIntrinsics) {
|
||||
throw new Error("TODO: Custom intrinsics are not supported yet");
|
||||
}
|
||||
const ctx = new _1.Lifetime(this.ffi.QTS_NewContext(this.rt.value), undefined, (ctx_ptr) => {
|
||||
this.contextMap.delete(ctx_ptr);
|
||||
this.callbacks.deleteContext(ctx_ptr);
|
||||
this.ffi.QTS_FreeContext(ctx_ptr);
|
||||
});
|
||||
const context = new context_asyncify_1.QuickJSAsyncContext({
|
||||
module: this.module,
|
||||
ctx,
|
||||
ffi: this.ffi,
|
||||
rt: this.rt,
|
||||
ownedLifetimes: [],
|
||||
runtime: this,
|
||||
callbacks: this.callbacks,
|
||||
});
|
||||
this.contextMap.set(ctx.value, context);
|
||||
return context;
|
||||
}
|
||||
setModuleLoader(moduleLoader, moduleNormalizer) {
|
||||
super.setModuleLoader(moduleLoader, moduleNormalizer);
|
||||
}
|
||||
/**
|
||||
* Set the max stack size for this runtime in bytes.
|
||||
* To remove the limit, set to `0`.
|
||||
*
|
||||
* Setting this limit also adjusts the global `ASYNCIFY_STACK_SIZE` for the entire {@link QuickJSAsyncWASMModule}.
|
||||
* See the [pull request](https://github.com/justjake/quickjs-emscripten/pull/114) for more details.
|
||||
*/
|
||||
setMaxStackSize(stackSize) {
|
||||
return super.setMaxStackSize(stackSize);
|
||||
}
|
||||
}
|
||||
exports.QuickJSAsyncRuntime = QuickJSAsyncRuntime;
|
||||
//# sourceMappingURL=runtime-asyncify.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/runtime-asyncify.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/runtime-asyncify.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"runtime-asyncify.js","sourceRoot":"","sources":["../ts/runtime-asyncify.ts"],"names":[],"mappings":";;;AACA,wBAA4B;AAC5B,yDAAwD;AAKxD,uCAA0C;AAC1C,mCAOgB;AAEhB,MAAa,mBAAoB,SAAQ,wBAAc;IAcrD,eAAe;IACf,YAAY,IAKX;QACC,KAAK,CAAC,IAAI,CAAC,CAAA;IACb,CAAC;IAEQ,UAAU,CAAC,UAA0B,EAAE;QAC9C,IAAI,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,UAAU,KAAK,yBAAiB,EAAE;YAClE,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;SACjE;QAED,MAAM,GAAG,GAAG,IAAI,WAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE;YACtF,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YAC/B,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;YACrC,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA;QACnC,CAAC,CAAC,CAAA;QAEF,MAAM,OAAO,GAAG,IAAI,sCAAmB,CAAC;YACtC,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,GAAG;YACH,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,cAAc,EAAE,EAAE;YAClB,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAC,CAAA;QACF,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;QAEvC,OAAO,OAAO,CAAA;IAChB,CAAC;IAEe,eAAe,CAC7B,YAAiC,EACjC,gBAA0C;QAE1C,KAAK,CAAC,eAAe,CACnB,YAA8B,EAC9B,gBAAkD,CACnD,CAAA;IACH,CAAC;IAED;;;;;;OAMG;IACa,eAAe,CAAC,SAAiB;QAC/C,OAAO,KAAK,CAAC,eAAe,CAAC,SAAS,CAAC,CAAA;IACzC,CAAC;CACF;AArED,kDAqEC","sourcesContent":["import type { QuickJSAsyncWASMModule } from \"./module-asyncify\"\nimport { Lifetime } from \".\"\nimport { QuickJSAsyncContext } from \"./context-asyncify\"\nimport { QuickJSAsyncEmscriptenModule } from \"./emscripten-types\"\nimport { QuickJSAsyncFFI } from \"./variants\"\nimport { JSContextPointer, JSRuntimePointer } from \"./types-ffi\"\nimport { QuickJSModuleCallbacks } from \"./module\"\nimport { QuickJSRuntime } from \"./runtime\"\nimport {\n ContextOptions,\n DefaultIntrinsics,\n JSModuleLoader,\n JSModuleLoaderAsync,\n JSModuleNormalizer,\n JSModuleNormalizerAsync,\n} from \"./types\"\n\nexport class QuickJSAsyncRuntime extends QuickJSRuntime {\n public context: QuickJSAsyncContext | undefined\n\n /** @private */\n protected declare module: QuickJSAsyncEmscriptenModule\n /** @private */\n protected declare ffi: QuickJSAsyncFFI\n /** @private */\n protected declare rt: Lifetime<JSRuntimePointer>\n /** @private */\n protected declare callbacks: QuickJSModuleCallbacks\n /** @private */\n protected declare contextMap: Map<JSContextPointer, QuickJSAsyncContext>\n\n /** @private */\n constructor(args: {\n module: QuickJSAsyncEmscriptenModule\n ffi: QuickJSAsyncFFI\n rt: Lifetime<JSRuntimePointer>\n callbacks: QuickJSModuleCallbacks\n }) {\n super(args)\n }\n\n override newContext(options: ContextOptions = {}): QuickJSAsyncContext {\n if (options.intrinsics && options.intrinsics !== DefaultIntrinsics) {\n throw new Error(\"TODO: Custom intrinsics are not supported yet\")\n }\n\n const ctx = new Lifetime(this.ffi.QTS_NewContext(this.rt.value), undefined, (ctx_ptr) => {\n this.contextMap.delete(ctx_ptr)\n this.callbacks.deleteContext(ctx_ptr)\n this.ffi.QTS_FreeContext(ctx_ptr)\n })\n\n const context = new QuickJSAsyncContext({\n module: this.module,\n ctx,\n ffi: this.ffi,\n rt: this.rt,\n ownedLifetimes: [],\n runtime: this,\n callbacks: this.callbacks,\n })\n this.contextMap.set(ctx.value, context)\n\n return context\n }\n\n public override setModuleLoader(\n moduleLoader: JSModuleLoaderAsync,\n moduleNormalizer?: JSModuleNormalizerAsync\n ): void {\n super.setModuleLoader(\n moduleLoader as JSModuleLoader,\n moduleNormalizer as JSModuleNormalizer | undefined\n )\n }\n\n /**\n * Set the max stack size for this runtime in bytes.\n * To remove the limit, set to `0`.\n *\n * Setting this limit also adjusts the global `ASYNCIFY_STACK_SIZE` for the entire {@link QuickJSAsyncWASMModule}.\n * See the [pull request](https://github.com/justjake/quickjs-emscripten/pull/114) for more details.\n */\n public override setMaxStackSize(stackSize: number): void {\n return super.setMaxStackSize(stackSize)\n }\n}\n"]}
|
||||
174
node_modules/@tootallnate/quickjs-emscripten/dist/runtime.d.ts
generated
vendored
Normal file
174
node_modules/@tootallnate/quickjs-emscripten/dist/runtime.d.ts
generated
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
import { QuickJSContext } from "./context";
|
||||
import { EitherModule } from "./emscripten-types";
|
||||
import { JSContextPointer, JSRuntimePointer } from "./types-ffi";
|
||||
import { Disposable, Lifetime, Scope } from "./lifetime";
|
||||
import { ModuleMemory } from "./memory";
|
||||
import { QuickJSModuleCallbacks } from "./module";
|
||||
import { ContextOptions, EitherFFI, JSModuleLoader, JSModuleNormalizer, QuickJSHandle } from "./types";
|
||||
import { SuccessOrFail } from "./vm-interface";
|
||||
/**
|
||||
* Callback called regularly while the VM executes code.
|
||||
* Determines if a VM's execution should be interrupted.
|
||||
*
|
||||
* @returns `true` to interrupt JS execution inside the VM.
|
||||
* @returns `false` or `undefined` to continue JS execution inside the VM.
|
||||
*/
|
||||
export type InterruptHandler = (runtime: QuickJSRuntime) => boolean | undefined;
|
||||
/**
|
||||
* Used as an optional for the results of executing pendingJobs.
|
||||
* On success, `value` contains the number of async jobs executed
|
||||
* by the runtime.
|
||||
* @source
|
||||
*/
|
||||
export type ExecutePendingJobsResult = SuccessOrFail<
|
||||
/** Number of jobs successfully executed. */
|
||||
number,
|
||||
/** The error that occurred. */
|
||||
QuickJSHandle & {
|
||||
/** The context where the error occurred. */
|
||||
context: QuickJSContext;
|
||||
}>;
|
||||
/**
|
||||
* A runtime represents a Javascript runtime corresponding to an object heap.
|
||||
* Several runtimes can exist at the same time but they cannot exchange objects.
|
||||
* Inside a given runtime, no multi-threading is supported.
|
||||
*
|
||||
* You can think of separate runtimes like different domains in a browser, and
|
||||
* the contexts within a runtime like the different windows open to the same
|
||||
* domain.
|
||||
*
|
||||
* Create a runtime via {@link QuickJSWASMModule.newRuntime}.
|
||||
*
|
||||
* You should create separate runtime instances for untrusted code from
|
||||
* different sources for isolation. However, stronger isolation is also
|
||||
* available (at the cost of memory usage), by creating separate WebAssembly
|
||||
* modules to further isolate untrusted code.
|
||||
* See {@link newQuickJSWASMModule}.
|
||||
*
|
||||
* Implement memory and CPU constraints with [[setInterruptHandler]]
|
||||
* (called regularly while the interpreter runs), [[setMemoryLimit]], and
|
||||
* [[setMaxStackSize]].
|
||||
* Use [[computeMemoryUsage]] or [[dumpMemoryUsage]] to guide memory limit
|
||||
* tuning.
|
||||
*
|
||||
* Configure ES module loading with [[setModuleLoader]].
|
||||
*/
|
||||
export declare class QuickJSRuntime implements Disposable {
|
||||
/**
|
||||
* If this runtime was created as as part of a context, points to the context
|
||||
* associated with the runtime.
|
||||
*
|
||||
* If this runtime was created stand-alone, this may or may not contain a context.
|
||||
* A context here may be allocated if one is needed by the runtime, eg for [[computeMemoryUsage]].
|
||||
*/
|
||||
context: QuickJSContext | undefined;
|
||||
/** @private */
|
||||
protected module: EitherModule;
|
||||
/** @private */
|
||||
protected memory: ModuleMemory;
|
||||
/** @private */
|
||||
protected ffi: EitherFFI;
|
||||
/** @private */
|
||||
protected rt: Lifetime<JSRuntimePointer>;
|
||||
/** @private */
|
||||
protected callbacks: QuickJSModuleCallbacks;
|
||||
/** @private */
|
||||
protected scope: Scope;
|
||||
/** @private */
|
||||
protected contextMap: Map<JSContextPointer, QuickJSContext>;
|
||||
/** @private */
|
||||
protected moduleLoader: JSModuleLoader | undefined;
|
||||
/** @private */
|
||||
protected moduleNormalizer: JSModuleNormalizer | undefined;
|
||||
/** @private */
|
||||
constructor(args: {
|
||||
module: EitherModule;
|
||||
ffi: EitherFFI;
|
||||
rt: Lifetime<JSRuntimePointer>;
|
||||
callbacks: QuickJSModuleCallbacks;
|
||||
ownedLifetimes?: Disposable[];
|
||||
});
|
||||
get alive(): boolean;
|
||||
dispose(): void;
|
||||
newContext(options?: ContextOptions): QuickJSContext;
|
||||
/**
|
||||
* Set the loader for EcmaScript modules requested by any context in this
|
||||
* runtime.
|
||||
*
|
||||
* The loader can be removed with [[removeModuleLoader]].
|
||||
*/
|
||||
setModuleLoader(moduleLoader: JSModuleLoader, moduleNormalizer?: JSModuleNormalizer): void;
|
||||
/**
|
||||
* Remove the the loader set by [[setModuleLoader]]. This disables module loading.
|
||||
*/
|
||||
removeModuleLoader(): void;
|
||||
/**
|
||||
* In QuickJS, promises and async functions create pendingJobs. These do not execute
|
||||
* immediately and need to be run by calling [[executePendingJobs]].
|
||||
*
|
||||
* @return true if there is at least one pendingJob queued up.
|
||||
*/
|
||||
hasPendingJob(): boolean;
|
||||
private interruptHandler;
|
||||
/**
|
||||
* Set a callback which is regularly called by the QuickJS engine when it is
|
||||
* executing code. This callback can be used to implement an execution
|
||||
* timeout.
|
||||
*
|
||||
* The interrupt handler can be removed with [[removeInterruptHandler]].
|
||||
*/
|
||||
setInterruptHandler(cb: InterruptHandler): void;
|
||||
/**
|
||||
* Remove the interrupt handler, if any.
|
||||
* See [[setInterruptHandler]].
|
||||
*/
|
||||
removeInterruptHandler(): void;
|
||||
/**
|
||||
* Execute pendingJobs on the runtime until `maxJobsToExecute` jobs are
|
||||
* executed (default all pendingJobs), the queue is exhausted, or the runtime
|
||||
* encounters an exception.
|
||||
*
|
||||
* In QuickJS, promises and async functions *inside the runtime* create
|
||||
* pendingJobs. These do not execute immediately and need to triggered to run.
|
||||
*
|
||||
* @param maxJobsToExecute - When negative, run all pending jobs. Otherwise execute
|
||||
* at most `maxJobsToExecute` before returning.
|
||||
*
|
||||
* @return On success, the number of executed jobs. On error, the exception
|
||||
* that stopped execution, and the context it occurred in. Note that
|
||||
* executePendingJobs will not normally return errors thrown inside async
|
||||
* functions or rejected promises. Those errors are available by calling
|
||||
* [[resolvePromise]] on the promise handle returned by the async function.
|
||||
*/
|
||||
executePendingJobs(maxJobsToExecute?: number | void): ExecutePendingJobsResult;
|
||||
/**
|
||||
* Set the max memory this runtime can allocate.
|
||||
* To remove the limit, set to `-1`.
|
||||
*/
|
||||
setMemoryLimit(limitBytes: number): void;
|
||||
/**
|
||||
* Compute memory usage for this runtime. Returns the result as a handle to a
|
||||
* JSValue object. Use [[QuickJSContext.dump]] to convert to a native object.
|
||||
* Calling this method will allocate more memory inside the runtime. The information
|
||||
* is accurate as of just before the call to `computeMemoryUsage`.
|
||||
* For a human-digestible representation, see [[dumpMemoryUsage]].
|
||||
*/
|
||||
computeMemoryUsage(): QuickJSHandle;
|
||||
/**
|
||||
* @returns a human-readable description of memory usage in this runtime.
|
||||
* For programmatic access to this information, see [[computeMemoryUsage]].
|
||||
*/
|
||||
dumpMemoryUsage(): string;
|
||||
/**
|
||||
* Set the max stack size for this runtime, in bytes.
|
||||
* To remove the limit, set to `0`.
|
||||
*/
|
||||
setMaxStackSize(stackSize: number): void;
|
||||
/**
|
||||
* Assert that `handle` is owned by this runtime.
|
||||
* @throws QuickJSWrongOwner if owned by a different runtime.
|
||||
*/
|
||||
assertOwned(handle: QuickJSHandle): void;
|
||||
private getSystemContext;
|
||||
private cToHostCallbacks;
|
||||
}
|
||||
300
node_modules/@tootallnate/quickjs-emscripten/dist/runtime.js
generated
vendored
Normal file
300
node_modules/@tootallnate/quickjs-emscripten/dist/runtime.js
generated
vendored
Normal file
@@ -0,0 +1,300 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.QuickJSRuntime = void 0;
|
||||
const asyncify_helpers_1 = require("./asyncify-helpers");
|
||||
const context_1 = require("./context");
|
||||
const debug_1 = require("./debug");
|
||||
const errors_1 = require("./errors");
|
||||
const lifetime_1 = require("./lifetime");
|
||||
const memory_1 = require("./memory");
|
||||
const types_1 = require("./types");
|
||||
/**
|
||||
* A runtime represents a Javascript runtime corresponding to an object heap.
|
||||
* Several runtimes can exist at the same time but they cannot exchange objects.
|
||||
* Inside a given runtime, no multi-threading is supported.
|
||||
*
|
||||
* You can think of separate runtimes like different domains in a browser, and
|
||||
* the contexts within a runtime like the different windows open to the same
|
||||
* domain.
|
||||
*
|
||||
* Create a runtime via {@link QuickJSWASMModule.newRuntime}.
|
||||
*
|
||||
* You should create separate runtime instances for untrusted code from
|
||||
* different sources for isolation. However, stronger isolation is also
|
||||
* available (at the cost of memory usage), by creating separate WebAssembly
|
||||
* modules to further isolate untrusted code.
|
||||
* See {@link newQuickJSWASMModule}.
|
||||
*
|
||||
* Implement memory and CPU constraints with [[setInterruptHandler]]
|
||||
* (called regularly while the interpreter runs), [[setMemoryLimit]], and
|
||||
* [[setMaxStackSize]].
|
||||
* Use [[computeMemoryUsage]] or [[dumpMemoryUsage]] to guide memory limit
|
||||
* tuning.
|
||||
*
|
||||
* Configure ES module loading with [[setModuleLoader]].
|
||||
*/
|
||||
class QuickJSRuntime {
|
||||
/** @private */
|
||||
constructor(args) {
|
||||
/** @private */
|
||||
this.scope = new lifetime_1.Scope();
|
||||
/** @private */
|
||||
this.contextMap = new Map();
|
||||
this.cToHostCallbacks = {
|
||||
shouldInterrupt: (rt) => {
|
||||
if (rt !== this.rt.value) {
|
||||
throw new Error("QuickJSContext instance received C -> JS interrupt with mismatched rt");
|
||||
}
|
||||
const fn = this.interruptHandler;
|
||||
if (!fn) {
|
||||
throw new Error("QuickJSContext had no interrupt handler");
|
||||
}
|
||||
return fn(this) ? 1 : 0;
|
||||
},
|
||||
loadModuleSource: (0, asyncify_helpers_1.maybeAsyncFn)(this, function* (awaited, rt, ctx, moduleName) {
|
||||
const moduleLoader = this.moduleLoader;
|
||||
if (!moduleLoader) {
|
||||
throw new Error("Runtime has no module loader");
|
||||
}
|
||||
if (rt !== this.rt.value) {
|
||||
throw new Error("Runtime pointer mismatch");
|
||||
}
|
||||
const context = this.contextMap.get(ctx) ??
|
||||
this.newContext({
|
||||
contextPointer: ctx,
|
||||
});
|
||||
try {
|
||||
const result = yield* awaited(moduleLoader(moduleName, context));
|
||||
if (typeof result === "object" && "error" in result && result.error) {
|
||||
(0, debug_1.debugLog)("cToHostLoadModule: loader returned error", result.error);
|
||||
throw result.error;
|
||||
}
|
||||
const moduleSource = typeof result === "string" ? result : "value" in result ? result.value : result;
|
||||
return this.memory.newHeapCharPointer(moduleSource).value;
|
||||
}
|
||||
catch (error) {
|
||||
(0, debug_1.debugLog)("cToHostLoadModule: caught error", error);
|
||||
context.throw(error);
|
||||
return 0;
|
||||
}
|
||||
}),
|
||||
normalizeModule: (0, asyncify_helpers_1.maybeAsyncFn)(this, function* (awaited, rt, ctx, baseModuleName, moduleNameRequest) {
|
||||
const moduleNormalizer = this.moduleNormalizer;
|
||||
if (!moduleNormalizer) {
|
||||
throw new Error("Runtime has no module normalizer");
|
||||
}
|
||||
if (rt !== this.rt.value) {
|
||||
throw new Error("Runtime pointer mismatch");
|
||||
}
|
||||
const context = this.contextMap.get(ctx) ??
|
||||
this.newContext({
|
||||
/* TODO: Does this happen? Are we responsible for disposing? I don't think so */
|
||||
contextPointer: ctx,
|
||||
});
|
||||
try {
|
||||
const result = yield* awaited(moduleNormalizer(baseModuleName, moduleNameRequest, context));
|
||||
if (typeof result === "object" && "error" in result && result.error) {
|
||||
(0, debug_1.debugLog)("cToHostNormalizeModule: normalizer returned error", result.error);
|
||||
throw result.error;
|
||||
}
|
||||
const name = typeof result === "string" ? result : result.value;
|
||||
return context.getMemory(this.rt.value).newHeapCharPointer(name).value;
|
||||
}
|
||||
catch (error) {
|
||||
(0, debug_1.debugLog)("normalizeModule: caught error", error);
|
||||
context.throw(error);
|
||||
return 0;
|
||||
}
|
||||
}),
|
||||
};
|
||||
args.ownedLifetimes?.forEach((lifetime) => this.scope.manage(lifetime));
|
||||
this.module = args.module;
|
||||
this.memory = new memory_1.ModuleMemory(this.module);
|
||||
this.ffi = args.ffi;
|
||||
this.rt = args.rt;
|
||||
this.callbacks = args.callbacks;
|
||||
this.scope.manage(this.rt);
|
||||
this.callbacks.setRuntimeCallbacks(this.rt.value, this.cToHostCallbacks);
|
||||
this.executePendingJobs = this.executePendingJobs.bind(this);
|
||||
}
|
||||
get alive() {
|
||||
return this.scope.alive;
|
||||
}
|
||||
dispose() {
|
||||
return this.scope.dispose();
|
||||
}
|
||||
newContext(options = {}) {
|
||||
if (options.intrinsics && options.intrinsics !== types_1.DefaultIntrinsics) {
|
||||
throw new Error("TODO: Custom intrinsics are not supported yet");
|
||||
}
|
||||
const ctx = new lifetime_1.Lifetime(options.contextPointer || this.ffi.QTS_NewContext(this.rt.value), undefined, (ctx_ptr) => {
|
||||
this.contextMap.delete(ctx_ptr);
|
||||
this.callbacks.deleteContext(ctx_ptr);
|
||||
this.ffi.QTS_FreeContext(ctx_ptr);
|
||||
});
|
||||
const context = new context_1.QuickJSContext({
|
||||
module: this.module,
|
||||
ctx,
|
||||
ffi: this.ffi,
|
||||
rt: this.rt,
|
||||
ownedLifetimes: options.ownedLifetimes,
|
||||
runtime: this,
|
||||
callbacks: this.callbacks,
|
||||
});
|
||||
this.contextMap.set(ctx.value, context);
|
||||
return context;
|
||||
}
|
||||
/**
|
||||
* Set the loader for EcmaScript modules requested by any context in this
|
||||
* runtime.
|
||||
*
|
||||
* The loader can be removed with [[removeModuleLoader]].
|
||||
*/
|
||||
setModuleLoader(moduleLoader, moduleNormalizer) {
|
||||
this.moduleLoader = moduleLoader;
|
||||
this.moduleNormalizer = moduleNormalizer;
|
||||
this.ffi.QTS_RuntimeEnableModuleLoader(this.rt.value, this.moduleNormalizer ? 1 : 0);
|
||||
}
|
||||
/**
|
||||
* Remove the the loader set by [[setModuleLoader]]. This disables module loading.
|
||||
*/
|
||||
removeModuleLoader() {
|
||||
this.moduleLoader = undefined;
|
||||
this.ffi.QTS_RuntimeDisableModuleLoader(this.rt.value);
|
||||
}
|
||||
// Runtime management -------------------------------------------------------
|
||||
/**
|
||||
* In QuickJS, promises and async functions create pendingJobs. These do not execute
|
||||
* immediately and need to be run by calling [[executePendingJobs]].
|
||||
*
|
||||
* @return true if there is at least one pendingJob queued up.
|
||||
*/
|
||||
hasPendingJob() {
|
||||
return Boolean(this.ffi.QTS_IsJobPending(this.rt.value));
|
||||
}
|
||||
/**
|
||||
* Set a callback which is regularly called by the QuickJS engine when it is
|
||||
* executing code. This callback can be used to implement an execution
|
||||
* timeout.
|
||||
*
|
||||
* The interrupt handler can be removed with [[removeInterruptHandler]].
|
||||
*/
|
||||
setInterruptHandler(cb) {
|
||||
const prevInterruptHandler = this.interruptHandler;
|
||||
this.interruptHandler = cb;
|
||||
if (!prevInterruptHandler) {
|
||||
this.ffi.QTS_RuntimeEnableInterruptHandler(this.rt.value);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Remove the interrupt handler, if any.
|
||||
* See [[setInterruptHandler]].
|
||||
*/
|
||||
removeInterruptHandler() {
|
||||
if (this.interruptHandler) {
|
||||
this.ffi.QTS_RuntimeDisableInterruptHandler(this.rt.value);
|
||||
this.interruptHandler = undefined;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Execute pendingJobs on the runtime until `maxJobsToExecute` jobs are
|
||||
* executed (default all pendingJobs), the queue is exhausted, or the runtime
|
||||
* encounters an exception.
|
||||
*
|
||||
* In QuickJS, promises and async functions *inside the runtime* create
|
||||
* pendingJobs. These do not execute immediately and need to triggered to run.
|
||||
*
|
||||
* @param maxJobsToExecute - When negative, run all pending jobs. Otherwise execute
|
||||
* at most `maxJobsToExecute` before returning.
|
||||
*
|
||||
* @return On success, the number of executed jobs. On error, the exception
|
||||
* that stopped execution, and the context it occurred in. Note that
|
||||
* executePendingJobs will not normally return errors thrown inside async
|
||||
* functions or rejected promises. Those errors are available by calling
|
||||
* [[resolvePromise]] on the promise handle returned by the async function.
|
||||
*/
|
||||
executePendingJobs(maxJobsToExecute = -1) {
|
||||
const ctxPtrOut = this.memory.newMutablePointerArray(1);
|
||||
const valuePtr = this.ffi.QTS_ExecutePendingJob(this.rt.value, maxJobsToExecute ?? -1, ctxPtrOut.value.ptr);
|
||||
const ctxPtr = ctxPtrOut.value.typedArray[0];
|
||||
ctxPtrOut.dispose();
|
||||
if (ctxPtr === 0) {
|
||||
// No jobs executed.
|
||||
this.ffi.QTS_FreeValuePointerRuntime(this.rt.value, valuePtr);
|
||||
return { value: 0 };
|
||||
}
|
||||
const context = this.contextMap.get(ctxPtr) ??
|
||||
this.newContext({
|
||||
contextPointer: ctxPtr,
|
||||
});
|
||||
const resultValue = context.getMemory(this.rt.value).heapValueHandle(valuePtr);
|
||||
const typeOfRet = context.typeof(resultValue);
|
||||
if (typeOfRet === "number") {
|
||||
const executedJobs = context.getNumber(resultValue);
|
||||
resultValue.dispose();
|
||||
return { value: executedJobs };
|
||||
}
|
||||
else {
|
||||
const error = Object.assign(resultValue, { context });
|
||||
return {
|
||||
error,
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Set the max memory this runtime can allocate.
|
||||
* To remove the limit, set to `-1`.
|
||||
*/
|
||||
setMemoryLimit(limitBytes) {
|
||||
if (limitBytes < 0 && limitBytes !== -1) {
|
||||
throw new Error("Cannot set memory limit to negative number. To unset, pass -1");
|
||||
}
|
||||
this.ffi.QTS_RuntimeSetMemoryLimit(this.rt.value, limitBytes);
|
||||
}
|
||||
/**
|
||||
* Compute memory usage for this runtime. Returns the result as a handle to a
|
||||
* JSValue object. Use [[QuickJSContext.dump]] to convert to a native object.
|
||||
* Calling this method will allocate more memory inside the runtime. The information
|
||||
* is accurate as of just before the call to `computeMemoryUsage`.
|
||||
* For a human-digestible representation, see [[dumpMemoryUsage]].
|
||||
*/
|
||||
computeMemoryUsage() {
|
||||
const serviceContextMemory = this.getSystemContext().getMemory(this.rt.value);
|
||||
return serviceContextMemory.heapValueHandle(this.ffi.QTS_RuntimeComputeMemoryUsage(this.rt.value, serviceContextMemory.ctx.value));
|
||||
}
|
||||
/**
|
||||
* @returns a human-readable description of memory usage in this runtime.
|
||||
* For programmatic access to this information, see [[computeMemoryUsage]].
|
||||
*/
|
||||
dumpMemoryUsage() {
|
||||
return this.memory.consumeHeapCharPointer(this.ffi.QTS_RuntimeDumpMemoryUsage(this.rt.value));
|
||||
}
|
||||
/**
|
||||
* Set the max stack size for this runtime, in bytes.
|
||||
* To remove the limit, set to `0`.
|
||||
*/
|
||||
setMaxStackSize(stackSize) {
|
||||
if (stackSize < 0) {
|
||||
throw new Error("Cannot set memory limit to negative number. To unset, pass 0.");
|
||||
}
|
||||
this.ffi.QTS_RuntimeSetMaxStackSize(this.rt.value, stackSize);
|
||||
}
|
||||
/**
|
||||
* Assert that `handle` is owned by this runtime.
|
||||
* @throws QuickJSWrongOwner if owned by a different runtime.
|
||||
*/
|
||||
assertOwned(handle) {
|
||||
if (handle.owner && handle.owner.rt !== this.rt) {
|
||||
throw new errors_1.QuickJSWrongOwner(`Handle is not owned by this runtime: ${handle.owner.rt.value} != ${this.rt.value}`);
|
||||
}
|
||||
}
|
||||
getSystemContext() {
|
||||
if (!this.context) {
|
||||
// We own this context and should dispose of it.
|
||||
this.context = this.scope.manage(this.newContext());
|
||||
}
|
||||
return this.context;
|
||||
}
|
||||
}
|
||||
exports.QuickJSRuntime = QuickJSRuntime;
|
||||
//# sourceMappingURL=runtime.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/runtime.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/runtime.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
114
node_modules/@tootallnate/quickjs-emscripten/dist/types-ffi.d.ts
generated
vendored
Normal file
114
node_modules/@tootallnate/quickjs-emscripten/dist/types-ffi.d.ts
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* C pointer to type `CType`. Pointer types are used internally for FFI, but
|
||||
* are not intended for external use.
|
||||
*
|
||||
* @unstable This type is considered private and may change.
|
||||
*/
|
||||
type Pointer<CType extends string> = number & {
|
||||
ctype: CType;
|
||||
};
|
||||
type Brand<T, B> = T & {
|
||||
brand: B;
|
||||
};
|
||||
/**
|
||||
* `JSRuntime*`.
|
||||
*/
|
||||
export type JSRuntimePointer = Pointer<"JSRuntime">;
|
||||
/**
|
||||
* `JSContext*`.
|
||||
*/
|
||||
export type JSContextPointer = Pointer<"JSContext">;
|
||||
/**
|
||||
* `JSContext**`. Used internally for execute pending jobs.
|
||||
*/
|
||||
export type JSContextPointerPointer = Pointer<"JSContext">;
|
||||
/**
|
||||
* `JSModuleDef*`.
|
||||
*/
|
||||
export type JSModuleDefPointer = Pointer<"JSModuleDef">;
|
||||
/**
|
||||
* `JSValue*`.
|
||||
* See [[JSValue]].
|
||||
*/
|
||||
export type JSValuePointer = Pointer<"JSValue">;
|
||||
/**
|
||||
* `JSValueConst*
|
||||
* See [[JSValueConst]] and [[StaticJSValue]].
|
||||
*/
|
||||
export type JSValueConstPointer = Pointer<"JSValueConst">;
|
||||
/**
|
||||
* Used internally for Javascript-to-C function calls.
|
||||
*/
|
||||
export type JSValuePointerPointer = Pointer<"JSValue[]">;
|
||||
/**
|
||||
* Used internally for Javascript-to-C function calls.
|
||||
*/
|
||||
export type JSValueConstPointerPointer = Pointer<"JSValueConst[]">;
|
||||
/**
|
||||
* Used internally for C-to-Javascript function calls.
|
||||
*/
|
||||
/**
|
||||
* Used internally for C-to-Javascript function calls.
|
||||
*/
|
||||
export type QTS_C_To_HostCallbackFuncPointer = Pointer<"C_To_HostCallbackFunc">;
|
||||
/**
|
||||
* Used internally for C-to-Javascript interrupt handlers.
|
||||
*/
|
||||
export type QTS_C_To_HostInterruptFuncPointer = Pointer<"C_To_HostInterruptFunc">;
|
||||
/**
|
||||
* Used internally for C-to-Javascript module loading.
|
||||
*/
|
||||
export type QTS_C_To_HostLoadModuleFuncPointer = Pointer<"C_To_HostLoadModuleFunc">;
|
||||
/**
|
||||
* Used internally for Javascript-to-C calls that may contain strings too large
|
||||
* for the Emscripten stack.
|
||||
*/
|
||||
export type BorrowedHeapCharPointer = Pointer<"const char" | "char" | "js const char">;
|
||||
/**
|
||||
* Used internally for Javascript-to-C calls that may contain strings too large
|
||||
* for the Emscripten stack.
|
||||
*/
|
||||
export type OwnedHeapCharPointer = Pointer<"char">;
|
||||
/**
|
||||
* Used internally for Javascript-to-C calls that may contain strings too large
|
||||
* for the Emscripten stack.
|
||||
*/
|
||||
export type JSBorrowedCharPointer = Pointer<"js const char">;
|
||||
/**
|
||||
* Opaque pointer that was allocated by js_malloc.
|
||||
*/
|
||||
export type JSVoidPointer = Pointer<any>;
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
export type EvalFlags = Brand<number, "EvalFlags">;
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
export type EvalDetectModule = Brand<number, "EvalDetectModule">;
|
||||
export declare function assertSync<Args extends any[], R>(fn: (...args: Args) => R): (...args: Args) => R;
|
||||
/** Bitfield options for JS_Eval() C function. */
|
||||
export declare const EvalFlags: {
|
||||
/** global code (default) */
|
||||
JS_EVAL_TYPE_GLOBAL: number;
|
||||
/** module code */
|
||||
JS_EVAL_TYPE_MODULE: number;
|
||||
/** direct call (internal use) */
|
||||
JS_EVAL_TYPE_DIRECT: number;
|
||||
/** indirect call (internal use) */
|
||||
JS_EVAL_TYPE_INDIRECT: number;
|
||||
JS_EVAL_TYPE_MASK: number;
|
||||
/** force 'strict' mode */
|
||||
JS_EVAL_FLAG_STRICT: number;
|
||||
/** force 'strip' mode */
|
||||
JS_EVAL_FLAG_STRIP: number;
|
||||
/**
|
||||
* compile but do not run. The result is an object with a
|
||||
* JS_TAG_FUNCTION_BYTECODE or JS_TAG_MODULE tag. It can be executed
|
||||
* with JS_EvalFunction().
|
||||
*/
|
||||
JS_EVAL_FLAG_COMPILE_ONLY: number;
|
||||
/** don't include the stack frames before this eval in the Error() backtraces */
|
||||
JS_EVAL_FLAG_BACKTRACE_BARRIER: number;
|
||||
};
|
||||
export {};
|
||||
38
node_modules/@tootallnate/quickjs-emscripten/dist/types-ffi.js
generated
vendored
Normal file
38
node_modules/@tootallnate/quickjs-emscripten/dist/types-ffi.js
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.EvalFlags = exports.assertSync = void 0;
|
||||
function assertSync(fn) {
|
||||
return function mustBeSync(...args) {
|
||||
const result = fn(...args);
|
||||
if (result && typeof result === "object" && result instanceof Promise) {
|
||||
throw new Error("Function unexpectedly returned a Promise");
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
exports.assertSync = assertSync;
|
||||
/** Bitfield options for JS_Eval() C function. */
|
||||
exports.EvalFlags = {
|
||||
/** global code (default) */
|
||||
JS_EVAL_TYPE_GLOBAL: 0 << 0,
|
||||
/** module code */
|
||||
JS_EVAL_TYPE_MODULE: 1 << 0,
|
||||
/** direct call (internal use) */
|
||||
JS_EVAL_TYPE_DIRECT: 2 << 0,
|
||||
/** indirect call (internal use) */
|
||||
JS_EVAL_TYPE_INDIRECT: 3 << 0,
|
||||
JS_EVAL_TYPE_MASK: 3 << 0,
|
||||
/** force 'strict' mode */
|
||||
JS_EVAL_FLAG_STRICT: 1 << 3,
|
||||
/** force 'strip' mode */
|
||||
JS_EVAL_FLAG_STRIP: 1 << 4,
|
||||
/**
|
||||
* compile but do not run. The result is an object with a
|
||||
* JS_TAG_FUNCTION_BYTECODE or JS_TAG_MODULE tag. It can be executed
|
||||
* with JS_EvalFunction().
|
||||
*/
|
||||
JS_EVAL_FLAG_COMPILE_ONLY: 1 << 5,
|
||||
/** don't include the stack frames before this eval in the Error() backtraces */
|
||||
JS_EVAL_FLAG_BACKTRACE_BARRIER: 1 << 6,
|
||||
};
|
||||
//# sourceMappingURL=types-ffi.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/types-ffi.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/types-ffi.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"types-ffi.js","sourceRoot":"","sources":["../ts/types-ffi.ts"],"names":[],"mappings":";;;AAyGA,SAAgB,UAAU,CAAwB,EAAwB;IACxE,OAAO,SAAS,UAAU,CAAC,GAAG,IAAU;QACtC,MAAM,MAAM,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,CAAA;QAC1B,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,YAAY,OAAO,EAAE;YACrE,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAA;SAC5D;QACD,OAAO,MAAM,CAAA;IACf,CAAC,CAAA;AACH,CAAC;AARD,gCAQC;AAED,iDAAiD;AACpC,QAAA,SAAS,GAAG;IACvB,4BAA4B;IAC5B,mBAAmB,EAAE,CAAC,IAAI,CAAC;IAC3B,kBAAkB;IAClB,mBAAmB,EAAE,CAAC,IAAI,CAAC;IAC3B,iCAAiC;IACjC,mBAAmB,EAAE,CAAC,IAAI,CAAC;IAC3B,mCAAmC;IACnC,qBAAqB,EAAE,CAAC,IAAI,CAAC;IAC7B,iBAAiB,EAAE,CAAC,IAAI,CAAC;IACzB,0BAA0B;IAC1B,mBAAmB,EAAE,CAAC,IAAI,CAAC;IAC3B,yBAAyB;IACzB,kBAAkB,EAAE,CAAC,IAAI,CAAC;IAC1B;;;;OAIG;IACH,yBAAyB,EAAE,CAAC,IAAI,CAAC;IACjC,gFAAgF;IAChF,8BAA8B,EAAE,CAAC,IAAI,CAAC;CACvC,CAAA","sourcesContent":["/**\n * C pointer to type `CType`. Pointer types are used internally for FFI, but\n * are not intended for external use.\n *\n * @unstable This type is considered private and may change.\n */\ntype Pointer<CType extends string> = number & { ctype: CType }\n\ntype Brand<T, B> = T & { brand: B }\n\n/**\n * `JSRuntime*`.\n */\nexport type JSRuntimePointer = Pointer<\"JSRuntime\">\n\n/**\n * `JSContext*`.\n */\nexport type JSContextPointer = Pointer<\"JSContext\">\n\n/**\n * `JSContext**`. Used internally for execute pending jobs.\n */\nexport type JSContextPointerPointer = Pointer<\"JSContext\">\n\n/**\n * `JSModuleDef*`.\n */\nexport type JSModuleDefPointer = Pointer<\"JSModuleDef\">\n\n/**\n * `JSValue*`.\n * See [[JSValue]].\n */\nexport type JSValuePointer = Pointer<\"JSValue\">\n\n/**\n * `JSValueConst*\n * See [[JSValueConst]] and [[StaticJSValue]].\n */\nexport type JSValueConstPointer = Pointer<\"JSValueConst\">\n\n/**\n * Used internally for Javascript-to-C function calls.\n */\nexport type JSValuePointerPointer = Pointer<\"JSValue[]\">\n\n/**\n * Used internally for Javascript-to-C function calls.\n */\nexport type JSValueConstPointerPointer = Pointer<\"JSValueConst[]\">\n\n/**\n * Used internally for C-to-Javascript function calls.\n */\n// type JSCFunctionPointer = Pointer<'JSCFunction'>\n\n/**\n * Used internally for C-to-Javascript function calls.\n */\nexport type QTS_C_To_HostCallbackFuncPointer = Pointer<\"C_To_HostCallbackFunc\">\n\n/**\n * Used internally for C-to-Javascript interrupt handlers.\n */\nexport type QTS_C_To_HostInterruptFuncPointer = Pointer<\"C_To_HostInterruptFunc\">\n\n/**\n * Used internally for C-to-Javascript module loading.\n */\nexport type QTS_C_To_HostLoadModuleFuncPointer = Pointer<\"C_To_HostLoadModuleFunc\">\n\n/**\n * Used internally for Javascript-to-C calls that may contain strings too large\n * for the Emscripten stack.\n */\nexport type BorrowedHeapCharPointer = Pointer<\"const char\" | \"char\" | \"js const char\">\n\n/**\n * Used internally for Javascript-to-C calls that may contain strings too large\n * for the Emscripten stack.\n */\nexport type OwnedHeapCharPointer = Pointer<\"char\">\n\n/**\n * Used internally for Javascript-to-C calls that may contain strings too large\n * for the Emscripten stack.\n */\nexport type JSBorrowedCharPointer = Pointer<\"js const char\">\n\n/**\n * Opaque pointer that was allocated by js_malloc.\n */\nexport type JSVoidPointer = Pointer<any>\n\n/**\n * @private\n */\nexport type EvalFlags = Brand<number, \"EvalFlags\">\n\n/**\n * @private\n */\nexport type EvalDetectModule = Brand<number, \"EvalDetectModule\">\n\nexport function assertSync<Args extends any[], R>(fn: (...args: Args) => R): (...args: Args) => R {\n return function mustBeSync(...args: Args): R {\n const result = fn(...args)\n if (result && typeof result === \"object\" && result instanceof Promise) {\n throw new Error(\"Function unexpectedly returned a Promise\")\n }\n return result\n }\n}\n\n/** Bitfield options for JS_Eval() C function. */\nexport const EvalFlags = {\n /** global code (default) */\n JS_EVAL_TYPE_GLOBAL: 0 << 0,\n /** module code */\n JS_EVAL_TYPE_MODULE: 1 << 0,\n /** direct call (internal use) */\n JS_EVAL_TYPE_DIRECT: 2 << 0,\n /** indirect call (internal use) */\n JS_EVAL_TYPE_INDIRECT: 3 << 0,\n JS_EVAL_TYPE_MASK: 3 << 0,\n /** force 'strict' mode */\n JS_EVAL_FLAG_STRICT: 1 << 3,\n /** force 'strip' mode */\n JS_EVAL_FLAG_STRIP: 1 << 4,\n /**\n * compile but do not run. The result is an object with a\n * JS_TAG_FUNCTION_BYTECODE or JS_TAG_MODULE tag. It can be executed\n * with JS_EvalFunction().\n */\n JS_EVAL_FLAG_COMPILE_ONLY: 1 << 5,\n /** don't include the stack frames before this eval in the Error() backtraces */\n JS_EVAL_FLAG_BACKTRACE_BARRIER: 1 << 6,\n}\n"]}
|
||||
158
node_modules/@tootallnate/quickjs-emscripten/dist/types.d.ts
generated
vendored
Normal file
158
node_modules/@tootallnate/quickjs-emscripten/dist/types.d.ts
generated
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
import type { QuickJSFFI, QuickJSAsyncFFI } from "./variants";
|
||||
import type { QuickJSContext } from "./context";
|
||||
import type { SuccessOrFail, VmFunctionImplementation } from "./vm-interface";
|
||||
import type { Disposable, Lifetime } from "./lifetime";
|
||||
import type { QuickJSAsyncContext } from "./context-asyncify";
|
||||
import type { InterruptHandler, QuickJSRuntime } from "./runtime";
|
||||
import { JSContextPointer, JSValueConstPointer, JSValuePointer } from "./types-ffi";
|
||||
export type EitherFFI = QuickJSFFI | QuickJSAsyncFFI;
|
||||
/**
|
||||
* A QuickJSHandle to a constant that will never change, and does not need to
|
||||
* be disposed.
|
||||
*/
|
||||
export type StaticJSValue = Lifetime<JSValueConstPointer, JSValueConstPointer, QuickJSRuntime>;
|
||||
/**
|
||||
* A QuickJSHandle to a borrowed value that does not need to be disposed.
|
||||
*
|
||||
* In QuickJS, a JSValueConst is a "borrowed" reference that isn't owned by the
|
||||
* current scope. That means that the current scope should not `JS_FreeValue`
|
||||
* it, or retain a reference to it after the scope exits, because it may be
|
||||
* freed by its owner.
|
||||
*
|
||||
* quickjs-emscripten takes care of disposing JSValueConst references.
|
||||
*/
|
||||
export type JSValueConst = Lifetime<JSValueConstPointer, JSValuePointer, QuickJSRuntime>;
|
||||
/**
|
||||
* A owned QuickJSHandle that should be disposed or returned.
|
||||
*
|
||||
* The QuickJS interpreter passes Javascript values between functions as
|
||||
* `JSValue` structs that references some internal data. Because passing
|
||||
* structs cross the Empscripten FFI interfaces is bothersome, we use pointers
|
||||
* to these structs instead.
|
||||
*
|
||||
* A JSValue reference is "owned" in its scope. before exiting the scope, it
|
||||
* should be freed, by calling `JS_FreeValue(ctx, js_value)`) or returned from
|
||||
* the scope. We extend that contract - a JSValuePointer (`JSValue*`) must also
|
||||
* be `free`d.
|
||||
*
|
||||
* You can do so from Javascript by calling the .dispose() method.
|
||||
*/
|
||||
export type JSValue = Lifetime<JSValuePointer, JSValuePointer, QuickJSRuntime>;
|
||||
/**
|
||||
* Wraps a C pointer to a QuickJS JSValue, which represents a Javascript value inside
|
||||
* a QuickJS virtual machine.
|
||||
*
|
||||
* Values must not be shared between QuickJSContext instances.
|
||||
* You must dispose of any handles you create by calling the `.dispose()` method.
|
||||
*/
|
||||
export type QuickJSHandle = StaticJSValue | JSValue | JSValueConst;
|
||||
export type JSModuleExport = {
|
||||
type: "function";
|
||||
name: string;
|
||||
implementation: (vm: QuickJSContext) => VmFunctionImplementation<QuickJSHandle>;
|
||||
} | {
|
||||
type: "value";
|
||||
name: string;
|
||||
value: (vm: QuickJSContext) => QuickJSHandle;
|
||||
};
|
||||
export interface JSModuleDefinition {
|
||||
name: string;
|
||||
exports: JSModuleExport[];
|
||||
}
|
||||
export type JSModuleLoadSuccess = string;
|
||||
export type JSModuleLoadFailure = Error | QuickJSHandle;
|
||||
export type JSModuleLoadResult = JSModuleLoadSuccess | SuccessOrFail<JSModuleLoadSuccess, JSModuleLoadFailure>;
|
||||
export interface JSModuleLoaderAsync {
|
||||
/** Load module (async) */
|
||||
(moduleName: string, context: QuickJSAsyncContext): JSModuleLoadResult | Promise<JSModuleLoadResult>;
|
||||
}
|
||||
export interface JSModuleLoader {
|
||||
/** Load module (sync) */
|
||||
(moduleName: string, context: QuickJSContext): JSModuleLoadResult;
|
||||
}
|
||||
export type JSModuleNormalizeSuccess = string;
|
||||
export type JSModuleNormalizeFailure = Error | QuickJSHandle;
|
||||
export type JSModuleNormalizeResult = JSModuleNormalizeSuccess | SuccessOrFail<JSModuleNormalizeSuccess, JSModuleNormalizeFailure>;
|
||||
export interface JSModuleNormalizerAsync {
|
||||
(baseModuleName: string, requestedName: string, vm: QuickJSAsyncContext): JSModuleNormalizeResult | Promise<JSModuleNormalizeResult>;
|
||||
}
|
||||
export interface JSModuleNormalizer extends JSModuleNormalizerAsync {
|
||||
(baseModuleName: string, requestedName: string, vm: QuickJSContext): JSModuleNormalizeResult;
|
||||
}
|
||||
type TODO<hint extends string = "?", typeHint = unknown> = never;
|
||||
declare const UnstableSymbol: unique symbol;
|
||||
export type PartiallyImplemented<T> = never & T & {
|
||||
[UnstableSymbol]: "This feature may unimplemented, broken, throw errors, etc.";
|
||||
};
|
||||
export interface RuntimeOptionsBase {
|
||||
interruptHandler?: InterruptHandler;
|
||||
maxStackSizeBytes?: number;
|
||||
memoryLimitBytes?: number;
|
||||
promiseRejectionHandler?: TODO<"JSHostPromiseRejectionTracker">;
|
||||
runtimeInfo?: TODO<"JS_SetRuntimeInfo", string>;
|
||||
gcThreshold?: TODO<"JS_SetGCThreshold", number>;
|
||||
sharedArrayBufferFunctions?: TODO<"JS_SetJSSharedArrayBufferFunctions", {
|
||||
sab_alloc: TODO;
|
||||
sab_free: TODO;
|
||||
sab_dup: TODO;
|
||||
sab_opaque: TODO;
|
||||
}>;
|
||||
/**
|
||||
* Extra lifetimes the runtime should dispose of after it is destroyed.
|
||||
* @private
|
||||
*/
|
||||
ownedLifetimes?: Disposable[];
|
||||
}
|
||||
export interface RuntimeOptions extends RuntimeOptionsBase {
|
||||
moduleLoader?: JSModuleLoader;
|
||||
}
|
||||
export interface AsyncRuntimeOptions extends RuntimeOptionsBase {
|
||||
moduleLoader?: JSModuleLoaderAsync | JSModuleLoader;
|
||||
}
|
||||
/**
|
||||
* Work in progress.
|
||||
*/
|
||||
export type Intrinsic = "BaseObjects" | "Date" | "Eval" | "StringNormalize" | "RegExp" | "RegExpCompiler" | "JSON" | "Proxy" | "MapSet" | "TypedArrays" | "Promise" | "BigInt" | "BigFloat" | "BigDecimal" | "OperatorOverloading" | "BignumExt";
|
||||
/**
|
||||
* Work in progress.
|
||||
*/
|
||||
export declare const DefaultIntrinsics: unique symbol;
|
||||
export interface ContextOptions {
|
||||
/**
|
||||
* What built-in objects and language features to enable?
|
||||
* If unset, the default intrinsics will be used.
|
||||
* To omit all intrinsics, pass an empty array.
|
||||
*/
|
||||
intrinsics?: PartiallyImplemented<Intrinsic[]> | typeof DefaultIntrinsics;
|
||||
/**
|
||||
* Wrap the provided context instead of constructing a new one.
|
||||
* @private
|
||||
*/
|
||||
contextPointer?: JSContextPointer;
|
||||
/**
|
||||
* Extra lifetimes the context should dispose of after it is destroyed.
|
||||
* @private
|
||||
*/
|
||||
ownedLifetimes?: Disposable[];
|
||||
}
|
||||
export interface ContextEvalOptions {
|
||||
/** Global code (default) */
|
||||
type?: "global" | "module";
|
||||
/** Force "strict" mode */
|
||||
strict?: boolean;
|
||||
/** Force "strip" mode */
|
||||
strip?: boolean;
|
||||
/**
|
||||
* compile but do not run. The result is an object with a
|
||||
* JS_TAG_FUNCTION_BYTECODE or JS_TAG_MODULE tag. It can be executed
|
||||
* with JS_EvalFunction().
|
||||
*/
|
||||
compileOnly?: boolean;
|
||||
/** don't include the stack frames before this eval in the Error() backtraces */
|
||||
backtraceBarrier?: boolean;
|
||||
}
|
||||
/** Convert [[ContextEvalOptions]] to a bitfield flags */
|
||||
export declare function evalOptionsToFlags(evalOptions: ContextEvalOptions | number | undefined): number;
|
||||
export type PromiseExecutor<ResolveT, RejectT> = (resolve: (value: ResolveT | PromiseLike<ResolveT>) => void, reject: (reason: RejectT) => void) => void;
|
||||
export declare function concat<T>(...values: Array<T[] | T | undefined>): T[];
|
||||
export {};
|
||||
58
node_modules/@tootallnate/quickjs-emscripten/dist/types.js
generated
vendored
Normal file
58
node_modules/@tootallnate/quickjs-emscripten/dist/types.js
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.concat = exports.evalOptionsToFlags = exports.DefaultIntrinsics = void 0;
|
||||
const types_ffi_1 = require("./types-ffi");
|
||||
const UnstableSymbol = Symbol("Unstable");
|
||||
// For informational purposes
|
||||
const DefaultIntrinsicsList = [
|
||||
"BaseObjects",
|
||||
"Date",
|
||||
"Eval",
|
||||
"StringNormalize",
|
||||
"RegExp",
|
||||
"JSON",
|
||||
"Proxy",
|
||||
"MapSet",
|
||||
"TypedArrays",
|
||||
"Promise",
|
||||
];
|
||||
/**
|
||||
* Work in progress.
|
||||
*/
|
||||
exports.DefaultIntrinsics = Symbol("DefaultIntrinsics");
|
||||
/** Convert [[ContextEvalOptions]] to a bitfield flags */
|
||||
function evalOptionsToFlags(evalOptions) {
|
||||
if (typeof evalOptions === "number") {
|
||||
return evalOptions;
|
||||
}
|
||||
if (evalOptions === undefined) {
|
||||
return 0;
|
||||
}
|
||||
const { type, strict, strip, compileOnly, backtraceBarrier } = evalOptions;
|
||||
let flags = 0;
|
||||
if (type === "global")
|
||||
flags |= types_ffi_1.EvalFlags.JS_EVAL_TYPE_GLOBAL;
|
||||
if (type === "module")
|
||||
flags |= types_ffi_1.EvalFlags.JS_EVAL_TYPE_MODULE;
|
||||
if (strict)
|
||||
flags |= types_ffi_1.EvalFlags.JS_EVAL_FLAG_STRICT;
|
||||
if (strip)
|
||||
flags |= types_ffi_1.EvalFlags.JS_EVAL_FLAG_STRIP;
|
||||
if (compileOnly)
|
||||
flags |= types_ffi_1.EvalFlags.JS_EVAL_FLAG_COMPILE_ONLY;
|
||||
if (backtraceBarrier)
|
||||
flags |= types_ffi_1.EvalFlags.JS_EVAL_FLAG_BACKTRACE_BARRIER;
|
||||
return flags;
|
||||
}
|
||||
exports.evalOptionsToFlags = evalOptionsToFlags;
|
||||
function concat(...values) {
|
||||
let result = [];
|
||||
for (const value of values) {
|
||||
if (value !== undefined) {
|
||||
result = result.concat(value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
exports.concat = concat;
|
||||
//# sourceMappingURL=types.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/types.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/types.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
113
node_modules/@tootallnate/quickjs-emscripten/dist/variants.d.ts
generated
vendored
Normal file
113
node_modules/@tootallnate/quickjs-emscripten/dist/variants.d.ts
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
import type { QuickJSFFI as ReleaseSyncFFI } from "./generated/ffi.WASM_RELEASE_SYNC";
|
||||
import type { EmscriptenModuleLoader, QuickJSEmscriptenModule, QuickJSAsyncEmscriptenModule } from "./emscripten-types";
|
||||
import type { QuickJSWASMModule } from "./module";
|
||||
import type { QuickJSAsyncWASMModule } from "./module-asyncify";
|
||||
/** @private */
|
||||
export type QuickJSFFI = ReleaseSyncFFI;
|
||||
/** @private */
|
||||
export type QuickJSFFIConstructor = typeof ReleaseSyncFFI;
|
||||
/** @private */
|
||||
export type QuickJSAsyncFFI = any;
|
||||
/** @private */
|
||||
export type QuickJSAsyncFFIConstructor = any;
|
||||
/**
|
||||
* quickjs-emscripten provides multiple build variants of the core WebAssembly
|
||||
* module. These variants are each intended for a different use case.
|
||||
*
|
||||
* To create an instance of the library using a specific build variant, pass the
|
||||
* build variant to {@link newQuickJSWASMModule} or {@link newQuickJSAsyncWASMModule}.
|
||||
*
|
||||
* Synchronous build variants:
|
||||
*
|
||||
* - {@link RELEASE_SYNC} - This is the default synchronous variant, for general purpose use.
|
||||
* - {@link DEBUG_SYNC} - Synchronous build variant for debugging memory leaks.
|
||||
*/
|
||||
export interface SyncBuildVariant {
|
||||
type: "sync";
|
||||
importFFI: () => Promise<QuickJSFFIConstructor>;
|
||||
importModuleLoader: () => Promise<EmscriptenModuleLoader<QuickJSEmscriptenModule>>;
|
||||
}
|
||||
/**
|
||||
* quickjs-emscripten provides multiple build variants of the core WebAssembly
|
||||
* module. These variants are each intended for a different use case.
|
||||
*
|
||||
* To create an instance of the library using a specific build variant, pass the
|
||||
* build variant to {@link newQuickJSWASMModule} or {@link newQuickJSAsyncWASMModule}.
|
||||
*
|
||||
* Asyncified build variants:
|
||||
*
|
||||
* - {@link RELEASE_ASYNC} - This is the default asyncified build variant, for general purpose use.
|
||||
* - {@link DEBUG_ASYNC} - Asyncified build variant with debug logging.
|
||||
*/
|
||||
export interface AsyncBuildVariant {
|
||||
type: "async";
|
||||
importFFI: () => Promise<QuickJSAsyncFFIConstructor>;
|
||||
importModuleLoader: () => Promise<EmscriptenModuleLoader<QuickJSAsyncEmscriptenModule>>;
|
||||
}
|
||||
/**
|
||||
* Create a new, completely isolated WebAssembly module containing the QuickJS library.
|
||||
* See the documentation on [[QuickJSWASMModule]].
|
||||
*
|
||||
* Note that there is a hard limit on the number of WebAssembly modules in older
|
||||
* versions of v8:
|
||||
* https://bugs.chromium.org/p/v8/issues/detail?id=12076
|
||||
*/
|
||||
export declare function newQuickJSWASMModule(
|
||||
/**
|
||||
* Optionally, pass a {@link SyncBuildVariant} to construct a different WebAssembly module.
|
||||
*/
|
||||
variant?: SyncBuildVariant): Promise<QuickJSWASMModule>;
|
||||
/**
|
||||
* Create a new, completely isolated WebAssembly module containing a version of the QuickJS library
|
||||
* compiled with Emscripten's [ASYNCIFY](https://emscripten.org/docs/porting/asyncify.html) transform.
|
||||
*
|
||||
* This version of the library offers features that enable synchronous code
|
||||
* inside the VM to interact with asynchronous code in the host environment.
|
||||
* See the documentation on [[QuickJSAsyncWASMModule]], [[QuickJSAsyncRuntime]],
|
||||
* and [[QuickJSAsyncContext]].
|
||||
*
|
||||
* Note that there is a hard limit on the number of WebAssembly modules in older
|
||||
* versions of v8:
|
||||
* https://bugs.chromium.org/p/v8/issues/detail?id=12076
|
||||
*/
|
||||
export declare function newQuickJSAsyncWASMModule(
|
||||
/**
|
||||
* Optionally, pass a {@link AsyncBuildVariant} to construct a different WebAssembly module.
|
||||
*/
|
||||
variant?: AsyncBuildVariant): Promise<QuickJSAsyncWASMModule>;
|
||||
/**
|
||||
* Helper intended to memoize the creation of a WebAssembly module.
|
||||
* ```typescript
|
||||
* const getDebugModule = memoizePromiseFactory(() => newQuickJSWASMModule(DEBUG_SYNC))
|
||||
* ```
|
||||
*/
|
||||
export declare function memoizePromiseFactory<T>(fn: () => Promise<T>): () => Promise<T>;
|
||||
/**
|
||||
* This build variant is compiled with `-fsanitize=leak`. It instruments all
|
||||
* memory allocations and when combined with sourcemaps, can present stack trace
|
||||
* locations where memory leaks occur.
|
||||
*
|
||||
* See [[TestQuickJSWASMModule]] which provides access to the leak sanitizer via
|
||||
* {@link TestQuickJSWASMModule.assertNoMemoryAllocated}.
|
||||
*
|
||||
* The downside is that it's 100-1000x slower than the other variants.
|
||||
* Suggested use case: automated testing, regression testing, and interactive
|
||||
* debugging.
|
||||
*/
|
||||
export declare const DEBUG_SYNC: SyncBuildVariant;
|
||||
/**
|
||||
* This is the default (synchronous) build variant.
|
||||
* {@link getQuickJS} returns a memoized instance of this build variant.
|
||||
*/
|
||||
export declare const RELEASE_SYNC: SyncBuildVariant;
|
||||
/**
|
||||
* The async debug build variant may or may not have the sanitizer enabled.
|
||||
* It does print a lot of debug logs.
|
||||
*
|
||||
* Suggested use case: interactive debugging only.
|
||||
*/
|
||||
export declare const DEBUG_ASYNC: AsyncBuildVariant;
|
||||
/**
|
||||
* This is the default asyncified build variant.
|
||||
*/
|
||||
export declare const RELEASE_ASYNC: AsyncBuildVariant;
|
||||
169
node_modules/@tootallnate/quickjs-emscripten/dist/variants.js
generated
vendored
Normal file
169
node_modules/@tootallnate/quickjs-emscripten/dist/variants.js
generated
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.RELEASE_ASYNC = exports.DEBUG_ASYNC = exports.RELEASE_SYNC = exports.DEBUG_SYNC = exports.memoizePromiseFactory = exports.newQuickJSAsyncWASMModule = exports.newQuickJSWASMModule = void 0;
|
||||
const esmHelpers_1 = require("./esmHelpers");
|
||||
/**
|
||||
* Create a new, completely isolated WebAssembly module containing the QuickJS library.
|
||||
* See the documentation on [[QuickJSWASMModule]].
|
||||
*
|
||||
* Note that there is a hard limit on the number of WebAssembly modules in older
|
||||
* versions of v8:
|
||||
* https://bugs.chromium.org/p/v8/issues/detail?id=12076
|
||||
*/
|
||||
async function newQuickJSWASMModule(
|
||||
/**
|
||||
* Optionally, pass a {@link SyncBuildVariant} to construct a different WebAssembly module.
|
||||
*/
|
||||
variant = exports.RELEASE_SYNC) {
|
||||
const [wasmModuleLoader, QuickJSFFI, { QuickJSWASMModule }] = await Promise.all([
|
||||
variant.importModuleLoader(),
|
||||
variant.importFFI(),
|
||||
Promise.resolve().then(() => __importStar(require("./module.js"))).then(esmHelpers_1.unwrapTypescript),
|
||||
]);
|
||||
const wasmModule = await wasmModuleLoader();
|
||||
wasmModule.type = "sync";
|
||||
const ffi = new QuickJSFFI(wasmModule);
|
||||
return new QuickJSWASMModule(wasmModule, ffi);
|
||||
}
|
||||
exports.newQuickJSWASMModule = newQuickJSWASMModule;
|
||||
/**
|
||||
* Create a new, completely isolated WebAssembly module containing a version of the QuickJS library
|
||||
* compiled with Emscripten's [ASYNCIFY](https://emscripten.org/docs/porting/asyncify.html) transform.
|
||||
*
|
||||
* This version of the library offers features that enable synchronous code
|
||||
* inside the VM to interact with asynchronous code in the host environment.
|
||||
* See the documentation on [[QuickJSAsyncWASMModule]], [[QuickJSAsyncRuntime]],
|
||||
* and [[QuickJSAsyncContext]].
|
||||
*
|
||||
* Note that there is a hard limit on the number of WebAssembly modules in older
|
||||
* versions of v8:
|
||||
* https://bugs.chromium.org/p/v8/issues/detail?id=12076
|
||||
*/
|
||||
async function newQuickJSAsyncWASMModule(
|
||||
/**
|
||||
* Optionally, pass a {@link AsyncBuildVariant} to construct a different WebAssembly module.
|
||||
*/
|
||||
variant = exports.RELEASE_ASYNC) {
|
||||
const [wasmModuleLoader, QuickJSAsyncFFI, { QuickJSAsyncWASMModule }] = await Promise.all([
|
||||
variant.importModuleLoader(),
|
||||
variant.importFFI(),
|
||||
Promise.resolve().then(() => __importStar(require("./module-asyncify.js"))).then(esmHelpers_1.unwrapTypescript),
|
||||
]);
|
||||
const wasmModule = await wasmModuleLoader();
|
||||
wasmModule.type = "async";
|
||||
const ffi = new QuickJSAsyncFFI(wasmModule);
|
||||
return new QuickJSAsyncWASMModule(wasmModule, ffi);
|
||||
}
|
||||
exports.newQuickJSAsyncWASMModule = newQuickJSAsyncWASMModule;
|
||||
/**
|
||||
* Helper intended to memoize the creation of a WebAssembly module.
|
||||
* ```typescript
|
||||
* const getDebugModule = memoizePromiseFactory(() => newQuickJSWASMModule(DEBUG_SYNC))
|
||||
* ```
|
||||
*/
|
||||
function memoizePromiseFactory(fn) {
|
||||
let promise;
|
||||
return () => {
|
||||
return (promise ?? (promise = fn()));
|
||||
};
|
||||
}
|
||||
exports.memoizePromiseFactory = memoizePromiseFactory;
|
||||
/**
|
||||
* This build variant is compiled with `-fsanitize=leak`. It instruments all
|
||||
* memory allocations and when combined with sourcemaps, can present stack trace
|
||||
* locations where memory leaks occur.
|
||||
*
|
||||
* See [[TestQuickJSWASMModule]] which provides access to the leak sanitizer via
|
||||
* {@link TestQuickJSWASMModule.assertNoMemoryAllocated}.
|
||||
*
|
||||
* The downside is that it's 100-1000x slower than the other variants.
|
||||
* Suggested use case: automated testing, regression testing, and interactive
|
||||
* debugging.
|
||||
*/
|
||||
exports.DEBUG_SYNC = {
|
||||
type: "sync",
|
||||
async importFFI() {
|
||||
throw new Error("not implemented");
|
||||
// const mod = await import("./generated/ffi.WASM_DEBUG_SYNC.js")
|
||||
// return unwrapTypescript(mod).QuickJSFFI
|
||||
},
|
||||
async importModuleLoader() {
|
||||
throw new Error("not implemented");
|
||||
// const mod = await import("./generated/emscripten-module.WASM_DEBUG_SYNC.js")
|
||||
// return unwrapJavascript(mod).default
|
||||
},
|
||||
};
|
||||
/**
|
||||
* This is the default (synchronous) build variant.
|
||||
* {@link getQuickJS} returns a memoized instance of this build variant.
|
||||
*/
|
||||
exports.RELEASE_SYNC = {
|
||||
type: "sync",
|
||||
async importFFI() {
|
||||
const mod = await Promise.resolve().then(() => __importStar(require("./generated/ffi.WASM_RELEASE_SYNC.js")));
|
||||
return (0, esmHelpers_1.unwrapTypescript)(mod).QuickJSFFI;
|
||||
},
|
||||
async importModuleLoader() {
|
||||
const mod = await Promise.resolve().then(() => __importStar(require("./generated/emscripten-module.WASM_RELEASE_SYNC.js")));
|
||||
return (0, esmHelpers_1.unwrapJavascript)(mod);
|
||||
},
|
||||
};
|
||||
/**
|
||||
* The async debug build variant may or may not have the sanitizer enabled.
|
||||
* It does print a lot of debug logs.
|
||||
*
|
||||
* Suggested use case: interactive debugging only.
|
||||
*/
|
||||
exports.DEBUG_ASYNC = {
|
||||
type: "async",
|
||||
async importFFI() {
|
||||
throw new Error("not implemented");
|
||||
// const mod = await import("./generated/ffi.WASM_DEBUG_ASYNCIFY.js")
|
||||
// return unwrapTypescript(mod).QuickJSAsyncFFI
|
||||
},
|
||||
async importModuleLoader() {
|
||||
throw new Error("not implemented");
|
||||
// const mod = await import("./generated/emscripten-module.WASM_DEBUG_ASYNCIFY.js")
|
||||
// return unwrapJavascript(mod).default
|
||||
},
|
||||
};
|
||||
/**
|
||||
* This is the default asyncified build variant.
|
||||
*/
|
||||
exports.RELEASE_ASYNC = {
|
||||
type: "async",
|
||||
async importFFI() {
|
||||
throw new Error("not implemented");
|
||||
// const mod = await import("./generated/ffi.WASM_RELEASE_ASYNCIFY.js")
|
||||
// return unwrapTypescript(mod).QuickJSAsyncFFI
|
||||
},
|
||||
async importModuleLoader() {
|
||||
throw new Error("not implemented");
|
||||
// const mod = await import("./generated/emscripten-module.WASM_RELEASE_ASYNCIFY.js")
|
||||
// return unwrapJavascript(mod).default
|
||||
},
|
||||
};
|
||||
//# sourceMappingURL=variants.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/variants.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/variants.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
68
node_modules/@tootallnate/quickjs-emscripten/dist/vm-interface.d.ts
generated
vendored
Normal file
68
node_modules/@tootallnate/quickjs-emscripten/dist/vm-interface.d.ts
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Used as an optional.
|
||||
* `{ value: S } | { error: E }`.
|
||||
*/
|
||||
export type SuccessOrFail<S, F> = {
|
||||
value: S;
|
||||
error?: undefined;
|
||||
} | {
|
||||
error: F;
|
||||
};
|
||||
export declare function isSuccess<S, F>(successOrFail: SuccessOrFail<S, F>): successOrFail is {
|
||||
value: S;
|
||||
};
|
||||
export declare function isFail<S, F>(successOrFail: SuccessOrFail<S, F>): successOrFail is {
|
||||
error: F;
|
||||
};
|
||||
/**
|
||||
* Used as an optional for results of a Vm call.
|
||||
* `{ value: VmHandle } | { error: VmHandle }`.
|
||||
*/
|
||||
export type VmCallResult<VmHandle> = SuccessOrFail<VmHandle, VmHandle>;
|
||||
/**
|
||||
* A VmFunctionImplementation takes handles as arguments.
|
||||
* It should return a handle, or be void.
|
||||
*
|
||||
* To indicate an exception, a VMs can throw either a handle (transferred
|
||||
* directly) or any other Javascript value (only the poperties `name` and
|
||||
* `message` will be transferred). Or, the VmFunctionImplementation may return
|
||||
* a VmCallResult's `{ error: handle }` error variant.
|
||||
*
|
||||
* VmFunctionImplementation should not free its arguments or its return value.
|
||||
* It should not retain a reference to its return value or thrown error.
|
||||
*/
|
||||
export type VmFunctionImplementation<VmHandle> = (this: VmHandle, ...args: VmHandle[]) => VmHandle | VmCallResult<VmHandle> | void;
|
||||
/**
|
||||
* A minimal interface to a Javascript execution environment.
|
||||
*
|
||||
* Higher-level tools should build over the LowLevelJavascriptVm interface to
|
||||
* share as much as possible between executors.
|
||||
*
|
||||
* From https://www.figma.com/blog/how-we-built-the-figma-plugin-system/
|
||||
*/
|
||||
export interface LowLevelJavascriptVm<VmHandle> {
|
||||
global: VmHandle;
|
||||
undefined: VmHandle;
|
||||
typeof(handle: VmHandle): string;
|
||||
getNumber(handle: VmHandle): number;
|
||||
getString(handle: VmHandle): string;
|
||||
newNumber(value: number): VmHandle;
|
||||
newString(value: string): VmHandle;
|
||||
newObject(prototype?: VmHandle): VmHandle;
|
||||
newFunction(name: string, value: VmFunctionImplementation<VmHandle>): VmHandle;
|
||||
getProp(handle: VmHandle, key: string | VmHandle): VmHandle;
|
||||
setProp(handle: VmHandle, key: string | VmHandle, value: VmHandle): void;
|
||||
defineProp(handle: VmHandle, key: string | VmHandle, descriptor: VmPropertyDescriptor<VmHandle>): void;
|
||||
callFunction(func: VmHandle, thisVal: VmHandle, ...args: VmHandle[]): VmCallResult<VmHandle>;
|
||||
evalCode(code: string, filename?: string): VmCallResult<VmHandle>;
|
||||
}
|
||||
/**
|
||||
* From https://www.figma.com/blog/how-we-built-the-figma-plugin-system/
|
||||
*/
|
||||
export interface VmPropertyDescriptor<VmHandle> {
|
||||
value?: VmHandle;
|
||||
configurable?: boolean;
|
||||
enumerable?: boolean;
|
||||
get?: (this: VmHandle) => VmHandle;
|
||||
set?: (this: VmHandle, value: VmHandle) => void;
|
||||
}
|
||||
12
node_modules/@tootallnate/quickjs-emscripten/dist/vm-interface.js
generated
vendored
Normal file
12
node_modules/@tootallnate/quickjs-emscripten/dist/vm-interface.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.isFail = exports.isSuccess = void 0;
|
||||
function isSuccess(successOrFail) {
|
||||
return "error" in successOrFail === false;
|
||||
}
|
||||
exports.isSuccess = isSuccess;
|
||||
function isFail(successOrFail) {
|
||||
return "error" in successOrFail === true;
|
||||
}
|
||||
exports.isFail = isFail;
|
||||
//# sourceMappingURL=vm-interface.js.map
|
||||
1
node_modules/@tootallnate/quickjs-emscripten/dist/vm-interface.js.map
generated
vendored
Normal file
1
node_modules/@tootallnate/quickjs-emscripten/dist/vm-interface.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"vm-interface.js","sourceRoot":"","sources":["../ts/vm-interface.ts"],"names":[],"mappings":";;;AAaA,SAAgB,SAAS,CAAO,aAAkC;IAChE,OAAO,OAAO,IAAI,aAAa,KAAK,KAAK,CAAA;AAC3C,CAAC;AAFD,8BAEC;AAED,SAAgB,MAAM,CAAO,aAAkC;IAC7D,OAAO,OAAO,IAAI,aAAa,KAAK,IAAI,CAAA;AAC1C,CAAC;AAFD,wBAEC","sourcesContent":["/**\n * Used as an optional.\n * `{ value: S } | { error: E }`.\n */\nexport type SuccessOrFail<S, F> =\n | {\n value: S\n error?: undefined\n }\n | {\n error: F\n }\n\nexport function isSuccess<S, F>(successOrFail: SuccessOrFail<S, F>): successOrFail is { value: S } {\n return \"error\" in successOrFail === false\n}\n\nexport function isFail<S, F>(successOrFail: SuccessOrFail<S, F>): successOrFail is { error: F } {\n return \"error\" in successOrFail === true\n}\n\n/**\n * Used as an optional for results of a Vm call.\n * `{ value: VmHandle } | { error: VmHandle }`.\n */\nexport type VmCallResult<VmHandle> = SuccessOrFail<VmHandle, VmHandle>\n\n/**\n * A VmFunctionImplementation takes handles as arguments.\n * It should return a handle, or be void.\n *\n * To indicate an exception, a VMs can throw either a handle (transferred\n * directly) or any other Javascript value (only the poperties `name` and\n * `message` will be transferred). Or, the VmFunctionImplementation may return\n * a VmCallResult's `{ error: handle }` error variant.\n *\n * VmFunctionImplementation should not free its arguments or its return value.\n * It should not retain a reference to its return value or thrown error.\n */\nexport type VmFunctionImplementation<VmHandle> = (\n this: VmHandle,\n ...args: VmHandle[]\n) => VmHandle | VmCallResult<VmHandle> | void\n\n/**\n * A minimal interface to a Javascript execution environment.\n *\n * Higher-level tools should build over the LowLevelJavascriptVm interface to\n * share as much as possible between executors.\n *\n * From https://www.figma.com/blog/how-we-built-the-figma-plugin-system/\n */\nexport interface LowLevelJavascriptVm<VmHandle> {\n global: VmHandle\n undefined: VmHandle\n\n typeof(handle: VmHandle): string\n\n getNumber(handle: VmHandle): number\n getString(handle: VmHandle): string\n\n newNumber(value: number): VmHandle\n newString(value: string): VmHandle\n newObject(prototype?: VmHandle): VmHandle\n newFunction(name: string, value: VmFunctionImplementation<VmHandle>): VmHandle\n\n // For accessing properties of objects\n getProp(handle: VmHandle, key: string | VmHandle): VmHandle\n setProp(handle: VmHandle, key: string | VmHandle, value: VmHandle): void\n defineProp(\n handle: VmHandle,\n key: string | VmHandle,\n descriptor: VmPropertyDescriptor<VmHandle>\n ): void\n\n callFunction(func: VmHandle, thisVal: VmHandle, ...args: VmHandle[]): VmCallResult<VmHandle>\n evalCode(code: string, filename?: string): VmCallResult<VmHandle>\n}\n\n/**\n * From https://www.figma.com/blog/how-we-built-the-figma-plugin-system/\n */\nexport interface VmPropertyDescriptor<VmHandle> {\n value?: VmHandle\n configurable?: boolean\n enumerable?: boolean\n get?: (this: VmHandle) => VmHandle\n set?: (this: VmHandle, value: VmHandle) => void\n}\n"]}
|
||||
60
node_modules/@tootallnate/quickjs-emscripten/package.json
generated
vendored
Normal file
60
node_modules/@tootallnate/quickjs-emscripten/package.json
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"name": "@tootallnate/quickjs-emscripten",
|
||||
"version": "0.23.0",
|
||||
"main": "dist/index.js",
|
||||
"sideEffects": false,
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"eval",
|
||||
"quickjs",
|
||||
"vm",
|
||||
"interpreter",
|
||||
"runtime",
|
||||
"safe",
|
||||
"emscripten",
|
||||
"wasm"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/justjake/quickjs-emscripten"
|
||||
},
|
||||
"files": [
|
||||
"c/interface.c",
|
||||
"dist/**/*",
|
||||
"!dist/*.test.js",
|
||||
"!dist/*.tsbuildinfo"
|
||||
],
|
||||
"scripts": {
|
||||
"tarball": "make build/quickjs-emscripten.tgz",
|
||||
"clean": "make clean",
|
||||
"tsc": "node_modules/.bin/tsc",
|
||||
"build": "make dist",
|
||||
"doc": "typedoc",
|
||||
"test": "TS_NODE_TRANSPILE_ONLY=true mocha 'ts/**/*.test.ts'",
|
||||
"test-dist": "cd dist && TS_NODE_TRANSPILE_ONLY=true mocha --require source-map-support/register *.test.js",
|
||||
"test-fast": "TEST_NO_ASYNC=true yarn test 'ts/**/*.test.ts'",
|
||||
"test-all": "TEST_LEAK=1 yarn test && TEST_LEAK=1 yarn test-dist",
|
||||
"prettier": "prettier --write .",
|
||||
"prettier-check": "prettier --check .",
|
||||
"update-quickjs": "git subtree pull --prefix=quickjs --squash git@github.com:bellard/quickjs.git master",
|
||||
"smoketest-node": "yarn tarball && ./scripts/smoketest-node.sh",
|
||||
"smoketest-cra": "yarn tarball && ./scripts/smoketest-website.sh"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/emscripten": "^1.38.0",
|
||||
"@types/fs-extra": "^9.0.13",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "^13.1.4",
|
||||
"fs-extra": "^10.0.1",
|
||||
"markserv": "^1.17.4",
|
||||
"mocha": "7.2.0",
|
||||
"node-fetch-commonjs": "^3.1.1",
|
||||
"prettier": "2.8.4",
|
||||
"source-map-support": "^0.5.21",
|
||||
"ts-node": "^10.9.1",
|
||||
"typedoc": "^0.22.0",
|
||||
"typedoc-plugin-inline-sources": "^1.0.1",
|
||||
"typedoc-plugin-markdown": "^3.11.12",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user