tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

location.js (5083B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
      4 
      5 import { getSelectedLocation } from "./selected-location";
      6 import { getSource } from "../selectors/index";
      7 
      8 /**
      9 * Note that arguments can be created via `createLocation`.
     10 * But they can also be created via `createPendingLocation` in reducer/pending-breakpoints.js.
     11 * Both will have similar line and column attributes.
     12 */
     13 export function comparePosition(a, b) {
     14  return a && b && a.line == b.line && a.column == b.column;
     15 }
     16 
     17 export function createLocation({
     18  source,
     19  sourceActor = null,
     20 
     21  // Line 0 represents no specific line chosen for action
     22  line = 0,
     23  column,
     24 }) {
     25  return {
     26    source,
     27    sourceActor,
     28    sourceActorId: sourceActor?.id,
     29 
     30    // # Quick overview of 1-based versus 0-based lines and columns #
     31    //
     32    // Everything assumes a 1-based line, but columns can be 0 or 1 based.
     33    // Note that while lines are 1-based some RDP packet may refer to line 0 which should be considered as "no precise location".
     34    //
     35    // Columns are 0-based in:
     36    //  - overall all debugger frontend
     37    //  - anything around source maps (SourceMapLoader, SourceMapURLService, SourceMap library)
     38    //  - most RDP packets, especially around the thread actor:
     39    //    - breakpoints
     40    //    - breakpoint positions
     41    //    - pause location
     42    //    - paused frames
     43    //
     44    // Columns are 1-based in:
     45    //  - the UI displayed to the user (console messages, frames, stacktraces,...)
     46    //  - asserted locations in tests (to match displayed numbers)
     47    //  - Spidermonkey:
     48    //    This data is mostly coming from and driven by
     49    //    JSScript::lineno and JSScript::column
     50    //    https://searchfox.org/mozilla-central/rev/4c065f1df299065c305fb48b36cdae571a43d97c/js/src/vm/JSScript.h#1567-1570
     51    //  - some RDP packets outside of the thread actor:
     52    //    - CONSOLE_MESSAGE, CSS_MESSAGE, PAGE_ERROR resources for lineNumber, columnNumber and stacktrace attributes
     53    //    - Error objects's Object Actor's grip's "preview" attribute will expose its stacktraces with 1-based columns
     54    //  - SmartTrace is dealing with these RDP packets and consumes 1-based columns,
     55    //    but has to map to 0-based columns as it depends on debugger frontend Frames components.
     56    //
     57    // The RDP server, especially in the thread actor ecosystem has to map from spidermonkey 1-based to historical 0-based columns.
     58    line,
     59    column,
     60  };
     61 }
     62 
     63 /**
     64 * Convert location objects created via `createLocation` into
     65 * the format used by the Source Map Loader/Worker.
     66 * It only needs sourceId, line and column attributes.
     67 */
     68 export function debuggerToSourceMapLocation(location) {
     69  return {
     70    sourceId: location.source.id,
     71    // In case of errors loading the source, we might not have a precise location.
     72    // Defaults to first line and column.
     73    line: location.line || 1,
     74    column: location.column || 0,
     75  };
     76 }
     77 
     78 /**
     79 * Pending location only need these three attributes,
     80 * and especially doesn't need the large source and sourceActor objects of the regular location objects.
     81 *
     82 * @param {object} location
     83 */
     84 export function createPendingSelectedLocation(location) {
     85  return {
     86    url: location.source.url,
     87 
     88    line: location.line,
     89    column: location.column,
     90  };
     91 }
     92 
     93 export function sortSelectedLocations(locations, selectedSource) {
     94  return Array.from(locations).sort((locationA, locationB) => {
     95    const aSelected = getSelectedLocation(locationA, selectedSource);
     96    const bSelected = getSelectedLocation(locationB, selectedSource);
     97 
     98    // Order the locations by line number…
     99    if (aSelected.line < bSelected.line) {
    100      return -1;
    101    }
    102 
    103    if (aSelected.line > bSelected.line) {
    104      return 1;
    105    }
    106 
    107    // … and if we have the same line, we want to return location with undefined columns
    108    // first, and then order them by column
    109    if (aSelected.column == bSelected.column) {
    110      return 0;
    111    }
    112 
    113    if (aSelected.column === undefined) {
    114      return -1;
    115    }
    116 
    117    if (bSelected.column === undefined) {
    118      return 1;
    119    }
    120 
    121    return aSelected.column < bSelected.column ? -1 : 1;
    122  });
    123 }
    124 
    125 /**
    126 * Source map Loader/Worker and debugger frontend don't use the same objects for locations.
    127 * Worker uses 'sourceId' attributes whereas the frontend has 'source' attribute.
    128 */
    129 export function sourceMapToDebuggerLocation(state, location) {
    130  // From MapScopes modules, we might re-process the exact same location objects
    131  // for which we would already have computed the source object,
    132  // and which would lack sourceId attribute.
    133  if (location.source) {
    134    return location;
    135  }
    136 
    137  // SourceMapLoader doesn't known about debugger's source objects
    138  // so that we have to fetch it from here
    139  const source = getSource(state, location.sourceId);
    140  if (!source) {
    141    throw new Error(`Could not find source-map source ${location.sourceId}`);
    142  }
    143 
    144  return createLocation({
    145    ...location,
    146    source,
    147  });
    148 }