tailwind-lint 0.7.0 → 0.8.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 CHANGED
@@ -65,6 +65,7 @@ tailwind-lint --verbose
65
65
  - `-c, --config <path>` - Path to Tailwind config file (default: auto-discover)
66
66
  - `-a, --auto` - Auto-discover files from config content patterns (legacy, enabled by default)
67
67
  - `--fix` - Automatically fix problems that can be fixed
68
+ - `--format <text|json>` - Output format (`text` default, `json` for machine-readable output)
68
69
  - `-v, --verbose` - Enable verbose logging for debugging
69
70
  - `-h, --help` - Show help message
70
71
  - `--version` - Show version number
@@ -83,8 +84,33 @@ tailwind-lint "**/*.vue" --fix
83
84
 
84
85
  # Lint with a specific CSS config (v4)
85
86
  tailwind-lint --config ./styles/app.css
87
+
88
+ # Machine-readable output for LLMs/agents
89
+ tailwind-lint --auto --format json
86
90
  ```
87
91
 
92
+ ## LLM / Agent Integration
93
+
94
+ Use JSON output to avoid brittle text parsing:
95
+
96
+ ```bash
97
+ tailwind-lint --auto --format json
98
+ ```
99
+
100
+ The JSON payload includes:
101
+
102
+ - `ok` - `true` when no errors are found
103
+ - `summary` - counts for `errors`, `warnings`, `fixed`, `filesWithIssues`, `totalFilesProcessed`
104
+ - `config` - resolved runtime values (`cwd`, `configPath`, `autoDiscover`, `fix`, `patterns`)
105
+ - `files[]` - per-file diagnostics with 1-based `line`/`column` ranges
106
+
107
+ Typical agent flow:
108
+
109
+ 1. Run `tailwind-lint --auto --format json`.
110
+ 2. If `summary.errors > 0`, fail the check and surface diagnostics.
111
+ 3. If only warnings exist, optionally continue and open a cleanup task.
112
+ 4. Re-run with `--fix` when autofix is allowed.
113
+
88
114
  ## Configuration
89
115
 
90
116
  ### Tailwind CSS v4
@@ -172,4 +198,25 @@ pnpm format
172
198
 
173
199
  # Check code without fixing
174
200
  pnpm lint
201
+
202
+ # Preview next version locally (no publish)
203
+ pnpm release:dry
175
204
  ```
205
+
206
+ ## Releases
207
+
208
+ Releases are automated with Semantic Release on pushes to `main`.
209
+
210
+ - Version bump is derived from Conventional Commits.
211
+ - npm release and GitHub release are generated automatically.
212
+ - npm publish uses npm Trusted Publishing (OIDC), no `NPM_TOKEN` required.
213
+
214
+ Commit examples:
215
+
216
+ - `feat: add json output mode` -> minor release
217
+ - `fix: resolve v4 config discovery in monorepos` -> patch release
218
+ - `feat: drop Node 20 support` + commit body `BREAKING CHANGE: Node 20 is no longer supported` -> major release
219
+ - `perf: speed up config discovery` -> patch release
220
+ - `docs: update readme` -> no release
221
+
222
+ `pnpm release:dry` runs against the local repo metadata (`--repository-url .`) so it does not require GitHub remote access.
package/dist/cli.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const require_state = require('./state-BHl8x2Q1.cjs');
2
+ const require_state = require('./state-QQi4_-5a.cjs');
3
3
  const require_linter = require('./linter.cjs');
4
4
  let node_path = require("node:path");
5
5
  node_path = require_state.__toESM(node_path);
@@ -9,9 +9,8 @@ let node_fs = require("node:fs");
9
9
  node_fs = require_state.__toESM(node_fs);
10
10
  let commander = require("commander");
11
11
 
