Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: TypeScript #899

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Enhance typings
  • Loading branch information
tommyhtran committed Dec 16, 2022
commit c089dbcbbb6a9c0eba4cbea62702b723c795f38e
22 changes: 4 additions & 18 deletions src/Formidable.ts
Original file line number Diff line number Diff line change
@@ -35,7 +35,7 @@ const DEFAULT_OPTIONS: IFormidableOptions = {
enabledPlugins: [octetstream, querystring, multipart, json],
fileWriteStreamHandler: null,
defaultInvalidName: 'invalid-name',
filter(_part) {
filter(_part: IPart) {
return true;
},
filename: undefined,
@@ -71,10 +71,10 @@ class IncomingForm extends EventEmitter {
uploadDir: string;
error: any;
headers: http.IncomingHttpHeaders | null;
type: string | null;
type: string | null | undefined;
bytesExpected: number | null;
bytesReceived: number | null;
_parser: JSONParser | DummyParser | MultipartParser | OctetStreamParser | QueryStringParser;
_parser: JSONParser | DummyParser | MultipartParser | OctetStreamParser | QueryStringParser | null;
req: http.IncomingMessage | null;
_flushing: number;
_fieldsSize: number;
@@ -144,8 +144,6 @@ class IncomingForm extends EventEmitter {
errors.pluginFunction,
);
}
const a = plugin.bind(this);
type b = typeof a;
this._plugins.push(plugin.bind(this));
return this;
}
@@ -179,7 +177,7 @@ class IncomingForm extends EventEmitter {
return true;
}

parse(req: http.IncomingMessage, cb: (err: Error, fields: IFields, files: IFiles) => void) {
parse(req: http.IncomingMessage, cb: (err: Error | null, fields: IFields, files: IFiles) => void) {
this.req = req;

// Setup callback first, so we don't miss anything from data events emitted immediately.
@@ -202,18 +200,6 @@ class IncomingForm extends EventEmitter {
} else {
this.fields[name] = value;
}

/*
if (this.type === 'multipart' || this.type === 'urlencoded') {
if (!hasOwnProp(this.fields, name)) {
this.fields[name] = [value];
} else {
this.fields[name].push(value);
}
} else {
this.fields[name] = value;
}
*/
});
this.on('file', (name: string, file: IFile) => {
if (!hasOwnProp(files, name)) {
2 changes: 1 addition & 1 deletion src/PersistentFile.ts
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ class PersistentFile extends EventEmitter implements IFile {
mimetype: IFile['mimetype'];
hashAlgorithm: IFile['hashAlgorithm'];

constructor({ filepath, newFilename, originalFilename, mimetype, hashAlgorithm }: Partial<IFile>) {
constructor({ filepath, newFilename, originalFilename, mimetype, hashAlgorithm }: Pick<IFile, "filepath" | "newFilename" | "originalFilename" | "mimetype" | "hashAlgorithm">) {
super();

this.lastModifiedDate = null;
2 changes: 1 addition & 1 deletion src/VolatileFile.ts
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ class VolatileFile extends EventEmitter implements IFile {
hashAlgorithm: IFile['hashAlgorithm'];
createFileWriteStream: IFile['createFileWriteStream'];

constructor({ filepath, newFilename, originalFilename, mimetype, hashAlgorithm, createFileWriteStream }: Partial<IFile>) {
constructor({ filepath, newFilename, originalFilename, mimetype, hashAlgorithm, createFileWriteStream }: Pick<IFile, "filepath" | "newFilename" | "originalFilename" | "mimetype" | "hashAlgorithm" | "createFileWriteStream">) {
super();

this.lastModifiedDate = null;
18 changes: 18 additions & 0 deletions src/parsers/Multipart.ts
Original file line number Diff line number Diff line change
@@ -42,6 +42,24 @@ function lower(c: any) {

export const STATES = Object.assign({}, STATE);

export type MultipartParserContext = {
name: string;
buffer?: Buffer;
start?: number;
end?: number;
}

interface MultipartParser {
push(context: MultipartParserContext, encoding?: BufferEncoding): boolean;

on(event: 'close', listener: () => void): this;
on(event: 'data', listener: (context: {}) => void): this;
on(event: 'end', listener: () => void): this;
on(event: 'readable', listener: () => void): this;
on(event: 'error', listener: (err: Error) => void): this;
on(event: string | symbol, listener: (...args: any[]) => void): this;
}

class MultipartParser extends Transform {
boundary: Buffer | null;
boundaryChars: any;
36 changes: 11 additions & 25 deletions src/plugins/multipart.ts
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@

import { Stream } from 'node:stream';
import MultipartParser from '../parsers/Multipart';
import type { MultipartParserContext } from '../parsers/Multipart';
import * as errors from '../FormidableError';
import FormidableError from '../FormidableError';
import type { Formidable, IFormidableOptions, IPart } from '../types'
@@ -51,7 +52,7 @@ function createInitMultipart(boundary: string) {
parser.initWithBoundary(boundary);

// eslint-disable-next-line max-statements, consistent-return
parser.on('data', ({ name, buffer, start, end }) => {
parser.on('data', ({ name, buffer, start, end }: MultipartParserContext) => {
if (name === 'partBegin') {
part = new Stream();
part.readable = true;
@@ -87,25 +88,6 @@ function createInitMultipart(boundary: string) {
} else if (headerField === 'content-type') {
part.mimetype = headerValue;
} else if (headerField === 'content-transfer-encoding') {
/*
const lowercaseContentTransferEncoding = headerValue.toLowerCase();
if (lowercaseContentTransferEncoding === 'binary' ||
lowercaseContentTransferEncoding === '7bit' ||
lowercaseContentTransferEncoding === '8bit' ||
lowercaseContentTransferEncoding === 'utf-8' ||
lowercaseContentTransferEncoding === 'base64'
) {
part.transferEncoding = lowercaseContentTransferEncoding;
} else {
return this._error(
new FormidableError(
'unknown transfer-encoding1',
errors.unknownTransferEncoding,
501,
),
);
}
*/
part.transferEncoding = headerValue.toLowerCase();
}

@@ -117,24 +99,28 @@ function createInitMultipart(boundary: string) {
case '7bit':
case '8bit':
case 'utf-8': {
const dataPropagation = (ctx: any) => {
const dataPropagation = (ctx: MultipartParserContext) => {
if (ctx.name === 'partData') {
part.emit('data', ctx.buffer.slice(ctx.start, ctx.end));
}
};
const dataStopPropagation = (ctx: any) => {
const dataStopPropagation = (ctx: MultipartParserContext) => {
if (ctx.name === 'partEnd') {
part.emit('end');
parser.off('data', dataPropagation);
parser.off('data', dataStopPropagation);
}
};
parser.on('data', dataPropagation);
parser.on('data', (ctx: MultipartParserContext) => {
if (ctx.name === 'partData') {
part.emit('data', ctx.buffer.slice(ctx.start, ctx.end));
}
});
parser.on('data', dataStopPropagation);
break;
}
case 'base64': {
const dataPropagation = (ctx: any) => {
const dataPropagation = (ctx: MultipartParserContext) => {
if (ctx.name === 'partData') {
part.transferBuffer += ctx.buffer
.slice(ctx.start, ctx.end)
@@ -157,7 +143,7 @@ function createInitMultipart(boundary: string) {
part.transferBuffer = part.transferBuffer.substring(offset);
}
};
const dataStopPropagation = (ctx: any) => {
const dataStopPropagation = (ctx: MultipartParserContext) => {
if (ctx.name === 'partEnd') {
part.emit('data', Buffer.from(part.transferBuffer, 'base64'));
part.emit('end');
9 changes: 4 additions & 5 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@ export interface IFormidableOptions {
enabledPlugins: FormidablePlugin[];
fileWriteStreamHandler: (() => Writable) | null;
defaultInvalidName: string;
filter(_part: any): boolean;
filter(_part: IPart): boolean;
filename: ((name: string, ext: string, part: Pick<IPart, 'originalFilename' | 'mimetype'>, form: Formidable) => string) | undefined;
}

@@ -41,7 +41,7 @@ export interface IPart extends Stream {
name?: string | null;
originalFilename?: string | null;
mimetype?: string | null;
transferEncoding?: BufferEncoding | '7bit' | '8bit';
transferEncoding?: BufferEncoding;
transferBuffer?: string
}

@@ -55,7 +55,7 @@ export interface IFile {
/**
* Unknown
*/
length: null;
length: number | null;

/**
* The path this file is being written to. You can modify this in the `'fileBegin'` event in case
@@ -117,8 +117,7 @@ export interface IFile {
on(event: "end", listener: () => void): this;
}

interface FileJSON extends Pick<IFile, "size" | "originalFilename" | "mimetype" | "hash">, Partial<Pick<IFile, "filepath">> {
length: number;
interface FileJSON extends Pick<IFile, "size" | "length" | "originalFilename" | "newFilename" | "mimetype" | "hash">, Partial<Pick<IFile, "filepath">> {
mimetype: string | null;
mtime?: Date | null;
}