Last active
March 14, 2022 14:59
-
-
Save andresgutgon/36e01c91acb7a0c2dc7509b2b046a6cc to your computer and use it in GitHub Desktop.
Create File in Disk and validate size with `Meter`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import type { TransformCallback } from "stream" | |
import { Transform } from "stream" | |
export class Meter extends Transform { | |
public bytes: number | |
constructor( | |
public field: string, | |
public maxBytes: number | |
) { | |
super() | |
this.bytes = 0 | |
} | |
_transform(chunk: unknown, _: BufferEncoding, callback: TransformCallback) { | |
this.bytes += (chunk as Buffer).length | |
this.push(chunk) | |
if (typeof this.maxBytes === "number" && this.bytes > this.maxBytes) { | |
return callback(new MeterError(this.field, this.maxBytes)) | |
} | |
callback() | |
} | |
} | |
export class MeterError extends Error { | |
constructor(public field: string, public maxBytes: number) { | |
super(`Field "${field}" exceeded upload size of ${maxBytes} bytes.`) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import z from "zod" | |
import type { Readable } from "stream" | |
import { createWriteStream } from "fs" | |
import { rm, mkdir } from "fs/promises" | |
import { dirname } from "path" | |
import { FileValidationOptions } from "./zod/file/types" | |
import { makeFile } from "./files/makeFile" | |
import { Meter } from "./files/meter" | |
import { NodeFile } from "./files/file" | |
export type FileResult = { | |
name: string | |
success: boolean | |
data: NodeFile | null | |
errors: string[] | |
} | |
export type Props = { | |
shape: z.input<z.ZodTypeAny> | |
tmpdir: string | |
fileValidation: FileValidationOptions | null | |
name: string | |
filestream: Readable | |
filename: string | |
encoding: string | |
mimeType: string | |
} | |
exp | |
export async function validateFile({ │ 214| elephant_file: ["Only PDFs please"] | |
shape, │ ❯ runTest ../../node_modules/.pnpm/vitest@0.2.8/node_modules/vitest/src/ | |
fileValidation, │runtime/run.ts:101:1 | |
tmpdir, │ ❯ runSuite ../../node_modules/.pnpm/vitest@0.2.8/node_modules/vitest/src | |
name, │/runtime/run.ts:165:6 | |
filestream, │ ❯ runSuite ../../node_modules/.pnpm/vitest@0.2.8/node_modules/vitest/src | |
filename, │/runtime/run.ts:165:6 | |
mimeType │ ❯ runSuites ../../node_modules/.pnpm/vitest@0.2.8/node_modules/vitest/sr | |
}: Props): Promise<FileResult | undefined> { │c/runtime/entry.ts:4:8 | |
if (!shape) return undefined │ ❯ startTests ../../node_modules/.pnpm/vitest@0.2.8/node_modules/vitest/s | |
const filepath = await makeFile(tmpdir, filename, mimeType) │rc/runtime/entry.ts:9:1 | |
// Make the dir │ ❯ withEnv ../../node_modules/.pnpm/vitest@0.2.8/node_modules/vitest/src/ | |
await mkdir(dirname(filepath), { recursive: true }).catch(() => null) │runtime/error.ts:9:3 | |
│ | |
const maxFileSize = 1048576 // 1MB │ | |
│ | |
const meter = new Meter(name, maxFileSize) │⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/3]⎯ | |
await new Promise<void>((resolve, reject) => { │ | |
const writeFileStream = createWriteStream(filepath) │ FAIL src/index.test.ts > bodyparser > Validate file mimeType custom fun | |
│ction message | |
let aborted = false │AssertionError: expected true to be falsy | |
async function abort(error: Error) { │ ❯ src/index.test.ts:237:27 | |
if (aborted) return │ 235| } | |
aborted = true │ 236| }) | |
│ 237| expect(result.success).toBeFalsy() | |
filestream.unpipe() │ | ^ | |
meter.unpipe() │ 238| expect(result.fieldErrors).toEqual({ | |
filestream.removeAllListeners() │ 239| elephant_file: [ | |
meter.removeAllListeners() │ ❯ runTest ../../node_modules/.pnpm/vitest@0.2.8/node_modules/vitest/src/ | |
writeFileStream.removeAllListeners() │runtime/run.ts:101:1 | |
│ ❯ runSuite ../../node_modules/.pnpm/vitest@0.2.8/node_modules/vitest/src | |
await rm(filepath, { force: true }).catch(() => null) │/runtime/run.ts:165:6 | |
│ ❯ runSuite ../../node_modules/.pnpm/vitest@0.2.8/node_modules/vitest/src | |
reject(error) │/runtime/run.ts:165:6 | |
} │ ❯ runSuites ../../node_modules/.pnpm/vitest@0.2.8/node_modules/vitest/sr | |
│c/runtime/entry.ts:4:8 | |
filestream.on("error", abort) │ ❯ startTests ../../node_modules/.pnpm/vitest@0.2.8/node_modules/vitest/s | |
meter.on("error", abort) │rc/runtime/entry.ts:9:1 | |
writeFileStream.on("error", abort) │ ❯ withEnv ../../node_modules/.pnpm/vitest@0.2.8/node_modules/vitest/src/ | |
writeFileStream.on("finish", resolve) │runtime/error.ts:9:3 | |
│ | |
filestream.pipe(meter).pipe(writeFileStream) │ | |
}) │ | |
│⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/3]⎯ | |
const file = new NodeFile(filepath, meter.bytes, mimeType) │ | |
return { │Test Files 1 failed | 1 skipped (2) | |
name, │ Tests 3 failed | 7 passed | 1 skipped | 6 todo (17) | |
success: true, │ Time 47ms | |
data: file, │ | |
errors: [] │ | |
} │ FAIL Tests failed. Watching for file changes... | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment