Skip to content

Commit

Permalink
Add support for bias in allGeneratedPositionsFor (#23)
Browse files Browse the repository at this point in the history
Also defaults the behavior to match `SourceMapConsumer`'s behavior of `LEAST_UPPER_BOUND` on non-matches.
  • Loading branch information
jridgewell committed Oct 12, 2022
1 parent 1614656 commit f39b59a
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 12 deletions.
33 changes: 23 additions & 10 deletions src/trace-mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ const COL_GTR_EQ_ZERO = '`column` must be greater than or equal to 0 (columns st

export const LEAST_UPPER_BOUND = -1;
export const GREATEST_LOWER_BOUND = 1;
const ALL_BOUND = 0;

/**
* Returns the encoded (VLQ string) form of the SourceMap's mappings field.
Expand Down Expand Up @@ -248,12 +247,13 @@ export class TraceMap implements SourceMap {
);
};

allGeneratedPositionsFor = (map, { source, line, column }) => {
return generatedPosition(map, source, line, column, ALL_BOUND);
allGeneratedPositionsFor = (map, { source, line, column, bias }) => {
// SourceMapConsumer uses LEAST_UPPER_BOUND for some reason, so we follow suit.
return generatedPosition(map, source, line, column, bias || LEAST_UPPER_BOUND, true);
};

generatedPositionFor = (map, { source, line, column, bias }) => {
return generatedPosition(map, source, line, column, bias || GREATEST_LOWER_BOUND);
return generatedPosition(map, source, line, column, bias || GREATEST_LOWER_BOUND, false);
};

eachMapping = (map, cb) => {
Expand Down Expand Up @@ -320,20 +320,23 @@ export class TraceMap implements SourceMap {
line: number,
column: number,
bias: Bias,
all: false,
): GeneratedMapping | InvalidGeneratedMapping;
function generatedPosition(
map: TraceMap,
source: string,
line: number,
column: number,
bias: 0,
bias: Bias,
all: true,
): GeneratedMapping[];
function generatedPosition(
map: TraceMap,
source: string,
line: number,
column: number,
bias: Bias | 0,
bias: Bias,
all: boolean,
): GeneratedMapping | InvalidGeneratedMapping | GeneratedMapping[] {
line--;
if (line < 0) throw new Error(LINE_GTR_ZERO);
Expand All @@ -342,19 +345,19 @@ export class TraceMap implements SourceMap {
const { sources, resolvedSources } = map;
let sourceIndex = sources.indexOf(source);
if (sourceIndex === -1) sourceIndex = resolvedSources.indexOf(source);
if (sourceIndex === -1) return bias === ALL_BOUND ? [] : GMapping(null, null);
if (sourceIndex === -1) return all ? [] : GMapping(null, null);

const generated = (map._bySources ||= buildBySources(
decodedMappings(map),
(map._bySourceMemos = sources.map(memoizedState)),
));

const segments = generated[sourceIndex][line];
if (segments == null) return bias === ALL_BOUND ? [] : GMapping(null, null);
if (segments == null) return all ? [] : GMapping(null, null);

const memo = map._bySourceMemos![sourceIndex];

if (bias === ALL_BOUND) return sliceGeneratedPositions(segments, memo, line, column);
if (all) return sliceGeneratedPositions(segments, memo, line, column, bias);

const index = traceSegmentInternal(segments, memo, line, column, bias);
if (index === -1) return GMapping(null, null);
Expand Down Expand Up @@ -440,9 +443,19 @@ function sliceGeneratedPositions(
memo: MemoState,
line: number,
column: number,
bias: Bias,
): GeneratedMapping[] {
let min = traceSegmentInternal(segments, memo, line, column, GREATEST_LOWER_BOUND);
if (min === -1) return [];

// We ignored the bias when tracing the segment so that we're guarnateed to find the first (in
// insertion order) segment that matched. Even if we did respect the bias when tracing, we would
// still need to call `lowerBound()` to find the first segment, which is slower than just looking
// for the GREATEST_LOWER_BOUND to begin with. The only difference that matters for us is when the
// binary search didn't match, in which case GREATEST_LOWER_BOUND just needs to increment to
// match LEAST_UPPER_BOUND.
if (!bsFound && bias === LEAST_UPPER_BOUND) min++;

if (min === -1 || min === segments.length) return [];

// We may have found the segment that started at an earlier column. If this is the case, then we
// need to slice all generated segments that match _that_ column, because all such segments span
Expand Down
46 changes: 44 additions & 2 deletions test/trace-mapping.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,34 @@ describe('TraceMap', () => {
line: 2,
column: 9,
}),
[
{ line: 2, column: 8 },
{ line: 2, column: 17 },
{ line: 2, column: 32 },
],
);

t.deepEqual(
allGeneratedPositionsFor(tracer, {
source: 'input.js',
line: 2,
column: 9,
bias: LEAST_UPPER_BOUND,
}),
[
{ line: 2, column: 8 },
{ line: 2, column: 17 },
{ line: 2, column: 32 },
],
);

t.deepEqual(
allGeneratedPositionsFor(tracer, {
source: 'input.js',
line: 2,
column: 9,
bias: GREATEST_LOWER_BOUND,
}),
[
{ line: 2, column: 4 },
{ line: 2, column: 33 },
Expand All @@ -340,18 +368,32 @@ describe('TraceMap', () => {
],
);

t.deepEqual(
allGeneratedPositionsFor(tracer, {
source: 'input.js',
line: 2,
column: 10,
bias: GREATEST_LOWER_BOUND,
}),
[
{ line: 2, column: 8 },
{ line: 2, column: 17 },
{ line: 2, column: 32 },
],
);

t.deepEqual(
allGeneratedPositionsFor(tracer, { source: 'input.js', line: 100, column: 13 }),
[],
);

t.deepEqual(
allGeneratedPositionsFor(tracer, { source: 'input.js', line: 1, column: 100 }),
[{ line: 1, column: 18 }],
[],
);

t.deepEqual(allGeneratedPositionsFor(tracer, { source: 'input.js', line: 1, column: 10 }), [
{ line: 1, column: 9 },
{ line: 1, column: 13 },
]);
});
};
Expand Down

0 comments on commit f39b59a

Please sign in to comment.