Skip to content

Commit a4aed41

Browse files
wyattjohabhi12299
authored andcommitted
refactor: extracted zod configuration (vercel#70478)
<!-- Thanks for opening a PR! Your contribution is much appreciated. To make sure your PR is handled as smoothly as possible we request that you follow the checklist sections below. Choose the right checklist for the change(s) that you're making: ## For Contributors ### Improving Documentation - Run `pnpm prettier-fix` to fix formatting issues before opening the PR. - Read the Docs Contribution Guide to ensure your contribution follows the docs guidelines: https://nextjs.org/docs/community/contribution-guide ### Adding or Updating Examples - The "examples guidelines" are followed from our contributing doc https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md - Make sure the linting passes by running `pnpm build && pnpm lint`. See https://github.com/vercel/next.js/blob/canary/contributing/repository/linting.md ### Fixing a bug - Related issues linked using `fixes #number` - Tests added. See: https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ### Adding a feature - Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. (A discussion must be opened, see https://github.com/vercel/next.js/discussions/new?category=ideas) - Related issues/discussions are linked using `fixes #number` - e2e tests added (https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs) - Documentation added - Telemetry added. In case of a feature if it's used or not. - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ## For Maintainers - Minimal description (aim for explaining to someone not on the team to understand the PR) - When linking to a Slack thread, you might want to share details of the conclusion - Link both the Linear (Fixes NEXT-xxx) and the GitHub issues - Add review comments if necessary to explain to the reviewer the logic behind a change ### What? ### Why? ### How? Closes NEXT- Fixes # --> This just moves the zod helper utilities into it's own file so we can re-use it in future PR's.
1 parent 4d1e753 commit a4aed41

File tree

2 files changed

+76
-66
lines changed

2 files changed

+76
-66
lines changed

packages/next/src/server/config.ts

Lines changed: 9 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -22,87 +22,28 @@ import { setHttpClientAndAgentOptions } from './setup-http-agent-env'
2222
import { pathHasPrefix } from '../shared/lib/router/utils/path-has-prefix'
2323
import { matchRemotePattern } from '../shared/lib/match-remote-pattern'
2424

25-
import { ZodParsedType, util as ZodUtil } from 'next/dist/compiled/zod'
26-
import type { ZodError, ZodIssue } from 'next/dist/compiled/zod'
25+
import type { ZodError } from 'next/dist/compiled/zod'
2726
import { hasNextSupport } from '../server/ci-info'
2827
import { transpileConfig } from '../build/next-config-ts/transpile-config'
2928
import { dset } from '../shared/lib/dset'
29+
import { normalizeZodErrors } from '../shared/lib/zod'
3030

3131
export { normalizeConfig } from './config-shared'
3232
export type { DomainLocale, NextConfig } from './config-shared'
3333

34-
function processZodErrorMessage(issue: ZodIssue) {
35-
let message = issue.message
36-
37-
let path = ''
38-
39-
if (issue.path.length > 0) {
40-
if (issue.path.length === 1) {
41-
const identifier = issue.path[0]
42-
if (typeof identifier === 'number') {
43-
// The first identifier inside path is a number
44-
path = `index ${identifier}`
45-
} else {
46-
path = `"${identifier}"`
47-
}
48-
} else {
49-
// joined path to be shown in the error message
50-
path = `"${issue.path.reduce<string>((acc, cur) => {
51-
if (typeof cur === 'number') {
52-
// array index
53-
return `${acc}[${cur}]`
54-
}
55-
if (cur.includes('"')) {
56-
// escape quotes
57-
return `${acc}["${cur.replaceAll('"', '\\"')}"]`
58-
}
59-
// dot notation
60-
const separator = acc.length === 0 ? '' : '.'
61-
return acc + separator + cur
62-
}, '')}"`
63-
}
64-
}
65-
66-
if (
67-
issue.code === 'invalid_type' &&
68-
issue.received === ZodParsedType.undefined
69-
) {
70-
// missing key in object
71-
return `${path} is missing, expected ${issue.expected}`
72-
}
73-
if (issue.code === 'invalid_enum_value') {
74-
// Remove "Invalid enum value" prefix from zod default error message
75-
return `Expected ${ZodUtil.joinValues(issue.options)}, received '${
76-
issue.received
77-
}' at ${path}`
78-
}
79-
80-
return message + (path ? ` at ${path}` : '')
81-
}
82-
83-
function normalizeZodErrors(
34+
function normalizeNextConfigZodErrors(
8435
error: ZodError<NextConfig>
8536
): [errorMessages: string[], shouldExit: boolean] {
8637
let shouldExit = false
38+
const issues = normalizeZodErrors(error)
8739
return [
88-
error.issues.flatMap((issue) => {
89-
const messages = [processZodErrorMessage(issue)]
40+
issues.flatMap(({ issue, message }) => {
9041
if (issue.path[0] === 'images') {
9142
// We exit the build when encountering an error in the images config
9243
shouldExit = true
9344
}
9445

95-
if ('unionErrors' in issue) {
96-
issue.unionErrors
97-
.map(normalizeZodErrors)
98-
.forEach(([unionMessages, unionShouldExit]) => {
99-
messages.push(...unionMessages)
100-
// If any of the union results shows exit the build, we exit the build
101-
shouldExit = shouldExit || unionShouldExit
102-
})
103-
}
104-
105-
return messages
46+
return message
10647
}),
10748
shouldExit,
10849
]
@@ -1085,7 +1026,9 @@ export default async function loadConfig(
10851026
// error message header
10861027
const messages = [`Invalid ${configFileName} options detected: `]
10871028

1088-
const [errorMessages, shouldExit] = normalizeZodErrors(state.error)
1029+
const [errorMessages, shouldExit] = normalizeNextConfigZodErrors(
1030+
state.error
1031+
)
10891032
// ident list item
10901033
for (const error of errorMessages) {
10911034
messages.push(` ${error}`)

packages/next/src/shared/lib/zod.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import type { ZodError } from 'next/dist/compiled/zod'
2+
import { ZodParsedType, util, type ZodIssue } from 'next/dist/compiled/zod'
3+
4+
function processZodErrorMessage(issue: ZodIssue) {
5+
let message = issue.message
6+
7+
let path: string
8+
9+
if (issue.path.length > 0) {
10+
if (issue.path.length === 1) {
11+
const identifier = issue.path[0]
12+
if (typeof identifier === 'number') {
13+
// The first identifier inside path is a number
14+
path = `index ${identifier}`
15+
} else {
16+
path = `"${identifier}"`
17+
}
18+
} else {
19+
// joined path to be shown in the error message
20+
path = `"${issue.path.reduce<string>((acc, cur) => {
21+
if (typeof cur === 'number') {
22+
// array index
23+
return `${acc}[${cur}]`
24+
}
25+
if (cur.includes('"')) {
26+
// escape quotes
27+
return `${acc}["${cur.replaceAll('"', '\\"')}"]`
28+
}
29+
// dot notation
30+
const separator = acc.length === 0 ? '' : '.'
31+
return acc + separator + cur
32+
}, '')}"`
33+
}
34+
} else {
35+
path = ''
36+
}
37+
38+
if (
39+
issue.code === 'invalid_type' &&
40+
issue.received === ZodParsedType.undefined
41+
) {
42+
// Missing key in object.
43+
return `${path} is missing, expected ${issue.expected}`
44+
}
45+
46+
if (issue.code === 'invalid_enum_value') {
47+
// Remove "Invalid enum value" prefix from zod default error message
48+
return `Expected ${util.joinValues(issue.options)}, received '${
49+
issue.received
50+
}' at ${path}`
51+
}
52+
53+
return message + (path ? ` at ${path}` : '')
54+
}
55+
56+
export function normalizeZodErrors(error: ZodError) {
57+
return error.issues.flatMap((issue) => {
58+
const issues = [{ issue, message: processZodErrorMessage(issue) }]
59+
if ('unionErrors' in issue) {
60+
for (const unionError of issue.unionErrors) {
61+
issues.push(...normalizeZodErrors(unionError))
62+
}
63+
}
64+
65+
return issues
66+
})
67+
}

0 commit comments

Comments
 (0)