wed
Version:
Wed is a schema-aware editor for XML documents.
164 lines • 5.67 kB
JavaScript
/**
* Checks whether an object conforms to a template.
* @author Louis-Dominique Dubeau
* @license MPL 2.0
* @copyright Mangalam Research Center for Buddhist Languages
*/
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Checks whether a field is required.
*
* @param template The template to check.
*
* @param name The name of the field.
*
* @returns Whether the field is required or not.
*/
function _required(template, name) {
const val = template[name];
if (typeof val === "object") {
for (const subname in val) {
if (_required(val, subname)) {
return true;
}
}
return false;
}
return val;
}
function _check(template, toCheck, prefix, ret) {
for (const name in template) {
if (_required(template, name)) {
const prefixed = prefix !== undefined ? [prefix, name].join(".") : name;
if (!(name in toCheck)) {
ret.missing.push(prefixed);
}
else {
const val = toCheck[name];
const templateVal = template[name];
if (!(val instanceof Array) && typeof val === "object" &&
typeof templateVal === "object") {
_check(templateVal, val, prefixed, ret);
}
}
}
}
for (const name in toCheck) {
if (!(name in template)) {
const prefixed = prefix !== undefined ? [prefix, name].join(".") : name;
ret.extra.push(prefixed);
}
}
}
/**
* Checks whether an object conforms to a template. The template must be an
* object which specifies the known fields and which among them are required. A
* field is known if it appears in the template. A field is considered
* *required* if:
*
* + it is an object which has any field which is required, or
*
* + it is not an object but evaluates to a true value.
*
* A required field which does not appear in the object being checked will
* appear in the ``missing`` field in the returned value.
*
* A field which appears on the object being checked but which is not known will
* appear in the ``extra`` field in the returned value.
*
* The fields mentioned above exist only if there is something to report. The
* names returned in the lists are fully qualified names.
*
* For instance, given this template:
*
* {
* foo: false,
* bar: {
* baz: true,
* bin: false,
* },
* bip: {
* baz: false,
* bin: false,
* }
* }
*
* The names "foo", "bar", "bar.baz", "bar.bin", "bip", "bip.baz", bip.bin" are
* known. The names "bar" and "bar.baz" are required. The name "bar" is required
* because "bar.baz" is required. The other names correspond to objects whose
* fields are not required or are non-object values that evaluate to false.
*
* @param template The template to use for the check.
*
* @param toCheck The object to check
*
* @returns The results.
*/
function check(template, toCheck) {
const initial = { missing: [], extra: [] };
_check(template, toCheck, undefined, initial);
// clean up
// tslint:disable-next-line:no-any
const ret = initial;
for (const name in ret) {
if (ret[name].length === 0) {
delete ret[name];
}
}
return ret;
}
exports.check = check;
/**
* Check whether the object fits the template, and throw at the first sign of
* trouble. The thrown object contains information about the first error
* encountered.
*
* @param template The template to use for the check.
*
* @param toCheck The object to check
*
* @throws {Error} If there is any error.
*/
function assertSummarily(template, toCheck) {
const result = check(template, toCheck);
if (result.missing !== undefined) {
throw new Error(`missing option: ${result.missing[0]}`);
}
if (result.extra !== undefined) {
throw new Error(`extra option: ${result.extra[0]}`);
}
}
exports.assertSummarily = assertSummarily;
/**
* Check whether the object fits the template, and throw an error that reports
* all issues.
*
* @param template The template to use for the check.
*
* @param toCheck The object to check
*
* @throws {Error} If there is any error.
*/
function assertExtensively(template, toCheck) {
const result = check(template, toCheck);
const errors = [];
if (result.missing !== undefined) {
for (const name of result.missing) {
errors.push(`missing option: ${name}`);
}
}
if (result.extra !== undefined) {
for (const name of result.extra) {
errors.push(`extra option: ${name}`);
}
}
if (errors.length !== 0) {
throw new Error(errors.join(", "));
}
}
exports.assertExtensively = assertExtensively;
});
// LocalWords: MPL baz bip
//# sourceMappingURL=object-check.js.map