Skip to content

Commit 15abf21

Browse files
authored
refactor(zod/v4): replace z.function with z.custom (#10602)
* test: add function validation tests * refactor(zod/v4): replace `z.function` with `z.custom`
1 parent e215266 commit 15abf21

File tree

5 files changed

+110
-197
lines changed

5 files changed

+110
-197
lines changed

packages/rspack-test-tools/tests/Validation.test.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,29 @@ describe("Validation", () => {
147147
`);
148148
}
149149
);
150+
151+
createTestCase(
152+
"function type",
153+
{
154+
ignoreWarnings: [new Map()],
155+
output: {
156+
devtoolModuleFilenameTemplate: new Set()
157+
}
158+
},
159+
message => {
160+
throw new Error("should not have error");
161+
},
162+
"loose",
163+
log => {
164+
expect(log).toMatchInlineSnapshot(`
165+
Array [
166+
Invalid configuration object. Rspack has been initialized using a configuration object that does not match the API schema.
167+
- Expected string, received set at "output.devtoolModuleFilenameTemplate", or Expected function, received set at "output.devtoolModuleFilenameTemplate"
168+
- Input not instance of RegExp at "ignoreWarnings[0]", or Expected function, received map at "ignoreWarnings[0]",
169+
]
170+
`);
171+
}
172+
);
150173
});
151174

152175
describe("strict", () => {
@@ -189,6 +212,29 @@ describe("Validation", () => {
189212
throw new Error("should not have log");
190213
}
191214
);
215+
216+
createTestCase(
217+
"function type",
218+
{
219+
ignoreWarnings: [new Map()],
220+
output: {
221+
devtoolModuleFilenameTemplate: new Set(),
222+
filename: []
223+
}
224+
},
225+
message => {
226+
expect(message).toMatchInlineSnapshot(`
227+
Invalid configuration object. Rspack has been initialized using a configuration object that does not match the API schema.
228+
- Expected string, received array at "output.filename", or Expected function, received array at "output.filename"
229+
- Expected string, received set at "output.devtoolModuleFilenameTemplate", or Expected function, received set at "output.devtoolModuleFilenameTemplate"
230+
- Input not instance of RegExp at "ignoreWarnings[0]", or Expected function, received map at "ignoreWarnings[0]"
231+
`);
232+
},
233+
"strict",
234+
log => {
235+
throw new Error("should not have log");
236+
}
237+
);
192238
});
193239

194240
describe("default (strict)", () => {
@@ -229,5 +275,27 @@ describe("Validation", () => {
229275
throw new Error("should not have log");
230276
}
231277
);
278+
279+
createTestCase(
280+
"function type",
281+
{
282+
ignoreWarnings: [new Map()],
283+
output: {
284+
devtoolModuleFilenameTemplate: new Set(),
285+
filename: []
286+
}
287+
},
288+
message => {
289+
expect(message).toMatchInlineSnapshot(`
290+
Invalid configuration object. Rspack has been initialized using a configuration object that does not match the API schema.
291+
- Expected string, received array at "output.filename", or Expected function, received array at "output.filename"
292+
- Expected string, received set at "output.devtoolModuleFilenameTemplate", or Expected function, received set at "output.devtoolModuleFilenameTemplate"
293+
- Input not instance of RegExp at "ignoreWarnings[0]", or Expected function, received map at "ignoreWarnings[0]"
294+
`);
295+
},
296+
log => {
297+
throw new Error("should not have log");
298+
}
299+
);
232300
});
233301
});

packages/rspack/src/builtin-plugin/IgnorePlugin.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
} from "@rspack/binding";
55
import { z } from "zod";
66

7+
import { anyFunction } from "../config/utils";
78
import { validate } from "../util/validate";
89
import { create } from "./base";
910

@@ -26,7 +27,7 @@ const IgnorePluginOptions = z.union([
2627
resourceRegExp: z.instanceof(RegExp)
2728
}),
2829
z.object({
29-
checkResource: z.function(z.tuple([z.string(), z.string()]), z.boolean())
30+
checkResource: anyFunction
3031
})
3132
]) satisfies z.ZodType<IgnorePluginOptions>;
3233

packages/rspack/src/builtin-plugin/html-plugin/options.ts

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { z } from "zod";
22
import { Compilation } from "../../Compilation";
3+
import { anyFunction } from "../../config/utils";
34
import { validate } from "../../util/validate";
45

56
const compilationOptionsMap: WeakMap<Compilation, HtmlRspackPluginOptions> =
@@ -9,23 +10,15 @@ export type TemplateRenderFunction = (
910
params: Record<string, any>
1011
) => string | Promise<string>;
1112

12-
const templateRenderFunction = z
13-
.function()
14-
.args(z.record(z.string(), z.any()))
15-
.returns(
16-
z.string().or(z.promise(z.string()))
17-
) satisfies z.ZodType<TemplateRenderFunction>;
13+
const templateRenderFunction =
14+
anyFunction satisfies z.ZodType<TemplateRenderFunction>;
1815

1916
export type TemplateParamFunction = (
2017
params: Record<string, any>
2118
) => Record<string, any> | Promise<Record<string, any>>;
2219

23-
const templateParamFunction = z
24-
.function()
25-
.args(z.record(z.string(), z.any()))
26-
.returns(
27-
z.record(z.string(), z.any()).or(z.promise(z.record(z.string(), z.any())))
28-
) satisfies z.ZodType<TemplateParamFunction>;
20+
const templateParamFunction =
21+
anyFunction satisfies z.ZodType<TemplateParamFunction>;
2922

3023
export type HtmlRspackPluginOptions = {
3124
/** The title to use for the generated HTML document. */
@@ -120,13 +113,8 @@ export type HtmlRspackPluginOptions = {
120113
[key: string]: any;
121114
};
122115

123-
const templateFilenameFunction = z
124-
.function()
125-
.args(z.string())
126-
.returns(z.string());
127-
128116
const pluginOptionsSchema = z.object({
129-
filename: z.string().or(templateFilenameFunction).optional(),
117+
filename: z.string().or(anyFunction).optional(),
130118
template: z
131119
.string()
132120
.refine(

packages/rspack/src/config/utils.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
ZodUnion,
1919
type ZodUnionOptions,
2020
addIssueToContext,
21+
getParsedType,
2122
z
2223
} from "zod";
2324
import type { RspackOptions } from "./types";
@@ -222,3 +223,10 @@ export class ZodRspackCrossChecker<T> extends ZodType<T> {
222223
return root.data;
223224
}
224225
}
226+
227+
export const anyFunction = z.custom<(...args: unknown[]) => any>(
228+
data => typeof data === "function",
229+
// Make the similar error message as zod v3
230+
// https://github.com/colinhacks/zod/blob/64bfb7001cf6f2575bf38b5e6130bc73b4b0e371/packages/zod/src/v3/types.ts#L3821-L3828
231+
input => ({ message: `Expected function, received ${getParsedType(input)}` })
232+
);

0 commit comments

Comments
 (0)