Files
file-node/src/vm.ts
ashley zomo 832cecfe76 v1.1.0
translated to typescript and added .ts file support
2022-06-14 12:13:28 -05:00

111 lines
3.0 KiB
TypeScript

import { existsSync, readFileSync } from 'fs'
import { dirname, join, parse } from 'path'
import { REPLServer } from 'repl'
import { pathToFileURL } from 'url'
import { runInContext, createContext, RunningScriptOptions, Script } from 'vm'
import { logv } from './util'
import { getArgs } from './util/args'
import { readScript, supportedExt } from './build'
import { runRepl } from './repl'
// TODO possible `export` solution
// i might be able to convert TS to CJS and custom define `module.exports` into something i can pass to the REPL for context
export function runVM() {
const Options = getArgs()
const path = parse(Options.script)
const file = join(path.dir, path.base)
const content = readScript(file)
const loader = supportedExt(file)
if (!loader) {
throw new Error(`Unsupported file type: ${file}`)
}
const context: any = {
...global,
__dirname: process.cwd(),
__filename: join(process.cwd(), file),
// exports: {},
// module,
console,
require: (module: string) => {
logv(`Requiring ${module}`)
try {
return require(module)
} catch (e) {
if (module.startsWith('.')) {
return require(join(process.cwd(), path.dir, module))
} else {
return require(join(process.cwd(), 'node_modules', module))
}
}
},
}
logv(`Running ${file}`)
context.__FILE_NODE__INTERNAL__ = function (cont: any, exp: any, mod: any) {
logv(`Done`)
let context = {
...cont,
...exp,
...mod.exports,
}
let exported = Object.keys({ ...exp, ...mod.exports })
runRepl(context, loader, exported)
}
REPLServer.prototype.context
const script = `(async function() {
const exports = {}
const module = {exports: {}}
${content}
__FILE_NODE__INTERNAL__(this, exports, module);
})().catch(e => {console.error('script error', e)})`
logv(script)
createContext(context)
runInContext(script, context, {
filename: path.base,
importModuleDynamically,
} as RunningScriptOptions)
}
function importModuleDynamically(
module: string,
_script: Script,
_importAssertions: any
) {
const Options = getArgs()
logv(`Importing ${module}`)
let modulePath = ''
if (module.startsWith('.')) {
modulePath = join(process.cwd(), dirname(Options.script), module)
} else {
modulePath = join(process.cwd(), 'node_modules', module)
}
//windows `C:`
if (/^[a-z]:\\/i.test(modulePath)) modulePath = modulePath.substring(2)
if (existsSync(join(modulePath, 'package.json'))) {
let { main } = JSON.parse(
readFileSync(join(modulePath, 'package.json')).toString()
)
modulePath = join(modulePath, main)
}
modulePath = pathToFileURL(modulePath).href
return import(modulePath)
}