yousefed / typescript-json-schema Goto Github PK
View Code? Open in Web Editor NEWGenerate json-schema from your Typescript sources
License: BSD 3-Clause "New" or "Revised" License
Generate json-schema from your Typescript sources
License: BSD 3-Clause "New" or "Revised" License
typson seems to use $ref
by default to refer to other types.
typescript-json-schema defaults to defining one big json-schema type with the dependencies defined inline.
Does tjs (typescript-json-schema; too long to type) support this style or is it planned? I was expecting it to output something very similar to typson by default?
Tried to run the command in a subdirectory because I have multiple interfaces with the same name in different directories. I followed the instructions in the README and formatted the command thusly:
typescript-json-schema src/mappings/draft-3/*.ts Workflow
However, I get this error.
throw "type " + symbolName + " not found";
^
type src/mappings/draft-3/ArraySchema.ts not found
After some digging around in the code, I realized that the glob is expanded and supplied to the args, so the first x arguments of the command line are actually all the files that match the glob. This is actually expected glob behavior in bash. The specified type is all the way at the end of the args array, and not the second argument as expected.
My question: was this not the intended usage of a specific path or should the documentation be updated?
Thanks! Great work, by the way. ๐
interface MyObject {
prop: number;
}
type MyAlias = MyObject;
ts-node typescript-json-schema.ts --topRef true --aliasRefs true test/programs/type-aliases-alias-ref-topref/main.ts MyAlias
Expect
{
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
"MyObject": {
"type": "object",
"properties": {
"prop": {
"type": "number"
}
},
"required": [
"prop"
]
},
"MyAlias": {
"$ref": "#/definitions/MyObject"
}
},
"$ref": "#/definitions/MyAlias"
}
But get
{
"$ref": "#/definitions/MyObject",
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
"MyObject": {
"properties": {
"prop": {
"type": "number"
}
},
"type": "object"
}
}
}
When a project contains .d.ts typings, schema generation fails with the error:
/private/tmp/ts/typescript-json-schema/node_modules/typescript/lib/typescript.js:39567
throw e;
^
TypeError: Cannot read property 'replace' of undefined
at Object.normalizeSlashes (/private/tmp/ts/typescript-json-schema/node_modules/typescript/lib/typescript.js:1383:20)
at writeReferencePath (/private/tmp/ts/typescript-json-schema/node_modules/typescript/lib/typescript.js:31876:90)
at /private/tmp/ts/typescript-json-schema/node_modules/typescript/lib/typescript.js:30442:29
at Object.forEach (/private/tmp/ts/typescript-json-schema/node_modules/typescript/lib/typescript.js:938:30)
at /private/tmp/ts/typescript-json-schema/node_modules/typescript/lib/typescript.js:30434:20
at Object.forEach (/private/tmp/ts/typescript-json-schema/node_modules/typescript/lib/typescript.js:938:30)
at emitDeclarations (/private/tmp/ts/typescript-json-schema/node_modules/typescript/lib/typescript.js:30427:12)
at getDeclarationDiagnosticsFromFile (/private/tmp/ts/typescript-json-schema/node_modules/typescript/lib/typescript.js:30393:13)
at onSingleFileEmit (/private/tmp/ts/typescript-json-schema/node_modules/typescript/lib/typescript.js:6380:13)
at Object.forEachExpectedEmitFile (/private/tmp/ts/typescript-json-schema/node_modules/typescript/lib/typescript.js:6369:21)
The issue seems to be the call to getDeclarationDiagnostics
is failing with the error. I don't have enough insight into the typescript compiler, but it looks like a path is not being provided somewhere. The only workaround I can find is to revert the typescript dependency from 1.8.0 to 1.7.5, but someone who knows the typescript transpiler better might have more insight in how to work around it.
Change interface
to export interface
in test/programs/interface-single/main.ts
and you get the error:
09:10 typescript-json-schema$ ./bin/typescript-json-schema test/programs/interface-single/main.ts MyObject
/opt/src/typescript-json-schema/typescript-json-schema.js:314
throw "type {clazzName} not found";
^
type {clazzName} not found
Export interfaces were working with 0.0.6.
Hey guys,
I'm working with a custom version of the typescript compiler and was hoping to generate schema for certain types - but not all. I already have access to the ts.Type
I want a schema for and I used JsonSchemaGenerator.getSchemaForSymbols
to get it but I had to modify your code to export the JsonSchemaGenerator
class.
Do you see something inherently wrong with this approach ? If not, would you welcome a pull request changing the TJS
module to export the JsonSchemaGenerator
class so it can be accessed from the outside ?
Hi. Thank you for the great tool!
Could you please check this example?
Here's my TS file
namespace Test.Common {
export interface EmptyObject {}
export type DateTime = string;
}
namespace Test.Data {
import EmptyObject = Test.Common.EmptyObject;
import DateTime = Test.Common.DateTime;
export interface Result {
emptyObject: EmptyObject;
dateTime: DateTime;
}
}
command line:
./node_modules/.bin/typescript-json-schema test.ts Test.Data.Result --refs --aliasRefs
and the result:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
"Test.Common.EmptyObject": {
"properties": {
},
"type": "object"
},
"string": {
"type": "string"
}
},
"properties": {
"dateTime": {
"$ref": "#/definitions/string"
},
"emptyObject": {
"$ref": "#/definitions/Test.Common.EmptyObject"
}
},
"type": "object"
}
As you may see, the Test.Common.DateTime
name is replaced by string
in the definition name, but the Test.Common.EmptyObject
import isn't.
Is it possible to preserve names for type aliases? I'd like to have something like this:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
"Test.Common.EmptyObject": {
"properties": {
},
"type": "object"
},
"Test.Common.DateTime": {
"type": "string"
}
},
"properties": {
"dateTime": {
"$ref": "#/definitions/Test.Common.DateTime"
},
"emptyObject": {
"$ref": "#/definitions/Test.Common.EmptyObject"
}
},
"type": "object"
}
some functions are not neatly organized. Reconsider:
getTypeDefinition
getDefinitionForType
getClassDefinition
Some logic here should be merged
When generating schema for interface with property of type Date
as the output we get additional Date
which is typescript Date
type interface:
{
"Date": {
"type": "object",
"properties": {
"toString": {
"$ref": "#/definitions/() => string",
"description": "Returns a string representation of a date. The format of the string depends on the locale."
},
"toDateString": {
"$ref": "#/definitions/() => string",
"description": "Returns a date as a string value."
},
"toTimeString": {
"$ref": "#/definitions/() => string",
"description": "Returns a time as a string value."
},
"toLocaleString": {
"$ref": "#/definitions/{ (): string; (locales?: string[], options?: DateTimeFormatOptions): string; (locale?: string, op...",
"description": "Returns a value as a string value appropriate to the host environment's current locale.\n\nConverts a date and time to a string by using the current or specified locale.\n\nConverts a date and time to a string by using the current or specified locale."
},
"toLocaleDateString": {
"$ref": "#/definitions/{ (): string; (locales?: string[], options?: DateTimeFormatOptions): string; (locale?: string, op...",
"description": "Returns a date as a string value appropriate to the host environment's current locale.\n\nConverts a date to a string by using the current or specified locale.\n\nConverts a date to a string by using the current or specified locale."
},
"toLocaleTimeString": {
"$ref": "#/definitions/{ (): string; (locale?: string[], options?: DateTimeFormatOptions): string; (locale?: string, opt...",
"description": "Returns a time as a string value appropriate to the host environment's current locale.\n\nConverts a time to a string by using the current or specified locale.\n\nConverts a time to a string by using the current or specified locale."
},
"valueOf": {
"$ref": "#/definitions/() => number",
"description": "Returns the stored time value in milliseconds since midnight, January 1, 1970 UTC."
},
"getTime": {
"$ref": "#/definitions/() => number",
"description": "Gets the time value in milliseconds."
},
"getFullYear": {
"$ref": "#/definitions/() => number",
"description": "Gets the year, using local time."
},
"getUTCFullYear": {
"$ref": "#/definitions/() => number",
"description": "Gets the year using Universal Coordinated Time (UTC)."
},
"getMonth": {
"$ref": "#/definitions/() => number",
"description": "Gets the month, using local time."
},
"getUTCMonth": {
"$ref": "#/definitions/() => number",
"description": "Gets the month of a Date object using Universal Coordinated Time (UTC)."
},
"getDate": {
"$ref": "#/definitions/() => number",
"description": "Gets the day-of-the-month, using local time."
},
"getUTCDate": {
"$ref": "#/definitions/() => number",
"description": "Gets the day-of-the-month, using Universal Coordinated Time (UTC)."
},
"getDay": {
"$ref": "#/definitions/() => number",
"description": "Gets the day of the week, using local time."
},
"getUTCDay": {
"$ref": "#/definitions/() => number",
"description": "Gets the day of the week using Universal Coordinated Time (UTC)."
},
"getHours": {
"$ref": "#/definitions/() => number",
"description": "Gets the hours in a date, using local time."
},
"getUTCHours": {
"$ref": "#/definitions/() => number",
"description": "Gets the hours value in a Date object using Universal Coordinated Time (UTC)."
},
"getMinutes": {
"$ref": "#/definitions/() => number",
"description": "Gets the minutes of a Date object, using local time."
},
"getUTCMinutes": {
"$ref": "#/definitions/() => number",
"description": "Gets the minutes of a Date object using Universal Coordinated Time (UTC)."
},
"getSeconds": {
"$ref": "#/definitions/() => number",
"description": "Gets the seconds of a Date object, using local time."
},
"getUTCSeconds": {
"$ref": "#/definitions/() => number",
"description": "Gets the seconds of a Date object using Universal Coordinated Time (UTC)."
},
"getMilliseconds": {
"$ref": "#/definitions/() => number",
"description": "Gets the milliseconds of a Date, using local time."
},
"getUTCMilliseconds": {
"$ref": "#/definitions/() => number",
"description": "Gets the milliseconds of a Date object using Universal Coordinated Time (UTC)."
},
"getTimezoneOffset": {
"$ref": "#/definitions/() => number",
"description": "Gets the difference in minutes between the time on the local computer and Universal Coordinated Time (UTC)."
},
"setTime": {
"$ref": "#/definitions/(time: number) => number",
"description": "Sets the date and time value in the Date object."
},
"setMilliseconds": {
"$ref": "#/definitions/(ms: number) => number",
"description": "Sets the milliseconds value in the Date object using local time."
},
"setUTCMilliseconds": {
"$ref": "#/definitions/(ms: number) => number",
"description": "Sets the milliseconds value in the Date object using Universal Coordinated Time (UTC)."
},
"setSeconds": {
"$ref": "#/definitions/(sec: number, ms?: number) => number",
"description": "Sets the seconds value in the Date object using local time."
},
"setUTCSeconds": {
"$ref": "#/definitions/(sec: number, ms?: number) => number",
"description": "Sets the seconds value in the Date object using Universal Coordinated Time (UTC)."
},
"setMinutes": {
"$ref": "#/definitions/(min: number, sec?: number, ms?: number) => number",
"description": "Sets the minutes value in the Date object using local time."
},
"setUTCMinutes": {
"$ref": "#/definitions/(min: number, sec?: number, ms?: number) => number",
"description": "Sets the minutes value in the Date object using Universal Coordinated Time (UTC)."
},
"setHours": {
"$ref": "#/definitions/(hours: number, min?: number, sec?: number, ms?: number) => number",
"description": "Sets the hour value in the Date object using local time."
},
"setUTCHours": {
"$ref": "#/definitions/(hours: number, min?: number, sec?: number, ms?: number) => number",
"description": "Sets the hours value in the Date object using Universal Coordinated Time (UTC)."
},
"setDate": {
"$ref": "#/definitions/(date: number) => number",
"description": "Sets the numeric day-of-the-month value of the Date object using local time."
},
"setUTCDate": {
"$ref": "#/definitions/(date: number) => number",
"description": "Sets the numeric day of the month in the Date object using Universal Coordinated Time (UTC)."
},
"setMonth": {
"$ref": "#/definitions/(month: number, date?: number) => number",
"description": "Sets the month value in the Date object using local time."
},
"setUTCMonth": {
"$ref": "#/definitions/(month: number, date?: number) => number",
"description": "Sets the month value in the Date object using Universal Coordinated Time (UTC)."
},
"setFullYear": {
"$ref": "#/definitions/(year: number, month?: number, date?: number) => number",
"description": "Sets the year of the Date object using local time."
},
"setUTCFullYear": {
"$ref": "#/definitions/(year: number, month?: number, date?: number) => number",
"description": "Sets the year value in the Date object using Universal Coordinated Time (UTC)."
},
"toUTCString": {
"$ref": "#/definitions/() => string",
"description": "Returns a date converted to a string using Universal Coordinated Time (UTC)."
},
"toISOString": {
"$ref": "#/definitions/() => string",
"description": "Returns a date as a string value in ISO format."
},
"toJSON": {
"$ref": "#/definitions/(key?: any) => string",
"description": "Used by the JSON.stringify method to enable the transformation of an object's data for JavaScript Object Notation (JSON) serialization."
}
}
},
"() => string": {
"type": "object",
"properties": {}
},
"{ (): string; (locales?: string[], options?: DateTimeFormatOptions): string; (locale?: string, op...": {
"type": "object",
"properties": {}
},
"{ (): string; (locale?: string[], options?: DateTimeFormatOptions): string; (locale?: string, opt...": {
"type": "object",
"properties": {}
},
"() => number": {
"type": "object",
"properties": {}
},
"(time: number) => number": {
"type": "object",
"properties": {}
},
"(ms: number) => number": {
"type": "object",
"properties": {}
},
"(sec: number, ms?: number) => number": {
"type": "object",
"properties": {}
},
"(min: number, sec?: number, ms?: number) => number": {
"type": "object",
"properties": {}
},
"(hours: number, min?: number, sec?: number, ms?: number) => number": {
"type": "object",
"properties": {}
},
"(date: number) => number": {
"type": "object",
"properties": {}
},
"(month: number, date?: number) => number": {
"type": "object",
"properties": {}
},
"(year: number, month?: number, date?: number) => number": {
"type": "object",
"properties": {}
},
"(key?: any) => string": {
"type": "object",
"properties": {}
}
}
but IMHO it should fall back to
{
"type": "string",
"format": "date-time",
}
/usr/bin/typescript-json-schema: line 1: ๏ปฟ#!/usr/bin/env: No such file or directory
/usr/bin/typescript-json-schema: line 2: syntax error near unexpected token `$'{\r''
/usr/bin/typescript-json-schema: line 2: `if (process.argv[2] !== undefined && process.a'gv[3] !== undefined) {
type MyType1 = string | null;
type MyType2 = string | number | null;
type MyType3 = string | number[] | null;
type MyType4 = number[] | null;
type Ref = { foo: number };
type MyType5 = Ref | null;
interface MyObject
{
var1 : MyType1;
var2 : MyType2;
var3 : MyType3;
var4 : MyType4;
var5 : MyType5;
}
I'd expect this to behave the same as @nullable
but somehow adding | null
has no effect. Can somebody explain?
I am trying to do something like:
/**
* How to force a Widget to be encoded as number?
*
* @type number
*/
export interface Widget {}
export interface House {
name: string;
mainWidget: Widget;
otherWidgets: Widget[];
}
So that the mainWidget
field is encoded as a regular "number", and also otherWidgets
will be an array of numbers.
In other words I would like to get the following schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"properties": {
"name": {
"type": "string"
},
"mainWidget": {
"type": "number"
},
"otherWidgets": {
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"name",
"mainWidget",
"otherWidgets"
],
"type": "object"
}
thank you
Given the file ./dimension.ts
/**
Some dimension
@additionalProperties false
*/
interface Dimension {
/** Width in cm */
width: number;
/** Height in cm */
height: number;
/** Length in cm */
length: number;
}
we observe this output:
$ typescript-json-schema dimension.ts Dimension
{
"type": "object",
"properties": {
"width": {
"type": "number",
"description": "Width in cm"
},
"height": {
"type": "number",
"description": "Height in cm"
},
"length": {
"type": "number",
"description": "Length in cm"
}
},
"$schema": "http://json-schema.org/draft-04/schema#"
}
Do we expect the top-level type to include a description
(and additionalProperties
) attribute?
typson
output:
$ typson schema ./dimension.ts
{
"Dimension": {
"id": "Dimension",
"type": "object",
"description": "Some dimension",
"additionalProperties": false,
"properties": {
"width": {
"description": "Width in cm",
"type": "number"
},
"height": {
"description": "Height in cm",
"type": "number"
},
"length": {
"description": "Length in cm",
"type": "number"
}
},
"required": [
"width",
"height",
"length"
]
}
}
I usually run the generator using --noExtraProps true
as I don't want the API these schemas are protecting to silently discard unknown data. This works great in general, but fails in one specific cornercase: In one type I need to allow extra fields as part of a general key-value store.
In Typescript, I expressed this as
/**
* A widget **requires** at least a type, all other fields are
* mandated by deriving descriptions.
*/
export interface WidgetDescription {
type : string
[x: string]: any
}
Adding additional fields to this works fine in code:
const foo : WidgetDescription = {
type : "test",
additional : 2
}
But the generated schema does not allow any additional properties:
"WidgetDescription": {
"type": "object",
"properties": {
"type": {
"type": "string"
}
},
"additionalProperties": false
}
I am not quite sure how to correctly tackle this case in JSON schema. But from my understanding the presence of a property-specification like [x: string]: any
could translate to additionalProperties: true
.
With references we should be able to support interfaces that reference themselves, The easiest fix would be to only recurse if the type does not yet exist in the map of definitions.
Any objections against BSD?
First, glad to see someone pick up the torch from typson!
The commandline executable typescript-json-schema
doesn't work in Linux Mint 17.
I think this is due to the BOM at the beginning of the file. Recommend removing it. Maybe it's an artifact left by Visual Studio or something?
$ typescript-json-schema
/usr/bin/typescript-json-schema: line 1: ๏ปฟ#!/usr/bin/env: No such file or directory
/usr/bin/typescript-json-schema: line 2: syntax error near unexpected token `$'{\r''
'usr/bin/typescript-json-schema: line 2: `if (process.argv[2] !== undefined && process.argv[3] !== undefined) {
I can submit a pr if you'd like.
I would like to be able to override input and output when generating schemas. I am not sure how it should look like in details (or how to implement such a feature):
Overriding input:
I have some complex typescript definitions, where I would like to dynamically replace one typescript type definition with another when generating schemas (for instance dynamically replacing a specific typescript type "xxx" with type "any") in the input for the generated schema.
Overriding output
I have some typescript definitions where a corresponding schema file already exist that is official or better at representing json schema definitions for a property in a typescript interface. For instance, If I use an unofficial typescript type to represent a json schema like this one, I would like property type references for this JsonSchema type to be converted into one of the official json schema meta schema files around rather than typescript-json-schema producing it's own unofficial version (this is likely not be 100% correct anyway.
For example:
interface MyArray {
[index: number]: string | number;
}
and
type MyArray = [string, number];
type MyString = string;
I know you would like to step down as the maintainer of this package, but would it be possible to push the current state to npm?
Although @MarcusRiemer's fix for comments, shown in the test for comments-override, is great for extending interfaces, it fails to account for types. Here is an example:
/**
* @type integer
* @minimum 1
*/
export type PositiveInteger = number;
export interface MyObject {
user_ids: PositiveInteger[];
user_id: PositiveInteger;
}
and the expected schema is:
{
"type": "object",
"properties": {
"user_ids": {
"type": "array",
"items": {
"$ref": "#/definitions/PositiveInteger"
}
},
"user_id": {
"$ref": "#/definitions/PositiveInteger"
}
},
"required": [
"company_ids",
"user_id"
],
"definitions": {
"PositiveInteger": {
"type": "integer",
"minimum": 1
}
},
"$schema": "http://json-schema.org/draft-04/schema#"
}
Instead, the result looks like:
{
"type": "object",
"properties": {
"user_ids": {
"type": "array",
"items": {
"type": "number"
}
},
"user_id": {
"minimum": 1,
"type": "integer"
}
},
"required": [
"user_ids",
"user_id"
],
"$schema": "http://json-schema.org/draft-04/schema#"
}
If I have a minute, I'll look into this, but a little busy. Probably isn't too complicated
Very, very nice project! The generated code is however wrong for typescripts buildin ReadonlyArray type. If I generate a schema for BuggyType below it will be very strange. It looks like it does not understand that ReadonlyArray is just like an array except that typescript wont allow it to change.
Nb. tested with typescript 2.1.5 and typescript-json-schema 0.7.0
Test input:
export interface BuggyType {
readonly single: string;
readonly multiple: ReadonlyArray<string>;
}
Wrong output:
{
"type": "object",
"properties": {
"single": {
"type": "string"
},
"multiple": {
"$ref": "#/definitions/ReadonlyArray<string>"
}
},
"additionalProperties": false,
"required": [
"single",
"multiple"
],
"definitions": {
"ReadonlyArray<string>": {
"type": "object",
"properties": {
"find": {
"description": "Returns the value of the first element in the array where predicate is true, and undefined\notherwise.",
"type": "object",
"properties": {},
"additionalProperties": false
},
"findIndex": {
"description": "Returns the index of the first element in the array where predicate is true, and -1\notherwise.",
"type": "object",
"properties": {},
"additionalProperties": false
},
"length": {
"description": "Gets the length of the array. This is a number one higher than the highest element defined in an array.",
"type": "number"
},
"toString": {
"description": "Returns a string representation of an array.",
"type": "object",
"properties": {},
"additionalProperties": false
},
"toLocaleString": {
"type": "object",
"properties": {},
"additionalProperties": false
},
"concat": {
"description": "Combines two or more arrays.\nCombines two or more arrays.\nCombines two or more arrays.",
"type": "object",
"properties": {},
"additionalProperties": false
},
"join": {
"description": "Adds all the elements of an array separated by the specified separator string.",
"type": "object",
"properties": {},
"additionalProperties": false
},
"slice": {
"description": "Returns a section of an array.",
"type": "object",
"properties": {},
"additionalProperties": false
},
"indexOf": {
"description": "Returns the index of the first occurrence of a value in an array.",
"type": "object",
"properties": {},
"additionalProperties": false
},
"lastIndexOf": {
"description": "Returns the index of the last occurrence of a specified value in an array.",
"type": "object",
"properties": {},
"additionalProperties": false
},
"every": {
"description": "Determines whether all the members of an array satisfy the specified test.",
"type": "object",
"properties": {},
"additionalProperties": false
},
"some": {
"description": "Determines whether the specified callback function returns true for any element of an array.",
"type": "object",
"properties": {},
"additionalProperties": false
},
"forEach": {
"description": "Performs the specified action for each element in an array.",
"type": "object",
"properties": {},
"additionalProperties": false
},
"map": {
"description": "Calls a defined callback function on each element of an array, and returns an array that contains the results.",
"type": "object",
"properties": {},
"additionalProperties": false
},
"filter": {
"description": "Returns the elements of an array that meet the condition specified in a callback function.\nReturns the elements of an array that meet the condition specified in a callback function.",
"type": "object",
"properties": {},
"additionalProperties": false
},
"reduce": {
"description": "Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.\nCalls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.",
"type": "object",
"properties": {},
"additionalProperties": false
},
"reduceRight": {
"description": "Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.\nCalls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.",
"type": "object",
"properties": {},
"additionalProperties": false
}
},
"additionalProperties": false,
"required": [
"find",
"findIndex",
"length",
"toString",
"toLocaleString",
"concat",
"join",
"slice",
"indexOf",
"lastIndexOf",
"every",
"some",
"forEach",
"map",
"filter",
"reduce",
"reduceRight"
]
}
},
"$schema": "http://json-schema.org/draft-04/schema#"
}
interface MyType {
foo: number;
};
interface MyObject {
/**
* @nullable
*/
var1: MyType;
var2: MyType;
}
Output
{
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
"MyType": {
"anyOf": [
{
"properties": {
"foo": {
"type": "number"
}
},
"required": [
"foo"
],
"type": "object"
},
{
"type": "null"
}
]
}
},
"properties": {
"var1": {
"$ref": "#/definitions/MyType"
},
"var2": {
"$ref": "#/definitions/MyType"
}
},
"required": [
"var1",
"var2"
],
"type": "object"
}
In this case the MyType
becomes nullable and not just var1
. This causes issues for example in vega/vega-lite#1706
In this case
export interface Person {
/** @nullable */
name?: string;
}
allowed types art string
and null
.
There
export interface Person {
name?: null;
}
allowed type is null.
But there
export interface Person {
name?: string | null;
}
only string will be allowed.
Script should not skip null type if any other type is provided.
Temporary workaround - provide type information and @nullable
notation.
export interface Person {
/** @nullable */
name?: string | null;
}
If I add intersection type (&
) to my types, I get Unsupported type
error.
Is it possible to support this? Thanks
Typescript 2.0 has been recently released, would it make sense to upgrade the library? I tried 2.0 locally, so far so good.
This pull request allowed passing in arbitrary keywords that would be accepted and added to the generated schema. This functionality appears to be missing from master now. Am I missing a new way of passing in these kinds of fields (e.g. faker)? Unless I am mistaken, they are now picked up as 'otherAnnotation' and left out of the process
It would be nice if the generator was external node module, usable as in javascript code.
I'm thinking about generating my schemes dynamically from the ts on build time as webpack loader or so.
And also will be usable as gulp task
The readme only mentions that TJS was inspired by and built upon typson.
Already known issue
Type comments are not used, with union types
#64 (comment)
Type comments are not used, when type is imported from another file
String type, null type and pattern are applied.
/**
* @pattern \d{4}-\d{2}-\d{2}T\d{2}\:\d{2}\:\d{2}\.\d{3}[+-]\d{4}
*/
export type StringDateNullable = string | null; // "1992-04-10T20:00:00.000+0000"
export interface Person {
birthDate: StringDateNullable;
}
Only string and null types are applyed, not pattern.
import {
StringDateNullable
} from './common.types';
export interface Person {
birthDate: StringDateNullable;
}
Full property info
"birthDate": {
"pattern": "\\d{4}-\\d{2}-\\d{2}T\\d{2}\\:\\d{2}\\:\\d{2}\\.\\d{3}[+-]\\d{4}",
"type": [
"null",
"string"
]
},
// common.types.ts
/**
* @pattern \d{4}-\d{2}-\d{2}T\d{2}\:\d{2}\:\d{2}\.\d{3}[+-]\d{4}
*/
export type StringDate = string; // "1992-04-10T20:00:00.000+0000"
// person.types.ts
import {
StringDate
} from './common.types';
export interface Person {
birthDate: StringDate | null;
}
Expected result
{
"$schema": "http://json-schema.org/draft-04/schema#",
"properties": {
"birthDate": {
"anyOf": [
{
"pattern": "\\d{4}-\\d{2}-\\d{2}T\\d{2}\\:\\d{2}\\:\\d{2}\\.\\d{3}[+-]\\d{4}",
"type": "string"
},
{
"type": "null"
}
]
}
},
"type": "object"
}
Current result
{
"$schema": "http://json-schema.org/draft-04/schema#",
"properties": {
"birthDate": {
"type": [
"null",
"string"
]
}
},
"type": "object"
}
I think it should be just one line-break
Any idea why I'm getting this:
ฮป typescript-json-schema myTSFile.ts MyMainType
npm/node_modules/typescript-json-schema/typescript-json-schema.js:120
else if (propertyType.getSymbol().getName() == "Array") {
^
TypeError: Cannot read property 'getName' of undefined
at JsonSchemaGenerator.getDefinitionForRootType (npm/node_modules/typescript-json-schema/typescript-json-schema.js:120:54)
at JsonSchemaGenerator.getTypeDefinition (npm/node_modules/typescript-json-schema/typescript-json-schema.js:277:29)
at npm/node_modules/typescript-json-schema/typescript-json-schema.js:90:34
at Array.map (native)
at JsonSchemaGenerator.getDefinitionForRootType (npm/node_modules/typescript-json-schema/typescript-json-schema.js:89:45)
at JsonSchemaGenerator.getTypeDefinition (npm/node_modules/typescript-json-schema/typescript-json-schema.js:277:29)
at JsonSchemaGenerator.getDefinitionForProperty (npm/node_modules/typescript-json-schema/typescript-json-schema.js:135:35)
at npm/node_modules/typescript-json-schema/typescript-json-schema.js:237:41
at Array.reduce (native)
at JsonSchemaGenerator.getClassDefinition (npm/node_modules/typescript-json-schema/typescript-json-schema.js:235:49)
export interface IResultResponse {
success:boolean;
message?:string;
data?:any;
}
turns into
IResultResponse:
type: object
properties:
success:
type: boolean
message:
type: string
data:
additionalProperties: false
required:
- success
It would be great to have support for union types and generate oneOf
.
interface Test {
level: number | string;
}
See similar typson issue lbovet/typson#36
For example, start off with tests from typson: https://github.com/lbovet/typson/tree/master/test
Currently union type always output "oneOf", but sometimes a JSON spec might satisfy multiple types of the TS interfaces. Support using "anyOf" instead (and possibly by default would be useful).
I remember @domoritz implemented this with oneOf
, not sure how hard it is to use anyOf
.
interface Test {
/**
* Classification level from 1 to 5 (highest)
* @type integer
* @default 12
*/
level: number;
}
generates
{
"type": "object",
"title": "Category",
"defaultProperties": [],
"properties": {
"level": {
"type": "integer\n\n",
"title": "level",
"description": "Classification level from 1 to 5 (highest)",
"default": 12
}
}
}
Im wondering if there is any way to annotate the Typescript file so it generates something like that:
"type": ["string", "null"]. Can i somehow define this "nullable"-Property? Thanks a lot!
Hi,
I'm new to typescript and json-schema and I would like to know which one is the more complete. I want to use the most complete one as base in order to generate the other one. At first glance I would think json-schema is more complete and polyvalent than typescript.
Could someone confirm this?
An idea: it would be great to be able to be bidirectionnal.
Thanks for your response and for your work on this project.
I had an idea about instead of generating the schemas with the CLI, let the application parse his own interfaces and load the schema as objects at runtime, so they can be passed to https://www.npmjs.com/package/jsonschema. That would basically allow to do assertions at runtime against TypeScript interfaces instead of compile time. Is this possible?
What do you think about types compatible with Flow?
With typson, properties of an interface are serialized as 'required' unless they are marked optional.
Given an interface like:
interface Foo {
bar? : number
baz: string
}
In the resulting json-schema, I'd expect baz to be marked required and bar not. This is based on my previous experiments with typson. That said, toggling this behavior via a config setting or command line parameter would be nice.
It seems like this implementation is significantly different from typson and I maybe shouldn't assume it's a superset of typson?
This seems to fail when using a union of string literal types.
interface Test {
first: 'a'; // works
second: 'a' | 'b'; // fails
}
The error is:
/usr/lib/node_modules/typescript-json-schema/node_modules/typescript/lib/typescript.js:15712
return symbol.parent ? getFullyQualifiedName(symbol.parent) + "." + symbolToString(symbol) : symbolToString(symbol);
^
TypeError: Cannot read property 'parent' of null
at Object.getFullyQualifiedName (/usr/lib/node_modules/typescript-json-schema/node_modules/typescript/lib/typescript.js:15712:26)
at JsonSchemaGenerator.getTypeDefinition (/usr/lib/node_modules/typescript-json-schema/typescript-json-schema.js:315:35)
at JsonSchemaGenerator.getDefinitionForProperty (/usr/lib/node_modules/typescript-json-schema/typescript-json-schema.js:154:35)
at /usr/lib/node_modules/typescript-json-schema/typescript-json-schema.js:258:41
at Array.reduce (native)
at JsonSchemaGenerator.getClassDefinition (/usr/lib/node_modules/typescript-json-schema/typescript-json-schema.js:256:49)
at JsonSchemaGenerator.getTypeDefinition (/usr/lib/node_modules/typescript-json-schema/typescript-json-schema.js:356:26)
at JsonSchemaGenerator.getDefinitionForRootType (/usr/lib/node_modules/typescript-json-schema/typescript-json-schema.js:131:49)
at JsonSchemaGenerator.getTypeDefinition (/usr/lib/node_modules/typescript-json-schema/typescript-json-schema.js:350:26)
at JsonSchemaGenerator.getDefinitionForProperty (/usr/lib/node_modules/typescript-json-schema/typescript-json-schema.js:154:35)
/**
* @type integer
*/
age: number
Does not work since 0.3.5.
I guess that's because typescript (since 2.1.0?) has special treatment for JsDoc (which includes @type)
https://github.com/Microsoft/TypeScript/wiki/JSDoc-support-in-JavaScript
Hi,
I am looking for way to get all interfaces from one file. So far referenced all interfaces in that file in a interface that I exported so get all the interfaces, but that's ugly and error prone..
I also tried to use '*' wildcard when calling the cli but that does not work at all.
Any idea on how to accomplish it in a nice way?
I am not sure exactly what is wrong but if I use typescript-json-schema to output a schema for a (complex) guimodel from the open source json-schema-js-gui-model project(see type definitions below), the resulting schema does not work (unexpected validation errors in multiple validators like for example the online http://www.jsonschemavalidator.net/).
I fail to understand what exactly is wrong with the generated schema (apart from strangely named TypedField which may/may not be correct) ? Can someone see what is wrong from the type, generated schema and sample input (that I expect to be valid) ?
P.S. If it is a simple problem I can help fix it but would likely need some help as I have only made one small contribution to this project and don't fully understand the codebase.
Typescript GuiModel input definition:
export type ControlType =
'group' | 'input' | 'dropdown' | 'yesno';
export type DataType =
'string' | 'number' | 'integer' | 'boolean';
export type StringSubDataType =
'text'
| 'password'
| 'date'
| 'time'
| 'date-time'
| 'uri'
| 'email'
| 'hostname'
| 'ipv4'
| 'ipv6'
| 'regex'
| 'uuid'
| 'json-pointer'
| 'relative-json-pointer'
;
export type IntegerSubType =
'port-number'
| 'miliseconds'
| 'seconds'
| 'minutes'
| 'hours'
| 'days'
;
export type SubDataType = StringSubDataType | IntegerSubType | 'none';
export interface GuiElementBase {
readonly name: string;
readonly controlType: ControlType;
readonly label: string;
readonly tooltip: string;
readonly dataObjectPath: string;
readonly required: boolean;
}
export interface FieldBase extends GuiElementBase {
readonly kind: 'field';
readonly type: DataType;
readonly subType: SubDataType;
};
export interface TypedField<T> extends FieldBase {
readonly defaultValue: T;
readonly values?: ReadonlyArray<T>;
}
export interface Group extends GuiElementBase {
readonly kind: 'group';
readonly elements: ReadonlyArray<GuiElement>;
}
export interface TranslationError {
readonly schemaPath: string;
readonly errorText: string;
};
export interface GuiModel extends Group {
readonly errors: ReadonlyArray<TranslationError>;
}
export type Field = TypedField<string> | TypedField<number> | TypedField<boolean>;
export type GuiElement = Group | Field;
**Generated schema (note strangely named generic definitions TypedField) **
{
"description": "Represents a full gui model. Essentially a group but with an extra errors field.",
"type": "object",
"properties": {
"errors": {
"type": "array",
"items": {
"$ref": "#/definitions/TranslationError"
},
"title": "errors"
},
"kind": {
"type": "string",
"enum": [
"group"
],
"title": "kind"
},
"elements": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/Group"
},
{
"$ref": "#/definitions/TypedField<string>"
},
{
"$ref": "#/definitions/TypedField<number>"
},
{
"$ref": "#/definitions/TypedField<boolean>"
}
]
},
"title": "elements"
},
"name": {
"type": "string",
"title": "name"
},
"controlType": {
"$ref": "#/definitions/ControlType",
"title": "controlType"
},
"label": {
"type": "string",
"title": "label"
},
"tooltip": {
"type": "string",
"title": "tooltip"
},
"dataObjectPath": {
"description": "A string representing a path to the property in json data file conforming to the plugin schema,\nwhere each path component is seperated by a dot. Same as string representation of\nLodash.get method or mariocasciaro's object-path (https://github.com/mariocasciaro/object-path).\nThis string is unique for all elements in a model and may thus be used as a key if needed.",
"type": "string",
"title": "dataObjectPath"
},
"required": {
"type": "boolean",
"title": "required"
}
},
"additionalProperties": false,
"required": [
"errors",
"kind",
"elements",
"name",
"controlType",
"label",
"tooltip",
"dataObjectPath",
"required"
],
"definitions": {
"TranslationError": {
"title": "TranslationError",
"type": "object",
"properties": {
"schemaPath": {
"type": "string",
"title": "schemaPath"
},
"errorText": {
"type": "string",
"title": "errorText"
}
},
"additionalProperties": false,
"required": [
"schemaPath",
"errorText"
]
},
"Group": {
"description": "A containers for other gui elements.",
"title": "Group",
"type": "object",
"properties": {
"kind": {
"type": "string",
"enum": [
"group"
],
"title": "kind"
},
"elements": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/Group"
},
{
"$ref": "#/definitions/TypedField<string>"
},
{
"$ref": "#/definitions/TypedField<number>"
},
{
"$ref": "#/definitions/TypedField<boolean>"
}
]
},
"title": "elements"
},
"name": {
"type": "string",
"title": "name"
},
"controlType": {
"$ref": "#/definitions/ControlType",
"title": "controlType"
},
"label": {
"type": "string",
"title": "label"
},
"tooltip": {
"type": "string",
"title": "tooltip"
},
"dataObjectPath": {
"description": "A string representing a path to the property in json data file conforming to the plugin schema,\nwhere each path component is seperated by a dot. Same as string representation of\nLodash.get method or mariocasciaro's object-path (https://github.com/mariocasciaro/object-path).\nThis string is unique for all elements in a model and may thus be used as a key if needed.",
"type": "string",
"title": "dataObjectPath"
},
"required": {
"type": "boolean",
"title": "required"
}
},
"additionalProperties": false,
"required": [
"kind",
"elements",
"name",
"controlType",
"label",
"tooltip",
"dataObjectPath",
"required"
]
},
"TypedField<string>": {
"title": "TypedField<string>",
"type": "object",
"properties": {
"defaultValue": {
"type": "string",
"title": "defaultValue"
},
"values": {
"type": "array",
"items": {
"type": "string"
},
"title": "values"
},
"kind": {
"type": "string",
"enum": [
"field"
],
"title": "kind"
},
"type": {
"$ref": "#/definitions/DataType",
"title": "type"
},
"subType": {
"$ref": "#/definitions/SubDataType",
"title": "subType"
},
"name": {
"type": "string",
"title": "name"
},
"controlType": {
"$ref": "#/definitions/ControlType",
"title": "controlType"
},
"label": {
"type": "string",
"title": "label"
},
"tooltip": {
"type": "string",
"title": "tooltip"
},
"dataObjectPath": {
"description": "A string representing a path to the property in json data file conforming to the plugin schema,\nwhere each path component is seperated by a dot. Same as string representation of\nLodash.get method or mariocasciaro's object-path (https://github.com/mariocasciaro/object-path).\nThis string is unique for all elements in a model and may thus be used as a key if needed.",
"type": "string",
"title": "dataObjectPath"
},
"required": {
"type": "boolean",
"title": "required"
}
},
"additionalProperties": false,
"required": [
"defaultValue",
"kind",
"type",
"subType",
"name",
"controlType",
"label",
"tooltip",
"dataObjectPath",
"required"
]
},
"DataType": {
"description": "The javascript data types used.",
"title": "DataType",
"enum": [
"boolean",
"integer",
"number",
"string"
],
"type": "string"
},
"SubDataType": {
"title": "SubDataType",
"enum": [
"date",
"date-time",
"days",
"email",
"hostname",
"hours",
"ipv4",
"ipv6",
"json-pointer",
"miliseconds",
"minutes",
"none",
"password",
"port-number",
"regex",
"relative-json-pointer",
"seconds",
"text",
"time",
"uri",
"uuid"
],
"type": "string"
},
"ControlType": {
"description": "The main gui controls that should be used.",
"title": "ControlType",
"enum": [
"dropdown",
"group",
"input",
"yesno"
],
"type": "string"
},
"TypedField<number>": {
"title": "TypedField<number>",
"type": "object",
"properties": {
"defaultValue": {
"type": "number",
"title": "defaultValue"
},
"values": {
"type": "array",
"items": {
"type": "number"
},
"title": "values"
},
"kind": {
"type": "string",
"enum": [
"field"
],
"title": "kind"
},
"type": {
"$ref": "#/definitions/DataType",
"title": "type"
},
"subType": {
"$ref": "#/definitions/SubDataType",
"title": "subType"
},
"name": {
"type": "string",
"title": "name"
},
"controlType": {
"$ref": "#/definitions/ControlType",
"title": "controlType"
},
"label": {
"type": "string",
"title": "label"
},
"tooltip": {
"type": "string",
"title": "tooltip"
},
"dataObjectPath": {
"description": "A string representing a path to the property in json data file conforming to the plugin schema,\nwhere each path component is seperated by a dot. Same as string representation of\nLodash.get method or mariocasciaro's object-path (https://github.com/mariocasciaro/object-path).\nThis string is unique for all elements in a model and may thus be used as a key if needed.",
"type": "string",
"title": "dataObjectPath"
},
"required": {
"type": "boolean",
"title": "required"
}
},
"additionalProperties": false,
"required": [
"defaultValue",
"kind",
"type",
"subType",
"name",
"controlType",
"label",
"tooltip",
"dataObjectPath",
"required"
]
},
"TypedField<boolean>": {
"title": "TypedField<boolean>",
"type": "object",
"properties": {
"defaultValue": {
"type": "boolean",
"title": "defaultValue"
},
"values": {
"type": "array",
"items": {
"type": "boolean"
},
"title": "values"
},
"kind": {
"type": "string",
"enum": [
"field"
],
"title": "kind"
},
"type": {
"$ref": "#/definitions/DataType",
"title": "type"
},
"subType": {
"$ref": "#/definitions/SubDataType",
"title": "subType"
},
"name": {
"type": "string",
"title": "name"
},
"controlType": {
"$ref": "#/definitions/ControlType",
"title": "controlType"
},
"label": {
"type": "string",
"title": "label"
},
"tooltip": {
"type": "string",
"title": "tooltip"
},
"dataObjectPath": {
"description": "A string representing a path to the property in json data file conforming to the plugin schema,\nwhere each path component is seperated by a dot. Same as string representation of\nLodash.get method or mariocasciaro's object-path (https://github.com/mariocasciaro/object-path).\nThis string is unique for all elements in a model and may thus be used as a key if needed.",
"type": "string",
"title": "dataObjectPath"
},
"required": {
"type": "boolean",
"title": "required"
}
},
"additionalProperties": false,
"required": [
"defaultValue",
"kind",
"type",
"subType",
"name",
"controlType",
"label",
"tooltip",
"dataObjectPath",
"required"
]
}
},
"$schema": "http://json-schema.org/draft-04/schema#"
}
** Example input that should validate but instead gives various errors **
{
"kind": "group",
"name": "",
"controlType": "group",
"label": "",
"tooltip": "",
"dataObjectPath": "",
"required": true,
"elements": [
{
"kind": "field",
"name": "username",
"controlType": "input",
"label": "User name",
"tooltip": "a username description here",
"dataObjectPath": "username",
"defaultValue": "username default",
"required": true,
"type": "string",
"subType": "none"
},
{
"kind": "field",
"name": "usertype",
"controlType": "dropdown",
"label": "User type",
"tooltip": "a type description here",
"dataObjectPath": "usertype",
"defaultValue": "user",
"values": [
"user",
"superuser"
],
"required": true,
"type": "string",
"subType": "none"
},
{
"kind": "field",
"name": "host",
"controlType": "input",
"label": "Hostname",
"tooltip": "a hostname description here",
"dataObjectPath": "host",
"defaultValue": "localhost",
"required": false,
"type": "string",
"subType": "hostname"
},
{
"kind": "field",
"name": "age",
"controlType": "input",
"label": "Age",
"tooltip": "an age description here",
"dataObjectPath": "age",
"defaultValue": 18,
"required": false,
"type": "integer",
"subType": "none"
},
{
"kind": "field",
"name": "size",
"controlType": "dropdown",
"label": "Size",
"tooltip": "a size description here",
"dataObjectPath": "size",
"defaultValue": 0,
"values": [
0,
1,
2,
null
],
"required": false,
"type": "integer",
"subType": "none"
},
{
"kind": "field",
"name": "rate",
"controlType": "input",
"label": "Rate",
"tooltip": "a rate description here",
"dataObjectPath": "rate",
"defaultValue": 41.42,
"required": false,
"type": "number",
"subType": "none"
},
{
"kind": "field",
"name": "rank",
"controlType": "dropdown",
"label": "Rank",
"tooltip": "a rank description here",
"dataObjectPath": "rank",
"defaultValue": 3.14,
"values": [
3.14,
0.33,
9.99
],
"required": false,
"type": "number",
"subType": "none"
},
{
"kind": "field",
"name": "registered",
"controlType": "yesno",
"label": "Registered",
"tooltip": "a registered description here",
"dataObjectPath": "registered",
"defaultValue": false,
"required": false,
"type": "boolean",
"subType": "none"
}
],
"errors": []
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.