@teamscale/javascript-instrumenter 1.0.0-beta.6 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +0 -25
  2. package/dist/main.mjs +216 -0
  3. package/dist/vaccine.js +1 -1
  4. package/package.json +28 -19
  5. package/dist/package.json +0 -69
  6. package/dist/src/App.d.ts +0 -52
  7. package/dist/src/App.d.ts.map +0 -1
  8. package/dist/src/App.js +0 -283
  9. package/dist/src/instrumenter/FileSystem.d.ts +0 -38
  10. package/dist/src/instrumenter/FileSystem.d.ts.map +0 -1
  11. package/dist/src/instrumenter/FileSystem.js +0 -134
  12. package/dist/src/instrumenter/Instrumenter.d.ts +0 -92
  13. package/dist/src/instrumenter/Instrumenter.d.ts.map +0 -1
  14. package/dist/src/instrumenter/Instrumenter.js +0 -376
  15. package/dist/src/instrumenter/InstrumenterConfig.d.ts +0 -37
  16. package/dist/src/instrumenter/InstrumenterConfig.d.ts.map +0 -1
  17. package/dist/src/instrumenter/InstrumenterConfig.js +0 -165
  18. package/dist/src/instrumenter/RelativeCollectorPatternParser.d.ts +0 -8
  19. package/dist/src/instrumenter/RelativeCollectorPatternParser.d.ts.map +0 -1
  20. package/dist/src/instrumenter/RelativeCollectorPatternParser.js +0 -53
  21. package/dist/src/instrumenter/RelativeCollectorPatternParser.test.d.ts +0 -2
  22. package/dist/src/instrumenter/RelativeCollectorPatternParser.test.d.ts.map +0 -1
  23. package/dist/src/instrumenter/RelativeCollectorPatternParser.test.js +0 -28
  24. package/dist/src/instrumenter/Task.d.ts +0 -224
  25. package/dist/src/instrumenter/Task.d.ts.map +0 -1
  26. package/dist/src/instrumenter/Task.js +0 -309
  27. package/dist/src/instrumenter/TaskBuilder.d.ts +0 -75
  28. package/dist/src/instrumenter/TaskBuilder.d.ts.map +0 -1
  29. package/dist/src/instrumenter/TaskBuilder.js +0 -228
  30. package/dist/src/instrumenter/WebToolkit.d.ts +0 -40
  31. package/dist/src/instrumenter/WebToolkit.d.ts.map +0 -1
  32. package/dist/src/instrumenter/WebToolkit.js +0 -146
  33. package/dist/src/main.d.ts +0 -3
  34. package/dist/src/main.d.ts.map +0 -1
  35. package/dist/src/main.js +0 -8
  36. package/dist/src/vaccine/types.d.ts +0 -65
  37. package/dist/src/vaccine/types.d.ts.map +0 -1
  38. package/dist/src/vaccine/types.js +0 -2
