UNPKG

@semo/cli

Version:

A command line tools dispatcher

341 lines 13.6 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.handler = exports.builder = exports.desc = exports.aliases = exports.command = exports.plugin = void 0; const repl_1 = __importDefault(require("repl")); const path_1 = __importDefault(require("path")); const core_1 = require("@semo/core"); const yargs_parser_1 = __importDefault(require("yargs-parser")); const fs_extra_1 = __importDefault(require("fs-extra")); let r; // repl instance let v; // yargs argv const importPackage = (name, force = false) => { return core_1.Utils.importPackage(name, 'repl-package-cache', true, force); }; const reload = () => __awaiter(void 0, void 0, void 0, function* () { const scriptName = v.scriptName || 'semo'; let pluginsReturn = yield core_1.Utils.invokeHook(`${scriptName}:repl`, core_1.Utils._.isBoolean(v.hook) ? { reload: true, mode: 'group', } : { mode: 'group', include: core_1.Utils.splitComma(v.hook), reload: true, }); pluginsReturn = core_1.Utils._.omitBy(pluginsReturn, core_1.Utils._.isEmpty); r.context.Semo.hooks = core_1.Utils.formatRcOptions(pluginsReturn); if (v.extract && v.extract.length > 0) { v.extract.forEach(keyPath => { r.context = Object.assign(r.context, core_1.Utils._.get(r.context, keyPath) || {}); }); } const hookReplCommands = yield core_1.Utils.invokeHook('semo:repl_command'); Object.keys(hookReplCommands) .filter(command => { return ![ 'break', 'clear', 'editor', 'exit', 'help', 'history', 'load', 'reload', 'save', ].includes(command); }) .forEach(command => { r.defineCommand(command, hookReplCommands[command]); }); console.log(core_1.Utils.success('Hooked files reloaded.')); }); const extract = (obj, keys = []) => { const keysCast = core_1.Utils._.castArray(keys); Object.keys(obj).forEach(key => { if (keys.length === 0 || keysCast.includes(key)) { Object.defineProperty(r.context, key, { value: obj[key] }); } }); }; const corepl = (cli) => { const originalEval = cli.eval; // @ts-ignore cli.eval = function coEval(cmd, context, filename, callback) { if (cmd.match(/^await\s+/) || (cmd.match(/.*?await\s+/) && cmd.match(/^\s*\{/))) { if (cmd.match(/=/)) { cmd = '(async function() { (' + cmd + ') })()'; } else { cmd = '(async function() { let _ = ' + cmd + '; return _;})()'; } } else if (cmd.match(/\W*await\s+/)) { cmd = '(async function() { (' + cmd.replace(/^\s*(var|let|const)\s+/, '') + ') })()'; } function done(val) { return callback(null, val); } originalEval.call(cli, cmd, context, filename, function (err, res) { if (err || !res || typeof res.then !== 'function') { return callback(err, res); } else { return res.then(done, callback); } }); }; return cli; }; exports.plugin = 'semo'; exports.command = 'repl [replFile]'; exports.aliases = 'r'; exports.desc = 'Play with REPL'; function openRepl(context) { return __awaiter(this, void 0, void 0, function* () { const { Semo } = context; const argv = Semo.argv; r = repl_1.default.start({ prompt: argv.prompt, ignoreUndefined: true, }); r.defineCommand('reload', { help: 'Reload hooked files', action(name) { return __awaiter(this, void 0, void 0, function* () { this.clearBufferedCommand(); try { yield reload(); } catch (e) { core_1.Utils.error(e.message); } this.displayPrompt(); }); }, }); r.defineCommand('shell', { help: 'Execute shell commands', action(cmd) { return __awaiter(this, void 0, void 0, function* () { this.clearBufferedCommand(); try { core_1.Utils.exec(cmd); } catch (e) { } this.displayPrompt(); }); }, }); const requireAction = function (input) { return __awaiter(this, void 0, void 0, function* () { // @ts-ignore this.clearBufferedCommand(); try { const opts = (0, yargs_parser_1.default)(input); const packages = {}; for (const part of opts._) { const split = part.split(':'); if (split.length === 1) { packages[part] = part; } else if (split.length > 1) { packages[split[0]] = split[1]; } } for (const pack in packages) { const imported = importPackage(pack); Object.defineProperty(r.context, packages[pack], { value: imported }); } } catch (e) { } // @ts-ignore this.displayPrompt(); }); }; // Add require and import command r.defineCommand('require', { help: 'Require npm packages', action: requireAction, }); r.defineCommand('import', { help: 'import npm packages', action: requireAction, }); const hookReplCommands = yield core_1.Utils.invokeHook('semo:repl_command'); Object.keys(hookReplCommands) .filter(command => { return ![ 'break', 'clear', 'editor', 'exit', 'help', 'history', 'load', 'reload', 'save', ].includes(command); }) .forEach(command => { r.defineCommand(command, hookReplCommands[command]); }); const Home = process.env.HOME + `/.${argv.scriptName}`; fs_extra_1.default.ensureDirSync(Home); if (!core_1.Utils.fileExistsSyncCache(Home)) { core_1.Utils.exec(`mkdir -p ${Home}`); } core_1.Utils.replHistory(r, `${Home}/.${argv.scriptName}_repl_history`); // @ts-ignore // context即为REPL中的上下文环境 r.context = Object.assign(r.context, context); r.context.Semo.repl = r; corepl(r); }); } const builder = function (yargs) { yargs.option('hook', { describe: 'If or not load all plugins repl hook', }); yargs.option('prompt', { describe: 'Prompt for input. default is >>>', }); yargs.option('extract', { describe: 'Auto extract k/v from Semo object by key path', }); yargs.option('import', { describe: 'import package, same as require option, e.g. --import=lodash:_', }); yargs.option('require', { describe: 'require package, same as import option, e.g. --require=lodash:_', alias: 'r', }); }; exports.builder = builder; const handler = function (argv) { return __awaiter(this, void 0, void 0, function* () { const VERSION = argv.$semo.VERSION; const scriptName = argv.scriptName || 'semo'; argv.hook = core_1.Utils.pluginConfig('repl.hook', core_1.Utils.pluginConfig('hook', false)); argv.prompt = core_1.Utils.pluginConfig('repl.prompt', core_1.Utils.pluginConfig('prompt', '>>> ')); argv.extract = core_1.Utils.pluginConfig('repl.extract', core_1.Utils.pluginConfig('extract', '')); argv.require = core_1.Utils.pluginConfig('repl.require', []).concat(core_1.Utils.pluginConfig('require', [])); argv.import = core_1.Utils.pluginConfig('repl.import', []).concat(core_1.Utils.pluginConfig('import', [])); const requiredPackages = core_1.Utils._.castArray(argv.require); const importedPackages = core_1.Utils._.castArray(argv.import); const concatPackages = core_1.Utils._.chain(requiredPackages) .concat(importedPackages) .uniq() .filter() .value(); const packages = {}; concatPackages.forEach(item => { const splited = item.split(':'); if (splited.length === 1) { packages[item] = item; } else { packages[splited[0]] = splited[1]; } }); if (core_1.Utils._.isString(argv.extract)) { argv.extract = core_1.Utils._.castArray(argv.extract); } v = argv; try { let context = Object.assign({ await: true }, { Semo: { VERSION, Utils: core_1.Utils, argv, import: importPackage, require: importPackage, extract, reload, run: core_1.Utils.run, }, }); for (const pack in packages) { context[packages[pack]] = importPackage(pack); } if (argv.hook) { let pluginsReturn = yield core_1.Utils.invokeHook(`${scriptName}:repl`, core_1.Utils._.isBoolean(argv.hook) ? { mode: 'group', } : { include: core_1.Utils.splitComma(argv.hook), mode: 'group', }); pluginsReturn = core_1.Utils._.omitBy(pluginsReturn, core_1.Utils._.isEmpty); const shortenKeysPluginsReturn = {}; Object.keys(pluginsReturn).forEach(plugin => { let newKey = plugin; const prefix = scriptName + '-plugin-'; if (plugin.indexOf(prefix) > -1) { newKey = plugin.substring(prefix.length); } shortenKeysPluginsReturn[newKey] = pluginsReturn[plugin]; }); context.Semo.hooks = core_1.Utils.formatRcOptions(shortenKeysPluginsReturn) || {}; } if (core_1.Utils._.isArray(argv.extract)) { if (argv.extract && argv.extract.length > 0) { argv.extract.forEach(keyPath => { context = Object.assign(context, core_1.Utils._.get(context.Semo.hooks, keyPath) || {}); }); } } else { Object.keys(argv.extract).forEach(key => { const extractKeys = core_1.Utils._.castArray(argv.extract[key]); extractKeys.forEach(extractKey => { const splitExtractKey = extractKey.split('.'); const finalExtractKey = splitExtractKey[splitExtractKey.length - 1]; context[finalExtractKey] = core_1.Utils._.get(context.Semo.hooks, `${key}.${extractKey}`); }); }); } if (argv.replFile) { const replFilePath = path_1.default.resolve(process.cwd(), argv.replFile); if (argv.replFile && fs_extra_1.default.existsSync(replFilePath)) { try { const replRequired = require(replFilePath); if (replRequired.handler && core_1.Utils._.isFunction(replRequired.handler)) { yield replRequired.handler(argv, context); } else if (core_1.Utils._.isFunction(replRequired)) { yield replRequired(argv, context); } } catch (e) { } } } yield openRepl(context); return false; } catch (e) { core_1.Utils.error(e.stack); } return true; }); }; exports.handler = handler; //# sourceMappingURL=repl.js.map