UNPKG

@backland/schema

Version:

TypeScript schema declaration and validation library with static type inference

276 lines (275 loc) 7.1 kB
"use strict"; 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