@code-pushup/js-packages-plugin 0.55.0 → 0.57.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.
Files changed (115) hide show
  1. package/README.md +4 -4
  2. package/package.json +8 -7
  3. package/src/bin.js +3 -0
  4. package/src/bin.js.map +1 -0
  5. package/src/index.d.ts +2 -2
  6. package/src/index.js +3 -0
  7. package/src/index.js.map +1 -0
  8. package/src/lib/config.d.ts +4 -4
  9. package/src/lib/config.js +59 -0
  10. package/src/lib/config.js.map +1 -0
  11. package/src/lib/constants.d.ts +2 -2
  12. package/src/lib/constants.js +25 -0
  13. package/src/lib/constants.js.map +1 -0
  14. package/src/lib/js-packages-plugin.d.ts +1 -1
  15. package/src/lib/js-packages-plugin.js +101 -0
  16. package/src/lib/js-packages-plugin.js.map +1 -0
  17. package/src/lib/package-managers/constants.js +3 -0
  18. package/src/lib/package-managers/constants.js.map +1 -0
  19. package/src/lib/package-managers/derive-package-manager.d.ts +2 -2
  20. package/src/lib/package-managers/derive-package-manager.js +43 -0
  21. package/src/lib/package-managers/derive-package-manager.js.map +1 -0
  22. package/src/lib/package-managers/derive-yarn.js +16 -0
  23. package/src/lib/package-managers/derive-yarn.js.map +1 -0
  24. package/src/lib/package-managers/npm/audit-result.d.ts +2 -2
  25. package/src/lib/package-managers/npm/audit-result.js +65 -0
  26. package/src/lib/package-managers/npm/audit-result.js.map +1 -0
  27. package/src/lib/package-managers/npm/npm.d.ts +1 -1
  28. package/src/lib/package-managers/npm/npm.js +49 -0
  29. package/src/lib/package-managers/npm/npm.js.map +1 -0
  30. package/src/lib/package-managers/npm/outdated-result.d.ts +1 -1
  31. package/src/lib/package-managers/npm/outdated-result.js +16 -0
  32. package/src/lib/package-managers/npm/outdated-result.js.map +1 -0
  33. package/src/lib/package-managers/npm/types.d.ts +3 -3
  34. package/src/lib/package-managers/npm/types.js +2 -0
  35. package/src/lib/package-managers/npm/types.js.map +1 -0
  36. package/src/lib/package-managers/package-managers.d.ts +2 -2
  37. package/src/lib/package-managers/package-managers.js +11 -0
  38. package/src/lib/package-managers/package-managers.js.map +1 -0
  39. package/src/lib/package-managers/pnpm/audit-result.d.ts +1 -1
  40. package/src/lib/package-managers/pnpm/audit-result.js +34 -0
  41. package/src/lib/package-managers/pnpm/audit-result.js.map +1 -0
  42. package/src/lib/package-managers/pnpm/outdated-result.d.ts +1 -1
  43. package/src/lib/package-managers/pnpm/outdated-result.js +12 -0
  44. package/src/lib/package-managers/pnpm/outdated-result.js.map +1 -0
  45. package/src/lib/package-managers/pnpm/pnpm.d.ts +1 -1
  46. package/src/lib/package-managers/pnpm/pnpm.js +49 -0
  47. package/src/lib/package-managers/pnpm/pnpm.js.map +1 -0
  48. package/src/lib/package-managers/pnpm/types.d.ts +2 -2
  49. package/src/lib/package-managers/pnpm/types.js +2 -0
  50. package/src/lib/package-managers/pnpm/types.js.map +1 -0
  51. package/src/lib/package-managers/pnpm/utils.js +5 -0
  52. package/src/lib/package-managers/pnpm/utils.js.map +1 -0
  53. package/src/lib/package-managers/types.d.ts +3 -3
  54. package/src/lib/package-managers/types.js +2 -0
  55. package/src/lib/package-managers/types.js.map +1 -0
  56. package/src/lib/package-managers/yarn-classic/audit-result.d.ts +1 -1
  57. package/src/lib/package-managers/yarn-classic/audit-result.js +36 -0
  58. package/src/lib/package-managers/yarn-classic/audit-result.js.map +1 -0
  59. package/src/lib/package-managers/yarn-classic/constants.d.ts +2 -2
  60. package/src/lib/package-managers/yarn-classic/constants.js +14 -0
  61. package/src/lib/package-managers/yarn-classic/constants.js.map +1 -0
  62. package/src/lib/package-managers/yarn-classic/outdated-result.d.ts +1 -1
  63. package/src/lib/package-managers/yarn-classic/outdated-result.js +39 -0
  64. package/src/lib/package-managers/yarn-classic/outdated-result.js.map +1 -0
  65. package/src/lib/package-managers/yarn-classic/types.d.ts +1 -1
  66. package/src/lib/package-managers/yarn-classic/types.js +8 -0
  67. package/src/lib/package-managers/yarn-classic/types.js.map +1 -0
  68. package/src/lib/package-managers/yarn-classic/yarn-classic.d.ts +1 -1
  69. package/src/lib/package-managers/yarn-classic/yarn-classic.js +29 -0
  70. package/src/lib/package-managers/yarn-classic/yarn-classic.js.map +1 -0
  71. package/src/lib/package-managers/yarn-modern/audit-result.d.ts +1 -1
  72. package/src/lib/package-managers/yarn-modern/audit-result.js +25 -0
  73. package/src/lib/package-managers/yarn-modern/audit-result.js.map +1 -0
  74. package/src/lib/package-managers/yarn-modern/outdated-result.d.ts +1 -1
  75. package/src/lib/package-managers/yarn-modern/outdated-result.js +10 -0
  76. package/src/lib/package-managers/yarn-modern/outdated-result.js.map +1 -0
  77. package/src/lib/package-managers/yarn-modern/types.d.ts +2 -2
  78. package/src/lib/package-managers/yarn-modern/types.js +2 -0
  79. package/src/lib/package-managers/yarn-modern/types.js.map +1 -0
  80. package/src/lib/package-managers/yarn-modern/yarn-modern.d.ts +1 -1
  81. package/src/lib/package-managers/yarn-modern/yarn-modern.js +36 -0
  82. package/src/lib/package-managers/yarn-modern/yarn-modern.js.map +1 -0
  83. package/src/lib/runner/audit/constants.d.ts +1 -1
  84. package/src/lib/runner/audit/constants.js +10 -0
  85. package/src/lib/runner/audit/constants.js.map +1 -0
  86. package/src/lib/runner/audit/transform.d.ts +2 -2
  87. package/src/lib/runner/audit/transform.js +63 -0
  88. package/src/lib/runner/audit/transform.js.map +1 -0
  89. package/src/lib/runner/audit/types.d.ts +1 -1
  90. package/src/lib/runner/audit/types.js +2 -0
  91. package/src/lib/runner/audit/types.js.map +1 -0
  92. package/src/lib/runner/audit/utils.d.ts +1 -1
  93. package/src/lib/runner/audit/utils.js +4 -0
  94. package/src/lib/runner/audit/utils.js.map +1 -0
  95. package/src/lib/runner/constants.js +6 -0
  96. package/src/lib/runner/constants.js.map +1 -0
  97. package/src/lib/runner/index.d.ts +1 -1
  98. package/src/lib/runner/index.js +82 -0
  99. package/src/lib/runner/index.js.map +1 -0
  100. package/src/lib/runner/outdated/constants.js +13 -0
  101. package/src/lib/runner/outdated/constants.js.map +1 -0
  102. package/src/lib/runner/outdated/transform.d.ts +2 -2
  103. package/src/lib/runner/outdated/transform.js +60 -0
  104. package/src/lib/runner/outdated/transform.js.map +1 -0
  105. package/src/lib/runner/outdated/types.js +6 -0
  106. package/src/lib/runner/outdated/types.js.map +1 -0
  107. package/src/lib/runner/utils.d.ts +2 -2
  108. package/src/lib/runner/utils.js +56 -0
  109. package/src/lib/runner/utils.js.map +1 -0
  110. package/src/lib/utils.d.ts +3 -3
  111. package/src/lib/utils.js +17 -0
  112. package/src/lib/utils.js.map +1 -0
  113. package/bin.js +0 -1759
  114. package/index.js +0 -1651
  115. package/src/lib/package-managers/index.d.ts +0 -2
