mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-25 04:34:06 -08:00
fix(core): Fix resolve RL values in expressions (#4173)
* update interface
* update expression resolving
* 🔥 remove ExtractValue functions
* add flags
* update resolving
* update expr
* fix for list mode
* clean up
* Fix up
* update guard
* fix bug with switching
* update to handle expr referencing
* fix legacy expression
* fix when switching
* update spacing
Co-authored-by: Valya Bullions <valya@n8n.io>
This commit is contained in:
parent
d01f7d4d93
commit
469c391fee
|
@ -1,183 +0,0 @@
|
|||
import {
|
||||
INode,
|
||||
INodeParameters,
|
||||
INodeProperties,
|
||||
INodePropertyCollection,
|
||||
INodePropertyOptions,
|
||||
INodeType,
|
||||
NodeOperationError,
|
||||
NodeParameterValueType,
|
||||
NodeHelpers,
|
||||
LoggerProxy,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
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),
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
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 {
|
||||
throw new Error(`Couldn't not find property "${parameterName}"`);
|
||||
}
|
||||
if (!property) {
|
||||
throw new Error(`Couldn't not find property "${parameterName}"`);
|
||||
}
|
||||
}
|
||||
if (!property) {
|
||||
throw new Error(`Couldn't not find property "${parameterName}"`);
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
function executeRegexExtractValue(
|
||||
value: string,
|
||||
regex: RegExp,
|
||||
parameterName: string,
|
||||
parameterDisplayName: string,
|
||||
): NodeParameterValueType | object {
|
||||
const extracted = regex.exec(value);
|
||||
if (!extracted) {
|
||||
throw new Error(
|
||||
`ERROR: ${parameterDisplayName} parameter's value is invalid. This is likely because the URL entered is incorrect`,
|
||||
);
|
||||
}
|
||||
if (extracted.length < 2 || extracted.length > 2) {
|
||||
throw new Error(
|
||||
`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}"`,
|
||||
);
|
||||
throw new Error(
|
||||
`ERROR: ${property.displayName} parameter's value is invalid. Please enter a valid ${modeProp.displayName}.`,
|
||||
);
|
||||
}
|
||||
|
||||
if (modeProp.extractValue.type !== 'regex') {
|
||||
throw new Error(
|
||||
`Property "${parameterName}" has an unknown extractValue type "${
|
||||
modeProp.extractValue.type as string
|
||||
}"`,
|
||||
);
|
||||
}
|
||||
|
||||
const regex = new RegExp(modeProp.extractValue.regex);
|
||||
return executeRegexExtractValue(value.value, regex, parameterName, property.displayName);
|
||||
}
|
||||
|
||||
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}"`,
|
||||
);
|
||||
throw new Error(
|
||||
`ERROR: ${property.displayName} parameter's value is invalid. Please enter a valid value.`,
|
||||
);
|
||||
}
|
||||
|
||||
if (property.extractValue.type !== 'regex') {
|
||||
throw new Error(
|
||||
`Property "${parameterName}" has an unknown extractValue type "${
|
||||
property.extractValue.type as string
|
||||
}"`,
|
||||
);
|
||||
}
|
||||
|
||||
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,
|
||||
): 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);
|
||||
}
|
||||
return extractValueOther(value, property, parameterName);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
throw new NodeOperationError(node, error);
|
||||
}
|
||||
}
|
|
@ -59,7 +59,6 @@ import {
|
|||
LoggerProxy as Logger,
|
||||
IExecuteData,
|
||||
OAuth2GrantType,
|
||||
IGetNodeParameterOptions,
|
||||
NodeParameterValueType,
|
||||
NodeExecutionWithMetadata,
|
||||
IPairedItemData,
|
||||
|
@ -100,7 +99,6 @@ import {
|
|||
IWorkflowSettings,
|
||||
PLACEHOLDER_EMPTY_EXECUTION_ID,
|
||||
} from '.';
|
||||
import { extractValue } from './ExtractValue';
|
||||
|
||||
axios.defaults.timeout = 300000;
|
||||
// Prevent axios from adding x-form-www-urlencoded headers by default
|
||||
|
@ -1727,7 +1725,6 @@ export function getNodeParameter(
|
|||
additionalKeys: IWorkflowDataProxyAdditionalKeys,
|
||||
executeData?: IExecuteData,
|
||||
fallbackValue?: any,
|
||||
options?: IGetNodeParameterOptions,
|
||||
): NodeParameterValueType | object {
|
||||
const nodeType = workflow.nodeTypes.getByNameAndVersion(node.type, node.typeVersion);
|
||||
if (nodeType === undefined) {
|
||||
|
@ -1762,11 +1759,6 @@ export function getNodeParameter(
|
|||
throw e;
|
||||
}
|
||||
|
||||
// This is outside the try/catch because it throws errors with proper messages
|
||||
if (options?.extractValue) {
|
||||
returnData = extractValue(returnData, parameterName, node, nodeType);
|
||||
}
|
||||
|
||||
return returnData;
|
||||
}
|
||||
|
||||
|
@ -1939,7 +1931,6 @@ export function getExecutePollFunctions(
|
|||
getNodeParameter: (
|
||||
parameterName: string,
|
||||
fallbackValue?: any,
|
||||
options?: IGetNodeParameterOptions,
|
||||
): NodeParameterValueType | object => {
|
||||
const runExecutionData: IRunExecutionData | null = null;
|
||||
const itemIndex = 0;
|
||||
|
@ -1959,7 +1950,6 @@ export function getExecutePollFunctions(
|
|||
getAdditionalKeys(additionalData),
|
||||
undefined,
|
||||
fallbackValue,
|
||||
options,
|
||||
);
|
||||
},
|
||||
getRestApiUrl: (): string => {
|
||||
|
@ -2094,7 +2084,6 @@ export function getExecuteTriggerFunctions(
|
|||
getNodeParameter: (
|
||||
parameterName: string,
|
||||
fallbackValue?: any,
|
||||
options?: IGetNodeParameterOptions,
|
||||
): NodeParameterValueType | object => {
|
||||
const runExecutionData: IRunExecutionData | null = null;
|
||||
const itemIndex = 0;
|
||||
|
@ -2114,7 +2103,6 @@ export function getExecuteTriggerFunctions(
|
|||
getAdditionalKeys(additionalData),
|
||||
undefined,
|
||||
fallbackValue,
|
||||
options,
|
||||
);
|
||||
},
|
||||
getRestApiUrl: (): string => {
|
||||
|
@ -2314,7 +2302,6 @@ export function getExecuteFunctions(
|
|||
parameterName: string,
|
||||
itemIndex: number,
|
||||
fallbackValue?: any,
|
||||
options?: IGetNodeParameterOptions,
|
||||
): NodeParameterValueType | object => {
|
||||
return getNodeParameter(
|
||||
workflow,
|
||||
|
@ -2329,7 +2316,6 @@ export function getExecuteFunctions(
|
|||
getAdditionalKeys(additionalData),
|
||||
executeData,
|
||||
fallbackValue,
|
||||
options,
|
||||
);
|
||||
},
|
||||
getMode: (): WorkflowExecuteMode => {
|
||||
|
@ -2589,7 +2575,6 @@ export function getExecuteSingleFunctions(
|
|||
getNodeParameter: (
|
||||
parameterName: string,
|
||||
fallbackValue?: any,
|
||||
options?: IGetNodeParameterOptions,
|
||||
): NodeParameterValueType | object => {
|
||||
return getNodeParameter(
|
||||
workflow,
|
||||
|
@ -2604,7 +2589,6 @@ export function getExecuteSingleFunctions(
|
|||
getAdditionalKeys(additionalData),
|
||||
executeData,
|
||||
fallbackValue,
|
||||
options,
|
||||
);
|
||||
},
|
||||
getWorkflow: () => {
|
||||
|
@ -2758,7 +2742,6 @@ export function getLoadOptionsFunctions(
|
|||
getNodeParameter: (
|
||||
parameterName: string,
|
||||
fallbackValue?: any,
|
||||
options?: IGetNodeParameterOptions,
|
||||
): NodeParameterValueType | object => {
|
||||
const runExecutionData: IRunExecutionData | null = null;
|
||||
const itemIndex = 0;
|
||||
|
@ -2778,7 +2761,6 @@ export function getLoadOptionsFunctions(
|
|||
getAdditionalKeys(additionalData),
|
||||
undefined,
|
||||
fallbackValue,
|
||||
options,
|
||||
);
|
||||
},
|
||||
getTimezone: (): string => {
|
||||
|
@ -2886,7 +2868,6 @@ export function getExecuteHookFunctions(
|
|||
getNodeParameter: (
|
||||
parameterName: string,
|
||||
fallbackValue?: any,
|
||||
options?: IGetNodeParameterOptions,
|
||||
): NodeParameterValueType | object => {
|
||||
const runExecutionData: IRunExecutionData | null = null;
|
||||
const itemIndex = 0;
|
||||
|
@ -2906,7 +2887,6 @@ export function getExecuteHookFunctions(
|
|||
getAdditionalKeys(additionalData),
|
||||
undefined,
|
||||
fallbackValue,
|
||||
options,
|
||||
);
|
||||
},
|
||||
getNodeWebhookUrl: (name: string): string | undefined => {
|
||||
|
@ -3046,7 +3026,6 @@ export function getExecuteWebhookFunctions(
|
|||
getNodeParameter: (
|
||||
parameterName: string,
|
||||
fallbackValue?: any,
|
||||
options?: IGetNodeParameterOptions,
|
||||
): NodeParameterValueType | object => {
|
||||
const runExecutionData: IRunExecutionData | null = null;
|
||||
const itemIndex = 0;
|
||||
|
@ -3066,7 +3045,6 @@ export function getExecuteWebhookFunctions(
|
|||
getAdditionalKeys(additionalData),
|
||||
undefined,
|
||||
fallbackValue,
|
||||
options,
|
||||
);
|
||||
},
|
||||
getParamsData(): object {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div @keydown.stop :class="parameterInputClasses">
|
||||
<expression-edit
|
||||
:dialogVisible="expressionEditDialogVisible"
|
||||
:value="isResourceLocatorParameter ? (value ? value.value : '') : value"
|
||||
:value="isResourceLocatorParameter && typeof value !== 'string' ? (value ? value.value : '') : value"
|
||||
:parameter="parameter"
|
||||
:path="path"
|
||||
:eventSource="eventSource || 'ndv'"
|
||||
|
@ -295,6 +295,7 @@ import {
|
|||
INodeParameters,
|
||||
INodePropertyOptions,
|
||||
Workflow,
|
||||
NodeParameterValueType,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import CodeEdit from '@/components/CodeEdit.vue';
|
||||
|
@ -819,7 +820,7 @@ export default mixins(
|
|||
return this.parameter.typeOptions[argumentName];
|
||||
},
|
||||
expressionUpdated (value: string) {
|
||||
const val = this.isResourceLocatorParameter ? { value, mode: this.value.mode } : value;
|
||||
const val: NodeParameterValueType = this.isResourceLocatorParameter ? { __rl: true, value, mode: this.value.mode } : value;
|
||||
this.valueChanged(val);
|
||||
},
|
||||
openExpressionEdit() {
|
||||
|
@ -937,9 +938,9 @@ export default mixins(
|
|||
} else if (command === 'addExpression') {
|
||||
if (this.isResourceLocatorParameter) {
|
||||
if (isResourceLocatorValue(this.value)) {
|
||||
this.valueChanged({ value: `=${this.value.value}`, mode: this.value.mode });
|
||||
this.valueChanged({ __rl: true, value: `=${this.value.value}`, mode: this.value.mode });
|
||||
} else {
|
||||
this.valueChanged({ value: `=${this.value}`, mode: '' });
|
||||
this.valueChanged({ __rl: true, value: `=${this.value}`, mode: '' });
|
||||
}
|
||||
}
|
||||
else if (this.parameter.type === 'number' || this.parameter.type === 'boolean') {
|
||||
|
@ -962,7 +963,7 @@ export default mixins(
|
|||
}
|
||||
|
||||
if (this.isResourceLocatorParameter) {
|
||||
this.valueChanged({ value, mode: this.value.mode });
|
||||
this.valueChanged({ __rl: true, value, mode: this.value.mode });
|
||||
} else {
|
||||
this.valueChanged(typeof value !== 'undefined' ? value : null);
|
||||
}
|
||||
|
|
|
@ -153,7 +153,7 @@ export default mixins(
|
|||
parameterData = {
|
||||
node: this.node.name,
|
||||
name: this.path,
|
||||
value: { value: updatedValue, mode: '' },
|
||||
value: { __rl: true, value: updatedValue, mode: '' },
|
||||
};
|
||||
}
|
||||
else if (this.value.mode === 'list' && this.parameter.modes && this.parameter.modes.length > 1) {
|
||||
|
@ -165,14 +165,14 @@ export default mixins(
|
|||
parameterData = {
|
||||
node: this.node.name,
|
||||
name: this.path,
|
||||
value: { value: updatedValue, mode: mode ? mode.name : '' },
|
||||
value: { __rl: true, value: updatedValue, mode: mode ? mode.name : '' },
|
||||
};
|
||||
}
|
||||
else {
|
||||
parameterData = {
|
||||
node: this.node.name,
|
||||
name: this.path,
|
||||
value: { value: updatedValue, mode: this.value.mode },
|
||||
value: { __rl: true, value: updatedValue, mode: this.value.mode },
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -174,6 +174,7 @@ import { workflowHelpers } from '../mixins/workflowHelpers';
|
|||
import { nodeHelpers } from '../mixins/nodeHelpers';
|
||||
import { getAppNameFromNodeName } from '../helpers';
|
||||
import { type } from 'os';
|
||||
import { isResourceLocatorValue } from '@/typeGuards';
|
||||
|
||||
interface IResourceLocatorQuery {
|
||||
results: INodeListSearchItems[];
|
||||
|
@ -199,10 +200,6 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({
|
|||
value: {
|
||||
type: [Object, String] as PropType<INodeParameterResourceLocator | NodeParameterValue | undefined>,
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
inputSize: {
|
||||
type: String,
|
||||
default: 'small',
|
||||
|
@ -423,6 +420,11 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({
|
|||
this.switchFromListMode();
|
||||
}
|
||||
},
|
||||
currentMode(mode: INodePropertyMode) {
|
||||
if (mode.extractValue && mode.extractValue.regex && isResourceLocatorValue(this.value) && this.value.__regex !== mode.extractValue.regex) {
|
||||
this.$emit('input', {...this.value, __regex: mode.extractValue.regex});
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$on('refreshList', this.refreshList);
|
||||
|
@ -505,7 +507,7 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({
|
|||
return null;
|
||||
},
|
||||
onInputChange(value: string): void {
|
||||
const params: INodeParameterResourceLocator = { value, mode: this.selectedMode };
|
||||
const params: INodeParameterResourceLocator = { __rl: true, value, mode: this.selectedMode };
|
||||
if (this.isListMode) {
|
||||
const resource = this.currentQueryResults.find((resource) => resource.value === value);
|
||||
if (resource && resource.name) {
|
||||
|
@ -520,13 +522,13 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({
|
|||
},
|
||||
onModeSelected(value: string): void {
|
||||
if (typeof this.value !== 'object') {
|
||||
this.$emit('input', { value: this.value, mode: value });
|
||||
this.$emit('input', { __rl: true, value: this.value, mode: value });
|
||||
} else if (value === 'url' && this.value && this.value.cachedResultUrl) {
|
||||
this.$emit('input', { mode: value, value: this.value.cachedResultUrl });
|
||||
this.$emit('input', { __rl: true, mode: value, value: this.value.cachedResultUrl });
|
||||
} else if (value === 'id' && this.selectedMode === 'list' && this.value && this.value.value) {
|
||||
this.$emit('input', { mode: value, value: this.value.value });
|
||||
this.$emit('input', { __rl: true, mode: value, value: this.value.value });
|
||||
} else {
|
||||
this.$emit('input', { mode: value, value: '' });
|
||||
this.$emit('input', { __rl: true, mode: value, value: '' });
|
||||
}
|
||||
|
||||
this.trackEvent('User changed resource locator mode', { mode: value });
|
||||
|
@ -657,7 +659,7 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({
|
|||
}
|
||||
|
||||
if (mode) {
|
||||
this.$emit('input', { value: ((this.value && typeof this.value === 'object')? this.value.value: ''), mode: mode.name });
|
||||
this.$emit('input', { __rl: true, value: ((this.value && typeof this.value === 'object')? this.value.value: ''), mode: mode.name });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { INodeParameterResourceLocator } from "n8n-workflow";
|
||||
|
||||
export function isResourceLocatorValue(value: unknown): value is INodeParameterResourceLocator {
|
||||
return Boolean(typeof value === 'object' && value && 'mode' in value && 'mode' in value);
|
||||
return Boolean(typeof value === 'object' && value && 'mode' in value && 'value' in value);
|
||||
}
|
||||
|
|
|
@ -508,15 +508,8 @@ export class Airtable implements INodeType {
|
|||
|
||||
const operation = this.getNodeParameter('operation', 0) as string;
|
||||
|
||||
const application = this.getNodeParameter('application', 0, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
|
||||
const table = encodeURI(
|
||||
this.getNodeParameter('table', 0, undefined, {
|
||||
extractValue: true,
|
||||
}) as string,
|
||||
);
|
||||
const application = this.getNodeParameter('application', 0) as string;
|
||||
const table = encodeURI(this.getNodeParameter('table', 0) as string);
|
||||
|
||||
let returnAll = false;
|
||||
let endpoint = '';
|
||||
|
|
|
@ -2153,9 +2153,7 @@ export class GoogleDrive implements INodeType {
|
|||
// delete
|
||||
// ----------------------------------
|
||||
|
||||
const driveId = this.getNodeParameter('driveId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const driveId = this.getNodeParameter('driveId', i) as string;
|
||||
|
||||
await googleApiRequest.call(this, 'DELETE', `/drive/v3/drives/${driveId}`);
|
||||
|
||||
|
@ -2171,9 +2169,7 @@ export class GoogleDrive implements INodeType {
|
|||
// get
|
||||
// ----------------------------------
|
||||
|
||||
const driveId = this.getNodeParameter('driveId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const driveId = this.getNodeParameter('driveId', i) as string;
|
||||
|
||||
const qs: IDataObject = {};
|
||||
|
||||
|
@ -2233,9 +2229,7 @@ export class GoogleDrive implements INodeType {
|
|||
// update
|
||||
// ----------------------------------
|
||||
|
||||
const driveId = this.getNodeParameter('driveId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const driveId = this.getNodeParameter('driveId', i) as string;
|
||||
|
||||
const body: IDataObject = {};
|
||||
|
||||
|
@ -2262,9 +2256,7 @@ export class GoogleDrive implements INodeType {
|
|||
// copy
|
||||
// ----------------------------------
|
||||
|
||||
const fileId = this.getNodeParameter('fileId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const fileId = this.getNodeParameter('fileId', i) as string;
|
||||
|
||||
const body: IDataObject = {
|
||||
fields: queryFields,
|
||||
|
@ -2300,9 +2292,7 @@ export class GoogleDrive implements INodeType {
|
|||
// download
|
||||
// ----------------------------------
|
||||
|
||||
const fileId = this.getNodeParameter('fileId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const fileId = this.getNodeParameter('fileId', i) as string;
|
||||
const options = this.getNodeParameter('options', i) as IDataObject;
|
||||
|
||||
const requestOptions = {
|
||||
|
@ -2645,9 +2635,7 @@ export class GoogleDrive implements INodeType {
|
|||
// file:update
|
||||
// ----------------------------------
|
||||
|
||||
const id = this.getNodeParameter('fileId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const id = this.getNodeParameter('fileId', i) as string;
|
||||
const updateFields = this.getNodeParameter('updateFields', i, {}) as IDataObject;
|
||||
|
||||
const qs: IDataObject = {
|
||||
|
@ -2721,9 +2709,7 @@ export class GoogleDrive implements INodeType {
|
|||
// delete
|
||||
// ----------------------------------
|
||||
|
||||
const fileId = this.getNodeParameter('fileId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const fileId = this.getNodeParameter('fileId', i) as string;
|
||||
|
||||
await googleApiRequest.call(
|
||||
this,
|
||||
|
@ -2745,9 +2731,7 @@ export class GoogleDrive implements INodeType {
|
|||
returnData.push(...executionData);
|
||||
}
|
||||
if (operation === 'share') {
|
||||
const fileId = this.getNodeParameter('fileId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const fileId = this.getNodeParameter('fileId', i) as string;
|
||||
|
||||
const permissions = this.getNodeParameter('permissionsUi', i) as IDataObject;
|
||||
|
||||
|
|
|
@ -239,9 +239,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'DELETE';
|
||||
|
||||
const id = this.getNodeParameter('id', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const id = this.getNodeParameter('id', i) as string;
|
||||
|
||||
endpoint = `boards/${id}`;
|
||||
} else if (operation === 'get') {
|
||||
|
@ -251,7 +249,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'GET';
|
||||
|
||||
const id = this.getNodeParameter('id', i, undefined, { extractValue: true });
|
||||
const id = this.getNodeParameter('id', i);
|
||||
|
||||
endpoint = `boards/${id}`;
|
||||
|
||||
|
@ -264,7 +262,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'PUT';
|
||||
|
||||
const id = this.getNodeParameter('id', i, undefined, { extractValue: true });
|
||||
const id = this.getNodeParameter('id', i);
|
||||
|
||||
endpoint = `boards/${id}`;
|
||||
|
||||
|
@ -367,7 +365,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'DELETE';
|
||||
|
||||
const id = this.getNodeParameter('id', i, undefined, { extractValue: true });
|
||||
const id = this.getNodeParameter('id', i);
|
||||
|
||||
endpoint = `cards/${id}`;
|
||||
} else if (operation === 'get') {
|
||||
|
@ -377,7 +375,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'GET';
|
||||
|
||||
const id = this.getNodeParameter('id', i, undefined, { extractValue: true });
|
||||
const id = this.getNodeParameter('id', i);
|
||||
|
||||
endpoint = `cards/${id}`;
|
||||
|
||||
|
@ -390,7 +388,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'PUT';
|
||||
|
||||
const id = this.getNodeParameter('id', i, undefined, { extractValue: true });
|
||||
const id = this.getNodeParameter('id', i);
|
||||
|
||||
endpoint = `cards/${id}`;
|
||||
|
||||
|
@ -409,9 +407,7 @@ export class Trello implements INodeType {
|
|||
// create
|
||||
// ----------------------------------
|
||||
|
||||
const cardId = this.getNodeParameter('cardId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const cardId = this.getNodeParameter('cardId', i) as string;
|
||||
|
||||
qs.text = this.getNodeParameter('text', i) as string;
|
||||
|
||||
|
@ -425,9 +421,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'DELETE';
|
||||
|
||||
const cardId = this.getNodeParameter('cardId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const cardId = this.getNodeParameter('cardId', i) as string;
|
||||
|
||||
const commentId = this.getNodeParameter('commentId', i) as string;
|
||||
|
||||
|
@ -439,9 +433,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'PUT';
|
||||
|
||||
const cardId = this.getNodeParameter('cardId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const cardId = this.getNodeParameter('cardId', i) as string;
|
||||
|
||||
const commentId = this.getNodeParameter('commentId', i) as string;
|
||||
|
||||
|
@ -560,9 +552,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'POST';
|
||||
|
||||
const cardId = this.getNodeParameter('cardId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const cardId = this.getNodeParameter('cardId', i) as string;
|
||||
|
||||
const url = this.getNodeParameter('url', i) as string;
|
||||
|
||||
|
@ -581,9 +571,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'DELETE';
|
||||
|
||||
const cardId = this.getNodeParameter('cardId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const cardId = this.getNodeParameter('cardId', i) as string;
|
||||
|
||||
const id = this.getNodeParameter('id', i) as string;
|
||||
|
||||
|
@ -595,9 +583,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'GET';
|
||||
|
||||
const cardId = this.getNodeParameter('cardId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const cardId = this.getNodeParameter('cardId', i) as string;
|
||||
|
||||
const id = this.getNodeParameter('id', i) as string;
|
||||
|
||||
|
@ -612,9 +598,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'GET';
|
||||
|
||||
const cardId = this.getNodeParameter('cardId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const cardId = this.getNodeParameter('cardId', i) as string;
|
||||
|
||||
endpoint = `cards/${cardId}/attachments`;
|
||||
|
||||
|
@ -635,9 +619,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'POST';
|
||||
|
||||
const cardId = this.getNodeParameter('cardId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const cardId = this.getNodeParameter('cardId', i) as string;
|
||||
|
||||
const name = this.getNodeParameter('name', i) as string;
|
||||
|
||||
|
@ -654,9 +636,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'DELETE';
|
||||
|
||||
const cardId = this.getNodeParameter('cardId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const cardId = this.getNodeParameter('cardId', i) as string;
|
||||
|
||||
const id = this.getNodeParameter('id', i) as string;
|
||||
|
||||
|
@ -681,9 +661,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'GET';
|
||||
|
||||
const cardId = this.getNodeParameter('cardId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const cardId = this.getNodeParameter('cardId', i) as string;
|
||||
|
||||
endpoint = `cards/${cardId}/checklists`;
|
||||
|
||||
|
@ -696,9 +674,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'GET';
|
||||
|
||||
const cardId = this.getNodeParameter('cardId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const cardId = this.getNodeParameter('cardId', i) as string;
|
||||
|
||||
const checkItemId = this.getNodeParameter('checkItemId', i) as string;
|
||||
|
||||
|
@ -727,9 +703,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'DELETE';
|
||||
|
||||
const cardId = this.getNodeParameter('cardId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const cardId = this.getNodeParameter('cardId', i) as string;
|
||||
|
||||
const checkItemId = this.getNodeParameter('checkItemId', i) as string;
|
||||
|
||||
|
@ -741,9 +715,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'PUT';
|
||||
|
||||
const cardId = this.getNodeParameter('cardId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const cardId = this.getNodeParameter('cardId', i) as string;
|
||||
|
||||
const checkItemId = this.getNodeParameter('checkItemId', i) as string;
|
||||
|
||||
|
@ -758,9 +730,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'GET';
|
||||
|
||||
const cardId = this.getNodeParameter('cardId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const cardId = this.getNodeParameter('cardId', i) as string;
|
||||
|
||||
endpoint = `cards/${cardId}/checkItemStates`;
|
||||
|
||||
|
@ -781,9 +751,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'POST';
|
||||
|
||||
const idBoard = this.getNodeParameter('boardId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const idBoard = this.getNodeParameter('boardId', i) as string;
|
||||
|
||||
const name = this.getNodeParameter('name', i) as string;
|
||||
const color = this.getNodeParameter('color', i) as string;
|
||||
|
@ -825,9 +793,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'GET';
|
||||
|
||||
const idBoard = this.getNodeParameter('boardId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const idBoard = this.getNodeParameter('boardId', i) as string;
|
||||
|
||||
endpoint = `board/${idBoard}/labels`;
|
||||
|
||||
|
@ -854,9 +820,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'POST';
|
||||
|
||||
const cardId = this.getNodeParameter('cardId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const cardId = this.getNodeParameter('cardId', i) as string;
|
||||
|
||||
const id = this.getNodeParameter('id', i) as string;
|
||||
|
||||
|
@ -870,9 +834,7 @@ export class Trello implements INodeType {
|
|||
|
||||
requestMethod = 'DELETE';
|
||||
|
||||
const cardId = this.getNodeParameter('cardId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const cardId = this.getNodeParameter('cardId', i) as string;
|
||||
|
||||
const id = this.getNodeParameter('id', i) as string;
|
||||
|
||||
|
|
|
@ -543,10 +543,6 @@ export interface IN8nRequestOperationPaginationOffset extends IN8nRequestOperati
|
|||
};
|
||||
}
|
||||
|
||||
export interface IGetNodeParameterOptions {
|
||||
extractValue?: boolean;
|
||||
}
|
||||
|
||||
export interface IExecuteFunctions {
|
||||
continueOnFail(): boolean;
|
||||
evaluateExpression(expression: string, itemIndex: number): NodeParameterValueType;
|
||||
|
@ -568,7 +564,6 @@ export interface IExecuteFunctions {
|
|||
parameterName: string,
|
||||
itemIndex: number,
|
||||
fallbackValue?: any,
|
||||
options?: IGetNodeParameterOptions,
|
||||
): NodeParameterValueType | object;
|
||||
getWorkflowDataProxy(itemIndex: number): IWorkflowDataProxyData;
|
||||
getWorkflowStaticData(type: string): IDataObject;
|
||||
|
@ -606,11 +601,7 @@ export interface IExecuteSingleFunctions {
|
|||
getItemIndex(): number;
|
||||
getMode(): WorkflowExecuteMode;
|
||||
getNode(): INode;
|
||||
getNodeParameter(
|
||||
parameterName: string,
|
||||
fallbackValue?: any,
|
||||
options?: IGetNodeParameterOptions,
|
||||
): NodeParameterValueType | object;
|
||||
getNodeParameter(parameterName: string, fallbackValue?: any): NodeParameterValueType | object;
|
||||
getRestApiUrl(): string;
|
||||
getTimezone(): string;
|
||||
getExecuteData(): IExecuteData;
|
||||
|
@ -656,11 +647,7 @@ export interface ICredentialTestFunctions {
|
|||
export interface ILoadOptionsFunctions {
|
||||
getCredentials(type: string): Promise<ICredentialDataDecryptedObject>;
|
||||
getNode(): INode;
|
||||
getNodeParameter(
|
||||
parameterName: string,
|
||||
fallbackValue?: any,
|
||||
options?: IGetNodeParameterOptions,
|
||||
): NodeParameterValueType | object;
|
||||
getNodeParameter(parameterName: string, fallbackValue?: any): NodeParameterValueType | object;
|
||||
getCurrentNodeParameter(parameterName: string): NodeParameterValueType | object | undefined;
|
||||
getCurrentNodeParameters(): INodeParameters | undefined;
|
||||
getTimezone(): string;
|
||||
|
@ -693,11 +680,7 @@ export interface IHookFunctions {
|
|||
getActivationMode(): WorkflowActivateMode;
|
||||
getNode(): INode;
|
||||
getNodeWebhookUrl: (name: string) => string | undefined;
|
||||
getNodeParameter(
|
||||
parameterName: string,
|
||||
fallbackValue?: any,
|
||||
options?: IGetNodeParameterOptions,
|
||||
): NodeParameterValueType | object;
|
||||
getNodeParameter(parameterName: string, fallbackValue?: any): NodeParameterValueType | object;
|
||||
getTimezone(): string;
|
||||
getWebhookDescription(name: string): IWebhookDescription | undefined;
|
||||
getWebhookName(): string;
|
||||
|
@ -723,11 +706,7 @@ export interface IPollFunctions {
|
|||
getMode(): WorkflowExecuteMode;
|
||||
getActivationMode(): WorkflowActivateMode;
|
||||
getNode(): INode;
|
||||
getNodeParameter(
|
||||
parameterName: string,
|
||||
fallbackValue?: any,
|
||||
options?: IGetNodeParameterOptions,
|
||||
): NodeParameterValueType | object;
|
||||
getNodeParameter(parameterName: string, fallbackValue?: any): NodeParameterValueType | object;
|
||||
getRestApiUrl(): string;
|
||||
getTimezone(): string;
|
||||
getWorkflow(): IWorkflowMetadata;
|
||||
|
@ -757,11 +736,7 @@ export interface ITriggerFunctions {
|
|||
getMode(): WorkflowExecuteMode;
|
||||
getActivationMode(): WorkflowActivateMode;
|
||||
getNode(): INode;
|
||||
getNodeParameter(
|
||||
parameterName: string,
|
||||
fallbackValue?: any,
|
||||
options?: IGetNodeParameterOptions,
|
||||
): NodeParameterValueType | object;
|
||||
getNodeParameter(parameterName: string, fallbackValue?: any): NodeParameterValueType | object;
|
||||
getRestApiUrl(): string;
|
||||
getTimezone(): string;
|
||||
getWorkflow(): IWorkflowMetadata;
|
||||
|
@ -786,11 +761,7 @@ export interface IWebhookFunctions {
|
|||
getHeaderData(): object;
|
||||
getMode(): WorkflowExecuteMode;
|
||||
getNode(): INode;
|
||||
getNodeParameter(
|
||||
parameterName: string,
|
||||
fallbackValue?: any,
|
||||
options?: IGetNodeParameterOptions,
|
||||
): NodeParameterValueType | object;
|
||||
getNodeParameter(parameterName: string, fallbackValue?: any): NodeParameterValueType | object;
|
||||
getNodeWebhookUrl: (name: string) => string | undefined;
|
||||
getParamsData(): object;
|
||||
getQueryData(): object;
|
||||
|
@ -905,10 +876,12 @@ export interface IResourceLocatorResult {
|
|||
}
|
||||
|
||||
export interface INodeParameterResourceLocator {
|
||||
__rl: true;
|
||||
mode: ResourceLocatorModes;
|
||||
value: NodeParameterValue;
|
||||
cachedResultName?: string;
|
||||
cachedResultUrl?: string;
|
||||
__regex?: string;
|
||||
}
|
||||
|
||||
export type NodeParameterValueType =
|
||||
|
|
|
@ -643,15 +643,8 @@ export class RoutingNode {
|
|||
if (nodeProperties.routing) {
|
||||
let parameterValue: string | undefined;
|
||||
if (basePath + nodeProperties.name && 'type' in nodeProperties) {
|
||||
// Extract value if it has extractValue defined or if it's a
|
||||
// resourceLocator component. Resource locators are likely to have extractors
|
||||
// and we can't know if the mode has one unless we dig all the way in.
|
||||
const shouldExtractValue =
|
||||
nodeProperties.extractValue !== undefined || nodeProperties.type === 'resourceLocator';
|
||||
parameterValue = executeSingleFunctions.getNodeParameter(
|
||||
basePath + nodeProperties.name,
|
||||
undefined,
|
||||
{ extractValue: shouldExtractValue },
|
||||
) as string;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,12 +23,19 @@ import {
|
|||
ITaskData,
|
||||
IWorkflowDataProxyAdditionalKeys,
|
||||
IWorkflowDataProxyData,
|
||||
INodeParameterResourceLocator,
|
||||
NodeHelpers,
|
||||
NodeParameterValueType,
|
||||
Workflow,
|
||||
WorkflowExecuteMode,
|
||||
} from '.';
|
||||
|
||||
export function isResourceLocatorValue(value: unknown): value is INodeParameterResourceLocator {
|
||||
return Boolean(
|
||||
typeof value === 'object' && value && 'mode' in value && 'value' in value && '__rl' in value,
|
||||
);
|
||||
}
|
||||
|
||||
export class WorkflowDataProxy {
|
||||
private workflow: Workflow;
|
||||
|
||||
|
@ -194,6 +201,20 @@ export class WorkflowDataProxy {
|
|||
returnValue = node.parameters[name];
|
||||
}
|
||||
|
||||
if (isResourceLocatorValue(returnValue)) {
|
||||
if (returnValue.__regex && typeof returnValue.value === 'string') {
|
||||
const expr = new RegExp(returnValue.__regex);
|
||||
const extracted = expr.exec(returnValue.value);
|
||||
if (extracted && extracted.length >= 2) {
|
||||
returnValue = extracted[1];
|
||||
} else {
|
||||
return returnValue.value;
|
||||
}
|
||||
} else {
|
||||
returnValue = returnValue.value;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof returnValue === 'string' && returnValue.charAt(0) === '=') {
|
||||
// The found value is an expression so resolve it
|
||||
return that.workflow.expression.getParameterValue(
|
||||
|
|
Loading…
Reference in a new issue