UNPKG

next

Version:

The React Framework

224 lines (223 loc) • 10.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "patchErrorInspect", { enumerable: true, get: function() { return patchErrorInspect; } }); const _module = require("module"); const _path = /*#__PURE__*/ _interop_require_wildcard(require("path")); const _url = /*#__PURE__*/ _interop_require_wildcard(require("url")); const _sourcemap = require("next/dist/compiled/source-map"); const _middleware = require("../client/components/react-dev-overlay/server/middleware"); const _shared = require("../client/components/react-dev-overlay/server/shared"); const _workunitasyncstorageexternal = require("./app-render/work-unit-async-storage.external"); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interop_require_wildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = { __proto__: null }; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for(var key in obj){ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } // TODO: Implement for Edge runtime const inspectSymbol = Symbol.for('nodejs.util.inspect.custom'); function frameToString(frame) { let sourceLocation = frame.lineNumber !== null ? `:${frame.lineNumber}` : ''; if (frame.column !== null && sourceLocation !== '') { sourceLocation += `:${frame.column}`; } const filePath = frame.file !== null && frame.file.startsWith('file://') && URL.canParse(frame.file) ? // In a multi-app repo, this leads to potentially larger file names but will make clicking snappy. // There's no tradeoff for the cases where `dir` in `next dev [dir]` is omitted // since relative to cwd is both the shortest and snappiest. _path.relative(process.cwd(), _url.fileURLToPath(frame.file)) : frame.file; return frame.methodName ? ` at ${frame.methodName} (${filePath}${sourceLocation})` : ` at ${filePath}${frame.lineNumber}:${frame.column}`; } function computeErrorName(error) { // TODO: Node.js seems to use a different algorithm // class ReadonlyRequestCookiesError extends Error {}` would read `ReadonlyRequestCookiesError: [...]` // in the stack i.e. seems like under certain conditions it favors the constructor name. return error.name || 'Error'; } function prepareUnsourcemappedStackTrace(error, structuredStackTrace) { const name = computeErrorName(error); const message = error.message || ''; let stack = name + ': ' + message; for(let i = 0; i < structuredStackTrace.length; i++){ stack += '\n at ' + structuredStackTrace[i].toString(); } return stack; } function shouldIgnoreListByDefault(file) { return file.startsWith('node:'); } function getSourcemappedFrameIfPossible(frame, sourceMapCache) { var _rawSourceMap_ignoreList, // default is not a valid identifier in JS so webpack uses a custom variable when it's an unnamed default export // Resolve it back to `default` for the method name if the source position didn't have the method. _frame_methodName_replace, _frame_methodName; if (frame.file === null) { return null; } const sourceMapCacheEntry = sourceMapCache.get(frame.file); let sourceMap; let rawSourceMap; if (sourceMapCacheEntry === undefined) { const moduleSourceMap = (0, _module.findSourceMap)(frame.file); if (moduleSourceMap === undefined) { return null; } rawSourceMap = moduleSourceMap.payload; sourceMap = new _sourcemap.SourceMapConsumer(// @ts-expect-error -- Module.SourceMap['version'] is number but SyncSourceMapConsumer wants a string rawSourceMap); sourceMapCache.set(frame.file, { map: sourceMap, raw: rawSourceMap }); } else { sourceMap = sourceMapCacheEntry.map; rawSourceMap = sourceMapCacheEntry.raw; } const sourcePosition = sourceMap.originalPositionFor({ column: frame.column ?? 0, line: frame.lineNumber ?? 1 }); if (sourcePosition.source === null) { return null; } const sourceContent = sourceMap.sourceContentFor(sourcePosition.source, /* returnNullOnMissing */ true) ?? null; // TODO: O(n^2). Consider moving `ignoreList` into a Set const sourceIndex = rawSourceMap.sources.indexOf(sourcePosition.source); const ignored = ((_rawSourceMap_ignoreList = rawSourceMap.ignoreList) == null ? void 0 : _rawSourceMap_ignoreList.includes(sourceIndex)) ?? false; const originalFrame = { methodName: sourcePosition.name || ((_frame_methodName = frame.methodName) == null ? void 0 : (_frame_methodName_replace = _frame_methodName.replace('__WEBPACK_DEFAULT_EXPORT__', 'default')) == null ? void 0 : _frame_methodName_replace.replace('__webpack_exports__.', '')), column: sourcePosition.column, file: sourcePosition.source, lineNumber: sourcePosition.line, // TODO: c&p from async createOriginalStackFrame but why not frame.arguments? arguments: [], ignored }; const codeFrame = process.env.NODE_ENV !== 'production' ? (0, _shared.getOriginalCodeFrame)(originalFrame, sourceContent) : null; return { stack: originalFrame, code: codeFrame }; } function parseAndSourceMap(error) { // We overwrote Error.prepareStackTrace earlier so error.stack is not sourcemapped. let unparsedStack = String(error.stack); // We could just read it from `error.stack`. // This works around cases where a 3rd party `Error.prepareStackTrace` implementation // doesn't implement the name computation correctly. const errorName = computeErrorName(error); let idx = unparsedStack.indexOf('react-stack-bottom-frame'); if (idx !== -1) { idx = unparsedStack.lastIndexOf('\n', idx); } if (idx !== -1) { // Cut off everything after the bottom frame since it'll be React internals. unparsedStack = unparsedStack.slice(0, idx); } const unsourcemappedStack = (0, _middleware.parseStack)(unparsedStack); const sourceMapCache = new Map(); let sourceMappedStack = ''; let sourceFrameDEV = null; for (const frame of unsourcemappedStack){ if (frame.file === null) { sourceMappedStack += '\n' + frameToString(frame); } else if (!shouldIgnoreListByDefault(frame.file)) { const sourcemappedFrame = getSourcemappedFrameIfPossible(frame, sourceMapCache); if (sourcemappedFrame === null) { sourceMappedStack += '\n' + frameToString(frame); } else { if (process.env.NODE_ENV !== 'production' && sourcemappedFrame.code !== null && sourceFrameDEV === null && // TODO: Is this the right choice? !sourcemappedFrame.stack.ignored) { sourceFrameDEV = sourcemappedFrame.code; } if (!sourcemappedFrame.stack.ignored) { // TODO: Consider what happens if every frame is ignore listed. sourceMappedStack += '\n' + frameToString(sourcemappedFrame.stack); } } } } return errorName + ': ' + error.message + sourceMappedStack + (sourceFrameDEV !== null ? '\n' + sourceFrameDEV : ''); } function patchErrorInspect() { Error.prepareStackTrace = prepareUnsourcemappedStackTrace; // @ts-expect-error -- TODO upstream types // eslint-disable-next-line no-extend-native -- We're not extending but overriding. Error.prototype[inspectSymbol] = function(depth, inspectOptions, inspect) { // avoid false-positive dynamic i/o warnings e.g. due to usage of `Math.random` in `source-map`. return _workunitasyncstorageexternal.workUnitAsyncStorage.exit(()=>{ // Create a new Error object with the source mapping applied and then use native // Node.js formatting on the result. const newError = this.cause !== undefined ? new Error(this.message, { cause: this.cause }) : new Error(this.message); // TODO: Ensure `class MyError extends Error {}` prints `MyError` as the name newError.stack = parseAndSourceMap(this); for(const key in this){ if (!Object.prototype.hasOwnProperty.call(newError, key)) { // @ts-expect-error -- We're copying all enumerable properties. // So they definitely exist on `this` and obviously have no type on `newError` (yet) newError[key] = this[key]; } } const originalCustomInspect = newError[inspectSymbol]; // Prevent infinite recursion. // { customInspect: false } would result in `error.cause` not using our inspect. Object.defineProperty(newError, inspectSymbol, { value: undefined, enumerable: false, writable: true }); try { return inspect(newError, { ...inspectOptions, depth: (inspectOptions.depth ?? // Default in Node.js 2) - depth }); } finally{ newError[inspectSymbol] = originalCustomInspect; } }); }; } //# sourceMappingURL=patch-error-inspect.js.map