Skip to content

Commit dc8ffeb

Browse files
Add require functionality in annotations (#399)
1 parent e9038ca commit dc8ffeb

File tree

9 files changed

+466
-72
lines changed

9 files changed

+466
-72
lines changed

README.md

Lines changed: 133 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Options:
4848
--rejectDateType Rejects Date fields in type definitions. [boolean] [default: false]
4949
--id Set schema id. [string] [default: ""]
5050
--defaultNumberType Default number type. [choices: "number", "integer"] [default: "number"]
51+
--tsNodeRegister Use ts-node/register (needed for require typescript files). [boolean] [default: false]
5152
```
5253

5354
### Programmatic use
@@ -59,12 +60,12 @@ import * as TJS from "typescript-json-schema";
5960

6061
// optionally pass argument to schema generator
6162
const settings: TJS.PartialArgs = {
62-
required: true,
63+
required: true,
6364
};
6465

6566
// optionally pass ts compiler options
6667
const compilerOptions: TJS.CompilerOptions = {
67-
strictNullChecks: true,
68+
strictNullChecks: true,
6869
};
6970

7071
// optionally pass a base path
@@ -95,7 +96,7 @@ generator.getSchemaForSymbol("AnotherType");
9596
// In larger projects type names may not be unique,
9697
// while unique names may be enabled.
9798
const settings: TJS.PartialArgs = {
98-
uniqueNames: true,
99+
uniqueNames: true,
99100
};
100101

101102
const generator = TJS.buildGenerator(program, settings);
@@ -114,10 +115,10 @@ const fullSymbolList = generator.getSymbols();
114115

115116
```ts
116117
type SymbolRef = {
117-
name: string;
118-
typeName: string;
119-
fullyQualifiedName: string;
120-
symbol: ts.Symbol;
118+
name: string;
119+
typeName: string;
120+
fullyQualifiedName: string;
121+
symbol: ts.Symbol;
121122
};
122123
```
123124

@@ -131,34 +132,34 @@ For example
131132

132133
```ts
133134
export interface Shape {
134-
/**
135-
* The size of the shape.
136-
*
137-
* @minimum 0
138-
* @TJS-type integer
139-
*/
140-
size: number;
135+
/**
136+
* The size of the shape.
137+
*
138+
* @minimum 0
139+
* @TJS-type integer
140+
*/
141+
size: number;
141142
}
142143
```
143144

144145
will be translated to
145146

146147
```json
147148
{
148-
"$ref": "#/definitions/Shape",
149-
"$schema": "http://json-schema.org/draft-07/schema#",
150-
"definitions": {
151-
"Shape": {
152-
"properties": {
153-
"size": {
154-
"description": "The size of the shape.",
155-
"minimum": 0,
156-
"type": "integer"
149+
"$ref": "#/definitions/Shape",
150+
"$schema": "http://json-schema.org/draft-07/schema#",
151+
"definitions": {
152+
"Shape": {
153+
"properties": {
154+
"size": {
155+
"description": "The size of the shape.",
156+
"minimum": 0,
157+
"type": "integer"
158+
}
159+
},
160+
"type": "object"
157161
}
158-
},
159-
"type": "object"
160162
}
161-
}
162163
}
163164
```
164165

@@ -172,52 +173,52 @@ Example:
172173

173174
```ts
174175
export interface ShapesData {
175-
/**
176-
* Specify individual fields in items.
177-
*
178-
* @items.type integer
179-
* @items.minimum 0
180-
*/
181-
sizes: number[];
182-
183-
/**
184-
* Or specify a JSON spec:
185-
*
186-
* @items {"type":"string","format":"email"}
187-
*/
188-
emails: string[];
176+
/**
177+
* Specify individual fields in items.
178+
*
179+
* @items.type integer
180+
* @items.minimum 0
181+
*/
182+
sizes: number[];
183+
184+
/**
185+
* Or specify a JSON spec:
186+
*
187+
* @items {"type":"string","format":"email"}
188+
*/
189+
emails: string[];
189190
}
190191
```
191192

192193
Translation:
193194

194195
```json
195196
{
196-
"$ref": "#/definitions/ShapesData",
197-
"$schema": "http://json-schema.org/draft-07/schema#",
198-
"definitions": {
199-
"Shape": {
200-
"properties": {
201-
"sizes": {
202-
"description": "Specify individual fields in items.",
203-
"items": {
204-
"minimum": 0,
205-
"type": "integer"
206-
},
207-
"type": "array"
208-
},
209-
"emails": {
210-
"description": "Or specify a JSON spec:",
211-
"items": {
212-
"format": "email",
213-
"type": "string"
214-
},
215-
"type": "array"
197+
"$ref": "#/definitions/ShapesData",
198+
"$schema": "http://json-schema.org/draft-07/schema#",
199+
"definitions": {
200+
"Shape": {
201+
"properties": {
202+
"sizes": {
203+
"description": "Specify individual fields in items.",
204+
"items": {
205+
"minimum": 0,
206+
"type": "integer"
207+
},
208+
"type": "array"
209+
},
210+
"emails": {
211+
"description": "Or specify a JSON spec:",
212+
"items": {
213+
"format": "email",
214+
"type": "string"
215+
},
216+
"type": "array"
217+
}
218+
},
219+
"type": "object"
216220
}
217-
},
218-
"type": "object"
219221
}
220-
}
221222
}
222223
```
223224

@@ -232,12 +233,80 @@ Example:
232233
```typescript
233234
type integer = number;
234235
interface MyObject {
235-
n: integer;
236+
n: integer;
236237
}
237238
```
238239

239240
Note: this feature doesn't work for generic types & array types, it mainly works in very simple cases.
240241

242+
### `require` a variable from a file
243+
244+
(for requiring typescript files is needed to set argument `tsNodeRegister` to true)
245+
246+
When you want to import for example an object or an array into your property defined in annotation, you can use `require`.
247+
248+
Example:
249+
250+
```ts
251+
export interface InnerData {
252+
age: number;
253+
name: string;
254+
free: boolean;
255+
}
256+
257+
export interface UserData {
258+
/**
259+
* Specify required object
260+
*
261+
* @examples require("./example.ts").example
262+
*/
263+
data: InnerData;
264+
}
265+
```
266+
267+
file `example.ts`
268+
269+
```ts
270+
export const example: InnerData[] = [{
271+
age: 30,
272+
name: "Ben",
273+
free: false
274+
}]
275+
```
276+
277+
Translation:
278+
279+
```json
280+
{
281+
"$schema": "http://json-schema.org/draft-07/schema#",
282+
"properties": {
283+
"data": {
284+
"description": "Specify required object",
285+
"examples": [
286+
{
287+
"age": 30,
288+
"name": "Ben",
289+
"free": false
290+
}
291+
],
292+
"type": "object",
293+
"properties": {
294+
"age": { "type": "number" },
295+
"name": { "type": "string" },
296+
"free": { "type": "boolean" }
297+
},
298+
"required": ["age", "free", "name"]
299+
}
300+
},
301+
"required": ["data"],
302+
"type": "object"
303+
}
304+
```
305+
306+
Also you can use `require(".").example`, which will try to find exported variable with name 'example' in current file. Or you can use `require("./someFile.ts")`, which will try to use default exported variable from 'someFile.ts'.
307+
308+
Note: For `examples` a required variable must be an array.
309+
241310
## Background
242311

243312
Inspired and builds upon [Typson](https://github.com/lbovet/typson/), but typescript-json-schema is compatible with more recent Typescript versions. Also, since it uses the Typescript compiler internally, more advanced scenarios are possible. If you are looking for a library that uses the AST instead of the type hierarchy and therefore better support for type aliases, have a look at [vega/ts-json-schema-generator](https://github.com/vega/ts-json-schema-generator).

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"@types/json-schema": "^7.0.6",
4949
"glob": "^7.1.6",
5050
"json-stable-stringify": "^1.0.1",
51+
"ts-node": "^9.1.1",
5152
"typescript": "^4.1.3",
5253
"yargs": "^16.2.0"
5354
},
@@ -62,7 +63,6 @@
6263
"mocha": "^8.2.1",
6364
"prettier": "^2.2.1",
6465
"source-map-support": "^0.5.19",
65-
"ts-node": "^9.1.1",
6666
"tslint": "^6.1.3"
6767
},
6868
"scripts": {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { MyDefaultObject, MySubObject2 } from "./main";
2+
3+
export const mySubObject2Example: MySubObject2[] = [{
4+
bool: true,
5+
string: "string",
6+
object: { prop: 1 }
7+
}];
8+
9+
const myDefaultExample: MyDefaultObject[] = [{
10+
age: 30,
11+
name: "me",
12+
free: true
13+
}]
14+
15+
export default myDefaultExample;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
interface MySubObject {
2+
bool: boolean;
3+
string: string;
4+
object: object | null;
5+
/**
6+
* @examples require('./examples.ts').mySubObject2Example
7+
*/
8+
subObject?: MySubObject2;
9+
}
10+
11+
export interface MySubObject2 {
12+
bool: boolean;
13+
string: string;
14+
object: object;
15+
}
16+
17+
export interface MyDefaultObject {
18+
age: number;
19+
name: string;
20+
free?: boolean;
21+
}
22+
23+
export interface MyObject {
24+
/**
25+
* @examples require(".").innerExample
26+
*/
27+
filled: MySubObject;
28+
/**
29+
* @examples require('./examples.ts')
30+
*/
31+
defaultObject: MyDefaultObject;
32+
}
33+
34+
export const innerExample: MySubObject[] = [
35+
{
36+
bool: true,
37+
string: "string",
38+
object: {}
39+
},
40+
];

0 commit comments

Comments
 (0)