n8n-nodes-base
Version:
Base nodes of n8n
399 lines • 18.1 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SwitchV3 = void 0;
const set_1 = __importDefault(require("lodash/set"));
const n8n_workflow_1 = require("n8n-workflow");
const utilities_1 = require("../../../utils/utilities");
const constants_1 = require("../../../utils/constants");
const descriptions_1 = require("../../../utils/descriptions");
const utils_1 = require("../../If/V2/utils");
const configuredOutputs = (parameters) => {
const mode = parameters.mode;
if (mode === 'expression') {
return Array.from({ length: parameters.numberOutputs }, (_, i) => ({
type: 'main',
displayName: i.toString(),
}));
}
else {
const rules = parameters.rules?.values ?? [];
const ruleOutputs = rules.map((rule, index) => {
return {
type: 'main',
displayName: rule.outputKey || index.toString(),
};
});
if (parameters.options?.fallbackOutput === 'extra') {
const renameFallbackOutput = parameters.options?.renameFallbackOutput;
ruleOutputs.push({
type: 'main',
displayName: renameFallbackOutput || 'Fallback',
});
}
return ruleOutputs;
}
};
class SwitchV3 {
description;
constructor(baseDescription) {
this.description = {
...baseDescription,
subtitle: `=mode: {{(${utilities_1.capitalize})($parameter["mode"])}}`,
version: [3, 3.1, 3.2, 3.3, 3.4],
defaults: {
name: 'Switch',
color: '#506000',
},
inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
outputs: `={{(${configuredOutputs})($parameter)}}`,
properties: [
{
displayName: 'Mode',
name: 'mode',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Rules',
value: 'rules',
description: 'Build a matching rule for each output',
},
{
name: 'Expression',
value: 'expression',
description: 'Write an expression to return the output index',
},
],
default: 'rules',
description: 'How data should be routed',
},
{
displayName: 'Number of Outputs',
name: 'numberOutputs',
type: 'number',
noDataExpression: true,
displayOptions: {
show: {
mode: ['expression'],
'@version': [{ _cnd: { gte: 3.3 } }],
},
},
default: 4,
description: 'How many outputs to create',
},
{
displayName: 'Number of Outputs',
name: 'numberOutputs',
type: 'number',
displayOptions: {
show: {
mode: ['expression'],
'@version': [{ _cnd: { lt: 3.3 } }],
},
},
default: 4,
description: 'How many outputs to create',
},
{
displayName: 'Output Index',
name: 'output',
type: 'number',
validateType: 'number',
hint: 'The index to route the item to, starts at 0',
displayOptions: {
show: {
mode: ['expression'],
},
},
// eslint-disable-next-line n8n-nodes-base/node-param-default-wrong-for-number
default: '={{}}',
description: 'The output index to send the input item to. Use an expression to calculate which input item should be routed to which output. The expression must return a number.',
},
{
displayName: 'Routing Rules',
name: 'rules',
placeholder: 'Add Routing Rule',
type: 'fixedCollection',
typeOptions: {
multipleValues: true,
sortable: true,
},
default: {
values: [
{
conditions: {
options: {
caseSensitive: true,
leftValue: '',
typeValidation: 'strict',
},
conditions: [
{
leftValue: '',
rightValue: '',
operator: {
type: 'string',
operation: 'equals',
},
},
],
combinator: 'and',
},
},
],
},
displayOptions: {
show: {
mode: ['rules'],
},
},
options: [
{
name: 'values',
displayName: 'Routing Rule',
values: [
{
displayName: 'Conditions',
name: 'conditions',
placeholder: 'Add Condition',
type: 'filter',
default: {},
typeOptions: {
multipleValues: false,
filter: {
caseSensitive: '={{!$parameter.options.ignoreCase}}',
typeValidation: (0, utils_1.getTypeValidationStrictness)(3.1),
version: '={{ $nodeVersion >=3.4 ? 3 : $nodeVersion >= 3.2 ? 2 : 1 }}',
},
},
},
{
displayName: 'Rename Output',
name: 'renameOutput',
type: 'boolean',
default: false,
},
{
displayName: 'Output Name',
name: 'outputKey',
type: 'string',
default: '',
description: 'The label of output to which to send data to if rule matches',
displayOptions: {
show: {
renameOutput: [true],
},
},
},
],
},
],
},
{
...descriptions_1.looseTypeValidationProperty,
default: false,
displayOptions: {
show: {
'@version': [{ _cnd: { gte: 3.1 } }],
},
},
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add option',
default: {},
displayOptions: {
show: {
mode: ['rules'],
},
},
options: [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Fallback Output',
name: 'fallbackOutput',
type: 'options',
typeOptions: {
loadOptionsDependsOn: ['rules.values', '/rules', '/rules.values'],
loadOptionsMethod: 'getFallbackOutputOptions',
},
default: 'none',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description: 'If no rule matches the item will be sent to this output, by default they will be ignored',
},
{
displayName: 'Ignore Case',
description: 'Whether to ignore letter case when evaluating conditions',
name: 'ignoreCase',
type: 'boolean',
default: true,
},
{
...descriptions_1.looseTypeValidationProperty,
displayOptions: {
show: {
'@version': [{ _cnd: { lt: 3.1 } }],
},
},
},
{
displayName: 'Rename Fallback Output',
name: 'renameFallbackOutput',
type: 'string',
placeholder: 'e.g. Fallback',
default: '',
displayOptions: {
show: {
fallbackOutput: ['extra'],
},
},
},
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
displayName: 'Send data to all matching outputs',
name: 'allMatchingOutputs',
type: 'boolean',
default: false,
description: 'Whether to send data to all outputs meeting conditions (and not just the first one)',
},
],
},
],
};
}
methods = {
loadOptions: {
async getFallbackOutputOptions() {
const rules = this.getCurrentNodeParameter('rules.values') ?? [];
const outputOptions = [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
name: 'None (default)',
value: 'none',
description: 'Items will be ignored',
},
{
name: 'Extra Output',
value: 'extra',
description: 'Items will be sent to the extra, separate, output',
},
];
for (const [index, rule] of rules.entries()) {
outputOptions.push({
name: `Output ${rule.outputKey || index}`,
value: index,
description: `Items will be sent to the same output as when matched rule ${index + 1}`,
});
}
return outputOptions;
},
},
};
async execute() {
let returnData = [];
const items = this.getInputData();
const mode = this.getNodeParameter('mode', 0);
const checkIndexRange = (returnDataLength, index, itemIndex = 0) => {
if (Number(index) === returnDataLength) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The ouput ${index} is not allowed. `, {
itemIndex,
description: `Output indexes are zero based, if you want to use the extra output use ${index - 1}`,
});
}
if (index < 0 || index > returnDataLength) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The ouput ${index} is not allowed`, {
itemIndex,
description: `It has to be between 0 and ${returnDataLength - 1}`,
});
}
};
itemLoop: for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
try {
const item = items[itemIndex];
item.pairedItem = { item: itemIndex };
if (mode === 'expression') {
const numberOutputs = this.getNodeParameter('numberOutputs', itemIndex);
if (itemIndex === 0) {
returnData = new Array(numberOutputs).fill(0).map(() => []);
}
const outputIndex = this.getNodeParameter('output', itemIndex);
checkIndexRange(returnData.length, outputIndex, itemIndex);
returnData[outputIndex].push(item);
}
else if (mode === 'rules') {
const rules = this.getNodeParameter('rules.values', itemIndex, []);
if (!rules.length)
continue;
const options = this.getNodeParameter('options', itemIndex, {});
const fallbackOutput = options.fallbackOutput;
if (itemIndex === 0) {
returnData = new Array(rules.length).fill(0).map(() => []);
if (fallbackOutput === 'extra') {
returnData.push([]);
}
}
let matchFound = false;
for (const [ruleIndex, rule] of rules.entries()) {
let conditionPass;
try {
conditionPass = this.getNodeParameter(`rules.values[${ruleIndex}].conditions`, itemIndex, false, {
extractValue: true,
});
}
catch (error) {
if (!(0, utils_1.getTypeValidationParameter)(3.1)(this, itemIndex, options.looseTypeValidation) &&
!error.description) {
error.description = constants_1.ENABLE_LESS_STRICT_TYPE_VALIDATION;
}
(0, set_1.default)(error, 'context.itemIndex', itemIndex);
(0, set_1.default)(error, 'node', this.getNode());
throw error;
}
if (conditionPass) {
matchFound = true;
checkIndexRange(returnData.length, rule.output, itemIndex);
returnData[ruleIndex].push(item);
if (!options.allMatchingOutputs) {
continue itemLoop;
}
}
}
if (fallbackOutput !== undefined && fallbackOutput !== 'none' && !matchFound) {
if (fallbackOutput === 'extra') {
returnData[returnData.length - 1].push(item);
continue;
}
checkIndexRange(returnData.length, fallbackOutput, itemIndex);
returnData[fallbackOutput].push(item);
}
}
}
catch (error) {
if (this.continueOnFail()) {
returnData[0].push({ json: { error: error.message } });
continue;
}
if (error instanceof n8n_workflow_1.NodeOperationError) {
throw error;
}
if (error instanceof n8n_workflow_1.ApplicationError) {
(0, set_1.default)(error, 'context.itemIndex', itemIndex);
throw error;
}
throw new n8n_workflow_1.NodeOperationError(this.getNode(), error, {
itemIndex,
});
}
}
if (!returnData.length)
return [[]];
return returnData;
}
}
exports.SwitchV3 = SwitchV3;
//# sourceMappingURL=SwitchV3.node.js.map