refactor(core): fix for no-uncaught-json-parse warnings

This commit is contained in:
Michael Kret 2022-10-21 21:52:43 +03:00 committed by GitHub
parent ca9eca9ae9
commit 1d57b10942
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 150 additions and 93 deletions

View file

@ -319,9 +319,7 @@ const config = (module.exports = {
// ----------------------------------
// eslint-plugin-n8n-local-rules
// ----------------------------------
// TODO: set to `error` and fix offenses
'n8n-local-rules/no-uncaught-json-parse': 'warn',
'n8n-local-rules/no-uncaught-json-parse': 'error',
'n8n-local-rules/no-json-parse-json-stringify': 'error',

View file

@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import curlconverter from 'curlconverter';
import get from 'lodash.get';
import { jsonParse } from 'n8n-workflow';
interface CurlJson {
url: string;
@ -109,8 +110,7 @@ const DOWNLOAD_FILE_FLAGS = ['-O', '-o'];
const IGNORE_SSL_ISSUES_FLAGS = ['-k', '--insecure'];
const curlToJson = (curlCommand: string): CurlJson => {
// eslint-disable-next-line n8n-local-rules/no-uncaught-json-parse
return JSON.parse(curlconverter.toJsonString(curlCommand)) as CurlJson;
return jsonParse(curlconverter.toJsonString(curlCommand));
};
const isContentType = (headers: CurlJson['headers'], contentType: ContentTypes): boolean => {
@ -196,8 +196,7 @@ const extractQueries = (queries: CurlJson['queries'] = {}): HttpNodeQueries => {
const extractJson = (body: CurlJson['data']) =>
//@ts-ignore
// eslint-disable-next-line n8n-local-rules/no-uncaught-json-parse
JSON.parse(Object.keys(body)[0]) as { [key: string]: string };
jsonParse<{ [key: string]: string }>(Object.keys(body)[0]);
const jsonBodyToNodeParameters = (body: CurlJson['data'] = {}): Parameter[] | [] => {
const data = extractJson(body);

View file

@ -13,6 +13,7 @@ import {
IDataObject,
INode,
IRunExecutionData,
jsonParse,
Workflow,
WorkflowExecuteMode,
} from 'n8n-workflow';
@ -28,6 +29,7 @@ import {
IPackageVersions,
IWorkflowDb,
ResponseHelper,
IN8nNodePackageJson,
} from '.';
// eslint-disable-next-line import/order
import { Like } from 'typeorm';
@ -74,7 +76,7 @@ export async function getVersions(): Promise<IPackageVersions> {
const packageFile = await fsReadFile(pathJoin(__dirname, '../../package.json'), 'utf8');
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const packageData = JSON.parse(packageFile);
const packageData = jsonParse<IN8nNodePackageJson>(packageFile);
versionCache = {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment

View file

@ -21,6 +21,7 @@ import {
INodeTypeNameVersion,
INodeVersionedType,
LoggerProxy,
jsonParse,
} from 'n8n-workflow';
import {
@ -509,7 +510,7 @@ class LoadNodesAndCredentialsClass {
async readPackageJson(packagePath: string): Promise<IN8nNodePackageJson> {
// Get the absolute path of the package
const packageFileString = await fsReadFile(path.join(packagePath, 'package.json'), 'utf8');
return JSON.parse(packageFileString) as IN8nNodePackageJson;
return jsonParse(packageFileString);
}
/**

View file

@ -1,3 +1,4 @@
import { jsonParse } from 'n8n-workflow';
import {
CursorPagination,
OffsetPagination,
@ -6,9 +7,7 @@ import {
} from '../../../types';
export const decodeCursor = (cursor: string): PaginationOffsetDecoded | PaginationCursorDecoded => {
return JSON.parse(Buffer.from(cursor, 'base64').toString()) as
| PaginationCursorDecoded
| PaginationOffsetDecoded;
return jsonParse(Buffer.from(cursor, 'base64').toString());
};
const encodeOffSetPagination = (pagination: OffsetPagination): string | null => {

View file

@ -67,6 +67,7 @@ import {
ITelemetrySettings,
LoggerProxy,
NodeHelpers,
jsonParse,
WebhookHttpMethod,
WorkflowExecuteMode,
} from 'n8n-workflow';
@ -787,20 +788,20 @@ class App {
`/${this.restEndpoint}/node-parameter-options`,
ResponseHelper.send(
async (req: NodeParameterOptionsRequest): Promise<INodePropertyOptions[]> => {
const nodeTypeAndVersion = JSON.parse(
const nodeTypeAndVersion = jsonParse(
req.query.nodeTypeAndVersion,
) as INodeTypeNameVersion;
const { path, methodName } = req.query;
const currentNodeParameters = JSON.parse(
const currentNodeParameters = jsonParse(
req.query.currentNodeParameters,
) as INodeParameters;
let credentials: INodeCredentials | undefined;
if (req.query.credentials) {
credentials = JSON.parse(req.query.credentials);
credentials = jsonParse(req.query.credentials);
}
const loadDataInstance = new LoadNodeParameterOptions(
@ -823,7 +824,7 @@ class App {
if (req.query.loadOptions) {
return loadDataInstance.getOptionsViaRequestProperty(
// @ts-ignore
JSON.parse(req.query.loadOptions as string),
jsonParse(req.query.loadOptions as string),
additionalData,
);
}
@ -842,7 +843,7 @@ class App {
req: NodeListSearchRequest,
res: express.Response,
): Promise<INodeListSearchResult | undefined> => {
const nodeTypeAndVersion = JSON.parse(
const nodeTypeAndVersion = jsonParse(
req.query.nodeTypeAndVersion,
) as INodeTypeNameVersion;
@ -852,14 +853,14 @@ class App {
throw new ResponseError('Parameter currentNodeParameters is required.', undefined, 400);
}
const currentNodeParameters = JSON.parse(
const currentNodeParameters = jsonParse(
req.query.currentNodeParameters,
) as INodeParameters;
let credentials: INodeCredentials | undefined;
if (req.query.credentials) {
credentials = JSON.parse(req.query.credentials);
credentials = jsonParse(req.query.credentials);
}
const listSearchInstance = new LoadNodeListSearch(
@ -1454,7 +1455,7 @@ class App {
if (!sharedWorkflowIds.length) return [];
if (req.query.filter) {
const { workflowId } = JSON.parse(req.query.filter);
const { workflowId } = jsonParse<any>(req.query.filter);
if (workflowId && sharedWorkflowIds.includes(workflowId)) {
Object.assign(findOptions.where!, { workflowId });
}
@ -1481,7 +1482,7 @@ class App {
const returnData: IExecutionsSummary[] = [];
const filter = req.query.filter ? JSON.parse(req.query.filter) : {};
const filter = req.query.filter ? jsonParse<any>(req.query.filter) : {};
const sharedWorkflowIds = await getSharedWorkflowIds(req.user).then((ids) =>
ids.map((id) => id.toString()),

View file

@ -11,7 +11,7 @@
import express from 'express';
import _, { cloneDeep } from 'lodash';
import { BinaryDataManager } from 'n8n-core';
import { IDataObject, IWorkflowBase, LoggerProxy, Workflow } from 'n8n-workflow';
import { IDataObject, IWorkflowBase, LoggerProxy, jsonParse, Workflow } from 'n8n-workflow';
import { FindManyOptions, In, IsNull, LessThanOrEqual, Not, Raw } from 'typeorm';
import {
@ -111,7 +111,7 @@ async function getExecutionsCount(
executionsController.get(
'/',
ResponseHelper.send(async (req: ExecutionRequest.GetAll): Promise<IExecutionsListResponse> => {
const filter = req.query.filter ? JSON.parse(req.query.filter) : {};
const filter = req.query.filter ? jsonParse<IDataObject>(req.query.filter) : {};
const limit = req.query.limit
? parseInt(req.query.limit, 10)

View file

@ -1,3 +1,4 @@
import { jsonParse } from 'n8n-workflow';
import { ValueTransformer } from 'typeorm';
import config from '../../../config';
@ -16,8 +17,7 @@ export const lowerCaser = {
*/
export const objectRetriever: ValueTransformer = {
to: (value: object): object => value,
from: (value: string | object): object =>
typeof value === 'string' ? (JSON.parse(value) as object) : value,
from: (value: string | object): object => (typeof value === 'string' ? jsonParse(value) : value),
};
/**
@ -27,8 +27,7 @@ export const objectRetriever: ValueTransformer = {
const jsonColumn: ValueTransformer = {
to: (value: object): string | object =>
config.getEnv('database.type') === 'sqlite' ? JSON.stringify(value) : value,
from: (value: string | object): object =>
typeof value === 'string' ? (JSON.parse(value) as object) : value,
from: (value: string | object): object => (typeof value === 'string' ? jsonParse(value) : value),
};
export const sqlite = { jsonColumn };

View file

@ -112,6 +112,7 @@ import {
IRunData,
IRunExecutionData,
Workflow,
jsonParse,
} from 'n8n-workflow';
import { IExecutionResponse, INodeUi, IUpdateInformation, TargetItem } from '../Interface';
@ -554,7 +555,7 @@ export default mixins(
return;
}
this.$store.commit('pinData', { node: this.activeNode, data: JSON.parse(value) });
this.$store.commit('pinData', { node: this.activeNode, data: jsonParse(value) });
}
this.$store.commit('ui/setOutputPanelEditModeEnabled', false);

View file

@ -2,7 +2,7 @@ import { CORE_NODES_CATEGORY, ERROR_TRIGGER_NODE_TYPE, MAPPING_PARAMS, TEMPLATES
import { INodeUi, ITemplatesNode } from '@/Interface';
import { isResourceLocatorValue } from '@/typeGuards';
import dateformat from 'dateformat';
import {IDataObject, INodeProperties, INodeTypeDescription, NodeParameterValueType,INodeExecutionData} from 'n8n-workflow';
import {IDataObject, INodeProperties, INodeTypeDescription, NodeParameterValueType,INodeExecutionData, parseJson} from 'n8n-workflow';
import { isJsonKeyObject } from "@/utils";
const CRED_KEYWORDS_TO_FILTER = ['API', 'OAuth1', 'OAuth2'];
@ -169,7 +169,7 @@ export const convertPath = (path: string): string => {
};
export const clearJsonKey = (userInput: string | object) => {
const parsedUserInput = typeof userInput === 'string' ? JSON.parse(userInput) : userInput;
const parsedUserInput = typeof userInput === 'string' ? jsonParse(userInput) : userInput;
if (!Array.isArray(parsedUserInput)) return parsedUserInput;

View file

@ -5,6 +5,7 @@ import {
INodeExecutionData,
INodeType,
INodeTypeDescription,
jsonParse,
NodeOperationError,
} from 'n8n-workflow';
@ -149,7 +150,7 @@ export class AgileCrm implements INodeType {
} else if (filterType === 'json') {
const filterJsonRules = this.getNodeParameter('filterJson', i) as string;
if (validateJSON(filterJsonRules) !== undefined) {
Object.assign(filterJson, JSON.parse(filterJsonRules) as IFilter);
Object.assign(filterJson, jsonParse(filterJsonRules) as IFilter);
} else {
throw new NodeOperationError(this.getNode(), 'Filter (JSON) must be a valid json', {
itemIndex: i,
@ -203,7 +204,7 @@ export class AgileCrm implements INodeType {
if (additionalFieldsJson !== '') {
if (validateJSON(additionalFieldsJson) !== undefined) {
Object.assign(body, JSON.parse(additionalFieldsJson));
Object.assign(body, jsonParse(additionalFieldsJson));
} else {
throw new NodeOperationError(
this.getNode(),
@ -355,7 +356,7 @@ export class AgileCrm implements INodeType {
if (additionalFieldsJson !== '') {
if (validateJSON(additionalFieldsJson) !== undefined) {
Object.assign(body, JSON.parse(additionalFieldsJson));
Object.assign(body, jsonParse(additionalFieldsJson));
} else {
throw new NodeOperationError(
this.getNode(),
@ -533,7 +534,7 @@ export class AgileCrm implements INodeType {
if (additionalFieldsJson !== '') {
if (validateJSON(additionalFieldsJson) !== undefined) {
Object.assign(body, JSON.parse(additionalFieldsJson));
Object.assign(body, jsonParse(additionalFieldsJson));
} else {
throw new NodeOperationError(
this.getNode(),
@ -573,7 +574,7 @@ export class AgileCrm implements INodeType {
if (additionalFieldsJson !== '') {
if (validateJSON(additionalFieldsJson) !== undefined) {
Object.assign(body, JSON.parse(additionalFieldsJson));
Object.assign(body, jsonParse(additionalFieldsJson));
} else {
throw new NodeOperationError(
this.getNode(),

View file

@ -7,6 +7,7 @@ import {
INodeType,
INodeTypeDescription,
ITriggerResponse,
jsonParse,
NodeOperationError,
} from 'n8n-workflow';
@ -190,7 +191,7 @@ export class AmqpTrigger implements INodeType {
}
if (options.jsonParseBody === true) {
data.body = JSON.parse(data.body);
data.body = jsonParse(data.body);
}
if (options.onlyBody === true) {
data = data.body;

View file

@ -178,7 +178,7 @@ export class AwsSnsTrigger implements INodeType {
const topic = this.getNodeParameter('topic') as string;
// @ts-ignore
const body = JSON.parse(req.rawBody.toString());
const body = jsonParse(req.rawBody.toString());
if (body.Type === 'SubscriptionConfirmation' && body.TopicArn === topic) {
const { Token } = body;

View file

@ -7,7 +7,7 @@ import {
IWebhookFunctions,
} from 'n8n-core';
import { IDataObject, IHttpRequestOptions, NodeApiError } from 'n8n-workflow';
import { IDataObject, IHttpRequestOptions, jsonParse, NodeApiError } from 'n8n-workflow';
export async function awsApiRequest(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
@ -18,7 +18,7 @@ export async function awsApiRequest(
query: IDataObject = {},
headers?: object,
// tslint:disable-next-line:no-any
): Promise<any> {
): Promise<any> {
const credentials = await this.getCredentials('aws');
const requestOptions = {
@ -50,7 +50,7 @@ export async function awsApiRequestREST(
query: IDataObject = {},
headers?: object,
// tslint:disable-next-line:no-any
): Promise<any> {
): Promise<any> {
const response = await awsApiRequest.call(this, service, method, path, body, query, headers);
try {
return JSON.parse(response);
@ -70,23 +70,17 @@ export async function awsApiRequestAllItems(
headers: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
do {
responseData = await awsApiRequestREST.call(
this,
service,
method,
path,
body,
query,
headers,
);
responseData = await awsApiRequestREST.call(this, service, method, path, body, query, headers);
if (responseData.NextToken) {
const data = JSON.parse(body as string);
// tslint:disable-next-line:no-any
const data = jsonParse<any>(body as string, {
errorMessage: 'Response body is not valid JSON',
});
data['NextToken'] = responseData.NextToken;
}
returnData.push.apply(returnData, get(responseData, propertyName));

View file

@ -1,5 +1,5 @@
import { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core';
import { IDataObject } from 'n8n-workflow';
import { IDataObject, jsonParse } from 'n8n-workflow';
import { ICollection } from './CollectionInterface';
import { cockpitApiRequest } from './GenericFunctions';
@ -46,7 +46,9 @@ export async function getAllCollectionEntries(
}
if (options.filter) {
body.filter = JSON.parse(options.filter.toString());
body.filter = jsonParse(options.filter.toString(), {
errorMessage: "'Filter' option is not valid JSON",
});
}
if (options.limit) {
@ -58,7 +60,9 @@ export async function getAllCollectionEntries(
}
if (options.sort) {
body.sort = JSON.parse(options.sort.toString());
body.sort = jsonParse(options.sort.toString(), {
errorMessage: "'Sort' option is not valid JSON",
});
}
if (options.populate) {

View file

@ -1,5 +1,5 @@
import { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core';
import { IDataObject, NodeApiError, NodeOperationError } from 'n8n-workflow';
import { IDataObject, jsonParse, NodeApiError, NodeOperationError } from 'n8n-workflow';
import { OptionsWithUri } from 'request';
export async function cockpitApiRequest(
@ -48,7 +48,7 @@ export function createDataFromParameters(
if (dataFieldsAreJson) {
// Parameters are defined as JSON
return JSON.parse(this.getNodeParameter('dataFieldsJson', itemIndex, '{}') as string);
return jsonParse(this.getNodeParameter('dataFieldsJson', itemIndex, '{}') as string);
}
// Parameters are defined in UI

View file

@ -4,6 +4,7 @@ import {
INodeExecutionData,
INodeType,
INodeTypeDescription,
jsonParse,
NodeApiError,
NodeOperationError,
} from 'n8n-workflow';
@ -171,7 +172,7 @@ export class Discord implements INodeType {
if (options.allowed_mentions) {
//@ts-expect-error
body.allowed_mentions = JSON.parse(options.allowed_mentions);
body.allowed_mentions = jsonParse(options.allowed_mentions);
}
if (options.avatarUrl) {
@ -188,12 +189,12 @@ export class Discord implements INodeType {
if (options.payloadJson) {
//@ts-expect-error
body.payload_json = JSON.parse(options.payloadJson);
body.payload_json = jsonParse(options.payloadJson);
}
if (options.attachments) {
//@ts-expect-error
body.attachments = JSON.parse(options.attachments as DiscordAttachment[]);
body.attachments = jsonParse(options.attachments as DiscordAttachment[]);
}
//* Not used props, delete them from the payload as Discord won't need them :^
@ -270,7 +271,7 @@ export class Discord implements INodeType {
}
const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray({success: true}),
this.helpers.returnJsonArray({ success: true }),
{ itemData: { item: i } },
);
returnData.push(...executionData);

View file

@ -1,6 +1,12 @@
import { IExecuteFunctions } from 'n8n-core';
import { IDataObject, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
import {
IDataObject,
INodeExecutionData,
INodeType,
INodeTypeDescription,
jsonParse,
} from 'n8n-workflow';
import { elasticsearchApiRequest, elasticsearchApiRequestAllItems } from './GenericFunctions';
@ -127,7 +133,12 @@ export class Elasticsearch implements INodeType {
if (Object.keys(options).length) {
const { query, ...rest } = options;
if (query) Object.assign(body, JSON.parse(query));
if (query) {
Object.assign(
body,
jsonParse(query, { errorMessage: "Invalid JSON in 'Query' option" }),
);
}
Object.assign(qs, rest);
qs._source = true;
}

View file

@ -7,6 +7,7 @@ import {
INodePropertyOptions,
INodeType,
INodeTypeDescription,
jsonParse,
} from 'n8n-workflow';
import {
@ -338,7 +339,7 @@ export class GoogleFirebaseCloudFirestore implements INodeType {
this,
'POST',
`/${projectId}/databases/${database}/documents:runQuery`,
JSON.parse(query),
jsonParse(query),
);
responseData = responseData.map(

View file

@ -6,6 +6,7 @@ import {
INodeType,
INodeTypeBaseDescription,
INodeTypeDescription,
jsonParse,
NodeApiError,
NodeOperationError,
} from 'n8n-workflow';
@ -951,7 +952,11 @@ export class HttpRequestV3 implements INodeType {
itemIndex,
[],
) as [{ name: string; value: string }];
const specifyHeaders = this.getNodeParameter('specifyHeaders', itemIndex, 'keypair') as string;
const specifyHeaders = this.getNodeParameter(
'specifyHeaders',
itemIndex,
'keypair',
) as string;
const jsonHeadersParameter = this.getNodeParameter('jsonHeaders', itemIndex, '') as string;
const {
@ -1097,7 +1102,7 @@ export class HttpRequestV3 implements INodeType {
);
}
requestOptions.body = JSON.parse(jsonBodyParameter);
requestOptions.body = jsonParse(jsonBodyParameter);
} else if (specifyBody === 'string') {
//form urlencoded
requestOptions.body = Object.fromEntries(new URLSearchParams(body));
@ -1147,7 +1152,7 @@ export class HttpRequestV3 implements INodeType {
);
}
requestOptions.qs = JSON.parse(jsonQueryParameter);
requestOptions.qs = jsonParse(jsonQueryParameter);
}
}
@ -1172,7 +1177,7 @@ export class HttpRequestV3 implements INodeType {
);
}
requestOptions.headers = JSON.parse(jsonHeadersParameter);
requestOptions.headers = jsonParse(jsonHeadersParameter);
}
}
@ -1323,7 +1328,7 @@ export class HttpRequestV3 implements INodeType {
const responseContentType = response.headers['content-type'] ?? '';
if (responseContentType.includes('application/json')) {
responseFormat = 'json';
response.body = JSON.parse(Buffer.from(response.body).toString());
response.body = jsonParse(Buffer.from(response.body).toString());
} else if (binaryContentTypes.some((e) => responseContentType.includes(e))) {
responseFormat = 'file';
} else {

View file

@ -9,6 +9,7 @@ import {
INodeType,
INodeTypeDescription,
IWebhookResponseData,
jsonParse,
} from 'n8n-workflow';
import { jotformApiRequest } from './GenericFunctions';
@ -167,7 +168,8 @@ export class JotFormTrigger implements INodeType {
return new Promise((resolve, reject) => {
form.parse(req, async (err, data, files) => {
const rawRequest = JSON.parse(data.rawRequest as string);
// tslint:disable-next-line:no-any
const rawRequest = jsonParse<any>(data.rawRequest as string);
data.rawRequest = rawRequest;
let returnData: IDataObject;

View file

@ -4,6 +4,7 @@ import {
IN8nHttpFullResponse,
INodeExecutionData,
INodeProperties,
jsonParse,
} from 'n8n-workflow';
export const questionsOperations: INodeProperties[] = [
@ -74,9 +75,7 @@ export const questionsOperations: INodeProperties[] = [
}
items[i] = newItem;
if (this.getNode().parameters.format === 'json') {
items[i].json = JSON.parse(
items[i].json as unknown as string,
)[0] as unknown as IDataObject;
items[i].json = jsonParse<IDataObject[]>(items[i].json as unknown as string)[0];
console.log(items[i].json);
delete items[i].binary;
} else {

View file

@ -11,6 +11,7 @@ import {
INodePropertyOptions,
INodeType,
INodeTypeDescription,
jsonParse,
NodeOperationError,
} from 'n8n-workflow';
@ -362,7 +363,7 @@ export class MoveBinaryData implements INodeType {
convertedValue = iconv.decode(buffer, encoding, {
stripBOM: options.stripBOM as boolean,
});
newItem.json = JSON.parse(convertedValue);
newItem.json = jsonParse(convertedValue);
} else {
// Does get added to existing data so copy it first
newItem.json = deepCopy(item.json);
@ -376,7 +377,7 @@ export class MoveBinaryData implements INodeType {
}
if (options.jsonParse) {
convertedValue = JSON.parse(convertedValue);
convertedValue = jsonParse(convertedValue);
}
const destinationKey = this.getNodeParameter('destinationKey', itemIndex, '') as string;

View file

@ -7,6 +7,7 @@ import {
IDataObject,
INodeExecutionData,
IPollFunctions,
jsonParse,
NodeApiError,
NodeOperationError,
} from 'n8n-workflow';
@ -115,7 +116,7 @@ export async function downloadRecordAttachments(
for (const fieldName of fieldNames) {
if (record[fieldName]) {
for (const [index, attachment] of (
JSON.parse(record[fieldName] as string) as IAttachment[]
jsonParse(record[fieldName] as string) as IAttachment[]
).entries()) {
const file = await apiRequest.call(this, 'GET', '', {}, {}, attachment.url, {
json: false,

View file

@ -12,6 +12,7 @@ import {
INodeType,
INodeTypeBaseDescription,
INodeTypeDescription,
jsonParse,
NodeApiError,
} from 'n8n-workflow';
@ -528,7 +529,7 @@ export class NotionV2 implements INodeType {
} else if (filterType === 'json') {
const filterJson = this.getNodeParameter('filterJson', i) as string;
if (validateJSON(filterJson) !== undefined) {
body.filter = JSON.parse(filterJson);
body.filter = jsonParse(filterJson);
} else {
throw new NodeApiError(this.getNode(), {
message: 'Filters (JSON) must be a valid json',

View file

@ -8,7 +8,6 @@ import {
} from 'n8n-workflow';
import { get, set, unset } from 'lodash';
import { options } from 'rhea';
interface IRenameKey {
currentKey: string;

View file

@ -7,6 +7,7 @@ import {
INodeExecutionData,
INodeType,
INodeTypeDescription,
jsonParse,
NodeOperationError,
} from 'n8n-workflow';
@ -206,7 +207,9 @@ export class RespondToWebhook implements INodeType {
if (respondWith === 'json') {
const responseBodyParameter = this.getNodeParameter('responseBody', 0) as string;
if (responseBodyParameter) {
responseBody = JSON.parse(responseBodyParameter);
responseBody = jsonParse(responseBodyParameter, {
errorMessage: "Invalid JSON in 'Response Body' field",
});
}
} else if (respondWith === 'firstIncomingItem') {
responseBody = items[0].json;

View file

@ -4,6 +4,7 @@ import {
IHttpRequestOptions,
IWebhookFunctions,
JsonObject,
jsonParse,
NodeOperationError,
} from 'n8n-workflow';
import { OptionsWithUri } from 'request';
@ -337,7 +338,7 @@ export namespace SendInBlueWebhookApi {
options,
)) as string;
return JSON.parse(webhooks) as Webhooks;
return jsonParse(webhooks) as Webhooks;
};
export const createWebHook = async (
@ -367,7 +368,7 @@ export namespace SendInBlueWebhookApi {
options,
);
return JSON.parse(webhookId) as WebhookId;
return jsonParse(webhookId) as WebhookId;
};
export const deleteWebhook = async (ref: IHookFunctions, webhookId: string) => {

View file

@ -1,6 +1,6 @@
import EventSource from 'eventsource';
import { ITriggerFunctions } from 'n8n-core';
import { INodeType, INodeTypeDescription, ITriggerResponse } from 'n8n-workflow';
import { INodeType, INodeTypeDescription, ITriggerResponse, jsonParse } from 'n8n-workflow';
export class SseTrigger implements INodeType {
description: INodeTypeDescription = {
@ -37,7 +37,8 @@ export class SseTrigger implements INodeType {
const eventSource = new EventSource(url);
eventSource.onmessage = (event) => {
const eventData = JSON.parse(event.data);
// tslint:disable-next-line:no-any
const eventData = jsonParse<any>(event.data, { errorMessage: 'Invalid JSON for event data' });
this.emit([this.helpers.returnJsonArray([eventData])]);
};

View file

@ -4,6 +4,7 @@ import {
INodeExecutionData,
INodeType,
INodeTypeDescription,
jsonParse,
NodeOperationError,
} from 'n8n-workflow';
@ -91,7 +92,8 @@ export class StopAndError implements INodeType {
toThrow = this.getNodeParameter('errorMessage', 0) as string;
} else {
const json = this.getNodeParameter('errorObject', 0) as string;
const errorObject = JSON.parse(json);
// tslint:disable-next-line:no-any
const errorObject = jsonParse<any>(json);
toThrow = {
name: 'User-thrown error',

View file

@ -9,6 +9,7 @@ import {
INodeType,
INodeTypeDescription,
IWebhookResponseData,
jsonParse,
NodeApiError,
NodeOperationError,
} from 'n8n-workflow';
@ -514,7 +515,8 @@ export class SurveyMonkeyTrigger implements INodeType {
return {};
}
let responseData = JSON.parse(data.join(''));
// tslint:disable-next-line:no-any
let responseData = jsonParse<any>(data.join(''));
let endpoint = '';
let returnItem: INodeExecutionData[] = [

View file

@ -2,7 +2,7 @@ import { OptionsWithUri } from 'request';
import { IExecuteFunctions, IHookFunctions, ILoadOptionsFunctions } from 'n8n-core';
import { IDataObject, NodeApiError, NodeOperationError } from 'n8n-workflow';
import { IDataObject, jsonParse, NodeApiError, NodeOperationError } from 'n8n-workflow';
import moment from 'moment';
import { Eq } from './QueryFunctions';
@ -79,7 +79,7 @@ export function prepareOptional(optionals: IDataObject): IDataObject {
response[key] = Date.parse(optionals[key] as string);
} else if (key === 'artifacts') {
try {
response[key] = JSON.parse(optionals[key] as string);
response[key] = jsonParse(optionals[key] as string);
} catch (error) {
throw new Error('Invalid JSON for artifacts');
}
@ -107,7 +107,7 @@ export async function prepareCustomFields(
if (typeof customFieldsJson === 'string') {
try {
customFieldsJson = JSON.parse(customFieldsJson);
customFieldsJson = jsonParse(customFieldsJson);
} catch (error) {
throw new Error('Invalid JSON for customFields');
}

View file

@ -1,4 +1,4 @@
import { IDataObject } from 'n8n-workflow';
import { IDataObject, jsonParse } from 'n8n-workflow';
import {
Context,
FormatDueDatetime,
@ -228,7 +228,7 @@ export class SyncHandler implements OperationHandler {
const commandsJson = ctx.getNodeParameter('commands', itemIndex) as string;
const projectId = ctx.getNodeParameter('project', itemIndex) as number;
const sections = await getSectionIds(ctx, projectId);
const commands: Command[] = JSON.parse(commandsJson);
const commands: Command[] = jsonParse(commandsJson);
const tempIdMapping = new Map<string, string>();
for (let i = 0; i < commands.length; i++) {

View file

@ -7,6 +7,7 @@ import {
INodeType,
INodeTypeDescription,
IWebhookResponseData,
jsonParse,
} from 'n8n-workflow';
import { wufooApiRequest } from './GenericFunctions';
@ -153,7 +154,10 @@ export class WufooTrigger implements INodeType {
return {};
}
const fieldsObject = JSON.parse(req.body.FieldStructure);
// tslint:disable-next-line:no-any
const fieldsObject = jsonParse<any>(req.body.FieldStructure, {
errorMessage: "Invalid JSON in request body field 'FieldStructure'",
});
fieldsObject.Fields.map((field: IField) => {
// TODO
@ -206,8 +210,12 @@ export class WufooTrigger implements INodeType {
entryId: req.body.EntryId as number,
dateCreated: req.body.DateCreated as Date,
formId: req.body.FormId as string,
formStructure: JSON.parse(req.body.FormStructure),
fieldStructure: JSON.parse(req.body.FieldStructure),
formStructure: jsonParse(req.body.FormStructure, {
errorMessage: "Invalid JSON in request body field 'FormStructure'",
}),
fieldStructure: jsonParse(req.body.FieldStructure, {
errorMessage: "Invalid JSON in request body field 'FieldStructure'",
}),
entries,
};

View file

@ -16,4 +16,4 @@ export * from './WorkflowDataProxy';
export * from './WorkflowErrors';
export * from './WorkflowHooks';
export { LoggerProxy, NodeHelpers, ObservableObject, TelemetryHelpers };
export { deepCopy } from './utils';
export { deepCopy, jsonParse } from './utils';

View file

@ -30,3 +30,22 @@ export const deepCopy = <T>(source: T): T => {
return clone;
};
// eslint-enable
type ErrorMessage = { errorMessage: string };
type FallbackValue<T> = { fallbackValue: T };
export const jsonParse = <T>(
jsonString: string,
options: ErrorMessage | FallbackValue<T> | {} = {},
): T => {
try {
return JSON.parse(jsonString) as T;
} catch (error) {
if ('fallbackValue' in options) {
return options.fallbackValue;
}
if ('errorMessage' in options) {
throw new Error(options.errorMessage);
}
throw error;
}
};