UNPKG

@backland/schema

Version:

TypeScript schema declaration and validation library with static type inference

442 lines (438 loc) 14.2 kB
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } import { RuntimeError } from '@backland/utils'; import { isProduction } from '@backland/utils'; import { getKeys } from '@backland/utils'; import { getTypeName } from '@backland/utils'; import { inspectObject } from '@backland/utils'; import { GraphType } from './GraphType/GraphType'; import { isObject } from './ObjectType'; import { fieldInstanceFromDef } from './fieldInstanceFromDef'; import { isFieldInstance } from './fields/FieldType'; import { LiteralField } from './fields/LiteralField'; import { createEmptyMetaField, isMetaField, objectMetaFieldKey } from './fields/MetaFieldField'; import { types } from './fields/fieldTypes'; import { isStringFieldDefinition, parseStringDefinition } from './parseStringDefinition'; export var _parserHooks = []; export 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; } export function parseObjectField(fieldName, definition) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var { 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; var parsed = parseFieldDefinitionConfig(definition, { deep, omitMeta }); if (_parserHooks.length) { _parserHooks.forEach(cb => cb(parsed)); } if (typeof parsed === 'string') { return parsed; } else { if (asString) return parsed; } var instanceFromDef = fieldInstanceFromDef(parsed); setCachedFieldInstance(parsed, instanceFromDef); if (instanceFromDef.def) { parsed.def = instanceFromDef.def; } if (returnInstance) { return instanceFromDef; } if (parsed) return parsed; throw new RuntimeError("field \"".concat(fieldName, "\": invalid definition."), { definition, parsed }); } export function parseField(definition) { return parseObjectField('__parseField__', definition); } var stringifiableDefKeys = new Set(['type', 'list', 'optional' // ]); export function parseFieldDefinitionConfig(definition, options) { var { deep, asString } = options || {}; if (deep !== null && deep !== void 0 && deep.asString) { asString = true; } function _parseField() { if (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.is(definition)) { var def = parseFieldDefinitionConfig(definition.definition, { deep }); def.hidden = def.hidden || definition.hidden; return def; } if (GraphType.isTypeDefinition(definition)) { var { list = false, optional = false, description, defaultValue, hidden, type: { definition: { type, def: _def, defaultValue: _defaultValue } } } = definition; return { def: _def, defaultValue: defaultValue === undefined ? _defaultValue : defaultValue, description, hidden, list, optional, type }; } if (isStringFieldDefinition(definition)) { return parseStringDefinition(definition); } if (isFieldInstance(definition)) { return definition.asFinalFieldDef; } if (isFinalFieldDefinition(definition)) { if (definition.type === 'object') { if (typeof definition.def !== 'object' || !definition.def) { throw new RuntimeError("Missing def for object field.", { definition }); } if (isObject(definition.def)) { definition.def = definition.def.definition; } else { definition.def = parseObjectDefinition(definition.def, { deep }).definition; } } if (definition.type === 'union') { var isOptionalUnion = definition.optional; definition.def = definition.def.map(el => { var 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)) { var parsed = parseFieldDefinitionConfig(definition[0], { deep }); parsed.list = true; parsed.optional = false; return parsed; } if (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' }; } var keyObjectDefinition = parseFlattenFieldDefinition(definition, { deep }); if (keyObjectDefinition) { return keyObjectDefinition; } throw new Error("Unexpected field definition: ".concat(inspectObject(definition))); } try { var result = _parseField(); if (definition && typeof definition === 'object') { if ('name' in definition && definition.name && typeof definition.name === 'string') { result.name = definition.name; } } var hasNotStringifiableKeys = false; var hasDef = false; Object.entries(result).forEach(_ref => { var [k, v] = _ref; 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) { var { type, list, optional, def } = result; var _type = type; if (list) _type = "[".concat(_type, "]"); if (optional) _type = "".concat(_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; } } export function parseObjectDefinition(input) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var { deep, omitMeta } = options; if (deep !== null && deep !== void 0 && deep.omitMeta) { omitMeta = true; } var result = {}; var meta = undefined; var keys = getKeys(input); keys.forEach(function (fieldName) { try { var _field = input[fieldName]; if (isMetaField(_field, fieldName)) { return meta = _field; } var cached = hasCachedFieldInstance(_field); if (cached) { return result[fieldName] = cached; } return result[fieldName] = parseObjectField(fieldName, _field, { deep }); } catch (err) { debugger; throw new RuntimeError("Failed to process object field \"".concat(fieldName, "\":\n").concat(err.message), { err: err.stack, input }); } }); meta = meta || createEmptyMetaField(); if (!omitMeta) { result[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 (!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' && !isStringFieldDefinition(el)) { throw new Error("Plain array is used only for union definitions.\n" + " \"".concat(el, "\" is not valid as union item.\n") + " You can use { enum: ['".concat(el, "'] } instead of ['").concat(el, "'].")); } }); } return false; } /** * Object as field['type'] is deprecated * @param input */ export function isObjectAsTypeDefinition(input) { return input && typeof input === 'object' && isObject(input.type); } var validFlattenDefinitionKeys = { defaultValue: 'any', description: 'string', hidden: 'boolean', list: 'boolean', name: 'string', optional: 'boolean' }; var validFlattenDefinitionKeysList = getKeys(validFlattenDefinitionKeys); export function parseFlattenFieldDefinition(input) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var { deep } = options; if (getTypeName(input) !== 'Object') return false; if (input.type !== undefined) return false; var type; var def; for (var k in input) { var valueOfDefOrOptionalOrListOrDescription = input[k]; if (types[k]) { type = k; def = valueOfDefOrOptionalOrListOrDescription; if (k !== 'object' && def && typeof def === 'object') { for (var 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) { var 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; } } } } var { description, optional = false, list = false, defaultValue, name, hidden } = input; return parseFieldDefinitionConfig({ def, defaultValue, description, hidden, list, name, optional, type }, { deep }); } export var CACHED_FIELD_INSTANCE_KEY = '__cachedFieldInstance'; export function __getCachedFieldInstance(field) { if (field !== null && field !== void 0 && field[CACHED_FIELD_INSTANCE_KEY]) { return field[CACHED_FIELD_INSTANCE_KEY]; } var parsed = parseFieldDefinitionConfig(field); var instanceFromDef = 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 }); } export function deleteCachedFieldInstance(def) { if (!def || typeof def !== 'object') return def; var _ref2 = def, { [CACHED_FIELD_INSTANCE_KEY]: _ } = _ref2, rest = _objectWithoutProperties(_ref2, [CACHED_FIELD_INSTANCE_KEY].map(_toPropertyKey)); 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