Skip to content

Commit ad6e0eb

Browse files
committed
feat: Generate titles from definition names
All root child definitions have a 'title' added to their definition if the opt-in definitionTitles option is set
1 parent d500564 commit ad6e0eb

File tree

7 files changed

+302
-65
lines changed

7 files changed

+302
-65
lines changed

README.md

+126-65
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,27 @@
44
[![codecov](https://codecov.io/gh/vega/ts-json-schema-generator/branch/master/graph/badge.svg)](https://codecov.io/gh/vega/ts-json-schema-generator)
55
[![npm version](https://img.shields.io/npm/v/ts-json-schema-generator.svg)](https://www.npmjs.com/package/ts-json-schema-generator)
66

7-
Extended version of [https://github.com/xiag-ag/typescript-to-json-schema](https://github.com/xiag-ag/typescript-to-json-schema).
7+
Extended version of
8+
[https://github.com/xiag-ag/typescript-to-json-schema](https://github.com/xiag-ag/typescript-to-json-schema).
89

9-
Inspired by [`YousefED/typescript-json-schema`](https://github.com/YousefED/typescript-json-schema). Here's the differences list:
10+
Inspired by
11+
[`YousefED/typescript-json-schema`](https://github.com/YousefED/typescript-json-schema).
12+
Here's the differences list:
1013

11-
- this implementation avoids the use of `typeChecker.getTypeAtLocation()` (so probably it keeps correct type aliases)
12-
- processing AST and formatting JSON schema have been split into two independent steps
13-
- not exported types, interfaces, enums are not exposed in the `definitions` section in the JSON schema
14+
- this implementation avoids the use of `typeChecker.getTypeAtLocation()` (so
15+
probably it keeps correct type aliases)
16+
- processing AST and formatting JSON schema have been split into two independent
17+
steps
18+
- not exported types, interfaces, enums are not exposed in the `definitions`
19+
section in the JSON schema
1420

1521
## Contributors
1622

17-
This project is made possible by a [community of contributors](https://github.com/vega/ts-json-schema-generator/graphs/contributors). We welcome contributions of any kind (issues, code, documentation, examples, tests,...). Please read our [code of conduct](https://vega.github.io/vega/about/code-of-conduct).
23+
This project is made possible by a
24+
[community of contributors](https://github.com/vega/ts-json-schema-generator/graphs/contributors).
25+
We welcome contributions of any kind (issues, code, documentation, examples,
26+
tests,...). Please read our
27+
[code of conduct](https://vega.github.io/vega/about/code-of-conduct).
1828

1929
## CLI Usage
2030

@@ -31,35 +41,43 @@ npm install --save ts-json-schema-generator
3141
./node_modules/.bin/ts-json-schema-generator --path 'my/project/**/*.ts' --type 'My.Type.Name'
3242
```
3343

34-
Note that different platforms (e.g. Windows) may use different path separators so you may have to adjust the command above.
44+
Note that different platforms (e.g. Windows) may use different path separators
45+
so you may have to adjust the command above.
3546

36-
Also note that you need to quote paths with `*` as otherwise the shell will expand the paths and therefore only pass the first path to the generator.
47+
Also note that you need to quote paths with `*` as otherwise the shell will
48+
expand the paths and therefore only pass the first path to the generator.
3749

38-
By default, the command-line generator will use the `tsconfig.json` file in the current working directory, or the first parent directory that contains a `tsconfig.json` file up to the root of the filesystem. If you want to use a different `tsconfig.json` file, you can use the `--tsconfig` option. In particular, if you need to use different compilation options for types, you may want to create a separate `tsconfig.json` file for the schema generation only.
50+
By default, the command-line generator will use the `tsconfig.json` file in the
51+
current working directory, or the first parent directory that contains a
52+
`tsconfig.json` file up to the root of the filesystem. If you want to use a
53+
different `tsconfig.json` file, you can use the `--tsconfig` option. In
54+
particular, if you need to use different compilation options for types, you may
55+
want to create a separate `tsconfig.json` file for the schema generation only.
3956

4057
### Options
4158

4259
```
43-
-p, --path <path> Source file path
44-
-t, --type <name> Type name
45-
-i, --id <name> $id for generated schema
46-
-f, --tsconfig <path> Custom tsconfig.json path
47-
-e, --expose <expose> Type exposing (choices: "all", "none", "export", default: "export")
48-
-j, --jsDoc <extended> Read JsDoc annotations (choices: "none", "basic", "extended", default: "extended")
49-
--markdown-description Generate `markdownDescription` in addition to `description`.
50-
--functions <functions> How to handle functions. `fail` will throw an error. `comment` will add a comment. `hide` will treat the function like a NeverType or HiddenType.
51-
(choices: "fail", "comment", "hide", default: "comment")
52-
--minify Minify generated schema (default: false)
53-
--unstable Do not sort properties
54-
--strict-tuples Do not allow additional items on tuples
55-
--no-top-ref Do not create a top-level $ref definition
56-
--no-type-check Skip type checks to improve performance
57-
--no-ref-encode Do not encode references
58-
-o, --out <file> Set the output file (default: stdout)
59-
--validation-keywords [value] Provide additional validation keywords to include (default: [])
60-
--additional-properties Allow additional properties for objects with no index signature (default: false)
61-
-V, --version output the version number
62-
-h, --help display help for command
60+
-p, --path <path> Source file path
61+
-t, --type <name> Type name
62+
-i, --id <name> $id for generated schema
63+
-f, --tsconfig <path> Custom tsconfig.json path
64+
-e, --expose <expose> Type exposing (choices: "all", "none", "export", default: "export")
65+
-j, --jsDoc <extended> Read JsDoc annotations (choices: "none", "basic", "extended", default: "extended")
66+
--markdown-description Generate `markdownDescription` in addition to `description`.
67+
--functions <functions> How to handle functions. `fail` will throw an error. `comment` will add a comment. `hide` will treat the function like a NeverType or HiddenType.
68+
(choices: "fail", "comment", "hide", default: "comment")
69+
--definition-titles Generates titles from definition names
70+
--minify Minify generated schema (default: false)
71+
--unstable Do not sort properties
72+
--strict-tuples Do not allow additional items on tuples
73+
--no-top-ref Do not create a top-level $ref definition
74+
--no-type-check Skip type checks to improve performance
75+
--no-ref-encode Do not encode references
76+
-o, --out <file> Set the output file (default: stdout)
77+
--validation-keywords [value] Provide additional validation keywords to include (default: [])
78+
--additional-properties Allow additional properties for objects with no index signature (default: false)
79+
-V, --version output the version number
80+
-h, --help display help for command
6381
```
6482

6583
## Programmatic Usage
@@ -90,13 +108,20 @@ Run the schema generator via `node main.js`.
90108

91109
### Custom formatting
92110

93-
Extending the built-in formatting is possible by creating a custom formatter and adding it to the main formatter:
111+
Extending the built-in formatting is possible by creating a custom formatter and
112+
adding it to the main formatter:
94113

95-
1. First we create a formatter, in this case for formatting function types (note that there is a built in one):
114+
1. First we create a formatter, in this case for formatting function types (note
115+
that there is a built in one):
96116

97117
```ts
98118
// my-function-formatter.ts
99-
import { BaseType, Definition, FunctionType, SubTypeFormatter } from "ts-json-schema-generator";
119+
import {
120+
BaseType,
121+
Definition,
122+
FunctionType,
123+
SubTypeFormatter,
124+
} from "ts-json-schema-generator";
100125
import ts from "typescript";
101126

102127
export class MyFunctionTypeFormatter implements SubTypeFormatter {
@@ -133,10 +158,16 @@ export class MyFunctionTypeFormatter implements SubTypeFormatter {
133158
}
134159
```
135160

136-
2. Then we add the formatter as a child to the core formatter using the augmentation callback:
161+
2. Then we add the formatter as a child to the core formatter using the
162+
augmentation callback:
137163

138164
```ts
139-
import { createProgram, createParser, SchemaGenerator, createFormatter } from "ts-json-schema-generator";
165+
import {
166+
createFormatter,
167+
createParser,
168+
createProgram,
169+
SchemaGenerator,
170+
} from "ts-json-schema-generator";
140171
import { MyFunctionTypeFormatter } from "./my-function-formatter.ts";
141172
import fs from "fs";
142173

@@ -147,12 +178,17 @@ const config = {
147178
};
148179

149180
// We configure the formatter an add our custom formatter to it.
150-
const formatter = createFormatter(config, (fmt, circularReferenceTypeFormatter) => {
151-
// If your formatter DOES NOT support children, e.g. getChildren() { return [] }:
152-
fmt.addTypeFormatter(new MyFunctionTypeFormatter());
153-
// If your formatter DOES support children, you'll need this reference too:
154-
fmt.addTypeFormatter(new MyFunctionTypeFormatter(circularReferenceTypeFormatter));
155-
});
181+
const formatter = createFormatter(
182+
config,
183+
(fmt, circularReferenceTypeFormatter) => {
184+
// If your formatter DOES NOT support children, e.g. getChildren() { return [] }:
185+
fmt.addTypeFormatter(new MyFunctionTypeFormatter());
186+
// If your formatter DOES support children, you'll need this reference too:
187+
fmt.addTypeFormatter(
188+
new MyFunctionTypeFormatter(circularReferenceTypeFormatter),
189+
);
190+
},
191+
);
156192

157193
const program = createProgram(config);
158194
const parser = createParser(program, config);
@@ -168,30 +204,47 @@ fs.writeFile(outputPath, schemaString, (err) => {
168204

169205
### Custom parsing
170206

171-
Similar to custom formatting, extending the built-in parsing works practically the same way:
207+
Similar to custom formatting, extending the built-in parsing works practically
208+
the same way:
172209

173210
1. First we create a parser, in this case for parsing construct types:
174211

175212
```ts
176213
// my-constructor-parser.ts
177-
import { Context, StringType, ReferenceType, BaseType, SubNodeParser } from "ts-json-schema-generator";
214+
import {
215+
BaseType,
216+
Context,
217+
ReferenceType,
218+
StringType,
219+
SubNodeParser,
220+
} from "ts-json-schema-generator";
178221
// use typescript exported by TJS to avoid version conflict
179222
import ts from "ts-json-schema-generator";
180223

181224
export class MyConstructorParser implements SubNodeParser {
182225
supportsNode(node: ts.Node): boolean {
183226
return node.kind === ts.SyntaxKind.ConstructorType;
184227
}
185-
createType(node: ts.Node, context: Context, reference?: ReferenceType): BaseType | undefined {
228+
createType(
229+
node: ts.Node,
230+
context: Context,
231+
reference?: ReferenceType,
232+
): BaseType | undefined {
186233
return new StringType(); // Treat constructors as strings in this example
187234
}
188235
}
189236
```
190237

191-
2. Then we add the parser as a child to the core parser using the augmentation callback:
238+
2. Then we add the parser as a child to the core parser using the augmentation
239+
callback:
192240

193241
```ts
194-
import { createProgram, createParser, SchemaGenerator, createFormatter } from "ts-json-schema-generator";
242+
import {
243+
createFormatter,
244+
createParser,
245+
createProgram,
246+
SchemaGenerator,
247+
} from "ts-json-schema-generator";
195248
import { MyConstructorParser } from "./my-constructor-parser.ts";
196249
import fs from "fs";
197250

@@ -221,20 +274,20 @@ fs.writeFile(outputPath, schemaString, (err) => {
221274

222275
## Current state
223276

224-
- `interface` types
225-
- `enum` types
226-
- `union`, `tuple`, `type[]` types
227-
- `Date`, `RegExp`, `URL` types
228-
- `string`, `boolean`, `number` types
229-
- `"value"`, `123`, `true`, `false`, `null`, `undefined` literals
230-
- type aliases
231-
- generics
232-
- `typeof`
233-
- `keyof`
234-
- conditional types
235-
- functions
236-
- `Promise<T>` unwraps to `T`
237-
- Overrides (like `@format`)
277+
- `interface` types
278+
- `enum` types
279+
- `union`, `tuple`, `type[]` types
280+
- `Date`, `RegExp`, `URL` types
281+
- `string`, `boolean`, `number` types
282+
- `"value"`, `123`, `true`, `false`, `null`, `undefined` literals
283+
- type aliases
284+
- generics
285+
- `typeof`
286+
- `keyof`
287+
- conditional types
288+
- functions
289+
- `Promise<T>` unwraps to `T`
290+
- Overrides (like `@format`)
238291

239292
## Run locally
240293

@@ -250,9 +303,17 @@ And connect via the debugger protocol.
250303

251304
## Publish
252305

253-
Publishing is handled by a 2-branch [pre-release process](https://intuit.github.io/auto/docs/generated/shipit#next-branch-default), configured in `publish-auto.yml`. All changes should be based off the default `next` branch, and are published automatically.
254-
255-
- PRs made into the default branch are auto-deployed to the `next` pre-release tag on NPM. The result can be installed with `npm install ts-json-schema-generator@next`
256-
- When merging into `next`, please use the `squash and merge` strategy.
257-
- To release a new stable version, open a PR from `next` into `stable` using this [compare link](https://github.com/vega/ts-json-schema-generator/compare/stable...next).
258-
- When merging from `next` into `stable`, please use the `create a merge commit` strategy.
306+
Publishing is handled by a 2-branch
307+
[pre-release process](https://intuit.github.io/auto/docs/generated/shipit#next-branch-default),
308+
configured in `publish-auto.yml`. All changes should be based off the default
309+
`next` branch, and are published automatically.
310+
311+
- PRs made into the default branch are auto-deployed to the `next` pre-release
312+
tag on NPM. The result can be installed with
313+
`npm install ts-json-schema-generator@next`
314+
- When merging into `next`, please use the `squash and merge` strategy.
315+
- To release a new stable version, open a PR from `next` into `stable` using
316+
this
317+
[compare link](https://github.com/vega/ts-json-schema-generator/compare/stable...next).
318+
- When merging from `next` into `stable`, please use the
319+
`create a merge commit` strategy.

src/Config.ts

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export interface Config {
1616
additionalProperties?: boolean;
1717
discriminatorType?: "json-schema" | "open-api";
1818
functions?: FunctionOptions;
19+
definitionTitles?: boolean;
1920
}
2021

2122
export type CompletedConfig = Config & typeof DEFAULT_CONFIG;
@@ -36,4 +37,5 @@ export const DEFAULT_CONFIG: Omit<Required<Config>, "path" | "type" | "schemaId"
3637
additionalProperties: false,
3738
discriminatorType: "json-schema",
3839
functions: "comment",
40+
definitionTitles: false,
3941
};

src/SchemaGenerator.ts

+3
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ export class SchemaGenerator {
135135
const name = child.getName();
136136
if (!(name in definitions)) {
137137
definitions[name] = this.typeFormatter.getDefinition(child.getType());
138+
if (this.config?.definitionTitles) {
139+
definitions[name].title = name;
140+
}
138141
}
139142
return definitions;
140143
}, childDefinitions);

test/config.test.ts

+11
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,17 @@ describe("config", () => {
229229
}),
230230
);
231231

232+
it(
233+
"definition-titles",
234+
assertSchema("definition-titles", {
235+
type: "MyObject",
236+
expose: "export",
237+
topRef: false,
238+
definitionTitles: true,
239+
jsDoc: "none",
240+
}),
241+
);
242+
232243
it(
233244
"jsdoc-complex-none",
234245
assertSchema("jsdoc-complex-none", {

test/config/definition-titles/main.ts

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
export interface ExportInterface {
2+
exportValue: string;
3+
}
4+
export type ExportAlias = ExportInterface;
5+
6+
interface PrivateInterface {
7+
privateValue: string;
8+
}
9+
type PrivateAlias = PrivateInterface;
10+
11+
interface MixedInterface {
12+
mixedValue: ExportAlias;
13+
}
14+
export type MixedAlias = PrivateInterface;
15+
16+
export type PublicAnonymousTypeLiteral = {
17+
publicValue: string;
18+
};
19+
20+
type PrivateAnonymousTypeLiteral = {
21+
privateValue: string;
22+
};
23+
24+
export interface MyObject {
25+
exportInterface: ExportInterface;
26+
exportAlias: ExportAlias;
27+
28+
privateInterface: PrivateInterface;
29+
privateAlias: PrivateAlias;
30+
31+
mixedInterface: MixedInterface;
32+
mixedAlias: MixedAlias;
33+
34+
publicAnonymousTypeLiteral: PublicAnonymousTypeLiteral;
35+
privateAnonymousTypeLiteral: PrivateAnonymousTypeLiteral;
36+
}

0 commit comments

Comments
 (0)