diff --git a/CallbackStorage.d.ts b/CallbackStorage.d.ts index 516e1b6..4449430 100644 --- a/CallbackStorage.d.ts +++ b/CallbackStorage.d.ts @@ -3,7 +3,7 @@ import { FileInfo } from "busboy"; import { FileHandler, StorageOption } from "./index"; export declare class CallbackStorage implements StorageOption { - callback: FileHandler; + #callback: FileHandler; constructor(callback: FileHandler); process(name: string, stream: Readable, info: FileInfo): import("./index").File | Promise; } \ No newline at end of file diff --git a/CallbackStorage.js b/CallbackStorage.js index 2f869c8..97bb327 100644 --- a/CallbackStorage.js +++ b/CallbackStorage.js @@ -1,12 +1,12 @@ "use strict"; class CallbackStorage { - callback; + #callback; constructor(callback) { - this.callback = callback; + this.#callback = callback; } process(name, stream, info) { - return this.callback(name, stream, info); + return this.#callback(name, stream, info); } } diff --git a/DiscStorage.d.ts b/DiscStorage.d.ts index 79615ad..49c4a0f 100644 --- a/DiscStorage.d.ts +++ b/DiscStorage.d.ts @@ -3,7 +3,7 @@ import { Readable } from "stream"; import { FileInfo } from "busboy"; export declare class DiscStorage implements StorageOption { - target: TargetType; + #target: TargetType; constructor(target: TargetType); process(name: string, stream: Readable, info: FileInfo): Promise; } \ No newline at end of file diff --git a/DiscStorage.js b/DiscStorage.js index fd16237..d42d60e 100644 --- a/DiscStorage.js +++ b/DiscStorage.js @@ -7,12 +7,12 @@ const os = require("os"); const fs = require("fs"); class DiscStorage { - target; + #target; constructor(target) { - this.target = target; + this.#target = target; } process(name, stream, info) { - const target = this.target; + const target = this.#target; const file = new FileInternal(name, info); const saveLocation = typeof target === "function" ? target(file) : target; const filePath = path.join(saveLocation?.directory || os.tmpdir(), saveLocation?.fileName || file.originalName); diff --git a/FieldParserNoSchema.d.ts b/FieldParserNoSchema.d.ts new file mode 100644 index 0000000..4d38f48 --- /dev/null +++ b/FieldParserNoSchema.d.ts @@ -0,0 +1,5 @@ +import { FieldParser } from "./index"; + +export declare class FieldParserNoSchema implements FieldParser { + parseField(name: string, value: any): any; +} \ No newline at end of file diff --git a/FieldParserNoSchema.js b/FieldParserNoSchema.js new file mode 100644 index 0000000..04d37e0 --- /dev/null +++ b/FieldParserNoSchema.js @@ -0,0 +1,9 @@ +"use strict"; + +class FieldParserNoSchema { + parseField(name, value) { + return value; + } +} + +exports.FieldParserNoSchema = FieldParserNoSchema; \ No newline at end of file diff --git a/FieldParserWithSchema.d.ts b/FieldParserWithSchema.d.ts new file mode 100644 index 0000000..e7491a2 --- /dev/null +++ b/FieldParserWithSchema.d.ts @@ -0,0 +1,7 @@ +import { Dictionary, FieldParser } from "./index"; + +export declare class FieldParserWithSchema implements FieldParser { + #props: Dictionary; + constructor(props: Dictionary); + parseField(name: string, value: any): any; +} \ No newline at end of file diff --git a/FieldParserWithSchema.js b/FieldParserWithSchema.js new file mode 100644 index 0000000..c88aa42 --- /dev/null +++ b/FieldParserWithSchema.js @@ -0,0 +1,20 @@ +"use strict"; + +class FieldParserWithSchema { + #props; + constructor(props) { + this.#props = props; + } + parseField(name, value) { + if (this.#props[name]?.type !== "string") { + try { + return JSON.parse(value); + } catch { + void 0; + } + } + return value; + } +} + +exports.FieldParserWithSchema = FieldParserWithSchema; \ No newline at end of file diff --git a/index.d.ts b/index.d.ts index 41827c7..f56f2fe 100644 --- a/index.d.ts +++ b/index.d.ts @@ -15,7 +15,7 @@ export interface File { data: Buffer | undefined; error: Error | undefined; } -export declare type FileHandler = (name: string, stream: Readable, info: FileInfo) => File | Promise; +export type FileHandler = (name: string, stream: Readable, info: FileInfo) => File | Promise; export interface StorageOption { process: FileHandler; } @@ -23,12 +23,15 @@ export interface FileSaveTarget { directory?: string; fileName?: string; } -export declare type TargetType = FileSaveTarget | ((source: File) => FileSaveTarget); +export type TargetType = FileSaveTarget | ((source: File) => FileSaveTarget); export interface FormDataParserPluginOptions extends FastifyPluginOptions { limits?: Limits; storage?: StorageOption; } -export declare type FormDataParserPlugin = FastifyPluginAsync & Dictionary; +export type FormDataParserPlugin = FastifyPluginAsync & Dictionary; +export interface FieldParser { + parseField(name: string, value: any): any; +} declare module "fastify" { interface FastifyRequest { __files__?: Array; diff --git a/index.js b/index.js index b1befec..a21b669 100644 --- a/index.js +++ b/index.js @@ -1,23 +1,18 @@ "use strict"; const { StreamStorage } = require("./StreamStorage"); +const { FieldParserNoSchema } = require("./FieldParserNoSchema"); +const { FieldParserWithSchema } = require("./FieldParserWithSchema"); const busboy = require("busboy"); const { finished } = require("stream"); -const tryParse = value => { - try { - return JSON.parse(value); - } catch { - return value; - } -}; const formDataParser = async (instance, options) => { const { limits, storage = new StreamStorage() } = options; instance.addContentTypeParser("multipart/form-data", (request, message, done) => { const results = []; const body = new Map(); const props = request.routeOptions.schema?.body?.properties; - const parseField = props ? (name, value) => (props[name]?.type === "string" ? value : tryParse(value)) : (name, value) => value; + const parser = props ? new FieldParserWithSchema(props) : new FieldParserNoSchema(); const bus = busboy({ headers: message.headers, limits, defParamCharset: "utf8" }); bus.on("file", (name, stream, info) => { results.push(storage.process(name, stream, info)); @@ -33,7 +28,7 @@ const formDataParser = async (instance, options) => { body.set(name, [fileProp, JSON.stringify(info)]); }); bus.on("field", (name, value) => { - body.set(name, parseField(name, value)); + body.set(name, parser.parseField(name, value)); }); finished(bus, (err = null) => { Promise.all(results).then(files => { diff --git a/package-lock.json b/package-lock.json index 32f69a0..ce37d34 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,20 +1,20 @@ { "name": "formzilla", - "version": "3.2.12", + "version": "3.2.13", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "formzilla", - "version": "3.2.12", + "version": "3.2.13", "license": "ISC", "dependencies": { "busboy": "^1.6.0", "fastify": "^4.26.2" }, "devDependencies": { - "@types/busboy": "^1.5.3", - "ava": "^6.1.2", + "@types/busboy": "^1.5.4", + "ava": "^6.1.3", "form-data": "^4.0.0" } }, @@ -139,9 +139,9 @@ } }, "node_modules/@types/busboy": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@types/busboy/-/busboy-1.5.3.tgz", - "integrity": "sha512-YMBLFN/xBD8bnqywIlGyYqsNFXu6bsiY7h3Ae0kO17qEuTjsqeyYMRPSUDacIKIquws2Y6KjmxAyNx8xB3xQbw==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/busboy/-/busboy-1.5.4.tgz", + "integrity": "sha512-kG7WrUuAKK0NoyxfQHsVE6j1m01s6kMma64E+OZenQABMQyTJop1DumUWcLwAQ2JzpefU7PDYoRDKl8uZosFjw==", "dev": true, "dependencies": { "@types/node": "*" @@ -396,9 +396,9 @@ } }, "node_modules/ava": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/ava/-/ava-6.1.2.tgz", - "integrity": "sha512-WcpxJ8yZ7mk9ABTinD0IAjcemovSeVGjuuwZx0JS9johREWFeLTl8UP6wd7l6nmnrWqkKZdwaD71a/ocH4qPKw==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/ava/-/ava-6.1.3.tgz", + "integrity": "sha512-tkKbpF1pIiC+q09wNU9OfyTDYZa8yuWvU2up3+lFJ3lr1RmnYh2GBpPwzYUEB0wvTPIUysGjcZLNZr7STDviRA==", "dev": true, "dependencies": { "@vercel/nft": "^0.26.2", @@ -446,7 +446,7 @@ "ava": "entrypoints/cli.mjs" }, "engines": { - "node": "^18.18 || ^20.8 || ^21" + "node": "^18.18 || ^20.8 || ^21 || ^22" }, "peerDependencies": { "@ava/typescript": "*" @@ -2914,9 +2914,9 @@ "dev": true }, "@types/busboy": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@types/busboy/-/busboy-1.5.3.tgz", - "integrity": "sha512-YMBLFN/xBD8bnqywIlGyYqsNFXu6bsiY7h3Ae0kO17qEuTjsqeyYMRPSUDacIKIquws2Y6KjmxAyNx8xB3xQbw==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/busboy/-/busboy-1.5.4.tgz", + "integrity": "sha512-kG7WrUuAKK0NoyxfQHsVE6j1m01s6kMma64E+OZenQABMQyTJop1DumUWcLwAQ2JzpefU7PDYoRDKl8uZosFjw==", "dev": true, "requires": { "@types/node": "*" @@ -3104,9 +3104,9 @@ "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==" }, "ava": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/ava/-/ava-6.1.2.tgz", - "integrity": "sha512-WcpxJ8yZ7mk9ABTinD0IAjcemovSeVGjuuwZx0JS9johREWFeLTl8UP6wd7l6nmnrWqkKZdwaD71a/ocH4qPKw==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/ava/-/ava-6.1.3.tgz", + "integrity": "sha512-tkKbpF1pIiC+q09wNU9OfyTDYZa8yuWvU2up3+lFJ3lr1RmnYh2GBpPwzYUEB0wvTPIUysGjcZLNZr7STDviRA==", "dev": true, "requires": { "@vercel/nft": "^0.26.2", diff --git a/package.json b/package.json index 178cac6..9f4907f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "formzilla", - "version": "3.2.12", + "version": "3.2.13", "description": "Fastify plugin for parsing multipart/form data", "main": "index.js", "scripts": { @@ -32,8 +32,8 @@ "@fastify/swagger" ], "devDependencies": { - "@types/busboy": "^1.5.3", - "ava": "^6.1.2", + "@types/busboy": "^1.5.4", + "ava": "^6.1.3", "form-data": "^4.0.0" }, "ava": {