提交 7cd8305e 编写于 作者: B Benjamin Pasero

revisit object.derive and ConnectionError (fixes #38234)

上级 f06a42a8
......@@ -5,157 +5,8 @@
'use strict';
import nls = require('vs/nls');
import objects = require('vs/base/common/objects');
import types = require('vs/base/common/types');
import arrays = require('vs/base/common/arrays');
import strings = require('vs/base/common/strings');
import { isUndefinedOrNull } from 'vs/base/common/types';
export interface IXHRResponse {
responseText: string;
status: number;
readyState: number;
getResponseHeader: (header: string) => string;
}
export interface IConnectionErrorData {
status: number;
statusText?: string;
responseText?: string;
}
/**
* The base class for all connection errors originating from XHR requests.
*/
export class ConnectionError implements Error {
public status: number;
public statusText: string;
public responseText: string;
public errorMessage: string;
public errorCode: string;
public errorObject: any;
public name: string;
constructor(mixin: IConnectionErrorData);
constructor(request: IXHRResponse);
constructor(arg: any) {
this.status = arg.status;
this.statusText = arg.statusText;
this.name = 'ConnectionError';
try {
this.responseText = arg.responseText;
} catch (e) {
this.responseText = '';
}
this.errorMessage = null;
this.errorCode = null;
this.errorObject = null;
if (this.responseText) {
try {
let errorObj = JSON.parse(this.responseText);
this.errorMessage = errorObj.message;
this.errorCode = errorObj.code;
this.errorObject = errorObj;
} catch (error) {
// Ignore
}
}
}
public get message(): string {
return this.connectionErrorToMessage(this, false);
}
public get verboseMessage(): string {
return this.connectionErrorToMessage(this, true);
}
private connectionErrorDetailsToMessage(error: ConnectionError, verbose: boolean): string {
let errorCode = error.errorCode;
let errorMessage = error.errorMessage;
if (!isUndefinedOrNull(errorCode) && typeof errorMessage === 'string') {
return nls.localize(
{
key: 'message',
comment: [
'{0} represents the error message',
'{1} represents the error code'
]
},
"{0}. Error code: {1}",
strings.rtrim(errorMessage, '.'), errorCode);
}
if (typeof errorMessage === 'string') {
return errorMessage;
}
if (verbose && typeof error.responseText === 'string') {
return error.responseText;
}
return null;
}
private connectionErrorToMessage(error: ConnectionError, verbose: boolean): string {
let details = this.connectionErrorDetailsToMessage(error, verbose);
// Status Code based Error
if (error.status === 401) {
if (typeof details === 'string') {
return nls.localize(
{
key: 'error.permission.verbose',
comment: [
'{0} represents detailed information why the permission got denied'
]
},
"Permission Denied (HTTP {0})",
details);
}
return nls.localize('error.permission', "Permission Denied");
}
// Return error details if present
if (details) {
return details;
}
// Fallback to HTTP Status and Code
if (error.status > 0 && typeof error.statusText === 'string') {
if (verbose && typeof error.responseText === 'string' && error.responseText.length > 0) {
return nls.localize('error.http.verbose', "{0} (HTTP {1}: {2})", error.statusText, error.status, error.responseText);
}
return nls.localize('error.http', "{0} (HTTP {1})", error.statusText, error.status);
}
// Finally its an Unknown Connection Error
if (verbose && typeof error.responseText === 'string' && error.responseText.length > 0) {
return nls.localize('error.connection.unknown.verbose', "Unknown Connection Error ({0})", error.responseText);
}
return nls.localize('error.connection.unknown', "An unknown connection error occurred. Either you are no longer connected to the internet or the server you are connected to is offline.");
}
}
// Bug: Can not subclass a JS Type. Do it manually (as done in WinJS.Class.derive)
objects.derive(Error, ConnectionError);
function xhrToErrorMessage(xhr: IConnectionErrorData, verbose: boolean): string {
let ce = new ConnectionError(xhr);
if (verbose) {
return ce.verboseMessage;
} else {
return ce.message;
}
}
function exceptionToErrorMessage(exception: any, verbose: boolean): string {
if (exception.message) {
......@@ -182,6 +33,7 @@ function detectSystemErrorMessage(exception: any): string {
/**
* Tries to generate a human readable error message out of the error. If the verbose parameter
* is set to true, the error message will include stacktrace details if provided.
*
* @returns A string containing the error message.
*/
export function toErrorMessage(error: any = null, verbose: boolean = false): string {
......@@ -190,8 +42,8 @@ export function toErrorMessage(error: any = null, verbose: boolean = false): str
}
if (Array.isArray(error)) {
let errors: any[] = arrays.coalesce(error);
let msg = toErrorMessage(errors[0], verbose);
const errors: any[] = arrays.coalesce(error);
const msg = toErrorMessage(errors[0], verbose);
if (errors.length > 1) {
return nls.localize('error.moreErrors', "{0} ({1} errors in total)", msg, errors.length);
......@@ -204,36 +56,14 @@ export function toErrorMessage(error: any = null, verbose: boolean = false): str
return error;
}
if (!types.isUndefinedOrNull(error.status)) {
return xhrToErrorMessage(error, verbose);
}
if (error.detail) {
let detail = error.detail;
const detail = error.detail;
if (detail.error) {
if (detail.error && !types.isUndefinedOrNull(detail.error.status)) {
return xhrToErrorMessage(detail.error, verbose);
}
if (types.isArray(detail.error)) {
for (let i = 0; i < detail.error.length; i++) {
if (detail.error[i] && !types.isUndefinedOrNull(detail.error[i].status)) {
return xhrToErrorMessage(detail.error[i], verbose);
}
}
}
else {
return exceptionToErrorMessage(detail.error, verbose);
}
return exceptionToErrorMessage(detail.error, verbose);
}
if (detail.exception) {
if (!types.isUndefinedOrNull(detail.exception.status)) {
return xhrToErrorMessage(detail.exception, verbose);
}
return exceptionToErrorMessage(detail.exception, verbose);
}
}
......
......@@ -205,34 +205,6 @@ export function createKeywordMatcher(arr: string[], caseInsensitive: boolean = f
}
}
/**
* Started from TypeScript's __extends function to make a type a subclass of a specific class.
* Modified to work with properties already defined on the derivedClass, since we can't get TS
* to call this method before the constructor definition.
*/
export function derive(baseClass: any, derivedClass: any): void {
for (let prop in baseClass) {
if (baseClass.hasOwnProperty(prop)) {
derivedClass[prop] = baseClass[prop];
}
}
derivedClass = derivedClass || function () { };
const basePrototype = baseClass.prototype;
const derivedPrototype = derivedClass.prototype;
derivedClass.prototype = Object.create(basePrototype);
for (let prop in derivedPrototype) {
if (derivedPrototype.hasOwnProperty(prop)) {
// handle getters and setters properly
Object.defineProperty(derivedClass.prototype, prop, Object.getOwnPropertyDescriptor(derivedPrototype, prop));
}
}
// Cast to any due to Bug 16188:PropertyDescriptor set and get function should be optional.
Object.defineProperty(derivedClass.prototype, 'constructor', { value: derivedClass, writable: true, configurable: true, enumerable: true });
}
/**
* Calls JSON.Stringify with a replacer to break apart any circular references.
* This prevents JSON.stringify from throwing the exception
......
......@@ -13,33 +13,12 @@ suite('Errors', () => {
assert.strictEqual(toErrorMessage(new Error('Foo Bar')), 'Foo Bar');
let error: any = new Error();
error.status = 404;
error.statusText = 'Not Found';
assert.strictEqual(toErrorMessage(error), 'Not Found (HTTP 404)');
error = new Error();
error.detail = {};
error.detail.exception = {};
error.detail.exception.message = 'Foo Bar';
assert.strictEqual(toErrorMessage(error), 'Foo Bar');
error = new Error();
error.detail = {};
error.detail.error = {};
error.detail.error.status = 404;
error.detail.error.statusText = 'Not Found';
assert.strictEqual(toErrorMessage(error), 'Not Found (HTTP 404)');
error = new Error();
error.detail = {};
error.detail.error = [];
let foo: any = {};
error.detail.error.push(foo);
foo.status = 404;
foo.statusText = 'Not Found';
assert.strictEqual(toErrorMessage(error), 'Not Found (HTTP 404)');
assert(toErrorMessage());
assert(toErrorMessage(null));
assert(toErrorMessage({}));
......
......@@ -138,42 +138,6 @@ suite('Objects', () => {
});
});
test('derive', function () {
let someValue = 2;
function Base(): void {
//example
}
(<any>Base).favoriteColor = 'blue';
Base.prototype.test = function () { return 42; };
function Child(): void {
//example
}
Child.prototype.test2 = function () { return 43; };
Object.defineProperty(Child.prototype, 'getter', {
get: function () { return someValue; },
enumerable: true,
configurable: true
});
objects.derive(Base, Child);
let base = new Base();
let child = new Child();
assert(base instanceof Base);
assert(child instanceof Child);
assert.strictEqual(base.test, child.test);
assert.strictEqual(base.test(), 42);
assert.strictEqual(child.test2(), 43);
assert.strictEqual((<any>Child).favoriteColor, 'blue');
someValue = 4;
assert.strictEqual(child.getter, 4);
});
test('distinct', function () {
let base = {
one: 'one',
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册