tailwind-lint 0.12.1 → 0.13.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 CHANGED
@@ -60,7 +60,15 @@ tailwind-lint --verbose
60
60
  **Tailwind CSS v3:**
61
61
 
62
62
  - Finds JavaScript config files: `tailwind.config.js`, `tailwind.config.cjs`, `tailwind.config.mjs`, `tailwind.config.ts`
63
- - Uses file patterns from the `content` array in your config
63
+ - Uses file patterns from the `content` array in your config, resolved from the package root (or from the config file with `content.relative: true`)
64
+
65
+ **Monorepos:**
66
+
67
+ - Workspace packages from `package.json` `workspaces` or `pnpm-workspace.yaml` are detected; without a workspace definition every directory with a `package.json` is treated as a package
68
+ - Each package gets its own config detected; packages without one fall back to the closest parent config
69
+ - Each file is linted with the config of the closest package that contains it, so apps with different themes or Tailwind versions (v3 and v4 side by side) are linted correctly
70
+ - `tailwindcss` is resolved from the config's package first, falling back to the working directory
71
+ - Use `--verbose` to see which config each package uses
64
72
 
65
73
  ### Options
66
74
 
package/dist/cli.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const require_linter = require("./linter-BP0uKBfa.cjs");
2
+ const require_linter = require("./linter-B-Bi_uRJ.cjs");
3
3
  let node_path = require("node:path");
4
4
  node_path = require_linter.__toESM(node_path, 1);
5
5
  let ansis = require("ansis");
