UNPKG

@barchart/common-js

Version:
256 lines (250 loc) 8.43 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var FailureReason_exports = {}; __export(FailureReason_exports, { default: () => FailureReason }); module.exports = __toCommonJS(FailureReason_exports); var assert = __toESM(require("./../../lang/assert.js")); var is = __toESM(require("./../../lang/is.js")); var import_FailureReasonItem = __toESM(require("./FailureReasonItem.js")); var import_FailureType = __toESM(require("./FailureType.js")); var import_Schema = __toESM(require("./../../serialization/json/Schema.js")); var import_Tree = __toESM(require("./../../collections/Tree.js")); class FailureReason { #data; #root; #current; /** * @param {object=} data - Data regarding the API request itself, likely independent of the failure data maintained in the tree structure. */ constructor(data) { this.#data = data || null; this.#root = new import_Tree.default(null); this.#current = this.#root; } /** * Adds a {@link FailureReasonItem} to the tree of reasons at the current node. * * @public * @param {FailureType} type - The failure type. * @param {object=} data - The data associated with the failure type. * @param {boolean=} group - Whether the newly added item is expected to have children. * @returns {FailureReason} The current instance, allowing for method chaining. */ addItem(type, data, group) { assert.argumentIsRequired(type, "type", import_FailureType.default, "FailureType"); assert.argumentIsOptional(group, "group", Boolean); const node = this.#current.addChild(new import_FailureReasonItem.default(type, data)); if (is.boolean(group) && group) { this.#current = node; } return this; } /** * Resets the current node to the head of the tree. * * @public * @param {boolean=} previous * @returns {FailureReason} The current instance, allowing for method chaining. */ reset(previous) { assert.argumentIsOptional(previous, "previous", Boolean); let node; if (previous && this.#current.getIsInner()) { node = this.#current.getParent(); } else { node = this.#root; } this.#current = node; return this; } /** * Returns a tree of strings describing the reasons for API failure. * * @public * @returns {Array} */ format() { const reasons = this.#root.toJSObj((item) => { const formatted = {}; formatted.code = item ? item.type.code : null; formatted.message = item ? item.format(this.#data) : null; if (item && item.type.verbose) { formatted.data = item.data; } return formatted; }, true); return reasons.children; } /** * Indicates whether the tree of {@link FailureReasonItem} instances * contains at least one item with a matching {@link FailureType}. * * @public * @param {FailureType} type * @returns {boolean} */ hasFailureType(type) { assert.argumentIsRequired(type, "type", import_FailureType.default, "FailureType"); return this.#root.search((item) => item.type === type, false, false) !== null; } /** * Indicates whether the tree of {@link FailureReasonItem} instances * contains at least one item considered severe. * * @public * @returns {boolean} */ getIsSevere() { return this.#root.search((item) => item.type.severe, false, false) !== null; } /** * Searches the tree of {@link FailureReasonItem} instances for a * non-standard HTTP error code. * * @public * @returns {number|null} */ getErrorCode() { const node = this.#root.search((item) => item.type.error !== null, true, false); if (node === null) { return null; } return node.getValue().type.error; } /** * A convenience function for creating a new {@link FailureReason} * with a single {@link FailureType}. * * @public * @static * @param {FailureType} type * @param {object=} data * @returns {FailureReason} */ static from(type, data) { const reason = new FailureReason(); return reason.addItem(type, data); } /** * Factory function for creating instances of {@link FailureReason}. * * @public * @static * @param {object=} data * @returns {FailureReason} */ static forRequest(data) { return new FailureReason(data); } /** * Returns a JSON representation of the failure reason. * * @public * @returns {Array} */ toJSON() { return this.format(); } /** * Returns an HTTP status code suitable for use with the failure reason. * * @public * @static * @param {FailureReason} reason * @returns {number|null} */ static getHttpStatusCode(reason) { assert.argumentIsRequired(reason, "reason", FailureReason, "FailureReason"); let returnValue = null; reason.#root.walk((item) => { const code = import_FailureType.default.getHttpStatusCode(item.type); if (returnValue === null || returnValue !== 400) { returnValue = code; } }, false, false); return returnValue; } /** * Validates that a candidate conforms to a schema, returning a rejected * promise with a serialized {@link FailureReason} if a problem exists. * * The schema argument can be either a {@link Schema} instance or an * {@link Enum} instance that exposes a Schema through its schema property. * * @public * @static * @async * @param {Schema|EnumWithSchema} schema * @param {object} candidate * @param {string=} description * @returns {Promise<null>} */ static async validateSchema(schema, candidate, description) { let schemaToUse; if (schema instanceof import_Schema.default) { schemaToUse = schema; } else if (schema.schema && schema.schema instanceof import_Schema.default) { schemaToUse = schema.schema; } else { throw new TypeError("The schema argument must be a Schema instance or an Enum instance containing a Schema."); } const fields = schemaToUse.getInvalidFields(candidate); if (fields.length === 0) { return null; } let failure = FailureReason.forRequest({ endpoint: { description: description || `serialize data into ${schemaToUse.name}` } }).addItem(import_FailureType.default.REQUEST_INPUT_MALFORMED, {}, true); failure = fields.reduce((accumulator, field) => { accumulator.addItem(import_FailureType.default.REQUEST_PARAMETER_MALFORMED, { name: field.name }); return accumulator; }, failure); throw failure.format(); } /** * Returns a string representation. * * @public * @returns {string} */ toString() { return "[FailureReason]"; } } { const cjsExports = module.exports; const cjsDefaultExport = cjsExports && cjsExports.__esModule ? cjsExports.default : cjsExports; if (cjsDefaultExport && (typeof cjsDefaultExport === 'function' || typeof cjsDefaultExport === 'object')) { Object.keys(cjsExports).forEach((key) => { if (key !== 'default' && key !== '__esModule') { cjsDefaultExport[key] = cjsExports[key]; } }); } module.exports = cjsDefaultExport; }