mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-12 13:27:31 -08:00
feat(eslint-config): add custom eslint rule 'no-uncaught-json-parse' (#4087)
feat(eslint-config): add custom eslint rule 'no-uncaugh-json-parse' Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
This commit is contained in:
parent
7aa40bf95d
commit
31391a5b19
2629
package-lock.json
generated
2629
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -40,6 +40,12 @@ module.exports = {
|
||||||
* https://github.com/paleite/eslint-plugin-diff#plugindiffdiff-recommended
|
* https://github.com/paleite/eslint-plugin-diff#plugindiffdiff-recommended
|
||||||
*/
|
*/
|
||||||
'eslint-plugin-diff',
|
'eslint-plugin-diff',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Plugin to allow specifying local ESLint rules.
|
||||||
|
* https://github.com/ivov/eslint-plugin-n8n-local-rules
|
||||||
|
*/
|
||||||
|
'eslint-plugin-n8n-local-rules',
|
||||||
],
|
],
|
||||||
|
|
||||||
extends: [
|
extends: [
|
||||||
|
@ -324,6 +330,13 @@ module.exports = {
|
||||||
*/
|
*/
|
||||||
'import/order': 'error',
|
'import/order': 'error',
|
||||||
|
|
||||||
|
// ----------------------------------
|
||||||
|
// eslint-plugin-n8n-local-rules
|
||||||
|
// ----------------------------------
|
||||||
|
|
||||||
|
// TODO: set to `error` and fix offenses
|
||||||
|
'n8n-local-rules/no-uncaught-json-parse': 'warn',
|
||||||
|
|
||||||
// ******************************************************************
|
// ******************************************************************
|
||||||
// overrides to base ruleset
|
// overrides to base ruleset
|
||||||
// ******************************************************************
|
// ******************************************************************
|
||||||
|
|
86
packages/@n8n_io/eslint-config/local-rules.js
Normal file
86
packages/@n8n_io/eslint-config/local-rules.js
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file contains any locally defined ESLint rules. They are picked up by
|
||||||
|
* eslint-plugin-n8n-local-rules and exposed as 'n8n-local-rules/<rule-name>'.
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* A rule to detect calls to JSON.parse() that are not wrapped inside try/catch blocks.
|
||||||
|
*
|
||||||
|
* Valid:
|
||||||
|
* ```js
|
||||||
|
* try { JSON.parse(foo) } catch(err) { baz() }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Invalid:
|
||||||
|
* ```js
|
||||||
|
* JSON.parse(foo)
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The pattern where an object is cloned with JSON.parse(JSON.stringify()) is allowed
|
||||||
|
* (abundant in the n8n codebase):
|
||||||
|
*
|
||||||
|
* Valid:
|
||||||
|
* ```js
|
||||||
|
* JSON.parse(JSON.stringify(foo))
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
'no-uncaught-json-parse': {
|
||||||
|
meta: {
|
||||||
|
type: 'problem',
|
||||||
|
docs: {
|
||||||
|
description: 'Calls to JSON.parse() must be surrounded with a try/catch block.',
|
||||||
|
recommended: 'error',
|
||||||
|
},
|
||||||
|
schema: [],
|
||||||
|
messages: {
|
||||||
|
noUncaughtJsonParse: 'Surround the JSON.parse() call with a try/catch block.',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultOptions: [],
|
||||||
|
create(context) {
|
||||||
|
return {
|
||||||
|
CallExpression(node) {
|
||||||
|
if (!isJsonParseCall(node)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDeepCloneOperation(node)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.getAncestors().find((node) => node.type === 'TryStatement') !== undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Found a JSON.parse() call not wrapped into a try/catch, so report it
|
||||||
|
context.report({
|
||||||
|
messageId: 'noUncaughtJsonParse',
|
||||||
|
node,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const isJsonParseCall = (node) =>
|
||||||
|
node.callee.type === 'MemberExpression' &&
|
||||||
|
node.callee.object.type === 'Identifier' &&
|
||||||
|
node.callee.object.name === 'JSON' &&
|
||||||
|
node.callee.property.type === 'Identifier' &&
|
||||||
|
node.callee.property.name === 'parse';
|
||||||
|
|
||||||
|
const isDeepCloneOperation = (node) => {
|
||||||
|
const parseArg = node.arguments?.[0];
|
||||||
|
return (
|
||||||
|
parseArg !== undefined &&
|
||||||
|
parseArg.type === 'CallExpression' &&
|
||||||
|
parseArg.callee.type === 'MemberExpression' &&
|
||||||
|
parseArg.callee.object.type === 'Identifier' &&
|
||||||
|
parseArg.callee.object.name === 'JSON' &&
|
||||||
|
parseArg.callee.property.type === 'Identifier' &&
|
||||||
|
parseArg.callee.property.name === 'stringify'
|
||||||
|
);
|
||||||
|
};
|
23
packages/@n8n_io/eslint-config/local-rules.test.js
Normal file
23
packages/@n8n_io/eslint-config/local-rules.test.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const rules = require('./local-rules'),
|
||||||
|
RuleTester = require('eslint').RuleTester;
|
||||||
|
|
||||||
|
const ruleTester = new RuleTester();
|
||||||
|
|
||||||
|
ruleTester.run('no-uncaught-json-parse', rules['no-uncaught-json-parse'], {
|
||||||
|
valid: [
|
||||||
|
{
|
||||||
|
code: 'try { JSON.parse(foo) } catch (e) {}',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'JSON.parse(JSON.stringify(foo))',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
invalid: [
|
||||||
|
{
|
||||||
|
code: 'JSON.parse(foo)',
|
||||||
|
errors: [{ messageId: 'noUncaughtJsonParse' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
|
@ -11,7 +11,12 @@
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-diff": "^2.0.1",
|
"eslint-plugin-diff": "^2.0.1",
|
||||||
"eslint-plugin-import": "^2.26.0",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
|
"eslint-plugin-n8n-local-rules": "^1.0.0",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"eslint-plugin-vue": "^9.4.0"
|
"eslint-plugin-vue": "^9.4.0",
|
||||||
|
"jest": "^28.1.3"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "jest"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue