/** * Command definitions for the `effect-bundle` bundle-size CLI. * * This module wires the top-level `bundle` command to the reporting service and * exposes the workflows used when maintaining fixture bundle sizes. `compare` * builds the package's local fixtures and compares them with matching fixture * files from another checkout, `report` bundles an explicit list of entrypoints * and prints a Markdown table, `compare-selected` compares explicit entrypoints * against a base checkout, `visualize-selected` analyzes explicit entrypoints, * and `visualize` prompts for local fixtures before producing visualization * output for inspection. * * Command output is intentionally split by workflow. `compare` requires an * existing `--base-dir` (`-b`) and writes its Markdown report to `--output-path` * (`-o`), defaulting to `stats.txt` resolved from the current working directory. * `report` accepts one or more existing files and writes to stdout. `visualize` * uses `--output-dir` (`-o`) for generated bundle artifacts, so `-o` names a * file for `compare` but a directory for `visualize`. * * @since 4.0.0 */ import * as Console from "effect/Console" import * as Effect from "effect/Effect" import * as FileSystem from "effect/FileSystem" import * as Path from "effect/Path" import * as Argument from "effect/unstable/cli/Argument" import * as Command from "effect/unstable/cli/Command" import * as Flag from "effect/unstable/cli/Flag" import * as Prompt from "effect/unstable/cli/Prompt" import { Fixtures } from "./Fixtures.ts" import { Reporter } from "./Reporter.ts" const baseDirectory = Flag.directory("base-dir", { mustExist: true }).pipe( Flag.withAlias("b"), Flag.withDescription("The base directory to use for bundle size comparisons") ) const outputPath = Flag.file("output-path").pipe( Flag.withAlias("o"), Flag.withDescription("The name of the file to write the bundle size report to"), Flag.withDefault("stats.txt"), Flag.mapEffect(Effect.fnUntraced(function*(outputPath) { const path = yield* Path.Path return path.resolve(outputPath) })) ) const compare = Command.make("compare", { baseDirectory, outputPath }).pipe( Command.withHandler(Effect.fnUntraced(function*({ baseDirectory, outputPath }) { const fs = yield* FileSystem.FileSystem const reporter = yield* Reporter const report = yield* reporter.report({ baseDirectory }) yield* fs.writeFileString(outputPath, report) yield* Effect.log(`Bundle size report written to: '${outputPath}'`) })) ) const outputDirectory = Flag.directory("output-dir").pipe( Flag.withAlias("o"), Flag.withDescription("The name of the directory to write the bundle size visualizations to"), Flag.mapEffect(Effect.fnUntraced(function*(outputPath) { const path = yield* Path.Path return path.resolve(outputPath) })) ) const visualize = Command.make("visualize", { outputDirectory }).pipe( Command.withHandler(Effect.fnUntraced(function*({ outputDirectory }) { const path = yield* Path.Path const { fixtures, fixturesDir } = yield* Fixtures const reporter = yield* Reporter const paths = yield* Prompt.multiSelect({ message: "Select files whose bundle size you would like to visualize", choices: fixtures.map((fixture) => ({ title: fixture, value: path.join(fixturesDir, fixture) })) }) const report = yield* reporter.visualize({ paths, outputDirectory }) yield* Console.log(report) })) ) const reportPaths = Argument.file("paths", { mustExist: true }).pipe( Argument.withDescription("Fixture files to include in the report"), Argument.variadic({ min: 1 }) ) const report = Command.make("report", { paths: reportPaths }).pipe( Command.withHandler(Effect.fnUntraced(function*({ paths }) { const reporter = yield* Reporter const report = yield* reporter.reportSelected({ paths }) yield* Console.log(report) })) ) const compareSelected = Command.make("compare-selected", { baseDirectory, paths: reportPaths }).pipe( Command.withHandler(Effect.fnUntraced(function*({ baseDirectory, paths }) { const reporter = yield* Reporter const report = yield* reporter.reportSelectedComparison({ baseDirectory, paths }) yield* Console.log(report) })) ) const visualizeSelected = Command.make("visualize-selected", { outputDirectory, paths: reportPaths }).pipe( Command.withHandler(Effect.fnUntraced(function*({ outputDirectory, paths }) { const reporter = yield* Reporter const report = yield* reporter.visualize({ outputDirectory, paths }) yield* Console.log(report) })) ) /** * Bundle analysis CLI command with subcommands for comparing fixture bundle sizes, reporting selected fixtures, and generating visualizations. * * @category commands * @since 4.0.0 */ export const cli = Command.make("bundle").pipe( Command.withSubcommands([compare, compareSelected, report, visualize, visualizeSelected]) )