@code-pushup/eslint-plugin 0.35.0 → 0.42.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.
package/bin.js CHANGED
@@ -1,9 +1,293 @@
1
1
  // packages/plugin-eslint/src/lib/runner/index.ts
2
- import { writeFile } from "node:fs/promises";
3
- import { dirname, join as join2 } from "node:path";
2
+ import { writeFile as writeFile2 } from "node:fs/promises";
3
+ import { dirname, join as join3 } from "node:path";
4
4
 
5
- // packages/models/src/lib/audit.ts
6
- import { z as z2 } from "zod";
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
+ function toArray(val) {
39
+ return Array.isArray(val) ? val : [val];
40
+ }
41
+ function objectToEntries(obj) {
42
+ return Object.entries(obj);
43
+ }
44
+ function countOccurrences(values) {
45
+ return values.reduce(
46
+ (acc, value) => ({ ...acc, [value]: (acc[value] ?? 0) + 1 }),
47
+ {}
48
+ );
49
+ }
50
+ function distinct(array) {
51
+ return [...new Set(array)];
52
+ }
53
+ function capitalize(text) {
54
+ return `${text.charAt(0).toLocaleUpperCase()}${text.slice(
55
+ 1
56
+ )}`;
57
+ }
58
+
59
+ // packages/utils/src/lib/table.ts
60
+ function rowToStringArray({ rows, columns = [] }) {
61
+ if (Array.isArray(rows.at(0)) && typeof columns.at(0) === "object") {
62
+ throw new TypeError(
63
+ "Column can`t be object when rows are primitive values"
64
+ );
65
+ }
66
+ return rows.map((row) => {
67
+ if (Array.isArray(row)) {
68
+ return row.map(String);
69
+ }
70
+ const objectRow = row;
71
+ if (columns.length === 0 || typeof columns.at(0) === "string") {
72
+ return Object.values(objectRow).map(String);
73
+ }
74
+ return columns.map(
75
+ ({ key }) => String(objectRow[key])
76
+ );
77
+ });
78
+ }
79
+ function columnsToStringArray({ rows, columns = [] }) {
80
+ const firstRow = rows.at(0);
81
+ const primitiveRows = Array.isArray(firstRow);
82
+ if (typeof columns.at(0) === "string" && !primitiveRows) {
83
+ throw new Error("invalid union type. Caught by model parsing.");
84
+ }
85
+ if (columns.length === 0) {
86
+ if (Array.isArray(firstRow)) {
87
+ return firstRow.map((_, idx) => String(idx));
88
+ }
89
+ return Object.keys(firstRow);
90
+ }
91
+ if (typeof columns.at(0) === "string") {
92
+ return columns.map(String);
93
+ }
94
+ const cols = columns;
95
+ return cols.map(({ label, key }) => label ?? capitalize(key));
96
+ }
97
+ function getColumnAlignmentForKeyAndIndex(targetKey, targetIdx, columns = []) {
98
+ const column = columns.at(targetIdx) ?? columns.find((col) => col.key === targetKey);
99
+ if (typeof column === "string") {
100
+ return column;
101
+ } else if (typeof column === "object") {
102
+ return column.align ?? "center";
103
+ } else {
104
+ return "center";
105
+ }
106
+ }
107
+ function getColumnAlignmentForIndex(targetIdx, columns = []) {
108
+ const column = columns.at(targetIdx);
109
+ if (column == null) {
110
+ return "center";
111
+ } else if (typeof column === "string") {
112
+ return column;
113
+ } else if (typeof column === "object") {
114
+ return column.align ?? "center";
115
+ } else {
116
+ return "center";
117
+ }
118
+ }
119
+ function getColumnAlignments({
120
+ rows,
121
+ columns = []
122
+ }) {
123
+ if (rows.at(0) == null) {
124
+ throw new Error("first row can`t be undefined.");
125
+ }
126
+ if (Array.isArray(rows.at(0))) {
127
+ const firstPrimitiveRow = rows.at(0);
128
+ return Array.from({ length: firstPrimitiveRow.length }).map(
129
+ (_, idx) => getColumnAlignmentForIndex(idx, columns)
130
+ );
131
+ }
132
+ const firstObject = rows.at(0);
133
+ return Object.keys(firstObject).map(
134
+ (key, idx) => getColumnAlignmentForKeyAndIndex(key, idx, columns)
135
+ );
136
+ }
137
+
138
+ // packages/utils/src/lib/text-formats/html/table.ts
139
+ function wrap(elem, content) {
140
+ return `<${elem}>${content}</${elem}>${NEW_LINE}`;
141
+ }
142
+ function wrapRow(content) {
143
+ const elem = "tr";
144
+ return `<${elem}>${NEW_LINE}${content}</${elem}>${NEW_LINE}`;
145
+ }
146
+ function table(tableData) {
147
+ if (tableData.rows.length === 0) {
148
+ throw new Error("Data can't be empty");
149
+ }
150
+ const tableHeaderCols = columnsToStringArray(tableData).map((s) => wrap("th", s)).join("");
151
+ const tableHeaderRow = wrapRow(tableHeaderCols);
152
+ const tableBody = rowToStringArray(tableData).map((arr) => {
153
+ const columns = arr.map((s) => wrap("td", s)).join("");
154
+ return wrapRow(columns);
155
+ }).join("");
156
+ return wrap("table", `${NEW_LINE}${tableHeaderRow}${tableBody}`);
157
+ }
158
+
159
+ // packages/utils/src/lib/text-formats/md/font-style.ts
160
+ var boldWrap = "**";
161
+ function bold2(text) {
162
+ return `${boldWrap}${text}${boldWrap}`;
163
+ }
164
+ var italicWrap = "_";
165
+ function italic2(text) {
166
+ return `${italicWrap}${text}${italicWrap}`;
167
+ }
168
+ var strikeThroughWrap = "~";
169
+ function strikeThrough(text) {
170
+ return `${strikeThroughWrap}${text}${strikeThroughWrap}`;
171
+ }
172
+ var codeWrap = "`";
173
+ function code2(text) {
174
+ return `${codeWrap}${text}${codeWrap}`;
175
+ }
176
+
177
+ // packages/utils/src/lib/text-formats/md/headline.ts
178
+ function headline(text, hierarchy = 1) {
179
+ return `${"#".repeat(hierarchy)} ${text}${NEW_LINE}`;
180
+ }
181
+ function h(text, hierarchy = 1) {
182
+ return headline(text, hierarchy);
183
+ }
184
+ function h1(text) {
185
+ return headline(text, 1);
186
+ }
187
+ function h2(text) {
188
+ return headline(text, 2);
189
+ }
190
+ function h3(text) {
191
+ return headline(text, 3);
192
+ }
193
+ function h4(text) {
194
+ return headline(text, 4);
195
+ }
196
+ function h5(text) {
197
+ return headline(text, 5);
198
+ }
199
+ function h6(text) {
200
+ return headline(text, 6);
201
+ }
202
+
203
+ // packages/utils/src/lib/text-formats/md/image.ts
204
+ function image(src, alt) {
205
+ return `![${alt}](${src})`;
206
+ }
207
+
208
+ // packages/utils/src/lib/text-formats/md/link.ts
209
+ function link2(href, text) {
210
+ return `[${text || href}](${href})`;
211
+ }
212
+
213
+ // packages/utils/src/lib/text-formats/md/list.ts
214
+ function li(text, order = "unordered") {
215
+ const style = order === "unordered" ? "-" : "- [ ]";
216
+ return `${style} ${text}`;
217
+ }
218
+ function indentation(text, level = 1) {
219
+ return `${TAB.repeat(level)}${text}`;
220
+ }
221
+
222
+ // packages/utils/src/lib/text-formats/md/paragraphs.ts
223
+ function paragraphs(...sections) {
224
+ return sections.filter(Boolean).join(`${NEW_LINE}${NEW_LINE}`);
225
+ }
226
+
227
+ // packages/utils/src/lib/text-formats/md/section.ts
228
+ function section(...contents) {
229
+ return `${lines(...contents)}${NEW_LINE}`;
230
+ }
231
+ function lines(...contents) {
232
+ return `${contents.filter(Boolean).join(NEW_LINE)}`;
233
+ }
234
+
235
+ // packages/utils/src/lib/text-formats/md/table.ts
236
+ var alignString = /* @__PURE__ */ new Map([
237
+ ["left", ":--"],
238
+ ["center", ":--:"],
239
+ ["right", "--:"]
240
+ ]);
241
+ function tableRow(rows) {
242
+ return `|${rows.join("|")}|`;
243
+ }
244
+ function table2(data) {
245
+ if (data.rows.length === 0) {
246
+ throw new Error("Data can't be empty");
247
+ }
248
+ const alignmentRow = getColumnAlignments(data).map(
249
+ (s) => alignString.get(s) ?? String(alignString.get("center"))
250
+ );
251
+ return section(
252
+ `${lines(
253
+ tableRow(columnsToStringArray(data)),
254
+ tableRow(alignmentRow),
255
+ ...rowToStringArray(data).map(tableRow)
256
+ )}`
257
+ );
258
+ }
259
+
260
+ // packages/utils/src/lib/text-formats/index.ts
261
+ var md = {
262
+ bold: bold2,
263
+ italic: italic2,
264
+ strikeThrough,
265
+ code: code2,
266
+ link: link2,
267
+ image,
268
+ headline,
269
+ h,
270
+ h1,
271
+ h2,
272
+ h3,
273
+ h4,
274
+ h5,
275
+ h6,
276
+ indentation,
277
+ lines,
278
+ li,
279
+ section,
280
+ paragraphs,
281
+ table: table2
282
+ };
283
+ var html = {
284
+ bold,
285
+ italic,
286
+ code,
287
+ link,
288
+ details,
289
+ table
290
+ };
7
291
 
