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

fix(types): make types better #1786

Merged
merged 1 commit into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
470 changes: 268 additions & 202 deletions package-lock.json

Large diffs are not rendered by default.

112 changes: 50 additions & 62 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,12 @@ const noop = () => {};
*/

/**
* @typedef {ReturnType<Compiler["watch"]>} MultiWatching
* @typedef {ReturnType<MultiCompiler["watch"]>} MultiWatching
*/

// TODO fix me after the next webpack release
/**
* @typedef {Compiler["outputFileSystem"] & { createReadStream?: import("fs").createReadStream, statSync?: import("fs").statSync, lstat?: import("fs").lstat, readFileSync?: import("fs").readFileSync }} OutputFileSystem
* @typedef {Object & { createReadStream?: import("fs").createReadStream, statSync?: import("fs").statSync, lstat?: import("fs").lstat, readFileSync?: import("fs").readFileSync }} OutputFileSystem
*/

/** @typedef {ReturnType<Compiler["getInfrastructureLogger"]>} Logger */
Expand Down Expand Up @@ -82,15 +83,23 @@ const noop = () => {};
* @property {Callback[]} callbacks
* @property {Options<RequestInternal, ResponseInternal>} options
* @property {Compiler | MultiCompiler} compiler
* @property {Watching | MultiWatching} watching
* @property {Watching | MultiWatching | undefined} watching
* @property {Logger} logger
* @property {OutputFileSystem} outputFileSystem
*/

/**
* @template {IncomingMessage} RequestInternal
* @template {ServerResponse} ResponseInternal
* @typedef {Record<string, string | number> | Array<{ key: string, value: number | string }> | ((req: RequestInternal, res: ResponseInternal, context: Context<RequestInternal, ResponseInternal>) => void | undefined | Record<string, string | number>) | undefined} Headers
* @typedef {WithoutUndefined<Context<RequestInternal, ResponseInternal>, "watching">} FilledContext
*/

/** @typedef {Record<string, string | number> | Array<{ key: string, value: number | string }>} NormalizedHeaders */

/**
* @template {IncomingMessage} RequestInternal
* @template {ServerResponse} ResponseInternal
* @typedef {NormalizedHeaders | ((req: RequestInternal, res: ResponseInternal, context: Context<RequestInternal, ResponseInternal>) => void | undefined | NormalizedHeaders) | undefined} Headers
*/

/**
Expand Down Expand Up @@ -161,6 +170,18 @@ const noop = () => {};
* @typedef {Middleware<RequestInternal, ResponseInternal> & AdditionalMethods<RequestInternal, ResponseInternal>} API
*/

/**
* @template T
* @template {keyof T} K
* @typedef {Omit<T, K> & Partial<T>} WithOptional
*/

/**
* @template T
* @template {keyof T} K
* @typedef {T & { [P in K]: NonNullable<T[P]> }} WithoutUndefined
*/

