lcov-badge2 1.1.0 → 1.1.2
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 -3
- package/badge.d.ts +1 -0
- package/badge.js +29 -0
- package/cli.d.ts +6 -0
- package/cli.js +59 -0
- package/coverage.d.ts +1 -0
- package/coverage.js +27 -0
- package/main.d.ts +1 -0
- package/main.js +94 -0
- package/package.json +3 -3
- package/.editorconfig +0 -16
- package/.eslintrc.yml +0 -343
- package/.github/dependabot.yml +0 -10
- package/.github/workflows/codeql-analysis.yml +0 -37
- package/.github/workflows/test.yml +0 -31
- package/SECURITY.md +0 -14
- package/gulpfile.mjs +0 -20
- package/src/badge.spec.ts +0 -36
- package/src/badge.ts +0 -22
- package/src/cli.spec.ts +0 -111
- package/src/cli.ts +0 -80
- package/src/coverage.spec.ts +0 -88
- package/src/coverage.ts +0 -24
- package/src/main.spec.ts +0 -78
- package/src/main.ts +0 -21
- package/tsconfig.build.json +0 -9
- package/tsconfig.json +0 -26
- package/types/badge-up2/index.d.ts +0 -19
package/README.md
CHANGED
|
@@ -4,12 +4,15 @@ A tool for generating SVG badges from LCOV reports, based on [lcov-badge](https:
|
|
|
4
4
|
|
|
5
5
|
[](https://github.com/stevenhair/lcov-badge2/actions/workflows/test.yml)
|
|
6
6
|
[](https://codecov.io/gh/stevenhair/lcov-badge2)
|
|
7
|
-
|
|
8
|
-
[](https://www.npmjs.com/package/lcov-badge2)
|
|
8
|
+
[](https://www.npmjs.com/package/lcov-badge2)
|
|
9
9
|
|
|
10
10
|
## Usage
|
|
11
11
|
|
|
12
|
-
lcov-badge2 can be used as either a command line utility or a library
|
|
12
|
+
lcov-badge2 can be used as either a command line utility or a library.
|
|
13
|
+
It produces your basic build badge:
|
|
14
|
+
|
|
15
|
+

|
|
13
16
|
|
|
14
17
|
### Command line usage
|
|
15
18
|
|
package/badge.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function createBadge(label: string, coverage: number): string;
|
package/badge.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createBadge = void 0;
|
|
4
|
+
var badge_up2_1 = require("badge-up2");
|
|
5
|
+
function getColor(coverage) {
|
|
6
|
+
if (coverage > 97) {
|
|
7
|
+
return badge_up2_1.basicColors.brightgreen;
|
|
8
|
+
}
|
|
9
|
+
else if (coverage > 93) {
|
|
10
|
+
return badge_up2_1.basicColors.green;
|
|
11
|
+
}
|
|
12
|
+
else if (coverage > 90) {
|
|
13
|
+
return badge_up2_1.basicColors.yellowgreen;
|
|
14
|
+
}
|
|
15
|
+
else if (coverage > 85) {
|
|
16
|
+
return badge_up2_1.basicColors.yellow;
|
|
17
|
+
}
|
|
18
|
+
else if (coverage > 75) {
|
|
19
|
+
return badge_up2_1.basicColors.orange;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
return badge_up2_1.basicColors.red;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function createBadge(label, coverage) {
|
|
26
|
+
var color = getColor(coverage);
|
|
27
|
+
return (0, badge_up2_1.basic)(label, "".concat(coverage, "%"), color);
|
|
28
|
+
}
|
|
29
|
+
exports.createBadge = createBadge;
|
package/cli.d.ts
ADDED
package/cli.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
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.processArguments = void 0;
|
|
7
|
+
var minimist_1 = __importDefault(require("minimist"));
|
|
8
|
+
var minimist_options_1 = __importDefault(require("minimist-options"));
|
|
9
|
+
var path_1 = require("path");
|
|
10
|
+
var defaultOutputPath = 'badge.svg';
|
|
11
|
+
var defaultLabel = 'coverage';
|
|
12
|
+
function exitWithError(message) {
|
|
13
|
+
console.error(message);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
function printHelp() {
|
|
17
|
+
var message = "Usage: ".concat((0, path_1.basename)(process.argv[1]), " [-h] [-o OUTPUT] [-l LABEL] input\n\nPositional Arguments:\n input Path to LCOV file to parse\n\nOptional Arguments:\n -h, --help Show this help message and exit\n -o OUTPUT, --output OUTPUT\n Output file path (default: ").concat(defaultOutputPath, ")\n -l LABEL, --label LABEL\n Badge label (default: ").concat(defaultLabel, ")\n ");
|
|
18
|
+
console.log(message);
|
|
19
|
+
process.exit(0);
|
|
20
|
+
}
|
|
21
|
+
function validateArguments(args) {
|
|
22
|
+
if (!args._.length) {
|
|
23
|
+
exitWithError('Input must be provided');
|
|
24
|
+
}
|
|
25
|
+
if (args._.length !== 1) {
|
|
26
|
+
exitWithError('Only one input can be provided');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function processArguments() {
|
|
30
|
+
var options = (0, minimist_options_1.default)({
|
|
31
|
+
help: {
|
|
32
|
+
type: 'boolean',
|
|
33
|
+
alias: 'h',
|
|
34
|
+
default: false,
|
|
35
|
+
},
|
|
36
|
+
label: {
|
|
37
|
+
type: 'string',
|
|
38
|
+
alias: 'l',
|
|
39
|
+
default: defaultLabel,
|
|
40
|
+
},
|
|
41
|
+
output: {
|
|
42
|
+
type: 'string',
|
|
43
|
+
alias: 'o',
|
|
44
|
+
default: defaultOutputPath,
|
|
45
|
+
},
|
|
46
|
+
arguments: 'string',
|
|
47
|
+
});
|
|
48
|
+
var args = (0, minimist_1.default)(process.argv.slice(2), options);
|
|
49
|
+
if (args.help) {
|
|
50
|
+
printHelp();
|
|
51
|
+
}
|
|
52
|
+
validateArguments(args);
|
|
53
|
+
return {
|
|
54
|
+
input: args._[0],
|
|
55
|
+
label: args.label,
|
|
56
|
+
output: args.output,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
exports.processArguments = processArguments;
|
package/coverage.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getCoverageLevel(lcov: string): number;
|
package/coverage.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
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.getCoverageLevel = void 0;
|
|
7
|
+
var parse_lcov_1 = __importDefault(require("parse-lcov"));
|
|
8
|
+
function getCoverageLevel(lcov) {
|
|
9
|
+
var coverage = (0, parse_lcov_1.default)(lcov);
|
|
10
|
+
var summary = {
|
|
11
|
+
lines: { found: 0, hit: 0 },
|
|
12
|
+
branches: { found: 0, hit: 0 },
|
|
13
|
+
functions: { found: 0, hit: 0 },
|
|
14
|
+
};
|
|
15
|
+
var keys = Object.keys(summary);
|
|
16
|
+
coverage.forEach(function (arg) {
|
|
17
|
+
keys.forEach(function (key) {
|
|
18
|
+
summary[key].found += arg[key].found;
|
|
19
|
+
summary[key].hit += arg[key].hit;
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
return Math.round(keys.reduce(function (avg, key) {
|
|
23
|
+
var found = summary[key].found;
|
|
24
|
+
return avg + (found > 0 ? summary[key].hit / found * 100 : 100);
|
|
25
|
+
}, 0) / keys.length * 100) / 100;
|
|
26
|
+
}
|
|
27
|
+
exports.getCoverageLevel = getCoverageLevel;
|
package/main.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function generateBadge(filename: string, label?: string): Promise<string>;
|
package/main.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
20
|
+
if (mod && mod.__esModule) return mod;
|
|
21
|
+
var result = {};
|
|
22
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
23
|
+
__setModuleDefault(result, mod);
|
|
24
|
+
return result;
|
|
25
|
+
};
|
|
26
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
27
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
28
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
29
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
30
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
31
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
32
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
36
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
37
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
38
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
39
|
+
function step(op) {
|
|
40
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
41
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
42
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
43
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
44
|
+
switch (op[0]) {
|
|
45
|
+
case 0: case 1: t = op; break;
|
|
46
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
47
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
48
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
49
|
+
default:
|
|
50
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
51
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
52
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
53
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
54
|
+
if (t[2]) _.ops.pop();
|
|
55
|
+
_.trys.pop(); continue;
|
|
56
|
+
}
|
|
57
|
+
op = body.call(thisArg, _);
|
|
58
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
59
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
63
|
+
exports.generateBadge = void 0;
|
|
64
|
+
var fs = __importStar(require("fs/promises"));
|
|
65
|
+
var badge_1 = require("./badge");
|
|
66
|
+
var cli_1 = require("./cli");
|
|
67
|
+
var coverage_1 = require("./coverage");
|
|
68
|
+
function generateBadge(filename, label) {
|
|
69
|
+
if (label === void 0) { label = 'coverage'; }
|
|
70
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
71
|
+
var input, coverage;
|
|
72
|
+
return __generator(this, function (_a) {
|
|
73
|
+
switch (_a.label) {
|
|
74
|
+
case 0: return [4, fs.readFile(filename)];
|
|
75
|
+
case 1:
|
|
76
|
+
input = (_a.sent()).toString();
|
|
77
|
+
coverage = (0, coverage_1.getCoverageLevel)(input);
|
|
78
|
+
return [2, (0, badge_1.createBadge)(label, coverage)];
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
exports.generateBadge = generateBadge;
|
|
84
|
+
if (require.main === module) {
|
|
85
|
+
var args_1 = (0, cli_1.processArguments)();
|
|
86
|
+
generateBadge(args_1.input, args_1.label)
|
|
87
|
+
.then(function (badge) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
88
|
+
return [2, fs.writeFile(args_1.output, badge)];
|
|
89
|
+
}); }); })
|
|
90
|
+
.catch(function (e) {
|
|
91
|
+
console.error(e);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
});
|
|
94
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lcov-badge2",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Generate a badge from a LCOV report",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lcov",
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"start:prod": "dist/main.js",
|
|
30
30
|
"test": "jest",
|
|
31
31
|
"test:watch": "jest --watch",
|
|
32
|
-
"lint": "eslint src
|
|
32
|
+
"lint": "eslint src"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"badge-up2": "^
|
|
35
|
+
"badge-up2": "^2.0.1",
|
|
36
36
|
"minimist": "^1.2.5",
|
|
37
37
|
"minimist-options": "^4.1.0",
|
|
38
38
|
"parse-lcov": "^1.0.4"
|
package/.editorconfig
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# Editor configuration, see https://editorconfig.org
|
|
2
|
-
root = true
|
|
3
|
-
|
|
4
|
-
[*]
|
|
5
|
-
charset = utf-8
|
|
6
|
-
indent_style = space
|
|
7
|
-
indent_size = 4
|
|
8
|
-
insert_final_newline = true
|
|
9
|
-
trim_trailing_whitespace = true
|
|
10
|
-
|
|
11
|
-
[*.{json,yml}]
|
|
12
|
-
indent_size = 2
|
|
13
|
-
max_line_length = off
|
|
14
|
-
|
|
15
|
-
[*.md]
|
|
16
|
-
max_line_length = off
|
package/.eslintrc.yml
DELETED
|
@@ -1,343 +0,0 @@
|
|
|
1
|
-
root: true
|
|
2
|
-
parser: '@typescript-eslint/parser'
|
|
3
|
-
parserOptions:
|
|
4
|
-
project: tsconfig.json
|
|
5
|
-
sourceType: module
|
|
6
|
-
env:
|
|
7
|
-
node: true
|
|
8
|
-
jest: true
|
|
9
|
-
jest/globals: true
|
|
10
|
-
plugins:
|
|
11
|
-
- '@typescript-eslint'
|
|
12
|
-
- 'import'
|
|
13
|
-
- 'jest'
|
|
14
|
-
- 'unicorn'
|
|
15
|
-
extends:
|
|
16
|
-
- 'eslint:recommended'
|
|
17
|
-
- 'plugin:@typescript-eslint/eslint-recommended'
|
|
18
|
-
- 'plugin:@typescript-eslint/recommended'
|
|
19
|
-
settings:
|
|
20
|
-
import/internal-regex: '^(config|core|http-server|logging|operation-log|persistence|test|utils)/'
|
|
21
|
-
rules:
|
|
22
|
-
array-bracket-spacing:
|
|
23
|
-
- error
|
|
24
|
-
- never
|
|
25
|
-
arrow-parens: error
|
|
26
|
-
arrow-spacing: error
|
|
27
|
-
block-spacing:
|
|
28
|
-
- error
|
|
29
|
-
- always
|
|
30
|
-
brace-style:
|
|
31
|
-
- error
|
|
32
|
-
- 1tbs
|
|
33
|
-
camelcase: off
|
|
34
|
-
class-methods-use-this:
|
|
35
|
-
- warn
|
|
36
|
-
- exceptMethods:
|
|
37
|
-
- 'intercept'
|
|
38
|
-
- 'configure'
|
|
39
|
-
- 'getSession'
|
|
40
|
-
complexity: error
|
|
41
|
-
comma-dangle:
|
|
42
|
-
- warn
|
|
43
|
-
- always-multiline
|
|
44
|
-
computed-property-spacing:
|
|
45
|
-
- error
|
|
46
|
-
- never
|
|
47
|
-
constructor-super: error
|
|
48
|
-
curly: error
|
|
49
|
-
dot-notation: error
|
|
50
|
-
eol-last: error
|
|
51
|
-
eqeqeq:
|
|
52
|
-
- error
|
|
53
|
-
- always
|
|
54
|
-
- null: never
|
|
55
|
-
func-call-spacing:
|
|
56
|
-
- error
|
|
57
|
-
- never
|
|
58
|
-
func-style:
|
|
59
|
-
- error
|
|
60
|
-
- declaration
|
|
61
|
-
generator-star-spacing: error
|
|
62
|
-
guard-for-in: error
|
|
63
|
-
key-spacing: error
|
|
64
|
-
keyword-spacing: error
|
|
65
|
-
linebreak-style: error
|
|
66
|
-
max-len:
|
|
67
|
-
- error
|
|
68
|
-
- code: 120
|
|
69
|
-
ignoreTemplateLiterals: true
|
|
70
|
-
ignoreComments: true
|
|
71
|
-
new-parens: error
|
|
72
|
-
no-bitwise: error
|
|
73
|
-
no-caller: error
|
|
74
|
-
no-console: error
|
|
75
|
-
no-constant-condition: error
|
|
76
|
-
no-debugger: error
|
|
77
|
-
no-delete-var: error
|
|
78
|
-
no-eval: error
|
|
79
|
-
no-extra-bind: error
|
|
80
|
-
no-extra-semi: error
|
|
81
|
-
no-invalid-this: error
|
|
82
|
-
no-invalid-regexp: error
|
|
83
|
-
no-irregular-whitespace: error
|
|
84
|
-
no-multi-spaces:
|
|
85
|
-
- error
|
|
86
|
-
- ignoreEOLComments: true
|
|
87
|
-
no-multi-str: error
|
|
88
|
-
no-multiple-empty-lines:
|
|
89
|
-
- error
|
|
90
|
-
- max: 1
|
|
91
|
-
maxBOF: 0
|
|
92
|
-
maxEOF: 1
|
|
93
|
-
no-new-func: error
|
|
94
|
-
no-new-wrappers: error
|
|
95
|
-
no-octal-escape: error
|
|
96
|
-
no-param-reassign: error
|
|
97
|
-
no-plusplus:
|
|
98
|
-
- error
|
|
99
|
-
- allowForLoopAfterthoughts: true
|
|
100
|
-
no-regex-spaces: error
|
|
101
|
-
no-restricted-imports:
|
|
102
|
-
# this is a workaround for this bug: https://github.com/benmosher/eslint-plugin-import/issues/1610
|
|
103
|
-
- error
|
|
104
|
-
- patterns:
|
|
105
|
-
- '../*'
|
|
106
|
-
no-return-await: error
|
|
107
|
-
no-sequences: error
|
|
108
|
-
no-shadow: off # replaced by typescript-eslint/no-shadow rule below because of: https://github.com/typescript-eslint/typescript-eslint/issues/2471
|
|
109
|
-
no-sparse-arrays: error
|
|
110
|
-
no-template-curly-in-string: error
|
|
111
|
-
no-trailing-spaces: error
|
|
112
|
-
no-undef-init: error
|
|
113
|
-
no-unsafe-finally: error
|
|
114
|
-
no-unused-expressions: off
|
|
115
|
-
no-unused-labels: error
|
|
116
|
-
no-useless-rename: error
|
|
117
|
-
no-var: error
|
|
118
|
-
no-void: error
|
|
119
|
-
no-warning-comments: warn
|
|
120
|
-
no-whitespace-before-property: error
|
|
121
|
-
no-with: error
|
|
122
|
-
object-curly-spacing:
|
|
123
|
-
- error
|
|
124
|
-
- always
|
|
125
|
-
object-shorthand:
|
|
126
|
-
- error
|
|
127
|
-
- always
|
|
128
|
-
- avoidQuotes: true
|
|
129
|
-
one-var:
|
|
130
|
-
- error
|
|
131
|
-
- never
|
|
132
|
-
padded-blocks:
|
|
133
|
-
- error
|
|
134
|
-
- never
|
|
135
|
-
prefer-const: error
|
|
136
|
-
prefer-object-spread: error
|
|
137
|
-
prefer-template: error
|
|
138
|
-
quotes:
|
|
139
|
-
- error
|
|
140
|
-
- single
|
|
141
|
-
- avoidEscape: true
|
|
142
|
-
quote-props:
|
|
143
|
-
- error
|
|
144
|
-
- as-needed
|
|
145
|
-
radix: error
|
|
146
|
-
rest-spread-spacing: error
|
|
147
|
-
semi-spacing: error
|
|
148
|
-
space-before-function-paren:
|
|
149
|
-
- error
|
|
150
|
-
- asyncArrow: always
|
|
151
|
-
anonymous: always
|
|
152
|
-
named: never
|
|
153
|
-
space-in-parens:
|
|
154
|
-
- error
|
|
155
|
-
- never
|
|
156
|
-
space-infix-ops: error
|
|
157
|
-
space-unary-ops: error
|
|
158
|
-
spaced-comment: error
|
|
159
|
-
switch-colon-spacing: error
|
|
160
|
-
template-curly-spacing: error
|
|
161
|
-
template-tag-spacing: error
|
|
162
|
-
use-isnan: error
|
|
163
|
-
valid-typeof: error
|
|
164
|
-
yield-star-spacing: error
|
|
165
|
-
|
|
166
|
-
import/export: error
|
|
167
|
-
import/first: error
|
|
168
|
-
import/no-cycle: error
|
|
169
|
-
import/order:
|
|
170
|
-
- error
|
|
171
|
-
- groups:
|
|
172
|
-
- [builtin, external]
|
|
173
|
-
- [internal]
|
|
174
|
-
- [sibling, parent, index]
|
|
175
|
-
newlines-between: always
|
|
176
|
-
alphabetize:
|
|
177
|
-
order: asc
|
|
178
|
-
import/no-deprecated: warn
|
|
179
|
-
import/no-duplicates: error
|
|
180
|
-
import/no-extraneous-dependencies: error
|
|
181
|
-
import/no-mutable-exports: error
|
|
182
|
-
import/no-relative-parent-imports: error
|
|
183
|
-
import/no-unused-modules: error
|
|
184
|
-
jest/consistent-test-it:
|
|
185
|
-
- error
|
|
186
|
-
- fn: test
|
|
187
|
-
jest/expect-expect:
|
|
188
|
-
- error
|
|
189
|
-
- assertFunctionNames:
|
|
190
|
-
- expect
|
|
191
|
-
- assert*
|
|
192
|
-
jest/no-alias-methods: error
|
|
193
|
-
jest/no-commented-out-tests: warn
|
|
194
|
-
jest/no-deprecated-functions: warn
|
|
195
|
-
jest/no-disabled-tests: warn
|
|
196
|
-
# https://github.com/jest-community/eslint-plugin-jest/issues/642
|
|
197
|
-
# jest/no-duplicate-hooks: error
|
|
198
|
-
jest/no-export: error
|
|
199
|
-
jest/no-focused-tests: error
|
|
200
|
-
jest/no-identical-title: error
|
|
201
|
-
jest/no-if: warn
|
|
202
|
-
jest/no-jasmine-globals: error
|
|
203
|
-
jest/no-mocks-import: error
|
|
204
|
-
jest/no-standalone-expect:
|
|
205
|
-
- error
|
|
206
|
-
- additionalTestBlockFunctions:
|
|
207
|
-
- beforeEach
|
|
208
|
-
jest/no-test-prefixes: warn
|
|
209
|
-
jest/no-test-return-statement: error
|
|
210
|
-
jest/prefer-lowercase-title:
|
|
211
|
-
- error
|
|
212
|
-
- ignore:
|
|
213
|
-
- describe
|
|
214
|
-
jest/prefer-spy-on: error
|
|
215
|
-
jest/prefer-to-be: error
|
|
216
|
-
jest/prefer-to-contain: error
|
|
217
|
-
jest/prefer-to-have-length: warn
|
|
218
|
-
jest/prefer-todo: error
|
|
219
|
-
jest/require-to-throw-message: error
|
|
220
|
-
jest/valid-describe-callback: error
|
|
221
|
-
jest/valid-expect: error
|
|
222
|
-
jest/valid-expect-in-promise: error
|
|
223
|
-
unicorn/filename-case: error
|
|
224
|
-
|
|
225
|
-
# typescript-specific
|
|
226
|
-
'@typescript-eslint/array-type':
|
|
227
|
-
- error
|
|
228
|
-
- default: array
|
|
229
|
-
'@typescript-eslint/await-thenable': error
|
|
230
|
-
'@typescript-eslint/adjacent-overload-signatures': error
|
|
231
|
-
'@typescript-eslint/consistent-type-assertions':
|
|
232
|
-
- error
|
|
233
|
-
- assertionStyle: as
|
|
234
|
-
'@typescript-eslint/explicit-function-return-type':
|
|
235
|
-
- error
|
|
236
|
-
- allowExpressions: true
|
|
237
|
-
'@typescript-eslint/explicit-module-boundary-types':
|
|
238
|
-
- error
|
|
239
|
-
- allowHigherOrderFunctions: true
|
|
240
|
-
allowTypedFunctionExpressions: true
|
|
241
|
-
'@typescript-eslint/member-delimiter-style':
|
|
242
|
-
- error
|
|
243
|
-
- singleline:
|
|
244
|
-
delimiter: comma
|
|
245
|
-
requireLast: false
|
|
246
|
-
'@typescript-eslint/member-ordering':
|
|
247
|
-
- error
|
|
248
|
-
- default:
|
|
249
|
-
- static-field
|
|
250
|
-
- instance-field
|
|
251
|
-
- static-method
|
|
252
|
-
- instance-method
|
|
253
|
-
'@typescript-eslint/naming-convention':
|
|
254
|
-
- error
|
|
255
|
-
- selector: default
|
|
256
|
-
format:
|
|
257
|
-
- camelCase
|
|
258
|
-
leadingUnderscore: allow
|
|
259
|
-
trailingUnderscore: forbid
|
|
260
|
-
- selector: variable
|
|
261
|
-
format:
|
|
262
|
-
- camelCase
|
|
263
|
-
- PascalCase
|
|
264
|
-
- UPPER_CASE
|
|
265
|
-
leadingUnderscore: allow
|
|
266
|
-
- selector: function
|
|
267
|
-
format:
|
|
268
|
-
- camelCase
|
|
269
|
-
- PascalCase
|
|
270
|
-
- selector: property
|
|
271
|
-
format:
|
|
272
|
-
- camelCase
|
|
273
|
-
- PascalCase
|
|
274
|
-
- snake_case
|
|
275
|
-
- UPPER_CASE
|
|
276
|
-
leadingUnderscore: allow
|
|
277
|
-
- selector: enumMember
|
|
278
|
-
format:
|
|
279
|
-
- PascalCase
|
|
280
|
-
- selector: typeLike
|
|
281
|
-
format:
|
|
282
|
-
- PascalCase
|
|
283
|
-
'@typescript-eslint/no-array-constructor': error
|
|
284
|
-
'@typescript-eslint/no-dynamic-delete': error
|
|
285
|
-
'@typescript-eslint/no-explicit-any': error
|
|
286
|
-
'@typescript-eslint/no-empty-function':
|
|
287
|
-
- error
|
|
288
|
-
- allow:
|
|
289
|
-
- 'arrowFunctions'
|
|
290
|
-
'@typescript-eslint/no-empty-interface':
|
|
291
|
-
- error
|
|
292
|
-
- allowSingleExtends: true
|
|
293
|
-
'@typescript-eslint/no-extraneous-class': error
|
|
294
|
-
'@typescript-eslint/no-floating-promises': error
|
|
295
|
-
'@typescript-eslint/no-for-in-array': error
|
|
296
|
-
'@typescript-eslint/no-misused-new': error
|
|
297
|
-
'@typescript-eslint/no-require-imports': error
|
|
298
|
-
"@typescript-eslint/no-shadow": error
|
|
299
|
-
'@typescript-eslint/no-this-alias': error
|
|
300
|
-
'@typescript-eslint/no-throw-literal': error
|
|
301
|
-
'@typescript-eslint/no-unnecessary-qualifier': error
|
|
302
|
-
'@typescript-eslint/no-unnecessary-type-arguments': error
|
|
303
|
-
'@typescript-eslint/no-unnecessary-type-assertion': error
|
|
304
|
-
'@typescript-eslint/no-unused-vars':
|
|
305
|
-
- error
|
|
306
|
-
- ignoreRestSiblings: true
|
|
307
|
-
argsIgnorePattern: 'error|_.*'
|
|
308
|
-
varsIgnorePattern: '^_.*'
|
|
309
|
-
'@typescript-eslint/no-use-before-define':
|
|
310
|
-
- error
|
|
311
|
-
- functions: false
|
|
312
|
-
classes: false
|
|
313
|
-
'@typescript-eslint/no-useless-constructor': error
|
|
314
|
-
'@typescript-eslint/no-var-requires': error
|
|
315
|
-
'@typescript-eslint/prefer-for-of': error
|
|
316
|
-
'@typescript-eslint/prefer-function-type': error
|
|
317
|
-
'@typescript-eslint/prefer-nullish-coalescing': warn
|
|
318
|
-
'@typescript-eslint/prefer-optional-chain': error
|
|
319
|
-
'@typescript-eslint/prefer-readonly': error
|
|
320
|
-
'@typescript-eslint/promise-function-async': error
|
|
321
|
-
'@typescript-eslint/require-await': error
|
|
322
|
-
'@typescript-eslint/restrict-plus-operands': error
|
|
323
|
-
'@typescript-eslint/semi': error
|
|
324
|
-
'@typescript-eslint/type-annotation-spacing': error
|
|
325
|
-
'@typescript-eslint/unbound-method':
|
|
326
|
-
- error
|
|
327
|
-
- ignoreStatic: true
|
|
328
|
-
'@typescript-eslint/unified-signatures': error
|
|
329
|
-
overrides:
|
|
330
|
-
- files:
|
|
331
|
-
- 'cli*.ts'
|
|
332
|
-
- 'main*.ts'
|
|
333
|
-
rules:
|
|
334
|
-
no-console: off
|
|
335
|
-
- files:
|
|
336
|
-
- '*.spec.ts'
|
|
337
|
-
rules:
|
|
338
|
-
class-methods-use-this: off
|
|
339
|
-
no-unused-expressions: off
|
|
340
|
-
'@typescript-eslint/no-empty-function': off
|
|
341
|
-
'@typescript-eslint/no-explicit-any': off
|
|
342
|
-
'@typescript-eslint/unbound-method': off
|
|
343
|
-
'@typescript-eslint/ban-types': off
|
package/.github/dependabot.yml
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
name: "CodeQL"
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [ master ]
|
|
6
|
-
pull_request:
|
|
7
|
-
# The branches below must be a subset of the branches above
|
|
8
|
-
branches: [ master ]
|
|
9
|
-
schedule:
|
|
10
|
-
- cron: '19 4 * * 5'
|
|
11
|
-
|
|
12
|
-
jobs:
|
|
13
|
-
analyze:
|
|
14
|
-
name: Analyze
|
|
15
|
-
runs-on: ubuntu-latest
|
|
16
|
-
permissions:
|
|
17
|
-
actions: read
|
|
18
|
-
contents: read
|
|
19
|
-
security-events: write
|
|
20
|
-
|
|
21
|
-
strategy:
|
|
22
|
-
fail-fast: false
|
|
23
|
-
matrix:
|
|
24
|
-
language: [ 'typescript' ]
|
|
25
|
-
|
|
26
|
-
steps:
|
|
27
|
-
- name: Checkout repository
|
|
28
|
-
uses: actions/checkout@v4
|
|
29
|
-
|
|
30
|
-
- name: Initialize CodeQL
|
|
31
|
-
uses: github/codeql-action/init@v2
|
|
32
|
-
with:
|
|
33
|
-
languages: ${{ matrix.language }}
|
|
34
|
-
- name: Autobuild
|
|
35
|
-
uses: github/codeql-action/autobuild@v2
|
|
36
|
-
- name: Perform CodeQL Analysis
|
|
37
|
-
uses: github/codeql-action/analyze@v2
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
name: Build
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- '*'
|
|
7
|
-
pull_request:
|
|
8
|
-
branches:
|
|
9
|
-
- master
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
build:
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
strategy:
|
|
15
|
-
matrix:
|
|
16
|
-
node-version: [16.x, 18.x, 20.x]
|
|
17
|
-
|
|
18
|
-
steps:
|
|
19
|
-
- uses: actions/checkout@v4
|
|
20
|
-
- name: Use Node.js ${{ matrix.node-version }}
|
|
21
|
-
uses: actions/setup-node@v3
|
|
22
|
-
with:
|
|
23
|
-
node-version: ${{ matrix.node-version }}
|
|
24
|
-
- run: npm ci
|
|
25
|
-
- run: npm run build --if-present
|
|
26
|
-
- run: npm run coverage
|
|
27
|
-
- run: npm run lint
|
|
28
|
-
- name: Codecov
|
|
29
|
-
uses: codecov/codecov-action@v3.1.4
|
|
30
|
-
with:
|
|
31
|
-
directory: ./coverage
|
package/SECURITY.md
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# Security Policy
|
|
2
|
-
|
|
3
|
-
## Supported Versions
|
|
4
|
-
|
|
5
|
-
Currently, there's only one major and minor version, so of course it's supported!
|
|
6
|
-
|
|
7
|
-
| Version | Supported |
|
|
8
|
-
| ------- | ------------------- |
|
|
9
|
-
| 1.0.x | :heavy_check_mark: |
|
|
10
|
-
|
|
11
|
-
## Reporting a Vulnerability
|
|
12
|
-
|
|
13
|
-
If you notice a vulnerability, please open an issue or, if you'd like to fix it yourself, a pull request.
|
|
14
|
-
You can expect a response within a couple of days at the latest.
|
package/gulpfile.mjs
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { deleteAsync } from 'del';
|
|
2
|
-
import gulp from 'gulp';
|
|
3
|
-
import header from 'gulp-header';
|
|
4
|
-
|
|
5
|
-
export async function clean() {
|
|
6
|
-
await deleteAsync(['dist']);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function addShebang() {
|
|
10
|
-
return gulp.src('dist/main.js')
|
|
11
|
-
.pipe(header('#!/usr/bin/env node\n'))
|
|
12
|
-
.pipe(gulp.dest('dist'));
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function copyPackageFiles() {
|
|
16
|
-
return gulp.src(['package.json', 'README.md', 'LICENSE'])
|
|
17
|
-
.pipe(gulp.dest('dist'));
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export const postbuild = gulp.series(addShebang, copyPackageFiles);
|
package/src/badge.spec.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import badge, { colors } from 'badge-up2';
|
|
2
|
-
|
|
3
|
-
import { createBadge } from './badge';
|
|
4
|
-
|
|
5
|
-
jest.mock('badge-up2');
|
|
6
|
-
|
|
7
|
-
describe('Badge', () => {
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
(badge as jest.MockedFunction<typeof badge>).mockResolvedValue('this is a badge');
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
describe('Creating badge', () => {
|
|
13
|
-
test('it returns the badge contents', async () => {
|
|
14
|
-
const contents = await createBadge('coverage', 12.34);
|
|
15
|
-
expect(contents).toBe('this is a badge');
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
test.each([
|
|
19
|
-
[colors.red, 0],
|
|
20
|
-
[colors.red, 75],
|
|
21
|
-
[colors.orange, 75.01],
|
|
22
|
-
[colors.orange, 85],
|
|
23
|
-
[colors.yellow, 85.01],
|
|
24
|
-
[colors.yellow, 90],
|
|
25
|
-
[colors.yellowgreen, 90.01],
|
|
26
|
-
[colors.yellowgreen, 93],
|
|
27
|
-
[colors.green, 93.01],
|
|
28
|
-
[colors.green, 97],
|
|
29
|
-
[colors.brightgreen, 97.01],
|
|
30
|
-
[colors.brightgreen, 100],
|
|
31
|
-
])('the color is %s when the coverage is %s', async (color, coverage) => {
|
|
32
|
-
await createBadge('abc123', coverage);
|
|
33
|
-
expect(badge).toHaveBeenCalledWith('abc123', `${coverage}%`, color);
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
});
|
package/src/badge.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import badge, { colors } from 'badge-up2';
|
|
2
|
-
|
|
3
|
-
function getColor(coverage: number): colors {
|
|
4
|
-
if (coverage > 97) {
|
|
5
|
-
return colors.brightgreen;
|
|
6
|
-
} else if (coverage > 93) {
|
|
7
|
-
return colors.green;
|
|
8
|
-
} else if (coverage > 90) {
|
|
9
|
-
return colors.yellowgreen;
|
|
10
|
-
} else if (coverage > 85) {
|
|
11
|
-
return colors.yellow;
|
|
12
|
-
} else if (coverage > 75) {
|
|
13
|
-
return colors.orange;
|
|
14
|
-
} else {
|
|
15
|
-
return colors.red;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export async function createBadge(label: string, coverage: number): Promise<string> {
|
|
20
|
-
const color = getColor(coverage);
|
|
21
|
-
return badge(label, `${coverage}%`, color);
|
|
22
|
-
}
|
package/src/cli.spec.ts
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
|
|
3
|
-
import { Arguments, processArguments } from './cli';
|
|
4
|
-
|
|
5
|
-
describe('CLI', () => {
|
|
6
|
-
beforeEach(() => {
|
|
7
|
-
jest.spyOn(console, 'log').mockImplementation();
|
|
8
|
-
jest.spyOn(console, 'error').mockImplementation();
|
|
9
|
-
jest.spyOn(process, 'exit').mockImplementation();
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
afterEach(() => {
|
|
13
|
-
(console.log as jest.Mock).mockReset();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
describe('When the help argument is passed', () => {
|
|
17
|
-
describe.each(['-h', '--help'])('When %s is passed', (arg) => {
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
process.argv = ['node', path.join('some', 'path', 'whatever', 'foo.ts'), arg];
|
|
20
|
-
processArguments();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
test('it prints the help message', () => {
|
|
24
|
-
expect(console.log).toHaveBeenCalledTimes(1);
|
|
25
|
-
expect((console.log as jest.MockedFunction<typeof console.log>).mock.calls[0][0])
|
|
26
|
-
.toContain('Usage: foo.ts [-h] [-o OUTPUT] [-l LABEL] input');
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
test('it exits without an error', () => {
|
|
30
|
-
expect(process.exit).toHaveBeenCalledWith(0);
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
describe('When no positional arguments are passed', () => {
|
|
36
|
-
beforeEach(() => {
|
|
37
|
-
process.argv = ['node', 'foo.ts', '-l', 'foo'];
|
|
38
|
-
processArguments();
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
test('it prints an error message', () => {
|
|
42
|
-
expect(console.error).toHaveBeenCalledWith('Input must be provided');
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
test('it exits with an error', () => {
|
|
46
|
-
expect(process.exit).toHaveBeenCalledWith(1);
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
describe('When multiple positional arguments are passed', () => {
|
|
51
|
-
beforeEach(() => {
|
|
52
|
-
process.argv = ['node', 'foo.ts', '-l', 'foo', 'bar', 'baz'];
|
|
53
|
-
processArguments();
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
test('it prints an error message', () => {
|
|
57
|
-
expect(console.error).toHaveBeenCalledWith('Only one input can be provided');
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
test('it exits with an error', () => {
|
|
61
|
-
expect(process.exit).toHaveBeenCalledWith(1);
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
describe('When only an input is provided', () => {
|
|
66
|
-
let args: Arguments;
|
|
67
|
-
|
|
68
|
-
beforeEach(() => {
|
|
69
|
-
process.argv = ['node', 'foo.ts', 'foo'];
|
|
70
|
-
args = processArguments();
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
test('it sets the input', () => {
|
|
74
|
-
expect(args.input).toBe('foo');
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test('it uses the default label value', () => {
|
|
78
|
-
expect(args.label).toBe('coverage');
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test('it uses the default output value', () => {
|
|
82
|
-
expect(args.output).toBe('badge.svg');
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
describe('When providing a value for label', () => {
|
|
87
|
-
let args: Arguments;
|
|
88
|
-
|
|
89
|
-
beforeEach(() => {
|
|
90
|
-
process.argv = ['node', 'foo.ts', '-l', 'my-coverage', 'foo'];
|
|
91
|
-
args = processArguments();
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
test('it sets the value for label', () => {
|
|
95
|
-
expect(args.label).toBe('my-coverage');
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
describe('When providing a value for output', () => {
|
|
100
|
-
let args: Arguments;
|
|
101
|
-
|
|
102
|
-
beforeEach(() => {
|
|
103
|
-
process.argv = ['node', 'foo.ts', '-o', 'my-badge.svg', 'foo'];
|
|
104
|
-
args = processArguments();
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test('it sets the value for label', () => {
|
|
108
|
-
expect(args.output).toBe('my-badge.svg');
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
});
|
package/src/cli.ts
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import minimist, { ParsedArgs } from 'minimist';
|
|
2
|
-
import buildOptions from 'minimist-options';
|
|
3
|
-
import { basename } from 'path';
|
|
4
|
-
|
|
5
|
-
export interface Arguments {
|
|
6
|
-
input: string;
|
|
7
|
-
label: string;
|
|
8
|
-
output: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const defaultOutputPath = 'badge.svg';
|
|
12
|
-
const defaultLabel = 'coverage';
|
|
13
|
-
|
|
14
|
-
function exitWithError(message: string): never {
|
|
15
|
-
console.error(message);
|
|
16
|
-
process.exit(1);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function printHelp(): never {
|
|
20
|
-
const message = `Usage: ${basename(process.argv[1])} [-h] [-o OUTPUT] [-l LABEL] input
|
|
21
|
-
|
|
22
|
-
Positional Arguments:
|
|
23
|
-
input Path to LCOV file to parse
|
|
24
|
-
|
|
25
|
-
Optional Arguments:
|
|
26
|
-
-h, --help Show this help message and exit
|
|
27
|
-
-o OUTPUT, --output OUTPUT
|
|
28
|
-
Output file path (default: ${defaultOutputPath})
|
|
29
|
-
-l LABEL, --label LABEL
|
|
30
|
-
Badge label (default: ${defaultLabel})
|
|
31
|
-
`;
|
|
32
|
-
console.log(message);
|
|
33
|
-
process.exit(0);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function validateArguments(args: ParsedArgs): void {
|
|
37
|
-
if (!args._.length) {
|
|
38
|
-
exitWithError('Input must be provided');
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (args._.length !== 1) {
|
|
42
|
-
exitWithError('Only one input can be provided');
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function processArguments(): Arguments {
|
|
47
|
-
const options = buildOptions({
|
|
48
|
-
help: {
|
|
49
|
-
type: 'boolean',
|
|
50
|
-
alias: 'h',
|
|
51
|
-
default: false,
|
|
52
|
-
},
|
|
53
|
-
label: {
|
|
54
|
-
type: 'string',
|
|
55
|
-
alias: 'l',
|
|
56
|
-
default: defaultLabel,
|
|
57
|
-
},
|
|
58
|
-
output: {
|
|
59
|
-
type: 'string',
|
|
60
|
-
alias: 'o',
|
|
61
|
-
default: defaultOutputPath,
|
|
62
|
-
},
|
|
63
|
-
// Special option for positional arguments (`_` in minimist)
|
|
64
|
-
arguments: 'string',
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
const args = minimist(process.argv.slice(2), options);
|
|
68
|
-
|
|
69
|
-
if (args.help) {
|
|
70
|
-
printHelp();
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
validateArguments(args);
|
|
74
|
-
|
|
75
|
-
return {
|
|
76
|
-
input: args._[0],
|
|
77
|
-
label: args.label,
|
|
78
|
-
output: args.output,
|
|
79
|
-
};
|
|
80
|
-
}
|
package/src/coverage.spec.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import parse from 'parse-lcov';
|
|
2
|
-
|
|
3
|
-
import { getCoverageLevel } from './coverage';
|
|
4
|
-
|
|
5
|
-
jest.mock('parse-lcov');
|
|
6
|
-
|
|
7
|
-
describe('Coverage', () => {
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
(parse as jest.MockedFunction<typeof parse>).mockReturnValue([]);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
test('it reads the file', () => {
|
|
13
|
-
getCoverageLevel('foo.lcov');
|
|
14
|
-
expect(parse).toHaveBeenCalledWith('foo.lcov');
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
describe('When there are no lines of code', () => {
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
(parse as jest.MockedFunction<typeof parse>).mockReturnValue([
|
|
20
|
-
{
|
|
21
|
-
title: '',
|
|
22
|
-
file: '',
|
|
23
|
-
functions: { found: 0, hit: 0, details: [] },
|
|
24
|
-
branches: { found: 0, hit: 0, details: [] },
|
|
25
|
-
lines: { found: 0, hit: 0, details: [] },
|
|
26
|
-
},
|
|
27
|
-
]);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
test('it returns 100', () => {
|
|
31
|
-
expect(getCoverageLevel('foo')).toBe(100);
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
describe('When there are lines of code and none are hit', () => {
|
|
36
|
-
beforeEach(() => {
|
|
37
|
-
(parse as jest.MockedFunction<typeof parse>).mockReturnValue([
|
|
38
|
-
{
|
|
39
|
-
title: '',
|
|
40
|
-
file: '',
|
|
41
|
-
functions: { found: 1, hit: 0, details: [] },
|
|
42
|
-
branches: { found: 2, hit: 0, details: [] },
|
|
43
|
-
lines: { found: 3, hit: 0, details: [] },
|
|
44
|
-
},
|
|
45
|
-
]);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('it returns 0', () => {
|
|
49
|
-
expect(getCoverageLevel('foo')).toBe(0);
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
describe('When there are lines of code and all are hit', () => {
|
|
54
|
-
beforeEach(() => {
|
|
55
|
-
(parse as jest.MockedFunction<typeof parse>).mockReturnValue([
|
|
56
|
-
{
|
|
57
|
-
title: '',
|
|
58
|
-
file: '',
|
|
59
|
-
functions: { found: 1, hit: 1, details: [] },
|
|
60
|
-
branches: { found: 2, hit: 2, details: [] },
|
|
61
|
-
lines: { found: 3, hit: 3, details: [] },
|
|
62
|
-
},
|
|
63
|
-
]);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test('it returns 0', () => {
|
|
67
|
-
expect(getCoverageLevel('foo')).toBe(100);
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
describe('When there are lines of code and some are hit', () => {
|
|
72
|
-
beforeEach(() => {
|
|
73
|
-
(parse as jest.MockedFunction<typeof parse>).mockReturnValue([
|
|
74
|
-
{
|
|
75
|
-
title: '',
|
|
76
|
-
file: '',
|
|
77
|
-
functions: { found: 100, hit: 66, details: [] },
|
|
78
|
-
branches: { found: 200, hit: 157, details: [] },
|
|
79
|
-
lines: { found: 1234, hit: 963, details: [] },
|
|
80
|
-
},
|
|
81
|
-
]);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
test('it calculates the coverage', () => {
|
|
85
|
-
expect(getCoverageLevel('foo')).toBe(74.18);
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
});
|
package/src/coverage.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import parse from 'parse-lcov';
|
|
2
|
-
|
|
3
|
-
export function getCoverageLevel(lcov: string): number {
|
|
4
|
-
const coverage = parse(lcov);
|
|
5
|
-
|
|
6
|
-
const summary = {
|
|
7
|
-
lines: { found: 0, hit: 0 },
|
|
8
|
-
branches: { found: 0, hit: 0 },
|
|
9
|
-
functions: { found: 0, hit: 0 },
|
|
10
|
-
};
|
|
11
|
-
const keys = Object.keys(summary) as (keyof typeof summary)[];
|
|
12
|
-
|
|
13
|
-
coverage.forEach((arg) => {
|
|
14
|
-
keys.forEach((key) => {
|
|
15
|
-
summary[key].found += arg[key].found;
|
|
16
|
-
summary[key].hit += arg[key].hit;
|
|
17
|
-
});
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
return Math.round(keys.reduce((avg, key) => {
|
|
21
|
-
const found = summary[key].found;
|
|
22
|
-
return avg + (found > 0 ? summary[key].hit / found * 100 : 100);
|
|
23
|
-
}, 0) / keys.length * 100) / 100;
|
|
24
|
-
}
|
package/src/main.spec.ts
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { spawnSync, SpawnSyncReturns } from 'child_process';
|
|
2
|
-
import fs from 'fs/promises';
|
|
3
|
-
import os from 'os';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
|
|
6
|
-
import { createBadge } from './badge';
|
|
7
|
-
import { getCoverageLevel } from './coverage';
|
|
8
|
-
import { generateBadge } from './main';
|
|
9
|
-
|
|
10
|
-
jest.mock('./badge');
|
|
11
|
-
jest.mock('./coverage');
|
|
12
|
-
|
|
13
|
-
describe('Main', () => {
|
|
14
|
-
let badgeContents: string;
|
|
15
|
-
|
|
16
|
-
beforeEach(async () => {
|
|
17
|
-
jest.spyOn(fs, 'readFile').mockResolvedValue('some lcov content');
|
|
18
|
-
(getCoverageLevel as jest.MockedFunction<typeof getCoverageLevel>).mockReturnValue(99.5);
|
|
19
|
-
(createBadge as jest.MockedFunction<typeof createBadge>).mockResolvedValue('totally an svg');
|
|
20
|
-
|
|
21
|
-
badgeContents = await generateBadge('foo.lcov', 'something');
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
test('the main function generates the badge from the input', () => {
|
|
25
|
-
expect(fs.readFile).toHaveBeenCalledWith('foo.lcov');
|
|
26
|
-
expect(getCoverageLevel).toHaveBeenCalledWith('some lcov content');
|
|
27
|
-
expect(createBadge).toHaveBeenCalledWith('something', 99.5);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
test('it returns the SVG as a string', () => {
|
|
31
|
-
expect(badgeContents).toBe('totally an svg');
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
describe('Running as a script', () => {
|
|
35
|
-
const report = `
|
|
36
|
-
TN:
|
|
37
|
-
SF:src/badge.ts
|
|
38
|
-
FN:3,getColor
|
|
39
|
-
FN:19,createBadge
|
|
40
|
-
FNF:2
|
|
41
|
-
FNH:2
|
|
42
|
-
FNDA:13,getColor
|
|
43
|
-
FNDA:13,createBadge
|
|
44
|
-
DA:1,2
|
|
45
|
-
LF:15
|
|
46
|
-
LH:15
|
|
47
|
-
BRDA:4,0,0,2
|
|
48
|
-
BRF:10
|
|
49
|
-
BRH:10
|
|
50
|
-
end_of_record`;
|
|
51
|
-
let inputFilePath: string;
|
|
52
|
-
let filePath: string;
|
|
53
|
-
let result: SpawnSyncReturns<string | Buffer>;
|
|
54
|
-
|
|
55
|
-
beforeEach(async () => {
|
|
56
|
-
const dir = os.tmpdir();
|
|
57
|
-
filePath = path.join(dir, `badge-${new Date().valueOf()}.svg`);
|
|
58
|
-
inputFilePath = path.join(dir, `lcov-${new Date().valueOf()}.info`);
|
|
59
|
-
|
|
60
|
-
await fs.writeFile(inputFilePath, report);
|
|
61
|
-
|
|
62
|
-
result = spawnSync('ts-node', [path.join(__dirname, 'main.ts'), '-o', filePath, inputFilePath]);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
afterEach(async () => {
|
|
66
|
-
await fs.rm(filePath);
|
|
67
|
-
await fs.rm(inputFilePath);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
test('it exited successfully', () => {
|
|
71
|
-
expect(result.status).toBe(0);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test('it writes the badge file', async () => {
|
|
75
|
-
await expect(fs.stat(filePath)).resolves.not.toThrow();
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
});
|
package/src/main.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs/promises';
|
|
2
|
-
|
|
3
|
-
import { createBadge } from './badge';
|
|
4
|
-
import { processArguments } from './cli';
|
|
5
|
-
import { getCoverageLevel } from './coverage';
|
|
6
|
-
|
|
7
|
-
export async function generateBadge(filename: string, label = 'coverage'): Promise<string> {
|
|
8
|
-
const input = (await fs.readFile(filename)).toString();
|
|
9
|
-
const coverage = getCoverageLevel(input);
|
|
10
|
-
return createBadge(label, coverage);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
if (require.main === module) {
|
|
14
|
-
const args = processArguments();
|
|
15
|
-
generateBadge(args.input, args.label)
|
|
16
|
-
.then(async (badge) => fs.writeFile(args.output, badge))
|
|
17
|
-
.catch((e) => {
|
|
18
|
-
console.error(e);
|
|
19
|
-
process.exit(1);
|
|
20
|
-
});
|
|
21
|
-
}
|
package/tsconfig.build.json
DELETED
package/tsconfig.json
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"module": "commonjs",
|
|
4
|
-
"declaration": true,
|
|
5
|
-
"removeComments": true,
|
|
6
|
-
"emitDecoratorMetadata": true,
|
|
7
|
-
"esModuleInterop": true,
|
|
8
|
-
"experimentalDecorators": true,
|
|
9
|
-
"target": "ES5",
|
|
10
|
-
"lib": [
|
|
11
|
-
"es2020"
|
|
12
|
-
],
|
|
13
|
-
"sourceMap": true,
|
|
14
|
-
"outDir": "./dist",
|
|
15
|
-
"baseUrl": "./src",
|
|
16
|
-
"resolveJsonModule": true,
|
|
17
|
-
"strict": true,
|
|
18
|
-
"typeRoots": [
|
|
19
|
-
"node_modules/@types",
|
|
20
|
-
"types"
|
|
21
|
-
]
|
|
22
|
-
},
|
|
23
|
-
"include": [
|
|
24
|
-
"src/**/*.ts"
|
|
25
|
-
]
|
|
26
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
declare module 'badge-up2' {
|
|
2
|
-
export enum colors {
|
|
3
|
-
brightgreen = '#4C1',
|
|
4
|
-
green = '#97CA00',
|
|
5
|
-
yellow = '#DFB317',
|
|
6
|
-
yellowgreen = '#A4A61D',
|
|
7
|
-
orange = '#FE7D37',
|
|
8
|
-
red = '#E05D44',
|
|
9
|
-
blue = '#007EC6',
|
|
10
|
-
grey = '#555',
|
|
11
|
-
gray = '#555',
|
|
12
|
-
lightgrey = '#9F9F9F',
|
|
13
|
-
lightgray = '#9F9F9F',
|
|
14
|
-
purple = '#400090'
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function badge(field1: string, field2: string, color: colors): Promise<string>;
|
|
18
|
-
export default badge;
|
|
19
|
-
}
|