From ffe6e39ecfca5c9a231084458e52354f9a2652f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Thu, 8 Sep 2022 13:21:25 +0200 Subject: [PATCH] Create `node-param-operation-option-description-wrong-for-get-many` (#119) * Create `node-param-operation-option-description-wrong-for-get-many` * Restore version --- README.md | 1 + ...ration-option-action-wrong-for-get-many.md | 46 +--------- ...n-option-description-wrong-for-get-many.md | 66 ++++++++++++++ lib/ast/getters/nodeParameter.getters.ts | 12 +++ .../identifiers/nodeParameter.identifiers.ts | 14 +++ ...ration-option-action-wrong-for-get-many.ts | 38 +++----- ...n-option-description-wrong-for-get-many.ts | 77 ++++++++++++++++ ...n-option-action-wrong-for-get-many.test.ts | 84 +---------------- ...ion-description-wrong-for-get-many.test.ts | 89 +++++++++++++++++++ 9 files changed, 279 insertions(+), 148 deletions(-) create mode 100644 docs/rules/node-param-operation-option-description-wrong-for-get-many.md create mode 100644 lib/rules/node-param-operation-option-description-wrong-for-get-many.ts create mode 100644 tests/node-param-operation-option-description-wrong-for-get-many.test.ts diff --git a/README.md b/README.md index d97b864..6882a95 100644 --- a/README.md +++ b/README.md @@ -180,6 +180,7 @@ In the `community` ruleset, the five `*-still-default` rules allow you to define | [node-param-multi-options-type-unsorted-items](docs/rules/node-param-multi-options-type-unsorted-items.md) | Items in a multi-options-type node parameter must be alphabetized by `name` if five or more than five. | Yes | | [node-param-operation-option-action-miscased](docs/rules/node-param-operation-option-action-miscased.md) | The property `action` in an option in an Operation node parameter must be sentence-cased. | Yes | | [node-param-operation-option-action-wrong-for-get-many](docs/rules/node-param-operation-option-action-wrong-for-get-many.md) | The property `action` in a Get Many option in an Operation node parameter must start with `Get many`. | Yes | +| [node-param-operation-option-description-wrong-for-get-many](docs/rules/node-param-operation-option-description-wrong-for-get-many.md) | The property `description` in a Get Many option in an Operation node parameter must mention `many` instead of `all`. | Yes | | [node-param-operation-option-without-action](docs/rules/node-param-operation-option-without-action.md) | An option in an Operation node parameter must have an `action` property. The `action` property may or may not be identical to the `description` property. | Yes | | [node-param-operation-without-no-data-expression](docs/rules/node-param-operation-without-no-data-expression.md) | `noDataExpression` in an Operation node parameter must be present and enabled. | Yes | | [node-param-option-description-identical-to-name](docs/rules/node-param-option-description-identical-to-name.md) | `description` in option in options-type node parameter must not be identical to `name`. | Yes | diff --git a/docs/rules/node-param-operation-option-action-wrong-for-get-many.md b/docs/rules/node-param-operation-option-action-wrong-for-get-many.md index 3ed9584..356700c 100644 --- a/docs/rules/node-param-operation-option-action-wrong-for-get-many.md +++ b/docs/rules/node-param-operation-option-action-wrong-for-get-many.md @@ -26,30 +26,9 @@ const test = { default: "getAll", options: [ { - name: "Get All", - value: "getAll", - description: "Retrieve all entities", - action: "Get all entities", - }, - ], -}; - -const test = { - displayName: "Action", - name: "action", - type: "options", - noDataExpression: true, - displayOptions: { - show: { - resource: ["entity"], - }, - }, - default: "getAll", - options: [ - { - name: "Get All", + name: "Get Many", value: "getAll", - description: "Retrieve all entities", + description: "Retrieve many entities", action: "Get all entities", }, ], @@ -70,27 +49,6 @@ const test = { }, }, default: "getAll", - options: [ - { - name: "Get Many", - value: "getAll", - description: "Retrieve all entities", - action: "Get many entities", - }, - ], -}; - -const test = { - displayName: "Action", - name: "action", - type: "options", - noDataExpression: true, - displayOptions: { - show: { - resource: ["entity"], - }, - }, - default: "getAll", options: [ { name: "Get Many", diff --git a/docs/rules/node-param-operation-option-description-wrong-for-get-many.md b/docs/rules/node-param-operation-option-description-wrong-for-get-many.md new file mode 100644 index 0000000..9d05e3a --- /dev/null +++ b/docs/rules/node-param-operation-option-description-wrong-for-get-many.md @@ -0,0 +1,66 @@ +[//]: # "File generated from a template. Do not edit this file directly." + +# node-param-operation-option-description-wrong-for-get-many + +The property `description` in a Get Many option in an Operation node parameter must mention `many` instead of `all`. + +📋 This rule is part of the `plugin:n8n-nodes-base/nodes` config. + +🔧 Run ESLint with `--fix` option to autofix the issue flagged by this rule. + +## Examples + +❌ Example of **incorrect** code: + +```js +const test = { + displayName: "Operation", + name: "operation", + type: "options", + noDataExpression: true, + displayOptions: { + show: { + resource: ["entity"], + }, + }, + default: "getAll", + options: [ + { + name: "Get Many", + value: "getAll", + description: "Retrieve all entities", + action: "Get many entities", + }, + ], +}; +``` + +✅ Example of **correct** code: + +```js +const test = { + displayName: "Operation", + name: "operation", + type: "options", + noDataExpression: true, + displayOptions: { + show: { + resource: ["entity"], + }, + }, + default: "getAll", + options: [ + { + name: "Get Many", + value: "getAll", + description: "Retrieve many entities", + action: "Get many entities", + }, + ], +}; +``` + +## Links + +- [Rule source](../../lib/rules/node-param-operation-option-description-wrong-for-get-many.ts) +- [Test source](../../tests/node-param-operation-option-description-wrong-for-get-many.test.ts) diff --git a/lib/ast/getters/nodeParameter.getters.ts b/lib/ast/getters/nodeParameter.getters.ts index 0a99107..439f3d4 100644 --- a/lib/ast/getters/nodeParameter.getters.ts +++ b/lib/ast/getters/nodeParameter.getters.ts @@ -88,6 +88,18 @@ export function getNumberProperty( }; } +export function getGetAllOption(nodeParam: TSESTree.ObjectExpression) { + const found = nodeParam.properties.find(id.nodeParam.isGetAllOptionProperty); + + if (!found) return null; + + return { + ast: found, + value: '', // TODO + }; +} + + export function getTypeOptions(nodeParam: TSESTree.ObjectExpression) { const found = nodeParam.properties.find(id.nodeParam.isTypeOptions); diff --git a/lib/ast/identifiers/nodeParameter.identifiers.ts b/lib/ast/identifiers/nodeParameter.identifiers.ts index 0731f86..eb55fa1 100644 --- a/lib/ast/identifiers/nodeParameter.identifiers.ts +++ b/lib/ast/identifiers/nodeParameter.identifiers.ts @@ -339,3 +339,17 @@ export function isShowSetting( ): property is ArrayProperty { return isArrayPropertyNamed(showSettingKey, property); } + +export function isGetAllOptionProperty( + property: TSESTree.ObjectLiteralElement +) { + return ( + property.type === AST_NODE_TYPES.Property && + property.computed === false && + property.key.type === AST_NODE_TYPES.Identifier && + property.key.name === "value" && + property.value.type === AST_NODE_TYPES.Literal && + typeof property.value.value === "string" && + property.value.value === "getAll" + ); +} diff --git a/lib/rules/node-param-operation-option-action-wrong-for-get-many.ts b/lib/rules/node-param-operation-option-action-wrong-for-get-many.ts index 0c35a86..daeffb5 100644 --- a/lib/rules/node-param-operation-option-action-wrong-for-get-many.ts +++ b/lib/rules/node-param-operation-option-action-wrong-for-get-many.ts @@ -22,8 +22,6 @@ export default utils.createRule({ create(context) { return { ObjectExpression(node) { - if (!id.isNodeParameter(node)) return; - if (!id.nodeParam.isOperation(node) && !id.nodeParam.isAction(node)) { return; } @@ -35,41 +33,33 @@ export default utils.createRule({ // skip `options: [...].sort()`, see EditImage.node.ts if (!Array.isArray(options.ast.value.elements)) return; - const getAllOption = options.ast.value.elements.find((option) => { - return option.properties.find((property) => { - return ( - property.type === AST_NODE_TYPES.Property && - property.computed === false && - property.key.type === AST_NODE_TYPES.Identifier && - property.key.name === "value" && - property.value.type === AST_NODE_TYPES.Literal && - typeof property.value.value === "string" && - property.value.value === "getAll" - ); - }); - }); + const getAllOption = options.ast.value.elements.find( + getters.nodeParam.getGetAllOption + ); if (!getAllOption) return; - const action = getAllOption.properties.find(isActionProperty); + const actionNode = getAllOption.properties.find(isActionProperty); + + if (!actionNode) return; - if (!action) return; + const { value: action } = actionNode.value; - const actionSentence = action.value.value; + const DEPRECATED_START_OF_ACTION = "Get all "; - if (actionSentence.startsWith("Get all")) { - const [_, resourceName] = actionSentence.split("Get all"); + if (action.startsWith(DEPRECATED_START_OF_ACTION)) { + const [_, resourceName] = action.split(DEPRECATED_START_OF_ACTION); const fixed = utils.keyValue( "action", - actionSentence.replace("Get all", "Get many") + action.replace(DEPRECATED_START_OF_ACTION, "Get many ") ); context.report({ messageId: "changeToGetMany", - node: action, - fix: (fixer) => fixer.replaceText(action, fixed), - data: { resourceName: resourceName.trim() } + node: actionNode, + fix: (fixer) => fixer.replaceText(actionNode, fixed), + data: { resourceName }, }); } }, diff --git a/lib/rules/node-param-operation-option-description-wrong-for-get-many.ts b/lib/rules/node-param-operation-option-description-wrong-for-get-many.ts new file mode 100644 index 0000000..a6960f9 --- /dev/null +++ b/lib/rules/node-param-operation-option-description-wrong-for-get-many.ts @@ -0,0 +1,77 @@ +import { utils } from "../ast/utils"; +import { id } from "../ast/identifiers"; +import { getters } from "../ast/getters"; +import { AST_NODE_TYPES, TSESTree } from "@typescript-eslint/utils"; + +export default utils.createRule({ + name: utils.getRuleName(module), + meta: { + type: "problem", + docs: { + description: + "The property `description` in a Get Many option in an Operation node parameter must mention `many` instead of `all`.", + recommended: "error", + }, + fixable: "code", + schema: [], + messages: { + changeToGetMany: "Change to '{{ newDescription }}' [autofixable]", + }, + }, + defaultOptions: [], + create(context) { + return { + ObjectExpression(node) { + if (!id.nodeParam.isOperation(node)) return; + + const options = getters.nodeParam.getOptions(node); + + if (!options) return; + + // skip `options: [...].sort()`, see EditImage.node.ts + if (!Array.isArray(options.ast.value.elements)) return; + + const getAllOption = options.ast.value.elements.find( + getters.nodeParam.getGetAllOption + ); + + if (!getAllOption) return; + + const descriptionNode = + getAllOption.properties.find(isOptionDescription); + + if (!descriptionNode) return; + + const { value: description } = descriptionNode.value; + + if (description.includes(" all ")) { + const [start, end] = description.split(" all "); + + const newDescription = [start, "many", end].join(" "); + + const fixed = utils.keyValue("description", newDescription); + + context.report({ + messageId: "changeToGetMany", + node: descriptionNode, + fix: (fixer) => fixer.replaceText(descriptionNode, fixed), + data: { newDescription }, + }); + } + }, + }; + }, +}); + +function isOptionDescription( + property: TSESTree.ObjectLiteralElement +): property is TSESTree.Property & { value: { value: string } } { + return ( + property.type === AST_NODE_TYPES.Property && + property.computed === false && + property.key.type === AST_NODE_TYPES.Identifier && + property.key.name === "description" && + property.value.type === AST_NODE_TYPES.Literal && + typeof property.value.value === "string" + ); +} diff --git a/tests/node-param-operation-option-action-wrong-for-get-many.test.ts b/tests/node-param-operation-option-action-wrong-for-get-many.test.ts index 40048eb..8fddf89 100644 --- a/tests/node-param-operation-option-action-wrong-for-get-many.test.ts +++ b/tests/node-param-operation-option-action-wrong-for-get-many.test.ts @@ -19,31 +19,6 @@ ruleTester().run(getRuleName(module), rule, { }, }, default: 'getAll', - options: [ - { - name: 'Get Many', - value: 'getAll', - description: 'Retrieve all entities', - action: 'Get many entities', - }, - ], - };`, - }, - { - code: outdent` - const test = { - displayName: 'Action', - name: 'action', - type: 'options', - noDataExpression: true, - displayOptions: { - show: { - resource: [ - 'entity', - ], - }, - }, - default: 'getAll', options: [ { name: 'Get Many', @@ -73,9 +48,9 @@ ruleTester().run(getRuleName(module), rule, { default: 'getAll', options: [ { - name: 'Get All', + name: 'Get Many', value: 'getAll', - description: 'Retrieve all entities', + description: 'Retrieve many entities', action: 'Get all entities', }, ], @@ -99,60 +74,9 @@ ruleTester().run(getRuleName(module), rule, { default: 'getAll', options: [ { - name: 'Get All', - value: 'getAll', - description: 'Retrieve all entities', - action: 'Get many entities', - }, - ], - };`, - }, - { - code: outdent` - const test = { - displayName: 'Action', - name: 'action', - type: 'options', - noDataExpression: true, - displayOptions: { - show: { - resource: [ - 'entity', - ], - }, - }, - default: 'getAll', - options: [ - { - name: 'Get All', - value: 'getAll', - description: 'Retrieve all entities', - action: 'Get all entities', - }, - ], - };`, - errors: [ - { messageId: "changeToGetMany", data: { resourceName: "entities" } }, - ], - output: outdent` - const test = { - displayName: 'Action', - name: 'action', - type: 'options', - noDataExpression: true, - displayOptions: { - show: { - resource: [ - 'entity', - ], - }, - }, - default: 'getAll', - options: [ - { - name: 'Get All', + name: 'Get Many', value: 'getAll', - description: 'Retrieve all entities', + description: 'Retrieve many entities', action: 'Get many entities', }, ], diff --git a/tests/node-param-operation-option-description-wrong-for-get-many.test.ts b/tests/node-param-operation-option-description-wrong-for-get-many.test.ts new file mode 100644 index 0000000..3af48c8 --- /dev/null +++ b/tests/node-param-operation-option-description-wrong-for-get-many.test.ts @@ -0,0 +1,89 @@ +import rule from "../lib/rules/node-param-operation-option-description-wrong-for-get-many"; +import { ruleTester, getRuleName } from "../lib/ast"; +import outdent from "outdent"; + +ruleTester().run(getRuleName(module), rule, { + valid: [ + { + code: outdent` + const test = { + displayName: 'Operation', + name: 'operation', + type: 'options', + noDataExpression: true, + displayOptions: { + show: { + resource: [ + 'entity', + ], + }, + }, + default: 'getAll', + options: [ + { + name: 'Get Many', + value: 'getAll', + description: 'Retrieve many entities', + action: 'Get many entities', + }, + ], + };`, + }, + ], + invalid: [ + { + code: outdent` + const test = { + displayName: 'Operation', + name: 'operation', + type: 'options', + noDataExpression: true, + displayOptions: { + show: { + resource: [ + 'entity', + ], + }, + }, + default: 'getAll', + options: [ + { + name: 'Get Many', + value: 'getAll', + description: 'Retrieve all entities', + action: 'Get many entities', + }, + ], + };`, + errors: [ + { + messageId: "changeToGetMany", + data: { newDescription: "Retrieve many entities" }, + }, + ], + output: outdent` + const test = { + displayName: 'Operation', + name: 'operation', + type: 'options', + noDataExpression: true, + displayOptions: { + show: { + resource: [ + 'entity', + ], + }, + }, + default: 'getAll', + options: [ + { + name: 'Get Many', + value: 'getAll', + description: 'Retrieve many entities', + action: 'Get many entities', + }, + ], + };`, + }, + ], +});