tailwind-lint 0.12.0 → 0.13.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
@@ -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-DQMo7IYe.cjs");
2
+ const require_linter = require("./linter-gjoSGNMw.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));
@@ -32,6 +32,7 @@ let node_fs = require("node:fs");
32
32
  node_fs = __toESM(node_fs, 1);
33
33
  let postcss = require("postcss");
34
34
  postcss = __toESM(postcss, 1);
35
+ let node_fs_promises = require("node:fs/promises");
35
36
  //#region src/constants.ts
36
37
  const DEFAULT_IGNORE_PATTERNS = [
37
38
  "**/node_modules/**",
@@ -90,7 +91,6 @@ const VITE_CONFIG_PATHS = [
90
91
  "vite.config.mts",
91
92
  "vite.config.cts"
92
93
  ];
93
- const SYNTHETIC_VITE_CSS_CONFIG_NAME = ".tailwind-lint.vite.css";
94
94
  const SYNTHETIC_VITE_CSS_CONFIG_CONTENT = "@import \"tailwindcss\";";
95
95
  const LANGUAGE_MAP = {
96
96
  ".astro": "astro",
@@ -121,7 +121,8 @@ const SEVERITY = {
121
121
  const TAILWIND_V4_IMPORT_REGEX = /@import\s+["']tailwindcss(?:["'\s/]|$)/;
122
122
  const TAILWIND_VITE_PLUGIN_REGEX = /(?:from\s+["']@tailwindcss\/vite["']|require\(\s*["']@tailwindcss\/vite["']\s*\)|import\(\s*["']@tailwindcss\/vite["']\s*\))/;
123
123
  function getLanguageId(filePath) {
124
- return LANGUAGE_MAP[filePath.substring(filePath.lastIndexOf(".")).toLowerCase()] || "html";
124
+ const ext = filePath.substring(filePath.lastIndexOf(".")).toLowerCase();
125
+ return LANGUAGE_MAP[ext] || "html";
125
126
  }
126
127
  //#endregion
127
128
  //#region src/code-actions.ts
@@ -133,7 +134,7 @@ async function getQuickfixes(state, document, uri, diagnostics) {
133
134
  code: diag.code,
134
135
  source: diag.source || "tailwindcss"
135
136
  }));
136
- return (await (0, _tailwindcss_language_service.doCodeActions)(state, {
137
+ const params = {
137
138
  textDocument: { uri },
138
139
  range: {
139
140
  start: {
@@ -146,7 +147,8 @@ async function getQuickfixes(state, document, uri, diagnostics) {
146
147
  }
147
148
  },
148
149
  context: { diagnostics: lspDiagnostics }
149
- }, document)).filter((action) => action.kind === "quickfix" || action.kind?.startsWith(`quickfix.`));
150
+ };
151
+ return (await (0, _tailwindcss_language_service.doCodeActions)(state, params, document)).filter((action) => action.kind === "quickfix" || action.kind?.startsWith(`quickfix.`));
150
152
  }
151
153
  function applyFirstQuickfix(action, uri, document, content) {
152
154
  if (!action.edit?.changes?.[uri]) return null;
@@ -256,7 +258,7 @@ function readVsCodeTailwindSettings(cwd) {
256
258
  const files = readNestedObject(raw, "tailwindCSS.files");
257
259
  const lint = readNestedObject(raw, "tailwindCSS.lint");
258
260
  return {
259
- includeLanguages: asRecord(raw["tailwindCSS.includeLanguages"]),
261
+ includeLanguages: asStringRecord(raw["tailwindCSS.includeLanguages"]),
260
262
  classAttributes: asStringArray(raw["tailwindCSS.classAttributes"]),
261
263
  classFunctions: asStringArray(raw["tailwindCSS.classFunctions"]),
262
264
  experimental: {
@@ -274,7 +276,7 @@ function readZedTailwindSettings(cwd) {
274
276
  const normalized = asRecord(serverSettings?.tailwindCSS) ?? serverSettings;
275
277
  if (!normalized) return {};
276
278
  return {
277
- includeLanguages: asRecord(normalized.includeLanguages),
279
+ includeLanguages: asStringRecord(normalized.includeLanguages),
278
280
  classAttributes: asStringArray(normalized.classAttributes),
279
281
  classFunctions: asStringArray(normalized.classFunctions),
280
282
  experimental: {
@@ -302,6 +304,11 @@ function readNestedObject(input, key) {
302
304
  function asRecord(value) {
303
305
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
304
306
  }
307
+ function asStringRecord(value) {
308
+ const record = asRecord(value);
309
+ if (!record) return;
310
+ return Object.fromEntries(Object.entries(record).filter((entry) => typeof entry[1] === "string"));
311
+ }
305
312
  function asStringArray(value) {
306
313
  return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : void 0;
307
314
  }
@@ -439,6 +446,7 @@ function createEditorState(cwd) {
439
446
  invalidApply: "error",
440
447
  invalidScreen: "error",
441
448
  invalidVariant: "error",
449
+ deprecatedAtRule: "warning",
442
450
  invalidConfigPath: "error",
443
451
  invalidTailwindDirective: "error",
444
452
  invalidSourceDirective: "error",
@@ -455,6 +463,7 @@ function createEditorState(cwd) {
455
463
  capabilities: {
456
464
  configuration: true,
457
465
  diagnosticRelatedInformation: true,
466
+ diagnosticTagSupport: false,
458
467
  itemDefaults: []
459
468
  },
460
469
  getConfiguration: async () => settings,
@@ -486,49 +495,40 @@ var AdapterLoadError = class extends Error {
486
495
  //#endregion
487
496
  //#region src/adapters/v3-adapter.ts
488
497
  const require$4 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href || __filename);
489
- async function loadV3ClassMetadata(state, cwd, verbose = false) {
498
+ function interopDefault(module) {
499
+ return module && typeof module === "object" && "default" in module ? module.default : module;
500
+ }
501
+ async function loadV3ClassMetadata(state, resolvePaths, verbose = false) {
490
502
  try {
491
- const tailwindcss = require$4(require$4.resolve("tailwindcss", { paths: [cwd] }));
492
- try {
493
- const tailwindDir = node_path.dirname(require$4.resolve("tailwindcss/package.json", { paths: [cwd] }));
494
- const contextUtils = require$4(node_path.join(tailwindDir, "lib", "lib", "setupContextUtils"));
495
- const generateRulesModule = require$4(node_path.join(tailwindDir, "lib", "lib", "generateRules"));
496
- state.modules = {
497
- tailwindcss: {
498
- version: state.version || "unknown",
499
- module: tailwindcss
500
- },
501
- jit: {
502
- generateRules: { module: generateRulesModule.generateRules || ((_set, _context) => []) },
503
- createContext: { module: contextUtils.createContext },
504
- expandApplyAtRules: { module: generateRulesModule.expandApplyAtRules }
505
- }
506
- };
507
- if (verbose) console.log(ansis.default.dim(" ✓ Loaded v3 JIT modules"));
508
- } catch (jitError) {
509
- if (verbose) {
510
- const message = jitError instanceof Error ? jitError.message : String(jitError);
511
- console.log(ansis.default.yellow(` ⚠ Warning: Could not load v3 JIT modules: ${message}`));
512
- }
513
- state.modules = { tailwindcss: {
503
+ const tailwindDir = node_path.dirname(require$4.resolve("tailwindcss/package.json", { paths: resolvePaths }));
504
+ const load = (id) => require$4(require$4.resolve(id, { paths: [tailwindDir] }));
505
+ const loadLib = (name) => require$4(node_path.join(tailwindDir, "lib", "lib", name));
506
+ const { createContext } = loadLib("setupContextUtils");
507
+ const { generateRules } = loadLib("generateRules");
508
+ state.jit = true;
509
+ state.modules = {
510
+ tailwindcss: {
514
511
  version: state.version || "unknown",
515
- module: tailwindcss
516
- } };
517
- }
518
- extractConfigMetadata(state);
519
- if (!state.classNames) state.classNames = {
520
- context: {},
521
- classNames: {}
522
- };
523
- if (state.modules?.jit?.createContext && state.config) try {
524
- state.jitContext = state.modules.jit.createContext.module(state.config);
525
- if (verbose) console.log(ansis.default.dim(" ✓ Created JIT context"));
526
- } catch (contextError) {
527
- if (verbose) {
528
- const message = contextError instanceof Error ? contextError.message : String(contextError);
529
- console.log(ansis.default.yellow(` ⚠ Warning: Could not create JIT context: ${message}`));
512
+ module: load("tailwindcss")
513
+ },
514
+ postcss: {
515
+ version: load("postcss/package.json").version,
516
+ module: load("postcss")
517
+ },
518
+ postcssSelectorParser: { module: load("postcss-selector-parser") },
519
+ jit: {
520
+ generateRules: { module: generateRules },
521
+ createContext: { module: createContext },
522
+ expandApplyAtRules: { module: interopDefault(loadLib("expandApplyAtRules")) },
523
+ evaluateTailwindFunctions: { module: interopDefault(loadLib("evaluateTailwindFunctions")) }
530
524
  }
531
- }
525
+ };
526
+ extractConfigMetadata(state);
527
+ const jitContext = createContext(state.config);
528
+ state.jitContext = jitContext;
529
+ state.classList = jitContext.getClassList?.({ includeMetadata: true });
530
+ state.variants = jitContext.getVariants?.() ?? [];
531
+ if (verbose) console.log(ansis.default.dim(" ✓ Created v3 JIT context"));
532
532
  } catch (error) {
533
533
  if (error instanceof Error) throw new AdapterLoadError("v3", error);
534
534
  throw new Error(`Failed to load v3 class metadata: ${String(error)}`);
@@ -540,32 +540,50 @@ function extractConfigMetadata(state) {
540
540
  const theme = config.theme;
541
541
  state.screens = Object.keys(theme?.screens ?? {});
542
542
  state.blocklist = config.blocklist ?? [];
543
- if (config.variants && typeof config.variants === "object") state.variants = Object.keys(config.variants).map((name) => ({
544
- name,
545
- values: [],
546
- isArbitrary: false,
547
- hasDash: true,
548
- selectors: () => []
549
- }));
550
543
  if (config.corePlugins) state.corePlugins = Array.isArray(config.corePlugins) ? config.corePlugins : Object.keys(config.corePlugins);
551
544
  }
552
545
  //#endregion
553
546
  //#region src/adapters/v4-adapter.ts
554
547
  const require$3 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href || __filename);
555
- async function loadV4DesignSystem(state, cwd, configPath, verbose = false) {
548
+ function fromPostcss(nodes) {
549
+ return nodes.map((node) => {
550
+ switch (node.type) {
551
+ case "rule": return {
552
+ kind: "rule",
553
+ selector: node.selector,
554
+ nodes: fromPostcss(node.nodes)
555
+ };
556
+ case "atrule": return {
557
+ kind: "at-rule",
558
+ name: node.name,
559
+ params: node.params,
560
+ nodes: node.nodes ? fromPostcss(node.nodes) : null
561
+ };
562
+ case "decl": return {
563
+ kind: "declaration",
564
+ property: node.prop,
565
+ value: node.value,
566
+ important: node.important
567
+ };
568
+ default: return {
569
+ kind: "comment",
570
+ value: node.text
571
+ };
572
+ }
573
+ });
574
+ }
575
+ async function loadV4DesignSystem(state, resolvePaths, target, verbose = false) {
556
576
  try {
557
- const tailwindcss = require$3(require$3.resolve("tailwindcss", { paths: [cwd] }));
577
+ const tailwindPath = require$3.resolve("tailwindcss", { paths: resolvePaths });
578
+ const tailwindcss = require$3(tailwindPath);
558
579
  if (tailwindcss !== null && tailwindcss !== void 0 && (typeof tailwindcss === "object" || typeof tailwindcss === "function") && "__unstable__loadDesignSystem" in tailwindcss && typeof tailwindcss.__unstable__loadDesignSystem === "function") {
559
- let cssContent;
560
- const basePath = node_path.dirname(configPath);
561
- if (fileExists(configPath)) cssContent = readFileSync(configPath);
562
- else cssContent = SYNTHETIC_VITE_CSS_CONFIG_CONTENT;
580
+ const cssContent = target.kind === "vite" ? SYNTHETIC_VITE_CSS_CONFIG_CONTENT : readFileSync(target.path);
563
581
  const loadDesignSystem = tailwindcss.__unstable__loadDesignSystem;
564
582
  const designSystem = await loadDesignSystem(cssContent, {
565
- base: basePath,
583
+ base: node_path.dirname(target.path),
566
584
  async loadModule(id, base, _type) {
567
585
  try {
568
- const modulePath = require$3.resolve(id, { paths: [base, cwd] });
586
+ const modulePath = require$3.resolve(id, { paths: [base, ...resolvePaths] });
569
587
  const module = require$3(modulePath);
570
588
  return {
571
589
  base: node_path.dirname(modulePath),
@@ -581,7 +599,7 @@ async function loadV4DesignSystem(state, cwd, configPath, verbose = false) {
581
599
  content
582
600
  };
583
601
  if (!_id.startsWith(".") && !_id.startsWith("/")) try {
584
- const pkgJsonPath = require$3.resolve(`${_id}/package.json`, { paths: [base, cwd] });
602
+ const pkgJsonPath = require$3.resolve(`${_id}/package.json`, { paths: [base, ...resolvePaths] });
585
603
  const pkgDir = node_path.dirname(pkgJsonPath);
586
604
  const cssPath = node_path.join(pkgDir, "index.css");
587
605
  if (fileExists(cssPath)) return {
@@ -603,15 +621,16 @@ async function loadV4DesignSystem(state, cwd, configPath, verbose = false) {
603
621
  Object.assign(designSystem, {
604
622
  dependencies: () => /* @__PURE__ */ new Set(),
605
623
  compile(classes) {
606
- if (designSystem.candidatesToCss) return designSystem.candidatesToCss(classes).map((result) => {
607
- if (typeof result === "string" && result.length > 0) try {
608
- return postcss.default.parse(result);
624
+ if (designSystem.candidatesToAst) return designSystem.candidatesToAst(classes);
625
+ if (designSystem.candidatesToCss) return designSystem.candidatesToCss(classes).map((css) => {
626
+ if (!css) return [];
627
+ try {
628
+ return fromPostcss(postcss.default.parse(css).nodes);
609
629
  } catch {
610
- return postcss.default.root();
630
+ return [];
611
631
  }
612
- return postcss.default.root();
613
632
  });
614
- return classes.map(() => postcss.default.root());
633
+ return classes.map(() => []);
615
634
  }
616
635
  });
617
636
  state.designSystem = designSystem;
@@ -629,6 +648,7 @@ async function loadV4DesignSystem(state, cwd, configPath, verbose = false) {
629
648
  const require$2 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href || __filename);
630
649
  const CONFIG_DISCOVERY_MAX_DEPTH = 8;
631
650
  const PROJECT_ROOT_MARKERS = ["package.json", ".git"];
651
+ const VITE_CONFIG_NAME_REGEX = /^vite\.config\.[cm]?[jt]s$/;
632
652
  const isCssConfigFile = (filePath) => filePath.endsWith(".css");
633
653
  function findProjectRoot(startDir) {
634
654
  let current = node_path.resolve(startDir);
@@ -639,9 +659,6 @@ function findProjectRoot(startDir) {
639
659
  current = parent;
640
660
  }
641
661
  }
642
- function syntheticViteCssConfigPath(viteConfigPath) {
643
- return node_path.join(node_path.dirname(viteConfigPath), SYNTHETIC_VITE_CSS_CONFIG_NAME);
644
- }
645
662
  async function loadTailwindConfig(configPath) {
646
663
  if (isCssConfigFile(configPath)) return {};
647
664
  if (!node_path.isAbsolute(configPath)) throw new Error(`Config path must be absolute for security reasons: ${configPath}`);
@@ -658,66 +675,116 @@ async function loadTailwindConfig(configPath) {
658
675
  throw new Error(`Failed to load config from ${configPath}: ${errorMessage}`);
659
676
  }
660
677
  }
661
- async function findTailwindConfigPath(cwd, configPath) {
662
- if (configPath) {
663
- const resolved = node_path.isAbsolute(configPath) ? configPath : node_path.resolve(cwd, configPath);
664
- return fileExists(resolved) ? resolved : null;
665
- }
666
- const v4Paths = V4_CSS_FOLDERS.flatMap((folder) => V4_CSS_NAMES.map((name) => node_path.join(folder, name)));
667
- for (const p of v4Paths) {
668
- const fullPath = node_path.join(cwd, p);
669
- if (fileExists(fullPath)) try {
670
- const content = readFileSync(fullPath);
671
- if (TAILWIND_V4_IMPORT_REGEX.test(content)) return fullPath;
672
- } catch {}
673
- }
674
- for (const p of V3_CONFIG_PATHS) {
675
- const fullPath = node_path.join(cwd, p);
676
- if (fileExists(fullPath)) return fullPath;
677
- }
678
- const cssCandidates = await (0, tinyglobby.glob)("**/*.css", {
679
- cwd,
678
+ function toConfigTarget(configPath) {
679
+ return {
680
+ kind: configKind(configPath),
681
+ path: configPath,
682
+ root: findProjectRoot(node_path.dirname(configPath))
683
+ };
684
+ }
685
+ function configKind(configPath) {
686
+ if (isCssConfigFile(configPath)) return "css";
687
+ return VITE_CONFIG_NAME_REGEX.test(node_path.basename(configPath)) ? "vite" : "js";
688
+ }
689
+ async function findTailwindConfigs(cwd) {
690
+ const root = node_path.resolve(cwd);
691
+ const files = await (0, tinyglobby.glob)([
692
+ "**/package.json",
693
+ "**/*.css",
694
+ ...[...V3_CONFIG_PATHS, ...VITE_CONFIG_PATHS].map((p) => `**/${p}`)
695
+ ], {
696
+ cwd: root,
680
697
  absolute: true,
681
698
  ignore: DEFAULT_IGNORE_PATTERNS,
682
699
  deep: CONFIG_DISCOVERY_MAX_DEPTH
683
700
  });
684
- const v4Matches = [];
685
- for (const candidate of cssCandidates) try {
686
- const content = readFileSync(candidate);
687
- if (TAILWIND_V4_IMPORT_REGEX.test(content)) v4Matches.push(candidate);
688
- } catch {}
689
- if (v4Matches.length > 0) return sortCssCandidates(cwd, v4Matches)[0];
690
- const v3Recursive = await (0, tinyglobby.glob)(V3_CONFIG_PATHS.map((p) => `**/${p}`), {
691
- cwd,
701
+ const isPackageJson = (file) => node_path.basename(file) === "package.json";
702
+ const packageRoots = await findPackageRoots(root, files.filter(isPackageJson).map(node_path.dirname));
703
+ const deepestFirst = [...packageRoots].sort((a, b) => b.length - a.length);
704
+ const candidatesByRoot = new Map(packageRoots.map((packageRoot) => [packageRoot, []]));
705
+ for (const file of files) {
706
+ if (isPackageJson(file)) continue;
707
+ const owner = deepestFirst.find((packageRoot) => isInsideDir(packageRoot, file));
708
+ if (owner) candidatesByRoot.get(owner)?.push(file);
709
+ }
710
+ return {
711
+ targets: (await Promise.all([...candidatesByRoot].map(([packageRoot, candidates]) => pickConfig(packageRoot, candidates)))).filter((target) => target !== void 0),
712
+ packageRoots
713
+ };
714
+ }
715
+ async function findPackageRoots(root, packageDirs) {
716
+ const workspaces = await readWorkspacePatterns(root);
717
+ if (!workspaces) return [.../* @__PURE__ */ new Set([root, ...packageDirs])];
718
+ const toPackageJson = (pattern) => `${pattern.replace(/\/+$/, "")}/package.json`;
719
+ const workspacePackageJsons = await (0, tinyglobby.glob)(workspaces.filter((p) => !p.startsWith("!")).map(toPackageJson), {
720
+ cwd: root,
692
721
  absolute: true,
693
- ignore: DEFAULT_IGNORE_PATTERNS,
694
- deep: CONFIG_DISCOVERY_MAX_DEPTH
722
+ ignore: [...DEFAULT_IGNORE_PATTERNS, ...workspaces.filter((p) => p.startsWith("!")).map((p) => toPackageJson(p.slice(1)))]
695
723
  });
696
- if (v3Recursive.length > 0) return sortByPathDepth(v3Recursive)[0];
697
- const viteConfigPath = await findTailwindViteConfigPath(cwd);
698
- if (viteConfigPath) return syntheticViteCssConfigPath(viteConfigPath);
699
- return null;
700
- }
701
- async function findTailwindViteConfigPath(cwd) {
702
- for (const p of VITE_CONFIG_PATHS) {
703
- const fullPath = node_path.join(cwd, p);
704
- if (isTailwindViteConfig(fullPath)) return fullPath;
724
+ return [.../* @__PURE__ */ new Set([root, ...workspacePackageJsons.map(node_path.dirname)])];
725
+ }
726
+ async function readWorkspacePatterns(root) {
727
+ const [packageJson, pnpmWorkspace] = await Promise.all([readText(node_path.join(root, "package.json")), readText(node_path.join(root, "pnpm-workspace.yaml"))]);
728
+ const patterns = [...parsePackageJsonWorkspaces(packageJson), ...parsePnpmWorkspacePackages(pnpmWorkspace)];
729
+ return patterns.length > 0 ? patterns : void 0;
730
+ }
731
+ function parsePackageJsonWorkspaces(content) {
732
+ try {
733
+ const { workspaces } = JSON.parse(content);
734
+ return ((Array.isArray(workspaces) ? workspaces : workspaces?.packages) ?? []).filter((p) => typeof p === "string");
735
+ } catch {
736
+ return [];
705
737
  }
706
- const matches = (await (0, tinyglobby.glob)(VITE_CONFIG_PATHS.map((p) => `**/${p}`), {
707
- cwd,
708
- absolute: true,
709
- ignore: DEFAULT_IGNORE_PATTERNS,
710
- deep: CONFIG_DISCOVERY_MAX_DEPTH
711
- })).filter(isTailwindViteConfig);
712
- if (matches.length === 0) return null;
713
- return sortByPathDepth(matches)[0];
714
738
  }
715
- function isTailwindViteConfig(filePath) {
716
- if (!fileExists(filePath)) return false;
739
+ function parsePnpmWorkspacePackages(content) {
740
+ const patterns = [];
741
+ let inPackages = false;
742
+ for (const line of content.split(/\r?\n/)) if (/^packages\s*:/.test(line)) inPackages = true;
743
+ else if (/^[^\s#]/.test(line)) inPackages = false;
744
+ else if (inPackages) {
745
+ const item = line.match(/^\s*-\s*["']?([^"'#\s]+)["']?/);
746
+ if (item) patterns.push(item[1]);
747
+ }
748
+ return patterns;
749
+ }
750
+ function nestedRootIgnores(root, roots) {
751
+ return roots.filter((other) => other !== root && isInsideDir(root, other)).map((other) => `${node_path.relative(root, other)}/**`);
752
+ }
753
+ function isInsideDir(dir, filePath) {
754
+ const relative = node_path.relative(dir, filePath);
755
+ return !relative.startsWith("..") && !node_path.isAbsolute(relative);
756
+ }
757
+ async function pickConfig(root, candidates) {
758
+ const target = (kind, configPath) => ({
759
+ kind,
760
+ path: configPath,
761
+ root
762
+ });
763
+ const candidateSet = new Set(candidates);
764
+ const existing = (paths) => paths.map((p) => node_path.join(root, p)).filter((p) => candidateSet.has(p));
765
+ const byName = (names) => candidates.filter((c) => names.includes(node_path.basename(c)));
766
+ const preferredCss = existing(V4_CSS_FOLDERS.flatMap((folder) => V4_CSS_NAMES.map((name) => node_path.join(folder, name))));
767
+ const preferredCssMatch = await findFirstMatch(preferredCss, TAILWIND_V4_IMPORT_REGEX);
768
+ if (preferredCssMatch) return target("css", preferredCssMatch);
769
+ const rootV3 = existing(V3_CONFIG_PATHS)[0];
770
+ if (rootV3) return target("js", rootV3);
771
+ const cssMatch = await findFirstMatch(sortCssCandidates(root, candidates.filter((c) => isCssConfigFile(c) && !preferredCss.includes(c))), TAILWIND_V4_IMPORT_REGEX);
772
+ if (cssMatch) return target("css", cssMatch);
773
+ const nestedV3 = sortByPathDepth(byName(V3_CONFIG_PATHS))[0];
774
+ if (nestedV3) return target("js", nestedV3);
775
+ const viteConfigs = [...existing(VITE_CONFIG_PATHS), ...sortByPathDepth(byName(VITE_CONFIG_PATHS))];
776
+ const viteMatch = await findFirstMatch([...new Set(viteConfigs)], TAILWIND_VITE_PLUGIN_REGEX);
777
+ if (viteMatch) return target("vite", viteMatch);
778
+ }
779
+ async function findFirstMatch(paths, regex) {
780
+ const contents = await Promise.all(paths.map(readText));
781
+ return paths.find((_, index) => regex.test(contents[index]));
782
+ }
783
+ async function readText(filePath) {
717
784
  try {
718
- return TAILWIND_VITE_PLUGIN_REGEX.test(readFileSync(filePath));
785
+ return await (0, node_fs_promises.readFile)(filePath, "utf-8");
719
786
  } catch {
720
- return false;
787
+ return "";
721
788
  }
722
789
  }
723
790
  function sortByPathDepth(paths) {
@@ -755,9 +822,9 @@ function splitDepth(value) {
755
822
  //#endregion
756
823
  //#region src/state.ts
757
824
  const require$1 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href || __filename);
758
- function getTailwindVersion(cwd) {
825
+ function getTailwindVersion(paths) {
759
826
  try {
760
- const tailwindPackageJson = require$1.resolve("tailwindcss/package.json", { paths: [cwd] });
827
+ const tailwindPackageJson = require$1.resolve("tailwindcss/package.json", { paths });
761
828
  const { readFileSync } = require$1("node:fs");
762
829
  return JSON.parse(readFileSync(tailwindPackageJson, "utf-8")).version;
763
830
  } catch {
@@ -767,40 +834,52 @@ function getTailwindVersion(cwd) {
767
834
  function isV4Config(version) {
768
835
  return version?.startsWith("4.") ?? false;
769
836
  }
770
- function resolveTailwindPath(cwd, configDir) {
771
- const paths = configDir ? [configDir, cwd] : [cwd];
837
+ function resolveTailwindPath(paths) {
772
838
  try {
773
839
  return require$1.resolve("tailwindcss", { paths });
774
840
  } catch {
775
841
  throw new Error(`Could not find tailwindcss module in ${paths.join(" or ")}.\nInstall it with: npm install -D tailwindcss`);
776
842
  }
777
843
  }
778
- async function createState(cwd, configPath, verbose = false) {
779
- const resolvedConfigPath = await findTailwindConfigPath(cwd, configPath);
780
- 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.");
781
- const isCssConfig = isCssConfigFile(resolvedConfigPath);
782
- const tailwindcss = require$1(resolveTailwindPath(cwd, node_path.dirname(resolvedConfigPath)));
783
- const version = getTailwindVersion(cwd);
844
+ function loadResolveConfig(paths) {
845
+ try {
846
+ const module = require$1(require$1.resolve("tailwindcss/resolveConfig", { paths }));
847
+ return typeof module === "function" ? module : module.default;
848
+ } catch {
849
+ return;
850
+ }
851
+ }
852
+ const CONFIG_TYPE_LABELS = {
853
+ css: "CSS (v4)",
854
+ vite: "Vite (v4)",
855
+ js: "JavaScript"
856
+ };
857
+ async function createState(cwd, target, verbose = false) {
858
+ const isCssConfig = target.kind !== "js";
859
+ const resolvePaths = [node_path.dirname(target.path), cwd];
860
+ resolveTailwindPath(resolvePaths);
861
+ const version = getTailwindVersion(resolvePaths);
784
862
  const isV4 = isV4Config(version);
785
863
  if (verbose) {
786
864
  console.log(ansis.default.cyan.bold("→ Tailwind Configuration"));
787
865
  console.log(ansis.default.dim(` Version: ${version || "unknown"}`));
788
- console.log(ansis.default.dim(` Config type: ${isCssConfig ? "CSS (v4)" : "JavaScript"}`));
789
- console.log(ansis.default.dim(` Config path: ${resolvedConfigPath}`));
866
+ console.log(ansis.default.dim(` Config type: ${CONFIG_TYPE_LABELS[target.kind]}`));
867
+ console.log(ansis.default.dim(` Config path: ${target.path}`));
790
868
  }
791
869
  let config = {};
792
870
  let resolvedConfig = { separator: ":" };
793
871
  if (!isCssConfig) {
794
- config = await loadTailwindConfig(resolvedConfigPath);
872
+ config = await loadTailwindConfig(target.path);
795
873
  resolvedConfig = {
796
874
  ...config,
797
875
  separator: config.separator ?? ":"
798
876
  };
799
- if (tailwindcss.resolveConfig) resolvedConfig = tailwindcss.resolveConfig(config);
877
+ const resolveConfig = loadResolveConfig(resolvePaths);
878
+ if (resolveConfig) resolvedConfig = resolveConfig(config);
800
879
  }
801
880
  const state = {
802
881
  enabled: true,
803
- configPath: resolvedConfigPath,
882
+ configPath: target.path,
804
883
  config: resolvedConfig,
805
884
  version,
806
885
  v4: isV4 || void 0,
@@ -814,14 +893,15 @@ async function createState(cwd, configPath, verbose = false) {
814
893
  editor: createEditorState(cwd),
815
894
  features: ["diagnostics"]
816
895
  };
817
- if (isV4 || isCssConfig) await loadV4DesignSystem(state, cwd, resolvedConfigPath, verbose);
818
- else await loadV3ClassMetadata(state, cwd, verbose);
896
+ if (isV4 || isCssConfig) await loadV4DesignSystem(state, resolvePaths, target, verbose);
897
+ else await loadV3ClassMetadata(state, resolvePaths, verbose);
819
898
  return state;
820
899
  }
821
900
  //#endregion
822
901
  //#region src/linter.ts
823
902
  const SOURCE_FILE_PATTERN = "**/*.{js,jsx,ts,tsx,html,vue,svelte,astro,mdx}";
824
903
  const GLOB_PATTERN_REGEX = /[*?[\]{}]/;
904
+ const MAX_LISTED_PACKAGES = 10;
825
905
  async function validateDocument(state, filePath, content) {
826
906
  try {
827
907
  if (!state) throw new Error("State is not initialized");
@@ -829,7 +909,8 @@ async function validateDocument(state, filePath, content) {
829
909
  if (!state.v4 && !state.modules?.tailwindcss) throw new Error("Tailwind modules not initialized for Tailwind v3. This might indicate a configuration issue.");
830
910
  const languageId = getLanguageId(filePath);
831
911
  const uri = `file://${filePath}`;
832
- return await (0, _tailwindcss_language_service.doValidate)(state, vscode_languageserver_textdocument.TextDocument.create(uri, languageId, 1, content));
912
+ const document = vscode_languageserver_textdocument.TextDocument.create(uri, languageId, 1, content);
913
+ return await (0, _tailwindcss_language_service.doValidate)(state, document);
833
914
  } catch (error) {
834
915
  const message = error instanceof Error ? error.message : String(error);
835
916
  if (message.includes("Cannot read") || message.includes("undefined")) {
@@ -840,52 +921,43 @@ async function validateDocument(state, filePath, content) {
840
921
  throw new Error(`Failed to validate document ${filePath}: ${message}`);
841
922
  }
842
923
  }
843
- async function discoverFiles(cwd, patterns, configPath, autoDiscover) {
844
- if (autoDiscover) return discoverFilesFromConfig(cwd, configPath);
845
- return expandPatterns(cwd, patterns);
846
- }
847
924
  async function expandPatterns(cwd, patterns, extraIgnore = []) {
848
- const files = await (0, tinyglobby.glob)(patterns, {
925
+ return (0, tinyglobby.glob)(patterns, {
849
926
  cwd,
850
- absolute: false,
927
+ absolute: true,
851
928
  ignore: [...DEFAULT_IGNORE_PATTERNS, ...extraIgnore]
852
929
  });
853
- return [...new Set(files)].sort((a, b) => a.localeCompare(b));
854
- }
855
- async function discoverFilesFromConfig(cwd, configPath) {
856
- const configFilePath = await findTailwindConfigPath(cwd, configPath);
857
- if (!configFilePath) throw new Error("Could not find Tailwind config for auto-discovery.\nUse --config to specify the path, or provide file patterns directly.");
858
- const discoveryCwd = isCssConfigFile(configFilePath) ? findProjectRoot(node_path.dirname(configFilePath)) : cwd;
859
- if (!isCssConfigFile(configFilePath)) {
860
- const config = await loadTailwindConfig(configFilePath);
930
+ }
931
+ async function discoverFilesFromConfig(target, configRoots) {
932
+ if (target.kind === "js") {
933
+ const config = await loadTailwindConfig(target.path);
861
934
  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}']");
862
935
  const patterns = extractContentPatterns(config);
863
936
  if (patterns.length === 0) throw new Error("No content patterns found in Tailwind config.\nEnsure your config has a content array with file patterns.");
864
- return expandPatterns(discoveryCwd, patterns);
937
+ return expandPatterns(!Array.isArray(config.content) && config.content.relative === true ? node_path.dirname(target.path) : target.root, patterns);
865
938
  }
866
- const configDir = node_path.dirname(configFilePath);
867
- const cssContent = fileExists(configFilePath) ? readFileSync(configFilePath) : SYNTHETIC_VITE_CSS_CONFIG_CONTENT;
868
- const includeConfigFile = (files) => {
869
- if (!fileExists(configFilePath)) return files;
870
- const relativeConfigPath = node_path.relative(discoveryCwd, configFilePath);
871
- return [...new Set([relativeConfigPath, ...files])].sort((a, b) => a.localeCompare(b));
872
- };
873
- const resolveDiscoveredFiles = (files) => discoveryCwd === cwd ? files : files.map((file) => node_path.resolve(discoveryCwd, file)).sort((a, b) => a.localeCompare(b));
939
+ const { root } = target;
940
+ const configDir = node_path.dirname(target.path);
941
+ const cssContent = target.kind === "vite" ? SYNTHETIC_VITE_CSS_CONFIG_CONTENT : readFileSync(target.path);
874
942
  const { include, exclude } = extractSourcePatterns(cssContent);
875
943
  const importSource = extractImportSourceDirectives(cssContent);
876
- const resolveFromConfig = (pattern) => {
877
- const absolutePattern = node_path.resolve(configDir, pattern);
878
- return node_path.relative(discoveryCwd, absolutePattern);
879
- };
944
+ const resolveFromConfig = (pattern) => node_path.relative(root, node_path.resolve(configDir, pattern));
880
945
  const resolvedExclude = exclude.map(resolveFromConfig);
881
- const gitignorePatterns = readGitignorePatterns(discoveryCwd);
882
- const extraIgnore = [...resolvedExclude, ...gitignorePatterns];
946
+ const extraIgnore = [
947
+ ...resolvedExclude,
948
+ ...readGitignorePatterns(root),
949
+ ...nestedRootIgnores(root, configRoots)
950
+ ];
883
951
  const explicitSourcePatterns = include.map((source) => resolveFromConfig(normalizeSourcePattern(source)));
884
952
  let autoPatterns = [];
885
- if (!importSource.disableAutoSource) autoPatterns = importSource.roots.length > 0 ? importSource.roots.map((root) => resolveFromConfig(normalizeSourcePattern(root))) : [DEFAULT_FILE_PATTERN];
886
- const autoFiles = autoPatterns.length > 0 ? await expandPatterns(discoveryCwd, autoPatterns, extraIgnore) : [];
887
- const explicitFiles = explicitSourcePatterns.length > 0 ? await expandPatterns(discoveryCwd, explicitSourcePatterns, resolvedExclude) : [];
888
- return resolveDiscoveredFiles(includeConfigFile([...new Set([...autoFiles, ...explicitFiles])].sort((a, b) => a.localeCompare(b))));
953
+ if (!importSource.disableAutoSource) autoPatterns = importSource.roots.length > 0 ? importSource.roots.map((sourceRoot) => resolveFromConfig(normalizeSourcePattern(sourceRoot))) : [DEFAULT_FILE_PATTERN];
954
+ const [autoFiles, explicitFiles] = await Promise.all([autoPatterns.length > 0 ? expandPatterns(root, autoPatterns, extraIgnore) : [], explicitSourcePatterns.length > 0 ? expandPatterns(root, explicitSourcePatterns, resolvedExclude) : []]);
955
+ const configFile = target.kind === "css" ? [target.path] : [];
956
+ return [.../* @__PURE__ */ new Set([
957
+ ...configFile,
958
+ ...autoFiles,
959
+ ...explicitFiles
960
+ ])];
889
961
  }
890
962
  function normalizeSourcePattern(pattern) {
891
963
  if (GLOB_PATTERN_REGEX.test(pattern) || node_path.extname(pattern)) return pattern;
@@ -961,9 +1033,9 @@ async function processFile(state, cwd, filePath, fix) {
961
1033
  fixedCount
962
1034
  };
963
1035
  }
964
- async function initializeState(cwd, configPath, verbose = false) {
1036
+ async function initializeState(cwd, target, verbose = false) {
965
1037
  try {
966
- const state = await createState(cwd, configPath, verbose);
1038
+ const state = await createState(cwd, target, verbose);
967
1039
  if (verbose) console.log();
968
1040
  return state;
969
1041
  } catch (error) {
@@ -972,42 +1044,80 @@ async function initializeState(cwd, configPath, verbose = false) {
972
1044
  }
973
1045
  }
974
1046
  async function lint({ cwd, patterns, configPath, autoDiscover, fix = false, verbose = false, onProgress }) {
975
- const state = await initializeState(cwd, configPath, verbose);
976
- const discoveredFiles = await discoverFiles(cwd, patterns, configPath, autoDiscover);
977
- const files = uniqueFilesByResolvedPath(cwd, state.configPath && isCssConfigFile(state.configPath) && fileExists(state.configPath) ? [node_path.relative(cwd, state.configPath), ...discoveredFiles] : discoveredFiles);
1047
+ const targets = await resolveConfigTargets(cwd, configPath);
1048
+ if (verbose) logTargets(cwd, targets);
1049
+ const configRoots = targets.map((target) => target.root);
1050
+ const patternFiles = autoDiscover ? [] : await expandPatterns(cwd, patterns);
1051
+ const discoveredFilesByTarget = await Promise.all(targets.map((target) => autoDiscover ? discoverFilesFromConfig(target, configRoots) : patternFiles));
1052
+ const owners = /* @__PURE__ */ new Map();
1053
+ for (const [index, target] of targets.entries()) {
1054
+ const files = target.kind === "css" && !autoDiscover ? [target.path, ...discoveredFilesByTarget[index]] : discoveredFilesByTarget[index];
1055
+ for (const file of files) {
1056
+ const current = owners.get(file);
1057
+ if (!current || ownershipScore(target, file) > ownershipScore(current, file)) owners.set(file, target);
1058
+ }
1059
+ }
978
1060
  const skippedFiles = [];
979
- const lintableFiles = files.filter((file) => {
980
- if (getFileSize(node_path.isAbsolute(file) ? file : node_path.resolve(cwd, file)) > 524288) {
1061
+ const filesByTarget = /* @__PURE__ */ new Map();
1062
+ for (const [absolutePath, target] of owners) {
1063
+ const file = node_path.relative(cwd, absolutePath);
1064
+ if (getFileSize(absolutePath) > 524288) {
981
1065
  skippedFiles.push(file);
982
- return false;
1066
+ continue;
983
1067
  }
984
- return true;
985
- });
1068
+ const files = filesByTarget.get(target) ?? [];
1069
+ files.push(file);
1070
+ filesByTarget.set(target, files);
1071
+ }
1072
+ const totalFiles = owners.size - skippedFiles.length;
986
1073
  if (verbose) {
987
- console.log(ansis.default.cyan.bold(`→ Discovered ${lintableFiles.length} file${lintableFiles.length !== 1 ? "s" : ""} to lint`));
1074
+ console.log(ansis.default.cyan.bold(`→ Discovered ${totalFiles} file${totalFiles !== 1 ? "s" : ""} to lint`));
988
1075
  console.log();
989
1076
  }
990
- if (lintableFiles.length === 0) return {
991
- files: [],
992
- totalFilesProcessed: 0,
993
- skippedFiles
994
- };
1077
+ const results = [];
1078
+ let processedCount = 0;
1079
+ for (const target of targets) {
1080
+ const files = filesByTarget.get(target);
1081
+ if (!files) continue;
1082
+ const offset = processedCount;
1083
+ processedCount += files.length;
1084
+ 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)));
1085
+ results.push(...processed);
1086
+ }
995
1087
  return {
996
- files: (await processFiles(state, cwd, lintableFiles, fix, onProgress)).filter((result) => result.diagnostics.length > 0 || result.fixed),
997
- totalFilesProcessed: lintableFiles.length,
998
- skippedFiles
1088
+ files: results.filter((result) => result.diagnostics.length > 0 || result.fixed).sort((a, b) => a.path.localeCompare(b.path)),
1089
+ totalFilesProcessed: totalFiles,
1090
+ skippedFiles: skippedFiles.sort((a, b) => a.localeCompare(b))
999
1091
  };
1000
1092
  }
1001
- function uniqueFilesByResolvedPath(cwd, files) {
1002
- const seen = /* @__PURE__ */ new Set();
1003
- const unique = [];
1004
- for (const file of files) {
1005
- const absolutePath = node_path.isAbsolute(file) ? file : node_path.resolve(cwd, file);
1006
- if (seen.has(absolutePath)) continue;
1007
- seen.add(absolutePath);
1008
- unique.push(file);
1093
+ async function resolveConfigTargets(cwd, configPath) {
1094
+ if (configPath) {
1095
+ const absolutePath = node_path.resolve(cwd, configPath);
1096
+ if (!fileExists(absolutePath)) throw new Error(`Tailwind config file not found: ${absolutePath}`);
1097
+ return [toConfigTarget(absolutePath)];
1009
1098
  }
1010
- return unique.sort((a, b) => a.localeCompare(b));
1099
+ const { targets, packageRoots } = await findTailwindConfigs(cwd);
1100
+ if (targets.length === 0) throw new Error(noConfigMessage(cwd, packageRoots));
1101
+ return targets;
1102
+ }
1103
+ function noConfigMessage(cwd, packageRoots) {
1104
+ const packages = packageRoots.map((root) => node_path.relative(cwd, root)).filter(Boolean).sort((a, b) => a.localeCompare(b));
1105
+ const shown = packages.slice(0, MAX_LISTED_PACKAGES);
1106
+ const more = packages.length - shown.length;
1107
+ 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:
1108
+ • Tailwind v4 (CSS): a CSS file with @import "tailwindcss", e.g. app.css or src/index.css
1109
+ • Tailwind v4 (Vite): vite.config.* with @tailwindcss/vite
1110
+ • Tailwind v3 (JS): tailwind.config.js, tailwind.config.ts
1111
+ Use --config to specify the path.`;
1112
+ }
1113
+ function logTargets(cwd, targets) {
1114
+ const display = (p) => node_path.relative(cwd, p) || ".";
1115
+ console.log(ansis.default.cyan.bold("→ Tailwind configs"));
1116
+ for (const target of targets) console.log(ansis.default.dim(` ${display(target.root)} → ${display(target.path)}`));
1117
+ console.log();
1118
+ }
1119
+ function ownershipScore(target, absolutePath) {
1120
+ return isInsideDir(target.root, absolutePath) ? target.root.length : -1;
1011
1121
  }
1012
1122
  //#endregion
1013
1123
  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-DQMo7IYe.cjs");
2
+ const require_linter = require("./linter-gjoSGNMw.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,14 +383,6 @@ declare function extractImportSourceDirectives(cssContent: string): {
383
383
  roots: string[];
384
384
  disableAutoSource: boolean;
385
385
  };
386
- declare function lint({
387
- cwd,
388
- patterns,
389
- configPath,
390
- autoDiscover,
391
- fix,
392
- verbose,
393
- onProgress
394
- }: LintOptions): Promise<LintResult>;
386
+ export declare function lint({ cwd, patterns, configPath, autoDiscover, fix, verbose, onProgress }: LintOptions): Promise<LintResult>;
395
387
  //#endregion
396
- 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.0",
3
+ "version": "0.13.0",
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.15",
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": "^25.9.3",
70
- "oxfmt": "^0.54.0",
71
- "oxlint": "^1.69.0",
72
- "tsdown": "^0.22.2",
73
- "typescript": "^6.0.3",
74
- "vitest": "^4.1.8"
69
+ "@types/node": "^26.6.4",
70
+ "oxfmt": "^0.71.0",
71
+ "oxlint": "^1.86.0",
72
+ "tsdown": "^0.23.0",
73
+ "typescript": "^7.0.2",
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.5.3"
81
+ "packageManager": "pnpm@12.8.1"
81
82
  }