From 62e05cf0b371a633a50fe348c1004b14bc03036e Mon Sep 17 00:00:00 2001 From: Michael Kret <88898367+michael-radency@users.noreply.github.com> Date: Mon, 7 Mar 2022 10:54:52 +0200 Subject: [PATCH] :zap: Tolerate missing json key in function node output (#2885) * :hammer: implemented Tolerate missing json key in function node output * :hammer: clean up * Small change to code * :zap: tolerate returning object * :zap: Rename function Co-authored-by: Omar Ajoue Co-authored-by: Jan Oberhauser --- packages/core/src/Interfaces.ts | 1 + packages/core/src/NodeExecuteFunctions.ts | 46 +++++++++++++++++++ .../nodes/Function/Function.node.ts | 2 + 3 files changed, 49 insertions(+) diff --git a/packages/core/src/Interfaces.ts b/packages/core/src/Interfaces.ts index 0146b9ba2a..0a90ca6fee 100644 --- a/packages/core/src/Interfaces.ts +++ b/packages/core/src/Interfaces.ts @@ -62,6 +62,7 @@ export interface IExecuteFunctions extends IExecuteFunctionsBase { requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions, ): Promise; // tslint:disable-line:no-any returnJsonArray(jsonData: IDataObject | IDataObject[]): INodeExecutionData[]; + normalizeItemsInArray(items: INodeExecutionData[]): INodeExecutionData[]; httpRequestWithAuthentication( this: IAllExecuteFunctions, credentialsType: string, diff --git a/packages/core/src/NodeExecuteFunctions.ts b/packages/core/src/NodeExecuteFunctions.ts index 421314e61a..1d54de9a11 100644 --- a/packages/core/src/NodeExecuteFunctions.ts +++ b/packages/core/src/NodeExecuteFunctions.ts @@ -1132,6 +1132,51 @@ export function returnJsonArray(jsonData: IDataObject | IDataObject[]): INodeExe return returnData; } +/** + * Automatically put the objects under a 'json' key and don't error, + * if some objects contain json/binary keys and others don't, throws error 'Inconsistent item format' + * + * @export + * @param {INodeExecutionData | INodeExecutionData[]} executionData + * @returns {INodeExecutionData[]} + */ +export function normalizeItems( + executionData: INodeExecutionData | INodeExecutionData[], +): INodeExecutionData[] { + if (typeof executionData === 'object' && !Array.isArray(executionData)) + executionData = [{ json: executionData as IDataObject }]; + if (executionData.every((item) => typeof item === 'object' && 'json' in item)) + return executionData; + + if (executionData.some((item) => typeof item === 'object' && 'json' in item)) { + throw new Error('Inconsistent item format'); + } + + if (executionData.every((item) => typeof item === 'object' && 'binary' in item)) { + const normalizedItems: INodeExecutionData[] = []; + executionData.forEach((item) => { + const json = Object.keys(item).reduce((acc, key) => { + if (key === 'binary') return acc; + return { ...acc, [key]: item[key] }; + }, {}); + + normalizedItems.push({ + json, + binary: item.binary, + }); + }); + return normalizedItems; + } + + if (executionData.some((item) => typeof item === 'object' && 'binary' in item)) { + throw new Error('Inconsistent item format'); + } + + return executionData.map((item) => { + return { json: item }; + }); +} + // TODO: Move up later export async function requestWithAuthentication( this: IAllExecuteFunctions, @@ -2080,6 +2125,7 @@ export function getExecuteFunctions( ); }, returnJsonArray, + normalizeItems, }, }; })(workflow, runExecutionData, connectionInputData, inputData, node); diff --git a/packages/nodes-base/nodes/Function/Function.node.ts b/packages/nodes-base/nodes/Function/Function.node.ts index 0ce45f9f1a..f1c1576a31 100644 --- a/packages/nodes-base/nodes/Function/Function.node.ts +++ b/packages/nodes-base/nodes/Function/Function.node.ts @@ -119,6 +119,8 @@ return items;`, try { // Execute the function code items = (await vm.run(`module.exports = async function() {${functionCode}\n}()`, __dirname)); + items = this.helpers.normalizeItems(items); + // Do very basic validation of the data if (items === undefined) { throw new NodeOperationError(this.getNode(), 'No data got returned. Always return an Array of items!');