tcomb-json-schema
Version:
Transforms a JSON Schema to a tcomb type
196 lines (175 loc) • 4.99 kB
JavaScript
;
var t = require('tcomb');
var fcomb = require('fcomb');
var util = require('./util');
var SchemaType = t.enums.of(
'null string number integer boolean object array',
'SchemaType'
);
function and(f, g) {
return f ? fcomb.and(f, g) : g;
}
var types = {
string: function(s) {
if (s.hasOwnProperty('enum')) {
if (t.Array.is(s['enum'])) {
return t.enums.of(s['enum']);
} else {
return t.enums(s['enum']);
}
}
var predicate;
if (s.hasOwnProperty('minLength')) {
predicate = and(predicate, fcomb.minLength(s.minLength));
}
if (s.hasOwnProperty('maxLength')) {
predicate = and(predicate, fcomb.maxLength(s.maxLength));
}
if (s.hasOwnProperty('pattern')) {
var patternMatch = /^\/(.+)\/([gimuy]*)$/.exec(s.pattern);
if (patternMatch === null) {
predicate = and(predicate, fcomb.regexp(new RegExp(s.pattern)));
} else {
predicate = and(
predicate,
fcomb.regexp(new RegExp(patternMatch[1], patternMatch[2]))
);
}
}
if (s.hasOwnProperty('format')) {
t.assert(
formats.hasOwnProperty(s.format),
'[tcomb-json-schema] Missing format ' +
s.format +
', use the (format, predicate) API'
);
if (t.isType(formats[s.format])) {
return formats[s.format];
}
predicate = and(predicate, formats[s.format]);
}
return predicate ? t.subtype(t.String, predicate) : t.String;
},
number: function(s) {
var predicate;
if (s.hasOwnProperty('minimum')) {
predicate = s.exclusiveMinimum
? and(predicate, fcomb.gt(s.minimum))
: and(predicate, fcomb.gte(s.minimum));
}
if (s.hasOwnProperty('maximum')) {
predicate = s.exclusiveMaximum
? and(predicate, fcomb.lt(s.maximum))
: and(predicate, fcomb.lte(s.maximum));
}
if (s.hasOwnProperty('integer') && s.integer) {
predicate = and(predicate, util.isInteger);
}
return predicate ? t.subtype(t.Number, predicate) : t.Number;
},
integer: function(s) {
var predicate;
if (s.hasOwnProperty('minimum')) {
predicate = s.exclusiveMinimum
? and(predicate, fcomb.gt(s.minimum))
: and(predicate, fcomb.gte(s.minimum));
}
if (s.hasOwnProperty('maximum')) {
predicate = s.exclusiveMaximum
? and(predicate, fcomb.lt(s.maximum))
: and(predicate, fcomb.lte(s.maximum));
}
return predicate ? t.subtype(util.Int, predicate) : util.Int;
},
boolean: function() {
return t.Boolean;
},
object: function(s) {
var props = {};
var hasProperties = false;
var required = {};
if (s.required) {
s.required.forEach(function(k) {
required[k] = true;
});
}
for (var k in s.properties) {
if (s.properties.hasOwnProperty(k)) {
hasProperties = true;
var type = transform(s.properties[k]);
props[k] = required[k] || type === t.Boolean ? type : t.maybe(type);
}
}
return hasProperties ? t.struct(props, s.description) : t.Object;
},
array: function(s) {
var type = t.Array;
if (s.hasOwnProperty('items')) {
var items = s.items;
if (t.Object.is(items)) {
type = t.list(transform(s.items));
} else {
return t.tuple(items.map(transform));
}
}
var predicate;
if (s.hasOwnProperty('minItems')) {
predicate = and(predicate, fcomb.minLength(s.minItems));
}
if (s.hasOwnProperty('maxItems')) {
predicate = and(predicate, fcomb.maxLength(s.maxItems));
}
return predicate ? t.subtype(type, predicate) : type;
},
null: function() {
return util.Null;
}
};
var registerTypes = {};
function transform(s) {
t.assert(t.Object.is(s));
if (!s.hasOwnProperty('type')) {
return t.Any;
}
var type = s.type;
if (SchemaType.is(type)) {
return types[type](s);
}
if (t.Array.is(type)) {
return t.union(
type.map(function(type) {
return types[type](s);
})
);
}
if (registerTypes.hasOwnProperty(type)) {
return registerTypes[type];
}
t.fail('[tcomb-json-schema] Unsupported json schema ' + t.stringify(s));
}
var formats = {};
transform.registerFormat = function registerFormat(format, predicateOrType) {
t.assert(
!formats.hasOwnProperty(format),
'[tcomb-json-schema] Duplicated format ' + format
);
formats[format] = predicateOrType;
};
transform.resetFormats = function resetFormats() {
formats = {};
};
transform.registerType = function registerType(typeName, type) {
t.assert(
!registerTypes.hasOwnProperty(typeName),
'[tcomb-json-schema] Duplicated type ' + typeName
);
t.assert(
!SchemaType.is(typeName),
'[tcomb-json-schema] Reserved type ' + typeName
);
registerTypes[typeName] = type;
};
transform.resetTypes = function resetTypes() {
registerTypes = {};
};
module.exports = transform;