@@ -101,15 +101,13 @@ function createJsonErrorOutput({ error, cwd, configPath, autoDiscover, fix, patt
101
101
  //#region src/cli.ts
102
102
  const MAX_FILENAME_DISPLAY_LENGTH = 50;
103
103
  function resolveOptions(files, options) {
104
- const hasConfigFlag = !!options.config;
105
104
  const hasAutoFlag = !!options.auto;
106
105
  const hasFiles = files.length > 0;
107
106
  let cwd = process.cwd();
108
- let configPath = options.config;
107
+ const configPath = options.config && node_path.resolve(options.config);
109
108
  let patterns = files;
110
109
  let autoDiscover = hasAutoFlag;
111
- if (hasConfigFlag && options.config) configPath = node_path.isAbsolute(options.config) ? options.config : node_path.resolve(process.cwd(), options.config);
112
- if (hasConfigFlag && options.config && !hasFiles) {
110
+ if (configPath && !hasFiles) {
113
111
  const configDir = node_path.dirname(configPath);
114
112
  cwd = require_linter.isCssConfigFile(configPath) ? require_linter.findProjectRoot(configDir) : configDir;
115
113
  patterns = [];
@@ -158,11 +156,12 @@ async function displayResults(files, fixMode) {
158
156
  }
159
157
  }
160
158
  console.log();
161
- if (totalErrors === 0 && totalWarnings === 0) if (totalFixed > 0) {
162
- const issueText = `${totalFixed} issue${totalFixed !== 1 ? "s" : ""}`;
163
- console.log(ansis.default.green.bold(`✔ Fixed ${issueText}`));
164
- } else console.log(ansis.default.green.bold("✔ No issues found"));
165
- else {
159
+ if (totalErrors === 0 && totalWarnings === 0) {
160
+ if (totalFixed > 0) {
161
+ const issueText = `${totalFixed} issue${totalFixed !== 1 ? "s" : ""}`;
162
+ console.log(ansis.default.green.bold(`✔ Fixed ${issueText}`));
163
+ } else console.log(ansis.default.green.bold("✔ No issues found"));
164
+ } else {
166
165
  const parts = [];
167
166
  if (totalErrors > 0) parts.push(`${totalErrors} error${totalErrors !== 1 ? "s" : ""}`);
168
167
  if (totalWarnings > 0) parts.push(`${totalWarnings} warning${totalWarnings !== 1 ? "s" : ""}`);
package/dist/cli.d.cts CHANGED
@@ -1 +1 @@
1
- export { };
1
+ export {}
@@ -15,7 +15,7 @@ var __copyProps = (to, from, except, desc) => {
15
15
  }
16
16
  return to;
17
17
  };
18
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
19
19
  value: mod,
20
20
  enumerable: true
21
21
  }) : target, mod));
@@ -30,8 +30,10 @@ let vscode_languageserver_textdocument = require("vscode-languageserver-textdocu
30
30
  let node_module = require("node:module");
31
31
  let node_fs = require("node:fs");
32
32
  node_fs = __toESM(node_fs, 1);
33
+ let node_url = require("node:url");
33
34
  let postcss = require("postcss");
34
35
  postcss = __toESM(postcss, 1);
36
+ let node_fs_promises = require("node:fs/promises");
35
37
  //#region src/constants.ts
36
38
  const DEFAULT_IGNORE_PATTERNS = [
37
39
  "**/node_modules/**",
@@ -90,7 +92,6 @@ const VITE_CONFIG_PATHS = [
90
92
  "vite.config.mts",
91
93
  "vite.config.cts"
92
94
  ];
93
- const SYNTHETIC_VITE_CSS_CONFIG_NAME = ".tailwind-lint.vite.css";
94
95
  const SYNTHETIC_VITE_CSS_CONFIG_CONTENT = "@import \"tailwindcss\";";
95
96
  const LANGUAGE_MAP = {
96
97
  ".astro": "astro",
@@ -134,7 +135,7 @@ async function getQuickfixes(state, document, uri, diagnostics) {
134
135
  code: diag.code,
135
136
  source: diag.source || "tailwindcss"
136
137
  }));
137
- return (await (0, _tailwindcss_language_service.doCodeActions)(state, {
138
+ const params = {
138
139
  textDocument: { uri },
139
140
  range: {
140
141
  start: {
@@ -147,7 +148,8 @@ async function getQuickfixes(state, document, uri, diagnostics) {
147
148
  }
148
149
  },
149
150
  context: { diagnostics: lspDiagnostics }
150
- }, document)).filter((action) => action.kind === "quickfix" || action.kind?.startsWith(`quickfix.`));
151
+ };
152
+ return (await (0, _tailwindcss_language_service.doCodeActions)(state, params, document)).filter((action) => action.kind === "quickfix" || action.kind?.startsWith(`quickfix.`));
151
153
  }
152
154
  function applyFirstQuickfix(action, uri, document, content) {
153
155
  if (!action.edit?.changes?.[uri]) return null;
@@ -257,7 +259,7 @@ function readVsCodeTailwindSettings(cwd) {
257
259
  const files = readNestedObject(raw, "tailwindCSS.files");
258
260
  const lint = readNestedObject(raw, "tailwindCSS.lint");
259
261
  return {
260
- includeLanguages: asRecord(raw["tailwindCSS.includeLanguages"]),
262
+ includeLanguages: asStringRecord(raw["tailwindCSS.includeLanguages"]),
261
263
  classAttributes: asStringArray(raw["tailwindCSS.classAttributes"]),
262
264
  classFunctions: asStringArray(raw["tailwindCSS.classFunctions"]),
263
265
  experimental: {
@@ -275,7 +277,7 @@ function readZedTailwindSettings(cwd) {
275
277
  const normalized = asRecord(serverSettings?.tailwindCSS) ?? serverSettings;
276
278
  if (!normalized) return {};
277
279
  return {
278
- includeLanguages: asRecord(normalized.includeLanguages),
280
+ includeLanguages: asStringRecord(normalized.includeLanguages),
279
281
  classAttributes: asStringArray(normalized.classAttributes),
280
282
  classFunctions: asStringArray(normalized.classFunctions),
281
283
  experimental: {
@@ -303,6 +305,11 @@ function readNestedObject(input, key) {
303
305
  function asRecord(value) {
304
306
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
305
307
  }
308
+ function asStringRecord(value) {
309
+ const record = asRecord(value);
310
+ if (!record) return;
311
+ return Object.fromEntries(Object.entries(record).filter((entry) => typeof entry[1] === "string"));
312
+ }
306
313
  function asStringArray(value) {
307
314
  return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : void 0;
308
315
  }
@@ -440,6 +447,7 @@ function createEditorState(cwd) {
440
447
  invalidApply: "error",
441
448
  invalidScreen: "error",
442
449
  invalidVariant: "error",
450
+ deprecatedAtRule: "warning",
443
451
  invalidConfigPath: "error",
444
452
  invalidTailwindDirective: "error",
445
453
  invalidSourceDirective: "error",
@@ -456,6 +464,7 @@ function createEditorState(cwd) {
456
464
  capabilities: {
457
465
  configuration: true,
458
466
  diagnosticRelatedInformation: true,
467
+ diagnosticTagSupport: false,
459
468
  itemDefaults: []
460
469
  },
461
470
  getConfiguration: async () => settings,
@@ -487,50 +496,40 @@ var AdapterLoadError = class extends Error {
487
496
  //#endregion
488
497
  //#region src/adapters/v3-adapter.ts
489
498
  const require$4 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href || __filename);
490
- async function loadV3ClassMetadata(state, cwd, verbose = false) {
499
+ function interopDefault(module) {
500
+ return module && typeof module === "object" && "default" in module ? module.default : module;
501
+ }
502
+ async function loadV3ClassMetadata(state, resolvePaths, verbose = false) {
491
503
  try {
492
- const tailwindPath = require$4.resolve("tailwindcss", { paths: [cwd] });
493
- const tailwindcss = require$4(tailwindPath);
494
- try {
495
- const tailwindDir = node_path.dirname(require$4.resolve("tailwindcss/package.json", { paths: [cwd] }));
496
- const contextUtils = require$4(node_path.join(tailwindDir, "lib", "lib", "setupContextUtils"));
497
- const generateRulesModule = require$4(node_path.join(tailwindDir, "lib", "lib", "generateRules"));
498
- state.modules = {
499
- tailwindcss: {
500
- version: state.version || "unknown",
501
- module: tailwindcss
502
- },
503
- jit: {
504
- generateRules: { module: generateRulesModule.generateRules || ((_set, _context) => []) },
505
- createContext: { module: contextUtils.createContext },
506
- expandApplyAtRules: { module: generateRulesModule.expandApplyAtRules }
507
- }
508
- };
509
- if (verbose) console.log(ansis.default.dim(" ✓ Loaded v3 JIT modules"));
510
- } catch (jitError) {
511
- if (verbose) {
512
- const message = jitError instanceof Error ? jitError.message : String(jitError);
513
- console.log(ansis.default.yellow(` ⚠ Warning: Could not load v3 JIT modules: ${message}`));
514
- }
515
- state.modules = { tailwindcss: {
504
+ const tailwindDir = node_path.dirname(require$4.resolve("tailwindcss/package.json", { paths: resolvePaths }));
505
+ const load = (id) => require$4(require$4.resolve(id, { paths: [tailwindDir] }));
506
+ const loadLib = (name) => require$4(node_path.join(tailwindDir, "lib", "lib", name));
507
+ const { createContext } = loadLib("setupContextUtils");
508
+ const { generateRules } = loadLib("generateRules");
509
+ state.jit = true;
510
+ state.modules = {
511
+ tailwindcss: {
516
512
  version: state.version || "unknown",
517
- module: tailwindcss
518
- } };
519
- }
520
- extractConfigMetadata(state);
521
- if (!state.classNames) state.classNames = {
522
- context: {},
523
- classNames: {}
524
- };
525
- if (state.modules?.jit?.createContext && state.config) try {
526
- state.jitContext = state.modules.jit.createContext.module(state.config);
527
- if (verbose) console.log(ansis.default.dim(" ✓ Created JIT context"));
528
- } catch (contextError) {
529
- if (verbose) {
530
- const message = contextError instanceof Error ? contextError.message : String(contextError);
531
- console.log(ansis.default.yellow(` ⚠ Warning: Could not create JIT context: ${message}`));
513
+ module: load("tailwindcss")
514
+ },
515
+ postcss: {
516
+ version: load("postcss/package.json").version,
517
+ module: load("postcss")
518
+ },
519
+ postcssSelectorParser: { module: load("postcss-selector-parser") },
520
+ jit: {
521
+ generateRules: { module: generateRules },
522
+ createContext: { module: createContext },
523
+ expandApplyAtRules: { module: interopDefault(loadLib("expandApplyAtRules")) },
524
+ evaluateTailwindFunctions: { module: interopDefault(loadLib("evaluateTailwindFunctions")) }
532
525
  }
533
- }
526
+ };
527
+ extractConfigMetadata(state);
528
+ const jitContext = createContext(state.config);
529
+ state.jitContext = jitContext;
530
+ state.classList = jitContext.getClassList?.({ includeMetadata: true });
531
+ state.variants = jitContext.getVariants?.() ?? [];
532
+ if (verbose) console.log(ansis.default.dim(" ✓ Created v3 JIT context"));
534
533
  } catch (error) {
535
534
  if (error instanceof Error) throw new AdapterLoadError("v3", error);
536
535
  throw new Error(`Failed to load v3 class metadata: ${String(error)}`);
@@ -542,37 +541,72 @@ function extractConfigMetadata(state) {
542
541
  const theme = config.theme;
543
542
  state.screens = Object.keys(theme?.screens ?? {});
544
543
  state.blocklist = config.blocklist ?? [];
545
- if (config.variants && typeof config.variants === "object") state.variants = Object.keys(config.variants).map((name) => ({
546
- name,
547
- values: [],
548
- isArbitrary: false,
549
- hasDash: true,
550
- selectors: () => []
551
- }));
552
544
  if (config.corePlugins) state.corePlugins = Array.isArray(config.corePlugins) ? config.corePlugins : Object.keys(config.corePlugins);
553
545
  }
554
546
  //#endregion
555
547
  //#region src/adapters/v4-adapter.ts
556
548
  const require$3 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href || __filename);
557
- async function loadV4DesignSystem(state, cwd, configPath, verbose = false) {
549
+ function resolveModule(id, paths) {
550
+ let firstError;
551
+ for (const dir of paths) try {
552
+ return (0, node_module.createRequire)(node_path.join(dir, "noop.js")).resolve(id);
553
+ } catch (error) {
554
+ firstError ??= error;
555
+ }
556
+ throw firstError ?? /* @__PURE__ */ new Error(`Cannot find module "${id}"`);
557
+ }
558
+ async function importModule(modulePath) {
559
+ let mod;
558
560
  try {
559
- const tailwindPath = require$3.resolve("tailwindcss", { paths: [cwd] });
561
+ mod = await import((0, node_url.pathToFileURL)(modulePath).href);
562
+ } catch {
563
+ mod = require$3(modulePath);
564
+ }
565
+ if (mod !== null && typeof mod === "object" && "default" in mod) return mod.default;
566
+ return mod;
567
+ }
568
+ function fromPostcss(nodes) {
569
+ return nodes.map((node) => {
570
+ switch (node.type) {
571
+ case "rule": return {
572
+ kind: "rule",
573
+ selector: node.selector,
574
+ nodes: fromPostcss(node.nodes)
575
+ };
576
+ case "atrule": return {
577
+ kind: "at-rule",
578
+ name: node.name,
579
+ params: node.params,
580
+ nodes: node.nodes ? fromPostcss(node.nodes) : null
581
+ };
582
+ case "decl": return {
583
+ kind: "declaration",
584
+ property: node.prop,
585
+ value: node.value,
586
+ important: node.important
587
+ };
588
+ default: return {
589
+ kind: "comment",
590
+ value: node.text
591
+ };
592
+ }
593
+ });
594
+ }
595
+ async function loadV4DesignSystem(state, resolvePaths, target, verbose = false) {
596
+ try {
597
+ const tailwindPath = require$3.resolve("tailwindcss", { paths: resolvePaths });
560
598
  const tailwindcss = require$3(tailwindPath);
561
599
  if (tailwindcss !== null && tailwindcss !== void 0 && (typeof tailwindcss === "object" || typeof tailwindcss === "function") && "__unstable__loadDesignSystem" in tailwindcss && typeof tailwindcss.__unstable__loadDesignSystem === "function") {
562
- let cssContent;
563
- const basePath = node_path.dirname(configPath);
564
- if (fileExists(configPath)) cssContent = readFileSync(configPath);
565
- else cssContent = SYNTHETIC_VITE_CSS_CONFIG_CONTENT;
600
+ const cssContent = target.kind === "vite" ? SYNTHETIC_VITE_CSS_CONFIG_CONTENT : readFileSync(target.path);
566
601
  const loadDesignSystem = tailwindcss.__unstable__loadDesignSystem;
567
602
  const designSystem = await loadDesignSystem(cssContent, {
568
- base: basePath,
603
+ base: node_path.dirname(target.path),
569
604
  async loadModule(id, base, _type) {
570
605
  try {
571
- const modulePath = require$3.resolve(id, { paths: [base, cwd] });
572
- const module = require$3(modulePath);
606
+ const modulePath = resolveModule(id, [base, ...resolvePaths]);
573
607
  return {
574
608
  base: node_path.dirname(modulePath),
575
- module
609
+ module: await importModule(modulePath)
576
610
  };
577
611
  } catch (error) {
578
612
  throw new Error(`Failed to load module "${id}": ${error instanceof Error ? error.message : String(error)}`);
@@ -584,7 +618,7 @@ async function loadV4DesignSystem(state, cwd, configPath, verbose = false) {
584
618
  content
585
619
  };
586
620
  if (!_id.startsWith(".") && !_id.startsWith("/")) try {
587
- const pkgJsonPath = require$3.resolve(`${_id}/package.json`, { paths: [base, cwd] });
621
+ const pkgJsonPath = require$3.resolve(`${_id}/package.json`, { paths: [base, ...resolvePaths] });
588
622
  const pkgDir = node_path.dirname(pkgJsonPath);
589
623
  const cssPath = node_path.join(pkgDir, "index.css");
590
624
  if (fileExists(cssPath)) return {
@@ -606,15 +640,16 @@ async function loadV4DesignSystem(state, cwd, configPath, verbose = false) {
606
640
  Object.assign(designSystem, {
607
641
  dependencies: () => /* @__PURE__ */ new Set(),
608
642
  compile(classes) {
609
- if (designSystem.candidatesToCss) return designSystem.candidatesToCss(classes).map((result) => {
610
- if (typeof result === "string" && result.length > 0) try {
611
- return postcss.default.parse(result);
643
+ if (designSystem.candidatesToAst) return designSystem.candidatesToAst(classes);
644
+ if (designSystem.candidatesToCss) return designSystem.candidatesToCss(classes).map((css) => {
645
+ if (!css) return [];
646
+ try {
647
+ return fromPostcss(postcss.default.parse(css).nodes);
612
648
  } catch {
613
- return postcss.default.root();
649
+ return [];
614
650
  }
615
- return postcss.default.root();
616
651
  });
617
- return classes.map(() => postcss.default.root());
652
+ return classes.map(() => []);
618
653
  }
619
654
  });
620
655
  state.designSystem = designSystem;
@@ -632,6 +667,7 @@ async function loadV4DesignSystem(state, cwd, configPath, verbose = false) {
632
667
  const require$2 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href || __filename);
633
668
  const CONFIG_DISCOVERY_MAX_DEPTH = 8;
634
669
  const PROJECT_ROOT_MARKERS = ["package.json", ".git"];
670
+ const VITE_CONFIG_NAME_REGEX = /^vite\.config\.[cm]?[jt]s$/;
635
671
  const isCssConfigFile = (filePath) => filePath.endsWith(".css");
636
672
  function findProjectRoot(startDir) {
637
673
  let current = node_path.resolve(startDir);
@@ -642,9 +678,6 @@ function findProjectRoot(startDir) {
642
678
  current = parent;
643
679
  }
644
680
  }
645
- function syntheticViteCssConfigPath(viteConfigPath) {
646
- return node_path.join(node_path.dirname(viteConfigPath), SYNTHETIC_VITE_CSS_CONFIG_NAME);
647
- }
648
681
  async function loadTailwindConfig(configPath) {
649
682
  if (isCssConfigFile(configPath)) return {};
650
683
  if (!node_path.isAbsolute(configPath)) throw new Error(`Config path must be absolute for security reasons: ${configPath}`);
@@ -661,66 +694,116 @@ async function loadTailwindConfig(configPath) {
661
694
  throw new Error(`Failed to load config from ${configPath}: ${errorMessage}`);
662
695
  }
663
696
  }
664
- async function findTailwindConfigPath(cwd, configPath) {
665
- if (configPath) {
666
- const resolved = node_path.isAbsolute(configPath) ? configPath : node_path.resolve(cwd, configPath);
667
- return fileExists(resolved) ? resolved : null;
668
- }
669
- const v4Paths = V4_CSS_FOLDERS.flatMap((folder) => V4_CSS_NAMES.map((name) => node_path.join(folder, name)));
670
- for (const p of v4Paths) {
671
- const fullPath = node_path.join(cwd, p);
672
- if (fileExists(fullPath)) try {
673
- const content = readFileSync(fullPath);
674
- if (TAILWIND_V4_IMPORT_REGEX.test(content)) return fullPath;
675
- } catch {}
676
- }
677
- for (const p of V3_CONFIG_PATHS) {
678
- const fullPath = node_path.join(cwd, p);
679
- if (fileExists(fullPath)) return fullPath;
680
- }
681
- const cssCandidates = await (0, tinyglobby.glob)("**/*.css", {
682
- cwd,
697
+ function toConfigTarget(configPath) {
698
+ return {
699
+ kind: configKind(configPath),
700
+ path: configPath,
701
+ root: findProjectRoot(node_path.dirname(configPath))
702
+ };
703
+ }
704
+ function configKind(configPath) {
705
+ if (isCssConfigFile(configPath)) return "css";
706
+ return VITE_CONFIG_NAME_REGEX.test(node_path.basename(configPath)) ? "vite" : "js";
707
+ }
708
+ async function findTailwindConfigs(cwd) {
709
+ const root = node_path.resolve(cwd);
710
+ const files = await (0, tinyglobby.glob)([
711
+ "**/package.json",
712
+ "**/*.css",
713
+ ...[...V3_CONFIG_PATHS, ...VITE_CONFIG_PATHS].map((p) => `**/${p}`)
714
+ ], {
715
+ cwd: root,
683
716
  absolute: true,
684
717
  ignore: DEFAULT_IGNORE_PATTERNS,
685
718
  deep: CONFIG_DISCOVERY_MAX_DEPTH
686
719
  });
687
- const v4Matches = [];
688
- for (const candidate of cssCandidates) try {
689
- const content = readFileSync(candidate);
690
- if (TAILWIND_V4_IMPORT_REGEX.test(content)) v4Matches.push(candidate);
691
- } catch {}
692
- if (v4Matches.length > 0) return sortCssCandidates(cwd, v4Matches)[0];
693
- const v3Recursive = await (0, tinyglobby.glob)(V3_CONFIG_PATHS.map((p) => `**/${p}`), {
694
- cwd,
720
+ const isPackageJson = (file) => node_path.basename(file) === "package.json";
721
+ const packageRoots = await findPackageRoots(root, files.filter(isPackageJson).map(node_path.dirname));
722
+ const deepestFirst = [...packageRoots].sort((a, b) => b.length - a.length);
723
+ const candidatesByRoot = new Map(packageRoots.map((packageRoot) => [packageRoot, []]));
724
+ for (const file of files) {
725
+ if (isPackageJson(file)) continue;
726
+ const owner = deepestFirst.find((packageRoot) => isInsideDir(packageRoot, file));
727
+ if (owner) candidatesByRoot.get(owner)?.push(file);
728
+ }
729
+ return {
730
+ targets: (await Promise.all([...candidatesByRoot].map(([packageRoot, candidates]) => pickConfig(packageRoot, candidates)))).filter((target) => target !== void 0),
731
+ packageRoots
732
+ };
733
+ }
734
+ async function findPackageRoots(root, packageDirs) {
735
+ const workspaces = await readWorkspacePatterns(root);
736
+ if (!workspaces) return [.../* @__PURE__ */ new Set([root, ...packageDirs])];
737
+ const toPackageJson = (pattern) => `${pattern.replace(/\/+$/, "")}/package.json`;
738
+ const workspacePackageJsons = await (0, tinyglobby.glob)(workspaces.filter((p) => !p.startsWith("!")).map(toPackageJson), {
739
+ cwd: root,
695
740
  absolute: true,
696
- ignore: DEFAULT_IGNORE_PATTERNS,
697
- deep: CONFIG_DISCOVERY_MAX_DEPTH
741
+ ignore: [...DEFAULT_IGNORE_PATTERNS, ...workspaces.filter((p) => p.startsWith("!")).map((p) => toPackageJson(p.slice(1)))]
698
742
  });
699
- if (v3Recursive.length > 0) return sortByPathDepth(v3Recursive)[0];
700
- const viteConfigPath = await findTailwindViteConfigPath(cwd);
701
- if (viteConfigPath) return syntheticViteCssConfigPath(viteConfigPath);
702
- return null;
703
- }
704
- async function findTailwindViteConfigPath(cwd) {
705
- for (const p of VITE_CONFIG_PATHS) {
706
- const fullPath = node_path.join(cwd, p);
707
- if (isTailwindViteConfig(fullPath)) return fullPath;
743
+ return [.../* @__PURE__ */ new Set([root, ...workspacePackageJsons.map(node_path.dirname)])];
744
+ }
745
+ async function readWorkspacePatterns(root) {
746
+ const [packageJson, pnpmWorkspace] = await Promise.all([readText(node_path.join(root, "package.json")), readText(node_path.join(root, "pnpm-workspace.yaml"))]);
747
+ const patterns = [...parsePackageJsonWorkspaces(packageJson), ...parsePnpmWorkspacePackages(pnpmWorkspace)];
748
+ return patterns.length > 0 ? patterns : void 0;
749
+ }
750
+ function parsePackageJsonWorkspaces(content) {
751
+ try {
752
+ const { workspaces } = JSON.parse(content);
753
+ return ((Array.isArray(workspaces) ? workspaces : workspaces?.packages) ?? []).filter((p) => typeof p === "string");
754
+ } catch {
755
+ return [];
708
756
  }
709
- const matches = (await (0, tinyglobby.glob)(VITE_CONFIG_PATHS.map((p) => `**/${p}`), {
710
- cwd,
711
- absolute: true,
712
- ignore: DEFAULT_IGNORE_PATTERNS,
713
- deep: CONFIG_DISCOVERY_MAX_DEPTH
714
- })).filter(isTailwindViteConfig);
715
- if (matches.length === 0) return null;
716
- return sortByPathDepth(matches)[0];
717
757
  }
718
- function isTailwindViteConfig(filePath) {
719
- if (!fileExists(filePath)) return false;
758
+ function parsePnpmWorkspacePackages(content) {
759
+ const patterns = [];
760
+ let inPackages = false;
761
+ for (const line of content.split(/\r?\n/)) if (/^packages\s*:/.test(line)) inPackages = true;
762
+ else if (/^[^\s#]/.test(line)) inPackages = false;
763
+ else if (inPackages) {
764
+ const item = line.match(/^\s*-\s*["']?([^"'#\s]+)["']?/);
765
+ if (item) patterns.push(item[1]);
766
+ }
767
+ return patterns;
768
+ }
769
+ function nestedRootIgnores(root, roots) {
770
+ return roots.filter((other) => other !== root && isInsideDir(root, other)).map((other) => `${node_path.relative(root, other)}/**`);
771
+ }
772
+ function isInsideDir(dir, filePath) {
773
+ const relative = node_path.relative(dir, filePath);
774
+ return !relative.startsWith("..") && !node_path.isAbsolute(relative);
775
+ }
776
+ async function pickConfig(root, candidates) {
777
+ const target = (kind, configPath) => ({
778
+ kind,
779
+ path: configPath,
780
+ root
781
+ });
782
+ const candidateSet = new Set(candidates);
783
+ const existing = (paths) => paths.map((p) => node_path.join(root, p)).filter((p) => candidateSet.has(p));
784
+ const byName = (names) => candidates.filter((c) => names.includes(node_path.basename(c)));
785
+ const preferredCss = existing(V4_CSS_FOLDERS.flatMap((folder) => V4_CSS_NAMES.map((name) => node_path.join(folder, name))));
786
+ const preferredCssMatch = await findFirstMatch(preferredCss, TAILWIND_V4_IMPORT_REGEX);
787
+ if (preferredCssMatch) return target("css", preferredCssMatch);
788
+ const rootV3 = existing(V3_CONFIG_PATHS)[0];
789
+ if (rootV3) return target("js", rootV3);
790
+ const cssMatch = await findFirstMatch(sortCssCandidates(root, candidates.filter((c) => isCssConfigFile(c) && !preferredCss.includes(c))), TAILWIND_V4_IMPORT_REGEX);
791
+ if (cssMatch) return target("css", cssMatch);
792
+ const nestedV3 = sortByPathDepth(byName(V3_CONFIG_PATHS))[0];
793
+ if (nestedV3) return target("js", nestedV3);
794
+ const viteConfigs = [...existing(VITE_CONFIG_PATHS), ...sortByPathDepth(byName(VITE_CONFIG_PATHS))];
795
+ const viteMatch = await findFirstMatch([...new Set(viteConfigs)], TAILWIND_VITE_PLUGIN_REGEX);
796
+ if (viteMatch) return target("vite", viteMatch);
797
+ }
798
+ async function findFirstMatch(paths, regex) {
799
+ const contents = await Promise.all(paths.map(readText));
800
+ return paths.find((_, index) => regex.test(contents[index]));
801
+ }
802
+ async function readText(filePath) {
720
803
  try {
721
- return TAILWIND_VITE_PLUGIN_REGEX.test(readFileSync(filePath));
804
+ return await (0, node_fs_promises.readFile)(filePath, "utf-8");
722
805
  } catch {
723
- return false;
806
+ return "";
724
807
  }
725
808
  }
726
809
  function sortByPathDepth(paths) {
@@ -758,9 +841,9 @@ function splitDepth(value) {
758
841
  //#endregion
759
842
  //#region src/state.ts
760
843
  const require$1 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href || __filename);
761
- function getTailwindVersion(cwd) {
844
+ function getTailwindVersion(paths) {
762
845
  try {
763
- const tailwindPackageJson = require$1.resolve("tailwindcss/package.json", { paths: [cwd] });
846
+ const tailwindPackageJson = require$1.resolve("tailwindcss/package.json", { paths });
764
847
  const { readFileSync } = require$1("node:fs");
765
848
  return JSON.parse(readFileSync(tailwindPackageJson, "utf-8")).version;
766
849
  } catch {
@@ -770,41 +853,52 @@ function getTailwindVersion(cwd) {
770
853
  function isV4Config(version) {
771
854
  return version?.startsWith("4.") ?? false;
772
855
  }
773
- function resolveTailwindPath(cwd, configDir) {
774
- const paths = configDir ? [configDir, cwd] : [cwd];
856
+ function resolveTailwindPath(paths) {
775
857
  try {
776
858
  return require$1.resolve("tailwindcss", { paths });
777
859
  } catch {
778
860
  throw new Error(`Could not find tailwindcss module in ${paths.join(" or ")}.\nInstall it with: npm install -D tailwindcss`);
779
861
  }
780
862
  }
781
- async function createState(cwd, configPath, verbose = false) {
782
- const resolvedConfigPath = await findTailwindConfigPath(cwd, configPath);
783
- 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.");
784
- const isCssConfig = isCssConfigFile(resolvedConfigPath);
785
- const tailwindPath = resolveTailwindPath(cwd, node_path.dirname(resolvedConfigPath));
786
- const tailwindcss = require$1(tailwindPath);
787
- const version = getTailwindVersion(cwd);
863
+ function loadResolveConfig(paths) {
864
+ try {
865
+ const module = require$1(require$1.resolve("tailwindcss/resolveConfig", { paths }));
866
+ return typeof module === "function" ? module : module.default;
867
+ } catch {
868
+ return;
869
+ }
870
+ }
871
+ const CONFIG_TYPE_LABELS = {
872
+ css: "CSS (v4)",
873
+ vite: "Vite (v4)",
874
+ js: "JavaScript"
875
+ };
876
+ async function createState(cwd, target, verbose = false) {
877
+ const isCssConfig = target.kind !== "js";
878
+ const resolvePaths = [node_path.dirname(target.path), cwd];
879
+ resolveTailwindPath(resolvePaths);
880
+ const version = getTailwindVersion(resolvePaths);
788
881
  const isV4 = isV4Config(version);
789
882
  if (verbose) {
790
883
  console.log(ansis.default.cyan.bold("→ Tailwind Configuration"));
791
884
  console.log(ansis.default.dim(` Version: ${version || "unknown"}`));
792
- console.log(ansis.default.dim(` Config type: ${isCssConfig ? "CSS (v4)" : "JavaScript"}`));
793
- console.log(ansis.default.dim(` Config path: ${resolvedConfigPath}`));
885
+ console.log(ansis.default.dim(` Config type: ${CONFIG_TYPE_LABELS[target.kind]}`));
886
+ console.log(ansis.default.dim(` Config path: ${target.path}`));
794
887
  }
795
888
  let config = {};
796
889
  let resolvedConfig = { separator: ":" };
797
890
  if (!isCssConfig) {
798
- config = await loadTailwindConfig(resolvedConfigPath);
891
+ config = await loadTailwindConfig(target.path);
799
892
  resolvedConfig = {
800
893
  ...config,
801
894
  separator: config.separator ?? ":"
802
895
  };
803
- if (tailwindcss.resolveConfig) resolvedConfig = tailwindcss.resolveConfig(config);
896
+ const resolveConfig = loadResolveConfig(resolvePaths);
897
+ if (resolveConfig) resolvedConfig = resolveConfig(config);
804
898
  }
805
899
  const state = {
806
900
  enabled: true,
807
- configPath: resolvedConfigPath,
901
+ configPath: target.path,
808
902
  config: resolvedConfig,
809
903
  version,
810
904
  v4: isV4 || void 0,
@@ -818,14 +912,15 @@ async function createState(cwd, configPath, verbose = false) {
818
912
  editor: createEditorState(cwd),
819
913
  features: ["diagnostics"]
820
914
  };
821
- if (isV4 || isCssConfig) await loadV4DesignSystem(state, cwd, resolvedConfigPath, verbose);
822
- else await loadV3ClassMetadata(state, cwd, verbose);
915
+ if (isV4 || isCssConfig) await loadV4DesignSystem(state, resolvePaths, target, verbose);
916
+ else await loadV3ClassMetadata(state, resolvePaths, verbose);
823
917
  return state;
824
918
  }
825
919
  //#endregion
826
920
  //#region src/linter.ts
827
921
  const SOURCE_FILE_PATTERN = "**/*.{js,jsx,ts,tsx,html,vue,svelte,astro,mdx}";
828
922
  const GLOB_PATTERN_REGEX = /[*?[\]{}]/;
923
+ const MAX_LISTED_PACKAGES = 10;
829
924
  async function validateDocument(state, filePath, content) {
830
925
  try {
831
926
  if (!state) throw new Error("State is not initialized");
@@ -833,7 +928,8 @@ async function validateDocument(state, filePath, content) {
833
928
  if (!state.v4 && !state.modules?.tailwindcss) throw new Error("Tailwind modules not initialized for Tailwind v3. This might indicate a configuration issue.");
834
929
  const languageId = getLanguageId(filePath);
835
930
  const uri = `file://${filePath}`;
836
- return await (0, _tailwindcss_language_service.doValidate)(state, vscode_languageserver_textdocument.TextDocument.create(uri, languageId, 1, content));
931
+ const document = vscode_languageserver_textdocument.TextDocument.create(uri, languageId, 1, content);
932
+ return await (0, _tailwindcss_language_service.doValidate)(state, document);
837
933
  } catch (error) {
838
934
  const message = error instanceof Error ? error.message : String(error);
839
935
  if (message.includes("Cannot read") || message.includes("undefined")) {
@@ -844,52 +940,43 @@ async function validateDocument(state, filePath, content) {
844
940
  throw new Error(`Failed to validate document ${filePath}: ${message}`);
845
941
  }
846
942
  }
847
- async function discoverFiles(cwd, patterns, configPath, autoDiscover) {
848
- if (autoDiscover) return discoverFilesFromConfig(cwd, configPath);
849
- return expandPatterns(cwd, patterns);
850
- }
851
943
  async function expandPatterns(cwd, patterns, extraIgnore = []) {
852
- const files = await (0, tinyglobby.glob)(patterns, {
944
+ return (0, tinyglobby.glob)(patterns, {
853
945
  cwd,
854
- absolute: false,
946
+ absolute: true,
855
947
  ignore: [...DEFAULT_IGNORE_PATTERNS, ...extraIgnore]
856
948
  });
857
- return [...new Set(files)].sort((a, b) => a.localeCompare(b));
858
- }
859
- async function discoverFilesFromConfig(cwd, configPath) {
860
- const configFilePath = await findTailwindConfigPath(cwd, configPath);
861
- if (!configFilePath) throw new Error("Could not find Tailwind config for auto-discovery.\nUse --config to specify the path, or provide file patterns directly.");
862
- const discoveryCwd = isCssConfigFile(configFilePath) ? findProjectRoot(node_path.dirname(configFilePath)) : cwd;
863
- if (!isCssConfigFile(configFilePath)) {
864
- const config = await loadTailwindConfig(configFilePath);
949
+ }
950
+ async function discoverFilesFromConfig(target, configRoots) {
951
+ if (target.kind === "js") {
952
+ const config = await loadTailwindConfig(target.path);
865
953
  if (!config || !config.content) throw new Error("Tailwind config is missing the 'content' property.\nAdd a content array to specify which files to scan:\n content: ['./src/**/*.{js,jsx,ts,tsx}']");
866
954
  const patterns = extractContentPatterns(config);
867
955
  if (patterns.length === 0) throw new Error("No content patterns found in Tailwind config.\nEnsure your config has a content array with file patterns.");
868
- return expandPatterns(discoveryCwd, patterns);
956
+ return expandPatterns(!Array.isArray(config.content) && config.content.relative === true ? node_path.dirname(target.path) : target.root, patterns);
869
957
  }
870
- const configDir = node_path.dirname(configFilePath);
871
- const cssContent = fileExists(configFilePath) ? readFileSync(configFilePath) : SYNTHETIC_VITE_CSS_CONFIG_CONTENT;
872
- const includeConfigFile = (files) => {
873
- if (!fileExists(configFilePath)) return files;
874
- const relativeConfigPath = node_path.relative(discoveryCwd, configFilePath);
875
- return [.../* @__PURE__ */ new Set([relativeConfigPath, ...files])].sort((a, b) => a.localeCompare(b));
876
- };
877
- const resolveDiscoveredFiles = (files) => discoveryCwd === cwd ? files : files.map((file) => node_path.resolve(discoveryCwd, file)).sort((a, b) => a.localeCompare(b));
958
+ const { root } = target;
959
+ const configDir = node_path.dirname(target.path);
960
+ const cssContent = target.kind === "vite" ? SYNTHETIC_VITE_CSS_CONFIG_CONTENT : readFileSync(target.path);
878
961
  const { include, exclude } = extractSourcePatterns(cssContent);
879
962
  const importSource = extractImportSourceDirectives(cssContent);
880
- const resolveFromConfig = (pattern) => {
881
- const absolutePattern = node_path.resolve(configDir, pattern);
882
- return node_path.relative(discoveryCwd, absolutePattern);
883
- };
963
+ const resolveFromConfig = (pattern) => node_path.relative(root, node_path.resolve(configDir, pattern));
884
964
  const resolvedExclude = exclude.map(resolveFromConfig);
885
- const gitignorePatterns = readGitignorePatterns(discoveryCwd);
886
- const extraIgnore = [...resolvedExclude, ...gitignorePatterns];
965
+ const extraIgnore = [
966
+ ...resolvedExclude,
967
+ ...readGitignorePatterns(root),
968
+ ...nestedRootIgnores(root, configRoots)
969
+ ];
887
970
  const explicitSourcePatterns = include.map((source) => resolveFromConfig(normalizeSourcePattern(source)));
888
971
  let autoPatterns = [];
889
- if (!importSource.disableAutoSource) autoPatterns = importSource.roots.length > 0 ? importSource.roots.map((root) => resolveFromConfig(normalizeSourcePattern(root))) : [DEFAULT_FILE_PATTERN];
890
- const autoFiles = autoPatterns.length > 0 ? await expandPatterns(discoveryCwd, autoPatterns, extraIgnore) : [];
891
- const explicitFiles = explicitSourcePatterns.length > 0 ? await expandPatterns(discoveryCwd, explicitSourcePatterns, resolvedExclude) : [];
892
- return resolveDiscoveredFiles(includeConfigFile([.../* @__PURE__ */ new Set([...autoFiles, ...explicitFiles])].sort((a, b) => a.localeCompare(b))));
972
+ if (!importSource.disableAutoSource) autoPatterns = importSource.roots.length > 0 ? importSource.roots.map((sourceRoot) => resolveFromConfig(normalizeSourcePattern(sourceRoot))) : [DEFAULT_FILE_PATTERN];
973
+ const [autoFiles, explicitFiles] = await Promise.all([autoPatterns.length > 0 ? expandPatterns(root, autoPatterns, extraIgnore) : [], explicitSourcePatterns.length > 0 ? expandPatterns(root, explicitSourcePatterns, resolvedExclude) : []]);
974
+ const configFile = target.kind === "css" ? [target.path] : [];
975
+ return [.../* @__PURE__ */ new Set([
976
+ ...configFile,
977
+ ...autoFiles,
978
+ ...explicitFiles
979
+ ])];
893
980
  }
894
981
  function normalizeSourcePattern(pattern) {
895
982
  if (GLOB_PATTERN_REGEX.test(pattern) || node_path.extname(pattern)) return pattern;
@@ -965,9 +1052,9 @@ async function processFile(state, cwd, filePath, fix) {
965
1052
  fixedCount
966
1053
  };
967
1054
  }
968
- async function initializeState(cwd, configPath, verbose = false) {
1055
+ async function initializeState(cwd, target, verbose = false) {
969
1056
  try {
970
- const state = await createState(cwd, configPath, verbose);
1057
+ const state = await createState(cwd, target, verbose);
971
1058
  if (verbose) console.log();
972
1059
  return state;
973
1060
  } catch (error) {
@@ -976,42 +1063,80 @@ async function initializeState(cwd, configPath, verbose = false) {
976
1063
  }
977
1064
  }
978
1065
  async function lint({ cwd, patterns, configPath, autoDiscover, fix = false, verbose = false, onProgress }) {
979
- const state = await initializeState(cwd, configPath, verbose);
980
- const discoveredFiles = await discoverFiles(cwd, patterns, configPath, autoDiscover);
981
- const files = uniqueFilesByResolvedPath(cwd, state.configPath && isCssConfigFile(state.configPath) && fileExists(state.configPath) ? [node_path.relative(cwd, state.configPath), ...discoveredFiles] : discoveredFiles);
1066
+ const targets = await resolveConfigTargets(cwd, configPath);
1067
+ if (verbose) logTargets(cwd, targets);
1068
+ const configRoots = targets.map((target) => target.root);
1069
+ const patternFiles = autoDiscover ? [] : await expandPatterns(cwd, patterns);
1070
+ const discoveredFilesByTarget = await Promise.all(targets.map((target) => autoDiscover ? discoverFilesFromConfig(target, configRoots) : patternFiles));
1071
+ const owners = /* @__PURE__ */ new Map();
1072
+ for (const [index, target] of targets.entries()) {
1073
+ const files = target.kind === "css" && !autoDiscover ? [target.path, ...discoveredFilesByTarget[index]] : discoveredFilesByTarget[index];
1074
+ for (const file of files) {
1075
+ const current = owners.get(file);
1076
+ if (!current || ownershipScore(target, file) > ownershipScore(current, file)) owners.set(file, target);
1077
+ }
1078
+ }
982
1079
  const skippedFiles = [];
983
- const lintableFiles = files.filter((file) => {
984
- if (getFileSize(node_path.isAbsolute(file) ? file : node_path.resolve(cwd, file)) > 524288) {
1080
+ const filesByTarget = /* @__PURE__ */ new Map();
1081
+ for (const [absolutePath, target] of owners) {
1082
+ const file = node_path.relative(cwd, absolutePath);
1083
+ if (getFileSize(absolutePath) > 524288) {
985
1084
  skippedFiles.push(file);
986
- return false;
1085
+ continue;
987
1086
  }
988
- return true;
989
- });
1087
+ const files = filesByTarget.get(target) ?? [];
1088
+ files.push(file);
1089
+ filesByTarget.set(target, files);
1090
+ }
1091
+ const totalFiles = owners.size - skippedFiles.length;
990
1092
  if (verbose) {
991
- console.log(ansis.default.cyan.bold(`→ Discovered ${lintableFiles.length} file${lintableFiles.length !== 1 ? "s" : ""} to lint`));
1093
+ console.log(ansis.default.cyan.bold(`→ Discovered ${totalFiles} file${totalFiles !== 1 ? "s" : ""} to lint`));
992
1094
  console.log();
993
1095
  }
994
- if (lintableFiles.length === 0) return {
995
- files: [],
996
- totalFilesProcessed: 0,
997
- skippedFiles
998
- };
1096
+ const results = [];
1097
+ let processedCount = 0;
1098
+ for (const target of targets) {
1099
+ const files = filesByTarget.get(target);
1100
+ if (!files) continue;
1101
+ const offset = processedCount;
1102
+ processedCount += files.length;
1103
+ const processed = await processFiles(await initializeState(cwd, target, verbose), cwd, files.sort((a, b) => a.localeCompare(b)), fix, onProgress && ((current, _total, file) => onProgress(offset + current, totalFiles, file)));
1104
+ results.push(...processed);
1105
+ }
999
1106
  return {
1000
- files: (await processFiles(state, cwd, lintableFiles, fix, onProgress)).filter((result) => result.diagnostics.length > 0 || result.fixed),
1001
- totalFilesProcessed: lintableFiles.length,
1002
- skippedFiles
1107
+ files: results.filter((result) => result.diagnostics.length > 0 || result.fixed).sort((a, b) => a.path.localeCompare(b.path)),
1108
+ totalFilesProcessed: totalFiles,
1109
+ skippedFiles: skippedFiles.sort((a, b) => a.localeCompare(b))
1003
1110
  };
1004
1111
  }
1005
- function uniqueFilesByResolvedPath(cwd, files) {
1006
- const seen = /* @__PURE__ */ new Set();
1007
- const unique = [];
1008
- for (const file of files) {
1009
- const absolutePath = node_path.isAbsolute(file) ? file : node_path.resolve(cwd, file);
1010
- if (seen.has(absolutePath)) continue;
1011
- seen.add(absolutePath);
1012
- unique.push(file);
1112
+ async function resolveConfigTargets(cwd, configPath) {
1113
+ if (configPath) {
1114
+ const absolutePath = node_path.resolve(cwd, configPath);
1115
+ if (!fileExists(absolutePath)) throw new Error(`Tailwind config file not found: ${absolutePath}`);
1116
+ return [toConfigTarget(absolutePath)];
1013
1117
  }
1014
- return unique.sort((a, b) => a.localeCompare(b));
1118
+ const { targets, packageRoots } = await findTailwindConfigs(cwd);
1119
+ if (targets.length === 0) throw new Error(noConfigMessage(cwd, packageRoots));
1120
+ return targets;
1121
+ }
1122
+ function noConfigMessage(cwd, packageRoots) {
1123
+ const packages = packageRoots.map((root) => node_path.relative(cwd, root)).filter(Boolean).sort((a, b) => a.localeCompare(b));
1124
+ const shown = packages.slice(0, MAX_LISTED_PACKAGES);
1125
+ const more = packages.length - shown.length;
1126
+ return `Could not find a Tailwind config in ${cwd}${packages.length > 0 ? ` or its packages:\n${shown.map((p) => ` • ${p}`).join("\n")}${more > 0 ? `\n …and ${more} more` : ""}` : ""}\nExpected one of:
1127
+ • Tailwind v4 (CSS): a CSS file with @import "tailwindcss", e.g. app.css or src/index.css
1128
+ • Tailwind v4 (Vite): vite.config.* with @tailwindcss/vite
1129
+ • Tailwind v3 (JS): tailwind.config.js, tailwind.config.ts
1130
+ Use --config to specify the path.`;
1131
+ }
1132
+ function logTargets(cwd, targets) {
1133
+ const display = (p) => node_path.relative(cwd, p) || ".";
1134
+ console.log(ansis.default.cyan.bold("→ Tailwind configs"));
1135
+ for (const target of targets) console.log(ansis.default.dim(` ${display(target.root)} → ${display(target.path)}`));
1136
+ console.log();
1137
+ }
1138
+ function ownershipScore(target, absolutePath) {
1139
+ return isInsideDir(target.root, absolutePath) ? target.root.length : -1;
1015
1140
  }
1016
1141
  //#endregion
1017
1142
  Object.defineProperty(exports, "DEFAULT_FILE_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-BP0uKBfa.cjs");
2
+ const require_linter = require("./linter-B-Bi_uRJ.cjs");
3
3
  exports.extractImportSourceDirectives = require_linter.extractImportSourceDirectives;
4
4
  exports.extractSourcePatterns = require_linter.extractSourcePatterns;
5
5
  exports.lint = require_linter.lint;
package/dist/linter.d.cts CHANGED
@@ -383,6 +383,6 @@ declare function extractImportSourceDirectives(cssContent: string): {
383
383
  roots: string[];
384
384
  disableAutoSource: boolean;
385
385
  };
386
- declare function lint({ cwd, patterns, configPath, autoDiscover, fix, verbose, onProgress }: LintOptions): Promise<LintResult>;
386
+ export declare function lint({ cwd, patterns, configPath, autoDiscover, fix, verbose, onProgress }: LintOptions): Promise<LintResult>;
387
387
  //#endregion
388
- export { type LintFileResult, type LintOptions, type LintResult, extractImportSourceDirectives, extractSourcePatterns, lint };
388
+ export { type LintFileResult, type LintOptions, type LintResult, extractImportSourceDirectives, extractSourcePatterns };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tailwind-lint",
3
- "version": "0.12.1",
3
+ "version": "0.13.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",
@@ -58,24 +58,25 @@
58
58
  "test:watch": "vitest"
59
59
  },
60
60
  "dependencies": {
61
- "@tailwindcss/language-service": "^0.14.29",
62
- "ansis": "^4.3.1",
61
+ "@tailwindcss/language-service": "^0.16.0",
62
+ "ansis": "^4.4.0",
63
63
  "commander": "^15.0.0",
64
- "postcss": "^8.5.19",
64
+ "postcss": "^8.5.28",
65
65
  "tinyglobby": "^0.2.17",
66
- "vscode-languageserver-textdocument": "^1.0.12"
66
+ "vscode-languageserver-textdocument": "^1.0.15"
67
67
  },
68
68
  "devDependencies": {
69
- "@types/node": "^26.1.1",
70
- "oxfmt": "^0.58.0",
71
- "oxlint": "^1.73.0",
72
- "tsdown": "^0.22.7",
69
+ "@types/node": "^26.6.4",
70
+ "oxfmt": "^0.71.0",
71
+ "oxlint": "^1.86.0",
72
+ "tsdown": "^0.23.0",
73
73
  "typescript": "^7.0.2",
74
- "vitest": "^4.1.10"
74
+ "vitest": "^5.0.3",
75
+ "vscode-languageserver": "8.1.0"
75
76
  },
76
77
  "engines": {
77
78
  "node": ">=22.0.0",
78
79
  "pnpm": ">=10.0.0"
79
80
  },
80
- "packageManager": "pnpm@11.13.0"
81
+ "packageManager": "pnpm@12.8.1"
81
82
  }