@backland/schema
Version:
TypeScript schema declaration and validation library with static type inference
228 lines (226 loc) • 6.35 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _exportNames = {
FieldsTypeCache: true,
FieldType: true,
isFieldInstance: true
};
exports.FieldsTypeCache = exports.FieldType = void 0;
exports.isFieldInstance = isFieldInstance;
var _utils = require("@backland/utils");
var _CircularDeps = require("../CircularDeps");
var _applyValidator = require("../applyValidator");
Object.keys(_applyValidator).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
if (key in exports && exports[key] === _applyValidator[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _applyValidator[key];
}
});
});
var _ArrayFieldParse = require("./ArrayFieldParse");
var _FieldTypeErrors = require("./FieldTypeErrors");
var _Infer = require("./Infer");
const FieldsTypeCache = new Map();
exports.FieldsTypeCache = FieldsTypeCache;
class FieldType {
get definition() {
return this.asFinalFieldDef;
}
constructor(config) {
const {
name,
id,
def,
options = {}
} = config;
this.id = id;
this.typeName = name;
this.type = name;
this.options = options;
const defKeys = def ? Object.keys(def).sort() : undefined;
if (defKeys !== null && defKeys !== void 0 && defKeys.length) {
this.def = def;
}
if (id) {
const existing = FieldsTypeCache.get(id);
if (existing) {
var _existing$defKeys;
const existingKeys = (_existing$defKeys = existing.defKeys) === null || _existing$defKeys === void 0 ? void 0 : _existing$defKeys.join(', ');
if (existing.fieldType.typeName !== this.typeName) {
throw new Error(`Field with id "${id}" already registered with different type:\n "${(0, _utils.inspectObject)({
old: existing.fieldType.asFinalFieldDef,
current: this.asFinalFieldDef
}, {
depth: 2
})}"`);
}
if ((defKeys === null || defKeys === void 0 ? void 0 : defKeys.join(', ')) !== existingKeys) {
throw new Error(`Field with id "${id}" already registered with different fields:\n "${existingKeys}"`);
}
}
FieldsTypeCache.set(id, {
fieldType: this,
defKeys
});
}
}
validate(input) {
try {
this.parse(input);
return true;
} catch (e) {
return false;
}
}
is(input) {
return this.validate(input);
}
describe = description => {
this.description = description;
return this;
};
describeField = () => {
return this.asFinalFieldDef;
};
toOptional() {
// @ts-ignore
this.optional = true;
return this;
}
toRequired() {
// @ts-ignore
this.optional = false;
return this;
}
toList(options) {
// @ts-ignore
this.list = true;
if (options && typeof options === 'object') {
this.options = {
...this.options,
...options
};
}
return this;
}
setDefaultValue(value) {
// @ts-ignore
this.defaultValue = value;
return this;
}
applyParser = parser => {
return (input, _options) => {
let options = {};
if (typeof _options === 'function') {
options = {
customErrorMessage: _options
};
}
if (typeof _options === 'string') {
options = {
customErrorMessage: _options
};
}
if (typeof _options === 'object') {
options = _options;
}
const {
customErrorMessage: customMessage,
includeHidden = true
} = options;
// keep it secret
if (this.hidden && !includeHidden) return undefined;
if (parser.preParse) {
input = parser.preParse(input);
}
if ((input === undefined || input === null) && this.defaultValue !== undefined) {
input = this.defaultValue;
}
if (this.type === 'null' && input === undefined) {
return null;
}
if (this.type !== 'null' && input === null && this.optional) {
return undefined;
}
if (input === undefined && this.optional) {
return undefined;
}
if (input === undefined && !this.optional) {
throw (0, _FieldTypeErrors.createFieldTypeError)('requiredField');
}
if (this.asFinalFieldDef.list) {
return (0, _ArrayFieldParse.arrayFieldParse)({
arrayOptions: {},
// since is the shot definition (list:true) there is no options
input,
parser: input => parser.parse(input, options),
parserOptions: options
});
}
try {
return parser.parse(input, options);
} catch (originalError) {
if (!customMessage && (0, _FieldTypeErrors.isFieldError)(originalError)) {
throw originalError;
}
throw (0, _applyValidator.parseValidationError)(input, customMessage, originalError);
}
};
};
get asFinalFieldDef() {
const res = {
def: this.def,
defaultValue: this.defaultValue,
description: this.description,
hidden: this.hidden,
list: this.list,
optional: this.optional,
type: this.type
};
Object.entries(res).forEach(([k, v]) => {
if (v === undefined || v === false) {
delete res[k];
}
});
return res;
}
__isFieldType = true;
static create(..._args) {
throw new Error('not implemented in abstract class.');
}
clone = () => {
const {
def,
defaultValue,
...rest
} = this.asFinalFieldDef;
let field;
if (rest.type === 'literal') {
field = {
...(0, _utils.simpleObjectClone)(rest),
def,
defaultValue
};
} else {
field = (0, _utils.simpleObjectClone)(rest);
if (def !== undefined) {
field.def = (0, _utils.simpleObjectClone)(def);
}
if (defaultValue !== undefined) {
field.defaultValue = (0, _utils.simpleObjectClone)(def);
}
}
return _CircularDeps.CircularDeps.fieldInstanceFromDef(field);
};
}
exports.FieldType = FieldType;
function isFieldInstance(t) {
return (t === null || t === void 0 ? void 0 : t.__isFieldType) === true;
}
//# sourceMappingURL=FieldType.js.map