Skip to content

Commit 0d77b18

Browse files
refactor: code
1 parent 2ceba27 commit 0d77b18

File tree

7 files changed

+535
-363
lines changed

7 files changed

+535
-363
lines changed

src/index.js

+81-156
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,14 @@
11
/*
2-
MIT License http://www.opensource.org/licenses/mit-license.php
3-
Author Tobias Koppers @sokra
2+
MIT License http://www.opensource.org/licenses/mit-license.php
3+
Author Tobias Koppers @sokra
44
*/
55
import path from 'path';
66

7-
import { promisify } from 'util';
8-
97
import validateOptions from 'schema-utils';
10-
import parseDataURL from 'data-urls';
11-
12-
import { SourceMapConsumer } from 'source-map';
13-
14-
import { labelToName, decode } from 'whatwg-encoding';
15-
import { getOptions, urlToRequest } from 'loader-utils';
8+
import { getOptions } from 'loader-utils';
169

1710
import schema from './options.json';
18-
import {
19-
flattenSourceMap,
20-
readFile,
21-
getContentFromSourcesContent,
22-
getSourceMappingUrl,
23-
getRequestedUrl,
24-
} from './utils';
11+
import { getSourceMappingURL, fetchFromURL, flattenSourceMap } from './utils';
2512

2613
export default async function loader(input, inputMap) {
2714
const options = getOptions(this);
@@ -31,179 +18,117 @@ export default async function loader(input, inputMap) {
3118
baseDataPath: 'options',
3219
});
3320

34-
let { url } = getSourceMappingUrl(input);
35-
const { replacementString } = getSourceMappingUrl(input);
21+
const { sourceMappingURL, replacementString } = getSourceMappingURL(input);
3622
const callback = this.async();
3723

38-
if (!url) {
24+
if (!sourceMappingURL) {
3925
callback(null, input, inputMap);
4026

4127
return;
4228
}
4329

44-
const { fs, context, resolve, addDependency, emitWarning } = this;
45-
const resolver = promisify(resolve);
46-
const reader = promisify(fs.readFile).bind(fs);
30+
let sourceURL;
31+
let sourceContent;
4732

48-
if (url.toLowerCase().startsWith('data:')) {
49-
const dataURL = parseDataURL(url);
50-
51-
if (dataURL) {
52-
let map;
53-
54-
try {
55-
dataURL.encodingName =
56-
labelToName(dataURL.mimeType.parameters.get('charset')) || 'UTF-8';
57-
58-
map = decode(dataURL.body, dataURL.encodingName);
59-
map = JSON.parse(map.replace(/^\)\]\}'/, ''));
60-
} catch (error) {
61-
emitWarning(
62-
`Cannot parse inline SourceMap with Charset ${dataURL.encodingName}: ${error}`
63-
);
33+
try {
34+
({ sourceURL, sourceContent } = await fetchFromURL(
35+
this,
36+
this.context,
37+
sourceMappingURL
38+
));
39+
} catch (error) {
40+
this.emitWarning(error);
6441

65-
callback(null, input, inputMap);
42+
callback(null, input, inputMap);
6643

67-
return;
68-
}
44+
return;
45+
}
6946

70-
processMap(map, context, callback);
47+
if (sourceURL) {
48+
this.addDependency(sourceURL);
49+
}
7150

72-
return;
73-
}
51+
let map;
7452

75-
emitWarning(`Cannot parse inline SourceMap: ${url}`);
53+
try {
54+
map = JSON.parse(sourceContent.replace(/^\)\]\}'/, ''));
55+
} catch (parseError) {
56+
this.emitWarning(
57+
new Error(`Cannot parse source map from '${sourceURL}': ${parseError}`)
58+
);
7659

7760
callback(null, input, inputMap);
7861

7962
return;
8063
}
8164

