Skip to content

Commit caefbcf

Browse files
committed
clean up
1 parent ed25ce8 commit caefbcf

File tree

3 files changed

+105
-111
lines changed

3 files changed

+105
-111
lines changed

packages/cspell-lib/src/lib/Transform/SourceMap.ts

Lines changed: 88 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,109 @@ export interface SourceMapCursor {
66
/**
77
* The source map being traversed.
88
*/
9-
sourceMap: SourceMap;
9+
readonly sourceMap: SourceMap;
1010
/**
1111
* The current index in the source map.
1212
*/
13-
idx: number;
13+
readonly idx: number;
1414
/**
1515
* The base offset in the source text.
1616
*/
17-
base0: number;
17+
readonly begin0: number;
1818
/**
1919
* The base offset in the transformed text.
2020
*/
21-
base1: number;
21+
readonly begin1: number;
22+
23+
reset(): void;
24+
25+
mapOffsetToDest(offsetInSrc: number): number;
26+
mapOffsetToSrc(offsetInDst: number): number;
2227
}
2328

2429
class SourceMapCursorImpl implements SourceMapCursor {
2530
sourceMap: SourceMap;
2631
idx: number;
27-
base0: number;
28-
base1: number;
32+
begin0: number;
33+
begin1: number;
34+
/**
35+
* The delta in the source
36+
*/
37+
d0: number;
38+
/**
39+
* The delta in the transformed text.
40+
*/
41+
d1: number;
42+
/**
43+
* Indicates whether the current segment is linear (1:1) or non-linear.
44+
* A linear segment has equal deltas in the source and transformed text,
45+
* while a non-linear segment has different deltas.
46+
* It is possible that a non-linear segment has the same deltas,
47+
* but it is not possible for a linear segment to have different deltas.
48+
*/
49+
linear: boolean;
50+
/**
51+
* indicates that the cursor has reached the end of the source map.
52+
*/
53+
done: boolean;
2954

3055
constructor(sourceMap: SourceMap) {
3156
this.sourceMap = sourceMap;
32-
this.idx = 0;
33-
this.base0 = 0;
34-
this.base1 = 0;
57+
this.idx = -2;
58+
this.begin0 = 0;
59+
this.begin1 = 0;
60+
this.d0 = 0;
61+
this.d1 = 0;
62+
this.linear = true;
63+
this.done = false;
64+
this.next();
65+
}
66+
67+
next(): boolean {
68+
if (this.done) return false;
69+
this.idx += 2;
70+
this.begin0 += this.d0;
71+
this.begin1 += this.d1;
72+
this.d0 = this.sourceMap[this.idx] || 0;
73+
this.d1 = this.sourceMap[this.idx + 1] || 0;
74+
this.linear = this.d0 === this.d1;
75+
this.done = this.idx >= this.sourceMap.length;
76+
if (this.d0 === 0 && this.d1 === 0 && !this.done) {
77+
this.next();
78+
this.linear = this.done;
79+
}
80+
return !this.done;
81+
}
82+
83+
mapOffsetToDest(offsetInSrc: number): number {
84+
if (offsetInSrc < this.begin0) this.reset();
85+
while (!this.done && offsetInSrc >= this.begin0 + this.d0) {
86+
this.next();
87+
}
88+
if (this.linear) {
89+
return offsetInSrc - this.begin0 + this.begin1;
90+
}
91+
// For a non-linear segment, the offset in the source maps to the start of the segment in the transformed text.
92+
return this.begin1;
93+
}
94+
95+
mapOffsetToSrc(offsetInDst: number): number {
96+
if (offsetInDst < this.begin1) this.reset();
97+
while (!this.done && offsetInDst >= this.begin1 + this.d1) {
98+
this.next();
99+
}
100+
if (this.linear) {
101+
return offsetInDst - this.begin1 + this.begin0;
102+
}
103+
// For a non-linear segment, the offset in the source maps to the start of the segment in the transformed text.
104+
return this.begin0;
105+
}
106+
107+
reset(): void {
108+
this.idx = -2;
109+
this.begin0 = 0;
110+
this.begin1 = 0;
111+
this.next();
35112
}
36113
}
37114

@@ -50,12 +127,6 @@ export function createSourceMapCursor(sourceMap: SourceMap | undefined): SourceM
50127
return new SourceMapCursorImpl(sourceMap);
51128
}
52129

