From 305937bf1b3aa71fa630aa4dcc4dd1e2ce62e874 Mon Sep 17 00:00:00 2001 From: Vadim Demedes Date: Sat, 1 Jun 2019 10:14:15 -0700 Subject: [PATCH] Use relative command paths to fix distributed CLIs Fixes #12 --- boot.js | 5 +++-- entry.js | 2 +- index.js | 6 +++--- lib/get-entrypoint-paths.js | 7 ++++--- lib/read-commands.js | 9 ++++----- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/boot.js b/boot.js index 95a151b..32553e1 100644 --- a/boot.js +++ b/boot.js @@ -1,9 +1,10 @@ 'use strict'; +const path = require('path'); const camelcaseKeys = require('camelcase-keys'); const decamelize = require('decamelize'); const yargs = require('yargs'); -module.exports = (React, Ink, commands) => { +module.exports = (dirname, React, Ink, commands) => { const addCommand = (command, yargs) => { // Yargs expects a special format for positional args when defining a command // in order to correctly parse them, e.g. " " @@ -55,7 +56,7 @@ module.exports = (React, Ink, commands) => { inputArgs: argv._ }; - const UI = require(command.buildPath).default; + const UI = require(path.join(dirname, 'commands', command.path)).default; const {waitUntilExit} = Ink.render(React.createElement(UI, props)); waitUntilExit().catch(error => { diff --git a/entry.js b/entry.js index 747bbfe..5c704aa 100644 --- a/entry.js +++ b/entry.js @@ -8,4 +8,4 @@ const {commands} = require('./commands.json'); // eslint-disable-line import/no- // This file is an entrypoint of CLI applications based on Pastel // This file is copied to "build" directory of the CLI and "bin" field // in package.json must point to it -boot(React, Ink, commands); +boot(__dirname, React, Ink, commands); diff --git a/index.js b/index.js index 4c34ce9..249dd6e 100644 --- a/index.js +++ b/index.js @@ -37,7 +37,7 @@ class Pastel extends EventEmitter { } async scanCommands() { - const commands = await readCommands(this.commandsPath, path.join(this.buildPath, 'commands')); + const commands = await readCommands(this.commandsPath, this.commandsPath); await writeFile(path.join(this.buildPath, 'commands.json'), JSON.stringify({commands}, null, '\t')); return commands; @@ -65,7 +65,7 @@ class Pastel extends EventEmitter { await this.createBuildDir(); await this.saveEntrypoint(); const commands = await this.scanCommands(); - const bundler = this.createBundler(getEntrypointPaths(commands), {watch: false}); + const bundler = this.createBundler(getEntrypointPaths(this.commandsPath, commands), {watch: false}); return bundler.bundle(); } @@ -107,7 +107,7 @@ class Pastel extends EventEmitter { const commands = await this.scanCommands(); - bundler = this.createBundler(getEntrypointPaths(commands), {watch: true}); + bundler = this.createBundler(getEntrypointPaths(this.commandsPath, commands), {watch: true}); bundler.on('buildStart', onStart); bundler.on('bundled', handleAsyncErrors(async () => { diff --git a/lib/get-entrypoint-paths.js b/lib/get-entrypoint-paths.js index cb51aae..feb70a0 100644 --- a/lib/get-entrypoint-paths.js +++ b/lib/get-entrypoint-paths.js @@ -1,12 +1,13 @@ 'use strict'; +const path = require('path'); // This function extracts all command paths into a flat array -const getEntrypointPaths = commands => { +const getEntrypointPaths = (commandsPath, commands) => { const entrypointPaths = []; for (const command of commands) { - entrypointPaths.push(command.path); - entrypointPaths.push(...getEntrypointPaths(command.subCommands)); + entrypointPaths.push(path.join(commandsPath, command.path)); + entrypointPaths.push(...getEntrypointPaths(commandsPath, command.subCommands)); } return entrypointPaths; diff --git a/lib/read-commands.js b/lib/read-commands.js index 5134a5f..fe5bddc 100644 --- a/lib/read-commands.js +++ b/lib/read-commands.js @@ -1,6 +1,6 @@ 'use strict'; const {promisify} = require('util'); -const {join, basename} = require('path'); +const {join, basename, relative} = require('path'); const fs = require('fs'); const parseCommand = require('./parse-command'); @@ -10,7 +10,7 @@ const isIndexCommand = command => command.path.endsWith('index.js'); // `dirPath` is a path in source `commands` folder // `buildDirPath` is a path to the same folder, but in `build` folder -const readCommands = async (dirPath, buildDirPath) => { +const readCommands = async (commandsPath, dirPath) => { const paths = fs.readdirSync(dirPath); const commands = []; @@ -20,7 +20,7 @@ const readCommands = async (dirPath, buildDirPath) => { const stats = await stat(fullPath); if (stats.isDirectory()) { - const subCommands = await readCommands(fullPath, join(buildDirPath, path)); + const subCommands = await readCommands(commandsPath, fullPath); const indexCommand = subCommands.find(isIndexCommand); commands.push({ @@ -34,8 +34,7 @@ const readCommands = async (dirPath, buildDirPath) => { const {description, args} = await parseCommand(fullPath); commands.push({ - path: fullPath, - buildPath: join(buildDirPath, path), + path: relative(commandsPath, fullPath), name: basename(fullPath, '.js'), description, args,