0
# Source Maps
1
2
Automatic source map generation for tracking original source locations through transformations with character-level precision.
3
4
## Capabilities
5
6
### Automatic Source Map Generation
7
8
Recast automatically generates high-resolution source maps when reprinting modified ASTs, tracking which parts of the output correspond to which parts of the original source.
9
10
```typescript { .api }
11
/**
12
* Enable source map generation by providing source file information
13
*/
14
interface SourceMapOptions {
15
/** Original source file name */
16
sourceFileName?: string | null;
17
/** Output source map name */
18
sourceMapName?: string | null;
19
/** Root directory for relative source paths */
20
sourceRoot?: string | null;
21
/** Input source map for composition */
22
inputSourceMap?: string | null;
23
}
24
```
25
26
**Usage Examples:**
27
28
```typescript
29
import { parse, print } from "recast";
30
31
// Parse with source file information
32
const ast = parse(sourceCode, {
33
sourceFileName: "input.js"
34
});
35
36
// Transform AST
37
// ... modify ast ...
38
39
// Generate source map during printing
40
const result = print(ast, {
41
sourceMapName: "output.js"
42
});
43
44
console.log(result.code); // Generated code
45
console.log(result.map); // Source map object
46
```
47
48
### Source Map Composition
49
50
Compose multiple source maps when chaining transformations.
51
52
**Usage Example:**
53
54
```typescript
55
import { parse, print } from "recast";
56
57
// First transformation
58
const ast1 = parse(originalCode, {
59
sourceFileName: "original.js"
60
});
61
// ... transform ast1 ...
62
const result1 = print(ast1, {
63
sourceMapName: "intermediate.js"
64
});
65
66
// Second transformation using previous source map
67
const ast2 = parse(result1.code, {
68
sourceFileName: "intermediate.js"
69
});
70
// ... transform ast2 ...
71
const result2 = print(ast2, {
72
sourceMapName: "final.js",
73
inputSourceMap: JSON.stringify(result1.map)
74
});
75
76
// result2.map now contains composed source map from original to final
77
```
78
79
### Print Result with Source Maps
80
81
The result object returned by print operations when source maps are enabled.
82
83
```typescript { .api }
84
interface PrintResultType {
85
/** The generated source code */
86
code: string;
87
/** Source map object (when sourceMapName provided) */
88
map?: SourceMap;
89
/** Deprecated string conversion */
90
toString(): string;
91
}
92
93
interface SourceMap {
94
/** Source map version (always 3) */
95
version: number;
96
/** Generated file name */
97
file: string;
98
/** Root directory for source paths */
99
sourceRoot?: string;
100
/** Array of source file names */
101
sources: string[];
102
/** Array of source content (optional) */
103
sourcesContent?: Array<string | null>;
104
/** Encoded mapping data */
105
mappings: string;
106
/** Array of symbol names */
107
names: string[];
108
}
109
```
110
111
### Source Map Consumer Usage
112
113
Using generated source maps with the Mozilla source-map library.
114
115
**Usage Example:**
116
117
```typescript
118
import { parse, print } from "recast";
119
import { SourceMapConsumer } from "source-map";
120
121
const ast = parse(sourceCode, {
122
sourceFileName: "input.js"
123
});
124
125
// Transform code
126
// ... modify ast ...
127
128
const result = print(ast, {
129
sourceMapName: "output.js"
130
});
131
132
// Use source map to find original positions
133
const consumer = new SourceMapConsumer(result.map);
134
135
// Find original position for generated position
136
const originalPosition = consumer.originalPositionFor({
137
line: 5,
138
column: 10
139
});
140
141
console.log(originalPosition);
142
// {
143
// source: 'input.js',
144
// line: 3,
145
// column: 15,
146
// name: null
147
// }
148
```
149
150
### High-Resolution Mapping
151
152
Recast generates character-by-character mappings for maximum debugging precision.
153
154
**Characteristics:**
155
- **Character-level precision:** Maps individual characters rather than just lines
156
- **Preserve unchanged code:** Original source locations maintained for unmodified code
157
- **Automatic tracking:** No manual mapping required - handled during reprinting
158
- **Multiple source support:** Can track code from multiple source files in one output
159
160
**Example mapping data:**
161
162
```typescript
163
// Original code spans multiple files
164
const file1Code = "function add(a, b) { return a + b; }";
165
const file2Code = "const multiply = (x, y) => x * y;";
166
167
// Parse and combine
168
const ast1 = parse(file1Code, { sourceFileName: "math1.js" });
169
const ast2 = parse(file2Code, { sourceFileName: "math2.js" });
170
171
// Combine ASTs
172
ast1.program.body.push(...ast2.program.body);
173
174
// Generate combined source map
175
const result = print(ast1, {
176
sourceMapName: "combined.js"
177
});
178
179
// result.map.sources = ["math1.js", "math2.js"]
180
// Mappings track which output characters came from which source file
181
```
182
183
## Source Map Configuration
184
185
### File Path Configuration
186
187
Configure how source paths are handled in generated source maps.
188
189
```typescript { .api }
190
interface SourceMapConfig {
191
/** Name of the original source file */
192
sourceFileName?: string | null;
193
/** Name for the generated source map */
194
sourceMapName?: string | null;
195
/** Root directory for resolving relative source paths */
196
sourceRoot?: string | null;
197
}
198
```
199
200
**Usage Examples:**
201
202
```typescript
203
// Absolute paths
204
const result = print(ast, {
205
sourceFileName: "/project/src/input.js",
206
sourceMapName: "/project/dist/output.js",
207
sourceRoot: "/project"
208
});
209
210
// Relative paths (recommended)
211
const result = print(ast, {
212
sourceFileName: "src/input.js",
213
sourceMapName: "dist/output.js",
214
sourceRoot: ".."
215
});
216
```
217
218
### Source Content Embedding
219
220
Source maps can optionally include the original source content.
221
222
```typescript
223
// Source map will include sourcesContent array
224
// with original source code embedded
225
const result = print(ast, {
226
sourceFileName: "input.js",
227
sourceMapName: "output.js"
228
});
229
230
// result.map.sourcesContent[0] contains original source
231
```
232
233
## Integration with Build Tools
234
235
### Webpack Integration
236
237
Using recast-generated source maps with Webpack.
238
239
```typescript
240
// webpack.config.js
241
module.exports = {
242
module: {
243
rules: [
244
{
245
test: /\.js$/,
246
use: {
247
loader: 'recast-loader', // hypothetical loader
248
options: {
249
sourceMap: true,
250
sourceRoot: path.resolve(__dirname, 'src')
251
}
252
}
253
}
254
]
255
},
256
devtool: 'source-map'
257
};
258
```
259
260
### Gulp Integration
261
262
Composing recast transformations with Gulp source maps.
263
264
```typescript
265
const gulp = require('gulp');
266
const sourcemaps = require('gulp-sourcemaps');
267
const through2 = require('through2');
268
const { parse, print } = require('recast');
269
270
function recastTransform() {
271
return through2.obj(function(file, enc, callback) {
272
const ast = parse(file.contents.toString(), {
273
sourceFileName: file.relative
274
});
275
276
// Transform AST
277
// ... modify ast ...
278
279
const result = print(ast, {
280
sourceMapName: file.relative
281
});
282
283
file.contents = Buffer.from(result.code);
284
file.sourceMap = result.map;
285
286
callback(null, file);
287
});
288
}
289
290
gulp.task('transform', () => {
291
return gulp.src('src/*.js')
292
.pipe(sourcemaps.init())
293
.pipe(recastTransform())
294
.pipe(sourcemaps.write('.'))
295
.pipe(gulp.dest('dist'));
296
});
297
```
298
299
## Important Notes
300
301
### Source Map Accuracy
302
303
- **Format preservation:** Source maps accurately reflect preserved original formatting
304
- **Transformation tracking:** Modified code sections get new mappings while preserved sections maintain original mappings
305
- **Multi-file support:** Can track transformations across multiple input files
306
- **Character precision:** Maps individual characters for precise debugging
307
308
### Performance Considerations
309
310
- **Memory usage:** Source maps add memory overhead proportional to source size
311
- **Generation time:** Source map creation adds processing time during printing
312
- **File size:** Generated source maps can be large for heavily transformed code
313
314
### Debugging Benefits
315
316
- **Stack traces:** Error stack traces point to original source locations
317
- **Breakpoints:** Debugger breakpoints work on original source
318
- **Variable names:** Original variable names preserved in debugging info
319
- **Code navigation:** IDE navigation works with original source structure