53-
export function resetCursor(cursor: SourceMapCursor): void {
54-
cursor.idx = 0;
55-
cursor.base0 = 0;
56-
cursor.base1 = 0;
57-
}
58-
59130
/**
60131
* Calculated the transformed offset in the destination text based on the source map and the offset in the source text.
61132
* @param cursor - The cursor to use for the mapping. If undefined or empty, the input offset is returned, assuming it is a 1:1 mapping.
@@ -67,33 +138,7 @@ export function calcOffsetInDst(cursor: SourceMapCursor | undefined, offsetInSrc
67138
return offsetInSrc;
68139
}
69140

70-
if (offsetInSrc < cursor.base0) {
71-
// If the offset is before the current base, reset the cursor to the start of the map.
72-
resetCursor(cursor);
73-
}
74-
75-
const srcMap = cursor.sourceMap;
76-
77-
let idx = cursor.idx;
78-
let base0 = cursor.base0;
79-
let base1 = cursor.base1;
80-
for (; idx < srcMap.length && offsetInSrc > srcMap[idx] + base0; idx += 2) {
81-
base0 += srcMap[idx];
82-
base1 += srcMap[idx + 1];
83-
}
84-
85-
cursor.idx = idx;
86-
cursor.base0 = base0;
87-
cursor.base1 = base1;
88-
89-
if (offsetInSrc === srcMap[idx] + base1) {
90-
base0 += srcMap[idx];
91-
base1 += srcMap[idx + 1];
92-
idx += 2;
93-
}
94-
const d0 = srcMap[idx];
95-
const d1 = srcMap[idx + 1];
96-
return d0 === d1 ? offsetInSrc - base0 + base1 : base1;
141+
return cursor.mapOffsetToDest(offsetInSrc);
97142
}
98143

99144
/**
@@ -107,34 +152,7 @@ export function calcOffsetInSrc(cursor: SourceMapCursor | undefined, offsetInDst
107152
return offsetInDst;
108153
}
109154

110-
if (offsetInDst < cursor.base1) {
111-
// If the offset is before the current base, reset the cursor to the start of the map.
112-
resetCursor(cursor);
113-
}
114-
115-
const srcMap = cursor.sourceMap;
116-
117-
let idx = cursor.idx;
118-
let base0 = cursor.base0;
119-
let base1 = cursor.base1;
120-
for (; idx < srcMap.length && offsetInDst > srcMap[idx + 1] + base1; idx += 2) {
121-
base0 += srcMap[idx];
122-
base1 += srcMap[idx + 1];
123-
}
124-
125-
cursor.idx = idx;
126-
cursor.base0 = base0;
127-
cursor.base1 = base1;
128-
129-
if (offsetInDst === srcMap[idx + 1] + base1) {
130-
base0 += srcMap[idx];
131-
base1 += srcMap[idx + 1];
132-
idx += 2;
133-
}
134-
135-
const d0 = srcMap[idx];
136-
const d1 = srcMap[idx + 1];
137-
return d0 === d1 ? offsetInDst - base1 + base0 : base0;
155+
return cursor.mapOffsetToSrc(offsetInDst);
138156
}
139157

140158
/**

packages/cspell-lib/src/lib/Transform/TextMap.test.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { MappedText, SourceMap } from '@cspell/cspell-types';
22
import { describe, expect, test } from 'vitest';
33

44
import {
5-
calRangeInSrc,
5+
calculateRangeInSrc,
66
doesIntersect,
77
extractTextMapRangeOrigin,
88
mapOffsetToDest,
@@ -72,11 +72,11 @@ describe('TextMap', () => {
7272
expect(mapOffsetToSource(rev, 8)).toBe(3); // `9` -> 'é'
7373
expect(mapOffsetToSource(rev, 9)).toBe(4); // `'` -> `'`
7474
expect(mapOffsetToSource(rev, 10)).toBe(5); // `s` -> `s`
75-
expect(mapOffsetToSource(rev, 11)).toBe(6); // `` -> ` `
76-
expect(mapOffsetToSource(rev, 12)).toBe(8); // `G` -> `G`
77-
expect(mapOffsetToSource(rev, 13)).toBe(9); // `r` -> `r`
78-
expect(mapOffsetToSource(rev, 14)).toBe(10); // `a` -> `a`
79-
expect(mapOffsetToSource(rev, 15)).toBe(11); // `n` -> `n`
75+
expect(mapOffsetToSource(rev, 11)).toBe(7); // `G` -> `G`
76+
expect(mapOffsetToSource(rev, 12)).toBe(8); // `r` -> `r`
77+
expect(mapOffsetToSource(rev, 13)).toBe(9); // `a` -> `a`
78+
expect(mapOffsetToSource(rev, 14)).toBe(10); // `n` -> `n`
79+
expect(mapOffsetToSource(rev, 15)).toBe(11); // `d` -> `d`
8080
});
8181

8282
test('mapOffsetToDest', () => {
@@ -116,7 +116,7 @@ describe('TextMap', () => {
116116
expect(mapOffsetToDest(map, 8)).toBe(3); // `9` -> 'é'
117117
expect(mapOffsetToDest(map, 9)).toBe(4); // `'` -> `'`
118118
expect(mapOffsetToDest(map, 10)).toBe(5); // `s` -> `s`
119-
expect(mapOffsetToDest(map, 11)).toBe(6); // `` -> ` `
119+
expect(mapOffsetToDest(map, 11)).toBe(7); // `` -> ` `
120120
expect(mapOffsetToDest(map, 12)).toBe(8); // `G` -> `G`
121121
expect(mapOffsetToDest(map, 13)).toBe(9); // `r` -> `r`
122122
expect(mapOffsetToDest(map, 14)).toBe(10); // `a` -> `a`
@@ -133,12 +133,12 @@ describe('TextMap', () => {
133133
*/
134134
const map = [3, 3, 1, 6, 2, 2];
135135

