Skip to content

Commit c0990b0

Browse files
committed
feat: add value length cap to partialClone
1 parent d6d839a commit c0990b0

File tree

6 files changed

+71
-45
lines changed

6 files changed

+71
-45
lines changed

packages/amazonq/test/e2e/inline/inline.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ describe('Amazon Q Inline', async function () {
122122
.query({
123123
metricName: 'codewhisperer_userTriggerDecision',
124124
})
125-
.map((e) => collectionUtil.partialClone(e, 3, ['credentialStartUrl'], '[omitted]'))
125+
.map((e) => collectionUtil.partialClone(e, 3, ['credentialStartUrl'], { replacement: '[omitted]' }))
126126
}
127127

128128
for (const [name, invokeCompletion] of [

packages/core/src/auth/sso/clients.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ function addLoggingMiddleware(client: SSOOIDCClient) {
258258
args.input as unknown as Record<string, unknown>,
259259
3,
260260
['clientSecret', 'accessToken', 'refreshToken'],
261-
'[omitted]'
261+
{ replacement: '[omitted]' }
262262
)
263263
getLogger().debug('API request (%s %s): %O', hostname, path, input)
264264
}
@@ -288,7 +288,7 @@ function addLoggingMiddleware(client: SSOOIDCClient) {
288288
result.output as unknown as Record<string, unknown>,
289289
3,
290290
['clientSecret', 'accessToken', 'refreshToken'],
291-
'[omitted]'
291+
{ replacement: '[omitted]' }
292292
)
293293
getLogger().debug('API response (%s %s): %O', hostname, path, output)
294294
}

packages/core/src/shared/utilities/collectionUtils.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { isWeb } from '../extensionGlobals'
77
import { inspect as nodeInspect } from 'util'
88
import { AsyncCollection, toCollection } from './asyncCollection'
99
import { SharedProp, AccumulableKeys, Coalesce, isNonNullable } from './tsUtils'
10+
import { truncate } from './textUtilities'
1011

1112
export function union<T>(a: Iterable<T>, b: Iterable<T>): Set<T> {
1213
const result = new Set<T>()
@@ -304,26 +305,36 @@ export function assign<T extends Record<any, any>, U extends Partial<T>>(data: T
304305
* @param depth
305306
* @param omitKeys Omit properties matching these names (at any depth).
306307
* @param replacement Replacement for object whose fields extend beyond `depth`, and properties matching `omitKeys`.
308+
* @param maxLength truncates string values that exceed this threshold.
307309
*/
308-
export function partialClone(obj: any, depth: number = 3, omitKeys: string[] = [], replacement?: any): any {
310+
export function partialClone(
311+
obj: any,
312+
depth: number = 3,
313+
omitKeys: string[] = [],
314+
options?: {
315+
replacement?: any
316+
maxLength?: number
317+
}
318+
): any {
309319
// Base case: If input is not an object or has no children, return it.
310320
if (typeof obj !== 'object' || obj === null || 0 === Object.getOwnPropertyNames(obj).length) {
311-
return obj
321+
const maxLength = options?.maxLength
322+
return typeof obj === 'string' && maxLength !== undefined ? truncate(obj, maxLength, '...') : obj
312323
}
313324

314325
// Create a new object of the same type as the input object.
315326
const clonedObj = Array.isArray(obj) ? [] : {}
316327

317328
if (depth === 0) {
318-
return replacement ? replacement : clonedObj
329+
return options?.replacement ? options.replacement : clonedObj
319330
}
320331

321332
// Recursively clone properties of the input object
322333
for (const key in obj) {
323334
if (omitKeys.includes(key)) {
324-
;(clonedObj as any)[key] = replacement ? replacement : Array.isArray(obj) ? [] : {}
335+
;(clonedObj as any)[key] = options?.replacement ? options.replacement : Array.isArray(obj) ? [] : {}
325336
} else if (Object.prototype.hasOwnProperty.call(obj, key)) {
326-
;(clonedObj as any)[key] = partialClone(obj[key], depth - 1, omitKeys, replacement)
337+
;(clonedObj as any)[key] = partialClone(obj[key], depth - 1, omitKeys, options)
327338
}
328339
}
329340

packages/core/src/shared/utilities/textUtilities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { default as stripAnsi } from 'strip-ansi'
1010
import { getLogger } from '../logger/logger'
1111

1212
/**
13-
* Truncates string `s` if it exceeds `n` chars.
13+
* Truncates string `s` if it has or exceeds `n` chars.
1414
*
1515
* If `n` is negative, truncates at start instead of end.
1616
*

packages/core/src/shared/vscode/commands2.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ async function runCommand<T extends Callback>(fn: T, info: CommandInfo<T>): Prom
653653

654654
logger.debug(
655655
`command: running ${label} with arguments: %O`,
656-
partialClone(args, 3, ['clientSecret', 'accessToken', 'refreshToken', 'tooltip'], '[omitted]')
656+
partialClone(args, 3, ['clientSecret', 'accessToken', 'refreshToken', 'tooltip'], { replacement: '[omitted]' })
657657
)
658658

659659
try {

packages/core/src/test/shared/utilities/collectionUtils.test.ts

Lines changed: 50 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -710,8 +710,10 @@ describe('CollectionUtils', async function () {
710710
})
711711

712712
describe('partialClone', function () {
713-
it('omits properties by depth', function () {
714-
const testObj = {
713+
let multipleTypedObj: object
714+
715+
before(async function () {
716+
multipleTypedObj = {
715717
a: 34234234234,
716718
b: '123456789',
717719
c: new Date(2023, 1, 1),
@@ -724,56 +726,69 @@ describe('CollectionUtils', async function () {
724726
throw Error()
725727
},
726728
}
729+
})
727730

728-
assert.deepStrictEqual(partialClone(testObj, 1), {
729-
...testObj,
731+
it('omits properties by depth', function () {
732+
assert.deepStrictEqual(partialClone(multipleTypedObj, 1), {
733+
...multipleTypedObj,
730734
d: {},
731735
e: {},
732736
})
733-
assert.deepStrictEqual(partialClone(testObj, 0, [], '[replaced]'), '[replaced]')
734-
assert.deepStrictEqual(partialClone(testObj, 1, [], '[replaced]'), {
735-
...testObj,
737+
assert.deepStrictEqual(partialClone(multipleTypedObj, 0, [], { replacement: '[replaced]' }), '[replaced]')
738+
assert.deepStrictEqual(partialClone(multipleTypedObj, 1, [], { replacement: '[replaced]' }), {
739+
...multipleTypedObj,
736740
d: '[replaced]',
737741
e: '[replaced]',
738742
})
739-
assert.deepStrictEqual(partialClone(testObj, 3), {
740-
...testObj,
743+
assert.deepStrictEqual(partialClone(multipleTypedObj, 3), {
744+
...multipleTypedObj,
741745
d: { d1: { d2: {} } },
742746
})
743-
assert.deepStrictEqual(partialClone(testObj, 4), testObj)
747+
assert.deepStrictEqual(partialClone(multipleTypedObj, 4), multipleTypedObj)
744748
})
745749

746750
it('omits properties by name', function () {
747-
const testObj = {
748-
a: 34234234234,
749-
b: '123456789',
750-
c: new Date(2023, 1, 1),
751-
d: { d1: { d2: { d3: 'deep' } } },
752-
e: {
753-
e1: [4, 3, 7],
754-
e2: 'loooooooooo \n nnnnnnnnnnn \n gggggggg \n string',
755-
},
756-
f: () => {
757-
throw Error()
758-
},
759-
}
760-
761-
assert.deepStrictEqual(partialClone(testObj, 2, ['c', 'e2'], '[omitted]'), {
762-
...testObj,
763-
c: '[omitted]',
764-
d: { d1: '[omitted]' },
751+
assert.deepStrictEqual(partialClone(multipleTypedObj, 2, ['c', 'e2'], { replacement: '[replaced]' }), {
752+
...multipleTypedObj,
753+
c: '[replaced]',
754+
d: { d1: '[replaced]' },
765755
e: {
766-
e1: '[omitted]',
767-
e2: '[omitted]',
756+
e1: '[replaced]',
757+
e2: '[replaced]',
768758
},
769759
})
770-
assert.deepStrictEqual(partialClone(testObj, 3, ['c', 'e2'], '[omitted]'), {
771-
...testObj,
772-
c: '[omitted]',
773-
d: { d1: { d2: '[omitted]' } },
760+
assert.deepStrictEqual(partialClone(multipleTypedObj, 3, ['c', 'e2'], { replacement: '[replaced]' }), {
761+
...multipleTypedObj,
762+
c: '[replaced]',
763+
d: { d1: { d2: '[replaced]' } },
774764
e: {
775765
e1: [4, 3, 7],
776-
e2: '[omitted]',
766+
e2: '[replaced]',
767+
},
768+
})
769+
})
770+
771+
it('truncates properties by maxLength', function () {
772+
const testObj = {
773+
a: '1',
774+
b: '11',
775+
c: '11111',
776+
d: {
777+
e: {
778+
a: '11111',
779+
b: '11',
780+
},
781+
},
782+
}
783+
assert.deepStrictEqual(partialClone(testObj, 5, [], { maxLength: 2 }), {
784+
a: '1',
785+
b: '11',
786+
c: '11...',
787+
d: {
788+
e: {
789+
a: '11...',
790+
b: '11',
791+
},
777792
},
778793
})
779794
})

0 commit comments

Comments
 (0)