@n8n/eslint-plugin-community-nodes 0.27.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/dist/rules/index.d.ts +1 -1
- package/dist/rules/no-restricted-globals.d.ts +1 -1
- package/dist/rules/no-restricted-globals.d.ts.map +1 -1
- package/dist/rules/no-restricted-globals.js +18 -5
- package/dist/rules/no-restricted-globals.js.map +1 -1
- package/dist/typecheck.tsbuildinfo +1 -1
- package/docs/rules/no-restricted-globals.md +14 -0
- package/package.json +2 -2
- package/src/rules/no-restricted-globals.test.ts +26 -2
- package/src/rules/no-restricted-globals.ts +22 -5
|
@@ -33,12 +33,26 @@ export class MyNode implements INodeType {
|
|
|
33
33
|
### ✅ Correct
|
|
34
34
|
|
|
35
35
|
```typescript
|
|
36
|
+
import { sleep } from 'n8n-workflow';
|
|
37
|
+
|
|
36
38
|
export class MyNode implements INodeType {
|
|
37
39
|
async execute(this: IExecuteFunctions) {
|
|
38
40
|
// Use n8n context methods instead
|
|
39
41
|
const timezone = this.getTimezone();
|
|
40
42
|
|
|
43
|
+
// Use the sleep helper instead of setTimeout
|
|
44
|
+
await sleep(1000);
|
|
45
|
+
|
|
41
46
|
return this.prepareOutputData([]);
|
|
42
47
|
}
|
|
43
48
|
}
|
|
44
49
|
```
|
|
50
|
+
|
|
51
|
+
## Alternatives to restricted timer globals
|
|
52
|
+
|
|
53
|
+
`n8n-workflow` exports helpers that work the same everywhere, including on
|
|
54
|
+
n8n Cloud, instead of reaching for the restricted timer globals directly:
|
|
55
|
+
|
|
56
|
+
- Instead of `setTimeout(resolve, ms)`, use `await sleep(ms)`.
|
|
57
|
+
- Instead of `setTimeout` + `clearTimeout` for a cancellable delay, use
|
|
58
|
+
`await sleepWithAbort(ms, abortSignal)`.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@n8n/eslint-plugin-community-nodes",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.28.0",
|
|
5
5
|
"main": "./dist/plugin.js",
|
|
6
6
|
"types": "./dist/plugin.d.ts",
|
|
7
7
|
"exports": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"vitest": "^4.1.9",
|
|
28
28
|
"@n8n/typescript-config": "1.9.0",
|
|
29
29
|
"@n8n/vitest-config": "1.19.0",
|
|
30
|
-
"n8n-workflow": "2.
|
|
30
|
+
"n8n-workflow": "2.34.0"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"eslint": "9.29.0",
|
|
@@ -70,6 +70,17 @@ var __dirname = '/path';
|
|
|
70
70
|
const __filename = 'file.js';
|
|
71
71
|
`,
|
|
72
72
|
},
|
|
73
|
+
{
|
|
74
|
+
name: 'sleep and sleepWithAbort from n8n-workflow should be allowed',
|
|
75
|
+
code: `
|
|
76
|
+
import { sleep, sleepWithAbort } from 'n8n-workflow';
|
|
77
|
+
|
|
78
|
+
async function wait(signal) {
|
|
79
|
+
await sleep(1000);
|
|
80
|
+
await sleepWithAbort(1000, signal);
|
|
81
|
+
}
|
|
82
|
+
`,
|
|
83
|
+
},
|
|
73
84
|
],
|
|
74
85
|
invalid: [
|
|
75
86
|
{
|
|
@@ -82,7 +93,12 @@ const __filename = 'file.js';
|
|
|
82
93
|
},
|
|
83
94
|
{
|
|
84
95
|
code: 'setTimeout(() => {}, 1000);',
|
|
85
|
-
errors: [
|
|
96
|
+
errors: [
|
|
97
|
+
{
|
|
98
|
+
messageId: 'restrictedGlobalWithHint',
|
|
99
|
+
data: { name: 'setTimeout', hint: "Use the 'sleep' helper from 'n8n-workflow' instead." },
|
|
100
|
+
},
|
|
101
|
+
],
|
|
86
102
|
},
|
|
87
103
|
{
|
|
88
104
|
code: 'clearInterval(timer);',
|
|
@@ -90,7 +106,15 @@ const __filename = 'file.js';
|
|
|
90
106
|
},
|
|
91
107
|
{
|
|
92
108
|
code: 'clearTimeout(timer);',
|
|
93
|
-
errors: [
|
|
109
|
+
errors: [
|
|
110
|
+
{
|
|
111
|
+
messageId: 'restrictedGlobalWithHint',
|
|
112
|
+
data: {
|
|
113
|
+
name: 'clearTimeout',
|
|
114
|
+
hint: "Use 'sleepWithAbort' from 'n8n-workflow' with an AbortSignal instead.",
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
],
|
|
94
118
|
},
|
|
95
119
|
{
|
|
96
120
|
code: 'setInterval(() => {}, 1000);',
|
|
@@ -17,6 +17,12 @@ const restrictedGlobals = [
|
|
|
17
17
|
'__filename',
|
|
18
18
|
];
|
|
19
19
|
|
|
20
|
+
// Nudge toward the n8n-workflow alternatives that work under n8n Cloud's restrictions
|
|
21
|
+
const restrictedGlobalHints: Record<string, string> = {
|
|
22
|
+
setTimeout: "Use the 'sleep' helper from 'n8n-workflow' instead.",
|
|
23
|
+
clearTimeout: "Use 'sleepWithAbort' from 'n8n-workflow' with an AbortSignal instead.",
|
|
24
|
+
};
|
|
25
|
+
|
|
20
26
|
export const NoRestrictedGlobalsRule = createRule({
|
|
21
27
|
name: 'no-restricted-globals',
|
|
22
28
|
meta: {
|
|
@@ -26,6 +32,7 @@ export const NoRestrictedGlobalsRule = createRule({
|
|
|
26
32
|
},
|
|
27
33
|
messages: {
|
|
28
34
|
restrictedGlobal: "Use of restricted global '{{ name }}' is not allowed",
|
|
35
|
+
restrictedGlobalWithHint: "Use of restricted global '{{ name }}' is not allowed. {{ hint }}",
|
|
29
36
|
},
|
|
30
37
|
schema: [],
|
|
31
38
|
},
|
|
@@ -43,11 +50,21 @@ export const NoRestrictedGlobalsRule = createRule({
|
|
|
43
50
|
return;
|
|
44
51
|
}
|
|
45
52
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
const hint = restrictedGlobalHints[name];
|
|
54
|
+
|
|
55
|
+
context.report(
|
|
56
|
+
hint
|
|
57
|
+
? {
|
|
58
|
+
node: ref.identifier,
|
|
59
|
+
messageId: 'restrictedGlobalWithHint',
|
|
60
|
+
data: { name, hint },
|
|
61
|
+
}
|
|
62
|
+
: {
|
|
63
|
+
node: ref.identifier,
|
|
64
|
+
messageId: 'restrictedGlobal',
|
|
65
|
+
data: { name },
|
|
66
|
+
},
|
|
67
|
+
);
|
|
51
68
|
}
|
|
52
69
|
|
|
53
70
|
return {
|