Skip to content

Commit 5b5d5fe

Browse files
authored
Merge pull request #30 from parcel-bundler/sources-tweaks
Fixes and improvements to sourcepath handling
2 parents 62949c2 + f33f874 commit 5b5d5fe

14 files changed

+181
-114
lines changed

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@parcel/source-map",
3-
"version": "2.0.0-alpha.4.13",
3+
"version": "2.0.0-alpha.4.14",
44
"main": "./dist/node.js",
55
"browser": "./dist/wasm-browser.js",
66
"license": "MIT",
@@ -16,6 +16,7 @@
1616
"prebuild": "prebuildify -t 10.20.1 --napi --strip --tag-libc",
1717
"build:dev": "node-gyp rebuild --debug",
1818
"rebuild": "rm -rf build && yarn build:dev",
19+
"rebuild-all": "yarn transpile && yarn compile-wasm && yarn rebuild",
1920
"install": "node-gyp-build",
2021
"prepublish": "npm run transpile",
2122
"lint": "prettier --write bench/run.js src/*.js",

src/SourceMap.js

+32-24
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,42 @@
11
// @flow
2-
import type { ParsedMap, VLQMap, SourceMapStringifyOptions, IndexedMapping } from './types';
2+
import type { ParsedMap, VLQMap, SourceMapStringifyOptions, IndexedMapping, GenerateEmptyMapOptions } from './types';
33

44
import path from 'path';
5-
import { generateInlineMap, partialVlqMapToSourceMap } from './utils';
5+
import { generateInlineMap, partialVlqMapToSourceMap, relatifyPath, normalizePath } from './utils';
66

