@vertz/compiler 0.2.0 → 0.2.3
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 +8 -700
- package/dist/index.d.ts +104 -2
- package/dist/index.js +650 -6
- package/package.json +10 -9
package/README.md
CHANGED
|
@@ -1,711 +1,19 @@
|
|
|
1
1
|
# @vertz/compiler
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> **Internal package** — You don't use this directly. It powers `vertz build`, `vertz dev`, and `vertz codegen` behind the scenes.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Static analysis and code generation for Vertz applications. Analyzes TypeScript source code to extract application structure (routes, schemas, modules, middleware), validates conventions, and generates runtime artifacts like boot files, route tables, and OpenAPI specs.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Who uses this
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- **
|
|
12
|
-
- **TypeScript** 5.0+
|
|
13
|
-
|
|
14
|
-
## Installation
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
# npm
|
|
18
|
-
npm install @vertz/compiler
|
|
19
|
-
|
|
20
|
-
# bun
|
|
21
|
-
bun add @vertz/compiler
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Overview
|
|
25
|
-
|
|
26
|
-
The compiler consists of three main stages:
|
|
27
|
-
|
|
28
|
-
1. **Analysis** — Parse TypeScript AST and extract IR (Intermediate Representation)
|
|
29
|
-
2. **Validation** — Check conventions, completeness, and correctness
|
|
30
|
-
3. **Generation** — Emit runtime artifacts and documentation
|
|
31
|
-
|
|
32
|
-
```
|
|
33
|
-
Source Code (*.ts)
|
|
34
|
-
↓
|
|
35
|
-
[Analyzers] → AppIR (Intermediate Representation)
|
|
36
|
-
↓
|
|
37
|
-
[Validators] → Diagnostics (errors/warnings)
|
|
38
|
-
↓
|
|
39
|
-
[Generators] → Artifacts (boot.ts, manifest.json, openapi.json)
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Quick Start
|
|
43
|
-
|
|
44
|
-
```typescript
|
|
45
|
-
import { createCompiler } from '@vertz/compiler';
|
|
46
|
-
|
|
47
|
-
// Create compiler with default config
|
|
48
|
-
const compiler = createCompiler({
|
|
49
|
-
rootDir: './src',
|
|
50
|
-
appFile: './src/app.ts',
|
|
51
|
-
outDir: './.vertz',
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
// Analyze the application
|
|
55
|
-
const ir = await compiler.analyze();
|
|
56
|
-
|
|
57
|
-
// Validate the IR
|
|
58
|
-
const diagnostics = await compiler.validate(ir);
|
|
59
|
-
|
|
60
|
-
if (diagnostics.some((d) => d.severity === 'error')) {
|
|
61
|
-
console.error('Validation errors:', diagnostics);
|
|
62
|
-
process.exit(1);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Generate artifacts
|
|
66
|
-
await compiler.generate(ir);
|
|
67
|
-
|
|
68
|
-
console.log('✅ Compilation successful');
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## Core Concepts
|
|
72
|
-
|
|
73
|
-
### Intermediate Representation (IR)
|
|
74
|
-
|
|
75
|
-
The IR is a structured representation of your vertz application extracted from source code:
|
|
76
|
-
|
|
77
|
-
```typescript
|
|
78
|
-
interface AppIR {
|
|
79
|
-
app: AppDefinition; // App configuration (basePath, CORS, etc.)
|
|
80
|
-
modules: ModuleIR[]; // All modules
|
|
81
|
-
middleware: MiddlewareIR[]; // Global middleware
|
|
82
|
-
schemas: SchemaIR[]; // Schema definitions
|
|
83
|
-
env: EnvIR; // Environment variables
|
|
84
|
-
dependencyGraph: DependencyGraphIR; // Service dependency graph
|
|
85
|
-
diagnostics: Diagnostic[]; // Analysis issues
|
|
86
|
-
}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### Analyzers
|
|
90
|
-
|
|
91
|
-
Analyzers extract specific aspects of your application:
|
|
92
|
-
|
|
93
|
-
- **AppAnalyzer** — Extracts `createApp()` configuration
|
|
94
|
-
- **ModuleAnalyzer** — Extracts modules, services, and routers
|
|
95
|
-
- **SchemaAnalyzer** — Extracts schema definitions
|
|
96
|
-
- **MiddlewareAnalyzer** — Extracts middleware definitions
|
|
97
|
-
- **EnvAnalyzer** — Extracts environment variable declarations
|
|
98
|
-
- **DependencyGraphAnalyzer** — Builds service dependency graph
|
|
99
|
-
|
|
100
|
-
Each analyzer extends `BaseAnalyzer` and implements:
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
interface Analyzer<T> {
|
|
104
|
-
analyze(): Promise<T>;
|
|
105
|
-
}
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
### Validators
|
|
109
|
-
|
|
110
|
-
Validators check the IR for correctness:
|
|
111
|
-
|
|
112
|
-
- **NamingValidator** — Checks naming conventions (PascalCase modules, camelCase services)
|
|
113
|
-
- **PlacementValidator** — Ensures code is in the correct directories
|
|
114
|
-
- **CompletenessValidator** — Checks for missing exports, dangling references
|
|
115
|
-
- **ModuleValidator** — Validates module structure (services, routers, exports)
|
|
116
|
-
|
|
117
|
-
Each validator implements:
|
|
118
|
-
|
|
119
|
-
```typescript
|
|
120
|
-
interface Validator {
|
|
121
|
-
validate(ir: AppIR): Promise<Diagnostic[]>;
|
|
122
|
-
}
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
### Generators
|
|
126
|
-
|
|
127
|
-
Generators emit artifacts from the IR:
|
|
128
|
-
|
|
129
|
-
- **BootGenerator** — Generates `boot.ts` with module registration code
|
|
130
|
-
- **RouteTableGenerator** — Generates runtime route table with validation schemas
|
|
131
|
-
- **SchemaRegistryGenerator** — Generates schema registry for runtime validation
|
|
132
|
-
- **ManifestGenerator** — Generates JSON manifest for introspection
|
|
133
|
-
- **OpenAPIGenerator** — Generates OpenAPI 3.0 specification
|
|
134
|
-
|
|
135
|
-
Each generator implements:
|
|
136
|
-
|
|
137
|
-
```typescript
|
|
138
|
-
interface Generator {
|
|
139
|
-
generate(ir: AppIR, outputDir: string): Promise<void>;
|
|
140
|
-
}
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
## Configuration
|
|
144
|
-
|
|
145
|
-
### Basic Config
|
|
146
|
-
|
|
147
|
-
```typescript
|
|
148
|
-
import { defineConfig } from '@vertz/compiler';
|
|
149
|
-
|
|
150
|
-
export default defineConfig({
|
|
151
|
-
rootDir: './src',
|
|
152
|
-
appFile: './src/app.ts',
|
|
153
|
-
outDir: './.vertz',
|
|
154
|
-
});
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### Full Config Options
|
|
158
|
-
|
|
159
|
-
```typescript
|
|
160
|
-
interface VertzConfig {
|
|
161
|
-
rootDir: string; // Project root directory
|
|
162
|
-
appFile: string; // Path to app entry file
|
|
163
|
-
outDir: string; // Output directory for artifacts
|
|
164
|
-
|
|
165
|
-
compiler?: {
|
|
166
|
-
outputDir?: string; // Override output directory
|
|
167
|
-
incremental?: boolean; // Enable incremental compilation
|
|
168
|
-
watch?: boolean; // Enable watch mode
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
validation?: {
|
|
172
|
-
strict?: boolean; // Fail on warnings
|
|
173
|
-
rules?: {
|
|
174
|
-
naming?: boolean; // Check naming conventions
|
|
175
|
-
placement?: boolean; // Check file placement
|
|
176
|
-
completeness?: boolean; // Check for missing references
|
|
177
|
-
};
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
schema?: {
|
|
181
|
-
generateJSONSchema?: boolean; // Generate JSON Schema for validation
|
|
182
|
-
includeExamples?: boolean; // Include examples in schemas
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
openapi?: {
|
|
186
|
-
enabled?: boolean; // Generate OpenAPI spec
|
|
187
|
-
info?: {
|
|
188
|
-
title?: string;
|
|
189
|
-
version?: string;
|
|
190
|
-
description?: string;
|
|
191
|
-
};
|
|
192
|
-
servers?: Array<{
|
|
193
|
-
url: string;
|
|
194
|
-
description?: string;
|
|
195
|
-
}>;
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
## Analyzers
|
|
201
|
-
|
|
202
|
-
### AppAnalyzer
|
|
203
|
-
|
|
204
|
-
Extracts `createApp()` configuration:
|
|
205
|
-
|
|
206
|
-
```typescript
|
|
207
|
-
import { AppAnalyzer } from '@vertz/compiler';
|
|
208
|
-
import { Project } from 'ts-morph';
|
|
209
|
-
|
|
210
|
-
const project = new Project({ tsConfigFilePath: 'tsconfig.json' });
|
|
211
|
-
const analyzer = new AppAnalyzer(project, './src/app.ts');
|
|
212
|
-
const result = await analyzer.analyze();
|
|
213
|
-
|
|
214
|
-
console.log(result.app);
|
|
215
|
-
/*
|
|
216
|
-
{
|
|
217
|
-
basePath: '/api',
|
|
218
|
-
globalMiddleware: ['auth', 'logging'],
|
|
219
|
-
sourceFile: './src/app.ts',
|
|
220
|
-
sourceLine: 10,
|
|
221
|
-
sourceColumn: 15
|
|
222
|
-
}
|
|
223
|
-
*/
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
### ModuleAnalyzer
|
|
227
|
-
|
|
228
|
-
Extracts modules, services, and routers:
|
|
229
|
-
|
|
230
|
-
```typescript
|
|
231
|
-
import { ModuleAnalyzer } from '@vertz/compiler';
|
|
232
|
-
|
|
233
|
-
const analyzer = new ModuleAnalyzer(project, { rootDir: './src' });
|
|
234
|
-
const result = await analyzer.analyze();
|
|
235
|
-
|
|
236
|
-
console.log(result.modules);
|
|
237
|
-
/*
|
|
238
|
-
[
|
|
239
|
-
{
|
|
240
|
-
name: 'users',
|
|
241
|
-
sourceFile: './src/users/users.module.ts',
|
|
242
|
-
services: [...],
|
|
243
|
-
routers: [...],
|
|
244
|
-
exports: [...]
|
|
245
|
-
}
|
|
246
|
-
]
|
|
247
|
-
*/
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
### SchemaAnalyzer
|
|
251
|
-
|
|
252
|
-
Extracts schema definitions:
|
|
253
|
-
|
|
254
|
-
```typescript
|
|
255
|
-
import { SchemaAnalyzer } from '@vertz/compiler';
|
|
256
|
-
|
|
257
|
-
const analyzer = new SchemaAnalyzer(project, { rootDir: './src' });
|
|
258
|
-
const result = await analyzer.analyze();
|
|
259
|
-
|
|
260
|
-
console.log(result.schemas);
|
|
261
|
-
/*
|
|
262
|
-
[
|
|
263
|
-
{
|
|
264
|
-
id: 'users:CreateUserDto',
|
|
265
|
-
moduleName: 'users',
|
|
266
|
-
name: 'CreateUserDto',
|
|
267
|
-
sourceFile: './src/users/schemas.ts',
|
|
268
|
-
definition: { ... }
|
|
269
|
-
}
|
|
270
|
-
]
|
|
271
|
-
*/
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
## Validators
|
|
275
|
-
|
|
276
|
-
### Custom Validator
|
|
277
|
-
|
|
278
|
-
Create custom validators by implementing the `Validator` interface:
|
|
279
|
-
|
|
280
|
-
```typescript
|
|
281
|
-
import type { Validator, AppIR, Diagnostic } from '@vertz/compiler';
|
|
282
|
-
import { createDiagnostic } from '@vertz/compiler';
|
|
283
|
-
|
|
284
|
-
class CustomValidator implements Validator {
|
|
285
|
-
async validate(ir: AppIR): Promise<Diagnostic[]> {
|
|
286
|
-
const diagnostics: Diagnostic[] = [];
|
|
287
|
-
|
|
288
|
-
for (const module of ir.modules) {
|
|
289
|
-
if (module.services.length === 0) {
|
|
290
|
-
diagnostics.push(
|
|
291
|
-
createDiagnostic({
|
|
292
|
-
code: 'CUSTOM_001',
|
|
293
|
-
severity: 'warning',
|
|
294
|
-
message: `Module "${module.name}" has no services`,
|
|
295
|
-
file: module.sourceFile,
|
|
296
|
-
line: module.sourceLine,
|
|
297
|
-
}),
|
|
298
|
-
);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
return diagnostics;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
Use custom validators:
|
|
308
|
-
|
|
309
|
-
```typescript
|
|
310
|
-
const compiler = createCompiler(config, {
|
|
311
|
-
validators: [
|
|
312
|
-
new NamingValidator(),
|
|
313
|
-
new PlacementValidator(config),
|
|
314
|
-
new CustomValidator(), // ← Your validator
|
|
315
|
-
],
|
|
316
|
-
});
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
## Generators
|
|
320
|
-
|
|
321
|
-
### Custom Generator
|
|
322
|
-
|
|
323
|
-
Create custom generators by extending `BaseGenerator`:
|
|
324
|
-
|
|
325
|
-
```typescript
|
|
326
|
-
import { BaseGenerator, type AppIR } from '@vertz/compiler';
|
|
327
|
-
import { writeFile } from 'node:fs/promises';
|
|
328
|
-
import { join } from 'node:path';
|
|
329
|
-
|
|
330
|
-
class CustomGenerator extends BaseGenerator {
|
|
331
|
-
async generate(ir: AppIR, outputDir: string): Promise<void> {
|
|
332
|
-
const output = this.generateOutput(ir);
|
|
333
|
-
const outputPath = join(outputDir, 'custom-output.json');
|
|
334
|
-
await writeFile(outputPath, JSON.stringify(output, null, 2));
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
private generateOutput(ir: AppIR): object {
|
|
338
|
-
return {
|
|
339
|
-
moduleCount: ir.modules.length,
|
|
340
|
-
routeCount: ir.modules.flatMap((m) => m.routers.flatMap((r) => r.routes)).length,
|
|
341
|
-
serviceCount: ir.modules.flatMap((m) => m.services).length,
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
Use custom generators:
|
|
348
|
-
|
|
349
|
-
```typescript
|
|
350
|
-
const compiler = createCompiler(config, {
|
|
351
|
-
generators: [
|
|
352
|
-
new BootGenerator(config),
|
|
353
|
-
new ManifestGenerator(),
|
|
354
|
-
new CustomGenerator(), // ← Your generator
|
|
355
|
-
],
|
|
356
|
-
});
|
|
357
|
-
```
|
|
358
|
-
|
|
359
|
-
## Incremental Compilation
|
|
360
|
-
|
|
361
|
-
For faster rebuilds, use incremental compilation:
|
|
362
|
-
|
|
363
|
-
```typescript
|
|
364
|
-
import { IncrementalCompiler } from '@vertz/compiler';
|
|
365
|
-
|
|
366
|
-
const compiler = new IncrementalCompiler(config);
|
|
367
|
-
|
|
368
|
-
// Initial compilation
|
|
369
|
-
await compiler.compile();
|
|
370
|
-
|
|
371
|
-
// On file change
|
|
372
|
-
const changedFiles = ['./src/users/users.service.ts'];
|
|
373
|
-
await compiler.recompile(changedFiles);
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
The incremental compiler:
|
|
377
|
-
- Caches previous IR
|
|
378
|
-
- Categorizes file changes (app, module, schema, etc.)
|
|
379
|
-
- Reanalyzes only affected modules
|
|
380
|
-
- Merges changes into existing IR
|
|
381
|
-
|
|
382
|
-
## Typecheck Integration
|
|
383
|
-
|
|
384
|
-
Run TypeScript type checking alongside compilation:
|
|
385
|
-
|
|
386
|
-
```typescript
|
|
387
|
-
import { typecheck } from '@vertz/compiler';
|
|
388
|
-
|
|
389
|
-
const result = await typecheck({
|
|
390
|
-
project: './tsconfig.json',
|
|
391
|
-
noEmit: true,
|
|
392
|
-
});
|
|
393
|
-
|
|
394
|
-
if (!result.success) {
|
|
395
|
-
console.error('Type errors:', result.diagnostics);
|
|
396
|
-
}
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
Watch mode:
|
|
400
|
-
|
|
401
|
-
```typescript
|
|
402
|
-
import { typecheckWatch } from '@vertz/compiler';
|
|
403
|
-
|
|
404
|
-
for await (const result of typecheckWatch({ project: './tsconfig.json' })) {
|
|
405
|
-
if (result.success) {
|
|
406
|
-
console.log('✅ Types OK');
|
|
407
|
-
} else {
|
|
408
|
-
console.error('Type errors:', result.diagnostics);
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
```
|
|
412
|
-
|
|
413
|
-
## Diagnostics
|
|
414
|
-
|
|
415
|
-
All errors and warnings are represented as `Diagnostic` objects:
|
|
416
|
-
|
|
417
|
-
```typescript
|
|
418
|
-
interface Diagnostic {
|
|
419
|
-
code: string; // Unique error code (e.g., 'MODULE_001')
|
|
420
|
-
severity: 'error' | 'warning' | 'info';
|
|
421
|
-
message: string; // Human-readable message
|
|
422
|
-
file?: string; // Source file path
|
|
423
|
-
line?: number; // Line number
|
|
424
|
-
column?: number; // Column number
|
|
425
|
-
context?: SourceContext; // Additional context
|
|
426
|
-
}
|
|
427
|
-
```
|
|
428
|
-
|
|
429
|
-
Create diagnostics:
|
|
430
|
-
|
|
431
|
-
```typescript
|
|
432
|
-
import { createDiagnostic, createDiagnosticFromLocation } from '@vertz/compiler';
|
|
433
|
-
|
|
434
|
-
const diagnostic = createDiagnostic({
|
|
435
|
-
code: 'CUSTOM_001',
|
|
436
|
-
severity: 'error',
|
|
437
|
-
message: 'Invalid configuration',
|
|
438
|
-
file: './src/app.ts',
|
|
439
|
-
line: 10,
|
|
440
|
-
column: 5,
|
|
441
|
-
});
|
|
442
|
-
|
|
443
|
-
// Or from a ts-morph Node
|
|
444
|
-
const nodeWithError = sourceFile.getFunction('myFunction');
|
|
445
|
-
const diagnostic2 = createDiagnosticFromLocation(nodeWithError, {
|
|
446
|
-
code: 'CUSTOM_002',
|
|
447
|
-
message: 'Function is deprecated',
|
|
448
|
-
severity: 'warning',
|
|
449
|
-
});
|
|
450
|
-
```
|
|
451
|
-
|
|
452
|
-
Filter diagnostics:
|
|
453
|
-
|
|
454
|
-
```typescript
|
|
455
|
-
import { filterBySeverity, hasErrors } from '@vertz/compiler';
|
|
456
|
-
|
|
457
|
-
const errors = filterBySeverity(diagnostics, 'error');
|
|
458
|
-
const warnings = filterBySeverity(diagnostics, 'warning');
|
|
459
|
-
|
|
460
|
-
if (hasErrors(diagnostics)) {
|
|
461
|
-
console.error('Compilation failed');
|
|
462
|
-
process.exit(1);
|
|
463
|
-
}
|
|
464
|
-
```
|
|
465
|
-
|
|
466
|
-
## Architecture
|
|
467
|
-
|
|
468
|
-
### Compiler Pipeline
|
|
469
|
-
|
|
470
|
-
```
|
|
471
|
-
┌─────────────────────────────────────────────────────────┐
|
|
472
|
-
│ 1. Configuration │
|
|
473
|
-
│ - Load vertz.config.ts │
|
|
474
|
-
│ - Resolve paths, options │
|
|
475
|
-
└─────────────────────────────────────────────────────────┘
|
|
476
|
-
↓
|
|
477
|
-
┌─────────────────────────────────────────────────────────┐
|
|
478
|
-
│ 2. Analysis (ts-morph AST traversal) │
|
|
479
|
-
│ - AppAnalyzer → app config │
|
|
480
|
-
│ - ModuleAnalyzer → modules, services, routers │
|
|
481
|
-
│ - SchemaAnalyzer → schemas │
|
|
482
|
-
│ - MiddlewareAnalyzer → middleware │
|
|
483
|
-
│ - EnvAnalyzer → env vars │
|
|
484
|
-
│ - DependencyGraphAnalyzer → service graph │
|
|
485
|
-
└─────────────────────────────────────────────────────────┘
|
|
486
|
-
↓
|
|
487
|
-
┌─────────────────────────────────────────────────────────┐
|
|
488
|
-
│ 3. IR Construction │
|
|
489
|
-
│ - Combine analyzer results │
|
|
490
|
-
│ - Build unified AppIR │
|
|
491
|
-
│ - Add cross-references │
|
|
492
|
-
└─────────────────────────────────────────────────────────┘
|
|
493
|
-
↓
|
|
494
|
-
┌─────────────────────────────────────────────────────────┐
|
|
495
|
-
│ 4. Validation │
|
|
496
|
-
│ - NamingValidator │
|
|
497
|
-
│ - PlacementValidator │
|
|
498
|
-
│ - CompletenessValidator │
|
|
499
|
-
│ - ModuleValidator │
|
|
500
|
-
└─────────────────────────────────────────────────────────┘
|
|
501
|
-
↓
|
|
502
|
-
┌─────────────────────────────────────────────────────────┐
|
|
503
|
-
│ 5. Generation │
|
|
504
|
-
│ - BootGenerator → boot.ts │
|
|
505
|
-
│ - RouteTableGenerator → routes.ts │
|
|
506
|
-
│ - SchemaRegistryGenerator → schemas.ts │
|
|
507
|
-
│ - ManifestGenerator → manifest.json │
|
|
508
|
-
│ - OpenAPIGenerator → openapi.json │
|
|
509
|
-
└─────────────────────────────────────────────────────────┘
|
|
510
|
-
```
|
|
511
|
-
|
|
512
|
-
### Extensibility
|
|
513
|
-
|
|
514
|
-
The compiler is designed for extensibility:
|
|
515
|
-
|
|
516
|
-
- **Custom Analyzers** — Extract additional information from source code
|
|
517
|
-
- **Custom Validators** — Enforce custom rules and conventions
|
|
518
|
-
- **Custom Generators** — Emit custom artifacts (GraphQL schemas, docs, etc.)
|
|
519
|
-
|
|
520
|
-
All extension points use dependency injection — pass custom implementations to `createCompiler()`.
|
|
521
|
-
|
|
522
|
-
## CLI Integration
|
|
523
|
-
|
|
524
|
-
The compiler is typically used through `@vertz/cli`:
|
|
525
|
-
|
|
526
|
-
```bash
|
|
527
|
-
# Compile the app
|
|
528
|
-
vertz build
|
|
529
|
-
|
|
530
|
-
# Check for errors without building
|
|
531
|
-
vertz check
|
|
532
|
-
|
|
533
|
-
# Watch mode
|
|
534
|
-
vertz dev
|
|
535
|
-
```
|
|
536
|
-
|
|
537
|
-
See `@vertz/cli` for CLI documentation.
|
|
538
|
-
|
|
539
|
-
## Programmatic Usage
|
|
540
|
-
|
|
541
|
-
### Example: Extract Route Information
|
|
542
|
-
|
|
543
|
-
```typescript
|
|
544
|
-
import { createCompiler } from '@vertz/compiler';
|
|
545
|
-
|
|
546
|
-
const compiler = createCompiler({
|
|
547
|
-
rootDir: './src',
|
|
548
|
-
appFile: './src/app.ts',
|
|
549
|
-
outDir: './.vertz',
|
|
550
|
-
});
|
|
551
|
-
|
|
552
|
-
const ir = await compiler.analyze();
|
|
553
|
-
|
|
554
|
-
// Extract all routes
|
|
555
|
-
const routes = ir.modules.flatMap((module) =>
|
|
556
|
-
module.routers.flatMap((router) =>
|
|
557
|
-
router.routes.map((route) => ({
|
|
558
|
-
method: route.method,
|
|
559
|
-
path: `${module.prefix ?? ''}${router.prefix}${route.path}`,
|
|
560
|
-
module: module.name,
|
|
561
|
-
})),
|
|
562
|
-
),
|
|
563
|
-
);
|
|
564
|
-
|
|
565
|
-
console.log('Routes:', routes);
|
|
566
|
-
```
|
|
567
|
-
|
|
568
|
-
### Example: Generate Custom Documentation
|
|
569
|
-
|
|
570
|
-
```typescript
|
|
571
|
-
import { createCompiler, type AppIR } from '@vertz/compiler';
|
|
572
|
-
import { writeFile } from 'node:fs/promises';
|
|
573
|
-
|
|
574
|
-
const compiler = createCompiler(config);
|
|
575
|
-
const ir = await compiler.analyze();
|
|
576
|
-
|
|
577
|
-
// Generate markdown docs
|
|
578
|
-
const markdown = generateDocs(ir);
|
|
579
|
-
await writeFile('./docs/api.md', markdown);
|
|
580
|
-
|
|
581
|
-
function generateDocs(ir: AppIR): string {
|
|
582
|
-
let md = '# API Documentation\n\n';
|
|
583
|
-
|
|
584
|
-
for (const module of ir.modules) {
|
|
585
|
-
md += `## Module: ${module.name}\n\n`;
|
|
586
|
-
|
|
587
|
-
for (const router of module.routers) {
|
|
588
|
-
for (const route of router.routes) {
|
|
589
|
-
md += `### ${route.method.toUpperCase()} ${router.prefix}${route.path}\n\n`;
|
|
590
|
-
if (route.schema?.body) {
|
|
591
|
-
md += `**Request Body:**\n\`\`\`json\n${JSON.stringify(route.schema.body, null, 2)}\n\`\`\`\n\n`;
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
return md;
|
|
598
|
-
}
|
|
599
|
-
```
|
|
600
|
-
|
|
601
|
-
## API Reference
|
|
602
|
-
|
|
603
|
-
### Core Functions
|
|
604
|
-
|
|
605
|
-
- `createCompiler(config, deps?)` — Create compiler instance
|
|
606
|
-
- `defineConfig(config)` — Define configuration (for `vertz.config.ts`)
|
|
607
|
-
- `resolveConfig(config)` — Resolve configuration with defaults
|
|
608
|
-
|
|
609
|
-
### Analyzers
|
|
610
|
-
|
|
611
|
-
- `AppAnalyzer` — Extract app configuration
|
|
612
|
-
- `ModuleAnalyzer` — Extract modules
|
|
613
|
-
- `SchemaAnalyzer` — Extract schemas
|
|
614
|
-
- `MiddlewareAnalyzer` — Extract middleware
|
|
615
|
-
- `EnvAnalyzer` — Extract env variables
|
|
616
|
-
- `DependencyGraphAnalyzer` — Build dependency graph
|
|
617
|
-
|
|
618
|
-
### Validators
|
|
619
|
-
|
|
620
|
-
- `NamingValidator` — Check naming conventions
|
|
621
|
-
- `PlacementValidator` — Check file placement
|
|
622
|
-
- `CompletenessValidator` — Check completeness
|
|
623
|
-
- `ModuleValidator` — Validate module structure
|
|
624
|
-
|
|
625
|
-
### Generators
|
|
626
|
-
|
|
627
|
-
- `BootGenerator` — Generate boot file
|
|
628
|
-
- `RouteTableGenerator` — Generate route table
|
|
629
|
-
- `SchemaRegistryGenerator` — Generate schema registry
|
|
630
|
-
- `ManifestGenerator` — Generate JSON manifest
|
|
631
|
-
- `OpenAPIGenerator` — Generate OpenAPI spec
|
|
632
|
-
|
|
633
|
-
### Utilities
|
|
634
|
-
|
|
635
|
-
- `typecheck(options)` — Run TypeScript type checking
|
|
636
|
-
- `typecheckWatch(options)` — Run type checking in watch mode
|
|
637
|
-
- `createDiagnostic(options)` — Create diagnostic
|
|
638
|
-
- `hasErrors(diagnostics)` — Check if diagnostics contain errors
|
|
639
|
-
- `filterBySeverity(diagnostics, severity)` — Filter diagnostics
|
|
9
|
+
- **`@vertz/cli`** — All CLI commands (`vertz build`, `vertz dev`, `vertz check`) invoke the compiler.
|
|
10
|
+
- **`@vertz/codegen`** — Consumes the compiler's intermediate representation (IR) to generate SDKs and CLIs.
|
|
11
|
+
- **Framework contributors** — See [INTERNALS.md](./INTERNALS.md) for architecture, pipeline stages, and extension points.
|
|
640
12
|
|
|
641
13
|
## Related Packages
|
|
642
14
|
|
|
643
|
-
-
|
|
644
|
-
-
|
|
645
|
-
- **[@vertz/core](../core)** — Runtime framework (analyzed by compiler)
|
|
646
|
-
|
|
647
|
-
## Advanced Topics
|
|
648
|
-
|
|
649
|
-
### AST Traversal
|
|
650
|
-
|
|
651
|
-
The compiler uses `ts-morph` for AST traversal. Utilities are available:
|
|
652
|
-
|
|
653
|
-
```typescript
|
|
654
|
-
import { findCallExpressions, getStringValue, extractObjectLiteral } from '@vertz/compiler';
|
|
655
|
-
import { Project } from 'ts-morph';
|
|
656
|
-
|
|
657
|
-
const project = new Project({ tsConfigFilePath: 'tsconfig.json' });
|
|
658
|
-
const sourceFile = project.getSourceFile('app.ts');
|
|
659
|
-
|
|
660
|
-
// Find all createApp() calls
|
|
661
|
-
const appCalls = findCallExpressions(sourceFile, 'createApp');
|
|
662
|
-
|
|
663
|
-
// Extract string literal value
|
|
664
|
-
const basePath = getStringValue(configObject, 'basePath'); // '/api'
|
|
665
|
-
|
|
666
|
-
// Extract object literal
|
|
667
|
-
const corsConfig = extractObjectLiteral(configObject, 'cors');
|
|
668
|
-
```
|
|
669
|
-
|
|
670
|
-
### Schema Execution
|
|
671
|
-
|
|
672
|
-
Execute schemas at compile-time to extract metadata:
|
|
673
|
-
|
|
674
|
-
```typescript
|
|
675
|
-
import { createSchemaExecutor } from '@vertz/compiler';
|
|
676
|
-
|
|
677
|
-
const executor = createSchemaExecutor(project);
|
|
678
|
-
const result = await executor.execute('./src/schemas.ts', 'userSchema');
|
|
679
|
-
|
|
680
|
-
console.log(result.jsonSchema); // JSON Schema representation
|
|
681
|
-
```
|
|
682
|
-
|
|
683
|
-
### Import Resolution
|
|
684
|
-
|
|
685
|
-
Resolve imports and exports across files:
|
|
686
|
-
|
|
687
|
-
```typescript
|
|
688
|
-
import { resolveIdentifier, resolveExport } from '@vertz/compiler';
|
|
689
|
-
|
|
690
|
-
const resolved = resolveIdentifier(sourceFile, 'userService');
|
|
691
|
-
console.log(resolved.sourceFile, resolved.name);
|
|
692
|
-
|
|
693
|
-
const exported = resolveExport(sourceFile, 'userSchema');
|
|
694
|
-
console.log(exported);
|
|
695
|
-
```
|
|
696
|
-
|
|
697
|
-
## Performance
|
|
698
|
-
|
|
699
|
-
The compiler is optimized for large codebases:
|
|
700
|
-
|
|
701
|
-
- **Incremental compilation** — Only reanalyze changed modules
|
|
702
|
-
- **Parallel analysis** — Analyzers run concurrently
|
|
703
|
-
- **Caching** — IR is cached between runs
|
|
704
|
-
- **Lazy evaluation** — Generators only run when needed
|
|
705
|
-
|
|
706
|
-
Typical performance (1000 files, 50 modules):
|
|
707
|
-
- Initial compilation: ~2-5 seconds
|
|
708
|
-
- Incremental recompilation: ~100-500ms
|
|
15
|
+
- [`@vertz/cli`](../cli) — The CLI that invokes the compiler
|
|
16
|
+
- [`@vertz/codegen`](../codegen) — Code generation from compiler IR
|
|
709
17
|
|
|
710
18
|
## License
|
|
711
19
|
|