@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 +587 -127
- package/index.js +497 -149
- package/package.json +4 -4
- package/src/lib/config.d.ts +32 -4
- package/src/lib/meta/index.d.ts +2 -2
- package/src/lib/meta/rules.d.ts +3 -2
- package/src/lib/nx/find-all-projects.d.ts +2 -2
- package/src/lib/nx/find-project-with-deps.d.ts +2 -2
- package/src/lib/nx/projects-to-config.d.ts +2 -2
- package/src/lib/runner/index.d.ts +2 -2
- package/src/lib/runner/lint.d.ts +2 -2
- package/src/lib/runner/transform.d.ts +1 -0
- package/src/lib/setup.d.ts +2 -2
package/index.js
CHANGED
|
@@ -1,35 +1,298 @@
|
|
|
1
1
|
// packages/plugin-eslint/src/lib/eslint-plugin.ts
|
|
2
|
-
import { mkdir as mkdir2, writeFile as writeFile2 } from "node:fs/promises";
|
|
3
2
|
import { dirname as dirname2, join as join3 } from "node:path";
|
|
4
3
|
import { fileURLToPath } from "node:url";
|
|
5
4
|
|
|
6
5
|
// packages/plugin-eslint/package.json
|
|
7
6
|
var name = "@code-pushup/eslint-plugin";
|
|
8
|
-
var version = "0.
|
|
7
|
+
var version = "0.42.0";
|
|
9
8
|
|
|
10
9
|
// packages/plugin-eslint/src/lib/config.ts
|
|
11
|
-
import { z } from "zod";
|
|
12
|
-
var eslintPluginConfigSchema = z.object({
|
|
13
|
-
eslintrc: z.union(
|
|
14
|
-
[
|
|
15
|
-
z.string({ description: "Path to ESLint config file" }),
|
|
16
|
-
z.record(z.string(), z.unknown(), {
|
|
17
|
-
description: "ESLint config object"
|
|
18
|
-
})
|
|
19
|
-
],
|
|
20
|
-
{ description: "ESLint config as file path or inline object" }
|
|
21
|
-
),
|
|
22
|
-
patterns: z.union([z.string(), z.array(z.string()).min(1)], {
|
|
23
|
-
description: "Lint target files. May contain file paths, directory paths or glob patterns"
|
|
24
|
-
})
|
|
25
|
-
});
|
|
10
|
+
import { z as z16 } from "zod";
|
|
26
11
|
|
|
27
|
-
// packages/
|
|
28
|
-
|
|
12
|
+
// packages/utils/src/lib/text-formats/constants.ts
|
|
13
|
+
var NEW_LINE = "\n";
|
|
14
|
+
var TAB = " ";
|
|
15
|
+
|
|
16
|
+
// packages/utils/src/lib/text-formats/html/details.ts
|
|
17
|
+
function details(title, content, cfg = { open: false }) {
|
|
18
|
+
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.
|
|
19
|
+
NEW_LINE}${content}${NEW_LINE}${// @TODO in the future we could consider adding it only if the content ends with a code block
|
|
20
|
+
// ⚠️ The blank line ensure Markdown in content is rendered correctly.
|
|
21
|
+
NEW_LINE}</details>${// ⚠️ The blank line is needed to ensure Markdown after details is rendered correctly.
|
|
22
|
+
NEW_LINE}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// packages/utils/src/lib/text-formats/html/font-style.ts
|
|
26
|
+
var boldElement = "b";
|
|
27
|
+
function bold(text) {
|
|
28
|
+
return `<${boldElement}>${text}</${boldElement}>`;
|
|
29
|
+
}
|
|
30
|
+
var italicElement = "i";
|
|
31
|
+
function italic(text) {
|
|
32
|
+
return `<${italicElement}>${text}</${italicElement}>`;
|
|
33
|
+
}
|
|
34
|
+
var codeElement = "code";
|
|
35
|
+
function code(text) {
|
|
36
|
+
return `<${codeElement}>${text}</${codeElement}>`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// packages/utils/src/lib/text-formats/html/link.ts
|
|
40
|
+
function link(href, text) {
|
|
41
|
+
return `<a href="${href}">${text || href}"</a>`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// packages/utils/src/lib/transform.ts
|
|
45
|
+
function toArray(val) {
|
|
46
|
+
return Array.isArray(val) ? val : [val];
|
|
47
|
+
}
|
|
48
|
+
function objectToKeys(obj) {
|
|
49
|
+
return Object.keys(obj);
|
|
50
|
+
}
|
|
51
|
+
function distinct(array) {
|
|
52
|
+
return [...new Set(array)];
|
|
53
|
+
}
|
|
54
|
+
function capitalize(text) {
|
|
55
|
+
return `${text.charAt(0).toLocaleUpperCase()}${text.slice(
|
|
56
|
+
1
|
|
57
|
+
)}`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// packages/utils/src/lib/table.ts
|
|
61
|
+
function rowToStringArray({ rows, columns = [] }) {
|
|
62
|
+
if (Array.isArray(rows.at(0)) && typeof columns.at(0) === "object") {
|
|
63
|
+
throw new TypeError(
|
|
64
|
+
"Column can`t be object when rows are primitive values"
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
return rows.map((row) => {
|
|
68
|
+
if (Array.isArray(row)) {
|
|
69
|
+
return row.map(String);
|
|
70
|
+
}
|
|
71
|
+
const objectRow = row;
|
|
72
|
+
if (columns.length === 0 || typeof columns.at(0) === "string") {
|
|
73
|
+
return Object.values(objectRow).map(String);
|
|
74
|
+
}
|
|
75
|
+
return columns.map(
|
|
76
|
+
({ key }) => String(objectRow[key])
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
function columnsToStringArray({ rows, columns = [] }) {
|
|
81
|
+
const firstRow = rows.at(0);
|
|
82
|
+
const primitiveRows = Array.isArray(firstRow);
|
|
83
|
+
if (typeof columns.at(0) === "string" && !primitiveRows) {
|
|
84
|
+
throw new Error("invalid union type. Caught by model parsing.");
|
|
85
|
+
}
|
|
86
|
+
if (columns.length === 0) {
|
|
87
|
+
if (Array.isArray(firstRow)) {
|
|
88
|
+
return firstRow.map((_, idx) => String(idx));
|
|
89
|
+
}
|
|
90
|
+
return Object.keys(firstRow);
|
|
91
|
+
}
|
|
92
|
+
if (typeof columns.at(0) === "string") {
|
|
93
|
+
return columns.map(String);
|
|
94
|
+
}
|
|
95
|
+
const cols = columns;
|
|
96
|
+
return cols.map(({ label, key }) => label ?? capitalize(key));
|
|
97
|
+
}
|
|
98
|
+
function getColumnAlignmentForKeyAndIndex(targetKey, targetIdx, columns = []) {
|
|
99
|
+
const column = columns.at(targetIdx) ?? columns.find((col) => col.key === targetKey);
|
|
100
|
+
if (typeof column === "string") {
|
|
101
|
+
return column;
|
|
102
|
+
} else if (typeof column === "object") {
|
|
103
|
+
return column.align ?? "center";
|
|
104
|
+
} else {
|
|
105
|
+
return "center";
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function getColumnAlignmentForIndex(targetIdx, columns = []) {
|
|
109
|
+
const column = columns.at(targetIdx);
|
|
110
|
+
if (column == null) {
|
|
111
|
+
return "center";
|
|
112
|
+
} else if (typeof column === "string") {
|
|
113
|
+
return column;
|
|
114
|
+
} else if (typeof column === "object") {
|
|
115
|
+
return column.align ?? "center";
|
|
116
|
+
} else {
|
|
117
|
+
return "center";
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function getColumnAlignments({
|
|
121
|
+
rows,
|
|
122
|
+
columns = []
|
|
123
|
+
}) {
|
|
124
|
+
if (rows.at(0) == null) {
|
|
125
|
+
throw new Error("first row can`t be undefined.");
|
|
126
|
+
}
|
|
127
|
+
if (Array.isArray(rows.at(0))) {
|
|
128
|
+
const firstPrimitiveRow = rows.at(0);
|
|
129
|
+
return Array.from({ length: firstPrimitiveRow.length }).map(
|
|
130
|
+
(_, idx) => getColumnAlignmentForIndex(idx, columns)
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
const firstObject = rows.at(0);
|
|
134
|
+
return Object.keys(firstObject).map(
|
|
135
|
+
(key, idx) => getColumnAlignmentForKeyAndIndex(key, idx, columns)
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// packages/utils/src/lib/text-formats/html/table.ts
|
|
140
|
+
function wrap(elem, content) {
|
|
141
|
+
return `<${elem}>${content}</${elem}>${NEW_LINE}`;
|
|
142
|
+
}
|
|
143
|
+
function wrapRow(content) {
|
|
144
|
+
const elem = "tr";
|
|
145
|
+
return `<${elem}>${NEW_LINE}${content}</${elem}>${NEW_LINE}`;
|
|
146
|
+
}
|
|
147
|
+
function table(tableData) {
|
|
148
|
+
if (tableData.rows.length === 0) {
|
|
149
|
+
throw new Error("Data can't be empty");
|
|
150
|
+
}
|
|
151
|
+
const tableHeaderCols = columnsToStringArray(tableData).map((s) => wrap("th", s)).join("");
|
|
152
|
+
const tableHeaderRow = wrapRow(tableHeaderCols);
|
|
153
|
+
const tableBody = rowToStringArray(tableData).map((arr) => {
|
|
154
|
+
const columns = arr.map((s) => wrap("td", s)).join("");
|
|
155
|
+
return wrapRow(columns);
|
|
156
|
+
}).join("");
|
|
157
|
+
return wrap("table", `${NEW_LINE}${tableHeaderRow}${tableBody}`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// packages/utils/src/lib/text-formats/md/font-style.ts
|
|
161
|
+
var boldWrap = "**";
|
|
162
|
+
function bold2(text) {
|
|
163
|
+
return `${boldWrap}${text}${boldWrap}`;
|
|
164
|
+
}
|
|
165
|
+
var italicWrap = "_";
|
|
166
|
+
function italic2(text) {
|
|
167
|
+
return `${italicWrap}${text}${italicWrap}`;
|
|
168
|
+
}
|
|
169
|
+
var strikeThroughWrap = "~";
|
|
170
|
+
function strikeThrough(text) {
|
|
171
|
+
return `${strikeThroughWrap}${text}${strikeThroughWrap}`;
|
|
172
|
+
}
|
|
173
|
+
var codeWrap = "`";
|
|
174
|
+
function code2(text) {
|
|
175
|
+
return `${codeWrap}${text}${codeWrap}`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// packages/utils/src/lib/text-formats/md/headline.ts
|
|
179
|
+
function headline(text, hierarchy = 1) {
|
|
180
|
+
return `${"#".repeat(hierarchy)} ${text}${NEW_LINE}`;
|
|
181
|
+
}
|
|
182
|
+
function h(text, hierarchy = 1) {
|
|
183
|
+
return headline(text, hierarchy);
|
|
184
|
+
}
|
|
185
|
+
function h1(text) {
|
|
186
|
+
return headline(text, 1);
|
|
187
|
+
}
|
|
188
|
+
function h2(text) {
|
|
189
|
+
return headline(text, 2);
|
|
190
|
+
}
|
|
191
|
+
function h3(text) {
|
|
192
|
+
return headline(text, 3);
|
|
193
|
+
}
|
|
194
|
+
function h4(text) {
|
|
195
|
+
return headline(text, 4);
|
|
196
|
+
}
|
|
197
|
+
function h5(text) {
|
|
198
|
+
return headline(text, 5);
|
|
199
|
+
}
|
|
200
|
+
function h6(text) {
|
|
201
|
+
return headline(text, 6);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// packages/utils/src/lib/text-formats/md/image.ts
|
|
205
|
+
function image(src, alt) {
|
|
206
|
+
return ``;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// packages/utils/src/lib/text-formats/md/link.ts
|
|
210
|
+
function link2(href, text) {
|
|
211
|
+
return `[${text || href}](${href})`;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// packages/utils/src/lib/text-formats/md/list.ts
|
|
215
|
+
function li(text, order = "unordered") {
|
|
216
|
+
const style = order === "unordered" ? "-" : "- [ ]";
|
|
217
|
+
return `${style} ${text}`;
|
|
218
|
+
}
|
|
219
|
+
function indentation(text, level = 1) {
|
|
220
|
+
return `${TAB.repeat(level)}${text}`;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// packages/utils/src/lib/text-formats/md/paragraphs.ts
|
|
224
|
+
function paragraphs(...sections) {
|
|
225
|
+
return sections.filter(Boolean).join(`${NEW_LINE}${NEW_LINE}`);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// packages/utils/src/lib/text-formats/md/section.ts
|
|
229
|
+
function section(...contents) {
|
|
230
|
+
return `${lines(...contents)}${NEW_LINE}`;
|
|
231
|
+
}
|
|
232
|
+
function lines(...contents) {
|
|
233
|
+
return `${contents.filter(Boolean).join(NEW_LINE)}`;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// packages/utils/src/lib/text-formats/md/table.ts
|
|
237
|
+
var alignString = /* @__PURE__ */ new Map([
|
|
238
|
+
["left", ":--"],
|
|
239
|
+
["center", ":--:"],
|
|
240
|
+
["right", "--:"]
|
|
241
|
+
]);
|
|
242
|
+
function tableRow(rows) {
|
|
243
|
+
return `|${rows.join("|")}|`;
|
|
244
|
+
}
|
|
245
|
+
function table2(data) {
|
|
246
|
+
if (data.rows.length === 0) {
|
|
247
|
+
throw new Error("Data can't be empty");
|
|
248
|
+
}
|
|
249
|
+
const alignmentRow = getColumnAlignments(data).map(
|
|
250
|
+
(s) => alignString.get(s) ?? String(alignString.get("center"))
|
|
251
|
+
);
|
|
252
|
+
return section(
|
|
253
|
+
`${lines(
|
|
254
|
+
tableRow(columnsToStringArray(data)),
|
|
255
|
+
tableRow(alignmentRow),
|
|
256
|
+
...rowToStringArray(data).map(tableRow)
|
|
257
|
+
)}`
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// packages/utils/src/lib/text-formats/index.ts
|
|
262
|
+
var md = {
|
|
263
|
+
bold: bold2,
|
|
264
|
+
italic: italic2,
|
|
265
|
+
strikeThrough,
|
|
266
|
+
code: code2,
|
|
267
|
+
link: link2,
|
|
268
|
+
image,
|
|
269
|
+
headline,
|
|
270
|
+
h,
|
|
271
|
+
h1,
|
|
272
|
+
h2,
|
|
273
|
+
h3,
|
|
274
|
+
h4,
|
|
275
|
+
h5,
|
|
276
|
+
h6,
|
|
277
|
+
indentation,
|
|
278
|
+
lines,
|
|
279
|
+
li,
|
|
280
|
+
section,
|
|
281
|
+
paragraphs,
|
|
282
|
+
table: table2
|
|
283
|
+
};
|
|
284
|
+
var html = {
|
|
285
|
+
bold,
|
|
286
|
+
italic,
|
|
287
|
+
code,
|
|
288
|
+
link,
|
|
289
|
+
details,
|
|
290
|
+
table
|
|
291
|
+
};
|
|
29
292
|
|
|
30
293
|
// packages/models/src/lib/implementation/schemas.ts
|
|
31
294
|
import { MATERIAL_ICONS } from "vscode-material-icons";
|
|
32
|
-
import { z
|
|
295
|
+
import { z } from "zod";
|
|
33
296
|
|
|
34
297
|
// packages/models/src/lib/implementation/limits.ts
|
|
35
298
|
var MAX_SLUG_LENGTH = 128;
|
|
@@ -92,25 +355,26 @@ function missingRefsForCategoriesErrorMsg(categories, plugins) {
|
|
|
92
355
|
}
|
|
93
356
|
|
|
94
357
|
// packages/models/src/lib/implementation/schemas.ts
|
|
358
|
+
var primitiveValueSchema = z.union([z.string(), z.number()]);
|
|
95
359
|
function executionMetaSchema(options = {
|
|
96
360
|
descriptionDate: "Execution start date and time",
|
|
97
361
|
descriptionDuration: "Execution duration in ms"
|
|
98
362
|
}) {
|
|
99
|
-
return
|
|
100
|
-
date:
|
|
101
|
-
duration:
|
|
363
|
+
return z.object({
|
|
364
|
+
date: z.string({ description: options.descriptionDate }),
|
|
365
|
+
duration: z.number({ description: options.descriptionDuration })
|
|
102
366
|
});
|
|
103
367
|
}
|
|
104
|
-
var slugSchema =
|
|
368
|
+
var slugSchema = z.string({ description: "Unique ID (human-readable, URL-safe)" }).regex(slugRegex, {
|
|
105
369
|
message: "The slug has to follow the pattern [0-9a-z] followed by multiple optional groups of -[0-9a-z]. e.g. my-slug"
|
|
106
370
|
}).max(MAX_SLUG_LENGTH, {
|
|
107
371
|
message: `slug can be max ${MAX_SLUG_LENGTH} characters long`
|
|
108
372
|
});
|
|
109
|
-
var descriptionSchema =
|
|
110
|
-
var urlSchema =
|
|
111
|
-
var docsUrlSchema = urlSchema.optional().or(
|
|
112
|
-
var titleSchema =
|
|
113
|
-
var scoreSchema =
|
|
373
|
+
var descriptionSchema = z.string({ description: "Description (markdown)" }).max(MAX_DESCRIPTION_LENGTH).optional();
|
|
374
|
+
var urlSchema = z.string().url();
|
|
375
|
+
var docsUrlSchema = urlSchema.optional().or(z.literal("")).describe("Documentation site");
|
|
376
|
+
var titleSchema = z.string({ description: "Descriptive name" }).max(MAX_TITLE_LENGTH);
|
|
377
|
+
var scoreSchema = z.number({
|
|
114
378
|
description: "Value between 0 and 1"
|
|
115
379
|
}).min(0).max(1);
|
|
116
380
|
function metaSchema(options) {
|
|
@@ -120,7 +384,7 @@ function metaSchema(options) {
|
|
|
120
384
|
docsUrlDescription,
|
|
121
385
|
description
|
|
122
386
|
} = options ?? {};
|
|
123
|
-
return
|
|
387
|
+
return z.object(
|
|
124
388
|
{
|
|
125
389
|
title: titleDescription ? titleSchema.describe(titleDescription) : titleSchema,
|
|
126
390
|
description: descriptionDescription ? descriptionSchema.describe(descriptionDescription) : descriptionSchema,
|
|
@@ -129,17 +393,17 @@ function metaSchema(options) {
|
|
|
129
393
|
{ description }
|
|
130
394
|
);
|
|
131
395
|
}
|
|
132
|
-
var filePathSchema =
|
|
133
|
-
var fileNameSchema =
|
|
396
|
+
var filePathSchema = z.string().trim().min(1, { message: "path is invalid" });
|
|
397
|
+
var fileNameSchema = z.string().trim().regex(filenameRegex, {
|
|
134
398
|
message: `The filename has to be valid`
|
|
135
399
|
}).min(1, { message: "file name is invalid" });
|
|
136
|
-
var positiveIntSchema =
|
|
137
|
-
var nonnegativeIntSchema =
|
|
400
|
+
var positiveIntSchema = z.number().int().positive();
|
|
401
|
+
var nonnegativeIntSchema = z.number().int().nonnegative();
|
|
138
402
|
function packageVersionSchema(options) {
|
|
139
403
|
const { versionDescription = "NPM version of the package", required } = options ?? {};
|
|
140
|
-
const packageSchema =
|
|
141
|
-
const versionSchema =
|
|
142
|
-
return
|
|
404
|
+
const packageSchema = z.string({ description: "NPM package name" });
|
|
405
|
+
const versionSchema = z.string({ description: versionDescription });
|
|
406
|
+
return z.object(
|
|
143
407
|
{
|
|
144
408
|
packageName: required ? packageSchema : packageSchema.optional(),
|
|
145
409
|
version: required ? versionSchema : versionSchema.optional()
|
|
@@ -151,7 +415,7 @@ var weightSchema = nonnegativeIntSchema.describe(
|
|
|
151
415
|
"Coefficient for the given score (use weight 0 if only for display)"
|
|
152
416
|
);
|
|
153
417
|
function weightedRefSchema(description, slugDescription) {
|
|
154
|
-
return
|
|
418
|
+
return z.object(
|
|
155
419
|
{
|
|
156
420
|
slug: slugSchema.describe(slugDescription),
|
|
157
421
|
weight: weightSchema.describe("Weight used to calculate score")
|
|
@@ -160,10 +424,10 @@ function weightedRefSchema(description, slugDescription) {
|
|
|
160
424
|
);
|
|
161
425
|
}
|
|
162
426
|
function scorableSchema(description, refSchema, duplicateCheckFn, duplicateMessageFn) {
|
|
163
|
-
return
|
|
427
|
+
return z.object(
|
|
164
428
|
{
|
|
165
429
|
slug: slugSchema.describe('Human-readable unique ID, e.g. "performance"'),
|
|
166
|
-
refs:
|
|
430
|
+
refs: z.array(refSchema).min(1).refine(
|
|
167
431
|
(refs) => !duplicateCheckFn(refs),
|
|
168
432
|
(refs) => ({
|
|
169
433
|
message: duplicateMessageFn(refs)
|
|
@@ -175,7 +439,7 @@ function scorableSchema(description, refSchema, duplicateCheckFn, duplicateMessa
|
|
|
175
439
|
{ description }
|
|
176
440
|
);
|
|
177
441
|
}
|
|
178
|
-
var materialIconSchema =
|
|
442
|
+
var materialIconSchema = z.enum(MATERIAL_ICONS, {
|
|
179
443
|
description: "Icon from VSCode Material Icons extension"
|
|
180
444
|
});
|
|
181
445
|
function hasNonZeroWeightedRef(refs) {
|
|
@@ -183,7 +447,8 @@ function hasNonZeroWeightedRef(refs) {
|
|
|
183
447
|
}
|
|
184
448
|
|
|
185
449
|
// packages/models/src/lib/audit.ts
|
|
186
|
-
|
|
450
|
+
import { z as z2 } from "zod";
|
|
451
|
+
var auditSchema = z2.object({
|
|
187
452
|
slug: slugSchema.describe("ID (unique within plugin)")
|
|
188
453
|
}).merge(
|
|
189
454
|
metaSchema({
|
|
@@ -193,7 +458,7 @@ var auditSchema = z3.object({
|
|
|
193
458
|
description: "List of scorable metrics for the given plugin"
|
|
194
459
|
})
|
|
195
460
|
);
|
|
196
|
-
var pluginAuditsSchema =
|
|
461
|
+
var pluginAuditsSchema = z2.array(auditSchema, {
|
|
197
462
|
description: "List of audits maintained in a plugin"
|
|
198
463
|
}).min(1).refine(
|
|
199
464
|
(auditMetadata) => !getDuplicateSlugsInAudits(auditMetadata),
|
|
@@ -215,11 +480,11 @@ function getDuplicateSlugsInAudits(audits) {
|
|
|
215
480
|
import { z as z5 } from "zod";
|
|
216
481
|
|
|
217
482
|
// packages/models/src/lib/issue.ts
|
|
218
|
-
import { z as
|
|
219
|
-
var sourceFileLocationSchema =
|
|
483
|
+
import { z as z3 } from "zod";
|
|
484
|
+
var sourceFileLocationSchema = z3.object(
|
|
220
485
|
{
|
|
221
486
|
file: filePathSchema.describe("Relative path to source file in Git repo"),
|
|
222
|
-
position:
|
|
487
|
+
position: z3.object(
|
|
223
488
|
{
|
|
224
489
|
startLine: positiveIntSchema.describe("Start line"),
|
|
225
490
|
startColumn: positiveIntSchema.describe("Start column").optional(),
|
|
@@ -231,24 +496,69 @@ var sourceFileLocationSchema = z4.object(
|
|
|
231
496
|
},
|
|
232
497
|
{ description: "Source file location" }
|
|
233
498
|
);
|
|
234
|
-
var issueSeveritySchema =
|
|
499
|
+
var issueSeveritySchema = z3.enum(["info", "warning", "error"], {
|
|
235
500
|
description: "Severity level"
|
|
236
501
|
});
|
|
237
|
-
var issueSchema =
|
|
502
|
+
var issueSchema = z3.object(
|
|
238
503
|
{
|
|
239
|
-
message:
|
|
504
|
+
message: z3.string({ description: "Descriptive error message" }).max(MAX_ISSUE_MESSAGE_LENGTH),
|
|
240
505
|
severity: issueSeveritySchema,
|
|
241
506
|
source: sourceFileLocationSchema.optional()
|
|
242
507
|
},
|
|
243
508
|
{ description: "Issue information" }
|
|
244
509
|
);
|
|
245
510
|
|
|
511
|
+
// packages/models/src/lib/table.ts
|
|
512
|
+
import { z as z4 } from "zod";
|
|
513
|
+
var tableAlignmentSchema = z4.enum(["left", "center", "right"], {
|
|
514
|
+
description: "Cell alignment"
|
|
515
|
+
});
|
|
516
|
+
var tableColumnObjectSchema = z4.object({
|
|
517
|
+
key: z4.string(),
|
|
518
|
+
label: z4.string().optional(),
|
|
519
|
+
align: tableAlignmentSchema.optional()
|
|
520
|
+
});
|
|
521
|
+
var tableRowObjectSchema = z4.record(primitiveValueSchema, {
|
|
522
|
+
description: "Object row"
|
|
523
|
+
});
|
|
524
|
+
var tableRowPrimitiveSchema = z4.array(primitiveValueSchema, {
|
|
525
|
+
description: "Primitive row"
|
|
526
|
+
});
|
|
527
|
+
var tableSharedSchema = z4.object({
|
|
528
|
+
title: z4.string().optional().describe("Display title for table")
|
|
529
|
+
});
|
|
530
|
+
var tablePrimitiveSchema = tableSharedSchema.merge(
|
|
531
|
+
z4.object(
|
|
532
|
+
{
|
|
533
|
+
columns: z4.array(tableAlignmentSchema).optional(),
|
|
534
|
+
rows: z4.array(tableRowPrimitiveSchema)
|
|
535
|
+
},
|
|
536
|
+
{ description: "Table with primitive rows and optional alignment columns" }
|
|
537
|
+
)
|
|
538
|
+
);
|
|
539
|
+
var tableObjectSchema = tableSharedSchema.merge(
|
|
540
|
+
z4.object(
|
|
541
|
+
{
|
|
542
|
+
columns: z4.union([
|
|
543
|
+
z4.array(tableAlignmentSchema),
|
|
544
|
+
z4.array(tableColumnObjectSchema)
|
|
545
|
+
]).optional(),
|
|
546
|
+
rows: z4.array(tableRowObjectSchema)
|
|
547
|
+
},
|
|
548
|
+
{
|
|
549
|
+
description: "Table with object rows and optional alignment or object columns"
|
|
550
|
+
}
|
|
551
|
+
)
|
|
552
|
+
);
|
|
553
|
+
var tableSchema = (description = "Table information") => z4.union([tablePrimitiveSchema, tableObjectSchema], { description });
|
|
554
|
+
|
|
246
555
|
// packages/models/src/lib/audit-output.ts
|
|
247
556
|
var auditValueSchema = nonnegativeIntSchema.describe("Raw numeric value");
|
|
248
557
|
var auditDisplayValueSchema = z5.string({ description: "Formatted value (e.g. '0.9 s', '2.1 MB')" }).optional();
|
|
249
558
|
var auditDetailsSchema = z5.object(
|
|
250
559
|
{
|
|
251
|
-
issues: z5.array(issueSchema, { description: "List of findings" })
|
|
560
|
+
issues: z5.array(issueSchema, { description: "List of findings" }).optional(),
|
|
561
|
+
table: tableSchema("Table of related findings").optional()
|
|
252
562
|
},
|
|
253
563
|
{ description: "Detailed information" }
|
|
254
564
|
);
|
|
@@ -600,10 +910,14 @@ function makeArraysComparisonSchema(diffSchema, resultSchema, description) {
|
|
|
600
910
|
{ description }
|
|
601
911
|
);
|
|
602
912
|
}
|
|
603
|
-
var scorableMetaSchema = z15.object({
|
|
913
|
+
var scorableMetaSchema = z15.object({
|
|
914
|
+
slug: slugSchema,
|
|
915
|
+
title: titleSchema,
|
|
916
|
+
docsUrl: docsUrlSchema
|
|
917
|
+
});
|
|
604
918
|
var scorableWithPluginMetaSchema = scorableMetaSchema.merge(
|
|
605
919
|
z15.object({
|
|
606
|
-
plugin: pluginMetaSchema.pick({ slug: true, title: true }).describe("Plugin which defines it")
|
|
920
|
+
plugin: pluginMetaSchema.pick({ slug: true, title: true, docsUrl: true }).describe("Plugin which defines it")
|
|
607
921
|
})
|
|
608
922
|
);
|
|
609
923
|
var scorableDiffSchema = scorableMetaSchema.merge(
|
|
@@ -740,7 +1054,7 @@ async function ensureDirectoryExists(baseDir) {
|
|
|
740
1054
|
await mkdir(baseDir, { recursive: true });
|
|
741
1055
|
return;
|
|
742
1056
|
} catch (error) {
|
|
743
|
-
ui().logger.
|
|
1057
|
+
ui().logger.info(error.message);
|
|
744
1058
|
if (error.code !== "EEXIST") {
|
|
745
1059
|
throw error;
|
|
746
1060
|
}
|
|
@@ -750,27 +1064,65 @@ function pluginWorkDir(slug) {
|
|
|
750
1064
|
return join("node_modules", ".code-pushup", slug);
|
|
751
1065
|
}
|
|
752
1066
|
|
|
753
|
-
// packages/utils/src/lib/
|
|
1067
|
+
// packages/utils/src/lib/reports/utils.ts
|
|
1068
|
+
var { image: image2, bold: boldMd } = md;
|
|
1069
|
+
|
|
1070
|
+
// packages/utils/src/lib/git/git.ts
|
|
754
1071
|
import { simpleGit } from "simple-git";
|
|
755
1072
|
|
|
756
|
-
// packages/utils/src/lib/
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
return Object.keys(obj);
|
|
762
|
-
}
|
|
763
|
-
function distinct(array) {
|
|
764
|
-
return [...new Set(array)];
|
|
765
|
-
}
|
|
1073
|
+
// packages/utils/src/lib/git/git.commits-and-tags.ts
|
|
1074
|
+
import { simpleGit as simpleGit2 } from "simple-git";
|
|
1075
|
+
|
|
1076
|
+
// packages/utils/src/lib/semver.ts
|
|
1077
|
+
import { rcompare, valid } from "semver";
|
|
766
1078
|
|
|
767
1079
|
// packages/utils/src/lib/progress.ts
|
|
768
1080
|
import chalk3 from "chalk";
|
|
769
1081
|
import { MultiProgressBars } from "multi-progress-bars";
|
|
770
1082
|
|
|
1083
|
+
// packages/utils/src/lib/reports/formatting.ts
|
|
1084
|
+
var { headline: headline2, lines: lines2, link: link3, section: section2, table: table3 } = md;
|
|
1085
|
+
|
|
1086
|
+
// packages/utils/src/lib/reports/generate-md-report-categoy-section.ts
|
|
1087
|
+
var { link: link4, section: section3, h2: h22, lines: lines3, li: li2, bold: boldMd2, h3: h32, indentation: indentation2 } = md;
|
|
1088
|
+
|
|
1089
|
+
// packages/utils/src/lib/reports/generate-md-report.ts
|
|
1090
|
+
var { h1: h12, h2: h23, h3: h33, lines: lines4, link: link5, section: section4, code: codeMd } = md;
|
|
1091
|
+
var { bold: boldHtml, details: details2 } = html;
|
|
1092
|
+
|
|
1093
|
+
// packages/utils/src/lib/reports/generate-md-reports-diff.ts
|
|
1094
|
+
var {
|
|
1095
|
+
h1: h13,
|
|
1096
|
+
h2: h24,
|
|
1097
|
+
lines: lines5,
|
|
1098
|
+
link: link6,
|
|
1099
|
+
bold: boldMd3,
|
|
1100
|
+
italic: italicMd,
|
|
1101
|
+
table: table4,
|
|
1102
|
+
section: section5
|
|
1103
|
+
} = md;
|
|
1104
|
+
var { details: details3 } = html;
|
|
1105
|
+
|
|
771
1106
|
// packages/utils/src/lib/reports/log-stdout-summary.ts
|
|
772
1107
|
import chalk4 from "chalk";
|
|
773
1108
|
|
|
1109
|
+
// packages/plugin-eslint/src/lib/config.ts
|
|
1110
|
+
var eslintTargetSchema = z16.object({
|
|
1111
|
+
eslintrc: z16.union(
|
|
1112
|
+
[
|
|
1113
|
+
z16.string({ description: "Path to ESLint config file" }),
|
|
1114
|
+
z16.record(z16.string(), z16.unknown(), {
|
|
1115
|
+
description: "ESLint config object"
|
|
1116
|
+
})
|
|
1117
|
+
],
|
|
1118
|
+
{ description: "ESLint config as file path or inline object" }
|
|
1119
|
+
),
|
|
1120
|
+
patterns: z16.union([z16.string(), z16.array(z16.string()).min(1)], {
|
|
1121
|
+
description: "Lint target files. May contain file paths, directory paths or glob patterns"
|
|
1122
|
+
})
|
|
1123
|
+
});
|
|
1124
|
+
var eslintPluginConfigSchema = z16.union([eslintTargetSchema, z16.array(eslintTargetSchema).min(1)]).transform(toArray);
|
|
1125
|
+
|
|
774
1126
|
// packages/plugin-eslint/src/lib/meta/hash.ts
|
|
775
1127
|
import { createHash } from "node:crypto";
|
|
776
1128
|
function ruleIdToSlug(ruleId, options) {
|
|
@@ -784,8 +1136,27 @@ function jsonHash(data, bytes = 8) {
|
|
|
784
1136
|
return createHash("shake256", { outputLength: bytes }).update(JSON.stringify(data) || "null").digest("hex");
|
|
785
1137
|
}
|
|
786
1138
|
|
|
1139
|
+
// packages/plugin-eslint/src/lib/setup.ts
|
|
1140
|
+
import { ESLint } from "eslint";
|
|
1141
|
+
function setupESLint(eslintrc) {
|
|
1142
|
+
return new ESLint({
|
|
1143
|
+
...typeof eslintrc === "string" ? { overrideConfigFile: eslintrc } : { baseConfig: eslintrc },
|
|
1144
|
+
useEslintrc: false,
|
|
1145
|
+
errorOnUnmatchedPattern: false
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
|
|
787
1149
|
// packages/plugin-eslint/src/lib/meta/rules.ts
|
|
788
|
-
async function listRules(
|
|
1150
|
+
async function listRules(targets) {
|
|
1151
|
+
const rulesMap = await targets.reduce(async (acc, { eslintrc, patterns }) => {
|
|
1152
|
+
const eslint = setupESLint(eslintrc);
|
|
1153
|
+
const prev = await acc;
|
|
1154
|
+
const curr = await loadRulesMap(eslint, patterns);
|
|
1155
|
+
return mergeRulesMaps(prev, curr);
|
|
1156
|
+
}, Promise.resolve({}));
|
|
1157
|
+
return Object.values(rulesMap).flatMap(Object.values);
|
|
1158
|
+
}
|
|
1159
|
+
async function loadRulesMap(eslint, patterns) {
|
|
789
1160
|
const configs = await toArray(patterns).reduce(
|
|
790
1161
|
async (acc, pattern) => [
|
|
791
1162
|
...await acc,
|
|
@@ -803,31 +1174,39 @@ async function listRules(eslint, patterns) {
|
|
|
803
1174
|
suppressedMessages: []
|
|
804
1175
|
}
|
|
805
1176
|
]);
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
1177
|
+
return configs.flatMap((config) => Object.entries(config.rules ?? {})).filter(([, ruleEntry]) => ruleEntry != null && !isRuleOff(ruleEntry)).reduce((acc, [ruleId, ruleEntry]) => {
|
|
1178
|
+
const meta = rulesMeta[ruleId];
|
|
1179
|
+
if (!meta) {
|
|
1180
|
+
ui().logger.warning(`Metadata not found for ESLint rule ${ruleId}`);
|
|
1181
|
+
return acc;
|
|
1182
|
+
}
|
|
1183
|
+
const options = toArray(ruleEntry).slice(1);
|
|
1184
|
+
const optionsHash = jsonHash(options);
|
|
1185
|
+
const ruleData = {
|
|
1186
|
+
ruleId,
|
|
1187
|
+
meta,
|
|
1188
|
+
options
|
|
1189
|
+
};
|
|
1190
|
+
return {
|
|
1191
|
+
...acc,
|
|
1192
|
+
[ruleId]: {
|
|
1193
|
+
...acc[ruleId],
|
|
1194
|
+
[optionsHash]: ruleData
|
|
812
1195
|
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
...acc,
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
};
|
|
827
|
-
},
|
|
828
|
-
{}
|
|
1196
|
+
};
|
|
1197
|
+
}, {});
|
|
1198
|
+
}
|
|
1199
|
+
function mergeRulesMaps(prev, curr) {
|
|
1200
|
+
return Object.entries(curr).reduce(
|
|
1201
|
+
(acc, [ruleId, ruleVariants]) => ({
|
|
1202
|
+
...acc,
|
|
1203
|
+
[ruleId]: {
|
|
1204
|
+
...acc[ruleId],
|
|
1205
|
+
...ruleVariants
|
|
1206
|
+
}
|
|
1207
|
+
}),
|
|
1208
|
+
prev
|
|
829
1209
|
);
|
|
830
|
-
return Object.values(rulesMap).flatMap(Object.values);
|
|
831
1210
|
}
|
|
832
1211
|
function isRuleOff(entry) {
|
|
833
1212
|
const level = Array.isArray(entry) ? entry[0] : entry;
|
|
@@ -923,7 +1302,7 @@ function ruleToAudit({ ruleId, meta, options }) {
|
|
|
923
1302
|
const name2 = ruleId.split("/").at(-1) ?? ruleId;
|
|
924
1303
|
const plugin = name2 === ruleId ? null : ruleId.slice(0, ruleId.lastIndexOf("/"));
|
|
925
1304
|
const pluginContext = plugin ? `, from _${plugin}_ plugin` : "";
|
|
926
|
-
const
|
|
1305
|
+
const lines6 = [
|
|
927
1306
|
`ESLint rule **${name2}**${pluginContext}.`,
|
|
928
1307
|
...options?.length ? ["Custom options:"] : [],
|
|
929
1308
|
...options?.map(
|
|
@@ -933,7 +1312,7 @@ function ruleToAudit({ ruleId, meta, options }) {
|
|
|
933
1312
|
return {
|
|
934
1313
|
slug: ruleIdToSlug(ruleId, options),
|
|
935
1314
|
title: truncateTitle(meta.docs?.description ?? name2),
|
|
936
|
-
description: truncateDescription(
|
|
1315
|
+
description: truncateDescription(lines6.join("\n\n")),
|
|
937
1316
|
...meta.docs?.url && {
|
|
938
1317
|
docsUrl: meta.docs.url
|
|
939
1318
|
}
|
|
@@ -941,8 +1320,8 @@ function ruleToAudit({ ruleId, meta, options }) {
|
|
|
941
1320
|
}
|
|
942
1321
|
|
|
943
1322
|
// packages/plugin-eslint/src/lib/meta/index.ts
|
|
944
|
-
async function listAuditsAndGroups(
|
|
945
|
-
const rules = await listRules(
|
|
1323
|
+
async function listAuditsAndGroups(targets) {
|
|
1324
|
+
const rules = await listRules(targets);
|
|
946
1325
|
const audits = rules.map(ruleToAudit);
|
|
947
1326
|
const groups = [
|
|
948
1327
|
...groupsFromRuleTypes(rules),
|
|
@@ -954,31 +1333,17 @@ async function listAuditsAndGroups(eslint, patterns) {
|
|
|
954
1333
|
// packages/plugin-eslint/src/lib/runner/index.ts
|
|
955
1334
|
import { writeFile } from "node:fs/promises";
|
|
956
1335
|
import { dirname, join as join2 } from "node:path";
|
|
957
|
-
|
|
958
|
-
// packages/plugin-eslint/src/lib/setup.ts
|
|
959
|
-
import { ESLint } from "eslint";
|
|
960
|
-
function setupESLint(eslintrc) {
|
|
961
|
-
return new ESLint({
|
|
962
|
-
...typeof eslintrc === "string" ? { overrideConfigFile: eslintrc } : { baseConfig: eslintrc },
|
|
963
|
-
useEslintrc: false,
|
|
964
|
-
errorOnUnmatchedPattern: false
|
|
965
|
-
});
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
// packages/plugin-eslint/src/lib/runner/index.ts
|
|
969
1336
|
var WORKDIR = pluginWorkDir("eslint");
|
|
970
1337
|
var RUNNER_OUTPUT_PATH = join2(WORKDIR, "runner-output.json");
|
|
971
|
-
var ESLINTRC_PATH = join2(process.cwd(), WORKDIR, ".eslintrc.json");
|
|
972
1338
|
var PLUGIN_CONFIG_PATH = join2(
|
|
973
1339
|
process.cwd(),
|
|
974
1340
|
WORKDIR,
|
|
975
1341
|
"plugin-config.json"
|
|
976
1342
|
);
|
|
977
|
-
async function createRunnerConfig(scriptPath, audits,
|
|
1343
|
+
async function createRunnerConfig(scriptPath, audits, targets) {
|
|
978
1344
|
const config = {
|
|
979
|
-
|
|
980
|
-
slugs: audits.map((audit) => audit.slug)
|
|
981
|
-
patterns: toArray(patterns)
|
|
1345
|
+
targets,
|
|
1346
|
+
slugs: audits.map((audit) => audit.slug)
|
|
982
1347
|
};
|
|
983
1348
|
await ensureDirectoryExists(dirname(PLUGIN_CONFIG_PATH));
|
|
984
1349
|
await writeFile(PLUGIN_CONFIG_PATH, JSON.stringify(config));
|
|
@@ -991,14 +1356,8 @@ async function createRunnerConfig(scriptPath, audits, eslintrc, patterns) {
|
|
|
991
1356
|
|
|
992
1357
|
// packages/plugin-eslint/src/lib/eslint-plugin.ts
|
|
993
1358
|
async function eslintPlugin(config) {
|
|
994
|
-
const
|
|
995
|
-
const
|
|
996
|
-
const { audits, groups } = await listAuditsAndGroups(eslint, patterns);
|
|
997
|
-
if (typeof eslintrc !== "string") {
|
|
998
|
-
await mkdir2(dirname2(ESLINTRC_PATH), { recursive: true });
|
|
999
|
-
await writeFile2(ESLINTRC_PATH, JSON.stringify(eslintrc));
|
|
1000
|
-
}
|
|
1001
|
-
const eslintrcPath = typeof eslintrc === "string" ? eslintrc : ESLINTRC_PATH;
|
|
1359
|
+
const targets = eslintPluginConfigSchema.parse(config);
|
|
1360
|
+
const { audits, groups } = await listAuditsAndGroups(targets);
|
|
1002
1361
|
const runnerScriptPath = join3(
|
|
1003
1362
|
fileURLToPath(dirname2(import.meta.url)),
|
|
1004
1363
|
"bin.js"
|
|
@@ -1013,12 +1372,7 @@ async function eslintPlugin(config) {
|
|
|
1013
1372
|
version,
|
|
1014
1373
|
audits,
|
|
1015
1374
|
groups,
|
|
1016
|
-
runner: await createRunnerConfig(
|
|
1017
|
-
runnerScriptPath,
|
|
1018
|
-
audits,
|
|
1019
|
-
eslintrcPath,
|
|
1020
|
-
patterns
|
|
1021
|
-
)
|
|
1375
|
+
runner: await createRunnerConfig(runnerScriptPath, audits, targets)
|
|
1022
1376
|
};
|
|
1023
1377
|
}
|
|
1024
1378
|
|
|
@@ -1049,33 +1403,27 @@ async function nxProjectsToConfig(projectGraph, predicate = () => true) {
|
|
|
1049
1403
|
const { readProjectsConfigurationFromProjectGraph } = await import("@nx/devkit");
|
|
1050
1404
|
const projectsConfiguration = readProjectsConfigurationFromProjectGraph(projectGraph);
|
|
1051
1405
|
const projects = Object.values(projectsConfiguration.projects).filter((project) => "lint" in (project.targets ?? {})).filter(predicate).sort((a, b) => a.root.localeCompare(b.root));
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1406
|
+
return Promise.all(
|
|
1407
|
+
projects.map(
|
|
1408
|
+
async (project) => ({
|
|
1409
|
+
eslintrc: await findCodePushupEslintrc(project) ?? getEslintConfig(project),
|
|
1410
|
+
patterns: [
|
|
1411
|
+
...getLintFilePatterns(project),
|
|
1412
|
+
// HACK: ESLint.calculateConfigForFile won't find rules included only for subsets of *.ts when globs used
|
|
1413
|
+
// so we explicitly provide additional patterns used by @code-pushup/eslint-config to ensure those rules are included
|
|
1414
|
+
// this workaround won't be necessary once flat configs are stable (much easier to find all rules)
|
|
1415
|
+
`${project.sourceRoot}/*.spec.ts`,
|
|
1416
|
+
// jest/* and vitest/* rules
|
|
1417
|
+
`${project.sourceRoot}/*.cy.ts`,
|
|
1418
|
+
// cypress/* rules
|
|
1419
|
+
`${project.sourceRoot}/*.stories.ts`,
|
|
1420
|
+
// storybook/* rules
|
|
1421
|
+
`${project.sourceRoot}/.storybook/main.ts`
|
|
1422
|
+
// storybook/no-uninstalled-addons rule
|
|
1423
|
+
]
|
|
1424
|
+
})
|
|
1059
1425
|
)
|
|
1060
|
-
|
|
1061
|
-
const patterns = projects.flatMap((project) => [
|
|
1062
|
-
...getLintFilePatterns(project),
|
|
1063
|
-
// HACK: ESLint.calculateConfigForFile won't find rules included only for subsets of *.ts when globs used
|
|
1064
|
-
// so we explicitly provide additional patterns used by @code-pushup/eslint-config to ensure those rules are included
|
|
1065
|
-
// this workaround won't be necessary once flat configs are stable (much easier to find all rules)
|
|
1066
|
-
`${project.sourceRoot}/*.spec.ts`,
|
|
1067
|
-
// jest/* and vitest/* rules
|
|
1068
|
-
`${project.sourceRoot}/*.cy.ts`,
|
|
1069
|
-
// cypress/* rules
|
|
1070
|
-
`${project.sourceRoot}/*.stories.ts`,
|
|
1071
|
-
// storybook/* rules
|
|
1072
|
-
`${project.sourceRoot}/.storybook/main.ts`
|
|
1073
|
-
// storybook/no-uninstalled-addons rule
|
|
1074
|
-
]);
|
|
1075
|
-
return {
|
|
1076
|
-
eslintrc: eslintConfig,
|
|
1077
|
-
patterns
|
|
1078
|
-
};
|
|
1426
|
+
);
|
|
1079
1427
|
}
|
|
1080
1428
|
|
|
1081
1429
|
// packages/plugin-eslint/src/lib/nx/find-all-projects.ts
|