Skip to content

Commit a044af2

Browse files
authored
Expose "only" config as public API after renaming from "validate" (#109)
1 parent 5406457 commit a044af2

File tree

5 files changed

+122
-25
lines changed

5 files changed

+122
-25
lines changed

packages/core/src/client.ts

+22-18
Original file line numberDiff line numberDiff line change
@@ -123,24 +123,28 @@ const request = (userConfig: Config = {}): Promise<unknown> => {
123123
/**
124124
* Resolve the configuration.
125125
*/
126-
const resolveConfig = (config: Config): Config => ({
127-
...config,
128-
timeout: config.timeout ?? axiosClient.defaults['timeout'] ?? 30000,
129-
precognitive: config.precognitive !== false,
130-
fingerprint: typeof config.fingerprint === 'undefined'
131-
? requestFingerprintResolver(config, axiosClient)
132-
: config.fingerprint,
133-
headers: {
134-
...config.headers,
135-
'Content-Type': resolveContentType(config),
136-
...config.precognitive !== false ? {
137-
Precognition: true,
138-
} : {},
139-
...config.validate ? {
140-
'Precognition-Validate-Only': Array.from(config.validate).join(),
141-
} : {},
142-
},
143-
})
126+
const resolveConfig = (config: Config): Config => {
127+
const only = config.only ?? config.validate
128+
129+
return {
130+
...config,
131+
timeout: config.timeout ?? axiosClient.defaults['timeout'] ?? 30000,
132+
precognitive: config.precognitive !== false,
133+
fingerprint: typeof config.fingerprint === 'undefined'
134+
? requestFingerprintResolver(config, axiosClient)
135+
: config.fingerprint,
136+
headers: {
137+
...config.headers,
138+
'Content-Type': resolveContentType(config),
139+
...config.precognitive !== false ? {
140+
Precognition: true,
141+
} : {},
142+
...only ? {
143+
'Precognition-Validate-Only': Array.from(only).join(),
144+
} : {},
145+
},
146+
}
147+
}
144148

145149
/**
146150
* Determine if the status is successful.

packages/core/src/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ export type SimpleValidationErrors = Record<string, string>
88

99
export type Config = AxiosRequestConfig & {
1010
precognitive?: boolean,
11+
/** @deprecated Use `only` instead */
1112
validate?: Iterable<string> | ArrayLike<string>,
13+
only?: Iterable<string> | ArrayLike<string>,
1214
fingerprint?: string | null,
1315
onBefore?: () => boolean | undefined,
1416
onStart?: () => void,

packages/core/src/validator.ts

+11-7
Original file line numberDiff line numberDiff line change
@@ -216,37 +216,37 @@ export const createValidator = (callback: ValidationCallback, initialData: Recor
216216
...instanceConfig,
217217
}
218218

219-
const validate = Array.from(config.validate ?? touched)
219+
const only = Array.from(config.only ?? config.validate ?? touched)
220220

221221
return {
222222
...instanceConfig,
223223
// Axios has special rules for merging global and local config. We
224224
// use their merge function here to make sure things like headers
225225
// merge in an expected way.
226226
...mergeConfig(globalConfig, instanceConfig),
227-
validate,
227+
only,
228228
timeout: config.timeout ?? 5000,
229229
onValidationError: (response, axiosError) => {
230230
[
231-
...setValidated([...validated, ...validate]),
232-
...setErrors(merge(omit({ ...errors }, validate), response.data.errors)),
231+
...setValidated([...validated, ...only]),
232+
...setErrors(merge(omit({ ...errors }, only), response.data.errors)),
233233
].forEach((listener) => listener())
234234

235235
return config.onValidationError
236236
? config.onValidationError(response, axiosError)
237237
: Promise.reject(axiosError)
238238
},
239239
onSuccess: (response) => {
240-
setValidated([...validated, ...validate]).forEach((listener) => listener())
240+
setValidated([...validated, ...only]).forEach((listener) => listener())
241241

242242
return config.onSuccess
243243
? config.onSuccess(response)
244244
: response
245245
},
246246
onPrecognitionSuccess: (response) => {
247247
[
248-
...setValidated([...validated, ...validate]),
249-
...setErrors(omit({ ...errors }, validate)),
248+
...setValidated([...validated, ...only]),
249+
...setErrors(omit({ ...errors }, only)),
250250
].forEach((listener) => listener())
251251

252252
return config.onPrecognitionSuccess
@@ -294,6 +294,10 @@ export const createValidator = (callback: ValidationCallback, initialData: Recor
294294
*/
295295
const validate = (name?: string | NamedInputEvent, value?: unknown, config?: ValidationConfig): void => {
296296
if (typeof name === 'undefined') {
297+
const only = Array.from(config?.only ?? config?.validate ?? [])
298+
299+
setTouched([...touched, ...only]).forEach((listener) => listener())
300+
297301
validator(config ?? {})
298302

299303
return

packages/core/tests/client.test.js

+16
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,22 @@ it('can provide input names to validate via config', async () => {
187187
return Promise.resolve({ headers: { precognition: 'true' } })
188188
})
189189

190+
await client.get('https://laravel.com', {}, {
191+
only: ['username', 'email'],
192+
})
193+
194+
expect(config.headers['Precognition-Validate-Only']).toBe('username,email')
195+
})
196+
197+
it('continues to support the deprecated "validate" key as fallback of "only"', async () => {
198+
expect.assertions(1)
199+
200+
let config
201+
axios.request.mockImplementationOnce((c) => {
202+
config = c
203+
return Promise.resolve({ headers: { precognition: 'true' } })
204+
})
205+
190206
await client.get('https://laravel.com', {}, {
191207
validate: ['username', 'email'],
192208
})

packages/core/tests/validator.test.js

+71
Original file line numberDiff line numberDiff line change
@@ -674,3 +674,74 @@ it('does not cancel submit requests with custom abort signal', async () => {
674674

675675
await assertPendingValidateDebounceAndClear()
676676
})
677+
678+
it('supports async validate with only key for untouched values', async () => {
679+
let config
680+
axios.request.mockImplementation((c) => {
681+
config = c
682+
683+
return Promise.resolve({ headers: { precognition: 'true', 'precognition-success': 'true' }, status: 204, data: '' })
684+
})
685+
const validator = createValidator((client) => client.post('/foo', {}))
686+
687+
validator.validate({
688+
only: ['name', 'email'],
689+
})
690+
691+
expect(config.headers['Precognition-Validate-Only']).toBe('name,email')
692+
693+
await assertPendingValidateDebounceAndClear()
694+
})
695+
696+
it('supports async validate with depricated validate key for untouched values', async () => {
697+
let config
698+
axios.request.mockImplementation((c) => {
699+
config = c
700+
701+
return Promise.resolve({ headers: { precognition: 'true', 'precognition-success': 'true' }, status: 204, data: '' })
702+
})
703+
const validator = createValidator((client) => client.post('/foo', {}))
704+
705+
validator.validate({
706+
validate: ['name', 'email'],
707+
})
708+
709+
expect(config.headers['Precognition-Validate-Only']).toBe('name,email')
710+
711+
await assertPendingValidateDebounceAndClear()
712+
})
713+
714+
it('does not include already touched keys when specifying keys via only', async () => {
715+
let config
716+
axios.request.mockImplementation((c) => {
717+
config = c
718+
719+
return Promise.resolve({ headers: { precognition: 'true', 'precognition-success': 'true' }, status: 204, data: '' })
720+
})
721+
const validator = createValidator((client) => client.post('/foo', {}))
722+
723+
724+
validator.touch(['email']).validate({
725+
only: ['name'],
726+
})
727+
728+
expect(config.headers['Precognition-Validate-Only']).toBe('name')
729+
730+
await assertPendingValidateDebounceAndClear()
731+
})
732+
733+
it('marks fields as touched when the input has been included in validation', async () => {
734+
axios.request.mockImplementation(() => {
735+
return Promise.resolve({ headers: { precognition: 'true', 'precognition-success': 'true' }, status: 204, data: '' })
736+
})
737+
const validator = createValidator((client) => client.post('/foo', {}))
738+
739+
740+
validator.touch(['email']).validate({
741+
only: ['name'],
742+
})
743+
744+
expect(validator.touched()).toEqual(['email', 'name'])
745+
746+
await assertPendingValidateDebounceAndClear()
747+
})

0 commit comments

Comments
 (0)