tailwind-lint 0.11.2 → 0.12.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/dist/cli.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const require_linter = require("./linter-B9R7nuem.cjs");
2
+ const require_linter = require("./linter-BP0uKBfa.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");
@@ -110,7 +110,8 @@ function resolveOptions(files, options) {
110
110
  let autoDiscover = hasAutoFlag;
111
111
  if (hasConfigFlag && options.config) configPath = node_path.isAbsolute(options.config) ? options.config : node_path.resolve(process.cwd(), options.config);
112
112
  if (hasConfigFlag && options.config && !hasFiles) {
113
- cwd = node_path.dirname(configPath);
113
+ const configDir = node_path.dirname(configPath);
114
+ cwd = require_linter.isCssConfigFile(configPath) ? require_linter.findProjectRoot(configDir) : configDir;
114
115
  patterns = [];
115
116
  autoDiscover = true;
116
117
  }
@@ -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
@@ -488,7 +489,8 @@ var AdapterLoadError = class extends Error {
488
489
  const require$4 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href || __filename);
489
490
  async function loadV3ClassMetadata(state, cwd, verbose = false) {
490
491
  try {
491
- const tailwindcss = require$4(require$4.resolve("tailwindcss", { paths: [cwd] }));
492
+ const tailwindPath = require$4.resolve("tailwindcss", { paths: [cwd] });
493
+ const tailwindcss = require$4(tailwindPath);
492
494
  try {
493
495
  const tailwindDir = node_path.dirname(require$4.resolve("tailwindcss/package.json", { paths: [cwd] }));
494
496
  const contextUtils = require$4(node_path.join(tailwindDir, "lib", "lib", "setupContextUtils"));
@@ -554,7 +556,8 @@ function extractConfigMetadata(state) {
554
556
  const require$3 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href || __filename);
555
557
  async function loadV4DesignSystem(state, cwd, configPath, verbose = false) {
556
558
  try {
557
- const tailwindcss = require$3(require$3.resolve("tailwindcss", { paths: [cwd] }));
559
+ const tailwindPath = require$3.resolve("tailwindcss", { paths: [cwd] });
560
+ const tailwindcss = require$3(tailwindPath);
558
561
  if (tailwindcss !== null && tailwindcss !== void 0 && (typeof tailwindcss === "object" || typeof tailwindcss === "function") && "__unstable__loadDesignSystem" in tailwindcss && typeof tailwindcss.__unstable__loadDesignSystem === "function") {
559
562
  let cssContent;
560
563
  const basePath = node_path.dirname(configPath);
@@ -628,7 +631,17 @@ async function loadV4DesignSystem(state, cwd, configPath, verbose = false) {
628
631
  //#region src/utils/config.ts
629
632
  const require$2 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href || __filename);
630
633
  const CONFIG_DISCOVERY_MAX_DEPTH = 8;
634
+ const PROJECT_ROOT_MARKERS = ["package.json", ".git"];
631
635
  const isCssConfigFile = (filePath) => filePath.endsWith(".css");
636
+ function findProjectRoot(startDir) {
637
+ let current = node_path.resolve(startDir);
638
+ while (true) {
639
+ if (PROJECT_ROOT_MARKERS.some((marker) => fileExists(node_path.join(current, marker)))) return current;
640
+ const parent = node_path.dirname(current);
641
+ if (parent === current) return node_path.resolve(startDir);
642
+ current = parent;
643
+ }
644
+ }
632
645
  function syntheticViteCssConfigPath(viteConfigPath) {
633
646
  return node_path.join(node_path.dirname(viteConfigPath), SYNTHETIC_VITE_CSS_CONFIG_NAME);
634
647
  }
@@ -653,17 +666,6 @@ async function findTailwindConfigPath(cwd, configPath) {
653
666
  const resolved = node_path.isAbsolute(configPath) ? configPath : node_path.resolve(cwd, configPath);
654
667
  return fileExists(resolved) ? resolved : null;
655
668
  }
656
- for (const p of V3_CONFIG_PATHS) {
657
- const fullPath = node_path.join(cwd, p);
658
- if (fileExists(fullPath)) return fullPath;
659
- }
660
- const v3Recursive = await (0, tinyglobby.glob)(V3_CONFIG_PATHS.map((p) => `**/${p}`), {
661
- cwd,
662
- absolute: true,
663
- ignore: DEFAULT_IGNORE_PATTERNS,
664
- deep: CONFIG_DISCOVERY_MAX_DEPTH
665
- });
666
- if (v3Recursive.length > 0) return sortByPathDepth(v3Recursive)[0];
667
669
  const v4Paths = V4_CSS_FOLDERS.flatMap((folder) => V4_CSS_NAMES.map((name) => node_path.join(folder, name)));
668
670
  for (const p of v4Paths) {
669
671
  const fullPath = node_path.join(cwd, p);
@@ -672,6 +674,10 @@ async function findTailwindConfigPath(cwd, configPath) {
672
674
  if (TAILWIND_V4_IMPORT_REGEX.test(content)) return fullPath;
673
675
  } catch {}
674
676
  }
677
+ for (const p of V3_CONFIG_PATHS) {
678
+ const fullPath = node_path.join(cwd, p);
679
+ if (fileExists(fullPath)) return fullPath;
680
+ }
675
681
  const cssCandidates = await (0, tinyglobby.glob)("**/*.css", {
676
682
  cwd,
677
683
  absolute: true,
@@ -684,6 +690,13 @@ async function findTailwindConfigPath(cwd, configPath) {
684
690
  if (TAILWIND_V4_IMPORT_REGEX.test(content)) v4Matches.push(candidate);
685
691
  } catch {}
686
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,
695
+ absolute: true,
696
+ ignore: DEFAULT_IGNORE_PATTERNS,
697
+ deep: CONFIG_DISCOVERY_MAX_DEPTH
698
+ });
699
+ if (v3Recursive.length > 0) return sortByPathDepth(v3Recursive)[0];
687
700
  const viteConfigPath = await findTailwindViteConfigPath(cwd);
688
701
  if (viteConfigPath) return syntheticViteCssConfigPath(viteConfigPath);
689
702
  return null;
@@ -769,7 +782,8 @@ async function createState(cwd, configPath, verbose = false) {
769
782
  const resolvedConfigPath = await findTailwindConfigPath(cwd, configPath);
770
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.");
771
784
  const isCssConfig = isCssConfigFile(resolvedConfigPath);
772
- const tailwindcss = require$1(resolveTailwindPath(cwd, node_path.dirname(resolvedConfigPath)));
785
+ const tailwindPath = resolveTailwindPath(cwd, node_path.dirname(resolvedConfigPath));
786
+ const tailwindcss = require$1(tailwindPath);
773
787
  const version = getTailwindVersion(cwd);
774
788
  const isV4 = isV4Config(version);
775
789
  if (verbose) {
@@ -810,6 +824,8 @@ async function createState(cwd, configPath, verbose = false) {
810
824
  }
811
825
  //#endregion
812
826
  //#region src/linter.ts
827
+ const SOURCE_FILE_PATTERN = "**/*.{js,jsx,ts,tsx,html,vue,svelte,astro,mdx}";
828
+ const GLOB_PATTERN_REGEX = /[*?[\]{}]/;
813
829
  async function validateDocument(state, filePath, content) {
814
830
  try {
815
831
  if (!state) throw new Error("State is not initialized");
@@ -843,33 +859,41 @@ async function expandPatterns(cwd, patterns, extraIgnore = []) {
843
859
  async function discoverFilesFromConfig(cwd, configPath) {
844
860
  const configFilePath = await findTailwindConfigPath(cwd, configPath);
845
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;
846
863
  if (!isCssConfigFile(configFilePath)) {
847
864
  const config = await loadTailwindConfig(configFilePath);
848
865
  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}']");
849
866
  const patterns = extractContentPatterns(config);
850
867
  if (patterns.length === 0) throw new Error("No content patterns found in Tailwind config.\nEnsure your config has a content array with file patterns.");
851
- return expandPatterns(cwd, patterns);
868
+ return expandPatterns(discoveryCwd, patterns);
852
869
  }
853
870
  const configDir = node_path.dirname(configFilePath);
854
871
  const cssContent = fileExists(configFilePath) ? readFileSync(configFilePath) : SYNTHETIC_VITE_CSS_CONFIG_CONTENT;
855
872
  const includeConfigFile = (files) => {
856
873
  if (!fileExists(configFilePath)) return files;
857
- const relativeConfigPath = node_path.relative(cwd, configFilePath);
858
- return [...new Set([relativeConfigPath, ...files])].sort((a, b) => a.localeCompare(b));
874
+ const relativeConfigPath = node_path.relative(discoveryCwd, configFilePath);
875
+ return [.../* @__PURE__ */ new Set([relativeConfigPath, ...files])].sort((a, b) => a.localeCompare(b));
859
876
  };
877
+ const resolveDiscoveredFiles = (files) => discoveryCwd === cwd ? files : files.map((file) => node_path.resolve(discoveryCwd, file)).sort((a, b) => a.localeCompare(b));
860
878
  const { include, exclude } = extractSourcePatterns(cssContent);
861
879
  const importSource = extractImportSourceDirectives(cssContent);
862
880
  const resolveFromConfig = (pattern) => {
863
881
  const absolutePattern = node_path.resolve(configDir, pattern);
864
- return node_path.relative(cwd, absolutePattern);
882
+ return node_path.relative(discoveryCwd, absolutePattern);
865
883
  };
866
884
  const resolvedExclude = exclude.map(resolveFromConfig);
867
- const gitignorePatterns = readGitignorePatterns(cwd);
885
+ const gitignorePatterns = readGitignorePatterns(discoveryCwd);
868
886
  const extraIgnore = [...resolvedExclude, ...gitignorePatterns];
869
- if (include.length > 0) return includeConfigFile(await expandPatterns(cwd, include.map(resolveFromConfig), extraIgnore));
870
- if (importSource.roots.length > 0) return includeConfigFile(await expandPatterns(cwd, importSource.roots.map((root) => resolveFromConfig(node_path.join(root, "**/*.{js,jsx,ts,tsx,html,vue,svelte,astro,mdx}"))), extraIgnore));
871
- if (importSource.disableAutoSource) return includeConfigFile([]);
872
- return includeConfigFile(await expandPatterns(cwd, [DEFAULT_FILE_PATTERN], extraIgnore));
887
+ const explicitSourcePatterns = include.map((source) => resolveFromConfig(normalizeSourcePattern(source)));
888
+ 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))));
893
+ }
894
+ function normalizeSourcePattern(pattern) {
895
+ if (GLOB_PATTERN_REGEX.test(pattern) || node_path.extname(pattern)) return pattern;
896
+ return node_path.join(pattern, SOURCE_FILE_PATTERN);
873
897
  }
874
898
  function extractContentPatterns(config) {
875
899
  if (!config.content) return [];
@@ -954,7 +978,7 @@ async function initializeState(cwd, configPath, verbose = false) {
954
978
  async function lint({ cwd, patterns, configPath, autoDiscover, fix = false, verbose = false, onProgress }) {
955
979
  const state = await initializeState(cwd, configPath, verbose);
956
980
  const discoveredFiles = await discoverFiles(cwd, patterns, configPath, autoDiscover);
957
- const files = state.configPath && isCssConfigFile(state.configPath) && fileExists(state.configPath) ? [...new Set([node_path.relative(cwd, state.configPath), ...discoveredFiles])].sort((a, b) => a.localeCompare(b)) : discoveredFiles;
981
+ const files = uniqueFilesByResolvedPath(cwd, state.configPath && isCssConfigFile(state.configPath) && fileExists(state.configPath) ? [node_path.relative(cwd, state.configPath), ...discoveredFiles] : discoveredFiles);
958
982
  const skippedFiles = [];
959
983
  const lintableFiles = files.filter((file) => {
960
984
  if (getFileSize(node_path.isAbsolute(file) ? file : node_path.resolve(cwd, file)) > 524288) {
@@ -978,6 +1002,17 @@ async function lint({ cwd, patterns, configPath, autoDiscover, fix = false, verb
978
1002
  skippedFiles
979
1003
  };
980
1004
  }
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);
1013
+ }
1014
+ return unique.sort((a, b) => a.localeCompare(b));
1015
+ }
981
1016
  //#endregion
982
1017
  Object.defineProperty(exports, "DEFAULT_FILE_PATTERN", {
983
1018
  enumerable: true,
@@ -1015,6 +1050,18 @@ Object.defineProperty(exports, "extractSourcePatterns", {
1015
1050
  return extractSourcePatterns;
1016
1051
  }
1017
1052
  });
1053
+ Object.defineProperty(exports, "findProjectRoot", {
1054
+ enumerable: true,
1055
+ get: function() {
1056
+ return findProjectRoot;
1057
+ }
1058
+ });
1059
+ Object.defineProperty(exports, "isCssConfigFile", {
1060
+ enumerable: true,
1061
+ get: function() {
1062
+ return isCssConfigFile;
1063
+ }
1064
+ });
1018
1065
  Object.defineProperty(exports, "lint", {
1019
1066
  enumerable: true,
1020
1067
  get: function() {
package/dist/linter.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_linter = require("./linter-B9R7nuem.cjs");
2
+ const require_linter = require("./linter-BP0uKBfa.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
+ declare function lint({ cwd, patterns, configPath, autoDiscover, fix, verbose, onProgress }: LintOptions): Promise<LintResult>;
395
387
  //#endregion
396
388
  export { type LintFileResult, type LintOptions, type LintResult, extractImportSourceDirectives, extractSourcePatterns, lint };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tailwind-lint",
3
- "version": "0.11.2",
3
+ "version": "0.12.1",
4
4
  "description": "A command-line tool that uses the Tailwind CSS IntelliSense plugin to show linting suggestions for your Tailwind CSS classes",
5
5
  "keywords": [
6
6
  "cli",
@@ -61,21 +61,21 @@
61
61
  "@tailwindcss/language-service": "^0.14.29",
62
62
  "ansis": "^4.3.1",
63
63
  "commander": "^15.0.0",
64
- "postcss": "^8.5.15",
64
+ "postcss": "^8.5.19",
65
65
  "tinyglobby": "^0.2.17",
66
66
  "vscode-languageserver-textdocument": "^1.0.12"
67
67
  },
68
68
  "devDependencies": {
69
- "@types/node": "^25.9.1",
70
- "oxfmt": "^0.53.0",
71
- "oxlint": "^1.68.0",
72
- "tsdown": "^0.22.2",
73
- "typescript": "^6.0.3",
74
- "vitest": "^4.1.8"
69
+ "@types/node": "^26.1.1",
70
+ "oxfmt": "^0.58.0",
71
+ "oxlint": "^1.73.0",
72
+ "tsdown": "^0.22.7",
73
+ "typescript": "^7.0.2",
74
+ "vitest": "^4.1.10"
75
75
  },
76
76
  "engines": {
77
77
  "node": ">=22.0.0",
78
78
  "pnpm": ">=10.0.0"
79
79
  },
80
- "packageManager": "pnpm@11.5.1"
80
+ "packageManager": "pnpm@11.13.0"
81
81
  }