未验证 提交 d556e110 编写于 作者: A Asher

Include code in stringified errors

This is done by returning the entire error stringified instead of just
the message.

This fixes the issue with the "save as" dialog.
上级 be3f0c43
......@@ -496,8 +496,9 @@ describe("fs", () => {
});
it("should fail to stat nonexistent file", async () => {
await expect(util.promisify(fs.stat)(tmpFile()))
.rejects.toThrow("ENOENT");
const error = await util.promisify(fs.stat)(tmpFile()).catch((e) => e);
expect(error.message).toContain("ENOENT");
expect(error.code).toBe("ENOENT");
});
});
......
......@@ -98,7 +98,7 @@ export class Client {
const eventsMsg = new EvalEventMessage();
eventsMsg.setId(doEval.id);
eventsMsg.setEvent(event);
eventsMsg.setArgsList(args.map(stringify));
eventsMsg.setArgsList(args.map((a) => stringify(a)));
const clientMsg = new ClientMessage();
clientMsg.setEvalEvent(eventsMsg);
this.connection.send(clientMsg.serializeBinary());
......@@ -140,7 +140,7 @@ export class Client {
const id = this.evalId++;
newEval.setId(id);
newEval.setActive(active);
newEval.setArgsList([a1, a2, a3, a4, a5, a6].map(stringify));
newEval.setArgsList([a1, a2, a3, a4, a5, a6].map((a) => stringify(a)));
newEval.setFunction(func.toString());
const clientMsg = new ClientMessage();
......@@ -155,16 +155,15 @@ export class Client {
const d1 = this.evalDoneEmitter.event((doneMsg) => {
if (doneMsg.getId() === id) {
const resp = doneMsg.getResponse();
dispose();
resolve(parse(resp));
resolve(parse(doneMsg.getResponse()));
}
});
const d2 = this.evalFailedEmitter.event((failedMsg) => {
if (failedMsg.getId() === id) {
dispose();
reject(new Error(failedMsg.getMessage()));
reject(parse(failedMsg.getResponse()));
}
});
});
......
......@@ -25,17 +25,19 @@ export type IEncodingOptions = {
export type IEncodingOptionsCallback = IEncodingOptions | ((err: NodeJS.ErrnoException, ...args: any[]) => void);
/**
* Stringify an event argument.
* Stringify an event argument. isError is because although methods like
* `fs.stat` are supposed to throw Error objects, they currently throw regular
* objects when running tests through Jest.
*/
export const stringify = (arg: any): string => { // tslint:disable-line no-any
if (arg instanceof Error) {
export const stringify = (arg: any, isError?: boolean): string => { // tslint:disable-line no-any
if (arg instanceof Error || isError) {
// Errors don't stringify at all. They just become "{}".
return JSON.stringify({
type: "Error",
data: {
message: arg.message,
name: arg.name,
stack: arg.stack,
code: (arg as NodeJS.ErrnoException).code,
},
});
} else if (arg instanceof Uint8Array) {
......@@ -74,7 +76,16 @@ export const parse = (arg: string): any => { // tslint:disable-line no-any
// what happens to buffers and stringify them as regular objects.
case "Error":
if (result.data.message) {
return new Error(result.data.message);
const error = new Error(result.data.message);
// TODO: Can we set the stack? Doing so seems to make it into an
// "invalid object".
if (typeof result.data.code !== "undefined") {
(error as NodeJS.ErrnoException).code = result.data.code;
}
// tslint:disable-next-line no-any
(error as any).originalStack = result.data.stack;
return error;
}
break;
}
......
......@@ -36,8 +36,7 @@ export const evaluate = (connection: SendableConnection, message: NewEvalMessage
const sendException = (error: Error): void => {
const evalFailed = new EvalFailedMessage();
evalFailed.setId(message.getId());
evalFailed.setReason(EvalFailedMessage.Reason.EXCEPTION);
evalFailed.setMessage(error.toString() + " " + error.stack);
evalFailed.setResponse(stringify(error, true));
const serverMsg = new ServerMessage();
serverMsg.setEvalFailed(evalFailed);
......@@ -58,7 +57,7 @@ export const evaluate = (connection: SendableConnection, message: NewEvalMessage
logger.trace(() => [
`${event}`,
field("id", message.getId()),
field("args", args.map(stringify)),
field("args", args.map((a) => stringify(a))),
]);
cb(...args);
});
......@@ -67,11 +66,11 @@ export const evaluate = (connection: SendableConnection, message: NewEvalMessage
logger.trace(() => [
`emit ${event}`,
field("id", message.getId()),
field("args", args.map(stringify)),
field("args", args.map((a) => stringify(a))),
]);
const eventMsg = new EvalEventMessage();
eventMsg.setEvent(event);
eventMsg.setArgsList(args.map(stringify));
eventMsg.setArgsList(args.map((a) => stringify(a)));
eventMsg.setId(message.getId());
const serverMsg = new ServerMessage();
serverMsg.setEvalEvent(eventMsg);
......
......@@ -19,13 +19,7 @@ message EvalEventMessage {
message EvalFailedMessage {
uint64 id = 1;
enum Reason {
Timeout = 0;
Exception = 1;
Conflict = 2;
}
Reason reason = 2;
string message = 3;
string response = 2;
}
message EvalDoneMessage {
......
......@@ -75,11 +75,8 @@ export class EvalFailedMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
getReason(): EvalFailedMessage.Reason;
setReason(value: EvalFailedMessage.Reason): void;
getMessage(): string;
setMessage(value: string): void;
getResponse(): string;
setResponse(value: string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): EvalFailedMessage.AsObject;
......@@ -94,14 +91,7 @@ export class EvalFailedMessage extends jspb.Message {
export namespace EvalFailedMessage {
export type AsObject = {
id: number,
reason: EvalFailedMessage.Reason,
message: string,
}
export enum Reason {
TIMEOUT = 0,
EXCEPTION = 1,
CONFLICT = 2,
response: string,
}
}
......
......@@ -14,7 +14,6 @@ var global = Function('return this')();
goog.exportSymbol('proto.EvalDoneMessage', null, global);
goog.exportSymbol('proto.EvalEventMessage', null, global);
goog.exportSymbol('proto.EvalFailedMessage', null, global);
goog.exportSymbol('proto.EvalFailedMessage.Reason', null, global);
goog.exportSymbol('proto.NewEvalMessage', null, global);
/**
......@@ -554,8 +553,7 @@ proto.EvalFailedMessage.prototype.toObject = function(opt_includeInstance) {
proto.EvalFailedMessage.toObject = function(includeInstance, msg) {
var f, obj = {
id: jspb.Message.getFieldWithDefault(msg, 1, 0),
reason: jspb.Message.getFieldWithDefault(msg, 2, 0),
message: jspb.Message.getFieldWithDefault(msg, 3, "")
response: jspb.Message.getFieldWithDefault(msg, 2, "")
};
if (includeInstance) {
......@@ -597,12 +595,8 @@ proto.EvalFailedMessage.deserializeBinaryFromReader = function(msg, reader) {
msg.setId(value);
break;
case 2:
var value = /** @type {!proto.EvalFailedMessage.Reason} */ (reader.readEnum());
msg.setReason(value);
break;
case 3:
var value = /** @type {string} */ (reader.readString());
msg.setMessage(value);
msg.setResponse(value);
break;
default:
reader.skipField();
......@@ -640,32 +634,16 @@ proto.EvalFailedMessage.serializeBinaryToWriter = function(message, writer) {
f
);
}
f = message.getReason();
if (f !== 0.0) {
writer.writeEnum(
2,
f
);
}
f = message.getMessage();
f = message.getResponse();
if (f.length > 0) {
writer.writeString(
3,
2,
f
);
}
};
/**
* @enum {number}
*/
proto.EvalFailedMessage.Reason = {
TIMEOUT: 0,
EXCEPTION: 1,
CONFLICT: 2
};
/**
* optional uint64 id = 1;
* @return {number}
......@@ -682,32 +660,17 @@ proto.EvalFailedMessage.prototype.setId = function(value) {
/**
* optional Reason reason = 2;
* @return {!proto.EvalFailedMessage.Reason}
*/
proto.EvalFailedMessage.prototype.getReason = function() {
return /** @type {!proto.EvalFailedMessage.Reason} */ (jspb.Message.getFieldWithDefault(this, 2, 0));
};
/** @param {!proto.EvalFailedMessage.Reason} value */
proto.EvalFailedMessage.prototype.setReason = function(value) {
jspb.Message.setProto3EnumField(this, 2, value);
};
/**
* optional string message = 3;
* optional string response = 2;
* @return {string}
*/
proto.EvalFailedMessage.prototype.getMessage = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, ""));
proto.EvalFailedMessage.prototype.getResponse = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
};
/** @param {string} value */
proto.EvalFailedMessage.prototype.setMessage = function(value) {
jspb.Message.setProto3StringField(this, 3, value);
proto.EvalFailedMessage.prototype.setResponse = function(value) {
jspb.Message.setProto3StringField(this, 2, value);
};
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册