Skip to content

Instantly share code, notes, and snippets.

@al6x
Last active December 20, 2024 09:11
Show Gist options
  • Save al6x/3552efaa2e49776767bbfe994a801fd6 to your computer and use it in GitHub Desktop.
Save al6x/3552efaa2e49776767bbfe994a801fd6 to your computer and use it in GitHub Desktop.
export {}
type Req = { id?: string, target: string, args?: unknown[] }
type Res = { id?: string, is_error: true, error: string } | { id?: string, is_error: false, result: unknown }
const target_cache: { [name: string]: unknown } = {}
async function process({ id, target: path, args }: Req): Promise<Res> {
if (!(path in target_cache)) {
const [module_name, ...names] = path.split('.')
if (names.length < 1) return { id, is_error: true, error: `Invalid path: ${path}` }
let m
try {
m = module_name == 'globalThis' ? globalThis : await import(module_name)
} catch (e) {
return { id, is_error: true, error: `Can't load module: ${module_name}` }
}
let target: any = m
for (let i = 0; i < names.length; i++) {
target = target[names[i]]
if (!target)
return { id, is_error: true, error: `Not found: ${[module_name, ...names.slice(0, i + 1)].join('.')}` }
}
target_cache[path] = target
}
const target = target_cache[path] as any
try {
const result = args !== undefined ? await target(...args) : target
return { id, is_error: false, result }
} catch (e) {
return { id, is_error: true, error: error_message(e) }
}
}
switch (globalThis.process.argv.length) {
case 2:
for await (const req of console) if (req) console.log(JSON.stringify(await process(JSON.parse(req))))
break
case 3:
console.log(JSON.stringify(await process(JSON.parse(globalThis.process.argv[2]))))
break
default:
console.error('invalid arguments')
}
// Helpers -----------------------------------------------------------------------------------------
function error_message(e: unknown): string {
if (e === undefined || e === null) return 'Unknown error'
if (typeof e == 'string') return e
if (e instanceof Error) return e.message
return 'Unknown error'
}
// Test --------------------------------------------------------------------------------------------
//
// echo '{"id":"1","target":"path.join","args":["a","b"]}' | bun run jl/js_call.ts
// echo '{"id":"1","target":"globalThis.parseInt","args":["1"]}' | bun run jl/js_call.ts
// echo '{"id":"1","target":"globalThis.Number.MAX_SAFE_INTEGER"}' | bun run jl/js_call.ts
//
// bun run jl/js_call.ts '{"id":1,"target":"path.join","args":["a","b"]}'
using JSON
# Currently bun.js has bug with stdin https://github.com/oven-sh/bun/issues/15893
# so, untill it's fixed, using slower version with bash wrapper script `run_js_call`
rpc = `jl/run_js_call`
rpc_io = open(rpc, "r+")
function rcall(target::String, args::Union{Vector, Nothing}=nothing)
req = isnothing(args) ? Dict("target" => target) : Dict("target" => target, "args" => args)
write(rpc_io, JSON.json(req)*"\n"); flush(rpc_io)
resp = JSON.parse(readline(rpc_io))
if resp["is_error"]; error(String(resp["error"])) end
resp["result"]
end
# print(rcall("path.join", ["a", "b"]))
#!/usr/bin/env bash
set -e
while read line; do
bun run jl/js_call.ts $line
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment