ソースを参照

Housekeeping & Make ESLint Happy

SukkaW 1 年間 前
コミット
8a0690fe9e

+ 1 - 1
Build/build-cdn-download-conf.ts

@@ -1,4 +1,4 @@
-import path from 'path';
+import path from 'node:path';
 import { createRuleset } from './lib/create-file';
 import { readFileIntoProcessedArray } from './lib/fetch-text-by-line';
 import { createTrie } from './lib/trie';

+ 1 - 1
Build/build-cloudmounter-rules.ts

@@ -1,4 +1,4 @@
-import path from 'path';
+import path from 'node:path';
 import { DOMAINS, PROCESS_NAMES } from '../Source/non_ip/cloudmounter';
 import { SHARED_DESCRIPTION } from './lib/constants';
 import { createRuleset } from './lib/create-file';

+ 1 - 1
Build/build-common.ts

@@ -1,6 +1,6 @@
 // @ts-check
 
-import * as path from 'path';
+import * as path from 'node:path';
 import { readFileByLine } from './lib/fetch-text-by-line';
 import { processLine } from './lib/process-line';
 import { createRuleset } from './lib/create-file';

+ 1 - 1
Build/build-deprecate-files.ts

@@ -1,6 +1,6 @@
 import { compareAndWriteFile } from './lib/create-file';
 import { task } from './trace';
