@code-pushup/eslint-plugin 0.54.0 → 0.55.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,6 +1,6 @@
1
1
  // packages/plugin-eslint/src/lib/runner/index.ts
2
- import { writeFile as writeFile2 } from "node:fs/promises";
3
- import { dirname, join as join3 } from "node:path";
2
+ import { writeFile } from "node:fs/promises";
3
+ import { dirname as dirname2, join as join2 } from "node:path";
4
4
 
5
5
  // packages/models/src/lib/implementation/schemas.ts
6
6
  import { MATERIAL_ICONS } from "vscode-material-icons";
@@ -33,7 +33,7 @@ function exists(value) {
33
33
  return value != null;
34
34
  }
35
35
  function getMissingRefsForCategories(categories, plugins) {
36
- if (categories.length === 0) {
36
+ if (!categories || categories.length === 0) {
37
37
  return false;
38
38
  }
39
39
  const auditRefsFromCategory = categories.flatMap(
@@ -532,12 +532,9 @@ var unrefinedCoreConfigSchema = z14.object({
532
532
  var coreConfigSchema = refineCoreConfig(unrefinedCoreConfigSchema);
533
533
  function refineCoreConfig(schema) {
534
534
  return schema.refine(
535
- (coreCfg) => !getMissingRefsForCategories(coreCfg.categories ?? [], coreCfg.plugins),
536
- (coreCfg) => ({
537
- message: missingRefsForCategoriesErrorMsg(
538
- coreCfg.categories ?? [],
539
- coreCfg.plugins
540
- )
535
+ ({ categories, plugins }) => !getMissingRefsForCategories(categories, plugins),
536
+ ({ categories, plugins }) => ({
537
+ message: missingRefsForCategoriesErrorMsg(categories, plugins)
541
538
  })
542
539
  );
543
540
  }
@@ -589,19 +586,16 @@ var reportSchema = packageVersionSchema({
589
586
  ).merge(
590
587
  z15.object(
591
588
  {
592
- categories: z15.array(categoryConfigSchema),
593
589
  plugins: z15.array(pluginReportSchema).min(1),
590
+ categories: z15.array(categoryConfigSchema).optional(),
594
591
  commit: commitSchema.describe("Git commit for which report was collected").nullable()
595
592
  },
596
593
  { description: "Collect output data" }
597
594
  )
598
595
  ).refine(
599
- (report) => !getMissingRefsForCategories(report.categories, report.plugins),
600
- (report) => ({
601
- message: missingRefsForCategoriesErrorMsg(
602
- report.categories,
603
- report.plugins
604
- )
596
+ ({ categories, plugins }) => !getMissingRefsForCategories(categories, plugins),
597
+ ({ categories, plugins }) => ({
598
+ message: missingRefsForCategoriesErrorMsg(categories, plugins)
605
599
  })
606
600
  );
607
601
 
@@ -780,7 +774,7 @@ function executeProcess(cfg) {
780
774
  import { bold, gray } from "ansis";
781
775
  import { bundleRequire } from "bundle-require";
782
776
  import { mkdir, readFile, readdir, rm, stat } from "node:fs/promises";
783
- import { join } from "node:path";
777
+ import { dirname, join } from "node:path";
784
778
 
785
779
  // packages/utils/src/lib/formatting.ts
786
780
  function slugify(text) {
@@ -934,22 +928,24 @@ import { MarkdownDocument as MarkdownDocument4, md as md5 } from "build-md";
934
928
  import { bold as bold4, cyan, cyanBright, green as green2, red } from "ansis";
935
929
 
936
930
  // packages/plugin-eslint/src/lib/runner/lint.ts
937
- import { rm as rm2, writeFile } from "node:fs/promises";
938
931
  import { platform } from "node:os";
939
- import { join as join2 } from "node:path";
940
932
 
941
933
  // packages/plugin-eslint/src/lib/setup.ts
942
934
  import { ESLint } from "eslint";
943
- function setupESLint(eslintrc) {
944
- return new ESLint({
945
- ...typeof eslintrc === "string" && { overrideConfigFile: eslintrc },
946
- ...typeof eslintrc === "object" && {
947
- baseConfig: eslintrc,
948
- useEslintrc: false
949
- },
935
+ async function setupESLint(eslintrc) {
936
+ const eslintConstructor = await loadESLint();
937
+ return new eslintConstructor({
938
+ overrideConfigFile: eslintrc,
950
939
  errorOnUnmatchedPattern: false
951
940
  });
952
941
  }
942
+ async function loadESLint() {
943
+ const eslint = await import("eslint");
944
+ if ("loadESLint" in eslint && typeof eslint.loadESLint === "function") {
945
+ return await eslint.loadESLint();
946
+ }
947
+ return ESLint;
948
+ }
953
949
 
954
950
  // packages/plugin-eslint/src/lib/runner/lint.ts
955
951
  async function lint({
@@ -957,37 +953,35 @@ async function lint({
957
953
  patterns
958
954
  }) {
959
955
  const results = await executeLint({ eslintrc, patterns });
960
- const ruleOptionsPerFile = await loadRuleOptionsPerFile(eslintrc, results);
956
+ const eslint = await setupESLint(eslintrc);
957
+ const ruleOptionsPerFile = await loadRuleOptionsPerFile(eslint, results);
961
958
  return { results, ruleOptionsPerFile };
962
959
  }
963
- function executeLint({
960
+ async function executeLint({
964
961
  eslintrc,
965
962
  patterns
966
963
  }) {
967
- return withConfig(eslintrc, async (configPath) => {
968
- const { stdout } = await executeProcess({
969
- command: "npx",
970
- args: [
971
- "eslint",
972
- ...configPath ? [`--config=${filePathToCliArg(configPath)}`] : [],
973
- ...typeof eslintrc === "object" ? ["--no-eslintrc"] : [],
974
- "--no-error-on-unmatched-pattern",
975
- "--format=json",
976
- ...toArray(patterns).map(
977
- (pattern) => (
978
- // globs need to be escaped on Unix
979
- platform() === "win32" ? pattern : `'${pattern}'`
980
- )
964
+ const { stdout } = await executeProcess({
965
+ command: "npx",
966
+ args: [
967
+ "eslint",
968
+ ...eslintrc ? [`--config=${filePathToCliArg(eslintrc)}`] : [],
969
+ ...typeof eslintrc === "object" ? ["--no-eslintrc"] : [],
970
+ "--no-error-on-unmatched-pattern",
971
+ "--format=json",
972
+ ...toArray(patterns).map(
973
+ (pattern) => (
974
+ // globs need to be escaped on Unix
975
+ platform() === "win32" ? pattern : `'${pattern}'`
981
976
  )
982
- ],
983
- ignoreExitCode: true,
984
- cwd: process.cwd()
985
- });
986
- return JSON.parse(stdout);
977
+ )
978
+ ],
979
+ ignoreExitCode: true,
980
+ cwd: process.cwd()
987
981
  });
982
+ return JSON.parse(stdout);
988
983
  }
989
- function loadRuleOptionsPerFile(eslintrc, results) {
990
- const eslint = setupESLint(eslintrc);
984
+ function loadRuleOptionsPerFile(eslint, results) {
991
985
  return results.reduce(async (acc, { filePath, messages }) => {
992
986
  const filesMap = await acc;
993
987
  const config = await eslint.calculateConfigForFile(
@@ -1011,24 +1005,6 @@ function loadRuleOptionsPerFile(eslintrc, results) {
1011
1005
  };
1012
1006
  }, Promise.resolve({}));
1013
1007
  }
1014
- async function withConfig(eslintrc, fn) {
1015
- if (typeof eslintrc !== "object") {
1016
- return fn(eslintrc);
1017
- }
1018
- const configPath = generateTempConfigPath();
1019
- await writeFile(configPath, JSON.stringify(eslintrc));
1020
- try {
1021
- return await fn(configPath);
1022
- } finally {
1023
- await rm2(configPath);
1024
- }
1025
- }
1026
- function generateTempConfigPath() {
1027
- return join2(
1028
- process.cwd(),
1029
- `.eslintrc.${Math.random().toString().slice(2)}.json`
1030
- );
1031
- }
1032
1008
 
1033
1009
  // packages/plugin-eslint/src/lib/meta/hash.ts
1034
1010
  import { createHash } from "node:crypto";
@@ -1122,8 +1098,8 @@ function convertSeverity(severity) {
1122
1098
 
1123
1099
  // packages/plugin-eslint/src/lib/runner/index.ts
1124
1100
  var WORKDIR = pluginWorkDir("eslint");
1125
- var RUNNER_OUTPUT_PATH = join3(WORKDIR, "runner-output.json");
1126
- var PLUGIN_CONFIG_PATH = join3(
1101
+ var RUNNER_OUTPUT_PATH = join2(WORKDIR, "runner-output.json");
1102
+ var PLUGIN_CONFIG_PATH = join2(
1127
1103
  process.cwd(),
1128
1104
  WORKDIR,
1129
1105
  "plugin-config.json"
@@ -1145,8 +1121,8 @@ async function executeRunner() {
1145
1121
  details: { issues: [] }
1146
1122
  }
1147
1123
  );
1148
- await ensureDirectoryExists(dirname(RUNNER_OUTPUT_PATH));
1149
- await writeFile2(RUNNER_OUTPUT_PATH, JSON.stringify(audits));
1124
+ await ensureDirectoryExists(dirname2(RUNNER_OUTPUT_PATH));
1125
+ await writeFile(RUNNER_OUTPUT_PATH, JSON.stringify(audits));
1150
1126
  }
1151
1127
 
1152
1128
  // packages/plugin-eslint/src/bin.ts
package/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  // packages/plugin-eslint/src/lib/eslint-plugin.ts
2
- import { dirname as dirname2, join as join3 } from "node:path";
2
+ import { dirname as dirname3, join as join4 } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
 
5
5
  // packages/plugin-eslint/package.json
6
6
  var name = "@code-pushup/eslint-plugin";
7
- var version = "0.54.0";
7
+ var version = "0.55.0";
8
8
 
9
9
  // packages/plugin-eslint/src/lib/config.ts
10
10
  import { z as z17 } from "zod";
@@ -40,7 +40,7 @@ function exists(value) {
40
40
  return value != null;
41
41
  }
42
42
  function getMissingRefsForCategories(categories, plugins) {
43
- if (categories.length === 0) {
43
+ if (!categories || categories.length === 0) {
44
44
  return false;
45
45
  }
46
46
  const auditRefsFromCategory = categories.flatMap(
@@ -539,12 +539,9 @@ var unrefinedCoreConfigSchema = z14.object({
539
539
  var coreConfigSchema = refineCoreConfig(unrefinedCoreConfigSchema);
540
540
  function refineCoreConfig(schema) {
541
541
  return schema.refine(
542
- (coreCfg) => !getMissingRefsForCategories(coreCfg.categories ?? [], coreCfg.plugins),
543
- (coreCfg) => ({
544
- message: missingRefsForCategoriesErrorMsg(
545
- coreCfg.categories ?? [],
546
- coreCfg.plugins
547
- )
542
+ ({ categories, plugins }) => !getMissingRefsForCategories(categories, plugins),
543
+ ({ categories, plugins }) => ({
544
+ message: missingRefsForCategoriesErrorMsg(categories, plugins)
548
545
  })
549
546
  );
550
547
  }
@@ -596,19 +593,16 @@ var reportSchema = packageVersionSchema({
596
593
  ).merge(
597
594
  z15.object(
598
595
  {
599
- categories: z15.array(categoryConfigSchema),
600
596
  plugins: z15.array(pluginReportSchema).min(1),
597
+ categories: z15.array(categoryConfigSchema).optional(),
601
598
  commit: commitSchema.describe("Git commit for which report was collected").nullable()
602
599
  },
603
600
  { description: "Collect output data" }
604
601
  )
605
602
  ).refine(
606
- (report) => !getMissingRefsForCategories(report.categories, report.plugins),
607
- (report) => ({
608
- message: missingRefsForCategoriesErrorMsg(
609
- report.categories,
610
- report.plugins
611
- )
603
+ ({ categories, plugins }) => !getMissingRefsForCategories(categories, plugins),
604
+ ({ categories, plugins }) => ({
605
+ message: missingRefsForCategoriesErrorMsg(categories, plugins)
612
606
  })
613
607
  );
614
608
 
@@ -719,7 +713,7 @@ var TERMINAL_WIDTH = 80;
719
713
  import { bold, gray } from "ansis";
720
714
  import { bundleRequire } from "bundle-require";
721
715
  import { mkdir, readFile, readdir, rm, stat } from "node:fs/promises";
722
- import { join } from "node:path";
716
+ import { dirname, join } from "node:path";
723
717
 
724
718
  // packages/utils/src/lib/formatting.ts
725
719
  function slugify(text) {
@@ -802,6 +796,16 @@ async function ensureDirectoryExists(baseDir) {
802
796
  function pluginWorkDir(slug) {
803
797
  return join("node_modules", ".code-pushup", slug);
804
798
  }
799
+ async function findNearestFile(fileNames, cwd = process.cwd()) {
800
+ for (let directory = cwd; directory !== dirname(directory); directory = dirname(directory)) {
801
+ for (const file of fileNames) {
802
+ if (await fileExists(join(directory, file))) {
803
+ return join(directory, file);
804
+ }
805
+ }
806
+ }
807
+ return void 0;
808
+ }
805
809
  function filePathToCliArg(path) {
806
810
  return `"${path}"`;
807
811
  }
@@ -858,15 +862,7 @@ import { bold as bold4, cyan, cyanBright, green as green2, red } from "ansis";
858
862
  var patternsSchema = z17.union([z17.string(), z17.array(z17.string()).min(1)], {
859
863
  description: "Lint target files. May contain file paths, directory paths or glob patterns"
860
864
  });
861
- var eslintrcSchema = z17.union(
862
- [
863
- z17.string({ description: "Path to ESLint config file" }),
864
- z17.record(z17.string(), z17.unknown(), {
865
- description: "ESLint config object"
866
- })
867
- ],
868
- { description: "ESLint config as file path or inline object" }
869
- );
865
+ var eslintrcSchema = z17.string({ description: "Path to ESLint config file" });
870
866
  var eslintTargetObjectSchema = z17.object({
871
867
  eslintrc: eslintrcSchema.optional(),
872
868
  patterns: patternsSchema
@@ -889,80 +885,16 @@ function jsonHash(data, bytes = 8) {
889
885
  return createHash("shake256", { outputLength: bytes }).update(JSON.stringify(data) || "null").digest("hex");
890
886
  }
891
887
 
892
- // packages/plugin-eslint/src/lib/setup.ts
893
- import { ESLint } from "eslint";
894
- function setupESLint(eslintrc) {
895
- return new ESLint({
896
- ...typeof eslintrc === "string" && { overrideConfigFile: eslintrc },
897
- ...typeof eslintrc === "object" && {
898
- baseConfig: eslintrc,
899
- useEslintrc: false
900
- },
901
- errorOnUnmatchedPattern: false
902
- });
903
- }
904
-
905
- // packages/plugin-eslint/src/lib/meta/rules.ts
906
- async function listRules(targets) {
907
- const rulesMap = await targets.reduce(async (acc, { eslintrc, patterns }) => {
908
- const eslint = setupESLint(eslintrc);
909
- const prev = await acc;
910
- const curr = await loadRulesMap(eslint, patterns);
911
- return mergeRulesMaps(prev, curr);
912
- }, Promise.resolve({}));
913
- return Object.values(rulesMap).flatMap(Object.values);
914
- }
915
- async function loadRulesMap(eslint, patterns) {
916
- const configs = await toArray(patterns).reduce(
917
- async (acc, pattern) => [
918
- ...await acc,
919
- await eslint.calculateConfigForFile(pattern)
920
- ],
921
- Promise.resolve([])
922
- );
923
- const rulesIds = distinct(
924
- configs.flatMap((config) => Object.keys(config.rules ?? {}))
925
- );
926
- const rulesMeta = eslint.getRulesMetaForResults([
927
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
928
- {
929
- messages: rulesIds.map((ruleId) => ({ ruleId })),
930
- suppressedMessages: []
931
- }
932
- ]);
933
- return configs.flatMap((config) => Object.entries(config.rules ?? {})).filter(([, ruleEntry]) => ruleEntry != null && !isRuleOff(ruleEntry)).reduce((acc, [ruleId, ruleEntry]) => {
934
- const meta = rulesMeta[ruleId];
935
- if (!meta) {
936
- ui().logger.warning(`Metadata not found for ESLint rule ${ruleId}`);
937
- return acc;
938
- }
939
- const options = toArray(ruleEntry).slice(1);
940
- const optionsHash = jsonHash(options);
941
- const ruleData = {
942
- ruleId,
943
- meta,
944
- options
945
- };
946
- return {
947
- ...acc,
948
- [ruleId]: {
949
- ...acc[ruleId],
950
- [optionsHash]: ruleData
951
- }
952
- };
953
- }, {});
954
- }
955
- function mergeRulesMaps(prev, curr) {
956
- return Object.entries(curr).reduce(
957
- (acc, [ruleId, ruleVariants]) => ({
958
- ...acc,
959
- [ruleId]: {
960
- ...acc[ruleId],
961
- ...ruleVariants
962
- }
963
- }),
964
- prev
965
- );
888
+ // packages/plugin-eslint/src/lib/meta/parse.ts
889
+ function parseRuleId(ruleId) {
890
+ const i = ruleId.lastIndexOf("/");
891
+ if (i < 0) {
892
+ return { name: ruleId };
893
+ }
894
+ return {
895
+ plugin: ruleId.slice(0, i),
896
+ name: ruleId.slice(i + 1)
897
+ };
966
898
  }
967
899
  function isRuleOff(entry) {
968
900
  const level = Array.isArray(entry) ? entry[0] : entry;
@@ -977,15 +909,8 @@ function isRuleOff(entry) {
977
909
  return false;
978
910
  }
979
911
  }
980
- function parseRuleId(ruleId) {
981
- const i = ruleId.lastIndexOf("/");
982
- if (i < 0) {
983
- return { name: ruleId };
984
- }
985
- return {
986
- plugin: ruleId.slice(0, i),
987
- name: ruleId.slice(i + 1)
988
- };
912
+ function optionsFromRuleEntry(entry) {
913
+ return toArray(entry).slice(1);
989
914
  }
990
915
 
991
916
  // packages/plugin-eslint/src/lib/meta/groups.ts
@@ -1053,6 +978,191 @@ function groupsFromRuleCategories(rules) {
1053
978
  return groups.toSorted((a, b) => a.slug.localeCompare(b.slug));
1054
979
  }
1055
980
 
981
+ // packages/plugin-eslint/src/lib/meta/versions/flat.ts
982
+ import { builtinRules } from "eslint/use-at-your-own-risk";
983
+ import { isAbsolute, join as join2 } from "node:path";
984
+ import { pathToFileURL } from "node:url";
985
+ async function loadRulesForFlatConfig({
986
+ eslintrc
987
+ }) {
988
+ const config = eslintrc ? await loadConfigByPath(eslintrc) : await loadConfigByDefaultLocation();
989
+ const configs = toArray(config);
990
+ const rules = findEnabledRulesWithOptions(configs);
991
+ return rules.map((rule) => {
992
+ const meta = findRuleMeta(rule.ruleId, configs);
993
+ if (!meta) {
994
+ ui().logger.warning(`Cannot find metadata for rule ${rule.ruleId}`);
995
+ return null;
996
+ }
997
+ return { ...rule, meta };
998
+ }).filter(exists);
999
+ }
1000
+ async function loadConfigByDefaultLocation() {
1001
+ const flatConfigFileNames = [
1002
+ "eslint.config.js",
1003
+ "eslint.config.mjs",
1004
+ "eslint.config.cjs"
1005
+ ];
1006
+ const configPath = await findNearestFile(flatConfigFileNames);
1007
+ if (configPath) {
1008
+ return loadConfigByPath(configPath);
1009
+ }
1010
+ throw new Error(
1011
+ [
1012
+ `ESLint config file not found - expected ${flatConfigFileNames.join("/")} in ${process.cwd()} or some parent directory`,
1013
+ "If your ESLint config is in a non-standard location, use the `eslintrc` parameter to specify the path."
1014
+ ].join("\n")
1015
+ );
1016
+ }
1017
+ async function loadConfigByPath(path) {
1018
+ const absolutePath = isAbsolute(path) ? path : join2(process.cwd(), path);
1019
+ const url = pathToFileURL(absolutePath).toString();
1020
+ const mod = await import(url);
1021
+ return "default" in mod ? mod.default : mod;
1022
+ }
1023
+ function findEnabledRulesWithOptions(configs) {
1024
+ const enabledRules = configs.flatMap(({ rules }) => Object.entries(rules ?? {})).filter(([, entry]) => entry != null && !isRuleOff(entry)).map(([ruleId, entry]) => ({
1025
+ ruleId,
1026
+ options: entry ? optionsFromRuleEntry(entry) : []
1027
+ }));
1028
+ const uniqueRulesMap = new Map(
1029
+ enabledRules.map(({ ruleId, options }) => [
1030
+ `${ruleId}::${jsonHash(options)}`,
1031
+ { ruleId, options }
1032
+ ])
1033
+ );
1034
+ return [...uniqueRulesMap.values()];
1035
+ }
1036
+ function findRuleMeta(ruleId, configs) {
1037
+ const { plugin, name: name2 } = parseRuleId(ruleId);
1038
+ if (!plugin) {
1039
+ return findBuiltinRuleMeta(name2);
1040
+ }
1041
+ return findPluginRuleMeta(plugin, name2, configs);
1042
+ }
1043
+ function findBuiltinRuleMeta(name2) {
1044
+ const rule = builtinRules.get(name2);
1045
+ return rule?.meta;
1046
+ }
1047
+ function findPluginRuleMeta(plugin, name2, configs) {
1048
+ const config = configs.find(({ plugins = {} }) => plugin in plugins);
1049
+ const rule = config?.plugins?.[plugin]?.rules?.[name2];
1050
+ if (typeof rule === "function") {
1051
+ ui().logger.warning(
1052
+ `Cannot parse metadata for rule ${plugin}/${name2}, plugin registers it as a function`
1053
+ );
1054
+ return void 0;
1055
+ }
1056
+ return rule?.meta;
1057
+ }
1058
+
1059
+ // packages/plugin-eslint/src/lib/setup.ts
1060
+ import { ESLint } from "eslint";
1061
+ async function setupESLint(eslintrc) {
1062
+ const eslintConstructor = await loadESLint();
1063
+ return new eslintConstructor({
1064
+ overrideConfigFile: eslintrc,
1065
+ errorOnUnmatchedPattern: false
1066
+ });
1067
+ }
1068
+ async function loadESLint() {
1069
+ const eslint = await import("eslint");
1070
+ if ("loadESLint" in eslint && typeof eslint.loadESLint === "function") {
1071
+ return await eslint.loadESLint();
1072
+ }
1073
+ return ESLint;
1074
+ }
1075
+
1076
+ // packages/plugin-eslint/src/lib/meta/versions/legacy.ts
1077
+ async function loadRulesForLegacyConfig({
1078
+ eslintrc,
1079
+ patterns
1080
+ }) {
1081
+ const eslint = await setupESLint(eslintrc);
1082
+ const configs = await toArray(patterns).reduce(
1083
+ async (acc, pattern) => [
1084
+ ...await acc,
1085
+ await eslint.calculateConfigForFile(pattern)
1086
+ ],
1087
+ Promise.resolve([])
1088
+ );
1089
+ const rulesIds = distinct(
1090
+ configs.flatMap((config) => Object.keys(config.rules ?? {}))
1091
+ );
1092
+ const rulesMeta = eslint.getRulesMetaForResults([
1093
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
1094
+ {
1095
+ messages: rulesIds.map((ruleId) => ({ ruleId })),
1096
+ suppressedMessages: []
1097
+ }
1098
+ ]);
1099
+ return configs.flatMap((config) => Object.entries(config.rules ?? {})).map(([ruleId, ruleEntry]) => {
1100
+ if (ruleEntry == null || isRuleOff(ruleEntry)) {
1101
+ return null;
1102
+ }
1103
+ const meta = rulesMeta[ruleId];
1104
+ if (!meta) {
1105
+ ui().logger.warning(`Metadata not found for ESLint rule ${ruleId}`);
1106
+ return null;
1107
+ }
1108
+ const options = optionsFromRuleEntry(ruleEntry);
1109
+ return {
1110
+ ruleId,
1111
+ meta,
1112
+ options
1113
+ };
1114
+ }).filter(exists);
1115
+ }
1116
+
1117
+ // packages/plugin-eslint/src/lib/meta/versions/detect.ts
1118
+ import { ESLint as ESLint2 } from "eslint";
1119
+ async function detectConfigVersion() {
1120
+ if (process.env["ESLINT_USE_FLAT_CONFIG"] === "true") {
1121
+ return "flat";
1122
+ }
1123
+ if (process.env["ESLINT_USE_FLAT_CONFIG"] === "false") {
1124
+ return "legacy";
1125
+ }
1126
+ if (ESLint2.version.startsWith("8.")) {
1127
+ if (await fileExists("eslint.config.js")) {
1128
+ return "flat";
1129
+ }
1130
+ return "legacy";
1131
+ }
1132
+ return "flat";
1133
+ }
1134
+
1135
+ // packages/plugin-eslint/src/lib/meta/versions/index.ts
1136
+ function selectRulesLoader(version2) {
1137
+ switch (version2) {
1138
+ case "flat":
1139
+ return loadRulesForFlatConfig;
1140
+ case "legacy":
1141
+ return loadRulesForLegacyConfig;
1142
+ }
1143
+ }
1144
+
1145
+ // packages/plugin-eslint/src/lib/meta/rules.ts
1146
+ async function listRules(targets) {
1147
+ const version2 = await detectConfigVersion();
1148
+ const loadRulesMap = selectRulesLoader(version2);
1149
+ const rulesMap = await targets.reduce(async (acc, target) => {
1150
+ const map = await acc;
1151
+ const rules = await loadRulesMap(target);
1152
+ return rules.reduce(mergeRuleIntoMap, map);
1153
+ }, Promise.resolve({}));
1154
+ return Object.values(rulesMap).flatMap(Object.values);
1155
+ }
1156
+ function mergeRuleIntoMap(map, rule) {
1157
+ return {
1158
+ ...map,
1159
+ [rule.ruleId]: {
1160
+ ...map[rule.ruleId],
1161
+ [jsonHash(rule.options)]: rule
1162
+ }
1163
+ };
1164
+ }
1165
+
1056
1166
  // packages/plugin-eslint/src/lib/meta/transform.ts
1057
1167
  function ruleToAudit({ ruleId, meta, options }) {
1058
1168
  const name2 = ruleId.split("/").at(-1) ?? ruleId;
@@ -1088,10 +1198,10 @@ async function listAuditsAndGroups(targets) {
1088
1198
 
1089
1199
  // packages/plugin-eslint/src/lib/runner/index.ts
1090
1200
  import { writeFile } from "node:fs/promises";
1091
- import { dirname, join as join2 } from "node:path";
1201
+ import { dirname as dirname2, join as join3 } from "node:path";
1092
1202
  var WORKDIR = pluginWorkDir("eslint");
1093
- var RUNNER_OUTPUT_PATH = join2(WORKDIR, "runner-output.json");
1094
- var PLUGIN_CONFIG_PATH = join2(
1203
+ var RUNNER_OUTPUT_PATH = join3(WORKDIR, "runner-output.json");
1204
+ var PLUGIN_CONFIG_PATH = join3(
1095
1205
  process.cwd(),
1096
1206
  WORKDIR,
1097
1207
  "plugin-config.json"
@@ -1101,7 +1211,7 @@ async function createRunnerConfig(scriptPath, audits, targets) {
1101
1211
  targets,
1102
1212
  slugs: audits.map((audit) => audit.slug)
1103
1213
  };
1104
- await ensureDirectoryExists(dirname(PLUGIN_CONFIG_PATH));
1214
+ await ensureDirectoryExists(dirname2(PLUGIN_CONFIG_PATH));
1105
1215
  await writeFile(PLUGIN_CONFIG_PATH, JSON.stringify(config));
1106
1216
  return {
1107
1217
  command: "node",
@@ -1114,8 +1224,8 @@ async function createRunnerConfig(scriptPath, audits, targets) {
1114
1224
  async function eslintPlugin(config) {
1115
1225
  const targets = eslintPluginConfigSchema.parse(config);
1116
1226
  const { audits, groups } = await listAuditsAndGroups(targets);
1117
- const runnerScriptPath = join3(
1118
- fileURLToPath(dirname2(import.meta.url)),
1227
+ const runnerScriptPath = join4(
1228
+ fileURLToPath(dirname3(import.meta.url)),
1119
1229
  "bin.js"
1120
1230
  );
1121
1231
  return {
@@ -1152,13 +1262,13 @@ function filterProjectGraph(projectGraph, exclude = []) {
1152
1262
  }
1153
1263
 
1154
1264
  // packages/plugin-eslint/src/lib/nx/utils.ts
1155
- import { join as join4 } from "node:path";
1265
+ import { join as join5 } from "node:path";
1156
1266
  async function findCodePushupEslintrc(project) {
1157
1267
  const name2 = "code-pushup.eslintrc";
1158
1268
  const extensions = ["json", "js", "cjs", "yml", "yaml"];
1159
1269
  for (const ext of extensions) {
1160
1270
  const filename = `./${project.root}/${name2}.${ext}`;
1161
- if (await fileExists(join4(process.cwd(), filename))) {
1271
+ if (await fileExists(join5(process.cwd(), filename))) {
1162
1272
  return filename;
1163
1273
  }
1164
1274
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-pushup/eslint-plugin",
3
- "version": "0.54.0",
3
+ "version": "0.55.0",
4
4
  "license": "MIT",
5
5
  "description": "Code PushUp plugin for detecting problems in source code using ESLint.📋",
6
6
  "homepage": "https://github.com/code-pushup/cli/tree/main/packages/plugin-eslint#readme",
@@ -40,13 +40,13 @@
40
40
  "main": "./index.js",
41
41
  "types": "./src/index.d.ts",
42
42
  "dependencies": {
43
- "@code-pushup/utils": "0.54.0",
44
- "@code-pushup/models": "0.54.0",
45
- "eslint": "^8.46.0",
43
+ "@code-pushup/utils": "0.55.0",
44
+ "@code-pushup/models": "0.55.0",
46
45
  "zod": "^3.22.4"
47
46
  },
48
47
  "peerDependencies": {
49
- "@nx/devkit": ">=17.0.0"
48
+ "@nx/devkit": ">=17.0.0",
49
+ "eslint": "^8.46.0 || ^9.0.0"
50
50
  },
51
51
  "peerDependenciesMeta": {
52
52
  "@nx/devkit": {
@@ -1,61 +1,60 @@
1
- import type { ESLint } from 'eslint';
2
- import { type ZodType, z } from 'zod';
1
+ import { z } from 'zod';
3
2
  export declare const eslintTargetSchema: z.ZodEffects<z.ZodUnion<[z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>, z.ZodObject<{
4
- eslintrc: z.ZodOptional<z.ZodUnion<[z.ZodString, ZodType<ESLint.ConfigData<import("eslint").Linter.RulesRecord>, z.ZodTypeDef, ESLint.ConfigData<import("eslint").Linter.RulesRecord>>]>>;
3
+ eslintrc: z.ZodOptional<z.ZodString>;
5
4
  patterns: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>;
6
5
  }, "strip", z.ZodTypeAny, {
7
6
  patterns: string | string[];
8
- eslintrc?: string | ESLint.ConfigData<import("eslint").Linter.RulesRecord> | undefined;
7
+ eslintrc?: string | undefined;
9
8
  }, {
10
9
  patterns: string | string[];
11
- eslintrc?: string | ESLint.ConfigData<import("eslint").Linter.RulesRecord> | undefined;
10
+ eslintrc?: string | undefined;
12
11
  }>]>, {
13
12
  patterns: string | string[];
14
- eslintrc?: string | ESLint.ConfigData<import("eslint").Linter.RulesRecord> | undefined;
13
+ eslintrc?: string | undefined;
15
14
  }, string | string[] | {
16
15
  patterns: string | string[];
17
- eslintrc?: string | ESLint.ConfigData<import("eslint").Linter.RulesRecord> | undefined;
16
+ eslintrc?: string | undefined;
18
17
  }>;
19
18
  export type ESLintTarget = z.infer<typeof eslintTargetSchema>;
20
19
  export declare const eslintPluginConfigSchema: z.ZodEffects<z.ZodUnion<[z.ZodEffects<z.ZodUnion<[z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>, z.ZodObject<{
21
- eslintrc: z.ZodOptional<z.ZodUnion<[z.ZodString, ZodType<ESLint.ConfigData<import("eslint").Linter.RulesRecord>, z.ZodTypeDef, ESLint.ConfigData<import("eslint").Linter.RulesRecord>>]>>;
20
+ eslintrc: z.ZodOptional<z.ZodString>;
22
21
  patterns: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>;
23
22
  }, "strip", z.ZodTypeAny, {
24
23
  patterns: string | string[];
25
- eslintrc?: string | ESLint.ConfigData<import("eslint").Linter.RulesRecord> | undefined;
24
+ eslintrc?: string | undefined;
26
25
  }, {
27
26
  patterns: string | string[];
28
- eslintrc?: string | ESLint.ConfigData<import("eslint").Linter.RulesRecord> | undefined;
27
+ eslintrc?: string | undefined;
29
28
  }>]>, {
30
29
  patterns: string | string[];
31
- eslintrc?: string | ESLint.ConfigData<import("eslint").Linter.RulesRecord> | undefined;
30
+ eslintrc?: string | undefined;
32
31
  }, string | string[] | {
33
32
  patterns: string | string[];
34
- eslintrc?: string | ESLint.ConfigData<import("eslint").Linter.RulesRecord> | undefined;
33
+ eslintrc?: string | undefined;
35
34
  }>, z.ZodArray<z.ZodEffects<z.ZodUnion<[z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>, z.ZodObject<{
36
- eslintrc: z.ZodOptional<z.ZodUnion<[z.ZodString, ZodType<ESLint.ConfigData<import("eslint").Linter.RulesRecord>, z.ZodTypeDef, ESLint.ConfigData<import("eslint").Linter.RulesRecord>>]>>;
35
+ eslintrc: z.ZodOptional<z.ZodString>;
37
36
  patterns: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>;
38
37
  }, "strip", z.ZodTypeAny, {
39
38
  patterns: string | string[];
40
- eslintrc?: string | ESLint.ConfigData<import("eslint").Linter.RulesRecord> | undefined;
39
+ eslintrc?: string | undefined;
41
40
  }, {
42
41
  patterns: string | string[];
43
- eslintrc?: string | ESLint.ConfigData<import("eslint").Linter.RulesRecord> | undefined;
42
+ eslintrc?: string | undefined;
44
43
  }>]>, {
45
44
  patterns: string | string[];
46
- eslintrc?: string | ESLint.ConfigData<import("eslint").Linter.RulesRecord> | undefined;
45
+ eslintrc?: string | undefined;
47
46
  }, string | string[] | {
48
47
  patterns: string | string[];
49
- eslintrc?: string | ESLint.ConfigData<import("eslint").Linter.RulesRecord> | undefined;
48
+ eslintrc?: string | undefined;
50
49
  }>, "many">]>, {
51
50
  patterns: string | string[];
52
- eslintrc?: string | ESLint.ConfigData<import("eslint").Linter.RulesRecord> | undefined;
51
+ eslintrc?: string | undefined;
53
52
  }[], string | string[] | {
54
53
  patterns: string | string[];
55
- eslintrc?: string | ESLint.ConfigData<import("eslint").Linter.RulesRecord> | undefined;
54
+ eslintrc?: string | undefined;
56
55
  } | (string | string[] | {
57
56
  patterns: string | string[];
58
- eslintrc?: string | ESLint.ConfigData<import("eslint").Linter.RulesRecord> | undefined;
57
+ eslintrc?: string | undefined;
59
58
  })[]>;
60
59
  export type ESLintPluginConfig = z.input<typeof eslintPluginConfigSchema>;
61
60
  export type ESLintPluginRunnerConfig = {
@@ -1,4 +1,4 @@
1
1
  import type { Group } from '@code-pushup/models';
2
- import { type RuleData } from './rules';
2
+ import { type RuleData } from './parse';
3
3
  export declare function groupsFromRuleTypes(rules: RuleData[]): Group[];
4
4
  export declare function groupsFromRuleCategories(rules: RuleData[]): Group[];
@@ -0,0 +1,12 @@
1
+ import type { Linter, Rule } from 'eslint';
2
+ export type RuleData = {
3
+ ruleId: string;
4
+ meta: Rule.RuleMetaData;
5
+ options: unknown[] | undefined;
6
+ };
7
+ export declare function parseRuleId(ruleId: string): {
8
+ plugin?: string;
9
+ name: string;
10
+ };
11
+ export declare function isRuleOff(entry: Linter.RuleEntry<unknown[]>): boolean;
12
+ export declare function optionsFromRuleEntry(entry: Linter.RuleEntry<unknown[]>): unknown[];
@@ -1,12 +1,3 @@
1
- import type { Rule } from 'eslint';
2
1
  import type { ESLintTarget } from '../config';
3
- export type RuleData = {
4
- ruleId: string;
5
- meta: Rule.RuleMetaData;
6
- options: unknown[] | undefined;
7
- };
2
+ import type { RuleData } from './parse';
8
3
  export declare function listRules(targets: ESLintTarget[]): Promise<RuleData[]>;
9
- export declare function parseRuleId(ruleId: string): {
10
- plugin?: string;
11
- name: string;
12
- };
@@ -1,3 +1,3 @@
1
1
  import type { Audit } from '@code-pushup/models';
2
- import type { RuleData } from './rules';
2
+ import type { RuleData } from './parse';
3
3
  export declare function ruleToAudit({ ruleId, meta, options }: RuleData): Audit;
@@ -0,0 +1,2 @@
1
+ import type { ConfigFormat } from './formats';
2
+ export declare function detectConfigVersion(): Promise<ConfigFormat>;
@@ -0,0 +1,3 @@
1
+ import type { ESLintTarget } from '../../config';
2
+ import { type RuleData } from '../parse';
3
+ export declare function loadRulesForFlatConfig({ eslintrc, }: Pick<ESLintTarget, 'eslintrc'>): Promise<RuleData[]>;
@@ -0,0 +1 @@
1
+ export type ConfigFormat = 'flat' | 'legacy';
@@ -0,0 +1,6 @@
1
+ import type { ESLintTarget } from '../../config';
2
+ import type { RuleData } from '../parse';
3
+ import type { ConfigFormat } from './formats';
4
+ export { detectConfigVersion } from './detect';
5
+ export type { ConfigFormat } from './formats';
6
+ export declare function selectRulesLoader(version: ConfigFormat): (target: ESLintTarget) => Promise<RuleData[]>;
@@ -0,0 +1,3 @@
1
+ import type { ESLintTarget } from '../../config';
2
+ import { type RuleData } from '../parse';
3
+ export declare function loadRulesForLegacyConfig({ eslintrc, patterns, }: ESLintTarget): Promise<RuleData[]>;
@@ -1,3 +1,3 @@
1
1
  import { ESLint } from 'eslint';
2
2
  import type { ESLintTarget } from './config';
3
- export declare function setupESLint(eslintrc: ESLintTarget['eslintrc']): ESLint;
3
+ export declare function setupESLint(eslintrc: ESLintTarget['eslintrc']): Promise<ESLint>;