@zowe/imperative
Version:
framework for building configurable CLIs
243 lines • 9.42 kB
JavaScript
;
/*
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright Contributors to the Zowe Project.
*
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ImperativeError = void 0;
const os = require("node:os");
/**
*
* @export
* @class ImperativeError
* @extends {Error}
*/
class ImperativeError extends Error {
/**
* Construct the Imperative error object. Contains the defaults of the error and optionally captures diagnostics
* and other information.
* @param {IImperativeError} details - the error details and text (stack, messages, etc.)
* @param {IImperativeErrorParms} parms - control parameters to indicate logging of node-report and more
*/
constructor(mDetails, parms) {
super();
this.mDetails = mDetails;
this.mMessage = mDetails.msg;
/**
* If parms are present, handle them, otherwise perform the default diagnostic collection
*/
if (parms) {
/**
* Append a tag if present
*/
if (parms.tag) {
this.mMessage = parms.tag + ": " + this.mMessage;
}
}
}
/**
* Within the Zowe client SDK, errors are often thrown, caught, modified, and re-thrown.
* Sometimes the error that we catch is a standard JavaScript Error. Other times the
* error is already an ImperativeError (which can contain more details). A hard-coded
* reliance on ImperativeError properties like causeErrors and additionalDetails will not
* work if the existingErr is a standard JavaScript Error. Also, the properties of an
* ImperativeError can be nested under various properties within its causeErrors property.
*
* The purpose of this utility function is to interrogate the existing error to form the
* most meaningful ImperativeError possible.
*
* @param {string} existingErr
* An existing error to be incorporated into the resulting ImperativeError.
*
* @param {string} mainMsg
* The main message text for the resulting ImperativeError. If not supplied,
* the existingErr.message value will be used.
*
* @returns A newly created ImperativeError
* @memberof ImperativeError
*/
static newImpErrorFromExistingError(existingErr, mainMsg = "") {
var _a, _b, _c, _d, _e, _f, _g;
if (!existingErr) {
return new ImperativeError({
msg: "The supplied parameter 'existingErr' was incorrectly null or undefined",
causeErrors: "Stupid programming error",
additionalDetails: "Fix your program"
});
}
// set a mainMsg if one is not supplied as a parm
let existingErrMsgUsed = false;
if (!mainMsg) {
if (existingErr.mMessage) {
mainMsg = existingErr.mMessage;
existingErrMsgUsed = true;
}
else if (existingErr.message) {
mainMsg = existingErr.message;
existingErrMsgUsed = true;
}
else {
mainMsg = "No problem text was supplied.";
}
}
// use the existingErr's message text as the cause (unless we already used that message)
let causeToUse = "";
if (existingErr.mMessage && !existingErrMsgUsed) {
causeToUse = existingErr.mMessage;
}
else if (existingErr.message && !existingErrMsgUsed) {
causeToUse = existingErr.message;
}
else if ((_a = existingErr.causeErrors) === null || _a === void 0 ? void 0 : _a.mMessage) {
causeToUse = existingErr.causeErrors.mMessage;
}
else if ((_b = existingErr.cause) === null || _b === void 0 ? void 0 : _b.message) {
causeToUse = existingErr.cause.message;
}
const detailsOutput = {
stringVal: "",
rawVal: {}
};
// Record existingErr's causeErrors property as a string or as raw data.
// Sometimes causeErrors are nested. Try the nested one first.
if (!ImperativeError.recordPropForOutput((_e = (_d = (_c = existingErr.mDetails) === null || _c === void 0 ? void 0 : _c.causeErrors) === null || _d === void 0 ? void 0 : _d.mDetails) === null || _e === void 0 ? void 0 : _e.causeErrors, detailsOutput)) {
ImperativeError.recordPropForOutput((_f = existingErr.mDetails) === null || _f === void 0 ? void 0 : _f.causeErrors, detailsOutput);
}
// Append existingErr's additionalDetails-like property if it is a string, or record it as an object
if (!ImperativeError.recordPropForOutput(existingErr.additionalDetails, detailsOutput)) {
if (!ImperativeError.recordPropForOutput((_g = existingErr.causeErrors) === null || _g === void 0 ? void 0 : _g.additionalDetails, detailsOutput)) {
if (!ImperativeError.recordPropForOutput(existingErr.cause, detailsOutput)) {
if (!(existingErr instanceof ImperativeError)) {
// only record the entire existingErr for other people's errors
ImperativeError.recordPropForOutput(existingErr, detailsOutput);
}
}
}
}
// if we could not discover a text message, dump the recorded raw data
if (detailsOutput.stringVal.length === 0) {
if (Object.keys(detailsOutput.rawVal).length > 0) {
detailsOutput.stringVal = ImperativeError.RAW_ERR_MSG + JSON.stringify(detailsOutput.rawVal, null, 2);
}
}
if (detailsOutput.stringVal.length === 0) {
detailsOutput.stringVal = "No further details are available.";
}
const impErrProps = {
msg: mainMsg,
additionalDetails: detailsOutput.stringVal
};
if (causeToUse.length > 0) {
impErrProps.causeErrors = causeToUse;
}
return new ImperativeError(impErrProps);
}
/**
* This function interrogates the supplied propertyVal. If it is a string, it it appended
* to outputData.stringVal. If propertyVal is not a string and it is not null-or-undefined,
* and outputData.rawVal is currently empty, propertyVal is placed into outputData.rawVal.
*
* @param {IErrOutputData} outputData [output]
* One (or neither) of outputData.stringVal or outputData.rawVal properties are
* populated by this function. Before the first call to recordPropForOutput,
* stringVal should be an empty string and rawVal should be an empty object.
*
* @returns True if a property was recorded. False otherwise.
* @memberof ImperativeError
*/
static recordPropForOutput(propertyVal, outputData) {
if (!propertyVal) {
return false;
}
if (typeof propertyVal === "string") {
if (propertyVal.startsWith(ImperativeError.RAW_ERR_MSG)) {
// do not append to our stringVal if propertyVal is already stringified raw data
return false;
}
// append to the string output
if (outputData.stringVal.length > 0 && propertyVal.length > 0) {
outputData.stringVal += os.EOL;
}
outputData.stringVal += propertyVal;
return true;
}
else if (Object.keys(outputData.rawVal).length === 0) {
// only record one raw property
outputData.rawVal = JSON.stringify(propertyVal);
return true;
}
return false;
}
/**
* Return causeErrors
* @readonly
* @type {any[]}
* @memberof ImperativeError
*/
get causeErrors() {
return this.mDetails.causeErrors;
}
/**
* Return additionalDetails
* @readonly
* @type {string}
* @memberof ImperativeError
*/
get additionalDetails() {
return this.mDetails.additionalDetails;
}
/**
* Return IImperativeError object
* @readonly
* @type {IImperativeError}
* @memberof ImperativeError
*/
get details() {
return this.mDetails;
}
/**
* Return errorCode
* @readonly
* @type {string}
* @memberof ImperativeError
*/
get errorCode() {
return this.mDetails.errorCode;
}
/**
* Return whether or not the error dump should be suppressed
* @readonly
* @type {string}
* @memberof ImperativeError
*/
get suppressDump() {
return this.mDetails.suppressDump;
}
/**
* Return stack info
* @readonly
* @type {string}
* @memberof ImperativeError
*/
get stack() {
return this.mDetails.stack;
}
/**
* Accessor for the error message.
* @readonly
* @return {string}: The error message
* @memberof ImperativeError
*/
get message() {
return this.mMessage;
}
}
exports.ImperativeError = ImperativeError;
ImperativeError.RAW_ERR_MSG = "Raw error data from operation:\n";
//# sourceMappingURL=ImperativeError.js.map