@teamscale/javascript-instrumenter 1.0.0-beta.5 → 1.0.0-beta.7
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.
- package/README.md +0 -25
- package/dist/package.json +22 -28
- package/dist/src/App.d.ts +0 -36
- package/dist/src/App.d.ts.map +1 -1
- package/dist/src/App.js +4 -54
- package/dist/src/instrumenter/FileSystem.d.ts +0 -28
- package/dist/src/instrumenter/FileSystem.d.ts.map +1 -1
- package/dist/src/instrumenter/FileSystem.js +2 -32
- package/dist/src/instrumenter/Instrumenter.d.ts +2 -69
- package/dist/src/instrumenter/Instrumenter.d.ts.map +1 -1
- package/dist/src/instrumenter/Instrumenter.js +11 -94
- package/dist/src/instrumenter/InstrumenterConfig.d.ts +1 -9
- package/dist/src/instrumenter/InstrumenterConfig.d.ts.map +1 -1
- package/dist/src/instrumenter/InstrumenterConfig.js +22 -6
- package/dist/src/instrumenter/RelativeCollectorPatternParser.d.ts +1 -3
- package/dist/src/instrumenter/RelativeCollectorPatternParser.d.ts.map +1 -1
- package/dist/src/instrumenter/RelativeCollectorPatternParser.js +9 -9
- package/dist/src/instrumenter/RelativeCollectorPatternParser.test.js +12 -7
- package/dist/src/instrumenter/Task.d.ts +0 -144
- package/dist/src/instrumenter/Task.d.ts.map +1 -1
- package/dist/src/instrumenter/Task.js +29 -110
- package/dist/src/instrumenter/TaskBuilder.d.ts +0 -50
- package/dist/src/instrumenter/TaskBuilder.d.ts.map +1 -1
- package/dist/src/instrumenter/TaskBuilder.js +12 -59
- package/dist/src/instrumenter/WebToolkit.d.ts +0 -27
- package/dist/src/instrumenter/WebToolkit.d.ts.map +1 -1
- package/dist/src/instrumenter/WebToolkit.js +0 -27
- package/dist/src/main.js +3 -1
- package/dist/src/vaccine/types.d.ts +0 -37
- package/dist/src/vaccine/types.d.ts.map +1 -1
- package/dist/vaccine.js +1 -1
- package/package.json +13 -13
|
@@ -37,12 +37,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.IstanbulInstrumenter = exports.IS_INSTRUMENTED_TOKEN = void 0;
|
|
40
|
-
exports.loadSourceMap = loadSourceMap;
|
|
41
40
|
exports.loadInputSourceMap = loadInputSourceMap;
|
|
42
41
|
exports.sourceMapFromCodeComment = sourceMapFromCodeComment;
|
|
43
42
|
const Task_1 = require("./Task");
|
|
44
43
|
const commons_1 = require("@cqse/commons");
|
|
45
|
-
const source_map_1 = require("source-map");
|
|
46
44
|
const istanbul = __importStar(require("@teamscale/lib-instrument"));
|
|
47
45
|
const fs = __importStar(require("fs"));
|
|
48
46
|
const mkdirp = __importStar(require("mkdirp"));
|
|
@@ -53,12 +51,12 @@ const WebToolkit_1 = require("./WebToolkit");
|
|
|
53
51
|
const FileSystem_1 = require("./FileSystem");
|
|
54
52
|
exports.IS_INSTRUMENTED_TOKEN = '$IS_JS_PROFILER_INSTRUMENTED=true';
|
|
55
53
|
function readBundle(bundleContent, taskElement) {
|
|
56
|
-
const baseNameMatch =
|
|
54
|
+
const baseNameMatch = /^([a-zA-Z0-9]*).cache.js/.exec(path.basename(taskElement.fromFile));
|
|
57
55
|
const directories = path.dirname(taskElement.fromFile).split(path.sep);
|
|
58
56
|
if (baseNameMatch && directories.length > 1) {
|
|
59
57
|
const fragmentId = (0, WebToolkit_1.determineGwtFileUid)(taskElement.fromFile);
|
|
60
|
-
const functionCall =
|
|
61
|
-
if (fragmentId && functionCall
|
|
58
|
+
const functionCall = /^([^(]+)\((.*)\);*\s*$/.exec(bundleContent);
|
|
59
|
+
if (fragmentId && functionCall?.length === 3) {
|
|
62
60
|
const callInfos = (0, WebToolkit_1.extractGwtCallInfos)(bundleContent);
|
|
63
61
|
if (callInfos) {
|
|
64
62
|
return {
|
|
@@ -74,23 +72,17 @@ function readBundle(bundleContent, taskElement) {
|
|
|
74
72
|
}
|
|
75
73
|
return { type: 'javascript', content: bundleContent, codeArguments: [bundleContent] };
|
|
76
74
|
}
|
|
77
|
-
/**
|
|
78
|
-
* An instrumenter based on the IstanbulJs instrumentation and coverage framework.
|
|
79
|
-
*/
|
|
80
75
|
class IstanbulInstrumenter {
|
|
76
|
+
vaccineSource;
|
|
77
|
+
logger;
|
|
81
78
|
constructor(vaccineFilePath, logger, collector, targetBucket) {
|
|
82
79
|
commons_1.Contract.require(fs.existsSync(vaccineFilePath), `The vaccine file to inject "${vaccineFilePath}" must exist!\nCWD:${process.cwd()}`);
|
|
83
80
|
this.vaccineSource = this.loadVaccine(commons_1.Contract.requireNonEmpty(vaccineFilePath), collector, targetBucket);
|
|
84
81
|
this.logger = logger;
|
|
85
82
|
}
|
|
86
|
-
/**
|
|
87
|
-
* {@inheritDoc #IInstrumenter.instrument}
|
|
88
|
-
*/
|
|
89
83
|
async instrument(task) {
|
|
90
84
|
this.clearFile(task.dumpOriginsFile);
|
|
91
85
|
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
86
|
const result = await async_1.default
|
|
95
87
|
.mapLimit(task.elements, 1, async (taskElement) => {
|
|
96
88
|
return await this.instrumentOne(taskElement, task.excludeFilesPattern, task.originSourcePattern, task.dumpOriginsFile);
|
|
@@ -100,53 +92,35 @@ class IstanbulInstrumenter {
|
|
|
100
92
|
return prev.withIncrement(curr);
|
|
101
93
|
}, Task_1.TaskResult.neutral(task));
|
|
102
94
|
});
|
|
103
|
-
// Write the matching statistics to a JSON
|
|
104
95
|
this.dumpToJson(task.dumpMatchedOriginsFile, task.originSourcePattern.retrieveMatchingFiles());
|
|
105
96
|
return result;
|
|
106
97
|
}
|
|
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
98
|
async instrumentOne(taskElement, excludeBundles, sourcePattern, dumpOriginsFile) {
|
|
117
|
-
// Not all file types are supported by the instrumenter
|
|
118
99
|
if (!this.isFileTypeSupported(taskElement.fromFile)) {
|
|
119
100
|
if (!taskElement.isInPlace()) {
|
|
120
101
|
copyToFile(taskElement.toFile, taskElement.fromFile);
|
|
121
102
|
}
|
|
122
103
|
return new Task_1.TaskResult(0, 0, 0, 0, 1, 0, 0);
|
|
123
104
|
}
|
|
124
|
-
// Read the (supported) file
|
|
125
105
|
const bundleContent = fs.readFileSync(taskElement.fromFile, 'utf8');
|
|
126
106
|
const inputBundle = readBundle(bundleContent, taskElement);
|
|
127
|
-
// We skip files that we have already instrumented
|
|
128
107
|
if (inputBundle.content.substring(0, Math.min(inputBundle.content.length, 100)).includes(exports.IS_INSTRUMENTED_TOKEN)) {
|
|
129
108
|
if (!taskElement.isInPlace()) {
|
|
130
109
|
writeToFile(taskElement.toFile, inputBundle.content);
|
|
131
110
|
}
|
|
132
111
|
return new Task_1.TaskResult(0, 0, 0, 1, 0, 0, 0);
|
|
133
112
|
}
|
|
134
|
-
// We might want to skip the instrumentation of the file
|
|
135
113
|
if (excludeBundles.isExcluded(taskElement.fromFile)) {
|
|
136
114
|
if (!taskElement.isInPlace()) {
|
|
137
115
|
copyToFile(taskElement.toFile, taskElement.fromFile);
|
|
138
116
|
}
|
|
139
117
|
return new Task_1.TaskResult(0, 1, 0, 0, 0, 0, 0);
|
|
140
118
|
}
|
|
141
|
-
// Report progress
|
|
142
119
|
this.logger.info(`Instrumenting "${path.basename(taskElement.fromFile)}"`);
|
|
143
|
-
// Load the bundles source maps
|
|
144
120
|
const inputSourceMaps = loadInputSourceMaps(taskElement.fromFile, inputBundle, taskElement.externalSourceMapFile);
|
|
145
121
|
if (inputSourceMaps.length === 0) {
|
|
146
122
|
return Task_1.TaskResult.warning(`Failed loading input source map for ${taskElement.fromFile}.`);
|
|
147
123
|
}
|
|
148
|
-
// We try to perform the instrumentation with different
|
|
149
|
-
// alternative configurations of the instrumenter.
|
|
150
124
|
const configurationAlternatives = this.configurationAlternativesFor(taskElement);
|
|
151
125
|
for (let i = 0; i < configurationAlternatives.length; i++) {
|
|
152
126
|
const configurationAlternative = configurationAlternatives[i];
|
|
@@ -154,8 +128,6 @@ class IstanbulInstrumenter {
|
|
|
154
128
|
return await this.instrumentBundle(taskElement, inputBundle, inputSourceMaps, configurationAlternative, dumpOriginsFile, sourcePattern);
|
|
155
129
|
}
|
|
156
130
|
catch (e) {
|
|
157
|
-
// If also the last configuration alternative failed,
|
|
158
|
-
// we emit a corresponding warning or signal an error.
|
|
159
131
|
if (i === configurationAlternatives.length - 1) {
|
|
160
132
|
writeToFile(taskElement.toFile, inputBundle.content);
|
|
161
133
|
return Task_1.TaskResult.error(e);
|
|
@@ -165,22 +137,16 @@ class IstanbulInstrumenter {
|
|
|
165
137
|
return new Task_1.TaskResult(0, 0, 0, 0, 0, 1, 0);
|
|
166
138
|
}
|
|
167
139
|
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
140
|
for (const inputSourceMap of inputSourceMaps.filter(map => map)) {
|
|
174
|
-
const originSourceFiles =
|
|
141
|
+
const originSourceFiles = inputSourceMap?.sources ?? [];
|
|
175
142
|
if (dumpOriginsFile) {
|
|
176
143
|
this.dumpToJson(dumpOriginsFile, originSourceFiles);
|
|
177
144
|
}
|
|
178
145
|
}
|
|
179
|
-
// The main instrumentation (adding coverage statements) is performed now:
|
|
180
146
|
const instrumenter = istanbul.createInstrumenter(configurationAlternative);
|
|
181
147
|
const instrumentedSources = [];
|
|
182
148
|
for (let i = 0; i < inputBundle.codeArguments.length; i++) {
|
|
183
|
-
const shouldInstrument = (
|
|
149
|
+
const shouldInstrument = (_, originLocation) => {
|
|
184
150
|
if (!originLocation.filename) {
|
|
185
151
|
return false;
|
|
186
152
|
}
|
|
@@ -208,49 +174,32 @@ class IstanbulInstrumenter {
|
|
|
208
174
|
writeToFile(toFile, instrumentedSources[0]);
|
|
209
175
|
}
|
|
210
176
|
}
|
|
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
177
|
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
178
|
return fs.readFileSync(filePath, 'utf8')
|
|
222
179
|
.replace(/\$COLLECTOR_SPECIFIER/g, JSON.stringify(collector))
|
|
223
180
|
.replace(/\$BUCKET_SPECIFIER/g, Buffer.from(JSON.stringify(targetBucket)).toString('base64'));
|
|
224
181
|
}
|
|
225
|
-
/**
|
|
226
|
-
* @returns whether the given file is supported for instrumentation.
|
|
227
|
-
*/
|
|
228
182
|
isFileTypeSupported(fileName) {
|
|
229
183
|
if (fileName.endsWith('.devmode.js') || fileName.endsWith('.nocache.js')) {
|
|
230
|
-
// GWT dev mode files.
|
|
231
184
|
return false;
|
|
232
185
|
}
|
|
233
186
|
const ext = path.extname(fileName).toLowerCase();
|
|
234
187
|
return ext === '.js' || ext === '.mjs';
|
|
235
188
|
}
|
|
236
|
-
/**
|
|
237
|
-
* Determine the list of configurations to try conducting the
|
|
238
|
-
* given task element.
|
|
239
|
-
*/
|
|
240
189
|
configurationAlternativesFor(taskElement) {
|
|
241
190
|
this.logger.trace(`Determining configuration alternatives for ${taskElement.fromFile}`);
|
|
242
191
|
const baseConfig = {
|
|
243
192
|
isInstrumentedToken: exports.IS_INSTRUMENTED_TOKEN,
|
|
244
|
-
produceSourceMap: '
|
|
193
|
+
produceSourceMap: 'none',
|
|
245
194
|
codeToPrepend: this.vaccineSource,
|
|
246
|
-
|
|
195
|
+
preserveComments: false,
|
|
196
|
+
compact: false
|
|
247
197
|
};
|
|
248
198
|
return [
|
|
249
199
|
{ ...baseConfig, ...{ esModules: true } },
|
|
250
200
|
{ ...baseConfig, ...{ esModules: false } }
|
|
251
201
|
];
|
|
252
202
|
}
|
|
253
|
-
/** Deletes the file if it exists, such that it is now ready to be appended. */
|
|
254
203
|
clearFile(filePath) {
|
|
255
204
|
if (filePath && fs.existsSync(filePath)) {
|
|
256
205
|
try {
|
|
@@ -261,7 +210,6 @@ class IstanbulInstrumenter {
|
|
|
261
210
|
}
|
|
262
211
|
}
|
|
263
212
|
}
|
|
264
|
-
/** Write the contents of the given object into the given file, if provided. */
|
|
265
213
|
dumpToJson(targetFilePath, toDump) {
|
|
266
214
|
if (!targetFilePath) {
|
|
267
215
|
return;
|
|
@@ -275,19 +223,6 @@ class IstanbulInstrumenter {
|
|
|
275
223
|
}
|
|
276
224
|
}
|
|
277
225
|
exports.IstanbulInstrumenter = IstanbulInstrumenter;
|
|
278
|
-
/**
|
|
279
|
-
* Extract the sourcemap from the given source code.
|
|
280
|
-
*
|
|
281
|
-
* @param instrumentedSource - The source code.
|
|
282
|
-
* @param instrumentedSourceFileName - The file name to assume for the file name.
|
|
283
|
-
*/
|
|
284
|
-
async function loadSourceMap(instrumentedSource, instrumentedSourceFileName) {
|
|
285
|
-
const instrumentedSourceMap = loadInputSourceMap(instrumentedSource, instrumentedSourceFileName, undefined);
|
|
286
|
-
if (instrumentedSourceMap) {
|
|
287
|
-
return await new source_map_1.SourceMapConsumer(instrumentedSourceMap);
|
|
288
|
-
}
|
|
289
|
-
return undefined;
|
|
290
|
-
}
|
|
291
226
|
function loadInputSourceMaps(taskFile, bundleFile, externalSourceMapFile) {
|
|
292
227
|
if ((0, WebToolkit_1.isGwtBundle)(bundleFile)) {
|
|
293
228
|
return (0, WebToolkit_1.loadInputSourceMapsGwt)(taskFile, bundleFile);
|
|
@@ -299,13 +234,6 @@ function loadInputSourceMaps(taskFile, bundleFile, externalSourceMapFile) {
|
|
|
299
234
|
function loadInputSourceMapsStandard(taskFile, bundleFile, externalSourceMapFile) {
|
|
300
235
|
return bundleFile.codeArguments.map(code => loadInputSourceMap(code, taskFile, externalSourceMapFile));
|
|
301
236
|
}
|
|
302
|
-
/**
|
|
303
|
-
* Given a source code file, load the corresponding sourcemap.
|
|
304
|
-
*
|
|
305
|
-
* @param inputSource - The source code that might contain sourcemap comments.
|
|
306
|
-
* @param taskFile - The name of the file the `inputSource` is from.
|
|
307
|
-
* @param externalSourceMapFile - An external source map file to consider.
|
|
308
|
-
*/
|
|
309
237
|
function loadInputSourceMap(inputSource, taskFile, externalSourceMapFile) {
|
|
310
238
|
if (externalSourceMapFile) {
|
|
311
239
|
const sourceMapOrigin = externalSourceMapFile;
|
|
@@ -318,17 +246,7 @@ function loadInputSourceMap(inputSource, taskFile, externalSourceMapFile) {
|
|
|
318
246
|
return sourceMapFromCodeComment(inputSource, taskFile);
|
|
319
247
|
}
|
|
320
248
|
}
|
|
321
|
-
/**
|
|
322
|
-
* Extract a sourcemap for a given code comment.
|
|
323
|
-
*
|
|
324
|
-
* @param sourcecode - The source code that is scanned for source map comments.
|
|
325
|
-
* @param sourceFilePath - The file name the code was loaded from.
|
|
326
|
-
*/
|
|
327
249
|
function sourceMapFromCodeComment(sourcecode, sourceFilePath) {
|
|
328
|
-
// Either `//# sourceMappingURL=vendor.5d7ba975.js.map`
|
|
329
|
-
// or `//# sourceMappingURL=data:application/json;base64,eyJ2ZXJ ...`
|
|
330
|
-
//
|
|
331
|
-
// "It is reasonable for tools to also accept “//@” but “//#” is preferred."
|
|
332
250
|
const re = /\/\/[#@]\s(source(?:Mapping)?URL)=\s*(\S+)/g;
|
|
333
251
|
let failedLoading = 0;
|
|
334
252
|
let result;
|
|
@@ -349,8 +267,7 @@ function sourceMapFromCodeComment(sourcecode, sourceFilePath) {
|
|
|
349
267
|
.toObject();
|
|
350
268
|
}
|
|
351
269
|
}
|
|
352
|
-
catch
|
|
353
|
-
// One JS file can refer to several source map files in its comments.
|
|
270
|
+
catch {
|
|
354
271
|
failedLoading++;
|
|
355
272
|
}
|
|
356
273
|
}
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { ConfigurationParameters } from '@cqse/commons';
|
|
2
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
3
|
export type InstrumenterOptions = {
|
|
9
4
|
version?: boolean;
|
|
10
5
|
help?: boolean;
|
|
@@ -27,10 +22,7 @@ export type InstrumenterOptions = {
|
|
|
27
22
|
collectorConfigFileContent?: string;
|
|
28
23
|
collectorOption?: string[];
|
|
29
24
|
collectorOptionsList?: boolean;
|
|
25
|
+
coverageTargetFromCollector?: boolean;
|
|
30
26
|
};
|
|
31
|
-
/**
|
|
32
|
-
* Builds and returns a configuration parameters object for the JavaScript instrumenter.
|
|
33
|
-
* This function defines all supported command-line arguments and their descriptions.
|
|
34
|
-
*/
|
|
35
27
|
export declare function buildInstrumenterConfigurationParameters(): ConfigurationParameters;
|
|
36
28
|
//# sourceMappingURL=InstrumenterConfig.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AAQxC,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;AA0BF,wBAAgB,wCAAwC,IAAI,uBAAuB,CA+IlF"}
|
|
@@ -19,10 +19,6 @@ const CONFIG_GROUP_DEBUGGING = {
|
|
|
19
19
|
order: 4,
|
|
20
20
|
title: 'Troubleshooting'
|
|
21
21
|
};
|
|
22
|
-
/**
|
|
23
|
-
* Builds and returns a configuration parameters object for the JavaScript instrumenter.
|
|
24
|
-
* This function defines all supported command-line arguments and their descriptions.
|
|
25
|
-
*/
|
|
26
22
|
function buildInstrumenterConfigurationParameters() {
|
|
27
23
|
const parameters = new commons_1.ConfigurationParameters();
|
|
28
24
|
function addParameter(shortParameter, longParameter, type, options) {
|
|
@@ -53,6 +49,10 @@ function buildInstrumenterConfigurationParameters() {
|
|
|
53
49
|
help: 'The name of the application to report coverage for. Will be used to make the automatically generated application ID more readable.',
|
|
54
50
|
group: CONFIG_GROUP_TARGET_PARAMS
|
|
55
51
|
});
|
|
52
|
+
addParameter(undefined, '--coverage-target-from-collector', 'bool', {
|
|
53
|
+
help: 'All coverage target (upload) parameters, for example, the target partition, shall be specified by the collector.',
|
|
54
|
+
group: CONFIG_GROUP_TARGET_PARAMS
|
|
55
|
+
});
|
|
56
56
|
addParameter('-f', '--config-id', 'string', {
|
|
57
57
|
help: 'The ID of the profiler configuration to use; this configuration is refetched from Teamscale once a minute.',
|
|
58
58
|
group: CONFIG_GROUP_TARGET_PARAMS
|
|
@@ -127,8 +127,24 @@ function buildInstrumenterConfigurationParameters() {
|
|
|
127
127
|
}
|
|
128
128
|
});
|
|
129
129
|
parameters.addArgumentCheck(options => {
|
|
130
|
-
if (
|
|
131
|
-
|
|
130
|
+
if (options.coverageTargetFromCollector) {
|
|
131
|
+
if (Array.isArray(options.collectorOption) && options.collectorOption.length > 0) {
|
|
132
|
+
const optionsSet = new Set(options.collectorOption.map((value) => value.split("=")[0]));
|
|
133
|
+
if (optionsSet.has("teamscale-partition")
|
|
134
|
+
|| optionsSet.has("teamscale-project")
|
|
135
|
+
|| optionsSet.has("teamscale-repository")
|
|
136
|
+
|| optionsSet.has("teamscale-message")) {
|
|
137
|
+
return 'The parameter `--coverage-target-from-collector` cannot be combined ' +
|
|
138
|
+
'with explicitly setting upload target options in the instrumenter.';
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
if (!options.configId && !options.collectorConfigFile && !(Array.isArray(options.collectorOption) && options.collectorOption.length > 0)) {
|
|
144
|
+
return 'Either a configuration ID (--config-id), a collector configuration file (--collector-config-file) ' +
|
|
145
|
+
'or explicit collector options (--collector-option) must be specified. You can also decide to set all ' +
|
|
146
|
+
'coverage upload parameters on the collector side only by setting --coverage-target-from-collector.';
|
|
147
|
+
}
|
|
132
148
|
}
|
|
133
149
|
});
|
|
134
150
|
parameters.addArgumentCheck(options => {
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { CollectorSpecifierRelative } from "
|
|
2
|
-
/** Parses a relative collector pattern. */
|
|
1
|
+
import { CollectorSpecifierRelative } from "../vaccine/types";
|
|
3
2
|
export declare class RelativeCollectorPatternParser {
|
|
4
|
-
/** Parses the given pattern. */
|
|
5
3
|
static parse(pattern: string): CollectorSpecifierRelative;
|
|
6
4
|
private static apply;
|
|
7
5
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RelativeCollectorPatternParser.d.ts","sourceRoot":"","sources":["../../../src/instrumenter/RelativeCollectorPatternParser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,0BAA0B,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"RelativeCollectorPatternParser.d.ts","sourceRoot":"","sources":["../../../src/instrumenter/RelativeCollectorPatternParser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAG9D,qBAAa,8BAA8B;IAGvC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,0BAA0B;IAkBzD,OAAO,CAAC,MAAM,CAAC,KAAK;CAkCvB"}
|
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RelativeCollectorPatternParser = void 0;
|
|
4
4
|
const commons_1 = require("@cqse/commons");
|
|
5
|
-
/** Parses a relative collector pattern. */
|
|
6
5
|
class RelativeCollectorPatternParser {
|
|
7
|
-
/** Parses the given pattern. */
|
|
8
6
|
static parse(pattern) {
|
|
9
7
|
const parts = pattern.split(",");
|
|
10
8
|
const specifier = {
|
|
@@ -31,13 +29,15 @@ class RelativeCollectorPatternParser {
|
|
|
31
29
|
}
|
|
32
30
|
break;
|
|
33
31
|
case "replace-in-host":
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
32
|
+
{
|
|
33
|
+
commons_1.Contract.requireStringPattern(value, /[^ ]+ [^ ]*/, `Invalid relative collector pattern: replace-in-host must contain exactly one space to separate search string and replacement: ${value}`);
|
|
34
|
+
const parts = value.split(" ");
|
|
35
|
+
specifier.hostReplace = {
|
|
36
|
+
search: parts[0],
|
|
37
|
+
replace: parts[1],
|
|
38
|
+
};
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
41
|
case "path":
|
|
42
42
|
specifier.path = value;
|
|
43
43
|
break;
|
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_test_1 = require("node:test");
|
|
7
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
3
8
|
const RelativeCollectorPatternParser_1 = require("./RelativeCollectorPatternParser");
|
|
4
|
-
describe("SubstitutionPatternParser", () => {
|
|
5
|
-
test('empty pattern', () => {
|
|
6
|
-
|
|
9
|
+
(0, node_test_1.describe)("SubstitutionPatternParser", () => {
|
|
10
|
+
(0, node_test_1.test)('empty pattern', () => {
|
|
11
|
+
strict_1.default.deepStrictEqual(RelativeCollectorPatternParser_1.RelativeCollectorPatternParser.parse(""), {
|
|
7
12
|
type: "relative",
|
|
8
13
|
});
|
|
9
14
|
});
|
|
10
|
-
test('keep port', () => {
|
|
11
|
-
|
|
15
|
+
(0, node_test_1.test)('keep port', () => {
|
|
16
|
+
strict_1.default.deepStrictEqual(RelativeCollectorPatternParser_1.RelativeCollectorPatternParser.parse(""), {
|
|
12
17
|
type: "relative",
|
|
13
18
|
port: "keep",
|
|
14
19
|
});
|
|
15
20
|
});
|
|
16
|
-
test('all features', () => {
|
|
17
|
-
|
|
21
|
+
(0, node_test_1.test)('all features', () => {
|
|
22
|
+
strict_1.default.deepStrictEqual(RelativeCollectorPatternParser_1.RelativeCollectorPatternParser.parse("scheme:wss,port:1234,replace-in-host:foo bar,path:path/path"), {
|
|
18
23
|
type: "relative",
|
|
19
24
|
hostReplace: {
|
|
20
25
|
search: "foo",
|
|
@@ -1,107 +1,37 @@
|
|
|
1
1
|
import { CollectorSpecifier, CoverageBucketSpecifier } from '../vaccine/types';
|
|
2
|
-
/**
|
|
3
|
-
* An abstract source map type.
|
|
4
|
-
*/
|
|
5
2
|
export declare abstract class SourceMapReference {
|
|
6
3
|
}
|
|
7
4
|
type BaseBundle = {
|
|
8
5
|
content: string;
|
|
9
6
|
codeArguments: string[];
|
|
10
7
|
};
|
|
11
|
-
/**
|
|
12
|
-
* A standard JavaScript bundle. Produced, for example, with bundlers
|
|
13
|
-
* like Webpack or Vite.
|
|
14
|
-
*/
|
|
15
8
|
export type StandardBundle = BaseBundle & {
|
|
16
9
|
type: 'javascript';
|
|
17
10
|
};
|
|
18
|
-
/**
|
|
19
|
-
* A Google Web-Toolkit Js bundle file.
|
|
20
|
-
*/
|
|
21
11
|
export type GwtBundle = BaseBundle & {
|
|
22
12
|
type: 'gwt';
|
|
23
13
|
functionName: string;
|
|
24
14
|
fragmentId: string;
|
|
25
15
|
codeAsArrayArgument: boolean;
|
|
26
16
|
};
|
|
27
|
-
/**
|
|
28
|
-
* A bundle to be handled by the instrumenter.
|
|
29
|
-
*/
|
|
30
17
|
export type Bundle = BaseBundle & (StandardBundle | GwtBundle);
|
|
31
|
-
/**
|
|
32
|
-
* One element of an instrumentation task.
|
|
33
|
-
* It corresponds to instrumenting a single file.
|
|
34
|
-
*/
|
|
35
18
|
export declare class TaskElement {
|
|
36
|
-
/** The source file */
|
|
37
19
|
readonly fromFile: string;
|
|
38
|
-
/** The destination file */
|
|
39
20
|
readonly toFile: string;
|
|
40
|
-
/** An external source map file relevant for the file at hand */
|
|
41
21
|
readonly externalSourceMapFile?: SourceMapReference;
|
|
42
22
|
constructor(fromFile: string, toFile: string, externalSourceMap?: SourceMapReference);
|
|
43
|
-
/**
|
|
44
|
-
* Is it an in-place instrumentation task?
|
|
45
|
-
*/
|
|
46
23
|
isInPlace(): boolean;
|
|
47
24
|
}
|
|
48
|
-
/**
|
|
49
|
-
* Given a command-line URL and an optional relative pattern, create a specifier for how the vaccine can
|
|
50
|
-
* locate the connector.
|
|
51
|
-
*
|
|
52
|
-
* If a relative pattern is given, it is preferred, since the command-line interface always provides a URL
|
|
53
|
-
* (the default URL in case the user didn't explicitly specify one).
|
|
54
|
-
*/
|
|
55
25
|
export declare function createCollectorSpecifier(commandLineUrl: string, relativePattern?: string): CollectorSpecifier;
|
|
56
|
-
/**
|
|
57
|
-
* Patterns that define which parts of a given bundle to instrument or not.
|
|
58
|
-
*
|
|
59
|
-
* The patterns describe a set of filenames that can be found in the origin,
|
|
60
|
-
* that is, before conducting all the transpilation steps. The source maps
|
|
61
|
-
* are used to determine the original file names.
|
|
62
|
-
*/
|
|
63
26
|
export declare class OriginSourcePattern {
|
|
64
|
-
/** Glob pattern describing the set of files in the origin for that coverage should be produced. */
|
|
65
27
|
private readonly include;
|
|
66
|
-
/**
|
|
67
|
-
* Glob pattern describing the set of files in the origin for that coverage should EXPLICITLY NOT be produced.
|
|
68
|
-
* An exclude is stronger than an include.
|
|
69
|
-
*/
|
|
70
28
|
private readonly exclude;
|
|
71
|
-
/**
|
|
72
|
-
* Files that did match the `include` pattern.
|
|
73
|
-
*/
|
|
74
29
|
private readonly includeMatches;
|
|
75
|
-
/**
|
|
76
|
-
* Files that did match the `exclude` pattern.
|
|
77
|
-
*/
|
|
78
30
|
private readonly excludeMatches;
|
|
79
|
-
/**
|
|
80
|
-
* Files that did neither match the `exclude` nor the `include` pattern.
|
|
81
|
-
*/
|
|
82
31
|
private readonly neitherExcludedNorIncluded;
|
|
83
32
|
constructor(include: string[] | undefined, exclude: string[] | undefined);
|
|
84
|
-
/**
|
|
85
|
-
* Does the given pattern require to include the given file?
|
|
86
|
-
*
|
|
87
|
-
* For example, a JavaScript bundle is compiled from several (origin) source files.
|
|
88
|
-
* If one of the files in the bundle is needed, then the full bundle is needed, that is,
|
|
89
|
-
* this function is required to return `true`.
|
|
90
|
-
*
|
|
91
|
-
* @param originFile - The file to decide for include or exclude.
|
|
92
|
-
*
|
|
93
|
-
* @returns `false` if (1) the given file is supposed to be excluded,
|
|
94
|
-
* or (2) `true` if the given file is supposed to be included.
|
|
95
|
-
*/
|
|
96
33
|
isIncluded(originFile: string): boolean;
|
|
97
|
-
/**
|
|
98
|
-
* Variant of `isIncluded` working on a list of files to check.
|
|
99
|
-
* (Primarily, used for testing.)
|
|
100
|
-
*/
|
|
101
34
|
isAnyIncluded(originFiles: string[]): boolean;
|
|
102
|
-
/**
|
|
103
|
-
* Retrieve the file names that have been matching the different patterns.
|
|
104
|
-
*/
|
|
105
35
|
retrieveMatchingFiles(): {
|
|
106
36
|
includePatterns: string[];
|
|
107
37
|
excludePatterns: string[];
|
|
@@ -109,114 +39,40 @@ export declare class OriginSourcePattern {
|
|
|
109
39
|
includeMatches: string[];
|
|
110
40
|
neitherExcludedNorIncluded: string[];
|
|
111
41
|
};
|
|
112
|
-
/**
|
|
113
|
-
* Returns if include/exclude patterns are specified.
|
|
114
|
-
*/
|
|
115
42
|
patternsSpecified(): boolean;
|
|
116
43
|
}
|
|
117
|
-
/**
|
|
118
|
-
* Pattern describing files (bundles) to not instrument.
|
|
119
|
-
*/
|
|
120
44
|
export declare class FileExcludePattern {
|
|
121
|
-
/**
|
|
122
|
-
* Glob pattern describing a set of files to be excluded in the instrumentation process.
|
|
123
|
-
*/
|
|
124
45
|
private readonly exclude;
|
|
125
46
|
constructor(exclude: string[] | undefined);
|
|
126
|
-
/**
|
|
127
|
-
* Return `true` if the given `filePath` is matched by any of the patterns in `exclude`.
|
|
128
|
-
*/
|
|
129
47
|
isExcluded(filePath: string): boolean;
|
|
130
48
|
}
|
|
131
|
-
/**
|
|
132
|
-
* The actual instrumentation task.
|
|
133
|
-
*/
|
|
134
49
|
export declare class InstrumentationTask {
|
|
135
|
-
/**
|
|
136
|
-
* The collector to send coverage information to.
|
|
137
|
-
*/
|
|
138
50
|
readonly collector: CollectorSpecifier;
|
|
139
|
-
/**
|
|
140
|
-
* The target bucket within the collector the coverage is supposed to be sent to.
|
|
141
|
-
*/
|
|
142
51
|
readonly targetBucket: CoverageBucketSpecifier;
|
|
143
|
-
/**
|
|
144
|
-
* The files to instrument along with a specification of the target.
|
|
145
|
-
*/
|
|
146
52
|
private readonly _elements;
|
|
147
|
-
/**
|
|
148
|
-
* A pattern describing which files or fragments of a bundle to instrument
|
|
149
|
-
* based on the original file names the code was transpiled from.
|
|
150
|
-
*/
|
|
151
53
|
readonly originSourcePattern: OriginSourcePattern;
|
|
152
|
-
/**
|
|
153
|
-
* A pattern describing the set of files to not instrument but to output
|
|
154
|
-
* without adding instrumentations.
|
|
155
|
-
*/
|
|
156
54
|
readonly excludeFilesPattern: FileExcludePattern;
|
|
157
|
-
/**
|
|
158
|
-
* File to write the file-origin-mapping to.
|
|
159
|
-
*/
|
|
160
55
|
readonly dumpOriginsFile: string | undefined;
|
|
161
|
-
/**
|
|
162
|
-
* File to write the matched files to.
|
|
163
|
-
*/
|
|
164
56
|
readonly dumpMatchedOriginsFile: string | undefined;
|
|
165
57
|
constructor(collector: CollectorSpecifier, targetBucket: CoverageBucketSpecifier, elements: TaskElement[], excludeFilesPattern: FileExcludePattern, originSourcePattern: OriginSourcePattern, dumpOriginsFile: string | undefined, dumpMatchedOriginsFile: string | undefined);
|
|
166
|
-
/**
|
|
167
|
-
* @returns the elements of the task.
|
|
168
|
-
*/
|
|
169
58
|
get elements(): TaskElement[];
|
|
170
59
|
}
|
|
171
|
-
/**
|
|
172
|
-
* A summary of executing the instrumentation task.
|
|
173
|
-
*/
|
|
174
60
|
export declare class TaskResult {
|
|
175
|
-
/** Number of task elements that were performed (instrumented) */
|
|
176
61
|
readonly translated: number;
|
|
177
|
-
/** Number of task elements that were excluded because of corresponding include/exclude patterns. */
|
|
178
62
|
readonly excluded: number;
|
|
179
|
-
/** Number of instrumentations that were taken from a cache */
|
|
180
63
|
readonly translatedFromCache: number;
|
|
181
|
-
/** Number of skips due to a present instrumentation */
|
|
182
64
|
readonly alreadyInstrumented: number;
|
|
183
|
-
/** Number of files not support by the instrumenter */
|
|
184
65
|
readonly unsupported: number;
|
|
185
|
-
/** Number of elements for that the instrumentation failed */
|
|
186
66
|
readonly failed: number;
|
|
187
|
-
/** Number of warnings that were produced during the instrumentation process */
|
|
188
67
|
readonly warnings: number;
|
|
189
|
-
/** The instrumentation task for that the results were produced. */
|
|
190
68
|
readonly task?: InstrumentationTask;
|
|
191
69
|
constructor(translated: number, excluded: number, translatedFromCache: number, alreadyInstrumented: number, unsupported: number, failed: number, warnings: number, task?: InstrumentationTask);
|
|
192
|
-
/**
|
|
193
|
-
* Returns the sum of the present task results and the given one.
|
|
194
|
-
*
|
|
195
|
-
* @param incBy - The task result to add (as delta).
|
|
196
|
-
*/
|
|
197
70
|
withIncrement(incBy: TaskResult): TaskResult;
|
|
198
|
-
/**
|
|
199
|
-
* @returns the neutral task element (adding it with {@code withIncrement} does not change the result).
|
|
200
|
-
*/
|
|
201
71
|
static neutral(task?: InstrumentationTask): TaskResult;
|
|
202
|
-
/**
|
|
203
|
-
* @returns a task result signaling one error.
|
|
204
|
-
*
|
|
205
|
-
* @param e - The error to add.
|
|
206
|
-
*/
|
|
207
72
|
static error(e: Error): TaskResult;
|
|
208
|
-
/**
|
|
209
|
-
* @returns a task result signaling one warning.
|
|
210
|
-
*
|
|
211
|
-
* @param msg - The warning message to add.
|
|
212
|
-
*/
|
|
213
73
|
static warning(msg: string): TaskResult;
|
|
214
74
|
}
|
|
215
|
-
/**
|
|
216
|
-
* A source map in an external file.
|
|
217
|
-
*/
|
|
218
75
|
export declare class SourceMapFileReference extends SourceMapReference {
|
|
219
|
-
/** The path the source map is stored in */
|
|
220
76
|
readonly sourceMapFilePath: string;
|
|
221
77
|
constructor(sourceMapFilePath: string);
|
|
222
78
|
}
|