123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455 |
- 'use strict';
- class MergeStrategy {
-
- static overwrite(value1, value2) {
- return value2;
- }
-
- static replace(value1, value2) {
- if (typeof value2 !== "undefined") {
- return value2;
- }
- return value1;
- }
-
- static assign(value1, value2) {
- return Object.assign({}, value1, value2);
- }
- }
- class ValidationStrategy {
-
- static array(value) {
- if (!Array.isArray(value)) {
- throw new TypeError("Expected an array.");
- }
- }
-
- static boolean(value) {
- if (typeof value !== "boolean") {
- throw new TypeError("Expected a Boolean.");
- }
- }
-
- static number(value) {
- if (typeof value !== "number") {
- throw new TypeError("Expected a number.");
- }
- }
-
- static object(value) {
- if (!value || typeof value !== "object") {
- throw new TypeError("Expected an object.");
- }
- }
-
- static "object?"(value) {
- if (typeof value !== "object") {
- throw new TypeError("Expected an object or null.");
- }
- }
-
- static string(value) {
- if (typeof value !== "string") {
- throw new TypeError("Expected a string.");
- }
- }
-
- static "string!"(value) {
- if (typeof value !== "string" || value.length === 0) {
- throw new TypeError("Expected a non-empty string.");
- }
- }
- }
- function validateDefinition(name, definition) {
- let hasSchema = false;
- if (definition.schema) {
- if (typeof definition.schema === "object") {
- hasSchema = true;
- } else {
- throw new TypeError("Schema must be an object.");
- }
- }
- if (typeof definition.merge === "string") {
- if (!(definition.merge in MergeStrategy)) {
- throw new TypeError(
- `Definition for key "${name}" missing valid merge strategy.`,
- );
- }
- } else if (!hasSchema && typeof definition.merge !== "function") {
- throw new TypeError(
- `Definition for key "${name}" must have a merge property.`,
- );
- }
- if (typeof definition.validate === "string") {
- if (!(definition.validate in ValidationStrategy)) {
- throw new TypeError(
- `Definition for key "${name}" missing valid validation strategy.`,
- );
- }
- } else if (!hasSchema && typeof definition.validate !== "function") {
- throw new TypeError(
- `Definition for key "${name}" must have a validate() method.`,
- );
- }
- }
- class UnexpectedKeyError extends Error {
-
- constructor(key) {
- super(`Unexpected key "${key}" found.`);
- }
- }
- class MissingKeyError extends Error {
-
- constructor(key) {
- super(`Missing required key "${key}".`);
- }
- }
- class MissingDependentKeysError extends Error {
-
- constructor(key, requiredKeys) {
- super(`Key "${key}" requires keys "${requiredKeys.join('", "')}".`);
- }
- }
- class WrapperError extends Error {
-
- constructor(key, source) {
- super(`Key "${key}": ${source.message}`, { cause: source });
-
- for (const sourceKey of Object.keys(source)) {
- if (!(sourceKey in this)) {
- this[sourceKey] = source[sourceKey];
- }
- }
- }
- }
- class ObjectSchema {
-
-
-
-
-
- constructor(definitions) {
- if (!definitions) {
- throw new Error("Schema definitions missing.");
- }
-
- for (const key of Object.keys(definitions)) {
- validateDefinition(key, definitions[key]);
-
- if (typeof definitions[key].schema === "object") {
- const schema = new ObjectSchema(definitions[key].schema);
- definitions[key] = {
- ...definitions[key],
- merge(first = {}, second = {}) {
- return schema.merge(first, second);
- },
- validate(value) {
- ValidationStrategy.object(value);
- schema.validate(value);
- },
- };
- }
-
- if (typeof definitions[key].merge === "string") {
- definitions[key] = {
- ...definitions[key],
- merge: MergeStrategy[
- (definitions[key].merge)
- ],
- };
- }
-
- if (typeof definitions[key].validate === "string") {
- definitions[key] = {
- ...definitions[key],
- validate:
- ValidationStrategy[
- (definitions[key].validate)
- ],
- };
- }
- this.
- if (definitions[key].required) {
- this.
- }
- }
- }
-
- hasKey(key) {
- return this.
- }
-
- merge(...objects) {
-
- if (objects.length < 2) {
- throw new TypeError("merge() requires at least two arguments.");
- }
- if (
- objects.some(
- object => object === null || typeof object !== "object",
- )
- ) {
- throw new TypeError("All arguments must be objects.");
- }
- return objects.reduce((result, object) => {
- this.validate(object);
- for (const [key, strategy] of this.
- try {
- if (key in result || key in object) {
- const merge = (strategy.merge);
- const value = merge.call(
- this,
- result[key],
- object[key],
- );
- if (value !== undefined) {
- result[key] = value;
- }
- }
- } catch (ex) {
- throw new WrapperError(key, ex);
- }
- }
- return result;
- }, {});
- }
-
- validate(object) {
-
- for (const key of Object.keys(object)) {
-
- if (!this.hasKey(key)) {
- throw new UnexpectedKeyError(key);
- }
-
- const definition = this.
-
- if (Array.isArray(definition.requires)) {
- if (
- !definition.requires.every(otherKey => otherKey in object)
- ) {
- throw new MissingDependentKeysError(
- key,
- definition.requires,
- );
- }
- }
-
- try {
- const validate = (definition.validate);
- validate.call(definition, object[key]);
- } catch (ex) {
- throw new WrapperError(key, ex);
- }
- }
-
- for (const [key] of this.
- if (!(key in object)) {
- throw new MissingKeyError(key);
- }
- }
- }
- }
- exports.MergeStrategy = MergeStrategy;
- exports.ObjectSchema = ObjectSchema;
- exports.ValidationStrategy = ValidationStrategy;
|