laravel-precognition
Advanced tools
Comparing version 0.5.6 to 0.5.7
@@ -43,3 +43,3 @@ import { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; | ||
touched(): Array<string>; | ||
validate(input?: string | NamedInputEvent, value?: unknown): Validator; | ||
validate(input?: string | NamedInputEvent | ValidationConfig, value?: unknown, config?: ValidationConfig): Validator; | ||
touch(input: string | NamedInputEvent | Array<string>): Validator; | ||
@@ -77,2 +77,5 @@ validating(): boolean; | ||
} | ||
declare module 'axios' { | ||
function mergeConfig(config1: AxiosRequestConfig, config2: AxiosRequestConfig): AxiosRequestConfig; | ||
} | ||
export {}; |
import { debounce, isEqual, get, set, omit, merge } from 'lodash-es'; | ||
import { client, isFile } from './client.js'; | ||
import { isAxiosError } from 'axios'; | ||
import { isAxiosError, isCancel, mergeConfig } from 'axios'; | ||
export const createValidator = (callback, initialData = {}) => { | ||
@@ -136,11 +136,27 @@ /** | ||
*/ | ||
const createValidator = () => debounce(() => { | ||
const createValidator = () => debounce((instanceConfig) => { | ||
callback({ | ||
get: (url, data = {}, config = {}) => client.get(url, parseData(data), resolveConfig(config, data)), | ||
post: (url, data = {}, config = {}) => client.post(url, parseData(data), resolveConfig(config, data)), | ||
patch: (url, data = {}, config = {}) => client.patch(url, parseData(data), resolveConfig(config, data)), | ||
put: (url, data = {}, config = {}) => client.put(url, parseData(data), resolveConfig(config, data)), | ||
delete: (url, data = {}, config = {}) => client.delete(url, parseData(data), resolveConfig(config, data)), | ||
}) | ||
.catch(error => isAxiosError(error) ? null : Promise.reject(error)); | ||
get: (url, data = {}, globalConfig = {}) => client.get(url, parseData(data), resolveConfig(globalConfig, instanceConfig, data)), | ||
post: (url, data = {}, globalConfig = {}) => client.post(url, parseData(data), resolveConfig(globalConfig, instanceConfig, data)), | ||
patch: (url, data = {}, globalConfig = {}) => client.patch(url, parseData(data), resolveConfig(globalConfig, instanceConfig, data)), | ||
put: (url, data = {}, globalConfig = {}) => client.put(url, parseData(data), resolveConfig(globalConfig, instanceConfig, data)), | ||
delete: (url, data = {}, globalConfig = {}) => client.delete(url, parseData(data), resolveConfig(globalConfig, instanceConfig, data)), | ||
}).catch((error) => { | ||
// Precognition can often cancel in-flight requests. Instead of | ||
// throwing an exception for this expected behaviour, we silently | ||
// discard cancelled request errors to not flood the console with | ||
// expected errors. | ||
if (isCancel(error)) { | ||
return null; | ||
} | ||
// Unlike other status codes, 422 responses are expected and | ||
// regularly occur with Precognition requests. We silently ignore | ||
// these so we do not flood the console with expected errors. If | ||
// needed, they can be intercepted by the `onValidationError` | ||
// config option instead. | ||
if (isAxiosError(error) && error.response?.status === 422) { | ||
return null; | ||
} | ||
return Promise.reject(error); | ||
}); | ||
}, debounceTimeoutDuration, { leading: true, trailing: true }); | ||
@@ -154,6 +170,14 @@ /** | ||
*/ | ||
const resolveConfig = (config, data = {}) => { | ||
const resolveConfig = (globalConfig, instanceConfig, data = {}) => { | ||
const config = { | ||
...globalConfig, | ||
...instanceConfig, | ||
}; | ||
const validate = Array.from(config.validate ?? touched); | ||
return { | ||
...config, | ||
...instanceConfig, | ||
// Axios has special rules for merging global and local config. We | ||
// use their merge function here to make sure things like headers | ||
// merge in an expected way. | ||
...mergeConfig(globalConfig, instanceConfig), | ||
validate, | ||
@@ -170,4 +194,7 @@ timeout: config.timeout ?? 5000, | ||
}, | ||
onSuccess: () => { | ||
onSuccess: (response) => { | ||
setValidated([...validated, ...validate]).forEach(listener => listener()); | ||
return config.onSuccess | ||
? config.onSuccess(response) | ||
: response; | ||
}, | ||
@@ -184,6 +211,6 @@ onPrecognitionSuccess: (response) => { | ||
onBefore: () => { | ||
const beforeValidationResult = (config.onBeforeValidation ?? ((previous, next) => { | ||
return !isEqual(previous, next); | ||
}))({ data, touched }, { data: oldData, touched: oldTouched }); | ||
if (beforeValidationResult === false) { | ||
const beforeValidationHandler = config.onBeforeValidation ?? ((newRequest, oldRequest) => { | ||
return newRequest.touched.length > 0 && !isEqual(newRequest, oldRequest); | ||
}); | ||
if (beforeValidationHandler({ data, touched }, { data: oldData, touched: oldTouched }) === false) { | ||
return false; | ||
@@ -215,5 +242,5 @@ } | ||
*/ | ||
const validate = (name, value) => { | ||
const validate = (name, value, config) => { | ||
if (typeof name === 'undefined') { | ||
validator(); | ||
validator(config ?? {}); | ||
return; | ||
@@ -229,6 +256,3 @@ } | ||
} | ||
if (touched.length === 0) { | ||
return; | ||
} | ||
validator(); | ||
validator(config ?? {}); | ||
}; | ||
@@ -246,4 +270,8 @@ /** | ||
touched: () => touched, | ||
validate(input, value) { | ||
validate(input, value); | ||
validate(name, value, config) { | ||
if (typeof name === 'object' && !('target' in name)) { | ||
config = name; | ||
name = value = undefined; | ||
} | ||
validate(name, value, config); | ||
return form; | ||
@@ -250,0 +278,0 @@ }, |
{ | ||
"name": "laravel-precognition", | ||
"version": "0.5.6", | ||
"version": "0.5.7", | ||
"description": "Laravel Precognition.", | ||
@@ -23,3 +23,5 @@ "keywords": [ | ||
"scripts": { | ||
"watch": "rm -rf dist && tsc --watch", | ||
"build": "rm -rf dist && tsc", | ||
"typeCheck": "tsc --noEmit", | ||
"prepublishOnly": "npm run build", | ||
@@ -39,4 +41,4 @@ "test": "vitest run" | ||
"typescript": "^5.0.0", | ||
"vitest": "^0.31.3" | ||
"vitest": "^1.6.0" | ||
} | ||
} |
29113
699