12
- //#region src/cli.ts
13
- const MAX_FILENAME_DISPLAY_LENGTH = 50;
14
- function countDiagnosticsBySeverity(diagnostics) {
12
+ //#region src/output.ts
13
+ function countBySeverity(diagnostics) {
15
14
  let errors = 0;
16
15
  let warnings = 0;
17
16
  for (const diagnostic of diagnostics) {
@@ -23,6 +22,64 @@ function countDiagnosticsBySeverity(diagnostics) {
23
22
  warnings
24
23
  };
25
24
  }
25
+ function toJsonSeverity(severity) {
26
+ if (severity === require_state.SEVERITY.ERROR) return "error";
27
+ if (severity === require_state.SEVERITY.WARNING) return "warning";
28
+ return "info";
29
+ }
30
+ function toJsonDiagnostic(diagnostic) {
31
+ return {
32
+ line: diagnostic.range.start.line + 1,
33
+ column: diagnostic.range.start.character + 1,
34
+ endLine: diagnostic.range.end.line + 1,
35
+ endColumn: diagnostic.range.end.character + 1,
36
+ severity: toJsonSeverity(diagnostic.severity),
37
+ code: diagnostic.code ?? null,
38
+ message: diagnostic.message,
39
+ source: diagnostic.source
40
+ };
41
+ }
42
+ function createJsonOutput({ files, totalFilesProcessed, cwd, configPath, autoDiscover, fix, patterns }) {
43
+ let errors = 0;
44
+ let warnings = 0;
45
+ let fixed = 0;
46
+ let filesWithIssues = 0;
47
+ const mappedFiles = files.map((file) => {
48
+ const severityCount = countBySeverity(file.diagnostics);
49
+ errors += severityCount.errors;
50
+ warnings += severityCount.warnings;
51
+ fixed += file.fixedCount || 0;
52
+ if (file.diagnostics.length > 0) filesWithIssues++;
53
+ return {
54
+ path: file.path,
55
+ fixed: file.fixed || false,
56
+ fixedCount: file.fixedCount || 0,
57
+ diagnostics: file.diagnostics.map(toJsonDiagnostic)
58
+ };
59
+ });
60
+ return {
61
+ ok: errors === 0,
62
+ summary: {
63
+ errors,
64
+ warnings,
65
+ fixed,
66
+ filesWithIssues,
67
+ totalFilesProcessed
68
+ },
69
+ config: {
70
+ cwd,
71
+ configPath: configPath || null,
72
+ autoDiscover,
73
+ fix,
74
+ patterns
75
+ },
76
+ files: mappedFiles
77
+ };
78
+ }
79
+
80
+ //#endregion
81
+ //#region src/cli.ts
82
+ const MAX_FILENAME_DISPLAY_LENGTH = 50;
26
83
  function resolveOptions(files, options) {
27
84
  const hasConfigFlag = !!options.config;
28
85
  const hasAutoFlag = !!options.auto;
@@ -66,7 +123,7 @@ async function displayResults(files, fixMode) {
66
123
  console.log(chalk.default.green(` ✔ Fixed ${issueText}`));
67
124
  totalFixed += file.fixedCount || 0;
68
125
  }
69
- const { errors, warnings } = countDiagnosticsBySeverity(file.diagnostics);
126
+ const { errors, warnings } = countBySeverity(file.diagnostics);
70
127
  totalErrors += errors;
71
128
  totalWarnings += warnings;
72
129
  if (file.diagnostics.length > 0) filesWithIssues++;
@@ -132,7 +189,7 @@ program.configureHelp({ formatHelp: (cmd, helper) => {
132
189
  }
133
190
  return output;
134
191
  } });
135
- program.name("tailwind-lint").description("A CLI tool for linting Tailwind CSS class usage").version(getVersion()).argument("[files...]", "File patterns to lint (e.g., \"src/**/*.{js,jsx,ts,tsx}\")").option("-c, --config <path>", "Path to Tailwind config file (default: auto-discover)").option("-a, --auto", "Auto-discover files from Tailwind config content patterns").option("--fix", "Automatically fix problems that can be fixed").option("-v, --verbose", "Enable verbose logging for debugging").addHelpText("after", `
192
+ program.name("tailwind-lint").description("A CLI tool for linting Tailwind CSS class usage").version(getVersion()).argument("[files...]", "File patterns to lint (e.g., \"src/**/*.{js,jsx,ts,tsx}\")").option("-c, --config <path>", "Path to Tailwind config file (default: auto-discover)").option("-a, --auto", "Auto-discover files from Tailwind config content patterns").option("--fix", "Automatically fix problems that can be fixed").option("-v, --verbose", "Enable verbose logging for debugging").option("--format <format>", "Output format: text or json", "text").addHelpText("after", `
136
193
  ${chalk.default.bold.cyan("Examples:")}
137
194
  ${chalk.default.dim("$")} tailwind-lint
138
195
  ${chalk.default.dim("$")} tailwind-lint ${chalk.default.green("\"src/**/*.{js,jsx,ts,tsx}\"")}
@@ -151,8 +208,9 @@ ${chalk.default.bold.cyan("Notes:")}
151
208
  const hasAutoFlag = !!options.auto;
152
209
  if (!(files.length > 0) && !hasAutoFlag && !hasConfigFlag) options.auto = true;
153
210
  const resolved = resolveOptions(files, options);
211
+ const isJsonOutput = (options.format === "json" ? "json" : "text") === "json";
154
212
  try {
155
- if (resolved.verbose) {
213
+ if (resolved.verbose && !isJsonOutput) {
156
214
  console.log(chalk.default.cyan.bold("→ Configuration"));
157
215
  console.log(chalk.default.dim(` Working directory: ${resolved.cwd}`));
158
216
  console.log(chalk.default.dim(` Config path: ${resolved.configPath || "auto-discover"}`));
@@ -163,29 +221,51 @@ ${chalk.default.bold.cyan("Notes:")}
163
221
  const results = await require_linter.lint({
164
222
  ...resolved,
165
223
  onProgress: (current, total, file) => {
224
+ if (isJsonOutput) return;
166
225
  if (process.stdout.isTTY && !resolved.verbose) {
167
226
  const displayFile = truncateFilename(file);
168
227
  process.stdout.write(`\r${chalk.default.cyan("→")} Linting files... ${chalk.default.dim(`(${current}/${total})`)} ${chalk.default.dim(displayFile)}${" ".repeat(require_state.TERMINAL_PADDING)}`);
169
228
  } else if (resolved.verbose) console.log(chalk.default.dim(` [${current}/${total}] Linting ${file}`));
170
229
  }
171
230
  });
172
- if (process.stdout.isTTY && !resolved.verbose) process.stdout.write(`\r${" ".repeat(require_state.TERMINAL_WIDTH)}\r`);
231
+ if (process.stdout.isTTY && !resolved.verbose && !isJsonOutput) process.stdout.write(`\r${" ".repeat(require_state.TERMINAL_WIDTH)}\r`);
173
232
  if (results.totalFilesProcessed === 0) {
174
- console.log();
175
- console.log(chalk.default.yellow("⚠ No files found to lint"));
233
+ if (isJsonOutput) console.log(JSON.stringify(createJsonOutput({
234
+ ...resolved,
235
+ files: [],
236
+ totalFilesProcessed: 0
237
+ })));
238
+ else {
239
+ console.log();
240
+ console.log(chalk.default.yellow("⚠ No files found to lint"));
241
+ }
176
242
  process.exit(0);
177
243
  }
178
244
  if (results.files.length === 0) {
179
- console.log(chalk.default.green.bold("✔ No issues found"));
245
+ if (isJsonOutput) console.log(JSON.stringify(createJsonOutput({
246
+ ...resolved,
247
+ files: [],
248
+ totalFilesProcessed: results.totalFilesProcessed
249
+ })));
250
+ else console.log(chalk.default.green.bold("✔ No issues found"));
180
251
  process.exit(0);
181
252
  }
182
- await displayResults(results.files, resolved.fix);
253
+ if (isJsonOutput) console.log(JSON.stringify(createJsonOutput({
254
+ ...resolved,
255
+ files: results.files,
256
+ totalFilesProcessed: results.totalFilesProcessed
257
+ })));
258
+ else await displayResults(results.files, resolved.fix);
183
259
  const hasErrors = results.files.some((file) => file.diagnostics.some((d) => d.severity === require_state.SEVERITY.ERROR));
184
260
  process.exit(hasErrors ? 1 : 0);
185
261
  } catch (error) {
186
262
  const errorMessage = error instanceof Error ? error.message : String(error);
187
- console.error(chalk.default.red("✖ Error:"), errorMessage);
188
- if (resolved.verbose && error instanceof Error) {
263
+ if (isJsonOutput) console.log(JSON.stringify({
264
+ ok: false,
265
+ error: errorMessage
266
+ }));
267
+ else console.error(chalk.default.red("✖ Error:"), errorMessage);
268
+ if (resolved.verbose && error instanceof Error && !isJsonOutput) {
189
269
  console.error(chalk.default.dim("\nStack trace:"));
190
270
  console.error(chalk.default.dim(error.stack || error.toString()));
191
271
  }
package/dist/linter.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_state = require('./state-BHl8x2Q1.cjs');
2
+ const require_state = require('./state-QQi4_-5a.cjs');
3
3
  let node_path = require("node:path");
4
4
  node_path = require_state.__toESM(node_path);
5
5
  let _tailwindcss_language_service = require("@tailwindcss/language-service");
@@ -33,11 +33,12 @@ async function discoverFiles(cwd, patterns, configPath, autoDiscover) {
33
33
  return expandPatterns(cwd, patterns);
34
34
  }
35
35
  async function expandPatterns(cwd, patterns, extraIgnore = []) {
36
- return (0, fast_glob.default)(patterns, {
36
+ const files = await (0, fast_glob.default)(patterns, {
37
37
  cwd,
38
38
  absolute: false,
39
39
  ignore: [...require_state.DEFAULT_IGNORE_PATTERNS, ...extraIgnore]
40
40
  });
41
+ return [...new Set(files)].sort((a, b) => a.localeCompare(b));
41
42
  }
42
43
  async function discoverFilesFromConfig(cwd, configPath) {
43
44
  const configFilePath = await require_state.findTailwindConfigPath(cwd, configPath);
@@ -50,7 +51,9 @@ async function discoverFilesFromConfig(cwd, configPath) {
50
51
  return expandPatterns(cwd, patterns);
51
52
  }
52
53
  const configDir = node_path.dirname(configFilePath);
53
- const { include, exclude } = extractSourcePatterns(require_state.readFileSync(configFilePath));
54
+ const cssContent = require_state.readFileSync(configFilePath);
55
+ const { include, exclude } = extractSourcePatterns(cssContent);
56
+ const importSource = extractImportSourceDirectives(cssContent);
54
57
  const resolveFromConfig = (pattern) => {
55
58
  const absolutePattern = node_path.resolve(configDir, pattern);
56
59
  return node_path.relative(cwd, absolutePattern);
@@ -59,6 +62,8 @@ async function discoverFilesFromConfig(cwd, configPath) {
59
62
  const gitignorePatterns = require_state.readGitignorePatterns(cwd);
60
63
  const extraIgnore = [...resolvedExclude, ...gitignorePatterns];
61
64
  if (include.length > 0) return expandPatterns(cwd, include.map(resolveFromConfig), extraIgnore);
65
+ if (importSource.roots.length > 0) return expandPatterns(cwd, importSource.roots.map((root) => resolveFromConfig(node_path.join(root, "**/*.{js,jsx,ts,tsx,html,vue,svelte,astro,mdx}"))), extraIgnore);
66
+ if (importSource.disableAutoSource) return [];
62
67
  return expandPatterns(cwd, [require_state.DEFAULT_FILE_PATTERN], extraIgnore);
63
68
  }
64
69
  function extractContentPatterns(config) {
@@ -80,6 +85,24 @@ function extractSourcePatterns(cssContent) {
80
85
  exclude
81
86
  };
82
87
  }
88
+ function extractImportSourceDirectives(cssContent) {
89
+ const roots = [];
90
+ let disableAutoSource = false;
91
+ for (const match of cssContent.matchAll(/@import\s+["']tailwindcss(?:[^;]*?)\ssource\(\s*(none|["'][^"']+["'])\s*\)/g)) {
92
+ const raw = match[1];
93
+ if (!raw) continue;
94
+ if (raw === "none") {
95
+ disableAutoSource = true;
96
+ continue;
97
+ }
98
+ const sourceRoot = raw.slice(1, -1).trim();
99
+ if (sourceRoot.length > 0) roots.push(sourceRoot);
100
+ }
101
+ return {
102
+ roots: [...new Set(roots)],
103
+ disableAutoSource
104
+ };
105
+ }
83
106
  async function processFiles(state, cwd, files, fix, onProgress) {
84
107
  const results = [];
85
108
  for (let i = 0; i < files.length; i += require_state.CONCURRENT_FILES) {
@@ -141,5 +164,6 @@ async function lint({ cwd, patterns, configPath, autoDiscover, fix = false, verb
141
164
  }
142
165
 
143
166
  //#endregion
167
+ exports.extractImportSourceDirectives = extractImportSourceDirectives;
144
168
  exports.extractSourcePatterns = extractSourcePatterns;
145
169
  exports.lint = lint;
package/dist/linter.d.cts CHANGED
@@ -26,6 +26,10 @@ declare function extractSourcePatterns(cssContent: string): {
26
26
  include: string[];
27
27
  exclude: string[];
28
28
  };
29
+ declare function extractImportSourceDirectives(cssContent: string): {
30
+ roots: string[];
31
+ disableAutoSource: boolean;
32
+ };
29
33
  declare function lint({
30
34
  cwd,
31
35
  patterns,
@@ -36,4 +40,4 @@ declare function lint({
36
40
  onProgress
37
41
  }: LintOptions): Promise<LintResult>;
38
42
  //#endregion
39
- export { type LintFileResult, type LintOptions, type LintResult, extractSourcePatterns, lint };
43
+ export { type LintFileResult, type LintOptions, type LintResult, extractImportSourceDirectives, extractSourcePatterns, lint };
@@ -30,6 +30,8 @@ node_path = __toESM(node_path);
30
30
  let _tailwindcss_language_service = require("@tailwindcss/language-service");
31
31
  let chalk = require("chalk");
32
32
  chalk = __toESM(chalk);
33
+ let fast_glob = require("fast-glob");
34
+ fast_glob = __toESM(fast_glob);
33
35
  let vscode_languageserver_textdocument = require("vscode-languageserver-textdocument");
34
36
  let node_module = require("node:module");
35
37
  let node_fs = require("node:fs");
@@ -483,6 +485,7 @@ async function loadV4DesignSystem(state, cwd, configPath, verbose = false) {
483
485
  //#endregion
484
486
  //#region src/utils/config.ts
485
487
  const require$2 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href || __filename);
488
+ const CONFIG_DISCOVERY_MAX_DEPTH = 8;
486
489
  const isCssConfigFile = (filePath) => filePath.endsWith(".css");
487
490
  async function loadTailwindConfig(configPath) {
488
491
  if (isCssConfigFile(configPath)) return {};
@@ -509,6 +512,13 @@ async function findTailwindConfigPath(cwd, configPath) {
509
512
  const fullPath = node_path.join(cwd, p);
510
513
  if (fileExists(fullPath)) return fullPath;
511
514
  }
515
+ const v3Recursive = await (0, fast_glob.default)(V3_CONFIG_PATHS.map((p) => `**/${p}`), {
516
+ cwd,
517
+ absolute: true,
518
+ ignore: DEFAULT_IGNORE_PATTERNS,
519
+ deep: CONFIG_DISCOVERY_MAX_DEPTH
520
+ });
521
+ if (v3Recursive.length > 0) return sortByPathDepth(v3Recursive)[0];
512
522
  const v4Paths = V4_CSS_FOLDERS.flatMap((folder) => V4_CSS_NAMES.map((name) => node_path.join(folder, name)));
513
523
  for (const p of v4Paths) {
514
524
  const fullPath = node_path.join(cwd, p);
@@ -517,8 +527,52 @@ async function findTailwindConfigPath(cwd, configPath) {
517
527
  if (TAILWIND_V4_IMPORT_REGEX.test(content)) return fullPath;
518
528
  } catch {}
519
529
  }
530
+ const cssCandidates = await (0, fast_glob.default)("**/*.css", {
531
+ cwd,
532
+ absolute: true,
533
+ ignore: DEFAULT_IGNORE_PATTERNS,
534
+ deep: CONFIG_DISCOVERY_MAX_DEPTH
535
+ });
536
+ const v4Matches = [];
537
+ for (const candidate of cssCandidates) try {
538
+ const content = readFileSync(candidate);
539
+ if (TAILWIND_V4_IMPORT_REGEX.test(content)) v4Matches.push(candidate);
540
+ } catch {}
541
+ if (v4Matches.length > 0) return sortCssCandidates(cwd, v4Matches)[0];
520
542
  return null;
521
543
  }
544
+ function sortByPathDepth(paths) {
545
+ return [...paths].sort((a, b) => {
546
+ const depthA = splitDepth(a);
547
+ const depthB = splitDepth(b);
548
+ if (depthA !== depthB) return depthA - depthB;
549
+ return a.localeCompare(b);
550
+ });
551
+ }
552
+ function sortCssCandidates(cwd, paths) {
553
+ return [...paths].sort((a, b) => {
554
+ const scoreA = cssCandidateScore(cwd, a);
555
+ const scoreB = cssCandidateScore(cwd, b);
556
+ if (scoreA !== scoreB) return scoreA - scoreB;
557
+ return a.localeCompare(b);
558
+ });
559
+ }
560
+ function cssCandidateScore(cwd, candidate) {
561
+ const normalized = node_path.relative(cwd, candidate).split(node_path.sep).join("/");
562
+ const base = node_path.basename(candidate);
563
+ const depth = splitDepth(normalized);
564
+ const nameScore = V4_CSS_NAMES.includes(base) ? 0 : 20;
565
+ const folderScore = isPreferredCssFolder(normalized) ? 0 : 10;
566
+ return depth * 100 + nameScore + folderScore;
567
+ }
568
+ function isPreferredCssFolder(relativePath) {
569
+ const folder = node_path.dirname(relativePath).replace(/\\/g, "/");
570
+ const withSlash = folder === "." ? "./" : `./${folder}/`;
571
+ return V4_CSS_FOLDERS.includes(withSlash);
572
+ }
573
+ function splitDepth(value) {
574
+ return value.split(/[\\/]/).filter(Boolean).length;
575
+ }
522
576
 
523
577
  //#endregion
524
578
  //#region src/state.ts
package/package.json CHANGED
@@ -1,77 +1,81 @@
1
1
  {
2
- "name": "tailwind-lint",
3
- "version": "0.7.0",
4
- "description": "A command-line tool that uses the Tailwind CSS IntelliSense plugin to show linting suggestions for your Tailwind CSS classes",
5
- "keywords": [
6
- "cli",
7
- "code-quality",
8
- "css",
9
- "diagnostics",
10
- "intellisense",
11
- "lint",
12
- "linter",
13
- "tailwind",
14
- "tailwindcss",
15
- "utility-first"
16
- ],
17
- "homepage": "https://github.com/ph1p/tailwind-lint#readme",
18
- "bugs": {
19
- "url": "https://github.com/ph1p/tailwind-lint/issues"
20
- },
21
- "license": "MIT",
22
- "author": "Philip Stapelfeldt <me@ph1p.dev>",
23
- "repository": {
24
- "type": "git",
25
- "url": "https://github.com/ph1p/tailwind-lint.git"
26
- },
27
- "funding": {
28
- "type": "github",
29
- "url": "https://github.com/sponsors/ph1p"
30
- },
31
- "bin": {
32
- "tailwind-lint": "./dist/cli.cjs"
33
- },
34
- "files": [
35
- "dist",
36
- "README.md",
37
- "LICENSE"
38
- ],
39
- "type": "module",
40
- "types": "./dist/linter.d.ts",
41
- "publishConfig": {
42
- "access": "public",
43
- "registry": "https://registry.npmjs.org/"
44
- },
45
- "dependencies": {
46
- "@tailwindcss/language-service": "^0.14.29",
47
- "chalk": "^5.6.2",
48
- "commander": "^14.0.3",
49
- "fast-glob": "^3.3.3",
50
- "postcss": "^8.5.6",
51
- "vscode-languageserver-textdocument": "^1.0.12"
52
- },
53
- "devDependencies": {
54
- "@types/node": "^25.2.2",
55
- "oxfmt": "^0.28.0",
56
- "oxlint": "^1.43.0",
57
- "tsdown": "^0.20.3",
58
- "typescript": "^5.9.3",
59
- "vitest": "^4.0.18"
60
- },
61
- "engines": {
62
- "node": ">=22.0.0",
63
- "pnpm": ">=10.0.0"
64
- },
65
- "scripts": {
66
- "build": "tsdown",
67
- "dev": "tsdown --watch",
68
- "format": "oxfmt --write .",
69
- "format:check": "oxfmt --check .",
70
- "lint": "oxlint .",
71
- "lint:fix": "oxlint --fix .",
72
- "start": "node dist/cli.cjs",
73
- "test": "vitest run",
74
- "test:coverage": "vitest run --coverage",
75
- "test:watch": "vitest"
76
- }
77
- }
2
+ "name": "tailwind-lint",
3
+ "version": "0.8.0",
4
+ "description": "A command-line tool that uses the Tailwind CSS IntelliSense plugin to show linting suggestions for your Tailwind CSS classes",
5
+ "keywords": [
6
+ "cli",
7
+ "code-quality",
8
+ "css",
9
+ "diagnostics",
10
+ "intellisense",
11
+ "lint",
12
+ "linter",
13
+ "tailwind",
14
+ "tailwindcss",
15
+ "utility-first"
16
+ ],
17
+ "homepage": "https://github.com/ph1p/tailwind-lint#readme",
18
+ "bugs": {
19
+ "url": "https://github.com/ph1p/tailwind-lint/issues"
20
+ },
21
+ "license": "MIT",
22
+ "author": "Philip Stapelfeldt <me@ph1p.dev>",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/ph1p/tailwind-lint.git"
26
+ },
27
+ "funding": {
28
+ "type": "github",
29
+ "url": "https://github.com/sponsors/ph1p"
30
+ },
31
+ "bin": {
32
+ "tailwind-lint": "./dist/cli.cjs"
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "README.md",
37
+ "LICENSE"
38
+ ],
39
+ "type": "module",
40
+ "types": "./dist/linter.d.ts",
41
+ "publishConfig": {
42
+ "access": "public",
43
+ "registry": "https://registry.npmjs.org/"
44
+ },
45
+ "scripts": {
46
+ "build": "tsdown",
47
+ "dev": "tsdown --watch",
48
+ "format": "oxfmt --write .",
49
+ "format:check": "oxfmt --check .",
50
+ "lint": "oxlint .",
51
+ "lint:fix": "oxlint --fix .",
52
+ "prepublishOnly": "pnpm build && pnpm test",
53
+ "release": "pnpm dlx semantic-release",
54
+ "release:dry": "SEMREL_LOCAL=1 pnpm dlx semantic-release --dry-run --no-ci --repository-url .",
55
+ "start": "node dist/cli.cjs",
56
+ "test": "vitest run",
57
+ "test:coverage": "vitest run --coverage",
58
+ "test:watch": "vitest"
59
+ },
60
+ "dependencies": {
61
+ "@tailwindcss/language-service": "^0.14.29",
62
+ "chalk": "^5.6.2",
63
+ "commander": "^14.0.3",
64
+ "fast-glob": "^3.3.3",
65
+ "postcss": "^8.5.6",
66
+ "vscode-languageserver-textdocument": "^1.0.12"
67
+ },
68
+ "devDependencies": {
69
+ "@types/node": "^25.3.0",
70
+ "oxfmt": "^0.34.0",
71
+ "oxlint": "^1.49.0",
72
+ "tsdown": "^0.20.3",
73
+ "typescript": "^5.9.3",
74
+ "vitest": "^4.0.18"
75
+ },
76
+ "engines": {
77
+ "node": ">=22.0.0",
78
+ "pnpm": ">=10.0.0"
79
+ },
80
+ "packageManager": "pnpm@10.30.1"
81
+ }