From 740513b42440b8760cd488659e92abe9951462b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Tue, 22 Nov 2022 14:49:13 +0100 Subject: [PATCH] perf(Code Node): Improve n8n item key validation performance (#4669) :zap: Improve validator performance --- packages/nodes-base/nodes/Code/Sandbox.ts | 28 ++++++++++++----------- packages/nodes-base/nodes/Code/utils.ts | 2 +- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/nodes-base/nodes/Code/Sandbox.ts b/packages/nodes-base/nodes/Code/Sandbox.ts index 1ac56e2823982..6fc43c8bf1f1b 100644 --- a/packages/nodes-base/nodes/Code/Sandbox.ts +++ b/packages/nodes-base/nodes/Code/Sandbox.ts @@ -2,7 +2,7 @@ import { normalizeItems } from 'n8n-core'; import { NodeVM, NodeVMOptions } from 'vm2'; import { ValidationError } from './ValidationError'; import { ExecutionError } from './ExecutionError'; -import { CodeNodeMode, isObject, SUPPORTED_ITEM_KEYS } from './utils'; +import { CodeNodeMode, isObject, N8N_ITEM_KEYS } from './utils'; import type { IExecuteFunctions, IWorkflowDataProxyData, WorkflowExecuteMode } from 'n8n-workflow'; @@ -95,6 +95,17 @@ export class Sandbox extends NodeVM { } if (Array.isArray(executionResult)) { + /** + * If at least one top-level key is an n8n item key (`json`, `binary`, etc.), + * then require all item keys to be an n8n item key. + * + * If no top-level key is an n8n key, then skip this check, allowing non-n8n + * item keys to be wrapped in `json` when normalizing items below. + */ + const mustHaveTopLevelN8nKey = executionResult.some((item) => + Object.keys(item).find((key) => N8N_ITEM_KEYS.has(key)), + ); + for (const item of executionResult) { if (item.json !== undefined && !isObject(item.json)) { throw new ValidationError({ @@ -104,18 +115,9 @@ export class Sandbox extends NodeVM { }); } - // If at least one top-level key is a supported item key (`json`, `binary`, etc.), - // then validate all keys to be a supported item key, else allow user keys - // to be wrapped in `json` when normalizing items below. - - if ( - executionResult.some((item) => - Object.keys(item).find((key) => SUPPORTED_ITEM_KEYS.has(key)), - ) - ) { + if (mustHaveTopLevelN8nKey) { Object.keys(item).forEach((key) => { - if (SUPPORTED_ITEM_KEYS.has(key)) return; - + if (N8N_ITEM_KEYS.has(key)) return; throw new ValidationError({ message: `Unknown top-level item key: ${key}`, description: 'Access the properties of an item under `.json`, e.g. `item.json`', @@ -223,7 +225,7 @@ export class Sandbox extends NodeVM { // directly on the item, when they intended to add it on the `json` property Object.keys(executionResult).forEach((key) => { - if (SUPPORTED_ITEM_KEYS.has(key)) return; + if (N8N_ITEM_KEYS.has(key)) return; throw new ValidationError({ message: `Unknown top-level item key: ${key}`, diff --git a/packages/nodes-base/nodes/Code/utils.ts b/packages/nodes-base/nodes/Code/utils.ts index 0b389af9c145d..ffbfe31ea1b50 100644 --- a/packages/nodes-base/nodes/Code/utils.ts +++ b/packages/nodes-base/nodes/Code/utils.ts @@ -26,4 +26,4 @@ function isTraversable(maybe: unknown): maybe is IDataObject { export type CodeNodeMode = 'runOnceForAllItems' | 'runOnceForEachItem'; -export const SUPPORTED_ITEM_KEYS = new Set(['json', 'binary', 'error', 'pairedItem', 'index']); +export const N8N_ITEM_KEYS = new Set(['json', 'binary', 'error', 'pairedItem', 'index']);