77
export default class SourceMap {
88
/**
99
* @private
1010
*/
1111
sourceMapInstance: any;
1212

13+
/**
14+
* @private
15+
*/
16+
projectRoot: string;
17+
18+
/**
19+
* Construct a SourceMap instance
20+
*
21+
* @param projectRoot root directory of the project, this is to ensure all source paths are relative to this path
22+
*/
23+
constructor(projectRoot: string = '/') {
24+
this.projectRoot = normalizePath(projectRoot);
25+
}
26+
1327
/**
1428
* Generates an empty map from the provided fileName and sourceContent
1529
*
1630
* @param sourceName path of the source file
1731
* @param sourceContent content of the source file
1832
* @param lineOffset an offset that gets added to the sourceLine index of each mapping
1933
*/
20-
static generateEmptyMap(sourceName: string, sourceContent: string, lineOffset: number = 0): SourceMap {
34+
static generateEmptyMap({
35+
projectRoot,
36+
sourceName,
37+
sourceContent,
38+
lineOffset = 0,
39+
}: GenerateEmptyMapOptions): SourceMap {
2140
throw new Error('SourceMap.generateEmptyMap() must be implemented when extending SourceMap');
2241
}
2342

@@ -37,21 +56,7 @@ export default class SourceMap {
3756
* Appends raw VLQ mappings to the sourcemaps
3857
*/
3958
addRawMappings(map: VLQMap, lineOffset: number = 0, columnOffset: number = 0): SourceMap {
40-
let { sourcesContent, sources = [], mappings, names = [] } = map;
41-
if (!sourcesContent) {
42-
sourcesContent = sources.map(() => '');
43-
} else {
44-
sourcesContent = sourcesContent.map((content) => (content ? content : ''));
45-
}
46-
this.sourceMapInstance.addRawMappings(
47-
mappings,
48-
sources,
49-
sourcesContent.map((content) => (content ? content : '')),
50-
names,
51-
lineOffset,
52-
columnOffset
53-
);
54-
return this;
59+
throw new Error('SourceMap.addRawMappings() must be implemented when extending SourceMap');
5560
}
5661

5762
/**
@@ -90,7 +95,7 @@ export default class SourceMap {
9095
hasValidOriginal ? mapping.original.line - 1 : -1,
9196
// $FlowFixMe
9297
hasValidOriginal ? mapping.original.column : -1,
93-
mapping.source || '',
98+
mapping.source ? relatifyPath(mapping.source, this.projectRoot) : '',
9499
mapping.name || ''
95100
);
96101
}
@@ -144,7 +149,7 @@ export default class SourceMap {
144149
* @returns the index of the added source filepath in the sources array
145150
*/
146151
addSource(source: string): number {
147-
return this.sourceMapInstance.addSource(source);
152+
return this.sourceMapInstance.addSource(relatifyPath(source, this.projectRoot));
148153
}
149154

150155
/**
@@ -163,7 +168,7 @@ export default class SourceMap {
163168
* @param source the filepath of the source file
164169
*/
165170
getSourceIndex(source: string): number {
166-
return this.sourceMapInstance.getSourceIndex(source);
171+
return this.sourceMapInstance.getSourceIndex(relatifyPath(source, this.projectRoot));
167172
}
168173

169174
/**
@@ -183,7 +188,7 @@ export default class SourceMap {
183188
* @param sourceContent the content of the sourceFile
184189
*/
185190
setSourceContent(sourceName: string, sourceContent: string): void {
186-
return this.sourceMapInstance.setSourceContent(sourceName, sourceContent);
191+
return this.sourceMapInstance.setSourceContent(relatifyPath(sourceName, this.projectRoot), sourceContent);
187192
}
188193

189194
/**
@@ -192,7 +197,7 @@ export default class SourceMap {
192197
* @param sourceName filename
193198
*/
194199
getSourceContent(sourceName: string): string {
195-
return this.sourceMapInstance.getSourceContent(sourceName);
200+
return this.sourceMapInstance.getSourceContent(relatifyPath(sourceName, this.projectRoot));
196201
}
197202

198203
/**
@@ -299,6 +304,9 @@ export default class SourceMap {
299304
* @param options options used for formatting the serialised map
300305
*/
301306
async stringify(options: SourceMapStringifyOptions): Promise<string | VLQMap> {
302-
return partialVlqMapToSourceMap(this.toVLQ(), options);
307+
return partialVlqMapToSourceMap(this.toVLQ(), {
308+
...options,
309+
rootDir: this.projectRoot || options.rootDir,
310+
});
303311
}
304312
}

src/node.js

+30-6
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,35 @@
11
// @flow
2-
import type { ParsedMap, VLQMap, SourceMapStringifyOptions, IndexedMapping } from './types';
2+
import type { ParsedMap, VLQMap, SourceMapStringifyOptions, IndexedMapping, GenerateEmptyMapOptions } from './types';
33
import path from 'path';
44
import SourceMap from './SourceMap';
5+
import { relatifyPath } from './utils';
56

67
const bindings = require('node-gyp-build')(path.join(__dirname, '..'));
78

89
export default class NodeSourceMap extends SourceMap {
9-
constructor() {
10-
super();
10+
constructor(projectRoot: string = '/') {
11+
super(projectRoot);
1112
this.sourceMapInstance = new bindings.SourceMap();
1213
}
1314

15+
addRawMappings(map: VLQMap, lineOffset: number = 0, columnOffset: number = 0): SourceMap {
16+
let { sourcesContent, sources = [], mappings, names = [] } = map;
17+
if (!sourcesContent) {
18+
sourcesContent = sources.map(() => '');
19+
} else {
20+
sourcesContent = sourcesContent.map((content) => (content ? content : ''));
21+
}
22+
this.sourceMapInstance.addRawMappings(
23+
mappings,
24+
sources.map((source) => (source ? relatifyPath(source, this.projectRoot) : '')),
25+
sourcesContent.map((content) => (content ? content : '')),
26+
names,
27+
lineOffset,
28+
columnOffset
29+
);
30+
return this;
31+
}
32+
1433
toBuffer(): Buffer {
1534
return this.sourceMapInstance.toBuffer();
1635
}
@@ -23,9 +42,14 @@ export default class NodeSourceMap extends SourceMap {
2342

2443
delete() {}
2544

26-
static generateEmptyMap(sourceName: string, sourceContent: string, lineOffset: number = 0): NodeSourceMap {
27-
let map = new NodeSourceMap();
28-
map.addEmptyMap(sourceName, sourceContent, lineOffset);
45+
static generateEmptyMap({
46+
projectRoot,
47+
sourceName,
48+
sourceContent,
49+
lineOffset = 0,
50+
}: GenerateEmptyMapOptions): NodeSourceMap {
51+
let map = new NodeSourceMap(projectRoot);
52+
map.addEmptyMap(relatifyPath(sourceName, projectRoot), sourceContent, lineOffset);
2953
return map;
3054
}
3155
}

src/types.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,20 @@ export type VLQMap = {
3333
export type SourceMapStringifyOptions = {
3434
file?: string,
3535
sourceRoot?: string,
36-
rootDir?: string,
3736
inlineSources?: boolean,
3837
fs?: { readFile(path: string, encoding: string): Promise<string>, ... },
3938
format?: 'inline' | 'string' | 'object',
39+
/**
40+
* @private
41+
*/
42+
rootDir?: string,
43+
...
44+
};
45+
46+
export type GenerateEmptyMapOptions = {
47+
projectRoot: string,
48+
sourceName: string,
49+
sourceContent: string,
50+
lineOffset?: number,
4051
...
4152
};

src/utils.js

+13-16
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,24 @@ export function generateInlineMap(map: string): string {
77
return `data:application/json;charset=utf-8;base64,${Buffer.from(map).toString('base64')}`;
88
}
99

10-
function normalisePath(filepath: string): string {
11-
return filepath.replace(/\\/g, '/');
10+
export function normalizePath(filepath: string): string {
11+
filepath = filepath.replace(/\\/g, '/');
12+
13+
// Prefix relative paths with ./ as it makes it more clear and probably prevents issues
14+
if (filepath.length > 0 && filepath[0] !== '.' && !path.isAbsolute(filepath)) {
15+
filepath = `./${filepath}`;
16+
}
17+
18+
return filepath;
1219
}
1320

14-
function relatifyPath(filepath: string, rootDir: string): string {
21+
export function relatifyPath(filepath: string, rootDir: string): string {
1522
// Sourcemaps are made for web, so replace backslashes with regular slashes
16-
filepath = normalisePath(filepath);
23+
filepath = normalizePath(filepath);
1724

1825
// Make root paths relative to the rootDir
1926
if (filepath[0] === '/') {
20-
filepath = normalisePath(path.relative(rootDir, filepath));
21-
}
22-
23-
// Prefix relative paths with ./ as it makes it more clear and probably prevents issues
24-
if (filepath[0] !== '.') {
25-
filepath = `./${filepath}`;
27+
filepath = normalizePath(path.relative(rootDir, filepath));
2628
}
2729

2830
return filepath;
@@ -32,7 +34,6 @@ export async function partialVlqMapToSourceMap(
3234
map: VLQMap,
3335
{ fs, file, sourceRoot, inlineSources, rootDir, format = 'string' }: SourceMapStringifyOptions
3436
): Promise<VLQMap | string> {
35-
let root = normalisePath(rootDir || '/');
3637
let resultMap = {
3738
...map,
3839
sourcesContent: map.sourcesContent ? map.sourcesContent.map((content) => (content ? content : null)) : [],
@@ -41,10 +42,6 @@ export async function partialVlqMapToSourceMap(
4142
sourceRoot,
4243
};
4344

44-
resultMap.sources = resultMap.sources.map((sourceFilePath) => {
45-
return relatifyPath(sourceFilePath, root);
46-
});
47-
4845
if (resultMap.sourcesContent.length < resultMap.sources.length) {
4946
resultMap.sourcesContent.push(...new Array(resultMap.sources.length - resultMap.sourcesContent.length).fill(null));
5047
}
@@ -57,7 +54,7 @@ export async function partialVlqMapToSourceMap(
5754
// Because of this we have to include the sourceContent to ensure you can always see the sourcecontent for each mapping.
5855
if (!content && (inlineSources || sourceName.startsWith('..'))) {
5956
try {
60-
return await fs.readFile(path.resolve(root, sourceName), 'utf-8');
57+
return await fs.readFile(path.resolve(rootDir || '/', sourceName), 'utf-8');
6158
} catch (e) {}
6259
}
6360

src/wasm.js

+13-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
// @flow
2-
import type { ParsedMap, VLQMap, SourceMapStringifyOptions, IndexedMapping } from './types';
2+
import type { ParsedMap, VLQMap, SourceMapStringifyOptions, IndexedMapping, GenerateEmptyMapOptions } from './types';
33
import path from 'path';
44
import SourceMap from './SourceMap';
5+
import {relatifyPath} from './utils';
56

67
let Module;
78

@@ -36,14 +37,19 @@ function arrayToEmbind(Type, from): any {
3637
}
3738

3839
export default class WasmSourceMap extends SourceMap {
39-
constructor() {
40-
super();
40+
constructor(projectRoot: string = '/') {
41+
super(projectRoot);
4142
this.sourceMapInstance = new Module.SourceMap();
4243
}
4344

44-
static generateEmptyMap(sourceName: string, sourceContent: string, lineOffset: number = 0): WasmSourceMap {
45-
let map = new WasmSourceMap();
46-
map.addEmptyMap(sourceName, sourceContent, lineOffset);
45+
static generateEmptyMap({
46+
projectRoot,
47+
sourceName,
48+
sourceContent,
49+
lineOffset = 0,
50+
}: GenerateEmptyMapOptions): WasmSourceMap {
51+
let map = new WasmSourceMap(projectRoot);
52+
map.addEmptyMap(relatifyPath(sourceName, projectRoot), sourceContent, lineOffset);
4753
return map;
4854
}
4955

@@ -53,6 +59,7 @@ export default class WasmSourceMap extends SourceMap {
5359
columnOffset: number = 0
5460
) {
5561
let { sourcesContent, sources = [], mappings, names = [] } = map;
62+
sources = sources.map((source) => (source ? relatifyPath(source, this.projectRoot) : ''));
5663
if (!sourcesContent) {
5764
sourcesContent = sources.map(() => '');
5865
} else {

0 commit comments

Comments
 (0)