@decaf-ts/decorator-validation
Version:
simple decorator based validation engine
89 lines • 12.9 kB
JavaScript
import { COMPARISON_ERROR_MESSAGES, VALIDATION_PARENT_KEY } from "../constants";
import { sf } from "./strings";
const fallbackGetParent = (target) => {
return target[VALIDATION_PARENT_KEY];
};
const fallbackGetValue = (target, prop) => {
if (!Object.prototype.hasOwnProperty.call(target, prop))
throw new Error(sf(COMPARISON_ERROR_MESSAGES.PROPERTY_NOT_EXIST, prop));
return target[prop];
};
/**
* Standard path resolution utility for accessing nested object properties.
* Provides consistent dot-notation access to both parent and child properties
* across complex object structures.
*
* - Dot-notation path resolution ('object.child.property')
* - Parent traversal using '../' notation
* - Configurable property access behavior
* - Null/undefined safety checks
*/
export class PathProxyEngine {
/**
* Creates a path-aware proxy for the target object
* @template T - The type of the target object
* @param {T} rootTarget - The target object to proxy
* @param opts - Configuration options
* @param opts.getValue - Custom function to get property value
* @param opts.getParent - Custom function to get parent object
* @param opts.ignoreUndefined - Whether to ignore undefined values in paths
* @param opts.ignoreNull - Whether to ignore null values in paths
* @returns A proxy object with path access capabilities
*/
static create(rootTarget, opts) {
const { getValue, getParent, ignoreUndefined, ignoreNull } = {
getParent: fallbackGetParent,
getValue: fallbackGetValue,
ignoreNull: false,
ignoreUndefined: false,
...opts,
};
const proxy = new Proxy({}, {
get(target, prop) {
if (prop === "getValueFromPath") {
return function (path) {
const parts = PathProxyEngine.parsePath(path);
let current = rootTarget;
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
if (part === "..") {
const parent = getParent(current);
if (!parent || typeof parent !== "object") {
throw new Error(sf(COMPARISON_ERROR_MESSAGES.CONTEXT_NOT_OBJECT_COMPARISON, i + 1, path));
}
current = parent; //PathProxyEngine.create(parentTarget, opts);
continue;
}
current = getValue(current, part);
if (!ignoreUndefined && typeof current === "undefined")
throw new Error(sf(COMPARISON_ERROR_MESSAGES.PROPERTY_INVALID, path, part));
if (!ignoreNull && current === null)
throw new Error(sf(COMPARISON_ERROR_MESSAGES.PROPERTY_INVALID, path, part));
}
return current;
};
}
return target[prop];
},
});
// Object.defineProperty(proxy, PROXY_PROP, {
// value: true, // overwrite by proxy behavior
// enumerable: false,
// configurable: false,
// writable: false,
// });
return proxy;
}
/**
* Parses a path string into individual components
* @param path - The path string to parse (e.g., "user.address.city")
* @returns An array of path components
* @throws Error if the path is invalid
*/
static parsePath(path) {
if (typeof path !== "string" || !path.trim())
throw new Error(sf(COMPARISON_ERROR_MESSAGES.INVALID_PATH, path));
return path.match(/(\.\.|[^/.]+)/g) || [];
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGF0aFByb3h5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3V0aWxzL1BhdGhQcm94eS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUseUJBQXlCLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDaEYsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUUvQixNQUFNLGlCQUFpQixHQUFHLENBQUMsTUFBVyxFQUFFLEVBQUU7SUFDeEMsT0FBTyxNQUFNLENBQUMscUJBQXFCLENBQUMsQ0FBQztBQUN2QyxDQUFDLENBQUM7QUFFRixNQUFNLGdCQUFnQixHQUFHLENBQUMsTUFBVyxFQUFFLElBQVksRUFBRSxFQUFFO0lBQ3JELElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQztRQUNyRCxNQUFNLElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQyx5QkFBeUIsQ0FBQyxrQkFBa0IsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQzFFLE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQ3RCLENBQUMsQ0FBQztBQVdGOzs7Ozs7Ozs7R0FTRztBQUNILE1BQU0sT0FBTyxlQUFlO0lBQzFCOzs7Ozs7Ozs7O09BVUc7SUFDSCxNQUFNLENBQUMsTUFBTSxDQUNYLFVBQWEsRUFDYixJQUtDO1FBRUQsTUFBTSxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsZUFBZSxFQUFFLFVBQVUsRUFBRSxHQUFHO1lBQzNELFNBQVMsRUFBRSxpQkFBaUI7WUFDNUIsUUFBUSxFQUFFLGdCQUFnQjtZQUMxQixVQUFVLEVBQUUsS0FBSztZQUNqQixlQUFlLEVBQUUsS0FBSztZQUN0QixHQUFHLElBQUk7U0FDUixDQUFDO1FBRUYsTUFBTSxLQUFLLEdBQUcsSUFBSSxLQUFLLENBQUMsRUFBUyxFQUFFO1lBQ2pDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsSUFBSTtnQkFDZCxJQUFJLElBQUksS0FBSyxrQkFBa0IsRUFBRSxDQUFDO29CQUNoQyxPQUFPLFVBQVUsSUFBWTt3QkFDM0IsTUFBTSxLQUFLLEdBQUcsZUFBZSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQzt3QkFDOUMsSUFBSSxPQUFPLEdBQVEsVUFBVSxDQUFDO3dCQUU5QixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDOzRCQUN0QyxNQUFNLElBQUksR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7NEJBQ3RCLElBQUksSUFBSSxLQUFLLElBQUksRUFBRSxDQUFDO2dDQUNsQixNQUFNLE1BQU0sR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUM7Z0NBQ2xDLElBQUksQ0FBQyxNQUFNLElBQUksT0FBTyxNQUFNLEtBQUssUUFBUSxFQUFFLENBQUM7b0NBQzFDLE1BQU0sSUFBSSxLQUFLLENBQ2IsRUFBRSxDQUNBLHlCQUF5QixDQUFDLDZCQUE2QixFQUN2RCxDQUFDLEdBQUcsQ0FBQyxFQUNMLElBQUksQ0FDTCxDQUNGLENBQUM7Z0NBQ0osQ0FBQztnQ0FDRCxPQUFPLEdBQUcsTUFBTSxDQUFDLENBQUMsNkNBQTZDO2dDQUMvRCxTQUFTOzRCQUNYLENBQUM7NEJBRUQsT0FBTyxHQUFHLFFBQVEsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7NEJBQ2xDLElBQUksQ0FBQyxlQUFlLElBQUksT0FBTyxPQUFPLEtBQUssV0FBVztnQ0FDcEQsTUFBTSxJQUFJLEtBQUssQ0FDYixFQUFFLENBQUMseUJBQXlCLENBQUMsZ0JBQWdCLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUMzRCxDQUFDOzRCQUVKLElBQUksQ0FBQyxVQUFVLElBQUksT0FBTyxLQUFLLElBQUk7Z0NBQ2pDLE1BQU0sSUFBSSxLQUFLLENBQ2IsRUFBRSxDQUFDLHlCQUF5QixDQUFDLGdCQUFnQixFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsQ0FDM0QsQ0FBQzt3QkFDTixDQUFDO3dCQUVELE9BQU8sT0FBTyxDQUFDO29CQUNqQixDQUFDLENBQUM7Z0JBQ0osQ0FBQztnQkFFRCxPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUN0QixDQUFDO1NBQ0YsQ0FBQyxDQUFDO1FBRUgsNkNBQTZDO1FBQzdDLGdEQUFnRDtRQUNoRCx1QkFBdUI7UUFDdkIseUJBQXlCO1FBQ3pCLHFCQUFxQjtRQUNyQixNQUFNO1FBRU4sT0FBTyxLQUFxQixDQUFDO0lBQy9CLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNLLE1BQU0sQ0FBQyxTQUFTLENBQUMsSUFBWTtRQUNuQyxJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVEsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUU7WUFDMUMsTUFBTSxJQUFJLEtBQUssQ0FBQyxFQUFFLENBQUMseUJBQXlCLENBQUMsWUFBWSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDcEUsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLGdCQUFnQixDQUFDLElBQUksRUFBRSxDQUFDO0lBQzVDLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENPTVBBUklTT05fRVJST1JfTUVTU0FHRVMsIFZBTElEQVRJT05fUEFSRU5UX0tFWSB9IGZyb20gXCIuLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IHNmIH0gZnJvbSBcIi4vc3RyaW5nc1wiO1xuXG5jb25zdCBmYWxsYmFja0dldFBhcmVudCA9ICh0YXJnZXQ6IGFueSkgPT4ge1xuICByZXR1cm4gdGFyZ2V0W1ZBTElEQVRJT05fUEFSRU5UX0tFWV07XG59O1xuXG5jb25zdCBmYWxsYmFja0dldFZhbHVlID0gKHRhcmdldDogYW55LCBwcm9wOiBzdHJpbmcpID0+IHtcbiAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodGFyZ2V0LCBwcm9wKSlcbiAgICB0aHJvdyBuZXcgRXJyb3Ioc2YoQ09NUEFSSVNPTl9FUlJPUl9NRVNTQUdFUy5QUk9QRVJUWV9OT1RfRVhJU1QsIHByb3ApKTtcbiAgcmV0dXJuIHRhcmdldFtwcm9wXTtcbn07XG5cbi8qKlxuICogUHJveHkgb2JqZWN0IHRoYXQgcHJvdmlkZXMgcGF0aC1iYXNlZCBhY2Nlc3MgdG8gbmVzdGVkIHByb3BlcnRpZXNcbiAqIEB0ZW1wbGF0ZSBUIC0gVGhlIHR5cGUgb2YgdGhlIHRhcmdldCBvYmplY3QgYmVpbmcgcHJveGllZFxuICovXG5leHBvcnQgdHlwZSBQYXRoUHJveHk8VD4gPSBUICYge1xuICAvLyBbUFJPWFlfUFJPUF06IGJvb2xlYW47XG4gIGdldFZhbHVlRnJvbVBhdGg6IChwYXRoOiBzdHJpbmcsIGZhbGxiYWNrPzogYW55KSA9PiBhbnk7XG59O1xuXG4vKipcbiAqIFN0YW5kYXJkIHBhdGggcmVzb2x1dGlvbiB1dGlsaXR5IGZvciBhY2Nlc3NpbmcgbmVzdGVkIG9iamVjdCBwcm9wZXJ0aWVzLlxuICogUHJvdmlkZXMgY29uc2lzdGVudCBkb3Qtbm90YXRpb24gYWNjZXNzIHRvIGJvdGggcGFyZW50IGFuZCBjaGlsZCBwcm9wZXJ0aWVzXG4gKiBhY3Jvc3MgY29tcGxleCBvYmplY3Qgc3RydWN0dXJlcy5cbiAqXG4gKiAtIERvdC1ub3RhdGlvbiBwYXRoIHJlc29sdXRpb24gKCdvYmplY3QuY2hpbGQucHJvcGVydHknKVxuICogLSBQYXJlbnQgdHJhdmVyc2FsIHVzaW5nICcuLi8nIG5vdGF0aW9uXG4gKiAtIENvbmZpZ3VyYWJsZSBwcm9wZXJ0eSBhY2Nlc3MgYmVoYXZpb3JcbiAqIC0gTnVsbC91bmRlZmluZWQgc2FmZXR5IGNoZWNrc1xuICovXG5leHBvcnQgY2xhc3MgUGF0aFByb3h5RW5naW5lIHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBwYXRoLWF3YXJlIHByb3h5IGZvciB0aGUgdGFyZ2V0IG9iamVjdFxuICAgKiBAdGVtcGxhdGUgVCAtIFRoZSB0eXBlIG9mIHRoZSB0YXJnZXQgb2JqZWN0XG4gICAqIEBwYXJhbSB7VH0gcm9vdFRhcmdldCAtIFRoZSB0YXJnZXQgb2JqZWN0IHRvIHByb3h5XG4gICAqIEBwYXJhbSBvcHRzIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAqIEBwYXJhbSBvcHRzLmdldFZhbHVlIC0gQ3VzdG9tIGZ1bmN0aW9uIHRvIGdldCBwcm9wZXJ0eSB2YWx1ZVxuICAgKiBAcGFyYW0gb3B0cy5nZXRQYXJlbnQgLSBDdXN0b20gZnVuY3Rpb24gdG8gZ2V0IHBhcmVudCBvYmplY3RcbiAgICogQHBhcmFtIG9wdHMuaWdub3JlVW5kZWZpbmVkIC0gV2hldGhlciB0byBpZ25vcmUgdW5kZWZpbmVkIHZhbHVlcyBpbiBwYXRoc1xuICAgKiBAcGFyYW0gb3B0cy5pZ25vcmVOdWxsIC0gV2hldGhlciB0byBpZ25vcmUgbnVsbCB2YWx1ZXMgaW4gcGF0aHNcbiAgICogQHJldHVybnMgQSBwcm94eSBvYmplY3Qgd2l0aCBwYXRoIGFjY2VzcyBjYXBhYmlsaXRpZXNcbiAgICovXG4gIHN0YXRpYyBjcmVhdGU8VCBleHRlbmRzIG9iamVjdD4oXG4gICAgcm9vdFRhcmdldDogVCxcbiAgICBvcHRzPzoge1xuICAgICAgZ2V0VmFsdWU/OiAodGFyZ2V0OiBULCBwcm9wOiBzdHJpbmcpID0+IGFueTtcbiAgICAgIGdldFBhcmVudD86ICh0YXJnZXQ6IFQpID0+IGFueTtcbiAgICAgIGlnbm9yZVVuZGVmaW5lZDogYm9vbGVhbjtcbiAgICAgIGlnbm9yZU51bGw6IGJvb2xlYW47XG4gICAgfVxuICApOiBQYXRoUHJveHk8VD4ge1xuICAgIGNvbnN0IHsgZ2V0VmFsdWUsIGdldFBhcmVudCwgaWdub3JlVW5kZWZpbmVkLCBpZ25vcmVOdWxsIH0gPSB7XG4gICAgICBnZXRQYXJlbnQ6IGZhbGxiYWNrR2V0UGFyZW50LFxuICAgICAgZ2V0VmFsdWU6IGZhbGxiYWNrR2V0VmFsdWUsXG4gICAgICBpZ25vcmVOdWxsOiBmYWxzZSxcbiAgICAgIGlnbm9yZVVuZGVmaW5lZDogZmFsc2UsXG4gICAgICAuLi5vcHRzLFxuICAgIH07XG5cbiAgICBjb25zdCBwcm94eSA9IG5ldyBQcm94eSh7fSBhcyBhbnksIHtcbiAgICAgIGdldCh0YXJnZXQsIHByb3ApIHtcbiAgICAgICAgaWYgKHByb3AgPT09IFwiZ2V0VmFsdWVGcm9tUGF0aFwiKSB7XG4gICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChwYXRoOiBzdHJpbmcpOiBhbnkge1xuICAgICAgICAgICAgY29uc3QgcGFydHMgPSBQYXRoUHJveHlFbmdpbmUucGFyc2VQYXRoKHBhdGgpO1xuICAgICAgICAgICAgbGV0IGN1cnJlbnQ6IGFueSA9IHJvb3RUYXJnZXQ7XG5cbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcGFydHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgY29uc3QgcGFydCA9IHBhcnRzW2ldO1xuICAgICAgICAgICAgICBpZiAocGFydCA9PT0gXCIuLlwiKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgcGFyZW50ID0gZ2V0UGFyZW50KGN1cnJlbnQpO1xuICAgICAgICAgICAgICAgIGlmICghcGFyZW50IHx8IHR5cGVvZiBwYXJlbnQgIT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgc2YoXG4gICAgICAgICAgICAgICAgICAgICAgQ09NUEFSSVNPTl9FUlJPUl9NRVNTQUdFUy5DT05URVhUX05PVF9PQkpFQ1RfQ09NUEFSSVNPTixcbiAgICAgICAgICAgICAgICAgICAgICBpICsgMSxcbiAgICAgICAgICAgICAgICAgICAgICBwYXRoXG4gICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGN1cnJlbnQgPSBwYXJlbnQ7IC8vUGF0aFByb3h5RW5naW5lLmNyZWF0ZShwYXJlbnRUYXJnZXQsIG9wdHMpO1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgY3VycmVudCA9IGdldFZhbHVlKGN1cnJlbnQsIHBhcnQpO1xuICAgICAgICAgICAgICBpZiAoIWlnbm9yZVVuZGVmaW5lZCAmJiB0eXBlb2YgY3VycmVudCA9PT0gXCJ1bmRlZmluZWRcIilcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICAgICAgICBzZihDT01QQVJJU09OX0VSUk9SX01FU1NBR0VTLlBST1BFUlRZX0lOVkFMSUQsIHBhdGgsIHBhcnQpXG4gICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICBpZiAoIWlnbm9yZU51bGwgJiYgY3VycmVudCA9PT0gbnVsbClcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICAgICAgICBzZihDT01QQVJJU09OX0VSUk9SX01FU1NBR0VTLlBST1BFUlRZX0lOVkFMSUQsIHBhdGgsIHBhcnQpXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIGN1cnJlbnQ7XG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0YXJnZXRbcHJvcF07XG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgLy8gT2JqZWN0LmRlZmluZVByb3BlcnR5KHByb3h5LCBQUk9YWV9QUk9QLCB7XG4gICAgLy8gICB2YWx1ZTogdHJ1ZSwgLy8gb3ZlcndyaXRlIGJ5IHByb3h5IGJlaGF2aW9yXG4gICAgLy8gICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAvLyAgIGNvbmZpZ3VyYWJsZTogZmFsc2UsXG4gICAgLy8gICB3cml0YWJsZTogZmFsc2UsXG4gICAgLy8gfSk7XG5cbiAgICByZXR1cm4gcHJveHkgYXMgUGF0aFByb3h5PFQ+O1xuICB9XG5cbiAgLyoqXG4gICAqIFBhcnNlcyBhIHBhdGggc3RyaW5nIGludG8gaW5kaXZpZHVhbCBjb21wb25lbnRzXG4gICAqIEBwYXJhbSBwYXRoIC0gVGhlIHBhdGggc3RyaW5nIHRvIHBhcnNlIChlLmcuLCBcInVzZXIuYWRkcmVzcy5jaXR5XCIpXG4gICAqIEByZXR1cm5zIEFuIGFycmF5IG9mIHBhdGggY29tcG9uZW50c1xuICAgKiBAdGhyb3dzIEVycm9yIGlmIHRoZSBwYXRoIGlzIGludmFsaWRcbiAgICovXG4gIHByaXZhdGUgc3RhdGljIHBhcnNlUGF0aChwYXRoOiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gICAgaWYgKHR5cGVvZiBwYXRoICE9PSBcInN0cmluZ1wiIHx8ICFwYXRoLnRyaW0oKSlcbiAgICAgIHRocm93IG5ldyBFcnJvcihzZihDT01QQVJJU09OX0VSUk9SX01FU1NBR0VTLklOVkFMSURfUEFUSCwgcGF0aCkpO1xuICAgIHJldHVybiBwYXRoLm1hdGNoKC8oXFwuXFwufFteLy5dKykvZykgfHwgW107XG4gIH1cbn1cbiJdfQ==