eslint-plugin-n8n-nodes-base
Advanced tools
Comparing version 1.0.43 to 1.0.44
@@ -6,19 +6,43 @@ "use strict"; | ||
const rulesPath = path.join(__dirname, "lib", "rules"); // from dist | ||
const RULES_DIST_DIR = path.resolve(__dirname, "lib", "rules"); // /dist/lib/rules | ||
const allFullRuleNames = fs | ||
.readdirSync(rulesPath) | ||
const CONFIG_BASE_PROPERTIES = { | ||
env: { es2021: true }, | ||
parserOptions: { | ||
ecmaVersion: "latest", | ||
sourceType: "module", | ||
}, | ||
plugins: ["n8n-nodes-base"], | ||
}; | ||
const AUTOFIXABLE_UNSAFE_RULESET = [ | ||
"cred-class-name-unsuffixed", | ||
"cred-class-field-name-unsuffixed", | ||
"cred-class-field-name-uppercase-first-char", | ||
"node-param-array-type-assertion", | ||
"node-param-color-type-unused", | ||
"node-class-description-credentials-name-unsuffixed", | ||
"node-class-description-display-name-unsuffixed-trigger-node", | ||
"node-class-description-name-unsuffixed-trigger-node", | ||
]; | ||
const DEFAULT_SEVERITY = "error"; | ||
const getRuleModule = (rulename) => | ||
require(path.resolve(RULES_DIST_DIR, rulename)).default; | ||
const ALL_RULE_NAMES = fs | ||
.readdirSync(RULES_DIST_DIR) | ||
.filter((fileName) => fileName.endsWith(".js")) | ||
.map((fileName) => fileName.replace(/\.js$/, "")) | ||
.map((ruleName) => `n8n-nodes-base/${ruleName}`); | ||
.map((filename) => filename.replace(/\.js$/, "")); | ||
/** | ||
* Rules exported by this plugin: | ||
* All rules exported by this plugin. | ||
* | ||
* ```js | ||
* 'node-param-display-name-lowercase-first-char': { | ||
* 'node-class-description-credentials-name-unsuffixed': { | ||
* meta: { ... }, | ||
* create: { ... } | ||
* }, | ||
* 'node-param-display-name-miscased-id': { | ||
* 'node-class-description-display-name-unsuffixed-trigger-node': { | ||
* meta: { ... }, | ||
@@ -30,7 +54,6 @@ * create: { ... } | ||
*/ | ||
module.exports.rules = allFullRuleNames.reduce((acc, fullRuleName) => { | ||
const [_, ruleName] = fullRuleName.split("n8n-nodes-base/"); | ||
const allRules = ALL_RULE_NAMES.reduce((acc, rulename) => { | ||
return { | ||
...acc, | ||
[ruleName]: require(path.join(rulesPath, ruleName)).default, | ||
[rulename]: getRuleModule(rulename), | ||
}; | ||
@@ -40,54 +63,7 @@ }, {}); | ||
/** | ||
* Rules whose autofixes are breaking changes. | ||
*/ | ||
const AUTOFIXABLE_UNSAFE_RULES = [ | ||
"cred-class-name-unsuffixed", | ||
"cred-class-field-name-unsuffixed", | ||
"cred-class-field-name-uppercase-first-char", | ||
"node-param-array-type-assertion", | ||
"node-param-color-type-unused", | ||
"node-class-description-credentials-name-unsuffixed", | ||
"node-class-description-display-name-unsuffixed-trigger-node", | ||
"node-class-description-name-unsuffixed-trigger-node", | ||
]; | ||
const categorized = allFullRuleNames.reduce( | ||
(acc, fullRuleName) => { | ||
const [_, ruleName] = fullRuleName.split("n8n-nodes-base/"); | ||
const ruleModule = require(path.join(rulesPath, ruleName)).default; | ||
if (ruleModule.meta.fixable) { | ||
AUTOFIXABLE_UNSAFE_RULES.includes(ruleName) | ||
? acc["autofixable-unsafe"].push(fullRuleName) | ||
: acc["autofixable-safe"].push(fullRuleName); | ||
} else { | ||
acc["non-autofixable"].push(fullRuleName); | ||
} | ||
return acc; | ||
}, | ||
{ "autofixable-safe": [], "autofixable-unsafe": [], "non-autofixable": [] } | ||
); | ||
function addSeverity(ruleNames, severity = "warn") { | ||
return ruleNames.reduce((acc, ruleName) => { | ||
return { ...acc, [ruleName]: severity }; | ||
}, {}); | ||
} | ||
const BASE_CONFIG = { | ||
env: { es2021: true }, | ||
parserOptions: { | ||
ecmaVersion: "latest", | ||
sourceType: "module", | ||
}, | ||
plugins: ["n8n-nodes-base"], | ||
}; | ||
/** | ||
* Configs exported by this plugin: | ||
* Configs exported by this plugin. | ||
* | ||
* ```js | ||
* { | ||
* recommended: { | ||
* "all": { | ||
* env: { es2021: true }, | ||
@@ -97,29 +73,43 @@ * parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, | ||
* rules: { | ||
* 'n8n-nodes-base/cred-class-field-display-name-miscased': 'warn', | ||
* // etc | ||
* 'n8n-nodes-base/cred-class-field-display-name-miscased': 'error', | ||
* // etc: other rules | ||
* } | ||
* }, | ||
* // etc | ||
* "autofixable-safe": { ... }, | ||
* "autofixable-unsafe": { ... }, | ||
* "non-autofixable": { ... } | ||
* } | ||
* ``` | ||
*/ | ||
module.exports.configs = { | ||
recommended: { | ||
...BASE_CONFIG, | ||
rules: addSeverity(allFullRuleNames), | ||
const configs = ALL_RULE_NAMES.reduce( | ||
(acc, rulename) => { | ||
const fullRulename = `n8n-nodes-base/${rulename}`; | ||
const ruleModule = getRuleModule(rulename); | ||
acc["all"].rules[fullRulename] = DEFAULT_SEVERITY; | ||
const isAutofixable = ruleModule.meta.fixable !== undefined; | ||
if (isAutofixable && AUTOFIXABLE_UNSAFE_RULESET.includes(rulename)) { | ||
acc["autofixable-unsafe"].rules[fullRulename] = DEFAULT_SEVERITY; | ||
} else if (isAutofixable) { | ||
acc["autofixable-safe"].rules[fullRulename] = DEFAULT_SEVERITY; | ||
} else { | ||
acc["non-autofixable"].rules[fullRulename] = DEFAULT_SEVERITY; | ||
} | ||
return acc; | ||
}, | ||
"autofixable-safe": { | ||
...BASE_CONFIG, | ||
rules: addSeverity(categorized["autofixable-safe"]), | ||
}, | ||
"autofixable-unsafe": { | ||
...BASE_CONFIG, | ||
rules: addSeverity(categorized["autofixable-unsafe"]), | ||
}, | ||
"non-autofixable": { | ||
...BASE_CONFIG, | ||
rules: addSeverity(categorized["non-autofixable"]), | ||
}, | ||
{ | ||
all: { ...CONFIG_BASE_PROPERTIES, rules: {} }, | ||
"autofixable-safe": { ...CONFIG_BASE_PROPERTIES, rules: {} }, | ||
"autofixable-unsafe": { ...CONFIG_BASE_PROPERTIES, rules: {} }, | ||
"non-autofixable": { ...CONFIG_BASE_PROPERTIES, rules: {} }, | ||
} | ||
); | ||
module.exports = { | ||
rules: allRules, | ||
configs, | ||
AUTOFIXABLE_UNSAFE_RULESET, // for make-docs-readme-table.js | ||
}; | ||
module.exports.AUTOFIXABLE_UNSAFE_RULES = AUTOFIXABLE_UNSAFE_RULES; |
@@ -73,4 +73,6 @@ var __create = Object.create; | ||
"notion", | ||
"SyncroMsp" | ||
"syncromsp", | ||
"cisco" | ||
]; | ||
const EXCEPTION_DIRS = ["localfiletrigger"]; | ||
function isInsideNestedDir(context) { | ||
@@ -77,0 +79,0 @@ return DIRS_WITH_NESTING.some((d) => context.getFilename().toLowerCase().includes(d)); |
@@ -65,4 +65,5 @@ var __create = Object.create; | ||
return; | ||
if (options.isPropertyPointingToVar) | ||
if (options.hasPropertyPointingToIdentifier || options.hasPropertyPointingToMemberExpression) { | ||
return; | ||
} | ||
const eligibleOptions = options.value.reduce((acc, option) => { | ||
@@ -73,2 +74,3 @@ return acc.push(option.value), acc; | ||
const zerothOption = eligibleOptions[0]; | ||
const fixed = `default: ${typeof zerothOption === "string" ? `'${zerothOption}'` : zerothOption}`; | ||
context.report({ | ||
@@ -80,5 +82,3 @@ messageId: "chooseOption", | ||
node: _default.ast, | ||
fix: (fixer) => { | ||
return fixer.replaceText(_default.ast, `default: ${typeof zerothOption === "string" ? `'${zerothOption}'` : zerothOption}`); | ||
} | ||
fix: (fixer) => fixer.replaceText(_default.ast, fixed) | ||
}); | ||
@@ -85,0 +85,0 @@ } |
@@ -55,3 +55,3 @@ var __create = Object.create; | ||
return; | ||
if (options.isPropertyPointingToVar) | ||
if (options.hasPropertyPointingToIdentifier) | ||
return; | ||
@@ -58,0 +58,0 @@ const starOption = getStarOptionProperty(options); |
@@ -55,3 +55,3 @@ var __create = Object.create; | ||
return; | ||
if (options.isPropertyPointingToVar) | ||
if (options.hasPropertyPointingToIdentifier) | ||
return; | ||
@@ -58,0 +58,0 @@ const duplicate = findDuplicateOptionName(options); |
@@ -55,3 +55,3 @@ var __create = Object.create; | ||
return; | ||
if (options.isPropertyPointingToVar) | ||
if (options.hasPropertyPointingToIdentifier) | ||
return; | ||
@@ -58,0 +58,0 @@ const duplicate = findDuplicateOptionValue(options); |
@@ -20,2 +20,3 @@ var __defProp = Object.defineProperty; | ||
__export(restore_exports, { | ||
isMemberExpression: () => isMemberExpression, | ||
restoreArray: () => restoreArray, | ||
@@ -98,4 +99,8 @@ restoreClassDescriptionOptions: () => restoreClassDescriptionOptions, | ||
}; | ||
const isMemberExpression = (property) => { | ||
return property.type === import_utils.AST_NODE_TYPES.Property && property.key.type === import_utils.AST_NODE_TYPES.Identifier && typeof property.key.name === "string" && property.value.type === import_utils.AST_NODE_TYPES.MemberExpression; | ||
}; | ||
// Annotate the CommonJS export names for ESM import in node: | ||
0 && (module.exports = { | ||
isMemberExpression, | ||
restoreArray, | ||
@@ -102,0 +107,0 @@ restoreClassDescriptionOptions, |
@@ -102,3 +102,3 @@ var __defProp = Object.defineProperty; | ||
value: [{ name: "", value: "" }], | ||
isPropertyPointingToVar: true | ||
hasPropertyPointingToIdentifier: true | ||
}; | ||
@@ -109,8 +109,17 @@ } | ||
return null; | ||
if (hasMemberExpression(elements)) { | ||
return { | ||
ast: found, | ||
value: (0, import_restore.restoreNodeParamOptions)(elements), | ||
hasPropertyPointingToMemberExpression: true | ||
}; | ||
} | ||
return { | ||
ast: found, | ||
value: (0, import_restore.restoreNodeParamOptions)(elements), | ||
isPropertyPointingToVar: false | ||
value: (0, import_restore.restoreNodeParamOptions)(elements) | ||
}; | ||
} | ||
function hasMemberExpression(elements) { | ||
return elements.find((e) => e.properties.find(import_restore.isMemberExpression)); | ||
} | ||
function getFixedCollectionValues(nodeParam) { | ||
@@ -117,0 +126,0 @@ const found = nodeParam.properties.find(import_identifiers.identifiers.nodeParam.isFixedCollectionValues); |
@@ -24,3 +24,3 @@ var __defProp = Object.defineProperty; | ||
isObjectPropertyWithKey: () => isObjectPropertyWithKey, | ||
isPropertyPointingToVar: () => isPropertyPointingToVar, | ||
isPropertyPointingToIdentifier: () => isPropertyPointingToIdentifier, | ||
isStringPropertyWithKey: () => isStringPropertyWithKey | ||
@@ -45,3 +45,3 @@ }); | ||
} | ||
function isPropertyPointingToVar(keyName, property) { | ||
function isPropertyPointingToIdentifier(keyName, property) { | ||
return property.type === import_utils.AST_NODE_TYPES.Property && property.computed === false && property.key.type === import_utils.AST_NODE_TYPES.Identifier && property.key.name === keyName && property.value.type === import_utils.AST_NODE_TYPES.Identifier; | ||
@@ -55,4 +55,4 @@ } | ||
isObjectPropertyWithKey, | ||
isPropertyPointingToVar, | ||
isPropertyPointingToIdentifier, | ||
isStringPropertyWithKey | ||
}); |
@@ -164,3 +164,3 @@ var __defProp = Object.defineProperty; | ||
function isOptions(property) { | ||
return (0, import_typedProps.isArrayPropertyWithKey)("options", property) || (0, import_typedProps.isPropertyPointingToVar)("options", property); | ||
return (0, import_typedProps.isArrayPropertyWithKey)("options", property) || (0, import_typedProps.isPropertyPointingToIdentifier)("options", property); | ||
} | ||
@@ -167,0 +167,0 @@ function isTypeOptions(property) { |
{ | ||
"name": "eslint-plugin-n8n-nodes-base", | ||
"version": "1.0.43", | ||
"version": "1.0.44", | ||
"main": "dist/index.js", | ||
@@ -5,0 +5,0 @@ "author": { |
@@ -10,3 +10,3 @@ # eslint-plugin-n8n-nodes-base | ||
1. Install this plugin: | ||
Install this plugin: | ||
@@ -17,23 +17,14 @@ ```sh | ||
2. Choose a plugin config: | ||
Create an ESLint configuration file and decide how to enable rules: | ||
- `recommended` (all rules) | ||
- `autofixable-safe` (not causing breaking changes) | ||
- `autofixable-unsafe` (causing breaking changes) | ||
- `non-autofixable` (to manually fix) | ||
### Enable rules individually | ||
3. Create the ESLint configuration file. | ||
All rules are off by default and must be individually enabled: | ||
The following example... | ||
- provides the `n8n-nodes-base` plugin, | ||
- enables the rules tagged `recommended`, and | ||
- disables a specific rule from the enabled set. | ||
```js | ||
{ | ||
plugins: [ "eslint-plugin-n8n-nodes-base" ], | ||
extends: [ "plugin:n8n-nodes-base/recommended" ], | ||
rules: { | ||
"n8n-nodes-base/node-param-type-options-missing-from-limit": "off" | ||
"n8n-nodes-base/node-param-array-type-assertion": "error", | ||
"n8n-nodes-base/node-param-default-wrong-for-collection": "error" | ||
} | ||
@@ -43,11 +34,13 @@ } | ||
Optionally, omit `extends` and enable rules individually: | ||
### Enable a set of rules | ||
Config rules are enabled by default and must be individually disabled: | ||
```js | ||
{ | ||
plugins: [ "eslint-plugin-n8n-nodes-base" ], | ||
extends: [ "plugin:n8n-nodes-base/autofixable-safe" ], | ||
rules: { | ||
"n8n-nodes-base/node-param-type-options-missing-from-limit": "error" | ||
"n8n-nodes-base/node-param-resource-without-no-data-expression": "error" | ||
"n8n-nodes-base/node-param-resource-with-plural-option": "error" | ||
"n8n-nodes-base/node-param-array-type-assertion": "off", | ||
"n8n-nodes-base/node-param-default-wrong-for-collection": "off" | ||
} | ||
@@ -57,2 +50,9 @@ } | ||
Available configs: | ||
- `all` → all rules | ||
- `autofixable-safe` → rules whose autofix cannot cause breaking changes | ||
- `autofixable-unsafe` → rules whose autofix can cause breaking changes | ||
- `non-autofixable` → rules to be manually fixed | ||
## Ruleset | ||
@@ -59,0 +59,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
3
391499
117
8828