diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /devtools/client/debugger/src/utils/sources-tree | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream.tar.xz firefox-esr-upstream.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/client/debugger/src/utils/sources-tree')
4 files changed, 283 insertions, 0 deletions
diff --git a/devtools/client/debugger/src/utils/sources-tree/getURL.js b/devtools/client/debugger/src/utils/sources-tree/getURL.js new file mode 100644 index 0000000000..c06e522723 --- /dev/null +++ b/devtools/client/debugger/src/utils/sources-tree/getURL.js @@ -0,0 +1,180 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ + +import { parse } from "../url"; + +const { + getUnicodeHostname, + getUnicodeUrlPath, +} = require("devtools/client/shared/unicode-url"); + +export function getFilenameFromPath(pathname) { + let filename = ""; + if (pathname) { + filename = pathname.substring(pathname.lastIndexOf("/") + 1); + // This file does not have a name. Default should be (index). + if (filename == "") { + filename = "(index)"; + } else if (filename == ":formatted") { + filename = "(index:formatted)"; + } + } + return filename; +} + +function getFileExtension(path) { + if (!path) { + return ""; + } + + const lastIndex = path.lastIndexOf("."); + return lastIndex !== -1 ? path.slice(lastIndex + 1).toLowerCase() : ""; +} + +const NoDomain = "(no domain)"; +const def = { + path: "", + search: "", + group: "", + filename: "", + fileExtension: "", +}; + +/** + * Compute the URL which may be displayed in the Source Tree. + * + * @param {String} url + * The source absolute URL as a string + * @param {String} extensionName + * Optional, but mandatory when passing a moz-extension URL. + * Name of the extension serving this moz-extension source. + * @return URL Object + * A URL object to represent this source. + * + * Note that this isn't the standard URL object. + * This is augmented with custom properties like: + * - `group`, which is mostly the host of the source's URL. + * This is used to sort sources in the Source tree. + * - `fileExtension`, lowercased file extension of the source + * (if any extension is available) + * - `path` and `pathname` have some special behavior. + * See `parse` implementation. + */ +export function getDisplayURL(url, extensionName = null) { + if (!url) { + return def; + } + + const { pathname, search, protocol, host } = parse(url); + const filename = getUnicodeUrlPath(getFilenameFromPath(pathname)); + + switch (protocol) { + case "javascript:": + // Ignore `javascript:` URLs for now + return def; + + case "moz-extension:": + return { + ...def, + path: pathname, + search, + filename, + fileExtension: getFileExtension(pathname), + // For moz-extension, we replace the uuid by the extension name + // that we receive from the SourceActor.extensionName attribute. + // `extensionName` might be null for content script of disabled add-ons. + group: extensionName || `${protocol}//${host}`, + }; + case "resource:": + return { + ...def, + path: pathname, + search, + filename, + fileExtension: getFileExtension(pathname), + group: `${protocol}//${host || ""}`, + }; + case "webpack:": + return { + ...def, + path: pathname, + search, + filename, + fileExtension: getFileExtension(pathname), + group: `Webpack`, + }; + case "ng:": + return { + ...def, + path: pathname, + search, + filename, + fileExtension: getFileExtension(pathname), + group: `Angular`, + }; + case "about:": + // An about page is a special case + return { + ...def, + path: "/", + search, + filename, + fileExtension: getFileExtension("/"), + group: url, + }; + + case "data:": + return { + ...def, + path: "/", + search, + filename: url, + fileExtension: getFileExtension("/"), + group: NoDomain, + }; + + case "": + if (pathname && pathname.startsWith("/")) { + // use file protocol for a URL like "/foo/bar.js" + return { + ...def, + path: pathname, + search, + filename, + fileExtension: getFileExtension(pathname), + group: "file://", + }; + } else if (!host) { + return { + ...def, + path: pathname, + search, + filename, + fileExtension: getFileExtension(pathname), + group: "", + }; + } + break; + + case "http:": + case "https:": + return { + ...def, + path: pathname, + search, + filename, + fileExtension: getFileExtension(pathname), + group: getUnicodeHostname(host), + }; + } + + return { + ...def, + path: pathname, + search, + fileExtension: getFileExtension(pathname), + filename, + group: protocol ? `${protocol}//` : "", + }; +} diff --git a/devtools/client/debugger/src/utils/sources-tree/moz.build b/devtools/client/debugger/src/utils/sources-tree/moz.build new file mode 100644 index 0000000000..400c0f0d1a --- /dev/null +++ b/devtools/client/debugger/src/utils/sources-tree/moz.build @@ -0,0 +1,9 @@ +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +CompiledModules( + "getURL.js", + "utils.js", +) diff --git a/devtools/client/debugger/src/utils/sources-tree/tests/getUrl.spec.js b/devtools/client/debugger/src/utils/sources-tree/tests/getUrl.spec.js new file mode 100644 index 0000000000..51919ffc4e --- /dev/null +++ b/devtools/client/debugger/src/utils/sources-tree/tests/getUrl.spec.js @@ -0,0 +1,50 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ + +import { getDisplayURL } from "../getURL"; + +describe("getUrl", () => { + it("handles normal url with http and https for filename", function () { + const urlObject = getDisplayURL("https://a/b.js"); + expect(urlObject.filename).toBe("b.js"); + + const urlObject2 = getDisplayURL("http://a/b.js"); + expect(urlObject2.filename).toBe("b.js"); + }); + + it("handles url with querystring for filename", function () { + const urlObject = getDisplayURL("https://a/b.js?key=randomKey"); + expect(urlObject.filename).toBe("b.js"); + }); + + it("handles url with '#' for filename", function () { + const urlObject = getDisplayURL("https://a/b.js#specialSection"); + expect(urlObject.filename).toBe("b.js"); + }); + + it("handles url with no file extension for filename", function () { + const urlObject = getDisplayURL("https://a/c"); + expect(urlObject.filename).toBe("c"); + }); + + it("handles url with no name for filename", function () { + const urlObject = getDisplayURL("https://a/"); + expect(urlObject.filename).toBe("(index)"); + }); + + it("separates resources by protocol and host", () => { + const urlObject = getDisplayURL("moz-extension://xyz/123"); + expect(urlObject.group).toBe("moz-extension://xyz"); + }); + + it("creates a group name for webpack", () => { + const urlObject = getDisplayURL("webpack:///src/component.jsx"); + expect(urlObject.group).toBe("Webpack"); + }); + + it("creates a group name for angular source", () => { + const urlObject = getDisplayURL("ng://src/component.jsx"); + expect(urlObject.group).toBe("Angular"); + }); +}); diff --git a/devtools/client/debugger/src/utils/sources-tree/utils.js b/devtools/client/debugger/src/utils/sources-tree/utils.js new file mode 100644 index 0000000000..0a2f41752b --- /dev/null +++ b/devtools/client/debugger/src/utils/sources-tree/utils.js @@ -0,0 +1,44 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ + +import { parse } from "../../utils/url"; + +/** + * Get the relative path of the url + * Does not include any query parameters or fragment parts + * + * @param string url + * @returns string path + */ +export function getRelativePath(url) { + const { pathname } = parse(url); + if (!pathname) { + return url; + } + const index = pathname.indexOf("/"); + if (index !== -1) { + const path = pathname.slice(index + 1); + // If the path is empty this is likely the index file. + // e.g http://foo.com/ + if (path == "") { + return "(index)"; + } + return path; + } + return ""; +} + +/** + * + * @param {String} name: Name (e.g. computed in SourcesTreeItem renderItemName), + * which might include URI search. + * @returns {String} result of `decodedURI(name)`, or name if it `name` is malformed. + */ +export function safeDecodeItemName(name) { + try { + return decodeURI(name); + } catch (e) { + return name; + } +} |