bcherny / json-schema-to-typescript Goto Github PK
View Code? Open in Web Editor NEWCompile JSON Schema to TypeScript type declarations
Home Page: https://bcherny.github.io/json-schema-to-typescript-browser/
License: MIT License
Compile JSON Schema to TypeScript type declarations
Home Page: https://bcherny.github.io/json-schema-to-typescript-browser/
License: MIT License
Hi,
Thanks for the great library, and sorry if this question has already been answered in the docs (I was not able to find anything as far as I know).
Is it possible to perform batch compilation? For example, with the following directory structure:
+- json_schema
+-foo.json
+-bar.json
is it possible to create the following output?
+- json_schema
+-foo.json
+-foo.d.ts
+-bar.json
+-bar.d.ts
Thanks again for all the great work on this project. It's very much appreciated.
When a type can be multiple simple types but not all types, the resulting interface is not correct.
See https://github.com/bcherny/json-schema-to-typescript/blob/master/dist/index.d.ts#L46
and https://spacetelescope.github.io/understanding-json-schema/reference/type.html
I observed this problem with a larger schema and created this simple test case to demonstrate:
export var schema = {
"title": "Example Schema",
"description": "My cool schema",
"type": "object",
"properties": {
"value": {
"type": ["number", "string"]
},
"anotherValue": {
"type": ["null", "string"]
}
},
"required": ["value"]
}
export var types = `/** My cool schema */
export interface ExampleSchema {
value: number | string;
anotherValue: null | string;
}`
I haven't had time to investigate a fix.... but could try if someone else isn't able to get to it before me.
It will be nice to have possibility to provide custom template (eg mustache or some other template engine) for generating the interfaces in custom way eg. for putting some comments etc.
For all the things mentioned here: https://github.com/bcherny/json-schema-to-typescript#not-expressible-in-typescript , generate companion objects for the interfaces with a single validate
which accepts an instance of the interface and applies run-time validations.
I just realized that this project has no Open Source library which make it not usable in legal terms.
Try to compileFromFile
this schema throws.
/Users/foo/webpack/node_modules/lodash/lodash.js:2591
function baseClone(value, isDeep, isFull, customizer, key, object, stack) {
^
RangeError: Maximum call stack size exceeded
at baseClone (/Users/foo/webpack/node_modules/lodash/lodash.js:2591:23)
at /Users/foo/webpack/node_modules/lodash/lodash.js:2644:34
at arrayEach (/Users/foo/webpack/node_modules/lodash/lodash.js:520:11)
at baseClone (/Users/foo/webpack/node_modules/lodash/lodash.js:2638:7)
at baseMergeDeep (/Users/foo/webpack/node_modules/lodash/lodash.js:3627:24)
at /Users/foo/webpack/node_modules/lodash/lodash.js:3562:11
at arrayEach (/Users/foo/webpack/node_modules/lodash/lodash.js:520:11)
at baseMerge (/Users/foo/webpack/node_modules/lodash/lodash.js:3555:7)
at /Users/foo/webpack/node_modules/lodash/lodash.js:13254:7
at Function.<anonymous> (/Users/foo/webpack/node_modules/lodash/lodash.js:4781:13)
The webpack schema is quite heavy. Perfect stress test to optimize ;) Note that you have to delete this enum because of #34 to get this working for now.
This syntax is new to me:
https://github.com/bcherny/json-schema-to-typescript/blob/master/src/index.ts#L260
I see is used frequently in this src, but I don't understand the idiom or syntax and can't find reference to it in typescript's documentation.
Can you give me some pointers?
Thanks
As a user I sometimes have invalid JSON schema and I would like a debugging option to tell me my schema is invalid so I don't waste time looking for issues in how JSON Schema is compiled to TS interface definition. As well, I want to be confident my JSON schema is valid before filing an issue.
A rough WIP is here: https://github.com/darcyparker/json-schema-to-typescript/tree/validateJSONSchema
An additional nice to have feature would be to log warnings about cases of not-expressible to typescript and suggest using decorators as mentioned here: #8
export class String extends TsType<void> {
constructor() { super(undefined) }
toString() {
return 'string'
}
}
export class Boolean extends TsType<void> {
constructor() { super(undefined) }
toString() {
return 'boolean'
}
}
export class Number extends TsType<void> {
constructor() { super(undefined) }
toString() {
return 'number'
}
}
export class Object extends TsType<void> {
constructor() { super(undefined) }
toString() {
return 'Object'
}
}
export class Array extends TsType<TsType<any>> {
constructor(value: TsType<any> = new Any) { super(value) }
toString(settings: Settings) {
const type = this.value.toType(settings)
return `${type.indexOf('|') > -1 || type.indexOf('&') > -1 ? `(${type})` : type}[]` // hacky
}
}
/node_modules/json-schema-to-typescript/dist/TsTypes.js:3
var extendStatics = Object.setPrototypeOf ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
^
TypeError: Cannot read property 'setPrototypeOf' of undefined
....
/json-schema-to-typescript/dist_tests/src/TsTypes.js:2
Object.defineProperty(exports, "__esModule", { value: true });
^
ReferenceError: Object is not defined
at Object.<anonymous> (/json-schema-to-typescript/dist_tests/src/TsTypes.js:2:1)
at Module._compile (module.js:571:32)
at Module._extensions..js (module.js:580:10)
at extensions.(anonymous function) (/json-schema-to-typescript/node_modules/require-precompiled/index.js:16:3)
Why do you reset these standard constructors? And how do you build it?
Latest release use some features that unsupported by [email protected] - ES6 default parameters for instance. So there is an error in attempt to run cli.js
.../.nvm/versions/node/v4.7.2/lib/node_modules/json-schema-to-typescript/dist/src/index.js:30
function compileFromFile(filename, options = exports.DEFAULT_OPTIONS) {
^
SyntaxError: Unexpected token =
at exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:373:25)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Module.require (module.js:353:17)
If I have a description like this in my JSON Schema:
"description": "Some description\nWith multiple lines"
The output typescript definition neglects to comment the new lines too.
It would be great if long term, the description comment could support multiple lines. For the short term, I am simply stripping the new lines out of the JSON schema before I compile it to typescript.
https://github.com/bcherny/json-schema-to-typescript/blob/85b83eeed9e35f608a46805f9b0877d7fe027d41/test/e2e/realWorld.swagger.ts produces different output on Node 6.9.5 vs. 4.5.0.
import { compile } from 'json-schema-to-typescript';
compile(scheme); // error
import { compile } from 'json-schema-to-typescript';
compile(scheme, undefined); // ok
export declare function compile(schema: JSONSchema, path: string | undefined, settings?: Settings): string;
It's because the path param should be optional:
export declare function compile(schema: JSONSchema, path?: string, settings?: Settings): string;
I guess it's just a typo )
PS: could you export the JSONSchema
interface?
See #22
Source JSON
My code
const converter = require('json-schema-to-typescript');
var fs = require('fs');
converter.compileFromFile('./vk-api-schema/objects.json')
.then(function (interf) {
fs.writeFile("./types/objects.d.ts", interf);
});
Result:
export type Objects = any;
Currently the schema.id
is favored over the schema.title
when generating the type name.
For instance,
{
"id": "http://dummy.com/api/person",
"title": "Person",
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
}
}
}
will generate
export interface HttpDummyComApiPerson {
firstName?: string;
lastName?: string;
[k: string]: any;
}
Although it helps to avoid naming collisions, it's very awkward to have types named after URLs.
I would like to suggest one of the two possible improvements:
id
and title
on index.ts:47this.id = schema.title || schema.id || this.filePath.name || 'Interface1'
Which will favor the title
over the id
. The down side being that it may cause naming collisions.
id
, but generate a namespacefor id = "http://dummy.com/api/person"
we could have
namescape DummyComApi { // http protocol dropped
export interface Person {
firstName?: string;
lastName?: string;
[k: string]: any;
}
}
I noticed that any property in a json schema which has a title does not get resolved. Instead, the title is used as a type.
Example:
"users": {
"type": "array",
"title": "user id array",
"description": "Array of authorized user ids.",
"items": {
"type": "string"
}
}
gets translated to:
users?: UserIdArray;
which leads to a undefined type UserIdArray
. Is that behavior expected? How do I get json-schema-to-typescript to define the referenced types as well?
For now I created a workaround by removing || rule.title
from line 168. This generates:
users?: string[];
Schema using a local '$ref' to a definition in the same JSON document (have not tested against external file $ref's) is producing duplicate Interface statements causing creation of invalid .ts file. This seems to occur when the following conditions are met:
title
(in these cases the title seems to have no effect on interface name in definitions)object
with properties
or a string
with enum
.i.e. a definition such as the following, if referenced will result in a duplicate Interface in the ts output:
"definitions": {
"firstDefinition": {
"title": "First Definition Title",
"type": "object",
"properties": {
"name": {
"type": "string"
}
}
}
}
I've attached a test schema and the resulting ts output to better demonstrate the problem. Can try and assist if suitable - I understand @bcherny may be currently working on improvements to the $ref handling #44.
{
"type": "object",
"properties": {
"definitions": {
"$ref": "#/definitions/definitions"
}
},
"definitions": {
"definitions": {
"$ref": "#/definitions/schema"
},
"schema": {
"type": "object",
"properties": {
"additionalProperties": {
"anyOf": [
{
"$ref": "#/definitions/schema"
}
]
}
}
}
}
I made a mistake in part of the test case requested for #27.
is not valid.Unions of other simple types are being handled nicely - thank you again for adding this capability. But I didn't realize until having tsc
complain and then reading How to declare a type as nullable in TypeScript? (which coincidentally @bcherny submitted an answer) that the anotherValue?: null | string;
is not valid typescript. After reading the answers to this stackoverflow question I realize that anytime there are disjoint types for a property that includes null
, then null
should be filtered from the list of types and the property should become optional (which in the example test case coincidentally was).
Would you agree this is a correct interpretation of how to translate a disjoint type with null
in its list and transforming to a typescript interface? (If not, it's still a bug because null | string
is not valid according to tsc
. So I am open to other suggestions of how to handle disjoint types with null
in it.)
BTW: I saw this deeper in the comments of the above stackoverflow question: microsoft/TypeScript#7140. So it looks like this is just a bug with tsc
< 2.0
.
There are some points where tsEnumNames
could be enhanced:
snake_case
. Allow ts_enum_names.enum_titles
for a similar scenario. Allow both or adopt.See https://github.com/bcherny/json-schema-to-typescript/blob/master/src/index.ts#L251.
As far as I understand the standard it is allowed to create a schema like { enum: [ false ] }
. Currently an error is thrown if you use { enum: [ false ] }
: TypeError: Enum was declared as a string type but found at least one non-string member
.
E.g. given
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"foo": {
"enum": [ false ]
}
}
}
and
{
"foo": false
}
is valid here: http://www.jsonschemavalidator.net/.
"understanding json schema" also says "You can use enum even without a type, to accept values of different types."
Okay, I see I can't even workaround this by using { type: 'boolean', enum: [ false ] }
, because of https://github.com/bcherny/json-schema-to-typescript/blob/master/src/index.ts#L257: TypeError: Enum type must be string or integer; default is string if undefined
.
It is also valid to just use false
as a type in TypeScript. See this example:
interface Success<T> {
success: true; // type is `true`, not `boolean`
value: T;
}
interface Failure {
success: false; // type is `false`, not `boolean`
reason: string;
}
type Result<T> = Success<T> | Failure;
It would be nice to provide simple command line application within the package. It could be almost equal to one inside example
directory but allow to specify input and output file. What do you think about that?
Noticed the package version is much higher than npm release. Any chance for an npm update?
Can't install direct from github because of dist directory.
Thanks!
To avoid generating the same interface twice.
When I try to generate typings from swagger schema(https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/schemas/v2.0/schema.json), following error reported:
ReferenceError: Unable to find referenced file "/some/file/path/http:/json-schema.org/draft-04/schema#/properties/title"
at /Users/xxx/Projects/swagger-typings/node_modules/json-schema-to-typescript/dist/index.js:115:99
at tryFn (/Users/xxx/Projects/swagger-typings/node_modules/json-schema-to-typescript/dist/index.js:288:16)
...
Thanks for the great work here.
I'm also looking for the opposite of this library. A library that converts typings to json schema.
Do you know of such library exist?
When this pull requests will be available in TypeScript 2.2.1 you will be able to create AST from scratch and generate TS code without string transformations:
Currently the commentaries are based only on description.
Eg.
For schema:
{
"title": "My Object",
"description": "Some custom object",
"type": "object",
"properties": {
"bar" : {
"title": "Some property",
"description": "Some property description",
"type": "string"
}
}
}
We have:
/*
Some custom object
*/
export interface MyObject {
bar?: string; // Some property description
[k: string]: any;
}
It will be nice to have:
/**
* Some custom object.
*/
export interface MyObject {
/**
* Some property.
* Some property description.
*/
bar?: string;
[k: string]: any;
}
How do I generate named enums for string types. My JSON Schema looks like below:
"status": {
"enum": [
"I",
"A",
"C"
],
"tsEnumNames": [
"InProgress",
"ForApproval",
"Complete"
]
},
Should generate the following Typescript
status: Status
....
export const enum Status {
InProgress = "I"
ForApproval = "A"
Complete = "C"
}
Instead of the above, its generating the flags without quotes that results in TypeScript error. Can you please suggest, how can I generate the above typescript code?
Have a look at: https://github.com/darcyparker/json-schema-to-typescript/blob/fe3f08f1d7eb4445619488974f9f89b2353b74c7/test/cases/allOf.ts
As a comparison, dtsgenerator creates this output:
export interface Itest {
fooAndBar: {
a: string;
b: number;
};
foo: {
a: string;
b: number;
};
more: {
a: string;
};
}
declare namespace Itest {
namespace Definitions {
export interface Bar {
a: string;
}
export interface Foo {
a: string;
b: number;
}
}
}
Notes:
- ignore the interface name and namespace
Itest
...:dtgenerator
uses the filename rather than thetitle
of the schema.- I like
json-schema-typescript
's compiler's choice to use the definitions ofBar
andFoo
inItest
. but ignoring this, you can see it picks up the properties insideallOf
that is a sibling of the top levelproperties
. I believe this is correct behavior becauseajv compile -s test.json -o test.js
creates a validator that checks formore
.
The following test fails for unknown reason: simonschllng/json-schema-to-typescript@0140729
The TS references the schema file name instead of the type:
[k: string]: any;
}
export interface Referencing {
foo: ExampleSchema;
- bar?: geo;
+ bar?: Geo;
}
If you extend https://github.com/bcherny/json-schema-to-typescript/blob/master/test/cases/array-of-type.ts like this:
export var schema = {
"title": "Array of type",
"type": "object",
"properties": {
"foo": {
"items": {
"type": "string"
},
"type": "array"
},
"times": {
"items": {
"type": "string",
"format": "date-time"
},
"type": [ "array" ]
}
}
}
Then the output is this:
export interface ArrayOfType {
foo?: string[];
times?: array;
[k: string]: any;
}
times?: array
should be times?: Array<string>
or alternatively times?: string[]
I think this is connected to disjoint types
test case.
{
additionalProperties: true,
properties: {
foo: {
$ref: '#/definitions/bar'
}
},
definitions: {
bar: {
$ref: '#/definitions/bar'
}
},
required: ['foo'],
title: 'Cycle (3)'
}
Depends on APIDevTools/json-schema-ref-parser#37
Can you support generics? Like generating from this:
{
"title": "TGenericNumber",
"type": { "$ref": "#/definitions/iarg", "generics": ["number", "string"] },
"definitions": {
"iarg": {
"title": "IArg<T, R>",
"properties": {
"key": { "type": "T" },
"value": { "type": "R" }
}
}
}
}
to this:
export interface IArg<T, R> { key: T, value: R };
export type TGeneric = IArg<number, string>;
Now that dist/*
files aren't included in distribution, downstream repos that depend on json-schema-to-typescript
are failing with
>> Error: Cannot find module 'json-schema-to-typescript'
I think the cause is that https://github.com/bcherny/json-schema-to-typescript/blob/master/package.json#L5 refers to dist/index.js
and this is not in the repo after npm install json-schema-to-typescript
.
I speculate this can be resolved by adding postinstall
script to your package.json
like this: (See https://docs.npmjs.com/misc/scripts) (or something similar to this...)
{
"scripts": {
"postinstall": "./node_modules/.bin/gulp dist"
}
}
import * as jsonScheme from 'generate-schema';
import { compile } from 'json-schema-to-typescript';
let scheme = jsonScheme.json('x', {
"x[0]": 1
});
let result = compile(scheme, undefined);
console.log(result)
export interface X {
x[0]?: number;
[k: string]: any;
}
x[0]
is not a valid name. What is expected:
export interface X {
'x[0]'?: number;
[k: string]: any;
}
This is how we use json-schema-to-typescript in gulp. Maybe helpful for others, could be added to the docs/wiki.
gulp task:
let gulp = require('gulp');
let jsonType = require('../util/json-to-typings');
gulp.task('schema', () => {
return gulp.src('schema/*.schema.json')
.pipe(jsonType())
.pipe(gulp.dest('models'));
});
file json-to-typings.js
let through = require('through2');
let PluginError = require('gulp-util').PluginError;
let jsonToType = require('json-schema-to-typescript');
module.exports = function() {
return through.obj(function(file, encoding, callback) {
if (file.isNull()) {
return callback(null, file);
}
if (file.isStream()) {
this.emit('error', new PluginError(PLUGIN_NAME, 'Streams not supported!'));
}
file.path = file.path.replace('schema.json', 'ts');
file.contents = Buffer.from(jsonToType.compile(JSON.parse(file.contents.toString())));
callback(null, file);
});
};
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.