forked from firefox-devtools/debugger
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsyncBreakpoint.js
More file actions
177 lines (152 loc) · 4.76 KB
/
Copy pathsyncBreakpoint.js
File metadata and controls
177 lines (152 loc) · 4.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/* 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/>. */
// @flow
import {
locationMoved,
createBreakpoint,
assertBreakpoint,
assertPendingBreakpoint,
findScopeByName
} from "../../utils/breakpoint";
import { getGeneratedLocation } from "../../utils/source-maps";
import { getTextAtPosition } from "../../utils/source";
import { originalToGeneratedId } from "devtools-source-map";
import { getSource } from "../../selectors";
import type {
Location,
ASTLocation,
PendingBreakpoint,
SourceId,
Breakpoint
} from "../../types";
type BreakpointSyncData = {
previousLocation: Location,
breakpoint: ?Breakpoint
};
async function makeScopedLocation(
{ name, offset }: ASTLocation,
location: Location,
source
) {
const scope = await findScopeByName(source, name);
// fallback onto the location line, if the scope is not found
// note: we may at some point want to delete the breakpoint if the scope
// disappears
const line = scope ? scope.location.start.line + offset.line : location.line;
return {
line,
column: location.column,
sourceUrl: source.url,
sourceId: source.id
};
}
function createSyncData(
id: SourceId,
pendingBreakpoint: PendingBreakpoint,
location: Location,
generatedLocation: Location,
previousLocation: Location,
text: string,
originalText: string
): BreakpointSyncData {
const overrides = {
...pendingBreakpoint,
generatedLocation,
id,
text,
originalText
};
const breakpoint = createBreakpoint(location, overrides);
assertBreakpoint(breakpoint);
return { breakpoint, previousLocation };
}
// we have three forms of syncing: disabled syncing, existing server syncing
// and adding a new breakpoint
export async function syncClientBreakpoint(
getState: Function,
client: Object,
sourceMaps: Object,
sourceId: SourceId,
pendingBreakpoint: PendingBreakpoint
): Promise<BreakpointSyncData> {
assertPendingBreakpoint(pendingBreakpoint);
const source = getSource(getState(), sourceId);
const generatedSourceId = sourceMaps.isOriginalId(sourceId)
? originalToGeneratedId(sourceId)
: sourceId;
const generatedSource = getSource(getState(), generatedSourceId);
const { location, astLocation } = pendingBreakpoint;
const previousLocation = { ...location, sourceId };
const scopedLocation = await makeScopedLocation(
astLocation,
previousLocation,
source
);
const scopedGeneratedLocation = await getGeneratedLocation(
getState(),
source.toJS(),
scopedLocation,
sourceMaps
);
// this is the generatedLocation of the pending breakpoint, with
// the source id updated to reflect the new connection
const generatedLocation = {
...pendingBreakpoint.generatedLocation,
sourceId: generatedSourceId
};
const isSameLocation = !locationMoved(
generatedLocation,
scopedGeneratedLocation
);
const existingClient = client.getBreakpointByLocation(generatedLocation);
/** ******* CASE 1: No server change ***********/
// early return if breakpoint is disabled or we are in the sameLocation
// send update only to redux
if (pendingBreakpoint.disabled || (existingClient && isSameLocation)) {
const id = pendingBreakpoint.disabled ? "" : existingClient.id;
const originalText = getTextAtPosition(source, previousLocation);
const text = getTextAtPosition(generatedSource, generatedLocation);
return createSyncData(
id,
pendingBreakpoint,
scopedLocation,
scopedGeneratedLocation,
previousLocation,
text,
originalText
);
}
// clear server breakpoints if they exist and we have moved
if (existingClient) {
await client.removeBreakpoint(generatedLocation);
}
/** ******* Case 2: Add New Breakpoint ***********/
// If we are not disabled, set the breakpoint on the server and get
// that info so we can set it on our breakpoints.
if (!scopedGeneratedLocation.line) {
return { previousLocation, breakpoint: null };
}
const { id, actualLocation } = await client.setBreakpoint(
scopedGeneratedLocation,
pendingBreakpoint.condition,
sourceMaps.isOriginalId(sourceId)
);
// the breakpoint might have slid server side, so we want to get the location
// based on the server's return value
const newGeneratedLocation = actualLocation;
const newLocation = await sourceMaps.getOriginalLocation(
newGeneratedLocation
);
const originalText = getTextAtPosition(source, newLocation);
const text = getTextAtPosition(generatedSource, newGeneratedLocation);
return createSyncData(
id,
pendingBreakpoint,
newLocation,
newGeneratedLocation,
previousLocation,
text,
originalText
);
}