package/bin.js DELETED
@@ -1,1759 +0,0 @@
1
- // packages/plugin-js-packages/src/lib/runner/index.ts
2
- import { writeFile } from "node:fs/promises";
3
- import { dirname as dirname2 } from "node:path";
4
-
5
- // packages/models/src/lib/implementation/schemas.ts
6
- import { MATERIAL_ICONS } from "vscode-material-icons";
7
- import { z } from "zod";
8
-
9
- // packages/models/src/lib/implementation/limits.ts
10
- var MAX_SLUG_LENGTH = 128;
11
- var MAX_TITLE_LENGTH = 256;
12
- var MAX_DESCRIPTION_LENGTH = 65536;
13
- var MAX_ISSUE_MESSAGE_LENGTH = 1024;
14
-
15
- // packages/models/src/lib/implementation/utils.ts
16
- var slugRegex = /^[a-z\d]+(?:-[a-z\d]+)*$/;
17
- var filenameRegex = /^(?!.*[ \\/:*?"<>|]).+$/;
18
- function hasDuplicateStrings(strings) {
19
- const sortedStrings = strings.toSorted();
20
- const duplStrings = sortedStrings.filter(
21
- (item, index) => index !== 0 && item === sortedStrings[index - 1]
22
- );
23
- return duplStrings.length === 0 ? false : [...new Set(duplStrings)];
24
- }
25
- function hasMissingStrings(toCheck, existing) {
26
- const nonExisting = toCheck.filter((s) => !existing.includes(s));
27
- return nonExisting.length === 0 ? false : nonExisting;
28
- }
29
- function errorItems(items, transform = (itemArr) => itemArr.join(", ")) {
30
- return transform(items || []);
31
- }
32
- function exists(value) {
33
- return value != null;
34
- }
35
- function getMissingRefsForCategories(categories, plugins) {
36
- if (!categories || categories.length === 0) {
37
- return false;
38
- }
39
- const auditRefsFromCategory = categories.flatMap(
40
- ({ refs }) => refs.filter(({ type }) => type === "audit").map(({ plugin, slug }) => `${plugin}/${slug}`)
41
- );
42
- const auditRefsFromPlugins = plugins.flatMap(
43
- ({ audits, slug: pluginSlug }) => audits.map(({ slug }) => `${pluginSlug}/${slug}`)
44
- );
45
- const missingAuditRefs = hasMissingStrings(
46
- auditRefsFromCategory,
47
- auditRefsFromPlugins
48
- );
49
- const groupRefsFromCategory = categories.flatMap(
50
- ({ refs }) => refs.filter(({ type }) => type === "group").map(({ plugin, slug }) => `${plugin}#${slug} (group)`)
51
- );
52
- const groupRefsFromPlugins = plugins.flatMap(
53
- ({ groups, slug: pluginSlug }) => Array.isArray(groups) ? groups.map(({ slug }) => `${pluginSlug}#${slug} (group)`) : []
54
- );
55
- const missingGroupRefs = hasMissingStrings(
56
- groupRefsFromCategory,
57
- groupRefsFromPlugins
58
- );
59
- const missingRefs = [missingAuditRefs, missingGroupRefs].filter((refs) => Array.isArray(refs) && refs.length > 0).flat();
60
- return missingRefs.length > 0 ? missingRefs : false;
61
- }
62
- function missingRefsForCategoriesErrorMsg(categories, plugins) {
63
- const missingRefs = getMissingRefsForCategories(categories, plugins);
64
- return `The following category references need to point to an audit or group: ${errorItems(
65
- missingRefs
66
- )}`;
67
- }
68
-
69
- // packages/models/src/lib/implementation/schemas.ts
70
- var tableCellValueSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]).default(null);
71
- function executionMetaSchema(options = {
72
- descriptionDate: "Execution start date and time",
73
- descriptionDuration: "Execution duration in ms"
74
- }) {
75
- return z.object({
76
- date: z.string({ description: options.descriptionDate }),
77
- duration: z.number({ description: options.descriptionDuration })
78
- });
79
- }
80
- var slugSchema = z.string({ description: "Unique ID (human-readable, URL-safe)" }).regex(slugRegex, {
81
- message: "The slug has to follow the pattern [0-9a-z] followed by multiple optional groups of -[0-9a-z]. e.g. my-slug"
82
- }).max(MAX_SLUG_LENGTH, {
83
- message: `slug can be max ${MAX_SLUG_LENGTH} characters long`
84
- });
85
- var descriptionSchema = z.string({ description: "Description (markdown)" }).max(MAX_DESCRIPTION_LENGTH).optional();
86
- var urlSchema = z.string().url();
87
- var docsUrlSchema = urlSchema.optional().or(z.literal("")).describe("Documentation site");
88
- var titleSchema = z.string({ description: "Descriptive name" }).max(MAX_TITLE_LENGTH);
89
- var scoreSchema = z.number({
90
- description: "Value between 0 and 1"
91
- }).min(0).max(1);
92
- function metaSchema(options) {
93
- const {
94
- descriptionDescription,
95
- titleDescription,
96
- docsUrlDescription,
97
- description
98
- } = options ?? {};
99
- return z.object(
100
- {
101
- title: titleDescription ? titleSchema.describe(titleDescription) : titleSchema,
102
- description: descriptionDescription ? descriptionSchema.describe(descriptionDescription) : descriptionSchema,
103
- docsUrl: docsUrlDescription ? docsUrlSchema.describe(docsUrlDescription) : docsUrlSchema
104
- },
105
- { description }
106
- );
107
- }
108
- var filePathSchema = z.string().trim().min(1, { message: "path is invalid" });
109
- var fileNameSchema = z.string().trim().regex(filenameRegex, {
110
- message: `The filename has to be valid`
111
- }).min(1, { message: "file name is invalid" });
112
- var positiveIntSchema = z.number().int().positive();
113
- var nonnegativeNumberSchema = z.number().nonnegative();
114
- function packageVersionSchema(options) {
115
- const { versionDescription = "NPM version of the package", required } = options ?? {};
116
- const packageSchema = z.string({ description: "NPM package name" });
117
- const versionSchema = z.string({ description: versionDescription });
118
- return z.object(
119
- {
120
- packageName: required ? packageSchema : packageSchema.optional(),
121
- version: required ? versionSchema : versionSchema.optional()
122
- },
123
- { description: "NPM package name and version of a published package" }
124
- );
125
- }
126
- var weightSchema = nonnegativeNumberSchema.describe(
127
- "Coefficient for the given score (use weight 0 if only for display)"
128
- );
129
- function weightedRefSchema(description, slugDescription) {
130
- return z.object(
131
- {
132
- slug: slugSchema.describe(slugDescription),
133
- weight: weightSchema.describe("Weight used to calculate score")
134
- },
135
- { description }
136
- );
137
- }
138
- function scorableSchema(description, refSchema, duplicateCheckFn, duplicateMessageFn) {
139
- return z.object(
140
- {
141
- slug: slugSchema.describe('Human-readable unique ID, e.g. "performance"'),
142
- refs: z.array(refSchema).min(1).refine(
143
- (refs) => !duplicateCheckFn(refs),
144
- (refs) => ({
145
- message: duplicateMessageFn(refs)
146
- })
147
- ).refine(hasNonZeroWeightedRef, () => ({
148
- message: "In a category there has to be at least one ref with weight > 0"
149
- }))
150
- },
151
- { description }
152
- );
153
- }
154
- var materialIconSchema = z.enum(MATERIAL_ICONS, {
155
- description: "Icon from VSCode Material Icons extension"
156
- });
157
- function hasNonZeroWeightedRef(refs) {
158
- return refs.reduce((acc, { weight }) => weight + acc, 0) !== 0;
159
- }
160
-
161
- // packages/models/src/lib/source.ts
162
- import { z as z2 } from "zod";
163
- var sourceFileLocationSchema = z2.object(
164
- {
165
- file: filePathSchema.describe("Relative path to source file in Git repo"),
166
- position: z2.object(
167
- {
168
- startLine: positiveIntSchema.describe("Start line"),
169
- startColumn: positiveIntSchema.describe("Start column").optional(),
170
- endLine: positiveIntSchema.describe("End line").optional(),
171
- endColumn: positiveIntSchema.describe("End column").optional()
172
- },
173
- { description: "Location in file" }
174
- ).optional()
175
- },
176
- { description: "Source file location" }
177
- );
178
-
179
- // packages/models/src/lib/audit.ts
180
- import { z as z3 } from "zod";
181
- var auditSchema = z3.object({
182
- slug: slugSchema.describe("ID (unique within plugin)")
183
- }).merge(
184
- metaSchema({
185
- titleDescription: "Descriptive name",
186
- descriptionDescription: "Description (markdown)",
187
- docsUrlDescription: "Link to documentation (rationale)",
188
- description: "List of scorable metrics for the given plugin"
189
- })
190
- );
191
- var pluginAuditsSchema = z3.array(auditSchema, {
192
- description: "List of audits maintained in a plugin"
193
- }).min(1).refine(
194
- (auditMetadata) => !getDuplicateSlugsInAudits(auditMetadata),
195
- (auditMetadata) => ({
196
- message: duplicateSlugsInAuditsErrorMsg(auditMetadata)
197
- })
198
- );
199
- function duplicateSlugsInAuditsErrorMsg(audits) {
200
- const duplicateRefs = getDuplicateSlugsInAudits(audits);
201
- return `In plugin audits the following slugs are not unique: ${errorItems(
202
- duplicateRefs
203
- )}`;
204
- }
205
- function getDuplicateSlugsInAudits(audits) {
206
- return hasDuplicateStrings(audits.map(({ slug }) => slug));
207
- }
208
-
209
- // packages/models/src/lib/audit-output.ts
210
- import { z as z6 } from "zod";
211
-
212
- // packages/models/src/lib/issue.ts
213
- import { z as z4 } from "zod";
214
- var issueSeveritySchema = z4.enum(["info", "warning", "error"], {
215
- description: "Severity level"
216
- });
217
- var issueSchema = z4.object(
218
- {
219
- message: z4.string({ description: "Descriptive error message" }).max(MAX_ISSUE_MESSAGE_LENGTH),
220
- severity: issueSeveritySchema,
221
- source: sourceFileLocationSchema.optional()
222
- },
223
- { description: "Issue information" }
224
- );
225
-
226
- // packages/models/src/lib/table.ts
227
- import { z as z5 } from "zod";
228
- var tableAlignmentSchema = z5.enum(["left", "center", "right"], {
229
- description: "Cell alignment"
230
- });
231
- var tableColumnObjectSchema = z5.object({
232
- key: z5.string(),
233
- label: z5.string().optional(),
234
- align: tableAlignmentSchema.optional()
235
- });
236
- var tableRowObjectSchema = z5.record(tableCellValueSchema, {
237
- description: "Object row"
238
- });
239
- var tableRowPrimitiveSchema = z5.array(tableCellValueSchema, {
240
- description: "Primitive row"
241
- });
242
- var tableSharedSchema = z5.object({
243
- title: z5.string().optional().describe("Display title for table")
244
- });
245
- var tablePrimitiveSchema = tableSharedSchema.merge(
246
- z5.object(
247
- {
248
- columns: z5.array(tableAlignmentSchema).optional(),
249
- rows: z5.array(tableRowPrimitiveSchema)
250
- },
251
- { description: "Table with primitive rows and optional alignment columns" }
252
- )
253
- );
254
- var tableObjectSchema = tableSharedSchema.merge(
255
- z5.object(
256
- {
257
- columns: z5.union([
258
- z5.array(tableAlignmentSchema),
259
- z5.array(tableColumnObjectSchema)
260
- ]).optional(),
261
- rows: z5.array(tableRowObjectSchema)
262
- },
263
- {
264
- description: "Table with object rows and optional alignment or object columns"
265
- }
266
- )
267
- );
268
- var tableSchema = (description = "Table information") => z5.union([tablePrimitiveSchema, tableObjectSchema], { description });
269
-
270
- // packages/models/src/lib/audit-output.ts
271
- var auditValueSchema = nonnegativeNumberSchema.describe("Raw numeric value");
272
- var auditDisplayValueSchema = z6.string({ description: "Formatted value (e.g. '0.9 s', '2.1 MB')" }).optional();
273
- var auditDetailsSchema = z6.object(
274
- {
275
- issues: z6.array(issueSchema, { description: "List of findings" }).optional(),
276
- table: tableSchema("Table of related findings").optional()
277
- },
278
- { description: "Detailed information" }
279
- );
280
- var auditOutputSchema = z6.object(
281
- {
282
- slug: slugSchema.describe("Reference to audit"),
283
- displayValue: auditDisplayValueSchema,
284
- value: auditValueSchema,
285
- score: scoreSchema,
286
- details: auditDetailsSchema.optional()
287
- },
288
- { description: "Audit information" }
289
- );
290
- var auditOutputsSchema = z6.array(auditOutputSchema, {
291
- description: "List of JSON formatted audit output emitted by the runner process of a plugin"
292
- }).refine(
293
- (audits) => !getDuplicateSlugsInAudits2(audits),
294
- (audits) => ({ message: duplicateSlugsInAuditsErrorMsg2(audits) })
295
- );
296
- function duplicateSlugsInAuditsErrorMsg2(audits) {
297
- const duplicateRefs = getDuplicateSlugsInAudits2(audits);
298
- return `In plugin audits the slugs are not unique: ${errorItems(
299
- duplicateRefs
300
- )}`;
301
- }
302
- function getDuplicateSlugsInAudits2(audits) {
303
- return hasDuplicateStrings(audits.map(({ slug }) => slug));
304
- }
305
-
306
- // packages/models/src/lib/category-config.ts
307
- import { z as z7 } from "zod";
308
- var categoryRefSchema = weightedRefSchema(
309
- "Weighted references to audits and/or groups for the category",
310
- "Slug of an audit or group (depending on `type`)"
311
- ).merge(
312
- z7.object({
313
- type: z7.enum(["audit", "group"], {
314
- description: "Discriminant for reference kind, affects where `slug` is looked up"
315
- }),
316
- plugin: slugSchema.describe(
317
- "Plugin slug (plugin should contain referenced audit or group)"
318
- )
319
- })
320
- );
321
- var categoryConfigSchema = scorableSchema(
322
- "Category with a score calculated from audits and groups from various plugins",
323
- categoryRefSchema,
324
- getDuplicateRefsInCategoryMetrics,
325
- duplicateRefsInCategoryMetricsErrorMsg
326
- ).merge(
327
- metaSchema({
328
- titleDescription: "Category Title",
329
- docsUrlDescription: "Category docs URL",
330
- descriptionDescription: "Category description",
331
- description: "Meta info for category"
332
- })
333
- ).merge(
334
- z7.object({
335
- isBinary: z7.boolean({
336
- description: 'Is this a binary category (i.e. only a perfect score considered a "pass")?'
337
- }).optional()
338
- })
339
- );
340
- function duplicateRefsInCategoryMetricsErrorMsg(metrics) {
341
- const duplicateRefs = getDuplicateRefsInCategoryMetrics(metrics);
342
- return `In the categories, the following audit or group refs are duplicates: ${errorItems(
343
- duplicateRefs
344
- )}`;
345
- }
346
- function getDuplicateRefsInCategoryMetrics(metrics) {
347
- return hasDuplicateStrings(
348
- metrics.map(({ slug, type, plugin }) => `${type} :: ${plugin} / ${slug}`)
349
- );
350
- }
351
- var categoriesSchema = z7.array(categoryConfigSchema, {
352
- description: "Categorization of individual audits"
353
- }).refine(
354
- (categoryCfg) => !getDuplicateSlugCategories(categoryCfg),
355
- (categoryCfg) => ({
356
- message: duplicateSlugCategoriesErrorMsg(categoryCfg)
357
- })
358
- );
359
- function duplicateSlugCategoriesErrorMsg(categories) {
360
- const duplicateStringSlugs = getDuplicateSlugCategories(categories);
361
- return `In the categories, the following slugs are duplicated: ${errorItems(
362
- duplicateStringSlugs
363
- )}`;
364
- }
365
- function getDuplicateSlugCategories(categories) {
366
- return hasDuplicateStrings(categories.map(({ slug }) => slug));
367
- }
368
-
369
- // packages/models/src/lib/commit.ts
370
- import { z as z8 } from "zod";
371
- var commitSchema = z8.object(
372
- {
373
- hash: z8.string({ description: "Commit SHA (full)" }).regex(
374
- /^[\da-f]{40}$/,
375
- "Commit SHA should be a 40-character hexadecimal string"
376
- ),
377
- message: z8.string({ description: "Commit message" }),
378
- date: z8.coerce.date({
379
- description: "Date and time when commit was authored"
380
- }),
381
- author: z8.string({
382
- description: "Commit author name"
383
- }).trim()
384
- },
385
- { description: "Git commit" }
386
- );
387
-
388
- // packages/models/src/lib/core-config.ts
389
- import { z as z14 } from "zod";
390
-
391
- // packages/models/src/lib/persist-config.ts
392
- import { z as z9 } from "zod";
393
- var formatSchema = z9.enum(["json", "md"]);
394
- var persistConfigSchema = z9.object({
395
- outputDir: filePathSchema.describe("Artifacts folder").optional(),
396
- filename: fileNameSchema.describe("Artifacts file name (without extension)").optional(),
397
- format: z9.array(formatSchema).optional()
398
- });
399
-
400
- // packages/models/src/lib/plugin-config.ts
401
- import { z as z12 } from "zod";
402
-
403
- // packages/models/src/lib/group.ts
404
- import { z as z10 } from "zod";
405
- var groupRefSchema = weightedRefSchema(
406
- "Weighted reference to a group",
407
- "Reference slug to a group within this plugin (e.g. 'max-lines')"
408
- );
409
- var groupMetaSchema = metaSchema({
410
- titleDescription: "Descriptive name for the group",
411
- descriptionDescription: "Description of the group (markdown)",
412
- docsUrlDescription: "Group documentation site",
413
- description: "Group metadata"
414
- });
415
- var groupSchema = scorableSchema(
416
- 'A group aggregates a set of audits into a single score which can be referenced from a category. E.g. the group slug "performance" groups audits and can be referenced in a category',
417
- groupRefSchema,
418
- getDuplicateRefsInGroups,
419
- duplicateRefsInGroupsErrorMsg
420
- ).merge(groupMetaSchema);
421
- var groupsSchema = z10.array(groupSchema, {
422
- description: "List of groups"
423
- }).optional().refine(
424
- (groups) => !getDuplicateSlugsInGroups(groups),
425
- (groups) => ({
426
- message: duplicateSlugsInGroupsErrorMsg(groups)
427
- })
428
- );
429
- function duplicateRefsInGroupsErrorMsg(groups) {
430
- const duplicateRefs = getDuplicateRefsInGroups(groups);
431
- return `In plugin groups the following references are not unique: ${errorItems(
432
- duplicateRefs
433
- )}`;
434
- }
435
- function getDuplicateRefsInGroups(groups) {
436
- return hasDuplicateStrings(groups.map(({ slug: ref }) => ref).filter(exists));
437
- }
438
- function duplicateSlugsInGroupsErrorMsg(groups) {
439
- const duplicateRefs = getDuplicateSlugsInGroups(groups);
440
- return `In groups the following slugs are not unique: ${errorItems(
441
- duplicateRefs
442
- )}`;
443
- }
444
- function getDuplicateSlugsInGroups(groups) {
445
- return Array.isArray(groups) ? hasDuplicateStrings(groups.map(({ slug }) => slug)) : false;
446
- }
447
-
448
- // packages/models/src/lib/runner-config.ts
449
- import { z as z11 } from "zod";
450
- var outputTransformSchema = z11.function().args(z11.unknown()).returns(z11.union([auditOutputsSchema, z11.promise(auditOutputsSchema)]));
451
- var runnerConfigSchema = z11.object(
452
- {
453
- command: z11.string({
454
- description: "Shell command to execute"
455
- }),
456
- args: z11.array(z11.string({ description: "Command arguments" })).optional(),
457
- outputFile: filePathSchema.describe("Output path"),
458
- outputTransform: outputTransformSchema.optional()
459
- },
460
- {
461
- description: "How to execute runner"
462
- }
463
- );
464
- var onProgressSchema = z11.function().args(z11.unknown()).returns(z11.void());
465
- var runnerFunctionSchema = z11.function().args(onProgressSchema.optional()).returns(z11.union([auditOutputsSchema, z11.promise(auditOutputsSchema)]));
466
-
467
- // packages/models/src/lib/plugin-config.ts
468
- var pluginMetaSchema = packageVersionSchema().merge(
469
- metaSchema({
470
- titleDescription: "Descriptive name",
471
- descriptionDescription: "Description (markdown)",
472
- docsUrlDescription: "Plugin documentation site",
473
- description: "Plugin metadata"
474
- })
475
- ).merge(
476
- z12.object({
477
- slug: slugSchema.describe("Unique plugin slug within core config"),
478
- icon: materialIconSchema
479
- })
480
- );
481
- var pluginDataSchema = z12.object({
482
- runner: z12.union([runnerConfigSchema, runnerFunctionSchema]),
483
- audits: pluginAuditsSchema,
484
- groups: groupsSchema
485
- });
486
- var pluginConfigSchema = pluginMetaSchema.merge(pluginDataSchema).refine(
487
- (pluginCfg) => !getMissingRefsFromGroups(pluginCfg),
488
- (pluginCfg) => ({
489
- message: missingRefsFromGroupsErrorMsg(pluginCfg)
490
- })
491
- );
492
- function missingRefsFromGroupsErrorMsg(pluginCfg) {
493
- const missingRefs = getMissingRefsFromGroups(pluginCfg);
494
- return `The following group references need to point to an existing audit in this plugin config: ${errorItems(
495
- missingRefs
496
- )}`;
497
- }
498
- function getMissingRefsFromGroups(pluginCfg) {
499
- return hasMissingStrings(
500
- pluginCfg.groups?.flatMap(
501
- ({ refs: audits }) => audits.map(({ slug: ref }) => ref)
502
- ) ?? [],
503
- pluginCfg.audits.map(({ slug }) => slug)
504
- );
505
- }
506
-
507
- // packages/models/src/lib/upload-config.ts
508
- import { z as z13 } from "zod";
509
- var uploadConfigSchema = z13.object({
510
- server: urlSchema.describe("URL of deployed portal API"),
511
- apiKey: z13.string({
512
- description: "API key with write access to portal (use `process.env` for security)"
513
- }),
514
- organization: slugSchema.describe(
515
- "Organization slug from Code PushUp portal"
516
- ),
517
- project: slugSchema.describe("Project slug from Code PushUp portal"),
518
- timeout: z13.number({ description: "Request timeout in minutes (default is 5)" }).positive().int().optional()
519
- });
520
-
521
- // packages/models/src/lib/core-config.ts
522
- var unrefinedCoreConfigSchema = z14.object({
523
- plugins: z14.array(pluginConfigSchema, {
524
- description: "List of plugins to be used (official, community-provided, or custom)"
525
- }).min(1),
526
- /** portal configuration for persisting results */
527
- persist: persistConfigSchema.optional(),
528
- /** portal configuration for uploading results */
529
- upload: uploadConfigSchema.optional(),
530
- categories: categoriesSchema.optional()
531
- });
532
- var coreConfigSchema = refineCoreConfig(unrefinedCoreConfigSchema);
533
- function refineCoreConfig(schema) {
534
- return schema.refine(
535
- ({ categories, plugins }) => !getMissingRefsForCategories(categories, plugins),
536
- ({ categories, plugins }) => ({
537
- message: missingRefsForCategoriesErrorMsg(categories, plugins)
538
- })
539
- );
540
- }
541
-
542
- // packages/models/src/lib/report.ts
543
- import { z as z15 } from "zod";
544
- var auditReportSchema = auditSchema.merge(auditOutputSchema);
545
- var pluginReportSchema = pluginMetaSchema.merge(
546
- executionMetaSchema({
547
- descriptionDate: "Start date and time of plugin run",
548
- descriptionDuration: "Duration of the plugin run in ms"
549
- })
550
- ).merge(
551
- z15.object({
552
- audits: z15.array(auditReportSchema).min(1),
553
- groups: z15.array(groupSchema).optional()
554
- })
555
- ).refine(
556
- (pluginReport) => !getMissingRefsFromGroups2(pluginReport.audits, pluginReport.groups ?? []),
557
- (pluginReport) => ({
558
- message: missingRefsFromGroupsErrorMsg2(
559
- pluginReport.audits,
560
- pluginReport.groups ?? []
561
- )
562
- })
563
- );
564
- function missingRefsFromGroupsErrorMsg2(audits, groups) {
565
- const missingRefs = getMissingRefsFromGroups2(audits, groups);
566
- return `group references need to point to an existing audit in this plugin report: ${errorItems(
567
- missingRefs
568
- )}`;
569
- }
570
- function getMissingRefsFromGroups2(audits, groups) {
571
- return hasMissingStrings(
572
- groups.flatMap(
573
- ({ refs: auditRefs }) => auditRefs.map(({ slug: ref }) => ref)
574
- ),
575
- audits.map(({ slug }) => slug)
576
- );
577
- }
578
- var reportSchema = packageVersionSchema({
579
- versionDescription: "NPM version of the CLI",
580
- required: true
581
- }).merge(
582
- executionMetaSchema({
583
- descriptionDate: "Start date and time of the collect run",
584
- descriptionDuration: "Duration of the collect run in ms"
585
- })
586
- ).merge(
587
- z15.object(
588
- {
589
- plugins: z15.array(pluginReportSchema).min(1),
590
- categories: z15.array(categoryConfigSchema).optional(),
591
- commit: commitSchema.describe("Git commit for which report was collected").nullable()
592
- },
593
- { description: "Collect output data" }
594
- )
595
- ).refine(
596
- ({ categories, plugins }) => !getMissingRefsForCategories(categories, plugins),
597
- ({ categories, plugins }) => ({
598
- message: missingRefsForCategoriesErrorMsg(categories, plugins)
599
- })
600
- );
601
-
602
- // packages/models/src/lib/reports-diff.ts
603
- import { z as z16 } from "zod";
604
- function makeComparisonSchema(schema) {
605
- const sharedDescription = schema.description || "Result";
606
- return z16.object({
607
- before: schema.describe(`${sharedDescription} (source commit)`),
608
- after: schema.describe(`${sharedDescription} (target commit)`)
609
- });
610
- }
611
- function makeArraysComparisonSchema(diffSchema, resultSchema, description) {
612
- return z16.object(
613
- {
614
- changed: z16.array(diffSchema),
615
- unchanged: z16.array(resultSchema),
616
- added: z16.array(resultSchema),
617
- removed: z16.array(resultSchema)
618
- },
619
- { description }
620
- );
621
- }
622
- var scorableMetaSchema = z16.object({
623
- slug: slugSchema,
624
- title: titleSchema,
625
- docsUrl: docsUrlSchema
626
- });
627
- var scorableWithPluginMetaSchema = scorableMetaSchema.merge(
628
- z16.object({
629
- plugin: pluginMetaSchema.pick({ slug: true, title: true, docsUrl: true }).describe("Plugin which defines it")
630
- })
631
- );
632
- var scorableDiffSchema = scorableMetaSchema.merge(
633
- z16.object({
634
- scores: makeComparisonSchema(scoreSchema).merge(
635
- z16.object({
636
- diff: z16.number().min(-1).max(1).describe("Score change (`scores.after - scores.before`)")
637
- })
638
- ).describe("Score comparison")
639
- })
640
- );
641
- var scorableWithPluginDiffSchema = scorableDiffSchema.merge(
642
- scorableWithPluginMetaSchema
643
- );
644
- var categoryDiffSchema = scorableDiffSchema;
645
- var groupDiffSchema = scorableWithPluginDiffSchema;
646
- var auditDiffSchema = scorableWithPluginDiffSchema.merge(
647
- z16.object({
648
- values: makeComparisonSchema(auditValueSchema).merge(
649
- z16.object({
650
- diff: z16.number().describe("Value change (`values.after - values.before`)")
651
- })
652
- ).describe("Audit `value` comparison"),
653
- displayValues: makeComparisonSchema(auditDisplayValueSchema).describe(
654
- "Audit `displayValue` comparison"
655
- )
656
- })
657
- );
658
- var categoryResultSchema = scorableMetaSchema.merge(
659
- z16.object({ score: scoreSchema })
660
- );
661
- var groupResultSchema = scorableWithPluginMetaSchema.merge(
662
- z16.object({ score: scoreSchema })
663
- );
664
- var auditResultSchema = scorableWithPluginMetaSchema.merge(
665
- auditOutputSchema.pick({ score: true, value: true, displayValue: true })
666
- );
667
- var reportsDiffSchema = z16.object({
668
- commits: makeComparisonSchema(commitSchema).nullable().describe("Commits identifying compared reports"),
669
- portalUrl: urlSchema.optional().describe("Link to comparison page in Code PushUp portal"),
670
- label: z16.string().optional().describe("Label (e.g. project name)"),
671
- categories: makeArraysComparisonSchema(
672
- categoryDiffSchema,
673
- categoryResultSchema,
674
- "Changes affecting categories"
675
- ),
676
- groups: makeArraysComparisonSchema(
677
- groupDiffSchema,
678
- groupResultSchema,
679
- "Changes affecting groups"
680
- ),
681
- audits: makeArraysComparisonSchema(
682
- auditDiffSchema,
683
- auditResultSchema,
684
- "Changes affecting audits"
685
- )
686
- }).merge(
687
- packageVersionSchema({
688
- versionDescription: "NPM version of the CLI (when `compare` was run)",
689
- required: true
690
- })
691
- ).merge(
692
- executionMetaSchema({
693
- descriptionDate: "Start date and time of the compare run",
694
- descriptionDuration: "Duration of the compare run in ms"
695
- })
696
- );
697
-
698
- // packages/utils/src/lib/execute-process.ts
699
- import {
700
- spawn
701
- } from "node:child_process";
702
-
703
- // packages/utils/src/lib/reports/utils.ts
704
- import ansis from "ansis";
705
- import { md } from "build-md";
706
-
707
- // packages/utils/src/lib/reports/constants.ts
708
- var TERMINAL_WIDTH = 80;
709
-
710
- // packages/utils/src/lib/reports/utils.ts
711
- function calcDuration(start, stop) {
712
- return Math.round((stop ?? performance.now()) - start);
713
- }
714
-
715
- // packages/utils/src/lib/execute-process.ts
716
- var ProcessError = class extends Error {
717
- code;
718
- stderr;
719
- stdout;
720
- constructor(result) {
721
- super(result.stderr);
722
- this.code = result.code;
723
- this.stderr = result.stderr;
724
- this.stdout = result.stdout;
725
- }
726
- };
727
- function executeProcess(cfg) {
728
- const { command, args, observer, ignoreExitCode = false, ...options } = cfg;
729
- const { onStdout, onStderr, onError, onComplete } = observer ?? {};
730
- const date = (/* @__PURE__ */ new Date()).toISOString();
731
- const start = performance.now();
732
- return new Promise((resolve, reject) => {
733
- const spawnedProcess = spawn(command, args ?? [], {
734
- shell: true,
735
- windowsHide: true,
736
- ...options
737
- });
738
- let stdout = "";
739
- let stderr = "";
740
- spawnedProcess.stdout.on("data", (data) => {
741
- stdout += String(data);
742
- onStdout?.(String(data), spawnedProcess);
743
- });
744
- spawnedProcess.stderr.on("data", (data) => {
745
- stderr += String(data);
746
- onStderr?.(String(data), spawnedProcess);
747
- });
748
- spawnedProcess.on("error", (err) => {
749
- stderr += err.toString();
750
- });
751
- spawnedProcess.on("close", (code2) => {
752
- const timings = { date, duration: calcDuration(start) };
753
- if (code2 === 0 || ignoreExitCode) {
754
- onComplete?.();
755
- resolve({ code: code2, stdout, stderr, ...timings });
756
- } else {
757
- const errorMsg = new ProcessError({ code: code2, stdout, stderr, ...timings });
758
- onError?.(errorMsg);
759
- reject(errorMsg);
760
- }
761
- });
762
- });
763
- }
764
-
765
- // packages/utils/src/lib/file-system.ts
766
- import { bold, gray } from "ansis";
767
- import { bundleRequire } from "bundle-require";
768
- import { mkdir, readFile, readdir, rm, stat } from "node:fs/promises";
769
- import { dirname, join } from "node:path";
770
-
771
- // packages/utils/src/lib/formatting.ts
772
- function pluralize(text, amount) {
773
- if (amount != null && Math.abs(amount) === 1) {
774
- return text;
775
- }
776
- if (text.endsWith("y")) {
777
- return `${text.slice(0, -1)}ies`;
778
- }
779
- if (text.endsWith("s")) {
780
- return `${text}es`;
781
- }
782
- return `${text}s`;
783
- }
784
-
785
- // packages/utils/src/lib/guards.ts
786
- function isPromiseFulfilledResult(result) {
787
- return result.status === "fulfilled";
788
- }
789
- function isPromiseRejectedResult(result) {
790
- return result.status === "rejected";
791
- }
792
-
793
- // packages/utils/src/lib/logging.ts
794
- import isaacs_cliui from "@isaacs/cliui";
795
- import { cliui } from "@poppinss/cliui";
796
- import { underline } from "ansis";
797
- var singletonUiInstance;
798
- function ui() {
799
- if (singletonUiInstance === void 0) {
800
- singletonUiInstance = cliui();
801
- }
802
- return {
803
- ...singletonUiInstance,
804
- row: (args) => {
805
- logListItem(args);
806
- }
807
- };
808
- }
809
- var singletonisaacUi;
810
- function logListItem(args) {
811
- if (singletonisaacUi === void 0) {
812
- singletonisaacUi = isaacs_cliui({ width: TERMINAL_WIDTH });
813
- }
814
- singletonisaacUi.div(...args);
815
- const content = singletonisaacUi.toString();
816
- singletonisaacUi.rows = [];
817
- singletonUiInstance?.logger.log(content);
818
- }
819
-
820
- // packages/utils/src/lib/file-system.ts
821
- async function readTextFile(path) {
822
- const buffer = await readFile(path);
823
- return buffer.toString();
824
- }
825
- async function readJsonFile(path) {
826
- const text = await readTextFile(path);
827
- return JSON.parse(text);
828
- }
829
- async function ensureDirectoryExists(baseDir) {
830
- try {
831
- await mkdir(baseDir, { recursive: true });
832
- return;
833
- } catch (error) {
834
- ui().logger.info(error.message);
835
- if (error.code !== "EEXIST") {
836
- throw error;
837
- }
838
- }
839
- }
840
- function pluginWorkDir(slug) {
841
- return join("node_modules", ".code-pushup", slug);
842
- }
843
- async function crawlFileSystem(options) {
844
- const {
845
- directory,
846
- pattern,
847
- fileTransform = (filePath) => filePath
848
- } = options;
849
- const files = await readdir(directory);
850
- const promises = files.map(async (file) => {
851
- const filePath = join(directory, file);
852
- const stats = await stat(filePath);
853
- if (stats.isDirectory()) {
854
- return crawlFileSystem({ directory: filePath, pattern, fileTransform });
855
- }
856
- if (stats.isFile() && (!pattern || new RegExp(pattern).test(file))) {
857
- return fileTransform(filePath);
858
- }
859
- return [];
860
- });
861
- const resultsNestedArray = await Promise.all(promises);
862
- return resultsNestedArray.flat();
863
- }
864
-
865
- // packages/utils/src/lib/git/git.ts
866
- import { simpleGit } from "simple-git";
867
-
868
- // packages/utils/src/lib/transform.ts
869
- import { platform } from "node:os";
870
- function objectToKeys(obj) {
871
- return Object.keys(obj);
872
- }
873
- function objectToEntries(obj) {
874
- return Object.entries(obj);
875
- }
876
- function objectFromEntries(entries) {
877
- return Object.fromEntries(entries);
878
- }
879
- function toUnixNewlines(text) {
880
- return platform() === "win32" ? text.replace(/\r\n/g, "\n") : text;
881
- }
882
- function fromJsonLines(jsonLines) {
883
- const unifiedNewLines = toUnixNewlines(jsonLines).trim();
884
- return JSON.parse(`[${unifiedNewLines.split("\n").join(",")}]`);
885
- }
886
-
887
- // packages/utils/src/lib/git/git.commits-and-tags.ts
888
- import { simpleGit as simpleGit2 } from "simple-git";
889
-
890
- // packages/utils/src/lib/semver.ts
891
- import { rcompare, valid } from "semver";
892
-
893
- // packages/utils/src/lib/progress.ts
894
- import { black, bold as bold2, gray as gray2, green } from "ansis";
895
- import { MultiProgressBars } from "multi-progress-bars";
896
-
897
- // packages/utils/src/lib/reports/generate-md-report.ts
898
- import { MarkdownDocument as MarkdownDocument3, md as md4 } from "build-md";
899
-
900
- // packages/utils/src/lib/reports/formatting.ts
901
- import {
902
- MarkdownDocument,
903
- md as md2
904
- } from "build-md";
905
-
906
- // packages/utils/src/lib/reports/generate-md-report-categoy-section.ts
907
- import { MarkdownDocument as MarkdownDocument2, md as md3 } from "build-md";
908
-
909
- // packages/utils/src/lib/reports/generate-md-reports-diff.ts
910
- import {
911
- MarkdownDocument as MarkdownDocument5,
912
- md as md6
913
- } from "build-md";
914
-
915
- // packages/utils/src/lib/reports/generate-md-reports-diff-utils.ts
916
- import { MarkdownDocument as MarkdownDocument4, md as md5 } from "build-md";
917
-
918
- // packages/utils/src/lib/reports/log-stdout-summary.ts
919
- import { bold as bold4, cyan, cyanBright, green as green2, red } from "ansis";
920
-
921
- // packages/plugin-js-packages/src/lib/config.ts
922
- import { z as z17 } from "zod";
923
-
924
- // packages/plugin-js-packages/src/lib/constants.ts
925
- var defaultAuditLevelMapping = {
926
- critical: "error",
927
- high: "error",
928
- moderate: "warning",
929
- low: "warning",
930
- info: "info"
931
- };
932
- var dependencyGroupToLong = {
933
- prod: "dependencies",
934
- dev: "devDependencies",
935
- optional: "optionalDependencies"
936
- };
937
-
938
- // packages/plugin-js-packages/src/lib/config.ts
939
- var dependencyGroups = ["prod", "dev", "optional"];
940
- var dependencyGroupSchema = z17.enum(dependencyGroups);
941
- var packageCommandSchema = z17.enum(["audit", "outdated"]);
942
- var packageManagerIdSchema = z17.enum([
943
- "npm",
944
- "yarn-classic",
945
- "yarn-modern",
946
- "pnpm"
947
- ]);
948
- var packageJsonPathSchema = z17.union([
949
- z17.array(z17.string()).min(1),
950
- z17.object({ autoSearch: z17.literal(true) })
951
- ]).describe(
952
- "File paths to package.json. Looks only at root package.json by default"
953
- ).default(["package.json"]);
954
- var packageAuditLevels = [
955
- "critical",
956
- "high",
957
- "moderate",
958
- "low",
959
- "info"
960
- ];
961
- var packageAuditLevelSchema = z17.enum(packageAuditLevels);
962
- function fillAuditLevelMapping(mapping) {
963
- return {
964
- critical: mapping.critical ?? defaultAuditLevelMapping.critical,
965
- high: mapping.high ?? defaultAuditLevelMapping.high,
966
- moderate: mapping.moderate ?? defaultAuditLevelMapping.moderate,
967
- low: mapping.low ?? defaultAuditLevelMapping.low,
968
- info: mapping.info ?? defaultAuditLevelMapping.info
969
- };
970
- }
971
- var jsPackagesPluginConfigSchema = z17.object({
972
- checks: z17.array(packageCommandSchema, {
973
- description: "Package manager commands to be run. Defaults to both audit and outdated."
974
- }).min(1).default(["audit", "outdated"]),
975
- packageManager: packageManagerIdSchema.describe("Package manager to be used.").optional(),
976
- dependencyGroups: z17.array(dependencyGroupSchema).min(1).default(["prod", "dev"]),
977
- auditLevelMapping: z17.record(packageAuditLevelSchema, issueSeveritySchema, {
978
- description: "Mapping of audit levels to issue severity. Custom mapping or overrides may be entered manually, otherwise has a default preset."
979
- }).default(defaultAuditLevelMapping).transform(fillAuditLevelMapping),
980
- packageJsonPaths: packageJsonPathSchema
981
- });
982
-
983
- // packages/plugin-js-packages/src/lib/runner/utils.ts
984
- import { sep } from "node:path";
985
-
986
- // packages/plugin-js-packages/src/lib/runner/outdated/types.ts
987
- var dependencyGroupLong = [
988
- "dependencies",
989
- "devDependencies",
990
- "optionalDependencies"
991
- ];
992
-
993
- // packages/plugin-js-packages/src/lib/runner/utils.ts
994
- function filterAuditResult(result, key, referenceResult) {
995
- if (result.vulnerabilities.length === 0) {
996
- return result;
997
- }
998
- const uniqueResult = result.vulnerabilities.reduce(
999
- (acc, ref) => {
1000
- const matchReference = referenceResult ?? acc;
1001
- const isMatch = matchReference.vulnerabilities.map((vulnerability) => vulnerability[key]).includes(ref[key]);
1002
- if (isMatch) {
1003
- return {
1004
- vulnerabilities: acc.vulnerabilities,
1005
- summary: {
1006
- ...acc.summary,
1007
- [ref.severity]: acc.summary[ref.severity] - 1,
1008
- total: acc.summary.total - 1
1009
- }
1010
- };
1011
- }
1012
- return {
1013
- vulnerabilities: [...acc.vulnerabilities, ref],
1014
- summary: acc.summary
1015
- };
1016
- },
1017
- { vulnerabilities: [], summary: result.summary }
1018
- );
1019
- return {
1020
- vulnerabilities: uniqueResult.vulnerabilities,
1021
- summary: uniqueResult.summary
1022
- };
1023
- }
1024
- async function findAllPackageJson() {
1025
- return (await crawlFileSystem({
1026
- directory: ".",
1027
- pattern: /(^|[\\/])package\.json$/
1028
- })).filter(
1029
- (path) => !path.startsWith(`node_modules${sep}`) && !path.includes(`${sep}node_modules${sep}`) && !path.startsWith(`.nx${sep}`)
1030
- );
1031
- }
1032
- async function getTotalDependencies(packageJsonPaths) {
1033
- const parsedDeps = await Promise.all(
1034
- packageJsonPaths.map(readJsonFile)
1035
- );
1036
- const mergedDeps = parsedDeps.reduce(
1037
- (acc, depMapper) => objectFromEntries(
1038
- dependencyGroupLong.map((group) => {
1039
- const deps = depMapper[group];
1040
- return [
1041
- group,
1042
- [...acc[group], ...deps == null ? [] : objectToKeys(deps)]
1043
- ];
1044
- })
1045
- ),
1046
- { dependencies: [], devDependencies: [], optionalDependencies: [] }
1047
- );
1048
- return objectFromEntries(
1049
- objectToKeys(mergedDeps).map((deps) => [
1050
- deps,
1051
- new Set(mergedDeps[deps]).size
1052
- ])
1053
- );
1054
- }
1055
-
1056
- // packages/plugin-js-packages/src/lib/package-managers/constants.ts
1057
- var COMMON_AUDIT_ARGS = ["audit", "--json"];
1058
- var COMMON_OUTDATED_ARGS = ["outdated", "--json"];
1059
-
1060
- // packages/plugin-js-packages/src/lib/package-managers/npm/audit-result.ts
1061
- function npmToAuditResult(output) {
1062
- const npmAudit = JSON.parse(output);
1063
- const vulnerabilities = objectToEntries(npmAudit.vulnerabilities).map(
1064
- ([name, detail]) => {
1065
- const advisory = npmToAdvisory(name, npmAudit.vulnerabilities);
1066
- return {
1067
- name: name.toString(),
1068
- severity: detail.severity,
1069
- versionRange: detail.range,
1070
- directDependency: detail.isDirect ? true : detail.effects[0] ?? "",
1071
- fixInformation: npmToFixInformation(detail.fixAvailable),
1072
- ...advisory != null && {
1073
- title: advisory.title,
1074
- url: advisory.url
1075
- }
1076
- };
1077
- }
1078
- );
1079
- return {
1080
- vulnerabilities,
1081
- summary: npmAudit.metadata.vulnerabilities
1082
- };
1083
- }
1084
- function npmToFixInformation(fixAvailable) {
1085
- if (typeof fixAvailable === "boolean") {
1086
- return fixAvailable ? "Fix is available." : "";
1087
- }
1088
- return `Fix available: Update \`${fixAvailable.name}\` to version **${fixAvailable.version}**${fixAvailable.isSemVerMajor ? " (breaking change)." : "."}`;
1089
- }
1090
- function npmToAdvisory(name, vulnerabilities, prevNodes = /* @__PURE__ */ new Set()) {
1091
- const advisory = vulnerabilities[name]?.via;
1092
- if (Array.isArray(advisory) && advisory.length > 0 && typeof advisory[0] === "object") {
1093
- return { title: advisory[0].title, url: advisory[0].url };
1094
- }
1095
- if (Array.isArray(advisory) && advisory.length > 0 && advisory.every((value) => typeof value === "string")) {
1096
- let advisoryInfo = null;
1097
- let newReferences = [];
1098
- let advisoryInfoFound = false;
1099
- for (const via of advisory) {
1100
- if (!prevNodes.has(via)) {
1101
- newReferences.push(via);
1102
- }
1103
- }
1104
- while (newReferences.length > 0 && !advisoryInfoFound) {
1105
- const ref = newReferences.pop();
1106
- prevNodes.add(ref);
1107
- const result = npmToAdvisory(ref, vulnerabilities, prevNodes);
1108
- if (result != null) {
1109
- advisoryInfo = { title: result.title, url: result.url };
1110
- advisoryInfoFound = true;
1111
- }
1112
- }
1113
- return advisoryInfo;
1114
- }
1115
- return null;
1116
- }
1117
-
1118
- // packages/plugin-js-packages/src/lib/package-managers/npm/outdated-result.ts
1119
- function npmToOutdatedResult(output) {
1120
- const npmOutdated = JSON.parse(output);
1121
- return objectToEntries(npmOutdated).filter(
1122
- (entry) => entry[1].current != null
1123
- ).map(([name, overview]) => ({
1124
- name,
1125
- current: overview.current,
1126
- latest: overview.latest,
1127
- type: overview.type,
1128
- ...overview.homepage != null && { url: overview.homepage }
1129
- }));
1130
- }
1131
-
1132
- // packages/plugin-js-packages/src/lib/package-managers/npm/npm.ts
1133
- var npmDependencyOptions = {
1134
- prod: ["--omit=dev", "--omit=optional"],
1135
- dev: ["--include=dev", "--omit=optional"],
1136
- optional: ["--include=optional", "--omit=dev"]
1137
- };
1138
- var npmPackageManager = {
1139
- slug: "npm",
1140
- name: "NPM",
1141
- command: "npm",
1142
- icon: "npm",
1143
- docs: {
1144
- homepage: "https://docs.npmjs.com/",
1145
- audit: "https://docs.npmjs.com/cli/commands/npm-audit",
1146
- outdated: "https://docs.npmjs.com/cli/commands/npm-outdated"
1147
- },
1148
- audit: {
1149
- getCommandArgs: (groupDep) => [
1150
- ...COMMON_AUDIT_ARGS,
1151
- ...npmDependencyOptions[groupDep],
1152
- "--audit-level=none"
1153
- ],
1154
- unifyResult: npmToAuditResult,
1155
- // prod dependencies need to be filtered out manually since v10
1156
- postProcessResult: (results) => {
1157
- const depGroups = objectToKeys(results);
1158
- const devFilter = results.dev && results.prod ? filterAuditResult(results.dev, "name", results.prod) : results.dev;
1159
- const optionalFilter = results.optional && results.prod ? filterAuditResult(results.optional, "name", results.prod) : results.optional;
1160
- return {
1161
- ...depGroups.includes("prod") && { prod: results.prod },
1162
- ...depGroups.includes("dev") && { dev: devFilter },
1163
- ...depGroups.includes("optional") && { optional: optionalFilter }
1164
- };
1165
- }
1166
- },
1167
- outdated: {
1168
- commandArgs: [...COMMON_OUTDATED_ARGS, "--long"],
1169
- unifyResult: npmToOutdatedResult
1170
- }
1171
- };
1172
-
1173
- // packages/plugin-js-packages/src/lib/runner/audit/utils.ts
1174
- function getVulnerabilitiesTotal(summary) {
1175
- return Object.values(summary).reduce((acc, value) => acc + value, 0);
1176
- }
1177
-
1178
- // packages/plugin-js-packages/src/lib/package-managers/pnpm/utils.ts
1179
- var filterOutWarnings = (output) => output.split("\n").filter((line) => !line.trim().startsWith("WARN")).join("\n");
1180
-
1181
- // packages/plugin-js-packages/src/lib/package-managers/pnpm/audit-result.ts
1182
- function pnpmToAuditResult(output) {
1183
- const pnpmResult = JSON.parse(
1184
- filterOutWarnings(output)
1185
- );
1186
- const vulnerabilities = Object.values(pnpmResult.advisories).map(
1187
- ({
1188
- module_name: name,
1189
- id,
1190
- title,
1191
- url,
1192
- severity,
1193
- vulnerable_versions: versionRange,
1194
- recommendation: fixInformation,
1195
- findings
1196
- }) => {
1197
- const path = findings[0]?.paths[0];
1198
- return {
1199
- name,
1200
- id,
1201
- title,
1202
- url,
1203
- severity,
1204
- versionRange,
1205
- directDependency: path == null ? true : pnpmToDirectDependency(path),
1206
- fixInformation
1207
- };
1208
- }
1209
- );
1210
- return {
1211
- vulnerabilities,
1212
- summary: {
1213
- ...pnpmResult.metadata.vulnerabilities,
1214
- total: getVulnerabilitiesTotal(pnpmResult.metadata.vulnerabilities)
1215
- }
1216
- };
1217
- }
1218
- function pnpmToDirectDependency(path) {
1219
- const deps = path.split(" > ").slice(1);
1220
- if (deps.length <= 1) {
1221
- return true;
1222
- }
1223
- return deps[0]?.split("@")[0] ?? true;
1224
- }
1225
-
1226
- // packages/plugin-js-packages/src/lib/package-managers/pnpm/outdated-result.ts
1227
- function pnpmToOutdatedResult(output) {
1228
- const pnpmOutdated = JSON.parse(
1229
- filterOutWarnings(output)
1230
- );
1231
- return objectToEntries(pnpmOutdated).map(
1232
- ([name, { current, latest, dependencyType: type }]) => ({
1233
- name,
1234
- current,
1235
- latest,
1236
- type
1237
- })
1238
- );
1239
- }
1240
-
1241
- // packages/plugin-js-packages/src/lib/package-managers/pnpm/pnpm.ts
1242
- var pnpmDependencyOptions = {
1243
- prod: ["--prod", "--no-optional"],
1244
- dev: ["--dev", "--no-optional"],
1245
- optional: []
1246
- };
1247
- var pnpmPackageManager = {
1248
- slug: "pnpm",
1249
- name: "pnpm",
1250
- command: "pnpm",
1251
- icon: "pnpm",
1252
- docs: {
1253
- homepage: "https://pnpm.io/pnpm-cli",
1254
- audit: "https://pnpm.io/cli/audit/",
1255
- outdated: "https://pnpm.io/cli/outdated"
1256
- },
1257
- audit: {
1258
- getCommandArgs: (groupDep) => [
1259
- ...COMMON_AUDIT_ARGS,
1260
- ...pnpmDependencyOptions[groupDep]
1261
- ],
1262
- ignoreExitCode: true,
1263
- unifyResult: pnpmToAuditResult,
1264
- // optional dependencies don't have an exclusive option so they need duplicates filtered out
1265
- postProcessResult: (results) => {
1266
- const depGroups = objectToKeys(results);
1267
- const prodFilter = results.optional && results.prod ? filterAuditResult(results.optional, "id", results.prod) : results.optional;
1268
- const devFilter = prodFilter && results.dev ? filterAuditResult(prodFilter, "id", results.dev) : results.optional;
1269
- return {
1270
- ...depGroups.includes("prod") && { prod: results.prod },
1271
- ...depGroups.includes("dev") && { dev: results.dev },
1272
- ...results.optional && { optional: devFilter }
1273
- };
1274
- }
1275
- },
1276
- outdated: {
1277
- commandArgs: COMMON_OUTDATED_ARGS,
1278
- unifyResult: pnpmToOutdatedResult
1279
- }
1280
- };
1281
-
1282
- // packages/plugin-js-packages/src/lib/package-managers/yarn-classic/audit-result.ts
1283
- function yarnv1ToAuditResult(output) {
1284
- const yarnv1Result = fromJsonLines(output);
1285
- const [yarnv1Advisory, yarnv1Summary] = validateYarnv1Result(yarnv1Result);
1286
- const vulnerabilities = yarnv1Advisory.map(
1287
- ({ data: { resolution, advisory } }) => {
1288
- const { id, path } = resolution;
1289
- const directDependency = path.slice(0, path.indexOf(">"));
1290
- const {
1291
- module_name: name,
1292
- title,
1293
- url,
1294
- severity,
1295
- vulnerable_versions: versionRange,
1296
- recommendation: fixInformation
1297
- } = advisory;
1298
- return {
1299
- name,
1300
- title,
1301
- id,
1302
- url,
1303
- severity,
1304
- versionRange,
1305
- directDependency: name === directDependency ? true : directDependency,
1306
- fixInformation
1307
- };
1308
- }
1309
- );
1310
- const summary = {
1311
- ...yarnv1Summary.data.vulnerabilities,
1312
- total: Object.values(yarnv1Summary.data.vulnerabilities).reduce(
1313
- (acc, amount) => acc + amount,
1314
- 0
1315
- )
1316
- };
1317
- return filterAuditResult({ vulnerabilities, summary }, "id");
1318
- }
1319
- function validateYarnv1Result(result) {
1320
- const summary = result.at(-1);
1321
- if (summary?.type !== "auditSummary") {
1322
- throw new Error("Invalid Yarn v1 audit result - no summary found.");
1323
- }
1324
- const vulnerabilities = result.filter(
1325
- (item) => item.type === "auditAdvisory"
1326
- );
1327
- return [vulnerabilities, summary];
1328
- }
1329
-
1330
- // packages/plugin-js-packages/src/lib/package-managers/yarn-classic/constants.ts
1331
- var outdatedtoFieldMapper = {
1332
- name: "Package",
1333
- current: "Current",
1334
- latest: "Latest",
1335
- type: "Package Type",
1336
- url: "URL"
1337
- };
1338
- var REQUIRED_OUTDATED_FIELDS = [
1339
- "Package",
1340
- "Current",
1341
- "Latest",
1342
- "Package Type"
1343
- ];
1344
-
1345
- // packages/plugin-js-packages/src/lib/package-managers/yarn-classic/types.ts
1346
- var yarnv1FieldNames = [
1347
- "Package",
1348
- "Current",
1349
- "Latest",
1350
- "Package Type",
1351
- "URL"
1352
- ];
1353
-
1354
- // packages/plugin-js-packages/src/lib/package-managers/yarn-classic/outdated-result.ts
1355
- function yarnv1ToOutdatedResult(output) {
1356
- const yarnv1Outdated = fromJsonLines(output);
1357
- const fields = yarnv1Outdated[1].data.head;
1358
- const dependencies = yarnv1Outdated[1].data.body;
1359
- if (dependencies.length === 0) {
1360
- return [];
1361
- }
1362
- validateOutdatedFields(fields);
1363
- const indexMapping = getOutdatedFieldIndexes(fields);
1364
- return dependencies.map(
1365
- (dep) => objectFromEntries(
1366
- objectToKeys(indexMapping).map((field) => [field, dep[indexMapping[field]]]).filter(
1367
- (entry) => entry[1] != null
1368
- )
1369
- )
1370
- );
1371
- }
1372
- function validateOutdatedFields(head) {
1373
- const relevantFields = head.filter(isYarnv1FieldName);
1374
- if (hasAllRequiredFields(relevantFields)) {
1375
- return true;
1376
- }
1377
- throw new Error(
1378
- `Yarn v1 outdated: Template [${head.join(
1379
- ", "
1380
- )}] does not contain all required fields [${yarnv1FieldNames.join(", ")}]`
1381
- );
1382
- }
1383
- function isYarnv1FieldName(value) {
1384
- const names = yarnv1FieldNames;
1385
- return names.includes(value);
1386
- }
1387
- function hasAllRequiredFields(head) {
1388
- return REQUIRED_OUTDATED_FIELDS.every((field) => head.includes(field));
1389
- }
1390
- function getOutdatedFieldIndexes(all) {
1391
- return objectFromEntries(
1392
- objectToEntries(outdatedtoFieldMapper).map(([outdatedField, yarnField]) => [
1393
- outdatedField,
1394
- all.indexOf(yarnField)
1395
- ])
1396
- );
1397
- }
1398
-
1399
- // packages/plugin-js-packages/src/lib/package-managers/yarn-classic/yarn-classic.ts
1400
- var yarnv1PackageManager = {
1401
- slug: "yarn-classic",
1402
- name: "Yarn v1",
1403
- command: "yarn",
1404
- icon: "yarn",
1405
- docs: {
1406
- homepage: "https://classic.yarnpkg.com/docs/",
1407
- audit: "https://classic.yarnpkg.com/docs/cli/audit",
1408
- outdated: "https://classic.yarnpkg.com/docs/cli/outdated/"
1409
- },
1410
- audit: {
1411
- getCommandArgs: (groupDep) => [
1412
- ...COMMON_AUDIT_ARGS,
1413
- "--groups",
1414
- dependencyGroupToLong[groupDep]
1415
- ],
1416
- ignoreExitCode: true,
1417
- unifyResult: yarnv1ToAuditResult
1418
- },
1419
- outdated: {
1420
- commandArgs: COMMON_OUTDATED_ARGS,
1421
- unifyResult: yarnv1ToOutdatedResult
1422
- }
1423
- };
1424
-
1425
- // packages/plugin-js-packages/src/lib/package-managers/yarn-modern/audit-result.ts
1426
- function yarnv2ToAuditResult(output) {
1427
- const yarnv2Audit = JSON.parse(output);
1428
- const vulnerabilities = Object.values(yarnv2Audit.advisories).map(
1429
- ({
1430
- module_name: name,
1431
- severity,
1432
- title,
1433
- url,
1434
- vulnerable_versions: versionRange,
1435
- recommendation: fixInformation,
1436
- findings
1437
- }) => {
1438
- const directDep = findings[0]?.paths[0];
1439
- return {
1440
- name,
1441
- severity,
1442
- title,
1443
- url,
1444
- versionRange,
1445
- fixInformation,
1446
- directDependency: directDep != null && directDep !== name ? directDep : true
1447
- };
1448
- }
1449
- );
1450
- return {
1451
- vulnerabilities,
1452
- summary: {
1453
- ...yarnv2Audit.metadata.vulnerabilities,
1454
- total: getVulnerabilitiesTotal(yarnv2Audit.metadata.vulnerabilities)
1455
- }
1456
- };
1457
- }
1458
-
1459
- // packages/plugin-js-packages/src/lib/package-managers/yarn-modern/outdated-result.ts
1460
- function yarnv2ToOutdatedResult(output) {
1461
- const npmOutdated = JSON.parse(output);
1462
- return npmOutdated.map(({ name, current, latest, type }) => ({
1463
- name,
1464
- current,
1465
- latest,
1466
- type
1467
- }));
1468
- }
1469
-
1470
- // packages/plugin-js-packages/src/lib/package-managers/yarn-modern/yarn-modern.ts
1471
- var yarnv2EnvironmentOptions = {
1472
- prod: "production",
1473
- dev: "development",
1474
- optional: ""
1475
- };
1476
- var yarnv2PackageManager = {
1477
- slug: "yarn-modern",
1478
- name: "yarn-modern",
1479
- command: "yarn",
1480
- icon: "yarn",
1481
- docs: {
1482
- homepage: "https://yarnpkg.com/getting-started",
1483
- audit: "https://yarnpkg.com/cli/npm/audit",
1484
- outdated: "https://github.com/mskelton/yarn-plugin-outdated"
1485
- },
1486
- audit: {
1487
- getCommandArgs: (groupDep) => [
1488
- "npm",
1489
- ...COMMON_AUDIT_ARGS,
1490
- "--environment",
1491
- yarnv2EnvironmentOptions[groupDep]
1492
- ],
1493
- supportedDepGroups: ["prod", "dev"],
1494
- // Yarn v2 does not support audit for optional dependencies
1495
- unifyResult: yarnv2ToAuditResult,
1496
- ignoreExitCode: true
1497
- },
1498
- outdated: {
1499
- commandArgs: COMMON_OUTDATED_ARGS,
1500
- unifyResult: yarnv2ToOutdatedResult
1501
- }
1502
- };
1503
-
1504
- // packages/plugin-js-packages/src/lib/package-managers/package-managers.ts
1505
- var packageManagers = {
1506
- npm: npmPackageManager,
1507
- "yarn-classic": yarnv1PackageManager,
1508
- "yarn-modern": yarnv2PackageManager,
1509
- pnpm: pnpmPackageManager
1510
- };
1511
-
1512
- // packages/plugin-js-packages/src/lib/runner/audit/transform.ts
1513
- import { md as md7 } from "build-md";
1514
-
1515
- // packages/plugin-js-packages/src/lib/runner/audit/constants.ts
1516
- var auditScoreModifiers = {
1517
- critical: 1,
1518
- high: 0.1,
1519
- moderate: 0.05,
1520
- low: 0.02,
1521
- info: 0.01
1522
- };
1523
-
1524
- // packages/plugin-js-packages/src/lib/runner/audit/transform.ts
1525
- function auditResultToAuditOutput(result, id, depGroup, auditLevelMapping) {
1526
- const issues = vulnerabilitiesToIssues(
1527
- result.vulnerabilities,
1528
- auditLevelMapping
1529
- );
1530
- return {
1531
- slug: `${id}-audit-${depGroup}`,
1532
- score: calculateAuditScore(result.summary),
1533
- value: result.summary.total,
1534
- displayValue: summaryToDisplayValue(result.summary),
1535
- details: { issues }
1536
- };
1537
- }
1538
- function calculateAuditScore(stats) {
1539
- if (stats.total === 0) {
1540
- return 1;
1541
- }
1542
- return objectToEntries(stats).reduce(
1543
- (score, [level, vulnerabilities]) => {
1544
- if (level === "total") {
1545
- return score;
1546
- }
1547
- const reducedScore = score - auditScoreModifiers[level] * vulnerabilities;
1548
- return Math.max(reducedScore, 0);
1549
- },
1550
- 1
1551
- );
1552
- }
1553
- function summaryToDisplayValue(summary) {
1554
- if (summary.total === 0) {
1555
- return "0 vulnerabilities";
1556
- }
1557
- const vulnerabilityStats = packageAuditLevels.map((level) => summary[level] > 0 ? `${summary[level]} ${level}` : "").filter((text) => text !== "").join(", ");
1558
- return `${summary.total} ${summary.total === 1 ? "vulnerability" : "vulnerabilities"} (${vulnerabilityStats})`;
1559
- }
1560
- function vulnerabilitiesToIssues(vulnerabilities, auditLevelMapping) {
1561
- if (vulnerabilities.length === 0) {
1562
- return [];
1563
- }
1564
- return vulnerabilities.map((detail) => {
1565
- const versionRange = detail.versionRange === "*" ? md7`${md7.bold("all")} versions` : md7`versions ${md7.bold(detail.versionRange)}`;
1566
- const directDependency = typeof detail.directDependency === "string" && detail.directDependency !== "" ? md7.code(detail.directDependency) : "";
1567
- const depHierarchy = directDependency ? md7`${directDependency}'s dependency ${md7.code(detail.name)}` : md7`${md7.code(detail.name)} dependency`;
1568
- const vulnerabilitySummary = md7`has a ${md7.bold(
1569
- detail.severity
1570
- )} vulnerability in ${versionRange}.`;
1571
- const fixInfo = detail.fixInformation ? ` ${detail.fixInformation}` : "";
1572
- const additionalInfo = detail.title != null && detail.url != null ? md7` More information: ${md7.link(detail.url, detail.title)}` : "";
1573
- return {
1574
- message: md7`${depHierarchy} ${vulnerabilitySummary}${fixInfo}${additionalInfo}`.toString(),
1575
- severity: auditLevelMapping[detail.severity]
1576
- };
1577
- });
1578
- }
1579
-
1580
- // packages/plugin-js-packages/src/lib/runner/constants.ts
1581
- import { join as join2 } from "node:path";
1582
- var WORKDIR = pluginWorkDir("js-packages");
1583
- var RUNNER_OUTPUT_PATH = join2(WORKDIR, "runner-output.json");
1584
- var PLUGIN_CONFIG_PATH = join2(
1585
- process.cwd(),
1586
- WORKDIR,
1587
- "plugin-config.json"
1588
- );
1589
-
1590
- // packages/plugin-js-packages/src/lib/runner/outdated/transform.ts
1591
- import { md as md8 } from "build-md";
1592
- import { clean, diff, neq } from "semver";
1593
-
1594
- // packages/plugin-js-packages/src/lib/runner/outdated/constants.ts
1595
- var outdatedSeverity = {
1596
- major: "error",
1597
- premajor: "info",
1598
- minor: "warning",
1599
- preminor: "info",
1600
- patch: "info",
1601
- prepatch: "info",
1602
- prerelease: "info"
1603
- };
1604
- var RELEASE_TYPES = objectToKeys(outdatedSeverity);
1605
-
1606
- // packages/plugin-js-packages/src/lib/runner/outdated/transform.ts
1607
- function outdatedResultToAuditOutput(result, packageManager, depGroup, totalDeps) {
1608
- const relevantDependencies = result.filter(
1609
- (dep) => dep.type === dependencyGroupToLong[depGroup]
1610
- );
1611
- const validDependencies = relevantDependencies.map((dep) => ({
1612
- ...dep,
1613
- current: clean(dep.current),
1614
- latest: clean(dep.latest)
1615
- })).filter(
1616
- (dep) => dep.current != null && dep.latest != null
1617
- );
1618
- const outdatedDependencies = validDependencies.filter(
1619
- (dep) => neq(dep.current, dep.latest)
1620
- );
1621
- const outdatedStats = outdatedDependencies.reduce(
1622
- (acc, dep) => {
1623
- const outdatedLevel = diff(dep.current, dep.latest);
1624
- if (outdatedLevel == null) {
1625
- return acc;
1626
- }
1627
- return { ...acc, [outdatedLevel]: acc[outdatedLevel] + 1 };
1628
- },
1629
- objectFromEntries(RELEASE_TYPES.map((versionType) => [versionType, 0]))
1630
- );
1631
- const issues = outdatedDependencies.length === 0 ? [] : outdatedToIssues(outdatedDependencies);
1632
- return {
1633
- slug: `${packageManager}-outdated-${depGroup}`,
1634
- score: calculateOutdatedScore(outdatedStats.major, totalDeps),
1635
- value: outdatedDependencies.length,
1636
- displayValue: outdatedToDisplayValue(outdatedStats),
1637
- details: { issues }
1638
- };
1639
- }
1640
- function calculateOutdatedScore(majorOutdated, totalDeps) {
1641
- return totalDeps > 0 ? (totalDeps - majorOutdated) / totalDeps : 1;
1642
- }
1643
- function outdatedToDisplayValue(stats) {
1644
- const total = Object.values(stats).reduce((acc, value) => acc + value, 0);
1645
- const versionBreakdown = RELEASE_TYPES.map(
1646
- (version) => stats[version] > 0 ? `${stats[version]} ${version}` : ""
1647
- ).filter((text) => text !== "");
1648
- if (versionBreakdown.length === 0) {
1649
- return "all dependencies are up to date";
1650
- }
1651
- if (versionBreakdown.length > 1) {
1652
- return `${total} outdated package versions (${versionBreakdown.join(
1653
- ", "
1654
- )})`;
1655
- }
1656
- return `${versionBreakdown[0]} outdated package ${pluralize(
1657
- "version",
1658
- total
1659
- )}`;
1660
- }
1661
- function outdatedToIssues(dependencies) {
1662
- return dependencies.map((dep) => {
1663
- const { name, current, latest, url } = dep;
1664
- const outdatedLevel = diff(current, latest);
1665
- const packageReference = url == null ? md8.code(name) : md8.link(url, md8.code(name));
1666
- return {
1667
- message: md8`Package ${packageReference} requires a ${md8.bold(
1668
- outdatedLevel
1669
- )} update from ${md8.bold(current)} to ${md8.bold(latest)}.`.toString(),
1670
- severity: outdatedSeverity[outdatedLevel]
1671
- };
1672
- });
1673
- }
1674
-
1675
- // packages/plugin-js-packages/src/lib/runner/index.ts
1676
- async function executeRunner() {
1677
- const {
1678
- packageManager,
1679
- checks,
1680
- auditLevelMapping,
1681
- packageJsonPaths,
1682
- dependencyGroups: depGroups
1683
- } = await readJsonFile(PLUGIN_CONFIG_PATH);
1684
- const auditResults = checks.includes("audit") ? await processAudit(packageManager, depGroups, auditLevelMapping) : [];
1685
- const outdatedResults = checks.includes("outdated") ? await processOutdated(packageManager, depGroups, packageJsonPaths) : [];
1686
- const checkResults = [...auditResults, ...outdatedResults];
1687
- await ensureDirectoryExists(dirname2(RUNNER_OUTPUT_PATH));
1688
- await writeFile(RUNNER_OUTPUT_PATH, JSON.stringify(checkResults));
1689
- }
1690
- async function processOutdated(id, depGroups, packageJsonPaths) {
1691
- const pm = packageManagers[id];
1692
- const { stdout, stderr } = await executeProcess({
1693
- command: pm.command,
1694
- args: pm.outdated.commandArgs,
1695
- cwd: process.cwd(),
1696
- ignoreExitCode: true
1697
- // outdated returns exit code 1 when outdated dependencies are found
1698
- });
1699
- if (stderr) {
1700
- throw new Error(`JS packages plugin: outdated error: ${stderr}`);
1701
- }
1702
- const finalPaths = Array.isArray(packageJsonPaths) ? packageJsonPaths : await findAllPackageJson();
1703
- const depTotals = await getTotalDependencies(finalPaths);
1704
- const normalizedResult = pm.outdated.unifyResult(stdout);
1705
- return depGroups.map(
1706
- (depGroup) => outdatedResultToAuditOutput(
1707
- normalizedResult,
1708
- id,
1709
- depGroup,
1710
- depTotals[dependencyGroupToLong[depGroup]]
1711
- )
1712
- );
1713
- }
1714
- async function processAudit(id, depGroups, auditLevelMapping) {
1715
- const pm = packageManagers[id];
1716
- const supportedAuditDepGroups = pm.audit.supportedDepGroups ?? dependencyGroups;
1717
- const compatibleAuditDepGroups = depGroups.filter(
1718
- (group) => supportedAuditDepGroups.includes(group)
1719
- );
1720
- const auditResults = await Promise.allSettled(
1721
- compatibleAuditDepGroups.map(
1722
- async (depGroup) => {
1723
- const { stdout, stderr } = await executeProcess({
1724
- command: pm.command,
1725
- args: pm.audit.getCommandArgs(depGroup),
1726
- cwd: process.cwd(),
1727
- ignoreExitCode: pm.audit.ignoreExitCode
1728
- });
1729
- if (stderr) {
1730
- throw new Error(`JS packages plugin: audit error: ${stderr}`);
1731
- }
1732
- return [depGroup, pm.audit.unifyResult(stdout)];
1733
- }
1734
- )
1735
- );
1736
- const rejected = auditResults.filter(isPromiseRejectedResult);
1737
- if (rejected.length > 0) {
1738
- rejected.map((result) => {
1739
- console.error(result.reason);
1740
- });
1741
- throw new Error(`JS Packages plugin: Running ${pm.name} audit failed.`);
1742
- }
1743
- const fulfilled = objectFromEntries(
1744
- auditResults.filter(isPromiseFulfilledResult).map((x) => x.value)
1745
- );
1746
- const uniqueResults = pm.audit.postProcessResult?.(fulfilled) ?? fulfilled;
1747
- return compatibleAuditDepGroups.map(
1748
- (depGroup) => auditResultToAuditOutput(
1749
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1750
- uniqueResults[depGroup],
1751
- id,
1752
- depGroup,
1753
- auditLevelMapping
1754
- )
1755
- );
1756
- }
1757
-
1758
- // packages/plugin-js-packages/src/bin.ts
1759
- await executeRunner();