82-
try {
83-
url = getRequestedUrl(url);
84-
} catch (error) {
85-
emitWarning(error.message);
65+
const context = sourceURL ? path.dirname(sourceURL) : this.context;
8666

87-
callback(null, input, inputMap);
88-
89-
return;
67+
if (map.sections) {
68+
// eslint-disable-next-line no-param-reassign
69+
map = await flattenSourceMap(map);
9070
}
9171

92-
let urlResolved;
72+
const resolvedSources = await Promise.all(
73+
map.sources.map(async (source, i) => {
74+
// eslint-disable-next-line no-shadow
75+
let sourceURL;
76+
// eslint-disable-next-line no-shadow
77+
let sourceContent;
9378

94-
try {
95-
urlResolved = await resolver(context, urlToRequest(url, true));
96-
} catch (resolveError) {
97-
emitWarning(`Cannot find SourceMap '${url}': ${resolveError}`);
79+
const originalSourceContent =
80+
map.sourcesContent && map.sourcesContent[i]
81+
? map.sourcesContent[i]
82+
: null;
83+
const skipReading = originalSourceContent !== null;
9884

99-
callback(null, input, inputMap);
85+
try {
86+
({ sourceURL, sourceContent } = await fetchFromURL(
87+
this,
88+
context,
89+
source,
90+
map.sourceRoot,
91+
skipReading
92+
));
93+
} catch (error) {
94+
this.emitWarning(error);
10095

101-
return;
102-
}
96+
sourceURL = source;
97+
}
10398

104-
urlResolved = urlResolved.toString();
99+
if (originalSourceContent) {
100+
sourceContent = originalSourceContent;
101+
}
105102

106-
addDependency(urlResolved);
103+
if (sourceURL) {
104+
this.addDependency(sourceURL);
105+
}
107106

108-
const content = await reader(urlResolved);
109-
let map;
107+
return { sourceURL, sourceContent };
108+
})
109+
);
110110

111-
try {
112-
map = JSON.parse(content.toString());
113-
} catch (parseError) {
114-
emitWarning(`Cannot parse SourceMap '${url}': ${parseError}`);
111+
const newMap = { ...map };
115112

116-
callback(null, input, inputMap);
113+
newMap.sources = [];
114+
newMap.sourcesContent = [];
117115

118-
return;
119-
}
116+
delete newMap.sourceRoot;
120117

121-
processMap(map, path.dirname(urlResolved), callback);
122-
123-
// eslint-disable-next-line no-shadow
124-
async function processMap(map, context, callback) {
125-
if (map.sections) {
126-
// eslint-disable-next-line no-param-reassign
127-
map = await flattenSourceMap(map);
128-
}
129-
130-
const mapConsumer = await new SourceMapConsumer(map);
131-
132-
let resolvedSources;
133-
134-
try {
135-
resolvedSources = await Promise.all(
136-
map.sources.map(async (source) => {
137-
const fullPath = map.sourceRoot
138-
? `${map.sourceRoot}${path.sep}${source}`
139-
: source;
140-
141-
const originalData = getContentFromSourcesContent(
142-
mapConsumer,
143-
source
144-
);
145-
146-
if (path.isAbsolute(fullPath)) {
147-
return originalData
148-
? { source: fullPath, content: originalData }
149-
: readFile(fullPath, emitWarning, reader);
150-
}
151-
152-
let fullPathResolved;
153-
154-
try {
155-
fullPathResolved = await resolver(
156-
context,
157-
urlToRequest(fullPath, true)
158-
);
159-
} catch (resolveError) {
160-
emitWarning(`Cannot find source file '${source}': ${resolveError}`);
161-
162-
return originalData
163-
? {
164-
source: fullPath,
165-
content: originalData,
166-
}
167-
: { source: fullPath, content: null };
168-
}
169-
170-
return originalData
171-
? {
172-
source: fullPathResolved,
173-
content: originalData,
174-
}
175-
: readFile(fullPathResolved, emitWarning, reader);
176-
})
177-
);
178-
} catch (error) {
179-
emitWarning(error);
180-
181-
callback(null, input, inputMap);
182-
}
183-
184-
const resultMap = { ...map };
185-
resultMap.sources = [];
186-
resultMap.sourcesContent = [];
187-
188-
delete resultMap.sourceRoot;
189-
190-
resolvedSources.forEach((res) => {
191-
// eslint-disable-next-line no-param-reassign
192-
resultMap.sources.push(path.normalize(res.source));
193-
resultMap.sourcesContent.push(res.content);
194-
195-
if (res.source) {
196-
addDependency(res.source);
197-
}
198-
});
118+
resolvedSources.forEach((source) => {
119+
// eslint-disable-next-line no-shadow
120+
const { sourceURL, sourceContent } = source;
199121

200-
const sourcesContentIsEmpty =
201-
resultMap.sourcesContent.filter((entry) => !!entry).length === 0;
122+
newMap.sources.push(sourceURL || '');
123+
newMap.sourcesContent.push(sourceContent || '');
124+
});
202125

203-
if (sourcesContentIsEmpty) {
204-
delete resultMap.sourcesContent;
205-
}
126+
const sourcesContentIsEmpty =
127+
newMap.sourcesContent.filter((entry) => Boolean(entry)).length === 0;
206128

207-
callback(null, input.replace(replacementString, ''), resultMap);
129+
if (sourcesContentIsEmpty) {
130+
delete newMap.sourcesContent;
208131
}
132+
133+
callback(null, input.replace(replacementString, ''), newMap);
209134
}

0 commit comments

Comments
 (0)