fix(editor): Fix mapping with special characters (#5837)

* fix: Fix mapping with special characters

* refactor: rename var

* test: update more unit tests

* test: update mapping test

* test: update mapping test
This commit is contained in:
Mutasem Aldmour 2023-03-30 15:50:47 +02:00 committed by GitHub
parent ddc8f30e6d
commit f8f584c136
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 53 additions and 23 deletions

View file

@ -56,7 +56,7 @@ describe('Data mapping', () => {
ndv.actions.mapDataFromHeader(2, 'value'); ndv.actions.mapDataFromHeader(2, 'value');
ndv.getters ndv.getters
.inlineExpressionEditorInput() .inlineExpressionEditorInput()
.should('have.text', '{{ $json.timestamp }} {{ $json["Readable date"] }}'); .should('have.text', "{{ $json.timestamp }} {{ $json['Readable date'] }}");
}); });
it('maps expressions from table json, and resolves value based on hover', () => { it('maps expressions from table json, and resolves value based on hover', () => {
@ -193,7 +193,7 @@ describe('Data mapping', () => {
ndv.actions.mapToParameter('value'); ndv.actions.mapToParameter('value');
ndv.getters ndv.getters
.inlineExpressionEditorInput() .inlineExpressionEditorInput()
.should('have.text', `{{ $node["${SCHEDULE_TRIGGER_NODE_NAME}"].json.input[0].count }}`); .should('have.text', `{{ $node['${SCHEDULE_TRIGGER_NODE_NAME}'].json.input[0].count }}`);
ndv.getters.parameterExpressionPreview('value').should('not.exist'); ndv.getters.parameterExpressionPreview('value').should('not.exist');
ndv.actions.switchInputMode('Table'); ndv.actions.switchInputMode('Table');
@ -202,7 +202,7 @@ describe('Data mapping', () => {
.inlineExpressionEditorInput() .inlineExpressionEditorInput()
.should( .should(
'have.text', 'have.text',
`{{ $node["${SCHEDULE_TRIGGER_NODE_NAME}"].json.input[0].count }} {{ $node["${SCHEDULE_TRIGGER_NODE_NAME}"].json.input }}`, `{{ $node['${SCHEDULE_TRIGGER_NODE_NAME}'].json.input[0].count }} {{ $node['${SCHEDULE_TRIGGER_NODE_NAME}'].json.input }}`,
); );
ndv.getters.parameterExpressionPreview('value').should('not.exist'); ndv.getters.parameterExpressionPreview('value').should('not.exist');
@ -259,7 +259,7 @@ describe('Data mapping', () => {
ndv.getters ndv.getters
.parameterInput('fieldName') .parameterInput('fieldName')
.find('input') .find('input')
.should('have.value', 'input[0]["hello.world"]["my count"]'); .should('have.value', "input[0]['hello.world']['my count']");
}); });
it('maps expressions to updated fields correctly', () => { it('maps expressions to updated fields correctly', () => {

View file

@ -77,7 +77,9 @@ export default Vue.extend({
segment.kind === 'plaintext' segment.kind === 'plaintext'
? segment.plaintext.length ? segment.plaintext.length
: // eslint-disable-next-line @typescript-eslint/no-explicit-any : // eslint-disable-next-line @typescript-eslint/no-explicit-any
(segment.resolved as any).toString().length; segment.resolved
? (segment.resolved as any).toString().length
: 0;
segment.to = cursor; segment.to = cursor;

View file

@ -68,7 +68,9 @@ export default Vue.extend({
segment.kind === 'plaintext' segment.kind === 'plaintext'
? segment.plaintext.length ? segment.plaintext.length
: // eslint-disable-next-line @typescript-eslint/no-explicit-any : // eslint-disable-next-line @typescript-eslint/no-explicit-any
(segment.resolved as any).toString().length; segment.resolved
? (segment.resolved as any).toString().length
: 0;
segment.to = cursor; segment.to = cursor;
return segment; return segment;
}) })

View file

@ -301,9 +301,9 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
class="label" class="label"
data-depth="1" data-depth="1"
data-name="hello world" data-name="hello world"
data-path="[\\"hello world\\"]" data-path="['hello world']"
data-target="mappable" data-target="mappable"
data-value="{{ $json[\\"hello world\\"] }}" data-value="{{ $json['hello world'] }}"
> >
<font-awesome-icon-stub <font-awesome-icon-stub
icon="list" icon="list"
@ -347,9 +347,9 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
class="label" class="label"
data-depth="2" data-depth="2"
data-name="object[0]" data-name="object[0]"
data-path="[\\"hello world\\"][0]" data-path="['hello world'][0]"
data-target="mappable" data-target="mappable"
data-value="{{ $json[\\"hello world\\"][0] }}" data-value="{{ $json['hello world'][0] }}"
> >
<font-awesome-icon-stub <font-awesome-icon-stub
icon="cube" icon="cube"
@ -395,9 +395,9 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
class="label" class="label"
data-depth="3" data-depth="3"
data-name="test" data-name="test"
data-path="[\\"hello world\\"][0].test" data-path="['hello world'][0].test"
data-target="mappable" data-target="mappable"
data-value="{{ $json[\\"hello world\\"][0].test }}" data-value="{{ $json['hello world'][0].test }}"
> >
<font-awesome-icon-stub <font-awesome-icon-stub
icon="cube" icon="cube"
@ -441,9 +441,9 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
class="label" class="label"
data-depth="4" data-depth="4"
data-name="more to think about" data-name="more to think about"
data-path="[\\"hello world\\"][0].test[\\"more to think about\\"]" data-path="['hello world'][0].test['more to think about']"
data-target="mappable" data-target="mappable"
data-value="{{ $json[\\"hello world\\"][0].test[\\"more to think about\\"] }}" data-value="{{ $json['hello world'][0].test['more to think about'] }}"
> >
<font-awesome-icon-stub <font-awesome-icon-stub
icon="hashtag" icon="hashtag"
@ -481,9 +481,9 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
class="label" class="label"
data-depth="3" data-depth="3"
data-name="test.how" data-name="test.how"
data-path="[\\"hello world\\"][0][\\"test.how\\"]" data-path="['hello world'][0]['test.how']"
data-target="mappable" data-target="mappable"
data-value="{{ $json[\\"hello world\\"][0][\\"test.how\\"] }}" data-value="{{ $json['hello world'][0]['test.how'] }}"
> >
<font-awesome-icon-stub <font-awesome-icon-stub
icon="font" icon="font"

View file

@ -228,7 +228,30 @@ describe('Mapping Utils', () => {
}; };
const result = getMappedExpression(input); const result = getMappedExpression(input);
expect(result).toBe( expect(result).toBe(
'{{ $node.nodeName.json.sample["path with-space"]["path-with-hyphen"] }}', "{{ $node.nodeName.json.sample['path with-space']['path-with-hyphen'] }}",
);
});
it('should handle paths with special characters', () => {
const input = {
nodeName: 'nodeName',
distanceFromActive: 2,
path: [
'sample',
'"Execute"',
'`Execute`',
"'Execute'",
'[Execute]',
'{Execute}',
'execute?',
'test,',
'test:',
'path.',
],
};
const result = getMappedExpression(input);
expect(result).toBe(
"{{ $node.nodeName.json.sample['\"Execute\"']['`Execute`']['\\'Execute\\'']['[Execute]']['{Execute}']['execute?']['test,']['test:']['path.'] }}",
); );
}); });
@ -239,7 +262,7 @@ describe('Mapping Utils', () => {
path: ['propertyName', 'capitalizedName', 'hyphen-prop'], path: ['propertyName', 'capitalizedName', 'hyphen-prop'],
}; };
const result = getMappedExpression(input); const result = getMappedExpression(input);
expect(result).toBe('{{ $json.propertyName.capitalizedName["hyphen-prop"] }}'); expect(result).toBe("{{ $json.propertyName.capitalizedName['hyphen-prop'] }}");
}); });
it('should generate a mapped expression with a complex path', () => { it('should generate a mapped expression with a complex path', () => {
@ -250,7 +273,7 @@ describe('Mapping Utils', () => {
}; };
const result = getMappedExpression(input); const result = getMappedExpression(input);
expect(result).toBe( expect(result).toBe(
'{{ $json.propertyName.capitalizedName.stringVal["some-value"].capitalizedProp }}', "{{ $json.propertyName.capitalizedName.stringVal['some-value'].capitalizedProp }}",
); );
}); });
}); });

View file

@ -275,13 +275,13 @@ describe('Types Utils', () => {
type: 'array', type: 'array',
key: 'with space', key: 'with space',
value: [], value: [],
path: '["with space"]', path: "['with space']",
}, },
{ {
type: 'string', type: 'string',
key: 'with.dot', key: 'with.dot',
value: 'test', value: 'test',
path: '["with.dot"]', path: "['with.dot']",
}, },
], ],
path: '', path: '',

View file

@ -6,8 +6,11 @@ export function generatePath(root: string, path: Array<string | number>): string
return `${accu}[${part}]`; return `${accu}[${part}]`;
} }
if (part.includes('-') || part.includes(' ') || part.includes('.')) { const special = ['-', ' ', '.', "'", '"', '`', '[', ']', '{', '}', '(', ')', ':', ',', '?'];
return `${accu}["${part}"]`; const hasSpecial = !!special.find((s) => part.includes(s));
if (hasSpecial) {
const escaped = part.replaceAll("'", "\\'");
return `${accu}['${escaped}']`;
} }
return `${accu}.${part}`; return `${accu}.${part}`;