json-schema-to-typescript
Advanced tools
Comparing version 2.4.1 to 2.4.2
/// <reference types="node" /> | ||
import { JSONSchema } from './JSONSchema'; | ||
import { TsType } from './TsTypes'; | ||
export declare function compile(schema: JSONSchema, path: string | undefined, settings?: TsType.TsTypeSettings): string; | ||
export interface Settings { | ||
declareReferenced?: boolean; | ||
endPropertyWithSemicolon?: boolean; | ||
endTypeWithSemicolon?: boolean; | ||
useConstEnums?: boolean; | ||
useFullReferencePathAsName?: boolean; | ||
} | ||
export declare function compile(schema: JSONSchema, path: string | undefined, settings?: Settings): string; | ||
export declare function compileFromFile(inputFilename: string): Promise<string | NodeJS.ErrnoException>; |
"use strict"; | ||
var TsTypes_1 = require('./TsTypes'); | ||
var TsType = require('./TsTypes'); | ||
var fs_1 = require('fs'); | ||
@@ -36,4 +36,3 @@ var lodash_1 = require('lodash'); | ||
this.schema = schema; | ||
var path = path_1.resolve(filePath); | ||
this.filePath = path_1.parse(path); | ||
this.filePath = path_1.parse(path_1.resolve(filePath)); | ||
this.declarations = new Map; | ||
@@ -118,5 +117,5 @@ this.namedEnums = new Map; | ||
var contents = tryFn(function () { return JSON.parse(file.toString()); }, function () { throw new TypeError("Referenced local schema \"" + fullPath + "\" contains malformed JSON"); }); | ||
var targetType = this.toTsType(contents, propName, false, true); | ||
var targetType = this.toTsType(contents, propName, true); | ||
var id = targetType.id | ||
? targetType.toSafeType(this.settings) | ||
? targetType.toType(this.settings) | ||
: path_1.parse(fullPath).name; | ||
@@ -126,3 +125,3 @@ if (this.settings.declareReferenced) { | ||
} | ||
return new TsTypes_1.TsType.Reference(id); | ||
return new TsType.Reference(id); | ||
}; | ||
@@ -133,3 +132,3 @@ // eg. "#/definitions/diskDevice" => ["definitions", "diskDevice"] | ||
if (refPath === '#' || refPath === '#/') { | ||
return TsTypes_1.TsType.Interface.reference(this.id); | ||
return TsType.Interface.reference(this.id); | ||
} | ||
@@ -140,13 +139,13 @@ if (refPath[0] !== '#') { | ||
var parts = refPath.slice(2).split('/'); | ||
var ret = this.settings.declareReferenced ? this.declarations.get(parts.join('/')) : undefined; | ||
if (!ret) { | ||
var cur = this.schema; | ||
for (var 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)); | ||
var existingRef = this.declarations.get(parts.join('/')); | ||
// resolve existing declaration? | ||
if (existingRef) { | ||
return existingRef; | ||
} | ||
return ret; | ||
// resolve from elsewhere in the schema | ||
var type = this.toTsType(lodash_1.get(this.schema, parts.join('.'))); | ||
if (this.settings.declareReferenced || !type.isSimpleType()) { | ||
this.declareType(type, parts.join('/'), this.settings.useFullReferencePathAsName ? parts.join('/') : lodash_1.last(parts)); | ||
} | ||
return type; | ||
}; | ||
@@ -158,24 +157,7 @@ Compiler.prototype.declareType = function (type, refPath, id) { | ||
}; | ||
Compiler.prototype.toStringLiteral = function (a) { | ||
var _this = this; | ||
switch (typeof a) { | ||
case 'boolean': | ||
case 'number': | ||
case 'string': | ||
return new TsTypes_1.TsType.Literal(a); | ||
default: return new TsTypes_1.TsType.Interface(lodash_1.map(a, function (v, k) { | ||
return { | ||
name: k, | ||
required: true, | ||
type: _this.toStringLiteral(v) | ||
}; | ||
})); | ||
} | ||
}; | ||
Compiler.prototype.generateEnumName = function (rule, propName) { | ||
return rule.id || propName || "Enum" + this.namedEnums.size; | ||
}; | ||
Compiler.prototype.generateTsType = function (rule, propName, isTop, isReference) { | ||
Compiler.prototype.generateTsType = function (rule, propName, isReference) { | ||
var _this = this; | ||
if (isTop === void 0) { isTop = false; } | ||
if (isReference === void 0) { isReference = false; } | ||
@@ -187,26 +169,26 @@ switch (this.getRuleType(rule)) { | ||
case RuleType.Enum: | ||
return new TsTypes_1.TsType.Union(rule.enum.map(function (_) { return new TsTypes_1.TsType.Literal(_); })); | ||
return new TsType.Union(rule.enum.map(function (_) { return new TsType.Literal(_); })); | ||
case RuleType.NamedEnum: | ||
Compiler.validateNamedEnum(rule); | ||
var name = this.generateEnumName(rule, propName); | ||
var tsEnum = new TsTypes_1.TsType.Enum(name, lodash_1.zip(rule.tsEnumNames, rule.enum).map(function (_) { return new TsTypes_1.TsType.EnumValue(_); })); | ||
var tsEnum = new TsType.Enum(name, lodash_1.zip(rule.tsEnumNames, rule.enum).map(function (_) { return new TsType.EnumValue(_); })); | ||
this.namedEnums.set(name, tsEnum); | ||
return tsEnum; | ||
case RuleType.Any: return new TsTypes_1.TsType.Any; | ||
case RuleType.Literal: return new TsTypes_1.TsType.Literal(rule); | ||
case RuleType.TypedArray: return new TsTypes_1.TsType.Array(this.toTsType(rule.items)); | ||
case RuleType.Array: return new TsTypes_1.TsType.Array; | ||
case RuleType.Boolean: return new TsTypes_1.TsType.Boolean; | ||
case RuleType.Null: return new TsTypes_1.TsType.Null; | ||
case RuleType.Number: return new TsTypes_1.TsType.Number; | ||
case RuleType.Object: return new TsTypes_1.TsType.Object; | ||
case RuleType.String: return new TsTypes_1.TsType.String; | ||
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)); | ||
case RuleType.Array: return new TsType.Array; | ||
case RuleType.Boolean: return new TsType.Boolean; | ||
case RuleType.Null: return new TsType.Null; | ||
case RuleType.Number: return new TsType.Number; | ||
case RuleType.Object: return new TsType.Object; | ||
case RuleType.String: return new TsType.String; | ||
case RuleType.AllOf: | ||
return new TsTypes_1.TsType.Intersection(rule.allOf.map(function (_) { return _this.toTsType(_); })); | ||
return new TsType.Intersection(rule.allOf.map(function (_) { return _this.toTsType(_); })); | ||
case RuleType.AnyOf: | ||
return new TsTypes_1.TsType.Union(rule.anyOf.map(function (_) { return _this.toTsType(_); })); | ||
return new TsType.Union(rule.anyOf.map(function (_) { return _this.toTsType(_); })); | ||
case RuleType.Reference: | ||
return this.resolveRef(rule.$ref, propName); | ||
case RuleType.Union: | ||
return new TsTypes_1.TsType.Union(rule.type.map(function (_) { return _this.toTsType({ type: _ }); })); | ||
return new TsType.Union(rule.type.map(function (_) { return _this.toTsType({ type: _ }); })); | ||
} | ||
@@ -223,6 +205,5 @@ throw new Error('Unknown rule:' + rule.toString()); | ||
}; | ||
Compiler.prototype.toTsType = function (rule, propName, isTop, isReference) { | ||
if (isTop === void 0) { isTop = false; } | ||
Compiler.prototype.toTsType = function (rule, propName, isReference) { | ||
if (isReference === void 0) { isReference = false; } | ||
var type = this.generateTsType(rule, propName, isTop, isReference); | ||
var type = this.generateTsType(rule, propName, isReference); | ||
if (!type.id) { | ||
@@ -249,3 +230,3 @@ // the type is not declared, let's check if we should declare it or keep it inline | ||
if ('default' in schema) | ||
return new TsTypes_1.TsType.Null; | ||
return new TsType.Null; | ||
} | ||
@@ -255,4 +236,4 @@ if (this.supportsAdditionalProperties(copy)) { | ||
if (short && props.length === 0) | ||
return new TsTypes_1.TsType.Any; | ||
var type = short ? new TsTypes_1.TsType.Any : this.toTsType(copy.additionalProperties); | ||
return new TsType.Any; | ||
var type = short ? new TsType.Any : this.toTsType(copy.additionalProperties); | ||
props.push({ | ||
@@ -262,7 +243,13 @@ name: '[k: string]', | ||
type: type | ||
}); | ||
}); // TODO: fix type | ||
} | ||
return new TsTypes_1.TsType.Interface(props); | ||
return new TsType.Interface(props); | ||
}; | ||
Compiler.DEFAULT_SETTINGS = TsTypes_1.TsType.DEFAULT_SETTINGS; | ||
Compiler.DEFAULT_SETTINGS = { | ||
declareReferenced: true, | ||
endPropertyWithSemicolon: true, | ||
endTypeWithSemicolon: true, | ||
useConstEnums: true, | ||
useFullReferencePathAsName: false | ||
}; | ||
Compiler.DEFAULT_SCHEMA = { | ||
@@ -269,0 +256,0 @@ additionalProperties: true, |
@@ -1,98 +0,80 @@ | ||
export declare namespace TsType { | ||
interface TsTypeSettings { | ||
declareReferenced?: boolean; | ||
declareSimpleType?: boolean; | ||
endPropertyWithSemicolon?: boolean; | ||
endTypeWithSemicolon?: boolean; | ||
useConstEnums?: boolean; | ||
useFullReferencePathAsName?: boolean; | ||
} | ||
const DEFAULT_SETTINGS: TsTypeSettings; | ||
abstract class TsTypeBase { | ||
id: string; | ||
description?: string; | ||
protected generateComment(string: string): string[]; | ||
protected safeId(): string; | ||
protected toBlockComment(settings: TsTypeSettings): string; | ||
protected _toDeclaration(decl: string, settings: TsTypeSettings): string; | ||
protected abstract _type(settings: TsTypeSettings): string; | ||
isSimpleType(): boolean; | ||
toDeclaration(settings: TsTypeSettings): string; | ||
toSafeType(settings: TsTypeSettings): string; | ||
toType(settings: TsTypeSettings): string; | ||
toString(): string; | ||
} | ||
interface TsProp { | ||
name: string; | ||
required: boolean; | ||
type: TsTypeBase; | ||
} | ||
class Any extends TsTypeBase { | ||
_type(): string; | ||
} | ||
class String extends TsTypeBase { | ||
_type(): string; | ||
} | ||
class Boolean extends TsTypeBase { | ||
_type(): string; | ||
} | ||
class Number extends TsTypeBase { | ||
_type(): string; | ||
} | ||
class Object extends TsTypeBase { | ||
_type(): string; | ||
} | ||
class Null extends TsTypeBase { | ||
_type(): string; | ||
} | ||
class Literal extends TsTypeBase { | ||
private value; | ||
constructor(value: any); | ||
_type(): string; | ||
} | ||
class Reference extends TsTypeBase { | ||
private value; | ||
constructor(value: string); | ||
_type(): string; | ||
} | ||
class EnumValue { | ||
identifier: string; | ||
value: string; | ||
constructor(enumValues: string[]); | ||
toDeclaration(): string; | ||
toString(): string; | ||
} | ||
class Enum extends TsTypeBase { | ||
id: string; | ||
enumValues: EnumValue[]; | ||
constructor(id: string, enumValues: EnumValue[]); | ||
isSimpleType(): boolean; | ||
_type(settings: TsTypeSettings): string; | ||
toSafeType(settings: TsTypeSettings): string; | ||
toDeclaration(settings: TsTypeSettings): string; | ||
} | ||
class Array extends TsTypeBase { | ||
private type; | ||
constructor(type?: TsTypeBase); | ||
_type(settings: TsTypeSettings): string; | ||
} | ||
class Intersection extends TsTypeBase { | ||
protected data: TsTypeBase[]; | ||
constructor(data: TsTypeBase[]); | ||
isSimpleType(): boolean; | ||
_type(settings: TsTypeSettings): string; | ||
toSafeType(settings: TsTypeSettings): string; | ||
} | ||
class Union extends Intersection { | ||
isSimpleType(): boolean; | ||
_type(settings: TsTypeSettings): string; | ||
} | ||
class Interface extends TsTypeBase { | ||
private props; | ||
constructor(props: TsProp[]); | ||
static reference(id: string): Interface; | ||
protected _type(settings: TsTypeSettings): string; | ||
isSimpleType(): boolean; | ||
toDeclaration(settings: TsTypeSettings): string; | ||
} | ||
import { Settings } from './index'; | ||
export declare abstract class TsType<T> { | ||
protected value: T; | ||
id: string; | ||
description?: string; | ||
constructor(value: T); | ||
protected safeId(): string; | ||
protected toBlockComment(): string; | ||
isSimpleType(): boolean; | ||
toDeclaration(settings: Settings): string; | ||
toType(settings: Settings): string; | ||
abstract toString(settings: Settings): string; | ||
} | ||
export interface TsProp<T> { | ||
name: string; | ||
required: boolean; | ||
type: TsType<T>; | ||
} | ||
export declare class Any extends TsType<void> { | ||
constructor(); | ||
toString(): string; | ||
} | ||
export declare class String extends TsType<void> { | ||
constructor(); | ||
toString(): string; | ||
} | ||
export declare class Boolean extends TsType<void> { | ||
constructor(); | ||
toString(): string; | ||
} | ||
export declare class Number extends TsType<void> { | ||
constructor(); | ||
toString(): string; | ||
} | ||
export declare class Object extends TsType<void> { | ||
constructor(); | ||
toString(): string; | ||
} | ||
export declare class Null extends TsType<void> { | ||
constructor(); | ||
toString(): string; | ||
} | ||
export declare class Literal<T> extends TsType<T> { | ||
toString(): string; | ||
} | ||
export declare class Reference extends TsType<string> { | ||
toString(): string; | ||
} | ||
export declare class EnumValue extends TsType<string> { | ||
identifier: string; | ||
value: string; | ||
constructor([identifier, value]: string[]); | ||
toDeclaration(): string; | ||
toString(): string; | ||
} | ||
export declare class Enum extends TsType<EnumValue[]> { | ||
id: string; | ||
constructor(id: string, value: EnumValue[]); | ||
isSimpleType(): boolean; | ||
toString(settings: Settings): string; | ||
toDeclaration(settings: Settings): string; | ||
} | ||
export declare class Array extends TsType<TsType<any>> { | ||
constructor(value?: TsType<any>); | ||
toString(settings: Settings): string; | ||
} | ||
export declare class Intersection<T> extends TsType<TsType<T>[]> { | ||
isSimpleType(): boolean; | ||
toString(settings: Settings): string; | ||
} | ||
export declare class Union<T> extends TsType<TsType<T>[]> { | ||
isSimpleType(): boolean; | ||
toString(settings: Settings): string; | ||
} | ||
export declare class Interface extends TsType<TsProp<any>[]> { | ||
static reference(id: string): Interface; | ||
toString(settings: Settings): string; | ||
isSimpleType(): boolean; | ||
toDeclaration(settings: Settings): string; | ||
} |
@@ -12,253 +12,220 @@ "use strict"; | ||
var INDENT_STRING = ' '; | ||
var TsType; | ||
(function (TsType) { | ||
TsType.DEFAULT_SETTINGS = { | ||
declareReferenced: true, | ||
declareSimpleType: false, | ||
endPropertyWithSemicolon: true, | ||
endTypeWithSemicolon: true, | ||
useConstEnums: true, | ||
useFullReferencePathAsName: false | ||
var TsType = (function () { | ||
function TsType(value) { | ||
this.value = value; | ||
} | ||
TsType.prototype.safeId = function () { | ||
return nameToTsSafeName(this.id); | ||
}; | ||
var TsTypeBase = (function () { | ||
function TsTypeBase() { | ||
} | ||
TsTypeBase.prototype.generateComment = function (string) { | ||
return [ | ||
COMMENT_START | ||
].concat(string.split('\n').map(function (_) { return COMMENT_INDENT + _; }), [ | ||
COMMENT_END | ||
]); | ||
}; | ||
TsTypeBase.prototype.safeId = function () { | ||
return nameToTsSafeName(this.id); | ||
}; | ||
TsTypeBase.prototype.toBlockComment = function (settings) { | ||
return this.description && !this.isSimpleType() | ||
? this.generateComment(this.description).join('\n') + "\n" | ||
: ''; | ||
}; | ||
TsTypeBase.prototype._toDeclaration = function (decl, settings) { | ||
return this.toBlockComment(settings) + decl + (settings.endTypeWithSemicolon ? ';' : ''); | ||
}; | ||
TsTypeBase.prototype.isSimpleType = function () { return true; }; | ||
TsTypeBase.prototype.toDeclaration = function (settings) { | ||
return this._toDeclaration("export type " + this.safeId() + " = " + this._type(settings), settings); | ||
}; | ||
TsTypeBase.prototype.toSafeType = function (settings) { | ||
return this.toType(settings); | ||
}; | ||
TsTypeBase.prototype.toType = function (settings) { | ||
return this.safeId() || this._type(settings); | ||
}; | ||
TsTypeBase.prototype.toString = function () { | ||
return this._type(TsType.DEFAULT_SETTINGS); | ||
}; | ||
return TsTypeBase; | ||
}()); | ||
TsType.TsTypeBase = TsTypeBase; | ||
var Any = (function (_super) { | ||
__extends(Any, _super); | ||
function Any() { | ||
_super.apply(this, arguments); | ||
} | ||
Any.prototype._type = function () { | ||
return 'any'; | ||
}; | ||
return Any; | ||
}(TsTypeBase)); | ||
TsType.Any = Any; | ||
var String = (function (_super) { | ||
__extends(String, _super); | ||
function String() { | ||
_super.apply(this, arguments); | ||
} | ||
String.prototype._type = function () { | ||
return 'string'; | ||
}; | ||
return String; | ||
}(TsTypeBase)); | ||
TsType.String = String; | ||
var Boolean = (function (_super) { | ||
__extends(Boolean, _super); | ||
function Boolean() { | ||
_super.apply(this, arguments); | ||
} | ||
Boolean.prototype._type = function () { | ||
return 'boolean'; | ||
}; | ||
return Boolean; | ||
}(TsTypeBase)); | ||
TsType.Boolean = Boolean; | ||
var Number = (function (_super) { | ||
__extends(Number, _super); | ||
function Number() { | ||
_super.apply(this, arguments); | ||
} | ||
Number.prototype._type = function () { | ||
return 'number'; | ||
}; | ||
return Number; | ||
}(TsTypeBase)); | ||
TsType.Number = Number; | ||
var Object = (function (_super) { | ||
__extends(Object, _super); | ||
function Object() { | ||
_super.apply(this, arguments); | ||
} | ||
Object.prototype._type = function () { | ||
return 'Object'; | ||
}; | ||
return Object; | ||
}(TsTypeBase)); | ||
TsType.Object = Object; | ||
var Null = (function (_super) { | ||
__extends(Null, _super); | ||
function Null() { | ||
_super.apply(this, arguments); | ||
} | ||
Null.prototype._type = function () { | ||
return 'null'; | ||
}; | ||
return Null; | ||
}(TsTypeBase)); | ||
TsType.Null = Null; | ||
var Literal = (function (_super) { | ||
__extends(Literal, _super); | ||
function Literal(value) { | ||
_super.call(this); | ||
this.value = value; | ||
} | ||
Literal.prototype._type = function () { | ||
return JSON.stringify(this.value); | ||
}; | ||
return Literal; | ||
}(TsTypeBase)); | ||
TsType.Literal = Literal; | ||
var Reference = (function (_super) { | ||
__extends(Reference, _super); | ||
function Reference(value) { | ||
_super.call(this); | ||
this.value = value; | ||
} | ||
Reference.prototype._type = function () { return this.value; }; | ||
return Reference; | ||
}(TsTypeBase)); | ||
TsType.Reference = Reference; | ||
var EnumValue = (function () { | ||
function EnumValue(enumValues) { | ||
this.identifier = enumValues[0]; | ||
this.value = enumValues[1]; | ||
} | ||
EnumValue.prototype.toDeclaration = function () { | ||
// if there is a value associated with the identifier, declare as identifier=value | ||
// else declare as identifier | ||
return "" + this.identifier + (this.value ? (' = ' + this.value) : ''); | ||
}; | ||
EnumValue.prototype.toString = function () { | ||
return "Enum" + this.identifier; | ||
}; | ||
return EnumValue; | ||
}()); | ||
TsType.EnumValue = EnumValue; | ||
var Enum = (function (_super) { | ||
__extends(Enum, _super); | ||
function Enum(id, enumValues) { | ||
_super.call(this); | ||
this.id = id; | ||
this.enumValues = enumValues; | ||
} | ||
Enum.prototype.isSimpleType = function () { return false; }; | ||
Enum.prototype._type = function (settings) { | ||
return this.safeId(); | ||
}; | ||
Enum.prototype.toSafeType = function (settings) { | ||
return "" + this.toType(settings); | ||
}; | ||
Enum.prototype.toDeclaration = function (settings) { | ||
return this.toBlockComment(settings) | ||
+ ("export " + (settings.useConstEnums ? 'const ' : '') + "enum " + this.safeId() + " {") | ||
+ '\n' | ||
+ INDENT_STRING | ||
+ this.enumValues.map(function (_) { return _.toDeclaration(); }).join(",\n" + INDENT_STRING) | ||
+ '\n' | ||
+ '}'; | ||
}; | ||
return Enum; | ||
}(TsTypeBase)); | ||
TsType.Enum = Enum; | ||
var Array = (function (_super) { | ||
__extends(Array, _super); | ||
function Array(type) { | ||
_super.call(this); | ||
this.type = type; | ||
} | ||
Array.prototype._type = function (settings) { | ||
var type = (this.type || new Any()).toSafeType(settings); | ||
return (type.indexOf('|') > -1 || type.indexOf('&') > -1 ? "(" + type + ")" : type) + "[]"; // hacky | ||
}; | ||
return Array; | ||
}(TsTypeBase)); | ||
TsType.Array = Array; | ||
var Intersection = (function (_super) { | ||
__extends(Intersection, _super); | ||
function Intersection(data) { | ||
_super.call(this); | ||
this.data = data; | ||
} | ||
Intersection.prototype.isSimpleType = function () { return this.data.filter(function (_) { return !(_ instanceof Null); }).length <= 1; }; | ||
Intersection.prototype._type = function (settings) { | ||
return this.data | ||
.filter(function (_) { return !(_ instanceof Null); }) | ||
.map(function (_) { return _.toSafeType(settings); }) | ||
.join(' & '); | ||
}; | ||
Intersection.prototype.toSafeType = function (settings) { | ||
return "" + this.toType(settings); | ||
}; | ||
return Intersection; | ||
}(TsTypeBase)); | ||
TsType.Intersection = Intersection; | ||
var Union = (function (_super) { | ||
__extends(Union, _super); | ||
function Union() { | ||
_super.apply(this, arguments); | ||
} | ||
Union.prototype.isSimpleType = function () { return this.data.length <= 1; }; | ||
Union.prototype._type = function (settings) { | ||
return this.data | ||
.map(function (_) { return _.toSafeType(settings); }) | ||
.join(' | '); | ||
}; | ||
return Union; | ||
}(Intersection)); | ||
TsType.Union = Union; | ||
var Interface = (function (_super) { | ||
__extends(Interface, _super); | ||
function Interface(props) { | ||
_super.call(this); | ||
this.props = props; | ||
} | ||
Interface.reference = function (id) { | ||
var ret = new Interface([]); | ||
ret.id = id; | ||
return ret; | ||
}; | ||
Interface.prototype._type = function (settings) { | ||
var _this = this; | ||
return "{\n" | ||
+ (this.props.map(function (_) { | ||
return ("" + INDENT_STRING + (_.type.description | ||
? _this.generateComment(_.type.description).join("\n" + INDENT_STRING) + ("\n" + INDENT_STRING) | ||
: '') + _.name + (_.required ? '' : '?') + ": " + _.type.toType(settings).replace(/\n/g, '\n' + INDENT_STRING) + (settings.endPropertyWithSemicolon ? ';' : '')); | ||
}).join('\n') + "\n}"); | ||
}; | ||
Interface.prototype.isSimpleType = function () { return false; }; | ||
Interface.prototype.toDeclaration = function (settings) { | ||
return this.toBlockComment(settings) + "export interface " + this.safeId() + " " + this._type(settings); | ||
}; | ||
return Interface; | ||
}(TsTypeBase)); | ||
TsType.Interface = Interface; | ||
})(TsType = exports.TsType || (exports.TsType = {})); | ||
TsType.prototype.toBlockComment = function () { | ||
return this.description && !this.isSimpleType() | ||
? generateComment(this.description).join('\n') + "\n" | ||
: ''; | ||
}; | ||
TsType.prototype.isSimpleType = function () { return true; }; | ||
TsType.prototype.toDeclaration = function (settings) { | ||
return this.toBlockComment() | ||
+ ("export type " + this.safeId() + " = " + this.toString(settings)) | ||
+ (settings.endTypeWithSemicolon ? ';' : ''); | ||
}; | ||
TsType.prototype.toType = function (settings) { | ||
return this.safeId() || this.toString(settings); | ||
}; | ||
return TsType; | ||
}()); | ||
exports.TsType = TsType; | ||
var Any = (function (_super) { | ||
__extends(Any, _super); | ||
function Any() { | ||
_super.call(this, undefined); | ||
} | ||
Any.prototype.toString = function () { | ||
return 'any'; | ||
}; | ||
return Any; | ||
}(TsType)); | ||
exports.Any = Any; | ||
var String = (function (_super) { | ||
__extends(String, _super); | ||
function String() { | ||
_super.call(this, undefined); | ||
} | ||
String.prototype.toString = function () { | ||
return 'string'; | ||
}; | ||
return String; | ||
}(TsType)); | ||
exports.String = String; | ||
var Boolean = (function (_super) { | ||
__extends(Boolean, _super); | ||
function Boolean() { | ||
_super.call(this, undefined); | ||
} | ||
Boolean.prototype.toString = function () { | ||
return 'boolean'; | ||
}; | ||
return Boolean; | ||
}(TsType)); | ||
exports.Boolean = Boolean; | ||
var Number = (function (_super) { | ||
__extends(Number, _super); | ||
function Number() { | ||
_super.call(this, undefined); | ||
} | ||
Number.prototype.toString = function () { | ||
return 'number'; | ||
}; | ||
return Number; | ||
}(TsType)); | ||
exports.Number = Number; | ||
var Object = (function (_super) { | ||
__extends(Object, _super); | ||
function Object() { | ||
_super.call(this, undefined); | ||
} | ||
Object.prototype.toString = function () { | ||
return 'Object'; | ||
}; | ||
return Object; | ||
}(TsType)); | ||
exports.Object = Object; | ||
var Null = (function (_super) { | ||
__extends(Null, _super); | ||
function Null() { | ||
_super.call(this, undefined); | ||
} | ||
Null.prototype.toString = function () { | ||
return 'null'; | ||
}; | ||
return Null; | ||
}(TsType)); | ||
exports.Null = Null; | ||
var Literal = (function (_super) { | ||
__extends(Literal, _super); | ||
function Literal() { | ||
_super.apply(this, arguments); | ||
} | ||
Literal.prototype.toString = function () { | ||
return JSON.stringify(this.value); | ||
}; | ||
return Literal; | ||
}(TsType)); | ||
exports.Literal = Literal; | ||
var Reference = (function (_super) { | ||
__extends(Reference, _super); | ||
function Reference() { | ||
_super.apply(this, arguments); | ||
} | ||
Reference.prototype.toString = function () { return this.value; }; | ||
return Reference; | ||
}(TsType)); | ||
exports.Reference = Reference; | ||
var EnumValue = (function (_super) { | ||
__extends(EnumValue, _super); | ||
function EnumValue(_a) { | ||
var identifier = _a[0], value = _a[1]; | ||
_super.call(this, value); | ||
this.identifier = identifier; | ||
} | ||
EnumValue.prototype.toDeclaration = function () { | ||
// if there is a value associated with the identifier, declare as identifier=value | ||
// else declare as identifier | ||
return "" + this.identifier + (this.value ? (' = ' + this.value) : ''); | ||
}; | ||
EnumValue.prototype.toString = function () { | ||
return "Enum" + this.identifier; | ||
}; | ||
return EnumValue; | ||
}(TsType)); | ||
exports.EnumValue = EnumValue; | ||
var Enum = (function (_super) { | ||
__extends(Enum, _super); | ||
function Enum(id, value) { | ||
_super.call(this, value); | ||
this.id = id; | ||
} | ||
Enum.prototype.isSimpleType = function () { return false; }; | ||
Enum.prototype.toString = function (settings) { | ||
return this.safeId(); | ||
}; | ||
Enum.prototype.toDeclaration = function (settings) { | ||
return this.toBlockComment() | ||
+ ("export " + (settings.useConstEnums ? 'const ' : '') + "enum " + this.safeId() + " {") | ||
+ '\n' | ||
+ INDENT_STRING | ||
+ this.value.map(function (_) { return _.toDeclaration(); }).join(",\n" + INDENT_STRING) | ||
+ '\n' | ||
+ '}'; | ||
}; | ||
return Enum; | ||
}(TsType)); | ||
exports.Enum = Enum; | ||
var Array = (function (_super) { | ||
__extends(Array, _super); | ||
function Array(value) { | ||
if (value === void 0) { value = new Any; } | ||
_super.call(this, value); | ||
} | ||
Array.prototype.toString = function (settings) { | ||
var type = this.value.toType(settings); | ||
return (type.indexOf('|') > -1 || type.indexOf('&') > -1 ? "(" + type + ")" : type) + "[]"; // hacky | ||
}; | ||
return Array; | ||
}(TsType)); | ||
exports.Array = Array; | ||
var Intersection = (function (_super) { | ||
__extends(Intersection, _super); | ||
function Intersection() { | ||
_super.apply(this, arguments); | ||
} | ||
Intersection.prototype.isSimpleType = function () { return this.value.length <= 1; }; | ||
Intersection.prototype.toString = function (settings) { | ||
return this.value | ||
.filter(function (_) { return !(_ instanceof Null); }) | ||
.map(function (_) { return _.toType(settings); }) | ||
.join(' & '); | ||
}; | ||
return Intersection; | ||
}(TsType)); | ||
exports.Intersection = Intersection; | ||
var Union = (function (_super) { | ||
__extends(Union, _super); | ||
function Union() { | ||
_super.apply(this, arguments); | ||
} | ||
Union.prototype.isSimpleType = function () { return this.value.length <= 1; }; | ||
Union.prototype.toString = function (settings) { | ||
return this.value | ||
.map(function (_) { return _.toType(settings); }) | ||
.join(' | '); | ||
}; | ||
return Union; | ||
}(TsType)); | ||
exports.Union = Union; | ||
var Interface = (function (_super) { | ||
__extends(Interface, _super); | ||
function Interface() { | ||
_super.apply(this, arguments); | ||
} | ||
Interface.reference = function (id) { | ||
var ret = new Interface([]); | ||
ret.id = id; | ||
return ret; | ||
}; | ||
Interface.prototype.toString = function (settings) { | ||
return "{\n" | ||
+ (this.value.map(function (_) { | ||
return ("" + INDENT_STRING + (_.type.description | ||
? generateComment(_.type.description).join("\n" + INDENT_STRING) + ("\n" + INDENT_STRING) | ||
: '') + _.name + (_.required ? '' : '?') + ": " + _.type.toType(settings).replace(/\n/g, '\n' + INDENT_STRING) // ghetto nested indents | ||
+ (settings.endPropertyWithSemicolon ? ';' : '')); | ||
}).join('\n') + "\n}"); | ||
}; | ||
Interface.prototype.isSimpleType = function () { return false; }; | ||
Interface.prototype.toDeclaration = function (settings) { | ||
return this.toBlockComment() + "export interface " + this.safeId() + " " + this.toString(settings); | ||
}; | ||
return Interface; | ||
}(TsType)); | ||
exports.Interface = Interface; | ||
// eg. | ||
@@ -273,2 +240,9 @@ // foo -> Foo | ||
} | ||
function generateComment(string) { | ||
return [ | ||
COMMENT_START | ||
].concat(string.split('\n').map(function (_) { return COMMENT_INDENT + _; }), [ | ||
COMMENT_END | ||
]); | ||
} | ||
//# sourceMappingURL=TsTypes.js.map |
{ | ||
"name": "json-schema-to-typescript", | ||
"version": "2.4.1", | ||
"version": "2.4.2", | ||
"description": "compile json schema to typescript typings", | ||
@@ -10,4 +10,4 @@ "main": "dist/index.js", | ||
"build-sources": "tsc -p ./tsconfig.json", | ||
"build-tests": "tsc -p ./tsconfig.test.json", | ||
"watch": "tsc -p ./tsconfig.json --watch && tsc -p ./tsconfig.test.json --watch", | ||
"build-tests": "rm -rf ./dist_tests && tsc -p ./tsconfig.test.json", | ||
"watch": "tsc -p ./tsconfig.json --watch & tsc -p ./tsconfig.test.json --watch", | ||
"lint": "tslint -c tslint.json src/*.ts", | ||
@@ -14,0 +14,0 @@ "test": "npm run build-tests && ava", |
@@ -60,5 +60,8 @@ # json-schema-to-typescript [![Build Status][build]](https://circleci.com/gh/bcherny/json-schema-to-typescript) [![npm]](https://www.npmjs.com/package/json-schema-to-typescript) [![mit]](https://opensource.org/licenses/MIT) | ||
import {compileFromFile} from 'json-schema-to-typescript' | ||
fs.writeFileSync('foo.d.ts', await compileFromFile('foo.json')) | ||
fs.writeFileSync('dist/foo.d.ts', await compileFromFile('src/foo.json')) | ||
``` | ||
See [/example](example) for a fully working demo. | ||
## Tests | ||
@@ -65,0 +68,0 @@ |
103
src/index.ts
import { EnumJSONSchema, JSONSchema, NamedEnumJSONSchema } from './JSONSchema' | ||
import { TsType } from './TsTypes' | ||
import * as TsType from './TsTypes' | ||
import { readFile, readFileSync } from 'fs' | ||
import { isPlainObject, last, map, merge, zip } from 'lodash' | ||
import { get, isPlainObject, last, map, merge, zip } from 'lodash' | ||
import { join, parse, ParsedPath, resolve } from 'path' | ||
@@ -14,5 +14,20 @@ | ||
export interface Settings { | ||
declareReferenced?: boolean | ||
endPropertyWithSemicolon?: boolean | ||
endTypeWithSemicolon?: boolean | ||
useConstEnums?: boolean | ||
useFullReferencePathAsName?: boolean | ||
} | ||
class Compiler { | ||
static DEFAULT_SETTINGS = TsType.DEFAULT_SETTINGS | ||
static DEFAULT_SETTINGS: Settings = { | ||
declareReferenced: true, | ||
endPropertyWithSemicolon: true, | ||
endTypeWithSemicolon: true, | ||
useConstEnums: true, | ||
useFullReferencePathAsName: false | ||
} | ||
static DEFAULT_SCHEMA: JSONSchema = { | ||
@@ -28,6 +43,5 @@ additionalProperties: true, | ||
filePath: string | undefined = '', | ||
settings?: TsType.TsTypeSettings | ||
settings?: Settings | ||
) { | ||
let path = resolve(filePath) | ||
this.filePath = parse(path) | ||
this.filePath = parse(resolve(filePath)) | ||
this.declarations = new Map | ||
@@ -37,3 +51,3 @@ this.namedEnums = new Map | ||
this.settings = Object.assign({}, Compiler.DEFAULT_SETTINGS, settings) | ||
this.declareType(this.toTsType(this.schema, '', true), this.id, this.id) | ||
this.declareType(this.toTsType(this.schema, '', true) as TsType.Interface, this.id, this.id) | ||
} | ||
@@ -51,5 +65,5 @@ | ||
private settings: TsType.TsTypeSettings | ||
private settings: Settings | ||
private id: string | ||
private declarations: Map<string, TsType.TsTypeBase> | ||
private declarations: Map<string, TsType.TsType<any>> | ||
private namedEnums: Map<string, TsType.Enum> | ||
@@ -123,3 +137,3 @@ private filePath: ParsedPath | ||
private resolveRefFromLocalFS(refPath: string, propName: string): TsType.TsTypeBase { | ||
private resolveRefFromLocalFS<T>(refPath: string, propName: string): TsType.Reference { | ||
const fullPath = resolve(join(this.filePath.dir, refPath)) | ||
@@ -139,9 +153,9 @@ | ||
) | ||
const targetType = this.toTsType(contents, propName, false, true) | ||
const targetType = this.toTsType(contents, propName, true) | ||
const id = targetType.id | ||
? targetType.toSafeType(this.settings) | ||
? targetType.toType(this.settings) | ||
: parse(fullPath).name | ||
if (this.settings.declareReferenced) { | ||
this.declareType(targetType, id, id) | ||
this.declareType(targetType as TsType.Interface, id, id) | ||
} | ||
@@ -154,3 +168,3 @@ | ||
// only called in case of a $ref type | ||
private resolveRef(refPath: string, propName: string): TsType.TsTypeBase { | ||
private resolveRef(refPath: string, propName: string): TsType.TsType<any> { | ||
if (refPath === '#' || refPath === '#/'){ | ||
@@ -165,17 +179,18 @@ return TsType.Interface.reference(this.id) | ||
const parts = refPath.slice(2).split('/') | ||
let ret = this.settings.declareReferenced ? this.declarations.get(parts.join('/')) : undefined | ||
const existingRef = this.declarations.get(parts.join('/')) | ||
if (!ret) { | ||
let cur: any = this.schema | ||
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)) | ||
// resolve existing declaration? | ||
if (existingRef) { | ||
return existingRef | ||
} | ||
return ret | ||
// resolve from elsewhere in the schema | ||
const type = this.toTsType(get(this.schema, parts.join('.'))) | ||
if (this.settings.declareReferenced || !type.isSimpleType()) { | ||
this.declareType(type as TsType.Interface, parts.join('/'), this.settings.useFullReferencePathAsName ? parts.join('/') : last(parts)) | ||
} | ||
return type | ||
} | ||
private declareType(type: TsType.TsTypeBase, refPath: string, id: string) { | ||
private declareType(type: TsType.Interface, refPath: string, id: string) { | ||
type.id = id | ||
@@ -186,23 +201,2 @@ this.declarations.set(refPath, type) | ||
private toStringLiteral(a: boolean | number | string | Object): TsType.TsTypeBase { | ||
switch (typeof a) { | ||
case 'boolean': | ||
case 'number': | ||
case 'string': | ||
return new TsType.Literal(a) | ||
default: return new TsType.Interface(map( | ||
(a as any), | ||
(v: JSONSchema, k: string) => { | ||
return { | ||
name: k, | ||
required: true, | ||
type: this.toStringLiteral(v) | ||
} | ||
})) | ||
// TODO: support array types? | ||
// TODO: support enums of enums | ||
// TODO: support nulls | ||
} | ||
} | ||
private generateEnumName(rule: JSONSchema, propName: string | undefined): string { | ||
@@ -212,3 +206,3 @@ return rule.id || propName || `Enum${this.namedEnums.size}` | ||
private generateTsType (rule: JSONSchema, propName?: string, isTop: boolean = false, isReference: boolean = false): TsType.TsTypeBase { | ||
private generateTsType (rule: JSONSchema, propName?: string, isReference: boolean = false): TsType.TsType<any> { | ||
switch (this.getRuleType(rule)) { | ||
@@ -267,9 +261,8 @@ case RuleType.AnonymousSchema: | ||
private toTsType( | ||
private toTsType<T>( | ||
rule: JSONSchema, | ||
propName?: string, | ||
isTop: boolean = false, | ||
isReference: boolean = false | ||
): TsType.TsTypeBase { | ||
const type = this.generateTsType(rule, propName, isTop, isReference) | ||
): TsType.TsType<T> { | ||
const type = this.generateTsType(rule, propName, isReference) | ||
if (!type.id) { | ||
@@ -284,3 +277,3 @@ // the type is not declared, let's check if we should declare it or keep it inline | ||
} | ||
private toTsDeclaration(schema: JSONSchema): TsType.TsTypeBase { | ||
private toTsDeclaration(schema: JSONSchema): TsType.Interface | TsType.Null { | ||
const copy = merge({}, Compiler.DEFAULT_SCHEMA, schema) | ||
@@ -308,4 +301,4 @@ const props = map( | ||
required: true, | ||
type: type | ||
}) | ||
type | ||
} as any) // TODO: fix type | ||
} | ||
@@ -319,3 +312,3 @@ return new TsType.Interface(props) | ||
path: string | undefined, | ||
settings?: TsType.TsTypeSettings | ||
settings?: Settings | ||
): string { | ||
@@ -322,0 +315,0 @@ return new Compiler(schema, path, settings).toString() |
@@ -0,1 +1,2 @@ | ||
import { Settings } from './index' | ||
import { camelCase, upperFirst } from 'lodash' | ||
@@ -8,211 +9,170 @@ | ||
export namespace TsType { | ||
export abstract class TsType<T> { | ||
id: string | ||
description?: string | ||
export interface TsTypeSettings { | ||
declareReferenced?: boolean | ||
declareSimpleType?: boolean | ||
endPropertyWithSemicolon?: boolean | ||
endTypeWithSemicolon?: boolean | ||
useConstEnums?: boolean | ||
useFullReferencePathAsName?: boolean | ||
} | ||
constructor(protected value: T) {} | ||
export const DEFAULT_SETTINGS: TsTypeSettings = { | ||
declareReferenced: true, | ||
declareSimpleType: false, | ||
endPropertyWithSemicolon: true, | ||
endTypeWithSemicolon: true, | ||
useConstEnums: true, | ||
useFullReferencePathAsName: false | ||
protected safeId() { | ||
return nameToTsSafeName(this.id) | ||
} | ||
export abstract class TsTypeBase { | ||
id: string | ||
description?: string | ||
protected generateComment(string: string): string[] { | ||
return [ | ||
COMMENT_START, | ||
...string.split('\n').map(_ => COMMENT_INDENT + _), | ||
COMMENT_END | ||
] | ||
} | ||
protected safeId() { | ||
return nameToTsSafeName(this.id) | ||
} | ||
protected toBlockComment(settings: TsTypeSettings) { | ||
return this.description && !this.isSimpleType() | ||
? `${this.generateComment(this.description).join('\n')}\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(`export 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) | ||
} | ||
protected toBlockComment() { | ||
return this.description && !this.isSimpleType() | ||
? `${generateComment(this.description).join('\n')}\n` | ||
: '' | ||
} | ||
export interface TsProp { | ||
name: string | ||
required: boolean | ||
type: TsTypeBase | ||
isSimpleType() { return true } | ||
toDeclaration(settings: Settings): string { | ||
return this.toBlockComment() | ||
+ `export type ${this.safeId()} = ${this.toString(settings)}` | ||
+ (settings.endTypeWithSemicolon ? ';' : '') | ||
} | ||
toType(settings: Settings): string { | ||
return this.safeId() || this.toString(settings) | ||
} | ||
abstract toString(settings: Settings): string | ||
} | ||
export class Any extends TsTypeBase { | ||
_type() { | ||
return 'any' | ||
} | ||
export interface TsProp<T> { | ||
name: string | ||
required: boolean | ||
type: TsType<T> | ||
} | ||
export class Any extends TsType<void> { | ||
constructor() { super(undefined) } | ||
toString() { | ||
return 'any' | ||
} | ||
export class String extends TsTypeBase { | ||
_type() { | ||
return 'string' | ||
} | ||
} | ||
export class String extends TsType<void> { | ||
constructor() { super(undefined) } | ||
toString() { | ||
return 'string' | ||
} | ||
export class Boolean extends TsTypeBase { | ||
_type() { | ||
return 'boolean' | ||
} | ||
} | ||
export class Boolean extends TsType<void> { | ||
constructor() { super(undefined) } | ||
toString() { | ||
return 'boolean' | ||
} | ||
export class Number extends TsTypeBase { | ||
_type() { | ||
return 'number' | ||
} | ||
} | ||
export class Number extends TsType<void> { | ||
constructor() { super(undefined) } | ||
toString() { | ||
return 'number' | ||
} | ||
export class Object extends TsTypeBase { | ||
_type() { | ||
return 'Object' | ||
} | ||
} | ||
export class Object extends TsType<void> { | ||
constructor() { super(undefined) } | ||
toString() { | ||
return 'Object' | ||
} | ||
export class Null extends TsTypeBase { | ||
_type() { | ||
return 'null' | ||
} | ||
} | ||
export class Null extends TsType<void> { | ||
constructor() { super(undefined) } | ||
toString() { | ||
return 'null' | ||
} | ||
export class Literal extends TsTypeBase { | ||
constructor(private value: any) { super() } | ||
_type() { | ||
return JSON.stringify(this.value) | ||
} | ||
} | ||
export class Literal<T> extends TsType<T> { | ||
toString() { | ||
return JSON.stringify(this.value) | ||
} | ||
} | ||
export class Reference extends TsTypeBase { | ||
constructor(private value: string) { super() } | ||
_type() { return this.value } | ||
} | ||
export class Reference extends TsType<string> { | ||
toString() { return this.value } | ||
} | ||
export class EnumValue { | ||
identifier: string | ||
value: string | ||
export class EnumValue extends TsType<string> { | ||
identifier: string | ||
value: string | ||
constructor(enumValues: string[]) { | ||
this.identifier = enumValues[0] | ||
this.value = enumValues[1] | ||
} | ||
constructor([identifier, value]: string[]) { | ||
super(value) | ||
this.identifier = identifier | ||
} | ||
toDeclaration(){ | ||
// if there is a value associated with the identifier, declare as identifier=value | ||
// else declare as identifier | ||
return `${this.identifier}${this.value ? (' = ' + this.value) : ''}` | ||
} | ||
toDeclaration(){ | ||
// if there is a value associated with the identifier, declare as identifier=value | ||
// else declare as identifier | ||
return `${this.identifier}${this.value ? (' = ' + this.value) : ''}` | ||
} | ||
toString(){ | ||
return `Enum${this.identifier}` | ||
} | ||
toString(){ | ||
return `Enum${this.identifier}` | ||
} | ||
} | ||
export class Enum extends TsTypeBase { | ||
constructor(public id: string, public enumValues: EnumValue[]) { | ||
super() | ||
} | ||
isSimpleType() { return false } | ||
_type(settings: TsTypeSettings): string { | ||
return this.safeId() | ||
} | ||
toSafeType(settings: TsTypeSettings) { | ||
return `${this.toType(settings)}` | ||
} | ||
toDeclaration(settings: TsTypeSettings): string { | ||
return this.toBlockComment(settings) | ||
+ `export ${settings.useConstEnums ? 'const ' : ''}enum ${this.safeId()} {` | ||
+ '\n' | ||
+ INDENT_STRING | ||
+ this.enumValues.map(_ => _.toDeclaration()).join(`,\n${INDENT_STRING}`) | ||
+ '\n' | ||
+ '}' | ||
} | ||
export class Enum extends TsType<EnumValue[]> { | ||
constructor(public id: string, value: EnumValue[]) { | ||
super(value) | ||
} | ||
isSimpleType() { return false } | ||
toString(settings: Settings): string { | ||
return this.safeId() | ||
} | ||
toDeclaration(settings: Settings): string { | ||
return this.toBlockComment() | ||
+ `export ${settings.useConstEnums ? 'const ' : ''}enum ${this.safeId()} {` | ||
+ '\n' | ||
+ INDENT_STRING | ||
+ this.value.map(_ => _.toDeclaration()).join(`,\n${INDENT_STRING}`) | ||
+ '\n' | ||
+ '}' | ||
} | ||
} | ||
export class Array extends TsTypeBase { | ||
constructor(private type?: TsTypeBase) { super() } | ||
_type(settings: TsTypeSettings) { | ||
const type = (this.type || new Any()).toSafeType(settings) | ||
return `${type.indexOf('|') > -1 || type.indexOf('&') > -1 ? `(${type})` : type}[]` // hacky | ||
} | ||
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 | ||
} | ||
export class Intersection extends TsTypeBase { | ||
constructor(protected data: TsTypeBase[]) { | ||
super() | ||
} | ||
isSimpleType() { return this.data.filter(_ => !(_ instanceof Null)).length <= 1 } | ||
_type(settings: TsTypeSettings) { | ||
return this.data | ||
.filter(_ => !(_ instanceof Null)) | ||
.map(_ => _.toSafeType(settings)) | ||
.join(' & ') | ||
} | ||
toSafeType(settings: TsTypeSettings) { | ||
return `${this.toType(settings)}` | ||
} | ||
} | ||
export class Intersection<T> extends TsType<TsType<T>[]> { | ||
isSimpleType() { return this.value.length <= 1 } | ||
toString(settings: Settings) { | ||
return this.value | ||
.filter(_ => !(_ instanceof Null)) | ||
.map(_ => _.toType(settings)) | ||
.join(' & ') | ||
} | ||
export class Union extends Intersection { | ||
isSimpleType() { return this.data.length <= 1 } | ||
_type(settings: TsTypeSettings) { | ||
return this.data | ||
.map(_ => _.toSafeType(settings)) | ||
.join(' | ') | ||
} | ||
} | ||
export class Union<T> extends TsType<TsType<T>[]> { | ||
isSimpleType() { return this.value.length <= 1 } | ||
toString(settings: Settings) { | ||
return this.value | ||
.map(_ => _.toType(settings)) | ||
.join(' | ') | ||
} | ||
} | ||
export class Interface extends TsTypeBase { | ||
constructor(private props: TsProp[]) { | ||
super() | ||
} | ||
static reference(id: string) { | ||
let ret = new Interface([]) | ||
ret.id = id | ||
return ret | ||
} | ||
protected _type(settings: TsTypeSettings) { | ||
return `{\n` | ||
+ `${this.props.map(_ => | ||
`${INDENT_STRING}${_.type.description | ||
? this.generateComment(_.type.description).join(`\n${INDENT_STRING}`) + `\n${INDENT_STRING}` | ||
: '' | ||
}${_.name}${_.required ? '' : '?'}: ${ | ||
_.type.toType(settings).replace(/\n/g, '\n' + INDENT_STRING) | ||
}${ | ||
settings.endPropertyWithSemicolon ? ';' : '' | ||
}` | ||
).join('\n')} | ||
export class Interface extends TsType<TsProp<any>[]> { | ||
static reference(id: string) { | ||
let ret = new Interface([]) | ||
ret.id = id | ||
return ret | ||
} | ||
toString(settings: Settings) { | ||
return `{\n` | ||
+ `${this.value.map(_ => | ||
`${INDENT_STRING}${_.type.description | ||
? generateComment(_.type.description).join(`\n${INDENT_STRING}`) + `\n${INDENT_STRING}` | ||
: '' | ||
}${_.name}${_.required ? '' : '?'}: ${ | ||
_.type.toType(settings).replace(/\n/g, '\n' + INDENT_STRING) // ghetto nested indents | ||
}${ | ||
settings.endPropertyWithSemicolon ? ';' : '' | ||
}` | ||
).join('\n')} | ||
}` | ||
} | ||
isSimpleType() { return false } | ||
toDeclaration(settings: TsTypeSettings): string { | ||
return `${this.toBlockComment(settings)}export interface ${this.safeId()} ${this._type(settings)}` | ||
} | ||
} | ||
isSimpleType() { return false } | ||
toDeclaration(settings: Settings): string { | ||
return `${this.toBlockComment()}export interface ${this.safeId()} ${this.toString(settings)}` | ||
} | ||
} | ||
@@ -229,1 +189,9 @@ | ||
} | ||
function generateComment(string: string): string[] { | ||
return [ | ||
COMMENT_START, | ||
...string.split('\n').map(_ => COMMENT_INDENT + _), | ||
COMMENT_END | ||
] | ||
} |
@@ -38,3 +38,2 @@ export var schema = { | ||
export var types = `export interface Foo { | ||
@@ -41,0 +40,0 @@ a: string; |
@@ -33,7 +33,7 @@ export var schema = { | ||
"enum": [1, 2, 3], | ||
"tsEnumNames": ["One","Two","Three"] | ||
"tsEnumNames": ["One", "Two", "Three"] | ||
}, | ||
"impliedNamedIntegerEnum": { | ||
"enum": [4, 5, 6], | ||
"tsEnumNames": ["Four","Five","Six"] | ||
"tsEnumNames": ["Four", "Five", "Six"] | ||
}, | ||
@@ -40,0 +40,0 @@ "impliedHeterogeneousEnum": { |
@@ -150,3 +150,3 @@ export var schema = { | ||
"default": {} | ||
}; | ||
} | ||
@@ -156,3 +156,2 @@ export var configurations = [ | ||
settings: { | ||
declareSimpleType: true | ||
}, | ||
@@ -210,55 +209,3 @@ types: `export type PositiveInteger = number; | ||
}` | ||
}, | ||
{ | ||
settings: { | ||
declareSimpleType: false | ||
}, | ||
types:`export type SimpleTypes = "array" | "boolean" | "integer" | "null" | "number" | "object" | "string"; | ||
/** | ||
* Core schema meta-schema | ||
*/ | ||
export interface 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?: { | ||
[k: string]: HttpJsonSchemaOrgDraft04Schema; | ||
}; | ||
properties?: { | ||
[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; | ||
}` | ||
} | ||
] |
@@ -1,7 +0,6 @@ | ||
import { compile } from '../src/index' | ||
import { compile, Settings } from '../src/index' | ||
import { JSONSchema } from '../src/JSONSchema' | ||
import { TsType } from '../src/TsTypes' | ||
import test from 'ava' | ||
import * as fs from 'fs' | ||
import { find } from 'lodash' | ||
import * as fs from 'fs' | ||
import * as path from 'path' | ||
@@ -14,15 +13,19 @@ | ||
// exporting `const only=true` will only run that test | ||
// exporting `const exclude=true` will not run that test | ||
const only = find(modules, _ => _[1].only) | ||
if (only) { | ||
run(only[1], only[0]) | ||
} else { | ||
modules.forEach(_ => run(_[1], _[0])) | ||
modules | ||
.filter(_ => !_[1].exclude) | ||
.forEach(_ => run(_[1], _[0])) | ||
} | ||
interface TestCase { | ||
configurations?: { settings: TsType.TsTypeSettings, types: string }[] | ||
configurations?: { settings: Settings, types: string }[] | ||
error?: { type: ErrorConstructor } | ||
exclude?: boolean | ||
schema: JSONSchema | ||
settings?: TsType.TsTypeSettings | ||
settings?: Settings | ||
types?: string | ||
@@ -29,0 +32,0 @@ only?: boolean |
@@ -24,3 +24,5 @@ { | ||
"no-unused-variable": true, | ||
"no-var-keyword": true, | ||
"object-literal-key-quotes": [true, "as-needed"], | ||
"object-literal-shorthand": true, | ||
"object-literal-sort-keys": true, | ||
@@ -27,0 +29,0 @@ "one-line": [true, "check-catch", "check-finally", "check-else", "check-open-brace"], |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
140987
95
4246
127
5