fix(editor): Avoid infinite loops when resolving the expression {{ $parameter }} (no-changelog) (#6855)

Co-authored-by: Oleg Ivaniv <me@olegivaniv.com>
This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™ 2023-08-07 11:52:33 +02:00 committed by GitHub
parent adcf5a96e8
commit 8126181e18
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 14 additions and 5 deletions

View file

@ -51,7 +51,7 @@ describe('Inline expression editor', () => {
it('should resolve array resolvables', () => { it('should resolve array resolvables', () => {
WorkflowPage.getters.inlineExpressionEditorInput().clear(); WorkflowPage.getters.inlineExpressionEditorInput().clear();
WorkflowPage.getters.inlineExpressionEditorInput().type('{{'); WorkflowPage.getters.inlineExpressionEditorInput().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().type('[1, 2, 3]', { timeout: 20000 }); WorkflowPage.getters.inlineExpressionEditorInput().type('[1, 2, 3]');
WorkflowPage.getters.inlineExpressionEditorOutput().contains(/^\[Array: \[1,2,3\]\]$/); WorkflowPage.getters.inlineExpressionEditorOutput().contains(/^\[Array: \[1,2,3\]\]$/);
WorkflowPage.getters.inlineExpressionEditorInput().clear(); WorkflowPage.getters.inlineExpressionEditorInput().clear();
@ -66,7 +66,7 @@ describe('Inline expression editor', () => {
WorkflowPage.getters.inlineExpressionEditorInput().clear(); WorkflowPage.getters.inlineExpressionEditorInput().clear();
WorkflowPage.getters.inlineExpressionEditorInput().type('{{'); WorkflowPage.getters.inlineExpressionEditorInput().type('{{');
// Resolving $parameter is slow, especially on CI runner // Resolving $parameter is slow, especially on CI runner
WorkflowPage.getters.inlineExpressionEditorInput().type('$parameter["operation"]', { timeout: 35000 }); WorkflowPage.getters.inlineExpressionEditorInput().type('$parameter["operation"]');
WorkflowPage.getters.inlineExpressionEditorOutput().contains(/^get$/); WorkflowPage.getters.inlineExpressionEditorOutput().contains(/^get$/);
}); });
}); });

View file

@ -657,11 +657,14 @@ export const workflowHelpers = defineComponent({
return null; return null;
} }
if (typeof returnData['__xxxxxxx__'] === 'object') { const obj = returnData['__xxxxxxx__'];
if (typeof obj === 'object') {
const proxy = obj as { isProxy: boolean; toJSON?: () => unknown } | null;
if (proxy?.isProxy && proxy.toJSON) return JSON.stringify(proxy.toJSON());
const workflow = getCurrentWorkflow(); const workflow = getCurrentWorkflow();
return workflow.expression.convertObjectValueToString(returnData['__xxxxxxx__'] as object); return workflow.expression.convertObjectValueToString(obj as object);
} }
return returnData['__xxxxxxx__']; return obj;
}, },
async updateWorkflow( async updateWorkflow(

View file

@ -27,6 +27,7 @@ import * as NodeHelpers from './NodeHelpers';
import { ExpressionError } from './ExpressionError'; import { ExpressionError } from './ExpressionError';
import type { Workflow } from './Workflow'; import type { Workflow } from './Workflow';
import { augmentArray, augmentObject } from './AugmentObject'; import { augmentArray, augmentObject } from './AugmentObject';
import { deepCopy } from './utils';
export function isResourceLocatorValue(value: unknown): value is INodeParameterResourceLocator { export function isResourceLocatorValue(value: unknown): value is INodeParameterResourceLocator {
return Boolean( return Boolean(
@ -213,6 +214,8 @@ export class WorkflowDataProxy {
}, },
get(target, name, receiver) { get(target, name, receiver) {
if (name === 'isProxy') return true; if (name === 'isProxy') return true;
if (name === 'toJSON') return () => deepCopy(target);
name = name.toString(); name = name.toString();
let returnValue: NodeParameterValueType; let returnValue: NodeParameterValueType;
@ -231,6 +234,9 @@ export class WorkflowDataProxy {
returnValue = node.parameters[name]; returnValue = node.parameters[name];
} }
// Avoid recursion
if (returnValue === `={{ $parameter.${name} }}`) return undefined;
if (isResourceLocatorValue(returnValue)) { if (isResourceLocatorValue(returnValue)) {
if (returnValue.__regex && typeof returnValue.value === 'string') { if (returnValue.__regex && typeof returnValue.value === 'string') {
const expr = new RegExp(returnValue.__regex); const expr = new RegExp(returnValue.__regex);