@plugjs/cov8 0.1.0

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.
@@ -0,0 +1,236 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // report.ts
21
+ var report_exports = {};
22
+ __export(report_exports, {
23
+ COVERAGE_IGNORED: () => COVERAGE_IGNORED,
24
+ COVERAGE_SKIPPED: () => COVERAGE_SKIPPED,
25
+ coverageReport: () => coverageReport
26
+ });
27
+ module.exports = __toCommonJS(report_exports);
28
+ var import_node_url = require("node:url");
29
+ var import_parser = require("@babel/parser");
30
+ var import_types = require("@babel/types");
31
+ var import_fs = require("@plugjs/plug/fs");
32
+ var import_logging = require("@plugjs/plug/logging");
33
+ var COVERAGE_SKIPPED = -2;
34
+ var COVERAGE_IGNORED = -1;
35
+ var ignoreRegexp = /^\s+(coverage|istanbul)\s+ignore\s+(test|if|else|try|catch|finally|next|file)(\s|$)/g;
36
+ async function coverageReport(analyser, sourceFiles, log) {
37
+ var _a;
38
+ const results = {};
39
+ const nodes = {
40
+ coveredNodes: 0,
41
+ missingNodes: 0,
42
+ ignoredNodes: 0,
43
+ totalNodes: 0,
44
+ coverage: 0
45
+ };
46
+ for (const file of sourceFiles) {
47
+ const url = (0, import_node_url.pathToFileURL)(file).toString();
48
+ const code = await (0, import_fs.readFile)(file, "utf-8");
49
+ const tree = (0, import_parser.parse)(code, {
50
+ allowImportExportEverywhere: true,
51
+ allowAwaitOutsideFunction: true,
52
+ allowReturnOutsideFunction: true,
53
+ allowSuperOutsideMethod: true,
54
+ allowUndeclaredExports: true,
55
+ attachComment: true,
56
+ errorRecovery: false,
57
+ sourceType: "unambiguous",
58
+ sourceFilename: file,
59
+ startLine: 1,
60
+ startColumn: 0,
61
+ plugins: ["typescript"],
62
+ strictMode: false,
63
+ ranges: false,
64
+ tokens: false,
65
+ createParenthesizedExpressions: true
66
+ });
67
+ const codeCoverage = new Array(code.length).fill(0);
68
+ const nodeCoverage = {
69
+ coveredNodes: 0,
70
+ missingNodes: 0,
71
+ ignoredNodes: 0,
72
+ totalNodes: 0,
73
+ coverage: 0
74
+ };
75
+ const setCodeCoverage = (node, coverage, recursive) => {
76
+ if (!node)
77
+ return;
78
+ if (Array.isArray(node)) {
79
+ for (const n of node)
80
+ setCodeCoverage(n, coverage, recursive);
81
+ return;
82
+ }
83
+ if (node.start != null && node.end != null) {
84
+ for (let i = node.start; i < node.end; i++) {
85
+ codeCoverage[i] = coverage;
86
+ }
87
+ }
88
+ if (coverage == COVERAGE_IGNORED) {
89
+ nodeCoverage.ignoredNodes++;
90
+ } else if (coverage === 0) {
91
+ nodeCoverage.missingNodes++;
92
+ } else if (coverage > 0) {
93
+ nodeCoverage.coveredNodes++;
94
+ }
95
+ if (!recursive)
96
+ return;
97
+ const keys = import_types.VISITOR_KEYS[node.type] || [];
98
+ for (const key of keys) {
99
+ const value = node[key];
100
+ if (Array.isArray(value)) {
101
+ for (const child of value) {
102
+ setCodeCoverage(child, coverage, true);
103
+ }
104
+ } else if (value) {
105
+ setCodeCoverage(value, coverage, true);
106
+ }
107
+ }
108
+ };
109
+ const visitChildren = (node, depth) => {
110
+ const keys = import_types.VISITOR_KEYS[node.type] || [];
111
+ for (const key of keys) {
112
+ const children = node[key];
113
+ if (Array.isArray(children)) {
114
+ for (const child of children) {
115
+ if (child)
116
+ visitNode(child, depth + 1);
117
+ }
118
+ } else if (children) {
119
+ visitNode(children, depth + 1);
120
+ }
121
+ }
122
+ };
123
+ const maybeIgnoreNode = (condition, node, depth) => {
124
+ if (condition) {
125
+ setCodeCoverage(node, COVERAGE_IGNORED, true);
126
+ } else if (node) {
127
+ visitNode(node, depth);
128
+ }
129
+ };
130
+ const visitNode = (node, depth) => {
131
+ var _a2, _b;
132
+ log.trace("-".padStart(depth * 2 + 1, " "), node.type, `${(_a2 = node.loc) == null ? void 0 : _a2.start.line}:${(_b = node.loc) == null ? void 0 : _b.start.column}`);
133
+ if ((0, import_types.isFile)(node))
134
+ return visitChildren(node, depth);
135
+ if ((0, import_types.isProgram)(node))
136
+ return visitChildren(node, depth);
137
+ const ignores = [];
138
+ for (const comment of node.leadingComments || []) {
139
+ for (const match of comment.value.matchAll(ignoreRegexp)) {
140
+ ignores.push(match[2]);
141
+ }
142
+ }
143
+ if (ignores.includes("next"))
144
+ return setCodeCoverage(node, COVERAGE_IGNORED, true);
145
+ if ((0, import_types.isTypeScript)(node)) {
146
+ if ((0, import_types.isTSDeclareMethod)(node))
147
+ return setCodeCoverage(node, COVERAGE_SKIPPED, true);
148
+ if ((0, import_types.isTSTypeReference)(node))
149
+ return setCodeCoverage(node, COVERAGE_SKIPPED, true);
150
+ if ((0, import_types.isDeclaration)(node))
151
+ return setCodeCoverage(node, COVERAGE_SKIPPED, true);
152
+ setCodeCoverage(node, COVERAGE_SKIPPED, false);
153
+ return visitChildren(node, depth);
154
+ }
155
+ if ((0, import_types.isExportDeclaration)(node) && node.exportKind === "type") {
156
+ return setCodeCoverage(node, COVERAGE_SKIPPED, true);
157
+ }
158
+ if ((0, import_types.isImportDeclaration)(node) && node.importKind === "type") {
159
+ return setCodeCoverage(node, COVERAGE_SKIPPED, true);
160
+ }
161
+ let coverage = 0;
162
+ if (node.loc) {
163
+ const { line, column } = node.loc.start;
164
+ const c = analyser.coverage(url, line, column);
165
+ if (c == null) {
166
+ log.warn(`No coverage for ${node.type} at ${(0, import_logging.$p)(file)}:${line}:${column}`);
167
+ } else {
168
+ coverage = c;
169
+ }
170
+ }
171
+ setCodeCoverage(node, coverage, false);
172
+ if ((0, import_types.isIfStatement)(node)) {
173
+ maybeIgnoreNode(ignores.includes("test"), node.test, depth + 1);
174
+ maybeIgnoreNode(ignores.includes("if"), node.consequent, depth + 1);
175
+ maybeIgnoreNode(ignores.includes("else"), node.alternate, depth + 1);
176
+ return;
177
+ }
178
+ if ((0, import_types.isTryStatement)(node)) {
179
+ maybeIgnoreNode(ignores.includes("try"), node.block, depth + 1);
180
+ maybeIgnoreNode(ignores.includes("catch"), node.handler, depth + 1);
181
+ maybeIgnoreNode(ignores.includes("finally"), node.finalizer, depth + 1);
182
+ return;
183
+ }
184
+ visitChildren(node, depth);
185
+ };
186
+ codeCoverage.fill(COVERAGE_SKIPPED);
187
+ setCodeCoverage(tree.program.directives, 0, true);
188
+ setCodeCoverage(tree.program.body, 0, true);
189
+ nodeCoverage.coveredNodes = 0;
190
+ nodeCoverage.missingNodes = 0;
191
+ nodeCoverage.ignoredNodes = 0;
192
+ let ignoreFileCoverage = false;
193
+ for (const comment of ((_a = tree.program.body[0]) == null ? void 0 : _a.leadingComments) || []) {
194
+ for (const match of comment.value.matchAll(ignoreRegexp)) {
195
+ if (match[2] === "file") {
196
+ ignoreFileCoverage = true;
197
+ break;
198
+ }
199
+ }
200
+ if (ignoreFileCoverage)
201
+ break;
202
+ }
203
+ if (ignoreFileCoverage) {
204
+ setCodeCoverage(tree.program, COVERAGE_IGNORED, true);
205
+ } else {
206
+ visitChildren(tree.program, -1);
207
+ }
208
+ setCodeCoverage(tree.comments, COVERAGE_SKIPPED, false);
209
+ updateNodeCoverageResult(nodeCoverage);
210
+ nodes.coveredNodes += nodeCoverage.coveredNodes;
211
+ nodes.missingNodes += nodeCoverage.missingNodes;
212
+ nodes.ignoredNodes += nodeCoverage.ignoredNodes;
213
+ nodes.totalNodes += nodeCoverage.totalNodes;
214
+ results[file] = { code, codeCoverage, nodeCoverage };
215
+ }
216
+ updateNodeCoverageResult(nodes);
217
+ return { results, nodes };
218
+ }
219
+ function updateNodeCoverageResult(result) {
220
+ const { coveredNodes, missingNodes, ignoredNodes } = result;
221
+ const totalNodes = result.totalNodes = coveredNodes + missingNodes + ignoredNodes;
222
+ if (totalNodes === 0) {
223
+ result.coverage = null;
224
+ } else if (totalNodes === ignoredNodes) {
225
+ result.coverage = null;
226
+ } else {
227
+ result.coverage = Math.floor(100 * coveredNodes / (totalNodes - ignoredNodes));
228
+ }
229
+ }
230
+ // Annotate the CommonJS export names for ESM import in node:
231
+ 0 && (module.exports = {
232
+ COVERAGE_IGNORED,
233
+ COVERAGE_SKIPPED,
234
+ coverageReport
235
+ });
236
+ //# sourceMappingURL=report.cjs.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/report.ts"],
4
+ "mappings": "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",
5
+ "names": ["_a"]
6
+ }
@@ -0,0 +1,59 @@
1
+ import type { Logger } from '@plugjs/plug/logging';
2
+ import type { AbsolutePath } from '@plugjs/plug/paths';
3
+ import type { CoverageAnalyser } from './analysis';
4
+ /**
5
+ * A constant indicating that coverage was skipped (is irrelevant, for e.g.
6
+ * comment or typescript definition nodes)
7
+ */
8
+ export declare const COVERAGE_SKIPPED = -2;
9
+ /**
10
+ * A constant indicating that coverage was intentionally ignored because of a
11
+ * specific "coverage ignore ..." comment
12
+ */
13
+ export declare const COVERAGE_IGNORED = -1;
14
+ /** Node coverage summary */
15
+ export interface NodeCoverageResult {
16
+ /** Number of _covered_ nodes (good!) */
17
+ coveredNodes: number;
18
+ /** Number of nodes with _no coverage_ (bad!) */
19
+ missingNodes: number;
20
+ /** Number of nodes ignored by comments like `coverage ignore xxx` */
21
+ ignoredNodes: number;
22
+ /** Total number of nodes (sum of `covered`, `missing` and `ignored`) */
23
+ totalNodes: number;
24
+ /**
25
+ * Percentage of code coverage (covered as a % of total - ignored nodes)
26
+ *
27
+ * A `null` value for this field indicates that no coverage data was generated
28
+ * either because the source was all ignored or skipped (e.g. when using
29
+ * `coverage ignore file` or when covering a TS source only with types).
30
+ */
31
+ coverage: number | null;
32
+ }
33
+ /** Per-file coverage result */
34
+ export interface CoverageResult {
35
+ /** The actual code this coverage is for */
36
+ code: string;
37
+ /**
38
+ * Per _character_ coverage report:
39
+ * - `-2`: coverage skipped (comments, typescript declarations, ...)
40
+ * - `-1`: coverage ignored (when using `coverage ignore xxx`)
41
+ * - `0`: no coverage collected for this character
42
+ * - _any number greater than zero_: number of times this was covered
43
+ */
44
+ codeCoverage: number[];
45
+ /** Node coverage summary */
46
+ nodeCoverage: NodeCoverageResult;
47
+ }
48
+ /** Aggregation of {@link CoverageResult} over all files */
49
+ export declare type CoverageResults = Record<AbsolutePath, CoverageResult>;
50
+ /** Our coverage report, per file */
51
+ export interface CoverageReport {
52
+ results: CoverageResults;
53
+ nodes: NodeCoverageResult;
54
+ }
55
+ /**
56
+ * Analyse coverage for the specified source files, using the data from the
57
+ * specified coverage files and produce a {@link CoverageReport}.
58
+ */
59
+ export declare function coverageReport(analyser: CoverageAnalyser, sourceFiles: AbsolutePath[], log: Logger): Promise<CoverageReport>;
@@ -0,0 +1,221 @@
1
+ // report.ts
2
+ import { pathToFileURL } from "node:url";
3
+ import { parse } from "@babel/parser";
4
+ import {
5
+ isDeclaration,
6
+ isExportDeclaration,
7
+ isFile,
8
+ isIfStatement,
9
+ isImportDeclaration,
10
+ isProgram,
11
+ isTryStatement,
12
+ isTSDeclareMethod,
13
+ isTSTypeReference,
14
+ isTypeScript,
15
+ VISITOR_KEYS
16
+ } from "@babel/types";
17
+ import { readFile } from "@plugjs/plug/fs";
18
+ import { $p } from "@plugjs/plug/logging";
19
+ var COVERAGE_SKIPPED = -2;
20
+ var COVERAGE_IGNORED = -1;
21
+ var ignoreRegexp = /^\s+(coverage|istanbul)\s+ignore\s+(test|if|else|try|catch|finally|next|file)(\s|$)/g;
22
+ async function coverageReport(analyser, sourceFiles, log) {
23
+ var _a;
24
+ const results = {};
25
+ const nodes = {
26
+ coveredNodes: 0,
27
+ missingNodes: 0,
28
+ ignoredNodes: 0,
29
+ totalNodes: 0,
30
+ coverage: 0
31
+ };
32
+ for (const file of sourceFiles) {
33
+ const url = pathToFileURL(file).toString();
34
+ const code = await readFile(file, "utf-8");
35
+ const tree = parse(code, {
36
+ allowImportExportEverywhere: true,
37
+ allowAwaitOutsideFunction: true,
38
+ allowReturnOutsideFunction: true,
39
+ allowSuperOutsideMethod: true,
40
+ allowUndeclaredExports: true,
41
+ attachComment: true,
42
+ errorRecovery: false,
43
+ sourceType: "unambiguous",
44
+ sourceFilename: file,
45
+ startLine: 1,
46
+ startColumn: 0,
47
+ plugins: ["typescript"],
48
+ strictMode: false,
49
+ ranges: false,
50
+ tokens: false,
51
+ createParenthesizedExpressions: true
52
+ });
53
+ const codeCoverage = new Array(code.length).fill(0);
54
+ const nodeCoverage = {
55
+ coveredNodes: 0,
56
+ missingNodes: 0,
57
+ ignoredNodes: 0,
58
+ totalNodes: 0,
59
+ coverage: 0
60
+ };
61
+ const setCodeCoverage = (node, coverage, recursive) => {
62
+ if (!node)
63
+ return;
64
+ if (Array.isArray(node)) {
65
+ for (const n of node)
66
+ setCodeCoverage(n, coverage, recursive);
67
+ return;
68
+ }
69
+ if (node.start != null && node.end != null) {
70
+ for (let i = node.start; i < node.end; i++) {
71
+ codeCoverage[i] = coverage;
72
+ }
73
+ }
74
+ if (coverage == COVERAGE_IGNORED) {
75
+ nodeCoverage.ignoredNodes++;
76
+ } else if (coverage === 0) {
77
+ nodeCoverage.missingNodes++;
78
+ } else if (coverage > 0) {
79
+ nodeCoverage.coveredNodes++;
80
+ }
81
+ if (!recursive)
82
+ return;
83
+ const keys = VISITOR_KEYS[node.type] || [];
84
+ for (const key of keys) {
85
+ const value = node[key];
86
+ if (Array.isArray(value)) {
87
+ for (const child of value) {
88
+ setCodeCoverage(child, coverage, true);
89
+ }
90
+ } else if (value) {
91
+ setCodeCoverage(value, coverage, true);
92
+ }
93
+ }
94
+ };
95
+ const visitChildren = (node, depth) => {
96
+ const keys = VISITOR_KEYS[node.type] || [];
97
+ for (const key of keys) {
98
+ const children = node[key];
99
+ if (Array.isArray(children)) {
100
+ for (const child of children) {
101
+ if (child)
102
+ visitNode(child, depth + 1);
103
+ }
104
+ } else if (children) {
105
+ visitNode(children, depth + 1);
106
+ }
107
+ }
108
+ };
109
+ const maybeIgnoreNode = (condition, node, depth) => {
110
+ if (condition) {
111
+ setCodeCoverage(node, COVERAGE_IGNORED, true);
112
+ } else if (node) {
113
+ visitNode(node, depth);
114
+ }
115
+ };
116
+ const visitNode = (node, depth) => {
117
+ var _a2, _b;
118
+ log.trace("-".padStart(depth * 2 + 1, " "), node.type, `${(_a2 = node.loc) == null ? void 0 : _a2.start.line}:${(_b = node.loc) == null ? void 0 : _b.start.column}`);
119
+ if (isFile(node))
120
+ return visitChildren(node, depth);
121
+ if (isProgram(node))
122
+ return visitChildren(node, depth);
123
+ const ignores = [];
124
+ for (const comment of node.leadingComments || []) {
125
+ for (const match of comment.value.matchAll(ignoreRegexp)) {
126
+ ignores.push(match[2]);
127
+ }
128
+ }
129
+ if (ignores.includes("next"))
130
+ return setCodeCoverage(node, COVERAGE_IGNORED, true);
131
+ if (isTypeScript(node)) {
132
+ if (isTSDeclareMethod(node))
133
+ return setCodeCoverage(node, COVERAGE_SKIPPED, true);
134
+ if (isTSTypeReference(node))
135
+ return setCodeCoverage(node, COVERAGE_SKIPPED, true);
136
+ if (isDeclaration(node))
137
+ return setCodeCoverage(node, COVERAGE_SKIPPED, true);
138
+ setCodeCoverage(node, COVERAGE_SKIPPED, false);
139
+ return visitChildren(node, depth);
140
+ }
141
+ if (isExportDeclaration(node) && node.exportKind === "type") {
142
+ return setCodeCoverage(node, COVERAGE_SKIPPED, true);
143
+ }
144
+ if (isImportDeclaration(node) && node.importKind === "type") {
145
+ return setCodeCoverage(node, COVERAGE_SKIPPED, true);
146
+ }
147
+ let coverage = 0;
148
+ if (node.loc) {
149
+ const { line, column } = node.loc.start;
150
+ const c = analyser.coverage(url, line, column);
151
+ if (c == null) {
152
+ log.warn(`No coverage for ${node.type} at ${$p(file)}:${line}:${column}`);
153
+ } else {
154
+ coverage = c;
155
+ }
156
+ }
157
+ setCodeCoverage(node, coverage, false);
158
+ if (isIfStatement(node)) {
159
+ maybeIgnoreNode(ignores.includes("test"), node.test, depth + 1);
160
+ maybeIgnoreNode(ignores.includes("if"), node.consequent, depth + 1);
161
+ maybeIgnoreNode(ignores.includes("else"), node.alternate, depth + 1);
162
+ return;
163
+ }
164
+ if (isTryStatement(node)) {
165
+ maybeIgnoreNode(ignores.includes("try"), node.block, depth + 1);
166
+ maybeIgnoreNode(ignores.includes("catch"), node.handler, depth + 1);
167
+ maybeIgnoreNode(ignores.includes("finally"), node.finalizer, depth + 1);
168
+ return;
169
+ }
170
+ visitChildren(node, depth);
171
+ };
172
+ codeCoverage.fill(COVERAGE_SKIPPED);
173
+ setCodeCoverage(tree.program.directives, 0, true);
174
+ setCodeCoverage(tree.program.body, 0, true);
175
+ nodeCoverage.coveredNodes = 0;
176
+ nodeCoverage.missingNodes = 0;
177
+ nodeCoverage.ignoredNodes = 0;
178
+ let ignoreFileCoverage = false;
179
+ for (const comment of ((_a = tree.program.body[0]) == null ? void 0 : _a.leadingComments) || []) {
180
+ for (const match of comment.value.matchAll(ignoreRegexp)) {
181
+ if (match[2] === "file") {
182
+ ignoreFileCoverage = true;
183
+ break;
184
+ }
185
+ }
186
+ if (ignoreFileCoverage)
187
+ break;
188
+ }
189
+ if (ignoreFileCoverage) {
190
+ setCodeCoverage(tree.program, COVERAGE_IGNORED, true);
191
+ } else {
192
+ visitChildren(tree.program, -1);
193
+ }
194
+ setCodeCoverage(tree.comments, COVERAGE_SKIPPED, false);
195
+ updateNodeCoverageResult(nodeCoverage);
196
+ nodes.coveredNodes += nodeCoverage.coveredNodes;
197
+ nodes.missingNodes += nodeCoverage.missingNodes;
198
+ nodes.ignoredNodes += nodeCoverage.ignoredNodes;
199
+ nodes.totalNodes += nodeCoverage.totalNodes;
200
+ results[file] = { code, codeCoverage, nodeCoverage };
201
+ }
202
+ updateNodeCoverageResult(nodes);
203
+ return { results, nodes };
204
+ }
205
+ function updateNodeCoverageResult(result) {
206
+ const { coveredNodes, missingNodes, ignoredNodes } = result;
207
+ const totalNodes = result.totalNodes = coveredNodes + missingNodes + ignoredNodes;
208
+ if (totalNodes === 0) {
209
+ result.coverage = null;
210
+ } else if (totalNodes === ignoredNodes) {
211
+ result.coverage = null;
212
+ } else {
213
+ result.coverage = Math.floor(100 * coveredNodes / (totalNodes - ignoredNodes));
214
+ }
215
+ }
216
+ export {
217
+ COVERAGE_IGNORED,
218
+ COVERAGE_SKIPPED,
219
+ coverageReport
220
+ };
221
+ //# sourceMappingURL=report.mjs.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/report.ts"],
4
+ "mappings": "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",
5
+ "names": ["_a"]
6
+ }
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@plugjs/cov8",
3
+ "version": "0.1.0",
4
+ "type": "commonjs",
5
+ "main": "./dist/index.cjs",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "require": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.cjs"
13
+ },
14
+ "import": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.mjs"
17
+ }
18
+ },
19
+ "./coverage": {
20
+ "require": {
21
+ "types": "./dist/coverage.d.ts",
22
+ "default": "./dist/coverage.cjs"
23
+ },
24
+ "import": {
25
+ "types": "./dist/coverage.d.ts",
26
+ "default": "./dist/coverage.mjs"
27
+ }
28
+ }
29
+ },
30
+ "scripts": {
31
+ "build": "plug"
32
+ },
33
+ "author": "Juit Developers <developers@juit.com>",
34
+ "license": "Apache-2.0",
35
+ "devDependencies": {
36
+ "@plugjs/eslint": "^0.1.0",
37
+ "@plugjs/eslint-plugin": "^0.1.0",
38
+ "@plugjs/plug": "^0.1.0",
39
+ "@plugjs/typescript": "^0.1.0",
40
+ "@types/node": "<17",
41
+ "typescript": "^4.8.4"
42
+ },
43
+ "dependencies": {
44
+ "@babel/parser": "^7.20.2",
45
+ "@babel/types": "^7.20.2",
46
+ "@plugjs/cov8-html": "^0.1.0",
47
+ "source-map": "^0.7.4"
48
+ },
49
+ "peerDependencies": {
50
+ "@plugjs/plug": "^0.1.0"
51
+ },
52
+ "files": [
53
+ "*.md",
54
+ "dist/",
55
+ "src/"
56
+ ]
57
+ }