mirror of
https://github.com/balena-io/etcher.git
synced 2025-07-21 02:06:33 +00:00
Convert errors.js to typescript
Change-type: patch
This commit is contained in:
parent
30c2ef58cd
commit
9109f0ccd5
@ -24,6 +24,7 @@ const _ = require('lodash')
|
|||||||
const Bluebird = require('bluebird')
|
const Bluebird = require('bluebird')
|
||||||
// eslint-disable-next-line node/no-missing-require
|
// eslint-disable-next-line node/no-missing-require
|
||||||
const localSettings = require('./local-settings')
|
const localSettings = require('./local-settings')
|
||||||
|
// eslint-disable-next-line node/no-missing-require
|
||||||
const errors = require('../../../shared/errors')
|
const errors = require('../../../shared/errors')
|
||||||
const packageJSON = require('../../../../package.json')
|
const packageJSON = require('../../../../package.json')
|
||||||
const debug = require('debug')('etcher:models:settings')
|
const debug = require('debug')('etcher:models:settings')
|
||||||
|
@ -23,6 +23,7 @@ const uuidV4 = require('uuid/v4')
|
|||||||
const constraints = require('../../../shared/drive-constraints')
|
const constraints = require('../../../shared/drive-constraints')
|
||||||
// eslint-disable-next-line node/no-missing-require
|
// eslint-disable-next-line node/no-missing-require
|
||||||
const supportedFormats = require('../../../shared/supported-formats')
|
const supportedFormats = require('../../../shared/supported-formats')
|
||||||
|
// eslint-disable-next-line node/no-missing-require
|
||||||
const errors = require('../../../shared/errors')
|
const errors = require('../../../shared/errors')
|
||||||
// eslint-disable-next-line node/no-missing-require
|
// eslint-disable-next-line node/no-missing-require
|
||||||
const fileExtensions = require('../../../shared/file-extensions')
|
const fileExtensions = require('../../../shared/file-extensions')
|
||||||
|
@ -25,6 +25,7 @@ const electron = require('electron')
|
|||||||
const store = require('../models/store')
|
const store = require('../models/store')
|
||||||
const settings = require('../models/settings')
|
const settings = require('../models/settings')
|
||||||
const flashState = require('../models/flash-state')
|
const flashState = require('../models/flash-state')
|
||||||
|
// eslint-disable-next-line node/no-missing-require
|
||||||
const errors = require('../../../shared/errors')
|
const errors = require('../../../shared/errors')
|
||||||
const permissions = require('../../../shared/permissions')
|
const permissions = require('../../../shared/permissions')
|
||||||
// eslint-disable-next-line node/no-missing-require
|
// eslint-disable-next-line node/no-missing-require
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const electron = require('electron')
|
const electron = require('electron')
|
||||||
const Bluebird = require('bluebird')
|
const Bluebird = require('bluebird')
|
||||||
|
// eslint-disable-next-line node/no-missing-require
|
||||||
const errors = require('../../../shared/errors')
|
const errors = require('../../../shared/errors')
|
||||||
// eslint-disable-next-line node/no-missing-require
|
// eslint-disable-next-line node/no-missing-require
|
||||||
const supportedFormats = require('../../../shared/supported-formats')
|
const supportedFormats = require('../../../shared/supported-formats')
|
||||||
|
@ -22,6 +22,7 @@ const ipc = require('node-ipc')
|
|||||||
const sdk = require('etcher-sdk')
|
const sdk = require('etcher-sdk')
|
||||||
// eslint-disable-next-line node/no-missing-require
|
// eslint-disable-next-line node/no-missing-require
|
||||||
const EXIT_CODES = require('../../shared/exit-codes')
|
const EXIT_CODES = require('../../shared/exit-codes')
|
||||||
|
// eslint-disable-next-line node/no-missing-require
|
||||||
const errors = require('../../shared/errors')
|
const errors = require('../../shared/errors')
|
||||||
|
|
||||||
ipc.config.id = process.env.IPC_CLIENT_ID
|
ipc.config.id = process.env.IPC_CLIENT_ID
|
||||||
|
@ -1,369 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 balena.io
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict'
|
|
||||||
|
|
||||||
const _ = require('lodash')
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Create an error details object
|
|
||||||
* @function
|
|
||||||
* @private
|
|
||||||
*
|
|
||||||
* @param {Object} options - options
|
|
||||||
* @param {(String|Function)} options.title - error title
|
|
||||||
* @param {(String|Function)} options.description - error description
|
|
||||||
* @returns {Object} error details object
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* const details = createErrorDetails({
|
|
||||||
* title: (error) => {
|
|
||||||
* return `An error happened, the code is ${error.code}`;
|
|
||||||
* },
|
|
||||||
* description: 'This is the error description'
|
|
||||||
* });
|
|
||||||
*/
|
|
||||||
const createErrorDetails = (options) => {
|
|
||||||
return _.pick(_.mapValues(options, (value) => {
|
|
||||||
return _.isFunction(value) ? value : _.constant(value)
|
|
||||||
}), [ 'title', 'description' ])
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Human-friendly error messages
|
|
||||||
* @namespace HUMAN_FRIENDLY
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
exports.HUMAN_FRIENDLY = {
|
|
||||||
|
|
||||||
/* eslint-disable new-cap */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @namespace ENOENT
|
|
||||||
* @memberof HUMAN_FRIENDLY
|
|
||||||
*/
|
|
||||||
ENOENT: createErrorDetails({
|
|
||||||
title: (error) => {
|
|
||||||
return `No such file or directory: ${error.path}`
|
|
||||||
},
|
|
||||||
description: 'The file you\'re trying to access doesn\'t exist'
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @namespace EPERM
|
|
||||||
* @memberof HUMAN_FRIENDLY
|
|
||||||
*/
|
|
||||||
EPERM: createErrorDetails({
|
|
||||||
title: 'You\'re not authorized to perform this operation',
|
|
||||||
description: 'Please ensure you have necessary permissions for this task'
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @namespace EACCES
|
|
||||||
* @memberof HUMAN_FRIENDLY
|
|
||||||
*/
|
|
||||||
EACCES: createErrorDetails({
|
|
||||||
title: 'You don\'t have access to this resource',
|
|
||||||
description: 'Please ensure you have necessary permissions to access this resource'
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @namespace ENOMEM
|
|
||||||
* @memberof HUMAN_FRIENDLY
|
|
||||||
*/
|
|
||||||
ENOMEM: createErrorDetails({
|
|
||||||
title: 'Your system ran out of memory',
|
|
||||||
description: 'Please make sure your system has enough available memory for this task'
|
|
||||||
})
|
|
||||||
|
|
||||||
/* eslint-enable new-cap */
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get user friendly property from an error
|
|
||||||
* @function
|
|
||||||
* @private
|
|
||||||
*
|
|
||||||
* @param {Error} error - error
|
|
||||||
* @param {String} property - HUMAN_FRIENDLY property
|
|
||||||
* @returns {(String|Undefined)} user friendly message
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* const error = new Error('My error');
|
|
||||||
* error.code = 'ENOMEM';
|
|
||||||
*
|
|
||||||
* const friendlyDescription = getUserFriendlyMessageProperty(error, 'description');
|
|
||||||
*
|
|
||||||
* if (friendlyDescription) {
|
|
||||||
* console.log(friendlyDescription);
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
const getUserFriendlyMessageProperty = (error, property) => {
|
|
||||||
const code = _.get(error, [ 'code' ])
|
|
||||||
|
|
||||||
if (_.isNil(code) || !_.isString(code)) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return _.invoke(exports.HUMAN_FRIENDLY, [ code, property ], error)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Check if a string is blank
|
|
||||||
* @function
|
|
||||||
* @private
|
|
||||||
*
|
|
||||||
* @param {String} string - string
|
|
||||||
* @returns {Boolean} whether the string is blank
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* if (isBlank(' ')) {
|
|
||||||
* console.log('The string is blank');
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
const isBlank = _.flow([ _.trim, _.isEmpty ])
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get the title of an error
|
|
||||||
* @function
|
|
||||||
* @public
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Try to get as much information as possible about the error
|
|
||||||
* rather than falling back to generic messages right away.
|
|
||||||
*
|
|
||||||
* @param {Error} error - error
|
|
||||||
* @returns {String} error title
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* const error = new Error('Foo bar');
|
|
||||||
* const title = errors.getTitle(error);
|
|
||||||
* console.log(title);
|
|
||||||
*/
|
|
||||||
exports.getTitle = (error) => {
|
|
||||||
if (!_.isError(error) && !_.isPlainObject(error) && !_.isNil(error)) {
|
|
||||||
return _.toString(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
const codeTitle = getUserFriendlyMessageProperty(error, 'title')
|
|
||||||
if (!_.isNil(codeTitle)) {
|
|
||||||
return codeTitle
|
|
||||||
}
|
|
||||||
|
|
||||||
const message = _.get(error, [ 'message' ])
|
|
||||||
if (!isBlank(message)) {
|
|
||||||
return message
|
|
||||||
}
|
|
||||||
|
|
||||||
const code = _.get(error, [ 'code' ])
|
|
||||||
if (!_.isNil(code) && !isBlank(code)) {
|
|
||||||
return `Error code: ${code}`
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'An error ocurred'
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Get the description of an error
|
|
||||||
* @function
|
|
||||||
* @public
|
|
||||||
*
|
|
||||||
* @param {Error} error - error
|
|
||||||
* @param {Object} options - options
|
|
||||||
* @param {Boolean} [options.userFriendlyDescriptionsOnly=false] - only return user friendly descriptions
|
|
||||||
* @returns {String} error description
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* const error = new Error('Foo bar');
|
|
||||||
* const description = errors.getDescription(error);
|
|
||||||
* console.log(description);
|
|
||||||
*/
|
|
||||||
exports.getDescription = (error, options = {}) => {
|
|
||||||
_.defaults(options, {
|
|
||||||
userFriendlyDescriptionsOnly: false
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!_.isError(error) && !_.isPlainObject(error)) {
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isBlank(error.description)) {
|
|
||||||
return error.description
|
|
||||||
}
|
|
||||||
|
|
||||||
const codeDescription = getUserFriendlyMessageProperty(error, 'description')
|
|
||||||
if (!_.isNil(codeDescription)) {
|
|
||||||
return codeDescription
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.userFriendlyDescriptionsOnly) {
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error.stack) {
|
|
||||||
return error.stack
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_.isEmpty(error)) {
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
|
|
||||||
const INDENTATION_SPACES = 2
|
|
||||||
return JSON.stringify(error, null, INDENTATION_SPACES)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Create an error
|
|
||||||
* @function
|
|
||||||
* @public
|
|
||||||
*
|
|
||||||
* @param {Object} options - options
|
|
||||||
* @param {String} options.title - error title
|
|
||||||
* @param {String} [options.description] - error description
|
|
||||||
* @param {Boolean} [options.report] - report error
|
|
||||||
* @returns {Error} error
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* const error = errors.createError({
|
|
||||||
* title: 'Foo'
|
|
||||||
* description: 'Bar'
|
|
||||||
* });
|
|
||||||
*
|
|
||||||
* throw error;
|
|
||||||
*/
|
|
||||||
exports.createError = (options) => {
|
|
||||||
if (isBlank(options.title)) {
|
|
||||||
throw new Error(`Invalid error title: ${options.title}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
const error = new Error(options.title)
|
|
||||||
error.description = options.description
|
|
||||||
|
|
||||||
if (!_.isNil(options.report) && !options.report) {
|
|
||||||
error.report = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_.isNil(options.code)) {
|
|
||||||
error.code = options.code
|
|
||||||
}
|
|
||||||
|
|
||||||
return error
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Create a user error
|
|
||||||
* @function
|
|
||||||
* @public
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* User errors represent invalid states that the user
|
|
||||||
* caused, that are not errors on the application itself.
|
|
||||||
* Therefore, user errors don't get reported to analytics
|
|
||||||
* and error reporting services.
|
|
||||||
*
|
|
||||||
* @param {Object} options - options
|
|
||||||
* @param {String} options.title - error title
|
|
||||||
* @param {String} [options.description] - error description
|
|
||||||
* @returns {Error} user error
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* const error = errors.createUserError({
|
|
||||||
* title: 'Foo',
|
|
||||||
* description: 'Bar'
|
|
||||||
* });
|
|
||||||
*
|
|
||||||
* throw error;
|
|
||||||
*/
|
|
||||||
exports.createUserError = (options) => {
|
|
||||||
return exports.createError({
|
|
||||||
title: options.title,
|
|
||||||
description: options.description,
|
|
||||||
report: false,
|
|
||||||
code: options.code
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Check if an error is an user error
|
|
||||||
* @function
|
|
||||||
* @public
|
|
||||||
*
|
|
||||||
* @param {Error} error - error
|
|
||||||
* @returns {Boolean} whether the error is a user error
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* const error = errors.createUserError('Foo', 'Bar');
|
|
||||||
*
|
|
||||||
* if (errors.isUserError(error)) {
|
|
||||||
* console.log('This error is a user error');
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
exports.isUserError = (error) => {
|
|
||||||
return _.isNil(error.report) ? false : !error.report
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Convert an Error object to a JSON object
|
|
||||||
* @function
|
|
||||||
* @public
|
|
||||||
*
|
|
||||||
* @param {Error} error - error object
|
|
||||||
* @returns {Object} json error
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* const error = errors.toJSON(new Error('foo'))
|
|
||||||
*
|
|
||||||
* console.log(error.message);
|
|
||||||
* > 'foo'
|
|
||||||
*/
|
|
||||||
exports.toJSON = (error) => {
|
|
||||||
// Handle string error objects to be on the safe side
|
|
||||||
const isErrorLike = _.isError(error) || _.isPlainObject(error)
|
|
||||||
const errorObject = isErrorLike ? error : new Error(error)
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: errorObject.name,
|
|
||||||
message: errorObject.message,
|
|
||||||
description: errorObject.description,
|
|
||||||
stack: errorObject.stack,
|
|
||||||
report: errorObject.report,
|
|
||||||
code: errorObject.code,
|
|
||||||
syscall: errorObject.syscall,
|
|
||||||
errno: errorObject.errno,
|
|
||||||
stdout: errorObject.stdout,
|
|
||||||
stderr: errorObject.stderr,
|
|
||||||
device: errorObject.device
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Convert a JSON object to an Error object
|
|
||||||
* @function
|
|
||||||
* @public
|
|
||||||
*
|
|
||||||
* @param {Error} json - json object
|
|
||||||
* @returns {Object} error object
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* const error = errors.fromJSON(errors.toJSON(new Error('foo')));
|
|
||||||
*
|
|
||||||
* console.log(error.message);
|
|
||||||
* > 'foo'
|
|
||||||
*/
|
|
||||||
exports.fromJSON = (json) => {
|
|
||||||
return _.assign(new Error(json.message), json)
|
|
||||||
}
|
|
264
lib/shared/errors.ts
Normal file
264
lib/shared/errors.ts
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 balena.io
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
function createErrorDetails(options: {
|
||||||
|
title: string | ((error: Error) => string);
|
||||||
|
description: string | ((error: Error) => string);
|
||||||
|
}): {
|
||||||
|
title: (error: Error) => string;
|
||||||
|
description: (error: Error) => string;
|
||||||
|
} {
|
||||||
|
return _.pick(
|
||||||
|
_.mapValues(options, value => {
|
||||||
|
return _.isFunction(value) ? value : _.constant(value);
|
||||||
|
}),
|
||||||
|
['title', 'description'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Human-friendly error messages
|
||||||
|
*/
|
||||||
|
export const HUMAN_FRIENDLY = {
|
||||||
|
ENOENT: createErrorDetails({
|
||||||
|
title: (error: Error & { path: string }) => {
|
||||||
|
return `No such file or directory: ${error.path}`;
|
||||||
|
},
|
||||||
|
description: "The file you're trying to access doesn't exist",
|
||||||
|
}),
|
||||||
|
EPERM: createErrorDetails({
|
||||||
|
title: "You're not authorized to perform this operation",
|
||||||
|
description: 'Please ensure you have necessary permissions for this task',
|
||||||
|
}),
|
||||||
|
EACCES: createErrorDetails({
|
||||||
|
title: "You don't have access to this resource",
|
||||||
|
description:
|
||||||
|
'Please ensure you have necessary permissions to access this resource',
|
||||||
|
}),
|
||||||
|
ENOMEM: createErrorDetails({
|
||||||
|
title: 'Your system ran out of memory',
|
||||||
|
description:
|
||||||
|
'Please make sure your system has enough available memory for this task',
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Get user friendly property from an error
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const error = new Error('My error');
|
||||||
|
* error.code = 'ENOMEM';
|
||||||
|
*
|
||||||
|
* const friendlyDescription = getUserFriendlyMessageProperty(error, 'description');
|
||||||
|
*
|
||||||
|
* if (friendlyDescription) {
|
||||||
|
* console.log(friendlyDescription);
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
function getUserFriendlyMessageProperty(
|
||||||
|
error: Error,
|
||||||
|
property: 'title' | 'description',
|
||||||
|
): string | null {
|
||||||
|
const code = _.get(error, ['code']);
|
||||||
|
|
||||||
|
if (_.isNil(code) || !_.isString(code)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _.invoke(HUMAN_FRIENDLY, [code, property], error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isBlank = _.flow([_.trim, _.isEmpty]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Get the title of an error
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Try to get as much information as possible about the error
|
||||||
|
* rather than falling back to generic messages right away.
|
||||||
|
*/
|
||||||
|
export function getTitle(error: Error): string {
|
||||||
|
if (!_.isError(error) && !_.isPlainObject(error) && !_.isNil(error)) {
|
||||||
|
return _.toString(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const codeTitle = getUserFriendlyMessageProperty(error, 'title');
|
||||||
|
if (!_.isNil(codeTitle)) {
|
||||||
|
return codeTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = _.get(error, ['message']);
|
||||||
|
if (!isBlank(message)) {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
const code = _.get(error, ['code']);
|
||||||
|
if (!_.isNil(code) && !isBlank(code)) {
|
||||||
|
return `Error code: ${code}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'An error ocurred';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Get the description of an error
|
||||||
|
*/
|
||||||
|
export function getDescription(
|
||||||
|
error: Error & { description?: string },
|
||||||
|
options: { userFriendlyDescriptionsOnly?: boolean } = {},
|
||||||
|
): string {
|
||||||
|
_.defaults(options, {
|
||||||
|
userFriendlyDescriptionsOnly: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!_.isError(error) && !_.isPlainObject(error)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isBlank(error.description)) {
|
||||||
|
return error.description as string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const codeDescription = getUserFriendlyMessageProperty(error, 'description');
|
||||||
|
if (!_.isNil(codeDescription)) {
|
||||||
|
return codeDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.userFriendlyDescriptionsOnly) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error.stack) {
|
||||||
|
return error.stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_.isEmpty(error)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const INDENTATION_SPACES = 2;
|
||||||
|
return JSON.stringify(error, null, INDENTATION_SPACES);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Create an error
|
||||||
|
*/
|
||||||
|
export function createError(options: {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
report: boolean;
|
||||||
|
code: string;
|
||||||
|
}): Error & { description?: string; report?: boolean; code?: string } {
|
||||||
|
if (isBlank(options.title)) {
|
||||||
|
throw new Error(`Invalid error title: ${options.title}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const error: Error & {
|
||||||
|
description?: string;
|
||||||
|
report?: boolean;
|
||||||
|
code?: string;
|
||||||
|
} = new Error(options.title);
|
||||||
|
error.description = options.description;
|
||||||
|
|
||||||
|
if (!_.isNil(options.report) && !options.report) {
|
||||||
|
error.report = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_.isNil(options.code)) {
|
||||||
|
error.code = options.code;
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Create a user error
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* User errors represent invalid states that the user
|
||||||
|
* caused, that are not errors on the application itself.
|
||||||
|
* Therefore, user errors don't get reported to analytics
|
||||||
|
* and error reporting services.
|
||||||
|
*/
|
||||||
|
export function createUserError(options: {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
code: string;
|
||||||
|
}): Error {
|
||||||
|
return createError({
|
||||||
|
title: options.title,
|
||||||
|
description: options.description,
|
||||||
|
report: false,
|
||||||
|
code: options.code,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Check if an error is an user error
|
||||||
|
*/
|
||||||
|
export function isUserError(error: Error & { report?: boolean }): boolean {
|
||||||
|
return _.isNil(error.report) ? false : !error.report;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Convert an Error object to a JSON object
|
||||||
|
* @function
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* @param {Error} error - error object
|
||||||
|
* @returns {Object} json error
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const error = errors.toJSON(new Error('foo'))
|
||||||
|
*
|
||||||
|
* console.log(error.message);
|
||||||
|
* > 'foo'
|
||||||
|
*/
|
||||||
|
export function toJSON(
|
||||||
|
error: Error & {
|
||||||
|
description?: string;
|
||||||
|
report?: boolean;
|
||||||
|
code?: string;
|
||||||
|
syscall?: string;
|
||||||
|
errno?: number;
|
||||||
|
stdout?: string;
|
||||||
|
stderr?: string;
|
||||||
|
device?: string;
|
||||||
|
},
|
||||||
|
): any {
|
||||||
|
return {
|
||||||
|
name: error.name,
|
||||||
|
message: error.message,
|
||||||
|
description: error.description,
|
||||||
|
stack: error.stack,
|
||||||
|
report: error.report,
|
||||||
|
code: error.code,
|
||||||
|
syscall: error.syscall,
|
||||||
|
errno: error.errno,
|
||||||
|
stdout: error.stdout,
|
||||||
|
stderr: error.stderr,
|
||||||
|
device: error.device,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Convert a JSON object to an Error object
|
||||||
|
*/
|
||||||
|
export function fromJSON(json: any): Error {
|
||||||
|
return _.assign(new Error(json.message), json);
|
||||||
|
}
|
@ -28,6 +28,7 @@ const semver = require('semver')
|
|||||||
const sudoPrompt = Bluebird.promisifyAll(require('sudo-prompt'))
|
const sudoPrompt = Bluebird.promisifyAll(require('sudo-prompt'))
|
||||||
const { promisify } = require('util')
|
const { promisify } = require('util')
|
||||||
|
|
||||||
|
// eslint-disable-next-line node/no-missing-require
|
||||||
const errors = require('./errors')
|
const errors = require('./errors')
|
||||||
|
|
||||||
const { tmpFileDisposer } = require('./utils')
|
const { tmpFileDisposer } = require('./utils')
|
||||||
|
@ -21,6 +21,7 @@ const Bluebird = require('bluebird')
|
|||||||
const request = Bluebird.promisifyAll(require('request'))
|
const request = Bluebird.promisifyAll(require('request'))
|
||||||
const tmp = require('tmp')
|
const tmp = require('tmp')
|
||||||
|
|
||||||
|
// eslint-disable-next-line node/no-missing-require
|
||||||
const errors = require('./errors')
|
const errors = require('./errors')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
const m = require('mochainon')
|
const m = require('mochainon')
|
||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
|
// eslint-disable-next-line node/no-missing-require
|
||||||
const errors = require('../../lib/shared/errors')
|
const errors = require('../../lib/shared/errors')
|
||||||
|
|
||||||
describe('Shared: Errors', function () {
|
describe('Shared: Errors', function () {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user