Skip to content

Commit

Permalink
Создаст основу для cli
Browse files Browse the repository at this point in the history
  • Loading branch information
AdonaiJehosua committed Aug 1, 2024
1 parent 14e219c commit eaeaf8f
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 0 deletions.
40 changes: 40 additions & 0 deletions src/cli/cli-application.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Command } from './commands/command.interface.js';
import { CommandParser } from './command-parser.js';

type CommandCollection = Record<string, Command>;

export class CLIApplication {
private commands: CommandCollection = {};

constructor(
private readonly defaultCommand: string = '--help'
) {}

public registerCommands(commandList: Command[]): void {
commandList.forEach((command) => {
if (Object.hasOwn(this.commands, command.getName())) {
throw new Error(`Command ${command.getName()} is already registered`);
}
this.commands[command.getName()] = command;
});
}

public getCommand(commandName: string): Command {
return this.commands[commandName] ?? this.getDefaultCommand();
}

public getDefaultCommand(): Command | never {
if (! this.commands[this.defaultCommand]) {
throw new Error(`The default command (${this.defaultCommand}) is not registered.`);
}
return this.commands[this.defaultCommand];
}

public processCommand(argv: string[]): void {
const parsedCommand = CommandParser.parse(argv);
const [commandName] = Object.keys(parsedCommand);
const command = this.getCommand(commandName);
const commandArguments = parsedCommand[commandName] ?? [];
command.execute(...commandArguments);
}
}
19 changes: 19 additions & 0 deletions src/cli/command-parser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
type ParsedCommand = Record<string, string[]>

export class CommandParser {
static parse(cliArguments: string[]): ParsedCommand {
const parsedCommand: ParsedCommand = {};
let currentCommand = '';

for (const argument of cliArguments) {
if (argument.startsWith('--')) {
parsedCommand[argument] = [];
currentCommand = argument;
} else if (currentCommand && argument) {
parsedCommand[currentCommand].push(argument);
}
}

return parsedCommand;
}
}
4 changes: 4 additions & 0 deletions src/cli/commands/command.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface Command {
getName(): string;
execute(...parameters: string[]): void;
}
20 changes: 20 additions & 0 deletions src/cli/commands/help.command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Command } from './command.interface.js';

export class HelpCommand implements Command {
public getName(): string {
return '--help';
}

public async execute(..._parameters: string[]): Promise<void> {
console.info(`
Программа для подготовки данных для REST API сервера.
Пример:
cli.js --<command> [--arguments]
Команды:
--version: # выводит номер версии
--help: # печатает этот текст
--import <path>: # импортирует данные из TSV
--generate <n> <path> <url> # генерирует произвольное количество тестовых данных
`);
}
}
50 changes: 50 additions & 0 deletions src/cli/commands/version.command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import {Command} from './command.interface.js';

type PackageJSONConfig = {
version: string;
}

function isPackageJSONConfig(value: unknown): value is PackageJSONConfig {
return (
typeof value === 'object' &&
value !== null &&
!Array.isArray(value) &&
Object.hasOwn(value, 'version')
);
}

export class VersionCommand implements Command {
constructor(
private readonly filePath: string = './package.json'
) {}

private readVersion(): string {
const jsonContent = readFileSync(resolve(this.filePath), 'utf-8');
const importedContent: unknown = JSON.parse(jsonContent);

if (! isPackageJSONConfig(importedContent)) {
throw new Error('Failed to parse json content.');
}

return importedContent.version;
}

public getName(): string {
return '--version';
}

public async execute(..._parameters: string[]): Promise<void> {
try {
const version = this.readVersion();
console.info(version);
} catch (error: unknown) {
console.error(`Failed to read version from ${this.filePath}`);

if (error instanceof Error) {
console.error(error.message);
}
}
}
}
4 changes: 4 additions & 0 deletions src/cli/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './cli-application.js';
export * from './command-parser.js';
export * from './commands/help.command.js';
export * from './commands/version.command.js';
13 changes: 13 additions & 0 deletions src/main.cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { CLIApplication, HelpCommand, VersionCommand } from './cli/index.js';

function bootstrap() {
const cliApplication = new CLIApplication();
cliApplication.registerCommands([
new HelpCommand(),
new VersionCommand()
]);

cliApplication.processCommand(process.argv);
}

bootstrap();

0 comments on commit eaeaf8f

Please sign in to comment.