first commit
This commit is contained in:
88
node_modules/@n8n/errors/LICENSE.md
generated
vendored
Normal file
88
node_modules/@n8n/errors/LICENSE.md
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
# License
|
||||
|
||||
Portions of this software are licensed as follows:
|
||||
|
||||
- Content of branches other than the main branch (i.e. "master") are not licensed.
|
||||
- Source code files that contain ".ee." in their filename or ".ee" in their dirname are NOT licensed under
|
||||
the Sustainable Use License.
|
||||
To use source code files that contain ".ee." in their filename or ".ee" in their dirname you must hold a
|
||||
valid n8n Enterprise License specifically allowing you access to such source code files and as defined
|
||||
in "LICENSE_EE.md".
|
||||
- All third party components incorporated into the n8n Software are licensed under the original license
|
||||
provided by the owner of the applicable component.
|
||||
- Content outside of the above mentioned files or restrictions is available under the "Sustainable Use
|
||||
License" as defined below.
|
||||
|
||||
## Sustainable Use License
|
||||
|
||||
Version 1.0
|
||||
|
||||
### Acceptance
|
||||
|
||||
By using the software, you agree to all of the terms and conditions below.
|
||||
|
||||
### Copyright License
|
||||
|
||||
The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license
|
||||
to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject
|
||||
to the limitations below.
|
||||
|
||||
### Limitations
|
||||
|
||||
You may use or modify the software only for your own internal business purposes or for non-commercial or
|
||||
personal use. You may distribute the software or provide it to others only if you do so free of charge for
|
||||
non-commercial purposes. You may not alter, remove, or obscure any licensing, copyright, or other notices of
|
||||
the licensor in the software. Any use of the licensor’s trademarks is subject to applicable law.
|
||||
|
||||
### Patents
|
||||
|
||||
The licensor grants you a license, under any patent claims the licensor can license, or becomes able to
|
||||
license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case
|
||||
subject to the limitations and conditions in this license. This license does not cover any patent claims that
|
||||
you cause to be infringed by modifications or additions to the software. If you or your company make any
|
||||
written claim that the software infringes or contributes to infringement of any patent, your patent license
|
||||
for the software granted under these terms ends immediately. If your company makes such a claim, your patent
|
||||
license ends immediately for work on behalf of your company.
|
||||
|
||||
### Notices
|
||||
|
||||
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these
|
||||
terms. If you modify the software, you must include in any modified copies of the software a prominent notice
|
||||
stating that you have modified the software.
|
||||
|
||||
### No Other Rights
|
||||
|
||||
These terms do not imply any licenses other than those expressly granted in these terms.
|
||||
|
||||
### Termination
|
||||
|
||||
If you use the software in violation of these terms, such use is not licensed, and your license will
|
||||
automatically terminate. If the licensor provides you with a notice of your violation, and you cease all
|
||||
violation of this license no later than 30 days after you receive that notice, your license will be reinstated
|
||||
retroactively. However, if you violate these terms after such reinstatement, any additional violation of these
|
||||
terms will cause your license to terminate automatically and permanently.
|
||||
|
||||
### No Liability
|
||||
|
||||
As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will
|
||||
not be liable to you for any damages arising out of these terms or the use or nature of the software, under
|
||||
any kind of legal claim.
|
||||
|
||||
### Definitions
|
||||
|
||||
The “licensor” is the entity offering these terms.
|
||||
|
||||
The “software” is the software the licensor makes available under these terms, including any portion of it.
|
||||
|
||||
“You” refers to the individual or entity agreeing to these terms.
|
||||
|
||||
“Your company” is any legal entity, sole proprietorship, or other kind of organization that you work for, plus
|
||||
all organizations that have control over, are under the control of, or are under common control with that
|
||||
organization. Control means ownership of substantially all the assets of an entity, or the power to direct its
|
||||
management and policies by vote, contract, or otherwise. Control can be direct or indirect.
|
||||
|
||||
“Your license” is the license granted to you for the software under these terms.
|
||||
|
||||
“Use” means anything you do with the software requiring your license.
|
||||
|
||||
“Trademark” means trademarks, service marks, and similar rights.
|
||||
27
node_modules/@n8n/errors/LICENSE_EE.md
generated
vendored
Normal file
27
node_modules/@n8n/errors/LICENSE_EE.md
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# The n8n Enterprise License (the “Enterprise License”)
|
||||
|
||||
Copyright (c) 2022-present n8n GmbH.
|
||||
|
||||
With regard to the n8n Software:
|
||||
|
||||
This software and associated documentation files (the "Software") may only be used in production, if
|
||||
you (and any entity that you represent) hold a valid n8n Enterprise license corresponding to your
|
||||
usage. Subject to the foregoing sentence, you are free to modify this Software and publish patches
|
||||
to the Software. You agree that n8n and/or its licensors (as applicable) retain all right, title and
|
||||
interest in and to all such modifications and/or patches, and all such modifications and/or patches
|
||||
may only be used, copied, modified, displayed, distributed, or otherwise exploited with a valid n8n
|
||||
Enterprise license for the corresponding usage. Notwithstanding the foregoing, you may copy and
|
||||
modify the Software for development and testing purposes, without requiring a subscription. You
|
||||
agree that n8n and/or its licensors (as applicable) retain all right, title and interest in and to
|
||||
all such modifications. You are not granted any other rights beyond what is expressly stated herein.
|
||||
Subject to the foregoing, it is forbidden to copy, merge, publish, distribute, sublicense, and/or
|
||||
sell the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For all third party components incorporated into the n8n Software, those components are licensed
|
||||
under the original license provided by the owner of the applicable component.
|
||||
9
node_modules/@n8n/errors/dist/application.error.d.ts
generated
vendored
Normal file
9
node_modules/@n8n/errors/dist/application.error.d.ts
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import type { Event } from '@sentry/node';
|
||||
import type { ErrorLevel, ReportingOptions } from './types';
|
||||
export declare class ApplicationError extends Error {
|
||||
level: ErrorLevel;
|
||||
readonly tags: NonNullable<Event['tags']>;
|
||||
readonly extra?: Event['extra'];
|
||||
readonly packageName?: string;
|
||||
constructor(message: string, { level, tags, extra, ...rest }?: ErrorOptions & ReportingOptions);
|
||||
}
|
||||
24
node_modules/@n8n/errors/dist/application.error.js
generated
vendored
Normal file
24
node_modules/@n8n/errors/dist/application.error.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ApplicationError = void 0;
|
||||
const callsites_1 = __importDefault(require("callsites"));
|
||||
class ApplicationError extends Error {
|
||||
constructor(message, { level, tags = {}, extra, ...rest } = {}) {
|
||||
super(message, rest);
|
||||
this.level = level ?? 'error';
|
||||
this.tags = tags;
|
||||
this.extra = extra;
|
||||
try {
|
||||
const filePath = (0, callsites_1.default)()[2].getFileName() ?? '';
|
||||
const match = /packages\/([^\/]+)\//.exec(filePath)?.[1];
|
||||
if (match)
|
||||
this.tags.packageName = match;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
exports.ApplicationError = ApplicationError;
|
||||
//# sourceMappingURL=application.error.js.map
|
||||
1
node_modules/@n8n/errors/dist/application.error.js.map
generated
vendored
Normal file
1
node_modules/@n8n/errors/dist/application.error.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"application.error.js","sourceRoot":"","sources":["../src/application.error.ts"],"names":[],"mappings":";;;;;;AACA,0DAAkC;AAOlC,MAAa,gBAAiB,SAAQ,KAAK;IAS1C,YACC,OAAe,EACf,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,KAAK,EAAE,GAAG,IAAI,KAAsC,EAAE;QAE1E,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,KAAK,IAAI,OAAO,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QAEnB,IAAI,CAAC;YACJ,MAAM,QAAQ,GAAG,IAAA,mBAAS,GAAE,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC;YAEpD,MAAM,KAAK,GAAG,sBAAsB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAEzD,IAAI,KAAK;gBAAE,IAAI,CAAC,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QAE1C,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACX,CAAC;CACD;AA3BD,4CA2BC"}
|
||||
1
node_modules/@n8n/errors/dist/build.tsbuildinfo
generated
vendored
Normal file
1
node_modules/@n8n/errors/dist/build.tsbuildinfo
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
2
node_modules/@n8n/errors/dist/index.d.ts
generated
vendored
Normal file
2
node_modules/@n8n/errors/dist/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export { ApplicationError } from './application.error';
|
||||
export type * from './types';
|
||||
6
node_modules/@n8n/errors/dist/index.js
generated
vendored
Normal file
6
node_modules/@n8n/errors/dist/index.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ApplicationError = void 0;
|
||||
var application_error_1 = require("./application.error");
|
||||
Object.defineProperty(exports, "ApplicationError", { enumerable: true, get: function () { return application_error_1.ApplicationError; } });
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
node_modules/@n8n/errors/dist/index.js.map
generated
vendored
Normal file
1
node_modules/@n8n/errors/dist/index.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,yDAAuD;AAA9C,qHAAA,gBAAgB,OAAA"}
|
||||
11
node_modules/@n8n/errors/dist/types.d.ts
generated
vendored
Normal file
11
node_modules/@n8n/errors/dist/types.d.ts
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import type { Event } from '@sentry/node';
|
||||
export type ErrorLevel = 'fatal' | 'error' | 'warning' | 'info';
|
||||
export type ErrorTags = NonNullable<Event['tags']>;
|
||||
export type ReportingOptions = {
|
||||
shouldReport?: boolean;
|
||||
shouldBeLogged?: boolean;
|
||||
level?: ErrorLevel;
|
||||
tags?: ErrorTags;
|
||||
extra?: Event['extra'];
|
||||
executionId?: string;
|
||||
};
|
||||
3
node_modules/@n8n/errors/dist/types.js
generated
vendored
Normal file
3
node_modules/@n8n/errors/dist/types.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
//# sourceMappingURL=types.js.map
|
||||
1
node_modules/@n8n/errors/dist/types.js.map
generated
vendored
Normal file
1
node_modules/@n8n/errors/dist/types.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
||||
42
node_modules/@n8n/errors/package.json
generated
vendored
Normal file
42
node_modules/@n8n/errors/package.json
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "@n8n/errors",
|
||||
"version": "0.5.0",
|
||||
"main": "dist/index.js",
|
||||
"module": "src/index.ts",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"LICENSE.md",
|
||||
"LICENSE_EE.md"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@sentry/node": "^9.42.1",
|
||||
"@n8n/typescript-config": "1.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"callsites": "3.1.0"
|
||||
},
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"homepage": "https://n8n.io",
|
||||
"author": {
|
||||
"name": "Jan Oberhauser",
|
||||
"email": "jan@n8n.io"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/n8n-io/n8n.git"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf dist .turbo",
|
||||
"dev": "pnpm watch",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome ci .",
|
||||
"lint": "eslint . --quiet",
|
||||
"lint:fix": "eslint . --fix",
|
||||
"watch": "tsc -p tsconfig.build.json --watch",
|
||||
"test": "echo \"WARNING: no test specified\" && exit 0",
|
||||
"test:dev": "echo \"WARNING: no test specified\" && exit 0"
|
||||
}
|
||||
}
|
||||
4
node_modules/@n8n/eslint-plugin-community-nodes/.turbo/turbo-build.log
generated
vendored
Normal file
4
node_modules/@n8n/eslint-plugin-community-nodes/.turbo/turbo-build.log
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
> @n8n/eslint-plugin-community-nodes@0.6.0 build /home/runner/work/n8n/n8n/packages/@n8n/eslint-plugin-community-nodes
|
||||
> tsc --project tsconfig.build.json
|
||||
|
||||
88
node_modules/@n8n/eslint-plugin-community-nodes/LICENSE.md
generated
vendored
Normal file
88
node_modules/@n8n/eslint-plugin-community-nodes/LICENSE.md
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
# License
|
||||
|
||||
Portions of this software are licensed as follows:
|
||||
|
||||
- Content of branches other than the main branch (i.e. "master") are not licensed.
|
||||
- Source code files that contain ".ee." in their filename or ".ee" in their dirname are NOT licensed under
|
||||
the Sustainable Use License.
|
||||
To use source code files that contain ".ee." in their filename or ".ee" in their dirname you must hold a
|
||||
valid n8n Enterprise License specifically allowing you access to such source code files and as defined
|
||||
in "LICENSE_EE.md".
|
||||
- All third party components incorporated into the n8n Software are licensed under the original license
|
||||
provided by the owner of the applicable component.
|
||||
- Content outside of the above mentioned files or restrictions is available under the "Sustainable Use
|
||||
License" as defined below.
|
||||
|
||||
## Sustainable Use License
|
||||
|
||||
Version 1.0
|
||||
|
||||
### Acceptance
|
||||
|
||||
By using the software, you agree to all of the terms and conditions below.
|
||||
|
||||
### Copyright License
|
||||
|
||||
The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license
|
||||
to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject
|
||||
to the limitations below.
|
||||
|
||||
### Limitations
|
||||
|
||||
You may use or modify the software only for your own internal business purposes or for non-commercial or
|
||||
personal use. You may distribute the software or provide it to others only if you do so free of charge for
|
||||
non-commercial purposes. You may not alter, remove, or obscure any licensing, copyright, or other notices of
|
||||
the licensor in the software. Any use of the licensor’s trademarks is subject to applicable law.
|
||||
|
||||
### Patents
|
||||
|
||||
The licensor grants you a license, under any patent claims the licensor can license, or becomes able to
|
||||
license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case
|
||||
subject to the limitations and conditions in this license. This license does not cover any patent claims that
|
||||
you cause to be infringed by modifications or additions to the software. If you or your company make any
|
||||
written claim that the software infringes or contributes to infringement of any patent, your patent license
|
||||
for the software granted under these terms ends immediately. If your company makes such a claim, your patent
|
||||
license ends immediately for work on behalf of your company.
|
||||
|
||||
### Notices
|
||||
|
||||
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these
|
||||
terms. If you modify the software, you must include in any modified copies of the software a prominent notice
|
||||
stating that you have modified the software.
|
||||
|
||||
### No Other Rights
|
||||
|
||||
These terms do not imply any licenses other than those expressly granted in these terms.
|
||||
|
||||
### Termination
|
||||
|
||||
If you use the software in violation of these terms, such use is not licensed, and your license will
|
||||
automatically terminate. If the licensor provides you with a notice of your violation, and you cease all
|
||||
violation of this license no later than 30 days after you receive that notice, your license will be reinstated
|
||||
retroactively. However, if you violate these terms after such reinstatement, any additional violation of these
|
||||
terms will cause your license to terminate automatically and permanently.
|
||||
|
||||
### No Liability
|
||||
|
||||
As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will
|
||||
not be liable to you for any damages arising out of these terms or the use or nature of the software, under
|
||||
any kind of legal claim.
|
||||
|
||||
### Definitions
|
||||
|
||||
The “licensor” is the entity offering these terms.
|
||||
|
||||
The “software” is the software the licensor makes available under these terms, including any portion of it.
|
||||
|
||||
“You” refers to the individual or entity agreeing to these terms.
|
||||
|
||||
“Your company” is any legal entity, sole proprietorship, or other kind of organization that you work for, plus
|
||||
all organizations that have control over, are under the control of, or are under common control with that
|
||||
organization. Control means ownership of substantially all the assets of an entity, or the power to direct its
|
||||
management and policies by vote, contract, or otherwise. Control can be direct or indirect.
|
||||
|
||||
“Your license” is the license granted to you for the software under these terms.
|
||||
|
||||
“Use” means anything you do with the software requiring your license.
|
||||
|
||||
“Trademark” means trademarks, service marks, and similar rights.
|
||||
27
node_modules/@n8n/eslint-plugin-community-nodes/LICENSE_EE.md
generated
vendored
Normal file
27
node_modules/@n8n/eslint-plugin-community-nodes/LICENSE_EE.md
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# The n8n Enterprise License (the “Enterprise License”)
|
||||
|
||||
Copyright (c) 2022-present n8n GmbH.
|
||||
|
||||
With regard to the n8n Software:
|
||||
|
||||
This software and associated documentation files (the "Software") may only be used in production, if
|
||||
you (and any entity that you represent) hold a valid n8n Enterprise license corresponding to your
|
||||
usage. Subject to the foregoing sentence, you are free to modify this Software and publish patches
|
||||
to the Software. You agree that n8n and/or its licensors (as applicable) retain all right, title and
|
||||
interest in and to all such modifications and/or patches, and all such modifications and/or patches
|
||||
may only be used, copied, modified, displayed, distributed, or otherwise exploited with a valid n8n
|
||||
Enterprise license for the corresponding usage. Notwithstanding the foregoing, you may copy and
|
||||
modify the Software for development and testing purposes, without requiring a subscription. You
|
||||
agree that n8n and/or its licensors (as applicable) retain all right, title and interest in and to
|
||||
all such modifications. You are not granted any other rights beyond what is expressly stated herein.
|
||||
Subject to the foregoing, it is forbidden to copy, merge, publish, distribute, sublicense, and/or
|
||||
sell the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For all third party components incorporated into the n8n Software, those components are licensed
|
||||
under the original license provided by the owner of the applicable component.
|
||||
60
node_modules/@n8n/eslint-plugin-community-nodes/README.md
generated
vendored
Normal file
60
node_modules/@n8n/eslint-plugin-community-nodes/README.md
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
# @n8n/eslint-plugin-community-nodes
|
||||
|
||||
ESLint plugin for linting n8n community node packages to ensure consistency and best practices.
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
npm install --save-dev eslint @n8n/eslint-plugin-community-nodes
|
||||
```
|
||||
|
||||
**Requires ESLint `>=9` and [flat config](https://eslint.org/docs/latest/use/configure/configuration-files)
|
||||
|
||||
## Usage
|
||||
|
||||
See the [ESLint docs](https://eslint.org/docs/latest/use/configure/configuration-files) for more information about extending config files.
|
||||
|
||||
### Recommended config
|
||||
|
||||
This plugin exports a `recommended` config that enforces good practices.
|
||||
|
||||
```js
|
||||
import { n8nCommunityNodesPlugin } from '@n8n/eslint-plugin-community-nodes';
|
||||
|
||||
export default [
|
||||
// …
|
||||
n8nCommunityNodesPlugin.configs.recommended,
|
||||
{
|
||||
rules: {
|
||||
'@n8n/community-nodes/node-usable-as-tool': 'warn',
|
||||
},
|
||||
},
|
||||
];
|
||||
```
|
||||
|
||||
## Rules
|
||||
|
||||
<!-- begin auto-generated rules list -->
|
||||
|
||||
💼 Configurations enabled in.\
|
||||
⚠️ Configurations set to warn in.\
|
||||
✅ Set in the `recommended` configuration.\
|
||||
☑️ Set in the `recommendedWithoutN8nCloudSupport` configuration.\
|
||||
🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\
|
||||
💡 Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
|
||||
|
||||
| Name | Description | 💼 | ⚠️ | 🔧 | 💡 |
|
||||
| :--------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------- | :--- | :--- | :- | :- |
|
||||
| [credential-documentation-url](docs/rules/credential-documentation-url.md) | Enforce valid credential documentationUrl format (URL or camelCase slug) | ✅ ☑️ | | | |
|
||||
| [credential-password-field](docs/rules/credential-password-field.md) | Ensure credential fields with sensitive names have typeOptions.password = true | ✅ ☑️ | | 🔧 | |
|
||||
| [credential-test-required](docs/rules/credential-test-required.md) | Ensure credentials have a credential test | ✅ ☑️ | | | 💡 |
|
||||
| [icon-validation](docs/rules/icon-validation.md) | Validate node and credential icon files exist, are SVG format, and light/dark icons are different | ✅ ☑️ | | | 💡 |
|
||||
| [no-credential-reuse](docs/rules/no-credential-reuse.md) | Prevent credential re-use security issues by ensuring nodes only reference credentials from the same package | ✅ ☑️ | | | 💡 |
|
||||
| [no-deprecated-workflow-functions](docs/rules/no-deprecated-workflow-functions.md) | Disallow usage of deprecated functions and types from n8n-workflow package | ✅ ☑️ | | | 💡 |
|
||||
| [no-restricted-globals](docs/rules/no-restricted-globals.md) | Disallow usage of restricted global variables in community nodes. | ✅ | | | |
|
||||
| [no-restricted-imports](docs/rules/no-restricted-imports.md) | Disallow usage of restricted imports in community nodes. | ✅ | | | |
|
||||
| [node-usable-as-tool](docs/rules/node-usable-as-tool.md) | Ensure node classes have usableAsTool property | ✅ ☑️ | | 🔧 | |
|
||||
| [package-name-convention](docs/rules/package-name-convention.md) | Enforce correct package naming convention for n8n community nodes | ✅ ☑️ | | | 💡 |
|
||||
| [resource-operation-pattern](docs/rules/resource-operation-pattern.md) | Enforce proper resource/operation pattern for better UX in n8n nodes | | ✅ ☑️ | | |
|
||||
|
||||
<!-- end auto-generated rules list -->
|
||||
177
node_modules/@n8n/eslint-plugin-community-nodes/dist/plugin.d.ts
generated
vendored
Normal file
177
node_modules/@n8n/eslint-plugin-community-nodes/dist/plugin.d.ts
generated
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
import type { ESLint } from 'eslint';
|
||||
import { rules } from './rules/index.js';
|
||||
declare const configs: {
|
||||
recommended: {
|
||||
ignores: string[];
|
||||
plugins: {
|
||||
'@n8n/community-nodes': {
|
||||
meta: {
|
||||
name: string;
|
||||
version: string;
|
||||
namespace: string;
|
||||
};
|
||||
rules: ESLint.Plugin["rules"];
|
||||
};
|
||||
};
|
||||
rules: {
|
||||
'@n8n/community-nodes/no-restricted-globals': "error";
|
||||
'@n8n/community-nodes/no-restricted-imports': "error";
|
||||
'@n8n/community-nodes/credential-password-field': "error";
|
||||
'@n8n/community-nodes/no-deprecated-workflow-functions': "error";
|
||||
'@n8n/community-nodes/node-usable-as-tool': "error";
|
||||
'@n8n/community-nodes/package-name-convention': "error";
|
||||
'@n8n/community-nodes/credential-test-required': "error";
|
||||
'@n8n/community-nodes/no-credential-reuse': "error";
|
||||
'@n8n/community-nodes/icon-validation': "error";
|
||||
'@n8n/community-nodes/resource-operation-pattern': "warn";
|
||||
'@n8n/community-nodes/credential-documentation-url': "error";
|
||||
};
|
||||
};
|
||||
recommendedWithoutN8nCloudSupport: {
|
||||
ignores: string[];
|
||||
plugins: {
|
||||
'@n8n/community-nodes': {
|
||||
meta: {
|
||||
name: string;
|
||||
version: string;
|
||||
namespace: string;
|
||||
};
|
||||
rules: ESLint.Plugin["rules"];
|
||||
};
|
||||
};
|
||||
rules: {
|
||||
'@n8n/community-nodes/credential-password-field': "error";
|
||||
'@n8n/community-nodes/no-deprecated-workflow-functions': "error";
|
||||
'@n8n/community-nodes/node-usable-as-tool': "error";
|
||||
'@n8n/community-nodes/package-name-convention': "error";
|
||||
'@n8n/community-nodes/credential-test-required': "error";
|
||||
'@n8n/community-nodes/no-credential-reuse': "error";
|
||||
'@n8n/community-nodes/icon-validation': "error";
|
||||
'@n8n/community-nodes/credential-documentation-url': "error";
|
||||
'@n8n/community-nodes/resource-operation-pattern': "warn";
|
||||
};
|
||||
};
|
||||
};
|
||||
declare const pluginWithConfigs: {
|
||||
configs: {
|
||||
recommended: {
|
||||
ignores: string[];
|
||||
plugins: {
|
||||
'@n8n/community-nodes': {
|
||||
meta: {
|
||||
name: string;
|
||||
version: string;
|
||||
namespace: string;
|
||||
};
|
||||
rules: ESLint.Plugin["rules"];
|
||||
};
|
||||
};
|
||||
rules: {
|
||||
'@n8n/community-nodes/no-restricted-globals': "error";
|
||||
'@n8n/community-nodes/no-restricted-imports': "error";
|
||||
'@n8n/community-nodes/credential-password-field': "error";
|
||||
'@n8n/community-nodes/no-deprecated-workflow-functions': "error";
|
||||
'@n8n/community-nodes/node-usable-as-tool': "error";
|
||||
'@n8n/community-nodes/package-name-convention': "error";
|
||||
'@n8n/community-nodes/credential-test-required': "error";
|
||||
'@n8n/community-nodes/no-credential-reuse': "error";
|
||||
'@n8n/community-nodes/icon-validation': "error";
|
||||
'@n8n/community-nodes/resource-operation-pattern': "warn";
|
||||
'@n8n/community-nodes/credential-documentation-url': "error";
|
||||
};
|
||||
};
|
||||
recommendedWithoutN8nCloudSupport: {
|
||||
ignores: string[];
|
||||
plugins: {
|
||||
'@n8n/community-nodes': {
|
||||
meta: {
|
||||
name: string;
|
||||
version: string;
|
||||
namespace: string;
|
||||
};
|
||||
rules: ESLint.Plugin["rules"];
|
||||
};
|
||||
};
|
||||
rules: {
|
||||
'@n8n/community-nodes/credential-password-field': "error";
|
||||
'@n8n/community-nodes/no-deprecated-workflow-functions': "error";
|
||||
'@n8n/community-nodes/node-usable-as-tool': "error";
|
||||
'@n8n/community-nodes/package-name-convention': "error";
|
||||
'@n8n/community-nodes/credential-test-required': "error";
|
||||
'@n8n/community-nodes/no-credential-reuse': "error";
|
||||
'@n8n/community-nodes/icon-validation': "error";
|
||||
'@n8n/community-nodes/credential-documentation-url': "error";
|
||||
'@n8n/community-nodes/resource-operation-pattern': "warn";
|
||||
};
|
||||
};
|
||||
};
|
||||
meta: {
|
||||
name: string;
|
||||
version: string;
|
||||
namespace: string;
|
||||
};
|
||||
rules: ESLint.Plugin["rules"];
|
||||
};
|
||||
declare const n8nCommunityNodesPlugin: {
|
||||
configs: {
|
||||
recommended: {
|
||||
ignores: string[];
|
||||
plugins: {
|
||||
'@n8n/community-nodes': {
|
||||
meta: {
|
||||
name: string;
|
||||
version: string;
|
||||
namespace: string;
|
||||
};
|
||||
rules: ESLint.Plugin["rules"];
|
||||
};
|
||||
};
|
||||
rules: {
|
||||
'@n8n/community-nodes/no-restricted-globals': "error";
|
||||
'@n8n/community-nodes/no-restricted-imports': "error";
|
||||
'@n8n/community-nodes/credential-password-field': "error";
|
||||
'@n8n/community-nodes/no-deprecated-workflow-functions': "error";
|
||||
'@n8n/community-nodes/node-usable-as-tool': "error";
|
||||
'@n8n/community-nodes/package-name-convention': "error";
|
||||
'@n8n/community-nodes/credential-test-required': "error";
|
||||
'@n8n/community-nodes/no-credential-reuse': "error";
|
||||
'@n8n/community-nodes/icon-validation': "error";
|
||||
'@n8n/community-nodes/resource-operation-pattern': "warn";
|
||||
'@n8n/community-nodes/credential-documentation-url': "error";
|
||||
};
|
||||
};
|
||||
recommendedWithoutN8nCloudSupport: {
|
||||
ignores: string[];
|
||||
plugins: {
|
||||
'@n8n/community-nodes': {
|
||||
meta: {
|
||||
name: string;
|
||||
version: string;
|
||||
namespace: string;
|
||||
};
|
||||
rules: ESLint.Plugin["rules"];
|
||||
};
|
||||
};
|
||||
rules: {
|
||||
'@n8n/community-nodes/credential-password-field': "error";
|
||||
'@n8n/community-nodes/no-deprecated-workflow-functions': "error";
|
||||
'@n8n/community-nodes/node-usable-as-tool': "error";
|
||||
'@n8n/community-nodes/package-name-convention': "error";
|
||||
'@n8n/community-nodes/credential-test-required': "error";
|
||||
'@n8n/community-nodes/no-credential-reuse': "error";
|
||||
'@n8n/community-nodes/icon-validation': "error";
|
||||
'@n8n/community-nodes/credential-documentation-url': "error";
|
||||
'@n8n/community-nodes/resource-operation-pattern': "warn";
|
||||
};
|
||||
};
|
||||
};
|
||||
meta: {
|
||||
name: string;
|
||||
version: string;
|
||||
namespace: string;
|
||||
};
|
||||
rules: ESLint.Plugin["rules"];
|
||||
};
|
||||
export default pluginWithConfigs;
|
||||
export { rules, configs, n8nCommunityNodesPlugin };
|
||||
//# sourceMappingURL=plugin.d.ts.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/plugin.d.ts.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/plugin.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAC;AAG7C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAYzC,QAAA,MAAM,OAAO;;;;;;;;;;uBAHI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;uBAAtB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;CAwCE,CAAC;AAE1C,QAAA,MAAM,iBAAiB;;;;;;;;;;;2BA1CN,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;2BAAtB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;WAAtB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;CA0CiC,CAAC;AAEzE,QAAA,MAAM,uBAAuB;;;;;;;;;;;2BA5CZ,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;2BAAtB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;WAAtB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;CA4CU,CAAC;AAClD,eAAe,iBAAiB,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
|
||||
54
node_modules/@n8n/eslint-plugin-community-nodes/dist/plugin.js
generated
vendored
Normal file
54
node_modules/@n8n/eslint-plugin-community-nodes/dist/plugin.js
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
import pkg from '../package.json' with { type: 'json' };
|
||||
import { rules } from './rules/index.js';
|
||||
const plugin = {
|
||||
meta: {
|
||||
name: pkg.name,
|
||||
version: pkg.version,
|
||||
namespace: '@n8n/community-nodes',
|
||||
},
|
||||
// @ts-expect-error Rules type does not match for typescript-eslint and eslint
|
||||
rules: rules,
|
||||
};
|
||||
const configs = {
|
||||
recommended: {
|
||||
ignores: ['eslint.config.{js,mjs,ts,mts}'],
|
||||
plugins: {
|
||||
'@n8n/community-nodes': plugin,
|
||||
},
|
||||
rules: {
|
||||
'@n8n/community-nodes/no-restricted-globals': 'error',
|
||||
'@n8n/community-nodes/no-restricted-imports': 'error',
|
||||
'@n8n/community-nodes/credential-password-field': 'error',
|
||||
'@n8n/community-nodes/no-deprecated-workflow-functions': 'error',
|
||||
'@n8n/community-nodes/node-usable-as-tool': 'error',
|
||||
'@n8n/community-nodes/package-name-convention': 'error',
|
||||
'@n8n/community-nodes/credential-test-required': 'error',
|
||||
'@n8n/community-nodes/no-credential-reuse': 'error',
|
||||
'@n8n/community-nodes/icon-validation': 'error',
|
||||
'@n8n/community-nodes/resource-operation-pattern': 'warn',
|
||||
'@n8n/community-nodes/credential-documentation-url': 'error',
|
||||
},
|
||||
},
|
||||
recommendedWithoutN8nCloudSupport: {
|
||||
ignores: ['eslint.config.{js,mjs,ts,mts}'],
|
||||
plugins: {
|
||||
'@n8n/community-nodes': plugin,
|
||||
},
|
||||
rules: {
|
||||
'@n8n/community-nodes/credential-password-field': 'error',
|
||||
'@n8n/community-nodes/no-deprecated-workflow-functions': 'error',
|
||||
'@n8n/community-nodes/node-usable-as-tool': 'error',
|
||||
'@n8n/community-nodes/package-name-convention': 'error',
|
||||
'@n8n/community-nodes/credential-test-required': 'error',
|
||||
'@n8n/community-nodes/no-credential-reuse': 'error',
|
||||
'@n8n/community-nodes/icon-validation': 'error',
|
||||
'@n8n/community-nodes/credential-documentation-url': 'error',
|
||||
'@n8n/community-nodes/resource-operation-pattern': 'warn',
|
||||
},
|
||||
},
|
||||
};
|
||||
const pluginWithConfigs = { ...plugin, configs };
|
||||
const n8nCommunityNodesPlugin = pluginWithConfigs;
|
||||
export default pluginWithConfigs;
|
||||
export { rules, configs, n8nCommunityNodesPlugin };
|
||||
//# sourceMappingURL=plugin.js.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/plugin.js.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/plugin.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,GAAG,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,MAAM,MAAM,GAAG;IACd,IAAI,EAAE;QACL,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,SAAS,EAAE,sBAAsB;KACjC;IACD,8EAA8E;IAC9E,KAAK,EAAE,KAA+B;CACd,CAAC;AAE1B,MAAM,OAAO,GAAG;IACf,WAAW,EAAE;QACZ,OAAO,EAAE,CAAC,+BAA+B,CAAC;QAC1C,OAAO,EAAE;YACR,sBAAsB,EAAE,MAAM;SAC9B;QACD,KAAK,EAAE;YACN,4CAA4C,EAAE,OAAO;YACrD,4CAA4C,EAAE,OAAO;YACrD,gDAAgD,EAAE,OAAO;YACzD,uDAAuD,EAAE,OAAO;YAChE,0CAA0C,EAAE,OAAO;YACnD,8CAA8C,EAAE,OAAO;YACvD,+CAA+C,EAAE,OAAO;YACxD,0CAA0C,EAAE,OAAO;YACnD,sCAAsC,EAAE,OAAO;YAC/C,iDAAiD,EAAE,MAAM;YACzD,mDAAmD,EAAE,OAAO;SAC5D;KACD;IACD,iCAAiC,EAAE;QAClC,OAAO,EAAE,CAAC,+BAA+B,CAAC;QAC1C,OAAO,EAAE;YACR,sBAAsB,EAAE,MAAM;SAC9B;QACD,KAAK,EAAE;YACN,gDAAgD,EAAE,OAAO;YACzD,uDAAuD,EAAE,OAAO;YAChE,0CAA0C,EAAE,OAAO;YACnD,8CAA8C,EAAE,OAAO;YACvD,+CAA+C,EAAE,OAAO;YACxD,0CAA0C,EAAE,OAAO;YACnD,sCAAsC,EAAE,OAAO;YAC/C,mDAAmD,EAAE,OAAO;YAC5D,iDAAiD,EAAE,MAAM;SACzD;KACD;CACuC,CAAC;AAE1C,MAAM,iBAAiB,GAAG,EAAE,GAAG,MAAM,EAAE,OAAO,EAA0B,CAAC;AAEzE,MAAM,uBAAuB,GAAG,iBAAiB,CAAC;AAClD,eAAe,iBAAiB,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
|
||||
7
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-documentation-url.d.ts
generated
vendored
Normal file
7
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-documentation-url.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
type RuleOptions = {
|
||||
allowUrls?: boolean;
|
||||
allowSlugs?: boolean;
|
||||
};
|
||||
export declare const CredentialDocumentationUrlRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidDocumentationUrl", [RuleOptions], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
export {};
|
||||
//# sourceMappingURL=credential-documentation-url.d.ts.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-documentation-url.d.ts.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-documentation-url.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"credential-documentation-url.d.ts","sourceRoot":"","sources":["../../src/rules/credential-documentation-url.ts"],"names":[],"mappings":"AAOA,KAAK,WAAW,GAAG;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AA+CF,eAAO,MAAM,8BAA8B,uKAuEzC,CAAC"}
|
||||
100
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-documentation-url.js
generated
vendored
Normal file
100
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-documentation-url.js
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
import { isCredentialTypeClass, findClassProperty, getStringLiteralValue, createRule, } from '../utils/index.js';
|
||||
const DEFAULT_OPTIONS = {
|
||||
allowUrls: true,
|
||||
allowSlugs: false,
|
||||
};
|
||||
function isValidUrl(value) {
|
||||
try {
|
||||
new URL(value);
|
||||
return true;
|
||||
}
|
||||
catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function isValidSlug(value) {
|
||||
// TODO: Remove this special case once these slugs are updated
|
||||
if (['google/service-account', 'google/oauth-single-service', 'google/oauth-generic'].includes(value))
|
||||
return true;
|
||||
return value.split('/').every((segment) => /^[a-z][a-z0-9]*$/.test(segment));
|
||||
}
|
||||
function hasOnlyCaseIssues(value) {
|
||||
return value.split('/').every((segment) => /^[a-zA-Z][a-zA-Z0-9]*$/.test(segment));
|
||||
}
|
||||
function validateDocumentationUrl(value, options) {
|
||||
return (!!options.allowUrls && isValidUrl(value)) || (!!options.allowSlugs && isValidSlug(value));
|
||||
}
|
||||
function getExpectedFormatsMessage(options) {
|
||||
const formats = [
|
||||
...(options.allowUrls ? ['a valid URL'] : []),
|
||||
...(options.allowSlugs ? ['a lowercase alphanumeric slug (can contain slashes)'] : []),
|
||||
];
|
||||
if (formats.length === 0)
|
||||
return 'a valid format (none configured)';
|
||||
if (formats.length === 1)
|
||||
return formats[0];
|
||||
return formats.slice(0, -1).join(', ') + ' or ' + formats[formats.length - 1];
|
||||
}
|
||||
export const CredentialDocumentationUrlRule = createRule({
|
||||
name: 'credential-documentation-url',
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Enforce valid credential documentationUrl format (URL or lowercase alphanumeric slug)',
|
||||
},
|
||||
messages: {
|
||||
invalidDocumentationUrl: "documentationUrl '{{ value }}' must be {{ expectedFormats }}",
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
allowUrls: {
|
||||
type: 'boolean',
|
||||
description: 'Whether to allow valid URLs',
|
||||
},
|
||||
allowSlugs: {
|
||||
type: 'boolean',
|
||||
description: 'Whether to allow lowercase alphanumeric slugs with slashes',
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
defaultOptions: [DEFAULT_OPTIONS],
|
||||
create(context, [options = {}]) {
|
||||
const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
|
||||
return {
|
||||
ClassDeclaration(node) {
|
||||
if (!isCredentialTypeClass(node)) {
|
||||
return;
|
||||
}
|
||||
const documentationUrlProperty = findClassProperty(node, 'documentationUrl');
|
||||
if (!documentationUrlProperty?.value) {
|
||||
return;
|
||||
}
|
||||
const documentationUrl = getStringLiteralValue(documentationUrlProperty.value);
|
||||
if (documentationUrl === null) {
|
||||
return;
|
||||
}
|
||||
if (!validateDocumentationUrl(documentationUrl, mergedOptions)) {
|
||||
const canAutofix = !!mergedOptions.allowSlugs && hasOnlyCaseIssues(documentationUrl);
|
||||
context.report({
|
||||
node: documentationUrlProperty.value,
|
||||
messageId: 'invalidDocumentationUrl',
|
||||
data: {
|
||||
value: documentationUrl,
|
||||
expectedFormats: getExpectedFormatsMessage(mergedOptions),
|
||||
},
|
||||
fix: canAutofix
|
||||
? (fixer) => fixer.replaceText(documentationUrlProperty.value, `'${documentationUrl.toLowerCase()}'`)
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
//# sourceMappingURL=credential-documentation-url.js.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-documentation-url.js.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-documentation-url.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"credential-documentation-url.js","sourceRoot":"","sources":["../../src/rules/credential-documentation-url.ts"],"names":[],"mappings":"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"}
|
||||
2
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-password-field.d.ts
generated
vendored
Normal file
2
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-password-field.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare const CredentialPasswordFieldRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingPasswordOption", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
//# sourceMappingURL=credential-password-field.d.ts.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-password-field.d.ts.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-password-field.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"credential-password-field.d.ts","sourceRoot":"","sources":["../../src/rules/credential-password-field.ts"],"names":[],"mappings":"AAoFA,eAAO,MAAM,2BAA2B,0JAwDtC,CAAC"}
|
||||
108
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-password-field.js
generated
vendored
Normal file
108
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-password-field.js
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
import { TSESTree } from '@typescript-eslint/types';
|
||||
import { isCredentialTypeClass, findClassProperty, findObjectProperty, getStringLiteralValue, getBooleanLiteralValue, createRule, } from '../utils/index.js';
|
||||
const SENSITIVE_PATTERNS = [
|
||||
'password',
|
||||
'secret',
|
||||
'token',
|
||||
'cert',
|
||||
'passphrase',
|
||||
'apikey',
|
||||
'secretkey',
|
||||
'privatekey',
|
||||
'authkey',
|
||||
];
|
||||
const NON_SENSITIVE_PATTERNS = ['url', 'pub', 'id'];
|
||||
function isSensitiveFieldName(name) {
|
||||
const lowerName = name.toLowerCase();
|
||||
if (NON_SENSITIVE_PATTERNS.some((pattern) => lowerName.includes(pattern))) {
|
||||
return false;
|
||||
}
|
||||
return SENSITIVE_PATTERNS.some((pattern) => lowerName.includes(pattern));
|
||||
}
|
||||
function hasPasswordTypeOption(element) {
|
||||
const typeOptionsProperty = findObjectProperty(element, 'typeOptions');
|
||||
if (typeOptionsProperty?.value.type !== TSESTree.AST_NODE_TYPES.ObjectExpression) {
|
||||
return false;
|
||||
}
|
||||
const passwordProperty = findObjectProperty(typeOptionsProperty.value, 'password');
|
||||
const passwordValue = passwordProperty ? getBooleanLiteralValue(passwordProperty.value) : null;
|
||||
return passwordValue === true;
|
||||
}
|
||||
function createPasswordFix(element, typeOptionsProperty) {
|
||||
return (fixer) => {
|
||||
if (typeOptionsProperty?.value.type === TSESTree.AST_NODE_TYPES.ObjectExpression) {
|
||||
const passwordProperty = findObjectProperty(typeOptionsProperty.value, 'password');
|
||||
if (passwordProperty) {
|
||||
return fixer.replaceText(passwordProperty.value, 'true');
|
||||
}
|
||||
const objectValue = typeOptionsProperty.value;
|
||||
if (objectValue.properties.length > 0) {
|
||||
const lastProperty = objectValue.properties[objectValue.properties.length - 1];
|
||||
if (lastProperty) {
|
||||
return fixer.insertTextAfter(lastProperty, ', password: true');
|
||||
}
|
||||
}
|
||||
else {
|
||||
const range = objectValue.range;
|
||||
if (range) {
|
||||
const openBrace = range[0] + 1;
|
||||
return fixer.insertTextAfterRange([openBrace, openBrace], ' password: true ');
|
||||
}
|
||||
}
|
||||
}
|
||||
const lastProperty = element.properties[element.properties.length - 1];
|
||||
if (lastProperty) {
|
||||
return fixer.insertTextAfter(lastProperty, ',\n\t\t\ttypeOptions: { password: true }');
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
||||
export const CredentialPasswordFieldRule = createRule({
|
||||
name: 'credential-password-field',
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Ensure credential fields with sensitive names have typeOptions.password = true',
|
||||
},
|
||||
messages: {
|
||||
missingPasswordOption: "Field '{{ fieldName }}' appears to be a sensitive field but is missing 'typeOptions: { password: true }'",
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [],
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
return {
|
||||
ClassDeclaration(node) {
|
||||
if (!isCredentialTypeClass(node)) {
|
||||
return;
|
||||
}
|
||||
const propertiesProperty = findClassProperty(node, 'properties');
|
||||
if (!propertiesProperty?.value ||
|
||||
propertiesProperty.value.type !== TSESTree.AST_NODE_TYPES.ArrayExpression) {
|
||||
return;
|
||||
}
|
||||
for (const element of propertiesProperty.value.elements) {
|
||||
if (element?.type !== TSESTree.AST_NODE_TYPES.ObjectExpression) {
|
||||
continue;
|
||||
}
|
||||
const nameProperty = findObjectProperty(element, 'name');
|
||||
const fieldName = nameProperty ? getStringLiteralValue(nameProperty.value) : null;
|
||||
if (!fieldName || !isSensitiveFieldName(fieldName)) {
|
||||
continue;
|
||||
}
|
||||
if (!hasPasswordTypeOption(element)) {
|
||||
const typeOptionsProperty = findObjectProperty(element, 'typeOptions');
|
||||
context.report({
|
||||
node: element,
|
||||
messageId: 'missingPasswordOption',
|
||||
data: { fieldName },
|
||||
fix: createPasswordFix(element, typeOptionsProperty),
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
//# sourceMappingURL=credential-password-field.js.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-password-field.js.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-password-field.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"credential-password-field.js","sourceRoot":"","sources":["../../src/rules/credential-password-field.ts"],"names":[],"mappings":"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"}
|
||||
2
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-test-required.d.ts
generated
vendored
Normal file
2
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-test-required.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare const CredentialTestRequiredRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"addTemplate" | "missingCredentialTest", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
//# sourceMappingURL=credential-test-required.d.ts.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-test-required.d.ts.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-test-required.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"credential-test-required.d.ts","sourceRoot":"","sources":["../../src/rules/credential-test-required.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,0BAA0B,0KAyHrC,CAAC"}
|
||||
117
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-test-required.js
generated
vendored
Normal file
117
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-test-required.js
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
import { dirname } from 'node:path';
|
||||
import { isCredentialTypeClass, findClassProperty, hasArrayLiteralValue, isFileType, getStringLiteralValue, findPackageJson, areAllCredentialUsagesTestedByNodes, createRule, } from '../utils/index.js';
|
||||
export const CredentialTestRequiredRule = createRule({
|
||||
name: 'credential-test-required',
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Ensure credentials have a credential test',
|
||||
},
|
||||
messages: {
|
||||
addTemplate: 'Add basic credential test template',
|
||||
missingCredentialTest: 'Credential class "{{ className }}" must have a test property or be tested by a node via testedBy',
|
||||
},
|
||||
schema: [],
|
||||
hasSuggestions: true,
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
if (!isFileType(context.filename, '.credentials.ts')) {
|
||||
return {};
|
||||
}
|
||||
let packageDir = null;
|
||||
const getPackageDir = () => {
|
||||
if (packageDir !== null) {
|
||||
return packageDir;
|
||||
}
|
||||
const packageJsonPath = findPackageJson(context.filename);
|
||||
if (!packageJsonPath) {
|
||||
packageDir = '';
|
||||
return packageDir;
|
||||
}
|
||||
packageDir = dirname(packageJsonPath);
|
||||
return packageDir;
|
||||
};
|
||||
return {
|
||||
ClassDeclaration(node) {
|
||||
if (!isCredentialTypeClass(node)) {
|
||||
return;
|
||||
}
|
||||
const extendsProperty = findClassProperty(node, 'extends');
|
||||
if (extendsProperty && hasArrayLiteralValue(extendsProperty, 'oAuth2Api')) {
|
||||
return;
|
||||
}
|
||||
const testProperty = findClassProperty(node, 'test');
|
||||
if (testProperty) {
|
||||
return;
|
||||
}
|
||||
const nameProperty = findClassProperty(node, 'name');
|
||||
if (!nameProperty) {
|
||||
return;
|
||||
}
|
||||
const credentialName = getStringLiteralValue(nameProperty.value);
|
||||
if (!credentialName) {
|
||||
return;
|
||||
}
|
||||
const pkgDir = getPackageDir();
|
||||
if (!pkgDir) {
|
||||
const suggestions = [];
|
||||
const testProperty = createCredentialTestTemplate();
|
||||
suggestions.push({
|
||||
messageId: 'addTemplate',
|
||||
fix(fixer) {
|
||||
const classBody = node.body.body;
|
||||
const lastProperty = classBody[classBody.length - 1];
|
||||
if (lastProperty) {
|
||||
return fixer.insertTextAfter(lastProperty, `\n\n${testProperty}`);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
});
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'missingCredentialTest',
|
||||
data: {
|
||||
className: node.id?.name ?? 'Unknown',
|
||||
},
|
||||
suggest: suggestions,
|
||||
});
|
||||
return;
|
||||
}
|
||||
const allUsagesTestedByNodes = areAllCredentialUsagesTestedByNodes(credentialName, pkgDir);
|
||||
if (!allUsagesTestedByNodes) {
|
||||
const suggestions = [];
|
||||
const testProperty = createCredentialTestTemplate();
|
||||
suggestions.push({
|
||||
messageId: 'addTemplate',
|
||||
fix(fixer) {
|
||||
const classBody = node.body.body;
|
||||
const lastProperty = classBody[classBody.length - 1];
|
||||
if (lastProperty) {
|
||||
return fixer.insertTextAfter(lastProperty, `\n\n${testProperty}`);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
});
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'missingCredentialTest',
|
||||
data: {
|
||||
className: node.id?.name ?? 'Unknown',
|
||||
},
|
||||
suggest: suggestions,
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
function createCredentialTestTemplate() {
|
||||
return `\ttest: ICredentialTestRequest = {
|
||||
\t\trequest: {
|
||||
\t\t\tmethod: 'GET',
|
||||
\t\t\turl: '={{$credentials.server}}/test', // Replace with actual endpoint
|
||||
\t\t},
|
||||
\t};`;
|
||||
}
|
||||
//# sourceMappingURL=credential-test-required.js.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-test-required.js.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/credential-test-required.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"credential-test-required.js","sourceRoot":"","sources":["../../src/rules/credential-test-required.ts"],"names":[],"mappings":"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"}
|
||||
2
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/icon-validation.d.ts
generated
vendored
Normal file
2
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/icon-validation.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare const IconValidationRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"iconFileNotFound" | "iconNotSvg" | "lightDarkSame" | "invalidIconPath" | "missingIcon" | "addPlaceholder" | "addFileProtocol" | "changeExtension" | "similarIcon", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
//# sourceMappingURL=icon-validation.d.ts.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/icon-validation.d.ts.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/icon-validation.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"icon-validation.d.ts","sourceRoot":"","sources":["../../src/rules/icon-validation.ts"],"names":[],"mappings":"AA4BA,eAAO,MAAM,kBAAkB,qSAkN7B,CAAC"}
|
||||
197
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/icon-validation.js
generated
vendored
Normal file
197
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/icon-validation.js
generated
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
import { TSESTree } from '@typescript-eslint/utils';
|
||||
import { dirname } from 'node:path';
|
||||
import { isNodeTypeClass, isCredentialTypeClass, findClassProperty, findObjectProperty, getStringLiteralValue, validateIconPath, findSimilarSvgFiles, isFileType, createRule, } from '../utils/index.js';
|
||||
const messages = {
|
||||
iconFileNotFound: 'Icon file "{{ iconPath }}" does not exist',
|
||||
iconNotSvg: 'Icon file "{{ iconPath }}" must be an SVG file (end with .svg)',
|
||||
lightDarkSame: 'Light and dark icons cannot be the same file. Both point to "{{ iconPath }}"',
|
||||
invalidIconPath: 'Icon path "{{ iconPath }}" must use file: protocol and be a string',
|
||||
missingIcon: 'Node/Credential class must have an icon property defined',
|
||||
addPlaceholder: 'Add icon property with placeholder',
|
||||
addFileProtocol: "Add 'file:' protocol to icon path",
|
||||
changeExtension: "Change icon extension to '.svg'",
|
||||
similarIcon: "Use existing icon '{{ suggestedName }}'",
|
||||
};
|
||||
export const IconValidationRule = createRule({
|
||||
name: 'icon-validation',
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Validate node and credential icon files exist, are SVG format, and light/dark icons are different',
|
||||
},
|
||||
messages,
|
||||
schema: [],
|
||||
hasSuggestions: true,
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
if (!isFileType(context.filename, '.node.ts') &&
|
||||
!isFileType(context.filename, '.credentials.ts')) {
|
||||
return {};
|
||||
}
|
||||
const validateIcon = (iconPath, node) => {
|
||||
if (!iconPath) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'invalidIconPath',
|
||||
data: { iconPath: iconPath ?? '' },
|
||||
});
|
||||
return false;
|
||||
}
|
||||
const currentDir = dirname(context.filename);
|
||||
const validation = validateIconPath(iconPath, currentDir);
|
||||
if (!validation.isFile) {
|
||||
const suggestions = [];
|
||||
if (!iconPath.startsWith('file:')) {
|
||||
suggestions.push({
|
||||
messageId: 'addFileProtocol',
|
||||
fix(fixer) {
|
||||
return fixer.replaceText(node, `"file:${iconPath}"`);
|
||||
},
|
||||
});
|
||||
}
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'invalidIconPath',
|
||||
data: { iconPath },
|
||||
suggest: suggestions,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (!validation.isSvg) {
|
||||
const relativePath = iconPath.replace(/^file:/, '');
|
||||
const suggestions = [];
|
||||
const pathWithoutExt = relativePath.replace(/\.[^/.]+$/, '');
|
||||
const svgPath = `${pathWithoutExt}.svg`;
|
||||
suggestions.push({
|
||||
messageId: 'changeExtension',
|
||||
fix(fixer) {
|
||||
return fixer.replaceText(node, `"file:${svgPath}"`);
|
||||
},
|
||||
});
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'iconNotSvg',
|
||||
data: { iconPath: relativePath },
|
||||
suggest: suggestions,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (!validation.exists) {
|
||||
const relativePath = iconPath.replace(/^file:/, '');
|
||||
const suggestions = [];
|
||||
// Find similar SVG files in the same directory
|
||||
const similarFiles = findSimilarSvgFiles(relativePath, currentDir);
|
||||
for (const similarFile of similarFiles) {
|
||||
suggestions.push({
|
||||
messageId: 'similarIcon',
|
||||
data: { suggestedName: similarFile },
|
||||
fix(fixer) {
|
||||
return fixer.replaceText(node, `"file:${similarFile}"`);
|
||||
},
|
||||
});
|
||||
}
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'iconFileNotFound',
|
||||
data: { iconPath: relativePath },
|
||||
suggest: suggestions,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
const validateIconValue = (iconValue) => {
|
||||
if (iconValue.type === TSESTree.AST_NODE_TYPES.Literal) {
|
||||
const iconPath = getStringLiteralValue(iconValue);
|
||||
validateIcon(iconPath, iconValue);
|
||||
}
|
||||
else if (iconValue.type === TSESTree.AST_NODE_TYPES.ObjectExpression) {
|
||||
const lightProperty = findObjectProperty(iconValue, 'light');
|
||||
const darkProperty = findObjectProperty(iconValue, 'dark');
|
||||
const lightPath = lightProperty ? getStringLiteralValue(lightProperty.value) : null;
|
||||
const darkPath = darkProperty ? getStringLiteralValue(darkProperty.value) : null;
|
||||
if (lightProperty) {
|
||||
validateIcon(lightPath, lightProperty.value);
|
||||
}
|
||||
if (darkProperty) {
|
||||
validateIcon(darkPath, darkProperty.value);
|
||||
}
|
||||
if (lightPath && darkPath && lightPath === darkPath && lightProperty) {
|
||||
context.report({
|
||||
node: lightProperty.value,
|
||||
messageId: 'lightDarkSame',
|
||||
data: { iconPath: lightPath.replace(/^file:/, '') },
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
return {
|
||||
ClassDeclaration(node) {
|
||||
const isNodeClass = isNodeTypeClass(node);
|
||||
const isCredentialClass = isCredentialTypeClass(node);
|
||||
if (!isNodeClass && !isCredentialClass) {
|
||||
return;
|
||||
}
|
||||
if (isNodeClass) {
|
||||
const descriptionProperty = findClassProperty(node, 'description');
|
||||
if (!descriptionProperty?.value ||
|
||||
descriptionProperty.value.type !== TSESTree.AST_NODE_TYPES.ObjectExpression) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'missingIcon',
|
||||
});
|
||||
return;
|
||||
}
|
||||
const descriptionValue = descriptionProperty.value;
|
||||
const iconProperty = findObjectProperty(descriptionValue, 'icon');
|
||||
if (!iconProperty) {
|
||||
const suggestions = [];
|
||||
suggestions.push({
|
||||
messageId: 'addPlaceholder',
|
||||
fix(fixer) {
|
||||
const lastProperty = descriptionValue.properties[descriptionValue.properties.length - 1];
|
||||
if (lastProperty) {
|
||||
return fixer.insertTextAfter(lastProperty, ',\n\t\ticon: "file:./icon.svg"');
|
||||
}
|
||||
return null;
|
||||
},
|
||||
});
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'missingIcon',
|
||||
suggest: suggestions,
|
||||
});
|
||||
return;
|
||||
}
|
||||
validateIconValue(iconProperty.value);
|
||||
}
|
||||
else if (isCredentialClass) {
|
||||
const iconProperty = findClassProperty(node, 'icon');
|
||||
if (!iconProperty?.value) {
|
||||
const suggestions = [];
|
||||
suggestions.push({
|
||||
messageId: 'addPlaceholder',
|
||||
fix(fixer) {
|
||||
const classBody = node.body.body;
|
||||
const lastProperty = classBody[classBody.length - 1];
|
||||
if (lastProperty) {
|
||||
return fixer.insertTextAfter(lastProperty, '\n\n\ticon = "file:./icon.svg";');
|
||||
}
|
||||
return null;
|
||||
},
|
||||
});
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'missingIcon',
|
||||
suggest: suggestions,
|
||||
});
|
||||
return;
|
||||
}
|
||||
validateIconValue(iconProperty.value);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
//# sourceMappingURL=icon-validation.js.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/icon-validation.js.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/icon-validation.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
17
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/index.d.ts
generated
vendored
Normal file
17
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
export declare const rules: {
|
||||
'no-restricted-globals': import("@typescript-eslint/utils/ts-eslint").RuleModule<"restrictedGlobal", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
'no-restricted-imports': import("@typescript-eslint/utils/ts-eslint").RuleModule<"restrictedImport" | "restrictedRequire" | "restrictedDynamicImport", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
'credential-password-field': import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingPasswordOption", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
'no-deprecated-workflow-functions': import("@typescript-eslint/utils/ts-eslint").RuleModule<"deprecatedRequestFunction" | "deprecatedFunction" | "deprecatedType" | "deprecatedWithoutReplacement" | "suggestReplaceFunction" | "suggestReplaceType", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
'node-usable-as-tool': import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingUsableAsTool", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
'package-name-convention': import("@typescript-eslint/utils/ts-eslint").RuleModule<"renameTo" | "invalidPackageName", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
'credential-test-required': import("@typescript-eslint/utils/ts-eslint").RuleModule<"addTemplate" | "missingCredentialTest", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
'no-credential-reuse': import("@typescript-eslint/utils/ts-eslint").RuleModule<"didYouMean" | "useAvailable" | "credentialNotInPackage", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
'icon-validation': import("@typescript-eslint/utils/ts-eslint").RuleModule<"iconFileNotFound" | "iconNotSvg" | "lightDarkSame" | "invalidIconPath" | "missingIcon" | "addPlaceholder" | "addFileProtocol" | "changeExtension" | "similarIcon", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
'resource-operation-pattern': import("@typescript-eslint/utils/ts-eslint").RuleModule<"tooManyOperationsWithoutResources", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
'credential-documentation-url': import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidDocumentationUrl", [{
|
||||
allowUrls?: boolean;
|
||||
allowSlugs?: boolean;
|
||||
}], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
};
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/index.d.ts.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/index.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;CAYuB,CAAC"}
|
||||
25
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/index.js
generated
vendored
Normal file
25
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/index.js
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
import { CredentialDocumentationUrlRule } from './credential-documentation-url.js';
|
||||
import { CredentialPasswordFieldRule } from './credential-password-field.js';
|
||||
import { CredentialTestRequiredRule } from './credential-test-required.js';
|
||||
import { IconValidationRule } from './icon-validation.js';
|
||||
import { NoCredentialReuseRule } from './no-credential-reuse.js';
|
||||
import { NoDeprecatedWorkflowFunctionsRule } from './no-deprecated-workflow-functions.js';
|
||||
import { NoRestrictedGlobalsRule } from './no-restricted-globals.js';
|
||||
import { NoRestrictedImportsRule } from './no-restricted-imports.js';
|
||||
import { NodeUsableAsToolRule } from './node-usable-as-tool.js';
|
||||
import { PackageNameConventionRule } from './package-name-convention.js';
|
||||
import { ResourceOperationPatternRule } from './resource-operation-pattern.js';
|
||||
export const rules = {
|
||||
'no-restricted-globals': NoRestrictedGlobalsRule,
|
||||
'no-restricted-imports': NoRestrictedImportsRule,
|
||||
'credential-password-field': CredentialPasswordFieldRule,
|
||||
'no-deprecated-workflow-functions': NoDeprecatedWorkflowFunctionsRule,
|
||||
'node-usable-as-tool': NodeUsableAsToolRule,
|
||||
'package-name-convention': PackageNameConventionRule,
|
||||
'credential-test-required': CredentialTestRequiredRule,
|
||||
'no-credential-reuse': NoCredentialReuseRule,
|
||||
'icon-validation': IconValidationRule,
|
||||
'resource-operation-pattern': ResourceOperationPatternRule,
|
||||
'credential-documentation-url': CredentialDocumentationUrlRule,
|
||||
};
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/index.js.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/index.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,8BAA8B,EAAE,MAAM,mCAAmC,CAAC;AACnF,OAAO,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAC;AAC7E,OAAO,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,iCAAiC,EAAE,MAAM,uCAAuC,CAAC;AAC1F,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAAE,4BAA4B,EAAE,MAAM,iCAAiC,CAAC;AAE/E,MAAM,CAAC,MAAM,KAAK,GAAG;IACpB,uBAAuB,EAAE,uBAAuB;IAChD,uBAAuB,EAAE,uBAAuB;IAChD,2BAA2B,EAAE,2BAA2B;IACxD,kCAAkC,EAAE,iCAAiC;IACrE,qBAAqB,EAAE,oBAAoB;IAC3C,yBAAyB,EAAE,yBAAyB;IACpD,0BAA0B,EAAE,0BAA0B;IACtD,qBAAqB,EAAE,qBAAqB;IAC5C,iBAAiB,EAAE,kBAAkB;IACrC,4BAA4B,EAAE,4BAA4B;IAC1D,8BAA8B,EAAE,8BAA8B;CACtB,CAAC"}
|
||||
2
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-credential-reuse.d.ts
generated
vendored
Normal file
2
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-credential-reuse.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare const NoCredentialReuseRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"didYouMean" | "useAvailable" | "credentialNotInPackage", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
//# sourceMappingURL=no-credential-reuse.d.ts.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-credential-reuse.d.ts.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-credential-reuse.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"no-credential-reuse.d.ts","sourceRoot":"","sources":["../../src/rules/no-credential-reuse.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,qBAAqB,2LAyGhC,CAAC"}
|
||||
91
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-credential-reuse.js
generated
vendored
Normal file
91
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-credential-reuse.js
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
import { TSESTree } from '@typescript-eslint/types';
|
||||
import { isNodeTypeClass, findClassProperty, findArrayLiteralProperty, extractCredentialNameFromArray, findPackageJson, readPackageJsonCredentials, isFileType, findSimilarStrings, createRule, } from '../utils/index.js';
|
||||
export const NoCredentialReuseRule = createRule({
|
||||
name: 'no-credential-reuse',
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Prevent credential re-use security issues by ensuring nodes only reference credentials from the same package',
|
||||
},
|
||||
messages: {
|
||||
didYouMean: "Did you mean '{{ suggestedName }}'?",
|
||||
useAvailable: "Use available credential '{{ suggestedName }}'",
|
||||
credentialNotInPackage: 'SECURITY: Node references credential "{{ credentialName }}" which is not defined in this package. This creates a security risk as it attempts to reuse credentials from other packages. Nodes can only use credentials from the same package as listed in package.json n8n.credentials field.',
|
||||
},
|
||||
schema: [],
|
||||
hasSuggestions: true,
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
if (!isFileType(context.filename, '.node.ts')) {
|
||||
return {};
|
||||
}
|
||||
let packageCredentials = null;
|
||||
const loadPackageCredentials = () => {
|
||||
if (packageCredentials !== null) {
|
||||
return packageCredentials;
|
||||
}
|
||||
const packageJsonPath = findPackageJson(context.filename);
|
||||
if (!packageJsonPath) {
|
||||
packageCredentials = new Set();
|
||||
return packageCredentials;
|
||||
}
|
||||
packageCredentials = readPackageJsonCredentials(packageJsonPath);
|
||||
return packageCredentials;
|
||||
};
|
||||
return {
|
||||
ClassDeclaration(node) {
|
||||
if (!isNodeTypeClass(node)) {
|
||||
return;
|
||||
}
|
||||
const descriptionProperty = findClassProperty(node, 'description');
|
||||
if (!descriptionProperty?.value ||
|
||||
descriptionProperty.value.type !== TSESTree.AST_NODE_TYPES.ObjectExpression) {
|
||||
return;
|
||||
}
|
||||
const credentialsArray = findArrayLiteralProperty(descriptionProperty.value, 'credentials');
|
||||
if (!credentialsArray) {
|
||||
return;
|
||||
}
|
||||
const allowedCredentials = loadPackageCredentials();
|
||||
credentialsArray.elements.forEach((element) => {
|
||||
const credentialInfo = extractCredentialNameFromArray(element);
|
||||
if (credentialInfo && !allowedCredentials.has(credentialInfo.name)) {
|
||||
const similarCredentials = findSimilarStrings(credentialInfo.name, allowedCredentials);
|
||||
const suggestions = [];
|
||||
for (const similarName of similarCredentials) {
|
||||
suggestions.push({
|
||||
messageId: 'didYouMean',
|
||||
data: { suggestedName: similarName },
|
||||
fix(fixer) {
|
||||
return fixer.replaceText(credentialInfo.node, `"${similarName}"`);
|
||||
},
|
||||
});
|
||||
}
|
||||
if (suggestions.length === 0 && allowedCredentials.size > 0) {
|
||||
const availableCredentials = Array.from(allowedCredentials).slice(0, 3);
|
||||
for (const availableName of availableCredentials) {
|
||||
suggestions.push({
|
||||
messageId: 'useAvailable',
|
||||
data: { suggestedName: availableName },
|
||||
fix(fixer) {
|
||||
return fixer.replaceText(credentialInfo.node, `"${availableName}"`);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
context.report({
|
||||
node: credentialInfo.node,
|
||||
messageId: 'credentialNotInPackage',
|
||||
data: {
|
||||
credentialName: credentialInfo.name,
|
||||
},
|
||||
suggest: suggestions,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
//# sourceMappingURL=no-credential-reuse.js.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-credential-reuse.js.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-credential-reuse.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"no-credential-reuse.js","sourceRoot":"","sources":["../../src/rules/no-credential-reuse.ts"],"names":[],"mappings":"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"}
|
||||
2
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-deprecated-workflow-functions.d.ts
generated
vendored
Normal file
2
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-deprecated-workflow-functions.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare const NoDeprecatedWorkflowFunctionsRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"deprecatedRequestFunction" | "deprecatedFunction" | "deprecatedType" | "deprecatedWithoutReplacement" | "suggestReplaceFunction" | "suggestReplaceType", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
//# sourceMappingURL=no-deprecated-workflow-functions.d.ts.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-deprecated-workflow-functions.d.ts.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-deprecated-workflow-functions.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"no-deprecated-workflow-functions.d.ts","sourceRoot":"","sources":["../../src/rules/no-deprecated-workflow-functions.ts"],"names":[],"mappings":"AA0BA,eAAO,MAAM,iCAAiC,2RA6I5C,CAAC"}
|
||||
172
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-deprecated-workflow-functions.js
generated
vendored
Normal file
172
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-deprecated-workflow-functions.js
generated
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
||||
import { createRule } from '../utils/index.js';
|
||||
const DEPRECATED_FUNCTIONS = {
|
||||
request: 'httpRequest',
|
||||
requestWithAuthentication: 'httpRequestWithAuthentication',
|
||||
requestOAuth1: 'httpRequestWithAuthentication',
|
||||
requestOAuth2: 'httpRequestWithAuthentication',
|
||||
copyBinaryFile: null,
|
||||
prepareOutputData: null,
|
||||
};
|
||||
const DEPRECATED_TYPES = {
|
||||
IRequestOptions: 'IHttpRequestOptions',
|
||||
};
|
||||
function isDeprecatedFunctionName(name) {
|
||||
return name in DEPRECATED_FUNCTIONS;
|
||||
}
|
||||
function isDeprecatedTypeName(name) {
|
||||
return name in DEPRECATED_TYPES;
|
||||
}
|
||||
export const NoDeprecatedWorkflowFunctionsRule = createRule({
|
||||
name: 'no-deprecated-workflow-functions',
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Disallow usage of deprecated functions and types from n8n-workflow package',
|
||||
},
|
||||
messages: {
|
||||
deprecatedRequestFunction: "'{{ functionName }}' is deprecated. Use '{{ replacement }}' instead for better authentication support and consistency.",
|
||||
deprecatedFunction: "'{{ functionName }}' is deprecated and should be avoided. {{ message }}",
|
||||
deprecatedType: "'{{ typeName }}' is deprecated. Use '{{ replacement }}' instead.",
|
||||
deprecatedWithoutReplacement: "'{{ functionName }}' is deprecated and should be removed or replaced with alternative implementation.",
|
||||
suggestReplaceFunction: "Replace '{{ functionName }}' with '{{ replacement }}'",
|
||||
suggestReplaceType: "Replace '{{ typeName }}' with '{{ replacement }}'",
|
||||
},
|
||||
schema: [],
|
||||
hasSuggestions: true,
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
const n8nWorkflowTypes = new Set();
|
||||
return {
|
||||
ImportDeclaration(node) {
|
||||
if (node.source.value === 'n8n-workflow') {
|
||||
node.specifiers.forEach((specifier) => {
|
||||
if (specifier.type === AST_NODE_TYPES.ImportSpecifier &&
|
||||
specifier.imported.type === AST_NODE_TYPES.Identifier) {
|
||||
n8nWorkflowTypes.add(specifier.local.name);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
MemberExpression(node) {
|
||||
if (node.property.type === AST_NODE_TYPES.Identifier &&
|
||||
isDeprecatedFunctionName(node.property.name)) {
|
||||
if (!isThisHelpersAccess(node)) {
|
||||
return;
|
||||
}
|
||||
const functionName = node.property.name;
|
||||
const replacement = DEPRECATED_FUNCTIONS[functionName];
|
||||
if (replacement) {
|
||||
const messageId = functionName.includes('request')
|
||||
? 'deprecatedRequestFunction'
|
||||
: 'deprecatedFunction';
|
||||
context.report({
|
||||
node: node.property,
|
||||
messageId,
|
||||
data: {
|
||||
functionName,
|
||||
replacement,
|
||||
message: getDeprecationMessage(functionName),
|
||||
},
|
||||
suggest: [
|
||||
{
|
||||
messageId: 'suggestReplaceFunction',
|
||||
data: { functionName, replacement },
|
||||
fix: (fixer) => fixer.replaceText(node.property, replacement),
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
else {
|
||||
context.report({
|
||||
node: node.property,
|
||||
messageId: 'deprecatedWithoutReplacement',
|
||||
data: {
|
||||
functionName,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
TSTypeReference(node) {
|
||||
if (node.typeName.type === AST_NODE_TYPES.Identifier &&
|
||||
isDeprecatedTypeName(node.typeName.name) &&
|
||||
n8nWorkflowTypes.has(node.typeName.name)) {
|
||||
const typeName = node.typeName.name;
|
||||
const replacement = DEPRECATED_TYPES[typeName];
|
||||
context.report({
|
||||
node: node.typeName,
|
||||
messageId: 'deprecatedType',
|
||||
data: {
|
||||
typeName,
|
||||
replacement,
|
||||
},
|
||||
suggest: [
|
||||
{
|
||||
messageId: 'suggestReplaceType',
|
||||
data: { typeName, replacement },
|
||||
fix: (fixer) => fixer.replaceText(node.typeName, replacement),
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
},
|
||||
ImportSpecifier(node) {
|
||||
// Check if this import is from n8n-workflow by looking at the parent ImportDeclaration
|
||||
const importDeclaration = node.parent;
|
||||
if (importDeclaration?.type === AST_NODE_TYPES.ImportDeclaration &&
|
||||
importDeclaration.source.value === 'n8n-workflow' &&
|
||||
node.imported.type === AST_NODE_TYPES.Identifier &&
|
||||
isDeprecatedTypeName(node.imported.name)) {
|
||||
const typeName = node.imported.name;
|
||||
const replacement = DEPRECATED_TYPES[typeName];
|
||||
context.report({
|
||||
node: node.imported,
|
||||
messageId: 'deprecatedType',
|
||||
data: {
|
||||
typeName,
|
||||
replacement,
|
||||
},
|
||||
suggest: [
|
||||
{
|
||||
messageId: 'suggestReplaceType',
|
||||
data: { typeName, replacement },
|
||||
fix: (fixer) => fixer.replaceText(node.imported, replacement),
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
/**
|
||||
* Check if the MemberExpression follows the this.helpers.* pattern
|
||||
*/
|
||||
function isThisHelpersAccess(node) {
|
||||
if (node.object?.type === AST_NODE_TYPES.MemberExpression) {
|
||||
const outerObject = node.object;
|
||||
return (outerObject.object?.type === AST_NODE_TYPES.ThisExpression &&
|
||||
outerObject.property?.type === AST_NODE_TYPES.Identifier &&
|
||||
outerObject.property.name === 'helpers');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function getDeprecationMessage(functionName) {
|
||||
switch (functionName) {
|
||||
case 'request':
|
||||
return 'Use httpRequest for better type safety and consistency.';
|
||||
case 'requestWithAuthentication':
|
||||
case 'requestOAuth1':
|
||||
case 'requestOAuth2':
|
||||
return 'Use httpRequestWithAuthentication which provides unified authentication handling.';
|
||||
case 'copyBinaryFile':
|
||||
return 'This function has been removed. Handle binary data directly.';
|
||||
case 'prepareOutputData':
|
||||
return 'This function is deprecated. Return data directly from execute method.';
|
||||
default:
|
||||
return 'This function is deprecated and should be avoided.';
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=no-deprecated-workflow-functions.js.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-deprecated-workflow-functions.js.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-deprecated-workflow-functions.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"no-deprecated-workflow-functions.js","sourceRoot":"","sources":["../../src/rules/no-deprecated-workflow-functions.ts"],"names":[],"mappings":"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"}
|
||||
3
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-restricted-globals.d.ts
generated
vendored
Normal file
3
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-restricted-globals.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import type { TSESLint } from '@typescript-eslint/utils';
|
||||
export declare const NoRestrictedGlobalsRule: TSESLint.RuleModule<"restrictedGlobal", [], unknown, TSESLint.RuleListener>;
|
||||
//# sourceMappingURL=no-restricted-globals.d.ts.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-restricted-globals.d.ts.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-restricted-globals.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"no-restricted-globals.d.ts","sourceRoot":"","sources":["../../src/rules/no-restricted-globals.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAkBzD,eAAO,MAAM,uBAAuB,6EAsDlC,CAAC"}
|
||||
60
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-restricted-globals.js
generated
vendored
Normal file
60
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-restricted-globals.js
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
import { TSESTree } from '@typescript-eslint/types';
|
||||
import { createRule } from '../utils/index.js';
|
||||
const restrictedGlobals = [
|
||||
'clearInterval',
|
||||
'clearTimeout',
|
||||
'global',
|
||||
'globalThis',
|
||||
'process',
|
||||
'setInterval',
|
||||
'setTimeout',
|
||||
'setImmediate',
|
||||
'clearImmediate',
|
||||
'__dirname',
|
||||
'__filename',
|
||||
];
|
||||
export const NoRestrictedGlobalsRule = createRule({
|
||||
name: 'no-restricted-globals',
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Disallow usage of restricted global variables in community nodes.',
|
||||
},
|
||||
messages: {
|
||||
restrictedGlobal: "Use of restricted global '{{ name }}' is not allowed",
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
function checkReference(ref, name) {
|
||||
const { parent } = ref.identifier;
|
||||
// Skip property access (like console.process - we want process.exit but not obj.process)
|
||||
if (parent?.type === TSESTree.AST_NODE_TYPES.MemberExpression &&
|
||||
parent.property === ref.identifier &&
|
||||
!parent.computed) {
|
||||
return;
|
||||
}
|
||||
context.report({
|
||||
node: ref.identifier,
|
||||
messageId: 'restrictedGlobal',
|
||||
data: { name },
|
||||
});
|
||||
}
|
||||
return {
|
||||
Program() {
|
||||
const globalScope = context.sourceCode.getScope(context.sourceCode.ast);
|
||||
const allReferences = [
|
||||
...globalScope.variables
|
||||
.filter((variable) => restrictedGlobals.includes(variable.name) && variable.defs.length === 0)
|
||||
.flatMap((variable) => variable.references.map((ref) => ({ ref, name: variable.name }))),
|
||||
...globalScope.through
|
||||
.filter((ref) => restrictedGlobals.includes(ref.identifier.name))
|
||||
.map((ref) => ({ ref, name: ref.identifier.name })),
|
||||
];
|
||||
allReferences.forEach(({ ref, name }) => checkReference(ref, name));
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
//# sourceMappingURL=no-restricted-globals.js.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-restricted-globals.js.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-restricted-globals.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"no-restricted-globals.js","sourceRoot":"","sources":["../../src/rules/no-restricted-globals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGpD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,iBAAiB,GAAG;IACzB,eAAe;IACf,cAAc;IACd,QAAQ;IACR,YAAY;IACZ,SAAS;IACT,aAAa;IACb,YAAY;IACZ,cAAc;IACd,gBAAgB;IAChB,WAAW;IACX,YAAY;CACZ,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG,UAAU,CAAC;IACjD,IAAI,EAAE,uBAAuB;IAC7B,IAAI,EAAE;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACL,WAAW,EAAE,mEAAmE;SAChF;QACD,QAAQ,EAAE;YACT,gBAAgB,EAAE,sDAAsD;SACxE;QACD,MAAM,EAAE,EAAE;KACV;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACb,SAAS,cAAc,CAAC,GAA6B,EAAE,IAAY;YAClE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,UAAU,CAAC;YAElC,yFAAyF;YACzF,IACC,MAAM,EAAE,IAAI,KAAK,QAAQ,CAAC,cAAc,CAAC,gBAAgB;gBACzD,MAAM,CAAC,QAAQ,KAAK,GAAG,CAAC,UAAU;gBAClC,CAAC,MAAM,CAAC,QAAQ,EACf,CAAC;gBACF,OAAO;YACR,CAAC;YAED,OAAO,CAAC,MAAM,CAAC;gBACd,IAAI,EAAE,GAAG,CAAC,UAAU;gBACpB,SAAS,EAAE,kBAAkB;gBAC7B,IAAI,EAAE,EAAE,IAAI,EAAE;aACd,CAAC,CAAC;QACJ,CAAC;QAED,OAAO;YACN,OAAO;gBACN,MAAM,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;gBAExE,MAAM,aAAa,GAAG;oBACrB,GAAG,WAAW,CAAC,SAAS;yBACtB,MAAM,CACN,CAAC,QAAQ,EAAE,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CACrF;yBACA,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CACrB,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAChE;oBACF,GAAG,WAAW,CAAC,OAAO;yBACpB,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;yBAChE,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;iBACpD,CAAC;gBAEF,aAAa,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;YACrE,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC,CAAC"}
|
||||
2
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-restricted-imports.d.ts
generated
vendored
Normal file
2
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-restricted-imports.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare const NoRestrictedImportsRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"restrictedImport" | "restrictedRequire" | "restrictedDynamicImport", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
//# sourceMappingURL=no-restricted-imports.d.ts.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-restricted-imports.d.ts.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-restricted-imports.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"no-restricted-imports.d.ts","sourceRoot":"","sources":["../../src/rules/no-restricted-imports.ts"],"names":[],"mappings":"AA4BA,eAAO,MAAM,uBAAuB,uMA8DlC,CAAC"}
|
||||
80
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-restricted-imports.js
generated
vendored
Normal file
80
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-restricted-imports.js
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
import { getModulePath, isDirectRequireCall, isRequireMemberCall, createRule, } from '../utils/index.js';
|
||||
const allowedModules = [
|
||||
'n8n-workflow',
|
||||
'lodash',
|
||||
'moment',
|
||||
'p-limit',
|
||||
'luxon',
|
||||
'zod',
|
||||
'crypto',
|
||||
'node:crypto',
|
||||
];
|
||||
const isModuleAllowed = (modulePath) => {
|
||||
if (modulePath.startsWith('./') || modulePath.startsWith('../'))
|
||||
return true;
|
||||
const moduleName = modulePath.startsWith('@')
|
||||
? modulePath.split('/').slice(0, 2).join('/')
|
||||
: modulePath.split('/')[0];
|
||||
if (!moduleName)
|
||||
return true;
|
||||
return allowedModules.includes(moduleName);
|
||||
};
|
||||
export const NoRestrictedImportsRule = createRule({
|
||||
name: 'no-restricted-imports',
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Disallow usage of restricted imports in community nodes.',
|
||||
},
|
||||
messages: {
|
||||
restrictedImport: "Import of '{{ modulePath }}' is not allowed. n8n Cloud does not allow community nodes with dependencies.",
|
||||
restrictedRequire: "Require of '{{ modulePath }}' is not allowed. n8n Cloud does not allow community nodes with dependencies.",
|
||||
restrictedDynamicImport: "Dynamic import of '{{ modulePath }}' is not allowed. n8n Cloud does not allow community nodes with dependencies.",
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
return {
|
||||
ImportDeclaration(node) {
|
||||
const modulePath = getModulePath(node.source);
|
||||
if (modulePath && !isModuleAllowed(modulePath)) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'restrictedImport',
|
||||
data: {
|
||||
modulePath,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
ImportExpression(node) {
|
||||
const modulePath = getModulePath(node.source);
|
||||
if (modulePath && !isModuleAllowed(modulePath)) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'restrictedDynamicImport',
|
||||
data: {
|
||||
modulePath,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
CallExpression(node) {
|
||||
if (isDirectRequireCall(node) || isRequireMemberCall(node)) {
|
||||
const modulePath = getModulePath(node.arguments[0] ?? null);
|
||||
if (modulePath && !isModuleAllowed(modulePath)) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'restrictedRequire',
|
||||
data: {
|
||||
modulePath,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
//# sourceMappingURL=no-restricted-imports.js.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-restricted-imports.js.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/no-restricted-imports.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"no-restricted-imports.js","sourceRoot":"","sources":["../../src/rules/no-restricted-imports.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,UAAU,GACV,MAAM,mBAAmB,CAAC;AAE3B,MAAM,cAAc,GAAG;IACtB,cAAc;IACd,QAAQ;IACR,QAAQ;IACR,SAAS;IACT,OAAO;IACP,KAAK;IACL,QAAQ;IACR,aAAa;CACb,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,UAAkB,EAAW,EAAE;IACvD,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAE7E,MAAM,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC;QAC5C,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QAC7C,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5B,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAC7B,OAAO,cAAc,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;AAC5C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG,UAAU,CAAC;IACjD,IAAI,EAAE,uBAAuB;IAC7B,IAAI,EAAE;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACL,WAAW,EAAE,0DAA0D;SACvE;QACD,QAAQ,EAAE;YACT,gBAAgB,EACf,0GAA0G;YAC3G,iBAAiB,EAChB,2GAA2G;YAC5G,uBAAuB,EACtB,kHAAkH;SACnH;QACD,MAAM,EAAE,EAAE;KACV;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACb,OAAO;YACN,iBAAiB,CAAC,IAAI;gBACrB,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAC9C,IAAI,UAAU,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE,CAAC;oBAChD,OAAO,CAAC,MAAM,CAAC;wBACd,IAAI;wBACJ,SAAS,EAAE,kBAAkB;wBAC7B,IAAI,EAAE;4BACL,UAAU;yBACV;qBACD,CAAC,CAAC;gBACJ,CAAC;YACF,CAAC;YAED,gBAAgB,CAAC,IAAI;gBACpB,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAC9C,IAAI,UAAU,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE,CAAC;oBAChD,OAAO,CAAC,MAAM,CAAC;wBACd,IAAI;wBACJ,SAAS,EAAE,yBAAyB;wBACpC,IAAI,EAAE;4BACL,UAAU;yBACV;qBACD,CAAC,CAAC;gBACJ,CAAC;YACF,CAAC;YAED,cAAc,CAAC,IAAI;gBAClB,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC5D,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;oBAC5D,IAAI,UAAU,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE,CAAC;wBAChD,OAAO,CAAC,MAAM,CAAC;4BACd,IAAI;4BACJ,SAAS,EAAE,mBAAmB;4BAC9B,IAAI,EAAE;gCACL,UAAU;6BACV;yBACD,CAAC,CAAC;oBACJ,CAAC;gBACF,CAAC;YACF,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC,CAAC"}
|
||||
2
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/node-usable-as-tool.d.ts
generated
vendored
Normal file
2
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/node-usable-as-tool.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare const NodeUsableAsToolRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingUsableAsTool", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
//# sourceMappingURL=node-usable-as-tool.d.ts.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/node-usable-as-tool.d.ts.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/node-usable-as-tool.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"node-usable-as-tool.d.ts","sourceRoot":"","sources":["../../src/rules/node-usable-as-tool.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,oBAAoB,wJA8D/B,CAAC"}
|
||||
58
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/node-usable-as-tool.js
generated
vendored
Normal file
58
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/node-usable-as-tool.js
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
import { TSESTree } from '@typescript-eslint/types';
|
||||
import { isNodeTypeClass, findClassProperty, findObjectProperty, createRule, } from '../utils/index.js';
|
||||
export const NodeUsableAsToolRule = createRule({
|
||||
name: 'node-usable-as-tool',
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Ensure node classes have usableAsTool property',
|
||||
},
|
||||
messages: {
|
||||
missingUsableAsTool: 'Node class should have usableAsTool property. When in doubt, set it to true.',
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [],
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
return {
|
||||
ClassDeclaration(node) {
|
||||
if (!isNodeTypeClass(node)) {
|
||||
return;
|
||||
}
|
||||
const descriptionProperty = findClassProperty(node, 'description');
|
||||
if (!descriptionProperty) {
|
||||
return;
|
||||
}
|
||||
const descriptionValue = descriptionProperty.value;
|
||||
if (descriptionValue?.type !== TSESTree.AST_NODE_TYPES.ObjectExpression) {
|
||||
return;
|
||||
}
|
||||
const usableAsToolProperty = findObjectProperty(descriptionValue, 'usableAsTool');
|
||||
if (!usableAsToolProperty) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'missingUsableAsTool',
|
||||
fix(fixer) {
|
||||
if (descriptionValue?.type === TSESTree.AST_NODE_TYPES.ObjectExpression) {
|
||||
const properties = descriptionValue.properties;
|
||||
if (properties.length === 0) {
|
||||
const openBrace = descriptionValue.range[0] + 1;
|
||||
return fixer.insertTextAfterRange([openBrace, openBrace], '\n\t\tusableAsTool: true,');
|
||||
}
|
||||
else {
|
||||
const lastProperty = properties.at(-1);
|
||||
if (lastProperty) {
|
||||
return fixer.insertTextAfter(lastProperty, ',\n\t\tusableAsTool: true');
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
//# sourceMappingURL=node-usable-as-tool.js.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/node-usable-as-tool.js.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/node-usable-as-tool.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"node-usable-as-tool.js","sourceRoot":"","sources":["../../src/rules/node-usable-as-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEpD,OAAO,EACN,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,GACV,MAAM,mBAAmB,CAAC;AAE3B,MAAM,CAAC,MAAM,oBAAoB,GAAG,UAAU,CAAC;IAC9C,IAAI,EAAE,qBAAqB;IAC3B,IAAI,EAAE;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACL,WAAW,EAAE,gDAAgD;SAC7D;QACD,QAAQ,EAAE;YACT,mBAAmB,EAClB,8EAA8E;SAC/E;QACD,OAAO,EAAE,MAAM;QACf,MAAM,EAAE,EAAE;KACV;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACb,OAAO;YACN,gBAAgB,CAAC,IAAI;gBACpB,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC5B,OAAO;gBACR,CAAC;gBAED,MAAM,mBAAmB,GAAG,iBAAiB,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;gBACnE,IAAI,CAAC,mBAAmB,EAAE,CAAC;oBAC1B,OAAO;gBACR,CAAC;gBAED,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,KAAK,CAAC;gBACnD,IAAI,gBAAgB,EAAE,IAAI,KAAK,QAAQ,CAAC,cAAc,CAAC,gBAAgB,EAAE,CAAC;oBACzE,OAAO;gBACR,CAAC;gBAED,MAAM,oBAAoB,GAAG,kBAAkB,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC;gBAElF,IAAI,CAAC,oBAAoB,EAAE,CAAC;oBAC3B,OAAO,CAAC,MAAM,CAAC;wBACd,IAAI;wBACJ,SAAS,EAAE,qBAAqB;wBAChC,GAAG,CAAC,KAAK;4BACR,IAAI,gBAAgB,EAAE,IAAI,KAAK,QAAQ,CAAC,cAAc,CAAC,gBAAgB,EAAE,CAAC;gCACzE,MAAM,UAAU,GAAG,gBAAgB,CAAC,UAAU,CAAC;gCAC/C,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oCAC7B,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;oCAChD,OAAO,KAAK,CAAC,oBAAoB,CAChC,CAAC,SAAS,EAAE,SAAS,CAAC,EACtB,2BAA2B,CAC3B,CAAC;gCACH,CAAC;qCAAM,CAAC;oCACP,MAAM,YAAY,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;oCACvC,IAAI,YAAY,EAAE,CAAC;wCAClB,OAAO,KAAK,CAAC,eAAe,CAAC,YAAY,EAAE,2BAA2B,CAAC,CAAC;oCACzE,CAAC;gCACF,CAAC;4BACF,CAAC;4BAED,OAAO,IAAI,CAAC;wBACb,CAAC;qBACD,CAAC,CAAC;gBACJ,CAAC;YACF,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC,CAAC"}
|
||||
2
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/package-name-convention.d.ts
generated
vendored
Normal file
2
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/package-name-convention.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare const PackageNameConventionRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"renameTo" | "invalidPackageName", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
//# sourceMappingURL=package-name-convention.d.ts.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/package-name-convention.d.ts.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/package-name-convention.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"package-name-convention.d.ts","sourceRoot":"","sources":["../../src/rules/package-name-convention.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,yBAAyB,oKA0EpC,CAAC"}
|
||||
88
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/package-name-convention.js
generated
vendored
Normal file
88
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/package-name-convention.js
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
||||
import { createRule } from '../utils/index.js';
|
||||
export const PackageNameConventionRule = createRule({
|
||||
name: 'package-name-convention',
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Enforce correct package naming convention for n8n community nodes',
|
||||
},
|
||||
messages: {
|
||||
renameTo: "Rename to '{{suggestedName}}'",
|
||||
invalidPackageName: 'Package name "{{ packageName }}" must follow the convention "n8n-nodes-[PACKAGE-NAME]" or "@[AUTHOR]/n8n-nodes-[PACKAGE-NAME]"',
|
||||
},
|
||||
schema: [],
|
||||
hasSuggestions: true,
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
if (!context.filename.endsWith('package.json')) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
ObjectExpression(node) {
|
||||
if (node.parent?.type === AST_NODE_TYPES.Property) {
|
||||
return;
|
||||
}
|
||||
const nameProperty = node.properties.find((property) => property.type === AST_NODE_TYPES.Property &&
|
||||
property.key.type === AST_NODE_TYPES.Literal &&
|
||||
property.key.value === 'name');
|
||||
if (!nameProperty || nameProperty.type !== AST_NODE_TYPES.Property) {
|
||||
return;
|
||||
}
|
||||
if (nameProperty.value.type !== AST_NODE_TYPES.Literal) {
|
||||
return;
|
||||
}
|
||||
const packageName = nameProperty.value.value;
|
||||
const packageNameStr = typeof packageName === 'string' ? packageName : null;
|
||||
if (!packageNameStr || !isValidPackageName(packageNameStr)) {
|
||||
const suggestions = [];
|
||||
// Generate package name suggestions if we have a valid string
|
||||
if (packageNameStr) {
|
||||
const suggestedNames = generatePackageNameSuggestions(packageNameStr);
|
||||
for (const suggestedName of suggestedNames) {
|
||||
suggestions.push({
|
||||
messageId: 'renameTo',
|
||||
data: { suggestedName },
|
||||
fix(fixer) {
|
||||
return fixer.replaceText(nameProperty.value, `"${suggestedName}"`);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
context.report({
|
||||
node: nameProperty,
|
||||
messageId: 'invalidPackageName',
|
||||
data: {
|
||||
packageName: packageNameStr ?? 'undefined',
|
||||
},
|
||||
suggest: suggestions,
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
function isValidPackageName(name) {
|
||||
const unscoped = /^n8n-nodes-.+$/;
|
||||
const scoped = /^@.+\/n8n-nodes-.+$/;
|
||||
return unscoped.test(name) || scoped.test(name);
|
||||
}
|
||||
function generatePackageNameSuggestions(invalidName) {
|
||||
const cleanName = (name) => {
|
||||
return name
|
||||
.replace(/^nodes?-?n8n-?/, '')
|
||||
.replace(/^n8n-/, '')
|
||||
.replace(/^nodes?-?/, '')
|
||||
.replace(/^node-/, '')
|
||||
.replace(/-nodes$/, '');
|
||||
};
|
||||
if (invalidName.startsWith('@')) {
|
||||
const [scope, packagePart] = invalidName.split('/');
|
||||
const clean = cleanName(packagePart ?? '');
|
||||
return clean ? [`${scope}/n8n-nodes-${clean}`] : [];
|
||||
}
|
||||
const clean = cleanName(invalidName);
|
||||
return clean ? [`n8n-nodes-${clean}`] : [];
|
||||
}
|
||||
//# sourceMappingURL=package-name-convention.js.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/package-name-convention.js.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/package-name-convention.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"package-name-convention.js","sourceRoot":"","sources":["../../src/rules/package-name-convention.ts"],"names":[],"mappings":"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"}
|
||||
2
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/resource-operation-pattern.d.ts
generated
vendored
Normal file
2
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/resource-operation-pattern.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare const ResourceOperationPatternRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"tooManyOperationsWithoutResources", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
||||
//# sourceMappingURL=resource-operation-pattern.d.ts.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/resource-operation-pattern.d.ts.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/resource-operation-pattern.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"resource-operation-pattern.d.ts","sourceRoot":"","sources":["../../src/rules/resource-operation-pattern.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,4BAA4B,sKA2FvC,CAAC"}
|
||||
79
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/resource-operation-pattern.js
generated
vendored
Normal file
79
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/resource-operation-pattern.js
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
||||
import { isNodeTypeClass, findClassProperty, findObjectProperty, getStringLiteralValue, isFileType, createRule, } from '../utils/index.js';
|
||||
export const ResourceOperationPatternRule = createRule({
|
||||
name: 'resource-operation-pattern',
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Enforce proper resource/operation pattern for better UX in n8n nodes',
|
||||
},
|
||||
messages: {
|
||||
tooManyOperationsWithoutResources: 'Node has {{ operationCount }} operations without resources. Use resources to organize operations when there are more than 5 operations.',
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
if (!isFileType(context.filename, '.node.ts')) {
|
||||
return {};
|
||||
}
|
||||
const analyzeNodeDescription = (descriptionValue) => {
|
||||
if (!descriptionValue || descriptionValue.type !== AST_NODE_TYPES.ObjectExpression) {
|
||||
return;
|
||||
}
|
||||
const propertiesProperty = findObjectProperty(descriptionValue, 'properties');
|
||||
if (!propertiesProperty?.value ||
|
||||
propertiesProperty.value.type !== AST_NODE_TYPES.ArrayExpression) {
|
||||
return;
|
||||
}
|
||||
const propertiesArray = propertiesProperty.value;
|
||||
let hasResources = false;
|
||||
let operationCount = 0;
|
||||
let operationNode = null;
|
||||
for (const property of propertiesArray.elements) {
|
||||
if (!property || property.type !== AST_NODE_TYPES.ObjectExpression) {
|
||||
continue;
|
||||
}
|
||||
const nameProperty = findObjectProperty(property, 'name');
|
||||
const typeProperty = findObjectProperty(property, 'type');
|
||||
const name = nameProperty ? getStringLiteralValue(nameProperty.value) : null;
|
||||
const type = typeProperty ? getStringLiteralValue(typeProperty.value) : null;
|
||||
if (!name || !type) {
|
||||
continue;
|
||||
}
|
||||
if (name === 'resource' && type === 'options') {
|
||||
hasResources = true;
|
||||
}
|
||||
if (name === 'operation' && type === 'options') {
|
||||
operationNode = property;
|
||||
const optionsProperty = findObjectProperty(property, 'options');
|
||||
if (optionsProperty?.value?.type === AST_NODE_TYPES.ArrayExpression) {
|
||||
operationCount = optionsProperty.value.elements.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (operationCount > 5 && !hasResources && operationNode) {
|
||||
context.report({
|
||||
node: operationNode,
|
||||
messageId: 'tooManyOperationsWithoutResources',
|
||||
data: {
|
||||
operationCount: operationCount.toString(),
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
return {
|
||||
ClassDeclaration(node) {
|
||||
if (!isNodeTypeClass(node)) {
|
||||
return;
|
||||
}
|
||||
const descriptionProperty = findClassProperty(node, 'description');
|
||||
if (!descriptionProperty) {
|
||||
return;
|
||||
}
|
||||
analyzeNodeDescription(descriptionProperty.value);
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
//# sourceMappingURL=resource-operation-pattern.js.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/resource-operation-pattern.js.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/resource-operation-pattern.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"resource-operation-pattern.js","sourceRoot":"","sources":["../../src/rules/resource-operation-pattern.ts"],"names":[],"mappings":"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"}
|
||||
26
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/ast-utils.d.ts
generated
vendored
Normal file
26
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/ast-utils.d.ts
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
import type { TSESTree } from '@typescript-eslint/utils';
|
||||
export declare function isNodeTypeClass(node: TSESTree.ClassDeclaration): boolean;
|
||||
export declare function isCredentialTypeClass(node: TSESTree.ClassDeclaration): boolean;
|
||||
export declare function findClassProperty(node: TSESTree.ClassDeclaration, propertyName: string): TSESTree.PropertyDefinition | null;
|
||||
export declare function findObjectProperty(obj: TSESTree.ObjectExpression, propertyName: string): TSESTree.Property | null;
|
||||
export declare function getLiteralValue(node: TSESTree.Node | null): string | boolean | number | null;
|
||||
export declare function getStringLiteralValue(node: TSESTree.Node | null): string | null;
|
||||
export declare function getModulePath(node: TSESTree.Node | null): string | null;
|
||||
export declare function getBooleanLiteralValue(node: TSESTree.Node | null): boolean | null;
|
||||
export declare function findArrayLiteralProperty(obj: TSESTree.ObjectExpression, propertyName: string): TSESTree.ArrayExpression | null;
|
||||
export declare function hasArrayLiteralValue(node: TSESTree.PropertyDefinition, searchValue: string): boolean;
|
||||
export declare function getTopLevelObjectInJson(node: TSESTree.ObjectExpression): TSESTree.ObjectExpression | null;
|
||||
export declare function isFileType(filename: string, extension: string): boolean;
|
||||
export declare function isDirectRequireCall(node: TSESTree.CallExpression): boolean;
|
||||
export declare function isRequireMemberCall(node: TSESTree.CallExpression): boolean;
|
||||
export declare function extractCredentialInfoFromArray(element: TSESTree.ArrayExpression['elements'][number]): {
|
||||
name: string;
|
||||
testedBy?: string;
|
||||
node: TSESTree.Node;
|
||||
} | null;
|
||||
export declare function extractCredentialNameFromArray(element: TSESTree.ArrayExpression['elements'][number]): {
|
||||
name: string;
|
||||
node: TSESTree.Node;
|
||||
} | null;
|
||||
export declare function findSimilarStrings(target: string, candidates: Set<string>, maxDistance?: number, maxResults?: number): string[];
|
||||
//# sourceMappingURL=ast-utils.d.ts.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/ast-utils.d.ts.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/ast-utils.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"ast-utils.d.ts","sourceRoot":"","sources":["../../src/utils/ast-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAezD,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,CAAC,gBAAgB,GAAG,OAAO,CAUxE;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,QAAQ,CAAC,gBAAgB,GAAG,OAAO,CAE9E;AAED,wBAAgB,iBAAiB,CAChC,IAAI,EAAE,QAAQ,CAAC,gBAAgB,EAC/B,YAAY,EAAE,MAAM,GAClB,QAAQ,CAAC,kBAAkB,GAAG,IAAI,CAQpC;AAED,wBAAgB,kBAAkB,CACjC,GAAG,EAAE,QAAQ,CAAC,gBAAgB,EAC9B,YAAY,EAAE,MAAM,GAClB,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAQ1B;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,GAAG,IAAI,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,CAK5F;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAG/E;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAevE;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,GAAG,IAAI,GAAG,OAAO,GAAG,IAAI,CAGjF;AAED,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,QAAQ,CAAC,gBAAgB,EAC9B,YAAY,EAAE,MAAM,GAClB,QAAQ,CAAC,eAAe,GAAG,IAAI,CAMjC;AAED,wBAAgB,oBAAoB,CACnC,IAAI,EAAE,QAAQ,CAAC,kBAAkB,EACjC,WAAW,EAAE,MAAM,GACjB,OAAO,CAST;AAED,wBAAgB,uBAAuB,CACtC,IAAI,EAAE,QAAQ,CAAC,gBAAgB,GAC7B,QAAQ,CAAC,gBAAgB,GAAG,IAAI,CAKlC;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAEvE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,CAAC,cAAc,GAAG,OAAO,CAM1E;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,CAAC,cAAc,GAAG,OAAO,CAO1E;AAED,wBAAgB,8BAA8B,CAC7C,OAAO,EAAE,QAAQ,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,GACnD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAA;CAAE,GAAG,IAAI,CA6BjE;AAED,wBAAgB,8BAA8B,CAC7C,OAAO,EAAE,QAAQ,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,GACnD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAA;CAAE,GAAG,IAAI,CAG9C;AAED,wBAAgB,kBAAkB,CACjC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,EACvB,WAAW,GAAE,MAAU,EACvB,UAAU,GAAE,MAAU,GACpB,MAAM,EAAE,CAeV"}
|
||||
135
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/ast-utils.js
generated
vendored
Normal file
135
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/ast-utils.js
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
||||
import { distance } from 'fastest-levenshtein';
|
||||
function implementsInterface(node, interfaceName) {
|
||||
return (node.implements?.some((impl) => impl.type === AST_NODE_TYPES.TSClassImplements &&
|
||||
impl.expression.type === AST_NODE_TYPES.Identifier &&
|
||||
impl.expression.name === interfaceName) ?? false);
|
||||
}
|
||||
export function isNodeTypeClass(node) {
|
||||
if (implementsInterface(node, 'INodeType')) {
|
||||
return true;
|
||||
}
|
||||
if (node.superClass?.type === AST_NODE_TYPES.Identifier && node.superClass.name === 'Node') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
export function isCredentialTypeClass(node) {
|
||||
return implementsInterface(node, 'ICredentialType');
|
||||
}
|
||||
export function findClassProperty(node, propertyName) {
|
||||
const property = node.body.body.find((member) => member.type === AST_NODE_TYPES.PropertyDefinition &&
|
||||
member.key?.type === AST_NODE_TYPES.Identifier &&
|
||||
member.key.name === propertyName);
|
||||
return property?.type === AST_NODE_TYPES.PropertyDefinition ? property : null;
|
||||
}
|
||||
export function findObjectProperty(obj, propertyName) {
|
||||
const property = obj.properties.find((prop) => prop.type === AST_NODE_TYPES.Property &&
|
||||
prop.key.type === AST_NODE_TYPES.Identifier &&
|
||||
prop.key.name === propertyName);
|
||||
return property?.type === AST_NODE_TYPES.Property ? property : null;
|
||||
}
|
||||
export function getLiteralValue(node) {
|
||||
if (node?.type === AST_NODE_TYPES.Literal) {
|
||||
return node.value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
export function getStringLiteralValue(node) {
|
||||
const value = getLiteralValue(node);
|
||||
return typeof value === 'string' ? value : null;
|
||||
}
|
||||
export function getModulePath(node) {
|
||||
const stringValue = getStringLiteralValue(node);
|
||||
if (stringValue) {
|
||||
return stringValue;
|
||||
}
|
||||
if (node?.type === AST_NODE_TYPES.TemplateLiteral &&
|
||||
node.expressions.length === 0 &&
|
||||
node.quasis.length === 1) {
|
||||
return node.quasis[0]?.value.cooked ?? null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
export function getBooleanLiteralValue(node) {
|
||||
const value = getLiteralValue(node);
|
||||
return typeof value === 'boolean' ? value : null;
|
||||
}
|
||||
export function findArrayLiteralProperty(obj, propertyName) {
|
||||
const property = findObjectProperty(obj, propertyName);
|
||||
if (property?.value.type === AST_NODE_TYPES.ArrayExpression) {
|
||||
return property.value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
export function hasArrayLiteralValue(node, searchValue) {
|
||||
if (node.value?.type !== AST_NODE_TYPES.ArrayExpression)
|
||||
return false;
|
||||
return node.value.elements.some((element) => element?.type === AST_NODE_TYPES.Literal &&
|
||||
typeof element.value === 'string' &&
|
||||
element.value === searchValue);
|
||||
}
|
||||
export function getTopLevelObjectInJson(node) {
|
||||
if (node.parent?.type === AST_NODE_TYPES.Property) {
|
||||
return null;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
export function isFileType(filename, extension) {
|
||||
return filename.endsWith(extension);
|
||||
}
|
||||
export function isDirectRequireCall(node) {
|
||||
return (node.callee.type === AST_NODE_TYPES.Identifier &&
|
||||
node.callee.name === 'require' &&
|
||||
node.arguments.length > 0);
|
||||
}
|
||||
export function isRequireMemberCall(node) {
|
||||
return (node.callee.type === AST_NODE_TYPES.MemberExpression &&
|
||||
node.callee.object.type === AST_NODE_TYPES.Identifier &&
|
||||
node.callee.object.name === 'require' &&
|
||||
node.arguments.length > 0);
|
||||
}
|
||||
export function extractCredentialInfoFromArray(element) {
|
||||
if (!element)
|
||||
return null;
|
||||
const stringValue = getStringLiteralValue(element);
|
||||
if (stringValue) {
|
||||
return { name: stringValue, node: element };
|
||||
}
|
||||
if (element.type === AST_NODE_TYPES.ObjectExpression) {
|
||||
const nameProperty = findObjectProperty(element, 'name');
|
||||
const testedByProperty = findObjectProperty(element, 'testedBy');
|
||||
if (nameProperty) {
|
||||
const nameValue = getStringLiteralValue(nameProperty.value);
|
||||
const testedByValue = testedByProperty
|
||||
? getStringLiteralValue(testedByProperty.value)
|
||||
: undefined;
|
||||
if (nameValue) {
|
||||
return {
|
||||
name: nameValue,
|
||||
testedBy: testedByValue ?? undefined,
|
||||
node: nameProperty.value,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
export function extractCredentialNameFromArray(element) {
|
||||
const info = extractCredentialInfoFromArray(element);
|
||||
return info ? { name: info.name, node: info.node } : null;
|
||||
}
|
||||
export function findSimilarStrings(target, candidates, maxDistance = 3, maxResults = 3) {
|
||||
const matches = [];
|
||||
for (const candidate of candidates) {
|
||||
const levenshteinDistance = distance(target.toLowerCase(), candidate.toLowerCase());
|
||||
if (levenshteinDistance <= maxDistance) {
|
||||
matches.push({ name: candidate, distance: levenshteinDistance });
|
||||
}
|
||||
}
|
||||
return matches
|
||||
.sort((a, b) => a.distance - b.distance)
|
||||
.slice(0, maxResults)
|
||||
.map((match) => match.name);
|
||||
}
|
||||
//# sourceMappingURL=ast-utils.js.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/ast-utils.js.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/ast-utils.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
26
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/file-utils.d.ts
generated
vendored
Normal file
26
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/file-utils.d.ts
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Checks if the given childPath is contained within the parentPath. Resolves
|
||||
* the paths before comparing them, so that relative paths are also supported.
|
||||
*/
|
||||
export declare function isContainedWithin(parentPath: string, childPath: string): boolean;
|
||||
/**
|
||||
* Joins the given paths to the parentPath, ensuring that the resulting path
|
||||
* is still contained within the parentPath. If not, it throws an error to
|
||||
* prevent path traversal vulnerabilities.
|
||||
*
|
||||
* @throws {UnexpectedError} If the resulting path is not contained within the parentPath.
|
||||
*/
|
||||
export declare function safeJoinPath(parentPath: string, ...paths: string[]): string;
|
||||
export declare function findPackageJson(startPath: string): string | null;
|
||||
export declare function readPackageJsonCredentials(packageJsonPath: string): Set<string>;
|
||||
export declare function extractCredentialNameFromFile(credentialFilePath: string): string | null;
|
||||
export declare function validateIconPath(iconPath: string, baseDir: string): {
|
||||
isValid: boolean;
|
||||
isFile: boolean;
|
||||
isSvg: boolean;
|
||||
exists: boolean;
|
||||
};
|
||||
export declare function readPackageJsonNodes(packageJsonPath: string): string[];
|
||||
export declare function areAllCredentialUsagesTestedByNodes(credentialName: string, packageDir: string): boolean;
|
||||
export declare function findSimilarSvgFiles(targetPath: string, baseDir: string): string[];
|
||||
//# sourceMappingURL=file-utils.d.ts.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/file-utils.d.ts.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/file-utils.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"file-utils.d.ts","sourceRoot":"","sources":["../../src/utils/file-utils.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAShF;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAU3E;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAahE;AAyCD,wBAAgB,0BAA0B,CAAC,eAAe,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAkB/E;AAED,wBAAgB,6BAA6B,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA4BvF;AAED,wBAAgB,gBAAgB,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACb;IACF,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;CAChB,CAcA;AAED,wBAAgB,oBAAoB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,EAAE,CAItE;AAED,wBAAgB,mCAAmC,CAClD,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,GAChB,OAAO,CAoBT;AA+DD,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAuBjF"}
|
||||
221
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/file-utils.js
generated
vendored
Normal file
221
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/file-utils.js
generated
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
import { parse, simpleTraverse, AST_NODE_TYPES } from '@typescript-eslint/typescript-estree';
|
||||
import { readFileSync, existsSync, readdirSync } from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import { dirname, parse as parsePath } from 'node:path';
|
||||
import { isCredentialTypeClass, isNodeTypeClass, findClassProperty, getStringLiteralValue, findArrayLiteralProperty, extractCredentialInfoFromArray, findSimilarStrings, } from './ast-utils.js';
|
||||
/**
|
||||
* Checks if the given childPath is contained within the parentPath. Resolves
|
||||
* the paths before comparing them, so that relative paths are also supported.
|
||||
*/
|
||||
export function isContainedWithin(parentPath, childPath) {
|
||||
parentPath = path.resolve(parentPath);
|
||||
childPath = path.resolve(childPath);
|
||||
if (parentPath === childPath) {
|
||||
return true;
|
||||
}
|
||||
return childPath.startsWith(parentPath + path.sep);
|
||||
}
|
||||
/**
|
||||
* Joins the given paths to the parentPath, ensuring that the resulting path
|
||||
* is still contained within the parentPath. If not, it throws an error to
|
||||
* prevent path traversal vulnerabilities.
|
||||
*
|
||||
* @throws {UnexpectedError} If the resulting path is not contained within the parentPath.
|
||||
*/
|
||||
export function safeJoinPath(parentPath, ...paths) {
|
||||
const candidate = path.join(parentPath, ...paths);
|
||||
if (!isContainedWithin(parentPath, candidate)) {
|
||||
throw new Error(`Path traversal detected, refusing to join paths: ${parentPath} and ${JSON.stringify(paths)}`);
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
export function findPackageJson(startPath) {
|
||||
let currentDir = path.dirname(startPath);
|
||||
while (parsePath(currentDir).dir !== parsePath(currentDir).root) {
|
||||
const testPath = safeJoinPath(currentDir, 'package.json');
|
||||
if (fileExistsWithCaseSync(testPath)) {
|
||||
return testPath;
|
||||
}
|
||||
currentDir = dirname(currentDir);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function isValidPackageJson(obj) {
|
||||
return typeof obj === 'object' && obj !== null;
|
||||
}
|
||||
function readPackageJsonN8n(packageJsonPath) {
|
||||
try {
|
||||
const content = readFileSync(packageJsonPath, 'utf8');
|
||||
const parsed = JSON.parse(content);
|
||||
if (isValidPackageJson(parsed)) {
|
||||
return parsed.n8n ?? {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
function resolveN8nFilePaths(packageJsonPath, filePaths) {
|
||||
const packageDir = dirname(packageJsonPath);
|
||||
const resolvedFiles = [];
|
||||
for (const filePath of filePaths) {
|
||||
const sourcePath = filePath.replace(/^dist\//, '').replace(/\.js$/, '.ts');
|
||||
const fullSourcePath = safeJoinPath(packageDir, sourcePath);
|
||||
if (existsSync(fullSourcePath)) {
|
||||
resolvedFiles.push(fullSourcePath);
|
||||
}
|
||||
}
|
||||
return resolvedFiles;
|
||||
}
|
||||
export function readPackageJsonCredentials(packageJsonPath) {
|
||||
const n8nConfig = readPackageJsonN8n(packageJsonPath);
|
||||
const credentialPaths = n8nConfig.credentials ?? [];
|
||||
const credentialFiles = resolveN8nFilePaths(packageJsonPath, credentialPaths);
|
||||
const credentialNames = [];
|
||||
for (const credentialFile of credentialFiles) {
|
||||
try {
|
||||
const credentialName = extractCredentialNameFromFile(credentialFile);
|
||||
if (credentialName) {
|
||||
credentialNames.push(credentialName);
|
||||
}
|
||||
}
|
||||
catch {
|
||||
// Silently continue if file can't be parsed
|
||||
}
|
||||
}
|
||||
return new Set(credentialNames);
|
||||
}
|
||||
export function extractCredentialNameFromFile(credentialFilePath) {
|
||||
try {
|
||||
const sourceCode = readFileSync(credentialFilePath, 'utf8');
|
||||
const ast = parse(sourceCode, {
|
||||
jsx: false,
|
||||
range: true,
|
||||
});
|
||||
let credentialName = null;
|
||||
simpleTraverse(ast, {
|
||||
enter(node) {
|
||||
if (node.type === AST_NODE_TYPES.ClassDeclaration && isCredentialTypeClass(node)) {
|
||||
const nameProperty = findClassProperty(node, 'name');
|
||||
if (nameProperty) {
|
||||
const nameValue = getStringLiteralValue(nameProperty.value);
|
||||
if (nameValue) {
|
||||
credentialName = nameValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
return credentialName;
|
||||
}
|
||||
catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
export function validateIconPath(iconPath, baseDir) {
|
||||
const isFile = iconPath.startsWith('file:');
|
||||
const relativePath = iconPath.replace(/^file:/, '');
|
||||
const isSvg = relativePath.endsWith('.svg');
|
||||
// Should not use safeJoinPath here because iconPath can be outside of the node class folder
|
||||
const fullPath = path.join(baseDir, relativePath);
|
||||
const exists = fileExistsWithCaseSync(fullPath);
|
||||
return {
|
||||
isValid: isFile && isSvg && exists,
|
||||
isFile,
|
||||
isSvg,
|
||||
exists,
|
||||
};
|
||||
}
|
||||
export function readPackageJsonNodes(packageJsonPath) {
|
||||
const n8nConfig = readPackageJsonN8n(packageJsonPath);
|
||||
const nodePaths = n8nConfig.nodes ?? [];
|
||||
return resolveN8nFilePaths(packageJsonPath, nodePaths);
|
||||
}
|
||||
export function areAllCredentialUsagesTestedByNodes(credentialName, packageDir) {
|
||||
const packageJsonPath = safeJoinPath(packageDir, 'package.json');
|
||||
if (!existsSync(packageJsonPath)) {
|
||||
return false;
|
||||
}
|
||||
const nodeFiles = readPackageJsonNodes(packageJsonPath);
|
||||
let hasAnyCredentialUsage = false;
|
||||
for (const nodeFile of nodeFiles) {
|
||||
const result = checkCredentialUsageInFile(nodeFile, credentialName);
|
||||
if (result.hasUsage) {
|
||||
hasAnyCredentialUsage = true;
|
||||
if (!result.allTestedBy) {
|
||||
return false; // Found usage without testedBy
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasAnyCredentialUsage;
|
||||
}
|
||||
function checkCredentialUsageInFile(nodeFile, credentialName) {
|
||||
try {
|
||||
const sourceCode = readFileSync(nodeFile, 'utf8');
|
||||
const ast = parse(sourceCode, { jsx: false, range: true });
|
||||
let hasUsage = false;
|
||||
let allTestedBy = true;
|
||||
simpleTraverse(ast, {
|
||||
enter(node) {
|
||||
if (node.type === AST_NODE_TYPES.ClassDeclaration && isNodeTypeClass(node)) {
|
||||
const descriptionProperty = findClassProperty(node, 'description');
|
||||
if (!descriptionProperty?.value ||
|
||||
descriptionProperty.value.type !== AST_NODE_TYPES.ObjectExpression) {
|
||||
return;
|
||||
}
|
||||
const credentialsArray = findArrayLiteralProperty(descriptionProperty.value, 'credentials');
|
||||
if (!credentialsArray) {
|
||||
return;
|
||||
}
|
||||
for (const element of credentialsArray.elements) {
|
||||
const credentialInfo = extractCredentialInfoFromArray(element);
|
||||
if (credentialInfo?.name === credentialName) {
|
||||
hasUsage = true;
|
||||
if (!credentialInfo.testedBy) {
|
||||
allTestedBy = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
return { hasUsage, allTestedBy };
|
||||
}
|
||||
catch {
|
||||
return { hasUsage: false, allTestedBy: true };
|
||||
}
|
||||
}
|
||||
function fileExistsWithCaseSync(filePath) {
|
||||
try {
|
||||
const dir = path.dirname(filePath);
|
||||
const file = path.basename(filePath);
|
||||
const files = new Set(readdirSync(dir));
|
||||
return files.has(file);
|
||||
}
|
||||
catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
export function findSimilarSvgFiles(targetPath, baseDir) {
|
||||
try {
|
||||
const targetFileName = path.basename(targetPath, path.extname(targetPath));
|
||||
const targetDir = path.dirname(targetPath);
|
||||
// Should not use safeJoinPath here because iconPath can be outside of the node class folder
|
||||
const searchDir = path.join(baseDir, targetDir);
|
||||
if (!existsSync(searchDir)) {
|
||||
return [];
|
||||
}
|
||||
const files = readdirSync(searchDir);
|
||||
const svgFileNames = files
|
||||
.filter((file) => file.endsWith('.svg'))
|
||||
.map((file) => path.basename(file, '.svg'));
|
||||
const candidateNames = new Set(svgFileNames);
|
||||
const similarNames = findSimilarStrings(targetFileName, candidateNames);
|
||||
return similarNames.map((name) => path.join(targetDir, `${name}.svg`));
|
||||
}
|
||||
catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=file-utils.js.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/file-utils.js.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/file-utils.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
4
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/index.d.ts
generated
vendored
Normal file
4
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from './ast-utils.js';
|
||||
export * from './file-utils.js';
|
||||
export * from './rule-creator.js';
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/index.d.ts.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/index.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC"}
|
||||
4
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/index.js
generated
vendored
Normal file
4
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/index.js
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from './ast-utils.js';
|
||||
export * from './file-utils.js';
|
||||
export * from './rule-creator.js';
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/index.js.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/index.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC"}
|
||||
3
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/rule-creator.d.ts
generated
vendored
Normal file
3
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/rule-creator.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import { ESLintUtils } from '@typescript-eslint/utils';
|
||||
export declare const createRule: <Options extends readonly unknown[], MessageIds extends string>({ meta, name, ...rule }: Readonly<ESLintUtils.RuleWithMetaAndName<Options, MessageIds, unknown>>) => ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener>;
|
||||
//# sourceMappingURL=rule-creator.d.ts.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/rule-creator.d.ts.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/rule-creator.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"rule-creator.d.ts","sourceRoot":"","sources":["../../src/utils/rule-creator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAKvD,eAAO,MAAM,UAAU,qPAA2E,CAAC"}
|
||||
5
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/rule-creator.js
generated
vendored
Normal file
5
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/rule-creator.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import { ESLintUtils } from '@typescript-eslint/utils';
|
||||
const REPO_URL = 'https://github.com/n8n-io/n8n';
|
||||
const DOCS_PATH = 'blob/master/packages/@n8n/eslint-plugin-community-nodes/docs/rules';
|
||||
export const createRule = ESLintUtils.RuleCreator((name) => `${REPO_URL}/${DOCS_PATH}/${name}.md`);
|
||||
//# sourceMappingURL=rule-creator.js.map
|
||||
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/rule-creator.js.map
generated
vendored
Normal file
1
node_modules/@n8n/eslint-plugin-community-nodes/dist/utils/rule-creator.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"rule-creator.js","sourceRoot":"","sources":["../../src/utils/rule-creator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,MAAM,QAAQ,GAAG,+BAA+B,CAAC;AACjD,MAAM,SAAS,GAAG,oEAAoE,CAAC;AAEvF,MAAM,CAAC,MAAM,UAAU,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,QAAQ,IAAI,SAAS,IAAI,IAAI,KAAK,CAAC,CAAC"}
|
||||
94
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/credential-documentation-url.md
generated
vendored
Normal file
94
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/credential-documentation-url.md
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
# Enforce valid credential documentationUrl format (URL or lowercase alphanumeric slug) (`@n8n/community-nodes/credential-documentation-url`)
|
||||
|
||||
💼 This rule is enabled in the following configs: ✅ `recommended`, ☑️ `recommendedWithoutN8nCloudSupport`.
|
||||
|
||||
<!-- end auto-generated rule header -->
|
||||
|
||||
## Options
|
||||
|
||||
<!-- begin auto-generated rule options list -->
|
||||
|
||||
| Name | Description | Type |
|
||||
| :----------- | :----------------------------------------------------- | :------ |
|
||||
| `allowSlugs` | Whether to allow lowercase alphanumeric slugs with slashes | Boolean |
|
||||
| `allowUrls` | Whether to allow valid URLs | Boolean |
|
||||
|
||||
<!-- end auto-generated rule options list -->
|
||||
|
||||
## Rule Details
|
||||
|
||||
Ensures that credential `documentationUrl` values are in a valid format. For community packages, this should always be a complete URL to your documentation.
|
||||
|
||||
The lowercase alphanumeric slug option (`allowSlugs`) is only intended for internal n8n use when referring to slugs on docs.n8n.io, and should not be used in community packages. When enabled, uppercase letters in slugs will be automatically converted to lowercase.
|
||||
|
||||
## Examples
|
||||
|
||||
### ❌ Incorrect
|
||||
|
||||
```typescript
|
||||
export class MyApiCredential implements ICredentialType {
|
||||
name = 'myApi';
|
||||
displayName = 'My API';
|
||||
documentationUrl = 'invalid-url-format'; // Not a valid URL
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
export class MyApiCredential implements ICredentialType {
|
||||
name = 'myApi';
|
||||
displayName = 'My API';
|
||||
documentationUrl = 'MyApi'; // Invalid: uppercase letters (will be autofixed to 'myapi')
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
export class MyApiCredential implements ICredentialType {
|
||||
name = 'myApi';
|
||||
displayName = 'My API';
|
||||
documentationUrl = 'my-api'; // Invalid: special characters not allowed
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ Correct
|
||||
|
||||
```typescript
|
||||
export class MyApiCredential implements ICredentialType {
|
||||
name = 'myApi';
|
||||
displayName = 'My API';
|
||||
documentationUrl = 'https://docs.myservice.com/api-setup'; // Complete URL to documentation
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
export class MyApiCredential implements ICredentialType {
|
||||
name = 'myApi';
|
||||
displayName = 'My API';
|
||||
documentationUrl = 'https://github.com/myuser/n8n-nodes-myapi#credentials'; // GitHub README section
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
By default, only URLs are allowed, which is the recommended setting for community packages.
|
||||
|
||||
The `allowSlugs` option is available for internal n8n development:
|
||||
|
||||
```json
|
||||
{
|
||||
"rules": {
|
||||
"@n8n/community-nodes/credential-documentation-url": [
|
||||
"error",
|
||||
{
|
||||
"allowSlugs": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Note:** Community package developers should keep the default settings and always use complete URLs for their documentation.
|
||||
45
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/credential-password-field.md
generated
vendored
Normal file
45
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/credential-password-field.md
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
# Ensure credential fields with sensitive names have typeOptions.password = true (`@n8n/community-nodes/credential-password-field`)
|
||||
|
||||
💼 This rule is enabled in the following configs: ✅ `recommended`, ☑️ `recommendedWithoutN8nCloudSupport`.
|
||||
|
||||
🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
|
||||
|
||||
<!-- end auto-generated rule header -->
|
||||
|
||||
## Rule Details
|
||||
|
||||
Ensures that credential fields with names like "password", "secret", "token", or "key" are properly masked in the UI by having `typeOptions.password = true`.
|
||||
|
||||
## Examples
|
||||
|
||||
### ❌ Incorrect
|
||||
|
||||
```typescript
|
||||
export class MyApiCredential implements ICredentialType {
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
default: '',
|
||||
// Missing typeOptions.password
|
||||
},
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ Correct
|
||||
|
||||
```typescript
|
||||
export class MyApiCredential implements ICredentialType {
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
```
|
||||
58
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/credential-test-required.md
generated
vendored
Normal file
58
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/credential-test-required.md
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
# Ensure credentials have a credential test (`@n8n/community-nodes/credential-test-required`)
|
||||
|
||||
💼 This rule is enabled in the following configs: ✅ `recommended`, ☑️ `recommendedWithoutN8nCloudSupport`.
|
||||
|
||||
💡 This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
|
||||
|
||||
<!-- end auto-generated rule header -->
|
||||
|
||||
## Rule Details
|
||||
|
||||
Ensures that your credentials include a `test` method to validate user credentials. This helps users verify their credentials are working correctly.
|
||||
|
||||
## Examples
|
||||
|
||||
### ❌ Incorrect
|
||||
|
||||
```typescript
|
||||
export class MyApiCredential implements ICredentialType {
|
||||
name = 'myApi';
|
||||
displayName = 'My API';
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
// Missing test method
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ Correct
|
||||
|
||||
```typescript
|
||||
export class MyApiCredential implements ICredentialType {
|
||||
name = 'myApi';
|
||||
displayName = 'My API';
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://api.myservice.com',
|
||||
url: '/user',
|
||||
method: 'GET',
|
||||
},
|
||||
};
|
||||
}
|
||||
```
|
||||
67
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/icon-validation.md
generated
vendored
Normal file
67
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/icon-validation.md
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
# Validate node and credential icon files exist, are SVG format, and light/dark icons are different (`@n8n/community-nodes/icon-validation`)
|
||||
|
||||
💼 This rule is enabled in the following configs: ✅ `recommended`, ☑️ `recommendedWithoutN8nCloudSupport`.
|
||||
|
||||
💡 This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
|
||||
|
||||
<!-- end auto-generated rule header -->
|
||||
|
||||
## Rule Details
|
||||
|
||||
Validates that your node and credential icon files exist, are in SVG format, and use the correct `file:` protocol. Icons must be different files when providing light/dark theme variants.
|
||||
|
||||
## Examples
|
||||
|
||||
### ❌ Incorrect
|
||||
|
||||
```typescript
|
||||
export class MyNode implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'My Node',
|
||||
name: 'myNode',
|
||||
icon: 'icons/my-icon.png', // Missing 'file:' prefix, wrong format
|
||||
// ...
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
export class MyNode implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'My Node',
|
||||
name: 'myNode',
|
||||
icon: {
|
||||
light: 'file:icons/my-icon.svg',
|
||||
dark: 'file:icons/my-icon.svg', // Same file for both themes
|
||||
},
|
||||
// ...
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ Correct
|
||||
|
||||
```typescript
|
||||
export class MyNode implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'My Node',
|
||||
name: 'myNode',
|
||||
icon: 'file:icons/my-service.svg', // Correct format
|
||||
// ...
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
export class MyNode implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'My Node',
|
||||
name: 'myNode',
|
||||
icon: {
|
||||
light: 'file:icons/my-service-light.svg',
|
||||
dark: 'file:icons/my-service-dark.svg', // Different files
|
||||
},
|
||||
// ...
|
||||
};
|
||||
}
|
||||
```
|
||||
82
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/no-credential-reuse.md
generated
vendored
Normal file
82
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/no-credential-reuse.md
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
# Prevent credential re-use security issues by ensuring nodes only reference credentials from the same package (`@n8n/community-nodes/no-credential-reuse`)
|
||||
|
||||
💼 This rule is enabled in the following configs: ✅ `recommended`, ☑️ `recommendedWithoutN8nCloudSupport`.
|
||||
|
||||
💡 This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
|
||||
|
||||
<!-- end auto-generated rule header -->
|
||||
|
||||
## Rule Details
|
||||
|
||||
Ensures your nodes only reference credentials by their `name` property that match credential classes declared in your package's `package.json` file. This prevents security issues where nodes could access credentials from other packages.
|
||||
|
||||
## Examples
|
||||
|
||||
### ❌ Incorrect
|
||||
|
||||
```typescript
|
||||
// MyApiCredential.credentials.ts
|
||||
export class MyApiCredential implements ICredentialType {
|
||||
name = 'myApiCredential';
|
||||
displayName = 'My API';
|
||||
// ...
|
||||
}
|
||||
|
||||
// package.json: "n8n": { "credentials": ["dist/credentials/MyApiCredential.credentials.js"] }
|
||||
|
||||
export class MyNode implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'My Node',
|
||||
name: 'myNode',
|
||||
credentials: [
|
||||
{
|
||||
name: 'someOtherCredential', // No credential class with this name in package
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
// ...
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ Correct
|
||||
|
||||
```typescript
|
||||
// MyApiCredential.credentials.ts
|
||||
export class MyApiCredential implements ICredentialType {
|
||||
name = 'myApiCredential'; // This name must match what's used in nodes
|
||||
displayName = 'My API';
|
||||
// ...
|
||||
}
|
||||
|
||||
// package.json: "n8n": { "credentials": ["dist/credentials/MyApiCredential.credentials.js"] }
|
||||
|
||||
export class MyNode implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'My Node',
|
||||
name: 'myNode',
|
||||
credentials: [
|
||||
{
|
||||
name: 'myApiCredential', // Matches credential class name property
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
// ...
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
Declare your credential files in `package.json` and ensure the credential name in nodes matches the `name` property in your credential classes:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "n8n-nodes-my-service",
|
||||
"n8n": {
|
||||
"credentials": [
|
||||
"dist/credentials/MyApiCredential.credentials.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
61
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/no-deprecated-workflow-functions.md
generated
vendored
Normal file
61
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/no-deprecated-workflow-functions.md
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
# Disallow usage of deprecated functions and types from n8n-workflow package (`@n8n/community-nodes/no-deprecated-workflow-functions`)
|
||||
|
||||
💼 This rule is enabled in the following configs: ✅ `recommended`, ☑️ `recommendedWithoutN8nCloudSupport`.
|
||||
|
||||
💡 This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
|
||||
|
||||
<!-- end auto-generated rule header -->
|
||||
|
||||
## Rule Details
|
||||
|
||||
Prevents usage of deprecated functions from n8n-workflow package and suggests modern alternatives.
|
||||
|
||||
## Examples
|
||||
|
||||
### ❌ Incorrect
|
||||
|
||||
```typescript
|
||||
import { IRequestOptions } from 'n8n-workflow';
|
||||
|
||||
export class MyNode implements INodeType {
|
||||
async execute(this: IExecuteFunctions) {
|
||||
// Using deprecated request helper function
|
||||
const response = await this.helpers.request({
|
||||
method: 'GET',
|
||||
url: 'https://api.example.com/data',
|
||||
});
|
||||
|
||||
// Using deprecated type
|
||||
const options: IRequestOptions = {
|
||||
method: 'POST',
|
||||
url: 'https://api.example.com/data',
|
||||
};
|
||||
|
||||
return [this.helpers.returnJsonArray([response])];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ Correct
|
||||
|
||||
```typescript
|
||||
import { IHttpRequestOptions } from 'n8n-workflow';
|
||||
|
||||
export class MyNode implements INodeType {
|
||||
async execute(this: IExecuteFunctions) {
|
||||
// Using modern httpRequest helper function
|
||||
const response = await this.helpers.httpRequest({
|
||||
method: 'GET',
|
||||
url: 'https://api.example.com/data',
|
||||
});
|
||||
|
||||
// Using modern type
|
||||
const options: IHttpRequestOptions = {
|
||||
method: 'POST',
|
||||
url: 'https://api.example.com/data',
|
||||
};
|
||||
|
||||
return [this.helpers.returnJsonArray([response])];
|
||||
}
|
||||
}
|
||||
```
|
||||
44
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/no-restricted-globals.md
generated
vendored
Normal file
44
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/no-restricted-globals.md
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
# Disallow usage of restricted global variables in community nodes (`@n8n/community-nodes/no-restricted-globals`)
|
||||
|
||||
💼 This rule is enabled in the ✅ `recommended` config.
|
||||
|
||||
<!-- end auto-generated rule header -->
|
||||
|
||||
## Rule Details
|
||||
|
||||
Prevents the use of Node.js global variables that are not allowed in n8n Cloud. While these globals may be available in self-hosted environments, they are restricted on n8n Cloud for security and stability reasons.
|
||||
|
||||
Restricted globals include: `clearInterval`, `clearTimeout`, `global`, `globalThis`, `process`, `setInterval`, `setTimeout`, `setImmediate`, `clearImmediate`, `__dirname`, `__filename`.
|
||||
|
||||
## Examples
|
||||
|
||||
### ❌ Incorrect
|
||||
|
||||
```typescript
|
||||
export class MyNode implements INodeType {
|
||||
async execute(this: IExecuteFunctions) {
|
||||
// These globals are not allowed on n8n Cloud
|
||||
const pid = process.pid;
|
||||
const dir = __dirname;
|
||||
|
||||
setTimeout(() => {
|
||||
console.log('This will not work on n8n Cloud');
|
||||
}, 1000);
|
||||
|
||||
return this.prepareOutputData([]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ Correct
|
||||
|
||||
```typescript
|
||||
export class MyNode implements INodeType {
|
||||
async execute(this: IExecuteFunctions) {
|
||||
// Use n8n context methods instead
|
||||
const timezone = this.getTimezone();
|
||||
|
||||
return this.prepareOutputData([]);
|
||||
}
|
||||
}
|
||||
```
|
||||
47
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/no-restricted-imports.md
generated
vendored
Normal file
47
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/no-restricted-imports.md
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
# Disallow usage of restricted imports in community nodes (`@n8n/community-nodes/no-restricted-imports`)
|
||||
|
||||
💼 This rule is enabled in the ✅ `recommended` config.
|
||||
|
||||
<!-- end auto-generated rule header -->
|
||||
|
||||
## Rule Details
|
||||
|
||||
Prevents importing external dependencies that are not allowed on n8n Cloud. Community nodes running on n8n Cloud are restricted to a specific set of allowed modules for security and performance reasons.
|
||||
|
||||
**Allowed modules:** `n8n-workflow`, `lodash`, `moment`, `p-limit`, `luxon`, `zod`, `crypto`, `node:crypto`
|
||||
|
||||
Relative imports (starting with `./` or `../`) are always allowed.
|
||||
|
||||
## Examples
|
||||
|
||||
### ❌ Incorrect
|
||||
|
||||
```typescript
|
||||
import axios from 'axios'; // External dependency not allowed
|
||||
import { readFile } from 'fs'; // Node.js modules not in allowlist
|
||||
const request = require('request'); // Same applies to require()
|
||||
|
||||
// Dynamic imports are also restricted
|
||||
const module = await import('some-package');
|
||||
```
|
||||
|
||||
### ✅ Correct
|
||||
|
||||
```typescript
|
||||
import { IExecuteFunctions, INodeType } from 'n8n-workflow'; // Allowed
|
||||
import { get } from 'lodash'; // Allowed
|
||||
import moment from 'moment'; // Allowed
|
||||
import { DateTime } from 'luxon'; // Allowed
|
||||
import { createHash } from 'crypto'; // Allowed
|
||||
|
||||
import { MyHelper } from './helpers/MyHelper'; // Relative imports allowed
|
||||
import config from '../config'; // Relative imports allowed
|
||||
|
||||
export class MyNode implements INodeType {
|
||||
// ... implementation
|
||||
}
|
||||
```
|
||||
|
||||
## When This Rule Doesn't Apply
|
||||
|
||||
This rule only applies to community nodes intended for n8n Cloud. If you're building nodes exclusively for self-hosted environments, you may disable this rule, but be aware that your package will not be compatible with n8n Cloud.
|
||||
43
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/node-usable-as-tool.md
generated
vendored
Normal file
43
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/node-usable-as-tool.md
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
# Ensure node classes have usableAsTool property (`@n8n/community-nodes/node-usable-as-tool`)
|
||||
|
||||
💼 This rule is enabled in the following configs: ✅ `recommended`, ☑️ `recommendedWithoutN8nCloudSupport`.
|
||||
|
||||
🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
|
||||
|
||||
<!-- end auto-generated rule header -->
|
||||
|
||||
## Rule Details
|
||||
|
||||
Ensures your nodes declare whether they can be used as tools in AI workflows. This property helps n8n determine if your node is suitable for AI-assisted automation.
|
||||
|
||||
## Examples
|
||||
|
||||
### ❌ Incorrect
|
||||
|
||||
```typescript
|
||||
export class MyNode implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'My Node',
|
||||
name: 'myNode',
|
||||
group: ['input'],
|
||||
version: 1,
|
||||
// Missing usableAsTool property
|
||||
properties: [],
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ Correct
|
||||
|
||||
```typescript
|
||||
export class MyNode implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'My Node',
|
||||
name: 'myNode',
|
||||
group: ['input'],
|
||||
version: 1,
|
||||
usableAsTool: true,
|
||||
properties: [],
|
||||
};
|
||||
}
|
||||
```
|
||||
52
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/package-name-convention.md
generated
vendored
Normal file
52
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/package-name-convention.md
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
# Enforce correct package naming convention for n8n community nodes (`@n8n/community-nodes/package-name-convention`)
|
||||
|
||||
💼 This rule is enabled in the following configs: ✅ `recommended`, ☑️ `recommendedWithoutN8nCloudSupport`.
|
||||
|
||||
💡 This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
|
||||
|
||||
<!-- end auto-generated rule header -->
|
||||
|
||||
## Rule Details
|
||||
|
||||
Validates that your package name follows the correct n8n community node naming convention. Package names must start with `n8n-nodes-` and can optionally be scoped.
|
||||
|
||||
## Examples
|
||||
|
||||
### ❌ Incorrect
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-service-integration"
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "nodes-my-service"
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@company/my-service"
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ Correct
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "n8n-nodes-my-service"
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@company/n8n-nodes-my-service"
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Use descriptive service names: `n8n-nodes-github` rather than `n8n-nodes-api`
|
||||
- For company packages, use your organization scope: `@mycompany/n8n-nodes-internal-tool`
|
||||
84
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/resource-operation-pattern.md
generated
vendored
Normal file
84
node_modules/@n8n/eslint-plugin-community-nodes/docs/rules/resource-operation-pattern.md
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
# Enforce proper resource/operation pattern for better UX in n8n nodes (`@n8n/community-nodes/resource-operation-pattern`)
|
||||
|
||||
⚠️ This rule _warns_ in the following configs: ✅ `recommended`, ☑️ `recommendedWithoutN8nCloudSupport`.
|
||||
|
||||
<!-- end auto-generated rule header -->
|
||||
|
||||
## Rule Details
|
||||
|
||||
Warns when a node has more than 5 operations without organizing them into resources. The resource/operation pattern improves user experience by grouping related operations together, making complex nodes easier to navigate.
|
||||
|
||||
When you have many operations, users benefit from having them organized into logical resource groups (e.g., "User", "Project", "File") rather than seeing a long flat list of operations.
|
||||
|
||||
## Examples
|
||||
|
||||
### ❌ Incorrect
|
||||
|
||||
```typescript
|
||||
export class MyNode implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'My Service',
|
||||
name: 'myService',
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
options: [
|
||||
{ name: 'Get User', value: 'getUser' },
|
||||
{ name: 'Create User', value: 'createUser' },
|
||||
{ name: 'Update User', value: 'updateUser' },
|
||||
{ name: 'Delete User', value: 'deleteUser' },
|
||||
{ name: 'Get Project', value: 'getProject' },
|
||||
{ name: 'Create Project', value: 'createProject' },
|
||||
{ name: 'List Files', value: 'listFiles' },
|
||||
// 7+ operations without resources - hard to navigate!
|
||||
],
|
||||
},
|
||||
// ... other properties
|
||||
],
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ Correct
|
||||
|
||||
```typescript
|
||||
export class MyNode implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'My Service',
|
||||
name: 'myService',
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
options: [
|
||||
{ name: 'User', value: 'user' },
|
||||
{ name: 'Project', value: 'project' },
|
||||
{ name: 'File', value: 'file' },
|
||||
],
|
||||
default: 'user',
|
||||
},
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['user'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{ name: 'Get', value: 'get' },
|
||||
{ name: 'Create', value: 'create' },
|
||||
{ name: 'Update', value: 'update' },
|
||||
{ name: 'Delete', value: 'delete' },
|
||||
],
|
||||
default: 'get',
|
||||
},
|
||||
// ... similar operation blocks for 'project' and 'file' resources
|
||||
],
|
||||
};
|
||||
}
|
||||
```
|
||||
27
node_modules/@n8n/eslint-plugin-community-nodes/eslint.config.mjs
generated
vendored
Normal file
27
node_modules/@n8n/eslint-plugin-community-nodes/eslint.config.mjs
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import { nodeConfig } from '@n8n/eslint-config/node';
|
||||
import eslintPlugin from 'eslint-plugin-eslint-plugin';
|
||||
|
||||
export default defineConfig([
|
||||
nodeConfig,
|
||||
eslintPlugin.configs.recommended,
|
||||
{
|
||||
files: ['src/**/*.ts'],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
project: './tsconfig.json',
|
||||
allowDefaultProject: true,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
// We use RuleCreator which adds this automatically
|
||||
'eslint-plugin/require-meta-docs-url': 'off',
|
||||
// typescript-eslint uses different pattern
|
||||
'eslint-plugin/require-meta-default-options': 'off',
|
||||
// Disable naming convention for plugin configs (ESLint rule names use kebab-case)
|
||||
'@typescript-eslint/naming-convention': 'off',
|
||||
// Allow default exports for ESLint plugin
|
||||
'import-x/no-default-export': 'off',
|
||||
},
|
||||
},
|
||||
]);
|
||||
67
node_modules/@n8n/eslint-plugin-community-nodes/package.json
generated
vendored
Normal file
67
node_modules/@n8n/eslint-plugin-community-nodes/package.json
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"name": "@n8n/eslint-plugin-community-nodes",
|
||||
"type": "module",
|
||||
"version": "0.6.0",
|
||||
"main": "./dist/plugin.js",
|
||||
"types": "./dist/plugin.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/plugin.d.ts",
|
||||
"default": "./dist/plugin.js"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@typescript-eslint/utils": "^8.35.0",
|
||||
"fastest-levenshtein": "1.0.16"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/rule-tester": "^8.35.0",
|
||||
"eslint-doc-generator": "^2.2.2",
|
||||
"eslint-plugin-eslint-plugin": "^7.0.0",
|
||||
"rimraf": "6.0.1",
|
||||
"typescript": "5.9.2",
|
||||
"vitest": "^3.1.3",
|
||||
"@n8n/typescript-config": "1.3.0",
|
||||
"@n8n/vitest-config": "1.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">= 9"
|
||||
},
|
||||
"eslint-doc-generator": {
|
||||
"configEmoji": [
|
||||
[
|
||||
"recommended",
|
||||
"✅"
|
||||
],
|
||||
[
|
||||
"recommendedWithoutN8nCloudSupport",
|
||||
"☑️"
|
||||
]
|
||||
]
|
||||
},
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"homepage": "https://n8n.io",
|
||||
"author": {
|
||||
"name": "Jan Oberhauser",
|
||||
"email": "jan@n8n.io"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/n8n-io/n8n.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc --project tsconfig.build.json",
|
||||
"build:docs": "eslint-doc-generator",
|
||||
"clean": "rimraf dist .turbo",
|
||||
"dev": "pnpm watch",
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome ci .",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"lint:docs": "eslint-doc-generator --check",
|
||||
"test": "vitest run",
|
||||
"test:dev": "vitest",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"watch": "tsc --watch --project tsconfig.build.json"
|
||||
}
|
||||
}
|
||||
59
node_modules/@n8n/eslint-plugin-community-nodes/src/plugin.ts
generated
vendored
Normal file
59
node_modules/@n8n/eslint-plugin-community-nodes/src/plugin.ts
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
import type { ESLint, Linter } from 'eslint';
|
||||
|
||||
import pkg from '../package.json' with { type: 'json' };
|
||||
import { rules } from './rules/index.js';
|
||||
|
||||
const plugin = {
|
||||
meta: {
|
||||
name: pkg.name,
|
||||
version: pkg.version,
|
||||
namespace: '@n8n/community-nodes',
|
||||
},
|
||||
// @ts-expect-error Rules type does not match for typescript-eslint and eslint
|
||||
rules: rules as ESLint.Plugin['rules'],
|
||||
} satisfies ESLint.Plugin;
|
||||
|
||||
const configs = {
|
||||
recommended: {
|
||||
ignores: ['eslint.config.{js,mjs,ts,mts}'],
|
||||
plugins: {
|
||||
'@n8n/community-nodes': plugin,
|
||||
},
|
||||
rules: {
|
||||
'@n8n/community-nodes/no-restricted-globals': 'error',
|
||||
'@n8n/community-nodes/no-restricted-imports': 'error',
|
||||
'@n8n/community-nodes/credential-password-field': 'error',
|
||||
'@n8n/community-nodes/no-deprecated-workflow-functions': 'error',
|
||||
'@n8n/community-nodes/node-usable-as-tool': 'error',
|
||||
'@n8n/community-nodes/package-name-convention': 'error',
|
||||
'@n8n/community-nodes/credential-test-required': 'error',
|
||||
'@n8n/community-nodes/no-credential-reuse': 'error',
|
||||
'@n8n/community-nodes/icon-validation': 'error',
|
||||
'@n8n/community-nodes/resource-operation-pattern': 'warn',
|
||||
'@n8n/community-nodes/credential-documentation-url': 'error',
|
||||
},
|
||||
},
|
||||
recommendedWithoutN8nCloudSupport: {
|
||||
ignores: ['eslint.config.{js,mjs,ts,mts}'],
|
||||
plugins: {
|
||||
'@n8n/community-nodes': plugin,
|
||||
},
|
||||
rules: {
|
||||
'@n8n/community-nodes/credential-password-field': 'error',
|
||||
'@n8n/community-nodes/no-deprecated-workflow-functions': 'error',
|
||||
'@n8n/community-nodes/node-usable-as-tool': 'error',
|
||||
'@n8n/community-nodes/package-name-convention': 'error',
|
||||
'@n8n/community-nodes/credential-test-required': 'error',
|
||||
'@n8n/community-nodes/no-credential-reuse': 'error',
|
||||
'@n8n/community-nodes/icon-validation': 'error',
|
||||
'@n8n/community-nodes/credential-documentation-url': 'error',
|
||||
'@n8n/community-nodes/resource-operation-pattern': 'warn',
|
||||
},
|
||||
},
|
||||
} satisfies Record<string, Linter.Config>;
|
||||
|
||||
const pluginWithConfigs = { ...plugin, configs } satisfies ESLint.Plugin;
|
||||
|
||||
const n8nCommunityNodesPlugin = pluginWithConfigs;
|
||||
export default pluginWithConfigs;
|
||||
export { rules, configs, n8nCommunityNodesPlugin };
|
||||
306
node_modules/@n8n/eslint-plugin-community-nodes/src/rules/credential-documentation-url.test.ts
generated
vendored
Normal file
306
node_modules/@n8n/eslint-plugin-community-nodes/src/rules/credential-documentation-url.test.ts
generated
vendored
Normal file
@@ -0,0 +1,306 @@
|
||||
import { RuleTester } from '@typescript-eslint/rule-tester';
|
||||
|
||||
import { CredentialDocumentationUrlRule } from './credential-documentation-url.js';
|
||||
|
||||
const ruleTester = new RuleTester();
|
||||
|
||||
function createCredentialCode(documentationUrl: string): string {
|
||||
return `
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class TestCredential implements ICredentialType {
|
||||
name = 'testApi';
|
||||
displayName = 'Test API';
|
||||
documentationUrl = '${documentationUrl}';
|
||||
|
||||
properties: INodeProperties[] = [];
|
||||
}`;
|
||||
}
|
||||
|
||||
function createCredentialWithoutDocUrl(): string {
|
||||
return `
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class TestCredential implements ICredentialType {
|
||||
name = 'testApi';
|
||||
displayName = 'Test API';
|
||||
|
||||
properties: INodeProperties[] = [];
|
||||
}`;
|
||||
}
|
||||
|
||||
function createRegularClass(): string {
|
||||
return `
|
||||
export class RegularClass {
|
||||
documentationUrl = 'invalid-url';
|
||||
}`;
|
||||
}
|
||||
|
||||
ruleTester.run('credential-documentation-url', CredentialDocumentationUrlRule, {
|
||||
valid: [
|
||||
{
|
||||
name: 'valid URL with default options (URLs only)',
|
||||
code: createCredentialCode('https://example.com/docs'),
|
||||
},
|
||||
{
|
||||
name: 'valid URL with explicit options',
|
||||
code: createCredentialCode('https://example.com/docs'),
|
||||
options: [{ allowUrls: true, allowSlugs: false }],
|
||||
},
|
||||
{
|
||||
name: 'valid lowercase slug when slugs are allowed',
|
||||
code: createCredentialCode('myservice'),
|
||||
options: [{ allowUrls: false, allowSlugs: true }],
|
||||
},
|
||||
{
|
||||
name: 'valid lowercase slug with slashes when slugs are allowed',
|
||||
code: createCredentialCode('myservice/advanced/config'),
|
||||
options: [{ allowUrls: false, allowSlugs: true }],
|
||||
},
|
||||
{
|
||||
name: 'valid URL when both URLs and slugs are allowed',
|
||||
code: createCredentialCode('https://example.com/docs'),
|
||||
options: [{ allowUrls: true, allowSlugs: true }],
|
||||
},
|
||||
{
|
||||
name: 'valid lowercase slug when both URLs and slugs are allowed',
|
||||
code: createCredentialCode('myservice/config'),
|
||||
options: [{ allowUrls: true, allowSlugs: true }],
|
||||
},
|
||||
{
|
||||
name: 'credential without documentationUrl should not trigger',
|
||||
code: createCredentialWithoutDocUrl(),
|
||||
},
|
||||
{
|
||||
name: 'class not implementing ICredentialType should be ignored',
|
||||
code: createRegularClass(),
|
||||
},
|
||||
{
|
||||
name: 'valid lowercase slug with multiple segments',
|
||||
code: createCredentialCode('myservice/somefeature/advancedconfig'),
|
||||
options: [{ allowUrls: false, allowSlugs: true }],
|
||||
},
|
||||
{
|
||||
name: 'valid lowercase alphanumeric slug',
|
||||
code: createCredentialCode('myservice123'),
|
||||
options: [{ allowUrls: false, allowSlugs: true }],
|
||||
},
|
||||
{
|
||||
name: 'valid lowercase alphanumeric slug with slashes',
|
||||
code: createCredentialCode('myservice123/config456'),
|
||||
options: [{ allowUrls: false, allowSlugs: true }],
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
name: 'invalid URL with default options',
|
||||
code: createCredentialCode('invalid-url'),
|
||||
errors: [
|
||||
{
|
||||
messageId: 'invalidDocumentationUrl',
|
||||
data: {
|
||||
value: 'invalid-url',
|
||||
expectedFormats: 'a valid URL',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'slug not allowed with default options',
|
||||
code: createCredentialCode('myservice'),
|
||||
errors: [
|
||||
{
|
||||
messageId: 'invalidDocumentationUrl',
|
||||
data: {
|
||||
value: 'myservice',
|
||||
expectedFormats: 'a valid URL',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'slug with special characters should not be autofixable',
|
||||
code: createCredentialCode('My-Service'),
|
||||
options: [{ allowUrls: false, allowSlugs: true }],
|
||||
errors: [
|
||||
{
|
||||
messageId: 'invalidDocumentationUrl',
|
||||
data: {
|
||||
value: 'My-Service',
|
||||
expectedFormats: 'a lowercase alphanumeric slug (can contain slashes)',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'uppercase slug should be autofixable',
|
||||
code: createCredentialCode('MyService'),
|
||||
options: [{ allowUrls: false, allowSlugs: true }],
|
||||
output: createCredentialCode('myservice'),
|
||||
errors: [
|
||||
{
|
||||
messageId: 'invalidDocumentationUrl',
|
||||
data: {
|
||||
value: 'MyService',
|
||||
expectedFormats: 'a lowercase alphanumeric slug (can contain slashes)',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'invalid URL when only URLs are allowed',
|
||||
code: createCredentialCode('not-a-valid-url'),
|
||||
options: [{ allowUrls: true, allowSlugs: false }],
|
||||
errors: [
|
||||
{
|
||||
messageId: 'invalidDocumentationUrl',
|
||||
data: {
|
||||
value: 'not-a-valid-url',
|
||||
expectedFormats: 'a valid URL',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'invalid when neither URLs nor slugs are allowed',
|
||||
code: createCredentialCode('https://example.com'),
|
||||
options: [{ allowUrls: false, allowSlugs: false }],
|
||||
errors: [
|
||||
{
|
||||
messageId: 'invalidDocumentationUrl',
|
||||
data: {
|
||||
value: 'https://example.com',
|
||||
expectedFormats: 'a valid format (none configured)',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'slug with invalid characters (special chars) should not be autofixable',
|
||||
code: createCredentialCode('my@service/config'),
|
||||
options: [{ allowUrls: false, allowSlugs: true }],
|
||||
errors: [
|
||||
{
|
||||
messageId: 'invalidDocumentationUrl',
|
||||
data: {
|
||||
value: 'my@service/config',
|
||||
expectedFormats: 'a lowercase alphanumeric slug (can contain slashes)',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'slug with uppercase segment should be autofixable',
|
||||
code: createCredentialCode('myService/Config'),
|
||||
options: [{ allowUrls: false, allowSlugs: true }],
|
||||
output: createCredentialCode('myservice/config'),
|
||||
errors: [
|
||||
{
|
||||
messageId: 'invalidDocumentationUrl',
|
||||
data: {
|
||||
value: 'myService/Config',
|
||||
expectedFormats: 'a lowercase alphanumeric slug (can contain slashes)',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'slug with hyphens should not be autofixable',
|
||||
code: createCredentialCode('myservice/advanced-config'),
|
||||
options: [{ allowUrls: false, allowSlugs: true }],
|
||||
errors: [
|
||||
{
|
||||
messageId: 'invalidDocumentationUrl',
|
||||
data: {
|
||||
value: 'myservice/advanced-config',
|
||||
expectedFormats: 'a lowercase alphanumeric slug (can contain slashes)',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'slug with underscores should not be autofixable',
|
||||
code: createCredentialCode('my_service/config_advanced'),
|
||||
options: [{ allowUrls: false, allowSlugs: true }],
|
||||
errors: [
|
||||
{
|
||||
messageId: 'invalidDocumentationUrl',
|
||||
data: {
|
||||
value: 'my_service/config_advanced',
|
||||
expectedFormats: 'a lowercase alphanumeric slug (can contain slashes)',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'invalid value when both formats are allowed - shows both in error message',
|
||||
code: createCredentialCode('Invalid-Value!'),
|
||||
options: [{ allowUrls: true, allowSlugs: true }],
|
||||
errors: [
|
||||
{
|
||||
messageId: 'invalidDocumentationUrl',
|
||||
data: {
|
||||
value: 'Invalid-Value!',
|
||||
expectedFormats: 'a valid URL or a lowercase alphanumeric slug (can contain slashes)',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'empty string should be invalid with default options',
|
||||
code: createCredentialCode(''),
|
||||
errors: [
|
||||
{
|
||||
messageId: 'invalidDocumentationUrl',
|
||||
data: {
|
||||
value: '',
|
||||
expectedFormats: 'a valid URL',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'empty string should be invalid when slugs are allowed',
|
||||
code: createCredentialCode(''),
|
||||
options: [{ allowUrls: false, allowSlugs: true }],
|
||||
errors: [
|
||||
{
|
||||
messageId: 'invalidDocumentationUrl',
|
||||
data: {
|
||||
value: '',
|
||||
expectedFormats: 'a lowercase alphanumeric slug (can contain slashes)',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'mixed case slug with numbers should be autofixable',
|
||||
code: createCredentialCode('MyService123/Config456'),
|
||||
options: [{ allowUrls: false, allowSlugs: true }],
|
||||
output: createCredentialCode('myservice123/config456'),
|
||||
errors: [
|
||||
{
|
||||
messageId: 'invalidDocumentationUrl',
|
||||
data: {
|
||||
value: 'MyService123/Config456',
|
||||
expectedFormats: 'a lowercase alphanumeric slug (can contain slashes)',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'slug starting with number should be invalid and not autofixable',
|
||||
code: createCredentialCode('123service/config'),
|
||||
options: [{ allowUrls: false, allowSlugs: true }],
|
||||
errors: [
|
||||
{
|
||||
messageId: 'invalidDocumentationUrl',
|
||||
data: {
|
||||
value: '123service/config',
|
||||
expectedFormats: 'a lowercase alphanumeric slug (can contain slashes)',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user