getApplicableBindingsForOriginalPosition.js (3458B)
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 { positionCmp } from "./positionCmp"; 6 import { filterSortedArray } from "./filtering"; 7 import { mappingContains } from "./mappingContains"; 8 import { getGeneratedLocation } from "../../source-maps"; 9 10 export async function originalRangeStartsInside({ start, end }, thunkArgs) { 11 const endPosition = await getGeneratedLocation(end, thunkArgs); 12 const startPosition = await getGeneratedLocation(start, thunkArgs); 13 14 // If the start and end positions collapse into eachother, it means that 15 // the range in the original content didn't _start_ at the start position. 16 // Since this likely means that the range doesn't logically apply to this 17 // binding location, we skip it. 18 return positionCmp(startPosition, endPosition) !== 0; 19 } 20 21 export async function getApplicableBindingsForOriginalPosition( 22 generatedAstBindings, 23 source, 24 { start, end }, 25 bindingType, 26 locationType, 27 thunkArgs 28 ) { 29 const { sourceMapLoader } = thunkArgs; 30 const ranges = await sourceMapLoader.getGeneratedRanges(start); 31 32 const resultRanges = ranges.map(mapRange => ({ 33 start: { 34 line: mapRange.line, 35 column: mapRange.columnStart, 36 }, 37 end: { 38 line: mapRange.line, 39 // SourceMapConsumer's 'lastColumn' is inclusive, so we add 1 to make 40 // it exclusive like all other locations. 41 column: mapRange.columnEnd + 1, 42 }, 43 })); 44 45 // When searching for imports, we expand the range to up to the next available 46 // mapping to allow for import declarations that are composed of multiple 47 // variable statements, where the later ones are entirely unmapped. 48 // Babel 6 produces imports in this style, e.g. 49 // 50 // var _mod = require("mod"); // mapped from import statement 51 // var _mod2 = interop(_mod); // entirely unmapped 52 if (bindingType === "import" && locationType !== "ref") { 53 const endPosition = await getGeneratedLocation(end, thunkArgs); 54 const startPosition = await getGeneratedLocation(start, thunkArgs); 55 56 for (const range of resultRanges) { 57 if ( 58 mappingContains(range, { start: startPosition, end: startPosition }) && 59 positionCmp(range.end, endPosition) < 0 60 ) { 61 range.end = { 62 line: endPosition.line, 63 column: endPosition.column, 64 }; 65 break; 66 } 67 } 68 } 69 70 return filterApplicableBindings(generatedAstBindings, resultRanges); 71 } 72 73 function filterApplicableBindings(bindings, ranges) { 74 const result = []; 75 for (const range of ranges) { 76 // Any binding overlapping a part of the mapping range. 77 const filteredBindings = filterSortedArray(bindings, binding => { 78 if (positionCmp(binding.loc.end, range.start) <= 0) { 79 return -1; 80 } 81 if (positionCmp(binding.loc.start, range.end) >= 0) { 82 return 1; 83 } 84 85 return 0; 86 }); 87 88 let firstInRange = true; 89 let firstOnLine = true; 90 let line = -1; 91 92 for (const binding of filteredBindings) { 93 if (binding.loc.start.line === line) { 94 firstOnLine = false; 95 } else { 96 line = binding.loc.start.line; 97 firstOnLine = true; 98 } 99 100 result.push({ 101 binding, 102 range, 103 firstOnLine, 104 firstInRange, 105 }); 106 107 firstInRange = false; 108 } 109 } 110 111 return result; 112 }