Skip to content

Commit f60deda

Browse files
authored
Merge pull request #26 from parcel-bundler/inline-external-sources
Inline sources from outside the rootDir regardless of inline settings
2 parents 04f3e12 + d6f87eb commit f60deda

File tree

8 files changed

+190
-8
lines changed

8 files changed

+190
-8
lines changed

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ You can create a sourcemap from another sourcemap or by creating it one mapping
1616

1717
#### Creating from existing sourcemap
1818

19-
To create a sourcemap from an existing sourcemap you have to ensure it is a JS Object first by asking for the object version from whichever transpiler you're running or by parsing the serialised map using `JSON.parse`.
19+
To create a sourcemap from an existing sourcemap you have to ensure it is a JS Object first by asking for the object version from whichever transpiler you're running or by parsing the serialised map using `JSON.parse` or any other JSON parser.
2020

21-
After this you can call the function `addRawMappings(mappings, sources, names, lineOffset, columnOffset)` this function takes in the parameters `mappings`, `sources`, `names`, `lineOffset` and `columnOffset`. These correspond to the mappings, sources and names fields in the sourcemap object. The line and column offset are optional parameters used for offsetting the generated line and column. (this can be used when post-processing or wrapping the code linked to the sourcemap, in Parcel this is used when combining maps).
21+
After this you can call the function `addRawMappings(map, lineOffset, columnOffset)` this function takes in the parameters `map`, `lineOffset` and `columnOffset`. The map argument corresponds to the sourcemap object. The line and column offset are optional parameters used for offsetting the generated line and column. (this can be used when post-processing or wrapping the code linked to the sourcemap, in Parcel this is used when combining maps).
2222

2323
Example:
2424

@@ -34,7 +34,7 @@ const RAW_SOURCEMAP = {
3434
};
3535

3636
let sourcemap = new SourceMap();
37-
sourcemap.addRawMappings(RAW_SOURCEMAP.mappings, RAW_SOURCEMAP.sources, RAW_SOURCEMAP.names);
37+
sourcemap.addRawMappings(RAW_SOURCEMAP);
3838

3939
// This function removes the underlying references in the native code
4040
sourcemap.delete();

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.11",
3+
"version": "2.0.0-alpha.4.12",
44
"main": "./dist/node.js",
55
"browser": "./dist/wasm-browser.js",
66
"license": "MIT",
@@ -63,6 +63,7 @@
6363
"cross-env": "^7.0.2",
6464
"flow-bin": "^0.123.0",
6565
"flow-copy-source": "^2.0.9",
66+
"fs-extra": "^9.0.1",
6667
"husky": "^4.2.5",
6768
"lint-staged": "^10.2.9",
6869
"mocha": "^7.1.2",

src/SourceMap.js

+12
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,22 @@ export default class SourceMap {
175175
return this.sourceMapInstance.getSource(index);
176176
}
177177

178+
/**
179+
* Set the sourceContent for a certain file
180+
* this is optional and is only recommended for files that we cannot read in at the end when we serialise the sourcemap
181+
*
182+
* @param {string} sourceName the path of the sourceFile
183+
* @param {string} sourceContent the content of the sourceFile
184+
*/
178185
setSourceContent(sourceName: string, sourceContent: string): void {
179186
return this.sourceMapInstance.setSourceContent(sourceName, sourceContent);
180187
}
181188

189+
/**
190+
* Get the content of a source file if it is inlined as part of the source-map
191+
*
192+
* @param {string} sourceName
193+
*/
182194
getSourceContent(sourceName: string): string {
183195
return this.sourceMapInstance.getSourceContent(sourceName);
184196
}

src/utils.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,19 @@ export async function partialVlqMapToSourceMap(
4949
resultMap.sourcesContent.push(...new Array(resultMap.sources.length - resultMap.sourcesContent.length).fill(null));
5050
}
5151