136-
expect(calRangeInSrc(map, [0, 11])).toEqual([0, 6]);
137-
expect(calRangeInSrc(map, [3, 9])).toEqual([3, 4]);
138-
expect(calRangeInSrc(map, [9, 11])).toEqual([4, 6]);
139-
expect(calRangeInSrc(map, [9, 10])).toEqual([4, 5]);
140-
expect(calRangeInSrc(map, [3, 6])).toEqual([3, 3]);
141-
expect(calRangeInSrc(map, [3, 3])).toEqual([3, 3]);
136+
expect(calculateRangeInSrc(map, [0, 11])).toEqual([0, 6]);
137+
expect(calculateRangeInSrc(map, [3, 9])).toEqual([3, 4]);
138+
expect(calculateRangeInSrc(map, [9, 11])).toEqual([4, 6]);
139+
expect(calculateRangeInSrc(map, [9, 10])).toEqual([4, 5]);
140+
expect(calculateRangeInSrc(map, [3, 6])).toEqual([3, 3]);
141+
expect(calculateRangeInSrc(map, [3, 3])).toEqual([3, 3]);
142142
});
143143
});
144144

packages/cspell-lib/src/lib/Transform/TextMap.ts

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import assert from 'node:assert';
2-
31
import type { MappedText, Range, SourceMap } from '@cspell/cspell-types';
42

53
import { calcOffsetInDst, calcOffsetInSrc, createSourceMapCursor, sliceSourceMapToSourceRange } from './SourceMap.js';
@@ -47,8 +45,8 @@ export function calculateRangeInDest(srcMap: SourceMap | undefined, rangeOrigin:
4745
return rangeOrigin;
4846
}
4947

50-
const start = calcOffsetInDst(cursor, rangeOrigin[0]);
51-
const end = calcOffsetInDst(cursor, rangeOrigin[1]);
48+
const start = cursor.mapOffsetToDest(rangeOrigin[0]);
49+
const end = cursor.mapOffsetToDest(rangeOrigin[1]);
5250
return [start, end];
5351
}
5452

@@ -58,8 +56,8 @@ export function calculateRangeInSrc(srcMap: SourceMap | undefined, rangeOrigin:
5856
return rangeOrigin;
5957
}
6058

61-
const start = calcOffsetInSrc(cursor, rangeOrigin[0]);
62-
const end = calcOffsetInSrc(cursor, rangeOrigin[1]);
59+
const start = cursor.mapOffsetToSrc(rangeOrigin[0]);
60+
const end = cursor.mapOffsetToSrc(rangeOrigin[1]);
6361
return [start, end];
6462
}
6563

@@ -71,9 +69,6 @@ export function calculateTextMapRangeDest(textMap: MappedText, rangeOrigin: Rang
7169
const end = Math.min(Math.max(rangeOrigin[1], r0), r1) - r0;
7270

7371
const range = [start, end] as const;
74-
if (!srcMap || !srcMap.length) {
75-
return range;
76-
}
7772
return calculateRangeInDest(srcMap, range);
7873
}
7974

@@ -103,25 +98,6 @@ export function mapOffsetToDest(map: SourceMap | undefined, offset: number): num
10398
return calcOffsetInDst(cursor, offset);
10499
}
105100

106-
/**
107-
* Map an offset in the transformed text back to the original text.
108-
*
109-
* @param map - The source map to use for the mapping.
110-
* If undefined or empty, the input offset is returned, assuming it is a 1:1 mapping.
111-
* @param range - the range in the transformed text to map back to the original text
112-
*/
113-
export function calRangeInSrc(map: SourceMap | undefined, range: Range): Range {
114-
if (!map || !map.length) {
115-
return range;
116-
}
117-
assert(range[0] <= range[1], 'Range start must be less than or equal to range end.');
118-
119-
const cursor = createSourceMapCursor(map);
120-
const start = calcOffsetInSrc(cursor, range[0]);
121-
const end = calcOffsetInSrc(cursor, range[1]);
122-
return [start, end];
123-
}
124-
125101
interface WithRange {
126102
readonly range: Range;
127103
}

0 commit comments

Comments
 (0)