Skip to content

Commit

Permalink
Merge pull request #3129 from reduxjs/feature/regexp-in-ignored-paths
Browse files Browse the repository at this point in the history
  • Loading branch information
markerikson authored Jan 28, 2023
2 parents 85ec86b + 0fab520 commit dbe83fb
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 31 deletions.
4 changes: 2 additions & 2 deletions docs/api/immutabilityMiddleware.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ interface ImmutableStateInvariantMiddlewareOptions {
*/
isImmutable?: IsImmutableFunc
/**
An array of dot-separated path strings that match named nodes from
An array of dot-separated path strings or RegExps that match named nodes from
the root state to ignore when checking for immutability.
Defaults to undefined
*/
ignoredPaths?: string[]
ignoredPaths?: (string | RegExp)[]
/** Print a warning if checks take longer than N ms. Default: 32ms */
warnAfter?: number
// @deprecated. Use ignoredPaths
Expand Down
13 changes: 7 additions & 6 deletions docs/api/serializabilityMiddleware.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,17 @@ interface SerializableStateInvariantMiddlewareOptions {
ignoredActions?: string[]

/**
* An array of dot-separated path strings to ignore when checking
* for serializability, Defaults to ['meta.arg', 'meta.baseQueryMeta']
* An array of dot-separated path strings or regular expressions to ignore
* when checking for serializability, Defaults to
* ['meta.arg', 'meta.baseQueryMeta']
*/
ignoredActionPaths?: string[]
ignoredActionPaths?: (string | RegExp)[]

/**
* An array of dot-separated path strings to ignore when checking
* for serializability, Defaults to []
* An array of dot-separated path strings or regular expressions to ignore
* when checking for serializability, Defaults to []
*/
ignoredPaths?: string[]
ignoredPaths?: (string | RegExp)[]
/**
* Execution time warning threshold. If the middleware takes longer
* than `warnAfter` ms, a warning will be displayed in the console.
Expand Down
Empty file modified packages/rtk-codemods/bin/cli.js
100644 → 100755
Empty file.
6 changes: 3 additions & 3 deletions packages/toolkit/etc/redux-toolkit.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ export function findNonSerializableValue(
path?: string,
isSerializable?: (value: unknown) => boolean,
getEntries?: (value: unknown) => [string, any][],
ignoredPaths?: readonly string[]
ignoredPaths?: readonly (string | RegExp)[]
): NonSerializableValue | false

export { freeze }
Expand Down Expand Up @@ -762,9 +762,9 @@ export { Selector }
// @public
export interface SerializableStateInvariantMiddlewareOptions {
getEntries?: (value: any) => [string, any][]
ignoredActionPaths?: string[]
ignoredActionPaths?: (string | RegExp)[]
ignoredActions?: string[]
ignoredPaths?: string[]
ignoredPaths?: (string | RegExp)[]
ignoreState?: boolean
isSerializable?: (value: any) => boolean
warnAfter?: number
Expand Down
29 changes: 20 additions & 9 deletions packages/toolkit/src/immutableStateInvariantMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export function isImmutableDefault(value: unknown): boolean {

export function trackForMutations(
isImmutable: IsImmutableFunc,
ignorePaths: string[] | undefined,
ignorePaths: IgnorePaths | undefined,
obj: any
) {
const trackedProperties = trackProperties(isImmutable, ignorePaths, obj)
Expand Down Expand Up @@ -116,11 +116,11 @@ function trackProperties(
return tracked as TrackedProperty
}

type IgnorePaths = readonly string[]
type IgnorePaths = readonly (string | RegExp)[]

function detectMutations(
isImmutable: IsImmutableFunc,
ignorePaths: IgnorePaths = [],
ignoredPaths: IgnorePaths = [],
trackedProperty: TrackedProperty,
obj: any,
sameParentRef: boolean = false,
Expand All @@ -147,19 +147,30 @@ function detectMutations(
keysToDetect[key] = true
}

const hasIgnoredPaths = ignoredPaths.length > 0

for (let key in keysToDetect) {
const childPath = path ? path + '.' + key : key
if (ignorePaths.length && ignorePaths.indexOf(childPath) !== -1) {
continue
const nestedPath = path ? path + '.' + key : key

if (hasIgnoredPaths) {
const hasMatches = ignoredPaths.some((ignored) => {
if (ignored instanceof RegExp) {
return ignored.test(nestedPath)
}
return nestedPath === ignored
})
if (hasMatches) {
continue
}
}

const result = detectMutations(
isImmutable,
ignorePaths,
ignoredPaths,
trackedProperty.children[key],
obj[key],
sameRef,
childPath
nestedPath
)

if (result.wasMutated) {
Expand Down Expand Up @@ -189,7 +200,7 @@ export interface ImmutableStateInvariantMiddlewareOptions {
the root state to ignore when checking for immutability.
Defaults to undefined
*/
ignoredPaths?: string[]
ignoredPaths?: IgnorePaths
/** Print a warning if checks take longer than N ms. Default: 32ms */
warnAfter?: number
// @deprecated. Use ignoredPaths
Expand Down
29 changes: 20 additions & 9 deletions packages/toolkit/src/serializableStateInvariantMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ interface NonSerializableValue {
value: unknown
}

type IgnorePaths = readonly (string | RegExp)[]

/**
* @public
*/
Expand All @@ -36,7 +38,7 @@ export function findNonSerializableValue(
path: string = '',
isSerializable: (value: unknown) => boolean = isPlain,
getEntries?: (value: unknown) => [string, any][],
ignoredPaths: readonly string[] = []
ignoredPaths: IgnorePaths = []
): NonSerializableValue | false {
let foundNestedSerializable: NonSerializableValue | false

Expand All @@ -58,8 +60,16 @@ export function findNonSerializableValue(
for (const [key, nestedValue] of entries) {
const nestedPath = path ? path + '.' + key : key

if (hasIgnoredPaths && ignoredPaths.indexOf(nestedPath) >= 0) {
continue
if (hasIgnoredPaths) {
const hasMatches = ignoredPaths.some((ignored) => {
if (ignored instanceof RegExp) {
return ignored.test(nestedPath)
}
return nestedPath === ignored
})
if (hasMatches) {
continue
}
}

if (!isSerializable(nestedValue)) {
Expand Down Expand Up @@ -113,16 +123,17 @@ export interface SerializableStateInvariantMiddlewareOptions {
ignoredActions?: string[]

/**
* An array of dot-separated path strings to ignore when checking
* for serializability, Defaults to ['meta.arg', 'meta.baseQueryMeta']
* An array of dot-separated path strings or regular expressions to ignore
* when checking for serializability, Defaults to
* ['meta.arg', 'meta.baseQueryMeta']
*/
ignoredActionPaths?: string[]
ignoredActionPaths?: (string | RegExp)[]

/**
* An array of dot-separated path strings to ignore when checking
* for serializability, Defaults to []
* An array of dot-separated path strings or regular expressions to ignore
* when checking for serializability, Defaults to []
*/
ignoredPaths?: string[]
ignoredPaths?: (string | RegExp)[]
/**
* Execution time warning threshold. If the middleware takes longer
* than `warnAfter` ms, a warning will be displayed in the console.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ Take a look at the reducer(s) handling this action type: TEST_ACTION.

exports[`serializableStateInvariantMiddleware ignored action paths can specify (multiple) different values 1`] = `""`;

exports[`serializableStateInvariantMiddleware ignored action paths can specify regexp 1`] = `""`;

exports[`serializableStateInvariantMiddleware ignored action paths default value can be overridden 1`] = `
"A non-serializable value was detected in an action, in the path: \`meta.arg\`. Value: Map {}
Take a look at the logic that dispatched this action: Object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,16 @@ describe('createImmutableStateInvariantMiddleware', () => {
return action
}

const dispatch = middleware({ ignoredPaths: ['foo.bar'] })(next)
const dispatch1 = middleware({ ignoredPaths: ['foo.bar'] })(next)

expect(() => {
dispatch({ type: 'SOME_ACTION' })
dispatch1({ type: 'SOME_ACTION' })
}).not.toThrow()

const dispatch2 = middleware({ ignoredPaths: [/^foo/] })(next)

expect(() => {
dispatch2({ type: 'SOME_ACTION' })
}).not.toThrow()
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,22 @@ describe('serializableStateInvariantMiddleware', () => {

expect(getLog().log).toMatchInlineSnapshot(`""`)
})

it('can specify regexp', () => {
configureStore({
reducer,
middleware: [
createSerializableStateInvariantMiddleware({
ignoredActionPaths: [/^payload\..*$/],
}),
],
}).dispatch({
type: 'test',
payload: { arg: nonSerializableValue },
})

expect(getLog().log).toMatchInlineSnapshot(`""`)
})
})

it('allows ignoring actions entirely', () => {
Expand Down Expand Up @@ -439,6 +455,10 @@ describe('serializableStateInvariantMiddleware', () => {
d: badValue,
},
e: { f: badValue },
g: {
h: badValue,
i: badValue,
},
}
}
default:
Expand All @@ -455,6 +475,8 @@ describe('serializableStateInvariantMiddleware', () => {
'testSlice.b.c',
// Test for ignoring an object and its children
'testSlice.e',
// Test for ignoring based on RegExp
/^testSlice\.g\..*$/,
],
})

Expand Down

0 comments on commit dbe83fb

Please sign in to comment.