diff --git a/packages/editor-ui/src/plugins/codemirror/completions/__tests__/completions.test.ts b/packages/editor-ui/src/plugins/codemirror/completions/__tests__/completions.test.ts index 72b4bbd6053cb..28ff31972fde3 100644 --- a/packages/editor-ui/src/plugins/codemirror/completions/__tests__/completions.test.ts +++ b/packages/editor-ui/src/plugins/codemirror/completions/__tests__/completions.test.ts @@ -552,12 +552,32 @@ describe('Resolution-based completions', () => { const found = completions('{{ $json.| }}'); if (!found) throw new Error('Expected to find completions'); - expect( - found.find((completion) => completion.label === 'Key with spaces'), - ).not.toBeUndefined(); - expect( - found.find((completion) => completion.label === 'Key with spaces and \'quotes"'), - ).not.toBeUndefined(); + expect(found).toContainEqual( + expect.objectContaining({ + label: 'Key with spaces', + apply: utils.applyBracketAccessCompletion, + }), + ); + expect(found).toContainEqual( + expect.objectContaining({ + label: 'Key with spaces and \'quotes"', + apply: utils.applyBracketAccessCompletion, + }), + ); + }); + + test('should escape keys with quotes', () => { + vi.spyOn(workflowHelpers, 'resolveParameter').mockReturnValue({ + 'Key with spaces and \'quotes"': 1, + }); + + const found = completions('{{ $json[| }}'); + if (!found) throw new Error('Expected to find completions'); + expect(found).toContainEqual( + expect.objectContaining({ + label: "'Key with spaces and \\'quotes\"']", + }), + ); }); }); diff --git a/packages/editor-ui/src/plugins/codemirror/completions/bracketAccess.completions.ts b/packages/editor-ui/src/plugins/codemirror/completions/bracketAccess.completions.ts index 7557280732b26..a922b1354cdf5 100644 --- a/packages/editor-ui/src/plugins/codemirror/completions/bracketAccess.completions.ts +++ b/packages/editor-ui/src/plugins/codemirror/completions/bracketAccess.completions.ts @@ -3,6 +3,7 @@ import { prefixMatch, longestCommonPrefix } from './utils'; import type { IDataObject } from 'n8n-workflow'; import type { Completion, CompletionContext, CompletionResult } from '@codemirror/autocomplete'; import type { Resolved } from './types'; +import { escapeMappingString } from '@/utils/mappingUtils'; /** * Resolution-based completions offered at the start of bracket access notation. @@ -67,7 +68,7 @@ function bracketAccessOptions(resolved: IDataObject) { const isNumber = !isNaN(parseInt(key)); // array or string index return { - label: isNumber ? `${key}]` : `'${key}']`, + label: isNumber ? `${key}]` : `'${escapeMappingString(key)}']`, type: 'keyword', }; });