-
Notifications
You must be signed in to change notification settings - Fork 8
/
index.ts
68 lines (60 loc) · 2.46 KB
/
index.ts
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
import * as convert from "convert-source-map";
import { createInstrumenter, RawSourceMap } from "istanbul-lib-instrument";
import * as loaderUtils from "loader-utils";
import mergeSourceMap from "merge-source-map";
import * as path from "path";
import validateOptions from "schema-utils";
import { loader } from "webpack";
import * as optionsSchema from "./options-schema.json";
import { defaultOptions, Options } from "./options.js";
/**
* Adds code coverage instrumentation using Istanbul.
*
* If the source code has an existing source map, then it is used to re-map the instrumented
* code back to the original source.
*/
export default function(this: loader.LoaderContext, source: string, sourceMap?: RawSourceMap) {
let options: Options = loaderUtils.getOptions(this);
options = Object.assign(defaultOptions, options);
validateOptions(optionsSchema, options, "Coverage Istanbul Loader");
// If there's no external sourceMap file, then check for an inline sourceMap
if (!sourceMap) {
sourceMap = getInlineSourceMap.call(this, source);
}
// Instrument the code
let instrumenter = createInstrumenter(options);
instrumenter.instrument(source, this.resourcePath, done.bind(this), sourceMap);
function done(this: loader.LoaderContext, error: Error | null, instrumentedSource: string) {
// Get the source map for the instrumented code
let instrumentedSourceMap = instrumenter.lastSourceMap();
if (sourceMap && instrumentedSourceMap) {
// Re-map the source map to the original source code
instrumentedSourceMap = mergeSourceMap(sourceMap, instrumentedSourceMap);
}
this.callback(error, instrumentedSource, instrumentedSourceMap);
}
}
/**
* If the source code has an inline base64-encoded source map,
* then this function decodes it, parses it, and returns it.
*/
function getInlineSourceMap(this: loader.LoaderContext, source: string): RawSourceMap | undefined {
try {
// Check for an inline source map
const inlineSourceMap = convert.fromSource(source)
|| convert.fromMapFileSource(source, path.dirname(this.resourcePath));
if (inlineSourceMap) {
// Use the inline source map
return inlineSourceMap.sourcemap as RawSourceMap;
}
}
catch (e) {
// Exception is thrown by fromMapFileSource when there is no source map file
if (e instanceof Error && e.message.includes("An error occurred while trying to read the map file at")) {
this.emitWarning(e);
}
else {
throw e;
}
}
}