Skip to content

Instantly share code, notes, and snippets.

@andresgutgon
Last active March 14, 2022 14:59
Show Gist options
  • Select an option

  • Save andresgutgon/36e01c91acb7a0c2dc7509b2b046a6cc to your computer and use it in GitHub Desktop.

Select an option

Save andresgutgon/36e01c91acb7a0c2dc7509b2b046a6cc to your computer and use it in GitHub Desktop.
Create File in Disk and validate size with `Meter`
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.`)
}
}
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