@wondermarin/eslint-config 2.4.0 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/main.js +147 -197
  2. package/package.json +17 -18
package/dist/main.js CHANGED
@@ -1,5 +1,5 @@
1
- import fs from 'node:fs';
2
- import path, { join } from 'node:path';
1
+ import path, { join, dirname } from 'node:path';
2
+ import fs, { existsSync } from 'node:fs';
3
3
  import globals from 'globals';
4
4
 
5
5
  // node_modules/.pnpm/defu@6.1.4/node_modules/defu/dist/defu.mjs
@@ -57,6 +57,15 @@ function createDefu(merger) {
57
57
  );
58
58
  }
59
59
  var defu = createDefu();
60
+ function findProjectRoot() {
61
+ const startDir = process.cwd();
62
+ let currentDir = startDir;
63
+ while (!currentDir.endsWith("\\")) {
64
+ if (existsSync(join(currentDir, "package.json"))) return currentDir;
65
+ currentDir = dirname(currentDir);
66
+ }
67
+ return startDir;
68
+ }
60
69
 
61
70
  // src/configs/javascript.ts
62
71
  function javascriptConfig() {
@@ -408,7 +417,7 @@ async function interopDefault(module) {
408
417
  }
409
418
 
410
419
  // src/configs/typescript.ts
411
- async function typescriptConfig() {
420
+ async function typescriptConfig(projectRoot) {
412
421
  const [typescriptParser, typescriptPlugin] = await Promise.all([
413
422
  interopDefault(import('@typescript-eslint/parser')),
414
423
  interopDefault(import('@typescript-eslint/eslint-plugin'))
@@ -421,7 +430,7 @@ async function typescriptConfig() {
421
430
  parser: typescriptParser,
422
431
  parserOptions: {
423
432
  project: true,
424
- tsconfigRootDir: process.cwd()
433
+ tsconfigRootDir: projectRoot
425
434
  }
426
435
  },
427
436
  plugins: {
@@ -886,10 +895,9 @@ async function typescriptConfig() {
886
895
 
887
896
  // src/configs/stylistic.ts
888
897
  async function stylisticConfig() {
889
- const [prettierConfig, prettierPlugin, stylisticPlugin, perfectionistPlugin] = await Promise.all([
898
+ const [prettierConfig, prettierPlugin, perfectionistPlugin] = await Promise.all([
890
899
  interopDefault(import('eslint-config-prettier')),
891
900
  interopDefault(import('eslint-plugin-prettier')),
892
- interopDefault(import('@stylistic/eslint-plugin')),
893
901
  interopDefault(import('eslint-plugin-perfectionist'))
894
902
  ]);
895
903
  return [
@@ -904,176 +912,6 @@ async function stylisticConfig() {
904
912
  ...prettierConfig.rules
905
913
  }
906
914
  },
907
- {
908
- name: "wondermarin/eslint-config/stylistic",
909
- files: ["**/*.?([cm])js" /* JS */, "**/*.jsx" /* JSX */, "**/*.?([cm])ts" /* TS */, "**/*.tsx" /* TSX */, "**/*.vue" /* VUE */],
910
- plugins: {
911
- "@stylistic": stylisticPlugin
912
- },
913
- rules: {
914
- "@stylistic/array-bracket-newline": "off",
915
- "@stylistic/array-bracket-spacing": "off",
916
- "@stylistic/array-element-newline": "off",
917
- "@stylistic/arrow-parens": "off",
918
- "@stylistic/arrow-spacing": "off",
919
- "@stylistic/block-spacing": "off",
920
- "@stylistic/brace-style": "off",
921
- "@stylistic/comma-dangle": "off",
922
- "@stylistic/comma-spacing": "off",
923
- "@stylistic/comma-style": "off",
924
- "@stylistic/computed-property-spacing": "off",
925
- "@stylistic/dot-location": "off",
926
- "@stylistic/eol-last": "off",
927
- "@stylistic/function-call-argument-newline": "off",
928
- "@stylistic/function-call-spacing": "off",
929
- "@stylistic/function-paren-newline": "off",
930
- "@stylistic/generator-star-spacing": "off",
931
- "@stylistic/implicit-arrow-linebreak": "off",
932
- "@stylistic/indent": "off",
933
- "@stylistic/indent-binary-ops": "off",
934
- "@stylistic/jsx-child-element-spacing": "off",
935
- "@stylistic/jsx-closing-bracket-location": "off",
936
- "@stylistic/jsx-closing-tag-location": "off",
937
- "@stylistic/jsx-curly-brace-presence": "off",
938
- "@stylistic/jsx-curly-newline": "off",
939
- "@stylistic/jsx-curly-spacing": "off",
940
- "@stylistic/jsx-equals-spacing": "off",
941
- "@stylistic/jsx-first-prop-new-line": "off",
942
- "@stylistic/jsx-function-call-newline": "off",
943
- "@stylistic/jsx-indent-props": "off",
944
- "@stylistic/jsx-max-props-per-line": "off",
945
- "@stylistic/jsx-newline": "off",
946
- "@stylistic/jsx-one-expression-per-line": "off",
947
- "@stylistic/jsx-pascal-case": "off",
948
- "@stylistic/jsx-props-no-multi-spaces": "off",
949
- "@stylistic/jsx-quotes": "off",
950
- "@stylistic/jsx-self-closing-comp": "off",
951
- "@stylistic/jsx-sort-props": "off",
952
- "@stylistic/jsx-tag-spacing": "off",
953
- "@stylistic/jsx-wrap-multilines": "off",
954
- "@stylistic/key-spacing": "off",
955
- "@stylistic/keyword-spacing": "off",
956
- "@stylistic/line-comment-position": "off",
957
- "@stylistic/linebreak-style": "off",
958
- "@stylistic/lines-around-comment": "off",
959
- "@stylistic/lines-between-class-members": "off",
960
- "@stylistic/max-len": "off",
961
- "@stylistic/max-statements-per-line": "off",
962
- "@stylistic/member-delimiter-style": "off",
963
- "@stylistic/multiline-comment-style": "off",
964
- "@stylistic/multiline-ternary": "off",
965
- "@stylistic/new-parens": "off",
966
- "@stylistic/newline-per-chained-call": "off",
967
- "@stylistic/no-confusing-arrow": "off",
968
- "@stylistic/no-extra-parens": "off",
969
- "@stylistic/no-extra-semi": "off",
970
- "@stylistic/no-floating-decimal": "off",
971
- "@stylistic/no-mixed-operators": "off",
972
- "@stylistic/no-mixed-spaces-and-tabs": "off",
973
- "@stylistic/no-multi-spaces": "off",
974
- "@stylistic/no-multiple-empty-lines": "off",
975
- "@stylistic/no-tabs": "off",
976
- "@stylistic/no-trailing-spaces": "off",
977
- "@stylistic/no-whitespace-before-property": "off",
978
- "@stylistic/nonblock-statement-body-position": "off",
979
- "@stylistic/object-curly-newline": "off",
980
- "@stylistic/object-curly-spacing": "off",
981
- "@stylistic/object-property-newline": "off",
982
- "@stylistic/one-var-declaration-per-line": "off",
983
- "@stylistic/operator-linebreak": "off",
984
- "@stylistic/padded-blocks": "off",
985
- "@stylistic/padding-line-between-statements": [
986
- "error",
987
- {
988
- blankLine: "always",
989
- next: "*",
990
- prev: [
991
- "block-like",
992
- "case",
993
- "class",
994
- "debugger",
995
- "default",
996
- "directive",
997
- "do",
998
- "expression",
999
- "for",
1000
- "function",
1001
- "if",
1002
- "iife",
1003
- "multiline-expression",
1004
- "multiline-const",
1005
- "multiline-let",
1006
- "switch",
1007
- "throw",
1008
- "try",
1009
- "while",
1010
- "with"
1011
- ]
1012
- },
1013
- {
1014
- blankLine: "always",
1015
- next: [
1016
- "block-like",
1017
- "break",
1018
- "case",
1019
- "class",
1020
- "continue",
1021
- "debugger",
1022
- "default",
1023
- "do",
1024
- "expression",
1025
- "for",
1026
- "function",
1027
- "if",
1028
- "iife",
1029
- "multiline-expression",
1030
- "multiline-const",
1031
- "multiline-let",
1032
- "return",
1033
- "singleline-const",
1034
- "singleline-let",
1035
- "switch",
1036
- "throw",
1037
- "try",
1038
- "while",
1039
- "with"
1040
- ],
1041
- prev: "*"
1042
- },
1043
- {
1044
- blankLine: "any",
1045
- next: "expression",
1046
- prev: "expression"
1047
- },
1048
- {
1049
- blankLine: "any",
1050
- next: ["singleline-const", "singleline-let"],
1051
- prev: ["singleline-const", "singleline-let"]
1052
- }
1053
- ],
1054
- "@stylistic/quote-props": "off",
1055
- "@stylistic/quotes": "off",
1056
- "@stylistic/rest-spread-spacing": "off",
1057
- "@stylistic/semi": "off",
1058
- "@stylistic/semi-spacing": "off",
1059
- "@stylistic/semi-style": "off",
1060
- "@stylistic/space-before-blocks": "off",
1061
- "@stylistic/space-before-function-paren": "off",
1062
- "@stylistic/space-in-parens": "off",
1063
- "@stylistic/space-infix-ops": "off",
1064
- "@stylistic/space-unary-ops": "off",
1065
- "@stylistic/spaced-comment": "off",
1066
- "@stylistic/switch-colon-spacing": "off",
1067
- "@stylistic/template-curly-spacing": "off",
1068
- "@stylistic/template-tag-spacing": "off",
1069
- "@stylistic/type-annotation-spacing": "off",
1070
- "@stylistic/type-generic-spacing": "off",
1071
- "@stylistic/type-named-tuple-spacing": "off",
1072
- "@stylistic/wrap-iife": "off",
1073
- "@stylistic/wrap-regex": "off",
1074
- "@stylistic/yield-star-spacing": "off"
1075
- }
1076
- },
1077
915
  {
1078
916
  name: "wondermarin/eslint-config/perfectionist",
1079
917
  files: ["**/*.?([cm])js" /* JS */, "**/*.jsx" /* JSX */, "**/*.?([cm])ts" /* TS */, "**/*.tsx" /* TSX */, "**/*.vue" /* VUE */],
@@ -1198,6 +1036,21 @@ var fixedUpRuleReplacements = /* @__PURE__ */ new WeakMap();
1198
1036
  var fixedUpRules = /* @__PURE__ */ new WeakSet();
1199
1037
  var fixedUpPluginReplacements = /* @__PURE__ */ new WeakMap();
1200
1038
  var fixedUpPlugins = /* @__PURE__ */ new WeakSet();
1039
+ function nodesOrTokensOverlap(first, second) {
1040
+ return first.range[0] <= second.range[0] && first.range[1] >= second.range[0] || second.range[0] <= first.range[0] && second.range[1] >= first.range[0];
1041
+ }
1042
+ function looksLikeExport(node) {
1043
+ return node.type === "ExportDefaultDeclaration" || node.type === "ExportNamedDeclaration";
1044
+ }
1045
+ function findJSDocComment(node, sourceCode) {
1046
+ const tokenBefore = sourceCode.getTokenBefore(node, {
1047
+ includeComments: true
1048
+ });
1049
+ if (tokenBefore && tokenBefore.type === "Block" && tokenBefore.value.charAt(0) === "*" && node.loc.start.line - tokenBefore.loc.end.line <= 1) {
1050
+ return tokenBefore;
1051
+ }
1052
+ return null;
1053
+ }
1201
1054
  function fixupRule(ruleDefinition) {
1202
1055
  if (fixedUpRuleReplacements.has(ruleDefinition)) {
1203
1056
  return fixedUpRuleReplacements.get(ruleDefinition);
@@ -1208,35 +1061,129 @@ function fixupRule(ruleDefinition) {
1208
1061
  }
1209
1062
  const originalCreate = isLegacyRule ? ruleDefinition : ruleDefinition.create.bind(ruleDefinition);
1210
1063
  function ruleCreate(context) {
1064
+ const sourceCode = context.sourceCode;
1211
1065
  if ("getScope" in context) {
1212
1066
  return originalCreate(context);
1213
1067
  }
1214
- const sourceCode = context.sourceCode;
1215
- let currentNode = sourceCode.ast;
1216
- const newContext = Object.assign(Object.create(context), {
1217
- parserServices: sourceCode.parserServices,
1068
+ let eslintVersion = 9;
1069
+ if (!("getCwd" in context)) {
1070
+ eslintVersion = 10;
1071
+ }
1072
+ let compatSourceCode = sourceCode;
1073
+ if (eslintVersion >= 10) {
1074
+ compatSourceCode = Object.assign(Object.create(sourceCode), {
1075
+ getTokenOrCommentBefore(node, skip) {
1076
+ return sourceCode.getTokenBefore(node, {
1077
+ includeComments: true,
1078
+ skip
1079
+ });
1080
+ },
1081
+ getTokenOrCommentAfter(node, skip) {
1082
+ return sourceCode.getTokenAfter(node, {
1083
+ includeComments: true,
1084
+ skip
1085
+ });
1086
+ },
1087
+ isSpaceBetweenTokens(first, second) {
1088
+ if (nodesOrTokensOverlap(first, second)) {
1089
+ return false;
1090
+ }
1091
+ const [startingNodeOrToken, endingNodeOrToken] = first.range[1] <= second.range[0] ? [first, second] : [second, first];
1092
+ const firstToken = sourceCode.getLastToken(startingNodeOrToken) || startingNodeOrToken;
1093
+ const finalToken = sourceCode.getFirstToken(endingNodeOrToken) || endingNodeOrToken;
1094
+ let currentToken = firstToken;
1095
+ while (currentToken !== finalToken) {
1096
+ const nextToken = sourceCode.getTokenAfter(
1097
+ currentToken,
1098
+ {
1099
+ includeComments: true
1100
+ }
1101
+ );
1102
+ if (currentToken.range[1] !== nextToken.range[0] || nextToken !== finalToken && nextToken.type === "JSXText" && /\s/u.test(nextToken.value)) {
1103
+ return true;
1104
+ }
1105
+ currentToken = nextToken;
1106
+ }
1107
+ return false;
1108
+ },
1109
+ getJSDocComment(node) {
1110
+ let parent = node.parent;
1111
+ switch (node.type) {
1112
+ case "ClassDeclaration":
1113
+ case "FunctionDeclaration":
1114
+ return findJSDocComment(
1115
+ looksLikeExport(parent) ? parent : node,
1116
+ sourceCode
1117
+ );
1118
+ case "ClassExpression":
1119
+ return findJSDocComment(parent.parent, sourceCode);
1120
+ case "ArrowFunctionExpression":
1121
+ case "FunctionExpression":
1122
+ if (parent.type !== "CallExpression" && parent.type !== "NewExpression") {
1123
+ while (!sourceCode.getCommentsBefore(parent).length && !/Function/u.test(parent.type) && parent.type !== "MethodDefinition" && parent.type !== "Property") {
1124
+ parent = parent.parent;
1125
+ if (!parent) {
1126
+ break;
1127
+ }
1128
+ }
1129
+ if (parent && parent.type !== "FunctionDeclaration" && parent.type !== "Program") {
1130
+ return findJSDocComment(parent, sourceCode);
1131
+ }
1132
+ }
1133
+ return findJSDocComment(node, sourceCode);
1134
+ default:
1135
+ return null;
1136
+ }
1137
+ }
1138
+ });
1139
+ Object.freeze(compatSourceCode);
1140
+ }
1141
+ let currentNode = compatSourceCode.ast;
1142
+ const compatContext = Object.assign(Object.create(context), {
1143
+ parserServices: compatSourceCode.parserServices,
1218
1144
  /*
1219
1145
  * The following methods rely on the current node in the traversal,
1220
1146
  * so we need to add them manually.
1221
1147
  */
1222
1148
  getScope() {
1223
- return sourceCode.getScope(currentNode);
1149
+ return compatSourceCode.getScope(currentNode);
1224
1150
  },
1225
1151
  getAncestors() {
1226
- return sourceCode.getAncestors(currentNode);
1152
+ return compatSourceCode.getAncestors(currentNode);
1227
1153
  },
1228
1154
  markVariableAsUsed(variable) {
1229
- sourceCode.markVariableAsUsed(variable, currentNode);
1155
+ compatSourceCode.markVariableAsUsed(variable, currentNode);
1230
1156
  }
1231
1157
  });
1158
+ if (eslintVersion >= 10) {
1159
+ Object.assign(compatContext, {
1160
+ parserOptions: compatContext.languageOptions.parserOptions,
1161
+ getCwd() {
1162
+ return compatContext.cwd;
1163
+ },
1164
+ getFilename() {
1165
+ return compatContext.filename;
1166
+ },
1167
+ getPhysicalFilename() {
1168
+ return compatContext.physicalFilename;
1169
+ },
1170
+ getSourceCode() {
1171
+ return compatSourceCode;
1172
+ }
1173
+ });
1174
+ Object.defineProperty(compatContext, "sourceCode", {
1175
+ enumerable: true,
1176
+ value: compatSourceCode
1177
+ });
1178
+ }
1232
1179
  for (const [
1233
1180
  contextMethodName,
1234
1181
  sourceCodeMethodName
1235
1182
  ] of removedMethodNames) {
1236
- newContext[contextMethodName] = sourceCode[sourceCodeMethodName].bind(sourceCode);
1183
+ compatContext[contextMethodName] = compatSourceCode[sourceCodeMethodName].bind(compatSourceCode);
1237
1184
  }
1238
- Object.freeze(newContext);
1239
- const visitor = originalCreate(newContext);
1185
+ Object.freeze(compatContext);
1186
+ const visitor = originalCreate(compatContext);
1240
1187
  for (const [methodName, method] of Object.entries(visitor)) {
1241
1188
  if (methodName.startsWith("on")) {
1242
1189
  visitor[methodName] = (...args) => {
@@ -1303,13 +1250,14 @@ function convertIgnorePatternToMinimatch(pattern) {
1303
1250
  const matchEverywherePrefix = firstIndexOfSlash < 0 || firstIndexOfSlash === patternToTest.length - 1 ? "**/" : "";
1304
1251
  const patternWithoutLeadingSlash = firstIndexOfSlash === 0 ? patternToTest.slice(1) : patternToTest;
1305
1252
  const escapedPatternWithoutLeadingSlash = patternWithoutLeadingSlash.replaceAll(
1253
+ // eslint-disable-next-line regexp/no-empty-lookarounds-assertion -- False positive
1306
1254
  /(?=((?:\\.|[^{(])*))\1([{(])/guy,
1307
1255
  "$1\\$2"
1308
1256
  );
1309
1257
  const matchInsideSuffix = patternToTest.endsWith("/**") ? "/*" : "";
1310
1258
  return `${negatedPrefix}${matchEverywherePrefix}${escapedPatternWithoutLeadingSlash}${matchInsideSuffix}`;
1311
1259
  }
1312
- function includeIgnoreFile(ignoreFilePath) {
1260
+ function includeIgnoreFile(ignoreFilePath, name) {
1313
1261
  if (!path.isAbsolute(ignoreFilePath)) {
1314
1262
  throw new Error("The ignore file location must be an absolute path.");
1315
1263
  }
@@ -1325,7 +1273,6 @@ function includeIgnoreFile(ignoreFilePath) {
1325
1273
  async function reactConfig() {
1326
1274
  const [reactPlugin, reactHooksPlugin] = await Promise.all([
1327
1275
  interopDefault(import('eslint-plugin-react')),
1328
- // @ts-expect-error missing types
1329
1276
  interopDefault(import('eslint-plugin-react-hooks'))
1330
1277
  ]);
1331
1278
  return [
@@ -1520,7 +1467,7 @@ async function reactConfig() {
1520
1467
  }
1521
1468
  ];
1522
1469
  }
1523
- function baseConfig() {
1470
+ function baseConfig(projectRoot) {
1524
1471
  return [
1525
1472
  {
1526
1473
  name: "wondermarin/eslint-config",
@@ -1540,7 +1487,7 @@ function baseConfig() {
1540
1487
  },
1541
1488
  {
1542
1489
  name: "wondermarin/eslint-config/ignores",
1543
- ignores: includeIgnoreFile(join(process.cwd(), ".gitignore")).ignores
1490
+ ignores: includeIgnoreFile(join(projectRoot, ".gitignore")).ignores
1544
1491
  }
1545
1492
  ];
1546
1493
  }
@@ -1586,13 +1533,16 @@ async function wondermarin(options) {
1586
1533
  stylistic: true,
1587
1534
  json: true
1588
1535
  });
1589
- const config = [...baseConfig()];
1590
- if (options.javascript) config.push(...javascriptConfig());
1591
- if (options.typescript) config.push(...await typescriptConfig());
1592
- if (options.stylistic) config.push(...await stylisticConfig());
1593
- if (options.json) config.push(...await jsonConfig());
1594
- if (options.react) config.push(...await reactConfig());
1595
- return config;
1536
+ const projectRoot = findProjectRoot();
1537
+ const configs = await Promise.all([
1538
+ Promise.resolve(baseConfig(projectRoot)),
1539
+ Promise.resolve(options.javascript ? javascriptConfig() : []),
1540
+ options.typescript ? typescriptConfig(projectRoot) : [],
1541
+ options.stylistic ? stylisticConfig() : [],
1542
+ options.json ? jsonConfig() : [],
1543
+ options.react ? reactConfig() : []
1544
+ ]);
1545
+ return configs.flat();
1596
1546
  }
1597
1547
  var main_default = wondermarin;
1598
1548
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wondermarin/eslint-config",
3
- "version": "2.4.0",
3
+ "version": "2.5.0",
4
4
  "description": "Personal ESLint config.",
5
5
  "homepage": "https://github.com/Wondermarin/eslint-config#readme",
6
6
  "repository": {
@@ -28,37 +28,36 @@
28
28
  "build": "tsup"
29
29
  },
30
30
  "dependencies": {
31
- "@stylistic/eslint-plugin": "^2.10.1",
32
- "eslint-config-prettier": "^9.1.0",
31
+ "eslint-config-prettier": "^9.1.2",
33
32
  "eslint-plugin-package-json": "^0.15.6",
34
33
  "eslint-plugin-perfectionist": "^3.9.1",
35
- "eslint-plugin-prettier": "^5.2.1",
36
- "globals": "^15.12.0",
37
- "jsonc-eslint-parser": "^2.4.0"
34
+ "eslint-plugin-prettier": "^5.5.4",
35
+ "globals": "^15.15.0",
36
+ "jsonc-eslint-parser": "^2.4.2"
38
37
  },
39
38
  "devDependencies": {
40
- "@eslint/compat": "^1.2.3",
39
+ "@eslint/compat": "^2.0.0",
41
40
  "@types/eslint": "^9.6.1",
42
41
  "@types/eslint-config-prettier": "^6.11.3",
43
- "@types/node": "^22.9.0",
44
- "@typescript-eslint/eslint-plugin": "^8.14.0",
45
- "@typescript-eslint/parser": "^8.14.0",
42
+ "@types/node": "^25.0.3",
43
+ "@typescript-eslint/eslint-plugin": "^8.51.0",
44
+ "@typescript-eslint/parser": "^8.51.0",
46
45
  "@wondermarin/prettier-config": "^1.0.0",
47
46
  "defu": "^6.1.4",
48
- "eslint": "^9.14.0",
49
- "eslint-plugin-react": "^7.37.2",
50
- "eslint-plugin-react-hooks": "^5.0.0",
51
- "jiti": "^2.4.0",
52
- "prettier": "^3.3.3",
53
- "tsup": "^8.3.5",
54
- "typescript": "^5.6.3"
47
+ "eslint": "^9.39.2",
48
+ "eslint-plugin-react": "^7.37.5",
49
+ "eslint-plugin-react-hooks": "^7.0.1",
50
+ "jiti": "^2.6.1",
51
+ "prettier": "^3.7.4",
52
+ "tsup": "^8.5.1",
53
+ "typescript": "^5.9.3"
55
54
  },
56
55
  "peerDependencies": {
57
56
  "@typescript-eslint/eslint-plugin": "^8.14",
58
57
  "@typescript-eslint/parser": "^8.14",
59
58
  "eslint": "^9.14",
60
59
  "eslint-plugin-react": "^7.37",
61
- "eslint-plugin-react-hooks": "^5"
60
+ "eslint-plugin-react-hooks": "^5 || ^6.1 || ^7"
62
61
  },
63
62
  "peerDependenciesMeta": {
64
63
  "@typescript-eslint/eslint-plugin": {