-import path from 'path';
+import path from 'node:path';
 
 const DEPRECATED_FILES = [
   ['non_ip/global_plus', 'This file has been merged with non_ip/global'],

+ 1 - 1
Build/build-domestic-direct-lan-ruleset-dns-mapping-module.ts

@@ -1,5 +1,5 @@
 // @ts-check
-import path from 'path';
+import path from 'node:path';
 import { DOMESTICS } from '../Source/non_ip/domestic';
 import { DIRECTS, LANS } from '../Source/non_ip/direct';
 import { readFileIntoProcessedArray } from './lib/fetch-text-by-line';

+ 1 - 1
Build/build-internal-reverse-chn-cidr.ts

@@ -1,4 +1,4 @@
-import path from 'path';
+import path from 'node:path';
 import { task } from './trace';
 
 import { exclude, merge } from 'fast-cidr-tools';

+ 1 - 1
Build/build-mitm-hostname.ts

@@ -1,5 +1,5 @@
 import { readFileByLine } from './lib/fetch-text-by-line';
-import pathFn from 'path';
+import pathFn from 'node:path';
 import table from 'table';
 import { fdir as Fdir } from 'fdir';
 import { green, yellow } from 'picocolors';

+ 3 - 3
Build/build-public.ts

@@ -1,6 +1,6 @@
-import path from 'path';
-import fs from 'fs';
-import fsp from 'fs/promises';
+import path from 'node:path';
+import fs from 'node:fs';
+import fsp from 'node:fs/promises';
 import { task } from './trace';
 import { treeDir } from './lib/tree-dir';
 import type { TreeType, TreeTypeArray } from './lib/tree-dir';

+ 2 - 1
Build/build-reject-domainset.ts

@@ -1,5 +1,6 @@
 // @ts-check
-import path from 'path';
+import path from 'node:path';
+import process from 'node:process';
 
 import { processHosts, processFilterRules, processDomainLists } from './lib/parse-filter';
 import { createTrie } from './lib/trie';

+ 1 - 1
Build/build-reject-ip-list.ts

@@ -1,5 +1,5 @@
 // @ts-check
-import path from 'path';
+import path from 'node:path';
 import { createRuleset } from './lib/create-file';
 import { fetchRemoteTextByLine, readFileIntoProcessedArray } from './lib/fetch-text-by-line';
 import { task } from './trace';

+ 1 - 1
Build/build-sgmodule-always-realip.ts

@@ -1,4 +1,4 @@
-import path from 'path';
+import path from 'node:path';
 import { task } from './trace';
 import { compareAndWriteFile } from './lib/create-file';
 import { DIRECTS, LANS } from '../Source/non_ip/direct';

+ 1 - 1
Build/build-sgmodule-redirect.ts

@@ -1,4 +1,4 @@
-import path from 'path';
+import path from 'node:path';
 import { task } from './trace';
 import { compareAndWriteFile } from './lib/create-file';
 import { getHostname } from 'tldts';

+ 1 - 1
Build/build-speedtest-domainset.ts

@@ -1,5 +1,5 @@
 import { domainDeduper } from './lib/domain-deduper';
-import path from 'path';
+import path from 'node:path';
 import { createRuleset } from './lib/create-file';
 import { sortDomains } from './lib/stable-sort-domain';
 

+ 1 - 1
Build/build-sspanel-appprofile.ts

@@ -3,7 +3,7 @@ import { getDomesticAndDirectDomainsRulesetPromise } from './build-domestic-dire
 import { surgeRulesetToClashClassicalTextRuleset, surgeDomainsetToClashRuleset } from './lib/clash';
 import { readFileIntoProcessedArray } from './lib/fetch-text-by-line';
 import { task } from './trace';
-import path from 'path';
+import path from 'node:path';
 
 import { ALL as AllStreamServices } from '../Source/stream';
 import { getChnCidrPromise } from './build-chn-cidr';

+ 4 - 4
Build/download-mock-assets.ts

@@ -1,8 +1,8 @@
 import { task } from './trace';
-import path from 'path';
-import fs from 'fs';
-import { Readable } from 'stream';
-import { pipeline } from 'stream/promises';
+import path from 'node:path';
+import fs from 'node:fs';
+import { Readable } from 'node:stream';
+import { pipeline } from 'node:stream/promises';
 import { fetchWithRetry } from './lib/fetch-retry';
 
 const ASSETS_LIST = {

+ 8 - 10
Build/download-previous-build.ts

@@ -1,14 +1,14 @@
-import { existsSync, createWriteStream } from 'fs';
-import { mkdir } from 'fs/promises';
-import path from 'path';
-import { pipeline } from 'stream/promises';
+import { existsSync, createWriteStream } from 'node:fs';
+import { mkdir } from 'node:fs/promises';
+import path from 'node:path';
+import { pipeline } from 'node:stream/promises';
 import { readFileByLine } from './lib/fetch-text-by-line';
 import { isCI } from 'ci-info';
 import { task } from './trace';
 import { defaultRequestInit, fetchWithRetry } from './lib/fetch-retry';
 import tarStream from 'tar-stream';
-import zlib from 'zlib';
-import { Readable } from 'stream';
+import zlib from 'node:zlib';
+import { Readable } from 'node:stream';
 
 const IS_READING_BUILD_OUTPUT = 1 << 2;
 const ALL_FILES_EXISTS = 1 << 3;
@@ -32,10 +32,8 @@ export const downloadPreviousBuild = task(require.main === module, __filename)(a
 
         buildOutputList.push(line);
 
-        if (!isCI) {
-          if (!existsSync(path.join(__dirname, '..', line))) {
-            flag = flag & ~ALL_FILES_EXISTS;
-          }
+        if (!isCI && !existsSync(path.join(__dirname, '..', line))) {
+          flag = flag & ~ALL_FILES_EXISTS;
         }
       }
     });

+ 2 - 0
Build/index.ts

@@ -1,3 +1,5 @@
+import process from 'node:process';
+
 console.log('Version:', process.version);
 
 import { downloadPreviousBuild } from './download-previous-build';

+ 2 - 0
Build/lib/cache-apply.ts

@@ -1,3 +1,5 @@
+import process from 'node:process';
+
 export const createCache = (namespace?: string, printStats = false) => {
   const cache = new Map();
 

+ 6 - 7
Build/lib/cache-filesystem.ts

@@ -1,17 +1,16 @@
 import createDb from 'better-sqlite3';
 import type { Database } from 'better-sqlite3';
-import os from 'os';
-import path from 'path';
-import { mkdirSync } from 'fs';
+import os from 'node:os';
+import path from 'node:path';
+import { mkdirSync } from 'node:fs';
 import picocolors from 'picocolors';
 import { fastStringArrayJoin } from './misc';
-import { performance } from 'perf_hooks';
-import fs from 'fs';
+import { performance } from 'node:perf_hooks';
+import fs from 'node:fs';
 import { stringHash } from './string-hash';
 
 const identity = (x: any) => x;
 
-// eslint-disable-next-line sukka-ts/no-const-enum -- bun is smart, right?
 const enum CacheStatus {
   Hit = 'hit',
   Stale = 'stale',
@@ -156,7 +155,7 @@ export class Cache<S = string> {
     const now = Date.now();
     const rv = this.db.prepare<string, { ttl: number }>(`SELECT ttl FROM ${this.tableName} WHERE key = ?`).get(key);
 
-    return !rv ? CacheStatus.Miss : (rv.ttl > now ? CacheStatus.Hit : CacheStatus.Stale);
+    return rv ? (rv.ttl > now ? CacheStatus.Hit : CacheStatus.Stale) : CacheStatus.Miss;
   }
 
   del(key: string): void {

+ 8 - 6
Build/lib/convert-clash-meta-mrs.ts

@@ -1,9 +1,11 @@
-import path from 'path';
-import fs from 'fs';
-import fsp from 'fs/promises';
-import { Readable } from 'stream';
-import { pipeline } from 'stream/promises';
-import zlib from 'zlib';
+import path from 'node:path';
+import fs from 'node:fs';
+import fsp from 'node:fs/promises';
+import { Readable } from 'node:stream';
+import { pipeline } from 'node:stream/promises';
+import zlib from 'node:zlib';
+import process from 'node:process';
+
 import { async as ezspawn } from '@jsdevtools/ez-spawn';
 
 const mihomoBinaryDir = path.join(__dirname, '../../node_modules/.cache/mihomo');

+ 2 - 2
Build/lib/create-file.ts

@@ -2,8 +2,8 @@
 import { surgeDomainsetToClashDomainset, surgeRulesetToClashClassicalTextRuleset } from './clash';
 import picocolors from 'picocolors';
 import type { Span } from '../trace';
-import path from 'path';
-import fs from 'fs';
+import path from 'node:path';
+import fs from 'node:fs';
 import { fastStringArrayJoin, writeFile } from './misc';
 import { readFileByLine } from './fetch-text-by-line';
 import stringify from 'json-stringify-pretty-compact';

+ 6 - 1
Build/lib/fetch-assets.ts

@@ -1,8 +1,13 @@
 import picocolors from 'picocolors';
 import { defaultRequestInit, fetchWithRetry } from './fetch-retry';
-import { setTimeout } from 'timers/promises';
+import { setTimeout } from 'node:timers/promises';
 
 class CustomAbortError extends Error {
+  constructor() {
+    super();
+    this.name = 'CustomAbortError';
+  }
+
   public readonly name = 'AbortError';
   public readonly digest = 'AbortError';
 }

+ 8 - 11
Build/lib/fetch-retry.ts

@@ -1,6 +1,6 @@
 import retry from 'async-retry';
 import picocolors from 'picocolors';
-import { setTimeout } from 'timers/promises';
+import { setTimeout } from 'node:timers/promises';
 
 function isClientError(err: unknown): err is NodeJS.ErrnoException {
   if (!err || typeof err !== 'object') return false;
@@ -24,6 +24,7 @@ export class ResponseError extends Error {
       Error.captureStackTrace(this, ResponseError);
     }
 
+    // eslint-disable-next-line sukka/unicorn/custom-error-definition -- deliberatly use previous name
     this.name = this.constructor.name;
     this.res = res;
     this.code = res.status;
@@ -90,16 +91,12 @@ function createFetchRetry($fetch: typeof fetch): FetchWithRetry {
             return res;
           }
         } catch (err: unknown) {
-          if (err instanceof Error) {
-            if (
-              err.name === 'AbortError'
-              || ('digest' in err && err.digest === 'AbortError')
-            ) {
-              if (!retryOpts.retryOnAborted) {
-                console.log(picocolors.gray('[fetch abort]'), url);
-                return bail(err) as never;
-              }
-            }
+          if (err instanceof Error && (
+            err.name === 'AbortError'
+            || ('digest' in err && err.digest === 'AbortError')
+          ) && !retryOpts.retryOnAborted) {
+            console.log(picocolors.gray('[fetch abort]'), url);
+            return bail(err) as never;
           }
           if (isClientError(err)) {
             return bail(err) as never;

+ 2 - 2
Build/lib/fetch-text-by-line.bench.ts

@@ -1,8 +1,8 @@
 import { bench, group, run } from 'mitata';
 import { processLine, processLineFromReadline } from './process-line';
 import { readFileByLine } from './fetch-text-by-line';
-import path from 'path';
-import fsp from 'fs/promises';
+import path from 'node:path';
+import fsp from 'node:fs/promises';
 
 const file = path.resolve(__dirname, '../../Source/domainset/cdn.conf');
 

+ 5 - 5
Build/lib/fetch-text-by-line.ts

@@ -1,11 +1,11 @@
-import fs from 'fs';
-import { Readable } from 'stream';
+import fs from 'node:fs';
+import { Readable } from 'node:stream';
 import { fetchWithRetry, defaultRequestInit } from './fetch-retry';
-import type { FileHandle } from 'fs/promises';
+import type { FileHandle } from 'node:fs/promises';
 
 import { TextLineStream } from './text-line-transform-stream';
-import type { ReadableStream } from 'stream/web';
-import { TextDecoderStream } from 'stream/web';
+import type { ReadableStream } from 'node:stream/web';
+import { TextDecoderStream } from 'node:stream/web';
 import { processLine } from './process-line';
 
 const getReadableStream = (file: string | FileHandle): ReadableStream => {

+ 3 - 3
Build/lib/misc.ts

@@ -1,6 +1,6 @@
-import path, { dirname } from 'path';
-import fs from 'fs';
-import fsp from 'fs/promises';
+import path, { dirname } from 'node:path';
+import fs from 'node:fs';
+import fsp from 'node:fs/promises';
 
 export const isTruthy = <T>(i: T | 0 | '' | false | null | undefined): i is T => !!i;
 

+ 15 - 18
Build/lib/parse-filter.ts

@@ -132,7 +132,6 @@ export function processHosts(span: Span, hostsUrl: string, mirrors: string[] | n
   ));
 }
 
-// eslint-disable-next-line sukka-ts/no-const-enum -- bun bundler is smart, maybe?
 const enum ParseType {
   WhiteIncludeSubdomain = 0,
   WhiteAbsolute = -1,
@@ -174,25 +173,23 @@ export async function processFilterRules(
 
         const hostname = result[0];
 
-        if (DEBUG_DOMAIN_TO_FIND) {
-          if (hostname.includes(DEBUG_DOMAIN_TO_FIND)) {
-            console.warn(
-              picocolors.red(filterRulesUrl),
-              flag === ParseType.WhiteIncludeSubdomain || flag === ParseType.WhiteAbsolute
-                ? '(white)'
-                : '(black)',
-              hostname.replaceAll(DEBUG_DOMAIN_TO_FIND, picocolors.bold(DEBUG_DOMAIN_TO_FIND))
-            );
-            foundDebugDomain = true;
-          }
+        if (DEBUG_DOMAIN_TO_FIND && hostname.includes(DEBUG_DOMAIN_TO_FIND)) {
+          console.warn(
+            picocolors.red(filterRulesUrl),
+            flag === ParseType.WhiteIncludeSubdomain || flag === ParseType.WhiteAbsolute
+              ? '(white)'
+              : '(black)',
+            hostname.replaceAll(DEBUG_DOMAIN_TO_FIND, picocolors.bold(DEBUG_DOMAIN_TO_FIND))
+          );
+          foundDebugDomain = true;
         }
 
         switch (flag) {
           case ParseType.WhiteIncludeSubdomain:
-            if (hostname[0] !== '.') {
-              whitelistDomainSets.add(`.${hostname}`);
-            } else {
+            if (hostname[0] === '.') {
               whitelistDomainSets.add(hostname);
+            } else {
+              whitelistDomainSets.add(`.${hostname}`);
             }
             break;
           case ParseType.WhiteAbsolute:
@@ -202,10 +199,10 @@ export async function processFilterRules(
             blacklistDomainSets.add(hostname);
             break;
           case ParseType.BlackIncludeSubdomain:
-            if (hostname[0] !== '.') {
-              blacklistDomainSets.add(`.${hostname}`);
-            } else {
+            if (hostname[0] === '.') {
               blacklistDomainSets.add(hostname);
+            } else {
+              blacklistDomainSets.add(`.${hostname}`);
             }
             break;
           case ParseType.ErrorMessage:

+ 1 - 1
Build/lib/text-line-transform-stream.ts

@@ -2,7 +2,7 @@
 // This module is browser compatible.
 // Modified by Sukka (https://skk.moe) to increase compatibility and performance with Bun.
 
-import { TransformStream } from 'stream/web';
+import { TransformStream } from 'node:stream/web';
 
 interface TextLineStreamOptions {
   /** Allow splitting by solo \r */

+ 2 - 2
Build/lib/tree-dir.ts

@@ -1,5 +1,5 @@
-import fsp from 'fs/promises';
-import { sep } from 'path';
+import fsp from 'node:fs/promises';
+import { sep } from 'node:path';
 
 interface TreeFileType {
   type: 'file',

+ 1 - 1
Build/lib/trie.ts

@@ -3,7 +3,7 @@
  */
 
 import { fastStringArrayJoin } from './misc';
-import { inspect } from 'util';
+import { inspect } from 'node:util';
 
 const noop = () => { /** noop */ };
 

+ 1 - 1
Build/trace/index.ts

@@ -1,4 +1,4 @@
-import { basename, extname } from 'path';
+import { basename, extname } from 'node:path';
 import picocolors from 'picocolors';
 
 const SPAN_STATUS_START = 0;

+ 2 - 2
Build/trim-source.ts

@@ -1,5 +1,5 @@
-import path from 'path';
-import fsp from 'fs/promises';
+import path from 'node:path';
+import fsp from 'node:fs/promises';
 import { fdir as Fdir } from 'fdir';
 import { readFileByLine } from './lib/fetch-text-by-line';
 

+ 1 - 1
Build/validate-domestic.ts

@@ -1,7 +1,7 @@
 import { fetchRemoteTextByLine, readFileByLine } from './lib/fetch-text-by-line';
 import { parse } from 'csv-parse/sync';
 import { createTrie } from './lib/trie';
-import path from 'path';
+import path from 'node:path';
 import { processLine } from './lib/process-line';
 import { extractDomainsFromFelixDnsmasq } from './lib/parse-dnsmasq';
 

+ 1 - 1
Build/validate-gfwlist.ts

@@ -4,7 +4,7 @@ import { createTrie } from './lib/trie';
 // import { Readable } from 'stream';
 import { parse } from 'csv-parse/sync';
 import { readFileByLine } from './lib/fetch-text-by-line';
-import path from 'path';
+import path from 'node:path';
 
 export const parseGfwList = async () => {
   const whiteSet = new Set<string>();

+ 2 - 1
eslint.config.js

@@ -10,6 +10,7 @@ module.exports = require('eslint-config-sukka').sukka({
   rules: {
     'sukka/unicorn/prefer-math-trunc': 'off',
     'sukka/unicorn/prefer-number-properties': ['warn', { checkInfinity: false }],
-    'n/no-missing-require': 'off'
+    'n/no-missing-require': 'off',
+    'regexp/strict': 'off'
   }
 });

+ 3 - 3
package.json

@@ -41,7 +41,7 @@
     "yaml": "^2.5.0"
   },
   "devDependencies": {
-    "@eslint-sukka/node": "^6.1.11",
+    "@eslint-sukka/node": "^6.2.0",
     "@swc-node/register": "^1.10.9",
     "@swc/core": "^1.7.18",
     "@types/async-retry": "^1.4.8",
@@ -52,8 +52,8 @@
     "@types/tar-stream": "^3.1.3",
     "chai": "4",
     "eslint": "^9.9.1",
-    "eslint-config-sukka": "^6.1.11",
-    "eslint-formatter-sukka": "^6.1.11",
+    "eslint-config-sukka": "^6.2.0",
+    "eslint-formatter-sukka": "^6.2.0",
     "mitata": "^0.1.11",
     "mocha": "^10.7.3",
     "typescript": "^5.5.4"

+ 92 - 35
pnpm-lock.yaml

@@ -70,8 +70,8 @@ importers:
         version: 2.5.0
     devDependencies:
       '@eslint-sukka/node':
-        specifier: ^6.1.11
-        version: 6.1.11(eslint@9.9.1)(typescript@5.5.4)
+        specifier: ^6.2.0
+        version: 6.2.0(eslint@9.9.1)(typescript@5.5.4)
       '@swc-node/register':
         specifier: ^1.10.9
         version: 1.10.9(@swc/core@1.7.18)(@swc/types@0.1.12)(typescript@5.5.4)
@@ -103,11 +103,11 @@ importers:
         specifier: ^9.9.1
         version: 9.9.1
       eslint-config-sukka:
-        specifier: ^6.1.11
-        version: 6.1.11(@typescript-eslint/eslint-plugin@8.2.0(@typescript-eslint/parser@8.2.0(eslint@9.9.1)(typescript@5.5.4))(eslint@9.9.1)(typescript@5.5.4))(eslint@9.9.1)(typescript@5.5.4)
+        specifier: ^6.2.0
+        version: 6.2.0(@typescript-eslint/eslint-plugin@8.2.0(@typescript-eslint/parser@8.2.0(eslint@9.9.1)(typescript@5.5.4))(eslint@9.9.1)(typescript@5.5.4))(eslint@9.9.1)(typescript@5.5.4)
       eslint-formatter-sukka:
-        specifier: ^6.1.11
-        version: 6.1.11
+        specifier: ^6.2.0
+        version: 6.2.0
       mitata:
         specifier: ^0.1.11
         version: 0.1.11
@@ -157,11 +157,11 @@ packages:
     resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==}
     engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
 
-  '@eslint-sukka/node@6.1.11':
-    resolution: {integrity: sha512-9LT9i3k/0Gimkig3UqkytmlFmuraHoACgEHJ+SJB2mgktGVi2eEywTGpaVhWVWL7T1TC07cBMfzNLxD8QJheEA==}
+  '@eslint-sukka/node@6.2.0':
+    resolution: {integrity: sha512-IGZQBvGBrvf93YiBZtBvh/2Msv9SFtyWWLViOL5F4j/dAQiz5P0dep4AduxPOXrb0J9/bE/Yds+232NTtBGEvQ==}
 
-  '@eslint-sukka/shared@6.1.11':
-    resolution: {integrity: sha512-yLnOKIY1epkpmNsm5MQrWNlgJQbHDaOAzBay6YSvG1Oc1hVATtJgv/eIlrcFYwjffTbm1zro/3cawUf2i8phVA==}
+  '@eslint-sukka/shared@6.2.0':
+    resolution: {integrity: sha512-Rib7RV0fiRZC6ibmLzfPOuzOH1+wSPmDm1ZMMX9MGCA2ALVBl3z0xdJIp2295CSdEOjsgh7a9HXNx588/NzP6g==}
 
   '@eslint/compat@1.1.1':
     resolution: {integrity: sha512-lpHyRyplhGPL5mGEh6M9O5nnKk0Gz4bFI+Zu6tKlPpDUN7XshWvH9C/px4UVm87IAANE0W81CEsNGbS1KlzXpA==}
@@ -675,6 +675,10 @@ packages:
   colorette@2.0.20:
     resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
 
+  comment-parser@1.4.1:
+    resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==}
+    engines: {node: '>= 12.0.0'}
+
   concat-map@0.0.1:
     resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
 
@@ -764,17 +768,17 @@ packages:
     peerDependencies:
       eslint: '>=6.0.0'
 
-  eslint-config-sukka@6.1.11:
-    resolution: {integrity: sha512-qsllGJOCBuNfnbqH9B+eIDwKsEgvvmYjPMTTscesCj/Eaouu/i0A3Sz7FxlkSWwDBh7bm8NuZBK7Pc6EYPvb0A==}
+  eslint-config-sukka@6.2.0:
+    resolution: {integrity: sha512-Asc570Sybz6pZ3G6yZhj1emaeCwfCHUZCXPseZxYSIPEvwLlQW02lwJVTbvZiQRg6qij8NyldZZ57ABx2bagLQ==}
 
-  eslint-formatter-sukka@6.1.11:
-    resolution: {integrity: sha512-Ngn9yw4x1c8AFBgUMK1m719zvxmTfJ1FEfyl/q4mjA7OLsmJwh7+NekCPDIDmd4A3lOO9q0ip97VyzTMxz860Q==}
+  eslint-formatter-sukka@6.2.0:
+    resolution: {integrity: sha512-fNreMeIvRjbx+DtvtIUtEXxBUXFFWIs65mJS6ziDZ0G9OPpI+A+ym5CSYXfx0QZu0Rj1N2vZ8WfzbBSEK7UslQ==}
 
   eslint-import-resolver-node@0.3.9:
     resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
 
-  eslint-import-resolver-ts-bundled@6.1.11:
-    resolution: {integrity: sha512-CGUrIMc/sLHgyukuvkqsJan4Lwv6JL8VHZ3B58cSWT2BPptTlb4DcWWVOyArUuaXd5+L5VBQC8nhmnU7QZ8H+w==}
+  eslint-import-resolver-ts-bundled@6.2.0:
+    resolution: {integrity: sha512-7CveTfwrl38xc0k6I4aU0ZIPRZIoRNUkl10rN9v4Yc7d4tHZQ9bgjkHQWBQ6nfWsl0qBD+zbSY1AA8Qxc3/vuA==}
 
   eslint-plugin-autofix@2.1.0:
     resolution: {integrity: sha512-4ya5flaJ7P+s4WeCe7mVd5Mmv0ayghl9Xz1MDewQqDNXn3SFkvTMqbCuJT5fsTl+BdtJ/CFNV48YrABohQu1VQ==}
@@ -818,11 +822,17 @@ packages:
     peerDependencies:
       eslint: ^7.0.0 || ^8.0.0 || ^9.0.0
 
-  eslint-plugin-sukka-ts@6.1.11:
-    resolution: {integrity: sha512-BgIafrtdpV1YDj4d1UTy9MCa5r9Moc67d99FaGejc/61G0oBteGJYZTFlJ69ZRAsrVEKf40ukNg3RQOyhujGrw==}
+  eslint-plugin-regexp@2.6.0:
+    resolution: {integrity: sha512-FCL851+kislsTEQEMioAlpDuK5+E5vs0hi1bF8cFlPlHcEjeRhuAzEsGikXRreE+0j4WhW2uO54MqTjXtYOi3A==}
+    engines: {node: ^18 || >=20}
+    peerDependencies:
+      eslint: '>=8.44.0'
+
+  eslint-plugin-sukka-ts@6.2.0:
+    resolution: {integrity: sha512-7VJPbzsK4UXb2KIAYt7o8ak7UyaV5bmkFQVUsb8OC+7TkXQ6ww1vdYeNEmno5iAOI6H5lwU25gvPiEbV1LR9sQ==}
 
-  eslint-plugin-sukka@6.1.11:
-    resolution: {integrity: sha512-aJ/3koRiZutfiU0otVZrc0zhVBkz7UkBv6zfTCuRnasyIKVUFsmHgHztoH1YZEGLAZbErs6kbNi4oXP3Cw/EUg==}
+  eslint-plugin-sukka@6.2.0:
+    resolution: {integrity: sha512-qQ8Or3rPb2ggYfSw6/pp+WLrKo6yLbToqR99kAeKQ87fhCcifcf2+1hVH3ZPtl75O1QbfU1Xzt3/BqteCd8JKQ==}
 
   eslint-plugin-unused-imports@4.1.3:
     resolution: {integrity: sha512-lqrNZIZjFMUr7P06eoKtQLwyVRibvG7N+LtfKtObYGizAAGrcqLkc3tDx+iAik2z7q0j/XI3ihjupIqxhFabFA==}
@@ -1093,6 +1103,10 @@ packages:
     resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
     hasBin: true
 
+  jsdoc-type-pratt-parser@4.1.0:
+    resolution: {integrity: sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==}
+    engines: {node: '>=12.0.0'}
+
   json-buffer@3.0.1:
     resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
 
@@ -1294,6 +1308,14 @@ packages:
     resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
     engines: {node: '>=8.10.0'}
 
+  refa@0.12.1:
+    resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==}
+    engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+
+  regexp-ast-analysis@0.7.1:
+    resolution: {integrity: sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==}
+    engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+
   require-directory@2.1.1:
     resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
     engines: {node: '>=0.10.0'}
@@ -1327,6 +1349,10 @@ packages:
   safe-buffer@5.2.1:
     resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
 
+  scslre@0.3.0:
+    resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==}
+    engines: {node: ^14.0.0 || >=16.0.0}
+
   semver@7.6.3:
     resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==}
     engines: {node: '>=10'}
@@ -1595,17 +1621,17 @@ snapshots:
 
   '@eslint-community/regexpp@4.11.0': {}
 
-  '@eslint-sukka/node@6.1.11(eslint@9.9.1)(typescript@5.5.4)':
+  '@eslint-sukka/node@6.2.0(eslint@9.9.1)(typescript@5.5.4)':
     dependencies:
-      '@eslint-sukka/shared': 6.1.11(eslint@9.9.1)(typescript@5.5.4)
+      '@eslint-sukka/shared': 6.2.0(eslint@9.9.1)(typescript@5.5.4)
       eslint-plugin-n: 17.10.2(eslint@9.9.1)
-      eslint-plugin-sukka: 6.1.11(eslint@9.9.1)(typescript@5.5.4)
+      eslint-plugin-sukka: 6.2.0(eslint@9.9.1)(typescript@5.5.4)
     transitivePeerDependencies:
       - eslint
       - supports-color
       - typescript
 
-  '@eslint-sukka/shared@6.1.11(eslint@9.9.1)(typescript@5.5.4)':
+  '@eslint-sukka/shared@6.2.0(eslint@9.9.1)(typescript@5.5.4)':
     dependencies:
       '@dual-bundle/import-meta-resolve': 4.1.0
       '@types/eslint': 9.6.0
@@ -2152,6 +2178,8 @@ snapshots:
 
   colorette@2.0.20: {}
 
+  comment-parser@1.4.1: {}
+
   concat-map@0.0.1: {}
 
   cross-spawn@7.0.3:
@@ -2220,10 +2248,10 @@ snapshots:
       eslint: 9.9.1
       semver: 7.6.3
 
-  eslint-config-sukka@6.1.11(@typescript-eslint/eslint-plugin@8.2.0(@typescript-eslint/parser@8.2.0(eslint@9.9.1)(typescript@5.5.4))(eslint@9.9.1)(typescript@5.5.4))(eslint@9.9.1)(typescript@5.5.4):
+  eslint-config-sukka@6.2.0(@typescript-eslint/eslint-plugin@8.2.0(@typescript-eslint/parser@8.2.0(eslint@9.9.1)(typescript@5.5.4))(eslint@9.9.1)(typescript@5.5.4))(eslint@9.9.1)(typescript@5.5.4):
     dependencies:
       '@eslint-community/eslint-plugin-eslint-comments': 4.4.0(eslint@9.9.1)
-      '@eslint-sukka/shared': 6.1.11(eslint@9.9.1)(typescript@5.5.4)
+      '@eslint-sukka/shared': 6.2.0(eslint@9.9.1)(typescript@5.5.4)
       '@eslint/compat': 1.1.1
       '@eslint/js': 9.9.1
       '@stylistic/eslint-plugin-js': 2.6.4(eslint@9.9.1)
@@ -2232,14 +2260,15 @@ snapshots:
       '@typescript-eslint/parser': 8.2.0(eslint@9.9.1)(typescript@5.5.4)
       ci-info: 4.0.0
       defu: 6.1.4
-      eslint-import-resolver-ts-bundled: 6.1.11
+      eslint-import-resolver-ts-bundled: 6.2.0
       eslint-plugin-autofix: 2.1.0(eslint@9.9.1)
       eslint-plugin-deprecation: 3.0.0(eslint@9.9.1)(typescript@5.5.4)
       eslint-plugin-import-x: 3.1.0(eslint@9.9.1)(typescript@5.5.4)
       eslint-plugin-jsonc: 2.16.0(eslint@9.9.1)
       eslint-plugin-promise: 7.1.0(eslint@9.9.1)
-      eslint-plugin-sukka: 6.1.11(eslint@9.9.1)(typescript@5.5.4)
-      eslint-plugin-sukka-ts: 6.1.11(eslint@9.9.1)(typescript@5.5.4)
+      eslint-plugin-regexp: 2.6.0(eslint@9.9.1)
+      eslint-plugin-sukka: 6.2.0(eslint@9.9.1)(typescript@5.5.4)
+      eslint-plugin-sukka-ts: 6.2.0(eslint@9.9.1)(typescript@5.5.4)
       eslint-plugin-unused-imports: 4.1.3(@typescript-eslint/eslint-plugin@8.2.0(@typescript-eslint/parser@8.2.0(eslint@9.9.1)(typescript@5.5.4))(eslint@9.9.1)(typescript@5.5.4))(eslint@9.9.1)
       jsonc-eslint-parser: 2.4.0
       picocolors: 1.0.1
@@ -2250,7 +2279,7 @@ snapshots:
       - supports-color
       - typescript
 
-  eslint-formatter-sukka@6.1.11:
+  eslint-formatter-sukka@6.2.0:
     dependencies:
       ci-info: 4.0.0
       picocolors: 1.0.1
@@ -2263,7 +2292,7 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  eslint-import-resolver-ts-bundled@6.1.11:
+  eslint-import-resolver-ts-bundled@6.2.0:
     dependencies:
       enhanced-resolve: 5.17.1
 
@@ -2337,9 +2366,20 @@ snapshots:
     dependencies:
       eslint: 9.9.1
 
-  eslint-plugin-sukka-ts@6.1.11(eslint@9.9.1)(typescript@5.5.4):
+  eslint-plugin-regexp@2.6.0(eslint@9.9.1):
     dependencies:
-      '@eslint-sukka/shared': 6.1.11(eslint@9.9.1)(typescript@5.5.4)
+      '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.1)
+      '@eslint-community/regexpp': 4.11.0
+      comment-parser: 1.4.1
+      eslint: 9.9.1
+      jsdoc-type-pratt-parser: 4.1.0
+      refa: 0.12.1
+      regexp-ast-analysis: 0.7.1
+      scslre: 0.3.0
+
+  eslint-plugin-sukka-ts@6.2.0(eslint@9.9.1)(typescript@5.5.4):
+    dependencies:
+      '@eslint-sukka/shared': 6.2.0(eslint@9.9.1)(typescript@5.5.4)
       '@typescript-eslint/type-utils': 8.2.0(eslint@9.9.1)(typescript@5.5.4)
       '@typescript-eslint/utils': 8.2.0(eslint@9.9.1)(typescript@5.5.4)
     transitivePeerDependencies:
@@ -2347,9 +2387,9 @@ snapshots:
       - supports-color
       - typescript
 
-  eslint-plugin-sukka@6.1.11(eslint@9.9.1)(typescript@5.5.4):
+  eslint-plugin-sukka@6.2.0(eslint@9.9.1)(typescript@5.5.4):
     dependencies:
-      '@eslint-sukka/shared': 6.1.11(eslint@9.9.1)(typescript@5.5.4)
+      '@eslint-sukka/shared': 6.2.0(eslint@9.9.1)(typescript@5.5.4)
       '@typescript-eslint/utils': 8.2.0(eslint@9.9.1)(typescript@5.5.4)
     transitivePeerDependencies:
       - eslint
@@ -2605,6 +2645,8 @@ snapshots:
     dependencies:
       argparse: 2.0.1
 
+  jsdoc-type-pratt-parser@4.1.0: {}
+
   json-buffer@3.0.1: {}
 
   json-schema-traverse@0.4.1: {}
@@ -2827,6 +2869,15 @@ snapshots:
     dependencies:
       picomatch: 2.3.1
 
+  refa@0.12.1:
+    dependencies:
+      '@eslint-community/regexpp': 4.11.0
+
+  regexp-ast-analysis@0.7.1:
+    dependencies:
+      '@eslint-community/regexpp': 4.11.0
+      refa: 0.12.1
+
   require-directory@2.1.1: {}
 
   require-from-string@2.0.2: {}
@@ -2851,6 +2902,12 @@ snapshots:
 
   safe-buffer@5.2.1: {}
 
+  scslre@0.3.0:
+    dependencies:
+      '@eslint-community/regexpp': 4.11.0
+      refa: 0.12.1
+      regexp-ast-analysis: 0.7.1
+
   semver@7.6.3: {}
 
   serialize-javascript@6.0.2: