Socket
Socket
Sign inDemoInstall

json-schema-to-typescript

Package Overview
Dependencies
Maintainers
1
Versions
114
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

json-schema-to-typescript - npm Package Compare versions

Comparing version 0.1.1 to 1.0.0

.vscode/settings.json

169

dist/index.js

@@ -25,23 +25,16 @@ "use strict";

class Compiler {
constructor(schema) {
constructor(schema, settings) {
this.schema = schema;
this.state = {
interfaces: [],
anonymousSchemaNameGenerator: this.generateSchemaName()
};
this.id = schema.id || schema.title || "Interface1";
this.declarations = new Map();
this.settings = Object.assign({}, Compiler.DEFAULT_SETTINGS, settings);
let decl = this.declareType(this.toTsType(this.schema), this.id, this.id);
}
toString() {
return pretty_printer_1.format(this.state.interfaces
.concat(this.toTsInterface(this.schema))
.map(_ => _.toString())
return pretty_printer_1.format(Array.from(this.declarations.values())
.map(_ => _.toDeclaration(this.settings))
.join('\n'));
}
*generateSchemaName() {
let counter = 0;
while (++counter) {
yield `Interface${counter}`;
}
}
isRequired(propertyName, schema) {
return schema.required.indexOf(propertyName) > -1;
return schema.required ? schema.required.indexOf(propertyName) > -1 : false;
}

@@ -51,8 +44,7 @@ supportsAdditionalProperties(schema) {

}
toInterfaceName(a) {
return lodash_1.upperFirst(lodash_1.camelCase(a))
|| this.state.anonymousSchemaNameGenerator.next().value;
toDeclarationName(a) {
return lodash_1.upperFirst(lodash_1.camelCase(a));
}
getRuleType(rule) {
if (rule.type === 'array' && rule.items && rule.items.type) {
if (rule.type === 'array' && rule.items) {
return RuleType.TypedArray;

@@ -99,44 +91,50 @@ }

// eg. "#/definitions/diskDevice" => ["definitions", "diskDevice"]
parsePath(path) {
return (path.slice(0, 2) === '#/' ? path.slice(2) : path).split('/');
}
getReference(path, root) {
switch (path.length) {
case 0: throw ReferenceError(`$ref "#{path.join('/')}" points at invalid reference`);
case 1: return root[path[0]];
default: return this.getReference(path.slice(1), root[path[0]]);
resolveType(path) {
if (path[0] !== '#')
throw new Error("reference must start with #");
if (path === '#' || path === '#/')
return TsType.Interface.reference(this.id);
const parts = path.slice(2).split('/');
let ret = this.settings.declareReferenced ? this.declarations.get(parts.join('/')) : undefined;
if (!ret) {
let cur = this.schema;
let i = 0;
for (let i = 0; cur && i < parts.length; ++i) {
cur = cur[parts[i]];
}
ret = this.toTsType(cur);
if (this.settings.declareReferenced && (this.settings.declareSimpleType || !ret.isSimpleType()))
this.declareType(ret, parts.join('/'), this.settings.useFullReferencePathAsName ? parts.join('/') : lodash_1.last(parts));
}
return ret;
}
getInterface(name) {
return this.state.interfaces.find(_ => _.name === this.toInterfaceName(name));
declareType(type, path, id) {
type.id = id;
this.declarations.set(path, type);
return type;
}
createInterfaceNx(rule, name) {
return this.getInterface(name) || (() => {
const a = this.toTsInterface(rule, name);
this.state.interfaces.push(a);
return a;
})();
}
toStringLiteral(a) {
switch (typeof a) {
case 'boolean': return 'boolean'; // ts doesn't support literal boolean types
case 'number': return 'number'; // ts doesn't support literal numeric types
case 'string': return `"${a}"`;
default: return a;
case 'boolean': return new TsType.Boolean; // ts doesn't support literal boolean types
case 'number': return new TsType.Number; // ts doesn't support literal numeric types
case 'string': return new TsType.Literal(JSON.stringify(a));
default: return new TsType.Interface(lodash_1.map(a, (v, k) => {
return {
type: this.toStringLiteral(v),
name: k,
required: true
};
}));
}
}
toTsType(rule, root, name) {
createTsType(rule) {
switch (this.getRuleType(rule)) {
case RuleType.AnonymousSchema:
return new TsType.AnonymousInterface(this.schemaPropsToInterfaceProps(lodash_1.merge({}, Compiler.DEFAULT_SCHEMA, {
required: Object.keys(rule),
properties: rule
})));
case RuleType.NamedSchema:
return new TsType.NamedClass(this.createInterfaceNx(rule, name).name);
return this.toTsDeclaration(rule);
case RuleType.Enum:
return new TsType.Union(lodash_1.uniqBy(rule.enum.map(_ => this.toTsType(this.toStringLiteral(_), root)), _ => _.toString()));
return new TsType.Union(lodash_1.uniqBy(rule.enum.map(_ => this.toStringLiteral(_)), _ => _.toType(this.settings)));
case RuleType.Any: return new TsType.Any;
case RuleType.Literal: return new TsType.Literal(rule);
case RuleType.TypedArray: return new TsType.Array(this.toTsType(rule.items, root));
case RuleType.TypedArray: return new TsType.Array(this.toTsType(rule.items));
case RuleType.Array: return new TsType.Array;

@@ -149,46 +147,45 @@ case RuleType.Boolean: return new TsType.Boolean;

case RuleType.AllOf:
return new TsType.Intersection(rule.allOf.map(_ => {
const path = this.parsePath(_.$ref);
return this.toTsType(_, root, lodash_1.last(path));
}));
return new TsType.Intersection(rule.allOf.map(_ => this.toTsType(_)));
case RuleType.AnyOf:
return new TsType.Union(rule.anyOf.map(_ => {
const path = this.parsePath(_.$ref);
return this.toTsType(_, root, lodash_1.last(path));
}));
return new TsType.Union(rule.anyOf.map(_ => this.toTsType(_)));
case RuleType.Reference:
const path = this.parsePath(rule.$ref);
const int = this.getInterface(lodash_1.last(path));
return int
? new TsType.Literal(int.name)
: this.toTsType(this.getReference(path, root), root, lodash_1.last(path));
return this.resolveType(rule.$ref);
}
throw "bug";
}
schemaPropsToInterfaceProps(schema) {
return lodash_1.map(schema.properties, (v, k) => new TsType.InterfaceProperty({
isRequired: this.isRequired(k, schema),
key: k,
value: this.toTsType(v, schema),
description: v.description
}));
toTsType(rule) {
let type = this.createTsType(rule);
type.id = type.id || rule.id || rule.title;
type.description = type.description || rule.description;
return type;
}
toTsInterface(schema, title) {
schema = lodash_1.merge({}, Compiler.DEFAULT_SCHEMA, schema);
const props = this.schemaPropsToInterfaceProps(schema);
if (this.supportsAdditionalProperties(schema)) {
props.push(new TsType.InterfaceProperty({
key: '[k: string]',
isRequired: true,
value: (schema.additionalProperties === true
? new TsType.Any
: this.toTsType(schema.additionalProperties, schema))
}));
toTsDeclaration(schema) {
let copy = lodash_1.merge({}, Compiler.DEFAULT_SCHEMA, schema);
let set = new Set();
let props = lodash_1.map(copy.properties, (v, k) => {
return {
type: this.toTsType(v),
name: k,
required: this.isRequired(k, copy)
};
});
if (props.length === 0 && !("additionalProperties" in schema)) {
if ("default" in schema)
return new TsType.Void;
}
return new TsType.Interface({
name: this.toInterfaceName(title || schema.title),
description: schema.description,
props: props
});
if (this.supportsAdditionalProperties(copy)) {
let short = copy.additionalProperties === true;
if (short && props.length === 0)
return new TsType.Any;
let type = short ? new TsType.Any : this.toTsType(copy.additionalProperties);
props.push({
type: type,
name: '[k: string]',
required: true
});
}
return new TsType.Interface(props);
}
}
Compiler.DEFAULT_SETTINGS = TsType.DEFAULT_SETTINGS;
Compiler.DEFAULT_SCHEMA = {

@@ -200,4 +197,4 @@ additionalProperties: true,

};
function compile(schema) {
return new Compiler(schema).toString();
function compile(schema, settings) {
return new Compiler(schema, settings).toString();
}

@@ -204,0 +201,0 @@ exports.compile = compile;

"use strict";
const lodash_1 = require('lodash');
exports.DEFAULT_SETTINGS = {
declareSimpleType: false,
declareReferenced: true,
useFullReferencePathAsName: false,
// declareProperties: false,
useInterfaceDeclaration: false,
endTypeWithSemicolon: true,
endPropertyWithSemicolon: true,
declarationDescription: true,
propertyDescription: true,
};
class TsType {
safeId() {
return this.id && lodash_1.upperFirst(lodash_1.camelCase(this.id));
}
toBlockComment(settings) {
return this.description && settings.declarationDescription ? `/** ${this.description} */\n` : '';
}
_toDeclaration(decl, settings) {
return this.toBlockComment(settings) + decl + (settings.endTypeWithSemicolon ? ";" : "");
}
isSimpleType() { return true; }
toDeclaration(settings) {
return this._toDeclaration(`type ${this.safeId()} = ${this._type(settings)}`, settings);
}
toSafeType(settings) {
return this.toType(settings);
}
toType(settings) {
return this.safeId() || this._type(settings);
}
toString() {
return this._type(exports.DEFAULT_SETTINGS);
}
}
exports.TsType = TsType;
class Any extends TsType {
toString() {
_type() {
return 'any';

@@ -11,14 +45,10 @@ }

exports.Any = Any;
class Array extends TsType {
constructor(type) {
super();
this.type = type;
class String extends TsType {
_type() {
return 'string';
}
toString() {
return `${this.type ? this.type.toString() : (new Any()).toString()}[]`;
}
}
exports.Array = Array;
exports.String = String;
class Boolean extends TsType {
toString() {
_type() {
return 'boolean';

@@ -28,22 +58,20 @@ }

exports.Boolean = Boolean;
class NamedClass extends TsType {
constructor(name) {
super();
this.name = name;
class Number extends TsType {
_type() {
return 'number';
}
toString() {
return this.name;
}
exports.Number = Number;
class Object extends TsType {
_type() {
return 'Object';
}
}
exports.NamedClass = NamedClass;
class Intersection extends TsType {
constructor(data) {
super();
this.data = data;
exports.Object = Object;
class Void extends TsType {
_type() {
return 'void';
}
toString() {
return this.data.join('&');
}
}
exports.Intersection = Intersection;
exports.Void = Void;
class Literal extends TsType {

@@ -54,3 +82,3 @@ constructor(value) {

}
toString() {
_type() {
return this.value;

@@ -60,21 +88,13 @@ }

exports.Literal = Literal;
class Number extends TsType {
toString() {
return 'number';
class Array extends TsType {
constructor(type) {
super();
this.type = type;
}
}
exports.Number = Number;
class Object extends TsType {
toString() {
return 'Object';
_type(settings) {
return `${(this.type || new Any()).toSafeType(settings)}[]`;
}
}
exports.Object = Object;
class String extends TsType {
toString() {
return 'string';
}
}
exports.String = String;
class Union extends TsType {
exports.Array = Array;
class Intersection extends TsType {
constructor(data) {

@@ -84,29 +104,24 @@ super();

}
toString() {
return this.data.join('|');
isSimpleType() { return this.data.filter(_ => !(_ instanceof Void)).length <= 1; }
_type(settings) {
return this.data
.filter(_ => !(_ instanceof Void))
.map(_ => _.toSafeType(settings))
.join('&');
}
}
exports.Union = Union;
class Void extends TsType {
toString() {
return 'void';
toSafeType(settings) {
return `${this.toType(settings)}`;
}
}
exports.Void = Void;
class InterfaceProperty extends TsType {
constructor(data) {
super();
this.data = data;
exports.Intersection = Intersection;
class Union extends Intersection {
isSimpleType() { return this.data.length <= 1; }
_type(settings) {
return this.data
.map(_ => _.toSafeType(settings))
.join('|');
}
toString() {
return [
this.data.key,
`${this.data.isRequired ? '' : '?'}: `,
`${this.data.value.toString()};`,
this.data.description ? ` // ${this.data.description}` : ''
].join('');
}
}
exports.InterfaceProperty = InterfaceProperty;
class AnonymousInterface extends TsType {
exports.Union = Union;
class Interface extends TsType {
constructor(props) {

@@ -116,30 +131,32 @@ super();

}
toString() {
return `{
${this.props.join('\n')}
}`;
static reference(id) {
let ret = new Interface([]);
ret.id = id;
return ret;
}
}
exports.AnonymousInterface = AnonymousInterface;
class Interface extends TsType {
constructor(data) {
super();
this.data = data;
_type(settings, declaration = false) {
let id = this.safeId();
return declaration || !id ? `{
${this.props.map(_ => {
let decl = _.name;
if (!_.required)
decl += '?';
decl += ": " + _.type.toType(settings);
if (settings.endPropertyWithSemicolon)
decl += ';';
if (settings.propertyDescription && _.type.description)
decl += ' // ' + _.type.description;
return decl;
}).join('\n')}
}` : id;
}
get name() { return this.data.name; }
toBlockComment(a) {
return `/*
${a}
*/
`;
isSimpleType() { return false; }
toDeclaration(settings) {
if (settings.useInterfaceDeclaration)
return `${this.toBlockComment(settings)}interface ${this.safeId()} ${this._type(settings, true)}`;
else
return this._toDeclaration(`type ${this.safeId()} = ${this._type(settings, true)}`, settings);
}
toString() {
return `${this.data.description
? this.toBlockComment(this.data.description)
: ''}interface ${this.data.name} {
${this.data.props.join('\n')}
}`;
}
}
exports.Interface = Interface;
//# sourceMappingURL=TsTypes.js.map
{
"name": "json-schema-to-typescript",
"version": "0.1.1",
"version": "1.0.0",
"description": "compile json schema to typescript typings",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"test": "ava ./test/test.js",
"watch": "watch \"npm run build\" ./src/ ./test/"
"tsc": "tsc",
"build": "gulp tsc",
"test": "gulp test",
"debug": "gulp debug",
"watch": "watch \"npm run test\" ./src/ ./test/"
},

@@ -34,13 +36,14 @@ "repository": {

"lodash": "^4.6.1",
"typescript": "^1.8.9"
"typescript": "^2.0.0"
},
"devDependencies": {
"ava": "^0.13.0",
"colors": "^1.1.2",
"diff": "^2.2.2",
"glob-promise": "^1.0.6",
"json-schema-test-suite": "github:json-schema/JSON-Schema-Test-Suite#node",
"typings": "^0.7.9",
"@types/chai": "^3.4.29",
"@types/lodash": "0.0.28",
"@types/mocha": "^2.2.28",
"@types/node": "^4.0.30",
"chai": "^3.5.0",
"gulp": "^3.9.1",
"mocha": "^2.5.3",
"watch": "^0.17.1"
}
}

@@ -6,7 +6,9 @@ import {camelCase, isPlainObject, last, map, merge, uniqBy, upperFirst} from 'lodash'

import * as TsType from './TsTypes'
process.platform
enum RuleType {"Any","TypedArray","Enum","AllOf","AnyOf","Reference","NamedSchema", "AnonymousSchema",
"String","Number","Void","Object","Array","Boolean","Literal"}
class Compiler {
static DEFAULT_SETTINGS = TsType.DEFAULT_SETTINGS;

@@ -20,9 +22,13 @@ static DEFAULT_SCHEMA: JSONSchema.Schema = {

constructor(private schema: JSONSchema.Schema) {}
constructor(private schema: JSONSchema.Schema, settings?: TsType.TsTypeSettings) {
this.id = schema.id || schema.title || "Interface1";
this.declarations = new Map();
this.settings = Object.assign({}, Compiler.DEFAULT_SETTINGS, settings);
let decl = this.declareType(this.toTsType(this.schema), this.id, this.id);
}
toString(): string {
return format(
this.state.interfaces
.concat(this.toTsInterface(this.schema))
.map(_ => _.toString())
Array.from(this.declarations.values())
.map(_ => _.toDeclaration(this.settings))
.join('\n')

@@ -32,19 +38,8 @@ )

private state: {
interfaces: TsType.Interface[],
anonymousSchemaNameGenerator: IterableIterator<string>
} = {
interfaces: [],
anonymousSchemaNameGenerator: this.generateSchemaName()
}
private settings: TsType.TsTypeSettings;
private id: string;
private declarations: Map<string, TsType.TsType>;
private *generateSchemaName(): IterableIterator<string> {
let counter = 0
while (++counter) {
yield `Interface${counter}`
}
}
private isRequired(propertyName: string, schema: JSONSchema.Schema): boolean {
return schema.required.indexOf(propertyName) > -1
return schema.required ? schema.required.indexOf(propertyName) > -1 : false;
}

@@ -56,9 +51,8 @@

private toInterfaceName (a: string): string {
return upperFirst(camelCase(a))
|| this.state.anonymousSchemaNameGenerator.next().value
private toDeclarationName (a: string): string {
return upperFirst(camelCase(a))
}
private getRuleType (rule: JSONSchema.Schema): RuleType {
if (rule.type === 'array' && rule.items && rule.items.type) {
if (rule.type === 'array' && rule.items) {
return RuleType.TypedArray

@@ -106,32 +100,42 @@ }

// eg. "#/definitions/diskDevice" => ["definitions", "diskDevice"]
private parsePath (path: string): string[] {
return (path.slice(0, 2) === '#/' ? path.slice(2) : path).split('/')
}
private getReference(path: string[], root: JSONSchema.Schema): JSONSchema.Schema {
switch (path.length) {
case 0: throw ReferenceError(`$ref "#{path.join('/')}" points at invalid reference`)
case 1: return root[path[0]]
default: return this.getReference(path.slice(1), root[path[0]])
private resolveType(path: string): TsType.TsType {
if (path[0] !== '#')
throw new Error("reference must start with #");
if (path === '#' || path === '#/')
return TsType.Interface.reference(this.id);
const parts = path.slice(2).split('/');
let ret = this.settings.declareReferenced ? this.declarations.get(parts.join('/')) : undefined;
if (!ret) {
let cur: any = this.schema;
let i = 0;
for (let i = 0; cur && i < parts.length; ++i) {
cur = cur[parts[i]];
}
ret = this.toTsType(cur);
if (this.settings.declareReferenced && (this.settings.declareSimpleType || !ret.isSimpleType()))
this.declareType(ret, parts.join('/'), this.settings.useFullReferencePathAsName ? parts.join('/') : last(parts));
}
return ret;
}
private getInterface (name: string): TsType.Interface {
return this.state.interfaces.find(_ => _.name === this.toInterfaceName(name))
private declareType(type: TsType.TsType, path: string, id: string) {
type.id = id;
this.declarations.set(path, type);
return type;
}
private createInterfaceNx (rule: JSONSchema.Schema, name: string): TsType.Interface {
return this.getInterface(name) || (() => {
const a = this.toTsInterface(rule, name)
this.state.interfaces.push(a)
return a
})()
}
private toStringLiteral(a: boolean|number|string|Object): string|Object {
private toStringLiteral(a: boolean|number|string|Object): TsType.TsType {
switch (typeof a) {
case 'boolean': return 'boolean' // ts doesn't support literal boolean types
case 'number': return 'number' // ts doesn't support literal numeric types
case 'string': return `"${a}"`
default: return a
case 'boolean': return new TsType.Boolean; // ts doesn't support literal boolean types
case 'number': return new TsType.Number; // ts doesn't support literal numeric types
case 'string': return new TsType.Literal(JSON.stringify(a));
default: return new TsType.Interface(map(
<any>a,
(v: JSONSchema.Schema, k: string) => {
return {
type: this.toStringLiteral(v),
name: k,
required: true
};
}));
// TODO: support array types?

@@ -143,25 +147,15 @@ // TODO: support enums of enums

private toTsType (rule: JSONSchema.Schema, root: JSONSchema.Schema, name?: string): TsType.TsType {
private createTsType (rule: JSONSchema.Schema): TsType.TsType {
switch (this.getRuleType(rule)) {
case RuleType.AnonymousSchema:
return new TsType.AnonymousInterface(
this.schemaPropsToInterfaceProps(merge({}, Compiler.DEFAULT_SCHEMA, {
required: Object.keys(rule),
properties: rule
}))
)
case RuleType.NamedSchema:
return new TsType.NamedClass(
this.createInterfaceNx(rule, name).name
)
return this.toTsDeclaration(rule);
case RuleType.Enum:
return new TsType.Union(uniqBy(
rule.enum.map(_ =>
this.toTsType(this.toStringLiteral(_), root)
)
, _ => _.toString())
rule.enum!.map(_ => this.toStringLiteral(_))
, _ => _.toType(this.settings))
)
case RuleType.Any: return new TsType.Any
case RuleType.Literal: return new TsType.Literal(rule)
case RuleType.TypedArray: return new TsType.Array(this.toTsType(rule.items, root))
case RuleType.TypedArray: return new TsType.Array(this.toTsType(rule.items!))
case RuleType.Array: return new TsType.Array

@@ -174,57 +168,49 @@ case RuleType.Boolean: return new TsType.Boolean

case RuleType.AllOf:
return new TsType.Intersection(rule.allOf.map(_ => {
const path = this.parsePath(_.$ref)
return this.toTsType(_, root, last(path))
}))
return new TsType.Intersection(rule.allOf!.map(_ => this.toTsType(_)))
case RuleType.AnyOf:
return new TsType.Union(rule.anyOf.map(_ => {
const path = this.parsePath(_.$ref)
return this.toTsType(_, root, last(path))
}))
return new TsType.Union(rule.anyOf!.map(_ => this.toTsType(_)))
case RuleType.Reference:
const path = this.parsePath(rule.$ref)
const int = this.getInterface(last(path))
return int
? new TsType.Literal(int.name)
: this.toTsType(this.getReference(path, root), root, last(path))
return this.resolveType(rule.$ref!);
}
throw "bug";
}
private toTsType (rule: JSONSchema.Schema): TsType.TsType {
let type = this.createTsType(rule);
type.id = type.id || rule.id || rule.title;
type.description = type.description || rule.description;
return type;
}
private schemaPropsToInterfaceProps (schema: JSONSchema.Schema): TsType.InterfaceProperty[] {
return map(
schema.properties,
(v: JSONSchema.Schema, k: string) => new TsType.InterfaceProperty({
isRequired: this.isRequired(k, schema),
key: k,
value: this.toTsType(v, schema),
description: v.description
})
)
}
private toTsInterface (schema: JSONSchema.Schema, title?: string): TsType.Interface {
schema = merge({}, Compiler.DEFAULT_SCHEMA, schema)
const props = this.schemaPropsToInterfaceProps(schema)
if (this.supportsAdditionalProperties(schema)) {
props.push(new TsType.InterfaceProperty({
key: '[k: string]',
isRequired: true,
value: (
schema.additionalProperties === true
? new TsType.Any
: this.toTsType(<JSONSchema.Schema>schema.additionalProperties, schema)
)
}))
private toTsDeclaration (schema: JSONSchema.Schema) : TsType.TsType {
let copy = merge({}, Compiler.DEFAULT_SCHEMA, schema);
let set = new Set();
let props = map(
copy.properties!,
(v: JSONSchema.Schema, k: string) => {
return {
type: this.toTsType(v),
name: k,
required: this.isRequired(k, copy)
};
});
if (props.length === 0 && !("additionalProperties" in schema)) {
if ("default" in schema)
return new TsType.Void;
}
return new TsType.Interface({
name: this.toInterfaceName(title || schema.title),
description: schema.description,
props
})
if (this.supportsAdditionalProperties(copy)) {
let short = copy.additionalProperties === true;
if (short && props.length === 0)
return new TsType.Any;
let type = short ? new TsType.Any : this.toTsType(<JSONSchema.Schema>copy.additionalProperties);
props.push({
type: type,
name: '[k: string]',
required: true
});
}
return new TsType.Interface(props);
}
}
export function compile(schema: JSONSchema.Schema): string {
return new Compiler(schema).toString()
export function compile(schema: JSONSchema.Schema, settings?: TsType.TsTypeSettings): string {
return new Compiler(schema, settings).toString()
}

@@ -231,0 +217,0 @@

declare module JSONSchema {
interface Schema {
$ref?: string
additionalProperties?: boolean|Schema
type SimpleTypes = "array" | "boolean" | "integer" | "null" | "number" | "object" | "string";
/** Core schema meta-schema */
type HttpJsonSchemaOrgDraft04Schema = {
id?: string;
$schema?: string;
title?: string;
description?: string;
default?: any;
multipleOf?: number;
maximum?: number;
exclusiveMaximum?: boolean;
minimum?: number;
exclusiveMinimum?: boolean;
maxLength?: number;
minLength?: number;
pattern?: string;
additionalItems?: boolean | HttpJsonSchemaOrgDraft04Schema;
items?: HttpJsonSchemaOrgDraft04Schema | HttpJsonSchemaOrgDraft04Schema[];
maxItems?: number;
minItems?: number;
uniqueItems?: boolean;
maxProperties?: number;
minProperties?: number;
required?: string[];
additionalProperties?: boolean | HttpJsonSchemaOrgDraft04Schema;
definitions?: {
[a: string]: Schema
}
description?: string
enum?: (Schema|Type)[]
items?: Schema
minimum?: number
minItems?: number
maxLength?: number
minLength?: number
allOf?: Schema[]
anyOf?: Schema[]
oneOf?: Schema[]
[k: string]: HttpJsonSchemaOrgDraft04Schema;
};
properties?: {
[a: string]: Schema
}
required?: string[]
title?: string
type?: Type
uniqueItems?: boolean
}
[k: string]: HttpJsonSchemaOrgDraft04Schema;
};
patternProperties?: {
[k: string]: HttpJsonSchemaOrgDraft04Schema;
};
dependencies?: {
[k: string]: HttpJsonSchemaOrgDraft04Schema | string[];
};
enum?: any[];
type?: SimpleTypes | SimpleTypes[];
allOf?: HttpJsonSchemaOrgDraft04Schema[];
anyOf?: HttpJsonSchemaOrgDraft04Schema[];
oneOf?: HttpJsonSchemaOrgDraft04Schema[];
not?: HttpJsonSchemaOrgDraft04Schema;
[k: string]: any;
};
type Type = "array"|"boolean"|"integer"|"null"|"number"|"object"|"string"
type Schema = HttpJsonSchemaOrgDraft04Schema & { $ref?: string };
}

@@ -0,40 +1,82 @@

import {camelCase, upperFirst} from 'lodash'
export type TsTypeSettings = {
declareSimpleType?: boolean;
declareReferenced?: boolean;
useFullReferencePathAsName?: boolean;
// TODO declareProperties?: boolean;
useInterfaceDeclaration?: boolean;
endTypeWithSemicolon?: boolean;
endPropertyWithSemicolon?: boolean;
declarationDescription?: boolean;
propertyDescription?: boolean;
};
export var DEFAULT_SETTINGS: TsTypeSettings = {
declareSimpleType: false,
declareReferenced: true,
useFullReferencePathAsName: false,
// declareProperties: false,
useInterfaceDeclaration: false,
endTypeWithSemicolon: true,
endPropertyWithSemicolon: true,
declarationDescription: true,
propertyDescription: true,
};
export abstract class TsType {
abstract toString(): string
id?: string;
description?: string;
protected safeId() {
return this.id && upperFirst(camelCase(this.id));
}
protected toBlockComment(settings: TsTypeSettings) {
return this.description && settings.declarationDescription ? `/** ${this.description} */\n` : '';
}
protected _toDeclaration(decl: string, settings: TsTypeSettings): string
{
return this.toBlockComment(settings) + decl + (settings.endTypeWithSemicolon ? ";" : "");
}
protected abstract _type(settings: TsTypeSettings): string;
isSimpleType() { return true; }
toDeclaration(settings: TsTypeSettings): string
{
return this._toDeclaration(`type ${this.safeId()} = ${this._type(settings)}`, settings);
}
toSafeType(settings: TsTypeSettings): string
{
return this.toType(settings);
}
toType(settings: TsTypeSettings): string
{
return this.safeId() || this._type(settings);
}
toString() : string {
return this._type(DEFAULT_SETTINGS);
}
}
export type TsProp = {
name: string;
required: boolean;
type: TsType;
}
export class Any extends TsType {
toString() {
_type() {
return 'any'
}
}
export class Array extends TsType {
constructor(private type?: TsType) { super() }
toString() {
return `${this.type ? this.type.toString() : (new Any()).toString()}[]`
export class String extends TsType {
_type() {
return 'string'
}
}
export class Boolean extends TsType {
toString() {
_type() {
return 'boolean'
}
}
export class NamedClass extends TsType {
constructor(private name: string) { super() }
toString() {
return this.name
}
}
export class Intersection extends TsType {
constructor(private data: TsType[]) { super() }
toString() {
return this.data.join('&')
}
}
export class Literal extends TsType {
constructor(private value: any) { super() }
toString() {
return this.value
}
}
export class Number extends TsType {
toString() {
_type() {
return 'number'

@@ -44,71 +86,80 @@ }

export class Object extends TsType {
toString() {
_type() {
return 'Object'
}
}
export class String extends TsType {
toString() {
return 'string'
}
}
export class Union extends TsType {
constructor(private data: TsType[]) { super() }
toString() {
return this.data.join('|')
}
}
export class Void extends TsType {
toString() {
_type() {
return 'void'
}
}
export class InterfaceProperty extends TsType {
constructor(private data: {
isRequired: boolean,
key: string,
value: TsType,
description?: string
}) { super() }
toString(): string {
return [
this.data.key,
`${this.data.isRequired ? '' : '?'}: `,
`${this.data.value.toString()};`,
this.data.description ? ` // ${this.data.description}` : ''
].join('')
export class Literal extends TsType {
constructor(private value: any) { super() }
_type() {
return this.value
}
}
export class AnonymousInterface extends TsType {
constructor(private props: InterfaceProperty[]) {
super()
export class Array extends TsType {
constructor(private type?: TsType) { super() }
_type(settings: TsTypeSettings) {
return `${(this.type || new Any()).toSafeType(settings)}[]`
}
toString() {
return `{
${this.props.join('\n')}
}`
}
export class Intersection extends TsType {
constructor(protected data: TsType[]) {
super()
}
isSimpleType() { return this.data.filter(_ => !(_ instanceof Void)).length <= 1; }
_type(settings: TsTypeSettings) {
return this.data
.filter(_ => !(_ instanceof Void))
.map(_ => _.toSafeType(settings))
.join('&')
}
toSafeType(settings: TsTypeSettings) {
return `${this.toType(settings)}`;
}
}
export class Union extends Intersection {
isSimpleType() { return this.data.length <= 1; }
_type(settings: TsTypeSettings) {
return this.data
.map(_ => _.toSafeType(settings))
.join('|')
}
}
export class Interface extends TsType {
constructor(private data: {name: string, description?: string, props: InterfaceProperty[]}) {
constructor(private props: TsProp[]) {
super()
}
get name (){ return this.data.name }
private toBlockComment(a: string) {
return `/*
${a}
*/
`
static reference(id: string) {
let ret = new Interface([]);
ret.id = id;
return ret;
}
toString(): string {
return `${
this.data.description
? this.toBlockComment(this.data.description)
: ''
}interface ${this.data.name} {
${this.data.props.join('\n')}
}`
protected _type(settings: TsTypeSettings, declaration: boolean = false) {
let id = this.safeId();
return declaration || !id ? `{
${this.props.map(_ => {
let decl = _.name;
if (!_.required)
decl += '?';
decl += ": " + _.type.toType(settings);
if (settings.endPropertyWithSemicolon)
decl += ';';
if (settings.propertyDescription && _.type.description)
decl += ' // ' + _.type.description;
return decl;
}).join('\n')}
}` : id;
}
}
isSimpleType() { return false; }
toDeclaration(settings: TsTypeSettings): string {
if (settings.useInterfaceDeclaration)
return `${this.toBlockComment(settings)}interface ${this.safeId()} ${this._type(settings, true)}`
else
return this._toDeclaration(`type ${this.safeId()} = ${this._type(settings, true)}`, settings);
}
}

@@ -7,11 +7,19 @@ {

"preserveConstEnums": true,
"outDir": "dist",
"outDir": "out",
"sourceMap": true,
"target": "es6"
"target": "es6",
"strictNullChecks": true,
"types": [
"node",
"mocha"
]
},
"files": [
"./typings/main.d.ts",
"./src/JSONSchema.d.ts",
"./src/index.ts"
"src/JSONSchema.d.ts",
"src/index.ts",
"test/test.ts"
],
"include": [
"test/cases/*.ts"
]
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc