json-schema-ts
Advanced tools
Comparing version 1.0.1 to 1.1.0
46
index.js
@@ -49,8 +49,9 @@ "use strict"; | ||
s.tuple = tuple; | ||
// works with tuple | ||
function items() { | ||
var schema = []; | ||
var schemas = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
schema[_i] = arguments[_i]; | ||
schemas[_i] = arguments[_i]; | ||
} | ||
return schema; | ||
return schemas; | ||
} | ||
@@ -64,2 +65,41 @@ s.items = items; | ||
s.ref = ref; | ||
function anyOf() { | ||
var schemas = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
schemas[_i] = arguments[_i]; | ||
} | ||
if (schemas.length < 1) { | ||
throw new Error('anyOf must be a non-empty array'); | ||
} | ||
return { | ||
'anyOf': schemas, | ||
}; | ||
} | ||
s.anyOf = anyOf; | ||
function oneOf() { | ||
var schemas = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
schemas[_i] = arguments[_i]; | ||
} | ||
if (schemas.length < 1) { | ||
throw new Error('oneOf must be a non-empty array'); | ||
} | ||
return { | ||
'oneOf': schemas, | ||
}; | ||
} | ||
s.oneOf = oneOf; | ||
function allOf() { | ||
var schemas = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
schemas[_i] = arguments[_i]; | ||
} | ||
if (schemas.length < 1) { | ||
throw new Error('allOf must be a non-empty array'); | ||
} | ||
return { | ||
'allOf': schemas, | ||
}; | ||
} | ||
s.allOf = allOf; | ||
})(s = exports.s || (exports.s = {})); |
85
index.ts
@@ -16,2 +16,15 @@ export namespace t { | ||
definitions?: { [K: string]: Schema } | ||
default?: string | number | boolean | null | object | any[]; | ||
// MUST be a non-empty array. Validates successfully against all schemas | ||
allOf?: Schema[]; | ||
// MUST be a non-empty array. Validates successfully against at least one schema | ||
anyOf?: Schema[]; | ||
// MUST be a non-empty array. Validates successfully against exactly one schema | ||
oneOf?: Schema[]; | ||
// MUST be a valid JSON Schema | ||
not?: Schema; | ||
} | ||
@@ -29,2 +42,3 @@ | ||
enum?: Array<E>; | ||
default?: number; | ||
} | ||
@@ -42,2 +56,3 @@ | ||
enum?: Array<E>; | ||
default?: number; | ||
} | ||
@@ -54,2 +69,3 @@ | ||
enum?: Array<E>; | ||
default?: string; | ||
} | ||
@@ -60,2 +76,3 @@ | ||
enum?: Array<E>; | ||
default?: boolean; | ||
} | ||
@@ -66,2 +83,3 @@ | ||
enum?: Array<E>; | ||
default?: null; | ||
} | ||
@@ -80,2 +98,3 @@ | ||
// contains?: Schema; | ||
default?: any[]; | ||
} | ||
@@ -96,2 +115,3 @@ | ||
// contains?: Schema; | ||
default?: any[]; | ||
} | ||
@@ -101,2 +121,20 @@ | ||
export interface AnyOfType<T extends Schema[]> extends BaseType { | ||
anyOf: T; | ||
} | ||
interface GenericAnyOfType extends AnyOfType<Schema[]> {} | ||
export interface OneOfType<T extends Schema[]> extends BaseType { | ||
oneOf: T; | ||
} | ||
interface GenericOneOfType extends OneOfType<Schema[]> {} | ||
export interface AllOfType<T extends Schema[]> extends BaseType { | ||
allOf: T; | ||
} | ||
interface GenericAllOfType extends OneOfType<Schema[]> {} | ||
export type ObjectProperties = {[key: string]: Schema} | ||
@@ -115,2 +153,3 @@ | ||
propertyNames?: Schema; | ||
default?: object; | ||
} | ||
@@ -132,2 +171,5 @@ | ||
| NullType | ||
| GenericAnyOfType | ||
| GenericOneOfType | ||
| GenericAllOfType | ||
| GenericArrayType | ||
@@ -140,3 +182,3 @@ | GenericTupleType | ||
// FIXME: why can't use MapToTSType<T> in TSType? | ||
// FIXME: why can't use MapToTSType<T> in TSType | ||
type MapToTSType<T> = { [K in keyof T]: TSType<T[K]> }; | ||
@@ -152,4 +194,9 @@ | ||
: T extends ArrayType<infer T> ? ArrayTSType<T> | ||
: T extends TupleType<infer T> ? { [K in keyof T]: TSType<T[K]> } | ||
: T extends ObjectType<infer T> ? { [K in keyof T]: TSType<T[K]> } | ||
: T extends TupleType<infer T> ? MapToTSType<T> | ||
: T extends ObjectType<infer T> ? MapToTSType<T> | ||
// tuple to union. See https://github.com/Microsoft/TypeScript/issues/13298#issuecomment-423385929 | ||
: T extends AnyOfType<infer T> ? { [K in keyof T]: TSType<T[K]> }[number] | ||
: T extends OneOfType<infer T> ? { [K in keyof T]: TSType<T[K]> }[number] | ||
// FIXME: how to convert tuple to intersection type? | ||
: T extends AllOfType<infer T> ? { [K in keyof T]: TSType<T[K]> }[number] | ||
: never | ||
@@ -210,4 +257,5 @@ | ||
export function items<T extends t.Schema[]>(...schema: T): T { | ||
return schema; | ||
// works with tuple | ||
export function items<T extends t.Schema[]>(...schemas: T): T { | ||
return schemas; | ||
} | ||
@@ -220,2 +268,29 @@ | ||
} | ||
export function anyOf<T extends t.Schema[]>(...schemas: T): t.AnyOfType<T> { | ||
if (schemas.length < 1) { | ||
throw new Error('anyOf must be a non-empty array'); | ||
} | ||
return { | ||
'anyOf': schemas, | ||
}; | ||
} | ||
export function oneOf<T extends t.Schema[]>(...schemas: T): t.OneOfType<T> { | ||
if (schemas.length < 1) { | ||
throw new Error('oneOf must be a non-empty array'); | ||
} | ||
return { | ||
'oneOf': schemas, | ||
}; | ||
} | ||
export function allOf<T extends t.Schema[]>(...schemas: T): t.AllOfType<T> { | ||
if (schemas.length < 1) { | ||
throw new Error('allOf must be a non-empty array'); | ||
} | ||
return { | ||
'allOf': schemas, | ||
}; | ||
} | ||
} |
{ | ||
"name": "json-schema-ts", | ||
"version": "1.0.1", | ||
"version": "1.1.0", | ||
"description": "JSON schema types for TypeScript", | ||
@@ -12,4 +12,4 @@ "main": "index.js", | ||
"devDependencies": { | ||
"typescript": "^3.2.2" | ||
"typescript": "^3.2.4" | ||
} | ||
} |
@@ -9,2 +9,8 @@ # JSON Schema for TypeScript | ||
## Installation | ||
``` | ||
npm install json-schema-ts | ||
``` | ||
## Examples | ||
@@ -17,2 +23,3 @@ | ||
// personSchema is a valid JSON schema | ||
const personSchema = s.object({ | ||
@@ -26,10 +33,17 @@ 'title': 'person', | ||
'name': s.string(), | ||
// [first name, last name] | ||
'fullName': s.tuple({'items': s.items(s.string(), s.string())}), | ||
'fullName': s.object({'properties': { | ||
'firstName': s.string(), | ||
'lastName': s.string(), | ||
}}), | ||
'age': s.number(), | ||
'friends': s.array({'items': s.string()}), | ||
'sex': s.ref('#/definitions/sex', sex), | ||
'location': s.oneOf( | ||
s.string(), | ||
s.tuple({'items': s.items(s.number(), s.number())}), | ||
) | ||
} | ||
}); | ||
// Infer IPerson from personSchema | ||
type IPerson = t.TSType<typeof personSchema>; | ||
@@ -40,10 +54,20 @@ | ||
// name: string; | ||
// fullName: [string, string]; | ||
// fullName: { | ||
// firstName: string, | ||
// lastName: string, | ||
// }; | ||
// age: number; | ||
// friends: string[]; | ||
// sex: 'male' | 'female'; | ||
// location: string | [number, number]; | ||
// } | ||
``` | ||
## Development | ||
``` | ||
npx tsc -w | ||
``` | ||
## License | ||
MIT. See LICENSE. |
30
test.js
@@ -18,3 +18,5 @@ "use strict"; | ||
{ | ||
var the_string = index_1.s.string({}); | ||
var the_string = index_1.s.string({ | ||
'default': 'test', | ||
}); | ||
meta.equal(true); | ||
@@ -46,3 +48,3 @@ (function (_x) { })('hello'); | ||
{ | ||
var the_boolean = index_1.s.boolean({ 'description': 'this is a boolean' }); | ||
var the_boolean = index_1.s.boolean({ 'description': 'this is a boolean', 'default': false }); | ||
meta.equal(true); | ||
@@ -58,3 +60,5 @@ (function (_x) { })(true); | ||
{ | ||
var the_array = index_1.s.array(); | ||
var the_array = index_1.s.array({ | ||
default: [], | ||
}); | ||
meta.equal(true); | ||
@@ -66,3 +70,5 @@ // meta.equal<T, number[]>(false); | ||
{ | ||
var the_object = index_1.s.object(); | ||
var the_object = index_1.s.object({ | ||
'default': {}, | ||
}); | ||
meta.equal(true); | ||
@@ -94,2 +100,12 @@ // meta.equal<T, {[key: string]: number}>(false); | ||
{ | ||
var string = index_1.s.string({}); | ||
var tuple = index_1.s.tuple({ 'items': index_1.s.items(index_1.s.string(), index_1.s.integer()) }); | ||
var any_of = index_1.s.anyOf(tuple, string); | ||
var one_of = index_1.s.oneOf(string, tuple); | ||
var all_of = index_1.s.allOf(string, tuple); | ||
meta.equal(true); | ||
meta.equal(true); | ||
meta.equal(true); | ||
} | ||
{ | ||
var refObject = index_1.s.object({ | ||
@@ -151,6 +167,10 @@ 'properties': { | ||
// [first name, last name] | ||
'fullName': index_1.s.tuple({ 'items': index_1.s.items(index_1.s.string(), index_1.s.string()) }), | ||
'fullName': index_1.s.object({ 'properties': { | ||
'firstName': index_1.s.string(), | ||
'lastName': index_1.s.string(), | ||
} }), | ||
'age': index_1.s.number(), | ||
'friends': index_1.s.array({ 'items': index_1.s.string() }), | ||
'sex': index_1.s.ref('#/definitions/sex', sex), | ||
'location': index_1.s.oneOf(index_1.s.string(), index_1.s.tuple({ 'items': index_1.s.items(index_1.s.number(), index_1.s.number()) })) | ||
} | ||
@@ -157,0 +177,0 @@ }); |
44
test.ts
@@ -19,3 +19,5 @@ import {t, s} from './index'; | ||
{ | ||
const the_string = s.string({}); | ||
const the_string = s.string({ | ||
'default': 'test', | ||
}); | ||
type T = t.TSType<typeof the_string>; | ||
@@ -57,3 +59,3 @@ meta.equal<T, string>(true); | ||
{ | ||
const the_boolean = s.boolean({'description': 'this is a boolean'}); | ||
const the_boolean = s.boolean({'description': 'this is a boolean', 'default': false}); | ||
type T = t.TSType<typeof the_boolean>; | ||
@@ -73,3 +75,5 @@ meta.equal<T, boolean>(true); | ||
{ | ||
const the_array = s.array(); | ||
const the_array = s.array({ | ||
default: [], | ||
}); | ||
type T = t.TSType<typeof the_array>; | ||
@@ -83,3 +87,5 @@ meta.equal<T, any[]>(true); | ||
{ | ||
const the_object = s.object(); | ||
const the_object = s.object({ | ||
'default': {}, | ||
}); | ||
type T = t.TSType<typeof the_object>; | ||
@@ -130,2 +136,16 @@ meta.equal<T, {}>(true); | ||
{ | ||
const string = s.string({}); | ||
const tuple = s.tuple({'items': s.items(s.string(), s.integer())}); | ||
const any_of = s.anyOf(tuple, string); | ||
const one_of = s.oneOf(string, tuple); | ||
const all_of = s.allOf(string, tuple); | ||
type T1 = t.TSType<typeof any_of>; | ||
type T2 = t.TSType<typeof one_of>; | ||
type T3 = t.TSType<typeof all_of>; | ||
meta.equal<T1, string | number>(true); | ||
meta.equal<T2, string | number>(true); | ||
meta.equal<T3, string | number>(true); | ||
} | ||
{ | ||
const refObject = s.object({ | ||
@@ -191,7 +211,13 @@ 'properties': { | ||
'name': s.string(), | ||
// [first name, last name] | ||
'fullName': s.tuple({'items': s.items(s.string(), s.string())}), | ||
'fullName': s.object({'properties': { | ||
'firstName': s.string(), | ||
'lastName': s.string(), | ||
}}), | ||
'age': s.number(), | ||
'friends': s.array({'items': s.string()}), | ||
'sex': s.ref('#/definitions/sex', sex), | ||
'location': s.oneOf( | ||
s.string(), | ||
s.tuple({'items': s.items(s.number(), s.number())}), | ||
) | ||
} | ||
@@ -205,6 +231,10 @@ }); | ||
name: string; | ||
fullName: [string, string]; | ||
fullName: { | ||
firstName: string, | ||
lastName: string, | ||
}; | ||
age: number; | ||
friends: string[]; | ||
sex: 'male' | 'female'; | ||
location: string | [number, number]; | ||
} | ||
@@ -211,0 +241,0 @@ |
30840
772
69