Skip to content

Commit 2571504

Browse files
committed
feat: normalize standard schema issues
1 parent fcecd7c commit 2571504

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

packages/router-core/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ export type {
312312
StrictOrFrom,
313313
} from './utils'
314314

315+
export { normalizeValidatorIssues } from './validators'
315316
export type {
316317
StandardSchemaValidatorProps,
317318
StandardSchemaValidator,

packages/router-core/src/validators.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ export interface AnyStandardSchemaValidateFailure {
2727

2828
export interface AnyStandardSchemaValidateIssue {
2929
readonly message: string
30+
readonly path?:
31+
| ReadonlyArray<PropertyKey | AnyStandardSchemaValidatePathSegment>
32+
| undefined
33+
}
34+
35+
export interface AnyStandardSchemaValidatePathSegment {
36+
readonly key: PropertyKey
3037
}
3138

3239
export interface AnyStandardSchemaValidateInput {
@@ -119,3 +126,59 @@ export type ResolveValidatorOutput<TValidator> = unknown extends TValidator
119126
: TValidator extends AnyValidatorObj
120127
? ResolveValidatorOutputFn<TValidator['parse']>
121128
: ResolveValidatorOutputFn<TValidator>
129+
130+
/**
131+
* Creates and returns the dot path of an issue if possible.
132+
*
133+
* @param issue The issue to get the dot path from.
134+
*
135+
* @returns The dot path or null.
136+
*/
137+
function getDotPath(issue: AnyStandardSchemaValidateIssue): string | null {
138+
if (issue.path?.length) {
139+
let dotPath = ''
140+
for (const item of issue.path) {
141+
const key = typeof item === 'object' ? item.key : item
142+
if (typeof key === 'string' || typeof key === 'number') {
143+
if (dotPath) {
144+
dotPath += `.${key}`
145+
} else {
146+
dotPath += key
147+
}
148+
} else {
149+
return null
150+
}
151+
}
152+
return dotPath
153+
}
154+
return null
155+
}
156+
157+
/**
158+
* Extract spec-guaranteed issue's fields from validation results.
159+
*
160+
* @param issues Standard Schema validation issues.
161+
*
162+
* @returns Normalized issues, with root issues and issues by path.
163+
*/
164+
export function normalizeValidatorIssues(
165+
issues: ReadonlyArray<AnyStandardSchemaValidateIssue>,
166+
) {
167+
const pathlessIssues: Array<string> = []
168+
const issueMap: Record<string, Array<string>> = {}
169+
170+
for (const issue of issues) {
171+
const dotPath = getDotPath(issue)
172+
if (dotPath) {
173+
if (issueMap[dotPath]) {
174+
issueMap[dotPath].push(issue.message)
175+
} else {
176+
issueMap[dotPath] = [issue.message]
177+
}
178+
} else {
179+
pathlessIssues.push(issue.message)
180+
}
181+
}
182+
183+
return { root: pathlessIssues, issues: issueMap }
184+
}

0 commit comments

Comments
 (0)