2023-12-13 05:45:22 -08:00
|
|
|
import get from 'lodash/get';
|
2023-11-30 00:06:19 -08:00
|
|
|
import {
|
2023-12-13 05:45:22 -08:00
|
|
|
ApplicationError,
|
2023-11-30 00:06:19 -08:00
|
|
|
LoggerProxy,
|
2023-12-13 05:45:22 -08:00
|
|
|
NodeHelpers,
|
|
|
|
NodeOperationError,
|
2023-11-30 00:06:19 -08:00
|
|
|
WorkflowOperationError,
|
2023-12-13 05:45:22 -08:00
|
|
|
executeFilter,
|
|
|
|
isFilterValue,
|
|
|
|
type INode,
|
|
|
|
type INodeParameters,
|
|
|
|
type INodeProperties,
|
|
|
|
type INodePropertyCollection,
|
|
|
|
type INodePropertyOptions,
|
|
|
|
type INodeType,
|
|
|
|
type NodeParameterValueType,
|
2023-11-30 00:06:19 -08:00
|
|
|
} from 'n8n-workflow';
|
2022-09-23 02:56:57 -07:00
|
|
|
|
|
|
|
function findPropertyFromParameterName(
|
|
|
|
parameterName: string,
|
|
|
|
nodeType: INodeType,
|
|
|
|
node: INode,
|
|
|
|
nodeParameters: INodeParameters,
|
|
|
|
): INodePropertyOptions | INodeProperties | INodePropertyCollection {
|
|
|
|
let property: INodePropertyOptions | INodeProperties | INodePropertyCollection | undefined;
|
|
|
|
const paramParts = parameterName.split('.');
|
|
|
|
let currentParamPath = '';
|
|
|
|
|
|
|
|
const findProp = (
|
|
|
|
name: string,
|
|
|
|
options: Array<INodePropertyOptions | INodeProperties | INodePropertyCollection>,
|
|
|
|
): INodePropertyOptions | INodeProperties | INodePropertyCollection | undefined => {
|
|
|
|
return options.find(
|
|
|
|
(i) =>
|
|
|
|
i.name === name &&
|
|
|
|
NodeHelpers.displayParameterPath(nodeParameters, i, currentParamPath, node),
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const p of paramParts) {
|
|
|
|
const param = p.split('[')[0];
|
|
|
|
if (!property) {
|
|
|
|
property = findProp(param, nodeType.description.properties);
|
|
|
|
} else if ('options' in property && property.options) {
|
|
|
|
property = findProp(param, property.options);
|
|
|
|
currentParamPath += `.${param}`;
|
|
|
|
} else if ('values' in property) {
|
|
|
|
property = findProp(param, property.values);
|
|
|
|
currentParamPath += `.${param}`;
|
|
|
|
} else {
|
2023-11-30 00:06:19 -08:00
|
|
|
throw new ApplicationError('Could not find property', { extra: { parameterName } });
|
2022-09-23 02:56:57 -07:00
|
|
|
}
|
|
|
|
if (!property) {
|
2023-11-30 00:06:19 -08:00
|
|
|
throw new ApplicationError('Could not find property', { extra: { parameterName } });
|
2022-09-23 02:56:57 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!property) {
|
2023-11-30 00:06:19 -08:00
|
|
|
throw new ApplicationError('Could not find property', { extra: { parameterName } });
|
2022-09-23 02:56:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return property;
|
|
|
|
}
|
|
|
|
|
|
|
|
function executeRegexExtractValue(
|
|
|
|
value: string,
|
|
|
|
regex: RegExp,
|
|
|
|
parameterName: string,
|
|
|
|
parameterDisplayName: string,
|
|
|
|
): NodeParameterValueType | object {
|
|
|
|
const extracted = regex.exec(value);
|
|
|
|
if (!extracted) {
|
2023-11-02 08:28:44 -07:00
|
|
|
throw new WorkflowOperationError(
|
2022-09-23 02:56:57 -07:00
|
|
|
`ERROR: ${parameterDisplayName} parameter's value is invalid. This is likely because the URL entered is incorrect`,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (extracted.length < 2 || extracted.length > 2) {
|
2023-11-02 08:28:44 -07:00
|
|
|
throw new WorkflowOperationError(
|
2022-09-23 02:56:57 -07:00
|
|
|
`Property "${parameterName}" has an invalid extractValue regex "${regex.source}". extractValue expects exactly one group to be returned.`,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return extracted[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
function extractValueRLC(
|
|
|
|
value: NodeParameterValueType | object,
|
|
|
|
property: INodeProperties,
|
|
|
|
parameterName: string,
|
|
|
|
): NodeParameterValueType | object {
|
|
|
|
// Not an RLC value
|
|
|
|
if (typeof value !== 'object' || !value || !('mode' in value) || !('value' in value)) {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
const modeProp = (property.modes ?? []).find((i) => i.name === value.mode);
|
|
|
|
if (!modeProp) {
|
|
|
|
return value.value;
|
|
|
|
}
|
|
|
|
if (!('extractValue' in modeProp) || !modeProp.extractValue) {
|
|
|
|
return value.value;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof value.value !== 'string') {
|
|
|
|
let typeName: string | undefined = value.value?.constructor.name;
|
|
|
|
if (value.value === null) {
|
|
|
|
typeName = 'null';
|
|
|
|
} else if (typeName === undefined) {
|
|
|
|
typeName = 'undefined';
|
|
|
|
}
|
|
|
|
LoggerProxy.error(
|
|
|
|
`Only strings can be passed to extractValue. Parameter "${parameterName}" passed "${typeName}"`,
|
|
|
|
);
|
2023-11-30 00:06:19 -08:00
|
|
|
throw new ApplicationError(
|
|
|
|
"ERROR: This parameter's value is invalid. Please enter a valid mode.",
|
|
|
|
{ extra: { parameter: property.displayName, modeProp: modeProp.displayName } },
|
2022-09-23 02:56:57 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (modeProp.extractValue.type !== 'regex') {
|
2023-11-30 00:06:19 -08:00
|
|
|
throw new ApplicationError('Property with unknown `extractValue`', {
|
|
|
|
extra: { parameter: parameterName, extractValueType: modeProp.extractValue.type },
|
|
|
|
});
|
2022-09-23 02:56:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
const regex = new RegExp(modeProp.extractValue.regex);
|
|
|
|
return executeRegexExtractValue(value.value, regex, parameterName, property.displayName);
|
|
|
|
}
|
|
|
|
|
2023-12-13 05:45:22 -08:00
|
|
|
function extractValueFilter(
|
|
|
|
value: NodeParameterValueType | object,
|
|
|
|
property: INodeProperties,
|
|
|
|
parameterName: string,
|
|
|
|
itemIndex: number,
|
|
|
|
): NodeParameterValueType | object {
|
|
|
|
if (!isFilterValue(value)) {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (property.extractValue?.type) {
|
|
|
|
throw new ApplicationError(
|
|
|
|
`Property "${parameterName}" has an invalid extractValue type. Filter parameters only support extractValue: true`,
|
|
|
|
{ extra: { parameter: parameterName } },
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return executeFilter(value, { itemIndex });
|
|
|
|
}
|
|
|
|
|
2022-09-23 02:56:57 -07:00
|
|
|
function extractValueOther(
|
|
|
|
value: NodeParameterValueType | object,
|
|
|
|
property: INodeProperties | INodePropertyCollection,
|
|
|
|
parameterName: string,
|
|
|
|
): NodeParameterValueType | object {
|
|
|
|
if (!('extractValue' in property) || !property.extractValue) {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof value !== 'string') {
|
|
|
|
let typeName: string | undefined = value?.constructor.name;
|
|
|
|
if (value === null) {
|
|
|
|
typeName = 'null';
|
|
|
|
} else if (typeName === undefined) {
|
|
|
|
typeName = 'undefined';
|
|
|
|
}
|
|
|
|
LoggerProxy.error(
|
|
|
|
`Only strings can be passed to extractValue. Parameter "${parameterName}" passed "${typeName}"`,
|
|
|
|
);
|
2023-11-30 00:06:19 -08:00
|
|
|
throw new ApplicationError("This parameter's value is invalid", {
|
|
|
|
extra: { parameter: property.displayName },
|
|
|
|
});
|
2022-09-23 02:56:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (property.extractValue.type !== 'regex') {
|
2023-11-30 00:06:19 -08:00
|
|
|
throw new ApplicationError('Property with unknown `extractValue`', {
|
|
|
|
extra: { parameter: parameterName, extractValueType: property.extractValue.type },
|
|
|
|
});
|
2022-09-23 02:56:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
const regex = new RegExp(property.extractValue.regex);
|
|
|
|
return executeRegexExtractValue(value, regex, parameterName, property.displayName);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function extractValue(
|
|
|
|
value: NodeParameterValueType | object,
|
|
|
|
parameterName: string,
|
|
|
|
node: INode,
|
|
|
|
nodeType: INodeType,
|
2023-12-13 05:45:22 -08:00
|
|
|
itemIndex = 0,
|
2022-09-23 02:56:57 -07:00
|
|
|
): NodeParameterValueType | object {
|
|
|
|
let property: INodePropertyOptions | INodeProperties | INodePropertyCollection;
|
|
|
|
try {
|
|
|
|
property = findPropertyFromParameterName(parameterName, nodeType, node, node.parameters);
|
|
|
|
|
|
|
|
// Definitely doesn't have value extractor
|
|
|
|
if (!('type' in property)) {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (property.type === 'resourceLocator') {
|
|
|
|
return extractValueRLC(value, property, parameterName);
|
2023-12-13 05:45:22 -08:00
|
|
|
} else if (property.type === 'filter') {
|
|
|
|
return extractValueFilter(value, property, parameterName, itemIndex);
|
2022-09-23 02:56:57 -07:00
|
|
|
}
|
|
|
|
return extractValueOther(value, property, parameterName);
|
|
|
|
} catch (error) {
|
2023-12-13 05:45:22 -08:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-assignment
|
|
|
|
throw new NodeOperationError(node, error, { description: get(error, 'description') });
|
2022-09-23 02:56:57 -07:00
|
|
|
}
|
|
|
|
}
|