Merge branch 'validate-schema'
This commit is contained in:
commit
8e16d9fef7
@ -2,6 +2,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@yanick/updeep-remeda": "^2.2.0",
|
"@yanick/updeep-remeda": "^2.2.0",
|
||||||
|
"ajv": "^8.12.0",
|
||||||
"expect-type": "^0.16.0",
|
"expect-type": "^0.16.0",
|
||||||
"immer": "^9.0.15",
|
"immer": "^9.0.15",
|
||||||
"json-schema-shorthand": "^2.0.0",
|
"json-schema-shorthand": "^2.0.0",
|
||||||
|
25
src/Updux.ts
25
src/Updux.ts
@ -22,6 +22,7 @@ import {
|
|||||||
EffectMiddleware,
|
EffectMiddleware,
|
||||||
} from './effects.js';
|
} from './effects.js';
|
||||||
import buildSchema from './schema.js';
|
import buildSchema from './schema.js';
|
||||||
|
import Ajv from 'ajv';
|
||||||
|
|
||||||
export type Mutation<A = AnyAction, S = any> = (
|
export type Mutation<A = AnyAction, S = any> = (
|
||||||
payload: A extends {
|
payload: A extends {
|
||||||
@ -32,6 +33,19 @@ export type Mutation<A = AnyAction, S = any> = (
|
|||||||
action: A,
|
action: A,
|
||||||
) => (state: S) => S | void;
|
) => (state: S) => S | void;
|
||||||
|
|
||||||
|
|
||||||
|
function buildValidateMiddleware(schema) {
|
||||||
|
// @ts-ignore
|
||||||
|
const ajv = new Ajv();
|
||||||
|
const validate = ajv.compile(schema);
|
||||||
|
return (api) => next => action => {
|
||||||
|
next(action);
|
||||||
|
const valid = validate(api.getState());
|
||||||
|
|
||||||
|
if (!valid) throw new Error("validation failed after action " + JSON.stringify(action) + "\n" + JSON.stringify(validate.errors));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default class Updux<D extends DuxConfig> {
|
export default class Updux<D extends DuxConfig> {
|
||||||
#mutations = [];
|
#mutations = [];
|
||||||
|
|
||||||
@ -174,6 +188,7 @@ export default class Updux<D extends DuxConfig> {
|
|||||||
createStore(
|
createStore(
|
||||||
options: Partial<{
|
options: Partial<{
|
||||||
preloadedState: DuxState<D>;
|
preloadedState: DuxState<D>;
|
||||||
|
validate: boolean;
|
||||||
}> = {},
|
}> = {},
|
||||||
): EnhancedStore<DuxState<D>> & AugmentedMiddlewareAPI<D> {
|
): EnhancedStore<DuxState<D>> & AugmentedMiddlewareAPI<D> {
|
||||||
const preloadedState = options.preloadedState;
|
const preloadedState = options.preloadedState;
|
||||||
@ -184,10 +199,18 @@ export default class Updux<D extends DuxConfig> {
|
|||||||
this.selectors,
|
this.selectors,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const middleware = [effects];
|
||||||
|
|
||||||
|
if (options.validate) {
|
||||||
|
middleware.unshift(
|
||||||
|
buildValidateMiddleware(this.schema)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const store = configureStore({
|
const store = configureStore({
|
||||||
reducer: this.reducer,
|
reducer: this.reducer,
|
||||||
preloadedState,
|
preloadedState,
|
||||||
middleware: [effects],
|
middleware,
|
||||||
});
|
});
|
||||||
|
|
||||||
const dispatch: any = store.dispatch;
|
const dispatch: any = store.dispatch;
|
||||||
|
@ -29,3 +29,17 @@ test('schema default inherits from initial state', () => {
|
|||||||
|
|
||||||
expect(dux.schema.default).toEqual(8);
|
expect(dux.schema.default).toEqual(8);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('validate', () => {
|
||||||
|
const dux = new Updux({
|
||||||
|
initialState: 12,
|
||||||
|
actions: {
|
||||||
|
doItWrong: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
dux.addMutation('doItWrong', () => () => 'potato' as any);
|
||||||
|
|
||||||
|
const store = dux.createStore({ validate: true });
|
||||||
|
expect(() => store.dispatch.doItWrong()).toThrow();
|
||||||
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user