fix(Rename Keys Node): Add a warning for regex that affect performance (#18911)

This commit is contained in:
Shireen Missi
2025-08-29 14:44:28 +01:00
committed by GitHub
parent cc2ed19ecf
commit 0d1a0b5431
4 changed files with 131 additions and 27 deletions

View File

@@ -9,7 +9,6 @@ import type {
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
interface IRenameKey {
currentKey: string;
newKey: string;
@@ -81,7 +80,7 @@ export class RenameKeys implements INodeType {
displayName: 'Regex',
name: 'regexReplacement',
placeholder: 'Add new regular expression',
description: 'Adds a regular expressiond',
description: 'Adds a regular expression',
type: 'fixedCollection',
typeOptions: {
multipleValues: true,
@@ -149,11 +148,21 @@ export class RenameKeys implements INodeType {
],
},
],
hints: [
{
type: 'warning',
message:
'Complex regex patterns like nested quantifiers .*+, ()*+, or multiple wildcards may cause performance issues. Consider using simpler patterns like [a-z]+ or \\w+ for better performance.',
displayCondition:
'={{ $parameter.additionalOptions.regexReplacement.replacements && $parameter.additionalOptions.regexReplacement.replacements.some(r => r.searchRegex && /(\\.\\*\\+|\\)\\*\\+|\\+\\*|\\*.*\\*|\\+.*\\+|\\?.*\\?|\\{[0-9]+,\\}|\\*{2,}|\\+{2,}|\\?{2,}|[a-zA-Z0-9]{4,}[\\*\\+]|\\([^)]*\\|[^)]*\\)[\\*\\+])/.test(r.searchRegex)) }}',
whenToDisplay: 'always',
location: 'outputPane',
},
],
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const returnData: INodeExecutionData[] = [];
let item: INodeExecutionData;
@@ -208,34 +217,46 @@ export class RenameKeys implements INodeType {
newItem.json = renameObjectKeys(newItem.json, depth as number);
};
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
renameKeys = this.getNodeParameter('keys.key', itemIndex, []) as IRenameKey[];
const regexReplacements = this.getNodeParameter(
'additionalOptions.regexReplacement.replacements',
itemIndex,
[],
) as IDataObject[];
try {
renameKeys = this.getNodeParameter('keys.key', itemIndex, []) as IRenameKey[];
const regexReplacements = this.getNodeParameter(
'additionalOptions.regexReplacement.replacements',
itemIndex,
[],
) as IDataObject[];
item = items[itemIndex];
item = items[itemIndex];
// Copy the whole JSON data as data on any level can be renamed
newItem = {
json: deepCopy(item.json),
pairedItem: {
item: itemIndex,
},
};
// Copy the whole JSON data as data on any level can be renamed
newItem = {
json: deepCopy(item.json),
pairedItem: {
item: itemIndex,
},
};
if (item.binary !== undefined) {
// Reference binary data if any exists. We can reference it
// as this nodes does not change it
newItem.binary = item.binary;
if (item.binary !== undefined) {
// Reference binary data if any exists. We can reference it
// as this nodes does not change it
newItem.binary = item.binary;
}
renameKeys.forEach(renameKey);
regexReplacements.forEach(regexReplaceKey);
returnData.push(newItem);
} catch (error) {
if (this.continueOnFail()) {
const executionErrorData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray({ error: error.message }),
{ itemData: { item: itemIndex } },
);
returnData.push(...executionErrorData);
continue;
}
throw error;
}
renameKeys.forEach(renameKey);
regexReplacements.forEach(regexReplaceKey);
returnData.push(newItem);
}
return [returnData];