Skip to content

Commit

Permalink
perf(unsetcompact): avoids recursion for trailing [] notation
Browse files Browse the repository at this point in the history
  • Loading branch information
aviemet committed Jun 9, 2024
1 parent a06396a commit 3d888ba
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 10 deletions.
21 changes: 12 additions & 9 deletions src/utils/unsetCompact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@ import { unset, get } from 'lodash'
import { type NestedObject } from '../useInertiaForm'

/**
* Extends _.unset to remove empty array elements after unsetting an array by index
* Extends _.unset splice out array elements rather than leaving empty values in arrays
* e.g. unset(data, 'path[0]')
* Allows special syntax of '[]' to refer to every element of an array
* e.g. unset(data, 'path[].key'), will recursively unset 'key' in every array element
*/
type TArrType = string|number|NestedObject
export const unsetCompact = (data: NestedObject, path: string) => {
// Ignore tailing [] since it causes unnecessary recursion
const sanitizedPath = path.replace(/\[\]$/, '')

// Handle special empty array syntax
if(path.includes('[]')) {
const emptyArrayPosition = path.indexOf('[]')
const startPath = path.slice(0, emptyArrayPosition)
const restPath = path.slice(emptyArrayPosition + 2)
if(sanitizedPath.includes('[]')) {
const emptyArrayPosition = sanitizedPath.indexOf('[]')
const startPath = sanitizedPath.slice(0, emptyArrayPosition)
const restPath = sanitizedPath.slice(emptyArrayPosition + 2)
const arr = get(data, startPath) as TArrType[]

if(Array.isArray(arr)) {
Expand All @@ -26,14 +29,14 @@ export const unsetCompact = (data: NestedObject, path: string) => {

// Directly removing an array element is the only way to have an empty array element
// Handle it separately using slice rather than unset
if(path.charAt(path.length - 1) === ']') {
const match = path.match(/(?<index>\d*)\]$/)
const arr = get(data, path.slice(0, path.lastIndexOf('[')))
if(sanitizedPath.charAt(sanitizedPath.length - 1) === ']') {
const match = sanitizedPath.match(/(?<index>\d*)\]$/)
const arr = get(data, sanitizedPath.slice(0, sanitizedPath.lastIndexOf('[')))

if(Array.isArray(arr) && match?.groups?.index !== undefined) {
arr.splice(Number(match.groups.index), 1)
}
} else {
unset(data, path)
unset(data, sanitizedPath)
}
}
22 changes: 21 additions & 1 deletion tests/utils/unsetCompact.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ describe('unsetCompact', () => {
})
})

it('works when an empty bracket is specified after an element ', () => {
it('works when an empty bracket is specified after an element', () => {
const data = structuredClone(nestedData)

unsetCompact(data, 'two.four[2].ten[].eleven')
Expand All @@ -157,7 +157,27 @@ describe('unsetCompact', () => {
},
},
})
})

it('ignores trailing []', () => {
const data = structuredClone(nestedData)

unsetCompact(data, 'two.four[2].ten[]')
expect(data).toEqual({
one: 'one',
two: {
three: 'three',
four: [
{ five: 'five', six: 'six' },
{ seven: 'seven' },
{ five: 'eight', six: 'nine' },
],
last: {
just: 'testing',
},
},
})
})

})
})

0 comments on commit 3d888ba

Please sign in to comment.