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 hidden or 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 hidden or 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/[email protected]/node_modules/vitest/src/ | |
fileValidation, │runtime/run.ts:101:1 | |
tmpdir, │ ❯ runSuite ../../node_modules/.pnpm/[email protected]/node_modules/vitest/src | |
name, │/runtime/run.ts:165:6 | |
filestream, │ ❯ runSuite ../../node_modules/.pnpm/[email protected]/node_modules/vitest/src | |
filename, │/runtime/run.ts:165:6 | |
mimeType │ ❯ runSuites ../../node_modules/.pnpm/[email protected]/node_modules/vitest/sr | |
}: Props): Promise<FileResult | undefined> { │c/runtime/entry.ts:4:8 | |
if (!shape) return undefined │ ❯ startTests ../../node_modules/.pnpm/[email protected]/node_modules/vitest/s | |
const filepath = await makeFile(tmpdir, filename, mimeType) │rc/runtime/entry.ts:9:1 | |
// Make the dir │ ❯ withEnv ../../node_modules/.pnpm/[email protected]/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/[email protected]/node_modules/vitest/src/ | |
writeFileStream.removeAllListeners() │runtime/run.ts:101:1 | |
│ ❯ runSuite ../../node_modules/.pnpm/[email protected]/node_modules/vitest/src | |
await rm(filepath, { force: true }).catch(() => null) │/runtime/run.ts:165:6 | |
│ ❯ runSuite ../../node_modules/.pnpm/[email protected]/node_modules/vitest/src | |
reject(error) │/runtime/run.ts:165:6 | |
} │ ❯ runSuites ../../node_modules/.pnpm/[email protected]/node_modules/vitest/sr | |
│c/runtime/entry.ts:4:8 | |
filestream.on("error", abort) │ ❯ startTests ../../node_modules/.pnpm/[email protected]/node_modules/vitest/s | |
meter.on("error", abort) │rc/runtime/entry.ts:9:1 | |
writeFileStream.on("error", abort) │ ❯ withEnv ../../node_modules/.pnpm/[email protected]/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