@rotki/eslint-config 6.1.0 → 7.0.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 (3) hide show
  1. package/dist/index.d.mts +3495 -1257
  2. package/dist/index.mjs +323 -195
  3. package/package.json +45 -45
package/dist/index.mjs CHANGED
@@ -180,8 +180,19 @@ async function disables() {
180
180
  }
181
181
  //#endregion
182
182
  //#region src/configs/e18e.ts
183
- async function e18e(options = {}) {
183
+ function resolveE18eOptions(options) {
184
184
  const { isInEditor = false, modernization = true, type = "app", moduleReplacements = type === "lib" && isInEditor, overrides = {}, performanceImprovements = true } = options;
185
+ return {
186
+ isInEditor,
187
+ modernization,
188
+ moduleReplacements,
189
+ overrides,
190
+ performanceImprovements,
191
+ type
192
+ };
193
+ }
194
+ async function e18e(options = {}) {
195
+ const { modernization, moduleReplacements, overrides, performanceImprovements, type } = resolveE18eOptions(options);
185
196
  const configs = pluginE18e.configs;
186
197
  return [{
187
198
  name: "rotki/e18e/rules",
@@ -304,18 +315,20 @@ function isInGitHooksOrLintStaged() {
304
315
  //#endregion
305
316
  //#region src/configs/stylistic.ts
306
317
  const StylisticConfigDefaults = {
318
+ braceStyle: "stroustrup",
307
319
  indent: 2,
308
320
  jsx: true,
309
321
  quotes: "single",
310
322
  semi: true
311
323
  };
312
324
  async function stylistic(options = {}) {
313
- const { indent, jsx, lessOpinionated = false, overrides = {}, quotes, semi } = {
325
+ const { braceStyle, indent, jsx, lessOpinionated = false, overrides = {}, quotes, semi } = {
314
326
  ...StylisticConfigDefaults,
315
327
  ...options
316
328
  };
317
329
  const pluginStylistic = await interopDefault(import("@stylistic/eslint-plugin"));
318
330
  const config = pluginStylistic.configs.customize({
331
+ braceStyle,
319
332
  indent,
320
333
  jsx,
321
334
  quotes,
@@ -389,20 +402,17 @@ function mergePrettierOptions(options, overrides) {
389
402
  plugins: [...overrides.plugins || [], ...options.plugins || []]
390
403
  };
391
404
  }
392
- async function formatters(options = {}, stylistic = {}) {
393
- if (options === true) options = {
405
+ function resolveFormattersOptions(options) {
406
+ if (options === true) return {
394
407
  css: true,
395
408
  html: true,
396
409
  markdown: true,
397
410
  xml: isPackageInScope("@prettier/plugin-xml")
398
411
  };
399
- await ensurePackages(["eslint-plugin-format", options.xml ? "@prettier/plugin-xml" : void 0]);
400
- const { indent: rawIndent, quotes, semi } = {
401
- ...StylisticConfigDefaults,
402
- ...stylistic
403
- };
404
- const indent = Array.isArray(rawIndent) ? rawIndent[0] : rawIndent;
405
- const prettierOptions = Object.assign({
412
+ return options;
413
+ }
414
+ function buildPrettierOptions(indent, quotes, semi, options) {
415
+ return Object.assign({
406
416
  endOfLine: "auto",
407
417
  printWidth: 120,
408
418
  semi,
@@ -411,70 +421,95 @@ async function formatters(options = {}, stylistic = {}) {
411
421
  trailingComma: "all",
412
422
  useTabs: indent === "tab"
413
423
  }, options.prettierOptions || {});
414
- const dprintOptions = Object.assign({
424
+ }
425
+ function buildDprintOptions(indent, quotes, options) {
426
+ return Object.assign({
415
427
  indentWidth: typeof indent === "number" ? indent : 2,
416
428
  quoteStyle: quotes === "single" ? "preferSingle" : "preferDouble",
417
429
  useTabs: indent === "tab"
418
430
  }, options.dprintOptions || {});
419
- const prettierXmlOptions = {
420
- xmlQuoteAttributes: "double",
421
- xmlSelfClosingSpace: true,
422
- xmlSortAttributesByKey: false,
423
- xmlWhitespaceSensitivity: "ignore"
424
- };
425
- const configs = [{
426
- name: "rotki/formatter/setup",
427
- plugins: { format: await interopDefault(import("eslint-plugin-format")) }
428
- }];
429
- if (options.css) configs.push({
430
- files: [GLOB_CSS, GLOB_POSTCSS],
431
- languageOptions: { parser: parserPlain },
432
- name: "rotki/formatter/css",
433
- rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "css" })] }
434
- }, {
435
- files: [GLOB_SCSS],
436
- languageOptions: { parser: parserPlain },
437
- name: "rotki/formatter/scss",
438
- rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "scss" })] }
439
- }, {
440
- files: [GLOB_LESS],
441
- languageOptions: { parser: parserPlain },
442
- name: "rotki/formatter/less",
443
- rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "less" })] }
444
- });
445
- if (options.html) configs.push({
431
+ }
432
+ function cssFormatters(options, prettierOptions) {
433
+ if (!options.css) return [];
434
+ return [
435
+ {
436
+ files: [GLOB_CSS, GLOB_POSTCSS],
437
+ languageOptions: { parser: parserPlain },
438
+ name: "rotki/formatter/css",
439
+ rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "css" })] }
440
+ },
441
+ {
442
+ files: [GLOB_SCSS],
443
+ languageOptions: { parser: parserPlain },
444
+ name: "rotki/formatter/scss",
445
+ rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "scss" })] }
446
+ },
447
+ {
448
+ files: [GLOB_LESS],
449
+ languageOptions: { parser: parserPlain },
450
+ name: "rotki/formatter/less",
451
+ rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "less" })] }
452
+ }
453
+ ];
454
+ }
455
+ function htmlFormatter(options, prettierOptions) {
456
+ if (!options.html) return [];
457
+ return [{
446
458
  files: ["**/*.html"],
447
459
  languageOptions: { parser: parserPlain },
448
460
  name: "rotki/formatter/html",
449
461
  rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "html" })] }
