tor-browser

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

syncBreakpoint.js (4627B)


      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 { setBreakpointPositions } from "./breakpointPositions";
      6 import {
      7  findPosition,
      8  makeBreakpointServerLocation,
      9 } from "../../utils/breakpoint/index";
     10 
     11 import { comparePosition, createLocation } from "../../utils/location";
     12 
     13 import { addBreakpoint, removeBreakpointAtGeneratedLocation } from "./modify";
     14 
     15 async function findBreakpointPosition({ dispatch }, location) {
     16  const positions = await dispatch(setBreakpointPositions(location));
     17 
     18  const position = findPosition(positions, location);
     19  return position;
     20 }
     21 
     22 // Breakpoint syncing occurs when a source is found that matches either the
     23 // original or generated URL of a pending breakpoint. A new breakpoint is
     24 // constructed that might have a different original and/or generated location,
     25 // if the original source has changed since the pending breakpoint was created.
     26 // There are a couple subtle aspects to syncing:
     27 //
     28 // - We handle both the original and generated source because there is no
     29 //   guarantee that seeing the generated source means we will also see the
     30 //   original source. When connecting, a breakpoint will be installed in the
     31 //   client for the generated location in the pending breakpoint, and we need
     32 //   to make sure that either a breakpoint is added to the reducer or that this
     33 //   client breakpoint is deleted.
     34 //
     35 // - If we see both the original and generated sources and the source mapping
     36 //   has changed, we need to make sure that only a single breakpoint is added
     37 //   to the reducer for the new location corresponding to the original location
     38 //   in the pending breakpoint.
     39 export function syncPendingBreakpoint(source, pendingBreakpoint) {
     40  return async thunkArgs => {
     41    const { getState, client, dispatch } = thunkArgs;
     42 
     43    const generatedSource = source.isOriginal ? source.generatedSource : source;
     44 
     45    if (!source || !generatedSource) {
     46      return null;
     47    }
     48 
     49    // /!\ Pending breakpoint locations come only with sourceUrl, line and column attributes.
     50    // We have to map it to a specific source object and avoid trying to query its non-existent 'source' attribute.
     51    const { location, generatedLocation } = pendingBreakpoint;
     52    const isPendingBreakpointWithSourceMap =
     53      location.sourceUrl != generatedLocation.sourceUrl;
     54    const sourceGeneratedLocation = createLocation({
     55      ...generatedLocation,
     56      source: generatedSource,
     57    });
     58 
     59    if (source == generatedSource && isPendingBreakpointWithSourceMap) {
     60      // We are handling the generated source and the pending breakpoint has a
     61      // source mapping. Supply a cancellation callback that will abort the
     62      // breakpoint if the original source was synced to a different location,
     63      // in which case the client breakpoint has been removed.
     64      const breakpointServerLocation = makeBreakpointServerLocation(
     65        getState(),
     66        sourceGeneratedLocation
     67      );
     68      return dispatch(
     69        addBreakpoint(
     70          sourceGeneratedLocation,
     71          pendingBreakpoint.options,
     72          pendingBreakpoint.disabled,
     73          () => !client.hasBreakpoint(breakpointServerLocation)
     74        )
     75      );
     76    }
     77 
     78    const originalLocation = createLocation({
     79      ...location,
     80      source,
     81    });
     82 
     83    const newPosition = await findBreakpointPosition(
     84      thunkArgs,
     85      originalLocation
     86    );
     87 
     88    const newGeneratedLocation = newPosition?.generatedLocation;
     89    if (!newGeneratedLocation) {
     90      // We couldn't find a new mapping for the breakpoint. If there is a source
     91      // mapping, remove any breakpoints for the generated location, as if the
     92      // breakpoint moved. If the old generated location still maps to an
     93      // original location then we don't want to add a breakpoint for it.
     94      if (isPendingBreakpointWithSourceMap) {
     95        dispatch(removeBreakpointAtGeneratedLocation(sourceGeneratedLocation));
     96      }
     97      return null;
     98    }
     99 
    100    const isSameLocation = comparePosition(
    101      generatedLocation,
    102      newGeneratedLocation
    103    );
    104 
    105    // If the new generated location has changed from that in the pending
    106    // breakpoint, remove any breakpoint associated with the old generated
    107    // location.
    108    if (!isSameLocation) {
    109      dispatch(removeBreakpointAtGeneratedLocation(sourceGeneratedLocation));
    110    }
    111 
    112    return dispatch(
    113      addBreakpoint(
    114        newGeneratedLocation,
    115        pendingBreakpoint.options,
    116        pendingBreakpoint.disabled
    117      )
    118    );
    119  };
    120 }