Постановку взял тут https://t.me/we_use_js/3891
Подсчет статистики наивный
⋮)Gist - https://gist.github.com/KhraksMamtsov/c29c112a5e1bf01e21e309646528445e
Из крутого:
-
--wizard из коробки — возможность интерактивно составить какую-либо конкретную команду для cli-
--help коробочный -
--completions всякого рода — sh, bash, fish, zsh (сам не пользуюсь)- типобезопасность (не знаю нужно ли упоминать — это effect)
import { Args, Command } from "@effect/cli";
import { NodeContext, NodeRuntime } from "@effect/platform-node";
import { Path, FileSystem as FS } from "@effect/platform";
import { Effect, Stream } from "effect";
import * as Schema from "@effect/schema/Schema";
// Схема статистики файла
const StatsContract = Schema.Struct({
chars: Schema.Number,
lines: Schema.Number,
words: Schema.Number,
});
// Функция энкода статистики в JSON
const encodeStatsContractToJSON = Schema.encodeEither(
Schema.parseJson(StatsContract)
);
// Подсчет статистики файла
const calculateFileStats = (path: string) =>
Effect.gen(function* () {
// импорт сервиса файловой системы
const fs = yield* FS.FileSystem;
return yield* fs.stream(path).pipe(
Stream.decodeText("utf8"),
Stream.flatMap((x) => Stream.fromIterable(x.split(""))),
Stream.runFold({ lines: 0, words: 0, chars: 0 }, (acc, cur) => ({
chars: acc.chars + 1,
lines: acc.lines + (cur === "\n" ? 1 : 0),
words: acc.words + (cur === " " ? 1 : 0),
}))
);
});
// Описание аргумента команды
const pathArg = Args.file({ exists: "yes" }).pipe(
Args.withDescription("Path to file")
);
// Описание подкоманды с обработчиком
const reportSubCommand = Command.make("report", { pathArg }, (x) =>
Effect.gen(function* () {
const fs = yield* FS.FileSystem;
const path = yield* Path.Path;
const stats = yield* calculateFileStats(x.pathArg);
const cwd = path.resolve();
const statsPath = path.join(cwd, "stats.json");
const data = yield* encodeStatsContractToJSON(stats);
yield* fs.writeFileString(statsPath, data);
})
);
const printSubCommand = Command.make("print", { pathArg }, (x) =>
Effect.gen(function* () {
const stats = yield* calculateFileStats(x.pathArg);
yield* Effect.log(stats);
})
);
// Собираем приложение
const appCommand = Command.make("app").pipe(
Command.withDescription("Node Kata solution"),
Command.withSubcommands([reportSubCommand, printSubCommand])
);
// Конвертим в effect
const cli = Command.run(appCommand, {
name: "Node Kata",
version: "0.0.1",
});
// Предоставляем зависимости
const program = cli(process.argv).pipe(Effect.provide(NodeContext.layer));
// Запускаем
NodeRuntime.runMain(program);