From 8a2a37d5fbb8837ce6035ff468645ad52ac60c75 Mon Sep 17 00:00:00 2001 From: Marshall Cottrell Date: Mon, 30 Apr 2018 11:00:18 -0500 Subject: [PATCH 1/3] Support `ts-node` by checking `.ts` source files Should fix #41 --- src/core/cli.ts | 23 ++++++++--------------- src/internal-util/fs.ts | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/core/cli.ts b/src/core/cli.ts index c3ecd1b..3533eb8 100644 --- a/src/core/cli.ts +++ b/src/core/cli.ts @@ -17,7 +17,7 @@ import {CastableType, Printable, buildCastingContext, cast} from './object'; import {ExpectedError} from './error'; -import {existsDir, existsFile} from '../internal-util'; +import {existsDir, existsSourceFile} from '../internal-util'; const COMMAND_NAME_REGEX = /^[\w\d]+(?:-[\w\d]+)*$/; const HELP_OPTION_REGEX = /^(?:-[h?]|--help)$/; @@ -285,8 +285,7 @@ instead of "${definition.name}"`); let contexts: SubcommandSearchContext[] = await v.map( this.roots, async root => { - let path: string | undefined = Path.join(root.path, 'default.js'); - path = (await existsFile(path)) ? path : undefined; + let path: string | undefined = await existsSourceFile(root.path); let module: CommandModule | undefined; @@ -415,18 +414,12 @@ instead of "${definition.name}"`); private static async findEntryBySearchBase( searchBase: string, ): Promise { - let possiblePaths = [ - `${searchBase}.js`, - Path.join(searchBase, 'default.js'), - ]; - - for (let possiblePath of possiblePaths) { - if (await existsFile(possiblePath)) { - return { - path: possiblePath, - module: require(possiblePath) as CommandModule, - }; - } + const srcFile = await existsSourceFile(searchBase); + if (srcFile !== undefined) { + return { + path: srcFile, + module: require(srcFile) as CommandModule, + }; } if (await existsDir(searchBase)) { diff --git a/src/internal-util/fs.ts b/src/internal-util/fs.ts index f045d03..cf77f16 100644 --- a/src/internal-util/fs.ts +++ b/src/internal-util/fs.ts @@ -1,4 +1,5 @@ import * as FS from 'fs'; +import * as Path from 'path'; import * as v from 'villa'; @@ -11,6 +12,28 @@ export async function existsFile(path: string): Promise { return !!stats && stats.isFile(); } +export async function existsSourceFile(path: string, filename: string = 'default'): Promise { + const checkPaths = [ + Path.join(path, `${filename}.js`), + Path.join(path, `${filename}.ts`), + ]; + + if (filename === 'default') { + checkPaths.unshift( + `${path}.js`, + `${path}.ts`, + ) + } + + for (const check of checkPaths) { + if (await existsFile(check)) { + return check; + } + } + + return undefined; +} + export async function existsDir(path: string): Promise { let stats = await safeStat(path); return !!stats && stats.isDirectory(); From 8a8e81905dd3d981c23208efec2b2c93a6b298d5 Mon Sep 17 00:00:00 2001 From: Marshall Cottrell Date: Thu, 3 May 2018 10:55:32 -0500 Subject: [PATCH 2/3] Check for `.ts` files in `help.ts` --- src/core/command/help.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/core/command/help.ts b/src/core/command/help.ts index 04c61c2..08e6106 100644 --- a/src/core/command/help.ts +++ b/src/core/command/help.ts @@ -13,6 +13,7 @@ import {CLI, CommandModule} from '../cli'; import { buildTableOutput, existsDir, + existsSourceFile, indent, safeStat, } from '../../internal-util'; @@ -102,18 +103,22 @@ export class HelpInfo implements Printable { let names = await v.call(FS.readdir, dir); for (let name of names) { - let path = Path.join(dir, name); + let path: string | undefined = Path.join(dir, name); let stats = await safeStat(path); if (stats!.isFile()) { - if (name === 'default.js' || Path.extname(path) !== '.js') { + const ext = Path.extname(path); + name = Path.basename(path).replace(ext, ''); + + if ( + name === 'default' || + (ext !== '.js' && ext !== '.ts') || + path.endsWith('.d.ts') + ) { continue; } - - name = Path.basename(name, '.js'); } else { - path = Path.join(path, 'default.js'); - stats = await safeStat(path); + path = await existsSourceFile(path); } let existingItem = helpItemMap.get(name); @@ -130,7 +135,7 @@ export class HelpInfo implements Printable { let commandConstructor: CommandClass | undefined; let brief: string | undefined; - if (stats) { + if (path) { let module = require(path) as CommandModule; commandConstructor = module.default; brief = From 4ef9e9a5cc89a16566199aeb65255623862b8f42 Mon Sep 17 00:00:00 2001 From: Marshall Cottrell Date: Thu, 24 May 2018 12:33:26 -0500 Subject: [PATCH 3/3] use `require.resolve` instead of `fs` for path existence checks --- src/core/cli.ts | 41 +++++++++++++++++++--------------------- src/core/command/help.ts | 4 ++-- src/internal-util/fs.ts | 26 ++++++++++--------------- 3 files changed, 31 insertions(+), 40 deletions(-) diff --git a/src/core/cli.ts b/src/core/cli.ts index 3533eb8..bb2d92e 100644 --- a/src/core/cli.ts +++ b/src/core/cli.ts @@ -17,7 +17,7 @@ import {CastableType, Printable, buildCastingContext, cast} from './object'; import {ExpectedError} from './error'; -import {existsDir, existsSourceFile} from '../internal-util'; +import {existsDir, existsFile} from '../internal-util'; const COMMAND_NAME_REGEX = /^[\w\d]+(?:-[\w\d]+)*$/; const HELP_OPTION_REGEX = /^(?:-[h?]|--help)$/; @@ -282,31 +282,28 @@ instead of "${definition.name}"`); let targetPath: string | undefined; let targetModule: CommandModule | undefined; - let contexts: SubcommandSearchContext[] = await v.map( - this.roots, - async root => { - let path: string | undefined = await existsSourceFile(root.path); + let contexts: SubcommandSearchContext[] = this.roots.map(root => { + let path = existsFile(root.path); - let module: CommandModule | undefined; + let module: CommandModule | undefined; - if (path) { - module = require(path) as CommandModule; + if (path) { + module = require(path) as CommandModule; - if (module.default || !targetPath) { - targetPath = path; - targetModule = module; - } + if (module.default || !targetPath) { + targetPath = path; + targetModule = module; } + } - return { - label: root.label, - name: this.name, - searchBase: root.path, - path, - module, - }; - }, - ); + return { + label: root.label, + name: this.name, + searchBase: root.path, + path, + module, + }; + }); for (let i = argsIndex; i < argv.length && contexts.length; i++) { let possibleCommandName = argv[i]; @@ -414,7 +411,7 @@ instead of "${definition.name}"`); private static async findEntryBySearchBase( searchBase: string, ): Promise { - const srcFile = await existsSourceFile(searchBase); + const srcFile = existsFile(searchBase); if (srcFile !== undefined) { return { path: srcFile, diff --git a/src/core/command/help.ts b/src/core/command/help.ts index 08e6106..42ed9bd 100644 --- a/src/core/command/help.ts +++ b/src/core/command/help.ts @@ -13,7 +13,7 @@ import {CLI, CommandModule} from '../cli'; import { buildTableOutput, existsDir, - existsSourceFile, + existsFile, indent, safeStat, } from '../../internal-util'; @@ -118,7 +118,7 @@ export class HelpInfo implements Printable { continue; } } else { - path = await existsSourceFile(path); + path = await existsFile(path); } let existingItem = helpItemMap.get(name); diff --git a/src/internal-util/fs.ts b/src/internal-util/fs.ts index cf77f16..f71f5bb 100644 --- a/src/internal-util/fs.ts +++ b/src/internal-util/fs.ts @@ -7,27 +7,21 @@ export async function safeStat(path: string): Promise { return v.call(FS.stat, path).catch(v.bear); } -export async function existsFile(path: string): Promise { - let stats = await safeStat(path); - return !!stats && stats.isFile(); -} - -export async function existsSourceFile(path: string, filename: string = 'default'): Promise { - const checkPaths = [ - Path.join(path, `${filename}.js`), - Path.join(path, `${filename}.ts`), - ]; +export function existsFile( + path: string, + filename: string = 'default', +): string | undefined { + const checkPaths = [Path.join(path, filename)]; if (filename === 'default') { - checkPaths.unshift( - `${path}.js`, - `${path}.ts`, - ) + checkPaths.unshift(path); } for (const check of checkPaths) { - if (await existsFile(check)) { - return check; + try { + return require.resolve(check); + } catch { + continue; } }