diff --git a/cli/lib/cmd-fns/export-bom-csv.ts b/cli/lib/cmd-fns/export-bom-csv.ts new file mode 100644 index 0000000..ce12652 --- /dev/null +++ b/cli/lib/cmd-fns/export-bom-csv.ts @@ -0,0 +1,32 @@ +import fs from "fs/promises" +import kleur from "kleur" +import { z } from "zod" +import { exportBomCsvToBuffer } from "../export-fns/export-bom-csv" +import { AppContext } from "../util/app-context" + +export const exportBomCsv = async (ctx: AppContext, args: any) => { + const params = z + .object({ + input: z.string(), + export: z.string().optional(), + outputfile: z.string().default("bom.csv"), + }) + .refine((data) => data.input, { + message: "'input' must be provided", + }) + .parse(args) + + const bomCsvBuffer = await exportBomCsvToBuffer( + { + example_file_path: params.input!, + export_name: params.export, + }, + ctx, + ) + + console.log(kleur.gray(`[writing to ${params.outputfile}]...`)) + await fs.writeFile(params.outputfile, bomCsvBuffer) + console.log( + kleur.green(`Bill of Material CSV file exported to ${params.outputfile}`), + ) +} diff --git a/cli/lib/cmd-fns/index.ts b/cli/lib/cmd-fns/index.ts index f4847f1..7cec860 100644 --- a/cli/lib/cmd-fns/index.ts +++ b/cli/lib/cmd-fns/index.ts @@ -44,3 +44,4 @@ export { devServerFulfillExportRequests } from "./dev-server-fulfill-export-requ export { lintCmd as lint } from "./lint" export { renderCmd as render } from "./render" export { genJlcpcbComponent } from "./gen-jlcpcb-component" +export { exportBomCsv } from "./export-bom-csv" diff --git a/cli/lib/get-program.ts b/cli/lib/get-program.ts index 933bcc4..549002b 100644 --- a/cli/lib/get-program.ts +++ b/cli/lib/get-program.ts @@ -1,5 +1,5 @@ -import { Command } from "commander" import * as CMDFN from "cli/lib/cmd-fns" +import { Command } from "commander" import type { AppContext } from "./util/app-context" export const getProgram = (ctx: AppContext) => { @@ -323,6 +323,17 @@ export const getProgram = (ctx: AppContext) => { .option("--outputfile ", "Output file name", "pnp.csv") .action((args) => CMDFN.exportPnpCsv(ctx, args)) + exportCmd + .command("bom_csv") + .description("Export BOM CSV file from an example file") + .option("--input ", "Input example file") + .option( + "--export ", + "Name of export to soupify, if not specified, soupify the default/only export", + ) + .option("--outputfile ", "Output file name", "bom.csv") + .action((args) => CMDFN.exportBomCsv(ctx, args)) + cmd .command("soupify") .description("Convert an example file to tscircuit soup") diff --git a/cli/tests/export-bom-csv.test.ts b/cli/tests/export-bom-csv.test.ts new file mode 100644 index 0000000..0c3d5b4 --- /dev/null +++ b/cli/tests/export-bom-csv.test.ts @@ -0,0 +1,24 @@ +import { expect, test } from "bun:test" +import { existsSync, readFileSync } from "fs" +import { $ } from "bun" +import { join } from "path/posix" +import { temporaryDirectory } from "tempy" + +test("tsci export bom_csv --input example-project/examples/macrokeypad.tsx", async () => { + const tempDir = temporaryDirectory() + const bomCsvPath = join(tempDir, "bom.csv") + const { stdout, stderr } = + await $`bun cli/cli.ts export bom_csv --input example-project/examples/macrokeypad.tsx --outputfile ${bomCsvPath} --no-color` + + expect(stderr.toString()).toBe("") + expect(stdout.toString()).toContain("bom.csv") + + expect(existsSync(bomCsvPath)).toBe(true) + + const bomCsvContent = readFileSync(bomCsvPath, "utf-8") + expect(bomCsvContent).toContain("Designator") + expect(bomCsvContent).toContain("Comment") + expect(bomCsvContent).toContain("Value") + expect(bomCsvContent).toContain("Footprint") + expect(bomCsvContent).toContain("JLCPCB Part#") +})