mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-12 05:17:28 -08:00
refactor: lint for inefficient deep clones (#4378)
* 👕 Create rule `no-json-parse-json-stringify` * 🧪 Add tests * 👕 Enable new rule * 👕 FIx unrelated lint issue
This commit is contained in:
parent
a02e92d664
commit
6a1838d8c1
|
@ -323,6 +323,9 @@ const config = (module.exports = {
|
||||||
// TODO: set to `error` and fix offenses
|
// TODO: set to `error` and fix offenses
|
||||||
'n8n-local-rules/no-uncaught-json-parse': 'warn',
|
'n8n-local-rules/no-uncaught-json-parse': 'warn',
|
||||||
|
|
||||||
|
// TODO: set to `error` and fix offenses
|
||||||
|
'n8n-local-rules/no-json-parse-json-stringify': 'warn',
|
||||||
|
|
||||||
// ******************************************************************
|
// ******************************************************************
|
||||||
// overrides to base ruleset
|
// overrides to base ruleset
|
||||||
// ******************************************************************
|
// ******************************************************************
|
||||||
|
|
|
@ -46,7 +46,7 @@ module.exports = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDeepCloneOperation(node)) {
|
if (isJsonStringifyCall(node)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +63,47 @@ module.exports = {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'no-json-parse-json-stringify': {
|
||||||
|
meta: {
|
||||||
|
type: 'problem',
|
||||||
|
docs: {
|
||||||
|
description:
|
||||||
|
'Calls to `JSON.parse(JSON.stringify(arg))` must be replaced with `deepCopy(arg)` from `n8n-workflow`.',
|
||||||
|
recommended: 'error',
|
||||||
|
},
|
||||||
|
messages: {
|
||||||
|
noJsonParseJsonStringify: 'Replace with `deepCopy({{ argText }})`',
|
||||||
|
},
|
||||||
|
fixable: 'code',
|
||||||
|
},
|
||||||
|
create(context) {
|
||||||
|
return {
|
||||||
|
CallExpression(node) {
|
||||||
|
if (isJsonParseCall(node) && isJsonStringifyCall(node)) {
|
||||||
|
const [callExpression] = node.arguments;
|
||||||
|
|
||||||
|
const { arguments: args } = callExpression;
|
||||||
|
|
||||||
|
if (!Array.isArray(args) || args.length !== 1) return;
|
||||||
|
|
||||||
|
const [arg] = args;
|
||||||
|
|
||||||
|
if (!arg) return;
|
||||||
|
|
||||||
|
const argText = context.getSourceCode().getText(arg);
|
||||||
|
|
||||||
|
context.report({
|
||||||
|
messageId: 'noJsonParseJsonStringify',
|
||||||
|
node,
|
||||||
|
data: { argText },
|
||||||
|
fix: (fixer) => fixer.replaceText(node, `deepCopy(${argText})`),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const isJsonParseCall = (node) =>
|
const isJsonParseCall = (node) =>
|
||||||
|
@ -72,7 +113,7 @@ const isJsonParseCall = (node) =>
|
||||||
node.callee.property.type === 'Identifier' &&
|
node.callee.property.type === 'Identifier' &&
|
||||||
node.callee.property.name === 'parse';
|
node.callee.property.name === 'parse';
|
||||||
|
|
||||||
const isDeepCloneOperation = (node) => {
|
const isJsonStringifyCall = (node) => {
|
||||||
const parseArg = node.arguments?.[0];
|
const parseArg = node.arguments?.[0];
|
||||||
return (
|
return (
|
||||||
parseArg !== undefined &&
|
parseArg !== undefined &&
|
||||||
|
|
|
@ -21,3 +21,33 @@ ruleTester.run('no-uncaught-json-parse', rules['no-uncaught-json-parse'], {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ruleTester.run('no-json-parse-json-stringify', rules['no-json-parse-json-stringify'], {
|
||||||
|
valid: [
|
||||||
|
{
|
||||||
|
code: 'deepCopy(foo)',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
invalid: [
|
||||||
|
{
|
||||||
|
code: 'JSON.parse(JSON.stringify(foo))',
|
||||||
|
errors: [{ messageId: 'noJsonParseJsonStringify' }],
|
||||||
|
output: 'deepCopy(foo)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'JSON.parse(JSON.stringify(foo.bar))',
|
||||||
|
errors: [{ messageId: 'noJsonParseJsonStringify' }],
|
||||||
|
output: 'deepCopy(foo.bar)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'JSON.parse(JSON.stringify(foo.bar.baz))',
|
||||||
|
errors: [{ messageId: 'noJsonParseJsonStringify' }],
|
||||||
|
output: 'deepCopy(foo.bar.baz)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'JSON.parse(JSON.stringify(foo.bar[baz]))',
|
||||||
|
errors: [{ messageId: 'noJsonParseJsonStringify' }],
|
||||||
|
output: 'deepCopy(foo.bar[baz])',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
|
@ -62,6 +62,7 @@ export class ScheduleTrigger implements INodeType {
|
||||||
name: 'field',
|
name: 'field',
|
||||||
type: 'options',
|
type: 'options',
|
||||||
default: 'days',
|
default: 'days',
|
||||||
|
// eslint-disable-next-line n8n-nodes-base/node-param-options-type-unsorted-items
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
name: 'Seconds',
|
name: 'Seconds',
|
||||||
|
|
Loading…
Reference in a new issue