forked from firefox-devtools/debugger
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgetApplicableBindingsForOriginalPosition.js
More file actions
146 lines (126 loc) · 4.07 KB
/
Copy pathgetApplicableBindingsForOriginalPosition.js
File metadata and controls
146 lines (126 loc) · 4.07 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
/* 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 type { BindingLocationType, BindingType } from "../../../workers/parser";
import { positionCmp } from "./positionCmp";
import { filterSortedArray } from "./filtering";
import { mappingContains } from "./mappingContains";
import type { Source, Location, Position } from "../../../types";
import type { GeneratedBindingLocation } from "./buildGeneratedBindingList";
export type ApplicableBinding = {
binding: GeneratedBindingLocation,
range: GeneratedRange,
firstInRange: boolean,
firstOnLine: boolean
};
type GeneratedRange = {
start: Position,
end: Position
};
export async function originalRangeStartsInside(
source: Source,
{
start,
end
}: {
start: Location,
end: Location
},
sourceMaps: any
) {
const endPosition = await sourceMaps.getGeneratedLocation(end, source);
const startPosition = await sourceMaps.getGeneratedLocation(start, source);
// If the start and end positions collapse into eachother, it means that
// the range in the original content didn't _start_ at the start position.
// Since this likely means that the range doesn't logically apply to this
// binding location, we skip it.
return positionCmp(startPosition, endPosition) !== 0;
}
export async function getApplicableBindingsForOriginalPosition(
generatedAstBindings: Array<GeneratedBindingLocation>,
source: Source,
{
start,
end
}: {
start: Location,
end: Location
},
bindingType: BindingType,
locationType: BindingLocationType,
sourceMaps: any
): Promise<Array<ApplicableBinding>> {
const ranges = await sourceMaps.getGeneratedRanges(start, source);
const resultRanges = ranges.map(mapRange => ({
start: {
line: mapRange.line,
column: mapRange.columnStart
},
end: {
line: mapRange.line,
// SourceMapConsumer's 'lastColumn' is inclusive, so we add 1 to make
// it exclusive like all other locations.
column: mapRange.columnEnd + 1
}
}));
// When searching for imports, we expand the range to up to the next available
// mapping to allow for import declarations that are composed of multiple
// variable statements, where the later ones are entirely unmapped.
// Babel 6 produces imports in this style, e.g.
//
// var _mod = require("mod"); // mapped from import statement
// var _mod2 = interop(_mod); // entirely unmapped
if (bindingType === "import" && locationType !== "ref") {
const endPosition = await sourceMaps.getGeneratedLocation(end, source);
const startPosition = await sourceMaps.getGeneratedLocation(start, source);
for (const range of resultRanges) {
if (
mappingContains(range, { start: startPosition, end: startPosition }) &&
positionCmp(range.end, endPosition) < 0
) {
range.end.line = endPosition.line;
range.end.column = endPosition.column;
break;
}
}
}
return filterApplicableBindings(generatedAstBindings, resultRanges);
}
function filterApplicableBindings(
bindings: Array<GeneratedBindingLocation>,
ranges: Array<GeneratedRange>
): Array<ApplicableBinding> {
const result = [];
for (const range of ranges) {
// Any binding overlapping a part of the mapping range.
const filteredBindings = filterSortedArray(bindings, binding => {
if (positionCmp(binding.loc.end, range.start) <= 0) {
return -1;
}
if (positionCmp(binding.loc.start, range.end) >= 0) {
return 1;
}
return 0;
});
let firstInRange = true;
let firstOnLine = true;
let line = -1;
for (const binding of filteredBindings) {
if (binding.loc.start.line === line) {
firstOnLine = false;
} else {
line = binding.loc.start.line;
firstOnLine = true;
}
result.push({
binding,
range,
firstOnLine,
firstInRange
});
firstInRange = false;
}
}
return result;
}