UNPKG

@backland/schema

Version:

TypeScript schema declaration and validation library with static type inference

447 lines (442 loc) 13.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CACHED_FIELD_INSTANCE_KEY = void 0; exports.__getCachedFieldInstance = __getCachedFieldInstance; exports._parserHooks = void 0; exports.deleteCachedFieldInstance = deleteCachedFieldInstance; exports.isObjectAsTypeDefinition = isObjectAsTypeDefinition; exports.parseField = parseField; exports.parseFieldDefinitionConfig = parseFieldDefinitionConfig; exports.parseFlattenFieldDefinition = parseFlattenFieldDefinition; exports.parseObjectDefinition = parseObjectDefinition; exports.parseObjectField = parseObjectField; exports.setParserHook = setParserHook; var _utils = require("@backland/utils"); var _GraphType = require("./GraphType/GraphType"); var _ObjectType = require("./ObjectType"); var _fieldInstanceFromDef = require("./fieldInstanceFromDef"); var _FieldType = require("./fields/FieldType"); var _LiteralField = require("./fields/LiteralField"); var _MetaFieldField = require("./fields/MetaFieldField"); var _fieldTypes = require("./fields/fieldTypes"); var _parseStringDefinition = require("./parseStringDefinition"); const _parserHooks = []; exports._parserHooks = _parserHooks; function setParserHook(hook) { _parserHooks.push(hook); function remove() { _parserHooks.find((el, index) => { if (el !== hook) return false; delete _parserHooks[index]; return true; }); return _parserHooks; } return remove; } function parseObjectField(fieldName, definition, options = {}) { let { returnInstance, asString, deep, omitMeta } = options === true ? { returnInstance: true } : options; if (deep !== null && deep !== void 0 && deep.omitMeta) omitMeta = true; if (deep !== null && deep !== void 0 && deep.asString) asString = true; let parsed = parseFieldDefinitionConfig(definition, { deep, omitMeta }); if (_parserHooks.length) { _parserHooks.forEach(cb => cb(parsed)); } if (typeof parsed === 'string') { return parsed; } else { if (asString) return parsed; } const instanceFromDef = (0, _fieldInstanceFromDef.fieldInstanceFromDef)(parsed); setCachedFieldInstance(parsed, instanceFromDef); if (instanceFromDef.def) { parsed.def = instanceFromDef.def; } if (returnInstance) { return instanceFromDef; } if (parsed) return parsed; throw new _utils.RuntimeError(`field "${fieldName}": invalid definition.`, { definition, parsed }); } function parseField(definition) { return parseObjectField('__parseField__', definition); } const stringifiableDefKeys = new Set(['type', 'list', 'optional' // ]); function parseFieldDefinitionConfig(definition, options) { let { deep, asString } = options || {}; if (deep !== null && deep !== void 0 && deep.asString) { asString = true; } function _parseField() { if (_LiteralField.LiteralField.isFinalTypeDef(definition)) { return { def: definition.def, defaultValue: definition.defaultValue, description: definition.description, hidden: definition.hidden, list: !!definition.list, optional: !!definition.optional, type: 'literal' }; } if (_GraphType.GraphType.is(definition)) { const def = parseFieldDefinitionConfig(definition.definition, { deep }); def.hidden = def.hidden || definition.hidden; return def; } if (_GraphType.GraphType.isTypeDefinition(definition)) { const { list = false, optional = false, description, defaultValue, hidden, type: { definition: { type, def, defaultValue: _defaultValue } } } = definition; return { def, defaultValue: defaultValue === undefined ? _defaultValue : defaultValue, description, hidden, list, optional, type }; } if ((0, _parseStringDefinition.isStringFieldDefinition)(definition)) { return (0, _parseStringDefinition.parseStringDefinition)(definition); } if ((0, _FieldType.isFieldInstance)(definition)) { return definition.asFinalFieldDef; } if (isFinalFieldDefinition(definition)) { if (definition.type === 'object') { if (typeof definition.def !== 'object' || !definition.def) { throw new _utils.RuntimeError(`Missing def for object field.`, { definition }); } if ((0, _ObjectType.isObject)(definition.def)) { definition.def = definition.def.definition; } else { definition.def = parseObjectDefinition(definition.def, { deep }).definition; } } if (definition.type === 'union') { let isOptionalUnion = definition.optional; definition.def = definition.def.map(el => { const parsed = parseFieldDefinitionConfig(el, { deep }); if (parsed.optional) isOptionalUnion = true; return parsed; }); definition.optional = isOptionalUnion; } if (definition.type === 'alias') { if (typeof definition.def === 'object') { definition.def.type = parseFieldDefinitionConfig(definition.def.type, { deep }); validFlattenDefinitionKeysList.forEach(k => { if (definition[k] !== undefined) { // @ts-ignore definition.def.type[k] = definition[k]; } }); } } return definition; } if (isListDefinition(definition)) { const parsed = parseFieldDefinitionConfig(definition[0], { deep }); parsed.list = true; parsed.optional = false; return parsed; } if ((0, _ObjectType.isObject)(definition)) { return { def: deep ? parseObjectDefinition(definition.definition, { deep }) : definition.definition, defaultValue: undefined, description: definition.description, hidden: definition.hidden, type: 'object' }; } if (isObjectAsTypeDefinition(definition)) { return { def: deep ? parseObjectDefinition(definition.type.definition, { deep }) : definition.type.definition, defaultValue: undefined, description: definition.type.description, hidden: definition.hidden || definition.type.hidden, list: !!definition.list, name: definition.name, optional: !!definition.optional, type: 'object' }; } const keyObjectDefinition = parseFlattenFieldDefinition(definition, { deep }); if (keyObjectDefinition) { return keyObjectDefinition; } throw new Error(`Unexpected field definition: ${(0, _utils.inspectObject)(definition)}`); } try { const result = _parseField(); if (definition && typeof definition === 'object') { if ('name' in definition && definition.name && typeof definition.name === 'string') { result.name = definition.name; } } let hasNotStringifiableKeys = false; let hasDef = false; Object.entries(result).forEach(([k, v]) => { if (v === undefined || v === false) { delete result[k]; // deleting nullish values return; } if (k === 'def') { hasDef = true; return; } if (hasNotStringifiableKeys || !stringifiableDefKeys.has(k)) { hasNotStringifiableKeys = true; } }); if (asString && !hasNotStringifiableKeys) { const { type, list, optional, def } = result; let _type = type; if (list) _type = `[${_type}]`; if (optional) _type = `${_type}?`; if (hasDef) { // @ts-ignore return { [_type]: def }; } else { // @ts-ignore return _type; } } // return simpleObjectClone(result); return result; } catch (e) { debugger; console.error(e, definition); throw e; } } function parseObjectDefinition(input, options = {}) { let { deep, omitMeta } = options; if (deep !== null && deep !== void 0 && deep.omitMeta) { omitMeta = true; } const result = {}; let meta = undefined; const keys = (0, _utils.getKeys)(input); keys.forEach(function (fieldName) { try { let field = input[fieldName]; if ((0, _MetaFieldField.isMetaField)(field, fieldName)) { return meta = field; } const cached = hasCachedFieldInstance(field); if (cached) { return result[fieldName] = cached; } return result[fieldName] = parseObjectField(fieldName, field, { deep }); } catch (err) { debugger; throw new _utils.RuntimeError(`Failed to process object field "${fieldName}":\n${err.message}`, { err: err.stack, input }); } }); meta = meta || (0, _MetaFieldField.createEmptyMetaField)(); if (!omitMeta) { result[_MetaFieldField.objectMetaFieldKey] = meta; } return { definition: result, meta }; } function isFinalFieldDefinition(input) { return typeof (input === null || input === void 0 ? void 0 : input.type) === 'string'; } function isListDefinition(input) { if (Array.isArray(input) && input.length === 1) return true; if (!(0, _utils.isProduction)()) { var _input$forEach; // verify against old enum definition input === null || input === void 0 ? void 0 : (_input$forEach = input.forEach) === null || _input$forEach === void 0 ? void 0 : _input$forEach.call(input, el => { if (typeof el === 'string' && !(0, _parseStringDefinition.isStringFieldDefinition)(el)) { throw new Error(`Plain array is used only for union definitions.\n` + ` "${el}" is not valid as union item.\n` + ` You can use { enum: ['${el}'] } instead of ['${el}'].`); } }); } return false; } /** * Object as field['type'] is deprecated * @param input */ function isObjectAsTypeDefinition(input) { return input && typeof input === 'object' && (0, _ObjectType.isObject)(input.type); } const validFlattenDefinitionKeys = { defaultValue: 'any', description: 'string', hidden: 'boolean', list: 'boolean', name: 'string', optional: 'boolean' }; const validFlattenDefinitionKeysList = (0, _utils.getKeys)(validFlattenDefinitionKeys); function parseFlattenFieldDefinition(input, options = {}) { const { deep } = options; if ((0, _utils.getTypeName)(input) !== 'Object') return false; if (input.type !== undefined) return false; let type; let def; for (let k in input) { const valueOfDefOrOptionalOrListOrDescription = input[k]; if (_fieldTypes.types[k]) { type = k; def = valueOfDefOrOptionalOrListOrDescription; if (k !== 'object' && def && typeof def === 'object') { for (let defKey in def) { if (defKey === 'def' || validFlattenDefinitionKeys[defKey]) { console.warn(`using field def as type definition?\n`, { def, type: k }); return false; } } } } else { if (valueOfDefOrOptionalOrListOrDescription !== undefined) { const acceptAny = validFlattenDefinitionKeys[k] === 'any'; if (!acceptAny && // checking if the de `optional` or `list` or `description` // has the expected types typeof valueOfDefOrOptionalOrListOrDescription !== validFlattenDefinitionKeys[k]) { return false; } } } } let { description, optional = false, list = false, defaultValue, name, hidden } = input; return parseFieldDefinitionConfig({ def, defaultValue, description, hidden, list, name, optional, type }, { deep }); } const CACHED_FIELD_INSTANCE_KEY = '__cachedFieldInstance'; exports.CACHED_FIELD_INSTANCE_KEY = CACHED_FIELD_INSTANCE_KEY; function __getCachedFieldInstance(field) { if (field !== null && field !== void 0 && field[CACHED_FIELD_INSTANCE_KEY]) { return field[CACHED_FIELD_INSTANCE_KEY]; } const parsed = parseFieldDefinitionConfig(field); const instanceFromDef = (0, _fieldInstanceFromDef.fieldInstanceFromDef)(parsed); setCachedFieldInstance(parsed, instanceFromDef); return instanceFromDef; } function hasCachedFieldInstance(field) { return !!(field !== null && field !== void 0 && field[CACHED_FIELD_INSTANCE_KEY]) ? field : null; } function setCachedFieldInstance(field, instanceFromDef) { if (hasCachedFieldInstance(field)) return; Object.defineProperty(field, CACHED_FIELD_INSTANCE_KEY, { configurable: false, enumerable: false, value: instanceFromDef, writable: false }); } function deleteCachedFieldInstance(def) { if (!def || typeof def !== 'object') return def; const { [CACHED_FIELD_INSTANCE_KEY]: _, ...rest } = def; return rest; // if (currentDepth > depth) return def; // // Object.entries(rest).reduce((acc, [key, value]) => { // return { // ...acc, // [key]: value, // }; // }, rest); // // return rest; } //# sourceMappingURL=parseObjectDefinition.js.map