@infernodesign/eslint-config 2.4.1 → 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.
- package/README.md +4 -1
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.js +160 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -611,8 +611,11 @@ export default config( {
|
|
|
611
611
|
tailwindcss: {
|
|
612
612
|
// Enable component class detection
|
|
613
613
|
detectComponentClasses: true,
|
|
614
|
+
// Resolve Tailwind CSS files from a nested app when linting from a monorepo root
|
|
615
|
+
cwd: 'apps/web',
|
|
614
616
|
// Specify the entry point for Tailwind CSS
|
|
615
|
-
// If not provided, the config will try to find
|
|
617
|
+
// If not provided, the config will try to find a common Tailwind CSS entry point in the project
|
|
618
|
+
// like `global.css`, `globals.css`, `app.css`, `index.css`, or `style.css`.
|
|
616
619
|
entryPoint: 'src/styles/globals.css',
|
|
617
620
|
},
|
|
618
621
|
} )
|
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import { cac } from "cac";
|
|
|
8
8
|
import parse from "parse-gitignore";
|
|
9
9
|
import { execSync } from "node:child_process";
|
|
10
10
|
//#region package.json
|
|
11
|
-
var version = "2.
|
|
11
|
+
var version = "2.5.0";
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region src/cli/constants.ts
|
|
14
14
|
const vscodeSettingsString = `
|
package/dist/index.d.ts
CHANGED
|
@@ -19395,10 +19395,28 @@ interface OptionsTailwindcss {
|
|
|
19395
19395
|
* @default false
|
|
19396
19396
|
*/
|
|
19397
19397
|
detectComponentClasses?: boolean;
|
|
19398
|
+
/**
|
|
19399
|
+
* Working directory for resolving Tailwind CSS entry points.
|
|
19400
|
+
*
|
|
19401
|
+
* Use this when linting from a monorepo root while the Tailwind CSS setup lives in a nested app.
|
|
19402
|
+
*
|
|
19403
|
+
* @example
|
|
19404
|
+
* ```ts
|
|
19405
|
+
* tailwindcss: {
|
|
19406
|
+
* cwd: 'apps/web',
|
|
19407
|
+
* },
|
|
19408
|
+
* ```
|
|
19409
|
+
*
|
|
19410
|
+
* @see https://github.com/schoero/eslint-plugin-better-tailwindcss/blob/main/docs/settings/settings.md
|
|
19411
|
+
*
|
|
19412
|
+
* @default process.cwd()
|
|
19413
|
+
*/
|
|
19414
|
+
cwd?: string;
|
|
19398
19415
|
/**
|
|
19399
19416
|
* Entry point for Tailwind CSS.
|
|
19400
19417
|
*
|
|
19401
|
-
* If not provided, the config will try to find
|
|
19418
|
+
* If not provided, the config will try to find a common Tailwind CSS entry point in the project
|
|
19419
|
+
* like `global.css`, `globals.css`, `app.css`, `index.css`, or `style.css`.
|
|
19402
19420
|
*
|
|
19403
19421
|
* @example
|
|
19404
19422
|
* ```ts
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { FlatConfigComposer } from "eslint-flat-config-utils";
|
|
|
3
3
|
import process$1 from "node:process";
|
|
4
4
|
import fs from "node:fs/promises";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import fs$1, { existsSync, readdirSync, statSync } from "node:fs";
|
|
6
|
+
import fs$1, { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import { isPackageExists } from "local-pkg";
|
|
9
9
|
import createCommand from "eslint-plugin-command/config";
|
|
@@ -105,6 +105,9 @@ const GLOB_EXCLUDE = [
|
|
|
105
105
|
"**/.agents",
|
|
106
106
|
"**/.antigravity",
|
|
107
107
|
"**/.bmad",
|
|
108
|
+
"**/.bmad-*",
|
|
109
|
+
"**/_bmad",
|
|
110
|
+
"**/_bmad-*",
|
|
108
111
|
"**/.context",
|
|
109
112
|
"**/.codex",
|
|
110
113
|
"**/.claude",
|
|
@@ -112,10 +115,12 @@ const GLOB_EXCLUDE = [
|
|
|
112
115
|
"**/.windsurf",
|
|
113
116
|
"**/.*/skills",
|
|
114
117
|
"**/AGENTS.md",
|
|
118
|
+
"**/CLAUDE.md",
|
|
115
119
|
"**/.idea",
|
|
116
120
|
"**/.vscode",
|
|
117
121
|
"**/.zed",
|
|
118
122
|
"**/__snapshots__",
|
|
123
|
+
"**/badges",
|
|
119
124
|
"**/coverage",
|
|
120
125
|
"**/.cache",
|
|
121
126
|
"**/.eslintcache",
|
|
@@ -157,10 +162,14 @@ const GLOB_EXCLUDE = [
|
|
|
157
162
|
];
|
|
158
163
|
const GLOB_SEARCH_EXCLUDE = new Set([
|
|
159
164
|
"__snapshots__",
|
|
165
|
+
"_bmad",
|
|
166
|
+
"_bmad-*",
|
|
160
167
|
".bmad",
|
|
168
|
+
".bmad-*",
|
|
161
169
|
".cache",
|
|
162
170
|
".changeset",
|
|
163
171
|
".claude",
|
|
172
|
+
".codex",
|
|
164
173
|
".cursor",
|
|
165
174
|
".eslintcache",
|
|
166
175
|
".git",
|
|
@@ -2287,25 +2296,60 @@ async function svelte(options = {}) {
|
|
|
2287
2296
|
const defaultEntryPointCandidates = [
|
|
2288
2297
|
"src/styles/global.css",
|
|
2289
2298
|
"src/styles/globals.css",
|
|
2299
|
+
"src/styles/app.css",
|
|
2300
|
+
"src/styles/index.css",
|
|
2301
|
+
"src/styles/style.css",
|
|
2302
|
+
"src/app/styles/global.css",
|
|
2303
|
+
"src/app/styles/globals.css",
|
|
2304
|
+
"src/app/styles/app.css",
|
|
2305
|
+
"src/app/styles/index.css",
|
|
2306
|
+
"src/app/styles/style.css",
|
|
2290
2307
|
"src/app/global.css",
|
|
2291
2308
|
"src/app/globals.css",
|
|
2292
|
-
"src/
|
|
2293
|
-
"
|
|
2309
|
+
"src/app/app.css",
|
|
2310
|
+
"app/styles/global.css",
|
|
2311
|
+
"app/styles/globals.css",
|
|
2312
|
+
"app/styles/app.css",
|
|
2313
|
+
"app/styles/index.css",
|
|
2314
|
+
"app/styles/style.css",
|
|
2294
2315
|
"app/global.css",
|
|
2295
2316
|
"app/globals.css",
|
|
2317
|
+
"app/app.css",
|
|
2318
|
+
"src/global.css",
|
|
2319
|
+
"src/globals.css",
|
|
2320
|
+
"src/app.css",
|
|
2321
|
+
"src/index.css",
|
|
2322
|
+
"src/style.css",
|
|
2296
2323
|
"styles/global.css",
|
|
2297
2324
|
"styles/globals.css",
|
|
2325
|
+
"styles/app.css",
|
|
2326
|
+
"styles/index.css",
|
|
2327
|
+
"styles/style.css",
|
|
2298
2328
|
"global.css",
|
|
2299
|
-
"globals.css"
|
|
2329
|
+
"globals.css",
|
|
2330
|
+
"app.css",
|
|
2331
|
+
"index.css",
|
|
2332
|
+
"style.css"
|
|
2300
2333
|
];
|
|
2334
|
+
const entryPointCandidateFileNames = new Set([
|
|
2335
|
+
"app.css",
|
|
2336
|
+
"global.css",
|
|
2337
|
+
"globals.css",
|
|
2338
|
+
"index.css",
|
|
2339
|
+
"style.css"
|
|
2340
|
+
]);
|
|
2341
|
+
const tailwindEntryPointPattern = /@import\s+["']tailwindcss(?:\/[^"']+)?["']|@tailwind\s+(?:base|components|utilities|variants)|@theme\b|@utility\b|@custom-variant\b/;
|
|
2342
|
+
const tailwindEntryPointCache = /* @__PURE__ */ new Map();
|
|
2343
|
+
const warnings = /* @__PURE__ */ new Set();
|
|
2301
2344
|
async function tailwindcss(options = {}) {
|
|
2302
2345
|
const { files = [GLOB_SRC], overrides = {} } = options;
|
|
2303
2346
|
if (!isPackageExists("tailwindcss")) return [];
|
|
2304
2347
|
await ensurePackages(["eslint-plugin-better-tailwindcss"]);
|
|
2305
2348
|
const tsconfigPath = options?.tsconfigPath !== void 0 ? toArray(options.tsconfigPath) : void 0;
|
|
2306
|
-
const
|
|
2349
|
+
const cwd = resolveCwd(options.cwd);
|
|
2350
|
+
const resolvedTsconfigPath = tsconfigPath?.[0] ? path.resolve(cwd, tsconfigPath[0]) : void 0;
|
|
2307
2351
|
const isTypeAware = !!resolvedTsconfigPath;
|
|
2308
|
-
const resolvedEntryPointPath = resolveTailwindEntryPoint(options.entryPoint);
|
|
2352
|
+
const resolvedEntryPointPath = resolveTailwindEntryPoint(options.entryPoint, cwd);
|
|
2309
2353
|
const isUsingEntryPoint = !!resolvedEntryPointPath;
|
|
2310
2354
|
const [pluginTailwindCSS, parserTs] = await Promise.all([interopDefault(import("eslint-plugin-better-tailwindcss")), interopDefault(import("@typescript-eslint/parser"))]);
|
|
2311
2355
|
return [{
|
|
@@ -2316,7 +2360,7 @@ async function tailwindcss(options = {}) {
|
|
|
2316
2360
|
...isTypeAware ? {
|
|
2317
2361
|
jsxPragma: null,
|
|
2318
2362
|
project: tsconfigPath,
|
|
2319
|
-
tsconfigRootDir:
|
|
2363
|
+
tsconfigRootDir: cwd
|
|
2320
2364
|
} : {}
|
|
2321
2365
|
}
|
|
2322
2366
|
},
|
|
@@ -2324,6 +2368,7 @@ async function tailwindcss(options = {}) {
|
|
|
2324
2368
|
plugins: { "tailwindcss": pluginTailwindCSS },
|
|
2325
2369
|
settings: { tailwindcss: {
|
|
2326
2370
|
...isUsingEntryPoint ? { entryPoint: resolvedEntryPointPath } : {},
|
|
2371
|
+
...options.cwd ? { cwd } : {},
|
|
2327
2372
|
detectComponentClasses: options.detectComponentClasses ?? false,
|
|
2328
2373
|
...isTypeAware ? { tsconfig: resolvedTsconfigPath } : {}
|
|
2329
2374
|
} }
|
|
@@ -2368,15 +2413,15 @@ function findExistingFile(filePath) {
|
|
|
2368
2413
|
* @param {string} relativePath - The relative path to the file to find.
|
|
2369
2414
|
* @returns {string | undefined} The path to the existing file, or undefined if the file does not exist.
|
|
2370
2415
|
*/
|
|
2371
|
-
function findFileRecursiveFromCwd(relativePath) {
|
|
2372
|
-
let resolvedPath = path.resolve(
|
|
2416
|
+
function findFileRecursiveFromCwd(relativePath, cwd) {
|
|
2417
|
+
let resolvedPath = path.resolve(cwd, relativePath);
|
|
2373
2418
|
while (true) {
|
|
2374
2419
|
const foundFile = findExistingFile(resolvedPath);
|
|
2375
2420
|
if (foundFile) return foundFile;
|
|
2376
2421
|
const fileName = path.basename(resolvedPath);
|
|
2377
2422
|
const directory = path.dirname(resolvedPath);
|
|
2378
2423
|
const parentDirectory = path.resolve(directory, "..");
|
|
2379
|
-
if (parentDirectory === directory || directory ===
|
|
2424
|
+
if (parentDirectory === directory || directory === cwd) return;
|
|
2380
2425
|
resolvedPath = path.resolve(parentDirectory, fileName);
|
|
2381
2426
|
}
|
|
2382
2427
|
}
|
|
@@ -2385,12 +2430,17 @@ function findFileRecursiveFromCwd(relativePath) {
|
|
|
2385
2430
|
*
|
|
2386
2431
|
* @returns {string | undefined} The path to the global CSS entry point, or undefined if no entry point is found.
|
|
2387
2432
|
*/
|
|
2388
|
-
function findGlobalCssEntryPoint() {
|
|
2433
|
+
function findGlobalCssEntryPoint(cwd) {
|
|
2434
|
+
const explicitCandidates = [];
|
|
2389
2435
|
for (const candidate of defaultEntryPointCandidates) {
|
|
2390
|
-
const found = findExistingFile(path.resolve(
|
|
2391
|
-
if (found)
|
|
2436
|
+
const found = findExistingFile(path.resolve(cwd, candidate));
|
|
2437
|
+
if (found) explicitCandidates.push(found);
|
|
2438
|
+
}
|
|
2439
|
+
if (explicitCandidates.length) {
|
|
2440
|
+
const resolvedEntryPoint = resolveBestEntryPointCandidate(explicitCandidates);
|
|
2441
|
+
if (resolvedEntryPoint) return resolvedEntryPoint;
|
|
2392
2442
|
}
|
|
2393
|
-
const queue = [
|
|
2443
|
+
const queue = [cwd];
|
|
2394
2444
|
const candidates = [];
|
|
2395
2445
|
while (queue.length) {
|
|
2396
2446
|
const currentPath = queue.shift();
|
|
@@ -2408,18 +2458,57 @@ function findGlobalCssEntryPoint() {
|
|
|
2408
2458
|
queue.push(nextPath);
|
|
2409
2459
|
continue;
|
|
2410
2460
|
}
|
|
2411
|
-
if (entry.isFile() && (entry.name
|
|
2461
|
+
if (entry.isFile() && entryPointCandidateFileNames.has(entry.name)) candidates.push(nextPath);
|
|
2412
2462
|
}
|
|
2413
2463
|
}
|
|
2414
2464
|
if (!candidates.length) {
|
|
2415
|
-
|
|
2465
|
+
warnOnce(`[${PACKAGE_NAME}] No global CSS entry point found in "${cwd}".`);
|
|
2416
2466
|
return;
|
|
2417
2467
|
}
|
|
2418
|
-
const resolvedEntryPoint = candidates
|
|
2468
|
+
const resolvedEntryPoint = resolveBestEntryPointCandidate(candidates);
|
|
2469
|
+
if (!resolvedEntryPoint) return;
|
|
2419
2470
|
console.log(`[${PACKAGE_NAME}] Resolved global CSS entryPoint: "${resolvedEntryPoint}".`);
|
|
2420
2471
|
return resolvedEntryPoint;
|
|
2421
2472
|
}
|
|
2422
2473
|
/**
|
|
2474
|
+
* Resolve the best entry point candidate from a list of file paths.
|
|
2475
|
+
*
|
|
2476
|
+
* @param {string[]} candidates - The entry point candidate paths.
|
|
2477
|
+
* @returns {string | undefined} The best entry point candidate, or undefined if no candidate exists.
|
|
2478
|
+
*/
|
|
2479
|
+
function resolveBestEntryPointCandidate(candidates) {
|
|
2480
|
+
return candidates.sort(compareEntryPointPaths)[0];
|
|
2481
|
+
}
|
|
2482
|
+
/**
|
|
2483
|
+
* Compare two entry point paths.
|
|
2484
|
+
*
|
|
2485
|
+
* @param {string} a - The first entry point path.
|
|
2486
|
+
* @param {string} b - The second entry point path.
|
|
2487
|
+
* @returns {number} The comparison result.
|
|
2488
|
+
*/
|
|
2489
|
+
function compareEntryPointPaths(a, b) {
|
|
2490
|
+
return Number(hasTailwindEntryPointDirective(b)) - Number(hasTailwindEntryPointDirective(a)) || rankEntryPointPath(a) - rankEntryPointPath(b) || a.length - b.length || a.localeCompare(b);
|
|
2491
|
+
}
|
|
2492
|
+
/**
|
|
2493
|
+
* Check whether a CSS file appears to be a Tailwind entry point.
|
|
2494
|
+
*
|
|
2495
|
+
* @param {string} filePath - The path to the CSS file.
|
|
2496
|
+
* @returns {boolean} Whether the CSS file contains Tailwind entry point directives.
|
|
2497
|
+
*/
|
|
2498
|
+
function hasTailwindEntryPointDirective(filePath) {
|
|
2499
|
+
const cachedResult = tailwindEntryPointCache.get(filePath);
|
|
2500
|
+
if (cachedResult !== void 0) return cachedResult;
|
|
2501
|
+
try {
|
|
2502
|
+
const fileContents = readFileSync(filePath, "utf8");
|
|
2503
|
+
const hasTailwindDirective = tailwindEntryPointPattern.test(fileContents);
|
|
2504
|
+
tailwindEntryPointCache.set(filePath, hasTailwindDirective);
|
|
2505
|
+
return hasTailwindDirective;
|
|
2506
|
+
} catch {
|
|
2507
|
+
tailwindEntryPointCache.set(filePath, false);
|
|
2508
|
+
return false;
|
|
2509
|
+
}
|
|
2510
|
+
}
|
|
2511
|
+
/**
|
|
2423
2512
|
* Rank the entry point path.
|
|
2424
2513
|
*
|
|
2425
2514
|
* @param {string} filePath - The path to the entry point.
|
|
@@ -2427,11 +2516,37 @@ function findGlobalCssEntryPoint() {
|
|
|
2427
2516
|
*/
|
|
2428
2517
|
function rankEntryPointPath(filePath) {
|
|
2429
2518
|
const normalizedPath = filePath.split(path.sep).join("/");
|
|
2430
|
-
if (normalizedPath.includes("/src/styles/")) return 0;
|
|
2431
|
-
if (normalizedPath.includes("/src/")) return 1;
|
|
2432
|
-
if (normalizedPath.includes("/app/")) return 2;
|
|
2433
|
-
if (normalizedPath.
|
|
2434
|
-
if (normalizedPath.
|
|
2519
|
+
if (normalizedPath.includes("/src/styles/")) return getEntryPointRank(0, normalizedPath);
|
|
2520
|
+
if (normalizedPath.includes("/src/app/styles/")) return getEntryPointRank(1, normalizedPath);
|
|
2521
|
+
if (normalizedPath.includes("/src/app/")) return getEntryPointRank(2, normalizedPath);
|
|
2522
|
+
if (normalizedPath.includes("/app/styles/")) return getEntryPointRank(3, normalizedPath);
|
|
2523
|
+
if (normalizedPath.includes("/app/")) return getEntryPointRank(4, normalizedPath);
|
|
2524
|
+
if (normalizedPath.includes("/src/")) return getEntryPointRank(5, normalizedPath);
|
|
2525
|
+
if (normalizedPath.includes("/styles/")) return getEntryPointRank(6, normalizedPath);
|
|
2526
|
+
return getEntryPointRank(7, normalizedPath);
|
|
2527
|
+
}
|
|
2528
|
+
/**
|
|
2529
|
+
* Get the entry point rank from its directory and file name.
|
|
2530
|
+
*
|
|
2531
|
+
* @param {number} directoryRank - The rank of the entry point directory.
|
|
2532
|
+
* @param {string} normalizedPath - The normalized entry point path.
|
|
2533
|
+
* @returns {number} The entry point rank.
|
|
2534
|
+
*/
|
|
2535
|
+
function getEntryPointRank(directoryRank, normalizedPath) {
|
|
2536
|
+
return directoryRank * 10 + getEntryPointFileNameRank(normalizedPath);
|
|
2537
|
+
}
|
|
2538
|
+
/**
|
|
2539
|
+
* Get the entry point file name rank.
|
|
2540
|
+
*
|
|
2541
|
+
* @param {string} normalizedPath - The normalized entry point path.
|
|
2542
|
+
* @returns {number} The entry point file name rank.
|
|
2543
|
+
*/
|
|
2544
|
+
function getEntryPointFileNameRank(normalizedPath) {
|
|
2545
|
+
if (normalizedPath.endsWith("/global.css")) return 0;
|
|
2546
|
+
if (normalizedPath.endsWith("/globals.css")) return 1;
|
|
2547
|
+
if (normalizedPath.endsWith("/app.css")) return 2;
|
|
2548
|
+
if (normalizedPath.endsWith("/index.css")) return 3;
|
|
2549
|
+
if (normalizedPath.endsWith("/style.css")) return 4;
|
|
2435
2550
|
return 5;
|
|
2436
2551
|
}
|
|
2437
2552
|
/**
|
|
@@ -2440,16 +2555,35 @@ function rankEntryPointPath(filePath) {
|
|
|
2440
2555
|
* @param {string} entryPoint - The entry point to resolve.
|
|
2441
2556
|
* @returns {string | undefined} The path to the resolved entry point, or undefined if no entry point is found.
|
|
2442
2557
|
*/
|
|
2443
|
-
function resolveTailwindEntryPoint(entryPoint) {
|
|
2558
|
+
function resolveTailwindEntryPoint(entryPoint, cwd) {
|
|
2444
2559
|
if (entryPoint) {
|
|
2445
|
-
const resolvedEntryPoint = findFileRecursiveFromCwd(entryPoint);
|
|
2560
|
+
const resolvedEntryPoint = findFileRecursiveFromCwd(entryPoint, cwd);
|
|
2446
2561
|
if (resolvedEntryPoint) {
|
|
2447
2562
|
console.log(`[${PACKAGE_NAME}] Resolved Tailwind CSS entryPoint: "${resolvedEntryPoint}".`);
|
|
2448
2563
|
return resolvedEntryPoint;
|
|
2449
2564
|
}
|
|
2450
|
-
|
|
2565
|
+
warnOnce(`[${PACKAGE_NAME}] Tailwind CSS entryPoint "${entryPoint}" was not found from "${cwd}".`);
|
|
2451
2566
|
}
|
|
2452
|
-
return findGlobalCssEntryPoint();
|
|
2567
|
+
return findGlobalCssEntryPoint(cwd);
|
|
2568
|
+
}
|
|
2569
|
+
/**
|
|
2570
|
+
* Resolve the Tailwind CSS working directory.
|
|
2571
|
+
*
|
|
2572
|
+
* @param {string} cwd - The configured working directory.
|
|
2573
|
+
* @returns {string} The resolved working directory.
|
|
2574
|
+
*/
|
|
2575
|
+
function resolveCwd(cwd) {
|
|
2576
|
+
return cwd ? path.resolve(process.cwd(), cwd) : process.cwd();
|
|
2577
|
+
}
|
|
2578
|
+
/**
|
|
2579
|
+
* Warn only once per process for repeated Tailwind CSS resolution failures.
|
|
2580
|
+
*
|
|
2581
|
+
* @param {string} message - The warning message.
|
|
2582
|
+
*/
|
|
2583
|
+
function warnOnce(message) {
|
|
2584
|
+
if (warnings.has(message)) return;
|
|
2585
|
+
warnings.add(message);
|
|
2586
|
+
console.warn(message);
|
|
2453
2587
|
}
|
|
2454
2588
|
//#endregion
|
|
2455
2589
|
//#region src/configs/test.ts
|
package/package.json
CHANGED