1
0
Fork 0
mirror of https://github.com/n8n-io/n8n.git synced 2025-03-05 20:50:17 -08:00
n8n/packages/nodes-base/nodes/MoveBinaryData.node.ts
Kyle Mohr 69745c93d8
Update description of 'Keep Source' toggle ()
Fixed some improper grammar in the 'Keep Source' toggle of the Move Binary Data node in order to improve readability
2021-08-26 19:44:09 +02:00

499 lines
12 KiB
TypeScript

import {
get,
set,
unset,
} from 'lodash';
import {
BINARY_ENCODING,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
IBinaryData,
IDataObject,
INodeExecutionData,
INodePropertyOptions,
INodeType,
INodeTypeDescription,
NodeOperationError,
} from 'n8n-workflow';
import * as iconv from 'iconv-lite';
iconv.encodingExists('utf8');
// Create options for bomAware and encoding
const bomAware: string[] = [];
const encodeDecodeOptions: INodePropertyOptions[] = [];
const encodings = (iconv as any).encodings; // tslint:disable-line:no-any
Object.keys(encodings).forEach(encoding => {
if (!(encoding.startsWith('_') || typeof encodings[encoding] === 'string')) { // only encodings without direct alias or internals
if (encodings[encoding].bomAware) {
bomAware.push(encoding);
}
encodeDecodeOptions.push({ name: encoding, value: encoding });
}
});
encodeDecodeOptions.sort((a, b) => {
if (a.name < b.name) { return -1; }
if (a.name > b.name) { return 1; }
return 0;
});
export class MoveBinaryData implements INodeType {
description: INodeTypeDescription = {
displayName: 'Move Binary Data',
name: 'moveBinaryData',
icon: 'fa:exchange-alt',
group: ['transform'],
version: 1,
subtitle: '={{$parameter["mode"]==="binaryToJson" ? "Binary to JSON" : "JSON to Binary"}}',
description: 'Move data between binary and JSON properties',
defaults: {
name: 'Move Binary Data',
color: '#7722CC',
},
inputs: ['main'],
outputs: ['main'],
properties: [
{
displayName: 'Mode',
name: 'mode',
type: 'options',
options: [
{
name: 'Binary to JSON',
value: 'binaryToJson',
description: 'Move data from Binary to JSON',
},
{
name: 'JSON to Binary',
value: 'jsonToBinary',
description: 'Move data from JSON to Binary.',
},
],
default: 'binaryToJson',
description: 'From and to where data should be moved.',
},
// ----------------------------------
// binaryToJson
// ----------------------------------
{
displayName: 'Set all Data',
name: 'setAllData',
type: 'boolean',
displayOptions: {
show: {
mode: [
'binaryToJson',
],
},
},
default: true,
description: 'If all JSON data should be replaced with the data retrieved<br />from binary key. Else the data will be written to a single key.',
},
{
displayName: 'Source Key',
name: 'sourceKey',
type: 'string',
displayOptions: {
show: {
mode: [
'binaryToJson',
],
},
},
default: 'data',
required: true,
placeholder: 'data',
description: 'The name of the binary key to get data from.<br />It is also possible to define deep keys by using dot-notation like for example:<br />"level1.level2.currentKey"',
},
{
displayName: 'Destination Key',
name: 'destinationKey',
type: 'string',
displayOptions: {
show: {
mode: [
'binaryToJson',
],
setAllData: [
false,
],
},
},
default: 'data',
required: true,
placeholder: '',
description: 'The name the JSON key to copy data to. It is also possible<br />to define deep keys by using dot-notation like for example:<br />"level1.level2.newKey"',
},
// ----------------------------------
// jsonToBinary
// ----------------------------------
{
displayName: 'Convert all Data',
name: 'convertAllData',
type: 'boolean',
displayOptions: {
show: {
mode: [
'jsonToBinary',
],
},
},
default: true,
description: 'If all JSON data should be converted to binary.<br />Else only the data of one key will be converted.',
},
{
displayName: 'Source Key',
name: 'sourceKey',
type: 'string',
displayOptions: {
show: {
convertAllData: [
false,
],
mode: [
'jsonToBinary',
],
},
},
default: 'data',
required: true,
placeholder: 'data',
description: 'The name of the JSON key to get data from. It is also possible<br />to define deep keys by using dot-notation like for example:<br />"level1.level2.currentKey"',
},
{
displayName: 'Destination Key',
name: 'destinationKey',
type: 'string',
displayOptions: {
show: {
mode: [
'jsonToBinary',
],
},
},
default: 'data',
required: true,
placeholder: 'data',
description: 'The name the binary key to copy data to. It is also possible<br />to define deep keys by using dot-notation like for example:<br />"level1.level2.newKey"',
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
options: [
{
displayName: 'Data Is Base64',
name: 'dataIsBase64',
type: 'boolean',
displayOptions: {
hide: {
'useRawData': [
true,
],
},
show: {
'/mode': [
'jsonToBinary',
],
'/convertAllData': [
false,
],
},
},
default: false,
description: 'Keeps the binary data as base64 string.',
},
{
displayName: 'Encoding',
name: 'encoding',
type: 'options',
options: encodeDecodeOptions,
displayOptions: {
show: {
'/mode': [
'binaryToJson',
'jsonToBinary',
],
},
},
default: 'utf8',
description: 'Set the encoding of the data stream',
},
{
displayName: 'Strip BOM',
name: 'stripBOM',
displayOptions: {
show: {
'/mode': [
'binaryToJson',
],
encoding: bomAware,
},
},
type: 'boolean',
default: true,
},
{
displayName: 'Add BOM',
name: 'addBOM',
displayOptions: {
show: {
'/mode': [
'jsonToBinary',
],
encoding: bomAware,
},
},
type: 'boolean',
default: false,
},
{
displayName: 'File Name',
name: 'fileName',
type: 'string',
displayOptions: {
show: {
'/mode': [
'jsonToBinary',
],
},
},
default: '',
placeholder: 'example.json',
description: 'The file name to set.',
},
{
displayName: 'JSON Parse',
name: 'jsonParse',
type: 'boolean',
displayOptions: {
hide: {
'keepAsBase64': [
true,
],
},
show: {
'/mode': [
'binaryToJson',
],
'/setAllData': [
false,
],
},
},
default: false,
description: 'Run JSON parse on the data to get proper object data.',
},
{
displayName: 'Keep Source',
name: 'keepSource',
type: 'boolean',
default: false,
description: 'If the source key should be kept. By default it will be deleted.',
},
{
displayName: 'Keep As Base64',
name: 'keepAsBase64',
type: 'boolean',
displayOptions: {
hide: {
'jsonParse': [
true,
],
},
show: {
'/mode': [
'binaryToJson',
],
'/setAllData': [
false,
],
},
},
default: false,
description: 'Keeps the binary data as base64 string.',
},
{
displayName: 'Mime Type',
name: 'mimeType',
type: 'string',
displayOptions: {
show: {
'/mode': [
'jsonToBinary',
],
},
},
default: 'application/json',
placeholder: 'application/json',
description: 'The mime-type to set. By default will the mime-type for JSON be set.',
},
{
displayName: 'Use Raw Data',
name: 'useRawData',
type: 'boolean',
displayOptions: {
hide: {
'dataIsBase64': [
true,
],
},
show: {
'/mode': [
'jsonToBinary',
],
},
},
default: false,
description: 'Use data as is and do not JSON.stringify it.',
},
],
},
],
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const mode = this.getNodeParameter('mode', 0) as string;
const returnData: INodeExecutionData[] = [];
let item: INodeExecutionData;
let newItem: INodeExecutionData;
let options: IDataObject;
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
item = items[itemIndex];
options = this.getNodeParameter('options', itemIndex, {}) as IDataObject;
// Copy the whole JSON data as data on any level can be renamed
newItem = {
json: {},
};
if (mode === 'binaryToJson') {
const setAllData = this.getNodeParameter('setAllData', itemIndex) as boolean;
const sourceKey = this.getNodeParameter('sourceKey', itemIndex) as string;
const value = get(item.binary, sourceKey);
if (value === undefined) {
// No data found so skip
continue;
}
const encoding = (options.encoding as string) || 'utf8';
let convertedValue = value.data;
if (setAllData === true) {
// Set the full data
convertedValue = iconv.decode(Buffer.from(convertedValue, BINARY_ENCODING), encoding, { stripBOM: options.stripBOM as boolean });
newItem.json = JSON.parse(convertedValue);
} else {
// Does get added to existing data so copy it first
newItem.json = JSON.parse(JSON.stringify(item.json));
if (options.keepAsBase64 !== true) {
convertedValue = iconv.decode(Buffer.from(convertedValue, BINARY_ENCODING), encoding, { stripBOM: options.stripBOM as boolean });
}
if (options.jsonParse) {
convertedValue = JSON.parse(convertedValue);
}
const destinationKey = this.getNodeParameter('destinationKey', itemIndex, '') as string;
set(newItem.json, destinationKey, convertedValue);
}
if (options.keepSource === true) {
// Binary data does not get touched so simply reference it
newItem.binary = item.binary;
} else {
// Binary data will change so copy it
newItem.binary = JSON.parse(JSON.stringify(item.binary));
unset(newItem.binary, sourceKey);
}
} else if (mode === 'jsonToBinary') {
const convertAllData = this.getNodeParameter('convertAllData', itemIndex) as boolean;
const destinationKey = this.getNodeParameter('destinationKey', itemIndex) as string;
const encoding = (options.encoding as string) || 'utf8';
let value: IDataObject | string = item.json;
if (convertAllData === false) {
const sourceKey = this.getNodeParameter('sourceKey', itemIndex) as string;
value = get(item.json, sourceKey) as IDataObject;
}
if (value === undefined) {
// No data found so skip
continue;
}
if (item.binary !== undefined) {
// Item already has binary data so copy it
newItem.binary = JSON.parse(JSON.stringify(item.binary));
} else {
// Item does not have binary data yet so initialize empty
newItem.binary = {};
}
if (options.dataIsBase64 !== true) {
if (options.useRawData !== true) {
value = JSON.stringify(value);
}
value = iconv.encode(value as string, encoding, { addBOM: options.addBOM as boolean }).toString(BINARY_ENCODING);
}
const convertedValue: IBinaryData = {
data: value as string,
mimeType: (options.mimeType as string) || 'application/json',
};
if (options.fileName) {
convertedValue.fileName = options.fileName as string;
}
set(newItem.binary!, destinationKey, convertedValue);
if (options.keepSource === true) {
// JSON data does not get touched so simply reference it
newItem.json = item.json;
} else {
// JSON data will change so copy it
if (convertAllData === true) {
// Data should not be kept and all data got converted. So simply set new as empty
newItem.json = {};
} else {
// Data should not be kept and only one key has to get removed. So copy all
// data and then remove the not needed one
newItem.json = JSON.parse(JSON.stringify(item.json));
const sourceKey = this.getNodeParameter('sourceKey', itemIndex) as string;
unset(newItem.json, sourceKey);
}
}
} else {
throw new NodeOperationError(this.getNode(), `The operation "${mode}" is not known!`);
}
returnData.push(newItem);
}
return [returnData];
}
}