@code-pushup/js-packages-plugin 0.44.4 → 0.45.1
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 +1 -0
- package/bin.js +446 -365
- package/index.js +70 -59
- package/package.json +3 -3
- package/src/lib/config.d.ts +23 -0
- package/src/lib/runner/outdated/transform.d.ts +1 -1
- package/src/lib/runner/outdated/types.d.ts +6 -1
- package/src/lib/runner/utils.d.ts +3 -0
package/README.md
CHANGED
|
@@ -113,6 +113,7 @@ The plugin accepts the following parameters:
|
|
|
113
113
|
- `packageManager`: The package manager you are using. Supported values: `npm`, `yarn-classic` (v1), `yarn-modern` (v2+), `pnpm`.
|
|
114
114
|
- (optional) `checks`: Array of checks to be run. Supported commands: `audit`, `outdated`. Both are configured by default.
|
|
115
115
|
- (optional) `dependencyGroups`: Array of dependency groups to be checked. `prod` and `dev` are configured by default. `optional` are opt-in.
|
|
116
|
+
- (optional) `packageJsonPaths`: File path(s) to `package.json`. Root `package.json` is used by default. Multiple `package.json` paths may be passed. If `{ autoSearch: true }` is provided, all `package.json` files in the repository are searched.
|
|
116
117
|
- (optional) `auditLevelMapping`: If you wish to set a custom level of issue severity based on audit vulnerability level, you may do so here. Any omitted values will be filled in by defaults. Audit levels are: `critical`, `high`, `moderate`, `low` and `info`. Issue severities are: `error`, `warn` and `info`. By default the mapping is as follows: `critical` and `high` → `error`; `moderate` and `low` → `warning`; `info` → `info`.
|
|
117
118
|
|
|
118
119
|
### Audits and group
|
package/bin.js
CHANGED
|
@@ -2,300 +2,6 @@
|
|
|
2
2
|
import { writeFile } from "node:fs/promises";
|
|
3
3
|
import { dirname } from "node:path";
|
|
4
4
|
|
|
5
|
-
// packages/utils/src/lib/text-formats/constants.ts
|
|
6
|
-
var NEW_LINE = "\n";
|
|
7
|
-
var TAB = " ";
|
|
8
|
-
|
|
9
|
-
// packages/utils/src/lib/text-formats/html/details.ts
|
|
10
|
-
function details(title, content, cfg = { open: false }) {
|
|
11
|
-
return `<details${cfg.open ? " open" : ""}>${NEW_LINE}<summary>${title}</summary>${NEW_LINE}${// ⚠️ The blank line is needed to ensure Markdown in content is rendered correctly.
|
|
12
|
-
NEW_LINE}${content}${NEW_LINE}${// @TODO in the future we could consider adding it only if the content ends with a code block
|
|
13
|
-
// ⚠️ The blank line ensure Markdown in content is rendered correctly.
|
|
14
|
-
NEW_LINE}</details>${// ⚠️ The blank line is needed to ensure Markdown after details is rendered correctly.
|
|
15
|
-
NEW_LINE}`;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// packages/utils/src/lib/text-formats/html/font-style.ts
|
|
19
|
-
var boldElement = "b";
|
|
20
|
-
function bold(text) {
|
|
21
|
-
return `<${boldElement}>${text}</${boldElement}>`;
|
|
22
|
-
}
|
|
23
|
-
var italicElement = "i";
|
|
24
|
-
function italic(text) {
|
|
25
|
-
return `<${italicElement}>${text}</${italicElement}>`;
|
|
26
|
-
}
|
|
27
|
-
var codeElement = "code";
|
|
28
|
-
function code(text) {
|
|
29
|
-
return `<${codeElement}>${text}</${codeElement}>`;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// packages/utils/src/lib/text-formats/html/link.ts
|
|
33
|
-
function link(href, text) {
|
|
34
|
-
return `<a href="${href}">${text || href}"</a>`;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// packages/utils/src/lib/transform.ts
|
|
38
|
-
import { platform } from "node:os";
|
|
39
|
-
function objectToKeys(obj) {
|
|
40
|
-
return Object.keys(obj);
|
|
41
|
-
}
|
|
42
|
-
function objectToEntries(obj) {
|
|
43
|
-
return Object.entries(obj);
|
|
44
|
-
}
|
|
45
|
-
function objectFromEntries(entries) {
|
|
46
|
-
return Object.fromEntries(entries);
|
|
47
|
-
}
|
|
48
|
-
function toUnixNewlines(text) {
|
|
49
|
-
return platform() === "win32" ? text.replace(/\r\n/g, "\n") : text;
|
|
50
|
-
}
|
|
51
|
-
function fromJsonLines(jsonLines) {
|
|
52
|
-
const unifiedNewLines = toUnixNewlines(jsonLines).trim();
|
|
53
|
-
return JSON.parse(`[${unifiedNewLines.split("\n").join(",")}]`);
|
|
54
|
-
}
|
|
55
|
-
function capitalize(text) {
|
|
56
|
-
return `${text.charAt(0).toLocaleUpperCase()}${text.slice(
|
|
57
|
-
1
|
|
58
|
-
)}`;
|
|
59
|
-
}
|
|
60
|
-
function apostrophize(text, upperCase) {
|
|
61
|
-
const lastCharMatch = text.match(/(\w)\W*$/);
|
|
62
|
-
const lastChar = lastCharMatch?.[1] ?? "";
|
|
63
|
-
return `${text}'${lastChar.toLocaleLowerCase() === "s" ? "" : upperCase ? "S" : "s"}`;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// packages/utils/src/lib/table.ts
|
|
67
|
-
function rowToStringArray({ rows, columns = [] }) {
|
|
68
|
-
if (Array.isArray(rows.at(0)) && typeof columns.at(0) === "object") {
|
|
69
|
-
throw new TypeError(
|
|
70
|
-
"Column can`t be object when rows are primitive values"
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
return rows.map((row) => {
|
|
74
|
-
if (Array.isArray(row)) {
|
|
75
|
-
return row.map(String);
|
|
76
|
-
}
|
|
77
|
-
const objectRow = row;
|
|
78
|
-
if (columns.length === 0 || typeof columns.at(0) === "string") {
|
|
79
|
-
return Object.values(objectRow).map(String);
|
|
80
|
-
}
|
|
81
|
-
return columns.map(
|
|
82
|
-
({ key }) => String(objectRow[key])
|
|
83
|
-
);
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
function columnsToStringArray({ rows, columns = [] }) {
|
|
87
|
-
const firstRow = rows.at(0);
|
|
88
|
-
const primitiveRows = Array.isArray(firstRow);
|
|
89
|
-
if (typeof columns.at(0) === "string" && !primitiveRows) {
|
|
90
|
-
throw new Error("invalid union type. Caught by model parsing.");
|
|
91
|
-
}
|
|
92
|
-
if (columns.length === 0) {
|
|
93
|
-
if (Array.isArray(firstRow)) {
|
|
94
|
-
return firstRow.map((_, idx) => String(idx));
|
|
95
|
-
}
|
|
96
|
-
return Object.keys(firstRow);
|
|
97
|
-
}
|
|
98
|
-
if (typeof columns.at(0) === "string") {
|
|
99
|
-
return columns.map(String);
|
|
100
|
-
}
|
|
101
|
-
const cols = columns;
|
|
102
|
-
return cols.map(({ label, key }) => label ?? capitalize(key));
|
|
103
|
-
}
|
|
104
|
-
function getColumnAlignmentForKeyAndIndex(targetKey, targetIdx, columns = []) {
|
|
105
|
-
const column = columns.at(targetIdx) ?? columns.find((col) => col.key === targetKey);
|
|
106
|
-
if (typeof column === "string") {
|
|
107
|
-
return column;
|
|
108
|
-
} else if (typeof column === "object") {
|
|
109
|
-
return column.align ?? "center";
|
|
110
|
-
} else {
|
|
111
|
-
return "center";
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
function getColumnAlignmentForIndex(targetIdx, columns = []) {
|
|
115
|
-
const column = columns.at(targetIdx);
|
|
116
|
-
if (column == null) {
|
|
117
|
-
return "center";
|
|
118
|
-
} else if (typeof column === "string") {
|
|
119
|
-
return column;
|
|
120
|
-
} else if (typeof column === "object") {
|
|
121
|
-
return column.align ?? "center";
|
|
122
|
-
} else {
|
|
123
|
-
return "center";
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
function getColumnAlignments({
|
|
127
|
-
rows,
|
|
128
|
-
columns = []
|
|
129
|
-
}) {
|
|
130
|
-
if (rows.at(0) == null) {
|
|
131
|
-
throw new Error("first row can`t be undefined.");
|
|
132
|
-
}
|
|
133
|
-
if (Array.isArray(rows.at(0))) {
|
|
134
|
-
const firstPrimitiveRow = rows.at(0);
|
|
135
|
-
return Array.from({ length: firstPrimitiveRow.length }).map(
|
|
136
|
-
(_, idx) => getColumnAlignmentForIndex(idx, columns)
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
const firstObject = rows.at(0);
|
|
140
|
-
return Object.keys(firstObject).map(
|
|
141
|
-
(key, idx) => getColumnAlignmentForKeyAndIndex(key, idx, columns)
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// packages/utils/src/lib/text-formats/html/table.ts
|
|
146
|
-
function wrap(elem, content) {
|
|
147
|
-
return `<${elem}>${content}</${elem}>${NEW_LINE}`;
|
|
148
|
-
}
|
|
149
|
-
function wrapRow(content) {
|
|
150
|
-
const elem = "tr";
|
|
151
|
-
return `<${elem}>${NEW_LINE}${content}</${elem}>${NEW_LINE}`;
|
|
152
|
-
}
|
|
153
|
-
function table(tableData) {
|
|
154
|
-
if (tableData.rows.length === 0) {
|
|
155
|
-
throw new Error("Data can't be empty");
|
|
156
|
-
}
|
|
157
|
-
const tableHeaderCols = columnsToStringArray(tableData).map((s) => wrap("th", s)).join("");
|
|
158
|
-
const tableHeaderRow = wrapRow(tableHeaderCols);
|
|
159
|
-
const tableBody = rowToStringArray(tableData).map((arr) => {
|
|
160
|
-
const columns = arr.map((s) => wrap("td", s)).join("");
|
|
161
|
-
return wrapRow(columns);
|
|
162
|
-
}).join("");
|
|
163
|
-
return wrap("table", `${NEW_LINE}${tableHeaderRow}${tableBody}`);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// packages/utils/src/lib/text-formats/md/font-style.ts
|
|
167
|
-
var boldWrap = "**";
|
|
168
|
-
function bold2(text) {
|
|
169
|
-
return `${boldWrap}${text}${boldWrap}`;
|
|
170
|
-
}
|
|
171
|
-
var italicWrap = "_";
|
|
172
|
-
function italic2(text) {
|
|
173
|
-
return `${italicWrap}${text}${italicWrap}`;
|
|
174
|
-
}
|
|
175
|
-
var strikeThroughWrap = "~";
|
|
176
|
-
function strikeThrough(text) {
|
|
177
|
-
return `${strikeThroughWrap}${text}${strikeThroughWrap}`;
|
|
178
|
-
}
|
|
179
|
-
var codeWrap = "`";
|
|
180
|
-
function code2(text) {
|
|
181
|
-
return `${codeWrap}${text}${codeWrap}`;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// packages/utils/src/lib/text-formats/md/headline.ts
|
|
185
|
-
function headline(text, hierarchy = 1) {
|
|
186
|
-
return `${"#".repeat(hierarchy)} ${text}${NEW_LINE}`;
|
|
187
|
-
}
|
|
188
|
-
function h(text, hierarchy = 1) {
|
|
189
|
-
return headline(text, hierarchy);
|
|
190
|
-
}
|
|
191
|
-
function h1(text) {
|
|
192
|
-
return headline(text, 1);
|
|
193
|
-
}
|
|
194
|
-
function h2(text) {
|
|
195
|
-
return headline(text, 2);
|
|
196
|
-
}
|
|
197
|
-
function h3(text) {
|
|
198
|
-
return headline(text, 3);
|
|
199
|
-
}
|
|
200
|
-
function h4(text) {
|
|
201
|
-
return headline(text, 4);
|
|
202
|
-
}
|
|
203
|
-
function h5(text) {
|
|
204
|
-
return headline(text, 5);
|
|
205
|
-
}
|
|
206
|
-
function h6(text) {
|
|
207
|
-
return headline(text, 6);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// packages/utils/src/lib/text-formats/md/image.ts
|
|
211
|
-
function image(src, alt) {
|
|
212
|
-
return ``;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// packages/utils/src/lib/text-formats/md/link.ts
|
|
216
|
-
function link2(href, text) {
|
|
217
|
-
return `[${text || href}](${href})`;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// packages/utils/src/lib/text-formats/md/list.ts
|
|
221
|
-
function li(text, order = "unordered") {
|
|
222
|
-
const style = order === "unordered" ? "-" : "- [ ]";
|
|
223
|
-
return `${style} ${text}`;
|
|
224
|
-
}
|
|
225
|
-
function indentation(text, level = 1) {
|
|
226
|
-
return `${TAB.repeat(level)}${text}`;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// packages/utils/src/lib/text-formats/md/paragraphs.ts
|
|
230
|
-
function paragraphs(...sections) {
|
|
231
|
-
return sections.filter(Boolean).join(`${NEW_LINE}${NEW_LINE}`);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// packages/utils/src/lib/text-formats/md/section.ts
|
|
235
|
-
function section(...contents) {
|
|
236
|
-
return `${lines(...contents)}${NEW_LINE}`;
|
|
237
|
-
}
|
|
238
|
-
function lines(...contents) {
|
|
239
|
-
return `${contents.filter(Boolean).join(NEW_LINE)}`;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// packages/utils/src/lib/text-formats/md/table.ts
|
|
243
|
-
var alignString = /* @__PURE__ */ new Map([
|
|
244
|
-
["left", ":--"],
|
|
245
|
-
["center", ":--:"],
|
|
246
|
-
["right", "--:"]
|
|
247
|
-
]);
|
|
248
|
-
function tableRow(rows) {
|
|
249
|
-
return `|${rows.join("|")}|`;
|
|
250
|
-
}
|
|
251
|
-
function table2(data) {
|
|
252
|
-
if (data.rows.length === 0) {
|
|
253
|
-
throw new Error("Data can't be empty");
|
|
254
|
-
}
|
|
255
|
-
const alignmentRow = getColumnAlignments(data).map(
|
|
256
|
-
(s) => alignString.get(s) ?? String(alignString.get("center"))
|
|
257
|
-
);
|
|
258
|
-
return section(
|
|
259
|
-
`${lines(
|
|
260
|
-
tableRow(columnsToStringArray(data)),
|
|
261
|
-
tableRow(alignmentRow),
|
|
262
|
-
...rowToStringArray(data).map(tableRow)
|
|
263
|
-
)}`
|
|
264
|
-
);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// packages/utils/src/lib/text-formats/index.ts
|
|
268
|
-
var md = {
|
|
269
|
-
bold: bold2,
|
|
270
|
-
italic: italic2,
|
|
271
|
-
strikeThrough,
|
|
272
|
-
code: code2,
|
|
273
|
-
link: link2,
|
|
274
|
-
image,
|
|
275
|
-
headline,
|
|
276
|
-
h,
|
|
277
|
-
h1,
|
|
278
|
-
h2,
|
|
279
|
-
h3,
|
|
280
|
-
h4,
|
|
281
|
-
h5,
|
|
282
|
-
h6,
|
|
283
|
-
indentation,
|
|
284
|
-
lines,
|
|
285
|
-
li,
|
|
286
|
-
section,
|
|
287
|
-
paragraphs,
|
|
288
|
-
table: table2
|
|
289
|
-
};
|
|
290
|
-
var html = {
|
|
291
|
-
bold,
|
|
292
|
-
italic,
|
|
293
|
-
code,
|
|
294
|
-
link,
|
|
295
|
-
details,
|
|
296
|
-
table
|
|
297
|
-
};
|
|
298
|
-
|
|
299
5
|
// packages/models/src/lib/implementation/schemas.ts
|
|
300
6
|
import { MATERIAL_ICONS } from "vscode-material-icons";
|
|
301
7
|
import { z } from "zod";
|
|
@@ -405,6 +111,7 @@ var fileNameSchema = z.string().trim().regex(filenameRegex, {
|
|
|
405
111
|
}).min(1, { message: "file name is invalid" });
|
|
406
112
|
var positiveIntSchema = z.number().int().positive();
|
|
407
113
|
var nonnegativeIntSchema = z.number().int().nonnegative();
|
|
114
|
+
var nonnegativeNumberSchema = z.number().nonnegative();
|
|
408
115
|
function packageVersionSchema(options) {
|
|
409
116
|
const { versionDescription = "NPM version of the package", required } = options ?? {};
|
|
410
117
|
const packageSchema = z.string({ description: "NPM package name" });
|
|
@@ -417,7 +124,7 @@ function packageVersionSchema(options) {
|
|
|
417
124
|
{ description: "NPM package name and version of a published package" }
|
|
418
125
|
);
|
|
419
126
|
}
|
|
420
|
-
var weightSchema =
|
|
127
|
+
var weightSchema = nonnegativeNumberSchema.describe(
|
|
421
128
|
"Coefficient for the given score (use weight 0 if only for display)"
|
|
422
129
|
);
|
|
423
130
|
function weightedRefSchema(description, slugDescription) {
|
|
@@ -559,7 +266,7 @@ var tableObjectSchema = tableSharedSchema.merge(
|
|
|
559
266
|
var tableSchema = (description = "Table information") => z4.union([tablePrimitiveSchema, tableObjectSchema], { description });
|
|
560
267
|
|
|
561
268
|
// packages/models/src/lib/audit-output.ts
|
|
562
|
-
var auditValueSchema =
|
|
269
|
+
var auditValueSchema = nonnegativeNumberSchema.describe("Raw numeric value");
|
|
563
270
|
var auditDisplayValueSchema = z5.string({ description: "Formatted value (e.g. '0.9 s', '2.1 MB')" }).optional();
|
|
564
271
|
var auditDetailsSchema = z5.object(
|
|
565
272
|
{
|
|
@@ -1004,79 +711,394 @@ function pluralize(text, amount) {
|
|
|
1004
711
|
if (amount != null && Math.abs(amount) === 1) {
|
|
1005
712
|
return text;
|
|
1006
713
|
}
|
|
1007
|
-
if (text.endsWith("y")) {
|
|
1008
|
-
return `${text.slice(0, -1)}ies`;
|
|
714
|
+
if (text.endsWith("y")) {
|
|
715
|
+
return `${text.slice(0, -1)}ies`;
|
|
716
|
+
}
|
|
717
|
+
if (text.endsWith("s")) {
|
|
718
|
+
return `${text}es`;
|
|
719
|
+
}
|
|
720
|
+
return `${text}s`;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
// packages/utils/src/lib/guards.ts
|
|
724
|
+
function isPromiseFulfilledResult(result) {
|
|
725
|
+
return result.status === "fulfilled";
|
|
726
|
+
}
|
|
727
|
+
function isPromiseRejectedResult(result) {
|
|
728
|
+
return result.status === "rejected";
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// packages/utils/src/lib/logging.ts
|
|
732
|
+
import isaacs_cliui from "@isaacs/cliui";
|
|
733
|
+
import { cliui } from "@poppinss/cliui";
|
|
734
|
+
import chalk from "chalk";
|
|
735
|
+
|
|
736
|
+
// packages/utils/src/lib/reports/constants.ts
|
|
737
|
+
var TERMINAL_WIDTH = 80;
|
|
738
|
+
|
|
739
|
+
// packages/utils/src/lib/logging.ts
|
|
740
|
+
var singletonUiInstance;
|
|
741
|
+
function ui() {
|
|
742
|
+
if (singletonUiInstance === void 0) {
|
|
743
|
+
singletonUiInstance = cliui();
|
|
744
|
+
}
|
|
745
|
+
return {
|
|
746
|
+
...singletonUiInstance,
|
|
747
|
+
row: (args) => {
|
|
748
|
+
logListItem(args);
|
|
749
|
+
}
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
var singletonisaacUi;
|
|
753
|
+
function logListItem(args) {
|
|
754
|
+
if (singletonisaacUi === void 0) {
|
|
755
|
+
singletonisaacUi = isaacs_cliui({ width: TERMINAL_WIDTH });
|
|
756
|
+
}
|
|
757
|
+
singletonisaacUi.div(...args);
|
|
758
|
+
const content = singletonisaacUi.toString();
|
|
759
|
+
singletonisaacUi.rows = [];
|
|
760
|
+
singletonUiInstance?.logger.log(content);
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// packages/utils/src/lib/file-system.ts
|
|
764
|
+
async function readTextFile(path) {
|
|
765
|
+
const buffer = await readFile(path);
|
|
766
|
+
return buffer.toString();
|
|
767
|
+
}
|
|
768
|
+
async function readJsonFile(path) {
|
|
769
|
+
const text = await readTextFile(path);
|
|
770
|
+
return JSON.parse(text);
|
|
771
|
+
}
|
|
772
|
+
async function ensureDirectoryExists(baseDir) {
|
|
773
|
+
try {
|
|
774
|
+
await mkdir(baseDir, { recursive: true });
|
|
775
|
+
return;
|
|
776
|
+
} catch (error) {
|
|
777
|
+
ui().logger.info(error.message);
|
|
778
|
+
if (error.code !== "EEXIST") {
|
|
779
|
+
throw error;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
function pluginWorkDir(slug) {
|
|
784
|
+
return join("node_modules", ".code-pushup", slug);
|
|
785
|
+
}
|
|
786
|
+
async function crawlFileSystem(options) {
|
|
787
|
+
const {
|
|
788
|
+
directory,
|
|
789
|
+
pattern,
|
|
790
|
+
fileTransform = (filePath) => filePath
|
|
791
|
+
} = options;
|
|
792
|
+
const files = await readdir(directory);
|
|
793
|
+
const promises = files.map(async (file) => {
|
|
794
|
+
const filePath = join(directory, file);
|
|
795
|
+
const stats = await stat(filePath);
|
|
796
|
+
if (stats.isDirectory()) {
|
|
797
|
+
return crawlFileSystem({ directory: filePath, pattern, fileTransform });
|
|
798
|
+
}
|
|
799
|
+
if (stats.isFile() && (!pattern || new RegExp(pattern).test(file))) {
|
|
800
|
+
return fileTransform(filePath);
|
|
801
|
+
}
|
|
802
|
+
return [];
|
|
803
|
+
});
|
|
804
|
+
const resultsNestedArray = await Promise.all(promises);
|
|
805
|
+
return resultsNestedArray.flat();
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
// packages/utils/src/lib/text-formats/constants.ts
|
|
809
|
+
var NEW_LINE = "\n";
|
|
810
|
+
var TAB = " ";
|
|
811
|
+
|
|
812
|
+
// packages/utils/src/lib/text-formats/html/details.ts
|
|
813
|
+
function details(title, content, cfg = { open: false }) {
|
|
814
|
+
return `<details${cfg.open ? " open" : ""}>${NEW_LINE}<summary>${title}</summary>${NEW_LINE}${// ⚠️ The blank line is needed to ensure Markdown in content is rendered correctly.
|
|
815
|
+
NEW_LINE}${content}${NEW_LINE}${// @TODO in the future we could consider adding it only if the content ends with a code block
|
|
816
|
+
// ⚠️ The blank line ensure Markdown in content is rendered correctly.
|
|
817
|
+
NEW_LINE}</details>${// ⚠️ The blank line is needed to ensure Markdown after details is rendered correctly.
|
|
818
|
+
NEW_LINE}`;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
// packages/utils/src/lib/text-formats/html/font-style.ts
|
|
822
|
+
var boldElement = "b";
|
|
823
|
+
function bold(text) {
|
|
824
|
+
return `<${boldElement}>${text}</${boldElement}>`;
|
|
825
|
+
}
|
|
826
|
+
var italicElement = "i";
|
|
827
|
+
function italic(text) {
|
|
828
|
+
return `<${italicElement}>${text}</${italicElement}>`;
|
|
829
|
+
}
|
|
830
|
+
var codeElement = "code";
|
|
831
|
+
function code(text) {
|
|
832
|
+
return `<${codeElement}>${text}</${codeElement}>`;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// packages/utils/src/lib/text-formats/html/link.ts
|
|
836
|
+
function link(href, text) {
|
|
837
|
+
return `<a href="${href}">${text || href}"</a>`;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// packages/utils/src/lib/transform.ts
|
|
841
|
+
import { platform } from "node:os";
|
|
842
|
+
function objectToKeys(obj) {
|
|
843
|
+
return Object.keys(obj);
|
|
844
|
+
}
|
|
845
|
+
function objectToEntries(obj) {
|
|
846
|
+
return Object.entries(obj);
|
|
847
|
+
}
|
|
848
|
+
function objectFromEntries(entries) {
|
|
849
|
+
return Object.fromEntries(entries);
|
|
850
|
+
}
|
|
851
|
+
function toUnixNewlines(text) {
|
|
852
|
+
return platform() === "win32" ? text.replace(/\r\n/g, "\n") : text;
|
|
853
|
+
}
|
|
854
|
+
function fromJsonLines(jsonLines) {
|
|
855
|
+
const unifiedNewLines = toUnixNewlines(jsonLines).trim();
|
|
856
|
+
return JSON.parse(`[${unifiedNewLines.split("\n").join(",")}]`);
|
|
857
|
+
}
|
|
858
|
+
function capitalize(text) {
|
|
859
|
+
return `${text.charAt(0).toLocaleUpperCase()}${text.slice(
|
|
860
|
+
1
|
|
861
|
+
)}`;
|
|
862
|
+
}
|
|
863
|
+
function apostrophize(text, upperCase) {
|
|
864
|
+
const lastCharMatch = text.match(/(\w)\W*$/);
|
|
865
|
+
const lastChar = lastCharMatch?.[1] ?? "";
|
|
866
|
+
return `${text}'${lastChar.toLocaleLowerCase() === "s" ? "" : upperCase ? "S" : "s"}`;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
// packages/utils/src/lib/table.ts
|
|
870
|
+
function rowToStringArray({ rows, columns = [] }) {
|
|
871
|
+
if (Array.isArray(rows.at(0)) && typeof columns.at(0) === "object") {
|
|
872
|
+
throw new TypeError(
|
|
873
|
+
"Column can`t be object when rows are primitive values"
|
|
874
|
+
);
|
|
875
|
+
}
|
|
876
|
+
return rows.map((row) => {
|
|
877
|
+
if (Array.isArray(row)) {
|
|
878
|
+
return row.map(String);
|
|
879
|
+
}
|
|
880
|
+
const objectRow = row;
|
|
881
|
+
if (columns.length === 0 || typeof columns.at(0) === "string") {
|
|
882
|
+
return Object.values(objectRow).map(String);
|
|
883
|
+
}
|
|
884
|
+
return columns.map(
|
|
885
|
+
({ key }) => String(objectRow[key])
|
|
886
|
+
);
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
function columnsToStringArray({ rows, columns = [] }) {
|
|
890
|
+
const firstRow = rows.at(0);
|
|
891
|
+
const primitiveRows = Array.isArray(firstRow);
|
|
892
|
+
if (typeof columns.at(0) === "string" && !primitiveRows) {
|
|
893
|
+
throw new Error("invalid union type. Caught by model parsing.");
|
|
894
|
+
}
|
|
895
|
+
if (columns.length === 0) {
|
|
896
|
+
if (Array.isArray(firstRow)) {
|
|
897
|
+
return firstRow.map((_, idx) => String(idx));
|
|
898
|
+
}
|
|
899
|
+
return Object.keys(firstRow);
|
|
900
|
+
}
|
|
901
|
+
if (typeof columns.at(0) === "string") {
|
|
902
|
+
return columns.map(String);
|
|
903
|
+
}
|
|
904
|
+
const cols = columns;
|
|
905
|
+
return cols.map(({ label, key }) => label ?? capitalize(key));
|
|
906
|
+
}
|
|
907
|
+
function getColumnAlignmentForKeyAndIndex(targetKey, targetIdx, columns = []) {
|
|
908
|
+
const column = columns.at(targetIdx) ?? columns.find((col) => col.key === targetKey);
|
|
909
|
+
if (typeof column === "string") {
|
|
910
|
+
return column;
|
|
911
|
+
} else if (typeof column === "object") {
|
|
912
|
+
return column.align ?? "center";
|
|
913
|
+
} else {
|
|
914
|
+
return "center";
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
function getColumnAlignmentForIndex(targetIdx, columns = []) {
|
|
918
|
+
const column = columns.at(targetIdx);
|
|
919
|
+
if (column == null) {
|
|
920
|
+
return "center";
|
|
921
|
+
} else if (typeof column === "string") {
|
|
922
|
+
return column;
|
|
923
|
+
} else if (typeof column === "object") {
|
|
924
|
+
return column.align ?? "center";
|
|
925
|
+
} else {
|
|
926
|
+
return "center";
|
|
1009
927
|
}
|
|
1010
|
-
|
|
1011
|
-
|
|
928
|
+
}
|
|
929
|
+
function getColumnAlignments({
|
|
930
|
+
rows,
|
|
931
|
+
columns = []
|
|
932
|
+
}) {
|
|
933
|
+
if (rows.at(0) == null) {
|
|
934
|
+
throw new Error("first row can`t be undefined.");
|
|
1012
935
|
}
|
|
1013
|
-
|
|
936
|
+
if (Array.isArray(rows.at(0))) {
|
|
937
|
+
const firstPrimitiveRow = rows.at(0);
|
|
938
|
+
return Array.from({ length: firstPrimitiveRow.length }).map(
|
|
939
|
+
(_, idx) => getColumnAlignmentForIndex(idx, columns)
|
|
940
|
+
);
|
|
941
|
+
}
|
|
942
|
+
const firstObject = rows.at(0);
|
|
943
|
+
return Object.keys(firstObject).map(
|
|
944
|
+
(key, idx) => getColumnAlignmentForKeyAndIndex(key, idx, columns)
|
|
945
|
+
);
|
|
1014
946
|
}
|
|
1015
947
|
|
|
1016
|
-
// packages/utils/src/lib/
|
|
1017
|
-
function
|
|
1018
|
-
return
|
|
948
|
+
// packages/utils/src/lib/text-formats/html/table.ts
|
|
949
|
+
function wrap(elem, content) {
|
|
950
|
+
return `<${elem}>${content}</${elem}>${NEW_LINE}`;
|
|
1019
951
|
}
|
|
1020
|
-
function
|
|
1021
|
-
|
|
952
|
+
function wrapRow(content) {
|
|
953
|
+
const elem = "tr";
|
|
954
|
+
return `<${elem}>${NEW_LINE}${content}</${elem}>${NEW_LINE}`;
|
|
955
|
+
}
|
|
956
|
+
function table(tableData) {
|
|
957
|
+
if (tableData.rows.length === 0) {
|
|
958
|
+
throw new Error("Data can't be empty");
|
|
959
|
+
}
|
|
960
|
+
const tableHeaderCols = columnsToStringArray(tableData).map((s) => wrap("th", s)).join("");
|
|
961
|
+
const tableHeaderRow = wrapRow(tableHeaderCols);
|
|
962
|
+
const tableBody = rowToStringArray(tableData).map((arr) => {
|
|
963
|
+
const columns = arr.map((s) => wrap("td", s)).join("");
|
|
964
|
+
return wrapRow(columns);
|
|
965
|
+
}).join("");
|
|
966
|
+
return wrap("table", `${NEW_LINE}${tableHeaderRow}${tableBody}`);
|
|
1022
967
|
}
|
|
1023
968
|
|
|
1024
|
-
// packages/utils/src/lib/
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
969
|
+
// packages/utils/src/lib/text-formats/md/font-style.ts
|
|
970
|
+
var boldWrap = "**";
|
|
971
|
+
function bold2(text) {
|
|
972
|
+
return `${boldWrap}${text}${boldWrap}`;
|
|
973
|
+
}
|
|
974
|
+
var italicWrap = "_";
|
|
975
|
+
function italic2(text) {
|
|
976
|
+
return `${italicWrap}${text}${italicWrap}`;
|
|
977
|
+
}
|
|
978
|
+
var strikeThroughWrap = "~";
|
|
979
|
+
function strikeThrough(text) {
|
|
980
|
+
return `${strikeThroughWrap}${text}${strikeThroughWrap}`;
|
|
981
|
+
}
|
|
982
|
+
var codeWrap = "`";
|
|
983
|
+
function code2(text) {
|
|
984
|
+
return `${codeWrap}${text}${codeWrap}`;
|
|
985
|
+
}
|
|
1028
986
|
|
|
1029
|
-
// packages/utils/src/lib/
|
|
1030
|
-
|
|
987
|
+
// packages/utils/src/lib/text-formats/md/headline.ts
|
|
988
|
+
function headline(text, hierarchy = 1) {
|
|
989
|
+
return `${"#".repeat(hierarchy)} ${text}${NEW_LINE}`;
|
|
990
|
+
}
|
|
991
|
+
function h(text, hierarchy = 1) {
|
|
992
|
+
return headline(text, hierarchy);
|
|
993
|
+
}
|
|
994
|
+
function h1(text) {
|
|
995
|
+
return headline(text, 1);
|
|
996
|
+
}
|
|
997
|
+
function h2(text) {
|
|
998
|
+
return headline(text, 2);
|
|
999
|
+
}
|
|
1000
|
+
function h3(text) {
|
|
1001
|
+
return headline(text, 3);
|
|
1002
|
+
}
|
|
1003
|
+
function h4(text) {
|
|
1004
|
+
return headline(text, 4);
|
|
1005
|
+
}
|
|
1006
|
+
function h5(text) {
|
|
1007
|
+
return headline(text, 5);
|
|
1008
|
+
}
|
|
1009
|
+
function h6(text) {
|
|
1010
|
+
return headline(text, 6);
|
|
1011
|
+
}
|
|
1031
1012
|
|
|
1032
|
-
// packages/utils/src/lib/
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
if (singletonUiInstance === void 0) {
|
|
1036
|
-
singletonUiInstance = cliui();
|
|
1037
|
-
}
|
|
1038
|
-
return {
|
|
1039
|
-
...singletonUiInstance,
|
|
1040
|
-
row: (args) => {
|
|
1041
|
-
logListItem(args);
|
|
1042
|
-
}
|
|
1043
|
-
};
|
|
1013
|
+
// packages/utils/src/lib/text-formats/md/image.ts
|
|
1014
|
+
function image(src, alt) {
|
|
1015
|
+
return ``;
|
|
1044
1016
|
}
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
}
|
|
1050
|
-
singletonisaacUi.div(...args);
|
|
1051
|
-
const content = singletonisaacUi.toString();
|
|
1052
|
-
singletonisaacUi.rows = [];
|
|
1053
|
-
singletonUiInstance?.logger.log(content);
|
|
1017
|
+
|
|
1018
|
+
// packages/utils/src/lib/text-formats/md/link.ts
|
|
1019
|
+
function link2(href, text) {
|
|
1020
|
+
return `[${text || href}](${href})`;
|
|
1054
1021
|
}
|
|
1055
1022
|
|
|
1056
|
-
// packages/utils/src/lib/
|
|
1057
|
-
|
|
1058
|
-
const
|
|
1059
|
-
return
|
|
1023
|
+
// packages/utils/src/lib/text-formats/md/list.ts
|
|
1024
|
+
function li(text, order = "unordered") {
|
|
1025
|
+
const style = order === "unordered" ? "-" : "- [ ]";
|
|
1026
|
+
return `${style} ${text}`;
|
|
1060
1027
|
}
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
return JSON.parse(text);
|
|
1028
|
+
function indentation(text, level = 1) {
|
|
1029
|
+
return `${TAB.repeat(level)}${text}`;
|
|
1064
1030
|
}
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
} catch (error) {
|
|
1070
|
-
ui().logger.info(error.message);
|
|
1071
|
-
if (error.code !== "EEXIST") {
|
|
1072
|
-
throw error;
|
|
1073
|
-
}
|
|
1074
|
-
}
|
|
1031
|
+
|
|
1032
|
+
// packages/utils/src/lib/text-formats/md/paragraphs.ts
|
|
1033
|
+
function paragraphs(...sections) {
|
|
1034
|
+
return sections.filter(Boolean).join(`${NEW_LINE}${NEW_LINE}`);
|
|
1075
1035
|
}
|
|
1076
|
-
|
|
1077
|
-
|
|
1036
|
+
|
|
1037
|
+
// packages/utils/src/lib/text-formats/md/section.ts
|
|
1038
|
+
function section(...contents) {
|
|
1039
|
+
return `${lines(...contents)}${NEW_LINE}`;
|
|
1040
|
+
}
|
|
1041
|
+
function lines(...contents) {
|
|
1042
|
+
return `${contents.filter(Boolean).join(NEW_LINE)}`;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
// packages/utils/src/lib/text-formats/md/table.ts
|
|
1046
|
+
var alignString = /* @__PURE__ */ new Map([
|
|
1047
|
+
["left", ":--"],
|
|
1048
|
+
["center", ":--:"],
|
|
1049
|
+
["right", "--:"]
|
|
1050
|
+
]);
|
|
1051
|
+
function tableRow(rows) {
|
|
1052
|
+
return `|${rows.join("|")}|`;
|
|
1053
|
+
}
|
|
1054
|
+
function table2(data) {
|
|
1055
|
+
if (data.rows.length === 0) {
|
|
1056
|
+
throw new Error("Data can't be empty");
|
|
1057
|
+
}
|
|
1058
|
+
const alignmentRow = getColumnAlignments(data).map(
|
|
1059
|
+
(s) => alignString.get(s) ?? String(alignString.get("center"))
|
|
1060
|
+
);
|
|
1061
|
+
return section(
|
|
1062
|
+
`${lines(
|
|
1063
|
+
tableRow(columnsToStringArray(data)),
|
|
1064
|
+
tableRow(alignmentRow),
|
|
1065
|
+
...rowToStringArray(data).map(tableRow)
|
|
1066
|
+
)}`
|
|
1067
|
+
);
|
|
1078
1068
|
}
|
|
1079
1069
|
|
|
1070
|
+
// packages/utils/src/lib/text-formats/index.ts
|
|
1071
|
+
var md = {
|
|
1072
|
+
bold: bold2,
|
|
1073
|
+
italic: italic2,
|
|
1074
|
+
strikeThrough,
|
|
1075
|
+
code: code2,
|
|
1076
|
+
link: link2,
|
|
1077
|
+
image,
|
|
1078
|
+
headline,
|
|
1079
|
+
h,
|
|
1080
|
+
h1,
|
|
1081
|
+
h2,
|
|
1082
|
+
h3,
|
|
1083
|
+
h4,
|
|
1084
|
+
h5,
|
|
1085
|
+
h6,
|
|
1086
|
+
indentation,
|
|
1087
|
+
lines,
|
|
1088
|
+
li,
|
|
1089
|
+
section,
|
|
1090
|
+
paragraphs,
|
|
1091
|
+
table: table2
|
|
1092
|
+
};
|
|
1093
|
+
var html = {
|
|
1094
|
+
bold,
|
|
1095
|
+
italic,
|
|
1096
|
+
code,
|
|
1097
|
+
link,
|
|
1098
|
+
details,
|
|
1099
|
+
table
|
|
1100
|
+
};
|
|
1101
|
+
|
|
1080
1102
|
// packages/utils/src/lib/reports/utils.ts
|
|
1081
1103
|
var { image: image2, bold: boldMd } = md;
|
|
1082
1104
|
function calcDuration(start, stop) {
|
|
@@ -1194,6 +1216,12 @@ var packageManagerIdSchema = z16.enum([
|
|
|
1194
1216
|
"yarn-modern",
|
|
1195
1217
|
"pnpm"
|
|
1196
1218
|
]);
|
|
1219
|
+
var packageJsonPathSchema = z16.union([
|
|
1220
|
+
z16.array(z16.string()).min(1),
|
|
1221
|
+
z16.object({ autoSearch: z16.literal(true) })
|
|
1222
|
+
]).describe(
|
|
1223
|
+
"File paths to package.json. Looks only at root package.json by default"
|
|
1224
|
+
).default(["package.json"]);
|
|
1197
1225
|
var packageAuditLevels = [
|
|
1198
1226
|
"critical",
|
|
1199
1227
|
"high",
|
|
@@ -1221,9 +1249,20 @@ var jsPackagesPluginConfigSchema = z16.object({
|
|
|
1221
1249
|
dependencyGroups: z16.array(dependencyGroupSchema).min(1).default(["prod", "dev"]),
|
|
1222
1250
|
auditLevelMapping: z16.record(packageAuditLevelSchema, issueSeveritySchema, {
|
|
1223
1251
|
description: "Mapping of audit levels to issue severity. Custom mapping or overrides may be entered manually, otherwise has a default preset."
|
|
1224
|
-
}).default(defaultAuditLevelMapping).transform(fillAuditLevelMapping)
|
|
1252
|
+
}).default(defaultAuditLevelMapping).transform(fillAuditLevelMapping),
|
|
1253
|
+
packageJsonPaths: packageJsonPathSchema
|
|
1225
1254
|
});
|
|
1226
1255
|
|
|
1256
|
+
// packages/plugin-js-packages/src/lib/runner/utils.ts
|
|
1257
|
+
import { sep } from "node:path";
|
|
1258
|
+
|
|
1259
|
+
// packages/plugin-js-packages/src/lib/runner/outdated/types.ts
|
|
1260
|
+
var dependencyGroupLong = [
|
|
1261
|
+
"dependencies",
|
|
1262
|
+
"devDependencies",
|
|
1263
|
+
"optionalDependencies"
|
|
1264
|
+
];
|
|
1265
|
+
|
|
1227
1266
|
// packages/plugin-js-packages/src/lib/runner/utils.ts
|
|
1228
1267
|
function filterAuditResult(result, key, referenceResult) {
|
|
1229
1268
|
if (result.vulnerabilities.length === 0) {
|
|
@@ -1255,6 +1294,37 @@ function filterAuditResult(result, key, referenceResult) {
|
|
|
1255
1294
|
summary: uniqueResult.summary
|
|
1256
1295
|
};
|
|
1257
1296
|
}
|
|
1297
|
+
async function findAllPackageJson() {
|
|
1298
|
+
return (await crawlFileSystem({
|
|
1299
|
+
directory: ".",
|
|
1300
|
+
pattern: /(^|[\\/])package\.json$/
|
|
1301
|
+
})).filter(
|
|
1302
|
+
(path) => !path.startsWith(`node_modules${sep}`) && !path.includes(`${sep}node_modules${sep}`) && !path.startsWith(`.nx${sep}`)
|
|
1303
|
+
);
|
|
1304
|
+
}
|
|
1305
|
+
async function getTotalDependencies(packageJsonPaths) {
|
|
1306
|
+
const parsedDeps = await Promise.all(
|
|
1307
|
+
packageJsonPaths.map(readJsonFile)
|
|
1308
|
+
);
|
|
1309
|
+
const mergedDeps = parsedDeps.reduce(
|
|
1310
|
+
(acc, depMapper) => objectFromEntries(
|
|
1311
|
+
dependencyGroupLong.map((group) => {
|
|
1312
|
+
const deps = depMapper[group];
|
|
1313
|
+
return [
|
|
1314
|
+
group,
|
|
1315
|
+
[...acc[group], ...deps == null ? [] : objectToKeys(deps)]
|
|
1316
|
+
];
|
|
1317
|
+
})
|
|
1318
|
+
),
|
|
1319
|
+
{ dependencies: [], devDependencies: [], optionalDependencies: [] }
|
|
1320
|
+
);
|
|
1321
|
+
return objectFromEntries(
|
|
1322
|
+
objectToKeys(mergedDeps).map((deps) => [
|
|
1323
|
+
deps,
|
|
1324
|
+
new Set(mergedDeps[deps]).size
|
|
1325
|
+
])
|
|
1326
|
+
);
|
|
1327
|
+
}
|
|
1258
1328
|
|
|
1259
1329
|
// packages/plugin-js-packages/src/lib/package-managers/constants.ts
|
|
1260
1330
|
var COMMON_AUDIT_ARGS = ["audit", "--json"];
|
|
@@ -1793,7 +1863,7 @@ var outdatedSeverity = {
|
|
|
1793
1863
|
var RELEASE_TYPES = objectToKeys(outdatedSeverity);
|
|
1794
1864
|
|
|
1795
1865
|
// packages/plugin-js-packages/src/lib/runner/outdated/transform.ts
|
|
1796
|
-
function outdatedResultToAuditOutput(result, packageManager, depGroup) {
|
|
1866
|
+
function outdatedResultToAuditOutput(result, packageManager, depGroup, totalDeps) {
|
|
1797
1867
|
const relevantDependencies = result.filter(
|
|
1798
1868
|
(dep) => dep.type === dependencyGroupToLong[depGroup]
|
|
1799
1869
|
);
|
|
@@ -1817,10 +1887,7 @@ function outdatedResultToAuditOutput(result, packageManager, depGroup) {
|
|
|
1817
1887
|
const issues = outdatedDependencies.length === 0 ? [] : outdatedToIssues(outdatedDependencies);
|
|
1818
1888
|
return {
|
|
1819
1889
|
slug: `${packageManager}-outdated-${depGroup}`,
|
|
1820
|
-
score: calculateOutdatedScore(
|
|
1821
|
-
outdatedStats.major,
|
|
1822
|
-
relevantDependencies.length
|
|
1823
|
-
),
|
|
1890
|
+
score: calculateOutdatedScore(outdatedStats.major, totalDeps),
|
|
1824
1891
|
value: outdatedDependencies.length,
|
|
1825
1892
|
displayValue: outdatedToDisplayValue(outdatedStats),
|
|
1826
1893
|
details: { issues }
|
|
@@ -1865,29 +1932,40 @@ async function executeRunner() {
|
|
|
1865
1932
|
packageManager,
|
|
1866
1933
|
checks,
|
|
1867
1934
|
auditLevelMapping,
|
|
1935
|
+
packageJsonPaths,
|
|
1868
1936
|
dependencyGroups: depGroups
|
|
1869
1937
|
} = await readJsonFile(PLUGIN_CONFIG_PATH);
|
|
1870
|
-
const auditResults = checks.includes("audit") ? await processAudit(packageManager,
|
|
1871
|
-
const outdatedResults = checks.includes("outdated") ? await processOutdated(packageManager, depGroups) : [];
|
|
1938
|
+
const auditResults = checks.includes("audit") ? await processAudit(packageManager, depGroups, auditLevelMapping) : [];
|
|
1939
|
+
const outdatedResults = checks.includes("outdated") ? await processOutdated(packageManager, depGroups, packageJsonPaths) : [];
|
|
1872
1940
|
const checkResults = [...auditResults, ...outdatedResults];
|
|
1873
1941
|
await ensureDirectoryExists(dirname(RUNNER_OUTPUT_PATH));
|
|
1874
1942
|
await writeFile(RUNNER_OUTPUT_PATH, JSON.stringify(checkResults));
|
|
1875
1943
|
}
|
|
1876
|
-
async function processOutdated(id, depGroups) {
|
|
1944
|
+
async function processOutdated(id, depGroups, packageJsonPaths) {
|
|
1877
1945
|
const pm = packageManagers[id];
|
|
1878
|
-
const { stdout } = await executeProcess({
|
|
1946
|
+
const { stdout, stderr } = await executeProcess({
|
|
1879
1947
|
command: pm.command,
|
|
1880
1948
|
args: pm.outdated.commandArgs,
|
|
1881
1949
|
cwd: process.cwd(),
|
|
1882
1950
|
ignoreExitCode: true
|
|
1883
1951
|
// outdated returns exit code 1 when outdated dependencies are found
|
|
1884
1952
|
});
|
|
1953
|
+
if (stderr) {
|
|
1954
|
+
throw new Error(`JS packages plugin: outdated error: ${stderr}`);
|
|
1955
|
+
}
|
|
1956
|
+
const finalPaths = Array.isArray(packageJsonPaths) ? packageJsonPaths : await findAllPackageJson();
|
|
1957
|
+
const depTotals = await getTotalDependencies(finalPaths);
|
|
1885
1958
|
const normalizedResult = pm.outdated.unifyResult(stdout);
|
|
1886
1959
|
return depGroups.map(
|
|
1887
|
-
(depGroup) => outdatedResultToAuditOutput(
|
|
1960
|
+
(depGroup) => outdatedResultToAuditOutput(
|
|
1961
|
+
normalizedResult,
|
|
1962
|
+
id,
|
|
1963
|
+
depGroup,
|
|
1964
|
+
depTotals[dependencyGroupToLong[depGroup]]
|
|
1965
|
+
)
|
|
1888
1966
|
);
|
|
1889
1967
|
}
|
|
1890
|
-
async function processAudit(id,
|
|
1968
|
+
async function processAudit(id, depGroups, auditLevelMapping) {
|
|
1891
1969
|
const pm = packageManagers[id];
|
|
1892
1970
|
const supportedAuditDepGroups = pm.audit.supportedDepGroups ?? dependencyGroups;
|
|
1893
1971
|
const compatibleAuditDepGroups = depGroups.filter(
|
|
@@ -1896,12 +1974,15 @@ async function processAudit(id, auditLevelMapping, depGroups) {
|
|
|
1896
1974
|
const auditResults = await Promise.allSettled(
|
|
1897
1975
|
compatibleAuditDepGroups.map(
|
|
1898
1976
|
async (depGroup) => {
|
|
1899
|
-
const { stdout } = await executeProcess({
|
|
1977
|
+
const { stdout, stderr } = await executeProcess({
|
|
1900
1978
|
command: pm.command,
|
|
1901
1979
|
args: pm.audit.getCommandArgs(depGroup),
|
|
1902
1980
|
cwd: process.cwd(),
|
|
1903
1981
|
ignoreExitCode: pm.audit.ignoreExitCode
|
|
1904
1982
|
});
|
|
1983
|
+
if (stderr) {
|
|
1984
|
+
throw new Error(`JS packages plugin: audit error: ${stderr}`);
|
|
1985
|
+
}
|
|
1905
1986
|
return [depGroup, pm.audit.unifyResult(stdout)];
|
|
1906
1987
|
}
|
|
1907
1988
|
)
|
package/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { fileURLToPath } from "node:url";
|
|
|
4
4
|
|
|
5
5
|
// packages/plugin-js-packages/package.json
|
|
6
6
|
var name = "@code-pushup/js-packages-plugin";
|
|
7
|
-
var version = "0.
|
|
7
|
+
var version = "0.45.1";
|
|
8
8
|
|
|
9
9
|
// packages/plugin-js-packages/src/lib/config.ts
|
|
10
10
|
import { z as z16 } from "zod";
|
|
@@ -118,6 +118,7 @@ var fileNameSchema = z.string().trim().regex(filenameRegex, {
|
|
|
118
118
|
}).min(1, { message: "file name is invalid" });
|
|
119
119
|
var positiveIntSchema = z.number().int().positive();
|
|
120
120
|
var nonnegativeIntSchema = z.number().int().nonnegative();
|
|
121
|
+
var nonnegativeNumberSchema = z.number().nonnegative();
|
|
121
122
|
function packageVersionSchema(options) {
|
|
122
123
|
const { versionDescription = "NPM version of the package", required } = options ?? {};
|
|
123
124
|
const packageSchema = z.string({ description: "NPM package name" });
|
|
@@ -130,7 +131,7 @@ function packageVersionSchema(options) {
|
|
|
130
131
|
{ description: "NPM package name and version of a published package" }
|
|
131
132
|
);
|
|
132
133
|
}
|
|
133
|
-
var weightSchema =
|
|
134
|
+
var weightSchema = nonnegativeNumberSchema.describe(
|
|
134
135
|
"Coefficient for the given score (use weight 0 if only for display)"
|
|
135
136
|
);
|
|
136
137
|
function weightedRefSchema(description, slugDescription) {
|
|
@@ -272,7 +273,7 @@ var tableObjectSchema = tableSharedSchema.merge(
|
|
|
272
273
|
var tableSchema = (description = "Table information") => z4.union([tablePrimitiveSchema, tableObjectSchema], { description });
|
|
273
274
|
|
|
274
275
|
// packages/models/src/lib/audit-output.ts
|
|
275
|
-
var auditValueSchema =
|
|
276
|
+
var auditValueSchema = nonnegativeNumberSchema.describe("Raw numeric value");
|
|
276
277
|
var auditDisplayValueSchema = z5.string({ description: "Formatted value (e.g. '0.9 s', '2.1 MB')" }).optional();
|
|
277
278
|
var auditDetailsSchema = z5.object(
|
|
278
279
|
{
|
|
@@ -737,6 +738,12 @@ var packageManagerIdSchema = z16.enum([
|
|
|
737
738
|
"yarn-modern",
|
|
738
739
|
"pnpm"
|
|
739
740
|
]);
|
|
741
|
+
var packageJsonPathSchema = z16.union([
|
|
742
|
+
z16.array(z16.string()).min(1),
|
|
743
|
+
z16.object({ autoSearch: z16.literal(true) })
|
|
744
|
+
]).describe(
|
|
745
|
+
"File paths to package.json. Looks only at root package.json by default"
|
|
746
|
+
).default(["package.json"]);
|
|
740
747
|
var packageAuditLevels = [
|
|
741
748
|
"critical",
|
|
742
749
|
"high",
|
|
@@ -764,9 +771,67 @@ var jsPackagesPluginConfigSchema = z16.object({
|
|
|
764
771
|
dependencyGroups: z16.array(dependencyGroupSchema).min(1).default(["prod", "dev"]),
|
|
765
772
|
auditLevelMapping: z16.record(packageAuditLevelSchema, issueSeveritySchema, {
|
|
766
773
|
description: "Mapping of audit levels to issue severity. Custom mapping or overrides may be entered manually, otherwise has a default preset."
|
|
767
|
-
}).default(defaultAuditLevelMapping).transform(fillAuditLevelMapping)
|
|
774
|
+
}).default(defaultAuditLevelMapping).transform(fillAuditLevelMapping),
|
|
775
|
+
packageJsonPaths: packageJsonPathSchema
|
|
768
776
|
});
|
|
769
777
|
|
|
778
|
+
// packages/utils/src/lib/file-system.ts
|
|
779
|
+
import { bundleRequire } from "bundle-require";
|
|
780
|
+
import chalk2 from "chalk";
|
|
781
|
+
import { mkdir, readFile, readdir, rm, stat } from "node:fs/promises";
|
|
782
|
+
import { join } from "node:path";
|
|
783
|
+
|
|
784
|
+
// packages/utils/src/lib/logging.ts
|
|
785
|
+
import isaacs_cliui from "@isaacs/cliui";
|
|
786
|
+
import { cliui } from "@poppinss/cliui";
|
|
787
|
+
import chalk from "chalk";
|
|
788
|
+
|
|
789
|
+
// packages/utils/src/lib/reports/constants.ts
|
|
790
|
+
var TERMINAL_WIDTH = 80;
|
|
791
|
+
|
|
792
|
+
// packages/utils/src/lib/logging.ts
|
|
793
|
+
var singletonUiInstance;
|
|
794
|
+
function ui() {
|
|
795
|
+
if (singletonUiInstance === void 0) {
|
|
796
|
+
singletonUiInstance = cliui();
|
|
797
|
+
}
|
|
798
|
+
return {
|
|
799
|
+
...singletonUiInstance,
|
|
800
|
+
row: (args) => {
|
|
801
|
+
logListItem(args);
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
var singletonisaacUi;
|
|
806
|
+
function logListItem(args) {
|
|
807
|
+
if (singletonisaacUi === void 0) {
|
|
808
|
+
singletonisaacUi = isaacs_cliui({ width: TERMINAL_WIDTH });
|
|
809
|
+
}
|
|
810
|
+
singletonisaacUi.div(...args);
|
|
811
|
+
const content = singletonisaacUi.toString();
|
|
812
|
+
singletonisaacUi.rows = [];
|
|
813
|
+
singletonUiInstance?.logger.log(content);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// packages/utils/src/lib/file-system.ts
|
|
817
|
+
async function ensureDirectoryExists(baseDir) {
|
|
818
|
+
try {
|
|
819
|
+
await mkdir(baseDir, { recursive: true });
|
|
820
|
+
return;
|
|
821
|
+
} catch (error) {
|
|
822
|
+
ui().logger.info(error.message);
|
|
823
|
+
if (error.code !== "EEXIST") {
|
|
824
|
+
throw error;
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
function pluginWorkDir(slug) {
|
|
829
|
+
return join("node_modules", ".code-pushup", slug);
|
|
830
|
+
}
|
|
831
|
+
function filePathToCliArg(path) {
|
|
832
|
+
return `"${path}"`;
|
|
833
|
+
}
|
|
834
|
+
|
|
770
835
|
// packages/utils/src/lib/text-formats/constants.ts
|
|
771
836
|
var NEW_LINE = "\n";
|
|
772
837
|
var TAB = " ";
|
|
@@ -1056,60 +1121,6 @@ var html = {
|
|
|
1056
1121
|
table
|
|
1057
1122
|
};
|
|
1058
1123
|
|
|
1059
|
-
// packages/utils/src/lib/file-system.ts
|
|
1060
|
-
import { bundleRequire } from "bundle-require";
|
|
1061
|
-
import chalk2 from "chalk";
|
|
1062
|
-
import { mkdir, readFile, readdir, rm, stat } from "node:fs/promises";
|
|
1063
|
-
import { join } from "node:path";
|
|
1064
|
-
|
|
1065
|
-
// packages/utils/src/lib/logging.ts
|
|
1066
|
-
import isaacs_cliui from "@isaacs/cliui";
|
|
1067
|
-
import { cliui } from "@poppinss/cliui";
|
|
1068
|
-
import chalk from "chalk";
|
|
1069
|
-
|
|
1070
|
-
// packages/utils/src/lib/reports/constants.ts
|
|
1071
|
-
var TERMINAL_WIDTH = 80;
|
|
1072
|
-
|
|
1073
|
-
// packages/utils/src/lib/logging.ts
|
|
1074
|
-
var singletonUiInstance;
|
|
1075
|
-
function ui() {
|
|
1076
|
-
if (singletonUiInstance === void 0) {
|
|
1077
|
-
singletonUiInstance = cliui();
|
|
1078
|
-
}
|
|
1079
|
-
return {
|
|
1080
|
-
...singletonUiInstance,
|
|
1081
|
-
row: (args) => {
|
|
1082
|
-
logListItem(args);
|
|
1083
|
-
}
|
|
1084
|
-
};
|
|
1085
|
-
}
|
|
1086
|
-
var singletonisaacUi;
|
|
1087
|
-
function logListItem(args) {
|
|
1088
|
-
if (singletonisaacUi === void 0) {
|
|
1089
|
-
singletonisaacUi = isaacs_cliui({ width: TERMINAL_WIDTH });
|
|
1090
|
-
}
|
|
1091
|
-
singletonisaacUi.div(...args);
|
|
1092
|
-
const content = singletonisaacUi.toString();
|
|
1093
|
-
singletonisaacUi.rows = [];
|
|
1094
|
-
singletonUiInstance?.logger.log(content);
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
// packages/utils/src/lib/file-system.ts
|
|
1098
|
-
async function ensureDirectoryExists(baseDir) {
|
|
1099
|
-
try {
|
|
1100
|
-
await mkdir(baseDir, { recursive: true });
|
|
1101
|
-
return;
|
|
1102
|
-
} catch (error) {
|
|
1103
|
-
ui().logger.info(error.message);
|
|
1104
|
-
if (error.code !== "EEXIST") {
|
|
1105
|
-
throw error;
|
|
1106
|
-
}
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
function pluginWorkDir(slug) {
|
|
1110
|
-
return join("node_modules", ".code-pushup", slug);
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
1124
|
// packages/utils/src/lib/reports/utils.ts
|
|
1114
1125
|
var { image: image2, bold: boldMd } = md;
|
|
1115
1126
|
|
|
@@ -1667,7 +1678,7 @@ async function createRunnerConfig(scriptPath, config) {
|
|
|
1667
1678
|
await writeFile(PLUGIN_CONFIG_PATH, JSON.stringify(config));
|
|
1668
1679
|
return {
|
|
1669
1680
|
command: "node",
|
|
1670
|
-
args: [scriptPath],
|
|
1681
|
+
args: [filePathToCliArg(scriptPath)],
|
|
1671
1682
|
outputFile: RUNNER_OUTPUT_PATH
|
|
1672
1683
|
};
|
|
1673
1684
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-pushup/js-packages-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.45.1",
|
|
4
4
|
"dependencies": {
|
|
5
|
-
"@code-pushup/models": "0.
|
|
6
|
-
"@code-pushup/utils": "0.
|
|
5
|
+
"@code-pushup/models": "0.45.1",
|
|
6
|
+
"@code-pushup/utils": "0.45.1",
|
|
7
7
|
"semver": "^7.6.0",
|
|
8
8
|
"zod": "^3.22.4"
|
|
9
9
|
},
|
package/src/lib/config.d.ts
CHANGED
|
@@ -6,6 +6,14 @@ declare const packageCommandSchema: z.ZodEnum<["audit", "outdated"]>;
|
|
|
6
6
|
export type PackageCommand = z.infer<typeof packageCommandSchema>;
|
|
7
7
|
declare const packageManagerIdSchema: z.ZodEnum<["npm", "yarn-classic", "yarn-modern", "pnpm"]>;
|
|
8
8
|
export type PackageManagerId = z.infer<typeof packageManagerIdSchema>;
|
|
9
|
+
declare const packageJsonPathSchema: z.ZodDefault<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodObject<{
|
|
10
|
+
autoSearch: z.ZodLiteral<true>;
|
|
11
|
+
}, "strip", z.ZodTypeAny, {
|
|
12
|
+
autoSearch: true;
|
|
13
|
+
}, {
|
|
14
|
+
autoSearch: true;
|
|
15
|
+
}>]>>;
|
|
16
|
+
export type PackageJsonPaths = z.infer<typeof packageJsonPathSchema>;
|
|
9
17
|
export declare const packageAuditLevels: readonly ["critical", "high", "moderate", "low", "info"];
|
|
10
18
|
declare const packageAuditLevelSchema: z.ZodEnum<["critical", "high", "moderate", "low", "info"]>;
|
|
11
19
|
export type PackageAuditLevel = z.infer<typeof packageAuditLevelSchema>;
|
|
@@ -16,16 +24,31 @@ export declare const jsPackagesPluginConfigSchema: z.ZodObject<{
|
|
|
16
24
|
packageManager: z.ZodEnum<["npm", "yarn-classic", "yarn-modern", "pnpm"]>;
|
|
17
25
|
dependencyGroups: z.ZodDefault<z.ZodArray<z.ZodEnum<["prod", "dev", "optional"]>, "many">>;
|
|
18
26
|
auditLevelMapping: z.ZodEffects<z.ZodDefault<z.ZodRecord<z.ZodEnum<["critical", "high", "moderate", "low", "info"]>, z.ZodEnum<["info", "warning", "error"]>>>, AuditSeverity, Partial<Record<"info" | "critical" | "high" | "moderate" | "low", "error" | "info" | "warning">> | undefined>;
|
|
27
|
+
packageJsonPaths: z.ZodDefault<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodObject<{
|
|
28
|
+
autoSearch: z.ZodLiteral<true>;
|
|
29
|
+
}, "strip", z.ZodTypeAny, {
|
|
30
|
+
autoSearch: true;
|
|
31
|
+
}, {
|
|
32
|
+
autoSearch: true;
|
|
33
|
+
}>]>>;
|
|
19
34
|
}, "strip", z.ZodTypeAny, {
|
|
20
35
|
checks: ("audit" | "outdated")[];
|
|
21
36
|
packageManager: "npm" | "pnpm" | "yarn-classic" | "yarn-modern";
|
|
22
37
|
dependencyGroups: ("prod" | "dev" | "optional")[];
|
|
23
38
|
auditLevelMapping: AuditSeverity;
|
|
39
|
+
packageJsonPaths: (string[] | {
|
|
40
|
+
autoSearch: true;
|
|
41
|
+
}) & (string[] | {
|
|
42
|
+
autoSearch: true;
|
|
43
|
+
} | undefined);
|
|
24
44
|
}, {
|
|
25
45
|
packageManager: "npm" | "pnpm" | "yarn-classic" | "yarn-modern";
|
|
26
46
|
checks?: ("audit" | "outdated")[] | undefined;
|
|
27
47
|
dependencyGroups?: ("prod" | "dev" | "optional")[] | undefined;
|
|
28
48
|
auditLevelMapping?: Partial<Record<"info" | "critical" | "high" | "moderate" | "low", "error" | "info" | "warning">> | undefined;
|
|
49
|
+
packageJsonPaths?: string[] | {
|
|
50
|
+
autoSearch: true;
|
|
51
|
+
} | undefined;
|
|
29
52
|
}>;
|
|
30
53
|
export type JSPackagesPluginConfig = z.input<typeof jsPackagesPluginConfigSchema>;
|
|
31
54
|
export type FinalJSPackagesPluginConfig = z.infer<typeof jsPackagesPluginConfigSchema>;
|
|
@@ -2,7 +2,7 @@ import { ReleaseType } from 'semver';
|
|
|
2
2
|
import type { AuditOutput, Issue } from '@code-pushup/models';
|
|
3
3
|
import { DependencyGroup, PackageManagerId } from '../../config';
|
|
4
4
|
import { OutdatedResult } from './types';
|
|
5
|
-
export declare function outdatedResultToAuditOutput(result: OutdatedResult, packageManager: PackageManagerId, depGroup: DependencyGroup): AuditOutput;
|
|
5
|
+
export declare function outdatedResultToAuditOutput(result: OutdatedResult, packageManager: PackageManagerId, depGroup: DependencyGroup, totalDeps: number): AuditOutput;
|
|
6
6
|
export declare function calculateOutdatedScore(majorOutdated: number, totalDeps: number): number;
|
|
7
7
|
export declare function outdatedToDisplayValue(stats: Record<ReleaseType, number>): string;
|
|
8
8
|
export declare function outdatedToIssues(dependencies: OutdatedResult): Issue[];
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { ReleaseType } from 'semver';
|
|
2
2
|
export type PackageVersion = Record<ReleaseType, number>;
|
|
3
|
-
export
|
|
3
|
+
export declare const dependencyGroupLong: readonly ["dependencies", "devDependencies", "optionalDependencies"];
|
|
4
|
+
export type DependencyGroupLong = (typeof dependencyGroupLong)[number];
|
|
5
|
+
type PackageJsonDependencies = Record<string, string>;
|
|
6
|
+
export type PackageJson = Partial<Record<DependencyGroupLong, PackageJsonDependencies>>;
|
|
7
|
+
export type DependencyTotals = Record<DependencyGroupLong, number>;
|
|
4
8
|
export type OutdatedDependency = {
|
|
5
9
|
name: string;
|
|
6
10
|
current: string;
|
|
@@ -9,3 +13,4 @@ export type OutdatedDependency = {
|
|
|
9
13
|
url?: string;
|
|
10
14
|
};
|
|
11
15
|
export type OutdatedResult = OutdatedDependency[];
|
|
16
|
+
export {};
|
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
import { AuditResult, Vulnerability } from './audit/types';
|
|
2
|
+
import { DependencyTotals } from './outdated/types';
|
|
2
3
|
export declare function filterAuditResult(result: AuditResult, key: keyof Vulnerability, referenceResult?: AuditResult): AuditResult;
|
|
4
|
+
export declare function findAllPackageJson(): Promise<string[]>;
|
|
5
|
+
export declare function getTotalDependencies(packageJsonPaths: string[]): Promise<DependencyTotals>;
|