@backland/schema
Version:
TypeScript schema declaration and validation library with static type inference
276 lines (275 loc) • 7.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.objectToJSON = objectToJSON;
var _utils = require("@backland/utils");
var _ObjectType = require("./ObjectType");
var _AliasField = require("./fields/AliasField");
var _LiteralField = require("./fields/LiteralField");
var _PhoneField = require("./fields/PhoneField");
var _isHiddenFieldName = require("./isHiddenFieldName");
var _parseTypeName = require("./parseTypeName");
/**
* Converts an object to a json-schema format
* @param parentName
* @param object
* @param options
*/
function objectToJSON(parentName, object, options = {
ignoreDefaultValues: true
}) {
let definition;
if ((0, _ObjectType.isObject)(object)) {
definition = object.definition;
} else {
// @ts-ignore
definition = (0, _ObjectType.createObjectType)(object).definition;
}
const description = (0, _ObjectType.isObject)(object) ? object.description : undefined;
const topProperties = {};
const required = [];
const topJSON = {
additionalProperties: false,
properties: topProperties,
required,
title: parentName,
type: 'object'
};
if (description) {
topJSON.description = description;
}
const composers = [];
(0, _utils.getKeys)(definition).forEach(fieldName => {
if ((0, _isHiddenFieldName.isHiddenFieldName)(fieldName)) return;
const field = definition[fieldName];
if (field.hidden) return;
const parsedField = parseGraphQLField({
field,
fieldName,
options,
parentName
});
if (parsedField.required) {
required.push(fieldName);
}
topProperties[fieldName] = parsedField.jsonItem;
composers.push(...parsedField.composers);
});
composers.forEach(composer => {
const value = composer.compose(topProperties);
(0, _utils.setByPath)(topProperties, composer.key, value);
});
return topJSON;
}
function parseGraphQLField(params) {
let {
field,
fieldName,
parentName,
options
} = params;
field = (0, _ObjectType.parseField)(field);
const {
ignoreDefaultValues
} = options;
let {
type,
list,
optional,
description,
defaultValue
} = field;
const composers = [];
(0, _utils.nonNullValues)({
type
});
let required = !optional && type !== 'undefined';
const jsonItem = {
// title, // will generate extra types in typescript
};
if (ignoreDefaultValues) {
defaultValue = undefined;
}
if (defaultValue !== undefined) {
required = false;
jsonItem.default = defaultValue;
}
if (description) {
jsonItem.description = description;
}
if (type === 'array' || list) {
const parsedListItem = parseGraphQLField({
field: type === 'array' ? (0, _ObjectType.parseObjectField)(fieldName, field.def.of) : {
...field,
list: false
},
fieldName,
options,
parentName
});
return {
composers,
jsonItem: {
items: parsedListItem.jsonItem,
type: 'array'
},
required: !optional
};
}
const typeParsers = {
ID() {
jsonItem.type = 'string';
jsonItem.tsType = 'ID';
},
alias() {
const type = (0, _ObjectType.__getCachedFieldInstance)(field);
_AliasField.AliasField.assert(type);
composers.push({
compose(parent) {
if (typeof type.def === 'string') {
return (0, _utils.getByPath)(parent, type.def);
} else {
return parseGraphQLField({
field: type.utils.fieldType.asFinalFieldDef,
fieldName,
options,
parentName
}).jsonItem;
}
},
key: fieldName
});
},
any() {
jsonItem.type = 'any';
},
array() {
// handled above
},
boolean() {
jsonItem.type = 'boolean';
},
cursor() {
jsonItem.type = 'object';
jsonItem.tsType = 'Cursor';
},
date() {
jsonItem.type = 'string';
jsonItem.format = 'date-time';
jsonItem.tsType = 'Date';
},
email() {
jsonItem.type = 'string';
jsonItem.tsType = 'Email';
},
enum() {
const def = field.def;
(0, _utils.expectedType)({
def
}, 'array');
if (def.length == 1) {
jsonItem.const = def[0];
} else {
jsonItem.type = 'string';
jsonItem.enum = def;
}
},
float() {
jsonItem.type = 'number';
},
int() {
jsonItem.type = 'integer';
},
literal() {
if (!_LiteralField.LiteralField.isFinalTypeDef(field)) throw 'err';
const parsed = field.def['__o.proto__'] === 'String' ? field.def.value : _utils.BJSON.parse(field.def.value);
jsonItem.const = parsed;
const tsType = _utils.BJSON.stringify(parsed, {
handler: ({
serializer,
value
}) => {
var _serializer$formatter;
const typeName = (0, _utils.getTypeName)(value);
if (['Object', 'Array'].includes(typeName)) return;
if (typeName === 'String') return JSON.stringify(value);
if (typeName === 'Number') return value;
return (serializer === null || serializer === void 0 ? void 0 : (_serializer$formatter = serializer.formatter) === null || _serializer$formatter === void 0 ? void 0 : _serializer$formatter.tsName(value)) || typeName;
},
quoteValues: str => `${str}`
});
jsonItem.tsType = tsType;
},
meta() {},
null() {
jsonItem.type = 'null';
},
object() {
const objectName = (0, _parseTypeName.parseTypeName)({
field,
fieldName: '',
parentName: parentName || ''
});
Object.assign(jsonItem, objectToJSON(objectName, field.def, options), {
title: ''
});
},
phone() {
Object.assign(jsonItem, {
maxLength: 20,
minLength: 10,
pattern: _PhoneField.E164_PHONE_REGEX.toString()
});
jsonItem.tsType = 'Phone';
},
record() {
if (field.type !== 'record' || !field.def) {
throw new _utils.RuntimeError(`invalid record field definition.`, {
fieldDef: field
});
}
jsonItem.type = 'object';
},
string() {
jsonItem.type = 'string';
},
ulid() {
jsonItem.type = 'string';
jsonItem.tsType = 'Ulid';
},
undefined() {
jsonItem.type = 'null';
},
union() {
const def = field.def;
(0, _utils.expectedType)({
def
}, 'array');
jsonItem.anyOf = def.map(type => {
return parseGraphQLField({
field: type,
fieldName,
options,
parentName
}).jsonItem;
});
},
unknown() {
jsonItem.type = 'any';
jsonItem.tsType = 'unknown';
}
};
if (!typeParsers[type]) {
throw new _utils.RuntimeError(`invalid field type ${type}`, {
field
}, 0, 20);
}
typeParsers[type]();
return {
composers,
jsonItem,
required
};
}
//# sourceMappingURL=objectToJSON.js.map