lint-clean. not yet even run
MODIFY
packages/error-stack-shim/package.json
packages/error-stack-shim/package.json
},
"scripts": {
"test": "tape -r esm 'test/**/test*.js' | tap-spec",
- "pretty-fix": "prettier --write '**/*.{js}'",
- "pretty-check": "prettier --check '**/*.{js}'",
- "lint-fix": "eslint --fix '**/*.{js}'",
- "lint-check": "eslint '**/*.{js}'"
+ "pretty-fix": "prettier --write '**/*.js'",
+ "pretty-check": "prettier --check '**/*.js'",
+ "lint-fix": "eslint --fix '**/*.js'",
+ "lint-check": "eslint '**/*.js'"
},
"repository": {
"type": "git",

MODIFY
packages/error-stack-shim/src/getStack.js
packages/error-stack-shim/src/getStack.js
-// Shim https://tc39.es/proposal-error-stacks
-
-import harden from '@agoric/harden';
-
-import { getV8StackFramesUsing } from './v8StackFrames';
-
-import { getScrapedStackFramesUsing } from './scrapedStackFrames';
-
-var System = System || {};
+/* global require module */
-var Error;
+// Shim https://tc39.es/proposal-error-stacks
-(function shimGetStack() {
- "use strict";
+// import harden from '@agoric/harden';
+const harden = Object.freeze;
- const PROVIDE_OPTIOAL_STACK_ACCESSOR = false;
+// import { getV8StackFramesUsing } from './v8StackFrames';
+// import { getScrapedStackFramesUsing } from './scrapedStackFrames';
+const { getV8StackFramesUsing } = require('./v8StackFrames');
+const { getScrapedStackFramesUsing } = require('./scrapedStackFrames');
- if (typeof System.getStack === 'function') {
- return;
- }
+// Reconcile proposal:
+// Is normative optional, but "absence" should be space-returning
+// accessor.
+// If accessor provided, spec demands setter. But this is silly, so we
+// we make it separately switchable.
+const PROVIDE_OPTIONAL_STACK_GETTER = false;
+const PROVIDE_OPTIONAL_STACK_SETTER = false;
+
+const {
+ getPrototypeOf,
+ setPrototypeOf,
+ construct,
+ apply,
+ getOwnPropertyDescriptor,
+ defineProperty,
+} = Reflect;
const UnsafeError = Error;
function FakeError(...args) {
if (new.target) {
- return Reflect.construct(UnsafeError, args, new.target);
- } else {
- return Reflect.apply(UnsafeError, undefined, args);
+ return construct(UnsafeError, args, new.target);
}
+ return apply(UnsafeError, this, args);
}
FakeError.prototype = UnsafeError.prototype;
FakeError.prototype.constructore = FakeError;
+// eslint-disable-next-line no-global-assign
Error = FakeError;
- [EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError
- ].forEach(function(err) {
- if (Object.getPrototypeOf(err) === UnsafeError) {
- Object.setPrototypeOf(err, FakeError);
+[
+ EvalError,
+ RangeError,
+ ReferenceError,
+ SyntaxError,
+ TypeError,
+ URIError,
+].forEach(err => {
+ if (getPrototypeOf(err) === UnsafeError) {
+ setPrototypeOf(err, FakeError);
}
});
- let getStackFrames = function uselessGetStackFrames(error) {
- return harden([]);
- };
+// Default if we can't do anything for a given platform
+let getStackFrames = _error => harden([]);
// //////////////////////////////////////////////////////////////////
// //////// dispatch to platform dependent portions of shim /////////
if ('captureStackTrace' in UnsafeError) {
+ // v8 only
getStackFrames = getV8StackFramesUsing(UnsafeError);
} else {
- let getRawStackString = function defaultRawStackString(error) {
- return error.stack;
- };
- const primStackDesc =
- Reflect.getOwnPropertyDescriptor(Error.prototype, 'stack');
+ let getRawStackString;
+ const primStackDesc = getOwnPropertyDescriptor(FakeError.prototype, 'stack');
const primStackGetter = primStackDesc && primStackDesc.get;
if (primStackGetter) {
- delete Error.prototype.stack;
- getRawStackString = function(error) {
- return Reflect.apply(primStackGetter, error, []);
- };
+ // At the time of this writing, perhaps Firefox only
+ delete FakeError.prototype.stack;
+ // May error
+ getRawStackString = error => apply(primStackGetter, error, []);
+ } else {
+ // May return anything
+ getRawStackString = error => error.stack;
}
getStackFrames = getScrapedStackFramesUsing(getRawStackString);
}
@@ -65,33 +79,29 @@ var Error;
// //////////////////////////////////////////////////////////////////
function getPositionString(pos) {
- let posString = `${pos[0]}`;
- if (pos[1]) {
- posString += `:${pos[1]}`;
- }
- return posString;
+ return pos.join(':');
}
function getStackFrameSpanString(span) {
- let spanString = getPositionString(span[0]);
- if (span[1]) {
- spanString += `::${getPositionString(span[1])}`;
- }
- return spanString;
+ return span.map(getPositionString).join('::');
}
function getFrameString(frame) {
- let source = frame.source;
- if (typeof source !== 'string') {
- source = `eval ${getFrameString(source)}`;
+ const { name, source, span } = frame;
+ let fullSource = source;
+ if (typeof fullSource !== 'string') {
+ fullSource = `eval ${getFrameString(fullSource)}`;
+ }
+ const spanString = getStackFrameSpanString(span);
+ if (spanString) {
+ fullSource = `${fullSource}:${spanString}`;
}
- const spanString = getStackFrameSpanString(source.span);
- return ` at ${frame.name} (${source}${spanString})`;
+ return `at ${name} (${fullSource})`;
}
function getStack(error) {
const frames = getStackFrames(error);
- const string = `${error} ${frames.map(getFrameString).join('\n ')}`;
+ const string = [`${error}`, ...frames.map(getFrameString)].join('\n ');
return harden({ frames, string });
}
@@ -99,26 +109,28 @@ var Error;
return getStack(error).string;
}
- System.getStack = getStack;
- System.getStackString = getStackString;
-
- // Reconcile proposal:
- // Is normative optioal, but "absence" should be space-returning accessor.
- // No setter. Setter bad.
- if (PROVIDE_OPTIOAL_STACK_ACCESSOR) {
- Reflect.defineProperty(Error.prototype, 'stack', {
- get() { return getStackString(this); },
- set: undefined,
+const stackGetter = PROVIDE_OPTIONAL_STACK_GETTER
+ ? function stackGetter() {
+ return getStackString(this);
+ }
+ : () => ' ';
+const stackSetter = PROVIDE_OPTIONAL_STACK_SETTER
+ ? function stackSetter(v) {
+ defineProperty(this, 'stack', {
+ value: v,
+ writable: false,
enumerable: false,
- configurable: true
+ configurable: true,
});
- } else {
- Reflect.defineProperty(Error.prototype, 'stack', {
- get() { return ' '; },
- set: undefined,
+ }
+ : undefined;
+
+defineProperty(FakeError.prototype, 'stack', {
+ get: stackGetter,
+ set: stackSetter,
enumerable: false,
- configurable: true
+ configurable: true,
});
- }
-}());
+// export { getStack, getStackString };
+module.exports = { getStack, getStackString };

MODIFY
packages/error-stack-shim/src/scrapedStackFrames.js
packages/error-stack-shim/src/scrapedStackFrames.js
-// Platform dependent portion of error stack shim
+/* global module */
-function getScrapedStackFramesUsing(getRawStackString) {
+// Platform dependent portion of error stack shim, for unreliably
+// scraping the error stack string to produce the proposed JSON
+// representation.
- /**
- * line2CWFrame(line) takes a (typically) single line string,
- * representing a single stackframe of a stacktrace, and returns an
- * Extended Causeway frame JSON object as defined above.
- *
- * <p>There is no standard for how these lines are formatted and
- * they vary widely between platforms. line2CWFrame scrapes this
- * line unreliably by using a variety of regular expressions that
- * we've accumulated over time, to cover all the cases we've seen
- * across platforms. There are a variety of user-triggered
- * conditions that can cause this scraping to fail, such as a
- * methodName that contains an "(" or "@" character.
- */
- var line2CWFrame = (function() {
- // Each of these frame patterns should have the first capture
- // group be the function name, and the second capture group be
- // the source URL together with position
- // information. Afterwards, the lineColPattern will pull apart
- // these source position components. On all, we assume the
- // function name, if any, has no colon (":"), at-sign ("@"), or
- // open paren ("("), as each of these are used to recognize
- // other parts of a debug line.
-
- // See https://code.google.com/p/v8/issues/detail?id=4268
- var V8NestedCallSitePattern = /^eval at (.*) \((.*)\)$/;
-
- // Seen on FF: The function name is sometimes followed by
- // argument descriptions enclosed in parens, which we
- // ignore. Then there is always an at-sign followed by possibly
- // empty source position.
- var FFFramePattern = /^\s*([^:@(]*?)\s*(?:\(.*\))?@(.*?)$/;
+// lineToFrame(line) takes a (typically) single line string,
+// representing a single stackframe of a stacktrace, and returns a
+// JSON object in the proposed stack frame representation.
- // Seen on IE: The line begins with " at ", as on v8, which we
- // ignore. Then the function name, then the source position
- // enclosed in parens.
- var IEFramePattern = /^\s*(?:at\s+)?([^:@(]*?)\s*\((.*?)\)$/;
-
- // Seem on Safari (JSC): The name optionally followed by an
- // at-sign and source position information. This is like FF,
- // except that the at-sign and source position info may
- // together be absent.
- var JSCFramePatt1 = /^\s*([^:@(]*?)\s*(?:@(.*?))?$/;
-
- // Also seen on Safari (JSC): Just the source position info by
- // itself, with no preceding function name. The source position
- // always seems to contain at least a colon, which is how we
- // decide that it is a source position rather than a function
- // name. The pattern here is a bit more flexible, in that it
- // will accept a function name preceding the source position
- // and separated by whitespace.
- var JSCFramePatt2 = /^\s*?([^:@(]*?)\s*?(.*?)$/;
-
- // List the above patterns in priority order, where the first
- // matching pattern is the one used for any one stack line.
- var framePatterns = [V8NestedCallSitePattern,
- FFFramePattern, IEFramePattern,
- JSCFramePatt1, JSCFramePatt2];
+// How these lines are formatted varies widely between platforms.
+// lineToFrame scrapes this line unreliably by using a variety of
+// regular expressions that we've accumulated over time, to cover all
+// the cases we've seen across platforms. There are a variety of
+// user-triggered conditions that can cause this scraping to fail,
+// such as a methodName that contains an "(" or "@" character.
+// ///////////// Frame Patterns /////////////
- // Each of the LineColPatterns should have the first capture
- // group be the source URL if any, the second be the line
- // number if any, and the third be the column number if any.
- // If there are more, then we have an eval where the next three
- // are the function-name, line, and column within the evaled string.
+// Each of the following frame patterns should have the first capture
+// group be the function name, and the second capture group be the
+// source URL together with position information. Afterwards, the
+// lineColPattern will pull apart these source position components. On
+// all, we assume the function name, if any, has no colon (":"),
+// at-sign ("@"), or open paren ("("), as each of these are used to
+// recognize other parts of a debug line.
- // Seen on FF Nightly 30 for execution in evaled strings.
- // On the left of the &gt; is the position from which eval was
- // called. On the right is the position within the evaled
- // string.
- //
- // TODO(erights): Handle multiple eval nestings. This is low
- // priority because SES only exposes eval through functions
- // that call eval, and so SES never has direct eval
- // nestings. In any case, if the multiple eval syntax is
+// See https://bugs.chromium.org/p/v8/issues/detail?id=4268
+const V8NestedCallSitePattern = /^eval at (.*) \((.*)\)$/;
+
+// Seen on FF: The function name is sometimes followed by argument
+// descriptions enclosed in parens, which we ignore. Then there is
+// always an at-sign followed by possibly empty source position.
+const FFFramePattern = /^\s*([^:@(]*?)\s*(?:\(.*\))?@(.*?)$/;
+
+// Seen on IE: The line begins with " at ", as on v8, which we
+// ignore. Then the function name, then the source position enclosed
+// in parens.
+const IEFramePattern = /^\s*(?:at\s+)?([^:@(]*?)\s*\((.*?)\)$/;
+
+// Seem on Safari (JSC): The name optionally followed by an at-sign
+// and source position information. This is like FF, except that the
+// at-sign and source position info may together be absent.
+const JSCFramePatt1 = /^\s*([^:@(]*?)\s*(?:@(.*?))?$/;
+
+// Also seen on Safari (JSC): Just the source position info by itself,
+// with no preceding function name. The source position always seems
+// to contain at least a colon, which is how we decide that it is a
+// source position rather than a function name. The pattern here is a
+// bit more flexible, in that it will accept a function name preceding
+// the source position and separated by whitespace.
+const JSCFramePatt2 = /^\s*?([^:@(]*?)\s*?(.*?)$/;
+
+// Lists the above patterns in priority order, where the first
+// matching pattern is the one used for any one stack line.
+const framePatterns = [
+ V8NestedCallSitePattern,
+ FFFramePattern,
+ IEFramePattern,
+ JSCFramePatt1,
+ JSCFramePatt2,
+];
+
+// /////////////// Line Column Patterns ////////////////
+
+// Each of the following lineColPatterns should have the first capture
+// group be the source URL if any, the second be the line number if
+// any, and the third be the column number if any. If there are more,
+// then we have an eval where the next three are the function-name,
+// line, and column within the evaled string.
+
+// Seen on FF Nightly 30 for execution in evaled strings. On the left
+// of the &gt; is the position from which eval was called. On the
+// right is the position within the evaled string.
+
+// TODO: Handle multiple eval nestings. If the multiple eval syntax is
// encountered, e.g.,
+//
// http://example.com line 16 > eval line 1 > eval:2:8
- // it will match this pattern, but with the first capture
- // group being "http://example.com line 16 > eval"
- var FFEvalLineColPatterns =
- /^(.*) line (\d+)() > ([^:]*):(\d+):(\d+)$/;
+//
+// it will match this pattern, but with the first capture group being
+// "http://example.com line 16 > eval"
+const FFEvalLineColPatterns = /^(.*) line (\d+)() > ([^:]*):(\d+):(\d+)$/;
// If the source position ends in either one or two
- // colon-digit-sequence suffixes, then the first of these are
- // the line number, and the second, if present, is the column
- // number.
- var MainLineColPattern = /^(.*?)(?::(\d+)(?::(\d+))?)?$/;
+// colon-digit-sequence suffixes, then the first of these are the line
+// number, and the second, if present, is the column number.
+const MainLineColPattern = /^(.*?)(?::(\d+)(?::(\d+))?)?$/;
- // List the above patterns in priority order, where the first
- // matching pattern is the one used for any one stack line.
- var lineColPatterns = [FFEvalLineColPatterns, MainLineColPattern];
-
- function line2CWFrame(line) {
- var name = line.trim();
- var source = '?';
- var span = [];
- // Using .some here only because it gives us a way to escape
- // the loop early. We do not use the results of the .some.
- framePatterns.some(function(framePattern) {
- var match = framePattern.exec(line);
+// List the above patterns in priority order, where the first matching
+// pattern is the one used for any one stack line.
+const lineColPatterns = [FFEvalLineColPatterns, MainLineColPattern];
+
+function lineToFrame(line) {
+ let name = line.trim();
+ let source = '?';
+ let span = [];
+
+ for (const framePattern of framePatterns) {
+ const match = framePattern.exec(line);
+ if (match) {
+ const [
+ // eslint-disable-next-line no-unused-vars
+ ignore,
+ optName,
+ optSource,
+ ] = match;
+ name = optName || '?';
+ source = optSource || '?';
+ break;
+ }
+ }
+
+ for (const lineColPattern of lineColPatterns) {
+ const match = lineColPattern.exec(source);
if (match) {
- name = match[1] || '?';
- source = match[2] || '?';
- // Using .some here only because it gives us a way to escape
- // the loop early. We do not use the results of the .some.
- lineColPatterns.some(function(lineColPattern) {
- var sub = lineColPattern.exec(source);
- if (sub) {
- // sub[1] if present is the source URL.
- // sub[2] if present is the line number.
- // sub[3] if present is the column number.
- // sub[4] if present is the function name within the evaled
- // string.
- // sub[5] if present is the line number within the
- // evaled string.
- // sub[6] if present is the column number within
- // the evaled string.
- source = sub[1] || '?';
- if (sub[2]) {
- if (sub[3]) {
- span = [[+sub[2], +sub[3]]];
+ const [
+ // eslint-disable-next-line no-unused-vars
+ ignore,
+ optSourceURL,
+ optLineNum,
+ optColNum,
+ optEvalFuncName,
+ optEvalLineNum,
+ optEvalColNum,
+ ] = match;
+ source = optSourceURL || '?';
+ if (optLineNum) {
+ if (optColNum) {
+ span = [[+optLineNum, +optColNum]];
} else {
- span = [[+sub[2]]];
+ span = [[+optLineNum]];
}
}
- if (sub.length >= 5) {
+ if (match.length >= 5) {
source = {
- name: sub[4] === 'eval' ? '?' : (sub[4] || '?'),
- source: source,
- span: span
+ name: optEvalFuncName === 'eval' ? '?' : optEvalFuncName || '?',
+ source,
+ span,
};
span = [];
- if (sub[5]) {
- if (sub[6]) {
- span = [[+sub[5], +sub[6]]];
+ if (optEvalLineNum) {
+ if (optEvalColNum) {
+ span = [[+optEvalLineNum, +optEvalColNum]];
} else {
- span = [[+sub[5]]];
+ span = [[+optEvalLineNum]];
}
}
}
- return true;
+ break;
}
- return false;
- });
- return true;
}
- return false;
- });
+
if (name === 'Anonymous function') {
// Adjust for weirdness seen on IE
name = '?';
} else if (name.indexOf('/') !== -1) {
// Adjust for function name weirdness seen on FF.
name = name.replace(/[/<]/g, '');
- var parts = name.split('/');
+ const parts = name.split('/');
name = parts[parts.length - 1];
}
if (source === 'Unknown script code' || source === 'eval code') {
@@ -163,15 +165,26 @@ function getScrapedStackFramesUsing(getRawStackString) {
source = '?';
}
return {
- name: name,
- source: source,
- span: span
+ name,
+ source,
+ span,
};
}
+function getScrapedStackFramesUsing(getRawStackString) {
+ function getScrapedStackFrames(error) {
+ // may error. Propagate?
+ const rawStackString = `${getRawStackString(error)}`;
- });
+ let lines = rawStackString.split('\n');
+ if (/^\w*Error:/.test(lines[0])) {
+ lines = lines.slice(1);
+ }
+ lines = lines.filter(line => line !== '');
+ return lines.map(lineToFrame);
+ }
+ return getScrapedStackFrames;
}
-export { getScrapedStackFramesUsing };
-
+// export { getScrapedStackFramesUsing, lineToFrame };
+module.exports = { getScrapedStackFramesUsing, lineToFrame };

MODIFY
packages/error-stack-shim/src/v8StackFrames.js
packages/error-stack-shim/src/v8StackFrames.js
-// Platform dependent portion of error stack shim
+/* global require module */
-function getV8StackFramesUsing(UnsafeError) {
+// v8 specific portion of error stack shim
+// Assumes https://v8.dev/docs/stack-trace-api
+
+// import { lineToFrame } from './scrapedStackFrames';
+const { lineToFrame } = require('./scrapedStackFrames');
+function getV8StackFramesUsing(UnsafeError) {
const unsafeCaptureStackTrace = UnsafeError.captureStackTrace;
- UnsafeError.prepareStackTrace = function(err, sst) {
- if (ssts === undefined) {
- // If an error happens in the debug module after setting up
- // this prepareStackTrace but before or during the
- // initialization of ssts, then this method gets called
- // with ssts still undefined (undefined). In that case, we
- // should report the error we're asked to prepare, rather
- // than an error thrown by failing to prepare it.
- ses.logger.error('Error while initializing debug module', err);
- } else {
- ssts.set(err, sst);
- }
- // Technically redundant, but prepareStackTrace is supposed
- // to return a value, so this makes it clearer that this value
- // is undefined (undefined).
- return undefined;
+ const ssts = new WeakMap(); // error -> sst
+
+ UnsafeError.prepareStackTrace = (error, sst) => {
+ ssts.set(error, sst);
};
- UnsafeError.captureStackTrace = function(obj, opt_MyError) {
+ UnsafeError.captureStackTrace = (obj, optMyError = undefined) => {
const wasFrozen = Object.isFrozen(obj);
const stackDesc = Object.getOwnPropertyDescriptor(obj, 'stack');
try {
- const result = unsafeCaptureStackTrace(obj, opt_MyError);
+ const result = unsafeCaptureStackTrace(obj, optMyError);
+ // eslint-disable-next-line no-unused-vars
const ignore = obj.stack;
return result;
} finally {
if (wasFrozen && !Object.isFrozen(obj)) {
+ // TODO Do we still need to worry about this bug?
+ // Was it ever filed? Issue url?
if (stackDesc) {
Object.defineProperty(obj, 'stack', stackDesc);
} else {
@@ -41,48 +37,42 @@ function getV8StackFramesUsing(UnsafeError) {
}
};
- const ssts = new WeakMap(); // error -> sst
-
- /**
- * Given a v8 CallSite object as defined at
- * https://code.google.com/p/v8-wiki/wiki/JavaScriptStackTraceApi
- * return a stack frame in Extended Causeway Format as defined
- * above.
- */
- function callSite2CWFrame(callSite) {
+ function callSiteToFrame(callSite) {
if (typeof callSite === 'string') {
- // See https://code.google.com/p/v8/issues/detail?id=4268
- return line2CWFrame(callSite);
+ // See https://bugs.chromium.org/p/v8/issues/detail?id=4268
+ return lineToFrame(callSite);
}
- const source = callSite.isEval() ?
- callSite2CWFrame(callSite.getEvalOrigin()) :
- '' + (callSite.getFileName() || '?');
- const name = '' + (callSite.getFunctionName() ||
- callSite.getMethodName() || '?');
+ const source = callSite.isEval()
+ ? callSiteToFrame(callSite.getEvalOrigin())
+ : `${callSite.getFileName() || '?'}`;
+ const name = `${callSite.getFunctionName() ||
+ callSite.getMethodName() ||
+ '?'}`;
return {
- name: name,
- source: source,
- span: [ [ callSite.getLineNumber(), callSite.getColumnNumber() ] ]
+ name,
+ source,
+ span: [[callSite.getLineNumber(), callSite.getColumnNumber()]],
};
}
- /**
- * Returns a stack in Extended Causeway Format as defined above.
- */
- function getCWStack(err) {
- if (Object(err) !== err) { return undefined; }
- const sst = ssts.get(err);
- if (sst === undefined && err instanceof Error) {
+ function getV8StackFrames(error) {
+ if (Object(error) !== error) {
+ return undefined;
+ }
+ let sst = ssts.get(error);
+ if (sst === undefined && error instanceof Error) {
// We hope it triggers prepareStackTrace
- const ignore = err.stack;
- sst = ssts.get(err);
+ // eslint-disable-next-line no-unused-vars
+ const ignore = error.stack;
+ sst = ssts.get(error);
}
- if (sst === undefined) { return undefined; }
-
- return {calls: sst.map(callSite2CWFrame)};
- };
-
-
+ if (sst === undefined) {
+ return [];
+ }
+ return sst.map(callSiteToFrame);
+ }
+ return getV8StackFrames;
}
-export { getV8StackFramesUsing };
+// export { getV8StackFramesUsing };
+module.exports = { getV8StackFramesUsing };

lint-clean. not yet even run