forked from webpack-contrib/source-map-loader
-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
142 lines (138 loc) · 4.53 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var fs = require("fs");
var path = require("path");
var loaderUtils = require("loader-utils");
var urlUtils = require("url");
// Matches only the last occurrence of sourceMappingURL
var baseRegex = "\\s*[@#]\\s*sourceMappingURL\\s*=\\s*([^\\s]*)(?![\\S\\s]*sourceMappingURL)",
// Matches /* ... */ comments
regex1 = new RegExp("/\\*"+baseRegex+"\\s*\\*/"),
// Matches // .... comments
regex2 = new RegExp("//"+baseRegex+"($|\n|\r\n?)"),
// Matches DataUrls
regexDataUrl = /data:[^;\n]+(?:;charset=[^;\n]+)?;base64,([a-zA-Z0-9+/]+={0,2})/,
// Matches url with scheme, doesn't match Windows disk
regexUrl = /[a-zA-Z]{2,}:/;
const FILE_SCHEME = "file:";
const DEFAULT_OPTIONS = {
// Prevent the loader to rewrite all sources as absolute paths
keepRelativeSources: false
};
module.exports = function(input, inputMap) {
const options = Object.assign({}, DEFAULT_OPTIONS, loaderUtils.getOptions(this));
this.cacheable && this.cacheable();
var addDependency = this.addDependency;
var emitWarning = this.emitWarning || function() {};
var match = input.match(regex1) || input.match(regex2);
var callback;
if(match) {
var url = match[1];
var dataUrlMatch = regexDataUrl.exec(url);
callback = this.async();
if(dataUrlMatch) {
var mapBase64 = dataUrlMatch[1];
var mapStr = Buffer.from(mapBase64, "base64").toString();
var map;
try {
map = JSON.parse(mapStr)
} catch (e) {
emitWarning(new Error("Cannot parse inline SourceMap '"
+ mapBase64.substr(0, 50) + "': " + e));
return untouched();
}
processMap(map, this.context, callback);
} else {
resolveAbsolutePath(this.context, url, function(err, absoluteFilepath) {
if(err) {
emitWarning(new Error("Cannot find SourceMap '" + url + "': " + err));
return untouched();
}
fs.readFile(absoluteFilepath, "utf-8", function(err, content) {
if(err) {
emitWarning(new Error("Cannot open SourceMap '" + absoluteFilepath + "': " + err));
return untouched();
}
addDependency(absoluteFilepath);
var map;
try {
map = JSON.parse(content);
} catch (e) {
emitWarning(new Error("Cannot parse SourceMap '" + url + "': " + e));
return untouched();
}
processMap(map, path.dirname(absoluteFilepath), callback);
});
}.bind(this));
}
} else {
callback = this.callback;
return untouched();
}
function untouched() {
callback(null, input, inputMap);
}
function resolveAbsolutePath(context, url, resolveAbsolutePathCallback) {
let filepath = url;
if(regexUrl.test(filepath) && !filepath.startsWith(FILE_SCHEME)) {
resolveAbsolutePathCallback("URL scheme not supported");
return;
}
if(filepath.startsWith(FILE_SCHEME)) {
if(urlUtils.fileURLToPath) {
filepath = urlUtils.fileURLToPath(filepath);
} else {
resolveAbsolutePathCallback("file URL scheme support requires node 10.x");
return;
}
}
resolveAbsolutePathCallback(null, path.resolve(context, filepath));
}
function processMap(map, context, callback) {
const sourcePrefix = map.sourceRoot ? map.sourceRoot + "/" : "";
const sources = map.sources.map(function(s) { return sourcePrefix + s; });
delete map.sourceRoot;
const sourcesContent = map.sourcesContent || [];
const sourcesPromises = sources.map((source, sourceIndex) => new Promise((resolveSource) => {
resolveAbsolutePath(context, source, function(err, absoluteFilepath) {
if(err) {
emitWarning(new Error("Cannot find source file '" + source + "': " + err));
return resolveSource({
source: source,
content: sourcesContent[sourceIndex] != null ? sourcesContent[sourceIndex] : null
});
}
if(sourcesContent[sourceIndex] != null) {
return resolveSource({
source: absoluteFilepath,
content: sourcesContent[sourceIndex]
});
}
fs.readFile(absoluteFilepath, "utf-8", function(err, content) {
if(err) {
emitWarning(new Error("Cannot open source file '" + absoluteFilepath + "': " + err));
return resolveSource({
source: absoluteFilepath,
content: null
});
}
addDependency(absoluteFilepath);
resolveSource({
source: absoluteFilepath,
content: content
});
});
});
}));
Promise.all(sourcesPromises)
.then((results) => {
if (!options.keepRelativeSources) {
map.sources = results.map(res => res.source);
}
map.sourcesContent = results.map(res => res.content);
callback(null, input.replace(match[0], ""), map);
});
}
}