UNPKG

chrome-devtools-frontend

Version:
118 lines (105 loc) 4.79 kB
// Copyright 2023 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import {globMatch} from './GlobMatch.js'; /** * A path substitution specifies a string prefix pattern to be * replaced with a new string. This is the pendant of the * `set substitute-path old new` feature that is found in GDB * and `settings set target.source-map old new` feature that * is found in LLDB. */ export interface PathSubstitution { readonly from: string; readonly to: string; } /** * List of {@type PathSubstitution}s. */ export type PathSubstitutions = readonly PathSubstitution[]; /** * Resolve a source path (as stored in DWARF debugging information) to an absolute URL. * * Note that we treat "." specially as a pattern, since LLDB normalizes paths before * returning them from the DWARF parser. Our logic replicates the logic found in the * LLDB frontend in `PathMappingList::RemapPath()` inside `Target/PathMappingList.cpp` * (http://cs/github/llvm/llvm-project/lldb/source/Target/PathMappingList.cpp?l=157-185). * * @param pathSubstitutions possible substitutions to apply to the {@param sourcePath}, applies the first match. * @param sourcePath the source path as found in the debugging information. * @param baseURL the URL of the WebAssembly module, which is used to resolve relative source paths. * @return an absolute `file:`-URI or a URL relative to the {@param baseURL}. */ export function resolveSourcePathToURL(pathSubstitutions: PathSubstitutions, sourcePath: string, baseURL: URL): URL { // Normalize '\' to '/' in sourcePath first. let resolvedSourcePath = sourcePath.replace(/\\/g, '/'); // Apply source path substitutions first. for (const {from, to} of pathSubstitutions) { if (resolvedSourcePath.startsWith(from)) { resolvedSourcePath = to + resolvedSourcePath.slice(from.length); break; } // Relative paths won't have a leading "./" in them unless "." is the only // thing in the relative path so we need to work around "." carefully. if (from === '.') { // We need to figure whether sourcePath can be considered a relative path, // ruling out absolute POSIX and Windows paths, as well as file:, http: and // https: URLs. if (!resolvedSourcePath.startsWith('/') && !/^([A-Z]|file|https?):/i.test(resolvedSourcePath)) { resolvedSourcePath = `${to}/${resolvedSourcePath}`; break; } } } if (resolvedSourcePath.startsWith('/')) { if (resolvedSourcePath.startsWith('//')) { return new URL(`file:${resolvedSourcePath}`); } return new URL(`file://${resolvedSourcePath}`); } if (/^[A-Z]:/i.test(resolvedSourcePath)) { return new URL(`file:/${resolvedSourcePath}`); } return new URL(resolvedSourcePath, baseURL.href); } /** * Configuration for locating source files for a given WebAssembly module. * If the name is `undefined`, the configuration is the default configuration, * which is chosen if there's no named configuration matching the basename of * the WebAssembly module file. * The name can be a wildcard pattern, and {@see globMatch} will be used to * match the name against the URL of the WebAssembly module file. */ export interface ModuleConfiguration { readonly name?: string; readonly pathSubstitutions: PathSubstitutions; } /** * List of {@type ModuleConfiguration}s. These lists are intended to have * a default configuration, whose name field is `undefined`, which is chosen * when no matching named configuration is found. */ export type ModuleConfigurations = readonly ModuleConfiguration[]; /** * Locate the configuration for a given `something.wasm` module file name. * * @param moduleConfigurations list of module configurations to scan. * @param moduleName the URL of the module to lookup. * @return the matching module configuration or the default fallback. */ export function findModuleConfiguration( moduleConfigurations: ModuleConfigurations, moduleURL: URL): ModuleConfiguration { let defaultModuleConfiguration: ModuleConfiguration = {pathSubstitutions: []}; for (const moduleConfiguration of moduleConfigurations) { // The idea here is that module configurations will have at most // one default configuration, so picking the last here is fine. if (moduleConfiguration.name === undefined) { defaultModuleConfiguration = moduleConfiguration; continue; } // Perform wildcard pattern matching on the full URL. if (globMatch(moduleConfiguration.name, moduleURL.href)) { return moduleConfiguration; } } return defaultModuleConfiguration; } export const DEFAULT_MODULE_CONFIGURATIONS: ModuleConfigurations = [{pathSubstitutions: []}];