/**
* @template {IncomingMessage} RequestInternal
* @template {ServerResponse} ResponseInternal
Expand All @@ -186,7 +207,7 @@ function wdm(compiler, options = {}) {
}

/**
* @type {Context<RequestInternal, ResponseInternal>}
* @type {WithOptional<Context<RequestInternal, ResponseInternal>, "watching" | "outputFileSystem">}
*/
const context = {
state: false,
Expand All @@ -195,13 +216,7 @@ function wdm(compiler, options = {}) {
callbacks: [],
options,
compiler,
// @ts-ignore
// eslint-disable-next-line no-undefined
watching: undefined,
logger: compiler.getInfrastructureLogger("webpack-dev-middleware"),
// @ts-ignore
// eslint-disable-next-line no-undefined
outputFileSystem: undefined,
};

setupHooks(context);
Expand All @@ -216,11 +231,6 @@ function wdm(compiler, options = {}) {
if (/** @type {Compiler} */ (context.compiler).watching) {
context.watching = /** @type {Compiler} */ (context.compiler).watching;
} else {
/**
* @type {WatchOptions | WatchOptions[]}
*/
let watchOptions;

/**
* @param {Error | null | undefined} error
*/
Expand All @@ -237,69 +247,47 @@ function wdm(compiler, options = {}) {
if (
Array.isArray(/** @type {MultiCompiler} */ (context.compiler).compilers)
) {
watchOptions =
/** @type {MultiCompiler} */
(context.compiler).compilers.map(
/**
* @param {Compiler} childCompiler
* @returns {WatchOptions}
*/
(childCompiler) => childCompiler.options.watchOptions || {},
);

context.watching =
/** @type {MultiWatching} */
(
context.compiler.watch(
/** @type {WatchOptions}} */
(watchOptions),
errorHandler,
)
);
const compiler = /** @type {MultiCompiler} */ (context.compiler);
const watchOptions = compiler.compilers.map(
(childCompiler) => childCompiler.options.watchOptions || {},
);

context.watching = compiler.watch(watchOptions, errorHandler);
} else {
watchOptions =
/** @type {Compiler} */ (context.compiler).options.watchOptions || {};
const compiler = /** @type {Compiler} */ (context.compiler);
const watchOptions = compiler.options.watchOptions || {};

context.watching = /** @type {Watching} */ (
context.compiler.watch(watchOptions, errorHandler)
);
context.watching = compiler.watch(watchOptions, errorHandler);
}
}

const filledContext =
/** @type {FilledContext<RequestInternal, ResponseInternal>} */
(context);

const instance =
/** @type {API<RequestInternal, ResponseInternal>} */
(middleware(context));
(middleware(filledContext));

// API
/** @type {API<RequestInternal, ResponseInternal>} */
(instance).getFilenameFromUrl = (url, extra) =>
getFilenameFromUrl(context, url, extra);
instance.getFilenameFromUrl = (url, extra) =>
getFilenameFromUrl(filledContext, url, extra);

/** @type {API<RequestInternal, ResponseInternal>} */
(instance).waitUntilValid = (callback = noop) => {
ready(context, callback);
instance.waitUntilValid = (callback = noop) => {
ready(filledContext, callback);
};

/** @type {API<RequestInternal, ResponseInternal>} */
(instance).invalidate = (callback = noop) => {
ready(context, callback);
instance.invalidate = (callback = noop) => {
ready(filledContext, callback);

/**
* @type {NonNullable<Context<RequestInternal, ResponseInternal>["watching"]>}
*/
(context.watching).invalidate();
filledContext.watching.invalidate();
};

/** @type {API<RequestInternal, ResponseInternal>} */
(instance).close = (callback = noop) => {
/**
* @type {NonNullable<Context<RequestInternal, ResponseInternal>["watching"]>}
*/
(context.watching).close(callback);
instance.close = (callback = noop) => {
filledContext.watching.close(callback);
};

/** @type {API<RequestInternal, ResponseInternal>} */
(instance).context = context;
instance.context = filledContext;

return instance;
}
Expand Down
22 changes: 9 additions & 13 deletions src/middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const ready = require("./utils/ready");
/** @typedef {import("./index.js").NextFunction} NextFunction */
/** @typedef {import("./index.js").IncomingMessage} IncomingMessage */
/** @typedef {import("./index.js").ServerResponse} ServerResponse */
/** @typedef {import("./index.js").NormalizedHeaders} NormalizedHeaders */

/**
* @param {string} type
Expand All @@ -32,7 +33,7 @@ const BYTES_RANGE_REGEXP = /^ *bytes/i;
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("./index.js").Context<Request, Response>} context
* @param {import("./index.js").FilledContext<Request, Response>} context
* @return {import("./index.js").Middleware<Request, Response>}
*/
function wrapper(context) {
Expand Down Expand Up @@ -101,8 +102,7 @@ function wrapper(context) {
let { headers } = context.options;

if (typeof headers === "function") {
// @ts-ignore
headers = headers(req, res, context);
headers = /** @type {NormalizedHeaders} */ (headers(req, res, context));
}

/**
Expand All @@ -114,21 +114,15 @@ function wrapper(context) {
if (!Array.isArray(headers)) {
// eslint-disable-next-line guard-for-in
for (const name in headers) {
// @ts-ignore
allHeaders.push({ key: name, value: headers[name] });
}

headers = allHeaders;
}

headers.forEach(
/**
* @param {{key: string, value: any}} header
*/
(header) => {
setHeaderForResponse(res, header.key, header.value);
},
);
headers.forEach((header) => {
setHeaderForResponse(res, header.key, header.value);
});
}

if (!getHeaderFromResponse(res, "Content-Type")) {
Expand All @@ -152,7 +146,9 @@ function wrapper(context) {
setHeaderForResponse(res, "Accept-Ranges", "bytes");
}

const rangeHeader = getHeaderFromRequest(req, "range");
const rangeHeader =
/** @type {string} */
(getHeaderFromRequest(req, "range"));

let len = /** @type {import("fs").Stats} */ (extra.stats).size;
let offset = 0;
Expand Down
5 changes: 3 additions & 2 deletions src/utils/compatibleAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const escapeHtml = require("./escapeHtml");

/** @typedef {import("../index.js").IncomingMessage} IncomingMessage */
/** @typedef {import("../index.js").ServerResponse} ServerResponse */
/** @typedef {import("fs").ReadStream} ReadStream */

/**
* @typedef {Object} ExpectedRequest
Expand Down Expand Up @@ -37,7 +38,7 @@ function getHeaderNames(res) {
* @template {IncomingMessage} Request
* @param {Request} req
* @param {string} name
* @returns {string | undefined}
* @returns {string | string[] | undefined}
*/
function getHeaderFromRequest(req, name) {
// Express API
Expand All @@ -48,7 +49,6 @@ function getHeaderFromRequest(req, name) {
}

// Node.js API
// @ts-ignore
return req.headers[name];
}

Expand Down Expand Up @@ -256,6 +256,7 @@ async function send(req, res, filename, start, end, goNext, options) {
const isFsSupportsStream =
typeof options.outputFileSystem.createReadStream === "function";

/** @type {string | Buffer | ReadStream} */
let bufferOrStream;
let byteLength;

Expand Down
3 changes: 1 addition & 2 deletions src/utils/getFilenameFromUrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ const cacheStore = new WeakMap();
* @param {(value: T) => T} callback
* @returns {any}
*/
// @ts-ignore
const mem = (fn, { cache = new Map() } = {}, callback) => {
/**
* @param {any} arguments_
Expand Down Expand Up @@ -79,7 +78,7 @@ function decode(input) {
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("../index.js").Context<Request, Response>} context
* @param {import("../index.js").FilledContext<Request, Response>} context
* @param {string} url
* @param {Extra=} extra
* @returns {string | undefined}
Expand Down
2 changes: 1 addition & 1 deletion src/utils/getPaths.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("../index.js").Context<Request, Response>} context
* @param {import("../index.js").FilledContext<Request, Response>} context
*/
function getPaths(context) {
const { stats, options } = context;
Expand Down
2 changes: 1 addition & 1 deletion src/utils/ready.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("../index.js").Context<Request, Response>} context
* @param {import("../index.js").FilledContext<Request, Response>} context
* @param {(...args: any[]) => any} callback
* @param {Request} [req]
* @returns {void}
Expand Down
15 changes: 10 additions & 5 deletions src/utils/setupHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
/** @typedef {import("webpack").MultiCompiler} MultiCompiler */
/** @typedef {import("webpack").Stats} Stats */
/** @typedef {import("webpack").MultiStats} MultiStats */

/** @typedef {import("../index.js").IncomingMessage} IncomingMessage */
/** @typedef {import("../index.js").ServerResponse} ServerResponse */

/** @typedef {Configuration["stats"]} StatsOptions */
/** @typedef {{ children: Configuration["stats"][] }} MultiStatsOptions */
/** @typedef {Exclude<Configuration["stats"], boolean | string | undefined>} StatsObjectOptions */

/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("../index.js").Context<Request, Response>} context
* @param {import("../index.js").WithOptional<import("../index.js").Context<Request, Response>, "watching" | "outputFileSystem">} context
*/
function setupHooks(context) {
function invalid() {
Expand Down Expand Up @@ -155,9 +155,14 @@ function setupHooks(context) {
});
}

context.compiler.hooks.watchRun.tap("webpack-dev-middleware", invalid);
context.compiler.hooks.invalid.tap("webpack-dev-middleware", invalid);
context.compiler.hooks.done.tap("webpack-dev-middleware", done);
// eslint-disable-next-line prefer-destructuring
const compiler =
/** @type {import("../index.js").Context<Request, Response>} */
(context).compiler;

compiler.hooks.watchRun.tap("webpack-dev-middleware", invalid);
compiler.hooks.invalid.tap("webpack-dev-middleware", invalid);
compiler.hooks.done.tap("webpack-dev-middleware", done);
}

module.exports = setupHooks;
3 changes: 2 additions & 1 deletion src/utils/setupOutputFileSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const memfs = require("memfs");
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("../index.js").Context<Request, Response>} context
* @param {import("../index.js").WithOptional<import("../index.js").Context<Request, Response>, "watching" | "outputFileSystem">} context
*/
function setupOutputFileSystem(context) {
let outputFileSystem;
Expand Down Expand Up @@ -48,6 +48,7 @@ function setupOutputFileSystem(context) {
(context.compiler).compilers || [context.compiler];

for (const compiler of compilers) {
// @ts-ignore
compiler.outputFileSystem = outputFileSystem;
}

Expand Down
2 changes: 1 addition & 1 deletion src/utils/setupWriteToDisk.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const path = require("path");
/**
* @template {IncomingMessage} Request
* @template {ServerResponse} Response
* @param {import("../index.js").Context<Request, Response>} context
* @param {import("../index.js").WithOptional<import("../index.js").Context<Request, Response>, "watching" | "outputFileSystem">} context
*/
function setupWriteToDisk(context) {
/**
Expand Down