0
# @volar/source-map
1
2
@volar/source-map provides functionality for working with source maps, including bidirectional translation between source and generated code positions, ranges, and locations. It features a SourceMap class that enables precise mapping functionality with configurable fallback strategies and custom data filtering capabilities.
3
4
## Package Information
5
6
- **Package Name**: @volar/source-map
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install @volar/source-map`
10
11
## Core Imports
12
13
```typescript
14
import { SourceMap, translateOffset, type Mapping } from "@volar/source-map";
15
```
16
17
For CommonJS:
18
19
```javascript
20
const { SourceMap, translateOffset } = require("@volar/source-map");
21
```
22
23
## Basic Usage
24
25
```typescript
26
import { SourceMap, type Mapping } from "@volar/source-map";
27
28
// Create mappings between source and generated code
29
const mappings: Mapping[] = [
30
{
31
sourceOffsets: [10, 20],
32
generatedOffsets: [30, 50],
33
lengths: [5, 8],
34
data: { type: "identifier" }
35
},
36
{
37
sourceOffsets: [25],
38
generatedOffsets: [65],
39
lengths: [10],
40
generatedLengths: [12], // Optional, defaults to lengths
41
data: { type: "function" }
42
}
43
];
44
45
// Create SourceMap instance
46
const sourceMap = new SourceMap(mappings);
47
48
// Translate from generated to source
49
for (const [sourceOffset, mapping] of sourceMap.toSourceLocation(32)) {
50
console.log(`Generated offset 32 maps to source offset ${sourceOffset}`);
51
}
52
53
// Translate ranges with fallback matching
54
for (const [sourceStart, sourceEnd, startMapping, endMapping] of
55
sourceMap.toSourceRange(30, 40, true)) {
56
console.log(`Generated range [30-40] maps to source range [${sourceStart}-${sourceEnd}]`);
57
}
58
```
59
60
## Capabilities
61
62
### Source Map Translation
63
64
Core functionality for translating between source and generated code positions using mapping data.
65
66
```typescript { .api }
67
/**
68
* SourceMap class for bidirectional translation between source and generated code positions
69
*/
70
class SourceMap<Data = unknown> {
71
constructor(mappings: Mapping<Data>[]);
72
readonly mappings: Mapping<Data>[];
73
74
/**
75
* Maps generated range to source range(s)
76
* @param generatedStart - Start offset in generated code
77
* @param generatedEnd - End offset in generated code
78
* @param fallbackToAnyMatch - Allow start/end from different mappings
79
* @param filter - Optional function to filter mappings by data
80
* @returns Generator yielding [mappedStart, mappedEnd, startMapping, endMapping]
81
*/
82
toSourceRange(
83
generatedStart: number,
84
generatedEnd: number,
85
fallbackToAnyMatch: boolean,
86
filter?: (data: Data) => boolean
87
): Generator<[mappedStart: number, mappedEnd: number, startMapping: Mapping<Data>, endMapping: Mapping<Data>]>;
88
89
/**
90
* Maps source range to generated range(s)
91
* @param sourceStart - Start offset in source code
92
* @param sourceEnd - End offset in source code
93
* @param fallbackToAnyMatch - Allow start/end from different mappings
94
* @param filter - Optional function to filter mappings by data
95
* @returns Generator yielding [mappedStart, mappedEnd, startMapping, endMapping]
96
*/
97
toGeneratedRange(
98
sourceStart: number,
99
sourceEnd: number,
100
fallbackToAnyMatch: boolean,
101
filter?: (data: Data) => boolean
102
): Generator<[mappedStart: number, mappedEnd: number, startMapping: Mapping<Data>, endMapping: Mapping<Data>]>;
103
104
/**
105
* Maps generated offset to source offset(s)
106
* @param generatedOffset - Offset in generated code
107
* @param filter - Optional function to filter mappings by data
108
* @returns Generator yielding [mappedOffset, mapping]
109
*/
110
toSourceLocation(
111
generatedOffset: number,
112
filter?: (data: Data) => boolean
113
): Generator<[mappedOffset: number, mapping: Mapping<Data>]>;
114
115
/**
116
* Maps source offset to generated offset(s)
117
* @param sourceOffset - Offset in source code
118
* @param filter - Optional function to filter mappings by data
119
* @returns Generator yielding [mappedOffset, mapping]
120
*/
121
toGeneratedLocation(
122
sourceOffset: number,
123
filter?: (data: Data) => boolean
124
): Generator<[mappedOffset: number, mapping: Mapping<Data>]>;
125
126
/**
127
* Find matching offsets for a given position (internal method exposed publicly)
128
* @param offset - The offset to find matches for
129
* @param fromRange - Whether searching in source or generated offsets
130
* @param filter - Optional function to filter mappings by data
131
* @returns Generator yielding [mappedOffset, mapping]
132
*/
133
findMatchingOffsets(
134
offset: number,
135
fromRange: 'sourceOffsets' | 'generatedOffsets',
136
filter?: (data: Data) => boolean
137
): Generator<[mappedOffset: number, mapping: Mapping<Data>]>;
138
139
/**
140
* Find matching start/end ranges (internal method exposed publicly)
141
* @param start - Start offset
142
* @param end - End offset
143
* @param fallbackToAnyMatch - Allow start/end from different mappings
144
* @param fromRange - Whether searching in source or generated offsets
145
* @param filter - Optional function to filter mappings by data
146
* @returns Generator yielding [mappedStart, mappedEnd, startMapping, endMapping]
147
*/
148
findMatchingStartEnd(
149
start: number,
150
end: number,
151
fallbackToAnyMatch: boolean,
152
fromRange: 'sourceOffsets' | 'generatedOffsets',
153
filter?: (data: Data) => boolean
154
): Generator<[mappedStart: number, mappedEnd: number, startMapping: Mapping<Data>, endMapping: Mapping<Data>]>;
155
}
156
```
157
158
### Offset Translation Utility
159
160
Standalone utility function for translating offsets between ranges.
161
162
```typescript { .api }
163
/**
164
* Translates an offset from one range to another using mapping arrays
165
* @param start - The offset to translate
166
* @param fromOffsets - Source range offsets (should be sorted for optimal performance)
167
* @param toOffsets - Target range offsets
168
* @param fromLengths - Lengths for source ranges
169
* @param toLengths - Lengths for target ranges (defaults to fromLengths)
170
* @returns Translated offset or undefined if no mapping found
171
*/
172
function translateOffset(
173
start: number,
174
fromOffsets: number[],
175
toOffsets: number[],
176
fromLengths: number[],
177
toLengths: number[] = fromLengths
178
): number | undefined;
179
```
180
181
## Types
182
183
```typescript { .api }
184
/**
185
* Represents a single mapping between source and generated code positions
186
*/
187
interface Mapping<Data = unknown> {
188
/** Array of source code offsets */
189
sourceOffsets: number[];
190
/** Array of generated code offsets */
191
generatedOffsets: number[];
192
/** Array of lengths for source offsets */
193
lengths: number[];
194
/** Optional array of lengths for generated offsets (defaults to lengths) */
195
generatedLengths?: number[];
196
/** Custom data associated with the mapping */
197
data: Data;
198
}
199
```
200
201
## Usage Examples
202
203
### Basic Offset Translation
204
205
```typescript
206
import { translateOffset } from "@volar/source-map";
207
208
// Translate offset 15 from source to generated code
209
const generatedOffset = translateOffset(
210
15, // offset to translate
211
[10, 20, 30], // source offsets
212
[50, 80, 120], // generated offsets
213
[5, 8, 10], // source lengths
214
[8, 12, 15] // generated lengths
215
);
216
217
console.log(generatedOffset); // 55 (if offset 15 falls in first range)
218
```
219
220
### Custom Data Filtering
221
222
```typescript
223
import { SourceMap, type Mapping } from "@volar/source-map";
224
225
interface CustomData {
226
type: 'identifier' | 'function' | 'comment';
227
important: boolean;
228
}
229
230
const mappings: Mapping<CustomData>[] = [
231
{
232
sourceOffsets: [10],
233
generatedOffsets: [30],
234
lengths: [5],
235
data: { type: 'identifier', important: true }
236
},
237
{
238
sourceOffsets: [20],
239
generatedOffsets: [40],
240
lengths: [8],
241
data: { type: 'comment', important: false }
242
}
243
];
244
245
const sourceMap = new SourceMap(mappings);
246
247
// Only map important identifiers
248
for (const [offset, mapping] of sourceMap.toGeneratedLocation(
249
12,
250
(data) => data.important && data.type === 'identifier'
251
)) {
252
console.log(`Important identifier at source offset 12 maps to ${offset}`);
253
}
254
```
255
256
### Range Mapping with Fallback
257
258
```typescript
259
import { SourceMap, type Mapping } from "@volar/source-map";
260
261
const mappings: Mapping[] = [
262
{
263
sourceOffsets: [10, 30],
264
generatedOffsets: [100, 200],
265
lengths: [5, 10],
266
data: {}
267
}
268
];
269
270
const sourceMap = new SourceMap(mappings);
271
272
// Try exact range mapping first, then fallback to any match
273
for (const [start, end, startMapping, endMapping] of
274
sourceMap.toGeneratedRange(12, 35, true)) {
275
console.log(`Source range [12-35] maps to generated range [${start}-${end}]`);
276
console.log(`Start mapping:`, startMapping);
277
console.log(`End mapping:`, endMapping);
278
}
279
```
280
281
## Error Handling
282
283
- `translateOffset` returns `undefined` when no mapping is found for the given offset
284
- SourceMap generator methods yield no results when no mappings are found
285
- Console warning is logged if `fromOffsets` array is not sorted in `translateOffset` (performance optimization)
286
- No exceptions are thrown by the public API - all methods handle invalid inputs gracefully