@@ -27,6 +27,13 @@ export interface AnyStandardSchemaValidateFailure {
27
27
28
28
export interface AnyStandardSchemaValidateIssue {
29
29
readonly message : string
30
+ readonly path ?:
31
+ | ReadonlyArray < PropertyKey | AnyStandardSchemaValidatePathSegment >
32
+ | undefined
33
+ }
34
+
35
+ export interface AnyStandardSchemaValidatePathSegment {
36
+ readonly key : PropertyKey
30
37
}
31
38
32
39
export interface AnyStandardSchemaValidateInput {
@@ -119,3 +126,59 @@ export type ResolveValidatorOutput<TValidator> = unknown extends TValidator
119
126
: TValidator extends AnyValidatorObj
120
127
? ResolveValidatorOutputFn < TValidator [ 'parse' ] >
121
128
: 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