mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
107 lines
3 KiB
TypeScript
107 lines
3 KiB
TypeScript
import type { INodeProperties, NodeParameterValueType } from 'n8n-workflow';
|
|
import { isResourceLocatorValue } from 'n8n-workflow';
|
|
import { isExpression } from './expressions';
|
|
|
|
const validJsIdNameRegex = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
|
|
function isValidJsIdentifierName(name: string | number): boolean {
|
|
return validJsIdNameRegex.test(name.toString());
|
|
}
|
|
|
|
export function generatePath(root: string, path: Array<string | number>): string {
|
|
return path.reduce((accu: string, part: string | number) => {
|
|
if (typeof part === 'number') {
|
|
return `${accu}[${part}]`;
|
|
}
|
|
|
|
if (!isValidJsIdentifierName(part)) {
|
|
return `${accu}['${escapeMappingString(part)}']`;
|
|
}
|
|
|
|
return `${accu}.${part}`;
|
|
}, root);
|
|
}
|
|
|
|
export function escapeMappingString(str: string): string {
|
|
return str.replace(/\'/g, "\\'");
|
|
}
|
|
|
|
export function getMappedExpression({
|
|
nodeName,
|
|
distanceFromActive,
|
|
path,
|
|
}: {
|
|
nodeName: string;
|
|
distanceFromActive: number;
|
|
path: Array<string | number> | string;
|
|
}) {
|
|
const root =
|
|
distanceFromActive === 1
|
|
? '$json'
|
|
: generatePath(`$('${escapeMappingString(nodeName)}')`, ['item', 'json']);
|
|
|
|
if (typeof path === 'string') {
|
|
return `{{ ${root}${path} }}`;
|
|
}
|
|
|
|
return `{{ ${generatePath(root, path)} }}`;
|
|
}
|
|
|
|
const unquote = (str: string) => {
|
|
if (str.startsWith('"') && str.endsWith('"')) {
|
|
return str.slice(1, -1).replace(/\\"/g, '"');
|
|
}
|
|
|
|
if (str.startsWith("'") && str.endsWith("'")) {
|
|
return str.slice(1, -1).replace(/\\'/g, "'");
|
|
}
|
|
|
|
return str;
|
|
};
|
|
|
|
export function propertyNameFromExpression(expression: string, forceBracketAccess = false): string {
|
|
const propPath = expression
|
|
.replace(/^{{\s*|\s*}}$/g, '')
|
|
.replace(/^(\$\(.*\)\.item\.json|\$json|\$node\[.*\]\.json)\.?(.*)/, '$2');
|
|
|
|
const isSingleBracketAccess = propPath.startsWith('[') && !propPath.slice(1).includes('[');
|
|
if (isSingleBracketAccess && !forceBracketAccess) {
|
|
// "['Key with spaces']" -> "Key with spaces"
|
|
return unquote(propPath.slice(1, -1));
|
|
}
|
|
|
|
return propPath;
|
|
}
|
|
|
|
export function getMappedResult(
|
|
parameter: INodeProperties,
|
|
newParamValue: string,
|
|
prevParamValue: NodeParameterValueType,
|
|
): string {
|
|
const prevValue =
|
|
parameter.type === 'resourceLocator' && isResourceLocatorValue(prevParamValue)
|
|
? prevParamValue.value
|
|
: prevParamValue;
|
|
|
|
if (parameter.requiresDataPath) {
|
|
if (parameter.requiresDataPath === 'multiple') {
|
|
const propertyName = propertyNameFromExpression(newParamValue, true);
|
|
if (typeof prevValue === 'string' && (prevValue.trim() === '=' || prevValue.trim() === '')) {
|
|
return propertyName;
|
|
}
|
|
|
|
return `${prevValue}, ${propertyName}`;
|
|
}
|
|
|
|
return propertyNameFromExpression(newParamValue);
|
|
} else if (typeof prevValue === 'string' && isExpression(prevValue) && prevValue.length > 1) {
|
|
return `${prevValue} ${newParamValue}`;
|
|
} else if (prevValue && ['string', 'json'].includes(parameter.type)) {
|
|
return prevValue === '=' || typeof prevValue === 'object'
|
|
? `=${newParamValue}`
|
|
: `=${prevValue} ${newParamValue}`;
|
|
}
|
|
|
|
return `=${newParamValue}`;
|
|
}
|