@backland/schema
Version:
TypeScript schema declaration and validation library with static type inference
442 lines (438 loc) • 14.2 kB
JavaScript
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