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 CHANGED
@@ -4,12 +4,15 @@ A tool for generating SVG badges from LCOV reports, based on [lcov-badge](https:
4
4
 
5
5
  [![Build](https://github.com/stevenhair/lcov-badge2/actions/workflows/test.yml/badge.svg)](https://github.com/stevenhair/lcov-badge2/actions/workflows/test.yml)
6
6
  [![codecov](https://codecov.io/gh/stevenhair/lcov-badge2/branch/master/graph/badge.svg?token=nb0yy1Y6zc)](https://codecov.io/gh/stevenhair/lcov-badge2)
7
-
8
- [![NPM](https://nodei.co/npm/lcov-badge2.png)](https://nodei.co/npm/lcov-badge2/)
7
+ [![npm](https://img.shields.io/npm/v/lcov-badge2.svg?maxAge=2592000)](https://www.npmjs.com/package/lcov-badge2)
8
+ [![downloads](https://img.shields.io/npm/dt/lcov-badge2.svg?maxAge=2592000)](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
+ ![example](https://raw.githubusercontent.com/stevenhair/lcov-badge2/master/example.svg)
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
@@ -0,0 +1,6 @@
1
+ export interface Arguments {
2
+ input: string;
3
+ label: string;
4
+ output: string;
5
+ }
6
+ export declare function processArguments(): Arguments;
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.0",
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/**/*.ts"
32
+ "lint": "eslint src"
33
33
  },
34
34
  "dependencies": {
35
- "badge-up2": "^1.0.0",
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
@@ -1,10 +0,0 @@
1
- version: 2
2
- updates:
3
- - package-ecosystem: npm
4
- directory: '/'
5
- schedule:
6
- interval: weekly
7
- - package-ecosystem: github-actions
8
- directory: '/'
9
- schedule:
10
- interval: weekly
@@ -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
- }
@@ -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
- }
@@ -1,9 +0,0 @@
1
- {
2
- "extends": "./tsconfig.json",
3
- "compilerOptions": {
4
- "sourceMap": false
5
- },
6
- "exclude": [
7
- "src/**/*.spec.ts"
8
- ]
9
- }
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
- }