Skip to content

Commit ad4b460

Browse files
authored
Merge pull request #5643 from Shopify/mattellig/path-value-arrays
Use `PropertyPath` in path value methods
2 parents 75afb38 + f9ac5cf commit ad4b460

File tree

3 files changed

+90
-4
lines changed

3 files changed

+90
-4
lines changed

.changeset/funny-pots-visit.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@shopify/cli-kit': minor
3+
---
4+
5+
Update `getPathValue`, `setPathValue`, and `unsetPathValue` to support the lodash `PropertyPath` type

packages/cli-kit/src/public/common/object.test.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,17 @@ describe('getPathValue', () => {
184184
// Then
185185
expect(result).toBeUndefined()
186186
})
187+
188+
test('gets a property whose name contains dots using array notation', () => {
189+
// Given
190+
const obj: object = {'key1.with.dots': 'value'}
191+
192+
// When
193+
const result = getPathValue(obj, ['key1.with.dots'])
194+
195+
// Then
196+
expect(result).toEqual('value')
197+
})
187198
})
188199

189200
describe('setPathValue', () => {
@@ -242,6 +253,47 @@ describe('setPathValue', () => {
242253
// Then
243254
expect(getPathValue(result, 'key1')).toEqual({key11: 2})
244255
})
256+
257+
test('set the path value using an array path notation', () => {
258+
// Given
259+
const obj: object = {
260+
key1: {
261+
key11: 3,
262+
},
263+
}
264+
265+
// When
266+
const result = setPathValue(obj, ['key1', 'key11'], 4)
267+
268+
// Then
269+
expect(getPathValue(result, 'key1.key11')).toEqual(4)
270+
})
271+
272+
test('set a property whose name contains dots using array notation', () => {
273+
// Given
274+
const obj: object = {}
275+
276+
// When
277+
const result = setPathValue(obj, ['key1.with.dots'], 'value')
278+
279+
// Then
280+
expect(result).toEqual({'key1.with.dots': 'value'})
281+
// Should NOT create a nested structure
282+
expect(getPathValue(result, ['key1.with.dots'])).toEqual('value')
283+
// Should be accessible as a top-level property
284+
expect((result as {[key: string]: string})['key1.with.dots']).toEqual('value')
285+
})
286+
287+
test('set nested property under a key that contains dots', () => {
288+
// Given
289+
const obj: object = {'key1.with.dots': {}}
290+
291+
// When
292+
const result = setPathValue(obj, ['key1.with.dots', 'nested'], 'value')
293+
294+
// Then
295+
expect(result).toEqual({'key1.with.dots': {nested: 'value'}})
296+
})
245297
})
246298

247299
describe('compact', () => {
@@ -358,4 +410,33 @@ describe('unsetPathValue', () => {
358410
expect(result).toBeFalsy()
359411
expect(Object.prototype.hasOwnProperty.call(obj, 'key1')).toBeTruthy()
360412
})
413+
414+
test('removes the path value using array path notation', () => {
415+
// Given
416+
const obj: object = {
417+
key1: {
418+
key11: 2,
419+
key12: 3,
420+
},
421+
}
422+
423+
// When
424+
const result = unsetPathValue(obj, ['key1', 'key11'])
425+
426+
// Then
427+
expect(result).toBeTruthy()
428+
expect(obj).toEqual({key1: {key12: 3}})
429+
})
430+
431+
test('removes a property whose name contains dots using array notation', () => {
432+
// Given
433+
const obj: object = {'key1.with.dots': 'value', regular: 'value2'}
434+
435+
// When
436+
const result = unsetPathValue(obj, ['key1.with.dots'])
437+
438+
// Then
439+
expect(result).toBeTruthy()
440+
expect(obj).toEqual({regular: 'value2'})
441+
})
361442
})

packages/cli-kit/src/public/common/object.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {unionArrayStrategy} from '../../private/common/array.js'
22
import deepMerge from 'deepmerge'
3-
import {Dictionary, ObjectIterator, ValueKeyIteratee} from 'lodash'
3+
import {Dictionary, ObjectIterator, PropertyPath, ValueKeyIteratee} from 'lodash'
44
import lodashPickBy from 'lodash/pickBy.js'
55
import lodashMapValues from 'lodash/mapValues.js'
66
import lodashIsEqual from 'lodash/isEqual.js'
@@ -88,7 +88,7 @@ export function deepDifference(one: object, two: object): [object, object] {
8888
* @param path - The path of the property to get.
8989
* @returns - Returns the resolved value.
9090
*/
91-
export function getPathValue<T = object>(object: object, path: string): T | undefined {
91+
export function getPathValue<T = object>(object: object, path: PropertyPath): T | undefined {
9292
return get(object, path) === undefined ? undefined : (get(object, path) as T)
9393
}
9494

@@ -100,7 +100,7 @@ export function getPathValue<T = object>(object: object, path: string): T | unde
100100
* @param value - The value to set.
101101
* @returns - Returns object.
102102
*/
103-
export function setPathValue(object: object, path: string, value?: unknown): object {
103+
export function setPathValue(object: object, path: PropertyPath, value?: unknown): object {
104104
return set(object, path, value)
105105
}
106106

@@ -111,7 +111,7 @@ export function setPathValue(object: object, path: string, value?: unknown): obj
111111
* @param path - The path of the property to unset.
112112
* @returns - Returns true if the property is deleted or not found, else false.
113113
*/
114-
export function unsetPathValue(object: object, path: string): boolean {
114+
export function unsetPathValue(object: object, path: PropertyPath): boolean {
115115
return unset(object, path)
116116
}
117117

0 commit comments

Comments
 (0)