flowlint 0.5.1 → 0.6.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/README.md +45 -355
- package/dist/cli.js +163 -21
- package/dist/cli.js.map +1 -1
- package/package.json +52 -57
- package/dist/cli.d.ts +0 -8
- package/dist/commands/init.d.ts +0 -8
- package/dist/commands/init.js +0 -34
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/scan.d.ts +0 -11
- package/dist/commands/scan.js +0 -104
- package/dist/commands/scan.js.map +0 -1
- package/dist/packages/config/flowlint-config.d.ts +0 -73
- package/dist/packages/config/flowlint-config.js +0 -120
- package/dist/packages/config/flowlint-config.js.map +0 -1
- package/dist/packages/config/index.d.ts +0 -4
- package/dist/packages/config/index.js +0 -21
- package/dist/packages/config/index.js.map +0 -1
- package/dist/packages/github/client.d.ts +0 -2
- package/dist/packages/github/client.js +0 -94
- package/dist/packages/github/client.js.map +0 -1
- package/dist/packages/logger/index.d.ts +0 -11
- package/dist/packages/logger/index.js +0 -40
- package/dist/packages/logger/index.js.map +0 -1
- package/dist/packages/observability/collectors.d.ts +0 -40
- package/dist/packages/observability/collectors.js +0 -75
- package/dist/packages/observability/collectors.js.map +0 -1
- package/dist/packages/observability/index.d.ts +0 -10
- package/dist/packages/observability/index.js +0 -35
- package/dist/packages/observability/index.js.map +0 -1
- package/dist/packages/observability/metrics.d.ts +0 -119
- package/dist/packages/observability/metrics.js +0 -194
- package/dist/packages/observability/metrics.js.map +0 -1
- package/dist/packages/observability/middleware.d.ts +0 -32
- package/dist/packages/observability/middleware.js +0 -58
- package/dist/packages/observability/middleware.js.map +0 -1
- package/dist/packages/review/analysis-engine.d.ts +0 -19
- package/dist/packages/review/analysis-engine.js +0 -111
- package/dist/packages/review/analysis-engine.js.map +0 -1
- package/dist/packages/review/index.d.ts +0 -12
- package/dist/packages/review/index.js +0 -29
- package/dist/packages/review/index.js.map +0 -1
- package/dist/packages/review/parser-n8n.d.ts +0 -2
- package/dist/packages/review/parser-n8n.js +0 -122
- package/dist/packages/review/parser-n8n.js.map +0 -1
- package/dist/packages/review/providers/github.d.ts +0 -62
- package/dist/packages/review/providers/github.js +0 -275
- package/dist/packages/review/providers/github.js.map +0 -1
- package/dist/packages/review/providers.d.ts +0 -106
- package/dist/packages/review/providers.js +0 -12
- package/dist/packages/review/providers.js.map +0 -1
- package/dist/packages/review/reporter.d.ts +0 -17
- package/dist/packages/review/reporter.js +0 -59
- package/dist/packages/review/reporter.js.map +0 -1
- package/dist/packages/review/rules/index.d.ts +0 -9
- package/dist/packages/review/rules/index.js +0 -415
- package/dist/packages/review/rules/index.js.map +0 -1
- package/dist/packages/review/rules/rule-utils.d.ts +0 -36
- package/dist/packages/review/rules/rule-utils.js +0 -75
- package/dist/packages/review/rules/rule-utils.js.map +0 -1
- package/dist/packages/review/schemas/index.d.ts +0 -17
- package/dist/packages/review/schemas/index.js +0 -167
- package/dist/packages/review/schemas/index.js.map +0 -1
- package/dist/packages/review/schemas/n8n-workflow.schema.json +0 -177
- package/dist/packages/review/sniffer.d.ts +0 -15
- package/dist/packages/review/sniffer.js +0 -47
- package/dist/packages/review/sniffer.js.map +0 -1
- package/dist/packages/review/types.d.ts +0 -40
- package/dist/packages/review/types.js +0 -3
- package/dist/packages/review/types.js.map +0 -1
- package/dist/packages/review/utils/findings.d.ts +0 -23
- package/dist/packages/review/utils/findings.js +0 -34
- package/dist/packages/review/utils/findings.js.map +0 -1
- package/dist/packages/review/utils/merge.d.ts +0 -12
- package/dist/packages/review/utils/merge.js +0 -40
- package/dist/packages/review/utils/merge.js.map +0 -1
- package/dist/packages/review/utils.d.ts +0 -60
- package/dist/packages/review/utils.js +0 -214
- package/dist/packages/review/utils.js.map +0 -1
- package/dist/packages/tracing/github-tracer.d.ts +0 -38
- package/dist/packages/tracing/github-tracer.js +0 -79
- package/dist/packages/tracing/github-tracer.js.map +0 -1
- package/dist/packages/tracing/index.d.ts +0 -81
- package/dist/packages/tracing/index.js +0 -240
- package/dist/packages/tracing/index.js.map +0 -1
- package/dist/packages/tracing/tracer.d.ts +0 -30
- package/dist/packages/tracing/tracer.js +0 -141
- package/dist/packages/tracing/tracer.js.map +0 -1
- package/dist/providers/local-config-provider.d.ts +0 -11
- package/dist/providers/local-config-provider.js +0 -39
- package/dist/providers/local-config-provider.js.map +0 -1
- package/dist/providers/local-file-source.d.ts +0 -13
- package/dist/providers/local-file-source.js +0 -47
- package/dist/providers/local-file-source.js.map +0 -1
- package/dist/reporters/console-reporter.d.ts +0 -8
- package/dist/reporters/console-reporter.js +0 -75
- package/dist/reporters/console-reporter.js.map +0 -1
- package/dist/reporters/github-actions-reporter.d.ts +0 -30
- package/dist/reporters/github-actions-reporter.js +0 -104
- package/dist/reporters/github-actions-reporter.js.map +0 -1
- package/dist/reporters/json-reporter.d.ts +0 -14
- package/dist/reporters/json-reporter.js +0 -57
- package/dist/reporters/json-reporter.js.map +0 -1
- package/dist/reporters/junit-reporter.d.ts +0 -25
- package/dist/reporters/junit-reporter.js +0 -142
- package/dist/reporters/junit-reporter.js.map +0 -1
- package/dist/reporters/sarif-reporter.d.ts +0 -21
- package/dist/reporters/sarif-reporter.js +0 -125
- package/dist/reporters/sarif-reporter.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# FlowLint CLI
|
|
1
|
+
# FlowLint CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Command-line tool for static analysis of n8n workflows.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -8,391 +8,81 @@ Static analysis tool for n8n workflows - detect issues early, fix them faster.
|
|
|
8
8
|
npm install -g flowlint
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
Or use
|
|
11
|
+
Or use npx:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
npx flowlint scan
|
|
14
|
+
npx flowlint scan .
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
##
|
|
17
|
+
## Usage
|
|
18
18
|
|
|
19
|
-
Scan workflows
|
|
19
|
+
### Scan workflows
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
Scan a specific directory:
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
flowlint scan ./workflows
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
Scan with a custom config file:
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
flowlint scan . --config .flowlint.yml
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Output Formats
|
|
38
|
-
|
|
39
|
-
FlowLint supports multiple output formats for different use cases:
|
|
40
|
-
|
|
41
|
-
### Stylish (Default)
|
|
42
|
-
|
|
43
|
-
Human-readable console output with colors and formatting:
|
|
44
|
-
|
|
45
|
-
```bash
|
|
46
|
-
flowlint scan .
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### JSON
|
|
50
|
-
|
|
51
|
-
Machine-readable JSON output:
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
flowlint scan . --format json
|
|
55
|
-
flowlint scan . --format json --out-file report.json
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
### SARIF
|
|
59
|
-
|
|
60
|
-
SARIF 2.1.0 format for GitHub Code Scanning and other security platforms:
|
|
61
|
-
|
|
62
|
-
```bash
|
|
63
|
-
flowlint scan . --format sarif --out-file results.sarif
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### JUnit XML
|
|
67
|
-
|
|
68
|
-
JUnit XML format for CI/CD platforms (Jenkins, GitLab CI, CircleCI, etc.):
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
flowlint scan . --format junit --out-file results.xml
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### GitHub Actions
|
|
75
|
-
|
|
76
|
-
GitHub Actions workflow commands for inline annotations in workflow logs:
|
|
77
|
-
|
|
78
|
-
```bash
|
|
79
|
-
flowlint scan . --format github-actions
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## Command Reference
|
|
83
|
-
|
|
84
|
-
### `scan`
|
|
85
|
-
|
|
86
|
-
Scan workflow files for issues.
|
|
87
|
-
|
|
88
|
-
```bash
|
|
89
|
-
flowlint scan [path] [options]
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
**Arguments:**
|
|
93
|
-
- `path` - Directory to scan (default: current directory)
|
|
94
|
-
|
|
95
|
-
**Options:**
|
|
96
|
-
- `--config <path>` - Path to `.flowlint.yml` config file
|
|
97
|
-
- `--format <format>` - Output format: `stylish`, `json`, `sarif`, `junit`, `github-actions` (default: `stylish`)
|
|
98
|
-
- `--out-file <path>` - Write results to file (format inferred from extension or `--format`)
|
|
99
|
-
- `--fail-on-error` - Exit with code 1 if errors found
|
|
100
|
-
|
|
101
|
-
**Examples:**
|
|
102
|
-
|
|
103
|
-
```bash
|
|
104
|
-
# Scan current directory with default config
|
|
22
|
+
# Scan current directory
|
|
105
23
|
flowlint scan
|
|
106
24
|
|
|
107
25
|
# Scan specific directory
|
|
108
|
-
flowlint scan ./
|
|
109
|
-
|
|
110
|
-
# Use custom config
|
|
111
|
-
flowlint scan --config custom-config.yml
|
|
112
|
-
|
|
113
|
-
# Output JSON to file
|
|
114
|
-
flowlint scan --format json --out-file report.json
|
|
115
|
-
|
|
116
|
-
# Generate SARIF for GitHub Code Scanning
|
|
117
|
-
flowlint scan --format sarif --out-file results.sarif
|
|
26
|
+
flowlint scan ./workflows
|
|
118
27
|
|
|
119
|
-
#
|
|
120
|
-
flowlint scan --format
|
|
28
|
+
# Output as JSON
|
|
29
|
+
flowlint scan --format json
|
|
121
30
|
|
|
122
|
-
# Fail
|
|
31
|
+
# Fail on errors (for CI)
|
|
123
32
|
flowlint scan --fail-on-error
|
|
124
33
|
```
|
|
125
34
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
### GitHub Actions
|
|
129
|
-
|
|
130
|
-
#### Option 1: SARIF Upload (Recommended)
|
|
131
|
-
|
|
132
|
-
Upload results to GitHub Code Scanning for permanent PR annotations:
|
|
133
|
-
|
|
134
|
-
```yaml
|
|
135
|
-
name: FlowLint
|
|
136
|
-
|
|
137
|
-
on:
|
|
138
|
-
pull_request:
|
|
139
|
-
paths:
|
|
140
|
-
- '**.json'
|
|
141
|
-
|
|
142
|
-
jobs:
|
|
143
|
-
flowlint:
|
|
144
|
-
runs-on: ubuntu-latest
|
|
145
|
-
permissions:
|
|
146
|
-
contents: read
|
|
147
|
-
security-events: write # Required for SARIF upload
|
|
148
|
-
steps:
|
|
149
|
-
- uses: actions/checkout@v4
|
|
150
|
-
|
|
151
|
-
- name: Run FlowLint
|
|
152
|
-
run: npx flowlint scan --format sarif --out-file results.sarif
|
|
153
|
-
continue-on-error: true # Don't fail workflow on findings
|
|
154
|
-
|
|
155
|
-
- name: Upload SARIF results
|
|
156
|
-
uses: github/codeql-action/upload-sarif@v3
|
|
157
|
-
if: always()
|
|
158
|
-
with:
|
|
159
|
-
sarif_file: results.sarif
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
#### Option 2: Workflow Annotations
|
|
163
|
-
|
|
164
|
-
Show findings directly in workflow logs:
|
|
35
|
+
### Initialize configuration
|
|
165
36
|
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
on:
|
|
170
|
-
pull_request:
|
|
171
|
-
paths:
|
|
172
|
-
- '**.json'
|
|
173
|
-
|
|
174
|
-
jobs:
|
|
175
|
-
flowlint:
|
|
176
|
-
runs-on: ubuntu-latest
|
|
177
|
-
steps:
|
|
178
|
-
- uses: actions/checkout@v4
|
|
179
|
-
|
|
180
|
-
- name: Run FlowLint
|
|
181
|
-
run: npx flowlint scan --format github-actions --fail-on-error
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
#### Option 3: Both (Best of Both Worlds)
|
|
185
|
-
|
|
186
|
-
Combine both approaches for immediate feedback and permanent annotations:
|
|
187
|
-
|
|
188
|
-
```yaml
|
|
189
|
-
name: FlowLint
|
|
190
|
-
|
|
191
|
-
on:
|
|
192
|
-
pull_request:
|
|
193
|
-
paths:
|
|
194
|
-
- '**.json'
|
|
195
|
-
|
|
196
|
-
jobs:
|
|
197
|
-
flowlint:
|
|
198
|
-
runs-on: ubuntu-latest
|
|
199
|
-
permissions:
|
|
200
|
-
contents: read
|
|
201
|
-
security-events: write
|
|
202
|
-
steps:
|
|
203
|
-
- uses: actions/checkout@v4
|
|
204
|
-
|
|
205
|
-
- name: Run FlowLint (Workflow Annotations)
|
|
206
|
-
run: npx flowlint scan --format github-actions
|
|
207
|
-
continue-on-error: true
|
|
208
|
-
|
|
209
|
-
- name: Run FlowLint (SARIF)
|
|
210
|
-
run: npx flowlint scan --format sarif --out-file results.sarif
|
|
211
|
-
continue-on-error: true
|
|
212
|
-
|
|
213
|
-
- name: Upload SARIF results
|
|
214
|
-
uses: github/codeql-action/upload-sarif@v3
|
|
215
|
-
if: always()
|
|
216
|
-
with:
|
|
217
|
-
sarif_file: results.sarif
|
|
218
|
-
|
|
219
|
-
- name: Check for blocking issues
|
|
220
|
-
run: npx flowlint scan --fail-on-error
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
### GitLab CI
|
|
224
|
-
|
|
225
|
-
```yaml
|
|
226
|
-
flowlint:
|
|
227
|
-
stage: test
|
|
228
|
-
image: node:22
|
|
229
|
-
script:
|
|
230
|
-
- npx flowlint scan --format junit --out-file flowlint-results.xml
|
|
231
|
-
artifacts:
|
|
232
|
-
when: always
|
|
233
|
-
reports:
|
|
234
|
-
junit: flowlint-results.xml
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
### Jenkins
|
|
238
|
-
|
|
239
|
-
```groovy
|
|
240
|
-
pipeline {
|
|
241
|
-
agent any
|
|
242
|
-
|
|
243
|
-
stages {
|
|
244
|
-
stage('FlowLint') {
|
|
245
|
-
steps {
|
|
246
|
-
sh 'npx flowlint scan --format junit --out-file flowlint-results.xml'
|
|
247
|
-
}
|
|
248
|
-
post {
|
|
249
|
-
always {
|
|
250
|
-
junit 'flowlint-results.xml'
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
### CircleCI
|
|
259
|
-
|
|
260
|
-
```yaml
|
|
261
|
-
version: 2.1
|
|
262
|
-
|
|
263
|
-
jobs:
|
|
264
|
-
flowlint:
|
|
265
|
-
docker:
|
|
266
|
-
- image: cimg/node:22.0
|
|
267
|
-
steps:
|
|
268
|
-
- checkout
|
|
269
|
-
- run:
|
|
270
|
-
name: Run FlowLint
|
|
271
|
-
command: npx flowlint scan --format junit --out-file test-results/flowlint.xml
|
|
272
|
-
- store_test_results:
|
|
273
|
-
path: test-results
|
|
37
|
+
```bash
|
|
38
|
+
flowlint init
|
|
274
39
|
```
|
|
275
40
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
```yaml
|
|
279
|
-
trigger:
|
|
280
|
-
branches:
|
|
281
|
-
include:
|
|
282
|
-
- main
|
|
283
|
-
- develop
|
|
284
|
-
|
|
285
|
-
pool:
|
|
286
|
-
vmImage: 'ubuntu-latest'
|
|
287
|
-
|
|
288
|
-
steps:
|
|
289
|
-
- task: NodeTool@0
|
|
290
|
-
inputs:
|
|
291
|
-
versionSpec: '22.x'
|
|
292
|
-
|
|
293
|
-
- script: npx flowlint scan --format junit --out-file flowlint-results.xml
|
|
294
|
-
displayName: 'Run FlowLint'
|
|
295
|
-
|
|
296
|
-
- task: PublishTestResults@2
|
|
297
|
-
condition: always()
|
|
298
|
-
inputs:
|
|
299
|
-
testResultsFormat: 'JUnit'
|
|
300
|
-
testResultsFiles: 'flowlint-results.xml'
|
|
301
|
-
failTaskOnFailedTests: true
|
|
302
|
-
```
|
|
41
|
+
Creates a `.flowlint.yml` file in the current directory.
|
|
303
42
|
|
|
304
43
|
## Configuration
|
|
305
44
|
|
|
306
|
-
Create a `.flowlint.yml` file
|
|
45
|
+
Create a `.flowlint.yml` file:
|
|
307
46
|
|
|
308
47
|
```yaml
|
|
309
48
|
files:
|
|
310
49
|
include:
|
|
311
|
-
-
|
|
50
|
+
- "**/*.n8n.json"
|
|
312
51
|
ignore:
|
|
313
|
-
-
|
|
314
|
-
- 'dist/**'
|
|
315
|
-
|
|
316
|
-
report:
|
|
317
|
-
annotations: true
|
|
318
|
-
summary_limit: 100
|
|
52
|
+
- "node_modules/**"
|
|
319
53
|
|
|
320
54
|
rules:
|
|
321
|
-
|
|
55
|
+
rate_limit_retry:
|
|
322
56
|
enabled: true
|
|
323
|
-
|
|
57
|
+
error_handling:
|
|
324
58
|
enabled: true
|
|
325
|
-
# ...
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
- **R1** - Rate Limit & Retry
|
|
347
|
-
- **R2** - Error Handling
|
|
348
|
-
- **R3** - Idempotency
|
|
349
|
-
- **R4** - Secrets
|
|
350
|
-
- **R5** - Dead Ends
|
|
351
|
-
- **R6** - Long Running
|
|
352
|
-
- **R7** - Alert/Log Enforcement
|
|
353
|
-
- **R8** - Unused Data
|
|
354
|
-
- **R9** - Config Literals
|
|
355
|
-
- **R10** - Naming Convention
|
|
356
|
-
- **R11** - Deprecated Nodes
|
|
357
|
-
- **R12** - Unhandled Error Path
|
|
358
|
-
- **R13** - Webhook Acknowledgment
|
|
359
|
-
- **R14** - HTTP Retry-After Compliance
|
|
360
|
-
|
|
361
|
-
See [RULES.md](https://github.com/Replikanti/flowlint-examples/blob/main/README.md) for detailed rule documentation.
|
|
362
|
-
|
|
363
|
-
## Troubleshooting
|
|
59
|
+
# ... more rules
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Rules
|
|
63
|
+
|
|
64
|
+
| Rule | Description | Severity |
|
|
65
|
+
|------|-------------|----------|
|
|
66
|
+
| R1 | Rate limit retry | must |
|
|
67
|
+
| R2 | Error handling | must |
|
|
68
|
+
| R3 | Idempotency | should |
|
|
69
|
+
| R4 | Secrets exposure | must |
|
|
70
|
+
| R5 | Dead ends | nit |
|
|
71
|
+
| R6 | Long running | should |
|
|
72
|
+
| R7 | Alert/log enforcement | should |
|
|
73
|
+
| R8 | Unused data | nit |
|
|
74
|
+
| R9 | Config literals | should |
|
|
75
|
+
| R10 | Naming convention | nit |
|
|
76
|
+
| R11 | Deprecated nodes | should |
|
|
77
|
+
| R12 | Unhandled error path | must |
|
|
78
|
+
| R13 | Webhook acknowledgment | must |
|
|
79
|
+
| R14 | Retry-After compliance | should |
|
|
364
80
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
Make sure your workflow files match the glob patterns in `.flowlint.yml`:
|
|
368
|
-
|
|
369
|
-
```yaml
|
|
370
|
-
files:
|
|
371
|
-
include:
|
|
372
|
-
- '**/*.json' # Adjust pattern as needed
|
|
373
|
-
```
|
|
374
|
-
|
|
375
|
-
### SARIF upload fails in GitHub Actions
|
|
376
|
-
|
|
377
|
-
Ensure you have the correct permissions:
|
|
378
|
-
|
|
379
|
-
```yaml
|
|
380
|
-
permissions:
|
|
381
|
-
contents: read
|
|
382
|
-
security-events: write # Required for SARIF upload
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
### JUnit results not showing in CI
|
|
386
|
-
|
|
387
|
-
Make sure the file path in your CI configuration matches the `--out-file` path.
|
|
81
|
+
## License
|
|
388
82
|
|
|
389
|
-
|
|
83
|
+
MIT
|
|
390
84
|
|
|
391
|
-
- [Documentation](https://flowlint.dev)
|
|
392
|
-
- [GitHub Repository](https://github.com/Replikanti/flowlint-app)
|
|
393
|
-
- [Issue Tracker](https://github.com/Replikanti/flowlint-app/issues)
|
|
394
|
-
- [npm Package](https://www.npmjs.com/package/flowlint)
|
|
395
85
|
|
|
396
|
-
##
|
|
86
|
+
## Dependencies
|
|
397
87
|
|
|
398
|
-
|
|
88
|
+
This tool depends on [@replikanti/flowlint-core](https://www.npmjs.com/package/@replikanti/flowlint-core) for linting logic.
|
package/dist/cli.js
CHANGED
|
@@ -1,27 +1,169 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
//
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/cli.ts
|
|
27
|
+
var import_commander3 = require("commander");
|
|
28
|
+
|
|
29
|
+
// src/commands/scan.ts
|
|
30
|
+
var import_commander = require("commander");
|
|
31
|
+
var fs = __toESM(require("fs"));
|
|
32
|
+
var path = __toESM(require("path"));
|
|
33
|
+
var import_glob = require("glob");
|
|
34
|
+
var import_picocolors = __toESM(require("picocolors"));
|
|
35
|
+
var import_flowlint_core = require("@replikanti/flowlint-core");
|
|
36
|
+
var scanCommand = new import_commander.Command("scan").description("Scan workflow files for issues").argument("[path]", "Directory or file to scan", ".").option("--config <path>", "Path to .flowlint.yml config file").option("--format <format>", "Output format: stylish|json", "stylish").option("--fail-on-error", "Exit with code 1 if errors found", false).action(async (scanPath, options) => {
|
|
37
|
+
try {
|
|
38
|
+
const absolutePath = path.resolve(process.cwd(), scanPath);
|
|
39
|
+
const config = options.config ? (0, import_flowlint_core.loadConfig)(options.config) : (0, import_flowlint_core.loadConfig)();
|
|
40
|
+
const patterns = config.files.include.map(
|
|
41
|
+
(p) => path.join(absolutePath, p).replace(/\\/g, "/")
|
|
42
|
+
);
|
|
43
|
+
const ignorePatterns = config.files.ignore.map(
|
|
44
|
+
(p) => path.join(absolutePath, p).replace(/\\/g, "/")
|
|
45
|
+
);
|
|
46
|
+
const files = await (0, import_glob.glob)(patterns, {
|
|
47
|
+
ignore: ignorePatterns,
|
|
48
|
+
nodir: true
|
|
49
|
+
});
|
|
50
|
+
if (files.length === 0) {
|
|
51
|
+
console.log(import_picocolors.default.yellow("No workflow files found."));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
console.log(import_picocolors.default.blue("Scanning " + files.length + " file(s)..."));
|
|
55
|
+
const allFindings = [];
|
|
56
|
+
let errorCount = 0;
|
|
57
|
+
for (const file of files) {
|
|
58
|
+
try {
|
|
59
|
+
const content = fs.readFileSync(file, "utf-8");
|
|
60
|
+
const relativePath = path.relative(process.cwd(), file);
|
|
61
|
+
const graph = (0, import_flowlint_core.parseN8n)(content);
|
|
62
|
+
const findings = (0, import_flowlint_core.runAllRules)(graph, {
|
|
63
|
+
path: relativePath,
|
|
64
|
+
cfg: config,
|
|
65
|
+
nodeLines: graph.meta.nodeLines
|
|
66
|
+
});
|
|
67
|
+
allFindings.push(...findings);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
if (error instanceof import_flowlint_core.ValidationError) {
|
|
70
|
+
console.log(import_picocolors.default.red("x " + path.relative(process.cwd(), file) + ": Validation error"));
|
|
71
|
+
error.errors.forEach((e) => {
|
|
72
|
+
console.log(import_picocolors.default.gray(" " + e.path + ": " + e.message));
|
|
73
|
+
});
|
|
74
|
+
} else {
|
|
75
|
+
console.log(import_picocolors.default.red("x " + path.relative(process.cwd(), file) + ": " + (error instanceof Error ? error.message : String(error))));
|
|
76
|
+
}
|
|
77
|
+
errorCount++;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (options.format === "json") {
|
|
81
|
+
console.log(JSON.stringify({
|
|
82
|
+
findings: allFindings,
|
|
83
|
+
summary: (0, import_flowlint_core.countFindingsBySeverity)(allFindings),
|
|
84
|
+
filesScanned: files.length,
|
|
85
|
+
errors: errorCount
|
|
86
|
+
}, null, 2));
|
|
87
|
+
} else {
|
|
88
|
+
printStylishOutput(allFindings);
|
|
89
|
+
}
|
|
90
|
+
const summary = (0, import_flowlint_core.countFindingsBySeverity)(allFindings);
|
|
91
|
+
console.log("");
|
|
92
|
+
console.log(import_picocolors.default.bold("Summary:"));
|
|
93
|
+
console.log(" Files scanned: " + files.length);
|
|
94
|
+
console.log(" " + import_picocolors.default.red("Errors (must): " + summary.must));
|
|
95
|
+
console.log(" " + import_picocolors.default.yellow("Warnings (should): " + summary.should));
|
|
96
|
+
console.log(" " + import_picocolors.default.blue("Notes (nit): " + summary.nit));
|
|
97
|
+
if (options.failOnError && summary.must > 0) {
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.error(import_picocolors.default.red("Error:"), error instanceof Error ? error.message : String(error));
|
|
102
|
+
process.exit(2);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
function printStylishOutput(findings) {
|
|
106
|
+
if (findings.length === 0) {
|
|
107
|
+
console.log(import_picocolors.default.green("No issues found!"));
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
111
|
+
for (const finding of findings) {
|
|
112
|
+
const existing = byFile.get(finding.path) || [];
|
|
113
|
+
existing.push(finding);
|
|
114
|
+
byFile.set(finding.path, existing);
|
|
115
|
+
}
|
|
116
|
+
for (const [file, fileFindings] of byFile) {
|
|
117
|
+
console.log("");
|
|
118
|
+
console.log(import_picocolors.default.underline(file));
|
|
119
|
+
for (const finding of fileFindings) {
|
|
120
|
+
const severityColor = finding.severity === "must" ? import_picocolors.default.red : finding.severity === "should" ? import_picocolors.default.yellow : import_picocolors.default.blue;
|
|
121
|
+
const line = finding.line ? ":" + finding.line : "";
|
|
122
|
+
console.log(
|
|
123
|
+
" " + severityColor(finding.severity.padEnd(6)) + " " + import_picocolors.default.gray(finding.rule) + " " + finding.message + import_picocolors.default.gray(line)
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// src/commands/init.ts
|
|
130
|
+
var import_commander2 = require("commander");
|
|
131
|
+
var fs2 = __toESM(require("fs"));
|
|
132
|
+
var path2 = __toESM(require("path"));
|
|
133
|
+
var import_picocolors2 = __toESM(require("picocolors"));
|
|
134
|
+
var import_flowlint_core2 = require("@replikanti/flowlint-core");
|
|
135
|
+
var import_yaml = __toESM(require("yaml"));
|
|
136
|
+
var initCommand = new import_commander2.Command("init").description("Initialize FlowLint configuration in the current directory").option("--force", "Overwrite existing config file", false).action((options) => {
|
|
137
|
+
const configPath = path2.join(process.cwd(), ".flowlint.yml");
|
|
138
|
+
if (fs2.existsSync(configPath) && !options.force) {
|
|
139
|
+
console.log(import_picocolors2.default.yellow(".flowlint.yml already exists. Use --force to overwrite."));
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const userConfig = {
|
|
143
|
+
files: {
|
|
144
|
+
include: import_flowlint_core2.defaultConfig.files.include,
|
|
145
|
+
ignore: import_flowlint_core2.defaultConfig.files.ignore
|
|
146
|
+
},
|
|
147
|
+
rules: Object.fromEntries(
|
|
148
|
+
Object.entries(import_flowlint_core2.defaultConfig.rules).map(([key, value]) => [
|
|
149
|
+
key,
|
|
150
|
+
{ enabled: value.enabled }
|
|
151
|
+
])
|
|
152
|
+
)
|
|
153
|
+
};
|
|
154
|
+
const yamlContent = import_yaml.default.stringify(userConfig);
|
|
155
|
+
fs2.writeFileSync(configPath, yamlContent, "utf-8");
|
|
156
|
+
console.log(import_picocolors2.default.green("Created .flowlint.yml"));
|
|
157
|
+
console.log(import_picocolors2.default.gray("Edit this file to customize FlowLint behavior."));
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// src/cli.ts
|
|
161
|
+
var program = new import_commander3.Command();
|
|
162
|
+
program.name("flowlint").description("Static analysis tool for n8n workflows").version("0.6.0");
|
|
163
|
+
program.addCommand(scanCommand);
|
|
164
|
+
program.addCommand(initCommand);
|
|
22
165
|
program.parse(process.argv);
|
|
23
|
-
// Show help if no command provided
|
|
24
166
|
if (!process.argv.slice(2).length) {
|
|
25
|
-
|
|
167
|
+
program.outputHelp();
|
|
26
168
|
}
|
|
27
169
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../../apps/cli/src/cli.ts"],"names":[],"mappings":";;AAEA;;;;;GAKG;;AAEH,yCAAoC;AACpC,0CAA8C;AAC9C,0CAA8C;AAE9C,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,wCAAwC,CAAC;KACrD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,oBAAoB;AACpB,OAAO,CAAC,UAAU,CAAC,kBAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,kBAAW,CAAC,CAAC;AAEhC,oBAAoB;AACpB,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAE5B,mCAAmC;AACnC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAClC,OAAO,CAAC,UAAU,EAAE,CAAC;AACvB,CAAC"}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/commands/scan.ts","../src/commands/init.ts"],"sourcesContent":["/**\n * FlowLint CLI\n *\n * A command-line tool for static analysis of n8n workflow files.\n * Can be used locally, in CI pipelines, or pre-commit hooks.\n */\n\nimport { Command } from 'commander';\nimport { scanCommand } from './commands/scan';\nimport { initCommand } from './commands/init';\n\nconst program = new Command();\n\nprogram\n .name('flowlint')\n .description('Static analysis tool for n8n workflows')\n .version('0.6.0');\n\n// Register commands\nprogram.addCommand(scanCommand);\nprogram.addCommand(initCommand);\n\n// Parse and execute\nprogram.parse(process.argv);\n\n// Show help if no command provided\nif (!process.argv.slice(2).length) {\n program.outputHelp();\n}","/**\n * scan command - Analyze n8n workflow files in a directory\n */\n\nimport { Command } from 'commander';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { glob } from 'glob';\nimport pc from 'picocolors';\nimport { \n parseN8n, \n runAllRules, \n loadConfig, \n ValidationError,\n countFindingsBySeverity,\n type Finding,\n type FlowLintConfig\n} from '@replikanti/flowlint-core';\n\ninterface ScanOptions {\n config?: string;\n format: string;\n failOnError: boolean;\n}\n\nexport const scanCommand = new Command('scan')\n .description('Scan workflow files for issues')\n .argument('[path]', 'Directory or file to scan', '.')\n .option('--config <path>', 'Path to .flowlint.yml config file')\n .option('--format <format>', 'Output format: stylish|json', 'stylish')\n .option('--fail-on-error', 'Exit with code 1 if errors found', false)\n .action(async (scanPath: string, options: ScanOptions) => {\n try {\n const absolutePath = path.resolve(process.cwd(), scanPath);\n \n // Load configuration\n const config: FlowLintConfig = options.config \n ? loadConfig(options.config)\n : loadConfig();\n\n // Find workflow files\n const patterns = config.files.include.map(p => \n path.join(absolutePath, p).replace(/\\\\/g, '/')\n );\n \n const ignorePatterns = config.files.ignore.map(p =>\n path.join(absolutePath, p).replace(/\\\\/g, '/')\n );\n\n const files = await glob(patterns, { \n ignore: ignorePatterns,\n nodir: true \n });\n\n if (files.length === 0) {\n console.log(pc.yellow('No workflow files found.'));\n return;\n }\n\n console.log(pc.blue('Scanning ' + files.length + ' file(s)...'));\n\n // Analyze files\n const allFindings: Finding[] = [];\n let errorCount = 0;\n\n for (const file of files) {\n try {\n const content = fs.readFileSync(file, 'utf-8');\n const relativePath = path.relative(process.cwd(), file);\n \n const graph = parseN8n(content);\n const findings = runAllRules(graph, {\n path: relativePath,\n cfg: config,\n nodeLines: graph.meta.nodeLines as Record<string, number> | undefined,\n });\n\n allFindings.push(...findings);\n } catch (error) {\n if (error instanceof ValidationError) {\n console.log(pc.red('x ' + path.relative(process.cwd(), file) + ': Validation error'));\n error.errors.forEach(e => {\n console.log(pc.gray(' ' + e.path + ': ' + e.message));\n });\n } else {\n console.log(pc.red('x ' + path.relative(process.cwd(), file) + ': ' + (error instanceof Error ? error.message : String(error))));\n }\n errorCount++;\n }\n }\n\n // Output results\n if (options.format === 'json') {\n console.log(JSON.stringify({\n findings: allFindings,\n summary: countFindingsBySeverity(allFindings),\n filesScanned: files.length,\n errors: errorCount,\n }, null, 2));\n } else {\n // Stylish format\n printStylishOutput(allFindings);\n }\n\n // Summary\n const summary = countFindingsBySeverity(allFindings);\n console.log('');\n console.log(pc.bold('Summary:'));\n console.log(' Files scanned: ' + files.length);\n console.log(' ' + pc.red('Errors (must): ' + summary.must));\n console.log(' ' + pc.yellow('Warnings (should): ' + summary.should));\n console.log(' ' + pc.blue('Notes (nit): ' + summary.nit));\n\n // Exit code\n if (options.failOnError && summary.must > 0) {\n process.exit(1);\n }\n } catch (error) {\n console.error(pc.red('Error:'), error instanceof Error ? error.message : String(error));\n process.exit(2);\n }\n });\n\nfunction printStylishOutput(findings: Finding[]): void {\n if (findings.length === 0) {\n console.log(pc.green('No issues found!'));\n return;\n }\n\n // Group by file\n const byFile = new Map<string, Finding[]>();\n for (const finding of findings) {\n const existing = byFile.get(finding.path) || [];\n existing.push(finding);\n byFile.set(finding.path, existing);\n }\n\n for (const [file, fileFindings] of byFile) {\n console.log('');\n console.log(pc.underline(file));\n \n for (const finding of fileFindings) {\n const severityColor = finding.severity === 'must' \n ? pc.red \n : finding.severity === 'should' \n ? pc.yellow \n : pc.blue;\n \n const line = finding.line ? ':' + finding.line : '';\n console.log(\n ' ' + severityColor(finding.severity.padEnd(6)) + ' ' + pc.gray(finding.rule) + ' ' + finding.message + pc.gray(line)\n );\n }\n }\n}\r\n\r\n\r\n","/**\n * init command - Initialize FlowLint configuration\n */\n\nimport { Command } from 'commander';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport pc from 'picocolors';\nimport { defaultConfig } from '@replikanti/flowlint-core';\nimport YAML from 'yaml';\n\nexport const initCommand = new Command('init')\n .description('Initialize FlowLint configuration in the current directory')\n .option('--force', 'Overwrite existing config file', false)\n .action((options: { force: boolean }) => {\n const configPath = path.join(process.cwd(), '.flowlint.yml');\n\n if (fs.existsSync(configPath) && !options.force) {\n console.log(pc.yellow('.flowlint.yml already exists. Use --force to overwrite.'));\n return;\n }\n\n // Create a simplified config for user\n const userConfig = {\n files: {\n include: defaultConfig.files.include,\n ignore: defaultConfig.files.ignore,\n },\n rules: Object.fromEntries(\n Object.entries(defaultConfig.rules).map(([key, value]) => [\n key,\n { enabled: value.enabled },\n ])\n ),\n };\n\n const yamlContent = YAML.stringify(userConfig);\n fs.writeFileSync(configPath, yamlContent, 'utf-8');\n\n console.log(pc.green('Created .flowlint.yml'));\n console.log(pc.gray('Edit this file to customize FlowLint behavior.'));\n });\r\n\r\n\r\n"],"mappings":"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","names":["import_commander","pc","import_commander","fs","path","import_picocolors","import_flowlint_core","pc","YAML"]}
|