@@ -1,134 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.isExistingFile = isExistingFile;
40
- exports.isExistingDirectory = isExistingDirectory;
41
- exports.ensureExistingDirectory = ensureExistingDirectory;
42
- exports.findSubFolders = findSubFolders;
43
- exports.isDirectoryEmpty = isDirectoryEmpty;
44
- exports.expandToFileSet = expandToFileSet;
45
- exports.sourceMapFromMapFile = sourceMapFromMapFile;
46
- exports.replaceNonFilesystemCharacters = replaceNonFilesystemCharacters;
47
- const commons_1 = require("@cqse/commons");
48
- const fs = __importStar(require("fs"));
49
- const mkdirp = __importStar(require("mkdirp"));
50
- const path_1 = __importDefault(require("path"));
51
- const glob_1 = require("glob");
52
- /**
53
- * Does the given `path` point to an existing file?
54
- */
55
- function isExistingFile(path) {
56
- return fs.existsSync(path) && fs.lstatSync(path).isFile();
57
- }
58
- /**
59
- * Does the given `path` point to an existing directory?
60
- */
61
- function isExistingDirectory(path) {
62
- return fs.existsSync(path) && fs.lstatSync(path).isDirectory();
63
- }
64
- /**
65
- * Ensure that the given directory `path` exists.
66
- */
67
- function ensureExistingDirectory(path) {
68
- if (!fs.existsSync(path)) {
69
- mkdirp.sync(path);
70
- }
71
- if (!fs.lstatSync(path).isDirectory()) {
72
- throw new commons_1.InvalidConfigurationException(`The specified path '${path}' does not point to an existing directory!`);
73
- }
74
- }
75
- /**
76
- * Given a root folder find a folder with a given name.
77
- */
78
- function findSubFolders(startFromFolder, folderName) {
79
- const matches = [];
80
- const entries = fs.readdirSync(startFromFolder, { withFileTypes: true });
81
- for (const entry of entries) {
82
- const fullPath = path_1.default.join(startFromFolder, entry.name);
83
- if (entry.name === folderName && entry.isDirectory()) {
84
- matches.push(fullPath);
85
- }
86
- if (entry.isDirectory()) {
87
- const nestedMatches = findSubFolders(fullPath, folderName);
88
- matches.push(...nestedMatches);
89
- }
90
- }
91
- return matches;
92
- }
93
- /**
94
- * Is the given directory empty?
95
- */
96
- function isDirectoryEmpty(path) {
97
- return !isExistingDirectory(path) || fs.readdirSync(path).length > 0;
98
- }
99
- /**
100
- * Expand a given Glob pattern to a list of files.
101
- *
102
- * @param toExpand - The Glob pattern.
103
- */
104
- function expandToFileSet(toExpand) {
105
- let globPattern = toExpand;
106
- if (fs.existsSync(toExpand)) {
107
- const stat = fs.lstatSync(toExpand, {});
108
- if (stat.isFile()) {
109
- return [toExpand];
110
- }
111
- if (stat.isDirectory()) {
112
- globPattern = `${toExpand}${path_1.default.sep}**`;
113
- }
114
- }
115
- return glob_1.glob.sync(globPattern, { nodir: true });
116
- }
117
- /**
118
- * Read a source map from a source map file.
119
- *
120
- * @param mapFilePath
121
- */
122
- function sourceMapFromMapFile(mapFilePath) {
123
- const content = fs.readFileSync(mapFilePath, 'utf8');
124
- return JSON.parse(content);
125
- }
126
- /**
127
- * Ensure that the given name works as a file or folder name.
128
- */
129
- function replaceNonFilesystemCharacters(name) {
130
- // Replace undesired characters by underscore chars.
131
- const result = name.replace(/[^a-zA-Z0-9_\-.\\/]/g, '_');
132
- // Remove repeated underscores (_) from `result.
133
- return result.replace(/_+/g, '_');
134
- }
@@ -1,92 +0,0 @@
1
- import { FileExcludePattern, InstrumentationTask, OriginSourcePattern, SourceMapReference, TaskElement, TaskResult } from './Task';
2
- import { RawSourceMap, SourceMapConsumer } from 'source-map';
3
- import Logger from 'bunyan';
4
- import { CollectorSpecifier, CoverageBucketSpecifier } from '@src/vaccine/types';
5
- export declare const IS_INSTRUMENTED_TOKEN = "$IS_JS_PROFILER_INSTRUMENTED=true";
6
- /**
7
- * An instrumenter that can conduct a {@code InstrumentationTask}.
8
- */
9
- export interface IInstrumenter {
10
- /**
11
- * Perform the given instrumentation task.
12
- *
13
- * @param task - The instrumentation task to conduct.
14
- */
15
- instrument(task: InstrumentationTask): Promise<TaskResult>;
16
- }
17
- /**
18
- * An instrumenter based on the IstanbulJs instrumentation and coverage framework.
19
- */
20
- export declare class IstanbulInstrumenter implements IInstrumenter {
21
- /**
22
- * The vaccine to inject. The vaccine is a JavaScript
23
- * file with the code to forward the coverage information
24
- * produced by the Istanbul instrumentation.
25
- */
26
- private readonly vaccineSource;
27
- /**
28
- * The logger instance to log to.
29
- */
30
- private logger;
31
- constructor(vaccineFilePath: string, logger: Logger, collector: CollectorSpecifier, targetBucket: CoverageBucketSpecifier);
32
- /**
33
- * {@inheritDoc #IInstrumenter.instrument}
34
- */
35
- instrument(task: InstrumentationTask): Promise<TaskResult>;
36
- /**
37
- * Perform the instrumentation for one given task element (file to instrument).
38
- *
39
- * @param collector - The collector to send the coverage information to.
40
- * @param taskElement - The task element to perform the instrumentation for.
41
- * @param excludeBundles - A exclude pattern to restrict which bundles should be instrumented
42
- * @param sourcePattern - A pattern to restrict the instrumentation to only a fraction of the task element.
43
- * @param dumpOriginsFile - A file path where all origins from the source map should be dumped in json format, or undefined if no origins should be dumped
44
- */
45
- instrumentOne(taskElement: TaskElement, excludeBundles: FileExcludePattern, sourcePattern: OriginSourcePattern, dumpOriginsFile: string | undefined): Promise<TaskResult>;
46
- private instrumentBundle;
47
- private writeBundleFile;
48
- /**
49
- * Loads the vaccine from the vaccine file and adjusts some template parameters.
50
- *
51
- * @param filePath - The path to the vaccine file.
52
- * @param collector - The collector to send coverage information to.
53
- * @param targetBucket - The bucket within the collector to put the coverage into.
54
- */
55
- private loadVaccine;
56
- /**
57
- * @returns whether the given file is supported for instrumentation.
58
- */
59
- private isFileTypeSupported;
60
- /**
61
- * Determine the list of configurations to try conducting the
62
- * given task element.
63
- */
64
- private configurationAlternativesFor;
65
- /** Deletes the file if it exists, such that it is now ready to be appended. */
66
- private clearFile;
67
- /** Write the contents of the given object into the given file, if provided. */
68
- private dumpToJson;
69
- }
70
- /**
71
- * Extract the sourcemap from the given source code.
72
- *
73
- * @param instrumentedSource - The source code.
74
- * @param instrumentedSourceFileName - The file name to assume for the file name.
75
- */
76
- export declare function loadSourceMap(instrumentedSource: string, instrumentedSourceFileName: string): Promise<SourceMapConsumer | undefined>;
77
- /**
78
- * Given a source code file, load the corresponding sourcemap.
79
- *
80
- * @param inputSource - The source code that might contain sourcemap comments.
81
- * @param taskFile - The name of the file the `inputSource` is from.
82
- * @param externalSourceMapFile - An external source map file to consider.
83
- */
84
- export declare function loadInputSourceMap(inputSource: string, taskFile: string, externalSourceMapFile?: SourceMapReference): RawSourceMap | undefined;
85
- /**
86
- * Extract a sourcemap for a given code comment.
87
- *
88
- * @param sourcecode - The source code that is scanned for source map comments.
89
- * @param sourceFilePath - The file name the code was loaded from.
90
- */
91
- export declare function sourceMapFromCodeComment(sourcecode: string, sourceFilePath: string): RawSourceMap | undefined;
92
- //# sourceMappingURL=Instrumenter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Instrumenter.d.ts","sourceRoot":"","sources":["../../../src/instrumenter/Instrumenter.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,kBAAkB,EAElB,mBAAmB,EACnB,mBAAmB,EAEnB,kBAAkB,EAElB,WAAW,EACX,UAAU,EACV,MAAM,QAAQ,CAAC;AAEhB,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAM7D,OAAO,MAAM,MAAM,QAAQ,CAAC;AAO5B,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAEjF,eAAO,MAAM,qBAAqB,sCAAsC,CAAC;AAEzE;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B;;;;OAIG;IACH,UAAU,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAC3D;AA0BD;;GAEG;AACH,qBAAa,oBAAqB,YAAW,aAAa;IACzD;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IAEvC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAS;gBAEX,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,kBAAkB,EAAE,YAAY,EAAE,uBAAuB;IAUzH;;OAEG;IACG,UAAU,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC;IA2BhE;;;;;;;;OAQG;IACG,aAAa,CAClB,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,kBAAkB,EAClC,aAAa,EAAE,mBAAmB,EAClC,eAAe,EAAE,MAAM,GAAG,SAAS,GACjC,OAAO,CAAC,UAAU,CAAC;YAsER,gBAAgB;IA8C9B,OAAO,CAAC,eAAe;IA0BvB;;;;;;OAMG;IACH,OAAO,CAAC,WAAW;IAQnB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAS3B;;;OAGG;IACH,OAAO,CAAC,4BAA4B;IAiBpC,+EAA+E;IAC/E,OAAO,CAAC,SAAS;IAUjB,+EAA+E;IAC/E,OAAO,CAAC,UAAU;CAYlB;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CAClC,kBAAkB,EAAE,MAAM,EAC1B,0BAA0B,EAAE,MAAM,GAChC,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAUxC;AAsBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CACjC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,qBAAqB,CAAC,EAAE,kBAAkB,GACxC,YAAY,GAAG,SAAS,CAU1B;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAwC7G"}
@@ -1,376 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.IstanbulInstrumenter = exports.IS_INSTRUMENTED_TOKEN = void 0;
40
- exports.loadSourceMap = loadSourceMap;
41
- exports.loadInputSourceMap = loadInputSourceMap;
42
- exports.sourceMapFromCodeComment = sourceMapFromCodeComment;
43
- const Task_1 = require("./Task");
44
- const commons_1 = require("@cqse/commons");
45
- const source_map_1 = require("source-map");
46
- const istanbul = __importStar(require("@teamscale/lib-instrument"));
47
- const fs = __importStar(require("fs"));
48
- const mkdirp = __importStar(require("mkdirp"));
49
- const path = __importStar(require("path"));
50
- const convertSourceMap = __importStar(require("convert-source-map"));
51
- const async_1 = __importDefault(require("async"));
52
- const WebToolkit_1 = require("./WebToolkit");
53
- const FileSystem_1 = require("./FileSystem");
54
- exports.IS_INSTRUMENTED_TOKEN = '$IS_JS_PROFILER_INSTRUMENTED=true';
55
- function readBundle(bundleContent, taskElement) {
56
- const baseNameMatch = path.basename(taskElement.fromFile).match('^([a-zA-Z0-9]*).cache.js');
57
- const directories = path.dirname(taskElement.fromFile).split(path.sep);
58
- if (baseNameMatch && directories.length > 1) {
59
- const fragmentId = (0, WebToolkit_1.determineGwtFileUid)(taskElement.fromFile);
60
- const functionCall = bundleContent.match('^([^(]+)\\((.*)\\);*\\s*$');
61
- if (fragmentId && functionCall && functionCall.length === 3) {
62
- const callInfos = (0, WebToolkit_1.extractGwtCallInfos)(bundleContent);
63
- if (callInfos) {
64
- return {
65
- type: 'gwt',
66
- content: bundleContent,
67
- fragmentId,
68
- functionName: callInfos.functionName,
69
- codeAsArrayArgument: callInfos.codeAsArrayArgument,
70
- codeArguments: callInfos.codeArguments
71
- };
72
- }
73
- }
74
- }
75
- return { type: 'javascript', content: bundleContent, codeArguments: [bundleContent] };
76
- }
77
- /**
78
- * An instrumenter based on the IstanbulJs instrumentation and coverage framework.
79
- */
80
- class IstanbulInstrumenter {
81
- constructor(vaccineFilePath, logger, collector, targetBucket) {
82
- commons_1.Contract.require(fs.existsSync(vaccineFilePath), `The vaccine file to inject "${vaccineFilePath}" must exist!\nCWD:${process.cwd()}`);
83
- this.vaccineSource = this.loadVaccine(commons_1.Contract.requireNonEmpty(vaccineFilePath), collector, targetBucket);
84
- this.logger = logger;
85
- }
86
- /**
87
- * {@inheritDoc #IInstrumenter.instrument}
88
- */
89
- async instrument(task) {
90
- this.clearFile(task.dumpOriginsFile);
91
- this.clearFile(task.dumpMatchedOriginsFile);
92
- // We limit the number of instrumentations in parallel to one to
93
- // not overuse memory (NodeJS has only limited mem to use).
94
- const result = await async_1.default
95
- .mapLimit(task.elements, 1, async (taskElement) => {
96
- return await this.instrumentOne(taskElement, task.excludeFilesPattern, task.originSourcePattern, task.dumpOriginsFile);
97
- })
98
- .then(results => {
99
- return results.reduce((prev, curr) => {
100
- return prev.withIncrement(curr);
101
- }, Task_1.TaskResult.neutral(task));
102
- });
103
- // Write the matching statistics to a JSON
104
- this.dumpToJson(task.dumpMatchedOriginsFile, task.originSourcePattern.retrieveMatchingFiles());
105
- return result;
106
- }
107
- /**
108
- * Perform the instrumentation for one given task element (file to instrument).
109
- *
110
- * @param collector - The collector to send the coverage information to.
111
- * @param taskElement - The task element to perform the instrumentation for.
112
- * @param excludeBundles - A exclude pattern to restrict which bundles should be instrumented
113
- * @param sourcePattern - A pattern to restrict the instrumentation to only a fraction of the task element.
114
- * @param dumpOriginsFile - A file path where all origins from the source map should be dumped in json format, or undefined if no origins should be dumped
115
- */
116
- async instrumentOne(taskElement, excludeBundles, sourcePattern, dumpOriginsFile) {
117
- // Not all file types are supported by the instrumenter
118
- if (!this.isFileTypeSupported(taskElement.fromFile)) {
119
- if (!taskElement.isInPlace()) {
120
- copyToFile(taskElement.toFile, taskElement.fromFile);
121
- }
122
- return new Task_1.TaskResult(0, 0, 0, 0, 1, 0, 0);
123
- }
124
- // Read the (supported) file
125
- const bundleContent = fs.readFileSync(taskElement.fromFile, 'utf8');
126
- const inputBundle = readBundle(bundleContent, taskElement);
127
- // We skip files that we have already instrumented
128
- if (inputBundle.content.substring(0, Math.min(inputBundle.content.length, 100)).includes(exports.IS_INSTRUMENTED_TOKEN)) {
129
- if (!taskElement.isInPlace()) {
130
- writeToFile(taskElement.toFile, inputBundle.content);
131
- }
132
- return new Task_1.TaskResult(0, 0, 0, 1, 0, 0, 0);
133
- }
134
- // We might want to skip the instrumentation of the file
135
- if (excludeBundles.isExcluded(taskElement.fromFile)) {
136
- if (!taskElement.isInPlace()) {
137
- copyToFile(taskElement.toFile, taskElement.fromFile);
138
- }
139
- return new Task_1.TaskResult(0, 1, 0, 0, 0, 0, 0);
140
- }
141
- // Report progress
142
- this.logger.info(`Instrumenting "${path.basename(taskElement.fromFile)}"`);
143
- // Load the bundles source maps
144
- const inputSourceMaps = loadInputSourceMaps(taskElement.fromFile, inputBundle, taskElement.externalSourceMapFile);
145
- if (inputSourceMaps.length === 0) {
146
- return Task_1.TaskResult.warning(`Failed loading input source map for ${taskElement.fromFile}.`);
147
- }
148
- // We try to perform the instrumentation with different
149
- // alternative configurations of the instrumenter.
150
- const configurationAlternatives = this.configurationAlternativesFor(taskElement);
151
- for (let i = 0; i < configurationAlternatives.length; i++) {
152
- const configurationAlternative = configurationAlternatives[i];
153
- try {
154
- return await this.instrumentBundle(taskElement, inputBundle, inputSourceMaps, configurationAlternative, dumpOriginsFile, sourcePattern);
155
- }
156
- catch (e) {
157
- // If also the last configuration alternative failed,
158
- // we emit a corresponding warning or signal an error.
159
- if (i === configurationAlternatives.length - 1) {
160
- writeToFile(taskElement.toFile, inputBundle.content);
161
- return Task_1.TaskResult.error(e);
162
- }
163
- }
164
- }
165
- return new Task_1.TaskResult(0, 0, 0, 0, 0, 1, 0);
166
- }
167
- async instrumentBundle(taskElement, inputBundle, inputSourceMaps, configurationAlternative, dumpOriginsFile, sourcePattern) {
168
- var _a;
169
- // Based on the source maps of the file to instrument, we can now
170
- // decide if we should NOT write an instrumented version of it
171
- // and use the original code instead and write it to the target path.
172
- //
173
- for (const inputSourceMap of inputSourceMaps.filter(map => map)) {
174
- const originSourceFiles = (_a = inputSourceMap === null || inputSourceMap === void 0 ? void 0 : inputSourceMap.sources) !== null && _a !== void 0 ? _a : [];
175
- if (dumpOriginsFile) {
176
- this.dumpToJson(dumpOriginsFile, originSourceFiles);
177
- }
178
- }
179
- // The main instrumentation (adding coverage statements) is performed now:
180
- const instrumenter = istanbul.createInstrumenter(configurationAlternative);
181
- const instrumentedSources = [];
182
- for (let i = 0; i < inputBundle.codeArguments.length; i++) {
183
- const shouldInstrument = (node, originLocation) => {
184
- if (!originLocation.filename) {
185
- return false;
186
- }
187
- return sourcePattern.isIncluded(originLocation.filename);
188
- };
189
- const instrumented = await instrumenter.instrument(inputBundle.codeArguments[i], taskElement.fromFile, inputSourceMaps[i], shouldInstrument);
190
- instrumentedSources.push(instrumented);
191
- }
192
- this.writeBundleFile(taskElement.toFile, inputBundle, instrumentedSources);
193
- return new Task_1.TaskResult(1, 0, 0, 0, 0, 0, 0);
194
- }
195
- writeBundleFile(toFile, inputBundle, instrumentedSources) {
196
- if (inputBundle.type === 'gwt') {
197
- commons_1.Contract.require(instrumentedSources.length === 1, 'Assuming only one code fragment to be passed as argument.');
198
- const processedCodeString = JSON.stringify(`${this.vaccineSource} ${instrumentedSources[0]}`);
199
- if (inputBundle.codeAsArrayArgument) {
200
- writeToFile(toFile, `${exports.IS_INSTRUMENTED_TOKEN} ${inputBundle.functionName}([${processedCodeString}]);`);
201
- }
202
- else {
203
- writeToFile(toFile, `${exports.IS_INSTRUMENTED_TOKEN} ${inputBundle.functionName}(${processedCodeString});`);
204
- }
205
- }
206
- else {
207
- commons_1.Contract.require(instrumentedSources.length === 1, 'Assuming only one code fragment to be passed as argument for JavaScript bundles.');
208
- writeToFile(toFile, instrumentedSources[0]);
209
- }
210
- }
211
- /**
212
- * Loads the vaccine from the vaccine file and adjusts some template parameters.
213
- *
214
- * @param filePath - The path to the vaccine file.
215
- * @param collector - The collector to send coverage information to.
216
- * @param targetBucket - The bucket within the collector to put the coverage into.
217
- */
218
- loadVaccine(filePath, collector, targetBucket) {
219
- // We first replace parameters in the file with the
220
- // actual values, for example, the collector to send the coverage information to.
221
- return fs.readFileSync(filePath, 'utf8')
222
- .replace(/\$COLLECTOR_SPECIFIER/g, JSON.stringify(collector))
223
- .replace(/\$BUCKET_SPECIFIER/g, Buffer.from(JSON.stringify(targetBucket)).toString('base64'));
224
- }
225
- /**
226
- * @returns whether the given file is supported for instrumentation.
227
- */
228
- isFileTypeSupported(fileName) {
229
- if (fileName.endsWith('.devmode.js') || fileName.endsWith('.nocache.js')) {
230
- // GWT dev mode files.
231
- return false;
232
- }
233
- const ext = path.extname(fileName).toLowerCase();
234
- return ext === '.js' || ext === '.mjs';
235
- }
236
- /**
237
- * Determine the list of configurations to try conducting the
238
- * given task element.
239
- */
240
- configurationAlternativesFor(taskElement) {
241
- this.logger.trace(`Determining configuration alternatives for ${taskElement.fromFile}`);
242
- const baseConfig = {
243
- isInstrumentedToken: exports.IS_INSTRUMENTED_TOKEN,
244
- produceSourceMap: 'none',
245
- codeToPrepend: this.vaccineSource,
246
- preserveComments: false, // Will remove commends including old source maps that are provided inline as comments
247
- compact: false // Would lead to `code generator has deoptimised the styling of` errors otherwise
248
- };
249
- return [
250
- { ...baseConfig, ...{ esModules: true } },
251
- { ...baseConfig, ...{ esModules: false } }
252
- ];
253
- }
254
- /** Deletes the file if it exists, such that it is now ready to be appended. */
255
- clearFile(filePath) {
256
- if (filePath && fs.existsSync(filePath)) {
257
- try {
258
- fs.unlinkSync(filePath);
259
- }
260
- catch (err) {
261
- this.logger.warn(`Could not clear file ${filePath}:` + err);
262
- }
263
- }
264
- }
265
- /** Write the contents of the given object into the given file, if provided. */
266
- dumpToJson(targetFilePath, toDump) {
267
- if (!targetFilePath) {
268
- return;
269
- }
270
- const jsonContent = JSON.stringify(toDump, null, 2);
271
- fs.writeFile(targetFilePath, jsonContent + '\n', { flag: 'a' }, error => {
272
- if (error) {
273
- this.logger.warn(`Could not dump JSON to file ${targetFilePath}:` + error.message);
274
- }
275
- });
276
- }
277
- }
278
- exports.IstanbulInstrumenter = IstanbulInstrumenter;
279
- /**
280
- * Extract the sourcemap from the given source code.
281
- *
282
- * @param instrumentedSource - The source code.
283
- * @param instrumentedSourceFileName - The file name to assume for the file name.
284
- */
285
- async function loadSourceMap(instrumentedSource, instrumentedSourceFileName) {
286
- const instrumentedSourceMap = loadInputSourceMap(instrumentedSource, instrumentedSourceFileName, undefined);
287
- if (instrumentedSourceMap) {
288
- return await new source_map_1.SourceMapConsumer(instrumentedSourceMap);
289
- }
290
- return undefined;
291
- }
292
- function loadInputSourceMaps(taskFile, bundleFile, externalSourceMapFile) {
293
- if ((0, WebToolkit_1.isGwtBundle)(bundleFile)) {
294
- return (0, WebToolkit_1.loadInputSourceMapsGwt)(taskFile, bundleFile);
295
- }
296
- else {
297
- return loadInputSourceMapsStandard(taskFile, bundleFile, externalSourceMapFile);
298
- }
299
- }
300
- function loadInputSourceMapsStandard(taskFile, bundleFile, externalSourceMapFile) {
301
- return bundleFile.codeArguments.map(code => loadInputSourceMap(code, taskFile, externalSourceMapFile));
302
- }
303
- /**
304
- * Given a source code file, load the corresponding sourcemap.
305
- *
306
- * @param inputSource - The source code that might contain sourcemap comments.
307
- * @param taskFile - The name of the file the `inputSource` is from.
308
- * @param externalSourceMapFile - An external source map file to consider.
309
- */
310
- function loadInputSourceMap(inputSource, taskFile, externalSourceMapFile) {
311
- if (externalSourceMapFile) {
312
- const sourceMapOrigin = externalSourceMapFile;
313
- if (!(sourceMapOrigin instanceof Task_1.SourceMapFileReference)) {
314
- throw new commons_1.IllegalArgumentException('Type of source map not yet supported!');
315
- }
316
- return (0, FileSystem_1.sourceMapFromMapFile)(sourceMapOrigin.sourceMapFilePath);
317
- }
318
- else {
319
- return sourceMapFromCodeComment(inputSource, taskFile);
320
- }
321
- }
322
- /**
323
- * Extract a sourcemap for a given code comment.
324
- *
325
- * @param sourcecode - The source code that is scanned for source map comments.
326
- * @param sourceFilePath - The file name the code was loaded from.
327
- */
328
- function sourceMapFromCodeComment(sourcecode, sourceFilePath) {
329
- // Either `//# sourceMappingURL=vendor.5d7ba975.js.map`
330
- // or `//# sourceMappingURL=data:application/json;base64,eyJ2ZXJ ...`
331
- //
332
- // "It is reasonable for tools to also accept “//@” but “//#” is preferred."
333
- const re = /\/\/[#@]\s(source(?:Mapping)?URL)=\s*(\S+)/g;
334
- let failedLoading = 0;
335
- let result;
336
- let matched;
337
- do {
338
- matched = re.exec(sourcecode);
339
- if (matched) {
340
- const sourceMapComment = matched[0];
341
- try {
342
- if (sourceMapComment.slice(0, 50).indexOf('data:application/json') > 0) {
343
- result = convertSourceMap.fromComment(sourceMapComment).toObject();
344
- }
345
- else {
346
- result = convertSourceMap
347
- .fromMapFileComment(sourceMapComment, function (filename) {
348
- return fs.readFileSync(path.resolve(path.dirname(sourceFilePath), filename), 'utf-8');
349
- })
350
- .toObject();
351
- }
352
- }
353
- catch (e) {
354
- // One JS file can refer to several source map files in its comments.
355
- failedLoading++;
356
- }
357
- }
358
- } while (matched);
359
- if (result) {
360
- return result;
361
- }
362
- if (failedLoading > 0) {
363
- throw new commons_1.IllegalArgumentException('None of the referenced source map files loaded!');
364
- }
365
- else {
366
- return undefined;
367
- }
368
- }
369
- function writeToFile(filePath, fileContent) {
370
- mkdirp.sync(path.dirname(filePath));
371
- fs.writeFileSync(filePath, fileContent);
372
- }
373
- function copyToFile(targetFilePath, sourceFilePath) {
374
- mkdirp.sync(path.dirname(targetFilePath));
375
- fs.copyFileSync(sourceFilePath, targetFilePath);
376
- }
@@ -1,37 +0,0 @@
1
- import { ConfigurationParameters } from '@cqse/commons';
2
- import { LogLevelString } from 'bunyan';
3
- /**
4
- * The options the Instrumenter is configured with.
5
- * For more details on these options:
6
- * @see #buildInstrumenterConfigurationParameters
7
- */
8
- export type InstrumenterOptions = {
9
- version?: boolean;
10
- help?: boolean;
11
- input?: string[];
12
- inPlace?: boolean;
13
- to?: string;
14
- logLevel?: LogLevelString;
15
- configId?: string;
16
- appName?: string;
17
- commit?: string;
18
- sourceMap?: string;
19
- collector: string;
20
- relativeCollector?: string;
21
- includeOrigin?: string[];
22
- excludeOrigin?: string[];
23
- excludeBundle?: string[];
24
- dumpOriginsTo?: string;
25
- dumpOriginMatchesTo?: string;
26
- collectorConfigFile?: string;
27
- collectorConfigFileContent?: string;
28
- collectorOption?: string[];
29
- collectorOptionsList?: boolean;
30
- coverageTargetFromCollector?: boolean;
31
- };
32
- /**
33
- * Builds and returns a configuration parameters object for the JavaScript instrumenter.
34
- * This function defines all supported command-line arguments and their descriptions.
35
- */
36
- export declare function buildInstrumenterConfigurationParameters(): ConfigurationParameters;
37
- //# sourceMappingURL=InstrumenterConfig.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"InstrumenterConfig.d.ts","sourceRoot":"","sources":["../../../src/instrumenter/InstrumenterConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,uBAAuB,EAGvB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAGxC;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACtC,CAAC;AAsBF;;;GAGG;AACH,wBAAgB,wCAAwC,IAAI,uBAAuB,CA+IlF"}