Skip to content

Commit 7b6bca7

Browse files
committed
feat: csv picker
1 parent a45498b commit 7b6bca7

15 files changed

Lines changed: 374 additions & 22 deletions

package-lock.json

Lines changed: 7 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
{
2-
"name": "compound-interest",
2+
"name": "csv-picker",
33
"version": "1.0.0",
44
"description": "",
55
"main": "dist/src/index.js",
66
"module": "dist/src/index.esm.js",
77
"bin": {
8-
"pkg-name": "./dist/src/index.js"
8+
"csv-picker": "./dist/src/index.js"
99
},
1010
"scripts": {
1111
"dev": "npx vite-node ./src/index.ts",
@@ -21,6 +21,8 @@
2121
"author": "",
2222
"license": "ISC",
2323
"devDependencies": {
24+
"cac": "^6.7.14",
25+
"chalk": "^4.1.2",
2426
"@types/node": "^20.2.1",
2527
"@typescript-eslint/eslint-plugin": "^5.57.0",
2628
"@typescript-eslint/parser": "^5.57.0",

src/exampleFunction.test.ts

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/exampleFunction.ts

Lines changed: 0 additions & 4 deletions
This file was deleted.

src/helpers/checkColumns.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { logger } from "./logger";
2+
3+
export const checkColumns = (columns: string[]) => {
4+
logger.info("checking csv columns...");
5+
const requiredColumns = ["product_code", "quantity", "pick_location"];
6+
const missingColumns = requiredColumns.filter((requiredColumn) => !columns.includes(requiredColumn));
7+
if (missingColumns.length) {
8+
logger.error(`Missing columns: ${missingColumns.join(", ")}`);
9+
process.exit(1);
10+
}
11+
logger.success("all columns present");
12+
};

src/helpers/createFile.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { writeFileSync } from "fs";
2+
import { logger } from "./logger";
3+
4+
export const formatRow = (row: string[]) => row.join(",");
5+
export const formatCsv = (data: string[][]) => data.map(formatRow).join("\r\n");
6+
7+
export const createCsvFile = (path: string, data: string[][]) => {
8+
try {
9+
logger.info("creating csv file...");
10+
const csv = formatCsv(data);
11+
const file = writeFileSync(path, csv);
12+
logger.success(`csv file created in ${path}`);
13+
return file;
14+
} catch (err) {
15+
if (err instanceof Error) {
16+
logger.error(err.message);
17+
process.exit(1);
18+
}
19+
}
20+
};

src/helpers/helpers.test.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { describe, expect, it, vi } from "vitest";
2+
import { writeFileSync } from "fs";
3+
import { formatRow, formatCsv, createCsvFile } from "./createFile";
4+
import { parseCsv } from "./parseCsv";
5+
6+
vi.mock("fs", async () => ({
7+
default: vi.fn(),
8+
writeFileSync: vi.fn().mockReturnValue("foo")
9+
}));
10+
11+
describe("createCsvFile", () => {
12+
const data = [
13+
["product_code", "quantity", "pick_location"],
14+
["B1234", "2", "A1"],
15+
["B1235", "3", "A2"],
16+
["B1236", "4", "A3"]
17+
];
18+
19+
describe("formatRow", () => {
20+
it("should format a row", () => {
21+
const row = ["product_code", "quantity", "pick_location"];
22+
const formatted = formatRow(row);
23+
expect(formatted).toBe("product_code,quantity,pick_location");
24+
});
25+
});
26+
27+
describe("formatCsv", () => {
28+
it("should format a csv", () => {
29+
const formatted = formatCsv(data);
30+
expect(formatted).toBe("product_code,quantity,pick_location\r\nB1234,2,A1\r\nB1235,3,A2\r\nB1236,4,A3");
31+
});
32+
});
33+
34+
it("should create a csv file", () => {
35+
const csv = createCsvFile("./src/output.csv", data);
36+
const formatted = formatCsv(data);
37+
expect(writeFileSync).toBeCalled();
38+
expect(writeFileSync).toHaveBeenCalledWith("./src/output.csv", formatted);
39+
expect(csv).toBe("foo");
40+
});
41+
});
42+
43+
describe("parseCsv", () => {
44+
it("should return an array of arrays", () => {
45+
const csv = `product_code,quantity,pick_location\r\n
46+
B1234,2,A1\r\n
47+
B1235,3,A2\r\n
48+
B1236,4,A3\r\n`;
49+
const parsed = parseCsv(csv);
50+
expect(parsed).toEqual([
51+
["product_code", "quantity", "pick_location"],
52+
["B1234", "2", "A1"],
53+
["B1235", "3", "A2"],
54+
["B1236", "4", "A3"]
55+
]);
56+
});
57+
it("should trim whitespace and trailing commas", () => {
58+
const csv = `product_code,quantity,pick_location, \r\n
59+
B1234,2,A1 \r\n
60+
B1235,3,A2, \r\n
61+
B1236,4,A3 \r\n`;
62+
const parsed = parseCsv(csv);
63+
expect(parsed).toEqual([
64+
["product_code", "quantity", "pick_location"],
65+
["B1234", "2", "A1"],
66+
["B1235", "3", "A2"],
67+
["B1236", "4", "A3"]
68+
]);
69+
});
70+
});
71+
72+
describe("readCsv", () => {
73+
it.todo("should read a csv file");
74+
});
75+
76+
describe("logger", () => {
77+
it.todo("should log messages to the console");
78+
});
79+
80+
describe("checkColumns", () => {
81+
it.todo("should check for required columns in csv file");
82+
});

src/helpers/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export { createCsvFile } from "./createFile";
2+
export { parseCsv } from "./parseCsv";
3+
export { logger } from "./logger";
4+
export { checkColumns } from "./checkColumns";
5+
export { readCsvSync } from "./readCsv";

src/helpers/logger.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import chalk from "chalk";
2+
3+
export const logger = {
4+
info: (message: string) => console.log(chalk.blue(message)),
5+
error: (message: string) => console.log(chalk.red(message)),
6+
warn: (message: string) => console.log(chalk.yellow(message)),
7+
success: (message: string) => console.log(chalk.green(message))
8+
};
9+
10+
export default logger;

src/helpers/parseCsv.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { ProductTuple } from "./sort";
2+
3+
export const parseCsv = (csv: string): ProductTuple[] => {
4+
const rows = csv.split("\r");
5+
6+
const trimmedRows = rows.map((row) => {
7+
const trimmed = row.trim();
8+
if (!trimmed.length) {
9+
return [];
10+
}
11+
const [productCode, qty, pickLocation] = trimmed.split(",");
12+
return [productCode, qty, pickLocation];
13+
});
14+
15+
const result = trimmedRows.filter((row) => row.length === 3) as ProductTuple[];
16+
17+
return result;
18+
};

0 commit comments

Comments
 (0)