8
292
  // packages/models/src/lib/implementation/schemas.ts
9
293
  import { MATERIAL_ICONS } from "vscode-material-icons";
@@ -70,6 +354,7 @@ function missingRefsForCategoriesErrorMsg(categories, plugins) {
70
354
  }
71
355
 
72
356
  // packages/models/src/lib/implementation/schemas.ts
357
+ var primitiveValueSchema = z.union([z.string(), z.number()]);
73
358
  function executionMetaSchema(options = {
74
359
  descriptionDate: "Execution start date and time",
75
360
  descriptionDuration: "Execution duration in ms"
@@ -161,6 +446,7 @@ function hasNonZeroWeightedRef(refs) {
161
446
  }
162
447
 
163
448
  // packages/models/src/lib/audit.ts
449
+ import { z as z2 } from "zod";
164
450
  var auditSchema = z2.object({
165
451
  slug: slugSchema.describe("ID (unique within plugin)")
166
452
  }).merge(
@@ -190,7 +476,7 @@ function getDuplicateSlugsInAudits(audits) {
190
476
  }
191
477
 
192
478
  // packages/models/src/lib/audit-output.ts
193
- import { z as z4 } from "zod";
479
+ import { z as z5 } from "zod";
194
480
 
195
481
  // packages/models/src/lib/issue.ts
196
482
  import { z as z3 } from "zod";
@@ -221,16 +507,61 @@ var issueSchema = z3.object(
221
507
  { description: "Issue information" }
222
508
  );
223
509
 
510
+ // packages/models/src/lib/table.ts
511
+ import { z as z4 } from "zod";
512
+ var tableAlignmentSchema = z4.enum(["left", "center", "right"], {
513
+ description: "Cell alignment"
514
+ });
515
+ var tableColumnObjectSchema = z4.object({
516
+ key: z4.string(),
517
+ label: z4.string().optional(),
518
+ align: tableAlignmentSchema.optional()
519
+ });
520
+ var tableRowObjectSchema = z4.record(primitiveValueSchema, {
521
+ description: "Object row"
522
+ });
523
+ var tableRowPrimitiveSchema = z4.array(primitiveValueSchema, {
524
+ description: "Primitive row"
525
+ });
526
+ var tableSharedSchema = z4.object({
527
+ title: z4.string().optional().describe("Display title for table")
528
+ });
529
+ var tablePrimitiveSchema = tableSharedSchema.merge(
530
+ z4.object(
531
+ {
532
+ columns: z4.array(tableAlignmentSchema).optional(),
533
+ rows: z4.array(tableRowPrimitiveSchema)
534
+ },
535
+ { description: "Table with primitive rows and optional alignment columns" }
536
+ )
537
+ );
538
+ var tableObjectSchema = tableSharedSchema.merge(
539
+ z4.object(
540
+ {
541
+ columns: z4.union([
542
+ z4.array(tableAlignmentSchema),
543
+ z4.array(tableColumnObjectSchema)
544
+ ]).optional(),
545
+ rows: z4.array(tableRowObjectSchema)
546
+ },
547
+ {
548
+ description: "Table with object rows and optional alignment or object columns"
549
+ }
550
+ )
551
+ );
552
+ var tableSchema = (description = "Table information") => z4.union([tablePrimitiveSchema, tableObjectSchema], { description });
553
+
224
554
  // packages/models/src/lib/audit-output.ts
225
555
  var auditValueSchema = nonnegativeIntSchema.describe("Raw numeric value");
226
- var auditDisplayValueSchema = z4.string({ description: "Formatted value (e.g. '0.9 s', '2.1 MB')" }).optional();
227
- var auditDetailsSchema = z4.object(
556
+ var auditDisplayValueSchema = z5.string({ description: "Formatted value (e.g. '0.9 s', '2.1 MB')" }).optional();
557
+ var auditDetailsSchema = z5.object(
228
558
  {
229
- issues: z4.array(issueSchema, { description: "List of findings" })
559
+ issues: z5.array(issueSchema, { description: "List of findings" }).optional(),
560
+ table: tableSchema("Table of related findings").optional()
230
561
  },
231
562
  { description: "Detailed information" }
232
563
  );
233
- var auditOutputSchema = z4.object(
564
+ var auditOutputSchema = z5.object(
234
565
  {
235
566
  slug: slugSchema.describe("Reference to audit"),
236
567
  displayValue: auditDisplayValueSchema,
@@ -240,7 +571,7 @@ var auditOutputSchema = z4.object(
240
571
  },
241
572
  { description: "Audit information" }
242
573
  );
243
- var auditOutputsSchema = z4.array(auditOutputSchema, {
574
+ var auditOutputsSchema = z5.array(auditOutputSchema, {
244
575
  description: "List of JSON formatted audit output emitted by the runner process of a plugin"
245
576
  }).refine(
246
577
  (audits) => !getDuplicateSlugsInAudits2(audits),
@@ -257,13 +588,13 @@ function getDuplicateSlugsInAudits2(audits) {
257
588
  }
258
589
 
259
590
  // packages/models/src/lib/category-config.ts
260
- import { z as z5 } from "zod";
591
+ import { z as z6 } from "zod";
261
592
  var categoryRefSchema = weightedRefSchema(
262
593
  "Weighted references to audits and/or groups for the category",
263
594
  "Slug of an audit or group (depending on `type`)"
264
595
  ).merge(
265
- z5.object({
266
- type: z5.enum(["audit", "group"], {
596
+ z6.object({
597
+ type: z6.enum(["audit", "group"], {
267
598
  description: "Discriminant for reference kind, affects where `slug` is looked up"
268
599
  }),
269
600
  plugin: slugSchema.describe(
@@ -284,8 +615,8 @@ var categoryConfigSchema = scorableSchema(
284
615
  description: "Meta info for category"
285
616
  })
286
617
  ).merge(
287
- z5.object({
288
- isBinary: z5.boolean({
618
+ z6.object({
619
+ isBinary: z6.boolean({
289
620
  description: 'Is this a binary category (i.e. only a perfect score considered a "pass")?'
290
621
  }).optional()
291
622
  })
@@ -301,7 +632,7 @@ function getDuplicateRefsInCategoryMetrics(metrics) {
301
632
  metrics.map(({ slug, type, plugin }) => `${type} :: ${plugin} / ${slug}`)
302
633
  );
303
634
  }
304
- var categoriesSchema = z5.array(categoryConfigSchema, {
635
+ var categoriesSchema = z6.array(categoryConfigSchema, {
305
636
  description: "Categorization of individual audits"
306
637
  }).refine(
307
638
  (categoryCfg) => !getDuplicateSlugCategories(categoryCfg),
@@ -320,18 +651,18 @@ function getDuplicateSlugCategories(categories) {
320
651
  }
321
652
 
322
653
  // packages/models/src/lib/commit.ts
323
- import { z as z6 } from "zod";
324
- var commitSchema = z6.object(
654
+ import { z as z7 } from "zod";
655
+ var commitSchema = z7.object(
325
656
  {
326
- hash: z6.string({ description: "Commit SHA (full)" }).regex(
657
+ hash: z7.string({ description: "Commit SHA (full)" }).regex(
327
658
  /^[\da-f]{40}$/,
328
659
  "Commit SHA should be a 40-character hexadecimal string"
329
660
  ),
330
- message: z6.string({ description: "Commit message" }),
331
- date: z6.coerce.date({
661
+ message: z7.string({ description: "Commit message" }),
662
+ date: z7.coerce.date({
332
663
  description: "Date and time when commit was authored"
333
664
  }),
334
- author: z6.string({
665
+ author: z7.string({
335
666
  description: "Commit author name"
336
667
  }).trim()
337
668
  },
@@ -339,22 +670,22 @@ var commitSchema = z6.object(
339
670
  );
340
671
 
341
672
  // packages/models/src/lib/core-config.ts
342
- import { z as z12 } from "zod";
673
+ import { z as z13 } from "zod";
343
674
 
344
675
  // packages/models/src/lib/persist-config.ts
345
- import { z as z7 } from "zod";
346
- var formatSchema = z7.enum(["json", "md"]);
347
- var persistConfigSchema = z7.object({
676
+ import { z as z8 } from "zod";
677
+ var formatSchema = z8.enum(["json", "md"]);
678
+ var persistConfigSchema = z8.object({
348
679
  outputDir: filePathSchema.describe("Artifacts folder").optional(),
349
680
  filename: fileNameSchema.describe("Artifacts file name (without extension)").optional(),
350
- format: z7.array(formatSchema).optional()
681
+ format: z8.array(formatSchema).optional()
351
682
  });
352
683
 
353
684
  // packages/models/src/lib/plugin-config.ts
354
- import { z as z10 } from "zod";
685
+ import { z as z11 } from "zod";
355
686
 
356
687
  // packages/models/src/lib/group.ts
357
- import { z as z8 } from "zod";
688
+ import { z as z9 } from "zod";
358
689
  var groupRefSchema = weightedRefSchema(
359
690
  "Weighted reference to a group",
360
691
  "Reference slug to a group within this plugin (e.g. 'max-lines')"
@@ -371,7 +702,7 @@ var groupSchema = scorableSchema(
371
702
  getDuplicateRefsInGroups,
372
703
  duplicateRefsInGroupsErrorMsg
373
704
  ).merge(groupMetaSchema);
374
- var groupsSchema = z8.array(groupSchema, {
705
+ var groupsSchema = z9.array(groupSchema, {
375
706
  description: "List of groups"
376
707
  }).optional().refine(
377
708
  (groups) => !getDuplicateSlugsInGroups(groups),
@@ -399,14 +730,14 @@ function getDuplicateSlugsInGroups(groups) {
399
730
  }
400
731
 
401
732
  // packages/models/src/lib/runner-config.ts
402
- import { z as z9 } from "zod";
403
- var outputTransformSchema = z9.function().args(z9.unknown()).returns(z9.union([auditOutputsSchema, z9.promise(auditOutputsSchema)]));
404
- var runnerConfigSchema = z9.object(
733
+ import { z as z10 } from "zod";
734
+ var outputTransformSchema = z10.function().args(z10.unknown()).returns(z10.union([auditOutputsSchema, z10.promise(auditOutputsSchema)]));
735
+ var runnerConfigSchema = z10.object(
405
736
  {
406
- command: z9.string({
737
+ command: z10.string({
407
738
  description: "Shell command to execute"
408
739
  }),
409
- args: z9.array(z9.string({ description: "Command arguments" })).optional(),
740
+ args: z10.array(z10.string({ description: "Command arguments" })).optional(),
410
741
  outputFile: filePathSchema.describe("Output path"),
411
742
  outputTransform: outputTransformSchema.optional()
412
743
  },
@@ -414,8 +745,8 @@ var runnerConfigSchema = z9.object(
414
745
  description: "How to execute runner"
415
746
  }
416
747
  );
417
- var onProgressSchema = z9.function().args(z9.unknown()).returns(z9.void());
418
- var runnerFunctionSchema = z9.function().args(onProgressSchema.optional()).returns(z9.union([auditOutputsSchema, z9.promise(auditOutputsSchema)]));
748
+ var onProgressSchema = z10.function().args(z10.unknown()).returns(z10.void());
749
+ var runnerFunctionSchema = z10.function().args(onProgressSchema.optional()).returns(z10.union([auditOutputsSchema, z10.promise(auditOutputsSchema)]));
419
750
 
420
751
  // packages/models/src/lib/plugin-config.ts
421
752
  var pluginMetaSchema = packageVersionSchema().merge(
@@ -426,13 +757,13 @@ var pluginMetaSchema = packageVersionSchema().merge(
426
757
  description: "Plugin metadata"
427
758
  })
428
759
  ).merge(
429
- z10.object({
760
+ z11.object({
430
761
  slug: slugSchema.describe("Unique plugin slug within core config"),
431
762
  icon: materialIconSchema
432
763
  })
433
764
  );
434
- var pluginDataSchema = z10.object({
435
- runner: z10.union([runnerConfigSchema, runnerFunctionSchema]),
765
+ var pluginDataSchema = z11.object({
766
+ runner: z11.union([runnerConfigSchema, runnerFunctionSchema]),
436
767
  audits: pluginAuditsSchema,
437
768
  groups: groupsSchema
438
769
  });
@@ -458,22 +789,22 @@ function getMissingRefsFromGroups(pluginCfg) {
458
789
  }
459
790
 
460
791
  // packages/models/src/lib/upload-config.ts
461
- import { z as z11 } from "zod";
462
- var uploadConfigSchema = z11.object({
792
+ import { z as z12 } from "zod";
793
+ var uploadConfigSchema = z12.object({
463
794
  server: urlSchema.describe("URL of deployed portal API"),
464
- apiKey: z11.string({
795
+ apiKey: z12.string({
465
796
  description: "API key with write access to portal (use `process.env` for security)"
466
797
  }),
467
798
  organization: slugSchema.describe(
468
799
  "Organization slug from Code PushUp portal"
469
800
  ),
470
801
  project: slugSchema.describe("Project slug from Code PushUp portal"),
471
- timeout: z11.number({ description: "Request timeout in minutes (default is 5)" }).positive().int().optional()
802
+ timeout: z12.number({ description: "Request timeout in minutes (default is 5)" }).positive().int().optional()
472
803
  });
473
804
 
474
805
  // packages/models/src/lib/core-config.ts
475
- var unrefinedCoreConfigSchema = z12.object({
476
- plugins: z12.array(pluginConfigSchema, {
806
+ var unrefinedCoreConfigSchema = z13.object({
807
+ plugins: z13.array(pluginConfigSchema, {
477
808
  description: "List of plugins to be used (official, community-provided, or custom)"
478
809
  }).min(1),
479
810
  /** portal configuration for persisting results */
@@ -496,7 +827,7 @@ function refineCoreConfig(schema) {
496
827
  }
497
828
 
498
829
  // packages/models/src/lib/report.ts
499
- import { z as z13 } from "zod";
830
+ import { z as z14 } from "zod";
500
831
  var auditReportSchema = auditSchema.merge(auditOutputSchema);
501
832
  var pluginReportSchema = pluginMetaSchema.merge(
502
833
  executionMetaSchema({
@@ -504,9 +835,9 @@ var pluginReportSchema = pluginMetaSchema.merge(
504
835
  descriptionDuration: "Duration of the plugin run in ms"
505
836
  })
506
837
  ).merge(
507
- z13.object({
508
- audits: z13.array(auditReportSchema).min(1),
509
- groups: z13.array(groupSchema).optional()
838
+ z14.object({
839
+ audits: z14.array(auditReportSchema).min(1),
840
+ groups: z14.array(groupSchema).optional()
510
841
  })
511
842
  ).refine(
512
843
  (pluginReport) => !getMissingRefsFromGroups2(pluginReport.audits, pluginReport.groups ?? []),
@@ -540,10 +871,10 @@ var reportSchema = packageVersionSchema({
540
871
  descriptionDuration: "Duration of the collect run in ms"
541
872
  })
542
873
  ).merge(
543
- z13.object(
874
+ z14.object(
544
875
  {
545
- categories: z13.array(categoryConfigSchema),
546
- plugins: z13.array(pluginReportSchema).min(1),
876
+ categories: z14.array(categoryConfigSchema),
877
+ plugins: z14.array(pluginReportSchema).min(1),
547
878
  commit: commitSchema.describe("Git commit for which report was collected").nullable()
548
879
  },
549
880
  { description: "Collect output data" }
@@ -559,36 +890,40 @@ var reportSchema = packageVersionSchema({
559
890
  );
560
891
 
561
892
  // packages/models/src/lib/reports-diff.ts
562
- import { z as z14 } from "zod";
893
+ import { z as z15 } from "zod";
563
894
  function makeComparisonSchema(schema) {
564
895
  const sharedDescription = schema.description || "Result";
565
- return z14.object({
896
+ return z15.object({
566
897
  before: schema.describe(`${sharedDescription} (source commit)`),
567
898
  after: schema.describe(`${sharedDescription} (target commit)`)
568
899
  });
569
900
  }
570
901
  function makeArraysComparisonSchema(diffSchema, resultSchema, description) {
571
- return z14.object(
902
+ return z15.object(
572
903
  {
573
- changed: z14.array(diffSchema),
574
- unchanged: z14.array(resultSchema),
575
- added: z14.array(resultSchema),
576
- removed: z14.array(resultSchema)
904
+ changed: z15.array(diffSchema),
905
+ unchanged: z15.array(resultSchema),
906
+ added: z15.array(resultSchema),
907
+ removed: z15.array(resultSchema)
577
908
  },
578
909
  { description }
579
910
  );
580
911
  }
581
- var scorableMetaSchema = z14.object({ slug: slugSchema, title: titleSchema });
912
+ var scorableMetaSchema = z15.object({
913
+ slug: slugSchema,
914
+ title: titleSchema,
915
+ docsUrl: docsUrlSchema
916
+ });
582
917
  var scorableWithPluginMetaSchema = scorableMetaSchema.merge(
583
- z14.object({
584
- plugin: pluginMetaSchema.pick({ slug: true, title: true }).describe("Plugin which defines it")
918
+ z15.object({
919
+ plugin: pluginMetaSchema.pick({ slug: true, title: true, docsUrl: true }).describe("Plugin which defines it")
585
920
  })
586
921
  );
587
922
  var scorableDiffSchema = scorableMetaSchema.merge(
588
- z14.object({
923
+ z15.object({
589
924
  scores: makeComparisonSchema(scoreSchema).merge(
590
- z14.object({
591
- diff: z14.number().min(-1).max(1).describe("Score change (`scores.after - scores.before`)")
925
+ z15.object({
926
+ diff: z15.number().min(-1).max(1).describe("Score change (`scores.after - scores.before`)")
592
927
  })
593
928
  ).describe("Score comparison")
594
929
  })
@@ -599,10 +934,10 @@ var scorableWithPluginDiffSchema = scorableDiffSchema.merge(
599
934
  var categoryDiffSchema = scorableDiffSchema;
600
935
  var groupDiffSchema = scorableWithPluginDiffSchema;
601
936
  var auditDiffSchema = scorableWithPluginDiffSchema.merge(
602
- z14.object({
937
+ z15.object({
603
938
  values: makeComparisonSchema(auditValueSchema).merge(
604
- z14.object({
605
- diff: z14.number().int().describe("Value change (`values.after - values.before`)")
939
+ z15.object({
940
+ diff: z15.number().int().describe("Value change (`values.after - values.before`)")
606
941
  })
607
942
  ).describe("Audit `value` comparison"),
608
943
  displayValues: makeComparisonSchema(auditDisplayValueSchema).describe(
@@ -611,15 +946,15 @@ var auditDiffSchema = scorableWithPluginDiffSchema.merge(
611
946
  })
612
947
  );
613
948
  var categoryResultSchema = scorableMetaSchema.merge(
614
- z14.object({ score: scoreSchema })
949
+ z15.object({ score: scoreSchema })
615
950
  );
616
951
  var groupResultSchema = scorableWithPluginMetaSchema.merge(
617
- z14.object({ score: scoreSchema })
952
+ z15.object({ score: scoreSchema })
618
953
  );
619
954
  var auditResultSchema = scorableWithPluginMetaSchema.merge(
620
955
  auditOutputSchema.pick({ score: true, value: true, displayValue: true })
621
956
  );
622
- var reportsDiffSchema = z14.object({
957
+ var reportsDiffSchema = z15.object({
623
958
  commits: makeComparisonSchema(commitSchema).nullable().describe("Commits identifying compared reports"),
624
959
  categories: makeArraysComparisonSchema(
625
960
  categoryDiffSchema,
@@ -648,6 +983,9 @@ var reportsDiffSchema = z14.object({
648
983
  })
649
984
  );
650
985
 
986
+ // packages/utils/src/lib/execute-process.ts
987
+ import { spawn } from "node:child_process";
988
+
651
989
  // packages/utils/src/lib/file-system.ts
652
990
  import { bundleRequire } from "bundle-require";
653
991
  import chalk2 from "chalk";
@@ -730,7 +1068,7 @@ async function ensureDirectoryExists(baseDir) {
730
1068
  await mkdir(baseDir, { recursive: true });
731
1069
  return;
732
1070
  } catch (error) {
733
- ui().logger.error(error.message);
1071
+ ui().logger.info(error.message);
734
1072
  if (error.code !== "EEXIST") {
735
1073
  throw error;
736
1074
  }
@@ -741,6 +1079,10 @@ function pluginWorkDir(slug) {
741
1079
  }
742
1080
 
743
1081
  // packages/utils/src/lib/reports/utils.ts
1082
+ var { image: image2, bold: boldMd } = md;
1083
+ function calcDuration(start, stop) {
1084
+ return Math.round((stop ?? performance.now()) - start);
1085
+ }
744
1086
  function compareIssueSeverity(severity1, severity2) {
745
1087
  const levels = {
746
1088
  info: 0,
@@ -750,33 +1092,95 @@ function compareIssueSeverity(severity1, severity2) {
750
1092
  return levels[severity1] - levels[severity2];
751
1093
  }
752
1094
 
753
- // packages/utils/src/lib/git.ts
1095
+ // packages/utils/src/lib/execute-process.ts
1096
+ var ProcessError = class extends Error {
1097
+ code;
1098
+ stderr;
1099
+ stdout;
1100
+ constructor(result) {
1101
+ super(result.stderr);
1102
+ this.code = result.code;
1103
+ this.stderr = result.stderr;
1104
+ this.stdout = result.stdout;
1105
+ }
1106
+ };
1107
+ function executeProcess(cfg) {
1108
+ const { observer, cwd, command, args, ignoreExitCode = false } = cfg;
1109
+ const { onStdout, onError, onComplete } = observer ?? {};
1110
+ const date = (/* @__PURE__ */ new Date()).toISOString();
1111
+ const start = performance.now();
1112
+ return new Promise((resolve, reject) => {
1113
+ const process2 = spawn(command, args, { cwd, shell: true });
1114
+ let stdout = "";
1115
+ let stderr = "";
1116
+ process2.stdout.on("data", (data) => {
1117
+ stdout += String(data);
1118
+ onStdout?.(String(data));
1119
+ });
1120
+ process2.stderr.on("data", (data) => {
1121
+ stderr += String(data);
1122
+ });
1123
+ process2.on("error", (err) => {
1124
+ stderr += err.toString();
1125
+ });
1126
+ process2.on("close", (code3) => {
1127
+ const timings = { date, duration: calcDuration(start) };
1128
+ if (code3 === 0 || ignoreExitCode) {
1129
+ onComplete?.();
1130
+ resolve({ code: code3, stdout, stderr, ...timings });
1131
+ } else {
1132
+ const errorMsg = new ProcessError({ code: code3, stdout, stderr, ...timings });
1133
+ onError?.(errorMsg);
1134
+ reject(errorMsg);
1135
+ }
1136
+ });
1137
+ });
1138
+ }
1139
+
1140
+ // packages/utils/src/lib/git/git.ts
754
1141
  import { simpleGit } from "simple-git";
755
1142
 
756
- // packages/utils/src/lib/transform.ts
757
- function toArray(val) {
758
- return Array.isArray(val) ? val : [val];
759
- }
760
- function objectToEntries(obj) {
761
- return Object.entries(obj);
762
- }
763
- function countOccurrences(values) {
764
- return values.reduce(
765
- (acc, value) => ({ ...acc, [value]: (acc[value] ?? 0) + 1 }),
766
- {}
767
- );
768
- }
769
- function distinct(array) {
770
- return [...new Set(array)];
771
- }
1143
+ // packages/utils/src/lib/git/git.commits-and-tags.ts
1144
+ import { simpleGit as simpleGit2 } from "simple-git";
1145
+
1146
+ // packages/utils/src/lib/semver.ts
1147
+ import { rcompare, valid } from "semver";
772
1148
 
773
1149
  // packages/utils/src/lib/progress.ts
774
1150
  import chalk3 from "chalk";
775
1151
  import { MultiProgressBars } from "multi-progress-bars";
776
1152
 
1153
+ // packages/utils/src/lib/reports/formatting.ts
1154
+ var { headline: headline2, lines: lines2, link: link3, section: section2, table: table3 } = md;
1155
+
1156
+ // packages/utils/src/lib/reports/generate-md-report-categoy-section.ts
1157
+ var { link: link4, section: section3, h2: h22, lines: lines3, li: li2, bold: boldMd2, h3: h32, indentation: indentation2 } = md;
1158
+
1159
+ // packages/utils/src/lib/reports/generate-md-report.ts
1160
+ var { h1: h12, h2: h23, h3: h33, lines: lines4, link: link5, section: section4, code: codeMd } = md;
1161
+ var { bold: boldHtml, details: details2 } = html;
1162
+
1163
+ // packages/utils/src/lib/reports/generate-md-reports-diff.ts
1164
+ var {
1165
+ h1: h13,
1166
+ h2: h24,
1167
+ lines: lines5,
1168
+ link: link6,
1169
+ bold: boldMd3,
1170
+ italic: italicMd,
1171
+ table: table4,
1172
+ section: section5
1173
+ } = md;
1174
+ var { details: details3 } = html;
1175
+
777
1176
  // packages/utils/src/lib/reports/log-stdout-summary.ts
778
1177
  import chalk4 from "chalk";
779
1178
 
1179
+ // packages/plugin-eslint/src/lib/runner/lint.ts
1180
+ import { rm as rm2, writeFile } from "node:fs/promises";
1181
+ import { platform } from "node:os";
1182
+ import { join as join2 } from "node:path";
1183
+
780
1184
  // packages/plugin-eslint/src/lib/setup.ts
781
1185
  import { ESLint } from "eslint";
782
1186
  function setupESLint(eslintrc) {
@@ -792,34 +1196,78 @@ async function lint({
792
1196
  eslintrc,
793
1197
  patterns
794
1198
  }) {
1199
+ const results = await executeLint({ eslintrc, patterns });
1200
+ const ruleOptionsPerFile = await loadRuleOptionsPerFile(eslintrc, results);
1201
+ return { results, ruleOptionsPerFile };
1202
+ }
1203
+ function executeLint({
1204
+ eslintrc,
1205
+ patterns
1206
+ }) {
1207
+ return withConfig(eslintrc, async (configPath) => {
1208
+ const { stdout } = await executeProcess({
1209
+ command: "npx",
1210
+ args: [
1211
+ "eslint",
1212
+ `--config=${configPath}`,
1213
+ "--no-eslintrc",
1214
+ "--no-error-on-unmatched-pattern",
1215
+ "--format=json",
1216
+ ...toArray(patterns).map(
1217
+ (pattern) => (
1218
+ // globs need to be escaped on Unix
1219
+ platform() === "win32" ? pattern : `'${pattern}'`
1220
+ )
1221
+ )
1222
+ ],
1223
+ ignoreExitCode: true,
1224
+ cwd: process.cwd()
1225
+ });
1226
+ return JSON.parse(stdout);
1227
+ });
1228
+ }
1229
+ function loadRuleOptionsPerFile(eslintrc, results) {
795
1230
  const eslint = setupESLint(eslintrc);
796
- const results = await eslint.lintFiles(patterns);
797
- const ruleOptionsPerFile = await results.reduce(
798
- async (acc, { filePath, messages }) => {
799
- const filesMap = await acc;
800
- const config = await eslint.calculateConfigForFile(
801
- filePath
802
- );
803
- const ruleIds = distinct(
804
- messages.map(({ ruleId }) => ruleId).filter((ruleId) => ruleId != null)
805
- );
806
- const rulesMap = Object.fromEntries(
807
- ruleIds.map((ruleId) => [
808
- ruleId,
809
- toArray(config.rules?.[ruleId] ?? []).slice(1)
810
- ])
811
- );
812
- return {
813
- ...filesMap,
814
- [filePath]: {
815
- ...filesMap[filePath],
816
- ...rulesMap
817
- }
818
- };
819
- },
820
- Promise.resolve({})
1231
+ return results.reduce(async (acc, { filePath, messages }) => {
1232
+ const filesMap = await acc;
1233
+ const config = await eslint.calculateConfigForFile(
1234
+ filePath
1235
+ );
1236
+ const ruleIds = distinct(
1237
+ messages.map(({ ruleId }) => ruleId).filter((ruleId) => ruleId != null)
1238
+ );
1239
+ const rulesMap = Object.fromEntries(
1240
+ ruleIds.map((ruleId) => [
1241
+ ruleId,
1242
+ toArray(config.rules?.[ruleId] ?? []).slice(1)
1243
+ ])
1244
+ );
1245
+ return {
1246
+ ...filesMap,
1247
+ [filePath]: {
1248
+ ...filesMap[filePath],
1249
+ ...rulesMap
1250
+ }
1251
+ };
1252
+ }, Promise.resolve({}));
1253
+ }
1254
+ async function withConfig(eslintrc, fn) {
1255
+ if (typeof eslintrc === "string") {
1256
+ return fn(eslintrc);
1257
+ }
1258
+ const configPath = generateTempConfigPath();
1259
+ await writeFile(configPath, JSON.stringify(eslintrc));
1260
+ try {
1261
+ return await fn(configPath);
1262
+ } finally {
1263
+ await rm2(configPath);
1264
+ }
1265
+ }
1266
+ function generateTempConfigPath() {
1267
+ return join2(
1268
+ process.cwd(),
1269
+ `.eslintrc.${Math.random().toString().slice(2)}.json`
821
1270
  );
822
- return { results, ruleOptionsPerFile };
823
1271
  }
824
1272
 
825
1273
  // packages/plugin-eslint/src/lib/meta/hash.ts
@@ -836,6 +1284,15 @@ function jsonHash(data, bytes = 8) {
836
1284
  }
837
1285
 
838
1286
  // packages/plugin-eslint/src/lib/runner/transform.ts
1287
+ function mergeLinterOutputs(outputs) {
1288
+ return outputs.reduce(
1289
+ (acc, { results, ruleOptionsPerFile }) => ({
1290
+ results: [...acc.results, ...results],
1291
+ ruleOptionsPerFile: { ...acc.ruleOptionsPerFile, ...ruleOptionsPerFile }
1292
+ }),
1293
+ { results: [], ruleOptionsPerFile: {} }
1294
+ );
1295
+ }
839
1296
  function lintResultsToAudits({
840
1297
  results,
841
1298
  ruleOptionsPerFile
@@ -845,7 +1302,9 @@ function lintResultsToAudits({
845
1302
  ).reduce((acc, issue) => {
846
1303
  const { ruleId, message, filePath } = issue;
847
1304
  if (!ruleId) {
848
- ui().logger.warning(`ESLint core error - ${message}`);
1305
+ ui().logger.warning(
1306
+ `ESLint core error - ${message} (file: ${filePath})`
1307
+ );
849
1308
  return acc;
850
1309
  }
851
1310
  const options = ruleOptionsPerFile[filePath]?.[ruleId] ?? [];
@@ -903,20 +1362,21 @@ function convertSeverity(severity) {
903
1362
 
904
1363
  // packages/plugin-eslint/src/lib/runner/index.ts
905
1364
  var WORKDIR = pluginWorkDir("eslint");
906
- var RUNNER_OUTPUT_PATH = join2(WORKDIR, "runner-output.json");
907
- var ESLINTRC_PATH = join2(process.cwd(), WORKDIR, ".eslintrc.json");
908
- var PLUGIN_CONFIG_PATH = join2(
1365
+ var RUNNER_OUTPUT_PATH = join3(WORKDIR, "runner-output.json");
1366
+ var PLUGIN_CONFIG_PATH = join3(
909
1367
  process.cwd(),
910
1368
  WORKDIR,
911
1369
  "plugin-config.json"
912
1370
  );
913
1371
  async function executeRunner() {
914
- const { slugs, eslintrc, patterns } = await readJsonFile(PLUGIN_CONFIG_PATH);
915
- const lintResults = await lint({
916
- // if file created from inline object, provide inline to preserve relative links
917
- eslintrc: eslintrc === ESLINTRC_PATH ? await readJsonFile(eslintrc) : eslintrc,
918
- patterns
919
- });
1372
+ const { slugs, targets } = await readJsonFile(
1373
+ PLUGIN_CONFIG_PATH
1374
+ );
1375
+ const linterOutputs = await targets.reduce(
1376
+ async (acc, target) => [...await acc, await lint(target)],
1377
+ Promise.resolve([])
1378
+ );
1379
+ const lintResults = mergeLinterOutputs(linterOutputs);
920
1380
  const failedAudits = lintResultsToAudits(lintResults);
921
1381
  const audits = slugs.map(
922
1382
  (slug) => failedAudits.find((audit) => audit.slug === slug) ?? {
@@ -928,7 +1388,7 @@ async function executeRunner() {
928
1388
  }
929
1389
  );
930
1390
  await ensureDirectoryExists(dirname(RUNNER_OUTPUT_PATH));
931
- await writeFile(RUNNER_OUTPUT_PATH, JSON.stringify(audits));
1391
+ await writeFile2(RUNNER_OUTPUT_PATH, JSON.stringify(audits));
932
1392
  }
933
1393
 
934
1394
  // packages/plugin-eslint/src/bin.ts