@flink-app/ts-source-to-json-schema 0.1.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/LICENSE +21 -0
- package/README.md +574 -0
- package/dist/ast.d.ts +102 -0
- package/dist/ast.d.ts.map +1 -0
- package/dist/ast.js +5 -0
- package/dist/ast.js.map +1 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +276 -0
- package/dist/cli.js.map +1 -0
- package/dist/emitter.d.ts +120 -0
- package/dist/emitter.d.ts.map +1 -0
- package/dist/emitter.js +808 -0
- package/dist/emitter.js.map +1 -0
- package/dist/import-parser.d.ts +18 -0
- package/dist/import-parser.d.ts.map +1 -0
- package/dist/import-parser.js +117 -0
- package/dist/import-parser.js.map +1 -0
- package/dist/index.d.ts +99 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +177 -0
- package/dist/index.js.map +1 -0
- package/dist/module-resolver.d.ts +29 -0
- package/dist/module-resolver.d.ts.map +1 -0
- package/dist/module-resolver.js +95 -0
- package/dist/module-resolver.js.map +1 -0
- package/dist/parser.d.ts +38 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +464 -0
- package/dist/parser.js.map +1 -0
- package/dist/path-utils.d.ts +16 -0
- package/dist/path-utils.d.ts.map +1 -0
- package/dist/path-utils.js +63 -0
- package/dist/path-utils.js.map +1 -0
- package/dist/tokenizer.d.ts +9 -0
- package/dist/tokenizer.d.ts.map +1 -0
- package/dist/tokenizer.js +192 -0
- package/dist/tokenizer.js.map +1 -0
- package/package.json +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
# ts-to-jsonschema
|
|
2
|
+
|
|
3
|
+
A zero-dependency TypeScript-to-JSON Schema converter that uses its own mini-parser instead of the TypeScript compiler.
|
|
4
|
+
|
|
5
|
+
It parses TypeScript type declarations (interfaces, type aliases, enums) directly from source strings and emits JSON Schema (2020-12 draft). No `ts.createProgram`, no `node_modules` bloat, no compiler startup cost.
|
|
6
|
+
|
|
7
|
+
## Why
|
|
8
|
+
|
|
9
|
+
Existing tools like `ts-json-schema-generator` and `typescript-json-schema` rely on the full TypeScript compiler API to resolve types. That works, but it's slow, heavy, and ties you to Node.js. Furthermore, these libraries might need significant rewrites when TypeScript 7 (tsgo) is released, making their long-term future uncertain.
|
|
10
|
+
|
|
11
|
+
This library takes a different approach: instead of running the type checker, it tokenizes and parses a **practical subset** of TypeScript's type syntax directly. The result is a tool that's fast enough to run in a hot path, portable enough to run anywhere (Cloudflare Workers, browser, CLI), and simple enough to extend.
|
|
12
|
+
|
|
13
|
+
The trade-off is explicit: it handles the type constructs you'd actually use in API contracts, tool schemas, and config definitions — not the full type-level programming language.
|
|
14
|
+
|
|
15
|
+
## What it handles
|
|
16
|
+
|
|
17
|
+
- **Declarations**: `interface`, `type`, `enum` (string + numeric), `export`
|
|
18
|
+
- **Primitives**: `string`, `number`, `boolean`, `null`, `undefined`, `any`, `unknown`, `never`, `void`, `bigint`
|
|
19
|
+
- **Built-in types**: `Date` → `{ type: "string", format: "date-time" }`
|
|
20
|
+
- **Literal types**: `"active"`, `42`, `true`
|
|
21
|
+
- **Unions**: `A | B | C` → `anyOf` (or `enum` when all members are literals)
|
|
22
|
+
- **Intersections**: `A & B` → `allOf`
|
|
23
|
+
- **Arrays**: `T[]`, `Array<T>`, nested `T[][]`
|
|
24
|
+
- **Tuples**: `[string, number]` → `prefixItems`
|
|
25
|
+
- **Nullable**: `string | null` → `type: ["string", "null"]`
|
|
26
|
+
- **Nested objects**: inline `{ foo: string }` and cross-references via `$ref`
|
|
27
|
+
- **Self-referential types**: `Task` containing `subtasks: Task[]`
|
|
28
|
+
- **Interface extends**: `interface Dog extends Animal` → `allOf`
|
|
29
|
+
- **Index signatures**: `[key: string]: T` → `additionalProperties`
|
|
30
|
+
- **Utility types**: `Partial<T>`, `Required<T>`, `Pick<T, K>`, `Omit<T, K>`, `Record<K, V>`, `Readonly<T>`, `Set<T>`, `Map<K, V>`, `Promise<T>` (unwrapped)
|
|
31
|
+
- **Local imports**: Automatic resolution of relative imports (`./` and `../`) across files
|
|
32
|
+
- **JSDoc**: `/** description */` → `description`, plus tags: `@minimum`, `@maximum`, `@minLength`, `@maxLength`, `@pattern`, `@format`, `@default`, `@deprecated`, `@title`, `@example`, `@additionalProperties`
|
|
33
|
+
- **Readonly**: `readonly` → `readOnly` in schema
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install ts-source-to-json-schema
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## CLI Usage
|
|
42
|
+
|
|
43
|
+
The package includes a command-line tool for converting TypeScript files to JSON Schema:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# Convert a TypeScript file
|
|
47
|
+
npx ts-source-to-json-schema src/types.ts
|
|
48
|
+
|
|
49
|
+
# Convert with automatic import resolution (default)
|
|
50
|
+
npx ts-source-to-json-schema src/api.ts
|
|
51
|
+
|
|
52
|
+
# Convert a specific type as the root schema
|
|
53
|
+
npx ts-source-to-json-schema src/api.ts --rootType ApiResponse
|
|
54
|
+
|
|
55
|
+
# Use strict mode (no additional properties allowed)
|
|
56
|
+
npx ts-source-to-json-schema src/config.ts --strictObjects
|
|
57
|
+
|
|
58
|
+
# Disable JSDoc processing
|
|
59
|
+
npx ts-source-to-json-schema src/types.ts --includeJSDoc false
|
|
60
|
+
|
|
61
|
+
# Single file mode, no imports
|
|
62
|
+
npx ts-source-to-json-schema src/types.ts --followImports none
|
|
63
|
+
|
|
64
|
+
# Combine multiple options
|
|
65
|
+
npx ts-source-to-json-schema src/user.ts -r User --strictObjects --followImports local
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### CLI Options
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
-h, --help Show help message
|
|
72
|
+
-v, --version Show version number
|
|
73
|
+
--doctor Output diagnostic information for debugging
|
|
74
|
+
|
|
75
|
+
-r, --rootType <name> Emit this type as root (others in $defs)
|
|
76
|
+
-s, --includeSchema <bool> Include $schema property (default: true)
|
|
77
|
+
--schemaVersion <url> Custom $schema URL
|
|
78
|
+
--strictObjects Set additionalProperties: false globally
|
|
79
|
+
--additionalProperties Set additionalProperties default (true/false)
|
|
80
|
+
--includeJSDoc <bool> Include JSDoc comments (default: true)
|
|
81
|
+
|
|
82
|
+
--followImports <mode> Follow imports: none, local, all (default: local)
|
|
83
|
+
--baseDir <path> Base directory for resolving imports
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The CLI reads TypeScript files and outputs JSON Schema to stdout, making it easy to pipe to files or other tools:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Save to file
|
|
90
|
+
npx ts-source-to-json-schema src/types.ts > schema.json
|
|
91
|
+
|
|
92
|
+
# Pretty-print with jq
|
|
93
|
+
npx ts-source-to-json-schema src/types.ts | jq '.'
|
|
94
|
+
|
|
95
|
+
# Use in scripts
|
|
96
|
+
npx ts-source-to-json-schema src/api.ts --rootType Request > openapi/request-schema.json
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Multi-File Support (`--followImports`)
|
|
100
|
+
|
|
101
|
+
By default, the CLI automatically follows local relative imports (`./` and `../`) to resolve type definitions across multiple files:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// pet.ts
|
|
105
|
+
export interface Pet {
|
|
106
|
+
_id: string;
|
|
107
|
+
name: string;
|
|
108
|
+
species: string;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// api.ts
|
|
112
|
+
import { Pet } from './pet';
|
|
113
|
+
export interface PostPetReq extends Omit<Pet, "_id"> {}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Follows imports and resolves Pet type (default behavior)
|
|
118
|
+
npx ts-source-to-json-schema api.ts --rootType PostPetReq
|
|
119
|
+
|
|
120
|
+
# Output includes both Pet (in $defs) and PostPetReq (as root)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Import Resolution Modes:**
|
|
124
|
+
- `local` (default in CLI): Follows relative imports (`./` and `../`), skips `node_modules`
|
|
125
|
+
- `none`: Single-file mode, does not follow any imports
|
|
126
|
+
- `all`: Reserved for future `node_modules` support (currently behaves like `local`)
|
|
127
|
+
|
|
128
|
+
**Key Features:**
|
|
129
|
+
- Circular dependency detection (no infinite loops)
|
|
130
|
+
- Duplicate name detection (errors if same type name in multiple files)
|
|
131
|
+
- Automatic extension resolution (`.ts`, `.tsx`, `.d.ts`)
|
|
132
|
+
- Index file support (`./types` → `./types/index.ts`)
|
|
133
|
+
|
|
134
|
+
**Examples:**
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# Multi-file project with local imports
|
|
138
|
+
npx ts-source-to-json-schema src/api.ts --followImports local
|
|
139
|
+
|
|
140
|
+
# Single file only, ignore imports
|
|
141
|
+
npx ts-source-to-json-schema src/standalone.ts --followImports none
|
|
142
|
+
|
|
143
|
+
# Custom base directory for import resolution
|
|
144
|
+
npx ts-source-to-json-schema src/api.ts --baseDir ./src
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Diagnostics Mode (`--doctor`)
|
|
148
|
+
|
|
149
|
+
When you encounter issues with schema conversion, use the `--doctor` flag to output comprehensive diagnostic information that can be shared with developers:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
npx ts-source-to-json-schema src/problematic-types.ts --doctor
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The doctor output includes:
|
|
156
|
+
- **Timestamp**: When the conversion was attempted
|
|
157
|
+
- **Environment**: Node.js version, platform, architecture, and current working directory
|
|
158
|
+
- **Input file details**: Path, existence, size, modification time, source length, and full source code
|
|
159
|
+
- **Options used**: All configuration options passed to the converter
|
|
160
|
+
- **Conversion result**: Either the successfully generated schema or detailed error information with stack traces
|
|
161
|
+
|
|
162
|
+
This makes it easy to:
|
|
163
|
+
1. Copy-paste the full diagnostic output when reporting issues
|
|
164
|
+
2. Debug why a particular TypeScript file isn't converting as expected
|
|
165
|
+
3. Share reproducible examples with maintainers
|
|
166
|
+
|
|
167
|
+
**Example output:**
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"timestamp": "2026-02-25T10:50:55.680Z",
|
|
171
|
+
"environment": {
|
|
172
|
+
"nodeVersion": "v20.17.0",
|
|
173
|
+
"platform": "darwin",
|
|
174
|
+
"arch": "arm64",
|
|
175
|
+
"cwd": "/path/to/project"
|
|
176
|
+
},
|
|
177
|
+
"input": {
|
|
178
|
+
"filePath": "types.ts",
|
|
179
|
+
"absolutePath": "/absolute/path/to/types.ts",
|
|
180
|
+
"fileExists": true,
|
|
181
|
+
"fileSize": 486,
|
|
182
|
+
"sourceLength": 486,
|
|
183
|
+
"source": "interface User { ... }"
|
|
184
|
+
},
|
|
185
|
+
"options": { "rootType": "User" },
|
|
186
|
+
"conversionResult": {
|
|
187
|
+
"success": true,
|
|
188
|
+
"schema": { ... }
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Programmatic Usage
|
|
194
|
+
|
|
195
|
+
### String-Based API
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
import { toJsonSchema } from "ts-source-to-json-schema";
|
|
199
|
+
|
|
200
|
+
const schema = toJsonSchema(`
|
|
201
|
+
/** Input for the ad analysis tool */
|
|
202
|
+
interface AnalyzeAdInput {
|
|
203
|
+
/** URL of the ad to analyze */
|
|
204
|
+
url: string;
|
|
205
|
+
/** Platform the ad is from */
|
|
206
|
+
platform: "instagram" | "facebook" | "tiktok";
|
|
207
|
+
/** Whether to extract color palette */
|
|
208
|
+
extractColors?: boolean;
|
|
209
|
+
/** Max elements to identify
|
|
210
|
+
* @minimum 1
|
|
211
|
+
* @maximum 50
|
|
212
|
+
* @default 10
|
|
213
|
+
*/
|
|
214
|
+
maxElements?: number;
|
|
215
|
+
tags: string[];
|
|
216
|
+
}
|
|
217
|
+
`, { rootType: "AnalyzeAdInput" });
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### File-Based API with Import Resolution
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
import { toJsonSchemaFromFile } from "ts-source-to-json-schema";
|
|
224
|
+
|
|
225
|
+
// Convert a TypeScript file with automatic import resolution
|
|
226
|
+
const schema = toJsonSchemaFromFile('./src/types/api.ts', {
|
|
227
|
+
followImports: 'local', // Follow relative imports
|
|
228
|
+
rootType: 'ApiRequest',
|
|
229
|
+
strictObjects: true
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// Single-file mode (no import resolution)
|
|
233
|
+
const singleFileSchema = toJsonSchemaFromFile('./src/types.ts', {
|
|
234
|
+
followImports: 'none'
|
|
235
|
+
});
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Batch Schema Generation
|
|
239
|
+
|
|
240
|
+
When you need schemas for multiple types from the same source file, use `toJsonSchemas()` (plural) for better performance. This is particularly useful for build tools, documentation generators, or API schema validators that process many types at once.
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
import { toJsonSchemas } from "ts-source-to-json-schema";
|
|
244
|
+
|
|
245
|
+
const source = `
|
|
246
|
+
export interface User { id: string; name: string; }
|
|
247
|
+
export interface Post { id: string; title: string; author: User; }
|
|
248
|
+
export interface Comment { id: string; text: string; }
|
|
249
|
+
`;
|
|
250
|
+
|
|
251
|
+
// Generate all schemas at once (~70% faster than calling toJsonSchema() for each type)
|
|
252
|
+
const schemas = toJsonSchemas(source);
|
|
253
|
+
|
|
254
|
+
console.log(schemas.User); // Standalone User schema
|
|
255
|
+
console.log(schemas.Post); // Post schema with User in definitions
|
|
256
|
+
console.log(schemas.Comment); // Standalone Comment schema
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**Key benefits:**
|
|
260
|
+
- **Performance**: ~70% faster when generating 30+ schemas from the same source
|
|
261
|
+
- **Single parse**: Source is tokenized and parsed only once
|
|
262
|
+
- **Standalone schemas**: Each schema includes only the types it references in its `definitions` field
|
|
263
|
+
- **Self-contained**: Each schema includes `$schema` field by default for better IDE validation
|
|
264
|
+
- **Draft-07 compatible**: Uses `definitions` instead of `$defs` for broader compatibility
|
|
265
|
+
|
|
266
|
+
**How it works:**
|
|
267
|
+
- Parses the source once and emits all type declarations
|
|
268
|
+
- Each schema is standalone with minimal `definitions` (only transitively referenced types)
|
|
269
|
+
- Uses `#/definitions/TypeName` refs instead of `#/$defs/TypeName`
|
|
270
|
+
- Handles circular references, transitive dependencies, and utility types
|
|
271
|
+
|
|
272
|
+
**Use cases:**
|
|
273
|
+
- Framework integrations (like Flink) that need many schemas from one source
|
|
274
|
+
- Build tools generating schemas for entire API definition files
|
|
275
|
+
- Documentation generators processing large type files
|
|
276
|
+
- Schema validation libraries caching multiple schemas
|
|
277
|
+
|
|
278
|
+
**Example with real-world API:**
|
|
279
|
+
```typescript
|
|
280
|
+
const schemas = toJsonSchemas(`
|
|
281
|
+
interface User { id: string; name: string; }
|
|
282
|
+
interface CreateUserRequest { name: string; }
|
|
283
|
+
interface CreateUserResponse { user: User; }
|
|
284
|
+
interface GetUserRequest { id: string; }
|
|
285
|
+
interface GetUserResponse { user: User; }
|
|
286
|
+
`, { includeJSDoc: true, strictObjects: true });
|
|
287
|
+
|
|
288
|
+
// Extract specific schemas as needed
|
|
289
|
+
const requestSchemas = {
|
|
290
|
+
CreateUser: schemas.CreateUserRequest,
|
|
291
|
+
GetUser: schemas.GetUserRequest
|
|
292
|
+
};
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
#### Batch Generation with Import Resolution
|
|
296
|
+
|
|
297
|
+
If your types are spread across multiple files with imports, use `toJsonSchemasFromFile()` (the file-based batch API):
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
import { toJsonSchemasFromFile } from "ts-source-to-json-schema";
|
|
301
|
+
|
|
302
|
+
// Intermediate schema file (e.g., generated by a framework)
|
|
303
|
+
// schemas.ts:
|
|
304
|
+
// import TreeNode from "../../src/schemas/TreeNode";
|
|
305
|
+
// import Car from "../../src/schemas/Car";
|
|
306
|
+
// export interface GetTree_12_ResSchema extends TreeNode {}
|
|
307
|
+
// export interface GetCar_10_ResSchema extends Car {}
|
|
308
|
+
|
|
309
|
+
const schemas = toJsonSchemasFromFile('./schemas.ts', {
|
|
310
|
+
followImports: 'local', // Resolve relative imports
|
|
311
|
+
strictObjects: true
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
console.log(schemas.GetTree_12_ResSchema);
|
|
315
|
+
// {
|
|
316
|
+
// "$ref": "#/definitions/TreeNode",
|
|
317
|
+
// "definitions": {
|
|
318
|
+
// "TreeNode": { "type": "object", ... } // ✅ Included from imported file!
|
|
319
|
+
// }
|
|
320
|
+
// }
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
**Why use `toJsonSchemasFromFile()`?**
|
|
324
|
+
- Automatically resolves imports from local files
|
|
325
|
+
- Generates batch schemas for all types (like `toJsonSchemas()`)
|
|
326
|
+
- Handles circular dependencies across files
|
|
327
|
+
- Perfect for framework integrations (like Flink) with generated intermediate files
|
|
328
|
+
|
|
329
|
+
**Performance:** Same batch performance benefits as `toJsonSchemas()`, plus automatic import resolution.
|
|
330
|
+
|
|
331
|
+
Output:
|
|
332
|
+
|
|
333
|
+
```json
|
|
334
|
+
{
|
|
335
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
336
|
+
"type": "object",
|
|
337
|
+
"description": "Input for the ad analysis tool",
|
|
338
|
+
"properties": {
|
|
339
|
+
"url": { "type": "string", "description": "URL of the ad to analyze" },
|
|
340
|
+
"platform": {
|
|
341
|
+
"type": "string",
|
|
342
|
+
"enum": ["instagram", "facebook", "tiktok"],
|
|
343
|
+
"description": "Platform the ad is from"
|
|
344
|
+
},
|
|
345
|
+
"extractColors": { "type": "boolean", "description": "Whether to extract color palette" },
|
|
346
|
+
"maxElements": {
|
|
347
|
+
"type": "number",
|
|
348
|
+
"description": "Max elements to identify",
|
|
349
|
+
"minimum": 1,
|
|
350
|
+
"maximum": 50,
|
|
351
|
+
"default": 10
|
|
352
|
+
},
|
|
353
|
+
"tags": { "type": "array", "items": { "type": "string" } }
|
|
354
|
+
},
|
|
355
|
+
"required": ["url", "platform", "tags"]
|
|
356
|
+
}
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
## Options
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
toJsonSchema(source, {
|
|
363
|
+
rootType: "MyType", // Emit this type as the root schema (others go in $defs)
|
|
364
|
+
includeSchema: true, // Include $schema field (default: true)
|
|
365
|
+
strictObjects: false, // Set additionalProperties: false on all objects
|
|
366
|
+
schemaVersion: "https://json-schema.org/draft/2020-12/schema",
|
|
367
|
+
includeJSDoc: true, // Include JSDoc descriptions and tags (default: true)
|
|
368
|
+
additionalProperties: undefined, // Default value for additionalProperties (undefined, true, or false)
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
toJsonSchemaFromFile(filePath, {
|
|
372
|
+
// All options from toJsonSchema, plus:
|
|
373
|
+
followImports: 'local', // Follow imports: 'none' (default for API), 'local' (default for CLI), 'all'
|
|
374
|
+
baseDir: './src', // Base directory for resolving imports (default: dirname(filePath))
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
toJsonSchemasFromFile(filePath, {
|
|
378
|
+
// All options from toJsonSchemas, plus:
|
|
379
|
+
followImports: 'local', // Follow imports: 'none', 'local' (default), 'all'
|
|
380
|
+
baseDir: './src', // Base directory for resolving imports (default: dirname(filePath))
|
|
381
|
+
// Note: rootType is not supported (generates schemas for all types)
|
|
382
|
+
});
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### `includeJSDoc` (optional)
|
|
386
|
+
- **Type:** `boolean`
|
|
387
|
+
- **Default:** `true`
|
|
388
|
+
- **Description:** Controls whether JSDoc comments are processed and included in the schema
|
|
389
|
+
|
|
390
|
+
When `true` (default):
|
|
391
|
+
- Interface/type descriptions are extracted from JSDoc comments
|
|
392
|
+
- Property descriptions are included
|
|
393
|
+
- JSDoc tags like `@minimum`, `@maximum`, `@pattern` are applied as constraints
|
|
394
|
+
|
|
395
|
+
When `false`:
|
|
396
|
+
- All JSDoc comments are ignored
|
|
397
|
+
- Schema only contains structural information (types, properties, required fields)
|
|
398
|
+
- Useful for generating minimal schemas or when descriptions aren't needed
|
|
399
|
+
|
|
400
|
+
**Example:**
|
|
401
|
+
```typescript
|
|
402
|
+
const schema = toJsonSchema(`
|
|
403
|
+
/** User profile */
|
|
404
|
+
interface User {
|
|
405
|
+
/** @minLength 1 */
|
|
406
|
+
name: string;
|
|
407
|
+
}
|
|
408
|
+
`, { rootType: 'User', includeJSDoc: false });
|
|
409
|
+
|
|
410
|
+
// Result: { type: 'object', properties: { name: { type: 'string' } }, required: ['name'] }
|
|
411
|
+
// No description or minLength constraint
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### `includeSchema` (optional)
|
|
415
|
+
- **Type:** `boolean`
|
|
416
|
+
- **Default:** `true`
|
|
417
|
+
- **Description:** Controls whether the `$schema` field is included in generated schemas
|
|
418
|
+
|
|
419
|
+
When `true` (default):
|
|
420
|
+
- Each generated schema includes a `$schema` field pointing to the JSON Schema specification
|
|
421
|
+
- Makes schemas self-contained and improves IDE validation support
|
|
422
|
+
- Uses the URL from `schemaVersion` option (default: `https://json-schema.org/draft/2020-12/schema`)
|
|
423
|
+
|
|
424
|
+
When `false`:
|
|
425
|
+
- The `$schema` field is omitted from all generated schemas
|
|
426
|
+
- Useful when embedding schemas in larger documents or when the schema version is managed elsewhere
|
|
427
|
+
|
|
428
|
+
**Example:**
|
|
429
|
+
```typescript
|
|
430
|
+
const schema = toJsonSchema(`
|
|
431
|
+
interface User {
|
|
432
|
+
name: string;
|
|
433
|
+
}
|
|
434
|
+
`, { rootType: 'User', includeSchema: true });
|
|
435
|
+
|
|
436
|
+
// Result includes: { "$schema": "https://json-schema.org/draft/2020-12/schema", type: 'object', ... }
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
**Batch generation:** The `toJsonSchemas()` function also respects this option and includes `$schema` in each generated schema by default.
|
|
440
|
+
|
|
441
|
+
### `schemaVersion` (optional)
|
|
442
|
+
- **Type:** `string`
|
|
443
|
+
- **Default:** `"https://json-schema.org/draft/2020-12/schema"`
|
|
444
|
+
- **Description:** Specifies the JSON Schema draft version URL
|
|
445
|
+
|
|
446
|
+
Use this to generate schemas compatible with different JSON Schema drafts:
|
|
447
|
+
|
|
448
|
+
```typescript
|
|
449
|
+
// Generate draft-07 compatible schema
|
|
450
|
+
const schema = toJsonSchema(`interface User { name: string; }`, {
|
|
451
|
+
rootType: 'User',
|
|
452
|
+
schemaVersion: 'http://json-schema.org/draft-07/schema#'
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
// Result includes: { "$schema": "http://json-schema.org/draft-07/schema#", ... }
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
**Note:** This library always generates draft-2020-12 compatible schemas. The `schemaVersion` option only changes the `$schema` field value. For maximum compatibility with draft-07 validators, use `toJsonSchemas()` which uses `definitions` instead of `$defs`.
|
|
459
|
+
|
|
460
|
+
### `additionalProperties` (optional)
|
|
461
|
+
- **Type:** `boolean | undefined`
|
|
462
|
+
- **Default:** `undefined`
|
|
463
|
+
- **Description:** Sets the default value for `additionalProperties` on all object schemas
|
|
464
|
+
|
|
465
|
+
This option provides a global default for `additionalProperties` when not explicitly set via JSDoc or index signatures.
|
|
466
|
+
|
|
467
|
+
**Precedence (highest to lowest):**
|
|
468
|
+
1. Index signature: `[key: string]: T` → `additionalProperties: T`
|
|
469
|
+
2. JSDoc `@additionalProperties` tag
|
|
470
|
+
3. `strictObjects` option
|
|
471
|
+
4. `additionalProperties` option
|
|
472
|
+
5. Not set (JSON Schema default behavior)
|
|
473
|
+
|
|
474
|
+
**Example:**
|
|
475
|
+
```typescript
|
|
476
|
+
// Set all objects to disallow additional properties by default
|
|
477
|
+
const schema = toJsonSchema(`
|
|
478
|
+
interface User {
|
|
479
|
+
name: string;
|
|
480
|
+
}
|
|
481
|
+
`, { rootType: 'User', additionalProperties: false });
|
|
482
|
+
|
|
483
|
+
// Result: { type: 'object', properties: { name: { type: 'string' } }, required: ['name'], additionalProperties: false }
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
### `@additionalProperties` JSDoc Tag
|
|
487
|
+
|
|
488
|
+
Control `additionalProperties` on specific types or properties using the `@additionalProperties` JSDoc tag.
|
|
489
|
+
|
|
490
|
+
**Supported values:** `true` | `false` (case-insensitive)
|
|
491
|
+
|
|
492
|
+
**Usage at interface/type level:**
|
|
493
|
+
```typescript
|
|
494
|
+
/**
|
|
495
|
+
* Strict configuration object
|
|
496
|
+
* @additionalProperties false
|
|
497
|
+
*/
|
|
498
|
+
interface Config {
|
|
499
|
+
host: string;
|
|
500
|
+
port: number;
|
|
501
|
+
}
|
|
502
|
+
// Result: { type: 'object', properties: {...}, additionalProperties: false }
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
**Usage at property level:**
|
|
506
|
+
```typescript
|
|
507
|
+
interface Settings {
|
|
508
|
+
/**
|
|
509
|
+
* Database configuration
|
|
510
|
+
* @additionalProperties false
|
|
511
|
+
*/
|
|
512
|
+
database: {
|
|
513
|
+
host: string;
|
|
514
|
+
port: number;
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
// Result: database property has additionalProperties: false
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
**Interaction with other options:**
|
|
521
|
+
- When `includeJSDoc: false`, the tag is ignored
|
|
522
|
+
- The tag overrides the global `additionalProperties` and `strictObjects` options
|
|
523
|
+
- Index signatures take precedence over the tag
|
|
524
|
+
|
|
525
|
+
### `followImports` (optional)
|
|
526
|
+
- **Type:** `"none" | "local" | "all"`
|
|
527
|
+
- **Default:** `"none"` (programmatic API), `"local"` (CLI)
|
|
528
|
+
- **Description:** Controls import resolution across multiple TypeScript files
|
|
529
|
+
|
|
530
|
+
**Modes:**
|
|
531
|
+
- `none`: Single-file mode, imports are ignored
|
|
532
|
+
- `local`: Follows relative imports (`./` and `../`), skips `node_modules`
|
|
533
|
+
- `all`: Reserved for future `node_modules` support (currently behaves like `local`)
|
|
534
|
+
|
|
535
|
+
**Only available with file-based APIs** (`toJsonSchemaFromFile()` and `toJsonSchemasFromFile()`) — the string-based APIs (`toJsonSchema()` and `toJsonSchemas()`) do not support import resolution.
|
|
536
|
+
|
|
537
|
+
**Example:**
|
|
538
|
+
```typescript
|
|
539
|
+
// Given: pet.ts exports Pet interface
|
|
540
|
+
// Given: api.ts imports Pet and uses it in PostPetReq
|
|
541
|
+
|
|
542
|
+
const schema = toJsonSchemaFromFile('./api.ts', {
|
|
543
|
+
followImports: 'local',
|
|
544
|
+
rootType: 'PostPetReq'
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
// Result: Schema includes both Pet (in $defs) and PostPetReq
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
**Features:**
|
|
551
|
+
- Circular dependency detection (prevents infinite loops)
|
|
552
|
+
- Duplicate name detection (throws error if same type appears in multiple files)
|
|
553
|
+
- Automatic extension resolution (`.ts`, `.tsx`, `.d.ts`)
|
|
554
|
+
- Index file resolution (`./types` → `./types/index.ts`)
|
|
555
|
+
|
|
556
|
+
### `baseDir` (optional)
|
|
557
|
+
- **Type:** `string`
|
|
558
|
+
- **Default:** `path.dirname(filePath)`
|
|
559
|
+
- **Description:** Base directory for resolving relative imports
|
|
560
|
+
|
|
561
|
+
Only relevant when `followImports` is not `"none"`.
|
|
562
|
+
|
|
563
|
+
## What it doesn't handle
|
|
564
|
+
|
|
565
|
+
Anything that requires the type checker to evaluate:
|
|
566
|
+
|
|
567
|
+
- Conditional types (`T extends U ? X : Y`)
|
|
568
|
+
- Mapped types (`{ [K in keyof T]: ... }`)
|
|
569
|
+
- Template literal types (`` `${A}-${B}` ``)
|
|
570
|
+
- `typeof`, `keyof`, `infer`
|
|
571
|
+
- Generics (user-defined, beyond the built-in utility types)
|
|
572
|
+
- `node_modules` imports (planned for future)
|
|
573
|
+
|
|
574
|
+
If you need these, use `ts-json-schema-generator`. If your types look like API contracts and tool definitions, this is probably all you need.
|
package/dist/ast.d.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/** A property in an object/interface type */
|
|
2
|
+
export interface PropertyNode {
|
|
3
|
+
name: string;
|
|
4
|
+
type: TypeNode;
|
|
5
|
+
optional: boolean;
|
|
6
|
+
readonly: boolean;
|
|
7
|
+
description?: string;
|
|
8
|
+
tags?: Record<string, string>;
|
|
9
|
+
}
|
|
10
|
+
/** Index signature: [key: string]: ValueType */
|
|
11
|
+
export interface IndexSignatureNode {
|
|
12
|
+
keyType: TypeNode;
|
|
13
|
+
valueType: TypeNode;
|
|
14
|
+
}
|
|
15
|
+
/** All possible type AST nodes */
|
|
16
|
+
export type TypeNode = {
|
|
17
|
+
kind: "primitive";
|
|
18
|
+
value: "string" | "number" | "boolean" | "null" | "undefined" | "any" | "unknown" | "never" | "void" | "object" | "bigint";
|
|
19
|
+
} | {
|
|
20
|
+
kind: "literal_string";
|
|
21
|
+
value: string;
|
|
22
|
+
} | {
|
|
23
|
+
kind: "literal_number";
|
|
24
|
+
value: number;
|
|
25
|
+
} | {
|
|
26
|
+
kind: "literal_boolean";
|
|
27
|
+
value: boolean;
|
|
28
|
+
} | {
|
|
29
|
+
kind: "object";
|
|
30
|
+
properties: PropertyNode[];
|
|
31
|
+
indexSignature?: IndexSignatureNode;
|
|
32
|
+
} | {
|
|
33
|
+
kind: "array";
|
|
34
|
+
element: TypeNode;
|
|
35
|
+
} | {
|
|
36
|
+
kind: "tuple";
|
|
37
|
+
elements: TupleElement[];
|
|
38
|
+
} | {
|
|
39
|
+
kind: "union";
|
|
40
|
+
members: TypeNode[];
|
|
41
|
+
} | {
|
|
42
|
+
kind: "intersection";
|
|
43
|
+
members: TypeNode[];
|
|
44
|
+
} | {
|
|
45
|
+
kind: "reference";
|
|
46
|
+
name: string;
|
|
47
|
+
typeArgs?: TypeNode[];
|
|
48
|
+
} | {
|
|
49
|
+
kind: "parenthesized";
|
|
50
|
+
inner: TypeNode;
|
|
51
|
+
} | {
|
|
52
|
+
kind: "template_literal";
|
|
53
|
+
parts: (string | TypeNode)[];
|
|
54
|
+
} | {
|
|
55
|
+
kind: "record";
|
|
56
|
+
keyType: TypeNode;
|
|
57
|
+
valueType: TypeNode;
|
|
58
|
+
} | {
|
|
59
|
+
kind: "mapped";
|
|
60
|
+
keyName: string;
|
|
61
|
+
constraint: TypeNode;
|
|
62
|
+
valueType: TypeNode;
|
|
63
|
+
optional?: boolean;
|
|
64
|
+
};
|
|
65
|
+
export interface TupleElement {
|
|
66
|
+
type: TypeNode;
|
|
67
|
+
optional?: boolean;
|
|
68
|
+
label?: string;
|
|
69
|
+
rest?: boolean;
|
|
70
|
+
}
|
|
71
|
+
/** Top-level declarations we extract from source */
|
|
72
|
+
export type Declaration = InterfaceDeclaration | TypeAliasDeclaration | EnumDeclaration;
|
|
73
|
+
export interface InterfaceDeclaration {
|
|
74
|
+
kind: "interface";
|
|
75
|
+
name: string;
|
|
76
|
+
extends?: TypeNode[];
|
|
77
|
+
properties: PropertyNode[];
|
|
78
|
+
indexSignature?: IndexSignatureNode;
|
|
79
|
+
description?: string;
|
|
80
|
+
tags?: Record<string, string>;
|
|
81
|
+
exported: boolean;
|
|
82
|
+
}
|
|
83
|
+
export interface TypeAliasDeclaration {
|
|
84
|
+
kind: "type_alias";
|
|
85
|
+
name: string;
|
|
86
|
+
type: TypeNode;
|
|
87
|
+
description?: string;
|
|
88
|
+
tags?: Record<string, string>;
|
|
89
|
+
exported: boolean;
|
|
90
|
+
}
|
|
91
|
+
export interface EnumDeclaration {
|
|
92
|
+
kind: "enum";
|
|
93
|
+
name: string;
|
|
94
|
+
members: {
|
|
95
|
+
name: string;
|
|
96
|
+
value: string | number;
|
|
97
|
+
}[];
|
|
98
|
+
description?: string;
|
|
99
|
+
tags?: Record<string, string>;
|
|
100
|
+
exported: boolean;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=ast.d.ts.map
|