"use strict";
const resource = require("./resource");
/**
* Exposes objects as another value when serialized.
* `expose` uses the `expose` property of object [resources]{@link resource} internally.
* @module expose
* @param {!object} obj The object to expose.
* @param {any} [val] The value that should be used instead of obj when serialized. If not specified and `obj` is an `Error`, `obj.message` will be made enumerable and obj will get itself as its exposed value.
* @return {object} The exposed object.
*/
function expose(obj, val) {
if(arguments.length === 1) {
if(obj instanceof Error)
Object.defineProperty(obj, "message", {
enumerable: true,
value: obj.message
});
val = obj;
}
return resource(obj, {
expose: val
});
}
function subclassError(error) {
return class extends error {
constructor(msg) {
super(msg);
expose(this);
}
};
}
module.exports = Object.assign(expose, {
/**
* An Error constructor that builds exposed errors.
* @class
* @extends Error
*/
Error: subclassError(Error),
/**
* An TypeError constructor that builds exposed errors.
* @class
* @extends TypeError
*/
TypeError: subclassError(TypeError),
/**
* An ReferenceError constructor that builds exposed errors.
* @class
* @extends ReferenceError
*/
ReferenceError: subclassError(ReferenceError),
/**
* An RangeError constructor that builds exposed errors.
* @class
* @extends RangeError
*/
RangeError: subclassError(RangeError),
/**
* An SyntaxError constructor that builds exposed errors.
* @class
* @extends SyntaxError
*/
SyntaxError: subclassError(SyntaxError),
/**
* An URIError constructor that builds exposed errors.
* @class
* @extends URIError
*/
URIError: subclassError(URIError),
/**
* An EvalError constructor that builds exposed errors.
* @class
* @extends EvalError
*/
EvalError: subclassError(EvalError),
/**
* Checks whether a given object is exposed.
* @param {any} object The object to check. This can be any value. The method will always return `false` for non-objects.
* @return {boolean} `true` if the object is exposed. `false` if not.
*/
isExposed(object) {
return "expose" in resource(object);
},
/**
* Returns the value an object is exposed with. `undefined` if the given object is not exposed.
* @param {any} object The object to look up. This can be any value. The method will always return `undefined` for non-objects.
* @return {any} The exposed value of the given object.
*/
getValue(object) {
return resource(object).expose;
},
/**
* Exposes the given object so that only the given iterable collection of properties will be serialized.
* @param {object} obj The object that should be exposed.
* @param {Iterable.<string>} properties An iterable collection of property strings that should be exposed.
* @return {object} The exposed object.
*/
properties(obj, properties) {
if(!properties || typeof properties !== "object" || !(Symbol.iterator in properties))
throw new TypeError("The properties to be exposed have to be iterable.");
return resource(obj, Object.defineProperty({}, "expose", {
configurable: true,
enumerable: true,
get: properties instanceof Map ? () => {
const result = {};
for(const [key, value] of properties)
result[value] = obj[key];
return result;
} : () => {
const result = {};
for(const property of properties)
result[property] = obj[property];
return result;
}
}));
}
});