draig-car
Version:
Database REST API interactive generator CLI and REPL OpenAPI3 based JS generator with interactive ORM/ODM REPL
80 lines (74 loc) • 2.4 kB
JavaScript
const vm = require('vm')
const repl = require('repl')
const chalk = require('chalk')
const { processTopLevelAwait } = require('node-repl-await')
const i = require('./init')
const u = require('./util')
const synErrorRex = new RegExp(
'^(' + ['Unexpected end of input', 'Unexpected token'].join('|') + ')'
)
async function draigEval(code, ctx, filename, callback) {
if (code === '\n') return ctx.repl.displayPrompt()
if(code.includes("model.") || code.includes("knex.raw(") ||
code.includes("knex.select(") || code.includes("knex("))
u.lastquery = code.replace(/model./g, "").replace(/\n/g, "")
if(code.includes("_."))
u.lasttransform = code.replace(/\_./g, "rows.").replace(/\n/g, "")
code = processTopLevelAwait(code) || code
try {
callback(null, await (async () => {
let result = await vm.runInNewContext(code, ctx)
if(result && result.rows) return result.rows
return result
})(code, ctx))
} catch (e) {
if (e.name === 'SyntaxError' && synErrorRex.test(e.message))
callback(new repl.Recoverable(e))
else {
console.log('Error', e)
ctx.repl.displayPrompt()
}
}
}
async function startRepl(argv) {
if (!argv.silent && argv._.includes('repl')) u.showBanner()
u.testRequisites(argv)
let r = repl.start({ eval: draigEval, preview: true })
r.setupHistory('.draig-console.history', () => {})
r.on('reset', ctx => {
ctx.repl = r
ctx.argv = argv
i.initCtx(ctx)
})
r.on('exit', () => {
u.stopAPI(r.context)
process.exit()
})
process.on('unhandledRejection', reason => {
console.log(chalk`{yellow Unhandled Promise Rejection}: `, reason)
if (r.context.argv === undefined ||
r.context.argv._.includes('run')) process.exit(0)
else r.displayPrompt()
})
i.initRepl(r)
r.context.argv = argv
i.initCtx(r.context)
if (argv._.includes('run')) {
if (!(argv.intcmd in r.commands) || !r.commands[argv.intcmd].runnable) {
console.error(
chalk`Sorry, {green ${argv.intcmd}} is not a valid command`
)
process.exit(1)
}
let msg = chalk`Running internal command {green ${argv.intcmd}}`
if (argv.intargs.length) msg += chalk` with args {green ${argv.intargs}}`
console.log(msg + '...\n')
await r.commands[argv.intcmd].action.bind(r, argv.intargs)()
console.log(chalk`Command {green ${argv.intcmd}} done.`)
process.exit(0)
} else {
u.setPrompt(r.context, r)
r.displayPrompt()
}
}
module.exports.startRepl = startRepl