52-
if (inlineSources && fs) {
52+
if (fs) {
5353
resultMap.sourcesContent = await Promise.all(
5454
resultMap.sourcesContent.map(async (content, index): Promise<string | null> => {
55-
if (content) {
56-
let sourceName = map.sources[index];
55+
let sourceName = map.sources[index];
56+
// If sourceName starts with `..` it is outside rootDir, in this case we likely cannot access this file from the browser or packaged node_module
57+
// Because of this we have to include the sourceContent to ensure you can always see the sourcecontent for each mapping.
58+
if (!content && (inlineSources || sourceName.startsWith('..'))) {
5759
try {
5860
return await fs.readFile(path.resolve(root, sourceName), 'utf-8');
5961
} catch (e) {}
6062
}
6163

62-
return null;
64+
return content;
6365
})
6466
);
6567
}

test/inline-source.test.js

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
const assert = require('assert');
2+
const fs = require('fs-extra');
3+
const path = require('path');
4+
const SourceMap = require('.').default;
5+
6+
const SIMPLE_SOURCE_MAP = {
7+
version: 3,
8+
file: 'bundle.js',
9+
sources: ['../a.js', 'b.js'],
10+
names: [],
11+
mappings: 'AAAA;AAAA,EAAA,OAAO,CAAC,GAAR,CAAY,aAAZ,CAAA,CAAA;AAAA',
12+
};
13+
14+
const ROOT_DIR = path.join(__dirname, 'integration/sub-folder');
15+
const fileOneContent = fs.readFileSync(path.join(ROOT_DIR, SIMPLE_SOURCE_MAP.sources[0]), 'utf-8');
16+
const fileTwoContent = fs.readFileSync(path.join(ROOT_DIR, SIMPLE_SOURCE_MAP.sources[1]), 'utf-8');
17+
18+
describe('SourceMap - Inline Sources', () => {
19+
it('Should be able to inline sources', async () => {
20+
let map = new SourceMap();
21+
map.addRawMappings({
22+
mappings: SIMPLE_SOURCE_MAP.mappings,
23+
sources: SIMPLE_SOURCE_MAP.sources,
24+
names: SIMPLE_SOURCE_MAP.names,
25+
});
26+
27+
let stringifiedMap = await map.stringify({
28+
file: 'bundle.js.map',
29+
sourceRoot: '/',
30+
format: 'object',
31+
fs,
32+
rootDir: ROOT_DIR,
33+
inlineSources: true,
34+
});
35+
36+
assert.deepEqual(stringifiedMap, {
37+
mappings: 'AAAA;AAAA,EAAA,OAAO,CAAC,GAAR,CAAY,aAAZ,CAAA,CAAA;AAAA',
38+
sources: ['../a.js', './b.js'],
39+
sourcesContent: [fileOneContent, fileTwoContent],
40+
names: [],
41+
version: 3,
42+
file: 'bundle.js.map',
43+
sourceRoot: '/',
44+
});
45+
});
46+
47+
it('Should always inline sources outside the root', async () => {
48+
let map = new SourceMap();
49+
map.addRawMappings({
50+
mappings: SIMPLE_SOURCE_MAP.mappings,
51+
sources: SIMPLE_SOURCE_MAP.sources,
52+
names: SIMPLE_SOURCE_MAP.names,
53+
});
54+
55+
let stringifiedMap = await map.stringify({
56+
file: 'bundle.js.map',
57+
sourceRoot: '/',
58+
format: 'object',
59+
fs,
60+
rootDir: ROOT_DIR,
61+
inlineSources: false,
62+
});
63+
64+
assert.deepEqual(stringifiedMap, {
65+
mappings: 'AAAA;AAAA,EAAA,OAAO,CAAC,GAAR,CAAY,aAAZ,CAAA,CAAA;AAAA',
66+
sources: ['../a.js', './b.js'],
67+
sourcesContent: [fileOneContent, null],
68+
names: [],
69+
version: 3,
70+
file: 'bundle.js.map',
71+
sourceRoot: '/',
72+
});
73+
});
74+
75+
it('Should not overwrite existing sourceContent when inlining is true', async () => {
76+
let map = new SourceMap();
77+
map.addRawMappings({
78+
mappings: SIMPLE_SOURCE_MAP.mappings,
79+
sources: SIMPLE_SOURCE_MAP.sources,
80+
names: SIMPLE_SOURCE_MAP.names,
81+
sourcesContent: [null, 'b-content'],
82+
});
83+
84+
let stringifiedMap = await map.stringify({
85+
file: 'bundle.js.map',
86+
sourceRoot: '/',
87+
format: 'object',
88+
fs,
89+
rootDir: ROOT_DIR,
90+
inlineSources: true,
91+
});
92+
93+
assert.deepEqual(stringifiedMap, {
94+
mappings: 'AAAA;AAAA,EAAA,OAAO,CAAC,GAAR,CAAY,aAAZ,CAAA,CAAA;AAAA',
95+
sources: ['../a.js', './b.js'],
96+
sourcesContent: [fileOneContent, 'b-content'],
97+
names: [],
98+
version: 3,
99+
file: 'bundle.js.map',
100+
sourceRoot: '/',
101+
});
102+
});
103+
104+
it('Should not overwrite existing sourceContent when inlining is false', async () => {
105+
let map = new SourceMap();
106+
map.addRawMappings({
107+
mappings: SIMPLE_SOURCE_MAP.mappings,
108+
sources: SIMPLE_SOURCE_MAP.sources,
109+
names: SIMPLE_SOURCE_MAP.names,
110+
sourcesContent: ['a-content', 'b-content'],
111+
});
112+
113+
let stringifiedMap = await map.stringify({
114+
file: 'bundle.js.map',
115+
sourceRoot: '/',
116+
format: 'object',
117+
fs,
118+
rootDir: ROOT_DIR,
119+
inlineSources: false,
120+
});
121+
122+
assert.deepEqual(stringifiedMap, {
123+
mappings: 'AAAA;AAAA,EAAA,OAAO,CAAC,GAAR,CAAY,aAAZ,CAAA,CAAA;AAAA',
124+
sources: ['../a.js', './b.js'],
125+
sourcesContent: ['a-content', 'b-content'],
126+
names: [],
127+
version: 3,
128+
file: 'bundle.js.map',
129+
sourceRoot: '/',
130+
});
131+
});
132+
});

test/integration/a.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = () => {
2+
return 'a';
3+
};

test/integration/sub-folder/b.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = () => {
2+
return 'b';
3+
};

yarn.lock

+29
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,11 @@ async-each@^1.0.1:
926926
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
927927
integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
928928

929+
at-least-node@^1.0.0:
930+
version "1.0.0"
931+
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
932+
integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
933+
929934
atob@^2.1.2:
930935
version "2.1.2"
931936
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
@@ -1635,6 +1640,16 @@ fs-extra@^8.1.0:
16351640
jsonfile "^4.0.0"
16361641
universalify "^0.1.0"
16371642

1643+
fs-extra@^9.0.1:
1644+
version "9.0.1"
1645+
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.1.tgz#910da0062437ba4c39fedd863f1675ccfefcb9fc"
1646+
integrity sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==
1647+
dependencies:
1648+
at-least-node "^1.0.0"
1649+
graceful-fs "^4.2.0"
1650+
jsonfile "^6.0.1"
1651+
universalify "^1.0.0"
1652+
16381653
fs-readdir-recursive@^1.1.0:
16391654
version "1.1.0"
16401655
resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27"
@@ -2099,6 +2114,15 @@ jsonfile@^4.0.0:
20992114
optionalDependencies:
21002115
graceful-fs "^4.1.6"
21012116

2117+
jsonfile@^6.0.1:
2118+
version "6.0.1"
2119+
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.0.1.tgz#98966cba214378c8c84b82e085907b40bf614179"
2120+
integrity sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==
2121+
dependencies:
2122+
universalify "^1.0.0"
2123+
optionalDependencies:
2124+
graceful-fs "^4.1.6"
2125+
21022126
kefir@^3.7.3:
21032127
version "3.8.6"
21042128
resolved "https://registry.yarnpkg.com/kefir/-/kefir-3.8.6.tgz#046f0dabd870ff7cbfe039995c9bca2c1e68ac36"
@@ -3297,6 +3321,11 @@ universalify@^0.1.0:
32973321
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
32983322
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
32993323

3324+
universalify@^1.0.0:
3325+
version "1.0.0"
3326+
resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d"
3327+
integrity sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==
3328+
33003329
unset-value@^1.0.0:
33013330
version "1.0.0"
33023331
resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"

0 commit comments

Comments
 (0)