From ac8da8f0b7934aab8252cbce2c5f8658aed05e5c Mon Sep 17 00:00:00 2001 From: Jake Teton-Landis Date: Sun, 1 Sep 2024 00:32:03 -0400 Subject: [PATCH] quickjs-for-quickjs --- packages/quickjs-for-quickjs/LICENSE | 21 ++++++++++ packages/quickjs-for-quickjs/README.md | 3 ++ .../quickjs-for-quickjs/example/node-host.mjs | 32 +++++++++++++++ .../example/quickjs-host.mjs | 30 ++++++++++++++ packages/quickjs-for-quickjs/package.json | 39 +++++++++++++++++++ packages/quickjs-for-quickjs/src/index.mts | 18 +++++++++ packages/quickjs-for-quickjs/tsconfig.json | 7 ++++ packages/quickjs-for-quickjs/tsup.config.ts | 8 ++++ .../src/index.ts | 2 +- scripts/prepareVariants.ts | 2 +- 10 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 packages/quickjs-for-quickjs/LICENSE create mode 100644 packages/quickjs-for-quickjs/README.md create mode 100644 packages/quickjs-for-quickjs/example/node-host.mjs create mode 100644 packages/quickjs-for-quickjs/example/quickjs-host.mjs create mode 100644 packages/quickjs-for-quickjs/package.json create mode 100644 packages/quickjs-for-quickjs/src/index.mts create mode 100644 packages/quickjs-for-quickjs/tsconfig.json create mode 100644 packages/quickjs-for-quickjs/tsup.config.ts diff --git a/packages/quickjs-for-quickjs/LICENSE b/packages/quickjs-for-quickjs/LICENSE new file mode 100644 index 00000000..22f51c71 --- /dev/null +++ b/packages/quickjs-for-quickjs/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +quickjs-emscripten copyright (c) 2019-2024 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. diff --git a/packages/quickjs-for-quickjs/README.md b/packages/quickjs-for-quickjs/README.md new file mode 100644 index 00000000..bec5044b --- /dev/null +++ b/packages/quickjs-for-quickjs/README.md @@ -0,0 +1,3 @@ +# quickjs-for-quickjs + +This package is a build of [quickjs-emscripten](https://github.com/justjake/quickjs-emscripten) that can run inside QuickJS or any other JavaScript runtime without WebAssembly support. The QuickJS C library is compiled to Asm.js, and then bundled together with the quickjs-emscripten JavaScript wrapper into a single standalone file with no external dependencies. diff --git a/packages/quickjs-for-quickjs/example/node-host.mjs b/packages/quickjs-for-quickjs/example/node-host.mjs new file mode 100644 index 00000000..d14c96c4 --- /dev/null +++ b/packages/quickjs-for-quickjs/example/node-host.mjs @@ -0,0 +1,32 @@ +import fs from "node:fs/promises" +import module from "node:module" +const require = module.createRequire(import.meta.url) + +const quickjsSource = await fs.readFile(require.resolve("quickjs-for-quickjs"), "utf8") +const exportQuickjsSource = `export default ${JSON.stringify(quickjsSource)}` + +const exampleQuickjsHostSource = await fs.readFile(require.resolve("./quickjs-host.mjs"), "utf8") +const exportExampleQuickjsHostSource = `export default ${JSON.stringify(exampleQuickjsHostSource)}` + +const QuickJS = await import("quickjs-emscripten").then((mod) => mod.getQuickJS()) +const context = QuickJS.newContext() +context.runtime.setModuleLoader((name) => { + if (name === "quickjs-for-quickjs") { + return quickjsSource + } + if (name === "quickjs-for-quickjs-source") { + return exportQuickjsSource + } + if (name === "example-quickjs-host-source") { + return exportExampleQuickjsHostSource + } + return { error: new Error("not found") } +}) +context.setProp( + context.global, + "random", + context.newFunction("random", () => context.newNumber(Math.random())), +) +const promise = context.resolvePromise(context.evalCode(exampleQuickjsHostSource).unwrap()) +context.runtime.executePendingJobs() +console.log("result:", context.dump(await promise)) diff --git a/packages/quickjs-for-quickjs/example/quickjs-host.mjs b/packages/quickjs-for-quickjs/example/quickjs-host.mjs new file mode 100644 index 00000000..18166bb4 --- /dev/null +++ b/packages/quickjs-for-quickjs/example/quickjs-host.mjs @@ -0,0 +1,30 @@ +import quickjsSource from "quickjs-for-quickjs-source" +import exampleQuickjsHostSource from "example-quickjs-host-source" +const QuickJS = await import("quickjs-for-quickjs").then((mod) => mod.getQuickJS()) +const exportQuickjsSource = `export default ${JSON.stringify(quickjsSource)}` +const exportExampleQuickjsHostSource = `export default ${JSON.stringify(exampleQuickjsHostSource)}` + +const context = QuickJS.newContext() +context.runtime.setModuleLoader((name) => { + if (name === "quickjs-for-quickjs") { + return quickjsSource + } + if (name === "quickjs-for-quickjs-source") { + return exportQuickjsSource + } + if (name === "example-quickjs-host-source") { + return exportExampleQuickjsHostSource + } + return { error: new Error("not found") } +}) +context.setProp( + context.global, + "random", + context.newFunction("random", () => context.newNumber(random())), +) + +const codeToEval = + random() > 0.5 ? `export const result = ['hello', 'world'].join(' ')` : exampleQuickjsHostSource +const promise = context.resolvePromise(context.evalCode(codeToEval).unwrap()) +context.runtime.executePendingJobs() +export const result = "hello " + context.dump(await promise) diff --git a/packages/quickjs-for-quickjs/package.json b/packages/quickjs-for-quickjs/package.json new file mode 100644 index 00000000..d37ccee6 --- /dev/null +++ b/packages/quickjs-for-quickjs/package.json @@ -0,0 +1,39 @@ +{ + "name": "quickjs-for-quickjs", + "version": "0.30.0", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/justjake/quickjs-emscripten" + }, + "author": { + "name": "Jake Teton-Landis", + "url": "https://jake.tl" + }, + "scripts": { + "check": "npx tsc --project . --noEmit", + "build": "npx tsup", + "clean": "git clean -fx dist" + }, + "files": [ + "LICENSE", + "example/**", + "dist/**/*" + ], + "types": "dist/index.d.mts", + "main": "dist/index.mjs", + "module": "dist/index.mjs", + "exports": { + "./package.json": "./package.json", + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "default": "./dist/index.mjs" + } + }, + "devDependencies": { + "quickjs-emscripten-core": "workspace:*", + "@jitl/quickjs-asmjs-mjs-release-sync": "workspace:*", + "@jitl/tsconfig": "workspace:*" + } +} diff --git a/packages/quickjs-for-quickjs/src/index.mts b/packages/quickjs-for-quickjs/src/index.mts new file mode 100644 index 00000000..4ca9c583 --- /dev/null +++ b/packages/quickjs-for-quickjs/src/index.mts @@ -0,0 +1,18 @@ +import type { QuickJSWASMModule } from "quickjs-emscripten-core" +import { newQuickJSWASMModuleFromVariant } from "quickjs-emscripten-core" +import RELEASE_SYNC from "@jitl/quickjs-asmjs-mjs-release-sync" + +export * from "quickjs-emscripten-core" + +let promise: Promise | undefined + +export function getQuickJS(): Promise { + return (promise ??= newQuickJSWASMModule()) +} + +export function newQuickJSWASMModule(): Promise { + // TODO: why are the types mad? + return newQuickJSWASMModuleFromVariant(RELEASE_SYNC as any) +} + +export { RELEASE_SYNC } diff --git a/packages/quickjs-for-quickjs/tsconfig.json b/packages/quickjs-for-quickjs/tsconfig.json new file mode 100644 index 00000000..3dd81964 --- /dev/null +++ b/packages/quickjs-for-quickjs/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@jitl/tsconfig/tsconfig.json", + "include": ["src/**/*"], + "compilerOptions": { + "rootDir": "src" + } +} diff --git a/packages/quickjs-for-quickjs/tsup.config.ts b/packages/quickjs-for-quickjs/tsup.config.ts new file mode 100644 index 00000000..0fd61cb6 --- /dev/null +++ b/packages/quickjs-for-quickjs/tsup.config.ts @@ -0,0 +1,8 @@ +import { extendConfig } from "@jitl/tsconfig/tsup.base.config.js" + +export default extendConfig({ + entry: ["src/index.mts"], + format: ["esm"], + external: [], + clean: true, +}) diff --git a/packages/variant-quickjs-asmjs-mjs-release-sync/src/index.ts b/packages/variant-quickjs-asmjs-mjs-release-sync/src/index.ts index c3e929af..2c303d21 100644 --- a/packages/variant-quickjs-asmjs-mjs-release-sync/src/index.ts +++ b/packages/variant-quickjs-asmjs-mjs-release-sync/src/index.ts @@ -1,6 +1,6 @@ import type { QuickJSSyncVariant } from "@jitl/quickjs-ffi-types" -import { QuickJSFFI } from "./ffi.js" import moduleLoader from "@jitl/quickjs-asmjs-mjs-release-sync/emscripten-module" +import { QuickJSFFI } from "./ffi.js" /** * ### @jitl/quickjs-asmjs-mjs-release-sync * diff --git a/scripts/prepareVariants.ts b/scripts/prepareVariants.ts index 06bee65e..0f9b3b19 100755 --- a/scripts/prepareVariants.ts +++ b/scripts/prepareVariants.ts @@ -760,8 +760,8 @@ function renderIndexTs( // Eager loading please! return ` import type { ${variantTypeName} } from '@jitl/quickjs-ffi-types' -import { ${className} } from './ffi.js' import moduleLoader from '${packageJson.name}/emscripten-module' +import { ${className} } from './ffi.js' /** ${docComment} */