From 7b35e8335c5168e65323df138407f0fadc6f201e Mon Sep 17 00:00:00 2001 From: Mikayla Dobson Date: Mon, 1 Apr 2024 18:20:57 -0500 Subject: [PATCH] couple of corrections, new additions --- .gitignore | 2 ++ .npmignore | 4 ++- package.json | 1 + pkg/logger.ts | 69 +++++++++++++++++++++++++++++++++++++++++++++ pkg/queue.ts | 5 ++-- tests/csv.test.ts | 16 +++++++++++ tests/queue.test.ts | 67 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 tests/queue.test.ts diff --git a/.gitignore b/.gitignore index 504afef..fcacef3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ node_modules/ package-lock.json +tmp/ +dist/ diff --git a/.npmignore b/.npmignore index 2b29f27..d6e56a3 100644 --- a/.npmignore +++ b/.npmignore @@ -1 +1,3 @@ -tests +tests/ +tmp/ +pkg/ diff --git a/package.json b/package.json index f8ec480..f5379f6 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "description": "", "devDependencies": { "@types/csv-parse": "^1.2.2", + "@types/node": "^20.12.2", "@types/react": "^18.2.73", "vitest": "^1.4.0" } diff --git a/pkg/logger.ts b/pkg/logger.ts index e69de29..b803104 100644 --- a/pkg/logger.ts +++ b/pkg/logger.ts @@ -0,0 +1,69 @@ +import { Console } from "console"; +import { PathLike, existsSync, mkdirSync, writeFileSync } from "fs"; + +type LogLevelOptions = { + appendLog?: boolean; + appendWarn?: boolean; + appendError?: boolean; + appendDebug?: boolean; +} + +export class Logger extends Console implements Disposable { + outfileLocation: PathLike; + outfileName: `${string}.txt`; + options: LogLevelOptions; + contents = ""; + + constructor(outfileLocation?: PathLike, outfileName?: `${string}.txt`, options?: LogLevelOptions) { + super(process.stdout, process.stderr); + this.outfileLocation = outfileLocation ?? process.cwd(); + this.outfileName = outfileName ?? "log.txt"; + + this.options = { + appendError: true, + appendLog: true, + ...options + } + } + + override log(...args: unknown[]) { + this.append(args.join(" ") + "\n"); + super.log(...args); + } + + override warn(...args: unknown[]) { + this.append(args.join(" ") + "\n"); + super.warn(...args); + } + + override error(...args: unknown[]) { + this.append(args.join(" ") + "\n"); + super.error(...args); + } + + private append(contents: string) { + this.contents += contents; + } + + private write() { + try { + if (!existsSync(this.outfileLocation)) mkdirSync(this.outfileLocation, { recursive: true }) + + writeFileSync( + `${this.outfileLocation.toString()}/${this.outfileName}`, + this.contents, + { + encoding: "utf-8", + flag: "a", + } + ) + + } catch(e) { + this.error(e); + } + } + + [Symbol.dispose]() { + this.write(); + } +} diff --git a/pkg/queue.ts b/pkg/queue.ts index d4f5075..4649282 100644 --- a/pkg/queue.ts +++ b/pkg/queue.ts @@ -32,9 +32,10 @@ export default class Queue extends Array { const chunk = []; while (chunk.length < length && this.isNotEmpty) { - chunk.push(this.dequeue()); + const data = this.dequeue(); + if (data) chunk.push(data); } - return chunk; + return chunk satisfies TData[]; } } diff --git a/tests/csv.test.ts b/tests/csv.test.ts index b2e032b..ba30175 100644 --- a/tests/csv.test.ts +++ b/tests/csv.test.ts @@ -1,3 +1,19 @@ import { describe, assert, it } from "vitest"; +import { readCSVToType } from "../pkg/csv"; +import { z } from "zod"; +describe('readCSVToType', () => { + it('should read a CSV string into an array of objects', async () => { + const result = await readCSVToType("a,b,c\n1,2,3", z.object({ + a: z.coerce.number(), + b: z.coerce.number(), + c: z.coerce.number(), + })); + console.log(result); + + assert(result[0].a === 1); + assert(result[0].b === 2); + assert(result[0].c === 3); + }) +}) diff --git a/tests/queue.test.ts b/tests/queue.test.ts new file mode 100644 index 0000000..a321be4 --- /dev/null +++ b/tests/queue.test.ts @@ -0,0 +1,67 @@ +import { describe, assert, it } from "vitest"; +import Queue from "../pkg/queue"; + +describe("queue", () => { + it("should enqueue and dequeue items", () => { + const queue = new Queue(); + + queue.enqueue(1); + queue.enqueue(2); + queue.enqueue(3); + + assert(queue.dequeue() === 1); + assert(queue.dequeue() === 2); + assert(queue.dequeue() === 3); + }); + + it("should return undefined when dequeueing from an empty queue", () => { + const queue = new Queue(); + + assert(queue.dequeue() === undefined); + }); + + it("should return the correct length", () => { + const queue = new Queue(); + + queue.enqueue(1); + queue.enqueue(2); + queue.enqueue(3); + + assert(queue.length === 3); + }); +}) + +describe("Queue.walk", () => { + it("should walk the queue", async () => { + const queue = new Queue(1, 2, 3); + + const result = []; + + for await (const chunk of queue.walk({ interval: 0, chunkSize: 2 })) { + result.push(chunk); + } + + assert(result[0][0] === 1); + assert(result[0][1] === 2); + assert(result[1][0] === 3); + }); + + it("should allow for a custom interval", async () => { + const data = Array.from({ length: 100 }).map((_, i) => i); + const queue = new Queue(...data); + const result: number[][] = []; + const generator = queue.walk({ interval: 100, chunkSize: 10 }); + + const start = Date.now(); + + for await (const chunk of generator) { + result.push(chunk); + } + + const stop = Date.now(); + const diff = stop - start; + + assert(diff <= 1100 && diff >= 900, `Expected diff in range 900-1100ms, got ${diff.toString()}`); + assert(result.length == 10, "Expected data to be processed in exactly 10 chunks"); + }); +})