450
- });
451
- if (options.xml) configs.push({
462
+ }];
463
+ }
464
+ function xmlFormatter(options, prettierOptions) {
465
+ if (!options.xml) return [];
466
+ return [{
452
467
  files: [GLOB_XML],
453
468
  languageOptions: { parser: parserPlain },
454
469
  name: "rotki/formatter/xml",
455
470
  rules: { "format/prettier": ["error", mergePrettierOptions({
456
- ...prettierXmlOptions,
471
+ xmlQuoteAttributes: "double",
472
+ xmlSelfClosingSpace: true,
473
+ xmlSortAttributesByKey: false,
474
+ xmlWhitespaceSensitivity: "ignore",
457
475
  ...prettierOptions
458
476
  }, {
459
477
  parser: "xml",
460
478
  plugins: ["@prettier/plugin-xml"]
461
479
  })] }
462
- });
463
- if (options.markdown) {
464
- const formater = options.markdown === true ? "prettier" : options.markdown;
465
- configs.push({
466
- files: [GLOB_MARKDOWN],
467
- languageOptions: { parser: parserPlain },
468
- name: "rotki/formatter/markdown",
469
- rules: { [`format/${formater}`]: ["error", formater === "prettier" ? mergePrettierOptions(prettierOptions, {
470
- embeddedLanguageFormatting: "off",
471
- parser: "markdown"
472
- }) : {
473
- ...dprintOptions,
474
- language: "markdown"
475
- }] }
476
- });
477
- }
480
+ }];
481
+ }
482
+ function markdownFormatter(options, prettierOptions, dprintOptions) {
483
+ if (!options.markdown) return [];
484
+ const formater = options.markdown === true ? "prettier" : options.markdown;
485
+ return [{
486
+ files: [GLOB_MARKDOWN],
487
+ languageOptions: { parser: parserPlain },
488
+ name: "rotki/formatter/markdown",
489
+ rules: { [`format/${formater}`]: ["error", formater === "prettier" ? mergePrettierOptions(prettierOptions, {
490
+ embeddedLanguageFormatting: "off",
491
+ parser: "markdown"
492
+ }) : {
493
+ ...dprintOptions,
494
+ language: "markdown"
495
+ }] }
496
+ }];
497
+ }
498
+ async function formatters(options = {}, stylistic = {}) {
499
+ const resolvedOptions = resolveFormattersOptions(options);
500
+ await ensurePackages(["eslint-plugin-format", resolvedOptions.xml ? "@prettier/plugin-xml" : void 0]);
501
+ const { indent: rawIndent, quotes, semi } = {
502
+ ...StylisticConfigDefaults,
503
+ ...stylistic
504
+ };
505
+ const indent = Array.isArray(rawIndent) ? rawIndent[0] : rawIndent;
506
+ const prettierOptions = buildPrettierOptions(indent, quotes, semi, resolvedOptions);
507
+ const dprintOptions = buildDprintOptions(indent, quotes, resolvedOptions);
508
+ const configs = [{
509
+ name: "rotki/formatter/setup",
510
+ plugins: { format: await interopDefault(import("eslint-plugin-format")) }
511
+ }];
512
+ configs.push(...cssFormatters(resolvedOptions, prettierOptions), ...htmlFormatter(resolvedOptions, prettierOptions), ...xmlFormatter(resolvedOptions, prettierOptions), ...markdownFormatter(resolvedOptions, prettierOptions, dprintOptions));
478
513
  return configs;
479
514
  }
480
515
  //#endregion
