v1.1.0
translated to typescript and added .ts file support
This commit is contained in:
110
src/vm.ts
Normal file
110
src/vm.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user