Comparing version 0.6.0 to 0.7.0
import * as inversify_lib_interfaces_interfaces from 'inversify/lib/interfaces/interfaces'; | ||
import { Container } from 'inversify'; | ||
import { Argv as Argv$1 } from 'yargs'; | ||
import commander from 'commander'; | ||
export { Argument } from 'commander'; | ||
import { Writable } from 'node:stream'; | ||
interface CommandStatic<Args extends CommandArgs = CommandArgs> { | ||
interface CommandStatic { | ||
new (...args: any[]): Command; | ||
path?: string[]; | ||
default?: boolean; | ||
command: string; | ||
description: string; | ||
options: (y: Argv$1<CommandArgs>) => Argv$1<Args>; | ||
options?: (c: commander.Command) => commander.Command; | ||
} | ||
interface CommandArgs { | ||
'$?'?: CommandResult; | ||
'$!'?: unknown; | ||
} | ||
type CommandResult = number | void; | ||
interface Command { | ||
execute(): Promise<CommandResult> | CommandResult; | ||
execute(): Promise<void> | void; | ||
} | ||
declare const options: <Args extends CommandArgs>(fn?: (y: Argv$1<CommandArgs>) => Argv$1<any>) => (y: Argv$1<CommandArgs>) => Argv$1<Args>; | ||
declare const options: (fn: (c: commander.Command) => commander.Command) => (c: commander.Command) => commander.Command; | ||
@@ -27,3 +24,3 @@ declare class CLIError extends Error { | ||
} | ||
type ErrorHandler = (error: {}, context: ErrorHandlerContext) => number | Promise<number>; | ||
type ErrorHandler = (error: {}, context: ErrorHandlerContext) => number | Promise<void>; | ||
interface ErrorHandlerContext { | ||
@@ -34,5 +31,7 @@ stdout: Writable; | ||
type ProgramInit = () => commander.Command; | ||
interface CLIOptions { | ||
container?: Container; | ||
yargs?: () => Argv$1; | ||
program?: ProgramInit; | ||
onError?: ErrorHandler; | ||
@@ -42,12 +41,11 @@ } | ||
container: Container; | ||
private createYargs; | ||
private onError; | ||
constructor({ container, yargs, onError, }?: CLIOptions); | ||
program: ProgramInit; | ||
onError: ErrorHandler; | ||
constructor({ container, program, onError, }?: CLIOptions); | ||
register<T extends CommandStatic>(command: T): inversify_lib_interfaces_interfaces.interfaces.BindingWhenOnSyntax<T>; | ||
run(processArgs: string[]): Promise<number>; | ||
run(processArgv: string[]): Promise<number | void>; | ||
clone(): CLI; | ||
} | ||
declare const Argv = "argv"; | ||
declare const Args = "args"; | ||
declare const Argv = "args"; | ||
declare const Stdout = "stdout"; | ||
@@ -59,2 +57,2 @@ declare const Stderr = "stderr"; | ||
export { Args, Argv, CLI, CLIError, Command, CommandArgs, CommandResult, CommandStatic, ErrorHandler, ErrorHandlerContext, Stderr, Stdin, Stdout, array, options }; | ||
export { Argv, CLI, CLIError, Command, CommandStatic, ErrorHandler, ErrorHandlerContext, Stderr, Stdin, Stdout, array, options }; |
"use strict"; | ||
var __create = Object.create; | ||
var __defProp = Object.defineProperty; | ||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
var __getOwnPropNames = Object.getOwnPropertyNames; | ||
var __getProtoOf = Object.getPrototypeOf; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
@@ -21,10 +19,2 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); | ||
}; | ||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
// If the importer is in node compatibility mode or this is not an ESM | ||
// file that has been converted to a CommonJS file using a Babel- | ||
// compatible transform (i.e. "__esModule" has not been set), then set | ||
// "default" to the CommonJS "module.exports" for node compatibility. | ||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
mod | ||
)); | ||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
@@ -35,3 +25,3 @@ | ||
__export(src_exports, { | ||
Args: () => Args, | ||
Argument: () => import_commander3.Argument, | ||
Argv: () => Argv, | ||
@@ -48,58 +38,6 @@ CLI: () => CLI, | ||
// src/internal/argv.ts | ||
var import_yargs = __toESM(require("yargs/yargs")); | ||
var ArgvBuilder = class { | ||
static { | ||
__name(this, "ArgvBuilder"); | ||
} | ||
store = {}; | ||
addNode(path, name, node) { | ||
let target = this.store; | ||
for (const name2 of path) { | ||
let parentNode = target[name2]; | ||
if (parentNode == null) { | ||
parentNode = target[name2] = { | ||
command: null, | ||
children: {} | ||
}; | ||
} | ||
target = parentNode.children; | ||
} | ||
if (target[name] != null) { | ||
throw new Error(`command conflicts: "${path.join(" ")}"`); | ||
} | ||
target[name] = node; | ||
} | ||
add(command) { | ||
const path = command.path ?? []; | ||
const [name] = command.command.split(" ", 2); | ||
this.addNode(path, name, { | ||
command, | ||
children: {} | ||
}); | ||
return this; | ||
} | ||
build(yargs, handle, store = this.store) { | ||
for (const [name, { command, children }] of Object.entries(store)) { | ||
if (command != null) { | ||
yargs.command(command.command, command.description, command.options, (args) => handle(command, args)); | ||
} else { | ||
yargs.command(name, "", (y) => this.build(y, handle, children)); | ||
} | ||
} | ||
} | ||
static from(commands) { | ||
const instance = new this(); | ||
for (const command of commands) { | ||
instance.add(command); | ||
} | ||
return instance; | ||
} | ||
}; | ||
function createDefaultArgv() { | ||
return (0, import_yargs.default)().help(); | ||
} | ||
__name(createDefaultArgv, "createDefaultArgv"); | ||
// src/cli.ts | ||
var import_commander2 = require("commander"); | ||
// src/internal/container.ts | ||
// src/container.ts | ||
var import_inversify = require("inversify"); | ||
@@ -109,4 +47,3 @@ | ||
var Command = "command"; | ||
var Argv = "argv"; | ||
var Args = "args"; | ||
var Argv = "args"; | ||
var Stdout = "stdout"; | ||
@@ -116,4 +53,4 @@ var Stderr = "stderr"; | ||
// src/internal/container.ts | ||
function createDefaultContainer(options2) { | ||
// src/container.ts | ||
function createContainer(options2) { | ||
const container = new import_inversify.Container(options2); | ||
@@ -125,10 +62,4 @@ container.bind(Stdout).toConstantValue(process.stdout); | ||
} | ||
__name(createDefaultContainer, "createDefaultContainer"); | ||
__name(createContainer, "createContainer"); | ||
// src/internal/stream.ts | ||
var writeln = /* @__PURE__ */ __name((stream, data) => { | ||
stream.write(data); | ||
stream.write("\n"); | ||
}, "writeln"); | ||
// src/error.ts | ||
@@ -153,2 +84,78 @@ var CLIError = class extends Error { | ||
// src/program.ts | ||
var import_commander = require("commander"); | ||
var ProgramBuilder = class { | ||
static { | ||
__name(this, "ProgramBuilder"); | ||
} | ||
init; | ||
store; | ||
constructor(init) { | ||
this.init = init; | ||
this.store = {}; | ||
} | ||
addNode(path, name, node) { | ||
let parent = this.store; | ||
for (const name2 of path) { | ||
let parentNode = parent[name2]; | ||
if (parentNode == null) { | ||
parentNode = parent[name2] = { | ||
name: name2, | ||
command: null, | ||
children: {} | ||
}; | ||
} | ||
parent = parentNode.children; | ||
} | ||
if (parent[name] != null) { | ||
throw new Error(`command conflicts: "${path.join(" ")}"`); | ||
} | ||
parent[name] = node; | ||
return this; | ||
} | ||
add(Command2) { | ||
return this.addNode(Command2.path ?? [], Command2.command, { | ||
name: Command2.command, | ||
command: Command2, | ||
children: {} | ||
}); | ||
} | ||
build(handle) { | ||
function addCommand(parent, { name, command: Command2, children }) { | ||
if (Command2 != null) { | ||
const c = new import_commander.Command(Command2.command).description(Command2.description); | ||
Command2.options?.(c); | ||
c.action((...ctx) => { | ||
const argv = ctx[c.registeredArguments.length]; | ||
const args = c.registeredArguments.reduce((acc, arg, index) => { | ||
acc[arg.name()] = ctx[index]; | ||
return acc; | ||
}, {}); | ||
return handle(Command2, { | ||
...argv, | ||
...args | ||
}); | ||
}); | ||
parent.addCommand(c, { | ||
isDefault: Command2.default | ||
}); | ||
} else { | ||
const c = parent.command(name); | ||
Object.values(children).forEach((child) => addCommand(c, child)); | ||
} | ||
} | ||
__name(addCommand, "addCommand"); | ||
const program = this.init(); | ||
Object.values(this.store).forEach((child) => addCommand(program, child)); | ||
return program; | ||
} | ||
static from(init, commands) { | ||
const instance = new this(init); | ||
for (const command of commands) { | ||
instance.add(command); | ||
} | ||
return instance; | ||
} | ||
}; | ||
// src/cli.ts | ||
@@ -160,7 +167,7 @@ var CLI = class _CLI { | ||
container; | ||
createYargs; | ||
program; | ||
onError; | ||
constructor({ container = createDefaultContainer(), yargs = createDefaultArgv, onError = defualtErrorHandler } = {}) { | ||
constructor({ container = createContainer(), program = import_commander2.createCommand, onError = defualtErrorHandler } = {}) { | ||
this.container = container; | ||
this.createYargs = yargs; | ||
this.program = program; | ||
this.onError = onError; | ||
@@ -171,45 +178,28 @@ } | ||
} | ||
async run(processArgs) { | ||
const yargs = this.createYargs(); | ||
async run(processArgv) { | ||
const stdout = await this.container.getAsync(Stdout); | ||
const stderr = await this.container.getAsync(Stderr); | ||
const commands = await this.container.getAllAsync(Command); | ||
ArgvBuilder.from(commands).build(yargs, async (Command2, args) => { | ||
const program = ProgramBuilder.from(this.program, commands).build(async (Command2, argv) => { | ||
const container = this.container.createChild(); | ||
container.bind(_CLI).toConstantValue(this); | ||
container.bind(Argv).toConstantValue(yargs); | ||
container.bind(Args).toConstantValue(args); | ||
container.bind(Argv).toConstantValue(argv); | ||
container.bind(Command2).toSelf(); | ||
const command = await container.getAsync(Command2); | ||
try { | ||
args["$?"] = await command.execute(); | ||
} catch (error) { | ||
args["$!"] = error; | ||
} | ||
}); | ||
const stdout = await this.container.getAsync(Stdout); | ||
const stderr = await this.container.getAsync(Stderr); | ||
return new Promise((resolve) => { | ||
yargs.parse(processArgs, {}, (yargsError, argv, yargsOutput) => { | ||
const error = yargsError ?? argv["$!"]; | ||
if (error != null) { | ||
resolve(this.onError(error, { | ||
stdout, | ||
stderr | ||
})); | ||
return; | ||
} | ||
if (yargsOutput !== "") { | ||
writeln(stdout, yargsOutput); | ||
resolve(0); | ||
return; | ||
} | ||
resolve(argv["$?"] != null ? Number(argv["$?"]) : 0); | ||
return command.execute(); | ||
}).exitOverride(); | ||
try { | ||
await program.parseAsync(processArgv, { | ||
from: "user" | ||
}); | ||
}); | ||
return 0; | ||
} catch (error) { | ||
return this.onError(error, { | ||
stdout, | ||
stderr | ||
}); | ||
} | ||
} | ||
clone() { | ||
return new _CLI({ | ||
container: this.container, | ||
yargs: this.createYargs, | ||
onError: this.onError | ||
}); | ||
return new _CLI(this); | ||
} | ||
@@ -219,3 +209,3 @@ }; | ||
// src/command.ts | ||
var options = /* @__PURE__ */ __name((fn = (y) => y) => (y) => fn(y), "options"); | ||
var options = /* @__PURE__ */ __name((fn) => (c) => fn(c), "options"); | ||
@@ -226,5 +216,8 @@ // src/util.ts | ||
], "array"); | ||
// src/index.ts | ||
var import_commander3 = require("commander"); | ||
// Annotate the CommonJS export names for ESM import in node: | ||
0 && (module.exports = { | ||
Args, | ||
Argument, | ||
Argv, | ||
@@ -231,0 +224,0 @@ CLI, |
{ | ||
"name": "sgray", | ||
"version": "0.6.0", | ||
"version": "0.7.0", | ||
"author": "cumul <gg6123@naver.com>", | ||
@@ -31,3 +31,2 @@ "license": "MIT", | ||
"@types/node": "^18", | ||
"@types/yargs": "^17.0.24", | ||
"@typescript-eslint/eslint-plugin": "^6.0.0", | ||
@@ -47,8 +46,9 @@ "@typescript-eslint/parser": "^6.0.0", | ||
"typescript": "^5.1.6", | ||
"vitest": "^0.33.0", | ||
"yargs": "^17.7.2" | ||
"vitest": "^0.33.0" | ||
}, | ||
"dependencies": { | ||
"commander": "^11.1.0" | ||
}, | ||
"peerDependencies": { | ||
"inversify": "^6.0.1", | ||
"yargs": "^17.7.2" | ||
"inversify": "^6.0.1" | ||
}, | ||
@@ -55,0 +55,0 @@ "scripts": { |
# sgray | ||
[Yargs](https://yargs.js.org/), [inversified](https://inversify.io/). | ||
[Commander.js](https://github.com/tj/commander.js), [inversified](https://inversify.io/). | ||
`sgray` provides a DI/IoC mechanism for CLI applications with Yargs and InversifyJS. | ||
`sgray` provides a DI/IoC mechanism for CLI applications with Commander.js and InversifyJS. | ||
@@ -12,5 +12,5 @@ ## Installation | ||
```shell | ||
yarn add sgray yargs inversify reflect-metadata | ||
pnpm add sgray yargs inversify reflect-metadata | ||
npm install --save sgray yargs inversify reflect-metadata | ||
yarn add sgray inversify reflect-metadata | ||
pnpm add sgray inversify reflect-metadata | ||
npm install --save sgray inversify reflect-metadata | ||
``` | ||
@@ -39,6 +39,5 @@ | ||
import { inject, injectable } from 'inversify'; | ||
import { Args, CLI, Command, CommandArgs, options } from 'sgray'; | ||
import { hideBin } from 'yargs/helpers'; | ||
import { Argv, CLI, Command, CommandArgv, options } from 'sgray'; | ||
interface GreetArgs extends CommandArgs { | ||
interface GreetArgv { | ||
message: string; | ||
@@ -51,9 +50,9 @@ } | ||
static description = 'prints greeting message'; | ||
static options = options<GreetArgs>((y) => y.option('message', { type: 'string', alias: 'm', default: 'hi' })); | ||
static options = options((c) => c.option('-m, --message <string>', 'message to print')); | ||
@inject(Args) | ||
private args: GreetArgs; | ||
@inject(Argv) | ||
private argv: GreetArgv; | ||
async execute() { | ||
console.log(this.args.message); | ||
console.log(this.argv.message); | ||
} | ||
@@ -64,3 +63,3 @@ } | ||
cli.register(GreetCommand); | ||
cli.run(hideBin(process.argv)).then(exit); | ||
cli.run(process.argv.slice(2)).then(exit); | ||
``` |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
21
39718
433
62
+ Addedcommander@^11.1.0
+ Addedcommander@11.1.0(transitive)
- Removedansi-regex@5.0.1(transitive)
- Removedansi-styles@4.3.0(transitive)
- Removedcliui@8.0.1(transitive)
- Removedcolor-convert@2.0.1(transitive)
- Removedcolor-name@1.1.4(transitive)
- Removedemoji-regex@8.0.0(transitive)
- Removedescalade@3.2.0(transitive)
- Removedget-caller-file@2.0.5(transitive)
- Removedis-fullwidth-code-point@3.0.0(transitive)
- Removedrequire-directory@2.1.1(transitive)
- Removedstring-width@4.2.3(transitive)
- Removedstrip-ansi@6.0.1(transitive)
- Removedwrap-ansi@7.0.0(transitive)
- Removedy18n@5.0.8(transitive)
- Removedyargs@17.7.2(transitive)
- Removedyargs-parser@21.1.1(transitive)