@teamscale/javascript-instrumenter 0.0.1-beta.3 → 0.0.1-beta.30
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 +6 -39
- package/dist/package.json +15 -8
- package/dist/src/App.d.ts +1 -1
- package/dist/src/App.d.ts.map +1 -1
- package/dist/src/App.js +29 -20
- package/dist/src/instrumenter/Cleaner.d.ts +9 -0
- package/dist/src/instrumenter/Cleaner.d.ts.map +1 -0
- package/dist/src/instrumenter/Cleaner.js +102 -0
- package/dist/src/instrumenter/FileSystem.js +5 -1
- package/dist/src/instrumenter/Instrumenter.d.ts +7 -4
- package/dist/src/instrumenter/Instrumenter.d.ts.map +1 -1
- package/dist/src/instrumenter/Instrumenter.js +86 -34
- package/dist/src/instrumenter/Task.d.ts +13 -3
- package/dist/src/instrumenter/Task.d.ts.map +1 -1
- package/dist/src/instrumenter/Task.js +48 -12
- package/dist/src/instrumenter/TaskBuilder.d.ts.map +1 -1
- package/dist/src/instrumenter/TaskBuilder.js +10 -2
- package/dist/src/main.js +1 -0
- package/dist/vaccine.js +1 -221
- package/package.json +15 -8
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ in the Teamscale Simple Coverage Format and sent to a Teamscale instance.
|
|
|
9
9
|
The Teamscale JavaScript Profiler consists of the [Coverage Collector](https://www.npmjs.com/package/@teamscale/coverage-collector)
|
|
10
10
|
and this JavaScript Instrumenter.
|
|
11
11
|
More details on using them (in combination) can be found
|
|
12
|
-
|
|
12
|
+
in the [Teamscale Documentation](https://docs.teamscale.com/howto/recording-test-coverage-for-javascript/).
|
|
13
13
|
|
|
14
14
|
The Instrumenter instruments a given (set of) JavaScript file(s) such that (1) coverage
|
|
15
15
|
information is produced and (2) forwarded to the Collector.
|
|
@@ -25,34 +25,12 @@ yarn install
|
|
|
25
25
|
yarn build
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
### Preparation: Source Maps
|
|
29
|
-
|
|
30
|
-
Please make sure to enable the generation of source map files to ensure
|
|
31
|
-
that the profiled code can be mapped back to the original.
|
|
32
|
-
|
|
33
|
-
For example, when the tool Vite is used to bundle the code,
|
|
34
|
-
the generation of source map information can be enabled by setting:
|
|
35
|
-
|
|
36
|
-
```
|
|
37
|
-
build: {
|
|
38
|
-
sourcemap: true
|
|
39
|
-
}
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
or
|
|
43
|
-
|
|
44
|
-
```
|
|
45
|
-
build: {
|
|
46
|
-
sourcemap: `inline`
|
|
47
|
-
}
|
|
48
|
-
```
|
|
49
|
-
|
|
50
28
|
## Workflow Integration
|
|
51
29
|
|
|
52
30
|
There are several options to run the Instrumenter. For example, via `yarn` by running
|
|
53
31
|
|
|
54
32
|
```
|
|
55
|
-
yarn
|
|
33
|
+
yarn instrumenter
|
|
56
34
|
```
|
|
57
35
|
|
|
58
36
|
or via `npx` by running
|
|
@@ -74,30 +52,19 @@ the file must contain source-map information, or the source-map file
|
|
|
74
52
|
must be placed along with the source file in the same directory.
|
|
75
53
|
|
|
76
54
|
```
|
|
77
|
-
yarn
|
|
55
|
+
yarn instrumenter --inplace ./the/path/to/the/file.js
|
|
78
56
|
```
|
|
79
57
|
|
|
80
58
|
```
|
|
81
|
-
yarn
|
|
59
|
+
yarn instrumenter --inplace ./the/path/to/the/file.js --source-map ./the/path/to/the/source.map
|
|
82
60
|
```
|
|
83
61
|
|
|
84
62
|
```
|
|
85
|
-
yarn
|
|
63
|
+
yarn instrumenter ./the/path/to/the/file.js --to ./the/file/path/to/write/to.js
|
|
86
64
|
```
|
|
87
65
|
|
|
88
|
-
### Instrumenting all JavaScript Files in a Folder
|
|
89
|
-
|
|
90
|
-
We think that dealing with sets of files, in particular including or excluding
|
|
91
|
-
files that match particular file masks should be done by other tools.
|
|
92
|
-
In a UNIX environment, you should consider using `find` with corresponding
|
|
93
|
-
filters and an `-exec` argument to run the instrumenter.
|
|
94
|
-
|
|
95
|
-
### Integration with Testing Frameworks
|
|
96
|
-
|
|
97
|
-
This is planned work: Provide a Babel plugin that provides a code transformation
|
|
98
|
-
such that coverage information is collected and this information is forwarded.
|
|
99
|
-
|
|
100
66
|
## Limitations
|
|
101
67
|
|
|
102
68
|
This tool inherits most of the limitations of IstanbulJs, including
|
|
103
69
|
a considerable performance impact.
|
|
70
|
+
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teamscale/javascript-instrumenter",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.30",
|
|
4
4
|
"description": "Istanbul-based coverage instrumenter with coverage forwarding via WebSockets",
|
|
5
5
|
"main": "dist/src/main.js",
|
|
6
6
|
"bin": "dist/src/main.js",
|
|
@@ -12,19 +12,22 @@
|
|
|
12
12
|
"url": "https://github.com/cqse/teamscale-javascript-profiler.git"
|
|
13
13
|
},
|
|
14
14
|
"scripts": {
|
|
15
|
+
"prepublishOnly": "yarn clean && yarn build",
|
|
15
16
|
"clean": "rimraf dist tsconfig.tsbuildinfo",
|
|
16
|
-
"build": "tsc --project tsconfig.json &&
|
|
17
|
-
"
|
|
17
|
+
"build": "tsc --project tsconfig.json && yarn buildVaccine",
|
|
18
|
+
"buildVaccine": "node esbuild.mjs",
|
|
19
|
+
"instrumenter": "node dist/src/main.js",
|
|
18
20
|
"test": "yarn build && NODE_OPTIONS='--experimental-vm-modules' jest --forceExit --coverage --silent=true --detectOpenHandles"
|
|
19
21
|
},
|
|
20
22
|
"files": [
|
|
21
23
|
"dist/**/*"
|
|
22
24
|
],
|
|
23
25
|
"devDependencies": {
|
|
24
|
-
"@babel/core": "^7.
|
|
26
|
+
"@babel/core": "^7.17.5",
|
|
25
27
|
"@babel/plugin-transform-modules-commonjs": "^7.15.4",
|
|
26
28
|
"@babel/preset-env": "^7.14.1",
|
|
27
29
|
"@types/async": "^3.2.6",
|
|
30
|
+
"@types/bunyan": "^1.8.8",
|
|
28
31
|
"@types/convert-source-map": "^1.5.1",
|
|
29
32
|
"@types/glob": "^7.1.3",
|
|
30
33
|
"@types/istanbul-lib-instrument": "^1.7.4",
|
|
@@ -44,10 +47,15 @@
|
|
|
44
47
|
"typescript": "^4.4.3"
|
|
45
48
|
},
|
|
46
49
|
"dependencies": {
|
|
50
|
+
"@babel/generator": "^7.17.3",
|
|
51
|
+
"@babel/parser": "^7.17.3",
|
|
52
|
+
"@babel/traverse": "^7.17.3",
|
|
53
|
+
"@babel/types": "^7.17.0",
|
|
47
54
|
"@cqse/commons": "^0.0.1-beta.1",
|
|
48
55
|
"@types/micromatch": "^4.0.2",
|
|
49
56
|
"argparse": "^2.0.1",
|
|
50
|
-
"async": "^3.2.
|
|
57
|
+
"async": "^3.2.3",
|
|
58
|
+
"bunyan": "^1.8.15",
|
|
51
59
|
"convert-source-map": "^1.7.0",
|
|
52
60
|
"foreground-child": "^2.0.0",
|
|
53
61
|
"glob": "^7.1.7",
|
|
@@ -55,11 +63,10 @@
|
|
|
55
63
|
"micromatch": "4.0.4",
|
|
56
64
|
"mkdirp": "^1.0.4",
|
|
57
65
|
"nyc": "^15.1.0",
|
|
58
|
-
"source-map": "0.
|
|
66
|
+
"source-map": "0.7.3",
|
|
59
67
|
"typescript-optional": "^2.0.1",
|
|
60
68
|
"unload": "^2.2.0",
|
|
61
|
-
"web-worker": "^1.0.0"
|
|
62
|
-
"winston": "^3.3.3"
|
|
69
|
+
"web-worker": "^1.0.0"
|
|
63
70
|
},
|
|
64
71
|
"publishConfig": {
|
|
65
72
|
"access": "public"
|
package/dist/src/App.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TaskResult } from './instrumenter/Task';
|
|
2
2
|
import { ConfigurationParameters } from './instrumenter/TaskBuilder';
|
|
3
|
-
import
|
|
3
|
+
import Logger from "bunyan";
|
|
4
4
|
/**
|
|
5
5
|
* Entry points of the instrumenter, including command line argument parsing.
|
|
6
6
|
*/
|
package/dist/src/App.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/App.ts"],"names":[],"mappings":"AACA,OAAO,EAAuB,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGtE,OAAO,EAAE,uBAAuB,EAAe,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/App.ts"],"names":[],"mappings":"AACA,OAAO,EAAuB,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGtE,OAAO,EAAE,uBAAuB,EAAe,MAAM,4BAA4B,CAAC;AAKlF,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B;;GAEG;AACH,qBAAa,GAAG;IACf;;;OAGG;WACiB,GAAG,IAAI,OAAO,CAAC,UAAU,CAAC;IAa9C;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;IAgC1B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;IA0B1B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAI/B;;;;;OAKG;WACW,qBAAqB,CAAC,MAAM,EAAE,uBAAuB,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAO1G,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAIxC,OAAO,CAAC,MAAM,CAAC,kBAAkB;CAajC"}
|
package/dist/src/App.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
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);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -29,8 +33,9 @@ const commons_1 = require("@cqse/commons");
|
|
|
29
33
|
const TaskBuilder_1 = require("./instrumenter/TaskBuilder");
|
|
30
34
|
const path = __importStar(require("path"));
|
|
31
35
|
const package_json_1 = require("../package.json");
|
|
32
|
-
const winston_1 = __importDefault(require("winston"));
|
|
33
36
|
const fs_1 = require("fs");
|
|
37
|
+
const mkdirp_1 = __importDefault(require("mkdirp"));
|
|
38
|
+
const bunyan_1 = __importDefault(require("bunyan"));
|
|
34
39
|
/**
|
|
35
40
|
* Entry points of the instrumenter, including command line argument parsing.
|
|
36
41
|
*/
|
|
@@ -59,11 +64,11 @@ class App {
|
|
|
59
64
|
parser.add_argument('-v', '--version', { action: 'version', version: package_json_1.version });
|
|
60
65
|
parser.add_argument('-i', '--in-place', {
|
|
61
66
|
action: 'store_true',
|
|
62
|
-
help: 'If set, the original files to instrument are replaced
|
|
67
|
+
help: 'If set, the original files to instrument are replaced by their instrumented counterparts.'
|
|
63
68
|
});
|
|
64
69
|
parser.add_argument('-d', '--debug', { action: 'store_true' });
|
|
65
70
|
parser.add_argument('-o', '--to', {
|
|
66
|
-
help: '
|
|
71
|
+
help: 'Path (directory or file name) to write the instrumented version to.'
|
|
67
72
|
});
|
|
68
73
|
parser.add_argument('-s', '--source-map', {
|
|
69
74
|
help: 'External location of source-map files to consider.'
|
|
@@ -85,27 +90,31 @@ class App {
|
|
|
85
90
|
* Construct the logger.
|
|
86
91
|
*/
|
|
87
92
|
static buildLogger(config) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
93
|
+
const logfilePath = 'logs/instrumenter.log';
|
|
94
|
+
mkdirp_1.default.sync(path.dirname(logfilePath));
|
|
95
|
+
const logLevel = config.debug ? 'debug' : 'error';
|
|
96
|
+
return bunyan_1.default.createLogger({ name: "Instrumenter",
|
|
97
|
+
streams: [
|
|
98
|
+
{
|
|
99
|
+
level: logLevel,
|
|
100
|
+
stream: {
|
|
101
|
+
write: (rec) => {
|
|
102
|
+
console.log('[%s] %s: %s', rec.time.toISOString(), bunyan_1.default.nameFromLevel[rec.level], rec.msg);
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
type: 'raw'
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
level: logLevel,
|
|
109
|
+
path: logfilePath
|
|
110
|
+
}
|
|
111
|
+
] });
|
|
98
112
|
}
|
|
99
113
|
/**
|
|
100
114
|
* A logger for testing.
|
|
101
115
|
*/
|
|
102
116
|
static buildDummyLogger() {
|
|
103
|
-
return
|
|
104
|
-
level: 'info',
|
|
105
|
-
format: winston_1.default.format.json(),
|
|
106
|
-
defaultMeta: {},
|
|
107
|
-
transports: [new winston_1.default.transports.Console({ format: winston_1.default.format.simple(), level: 'info' })]
|
|
108
|
-
});
|
|
117
|
+
return bunyan_1.default.createLogger({ name: "Instrumenter" });
|
|
109
118
|
}
|
|
110
119
|
/**
|
|
111
120
|
* The instrumenter can also be started by providing the configuration dictionary explicitly.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SourceLocation } from '@babel/types';
|
|
2
|
+
/**
|
|
3
|
+
* Remove IstanbulJs instrumentations based on the given
|
|
4
|
+
* hook `makeCoverable`.
|
|
5
|
+
*
|
|
6
|
+
* An instrumentation is removed if the hook `makeCoverable` returns `false`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function cleanSourceCode(code: string, esModules: boolean, makeCoverable: (location: SourceLocation) => boolean): string;
|
|
9
|
+
//# sourceMappingURL=Cleaner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Cleaner.d.ts","sourceRoot":"","sources":["../../../src/instrumenter/Cleaner.ts"],"names":[],"mappings":"AAGA,OAAO,EAON,cAAc,EACd,MAAM,cAAc,CAAC;AAEtB;;;;;GAKG;AACH,wBAAgB,eAAe,CAC9B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,OAAO,EAClB,aAAa,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,OAAO,GAClD,MAAM,CAcR"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.cleanSourceCode = void 0;
|
|
7
|
+
const parser_1 = require("@babel/parser");
|
|
8
|
+
const generator_1 = __importDefault(require("@babel/generator"));
|
|
9
|
+
const traverse_1 = __importDefault(require("@babel/traverse"));
|
|
10
|
+
const types_1 = require("@babel/types");
|
|
11
|
+
/**
|
|
12
|
+
* Remove IstanbulJs instrumentations based on the given
|
|
13
|
+
* hook `makeCoverable`.
|
|
14
|
+
*
|
|
15
|
+
* An instrumentation is removed if the hook `makeCoverable` returns `false`.
|
|
16
|
+
*/
|
|
17
|
+
function cleanSourceCode(code, esModules, makeCoverable) {
|
|
18
|
+
const ast = (0, parser_1.parse)(code, { sourceType: esModules ? 'module' : 'script' });
|
|
19
|
+
(0, traverse_1.default)(ast, {
|
|
20
|
+
ExpressionStatement(path) {
|
|
21
|
+
if (isUnsupportedCounterTypeIncrement(path)) {
|
|
22
|
+
path.remove();
|
|
23
|
+
}
|
|
24
|
+
else if (isCoverageIncrementNode(path)) {
|
|
25
|
+
if (path.node.loc && !makeCoverable(path.node.loc)) {
|
|
26
|
+
path.remove();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
return (0, generator_1.default)(ast, {}, code).code;
|
|
32
|
+
}
|
|
33
|
+
exports.cleanSourceCode = cleanSourceCode;
|
|
34
|
+
/**
|
|
35
|
+
* Checks if the given `path.node` to a statement like `cov_104fq7oo4i().f[0]++;`
|
|
36
|
+
*/
|
|
37
|
+
function isCoverageIncrementNode(path) {
|
|
38
|
+
const expr = path.node.expression;
|
|
39
|
+
if (!(0, types_1.isUpdateExpression)(expr)) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return extractCoverageCallExpression(expr) !== undefined;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Is the given expression statement a coverage increment that
|
|
46
|
+
* is not supported by our approach?
|
|
47
|
+
*
|
|
48
|
+
* For example, branch coverage is not supported.
|
|
49
|
+
*/
|
|
50
|
+
function isUnsupportedCounterTypeIncrement(path) {
|
|
51
|
+
if (!(0, types_1.isUpdateExpression)(path.node.expression)) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return extractBranchCounterExpression(path.node.expression) !== undefined;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Returns the call expression from `cov_2pvvu1hl8v().b[2][0]++;` if
|
|
58
|
+
* the given UpdateExpression is a branch coverage update expression.
|
|
59
|
+
*/
|
|
60
|
+
function extractBranchCounterExpression(expr) {
|
|
61
|
+
if (expr.operator === '++' &&
|
|
62
|
+
(0, types_1.isMemberExpression)(expr.argument) &&
|
|
63
|
+
(0, types_1.isMemberExpression)(expr.argument.object) &&
|
|
64
|
+
(0, types_1.isMemberExpression)(expr.argument.object.object) &&
|
|
65
|
+
(0, types_1.isCallExpression)(expr.argument.object.object.object)) {
|
|
66
|
+
// Branch counter
|
|
67
|
+
return extractCoverageObjectCall(expr.argument.object.object.object);
|
|
68
|
+
}
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Returns the call expression from `cov_104fq7oo4i().f[0]++;` if
|
|
73
|
+
* the given UpdateExpression is a function or statement coverage update expression.
|
|
74
|
+
*/
|
|
75
|
+
function extractFunctionOrStatementCounterExpression(expr) {
|
|
76
|
+
if (expr.operator === '++' &&
|
|
77
|
+
(0, types_1.isMemberExpression)(expr.argument) &&
|
|
78
|
+
(0, types_1.isMemberExpression)(expr.argument.object) &&
|
|
79
|
+
(0, types_1.isCallExpression)(expr.argument.object.object)) {
|
|
80
|
+
// Function and statement counter
|
|
81
|
+
return extractCoverageObjectCall(expr.argument.object.object);
|
|
82
|
+
}
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Given an `UpdateExpression` extract the call expression returning the coverage object.
|
|
87
|
+
*/
|
|
88
|
+
function extractCoverageCallExpression(expr) {
|
|
89
|
+
var _a;
|
|
90
|
+
return (_a = extractBranchCounterExpression(expr)) !== null && _a !== void 0 ? _a : extractFunctionOrStatementCounterExpression(expr);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Check if the given call expression is a coverage call expression.
|
|
94
|
+
* If this is not the case return `undefined`, and the call expression itself otherwise.
|
|
95
|
+
*/
|
|
96
|
+
function extractCoverageObjectCall(callExpression) {
|
|
97
|
+
if (callExpression && (0, types_1.isIdentifier)(callExpression.callee)
|
|
98
|
+
&& callExpression.callee.name.startsWith('cov_')) {
|
|
99
|
+
return callExpression;
|
|
100
|
+
}
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
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);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CollectorSpecifier, InstrumentationTask, OriginSourcePattern, TaskElement, TaskResult } from './Task';
|
|
2
|
-
import
|
|
2
|
+
import Logger from "bunyan";
|
|
3
3
|
export declare const IS_INSTRUMENTED_TOKEN = "/** $IS_JS_PROFILER_INSTRUMENTED=true **/";
|
|
4
4
|
/**
|
|
5
5
|
* An instrumenter that can conduct a {@code InstrumentationTask}.
|
|
@@ -38,7 +38,9 @@ export declare class IstanbulInstrumenter implements IInstrumenter {
|
|
|
38
38
|
* @param taskElement - The task element to perform the instrumentation for.
|
|
39
39
|
* @param sourcePattern - A pattern to restrict the instrumentation to only a fraction of the task element.
|
|
40
40
|
*/
|
|
41
|
-
instrumentOne(collector: CollectorSpecifier, taskElement: TaskElement, sourcePattern: OriginSourcePattern): TaskResult
|
|
41
|
+
instrumentOne(collector: CollectorSpecifier, taskElement: TaskElement, sourcePattern: OriginSourcePattern): Promise<TaskResult>;
|
|
42
|
+
private removeUnwantedInstrumentation;
|
|
43
|
+
private loadSourceMap;
|
|
42
44
|
/**
|
|
43
45
|
* Loads the vaccine from the vaccine file and adjusts some template parameters.
|
|
44
46
|
*
|
|
@@ -64,10 +66,11 @@ export declare class IstanbulInstrumenter implements IInstrumenter {
|
|
|
64
66
|
*/
|
|
65
67
|
private configurationAlternativesFor;
|
|
66
68
|
/**
|
|
67
|
-
* Given a source code file
|
|
69
|
+
* Given a source code file, load the corresponding sourcemap.
|
|
68
70
|
*
|
|
69
71
|
* @param inputSource - The source code that might contain sourcemap comments.
|
|
70
|
-
* @param
|
|
72
|
+
* @param taskFile - The name of the file the `inputSource` is from.
|
|
73
|
+
* @param externalSourceMapFile - An external source map file to consider.
|
|
71
74
|
*/
|
|
72
75
|
private loadInputSourceMap;
|
|
73
76
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Instrumenter.d.ts","sourceRoot":"","sources":["../../../src/instrumenter/Instrumenter.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,
|
|
1
|
+
{"version":3,"file":"Instrumenter.d.ts","sourceRoot":"","sources":["../../../src/instrumenter/Instrumenter.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EAGnB,WAAW,EACX,UAAU,EACV,MAAM,QAAQ,CAAC;AAUhB,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,eAAO,MAAM,qBAAqB,8CAA8C,CAAC;AAEjF;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B;;;;OAIG;IACH,UAAU,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAC3D;AAED;;GAEG;AACH,qBAAa,oBAAqB,YAAW,aAAa;IACzD;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IAEzC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAS;gBAEX,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IASnD;;OAEG;IACG,UAAU,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC;IAYhE;;;;;;OAMG;IACG,aAAa,CAClB,SAAS,EAAE,kBAAkB,EAC7B,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,mBAAmB,GAChC,OAAO,CAAC,UAAU,CAAC;YAoGR,6BAA6B;YAkC7B,aAAa;IAe3B;;;;OAIG;IACH,OAAO,CAAC,WAAW;IASnB;;;;;;;OAOG;IACH,OAAO,CAAC,gCAAgC;IAQxC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAK3B;;;OAGG;IACH,OAAO,CAAC,4BAA4B;IAcpC;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;CAe1B"}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
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);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -18,14 +22,22 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
18
22
|
__setModuleDefault(result, mod);
|
|
19
23
|
return result;
|
|
20
24
|
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
21
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
29
|
exports.IstanbulInstrumenter = exports.IS_INSTRUMENTED_TOKEN = void 0;
|
|
23
30
|
const Task_1 = require("./Task");
|
|
24
31
|
const commons_1 = require("@cqse/commons");
|
|
32
|
+
const source_map_1 = require("source-map");
|
|
25
33
|
const istanbul = __importStar(require("istanbul-lib-instrument"));
|
|
26
34
|
const fs = __importStar(require("fs"));
|
|
35
|
+
const mkdirp = __importStar(require("mkdirp"));
|
|
27
36
|
const path = __importStar(require("path"));
|
|
28
37
|
const convertSourceMap = __importStar(require("convert-source-map"));
|
|
38
|
+
const Cleaner_1 = require("./Cleaner");
|
|
39
|
+
const typescript_optional_1 = require("typescript-optional");
|
|
40
|
+
const async_1 = __importDefault(require("async"));
|
|
29
41
|
exports.IS_INSTRUMENTED_TOKEN = '/** $IS_JS_PROFILER_INSTRUMENTED=true **/';
|
|
30
42
|
/**
|
|
31
43
|
* An instrumenter based on the IstanbulJs instrumentation and coverage framework.
|
|
@@ -39,14 +51,16 @@ class IstanbulInstrumenter {
|
|
|
39
51
|
/**
|
|
40
52
|
* {@inheritDoc #IInstrumenter.instrument}
|
|
41
53
|
*/
|
|
42
|
-
instrument(task) {
|
|
43
|
-
|
|
44
|
-
//
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
.reduce((prev,
|
|
49
|
-
|
|
54
|
+
async instrument(task) {
|
|
55
|
+
// We limit the number of instrumentations in parallel to one to
|
|
56
|
+
// not overuse memory (NodeJS has only limited mem to use).
|
|
57
|
+
return async_1.default.mapLimit(task.elements, 1, async (taskElement) => {
|
|
58
|
+
return await this.instrumentOne(task.collector, taskElement, task.originSourcePattern);
|
|
59
|
+
}).then((results) => {
|
|
60
|
+
return results.reduce((prev, curr) => {
|
|
61
|
+
return prev.withIncrement(curr);
|
|
62
|
+
}, Task_1.TaskResult.neutral());
|
|
63
|
+
});
|
|
50
64
|
}
|
|
51
65
|
/**
|
|
52
66
|
* Perform the instrumentation for one given task element (file to instrument).
|
|
@@ -55,19 +69,19 @@ class IstanbulInstrumenter {
|
|
|
55
69
|
* @param taskElement - The task element to perform the instrumentation for.
|
|
56
70
|
* @param sourcePattern - A pattern to restrict the instrumentation to only a fraction of the task element.
|
|
57
71
|
*/
|
|
58
|
-
instrumentOne(collector, taskElement, sourcePattern) {
|
|
59
|
-
var _a, _b
|
|
72
|
+
async instrumentOne(collector, taskElement, sourcePattern) {
|
|
73
|
+
var _a, _b;
|
|
60
74
|
const inputFileSource = fs.readFileSync(taskElement.fromFile, 'utf8');
|
|
61
75
|
// We skip files that we have already instrumented
|
|
62
76
|
if (inputFileSource.startsWith(exports.IS_INSTRUMENTED_TOKEN)) {
|
|
63
77
|
if (!taskElement.isInPlace()) {
|
|
64
|
-
|
|
78
|
+
writeToFile(taskElement.toFile, inputFileSource);
|
|
65
79
|
}
|
|
66
|
-
return new Task_1.TaskResult(0, 0, 1, 0, 0, 0);
|
|
80
|
+
return new Task_1.TaskResult(0, 0, 0, 1, 0, 0, 0);
|
|
67
81
|
}
|
|
68
82
|
// Not all file types are supported by the instrumenter
|
|
69
83
|
if (!this.isFileTypeSupported(taskElement.fromFile)) {
|
|
70
|
-
return new Task_1.TaskResult(0, 0, 0, 1, 0, 0);
|
|
84
|
+
return new Task_1.TaskResult(0, 0, 0, 0, 1, 0, 0);
|
|
71
85
|
}
|
|
72
86
|
// Report progress
|
|
73
87
|
this.logger.info(`Instrumenting "${path.basename(taskElement.fromFile)}"`);
|
|
@@ -77,29 +91,37 @@ class IstanbulInstrumenter {
|
|
|
77
91
|
// alternative configurations of the instrumenter.
|
|
78
92
|
const configurationAlternatives = this.configurationAlternativesFor(taskElement);
|
|
79
93
|
for (let i = 0; i < configurationAlternatives.length; i++) {
|
|
94
|
+
const configurationAlternative = configurationAlternatives[i];
|
|
80
95
|
let inputSourceMap;
|
|
81
96
|
try {
|
|
82
|
-
const instrumenter = istanbul.createInstrumenter(
|
|
83
|
-
inputSourceMap = this.loadInputSourceMap(inputFileSource, taskElement);
|
|
97
|
+
const instrumenter = istanbul.createInstrumenter(configurationAlternative);
|
|
98
|
+
inputSourceMap = this.loadInputSourceMap(inputFileSource, taskElement.fromFile, taskElement.externalSourceMapFile);
|
|
84
99
|
// Based on the source maps of the file to instrument, we can now
|
|
85
100
|
// decide if we should NOT write an instrumented version of it
|
|
86
101
|
// and use the original code instead and write it to the target path.
|
|
87
102
|
//
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
103
|
+
const originSourceFiles = (_a = inputSourceMap === null || inputSourceMap === void 0 ? void 0 : inputSourceMap.sources) !== null && _a !== void 0 ? _a : [];
|
|
104
|
+
if (this.shouldExcludeFromInstrumentation(sourcePattern, taskElement.fromFile, originSourceFiles)) {
|
|
105
|
+
writeToFile(taskElement.toFile, inputFileSource);
|
|
106
|
+
return new Task_1.TaskResult(0, 1, 0, 0, 0, 0, 0);
|
|
91
107
|
}
|
|
92
108
|
// The main instrumentation (adding coverage statements) is performed now:
|
|
93
109
|
instrumentedSource = instrumenter
|
|
94
110
|
.instrumentSync(inputFileSource, taskElement.fromFile, inputSourceMap)
|
|
95
111
|
.replace(/return actualCoverage/g, 'return makeCoverageInterceptor(actualCoverage)')
|
|
96
112
|
.replace(/new Function\("return this"\)\(\)/g, "typeof window === 'object' ? window : this");
|
|
97
|
-
this.logger.debug('Instrumentation source maps to:', (
|
|
113
|
+
this.logger.debug('Instrumentation source maps to:', (_b = instrumenter.lastSourceMap()) === null || _b === void 0 ? void 0 : _b.sources);
|
|
114
|
+
// In case of a bundle, the initial instrumentation step might have added
|
|
115
|
+
// too much and undesired instrumentations. Remove them now.
|
|
116
|
+
instrumentedSource = await this.removeUnwantedInstrumentation(taskElement, instrumentedSource, configurationAlternative, sourcePattern);
|
|
98
117
|
// The process also can result in a new source map that we will append in the result.
|
|
99
118
|
//
|
|
100
119
|
// `lastSourceMap` === Sourcemap for the last file that was instrumented.
|
|
101
120
|
finalSourceMap = convertSourceMap.fromObject(instrumenter.lastSourceMap()).toComment();
|
|
102
|
-
|
|
121
|
+
// We now can glue together the final version of the instrumented file.
|
|
122
|
+
const vaccineSource = this.loadVaccine(collector);
|
|
123
|
+
writeToFile(taskElement.toFile, `${exports.IS_INSTRUMENTED_TOKEN} ${vaccineSource} ${instrumentedSource} \n${finalSourceMap}`);
|
|
124
|
+
return new Task_1.TaskResult(1, 0, 0, 0, 0, 0, 0);
|
|
103
125
|
}
|
|
104
126
|
catch (e) {
|
|
105
127
|
// If also the last configuration alternative failed,
|
|
@@ -108,16 +130,41 @@ class IstanbulInstrumenter {
|
|
|
108
130
|
if (!inputSourceMap) {
|
|
109
131
|
return Task_1.TaskResult.warning(`Failed loading input source map for ${taskElement.fromFile}: ${e.message}`);
|
|
110
132
|
}
|
|
111
|
-
|
|
133
|
+
writeToFile(taskElement.toFile, inputFileSource);
|
|
112
134
|
return Task_1.TaskResult.error(e);
|
|
113
135
|
}
|
|
114
136
|
}
|
|
115
137
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
138
|
+
return new Task_1.TaskResult(0, 0, 0, 0, 0, 1, 0);
|
|
139
|
+
}
|
|
140
|
+
async removeUnwantedInstrumentation(taskElement, instrumentedSource, configurationAlternative, sourcePattern) {
|
|
141
|
+
// Read the source map from the instrumented file
|
|
142
|
+
const instrumentedSourceMapConsumer = await this.loadSourceMap(instrumentedSource, taskElement.fromFile);
|
|
143
|
+
// Without a source map, excludes/includes do not work.
|
|
144
|
+
if (!instrumentedSourceMapConsumer) {
|
|
145
|
+
return instrumentedSource;
|
|
146
|
+
}
|
|
147
|
+
// Remove the unwanted instrumentation
|
|
148
|
+
const cleaned = (0, Cleaner_1.cleanSourceCode)(instrumentedSource, configurationAlternative.esModules, location => {
|
|
149
|
+
const originalPosition = instrumentedSourceMapConsumer.originalPositionFor({
|
|
150
|
+
line: location.start.line,
|
|
151
|
+
column: location.start.column
|
|
152
|
+
});
|
|
153
|
+
if (!originalPosition.source) {
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
return sourcePattern.isAnyIncluded([originalPosition.source]);
|
|
157
|
+
});
|
|
158
|
+
// Explicitly free the source map to avoid memory leaks
|
|
159
|
+
instrumentedSourceMapConsumer.destroy();
|
|
160
|
+
return cleaned;
|
|
161
|
+
}
|
|
162
|
+
async loadSourceMap(instrumentedSource, instrumentedSourceFileName) {
|
|
163
|
+
const instrumentedSourceMap = this.loadInputSourceMap(instrumentedSource, instrumentedSourceFileName, typescript_optional_1.Optional.empty());
|
|
164
|
+
if (instrumentedSourceMap) {
|
|
165
|
+
return await new source_map_1.SourceMapConsumer(instrumentedSourceMap);
|
|
166
|
+
}
|
|
167
|
+
return undefined;
|
|
121
168
|
}
|
|
122
169
|
/**
|
|
123
170
|
* Loads the vaccine from the vaccine file and adjusts some template parameters.
|
|
@@ -125,7 +172,7 @@ class IstanbulInstrumenter {
|
|
|
125
172
|
* @param collector - The collector to send coverage information to.
|
|
126
173
|
*/
|
|
127
174
|
loadVaccine(collector) {
|
|
128
|
-
// We first replace
|
|
175
|
+
// We first replace parameters in the file with the
|
|
129
176
|
// actual values, for example, the collector to send the coverage information to.
|
|
130
177
|
return fs
|
|
131
178
|
.readFileSync(this.vaccineFilePath, 'utf8')
|
|
@@ -166,21 +213,22 @@ class IstanbulInstrumenter {
|
|
|
166
213
|
];
|
|
167
214
|
}
|
|
168
215
|
/**
|
|
169
|
-
* Given a source code file
|
|
216
|
+
* Given a source code file, load the corresponding sourcemap.
|
|
170
217
|
*
|
|
171
218
|
* @param inputSource - The source code that might contain sourcemap comments.
|
|
172
|
-
* @param
|
|
219
|
+
* @param taskFile - The name of the file the `inputSource` is from.
|
|
220
|
+
* @param externalSourceMapFile - An external source map file to consider.
|
|
173
221
|
*/
|
|
174
|
-
loadInputSourceMap(
|
|
175
|
-
if (
|
|
176
|
-
const sourceMapOrigin =
|
|
222
|
+
loadInputSourceMap(inputSourceCode, taskFile, externalSourceMapFile) {
|
|
223
|
+
if (externalSourceMapFile.isPresent()) {
|
|
224
|
+
const sourceMapOrigin = externalSourceMapFile.get();
|
|
177
225
|
if (!(sourceMapOrigin instanceof Task_1.SourceMapFileReference)) {
|
|
178
226
|
throw new commons_1.IllegalArgumentException('Type of source map not yet supported!');
|
|
179
227
|
}
|
|
180
228
|
return sourceMapFromMapFile(sourceMapOrigin.sourceMapFilePath);
|
|
181
229
|
}
|
|
182
230
|
else {
|
|
183
|
-
return sourceMapFromCodeComment(
|
|
231
|
+
return sourceMapFromCodeComment(inputSourceCode, taskFile);
|
|
184
232
|
}
|
|
185
233
|
}
|
|
186
234
|
}
|
|
@@ -239,3 +287,7 @@ function sourceMapFromMapFile(mapFilePath) {
|
|
|
239
287
|
const content = fs.readFileSync(mapFilePath, 'utf8');
|
|
240
288
|
return JSON.parse(content);
|
|
241
289
|
}
|
|
290
|
+
function writeToFile(filePath, fileContent) {
|
|
291
|
+
mkdirp.sync(path.dirname(filePath));
|
|
292
|
+
fs.writeFileSync(filePath, fileContent);
|
|
293
|
+
}
|
|
@@ -51,12 +51,20 @@ export declare class OriginSourcePattern {
|
|
|
51
51
|
/**
|
|
52
52
|
* Does the given pattern require to include the given set of files?
|
|
53
53
|
*
|
|
54
|
+
* For example, a JavaScript bundle is compiled from several (origin) source files.
|
|
55
|
+
* If one of the files in the bundle is needed, then the full bundle is needed, that is,
|
|
56
|
+
* this function is required to return `true`.
|
|
57
|
+
*
|
|
54
58
|
* @param originFiles - The file set to decide for include or exclude.
|
|
55
59
|
*
|
|
56
|
-
* @returns `
|
|
57
|
-
* or (2) if one of the files is supposed to be included.
|
|
60
|
+
* @returns `false` if (1) all given files are supposed to be excluded,
|
|
61
|
+
* or (2) `true` if at least one of the files is supposed to be included.
|
|
58
62
|
*/
|
|
59
63
|
isAnyIncluded(originFiles: string[]): boolean;
|
|
64
|
+
private static normalizeGlobPattern;
|
|
65
|
+
private static normalizePath;
|
|
66
|
+
private static removeTrailingCurrentWorkingDir;
|
|
67
|
+
private static removePrefix;
|
|
60
68
|
}
|
|
61
69
|
/**
|
|
62
70
|
* The actual instrumentation task.
|
|
@@ -87,6 +95,8 @@ export declare class InstrumentationTask {
|
|
|
87
95
|
export declare class TaskResult {
|
|
88
96
|
/** Number of task elements that were performed (instrumented) */
|
|
89
97
|
readonly translated: number;
|
|
98
|
+
/** Number of task elements that were excluded because of corresponding include/exclude patterns. */
|
|
99
|
+
readonly excluded: number;
|
|
90
100
|
/** Number of instrumentations that were taken from a cache */
|
|
91
101
|
readonly translatedFromCache: number;
|
|
92
102
|
/** Number of skips due to a present instrumentation */
|
|
@@ -97,7 +107,7 @@ export declare class TaskResult {
|
|
|
97
107
|
readonly failed: number;
|
|
98
108
|
/** Number of warnings that were produced during the instrumentation process */
|
|
99
109
|
readonly warnings: number;
|
|
100
|
-
constructor(translated: number, translatedFromCache: number, alreadyInstrumented: number, unsupported: number, failed: number, warnings: number);
|
|
110
|
+
constructor(translated: number, excluded: number, translatedFromCache: number, alreadyInstrumented: number, unsupported: number, failed: number, warnings: number);
|
|
101
111
|
/**
|
|
102
112
|
* Returns the sum of the present task results and the given one.
|
|
103
113
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Task.d.ts","sourceRoot":"","sources":["../../../src/instrumenter/Task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"Task.d.ts","sourceRoot":"","sources":["../../../src/instrumenter/Task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAK/C;;GAEG;AACH,8BAAsB,kBAAkB;CAAG;AAE3C;;;GAGG;AACH,qBAAa,WAAW;IACvB,sBAAsB;IACtB,SAAgB,QAAQ,EAAE,MAAM,CAAC;IAEjC,2BAA2B;IAC3B,SAAgB,MAAM,EAAE,MAAM,CAAC;IAE/B,gEAAgE;IAChE,SAAgB,qBAAqB,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC;gBAExD,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,kBAAkB;IAMpF;;OAEG;IACI,SAAS,IAAI,OAAO;CAK3B;AAED;;;GAGG;AACH,qBAAa,kBAAkB;IAC9B,2CAA2C;IAC3C,SAAgB,IAAI,EAAE,MAAM,CAAC;IAE7B,gDAAgD;IAChD,SAAgB,IAAI,EAAE,MAAM,CAAC;gBAEjB,SAAS,EAAE,MAAM;CAK7B;AAED;;;;;;GAMG;AACH,qBAAa,mBAAmB;IAC/B,mGAAmG;IACnG,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAE7C;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;gBAEjC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS;IAKpE;;;;;;;;;;;OAWG;IACI,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO;IAqBpD,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAQnC,OAAO,CAAC,MAAM,CAAC,aAAa;IAI5B,OAAO,CAAC,MAAM,CAAC,+BAA+B;IAO9C,OAAO,CAAC,MAAM,CAAC,YAAY;CAO3B;AAED;;GAEG;AACH,qBAAa,mBAAmB;IAC/B;;OAEG;IACH,SAAgB,SAAS,EAAE,kBAAkB,CAAC;IAE9C;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgB;IAE1C;;;OAGG;IACH,SAAgB,mBAAmB,EAAE,mBAAmB,CAAC;gBAE7C,SAAS,EAAE,kBAAkB,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,mBAAmB,EAAE,mBAAmB;IAM5G;;OAEG;IACH,IAAI,QAAQ,IAAI,WAAW,EAAE,CAI5B;CACD;AAED;;GAEG;AACH,qBAAa,UAAU;IACtB,iEAAiE;IACjE,SAAgB,UAAU,EAAE,MAAM,CAAC;IAEnC,oGAAoG;IACpG,SAAgB,QAAQ,EAAE,MAAM,CAAC;IAEjC,8DAA8D;IAC9D,SAAgB,mBAAmB,EAAE,MAAM,CAAC;IAE5C,uDAAuD;IACvD,SAAgB,mBAAmB,EAAE,MAAM,CAAC;IAE5C,sDAAsD;IACtD,SAAgB,WAAW,EAAE,MAAM,CAAC;IAEpC,6DAA6D;IAC7D,SAAgB,MAAM,EAAE,MAAM,CAAC;IAE/B,+EAA+E;IAC/E,SAAgB,QAAQ,EAAE,MAAM,CAAC;gBAGhC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,mBAAmB,EAAE,MAAM,EAC3B,mBAAmB,EAAE,MAAM,EAC3B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM;IAkBjB;;;;OAIG;IACI,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU;IAYnD;;OAEG;WACW,OAAO,IAAI,UAAU;IAInC;;;;OAIG;WACW,KAAK,CAAC,CAAC,EAAE,KAAK,GAAG,UAAU;IAKzC;;;;OAIG;WACW,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU;CAI9C;AAED;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,kBAAkB;IAC7D,2CAA2C;IAC3C,SAAgB,iBAAiB,EAAE,MAAM,CAAC;gBAE9B,iBAAiB,EAAE,MAAM;CAIrC"}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
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);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -18,11 +22,15 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
18
22
|
__setModuleDefault(result, mod);
|
|
19
23
|
return result;
|
|
20
24
|
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
21
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
29
|
exports.SourceMapFileReference = exports.TaskResult = exports.InstrumentationTask = exports.OriginSourcePattern = exports.CollectorSpecifier = exports.TaskElement = exports.SourceMapReference = void 0;
|
|
23
30
|
const typescript_optional_1 = require("typescript-optional");
|
|
24
31
|
const commons_1 = require("@cqse/commons");
|
|
25
32
|
const matching = __importStar(require("micromatch"));
|
|
33
|
+
const path_1 = __importDefault(require("path"));
|
|
26
34
|
/**
|
|
27
35
|
* An abstract source map type.
|
|
28
36
|
*/
|
|
@@ -70,31 +78,57 @@ exports.CollectorSpecifier = CollectorSpecifier;
|
|
|
70
78
|
*/
|
|
71
79
|
class OriginSourcePattern {
|
|
72
80
|
constructor(include, exclude) {
|
|
73
|
-
this.include = include;
|
|
74
|
-
this.exclude = exclude;
|
|
81
|
+
this.include = OriginSourcePattern.normalizeGlobPattern(include);
|
|
82
|
+
this.exclude = OriginSourcePattern.normalizeGlobPattern(exclude);
|
|
75
83
|
}
|
|
76
84
|
/**
|
|
77
85
|
* Does the given pattern require to include the given set of files?
|
|
78
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
|
+
*
|
|
79
91
|
* @param originFiles - The file set to decide for include or exclude.
|
|
80
92
|
*
|
|
81
|
-
* @returns `
|
|
82
|
-
* or (2) if one of the files is supposed to be included.
|
|
93
|
+
* @returns `false` if (1) all given files are supposed to be excluded,
|
|
94
|
+
* or (2) `true` if at least one of the files is supposed to be included.
|
|
83
95
|
*/
|
|
84
96
|
isAnyIncluded(originFiles) {
|
|
85
97
|
var _a;
|
|
98
|
+
if (originFiles.length === 0) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
const normalizedOriginFiles = originFiles.map(OriginSourcePattern.normalizePath);
|
|
86
102
|
if (this.exclude) {
|
|
87
|
-
const matchedToExclude = matching.match(
|
|
103
|
+
const matchedToExclude = matching.match(normalizedOriginFiles, this.exclude);
|
|
88
104
|
if (originFiles.length === matchedToExclude.length) {
|
|
89
105
|
return false;
|
|
90
106
|
}
|
|
91
107
|
}
|
|
92
108
|
if (this.include) {
|
|
93
|
-
const matchedToInclude = matching.match(
|
|
109
|
+
const matchedToInclude = matching.match(normalizedOriginFiles, (_a = this.include) !== null && _a !== void 0 ? _a : '**');
|
|
94
110
|
return matchedToInclude.length > 0;
|
|
95
111
|
}
|
|
96
112
|
return true;
|
|
97
113
|
}
|
|
114
|
+
static normalizeGlobPattern(pattern) {
|
|
115
|
+
if (!pattern) {
|
|
116
|
+
return pattern;
|
|
117
|
+
}
|
|
118
|
+
return OriginSourcePattern.removeTrailingCurrentWorkingDir(pattern);
|
|
119
|
+
}
|
|
120
|
+
static normalizePath(toNormalize) {
|
|
121
|
+
return OriginSourcePattern.removeTrailingCurrentWorkingDir(toNormalize);
|
|
122
|
+
}
|
|
123
|
+
static removeTrailingCurrentWorkingDir(removeFrom) {
|
|
124
|
+
return OriginSourcePattern.removePrefix('webpack:///', OriginSourcePattern.removePrefix('.' + path_1.default.sep, removeFrom));
|
|
125
|
+
}
|
|
126
|
+
static removePrefix(prefix, removeFrom) {
|
|
127
|
+
if (removeFrom.startsWith(prefix)) {
|
|
128
|
+
return removeFrom.substring(prefix.length);
|
|
129
|
+
}
|
|
130
|
+
return removeFrom;
|
|
131
|
+
}
|
|
98
132
|
}
|
|
99
133
|
exports.OriginSourcePattern = OriginSourcePattern;
|
|
100
134
|
/**
|
|
@@ -120,14 +154,16 @@ exports.InstrumentationTask = InstrumentationTask;
|
|
|
120
154
|
* A summary of executing the instrumentation task.
|
|
121
155
|
*/
|
|
122
156
|
class TaskResult {
|
|
123
|
-
constructor(translated, translatedFromCache, alreadyInstrumented, unsupported, failed, warnings) {
|
|
157
|
+
constructor(translated, excluded, translatedFromCache, alreadyInstrumented, unsupported, failed, warnings) {
|
|
124
158
|
commons_1.Contract.require(translated > -1);
|
|
159
|
+
commons_1.Contract.require(excluded > -1);
|
|
125
160
|
commons_1.Contract.require(translatedFromCache > -1);
|
|
126
161
|
commons_1.Contract.require(alreadyInstrumented > -1);
|
|
127
162
|
commons_1.Contract.require(unsupported > -1);
|
|
128
163
|
commons_1.Contract.require(failed > -1);
|
|
129
164
|
commons_1.Contract.require(warnings > -1);
|
|
130
165
|
this.translated = translated;
|
|
166
|
+
this.excluded = excluded;
|
|
131
167
|
this.translatedFromCache = translatedFromCache;
|
|
132
168
|
this.alreadyInstrumented = alreadyInstrumented;
|
|
133
169
|
this.unsupported = unsupported;
|
|
@@ -140,13 +176,13 @@ class TaskResult {
|
|
|
140
176
|
* @param incBy - The task result to add (as delta).
|
|
141
177
|
*/
|
|
142
178
|
withIncrement(incBy) {
|
|
143
|
-
return new TaskResult(this.translated + incBy.translated, this.translatedFromCache + incBy.translatedFromCache, this.alreadyInstrumented + incBy.alreadyInstrumented, this.unsupported + incBy.unsupported, this.failed + incBy.failed, this.warnings + incBy.warnings);
|
|
179
|
+
return new TaskResult(this.translated + incBy.translated, this.excluded + incBy.excluded, this.translatedFromCache + incBy.translatedFromCache, this.alreadyInstrumented + incBy.alreadyInstrumented, this.unsupported + incBy.unsupported, this.failed + incBy.failed, this.warnings + incBy.warnings);
|
|
144
180
|
}
|
|
145
181
|
/**
|
|
146
182
|
* @returns the neutral task element (adding it with {@code withIncrement} does not change the result).
|
|
147
183
|
*/
|
|
148
184
|
static neutral() {
|
|
149
|
-
return new TaskResult(0, 0, 0, 0, 0, 0);
|
|
185
|
+
return new TaskResult(0, 0, 0, 0, 0, 0, 0);
|
|
150
186
|
}
|
|
151
187
|
/**
|
|
152
188
|
* @returns a task result signaling one error.
|
|
@@ -155,7 +191,7 @@ class TaskResult {
|
|
|
155
191
|
*/
|
|
156
192
|
static error(e) {
|
|
157
193
|
console.error(e);
|
|
158
|
-
return new TaskResult(0, 0, 0, 0, 1, 0);
|
|
194
|
+
return new TaskResult(0, 0, 0, 0, 0, 1, 0);
|
|
159
195
|
}
|
|
160
196
|
/**
|
|
161
197
|
* @returns a task result signaling one warning.
|
|
@@ -164,7 +200,7 @@ class TaskResult {
|
|
|
164
200
|
*/
|
|
165
201
|
static warning(msg) {
|
|
166
202
|
console.warn(msg);
|
|
167
|
-
return new TaskResult(0, 0, 0, 0, 0, 1);
|
|
203
|
+
return new TaskResult(0, 0, 0, 0, 0, 0, 1);
|
|
168
204
|
}
|
|
169
205
|
}
|
|
170
206
|
exports.TaskResult = TaskResult;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TaskBuilder.d.ts","sourceRoot":"","sources":["../../../src/instrumenter/TaskBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,mBAAmB,EAGnB,kBAAkB,EAElB,MAAM,QAAQ,CAAC;AAMhB,2DAA2D;AAC3D,oBAAY,uBAAuB,GAAG;IACrC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAElB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAElB,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAkBF;;GAEG;AACH,qBAAa,WAAW;IACvB,gDAAgD;IAChD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IAEzC,6CAA6C;IAC7C,OAAO,CAAC,SAAS,CAA4B;IAE7C,0BAA0B;IAC1B,OAAO,CAAC,0BAA0B,CAAqB;IAEvD,0BAA0B;IAC1B,OAAO,CAAC,0BAA0B,CAAqB;;IAOvD,0EAA0E;IAC1E,sBAAsB,CAAC,sBAAsB,EAAE,MAAM,GAAG,IAAI;IAM5D,8BAA8B;IAC9B,6BAA6B,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAKhE,6BAA6B;IAC7B,6BAA6B,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAKhE,yBAAyB;IACzB,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,kBAAkB,GAAG,IAAI;IAKlG;;;;OAIG;IACH,aAAa,CAAC,MAAM,EAAE,uBAAuB,GAAG,IAAI;IAkCpD;;;;;;;OAOG;IACH,OAAO,CAAC,4CAA4C;
|
|
1
|
+
{"version":3,"file":"TaskBuilder.d.ts","sourceRoot":"","sources":["../../../src/instrumenter/TaskBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,mBAAmB,EAGnB,kBAAkB,EAElB,MAAM,QAAQ,CAAC;AAMhB,2DAA2D;AAC3D,oBAAY,uBAAuB,GAAG;IACrC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAElB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAElB,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAkBF;;GAEG;AACH,qBAAa,WAAW;IACvB,gDAAgD;IAChD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IAEzC,6CAA6C;IAC7C,OAAO,CAAC,SAAS,CAA4B;IAE7C,0BAA0B;IAC1B,OAAO,CAAC,0BAA0B,CAAqB;IAEvD,0BAA0B;IAC1B,OAAO,CAAC,0BAA0B,CAAqB;;IAOvD,0EAA0E;IAC1E,sBAAsB,CAAC,sBAAsB,EAAE,MAAM,GAAG,IAAI;IAM5D,8BAA8B;IAC9B,6BAA6B,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAKhE,6BAA6B;IAC7B,6BAA6B,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAKhE,yBAAyB;IACzB,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,kBAAkB,GAAG,IAAI;IAKlG;;;;OAIG;IACH,aAAa,CAAC,MAAM,EAAE,uBAAuB,GAAG,IAAI;IAkCpD;;;;;;;OAOG;IACH,OAAO,CAAC,4CAA4C;IAgCpD;;;;;;OAMG;IACH,OAAO,CAAC,0BAA0B;IASlC;;OAEG;IACI,KAAK,IAAI,mBAAmB;CAInC"}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
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);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -128,7 +132,11 @@ class TaskBuilder {
|
|
|
128
132
|
inputFiles.forEach(f => this.addElement(f, path.join(target, path.basename(f)), sourceMapInfo));
|
|
129
133
|
}
|
|
130
134
|
else {
|
|
131
|
-
inputFiles.forEach(f =>
|
|
135
|
+
inputFiles.forEach(f => {
|
|
136
|
+
const pathRelativeToInputDir = path.relative(input, f);
|
|
137
|
+
const targetFileName = path.join(target, pathRelativeToInputDir);
|
|
138
|
+
this.addElement(f, targetFileName, sourceMapInfo);
|
|
139
|
+
});
|
|
132
140
|
}
|
|
133
141
|
}
|
|
134
142
|
else {
|
package/dist/src/main.js
CHANGED
|
@@ -7,6 +7,7 @@ App_1.App.run()
|
|
|
7
7
|
.then(result => {
|
|
8
8
|
console.log('Instrumentation finished.');
|
|
9
9
|
console.log(`\tInstrumented: ${result.translated}`);
|
|
10
|
+
console.log(`\tExcluded: ${result.excluded}`);
|
|
10
11
|
console.log(`\tInstrumented from cache: ${result.translatedFromCache}`);
|
|
11
12
|
console.log(`\tAlready instrumented: ${result.alreadyInstrumented}`);
|
|
12
13
|
console.log(`\tUnsupported: ${result.unsupported}`);
|
package/dist/vaccine.js
CHANGED
|
@@ -1,221 +1 @@
|
|
|
1
|
-
(() => {
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
|
|
9
|
-
var __commonJS = (cb, mod) => function __require() {
|
|
10
|
-
return mod || (0, cb[Object.keys(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
11
|
-
};
|
|
12
|
-
var __reExport = (target, module, desc) => {
|
|
13
|
-
if (module && typeof module === "object" || typeof module === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(module))
|
|
15
|
-
if (!__hasOwnProp.call(target, key) && key !== "default")
|
|
16
|
-
__defProp(target, key, { get: () => module[key], enumerable: !(desc = __getOwnPropDesc(module, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return target;
|
|
19
|
-
};
|
|
20
|
-
var __toModule = (module) => {
|
|
21
|
-
return __reExport(__markAsModule(__defProp(module != null ? __create(__getProtoOf(module)) : {}, "default", module && module.__esModule && "default" in module ? { get: () => module.default, enumerable: true } : { value: module, enumerable: true })), module);
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
// ../../node_modules/detect-node/browser.js
|
|
25
|
-
var require_browser = __commonJS({
|
|
26
|
-
"../../node_modules/detect-node/browser.js"(exports, module) {
|
|
27
|
-
module.exports = false;
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
// (disabled):../../node_modules/unload/dist/es/node.js
|
|
32
|
-
var require_node = __commonJS({
|
|
33
|
-
"(disabled):../../node_modules/unload/dist/es/node.js"() {
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
// inline-worker:__inline-worker
|
|
38
|
-
function inlineWorker(scriptText) {
|
|
39
|
-
let blob = new Blob([scriptText], { type: "text/javascript" });
|
|
40
|
-
let url = URL.createObjectURL(blob);
|
|
41
|
-
let worker = new Worker(url);
|
|
42
|
-
URL.revokeObjectURL(url);
|
|
43
|
-
return worker;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// src/vaccine/worker/vaccine.worker.ts
|
|
47
|
-
function Worker2() {
|
|
48
|
-
return inlineWorker('var n=class{constructor(t){this.cachedMessages=[];this.url=t,this.socket=this.createSocket()}createSocket(){let t=new WebSocket(this.url);return t.onopen=()=>this.onopen(),t.onclose=()=>this.onclose(),t}onclose(){this.socket=this.createSocket()}onopen(){this.cachedMessages.forEach(t=>this.socket.send(t)),this.cachedMessages=[]}send(t){this.socket.readyState===WebSocket.OPEN?this.socket.send(t):this.cachedMessages.push(t)}};var o;(function(e){e.MESSAGE_TYPE_SOURCEMAP="s",e.MESSAGE_TYPE_COVERAGE="c"})(o||(o={}));var C=20,p=1e3,a=class{constructor(t,e){this.milliseconds=t;this.onCountedToZero=e;this.timerHandle=null}restartCountdown(){this.stopCountdown(),this.timerHandle=self.setTimeout(()=>{this.stopCountdown(),this.onCountedToZero()},this.milliseconds)}stopCountdown(){this.timerHandle!==null&&(self.clearTimeout(this.timerHandle),this.timerHandle=null)}},r=class{constructor(t){this.socket=t,this.cachedCoveredPositions=new Map,this.numberOfCachedPositions=0,this.flushCountdown=new a(p,()=>this.flush())}add(t){let e=t.split(":");if(e.length!==3)return;let[c,u,l]=e,i=this.cachedCoveredPositions.get(c);i||(i=new Set,this.cachedCoveredPositions.set(c,i)),i.add(`${u}:${l}`),this.numberOfCachedPositions+=1,this.flushCountdown.restartCountdown(),this.numberOfCachedPositions>=C&&this.flush()}flush(){this.numberOfCachedPositions!==0&&(this.flushCountdown.stopCountdown(),this.cachedCoveredPositions.forEach((t,e)=>{this.socket.send(`${o.MESSAGE_TYPE_COVERAGE} ${e} ${Array.from(t).join(" ")}`)}),this.cachedCoveredPositions=new Map,this.numberOfCachedPositions=0)}};console.log("Starting coverage forwarding worker.");var h=new n("ws://$REPORT_TO_HOST:$REPORT_TO_PORT/socket"),d=new r(h);onmessage=s=>{let t=s.data;t.startsWith(o.MESSAGE_TYPE_SOURCEMAP)?h.send(t):t==="unload"?d.flush():d.add(t)};\n');
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// src/vaccine/utils.ts
|
|
52
|
-
function universe() {
|
|
53
|
-
return getWindow();
|
|
54
|
-
}
|
|
55
|
-
function hasWindow() {
|
|
56
|
-
return typeof window !== "undefined";
|
|
57
|
-
}
|
|
58
|
-
function getWindow() {
|
|
59
|
-
return window;
|
|
60
|
-
}
|
|
61
|
-
function universeAttribute(attributeName, defaultValue) {
|
|
62
|
-
let result = universe()[attributeName];
|
|
63
|
-
if (!result) {
|
|
64
|
-
result = defaultValue;
|
|
65
|
-
universe()[attributeName] = result;
|
|
66
|
-
}
|
|
67
|
-
return result;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// src/vaccine/Interceptor.ts
|
|
71
|
-
var STATEMENT_COVERAGE_ID = "s";
|
|
72
|
-
var Interceptor = class {
|
|
73
|
-
constructor(coverageObj, path) {
|
|
74
|
-
this.coverageObj = coverageObj;
|
|
75
|
-
this.path = path;
|
|
76
|
-
}
|
|
77
|
-
get(target, prop, receiver) {
|
|
78
|
-
const value = target[prop];
|
|
79
|
-
if (value !== Object(value)) {
|
|
80
|
-
return value;
|
|
81
|
-
}
|
|
82
|
-
return makeProxy(this.coverageObj, value, [...this.path, prop]);
|
|
83
|
-
}
|
|
84
|
-
set(obj, prop, value) {
|
|
85
|
-
const fullPath = [...this.path, prop];
|
|
86
|
-
if (fullPath[0] === STATEMENT_COVERAGE_ID) {
|
|
87
|
-
const fileId = this.coverageObj.hash;
|
|
88
|
-
const start = this.coverageObj.statementMap[fullPath[1]].start;
|
|
89
|
-
universe()._$Bc(fileId, start.line, start.column);
|
|
90
|
-
}
|
|
91
|
-
return true;
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
function makeProxy(coverage, target, path) {
|
|
95
|
-
return new Proxy(target, new Interceptor(coverage, path));
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// ../../node_modules/unload/dist/es/index.js
|
|
99
|
-
var import_detect_node = __toModule(require_browser());
|
|
100
|
-
|
|
101
|
-
// ../../node_modules/unload/dist/es/browser.js
|
|
102
|
-
function add(fn) {
|
|
103
|
-
if (typeof WorkerGlobalScope === "function" && self instanceof WorkerGlobalScope) {
|
|
104
|
-
} else {
|
|
105
|
-
if (typeof window.addEventListener !== "function")
|
|
106
|
-
return;
|
|
107
|
-
window.addEventListener("beforeunload", function() {
|
|
108
|
-
fn();
|
|
109
|
-
}, true);
|
|
110
|
-
window.addEventListener("unload", function() {
|
|
111
|
-
fn();
|
|
112
|
-
}, true);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
var browser_default = {
|
|
116
|
-
add
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
// ../../node_modules/unload/dist/es/index.js
|
|
120
|
-
var import_node = __toModule(require_node());
|
|
121
|
-
var USE_METHOD = import_detect_node.default ? import_node.default : browser_default;
|
|
122
|
-
var LISTENERS = new Set();
|
|
123
|
-
var startedListening = false;
|
|
124
|
-
function startListening() {
|
|
125
|
-
if (startedListening)
|
|
126
|
-
return;
|
|
127
|
-
startedListening = true;
|
|
128
|
-
USE_METHOD.add(runAll);
|
|
129
|
-
}
|
|
130
|
-
function add2(fn) {
|
|
131
|
-
startListening();
|
|
132
|
-
if (typeof fn !== "function")
|
|
133
|
-
throw new Error("Listener is no function");
|
|
134
|
-
LISTENERS.add(fn);
|
|
135
|
-
var addReturn = {
|
|
136
|
-
remove: function remove() {
|
|
137
|
-
return LISTENERS["delete"](fn);
|
|
138
|
-
},
|
|
139
|
-
run: function run() {
|
|
140
|
-
LISTENERS["delete"](fn);
|
|
141
|
-
return fn();
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
return addReturn;
|
|
145
|
-
}
|
|
146
|
-
function runAll() {
|
|
147
|
-
var promises = [];
|
|
148
|
-
LISTENERS.forEach(function(fn) {
|
|
149
|
-
promises.push(fn());
|
|
150
|
-
LISTENERS["delete"](fn);
|
|
151
|
-
});
|
|
152
|
-
return Promise.all(promises);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// src/vaccine/protocol.ts
|
|
156
|
-
var ProtocolMessageTypes;
|
|
157
|
-
(function(ProtocolMessageTypes2) {
|
|
158
|
-
ProtocolMessageTypes2["MESSAGE_TYPE_SOURCEMAP"] = "s";
|
|
159
|
-
ProtocolMessageTypes2["MESSAGE_TYPE_COVERAGE"] = "c";
|
|
160
|
-
})(ProtocolMessageTypes || (ProtocolMessageTypes = {}));
|
|
161
|
-
|
|
162
|
-
// src/vaccine/main.ts
|
|
163
|
-
var globalAgentObject = universeAttribute("__TS_AGENT", {});
|
|
164
|
-
function getWorker() {
|
|
165
|
-
return globalAgentObject._$BcWorker;
|
|
166
|
-
}
|
|
167
|
-
function setWorker(worker) {
|
|
168
|
-
globalAgentObject._$BcWorker = worker;
|
|
169
|
-
return worker;
|
|
170
|
-
}
|
|
171
|
-
universe().makeCoverageInterceptor = function(coverage) {
|
|
172
|
-
const fileId = coverage.hash;
|
|
173
|
-
if (!getWorker()) {
|
|
174
|
-
const worker = setWorker(new Worker2());
|
|
175
|
-
(function handleUnloading() {
|
|
176
|
-
const protectWindowEvent = function(name) {
|
|
177
|
-
let wrappedHandler = getWindow()[name];
|
|
178
|
-
getWindow()[name] = function(...args) {
|
|
179
|
-
worker.postMessage("unload");
|
|
180
|
-
if (wrappedHandler) {
|
|
181
|
-
return wrappedHandler.apply(this, args);
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
if (hasWindow()) {
|
|
185
|
-
Object.defineProperty(getWindow(), name, {
|
|
186
|
-
get: function() {
|
|
187
|
-
return wrappedHandler;
|
|
188
|
-
},
|
|
189
|
-
set: function(newHandler) {
|
|
190
|
-
wrappedHandler = newHandler;
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
protectWindowEvent("onunload");
|
|
196
|
-
protectWindowEvent("onbeforeunload");
|
|
197
|
-
add2(() => worker.postMessage("unload"));
|
|
198
|
-
})();
|
|
199
|
-
}
|
|
200
|
-
(function sendSourceMaps() {
|
|
201
|
-
const sentMaps = universeAttribute("sentMaps", new Set());
|
|
202
|
-
if (coverage.inputSourceMap) {
|
|
203
|
-
if (!sentMaps.has(coverage.path)) {
|
|
204
|
-
getWorker().postMessage(`${ProtocolMessageTypes.MESSAGE_TYPE_SOURCEMAP} ${fileId}:${JSON.stringify(coverage.inputSourceMap)}`);
|
|
205
|
-
sentMaps.add(coverage.path);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
})();
|
|
209
|
-
(function registerCoverageReporter() {
|
|
210
|
-
const reported = new Set();
|
|
211
|
-
universe()._$Bc = (fileId2, coveredLine, coveredColumn) => {
|
|
212
|
-
const coverageMessage = `${fileId2}:${coveredLine}:${coveredColumn}`;
|
|
213
|
-
if (!reported.has(coverageMessage)) {
|
|
214
|
-
getWorker().postMessage(coverageMessage);
|
|
215
|
-
reported.add(coverageMessage);
|
|
216
|
-
}
|
|
217
|
-
};
|
|
218
|
-
})();
|
|
219
|
-
return makeProxy(coverage, coverage, []);
|
|
220
|
-
};
|
|
221
|
-
})();
|
|
1
|
+
(()=>{var R=Object.create;var h=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var I=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty;var j=e=>h(e,"__esModule",{value:!0});var v=(e,n)=>()=>(n||e((n={exports:{}}).exports,n),n.exports);var L=(e,n,t)=>{if(n&&typeof n=="object"||typeof n=="function")for(let o of $(n))!A.call(e,o)&&o!=="default"&&h(e,o,{get:()=>n[o],enumerable:!(t=y(n,o))||t.enumerable});return e},b=e=>L(j(h(e!=null?R(I(e)):{},"default",e&&e.__esModule&&"default"in e?{get:()=>e.default,enumerable:!0}:{value:e,enumerable:!0})),e);var E=v((K,C)=>{C.exports=!1});var W=v(()=>{});function f(e){let n=new Blob([e],{type:"text/javascript"}),t=URL.createObjectURL(n),o=new Worker(t);return URL.revokeObjectURL(t),o}function p(){return f('var i=class{constructor(e){this.cachedMessages=[];this.url=e,this.socket=this.createSocket()}createSocket(){let e=new WebSocket(this.url);return e.onopen=()=>this.onopen(),e.onclose=()=>this.onclose(),e}onclose(){this.socket=this.createSocket()}onopen(){this.cachedMessages.forEach(e=>this.socket.send(e)),this.cachedMessages=[]}send(e){this.socket.readyState===WebSocket.OPEN?this.socket.send(e):this.cachedMessages.push(e)}};var p=20,f=1e3,c=class{constructor(e,t){this.milliseconds=e;this.onCountedToZero=t;this.timerHandle=null}restartCountdown(){this.stopCountdown(),this.timerHandle=self.setTimeout(()=>{this.stopCountdown(),this.onCountedToZero()},this.milliseconds)}stopCountdown(){this.timerHandle!==null&&(self.clearTimeout(this.timerHandle),this.timerHandle=null)}},n=class{constructor(e){this.socket=e,this.cachedCoveredPositions=new Map,this.numberOfCachedPositions=0,this.flushCountdown=new c(f,()=>this.flush())}add(e){let t=e.split(":");if(t.length!==3)return;let[r,d,u]=t,o=this.cachedCoveredPositions.get(r);o||(o=new Set,this.cachedCoveredPositions.set(r,o)),o.add(`${d}:${u}`),this.numberOfCachedPositions+=1,this.flushCountdown.restartCountdown(),this.numberOfCachedPositions>=p&&this.flush()}flush(){this.numberOfCachedPositions!==0&&(this.flushCountdown.stopCountdown(),this.cachedCoveredPositions.forEach((e,t)=>{this.socket.send(`${"c"} ${t} ${Array.from(e).join(" ")}`)}),this.cachedCoveredPositions=new Map,this.numberOfCachedPositions=0)}};console.log("Starting coverage forwarding worker.");var h=new i("ws://$REPORT_TO_HOST:$REPORT_TO_PORT/socket"),a=new n(h);onmessage=s=>{let e=s.data;e.startsWith("s")?h.send(e):e==="unload"?a.flush():a.add(e)};\n')}function u(){return c()}function k(){return typeof window!="undefined"}function c(){return window}function m(e,n){let t=u()[e];return t||(t=n,u()[e]=t),t}var D="s",S=class{constructor(n,t){this.coverageObj=n;this.path=t}get(n,t,o){let r=n[t];return r!==Object(r)?r:w(this.coverageObj,r,[...this.path,t])}set(n,t,o){let r=[...this.path,t];if(r[0]===D){let i=this.coverageObj.hash,s=this.coverageObj.statementMap[r[1]].start;u()._$Bc(i,s.line,s.column)}return!0}};function w(e,n,t){return new Proxy(n,new S(e,t))}var M=b(E());function H(e){if(!(typeof WorkerGlobalScope=="function"&&self instanceof WorkerGlobalScope)){if(typeof window.addEventListener!="function")return;window.addEventListener("beforeunload",function(){e()},!0),window.addEventListener("unload",function(){e()},!0)}}var O={add:H};var T=b(W()),B=M.default?T.default:O,d=new Set,x=!1;function G(){x||(x=!0,B.add(U))}function P(e){if(G(),typeof e!="function")throw new Error("Listener is no function");d.add(e);var n={remove:function(){return d.delete(e)},run:function(){return d.delete(e),e()}};return n}function U(){var e=[];return d.forEach(function(n){e.push(n()),d.delete(n)}),Promise.all(e)}var l;(function(t){t.MESSAGE_TYPE_SOURCEMAP="s",t.MESSAGE_TYPE_COVERAGE="c"})(l||(l={}));var _=m("__TS_AGENT",{});function g(){return _._$BcWorker}function N(e){return _._$BcWorker=e,e}u().makeCoverageInterceptor=function(e){let n=e.hash;if(!g()){let t=N(new p);(function(){let r=function(i){let s=c()[i];c()[i]=function(...a){if(t.postMessage("unload"),s)return s.apply(this,a)},k()&&Object.defineProperty(c(),i,{get:function(){return s},set:function(a){s=a}})};r("onunload"),r("onbeforeunload"),P(()=>t.postMessage("unload"))})()}return function(){let o=m("sentMaps",new Set);e.inputSourceMap&&(o.has(e.path)||(g().postMessage(`${l.MESSAGE_TYPE_SOURCEMAP} ${n}:${JSON.stringify(e.inputSourceMap)}`),o.add(e.path)))}(),function(){let o=new Set;u()._$Bc=(r,i,s)=>{let a=`${r}:${i}:${s}`;o.has(a)||(g().postMessage(a),o.add(a))}}(),w(e,e,[])};})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teamscale/javascript-instrumenter",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.30",
|
|
4
4
|
"description": "Istanbul-based coverage instrumenter with coverage forwarding via WebSockets",
|
|
5
5
|
"main": "dist/src/main.js",
|
|
6
6
|
"bin": "dist/src/main.js",
|
|
@@ -12,19 +12,22 @@
|
|
|
12
12
|
"url": "https://github.com/cqse/teamscale-javascript-profiler.git"
|
|
13
13
|
},
|
|
14
14
|
"scripts": {
|
|
15
|
+
"prepublishOnly": "yarn clean && yarn build",
|
|
15
16
|
"clean": "rimraf dist tsconfig.tsbuildinfo",
|
|
16
|
-
"build": "tsc --project tsconfig.json &&
|
|
17
|
-
"
|
|
17
|
+
"build": "tsc --project tsconfig.json && yarn buildVaccine",
|
|
18
|
+
"buildVaccine": "node esbuild.mjs",
|
|
19
|
+
"instrumenter": "node dist/src/main.js",
|
|
18
20
|
"test": "yarn build && NODE_OPTIONS='--experimental-vm-modules' jest --forceExit --coverage --silent=true --detectOpenHandles"
|
|
19
21
|
},
|
|
20
22
|
"files": [
|
|
21
23
|
"dist/**/*"
|
|
22
24
|
],
|
|
23
25
|
"devDependencies": {
|
|
24
|
-
"@babel/core": "^7.
|
|
26
|
+
"@babel/core": "^7.17.5",
|
|
25
27
|
"@babel/plugin-transform-modules-commonjs": "^7.15.4",
|
|
26
28
|
"@babel/preset-env": "^7.14.1",
|
|
27
29
|
"@types/async": "^3.2.6",
|
|
30
|
+
"@types/bunyan": "^1.8.8",
|
|
28
31
|
"@types/convert-source-map": "^1.5.1",
|
|
29
32
|
"@types/glob": "^7.1.3",
|
|
30
33
|
"@types/istanbul-lib-instrument": "^1.7.4",
|
|
@@ -44,10 +47,15 @@
|
|
|
44
47
|
"typescript": "^4.4.3"
|
|
45
48
|
},
|
|
46
49
|
"dependencies": {
|
|
50
|
+
"@babel/generator": "^7.17.3",
|
|
51
|
+
"@babel/parser": "^7.17.3",
|
|
52
|
+
"@babel/traverse": "^7.17.3",
|
|
53
|
+
"@babel/types": "^7.17.0",
|
|
47
54
|
"@cqse/commons": "^0.0.1-beta.1",
|
|
48
55
|
"@types/micromatch": "^4.0.2",
|
|
49
56
|
"argparse": "^2.0.1",
|
|
50
|
-
"async": "^3.2.
|
|
57
|
+
"async": "^3.2.3",
|
|
58
|
+
"bunyan": "^1.8.15",
|
|
51
59
|
"convert-source-map": "^1.7.0",
|
|
52
60
|
"foreground-child": "^2.0.0",
|
|
53
61
|
"glob": "^7.1.7",
|
|
@@ -55,11 +63,10 @@
|
|
|
55
63
|
"micromatch": "4.0.4",
|
|
56
64
|
"mkdirp": "^1.0.4",
|
|
57
65
|
"nyc": "^15.1.0",
|
|
58
|
-
"source-map": "0.
|
|
66
|
+
"source-map": "0.7.3",
|
|
59
67
|
"typescript-optional": "^2.0.1",
|
|
60
68
|
"unload": "^2.2.0",
|
|
61
|
-
"web-worker": "^1.0.0"
|
|
62
|
-
"winston": "^3.3.3"
|
|
69
|
+
"web-worker": "^1.0.0"
|
|
63
70
|
},
|
|
64
71
|
"publishConfig": {
|
|
65
72
|
"access": "public"
|