Skip to content

Commit

Permalink
[field] Use keyed segments over indexes where possible
Browse files Browse the repository at this point in the history
  • Loading branch information
rexxars committed Oct 6, 2020
1 parent 773c6f2 commit 13f7ea9
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 7 deletions.
10 changes: 7 additions & 3 deletions packages/@sanity/field/src/diff/changes/buildChangeList.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable complexity */
import {pathToString} from '../../paths'
import {pathToString, pathsAreEqual, getItemKeySegment} from '../../paths'
import {getValueError} from '../../validation'
import {getArrayDiffItemType} from '../../schema/helpers'
import {resolveDiffComponent} from '../resolve/resolveDiffComponent'
Expand Down Expand Up @@ -135,8 +135,12 @@ function buildArrayChangeList(
return acc
}

const index = diff.items.indexOf(itemDiff)
const itemPath = path.concat(index)
const segment =
getItemKeySegment(itemDiff.diff.fromValue) ||
getItemKeySegment(itemDiff.diff.toValue) ||
diff.items.indexOf(itemDiff)

const itemPath = path.concat(segment)
const itemTitlePath = titlePath.concat({
hasMoved: itemDiff.hasMoved,
toIndex: itemDiff.toIndex,
Expand Down
36 changes: 32 additions & 4 deletions packages/@sanity/field/src/paths/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import {Path} from './types'
import {PathSegment} from './types'
import {KeyedSegment} from './types'
import {Path, PathSegment, KeyedSegment} from './types'

const rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g
const reKeySegment = /_key\s*==\s*['"](.*)['"]/
Expand Down Expand Up @@ -72,5 +70,35 @@ export function isKeySegment(segment: any): segment is KeyedSegment {
return reKeySegment.test(segment.trim())
}

return segment && segment._key
return Boolean(segment && segment._key)
}

export function pathsAreEqual(pathA: Path, pathB: Path): boolean {
if (pathA.length !== pathB.length) {
return false
}

return pathA.every((segmentA, index) => {
const segmentB = pathB[index]
if (isKeySegment(segmentA) && isKeySegment(segmentB)) {
return segmentA._key === segmentB._key
}

if (isIndexSegment(segmentA)) {
return Number(segmentA) === Number(segmentB)
}

return segmentA === segmentB
})
}

export function getItemKey(arrayItem: unknown): string | undefined {
return typeof arrayItem === 'object' && arrayItem !== null
? (arrayItem as KeyedSegment)._key
: undefined
}

export function getItemKeySegment(arrayItem: unknown): KeyedSegment | undefined {
const key = getItemKey(arrayItem)
return key ? {_key: key} : undefined
}

0 comments on commit 13f7ea9

Please sign in to comment.