@eventcatalog/linter 0.0.1
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 +583 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +54 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/parser/index.d.ts +17 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +43 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/reporters/index.d.ts +16 -0
- package/dist/reporters/index.d.ts.map +1 -0
- package/dist/reporters/index.js +151 -0
- package/dist/reporters/index.js.map +1 -0
- package/dist/scanner/index.d.ts +14 -0
- package/dist/scanner/index.d.ts.map +1 -0
- package/dist/scanner/index.js +99 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/schemas/channel.d.ts +389 -0
- package/dist/schemas/channel.d.ts.map +1 -0
- package/dist/schemas/channel.js +20 -0
- package/dist/schemas/channel.js.map +1 -0
- package/dist/schemas/common.d.ts +550 -0
- package/dist/schemas/common.d.ts.map +1 -0
- package/dist/schemas/common.js +144 -0
- package/dist/schemas/common.js.map +1 -0
- package/dist/schemas/domain.d.ts +381 -0
- package/dist/schemas/domain.d.ts.map +1 -0
- package/dist/schemas/domain.js +13 -0
- package/dist/schemas/domain.js.map +1 -0
- package/dist/schemas/entity.d.ts +382 -0
- package/dist/schemas/entity.d.ts.map +1 -0
- package/dist/schemas/entity.js +24 -0
- package/dist/schemas/entity.js.map +1 -0
- package/dist/schemas/flow.d.ts +733 -0
- package/dist/schemas/flow.d.ts.map +1 -0
- package/dist/schemas/flow.js +70 -0
- package/dist/schemas/flow.js.map +1 -0
- package/dist/schemas/index.d.ts +3432 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +47 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/message.d.ts +1076 -0
- package/dist/schemas/message.d.ts.map +1 -0
- package/dist/schemas/message.js +17 -0
- package/dist/schemas/message.js.map +1 -0
- package/dist/schemas/service.d.ts +381 -0
- package/dist/schemas/service.d.ts.map +1 -0
- package/dist/schemas/service.js +13 -0
- package/dist/schemas/service.js.map +1 -0
- package/dist/schemas/team.d.ts +45 -0
- package/dist/schemas/team.d.ts.map +1 -0
- package/dist/schemas/team.js +20 -0
- package/dist/schemas/team.js.map +1 -0
- package/dist/schemas/user.d.ts +48 -0
- package/dist/schemas/user.d.ts.map +1 -0
- package/dist/schemas/user.js +21 -0
- package/dist/schemas/user.js.map +1 -0
- package/dist/types/index.d.ts +81 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/validators/index.d.ts +6 -0
- package/dist/validators/index.d.ts.map +1 -0
- package/dist/validators/index.js +28 -0
- package/dist/validators/index.js.map +1 -0
- package/dist/validators/reference-validator.d.ts +11 -0
- package/dist/validators/reference-validator.d.ts.map +1 -0
- package/dist/validators/reference-validator.js +171 -0
- package/dist/validators/reference-validator.js.map +1 -0
- package/dist/validators/schema-validator.d.ts +5 -0
- package/dist/validators/schema-validator.d.ts.map +1 -0
- package/dist/validators/schema-validator.js +50 -0
- package/dist/validators/schema-validator.js.map +1 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
# EventCatalog Linter
|
|
2
|
+
|
|
3
|
+
A comprehensive linter for EventCatalog that validates frontmatter schemas and resource references to ensure your event-driven architecture documentation is correct and consistent.
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/js/eventcatalog-linter)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## 🚀 Features
|
|
9
|
+
|
|
10
|
+
- **📋 Schema Validation**: Validates all resource frontmatter against defined schemas using Zod
|
|
11
|
+
- **🔗 Reference Validation**: Ensures all referenced resources (services, events, domains, etc.) actually exist
|
|
12
|
+
- **📦 Semver Version Support**: Supports semantic versions, ranges (`^1.0.0`, `~1.2.0`), x-patterns (`0.0.x`), and `latest`
|
|
13
|
+
- **🎯 Comprehensive Coverage**: Supports all EventCatalog resource types
|
|
14
|
+
- **⚡ Fast Performance**: Efficiently scans large catalogs
|
|
15
|
+
- **🎨 ESLint-Inspired Output**: Clean, file-grouped error reporting with severity levels
|
|
16
|
+
- **⚠️ Warnings Support**: Distinguish between errors and warnings with `--fail-on-warning` option
|
|
17
|
+
- **🧪 Well Tested**: Comprehensive test suite with 100% coverage
|
|
18
|
+
|
|
19
|
+
### Supported Resource Types
|
|
20
|
+
|
|
21
|
+
- 🏢 **Domains** (including subdomains)
|
|
22
|
+
- ⚙️ **Services**
|
|
23
|
+
- 📨 **Events**
|
|
24
|
+
- 📤 **Commands**
|
|
25
|
+
- ❓ **Queries**
|
|
26
|
+
- 📡 **Channels**
|
|
27
|
+
- 🔄 **Flows**
|
|
28
|
+
- 📊 **Entities**
|
|
29
|
+
- 👤 **Users**
|
|
30
|
+
- 👥 **Teams**
|
|
31
|
+
|
|
32
|
+
## 📦 Installation
|
|
33
|
+
|
|
34
|
+
### Global Installation
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install -g @eventcatalog/linter
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Use with npx (Recommended)
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npx @eventcatalog/linter
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Add to your project
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm install --save-dev @eventcatalog/linter
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## 🛠️ Usage
|
|
53
|
+
|
|
54
|
+
### Basic Usage
|
|
55
|
+
|
|
56
|
+
Run the linter in your EventCatalog directory:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Lint current directory
|
|
60
|
+
eventcatalog-linter
|
|
61
|
+
|
|
62
|
+
# Lint specific directory
|
|
63
|
+
eventcatalog-linter ./my-eventcatalog
|
|
64
|
+
|
|
65
|
+
# Verbose output with detailed information
|
|
66
|
+
eventcatalog-linter --verbose
|
|
67
|
+
|
|
68
|
+
# Show help
|
|
69
|
+
eventcatalog-linter --help
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### CLI Options
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
Usage: eventcatalog-linter [options] [directory]
|
|
76
|
+
|
|
77
|
+
Arguments:
|
|
78
|
+
directory EventCatalog directory to lint (default: ".")
|
|
79
|
+
|
|
80
|
+
Options:
|
|
81
|
+
-V, --version output the version number
|
|
82
|
+
-v, --verbose Show verbose output (default: false)
|
|
83
|
+
--fail-on-warning Exit with non-zero code on warnings (default: false)
|
|
84
|
+
-h, --help display help for command
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Package.json Integration
|
|
88
|
+
|
|
89
|
+
Add to your `package.json` scripts:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"scripts": {
|
|
94
|
+
"lint:eventcatalog": "@eventcatalog/linter",
|
|
95
|
+
"lint:eventcatalog:verbose": "@eventcatalog/linter --verbose"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### CI/CD Integration
|
|
101
|
+
|
|
102
|
+
#### GitHub Actions
|
|
103
|
+
|
|
104
|
+
```yaml
|
|
105
|
+
name: EventCatalog Lint
|
|
106
|
+
on: [push, pull_request]
|
|
107
|
+
|
|
108
|
+
jobs:
|
|
109
|
+
lint:
|
|
110
|
+
runs-on: ubuntu-latest
|
|
111
|
+
steps:
|
|
112
|
+
- uses: actions/checkout@v3
|
|
113
|
+
- uses: actions/setup-node@v3
|
|
114
|
+
with:
|
|
115
|
+
node-version: '18'
|
|
116
|
+
- run: npx @eventcatalog/linter
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### GitLab CI
|
|
120
|
+
|
|
121
|
+
```yaml
|
|
122
|
+
eventcatalog-lint:
|
|
123
|
+
stage: test
|
|
124
|
+
image: node:18
|
|
125
|
+
script:
|
|
126
|
+
- npx @eventcatalog/linter
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## ✅ What It Validates
|
|
130
|
+
|
|
131
|
+
### Frontmatter Schema Validation
|
|
132
|
+
|
|
133
|
+
- ✅ Required fields are present (`id`, `name`, `version`)
|
|
134
|
+
- ✅ Field types are correct (strings, arrays, objects)
|
|
135
|
+
- ✅ Semantic versions follow proper format (`1.0.0`, `2.1.3-beta`)
|
|
136
|
+
- ✅ Version patterns supported (`latest`, `^1.0.0`, `~1.2.0`, `0.0.x`)
|
|
137
|
+
- ✅ URLs are valid format
|
|
138
|
+
- ✅ Email addresses are valid format
|
|
139
|
+
- ✅ Enum values are from allowed lists
|
|
140
|
+
- ✅ Nested object structures are correct
|
|
141
|
+
|
|
142
|
+
### Reference Validation
|
|
143
|
+
|
|
144
|
+
- ✅ Services referenced in domains exist
|
|
145
|
+
- ✅ Events/Commands/Queries referenced in services exist
|
|
146
|
+
- ✅ Entities referenced in domains/services exist
|
|
147
|
+
- ✅ Users/Teams referenced as owners exist
|
|
148
|
+
- ✅ Flow steps reference existing services/messages
|
|
149
|
+
- ✅ Entity properties reference existing entities
|
|
150
|
+
- ✅ Version-specific references are valid
|
|
151
|
+
|
|
152
|
+
### Example EventCatalog Structure
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
my-eventcatalog/
|
|
156
|
+
├── domains/
|
|
157
|
+
│ └── sales/
|
|
158
|
+
│ └── index.mdx
|
|
159
|
+
├── services/
|
|
160
|
+
│ ├── user-service/
|
|
161
|
+
│ │ └── index.mdx
|
|
162
|
+
│ └── order-service/
|
|
163
|
+
│ ├── index.mdx
|
|
164
|
+
│ └── 2.0.0/
|
|
165
|
+
│ └── index.mdx
|
|
166
|
+
├── events/
|
|
167
|
+
│ ├── user-created/
|
|
168
|
+
│ │ └── index.mdx
|
|
169
|
+
│ └── order-placed/
|
|
170
|
+
│ └── index.mdx
|
|
171
|
+
├── commands/
|
|
172
|
+
│ └── create-user/
|
|
173
|
+
│ └── index.mdx
|
|
174
|
+
├── flows/
|
|
175
|
+
│ └── user-registration/
|
|
176
|
+
│ └── index.mdx
|
|
177
|
+
├── entities/
|
|
178
|
+
│ ├── user/
|
|
179
|
+
│ │ └── index.mdx
|
|
180
|
+
│ └── order/
|
|
181
|
+
│ └── index.mdx
|
|
182
|
+
├── users/
|
|
183
|
+
│ ├── john-doe.mdx
|
|
184
|
+
│ └── jane-smith.mdx
|
|
185
|
+
└── teams/
|
|
186
|
+
└── platform-team.mdx
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## 📊 Example Output
|
|
190
|
+
|
|
191
|
+
### ✅ Success Output
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
$ eventcatalog-linter
|
|
195
|
+
|
|
196
|
+
✔ No problems found!
|
|
197
|
+
|
|
198
|
+
42 files checked
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### ❌ Error Output
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
$ eventcatalog-linter
|
|
205
|
+
|
|
206
|
+
services/user-service/index.mdx
|
|
207
|
+
✖ error version: Invalid semantic version format [version] (@eventcatalog/schema-validation)
|
|
208
|
+
⚠ warning summary should be provided for better documentation [summary] (@eventcatalog/schema-validation)
|
|
209
|
+
|
|
210
|
+
✖ 2 problems
|
|
211
|
+
|
|
212
|
+
domains/sales/index.mdx
|
|
213
|
+
✖ error Referenced service "order-service" does not exist [services] (@eventcatalog/invalid-reference)
|
|
214
|
+
|
|
215
|
+
✖ 1 problem
|
|
216
|
+
|
|
217
|
+
flows/user-registration/index.mdx
|
|
218
|
+
✖ error Referenced service "notification-service" (version: 2.0.0) does not exist [steps[1].service] (@eventcatalog/invalid-reference)
|
|
219
|
+
|
|
220
|
+
✖ 1 problem
|
|
221
|
+
|
|
222
|
+
✖ 4 problems (3 errors, 1 warning)
|
|
223
|
+
3 files checked
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### 🔍 Verbose Output
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
$ eventcatalog-linter --verbose
|
|
230
|
+
|
|
231
|
+
services/user-service/index.mdx
|
|
232
|
+
✖ error version: Invalid semantic version format [version] (@eventcatalog/schema-validation)
|
|
233
|
+
|
|
234
|
+
✖ 1 problem
|
|
235
|
+
|
|
236
|
+
domains/sales/index.mdx
|
|
237
|
+
✖ error Referenced service "order-service" does not exist [services] (@eventcatalog/invalid-reference)
|
|
238
|
+
|
|
239
|
+
✖ 1 problem
|
|
240
|
+
|
|
241
|
+
✖ 2 problems (2 errors, 0 warnings)
|
|
242
|
+
2 files checked
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## 🧪 Validation Examples
|
|
246
|
+
|
|
247
|
+
### Valid Frontmatter Examples
|
|
248
|
+
|
|
249
|
+
#### Domain
|
|
250
|
+
|
|
251
|
+
```yaml
|
|
252
|
+
---
|
|
253
|
+
id: sales
|
|
254
|
+
name: Sales Domain
|
|
255
|
+
version: 1.0.0
|
|
256
|
+
summary: Handles all sales-related operations
|
|
257
|
+
owners:
|
|
258
|
+
- sales-team
|
|
259
|
+
services:
|
|
260
|
+
- id: order-service
|
|
261
|
+
version: 2.0.0
|
|
262
|
+
- id: payment-service
|
|
263
|
+
entities:
|
|
264
|
+
- id: order
|
|
265
|
+
- id: customer
|
|
266
|
+
version: 1.2.0
|
|
267
|
+
---
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
#### Service
|
|
271
|
+
|
|
272
|
+
```yaml
|
|
273
|
+
---
|
|
274
|
+
id: user-service
|
|
275
|
+
name: User Service
|
|
276
|
+
version: 2.1.0
|
|
277
|
+
summary: Manages user accounts and authentication
|
|
278
|
+
owners:
|
|
279
|
+
- platform-team
|
|
280
|
+
- john-doe
|
|
281
|
+
sends:
|
|
282
|
+
- id: user-created
|
|
283
|
+
version: 1.0.0
|
|
284
|
+
- id: user-updated
|
|
285
|
+
receives:
|
|
286
|
+
- id: create-user
|
|
287
|
+
- id: update-user
|
|
288
|
+
entities:
|
|
289
|
+
- id: user
|
|
290
|
+
repository:
|
|
291
|
+
language: TypeScript
|
|
292
|
+
url: https://github.com/company/user-service
|
|
293
|
+
---
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
#### Event
|
|
297
|
+
|
|
298
|
+
```yaml
|
|
299
|
+
---
|
|
300
|
+
id: user-created
|
|
301
|
+
name: User Created
|
|
302
|
+
version: 1.0.0
|
|
303
|
+
summary: Triggered when a new user account is created
|
|
304
|
+
owners:
|
|
305
|
+
- platform-team
|
|
306
|
+
sidebar:
|
|
307
|
+
badge: POST
|
|
308
|
+
label: User Events
|
|
309
|
+
draft: false
|
|
310
|
+
deprecated: false
|
|
311
|
+
---
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
#### Flow
|
|
315
|
+
|
|
316
|
+
```yaml
|
|
317
|
+
---
|
|
318
|
+
id: user-registration
|
|
319
|
+
name: User Registration Flow
|
|
320
|
+
version: 1.0.0
|
|
321
|
+
summary: Complete user registration process
|
|
322
|
+
steps:
|
|
323
|
+
- id: step1
|
|
324
|
+
title: User submits registration form
|
|
325
|
+
actor:
|
|
326
|
+
name: User
|
|
327
|
+
next_step: step2
|
|
328
|
+
- id: step2
|
|
329
|
+
title: Validate user data
|
|
330
|
+
service:
|
|
331
|
+
id: user-service
|
|
332
|
+
version: 2.0.0
|
|
333
|
+
next_step: step3
|
|
334
|
+
- id: step3
|
|
335
|
+
title: Send welcome email
|
|
336
|
+
message:
|
|
337
|
+
id: user-created
|
|
338
|
+
version: 1.0.0
|
|
339
|
+
---
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## 📦 Version Pattern Support
|
|
343
|
+
|
|
344
|
+
The linter supports flexible version patterns for resource references, making it easy to work with different versioning strategies:
|
|
345
|
+
|
|
346
|
+
### Supported Version Patterns
|
|
347
|
+
|
|
348
|
+
#### Exact Versions
|
|
349
|
+
|
|
350
|
+
```yaml
|
|
351
|
+
sends:
|
|
352
|
+
- id: user-created
|
|
353
|
+
version: 1.0.0 # Exact semantic version
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
#### Latest Version
|
|
357
|
+
|
|
358
|
+
```yaml
|
|
359
|
+
sends:
|
|
360
|
+
- id: user-created
|
|
361
|
+
version: latest # Always use the latest available version
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
#### Semver Ranges
|
|
365
|
+
|
|
366
|
+
```yaml
|
|
367
|
+
sends:
|
|
368
|
+
- id: user-created
|
|
369
|
+
version: ^1.0.0 # Compatible with 1.x.x (1.0.0, 1.2.3, but not 2.0.0)
|
|
370
|
+
- id: user-updated
|
|
371
|
+
version: ~1.2.0 # Compatible with 1.2.x (1.2.0, 1.2.5, but not 1.3.0)
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
#### X-Pattern Matching
|
|
375
|
+
|
|
376
|
+
```yaml
|
|
377
|
+
sends:
|
|
378
|
+
- id: user-created
|
|
379
|
+
version: 0.0.x # Matches 0.0.1, 0.0.5, 0.0.12, etc.
|
|
380
|
+
- id: order-placed
|
|
381
|
+
version: 1.x # Matches 1.0.0, 1.5.3, 1.99.0, etc.
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
#### Real-World Example
|
|
385
|
+
|
|
386
|
+
```yaml
|
|
387
|
+
---
|
|
388
|
+
id: inventory-service
|
|
389
|
+
name: Inventory Service
|
|
390
|
+
version: 2.1.0
|
|
391
|
+
sends:
|
|
392
|
+
- id: OutOfStock
|
|
393
|
+
version: latest # Always use latest version
|
|
394
|
+
- id: GetInventoryList
|
|
395
|
+
version: 0.0.x # Use any 0.0.x version
|
|
396
|
+
- id: StockUpdated
|
|
397
|
+
version: ^1.0.0 # Use compatible 1.x versions
|
|
398
|
+
---
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Common Validation Errors
|
|
402
|
+
|
|
403
|
+
#### ❌ Missing Required Fields
|
|
404
|
+
|
|
405
|
+
```yaml
|
|
406
|
+
---
|
|
407
|
+
# Missing 'id' field
|
|
408
|
+
name: User Service
|
|
409
|
+
version: 1.0.0
|
|
410
|
+
---
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
#### ❌ Invalid Semantic Version
|
|
414
|
+
|
|
415
|
+
```yaml
|
|
416
|
+
---
|
|
417
|
+
id: user-service
|
|
418
|
+
name: User Service
|
|
419
|
+
version: v1.0 # Should be 1.0.0
|
|
420
|
+
---
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
#### ❌ Invalid Reference
|
|
424
|
+
|
|
425
|
+
```yaml
|
|
426
|
+
---
|
|
427
|
+
id: sales-domain
|
|
428
|
+
name: Sales Domain
|
|
429
|
+
version: 1.0.0
|
|
430
|
+
services:
|
|
431
|
+
- id: non-existent-service # Service doesn't exist
|
|
432
|
+
---
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
#### ❌ Invalid Email Format
|
|
436
|
+
|
|
437
|
+
```yaml
|
|
438
|
+
---
|
|
439
|
+
id: john-doe
|
|
440
|
+
name: John Doe
|
|
441
|
+
email: invalid-email # Should be john@example.com
|
|
442
|
+
---
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
## 🏷️ Error Codes
|
|
446
|
+
|
|
447
|
+
The linter provides descriptive error codes to help identify and fix issues quickly:
|
|
448
|
+
|
|
449
|
+
### Schema Validation Errors
|
|
450
|
+
|
|
451
|
+
- `@eventcatalog/required-field` - Required field is missing
|
|
452
|
+
- `@eventcatalog/invalid-type` - Field has wrong data type
|
|
453
|
+
- `@eventcatalog/schema-validation` - General schema validation error
|
|
454
|
+
- `@eventcatalog/schema` - Schema-related validation error
|
|
455
|
+
|
|
456
|
+
### Reference Validation Errors
|
|
457
|
+
|
|
458
|
+
- `@eventcatalog/invalid-reference` - Referenced resource doesn't exist
|
|
459
|
+
|
|
460
|
+
### Parse Errors
|
|
461
|
+
|
|
462
|
+
- `@eventcatalog/parse-error` - YAML/frontmatter parsing error
|
|
463
|
+
|
|
464
|
+
### Example with Error Codes
|
|
465
|
+
|
|
466
|
+
```bash
|
|
467
|
+
services/user-service/index.mdx
|
|
468
|
+
✖ error name: Required [name] (@eventcatalog/required-field)
|
|
469
|
+
✖ error version: Invalid semantic version format [version] (@eventcatalog/schema-validation)
|
|
470
|
+
✖ error Referenced service "missing-service" does not exist [sends] (@eventcatalog/invalid-reference)
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
## ⚠️ Warnings Support
|
|
474
|
+
|
|
475
|
+
The linter can distinguish between errors (which break functionality) and warnings (which suggest improvements):
|
|
476
|
+
|
|
477
|
+
- **Errors**: Critical issues that must be fixed
|
|
478
|
+
- **Warnings**: Suggestions for better documentation
|
|
479
|
+
|
|
480
|
+
Use `--fail-on-warning` to treat warnings as errors in CI/CD pipelines:
|
|
481
|
+
|
|
482
|
+
```bash
|
|
483
|
+
# Exit with error code if warnings are found
|
|
484
|
+
eventcatalog-linter --fail-on-warning
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
## 🔧 Development
|
|
488
|
+
|
|
489
|
+
### Setup
|
|
490
|
+
|
|
491
|
+
```bash
|
|
492
|
+
git clone https://github.com/event-catalog/eventcatalog-linter
|
|
493
|
+
cd eventcatalog-linter
|
|
494
|
+
npm install
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### Available Scripts
|
|
498
|
+
|
|
499
|
+
```bash
|
|
500
|
+
# Run tests
|
|
501
|
+
npm test
|
|
502
|
+
|
|
503
|
+
# Run tests in watch mode
|
|
504
|
+
npm run test:watch
|
|
505
|
+
|
|
506
|
+
# Build the project
|
|
507
|
+
npm run build
|
|
508
|
+
|
|
509
|
+
# Run in development mode
|
|
510
|
+
npm run dev
|
|
511
|
+
|
|
512
|
+
# Type checking
|
|
513
|
+
npm run typecheck
|
|
514
|
+
|
|
515
|
+
# Linting
|
|
516
|
+
npm run lint
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
### Testing
|
|
520
|
+
|
|
521
|
+
The linter includes comprehensive tests using Vitest:
|
|
522
|
+
|
|
523
|
+
- **Schema validation tests** - Ensures all Zod schemas work correctly
|
|
524
|
+
- **Reference validation tests** - Tests cross-reference checking
|
|
525
|
+
- **File scanning tests** - Tests file discovery and parsing
|
|
526
|
+
- **CLI tests** - Tests command-line interface
|
|
527
|
+
- **Integration tests** - End-to-end validation scenarios
|
|
528
|
+
|
|
529
|
+
```bash
|
|
530
|
+
# Run all tests
|
|
531
|
+
npm test
|
|
532
|
+
|
|
533
|
+
# Run tests with coverage
|
|
534
|
+
npm test -- --coverage
|
|
535
|
+
|
|
536
|
+
# Run specific test file
|
|
537
|
+
npm test schema-validator.test.ts
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
### Project Structure
|
|
541
|
+
|
|
542
|
+
```
|
|
543
|
+
src/
|
|
544
|
+
├── cli/ # Command-line interface
|
|
545
|
+
├── schemas/ # Zod validation schemas
|
|
546
|
+
├── scanner/ # File system scanning
|
|
547
|
+
├── parser/ # Frontmatter parsing
|
|
548
|
+
├── validators/ # Validation logic
|
|
549
|
+
├── reporters/ # Error reporting
|
|
550
|
+
└── types/ # TypeScript definitions
|
|
551
|
+
|
|
552
|
+
tests/
|
|
553
|
+
├── schema-validator.test.ts
|
|
554
|
+
├── reference-validator.test.ts
|
|
555
|
+
├── scanner.test.ts
|
|
556
|
+
└── utils/
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
## 🤝 Contributing
|
|
560
|
+
|
|
561
|
+
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
|
|
562
|
+
|
|
563
|
+
1. Fork the repository
|
|
564
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
565
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
566
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
567
|
+
5. Open a Pull Request
|
|
568
|
+
|
|
569
|
+
## 📄 License
|
|
570
|
+
|
|
571
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
572
|
+
|
|
573
|
+
## 🆘 Support
|
|
574
|
+
|
|
575
|
+
- 📖 [EventCatalog Documentation](https://eventcatalog.dev)
|
|
576
|
+
- 🐛 [Report Issues](https://github.com/event-catalog/eventcatalog-linter/issues)
|
|
577
|
+
- 💬 [Discussions](https://github.com/event-catalog/eventcatalog-linter/discussions)
|
|
578
|
+
|
|
579
|
+
## 🙏 Acknowledgments
|
|
580
|
+
|
|
581
|
+
- Built for the [EventCatalog](https://eventcatalog.dev) community
|
|
582
|
+
- Powered by [Zod](https://zod.dev) for schema validation
|
|
583
|
+
- Tested with [Vitest](https://vitest.dev)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const ora_1 = __importDefault(require("ora"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const scanner_1 = require("../scanner");
|
|
12
|
+
const parser_1 = require("../parser");
|
|
13
|
+
const validators_1 = require("../validators");
|
|
14
|
+
const reporters_1 = require("../reporters");
|
|
15
|
+
const program = new commander_1.Command();
|
|
16
|
+
program
|
|
17
|
+
.name('eventcatalog-linter')
|
|
18
|
+
.description('Lint your EventCatalog for frontmatter and reference validation')
|
|
19
|
+
.version('0.1.0')
|
|
20
|
+
.argument('[directory]', 'EventCatalog directory to lint', '.')
|
|
21
|
+
.option('-v, --verbose', 'Show verbose output', false)
|
|
22
|
+
.option('--fail-on-warning', 'Exit with non-zero code on warnings', false)
|
|
23
|
+
.action(async (directory, options) => {
|
|
24
|
+
const rootDir = path_1.default.resolve(directory);
|
|
25
|
+
const spinner = (0, ora_1.default)('Scanning EventCatalog files...').start();
|
|
26
|
+
try {
|
|
27
|
+
const files = await (0, scanner_1.scanCatalogFiles)(rootDir);
|
|
28
|
+
spinner.text = `Found ${files.length} catalog files`;
|
|
29
|
+
if (files.length === 0) {
|
|
30
|
+
spinner.warn('No EventCatalog files found');
|
|
31
|
+
process.exit(0);
|
|
32
|
+
}
|
|
33
|
+
spinner.text = 'Parsing frontmatter...';
|
|
34
|
+
const { parsed, errors: parseErrors } = await (0, parser_1.parseAllFiles)(files);
|
|
35
|
+
spinner.text = 'Validating catalog...';
|
|
36
|
+
const validationErrors = (0, validators_1.validateCatalog)(parsed);
|
|
37
|
+
spinner.stop();
|
|
38
|
+
const summary = (0, reporters_1.reportErrors)(validationErrors, parseErrors, options.verbose);
|
|
39
|
+
// Show scan summary
|
|
40
|
+
if (summary.totalErrors === 0) {
|
|
41
|
+
console.log(chalk_1.default.dim(`\n ${files.length} files checked`));
|
|
42
|
+
}
|
|
43
|
+
if (summary.totalErrors > 0 || (options.failOnWarning && summary.totalWarnings > 0)) {
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
spinner.fail('An error occurred');
|
|
49
|
+
console.error(chalk_1.default.red(error instanceof Error ? error.message : String(error)));
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
program.parse();
|
|
54
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;;;;;AAEA,yCAAoC;AACpC,kDAA0B;AAC1B,8CAAsB;AACtB,gDAAwB;AACxB,wCAA8C;AAC9C,sCAA0C;AAC1C,8CAAgD;AAChD,4CAA4C;AAG5C,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,qBAAqB,CAAC;KAC3B,WAAW,CAAC,iEAAiE,CAAC;KAC9E,OAAO,CAAC,OAAO,CAAC;KAChB,QAAQ,CAAC,aAAa,EAAE,gCAAgC,EAAE,GAAG,CAAC;KAC9D,MAAM,CAAC,eAAe,EAAE,qBAAqB,EAAE,KAAK,CAAC;KACrD,MAAM,CAAC,mBAAmB,EAAE,qCAAqC,EAAE,KAAK,CAAC;KACzE,MAAM,CAAC,KAAK,EAAE,SAAiB,EAAE,OAA+B,EAAE,EAAE;IACnE,MAAM,OAAO,GAAG,cAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,IAAA,aAAG,EAAC,gCAAgC,CAAC,CAAC,KAAK,EAAE,CAAC;IAE9D,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,IAAA,0BAAgB,EAAC,OAAO,CAAC,CAAC;QAC9C,OAAO,CAAC,IAAI,GAAG,SAAS,KAAK,CAAC,MAAM,gBAAgB,CAAC;QAErD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;YAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,OAAO,CAAC,IAAI,GAAG,wBAAwB,CAAC;QACxC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,IAAA,sBAAa,EAAC,KAAK,CAAC,CAAC;QAEnE,OAAO,CAAC,IAAI,GAAG,uBAAuB,CAAC;QACvC,MAAM,gBAAgB,GAAG,IAAA,4BAAe,EAAC,MAAM,CAAC,CAAC;QAEjD,OAAO,CAAC,IAAI,EAAE,CAAC;QAEf,MAAM,OAAO,GAAG,IAAA,wBAAY,EAAC,gBAAgB,EAAE,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QAE7E,oBAAoB;QACpB,IAAI,OAAO,CAAC,WAAW,KAAK,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC,CAAC,CAAC;QAC9D,CAAC;QAED,IAAI,OAAO,CAAC,WAAW,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,aAAa,GAAG,CAAC,CAAC,EAAE,CAAC;YACpF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAClC,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types"), exports);
|
|
18
|
+
__exportStar(require("./schemas"), exports);
|
|
19
|
+
__exportStar(require("./scanner"), exports);
|
|
20
|
+
__exportStar(require("./parser"), exports);
|
|
21
|
+
__exportStar(require("./validators"), exports);
|
|
22
|
+
__exportStar(require("./reporters"), exports);
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AACxB,4CAA0B;AAC1B,4CAA0B;AAC1B,2CAAyB;AACzB,+CAA6B;AAC7B,8CAA4B"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { CatalogFile } from '../scanner';
|
|
2
|
+
export interface ParsedFile {
|
|
3
|
+
file: CatalogFile;
|
|
4
|
+
frontmatter: Record<string, unknown>;
|
|
5
|
+
content: string;
|
|
6
|
+
raw: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ParseError {
|
|
9
|
+
file: CatalogFile;
|
|
10
|
+
error: Error;
|
|
11
|
+
}
|
|
12
|
+
export declare const parseFrontmatter: (file: CatalogFile) => Promise<ParsedFile | ParseError>;
|
|
13
|
+
export declare const parseAllFiles: (files: CatalogFile[]) => Promise<{
|
|
14
|
+
parsed: ParsedFile[];
|
|
15
|
+
errors: ParseError[];
|
|
16
|
+
}>;
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parser/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,WAAW,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC;CACd;AAED,eAAO,MAAM,gBAAgB,GAAU,MAAM,WAAW,KAAG,OAAO,CAAC,UAAU,GAAG,UAAU,CAiBzF,CAAC;AAEF,eAAO,MAAM,aAAa,GACxB,OAAO,WAAW,EAAE,KACnB,OAAO,CAAC;IACT,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB,CAeA,CAAC"}
|