tailwind-lint 0.9.3 → 0.10.1
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 +20 -1
- package/dist/cli.cjs +1 -1
- package/dist/{linter-DTFnITa5.cjs → linter-CQy2hg_B.cjs} +44 -5
- package/dist/linter.cjs +1 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/tailwind-lint)  
|
|
4
4
|
|
|
5
5
|
It just lints your Tailwind project as the IDE will do, just on the command line.
|
|
6
|
-
Supports **Tailwind CSS v4** (CSS
|
|
6
|
+
Supports **Tailwind CSS v4** (CSS config files and Vite projects using `@tailwindcss/vite`) and **v3** (JavaScript config, legacy).
|
|
7
7
|
|
|
8
8
|
## Installation
|
|
9
9
|
|
|
@@ -51,6 +51,8 @@ tailwind-lint --verbose
|
|
|
51
51
|
|
|
52
52
|
- Finds CSS config files in common locations: `app.css`, `index.css`, `tailwind.css`, `global.css`, etc.
|
|
53
53
|
- Searches in project root and subdirectories: `./`, `./src/`, `./src/styles/`, `./app/`, etc.
|
|
54
|
+
- Detects `vite.config.*` files that use `@tailwindcss/vite`
|
|
55
|
+
- Prefers real CSS configs when present, so custom `@theme` tokens and `@source` directives are available to diagnostics
|
|
54
56
|
- Uses file patterns from `@source` directives if present
|
|
55
57
|
- Falls back to default pattern: `./**/*.{js,jsx,ts,tsx,html,vue,svelte,astro,mdx}`
|
|
56
58
|
- **Note:** When CSS config is in a subdirectory (e.g., `src/styles/global.css`), files are discovered from the project root
|
|
@@ -85,6 +87,9 @@ tailwind-lint "**/*.vue" --fix
|
|
|
85
87
|
# Lint with a specific CSS config (v4)
|
|
86
88
|
tailwind-lint --config ./styles/app.css
|
|
87
89
|
|
|
90
|
+
# Lint a Vite-based Tailwind v4 project
|
|
91
|
+
tailwind-lint --auto
|
|
92
|
+
|
|
88
93
|
# Machine-readable output for LLMs/agents
|
|
89
94
|
tailwind-lint --auto --format json
|
|
90
95
|
```
|
|
@@ -129,6 +134,19 @@ Create a CSS config file (`app.css`, `index.css`, or `tailwind.css`):
|
|
|
129
134
|
|
|
130
135
|
The CLI auto-detects configs at: `app.css`, `src/app.css`, `index.css`, `src/index.css`, `tailwind.css`, `src/tailwind.css`
|
|
131
136
|
|
|
137
|
+
You can also use a Vite-based Tailwind v4 project with `@tailwindcss/vite` and no standalone Tailwind CSS config file:
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
141
|
+
import { defineConfig } from "vite";
|
|
142
|
+
|
|
143
|
+
export default defineConfig({
|
|
144
|
+
plugins: [tailwindcss()],
|
|
145
|
+
});
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
If a real CSS config is also present, the CLI uses that file so custom `@theme` tokens and `@source` directives are available to diagnostics.
|
|
149
|
+
|
|
132
150
|
### Tailwind CSS v3 (Legacy)
|
|
133
151
|
|
|
134
152
|
Create a JavaScript config file (`tailwind.config.js`):
|
|
@@ -165,6 +183,7 @@ Files are written atomically with multiple iterations to ensure all fixes are ap
|
|
|
165
183
|
- Recommended Variant Order - Suggests preferred ordering of variants
|
|
166
184
|
- Blocklisted Classes - Detects usage of blocklisted classes
|
|
167
185
|
- Autofix - Automatically fix issues with `--fix` flag
|
|
186
|
+
- Quoted class string extraction - Lints class-like strings in common helper patterns, not only direct `class` and `className` attributes
|
|
168
187
|
|
|
169
188
|
**v4-Specific:**
|
|
170
189
|
|
package/dist/cli.cjs
CHANGED
|
@@ -80,8 +80,19 @@ const V4_CSS_FOLDERS = [
|
|
|
80
80
|
"./style/",
|
|
81
81
|
"./styles/",
|
|
82
82
|
"./assets/css/",
|
|
83
|
-
"./resources/css/"
|
|
83
|
+
"./resources/css/",
|
|
84
|
+
"./.ladle/"
|
|
84
85
|
];
|
|
86
|
+
const VITE_CONFIG_PATHS = [
|
|
87
|
+
"vite.config.js",
|
|
88
|
+
"vite.config.mjs",
|
|
89
|
+
"vite.config.cjs",
|
|
90
|
+
"vite.config.ts",
|
|
91
|
+
"vite.config.mts",
|
|
92
|
+
"vite.config.cts"
|
|
93
|
+
];
|
|
94
|
+
const SYNTHETIC_VITE_CSS_CONFIG_NAME = ".tailwind-lint.vite.css";
|
|
95
|
+
const SYNTHETIC_VITE_CSS_CONFIG_CONTENT = "@import \"tailwindcss\";";
|
|
85
96
|
const LANGUAGE_MAP = {
|
|
86
97
|
".astro": "astro",
|
|
87
98
|
".css": "css",
|
|
@@ -109,6 +120,7 @@ const SEVERITY = {
|
|
|
109
120
|
WARNING: 2
|
|
110
121
|
};
|
|
111
122
|
const TAILWIND_V4_IMPORT_REGEX = /@import\s+["']tailwindcss(?:["'\s/]|$)/;
|
|
123
|
+
const TAILWIND_VITE_PLUGIN_REGEX = /(?:from\s+["']@tailwindcss\/vite["']|require\(\s*["']@tailwindcss\/vite["']\s*\)|import\(\s*["']@tailwindcss\/vite["']\s*\))/;
|
|
112
124
|
function getLanguageId(filePath) {
|
|
113
125
|
return LANGUAGE_MAP[filePath.substring(filePath.lastIndexOf(".")).toLowerCase()] || "html";
|
|
114
126
|
}
|
|
@@ -238,7 +250,7 @@ function createEditorState(cwd) {
|
|
|
238
250
|
] },
|
|
239
251
|
experimental: {
|
|
240
252
|
configFile: null,
|
|
241
|
-
classRegex: []
|
|
253
|
+
classRegex: ["[\"'`]([^\"'`]*\\b(?:bg|text|border|font|tracking|rounded|px|py|p|m|flex|grid|items|justify|gap|whitespace|overflow|align|leading|uppercase|lowercase|capitalize|shadow|transition|hover:|focus:)[^\"'`]*)[\"'`]"]
|
|
242
254
|
},
|
|
243
255
|
lint: {
|
|
244
256
|
cssConflict: "warning",
|
|
@@ -395,7 +407,7 @@ async function loadV4DesignSystem(state, cwd, configPath, verbose = false) {
|
|
|
395
407
|
let cssContent;
|
|
396
408
|
const basePath = node_path.dirname(configPath);
|
|
397
409
|
if (fileExists(configPath)) cssContent = readFileSync(configPath);
|
|
398
|
-
else cssContent =
|
|
410
|
+
else cssContent = SYNTHETIC_VITE_CSS_CONFIG_CONTENT;
|
|
399
411
|
const loadDesignSystem = tailwindcss.__unstable__loadDesignSystem;
|
|
400
412
|
const designSystem = await loadDesignSystem(cssContent, {
|
|
401
413
|
base: basePath,
|
|
@@ -465,6 +477,9 @@ async function loadV4DesignSystem(state, cwd, configPath, verbose = false) {
|
|
|
465
477
|
const require$2 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href || __filename);
|
|
466
478
|
const CONFIG_DISCOVERY_MAX_DEPTH = 8;
|
|
467
479
|
const isCssConfigFile = (filePath) => filePath.endsWith(".css");
|
|
480
|
+
function syntheticViteCssConfigPath(viteConfigPath) {
|
|
481
|
+
return node_path.join(node_path.dirname(viteConfigPath), SYNTHETIC_VITE_CSS_CONFIG_NAME);
|
|
482
|
+
}
|
|
468
483
|
async function loadTailwindConfig(configPath) {
|
|
469
484
|
if (isCssConfigFile(configPath)) return {};
|
|
470
485
|
if (!node_path.isAbsolute(configPath)) throw new Error(`Config path must be absolute for security reasons: ${configPath}`);
|
|
@@ -517,8 +532,32 @@ async function findTailwindConfigPath(cwd, configPath) {
|
|
|
517
532
|
if (TAILWIND_V4_IMPORT_REGEX.test(content)) v4Matches.push(candidate);
|
|
518
533
|
} catch {}
|
|
519
534
|
if (v4Matches.length > 0) return sortCssCandidates(cwd, v4Matches)[0];
|
|
535
|
+
const viteConfigPath = await findTailwindViteConfigPath(cwd);
|
|
536
|
+
if (viteConfigPath) return syntheticViteCssConfigPath(viteConfigPath);
|
|
520
537
|
return null;
|
|
521
538
|
}
|
|
539
|
+
async function findTailwindViteConfigPath(cwd) {
|
|
540
|
+
for (const p of VITE_CONFIG_PATHS) {
|
|
541
|
+
const fullPath = node_path.join(cwd, p);
|
|
542
|
+
if (isTailwindViteConfig(fullPath)) return fullPath;
|
|
543
|
+
}
|
|
544
|
+
const matches = (await (0, tinyglobby.glob)(VITE_CONFIG_PATHS.map((p) => `**/${p}`), {
|
|
545
|
+
cwd,
|
|
546
|
+
absolute: true,
|
|
547
|
+
ignore: DEFAULT_IGNORE_PATTERNS,
|
|
548
|
+
deep: CONFIG_DISCOVERY_MAX_DEPTH
|
|
549
|
+
})).filter(isTailwindViteConfig);
|
|
550
|
+
if (matches.length === 0) return null;
|
|
551
|
+
return sortByPathDepth(matches)[0];
|
|
552
|
+
}
|
|
553
|
+
function isTailwindViteConfig(filePath) {
|
|
554
|
+
if (!fileExists(filePath)) return false;
|
|
555
|
+
try {
|
|
556
|
+
return TAILWIND_VITE_PLUGIN_REGEX.test(readFileSync(filePath));
|
|
557
|
+
} catch {
|
|
558
|
+
return false;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
522
561
|
function sortByPathDepth(paths) {
|
|
523
562
|
return [...paths].sort((a, b) => {
|
|
524
563
|
const depthA = splitDepth(a);
|
|
@@ -576,7 +615,7 @@ function resolveTailwindPath(cwd, configDir) {
|
|
|
576
615
|
}
|
|
577
616
|
async function createState(cwd, configPath, verbose = false) {
|
|
578
617
|
const resolvedConfigPath = await findTailwindConfigPath(cwd, configPath);
|
|
579
|
-
if (!resolvedConfigPath) throw new Error("Could not find Tailwind config file. Expected one of:\n • Tailwind v4 (CSS): app.css, index.css, tailwind.css in project root or src/\n • Tailwind v3 (JS): tailwind.config.js, tailwind.config.ts\nRun 'npx tailwindcss init' to create a config file.");
|
|
618
|
+
if (!resolvedConfigPath) throw new Error("Could not find Tailwind config file. Expected one of:\n • Tailwind v4 (CSS): app.css, index.css, tailwind.css in project root or src/\n • Tailwind v4 (Vite): vite.config.* with @tailwindcss/vite\n • Tailwind v3 (JS): tailwind.config.js, tailwind.config.ts\nRun 'npx tailwindcss init' to create a config file.");
|
|
580
619
|
const isCssConfig = isCssConfigFile(resolvedConfigPath);
|
|
581
620
|
const tailwindcss = require$1(resolveTailwindPath(cwd, node_path.dirname(resolvedConfigPath)));
|
|
582
621
|
const version = getTailwindVersion(cwd);
|
|
@@ -660,7 +699,7 @@ async function discoverFilesFromConfig(cwd, configPath) {
|
|
|
660
699
|
return expandPatterns(cwd, patterns);
|
|
661
700
|
}
|
|
662
701
|
const configDir = node_path.dirname(configFilePath);
|
|
663
|
-
const cssContent = readFileSync(configFilePath);
|
|
702
|
+
const cssContent = fileExists(configFilePath) ? readFileSync(configFilePath) : SYNTHETIC_VITE_CSS_CONFIG_CONTENT;
|
|
664
703
|
const { include, exclude } = extractSourcePatterns(cssContent);
|
|
665
704
|
const importSource = extractImportSourceDirectives(cssContent);
|
|
666
705
|
const resolveFromConfig = (pattern) => {
|
package/dist/linter.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_linter = require("./linter-
|
|
2
|
+
const require_linter = require("./linter-CQy2hg_B.cjs");
|
|
3
3
|
exports.extractImportSourceDirectives = require_linter.extractImportSourceDirectives;
|
|
4
4
|
exports.extractSourcePatterns = require_linter.extractSourcePatterns;
|
|
5
5
|
exports.lint = require_linter.lint;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tailwind-lint",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "A command-line tool that uses the Tailwind CSS IntelliSense plugin to show linting suggestions for your Tailwind CSS classes",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -61,21 +61,21 @@
|
|
|
61
61
|
"@tailwindcss/language-service": "^0.14.29",
|
|
62
62
|
"ansis": "^4.2.0",
|
|
63
63
|
"commander": "^14.0.3",
|
|
64
|
-
"postcss": "^8.5.
|
|
64
|
+
"postcss": "^8.5.10",
|
|
65
65
|
"tinyglobby": "^0.2.16",
|
|
66
66
|
"vscode-languageserver-textdocument": "^1.0.12"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@types/node": "^25.6.0",
|
|
70
|
-
"oxfmt": "^0.
|
|
71
|
-
"oxlint": "^1.
|
|
72
|
-
"tsdown": "^0.21.
|
|
73
|
-
"typescript": "^6.0.
|
|
74
|
-
"vitest": "^4.1.
|
|
70
|
+
"oxfmt": "^0.46.0",
|
|
71
|
+
"oxlint": "^1.61.0",
|
|
72
|
+
"tsdown": "^0.21.10",
|
|
73
|
+
"typescript": "^6.0.3",
|
|
74
|
+
"vitest": "^4.1.5"
|
|
75
75
|
},
|
|
76
76
|
"engines": {
|
|
77
77
|
"node": ">=22.0.0",
|
|
78
78
|
"pnpm": ">=10.0.0"
|
|
79
79
|
},
|
|
80
|
-
"packageManager": "pnpm@10.33.
|
|
80
|
+
"packageManager": "pnpm@10.33.2"
|
|
81
81
|
}
|