summaryrefslogtreecommitdiff
path: root/cli/tsc/40_error_stack.js
diff options
context:
space:
mode:
authorRyan Dahl <ry@tinyclouds.org>2020-07-22 12:03:46 -0400
committerGitHub <noreply@github.com>2020-07-22 12:03:46 -0400
commitbf9930066d3a5d26baad22fb1766de26be49c2ae (patch)
treee6176c72fdf2d89bb3e45855aba03d8a535b599c /cli/tsc/40_error_stack.js
parent9d13b539b5dfc96e2b5a0e89fc8e0312d6500fff (diff)
Reduce size of TypeScript Compiler snapshot (#6809)
This PR is intentionally ugly. It duplicates all of the code in cli/js2/ into cli/tsc/ ... because it's very important that we all understand that this code is unnecessarily duplicated in our binary. I hope this ugliness provides the motivation to clean it up. The typescript git submodule is removed, because it's a very large repo and contains all sorts of stuff we don't need. Instead the necessary files are copied directly into the deno repo. Hence +200k lines. COMPILER_SNAPSHOT.bin size ``` master 3448139 this branch 3320972 ``` Fixes #6812
Diffstat (limited to 'cli/tsc/40_error_stack.js')
-rw-r--r--cli/tsc/40_error_stack.js267
1 files changed, 267 insertions, 0 deletions
diff --git a/cli/tsc/40_error_stack.js b/cli/tsc/40_error_stack.js
new file mode 100644
index 000000000..80f4fc5ed
--- /dev/null
+++ b/cli/tsc/40_error_stack.js
@@ -0,0 +1,267 @@
+// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
+
+((window) => {
+ // Some of the code here is adapted directly from V8 and licensed under a BSD
+ // style license available here: https://github.com/v8/v8/blob/24886f2d1c565287d33d71e4109a53bf0b54b75c/LICENSE.v8
+ const colors = window.__bootstrap.colors;
+ const assert = window.__bootstrap.util.assert;
+ const internals = window.__bootstrap.internals;
+ const dispatchJson = window.__bootstrap.dispatchJson;
+
+ function opFormatDiagnostics(items) {
+ return dispatchJson.sendSync("op_format_diagnostic", { items });
+ }
+
+ function opApplySourceMap(location) {
+ const res = dispatchJson.sendSync("op_apply_source_map", location);
+ return {
+ fileName: res.fileName,
+ lineNumber: res.lineNumber,
+ columnNumber: res.columnNumber,
+ };
+ }
+
+ function patchCallSite(callSite, location) {
+ return {
+ getThis() {
+ return callSite.getThis();
+ },
+ getTypeName() {
+ return callSite.getTypeName();
+ },
+ getFunction() {
+ return callSite.getFunction();
+ },
+ getFunctionName() {
+ return callSite.getFunctionName();
+ },
+ getMethodName() {
+ return callSite.getMethodName();
+ },
+ getFileName() {
+ return location.fileName;
+ },
+ getLineNumber() {
+ return location.lineNumber;
+ },
+ getColumnNumber() {
+ return location.columnNumber;
+ },
+ getEvalOrigin() {
+ return callSite.getEvalOrigin();
+ },
+ isToplevel() {
+ return callSite.isToplevel();
+ },
+ isEval() {
+ return callSite.isEval();
+ },
+ isNative() {
+ return callSite.isNative();
+ },
+ isConstructor() {
+ return callSite.isConstructor();
+ },
+ isAsync() {
+ return callSite.isAsync();
+ },
+ isPromiseAll() {
+ return callSite.isPromiseAll();
+ },
+ getPromiseIndex() {
+ return callSite.getPromiseIndex();
+ },
+ };
+ }
+
+ function getMethodCall(callSite) {
+ let result = "";
+
+ const typeName = callSite.getTypeName();
+ const methodName = callSite.getMethodName();
+ const functionName = callSite.getFunctionName();
+
+ if (functionName) {
+ if (typeName) {
+ const startsWithTypeName = functionName.startsWith(typeName);
+ if (!startsWithTypeName) {
+ result += `${typeName}.`;
+ }
+ }
+ result += functionName;
+
+ if (methodName) {
+ if (!functionName.endsWith(methodName)) {
+ result += ` [as ${methodName}]`;
+ }
+ }
+ } else {
+ if (typeName) {
+ result += `${typeName}.`;
+ }
+ if (methodName) {
+ result += methodName;
+ } else {
+ result += "<anonymous>";
+ }
+ }
+
+ return result;
+ }
+
+ function getFileLocation(callSite, internal = false) {
+ const cyan = internal ? colors.gray : colors.cyan;
+ const yellow = internal ? colors.gray : colors.yellow;
+ const black = internal ? colors.gray : (s) => s;
+ if (callSite.isNative()) {
+ return cyan("native");
+ }
+
+ let result = "";
+
+ const fileName = callSite.getFileName();
+ if (!fileName && callSite.isEval()) {
+ const evalOrigin = callSite.getEvalOrigin();
+ assert(evalOrigin != null);
+ result += cyan(`${evalOrigin}, `);
+ }
+
+ if (fileName) {
+ result += cyan(fileName);
+ } else {
+ result += cyan("<anonymous>");
+ }
+
+ const lineNumber = callSite.getLineNumber();
+ if (lineNumber != null) {
+ result += `${black(":")}${yellow(lineNumber.toString())}`;
+
+ const columnNumber = callSite.getColumnNumber();
+ if (columnNumber != null) {
+ result += `${black(":")}${yellow(columnNumber.toString())}`;
+ }
+ }
+
+ return result;
+ }
+
+ function callSiteToString(callSite, internal = false) {
+ const cyan = internal ? colors.gray : colors.cyan;
+ const black = internal ? colors.gray : (s) => s;
+
+ let result = "";
+ const functionName = callSite.getFunctionName();
+
+ const isTopLevel = callSite.isToplevel();
+ const isAsync = callSite.isAsync();
+ const isPromiseAll = callSite.isPromiseAll();
+ const isConstructor = callSite.isConstructor();
+ const isMethodCall = !(isTopLevel || isConstructor);
+
+ if (isAsync) {
+ result += colors.gray("async ");
+ }
+ if (isPromiseAll) {
+ result += colors.bold(
+ colors.italic(
+ black(`Promise.all (index ${callSite.getPromiseIndex()})`),
+ ),
+ );
+ return result;
+ }
+ if (isMethodCall) {
+ result += colors.bold(colors.italic(black(getMethodCall(callSite))));
+ } else if (isConstructor) {
+ result += colors.gray("new ");
+ if (functionName) {
+ result += colors.bold(colors.italic(black(functionName)));
+ } else {
+ result += cyan("<anonymous>");
+ }
+ } else if (functionName) {
+ result += colors.bold(colors.italic(black(functionName)));
+ } else {
+ result += getFileLocation(callSite, internal);
+ return result;
+ }
+
+ result += ` ${black("(")}${getFileLocation(callSite, internal)}${
+ black(")")
+ }`;
+ return result;
+ }
+
+ function evaluateCallSite(callSite) {
+ return {
+ this: callSite.getThis(),
+ typeName: callSite.getTypeName(),
+ function: callSite.getFunction(),
+ functionName: callSite.getFunctionName(),
+ methodName: callSite.getMethodName(),
+ fileName: callSite.getFileName(),
+ lineNumber: callSite.getLineNumber(),
+ columnNumber: callSite.getColumnNumber(),
+ evalOrigin: callSite.getEvalOrigin(),
+ isToplevel: callSite.isToplevel(),
+ isEval: callSite.isEval(),
+ isNative: callSite.isNative(),
+ isConstructor: callSite.isConstructor(),
+ isAsync: callSite.isAsync(),
+ isPromiseAll: callSite.isPromiseAll(),
+ promiseIndex: callSite.getPromiseIndex(),
+ };
+ }
+
+ function prepareStackTrace(
+ error,
+ callSites,
+ ) {
+ const mappedCallSites = callSites.map(
+ (callSite) => {
+ const fileName = callSite.getFileName();
+ const lineNumber = callSite.getLineNumber();
+ const columnNumber = callSite.getColumnNumber();
+ if (fileName && lineNumber != null && columnNumber != null) {
+ return patchCallSite(
+ callSite,
+ opApplySourceMap({
+ fileName,
+ lineNumber,
+ columnNumber,
+ }),
+ );
+ }
+ return callSite;
+ },
+ );
+ Object.defineProperties(error, {
+ __callSiteEvals: { value: [], configurable: true },
+ __formattedFrames: { value: [], configurable: true },
+ });
+ for (const callSite of mappedCallSites) {
+ error.__callSiteEvals.push(Object.freeze(evaluateCallSite(callSite)));
+ const isInternal = callSite.getFileName()?.startsWith("$deno$") ?? false;
+ error.__formattedFrames.push(callSiteToString(callSite, isInternal));
+ }
+ Object.freeze(error.__callSiteEvals);
+ Object.freeze(error.__formattedFrames);
+ return (
+ `${error.name}: ${error.message}\n` +
+ error.__formattedFrames
+ .map((s) => ` at ${colors.stripColor(s)}`)
+ .join("\n")
+ );
+ }
+
+ function setPrepareStackTrace(ErrorConstructor) {
+ ErrorConstructor.prepareStackTrace = prepareStackTrace;
+ }
+
+ internals.exposeForTest("setPrepareStackTrace", setPrepareStackTrace);
+
+ window.__bootstrap.errorStack = {
+ setPrepareStackTrace,
+ opApplySourceMap,
+ opFormatDiagnostics,
+ };
+})(this);