@@ -490,11 +525,10 @@ async function ignores(userIgnores = []) {
490
525
  async function imports(options = {}) {
491
526
  const { overrides = {}, stylistic = true } = options;
492
527
  await ensurePackages(["@rotki/eslint-plugin"]);
493
- const pluginRotki = await interopDefault(import("@rotki/eslint-plugin"));
494
528
  return [{
495
529
  name: "rotki/import/rules",
496
530
  plugins: {
497
- "@rotki": pluginRotki,
531
+ "@rotki": await interopDefault(import("@rotki/eslint-plugin")),
498
532
  "antfu": pluginAntfu,
499
533
  "import": pluginImport
500
534
  },
@@ -525,7 +559,7 @@ async function javascript(options = {}) {
525
559
  const { isInEditor = false, overrides = {} } = options;
526
560
  const customRules = {
527
561
  "arrow-body-style": ["error", "as-needed"],
528
- "complexity": ["warn", { max: 10 }],
562
+ "complexity": ["error", { max: 10 }],
529
563
  "max-lines": ["error", { max: 400 }]
530
564
  };
531
565
  return [{
@@ -862,20 +896,6 @@ async function markdown(options = {}) {
862
896
  ...overridesMarkdown
863
897
  }
864
898
  },
865
- {
866
- files,
867
- name: "rotki/markdown/disables/markdown",
868
- rules: {
869
- "@stylistic/indent": "off",
870
- "no-irregular-whitespace": "off",
871
- "perfectionist/sort-exports": "off",
872
- "perfectionist/sort-imports": "off",
873
- "regexp/no-legacy-features": "off",
874
- "regexp/no-missing-g-flag": "off",
875
- "regexp/no-useless-dollar-replacements": "off",
876
- "regexp/no-useless-flag": "off"
877
- }
878
- },
879
899
  {
880
900
  files: [GLOB_MARKDOWN_CODE, ...componentExts.map((ext) => `${GLOB_MARKDOWN}/**/*.${ext}`)],
881
901
  languageOptions: { parserOptions: { ecmaFeatures: { impliedStrict: true } } },
@@ -943,7 +963,8 @@ async function node() {
943
963
  *
944
964
  * @see https://github.com/azat-io/eslint-plugin-perfectionist
945
965
  */
946
- async function perfectionist() {
966
+ async function perfectionist(options = {}) {
967
+ const { overrides = {} } = options;
947
968
  return [{
948
969
  name: "rotki/perfectionist/setup",
949
970
  plugins: { perfectionist: pluginPerfectionist },
@@ -983,7 +1004,8 @@ async function perfectionist() {
983
1004
  "perfectionist/sort-named-imports": ["error", {
984
1005
  order: "asc",
985
1006
  type: "natural"
986
- }]
1007
+ }],
1008
+ ...overrides
987
1009
  }
988
1010
  }];
989
1011
  }
@@ -1154,24 +1176,26 @@ async function rotkiPlugin(options = {}) {
1154
1176
  },
1155
1177
  name: "rotki/rotki/rules",
1156
1178
  rules: {
1157
- "@rotki/composable-no-default-export": "warn",
1158
- "@rotki/composable-prefer-shallowref": "warn",
1159
- "@rotki/composable-require-cleanup": "warn",
1160
- "@rotki/composable-return-readonly": "warn",
1161
- "@rotki/composable-ssr-safety": "warn",
1179
+ "@rotki/composable-no-default-export": "error",
1180
+ "@rotki/composable-prefer-shallowref": "error",
1181
+ "@rotki/composable-require-cleanup": "error",
1182
+ "@rotki/composable-return-readonly": "error",
1183
+ "@rotki/composable-ssr-safety": "error",
1162
1184
  "@rotki/consistent-ref-type-annotation": ["error", { allowInference: true }],
1163
1185
  "@rotki/no-deprecated-classes": "error",
1164
1186
  "@rotki/no-deprecated-props": "error",
1165
1187
  "@rotki/no-dot-ts-imports": "error",
1188
+ "@rotki/no-redundant-flex-row": "error",
1189
+ "@rotki/no-shared-pinia": "error",
1166
1190
  "@rotki/no-unused-i18n-keys": ["error", {
1167
1191
  extensions: [".ts", ".vue"],
1168
1192
  ignoreKeys,
1169
1193
  src
1170
1194
  }],
1171
1195
  ...stylistic ? {
1172
- "@rotki/composable-input-flexibility": "warn",
1173
- "@rotki/composable-naming-convention": "warn",
1174
- "@rotki/require-jsdoc-on-composable-options": "warn"
1196
+ "@rotki/composable-input-flexibility": "error",
1197
+ "@rotki/composable-naming-convention": "error",
1198
+ "@rotki/require-jsdoc-on-composable-options": "error"
1175
1199
  } : {},
1176
1200
  ...overrides
1177
1201
  }
@@ -1221,6 +1245,7 @@ async function sortPackageJson() {
1221
1245
  "directories",
1222
1246
  "publishConfig",
1223
1247
  "scripts",
1248
+ "scripts-info",
1224
1249
  "peerDependencies",
1225
1250
  "peerDependenciesMeta",
1226
1251
  "optionalDependencies",
@@ -1477,63 +1502,86 @@ async function test(options = {}) {
1477
1502
  }
1478
1503
  //#endregion
1479
1504
  //#region src/configs/typescript.ts
1480
- async function typescript(options = {}) {
1505
+ const typeAwareCustom = {
1506
+ "@typescript-eslint/consistent-type-assertions": ["error", { assertionStyle: "never" }],
1507
+ "@typescript-eslint/naming-convention": [
1508
+ "error",
1509
+ {
1510
+ format: null,
1511
+ modifiers: ["destructured"],
1512
+ selector: "variable"
1513
+ },
1514
+ {
1515
+ format: ["camelCase"],
1516
+ leadingUnderscore: "allow",
1517
+ selector: "parameter"
1518
+ },
1519
+ {
1520
+ format: ["camelCase"],
1521
+ selector: "variable"
1522
+ },
1523
+ {
1524
+ format: [
1525
+ "camelCase",
1526
+ "UPPER_CASE",
1527
+ "PascalCase"
1528
+ ],
1529
+ modifiers: ["const"],
1530
+ selector: "variable"
1531
+ },
1532
+ {
1533
+ format: ["camelCase"],
1534
+ leadingUnderscore: "allow",
1535
+ modifiers: ["private"],
1536
+ selector: "memberLike"
1537
+ },
1538
+ {
1539
+ format: ["PascalCase"],
1540
+ selector: "typeLike"
1541
+ }
1542
+ ]
1543
+ };
1544
+ const customRules = {
1545
+ "@typescript-eslint/prefer-as-const": "error",
1546
+ "@typescript-eslint/prefer-literal-enum-member": ["warn", { allowBitwiseExpressions: true }],
1547
+ "max-lines": ["error", { max: 400 }]
1548
+ };
1549
+ function resolveTypeScriptFiles(options, componentExts) {
1550
+ return {
1551
+ files: options.files ?? [
1552
+ "**/*.?([cm])ts",
1553
+ "**/*.?([cm])tsx",
1554
+ ...componentExts.map((ext) => `**/*.${ext}`)
1555
+ ],
1556
+ filesTypeAware: options.filesTypeAware ?? ["**/*.?([cm])ts", "**/*.?([cm])tsx"],
1557
+ ignoresTypeAware: options.ignoresTypeAware ?? [`**/*.md/**`]
1558
+ };
1559
+ }
1560
+ function resolveTypeScriptOptions(options) {
1481
1561
  const { componentExts = [], isInEditor = false, overrides = {}, overridesTypeAware = {}, parserOptions = {}, type = "app" } = options;
1482
- const files = options.files ?? [
1483
- "**/*.?([cm])ts",
1484
- "**/*.?([cm])tsx",
1485
- ...componentExts.map((ext) => `**/*.${ext}`)
1486
- ];
1487
- const filesTypeAware = options.filesTypeAware ?? ["**/*.?([cm])ts", "**/*.?([cm])tsx"];
1488
- const ignoresTypeAware = options.ignoresTypeAware ?? [`**/*.md/**`];
1489
- const tsconfigPath = options?.tsconfigPath ? options.tsconfigPath : void 0;
1490
- const isTypeAware = !!tsconfigPath;
1491
- const typeAwareCustom = {
1492
- "@typescript-eslint/consistent-type-assertions": ["error", { assertionStyle: "never" }],
1493
- "@typescript-eslint/naming-convention": [
1494
- "error",
1495
- {
1496
- format: null,
1497
- modifiers: ["destructured"],
1498
- selector: "variable"
1499
- },
1500
- {
1501
- format: ["camelCase"],
1502
- leadingUnderscore: "allow",
1503
- selector: "parameter"
1504
- },
1505
- {
1506
- format: ["camelCase"],
1507
- selector: "variable"
1508
- },
1509
- {
1510
- format: [
1511
- "camelCase",
1512
- "UPPER_CASE",
1513
- "PascalCase"
1514
- ],
1515
- modifiers: ["const"],
1516
- selector: "variable"
1517
- },
1518
- {
1519
- format: ["camelCase"],
1520
- leadingUnderscore: "allow",
1521
- modifiers: ["private"],
1522
- selector: "memberLike"
1523
- },
1524
- {
1525
- format: ["PascalCase"],
1526
- selector: "typeLike"
1527
- }
1528
- ]
1562
+ const tsconfigPath = options.tsconfigPath ? options.tsconfigPath : void 0;
1563
+ return {
1564
+ componentExts,
1565
+ isInEditor,
1566
+ isTypeAware: !!tsconfigPath,
1567
+ overrides,
1568
+ overridesTypeAware,
1569
+ parserOptions,
1570
+ tsconfigPath,
1571
+ type,
1572
+ ...resolveTypeScriptFiles(options, componentExts)
1529
1573
  };
1530
- const typeAwareRules = {
1531
- "@typescript-eslint/await-thenable": "warn",
1574
+ }
1575
+ function buildTypeAwareRules(isInEditor) {
1576
+ return {
1577
+ "@typescript-eslint/await-thenable": "error",
1578
+ "@typescript-eslint/consistent-type-exports": "error",
1532
1579
  "@typescript-eslint/dot-notation": ["error", { allowKeywords: true }],
1533
1580
  "@typescript-eslint/no-floating-promises": ["error", { ignoreIIFE: true }],
1534
1581
  "@typescript-eslint/no-for-in-array": "error",
1535
1582
  "@typescript-eslint/no-implied-eval": "error",
1536
- "@typescript-eslint/no-misused-promises": "warn",
1583
+ "@typescript-eslint/no-misused-promises": "error",
1584
+ "@typescript-eslint/no-unnecessary-boolean-literal-compare": "error",
1537
1585
  "@typescript-eslint/no-unnecessary-type-assertion": "error",
1538
1586
  "@typescript-eslint/no-unsafe-argument": isInEditor ? "warn" : "off",
1539
1587
  "@typescript-eslint/no-unsafe-assignment": isInEditor ? "warn" : "off",
@@ -1541,6 +1589,9 @@ async function typescript(options = {}) {
1541
1589
  "@typescript-eslint/no-unsafe-member-access": isInEditor ? "warn" : "off",
1542
1590
  "@typescript-eslint/no-unsafe-return": isInEditor ? "warn" : "off",
1543
1591
  "@typescript-eslint/only-throw-error": "error",
1592
+ "@typescript-eslint/prefer-nullish-coalescing": "error",
1593
+ "@typescript-eslint/prefer-optional-chain": "error",
1594
+ "@typescript-eslint/prefer-readonly": "error",
1544
1595
  "@typescript-eslint/promise-function-async": "error",
1545
1596
  "@typescript-eslint/restrict-plus-operands": "error",
1546
1597
  "@typescript-eslint/restrict-template-expressions": "error",
@@ -1552,11 +1603,16 @@ async function typescript(options = {}) {
1552
1603
  "no-throw-literal": "off",
1553
1604
  ...typeAwareCustom
1554
1605
  };
1555
- const customRules = {
1556
- "@typescript-eslint/prefer-as-const": "warn",
1557
- "@typescript-eslint/prefer-literal-enum-member": ["warn", { allowBitwiseExpressions: true }],
1558
- "max-lines": ["error", { max: 400 }]
1559
- };
1606
+ }
1607
+ function buildLibRules(type) {
1608
+ return type === "lib" ? { "@typescript-eslint/explicit-function-return-type": ["error", {
1609
+ allowExpressions: true,
1610
+ allowHigherOrderFunctions: true,
1611
+ allowIIFEs: true
1612
+ }] } : {};
1613
+ }
1614
+ async function typescript(options = {}) {
1615
+ const { componentExts, files, filesTypeAware, ignoresTypeAware, isInEditor, isTypeAware, overrides, overridesTypeAware, parserOptions, tsconfigPath, type } = resolveTypeScriptOptions(options);
1560
1616
  const [pluginTs, parserTs] = await Promise.all([interopDefault(import("@typescript-eslint/eslint-plugin")), interopDefault(import("@typescript-eslint/parser"))]);
1561
1617
  function makeParser(typeAware, files, ignores) {
1562
1618
  return {
@@ -1628,11 +1684,7 @@ async function typescript(options = {}) {
1628
1684
  "no-redeclare": "off",
1629
1685
  "no-use-before-define": "off",
1630
1686
  "no-useless-constructor": "off",
1631
- ...type === "lib" ? { "@typescript-eslint/explicit-function-return-type": ["error", {
1632
- allowExpressions: true,
1633
- allowHigherOrderFunctions: true,
1634
- allowIIFEs: true
1635
- }] } : {},
1687
+ ...buildLibRules(type),
1636
1688
  ...customRules,
1637
1689
  ...overrides
1638
1690
  }
@@ -1642,7 +1694,7 @@ async function typescript(options = {}) {
1642
1694
  ignores: ignoresTypeAware,
1643
1695
  name: "rotki/typescript/rules-type-aware",
1644
1696
  rules: {
1645
- ...typeAwareRules,
1697
+ ...buildTypeAwareRules(isInEditor),
1646
1698
  ...overridesTypeAware
1647
1699
  }
1648
1700
  }] : []
@@ -1653,12 +1705,12 @@ async function typescript(options = {}) {
1653
1705
  const FILENAME_CASE_IGNORE = /^[A-Z]+\..*$/;
1654
1706
  async function unicorn(options = {}) {
1655
1707
  return [{
1708
+ files: [GLOB_SRC, GLOB_VUE],
1656
1709
  name: "rotki/unicorn/rules",
1657
1710
  plugins: { unicorn: pluginUnicorn },
1658
1711
  rules: { ...options.allRecommended ? pluginUnicorn.configs.recommended.rules : {
1659
- "unicorn/better-regex": "error",
1660
1712
  "unicorn/catch-error-name": "error",
1661
- "unicorn/consistent-destructuring": "warn",
1713
+ "unicorn/consistent-destructuring": "error",
1662
1714
  "unicorn/custom-error-definition": "error",
1663
1715
  "unicorn/error-message": "error",
1664
1716
  "unicorn/escape-case": "error",
@@ -1709,18 +1761,26 @@ async function unicorn(options = {}) {
1709
1761
  "unicorn/prefer-type-error": "error",
1710
1762
  "unicorn/throw-new-error": "error"
1711
1763
  } }
1712
- }, {
1713
- files: [".github/**/*.md"],
1714
- name: "rotki/unicorn/github-markdown",
1715
- rules: { "unicorn/filename-case": "off" }
1716
1764
  }];
1717
1765
  }
1718
1766
  //#endregion
1719
1767
  //#region src/configs/vue.ts
1720
- async function vue(options = {}) {
1768
+ function resolveVueOptions(options) {
1721
1769
  const { files = [GLOB_VUE], overrides = {}, stylistic = true, typescript } = options;
1722
1770
  const sfcBlocks = options.sfcBlocks === true ? {} : options.sfcBlocks ?? {};
1723
- const { indent = 2 } = typeof stylistic === "boolean" ? {} : stylistic;
1771
+ const { braceStyle = "stroustrup", indent = 2 } = typeof stylistic === "boolean" ? {} : stylistic;
1772
+ return {
1773
+ braceStyle,
1774
+ files,
1775
+ indent,
1776
+ overrides,
1777
+ sfcBlocks,
1778
+ stylistic,
1779
+ typescript
1780
+ };
1781
+ }
1782
+ async function vue(options = {}) {
1783
+ const { braceStyle, files, indent, overrides, sfcBlocks, stylistic, typescript } = resolveVueOptions(options);
1724
1784
  const [pluginVue, parserVue, processorVueBlocks] = await Promise.all([
1725
1785
  interopDefault(import("eslint-plugin-vue")),
1726
1786
  interopDefault(import("vue-eslint-parser")),
@@ -1728,10 +1788,11 @@ async function vue(options = {}) {
1728
1788
  ]);
1729
1789
  const customRules = {
1730
1790
  "max-lines": ["warn", { max: 800 }],
1791
+ "vue/block-lang": ["error", { script: { lang: "ts" } }],
1731
1792
  "vue/component-api-style": ["error", ["script-setup"]],
1732
1793
  "vue/define-emits-declaration": ["error", "type-literal"],
1733
1794
  "vue/define-props-declaration": ["error", "type-based"],
1734
- "vue/define-props-destructuring": "warn",
1795
+ "vue/define-props-destructuring": "error",
1735
1796
  "vue/first-attribute-linebreak": ["error", {
1736
1797
  multiline: "below",
1737
1798
  singleline: "ignore"
@@ -1746,14 +1807,14 @@ async function vue(options = {}) {
1746
1807
  math: "always",
1747
1808
  svg: "always"
1748
1809
  }],
1749
- "vue/max-props": ["warn", { maxProps: 6 }],
1750
- "vue/max-template-depth": ["warn", { maxDepth: 8 }],
1810
+ "vue/max-props": ["error", { maxProps: 8 }],
1811
+ "vue/max-template-depth": ["error", { maxDepth: 8 }],
1751
1812
  "vue/multiline-html-element-content-newline": ["error", {
1752
1813
  allowEmptyLines: false,
1753
1814
  ignores: ["pre", "textarea"],
1754
1815
  ignoreWhenEmpty: true
1755
1816
  }],
1756
- "vue/no-constant-condition": "warn",
1817
+ "vue/no-constant-condition": "error",
1757
1818
  "vue/no-deprecated-dollar-listeners-api": "error",
1758
1819
  "vue/no-deprecated-events-api": "error",
1759
1820
  "vue/no-deprecated-filter": "error",
@@ -1763,7 +1824,7 @@ async function vue(options = {}) {
1763
1824
  "vue/no-required-prop-with-default": ["error", { autofix: true }],
1764
1825
  "vue/no-static-inline-styles": ["error", { allowBinding: false }],
1765
1826
  "vue/no-unused-emit-declarations": "error",
1766
- "vue/no-unused-properties": ["warn", { groups: [
1827
+ "vue/no-unused-properties": ["error", { groups: [
1767
1828
  "props",
1768
1829
  "data",
1769
1830
  "computed",
@@ -1771,9 +1832,10 @@ async function vue(options = {}) {
1771
1832
  ] }],
1772
1833
  "vue/prefer-define-options": "error",
1773
1834
  "vue/prefer-import-from-vue": "error",
1774
- "vue/prefer-use-template-ref": "warn",
1835
+ "vue/prefer-true-attribute-shorthand": "error",
1836
+ "vue/prefer-use-template-ref": "error",
1775
1837
  "vue/require-explicit-emits": "error",
1776
- "vue/require-explicit-slots": "warn",
1838
+ "vue/require-explicit-slots": "error",
1777
1839
  "vue/require-expose": "error",
1778
1840
  "vue/require-macro-variable-name": ["error", {
1779
1841
  defineEmits: "emit",
@@ -1947,7 +2009,7 @@ async function vue(options = {}) {
1947
2009
  }],
1948
2010
  "vue/brace-style": [
1949
2011
  "error",
1950
- "stroustrup",
2012
+ braceStyle,
1951
2013
  { allowSingleLine: true }
1952
2014
  ],
1953
2015
  "vue/comma-dangle": ["error", "always-multiline"],
@@ -1985,7 +2047,7 @@ async function vue(options = {}) {
1985
2047
  }
1986
2048
  //#endregion
1987
2049
  //#region src/configs/vue-i18n.ts
1988
- async function vueI18n(options = {}) {
2050
+ function resolveVueI18nOptions(options) {
1989
2051
  const { files = [GLOB_TS, GLOB_VUE], isInEditor = false, localesDirectory = "locales", noRawTextIgnores = {
1990
2052
  nodes: [
1991
2053
  "md-icon",
@@ -1999,6 +2061,18 @@ async function vueI18n(options = {}) {
1999
2061
  "USD"
2000
2062
  ]
2001
2063
  }, overrides = {}, src = "src", typescript } = options;
2064
+ return {
2065
+ files,
2066
+ isInEditor,
2067
+ localesDirectory,
2068
+ noRawTextIgnores,
2069
+ overrides,
2070
+ src,
2071
+ typescript
2072
+ };
2073
+ }
2074
+ async function vueI18n(options = {}) {
2075
+ const { files, isInEditor, localesDirectory, noRawTextIgnores, overrides, src, typescript } = resolveVueI18nOptions(options);
2002
2076
  const fileGlobs = files.map((x) => `**/${src}/${x}`);
2003
2077
  if (localesDirectory) fileGlobs.push(`**/${src}/${localesDirectory}/${GLOB_JSON}`, `**/${src}/${localesDirectory}/${GLOB_JSON5}`, `**/${src}/${localesDirectory}/${GLOB_YAML}`);
2004
2078
  const localeDir = path.resolve(path.join(process.cwd(), src, localesDirectory));
@@ -2050,10 +2124,19 @@ async function vueI18n(options = {}) {
2050
2124
  }
2051
2125
  //#endregion
2052
2126
  //#region src/configs/yaml.ts
2053
- async function yaml(options = {}) {
2127
+ function resolveYamlOptions(options) {
2054
2128
  const { files = [GLOB_YAML], overrides = {}, stylistic = true } = options;
2055
2129
  const { indent: rawIndent = 2, quotes = "single" } = typeof stylistic === "boolean" ? {} : stylistic;
2056
- const indent = Array.isArray(rawIndent) ? rawIndent[0] : rawIndent;
2130
+ return {
2131
+ files,
2132
+ indent: Array.isArray(rawIndent) ? rawIndent[0] : rawIndent,
2133
+ overrides,
2134
+ quotes,
2135
+ stylistic
2136
+ };
2137
+ }
2138
+ async function yaml(options = {}) {
2139
+ const { files, indent, overrides, quotes, stylistic } = resolveYamlOptions(options);
2057
2140
  const [pluginYaml, parserYaml] = await Promise.all([interopDefault(import("eslint-plugin-yml")), interopDefault(import("yaml-eslint-parser"))]);
2058
2141
  return [{
2059
2142
  name: "rotki/yaml/setup",
@@ -2115,24 +2198,49 @@ const defaultPluginRenaming = {
2115
2198
  "vitest": "test",
2116
2199
  "yml": "yaml"
2117
2200
  };
2118
- /**
2119
- * Construct an array of ESLint flat config items.
2120
- */
2121
- function rotki(options = {}, ...userConfigs) {
2122
- const { autoRenamePlugins = true, componentExts = [], e18e: enableE18e = true, gitignore: enableGitignore = true, jsx = true, pnpm: enablePnpm = !!findUpSync("pnpm-workspace.yaml"), regexp: enableRegexp = false, rotki: enableRotki, storybook: enableStorybook, typescript: enableTypeScript = isPackageExists("typescript") || isPackageExists("@typescript/native-preview"), unicorn: enableUnicorn = true, vue: enableVue = VuePackages.some((i) => isPackageExists(i)), vueI18n: enableVueI18n } = options;
2201
+ function resolveStylisticOptions(options, jsx) {
2202
+ if (options.stylistic === false) return false;
2203
+ const stylisticOptions = typeof options.stylistic === "object" ? options.stylistic : {};
2204
+ if (!("jsx" in stylisticOptions)) stylisticOptions.jsx = jsx;
2205
+ return stylisticOptions;
2206
+ }
2207
+ function resolveEnableFlags(options) {
2208
+ return {
2209
+ autoRenamePlugins: options.autoRenamePlugins ?? true,
2210
+ enableE18e: options.e18e ?? true,
2211
+ enableGitignore: options.gitignore ?? true,
2212
+ enablePerfectionist: !!(options.perfectionist ?? true),
2213
+ enablePnpm: !!(options.pnpm ?? findUpSync("pnpm-workspace.yaml")),
2214
+ enableRegexp: options.regexp ?? false,
2215
+ enableRotki: options.rotki,
2216
+ enableStorybook: options.storybook,
2217
+ enableUnicorn: options.unicorn ?? true,
2218
+ enableVueI18n: options.vueI18n
2219
+ };
2220
+ }
2221
+ function resolveIsInEditor(options) {
2123
2222
  let isInEditor = options.isInEditor;
2124
2223
  if (isInEditor === null) {
2125
2224
  isInEditor = isInEditorEnv();
2126
2225
  if (isInEditor) console.log("[@rotki/eslint-config] Detected running in editor, some rules are disabled.");
2127
2226
  }
2128
- function resolveStylisticOptions() {
2129
- if (options.stylistic === false) return false;
2130
- if (typeof options.stylistic === "object") return options.stylistic;
2131
- return {};
2132
- }
2133
- const stylisticOptions = resolveStylisticOptions();
2134
- if (stylisticOptions && !("jsx" in stylisticOptions)) stylisticOptions.jsx = jsx;
2135
- const configs = [];
2227
+ return !!isInEditor;
2228
+ }
2229
+ function resolveOptions(options) {
2230
+ const jsx = options.jsx ?? true;
2231
+ const enableVue = !!(options.vue ?? VuePackages.some((i) => isPackageExists(i)));
2232
+ return {
2233
+ ...resolveEnableFlags(options),
2234
+ componentExts: [...options.componentExts ?? [], ...enableVue ? ["vue"] : []],
2235
+ enableTypeScript: options.typescript ?? (isPackageExists("typescript") || isPackageExists("@typescript/native-preview")),
2236
+ enableVue,
2237
+ isInEditor: resolveIsInEditor(options),
2238
+ stylisticOptions: resolveStylisticOptions(options, jsx),
2239
+ typescriptOptions: resolveSubOptions(options, "typescript")
2240
+ };
2241
+ }
2242
+ function buildLanguageConfigs(configs, options, resolved) {
2243
+ const { enableE18e, enableGitignore, enablePerfectionist, enableUnicorn, isInEditor, stylisticOptions } = resolved;
2136
2244
  if (enableGitignore) {
2137
2245
  const gitignoreOptions = typeof enableGitignore !== "boolean" ? enableGitignore : { strict: false };
2138
2246
  configs.push(interopDefault(import("eslint-config-flat-gitignore")).then((r) => [r({
@@ -2140,21 +2248,23 @@ function rotki(options = {}, ...userConfigs) {
2140
2248
  ...gitignoreOptions
2141
2249
  })]));
2142
2250
  }
2143
- const typescriptOptions = resolveSubOptions(options, "typescript");
2144
2251
  configs.push(ignores(options.ignores), javascript({
2145
2252
  isInEditor,
2146
2253
  overrides: getOverrides(options, "javascript")
2147
2254
  }), comments(), node(), imports({
2148
2255
  overrides: getOverrides(options, "imports"),
2149
2256
  stylistic: stylisticOptions
2150
- }), perfectionist());
2257
+ }));
2258
+ if (enablePerfectionist) configs.push(perfectionist({ overrides: getOverrides(options, "perfectionist") }));
2151
2259
  if (enableUnicorn) configs.push(unicorn(enableUnicorn === true ? {} : enableUnicorn));
2152
2260
  if (enableE18e) configs.push(e18e({
2153
2261
  ...typeof enableE18e === "boolean" ? {} : enableE18e,
2154
2262
  isInEditor,
2155
2263
  type: options.type
2156
2264
  }));
2157
- if (enableVue) componentExts.push("vue");
2265
+ }
2266
+ function buildTypeScriptAndStyleConfigs(configs, options, resolved) {
2267
+ const { componentExts, enableRegexp, enableTypeScript, isInEditor, stylisticOptions, typescriptOptions } = resolved;
2158
2268
  if (enableTypeScript) configs.push(typescript({
2159
2269
  ...typescriptOptions,
2160
2270
  componentExts,
@@ -2171,6 +2281,9 @@ function rotki(options = {}, ...userConfigs) {
2171
2281
  isInEditor,
2172
2282
  overrides: getOverrides(options, "test")
2173
2283
  }));
2284
+ }
2285
+ function buildFrameworkConfigs(configs, options, resolved) {
2286
+ const { enableRotki, enableStorybook, enableTypeScript, enableVue, enableVueI18n, stylisticOptions } = resolved;
2174
2287
  if (enableVue) configs.push(vue({
2175
2288
  ...resolveSubOptions(options, "vue"),
2176
2289
  overrides: getOverrides(options, "vue"),
@@ -2189,19 +2302,19 @@ function rotki(options = {}, ...userConfigs) {
2189
2302
  typescript: !!enableTypeScript
2190
2303
  }));
2191
2304
  if (enableStorybook) configs.push(storybook({ overrides: getOverrides(options, "storybook") }));
2305
+ }
2306
+ function buildFileFormatConfigs(configs, options, resolved) {
2307
+ const { componentExts, enablePnpm, isInEditor, stylisticOptions } = resolved;
2192
2308
  if (options.jsonc ?? true) configs.push(jsonc({
2193
2309
  overrides: getOverrides(options, "jsonc"),
2194
2310
  stylistic: stylisticOptions
2195
2311
  }), sortPackageJson(), sortTsconfig());
2196
- if (enablePnpm) {
2197
- const optionsPnpm = resolveSubOptions(options, "pnpm");
2198
- configs.push(pnpm({
2199
- isInEditor,
2200
- json: options.jsonc !== false,
2201
- yaml: options.yaml !== false,
2202
- ...optionsPnpm
2203
- }));
2204
- }
2312
+ if (enablePnpm) configs.push(pnpm({
2313
+ isInEditor,
2314
+ json: options.jsonc !== false,
2315
+ yaml: options.yaml !== false,
2316
+ ...resolveSubOptions(options, "pnpm")
2317
+ }));
2205
2318
  if (options.yaml ?? true) configs.push(yaml({
2206
2319
  overrides: getOverrides(options, "yaml"),
2207
2320
  stylistic: stylisticOptions
@@ -2211,8 +2324,8 @@ function rotki(options = {}, ...userConfigs) {
2211
2324
  overrides: getOverrides(options, "markdown")
2212
2325
  }));
2213
2326
  if (options.formatters) configs.push(formatters(options.formatters, typeof stylisticOptions === "boolean" ? {} : stylisticOptions));
2214
- configs.push(disables());
2215
- if ("files" in options) throw new Error("[@rotki/eslint-config] The first argument should not contain the \"files\" property as the options are supposed to be global. Place it in the second or later config instead.");
2327
+ }
2328
+ function finalizeComposer(configs, options, resolved, userConfigs) {
2216
2329
  const fusedConfig = flatConfigProps.reduce((acc, key) => {
2217
2330
  if (key in options) acc[key] = options[key];
2218
2331
  return acc;
@@ -2220,14 +2333,29 @@ function rotki(options = {}, ...userConfigs) {
2220
2333
  if (Object.keys(fusedConfig).length > 0) configs.push([fusedConfig]);
2221
2334
  let composer = new FlatConfigComposer();
2222
2335
  composer = composer.append(...configs, ...userConfigs);
2223
- if (autoRenamePlugins) composer = composer.renamePlugins(defaultPluginRenaming);
2224
- if (isInEditor) composer = composer.disableRulesFix([
2336
+ if (options.markdown ?? true) composer = composer.setDefaultIgnores((prev) => [...prev, GLOB_MARKDOWN]);
2337
+ if (resolved.autoRenamePlugins) composer = composer.renamePlugins(defaultPluginRenaming);
2338
+ if (resolved.isInEditor) composer = composer.disableRulesFix([
2225
2339
  "unused-imports/no-unused-imports",
2226
2340
  "test/no-only-tests",
2227
2341
  "prefer-const"
2228
2342
  ], { builtinRules: () => import(["eslint", "use-at-your-own-risk"].join("/")).then((r) => r.builtinRules) });
2229
2343
  return composer;
2230
2344
  }
2345
+ /**
2346
+ * Construct an array of ESLint flat config items.
2347
+ */
2348
+ function rotki(options = {}, ...userConfigs) {
2349
+ if ("files" in options) throw new Error("[@rotki/eslint-config] The first argument should not contain the \"files\" property as the options are supposed to be global. Place it in the second or later config instead.");
2350
+ const resolved = resolveOptions(options);
2351
+ const configs = [];
2352
+ buildLanguageConfigs(configs, options, resolved);
2353
+ buildTypeScriptAndStyleConfigs(configs, options, resolved);
2354
+ buildFrameworkConfigs(configs, options, resolved);
2355
+ buildFileFormatConfigs(configs, options, resolved);
2356
+ configs.push(disables());
2357
+ return finalizeComposer(configs, options, resolved, userConfigs);
2358
+ }
2231
2359
  function resolveSubOptions(options, key) {
2232
2360
  return typeof options[key] === "boolean" ? {} : options[key] || {};
2233
2361
  }