rangeMetadata.js (3343B)
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 { locColumn } from "./locColumn"; 6 import { positionCmp } from "./positionCmp"; 7 import { filterSortedArray } from "./filtering"; 8 9 // * match - Range contains a single identifier with matching start location 10 // * contains - Range contains a single identifier with non-matching start 11 // * multiple - Range contains multiple identifiers 12 // * empty - Range contains no identifiers 13 14 export async function loadRangeMetadata( 15 location, 16 originalAstScopes, 17 { sourceMapLoader } 18 ) { 19 const originalRanges = await sourceMapLoader.getOriginalRanges( 20 location.source.id 21 ); 22 23 const sortedOriginalAstBindings = []; 24 for (const item of originalAstScopes) { 25 for (const name of Object.keys(item.bindings)) { 26 for (const ref of item.bindings[name].refs) { 27 sortedOriginalAstBindings.push(ref); 28 } 29 } 30 } 31 sortedOriginalAstBindings.sort((a, b) => positionCmp(a.start, b.start)); 32 33 let i = 0; 34 35 return originalRanges.map(range => { 36 const bindings = []; 37 38 while ( 39 i < sortedOriginalAstBindings.length && 40 (sortedOriginalAstBindings[i].start.line < range.line || 41 (sortedOriginalAstBindings[i].start.line === range.line && 42 locColumn(sortedOriginalAstBindings[i].start) < range.columnStart)) 43 ) { 44 i++; 45 } 46 47 while ( 48 i < sortedOriginalAstBindings.length && 49 sortedOriginalAstBindings[i].start.line === range.line && 50 locColumn(sortedOriginalAstBindings[i].start) >= range.columnStart && 51 locColumn(sortedOriginalAstBindings[i].start) < range.columnEnd 52 ) { 53 const lastBinding = bindings[bindings.length - 1]; 54 // Only add bindings when they're in new positions 55 if ( 56 !lastBinding || 57 positionCmp(lastBinding.start, sortedOriginalAstBindings[i].start) !== 0 58 ) { 59 bindings.push(sortedOriginalAstBindings[i]); 60 } 61 i++; 62 } 63 64 let type = "empty"; 65 let singleDeclaration = true; 66 if (bindings.length === 1) { 67 const binding = bindings[0]; 68 if ( 69 binding.start.line === range.line && 70 binding.start.column === range.columnStart 71 ) { 72 type = "match"; 73 } else { 74 type = "contains"; 75 } 76 } else if (bindings.length > 1) { 77 type = "multiple"; 78 const binding = bindings[0]; 79 const declStart = 80 binding.type !== "ref" ? binding.declaration.start : null; 81 82 singleDeclaration = bindings.every(b => { 83 return ( 84 declStart && 85 b.type !== "ref" && 86 positionCmp(declStart, b.declaration.start) === 0 87 ); 88 }); 89 } 90 91 return { 92 type, 93 singleDeclaration, 94 ...range, 95 }; 96 }); 97 } 98 99 export function findMatchingRange(sortedOriginalRanges, bindingRange) { 100 return filterSortedArray(sortedOriginalRanges, range => { 101 if (range.line < bindingRange.start.line) { 102 return -1; 103 } 104 if (range.line > bindingRange.start.line) { 105 return 1; 106 } 107 108 if (range.columnEnd <= locColumn(bindingRange.start)) { 109 return -1; 110 } 111 if (range.columnStart > locColumn(bindingRange.start)) { 112 return 1; 113 } 114 115 return 0; 116 }).pop(); 117 }