| 1 | /** |
| 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. |
| 3 | * |
| 4 | * This source code is licensed under the MIT license found in the |
| 5 | * LICENSE file in the root directory of this source tree. |
| 6 | * |
| 7 | * @flow |
| 8 | */ |
| 9 | |
| 10 | import {toNormalUrl} from 'jsc-safe-url'; |
| 11 | |
| 12 | // This function is based on describeComponentFrame() in packages/shared/ReactComponentStackFrame |
| 13 | export default function formatLocationForDisplay( |
| 14 | sourceURL: string, |
| 15 | line: number, |
| 16 | column: number, |
| 17 | ): string { |
| 18 | // Metro can return JSC-safe URLs, which have `//&` as a delimiter |
| 19 | // https://www.npmjs.com/package/jsc-safe-url |
| 20 | const sanitizedSourceURL = sourceURL.includes('//&') |
| 21 | ? toNormalUrl(sourceURL) |
| 22 | : sourceURL; |
| 23 | |
| 24 | // Note: this RegExp doesn't work well with URLs from Metro, |
| 25 | // which provides bundle URL with query parameters prefixed with /& |
| 26 | const BEFORE_SLASH_RE = /^(.*)[\\\/]/; |
| 27 | |
| 28 | let nameOnly = sanitizedSourceURL.replace(BEFORE_SLASH_RE, ''); |
| 29 | |
| 30 | // In DEV, include code for a common special case: |
| 31 | // prefer "folder/index.js" instead of just "index.js". |
| 32 | if (/^index\./.test(nameOnly)) { |
| 33 | const match = sanitizedSourceURL.match(BEFORE_SLASH_RE); |
| 34 | if (match) { |
| 35 | const pathBeforeSlash = match[1]; |
| 36 | if (pathBeforeSlash) { |
| 37 | const folderName = pathBeforeSlash.replace(BEFORE_SLASH_RE, ''); |
| 38 | nameOnly = folderName + '/' + nameOnly; |
| 39 | } |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | if (line === 0) { |
| 44 | return nameOnly; |
| 45 | } |
| 46 | |
| 47 | return `${nameOnly}:${line}`; |
| 48 | } |