tailwind-lint 0.1.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.
@@ -0,0 +1,686 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) {
13
+ __defProp(to, key, {
14
+ get: ((k) => from[k]).bind(null, key),
15
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
+ });
17
+ }
18
+ }
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
23
+ value: mod,
24
+ enumerable: true
25
+ }) : target, mod));
26
+
27
+ //#endregion
28
+ const require_constants = require('./constants-BFubEpZ9.cjs');
29
+ let node_path = require("node:path");
30
+ node_path = __toESM(node_path);
31
+ let _tailwindcss_language_service = require("@tailwindcss/language-service");
32
+ let fast_glob = require("fast-glob");
33
+ fast_glob = __toESM(fast_glob);
34
+ let vscode_languageserver_textdocument = require("vscode-languageserver-textdocument");
35
+ let node_fs = require("node:fs");
36
+ node_fs = __toESM(node_fs);
37
+ let node_module = require("node:module");
38
+
39
+ //#region src/code-actions.ts
40
+ function getLanguageId$1(filePath) {
41
+ return {
42
+ ".astro": "astro",
43
+ ".css": "css",
44
+ ".erb": "erb",
45
+ ".hbs": "handlebars",
46
+ ".htm": "html",
47
+ ".html": "html",
48
+ ".js": "javascript",
49
+ ".jsx": "javascriptreact",
50
+ ".less": "less",
51
+ ".md": "markdown",
52
+ ".mdx": "mdx",
53
+ ".php": "php",
54
+ ".sass": "sass",
55
+ ".scss": "scss",
56
+ ".svelte": "svelte",
57
+ ".ts": "typescript",
58
+ ".tsx": "typescriptreact",
59
+ ".twig": "twig",
60
+ ".vue": "vue"
61
+ }[node_path.extname(filePath).toLowerCase()] || "html";
62
+ }
63
+ async function getQuickfixes(state, document, uri, diagnostics) {
64
+ const lspDiagnostics = diagnostics.map((diag) => ({
65
+ range: diag.range,
66
+ severity: diag.severity,
67
+ message: diag.message,
68
+ code: diag.code,
69
+ source: diag.source || "tailwindcss"
70
+ }));
71
+ return (await (0, _tailwindcss_language_service.doCodeActions)(state, {
72
+ textDocument: { uri },
73
+ range: {
74
+ start: {
75
+ line: 0,
76
+ character: 0
77
+ },
78
+ end: {
79
+ line: document.lineCount,
80
+ character: 0
81
+ }
82
+ },
83
+ context: { diagnostics: lspDiagnostics }
84
+ }, document)).filter((action) => action.kind === "quickfix" || action.kind?.startsWith("quickfix."));
85
+ }
86
+ function applyFirstQuickfix(action, uri, document, content) {
87
+ if (!action.edit?.changes?.[uri]) return null;
88
+ const sortedEdits = [...action.edit.changes[uri]].sort((a, b) => {
89
+ const lineDiff = b.range.start.line - a.range.start.line;
90
+ if (lineDiff !== 0) return lineDiff;
91
+ return b.range.start.character - a.range.start.character;
92
+ });
93
+ let newContent = content;
94
+ for (const edit of sortedEdits) {
95
+ const startOffset = document.offsetAt(edit.range.start);
96
+ const endOffset = document.offsetAt(edit.range.end);
97
+ newContent = newContent.substring(0, startOffset) + edit.newText + newContent.substring(endOffset);
98
+ }
99
+ return { content: newContent };
100
+ }
101
+ async function applyCodeActions(state, filePath, content, diagnostics) {
102
+ if (diagnostics.length === 0) return {
103
+ content,
104
+ changed: false,
105
+ fixedCount: 0
106
+ };
107
+ const languageId = getLanguageId$1(filePath);
108
+ const uri = `file://${filePath}`;
109
+ let currentDocument = vscode_languageserver_textdocument.TextDocument.create(uri, languageId, 1, content);
110
+ let currentContent = content;
111
+ let totalFixed = 0;
112
+ let iteration = 0;
113
+ for (; iteration < require_constants.MAX_FIX_ITERATIONS; iteration++) {
114
+ const currentDiagnostics = await (0, _tailwindcss_language_service.doValidate)(state, currentDocument);
115
+ if (currentDiagnostics.length === 0) break;
116
+ const quickfixes = await getQuickfixes(state, currentDocument, uri, currentDiagnostics);
117
+ if (quickfixes.length === 0) break;
118
+ const fixResult = applyFirstQuickfix(quickfixes[0], uri, currentDocument, currentContent);
119
+ if (!fixResult) break;
120
+ currentContent = fixResult.content;
121
+ currentDocument = vscode_languageserver_textdocument.TextDocument.create(uri, languageId, currentDocument.version + 1, currentContent);
122
+ totalFixed++;
123
+ }
124
+ if (iteration === require_constants.MAX_FIX_ITERATIONS) {
125
+ if ((await (0, _tailwindcss_language_service.doValidate)(state, currentDocument)).length > 0) console.warn(`Warning: Reached maximum fix iterations (${require_constants.MAX_FIX_ITERATIONS}) for ${filePath}. Some issues may remain.`);
126
+ }
127
+ return {
128
+ content: currentContent,
129
+ changed: currentContent !== content,
130
+ fixedCount: totalFixed
131
+ };
132
+ }
133
+
134
+ //#endregion
135
+ //#region src/adapters/editor-state-adapter.ts
136
+ function isDirectory(filePath) {
137
+ try {
138
+ return node_fs.statSync(filePath).isDirectory();
139
+ } catch {
140
+ return false;
141
+ }
142
+ }
143
+ function createEditorState(cwd) {
144
+ const settings = {
145
+ editor: { tabSize: require_constants.DEFAULT_TAB_SIZE },
146
+ tailwindCSS: {
147
+ inspectPort: null,
148
+ emmetCompletions: false,
149
+ includeLanguages: {},
150
+ classAttributes: [
151
+ "class",
152
+ "className",
153
+ "ngClass",
154
+ "[class]",
155
+ ":class",
156
+ "v-bind:class",
157
+ "x-bind:class",
158
+ "class:list",
159
+ "classList"
160
+ ],
161
+ classFunctions: [],
162
+ codeActions: true,
163
+ hovers: true,
164
+ codeLens: false,
165
+ suggestions: true,
166
+ validate: true,
167
+ colorDecorators: true,
168
+ rootFontSize: require_constants.DEFAULT_ROOT_FONT_SIZE,
169
+ showPixelEquivalents: true,
170
+ files: { exclude: [
171
+ "**/.git/**",
172
+ "**/node_modules/**",
173
+ "**/.hg/**",
174
+ "**/.svn/**"
175
+ ] },
176
+ experimental: {
177
+ configFile: null,
178
+ classRegex: []
179
+ },
180
+ lint: {
181
+ cssConflict: "warning",
182
+ invalidApply: "error",
183
+ invalidScreen: "error",
184
+ invalidVariant: "error",
185
+ invalidConfigPath: "error",
186
+ invalidTailwindDirective: "error",
187
+ invalidSourceDirective: "error",
188
+ recommendedVariantOrder: "warning",
189
+ usedBlocklistedClass: "warning",
190
+ suggestCanonicalClasses: "warning"
191
+ }
192
+ }
193
+ };
194
+ return {
195
+ connection: null,
196
+ folder: cwd,
197
+ userLanguages: {},
198
+ capabilities: {
199
+ configuration: true,
200
+ diagnosticRelatedInformation: true,
201
+ itemDefaults: []
202
+ },
203
+ getConfiguration: async () => settings,
204
+ getDocumentSymbols: async () => [],
205
+ readDirectory: async (document, directory) => {
206
+ const docPath = typeof document === "string" ? document : document.uri.replace("file://", "");
207
+ const dir = node_path.resolve(node_path.dirname(docPath), directory);
208
+ try {
209
+ return node_fs.readdirSync(dir).map((file) => [file, { isDirectory: isDirectory(node_path.join(dir, file)) }]);
210
+ } catch {
211
+ return [];
212
+ }
213
+ }
214
+ };
215
+ }
216
+
217
+ //#endregion
218
+ //#region src/types.ts
219
+ /**
220
+ * Error thrown when adapter fails to load required modules
221
+ */
222
+ var AdapterLoadError = class extends Error {
223
+ constructor(version, cause) {
224
+ super(`Failed to load ${version} adapter: ${cause.message}`);
225
+ this.version = version;
226
+ this.name = "AdapterLoadError";
227
+ }
228
+ };
229
+
230
+ //#endregion
231
+ //#region src/adapters/v3-adapter.ts
232
+ const require$3 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href || __filename);
233
+ async function loadV3ClassMetadata(state, cwd, verbose = false) {
234
+ try {
235
+ const tailwindcss = require$3(require$3.resolve("tailwindcss", { paths: [cwd] }));
236
+ try {
237
+ const tailwindDir = node_path.dirname(require$3.resolve("tailwindcss/package.json", { paths: [cwd] }));
238
+ const contextUtils = require$3(node_path.join(tailwindDir, "lib", "lib", "setupContextUtils"));
239
+ const generateRulesModule = require$3(node_path.join(tailwindDir, "lib", "lib", "generateRules"));
240
+ state.modules = {
241
+ tailwindcss: {
242
+ version: state.version || "unknown",
243
+ module: tailwindcss
244
+ },
245
+ jit: {
246
+ generateRules: { module: generateRulesModule.generateRules || ((_set, _context) => []) },
247
+ createContext: { module: contextUtils.createContext },
248
+ expandApplyAtRules: { module: generateRulesModule.expandApplyAtRules }
249
+ }
250
+ };
251
+ if (verbose) console.log(" ✓ Loaded v3 JIT modules");
252
+ } catch (jitError) {
253
+ if (verbose) {
254
+ const message = jitError instanceof Error ? jitError.message : String(jitError);
255
+ console.log(` ⚠ Warning: Could not load v3 JIT modules: ${message}`);
256
+ }
257
+ state.modules = { tailwindcss: {
258
+ version: state.version || "unknown",
259
+ module: tailwindcss
260
+ } };
261
+ }
262
+ extractConfigMetadata(state);
263
+ } catch (error) {
264
+ if (error instanceof Error) throw new AdapterLoadError("v3", error);
265
+ throw new Error(`Failed to load v3 class metadata: ${String(error)}`);
266
+ }
267
+ }
268
+ function extractConfigMetadata(state) {
269
+ const { config } = state;
270
+ if (!config || typeof config !== "object") return;
271
+ const theme = config.theme;
272
+ state.screens = Object.keys(theme?.screens ?? {});
273
+ state.blocklist = config.blocklist ?? [];
274
+ if (config.variants && typeof config.variants === "object") state.variants = Object.keys(config.variants).map((name) => ({
275
+ name,
276
+ values: [],
277
+ isArbitrary: false,
278
+ hasDash: true,
279
+ selectors: () => []
280
+ }));
281
+ if (config.corePlugins) state.corePlugins = Array.isArray(config.corePlugins) ? config.corePlugins : Object.keys(config.corePlugins);
282
+ }
283
+
284
+ //#endregion
285
+ //#region src/adapters/v4-adapter.ts
286
+ const require$2 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href || __filename);
287
+ function fileExists$2(filePath) {
288
+ try {
289
+ return node_fs.existsSync(filePath);
290
+ } catch {
291
+ return false;
292
+ }
293
+ }
294
+ function readFileSync$2(filePath) {
295
+ if (!filePath || typeof filePath !== "string") throw new TypeError("File path must be a non-empty string");
296
+ return node_fs.readFileSync(filePath, "utf-8");
297
+ }
298
+ async function loadV4DesignSystem(state, cwd, configPath, verbose = false) {
299
+ try {
300
+ const tailwindcss = require$2(require$2.resolve("tailwindcss", { paths: [cwd] }));
301
+ if (tailwindcss !== null && tailwindcss !== void 0 && (typeof tailwindcss === "object" || typeof tailwindcss === "function") && "__unstable__loadDesignSystem" in tailwindcss && typeof tailwindcss.__unstable__loadDesignSystem === "function") {
302
+ let cssContent;
303
+ const basePath = node_path.dirname(configPath);
304
+ if (fileExists$2(configPath)) cssContent = readFileSync$2(configPath, true);
305
+ else cssContent = "@import \"tailwindcss\";";
306
+ const loadDesignSystem = tailwindcss.__unstable__loadDesignSystem;
307
+ const designSystem = await loadDesignSystem(cssContent, {
308
+ base: basePath,
309
+ async loadStylesheet(_id, base, content) {
310
+ if (content) return {
311
+ base,
312
+ content
313
+ };
314
+ if (!_id.startsWith(".") && !_id.startsWith("/")) try {
315
+ const pkgJsonPath = require$2.resolve(`${_id}/package.json`, { paths: [base, cwd] });
316
+ const pkgDir = node_path.dirname(pkgJsonPath);
317
+ const cssPath = node_path.join(pkgDir, "index.css");
318
+ if (fileExists$2(cssPath)) return {
319
+ base: pkgDir,
320
+ content: readFileSync$2(cssPath, true)
321
+ };
322
+ } catch {}
323
+ const filePath = node_path.resolve(base, _id);
324
+ if (fileExists$2(filePath)) return {
325
+ base: node_path.dirname(filePath),
326
+ content: readFileSync$2(filePath, true)
327
+ };
328
+ return {
329
+ base,
330
+ content: ""
331
+ };
332
+ }
333
+ });
334
+ Object.assign(designSystem, {
335
+ dependencies: () => /* @__PURE__ */ new Set(),
336
+ compile(classes) {
337
+ return (designSystem.candidatesToAst ? designSystem.candidatesToAst(classes) : designSystem.candidatesToCss?.(classes) || []).map((result) => {
338
+ if (Array.isArray(result)) return result;
339
+ if (result === null) return [];
340
+ return [];
341
+ });
342
+ }
343
+ });
344
+ state.designSystem = designSystem;
345
+ if (!state.classNames) state.classNames = { context: {} };
346
+ if (verbose) console.log(" ✓ Loaded v4 design system");
347
+ } else throw new AdapterLoadError("v4", /* @__PURE__ */ new Error("Tailwind v4 __unstable__loadDesignSystem is not available. Please ensure you have Tailwind CSS v4 installed."));
348
+ } catch (error) {
349
+ if (error instanceof AdapterLoadError) throw error;
350
+ if (error instanceof Error) throw new AdapterLoadError("v4", error);
351
+ throw new Error(`Failed to load v4 design system: ${String(error)}`);
352
+ }
353
+ }
354
+
355
+ //#endregion
356
+ //#region src/state.ts
357
+ const require$1 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href || __filename);
358
+ function fileExists$1(filePath) {
359
+ try {
360
+ return node_fs.existsSync(filePath);
361
+ } catch {
362
+ return false;
363
+ }
364
+ }
365
+ function readFileSync$1(filePath) {
366
+ if (!filePath || typeof filePath !== "string") throw new TypeError("File path must be a non-empty string");
367
+ return node_fs.readFileSync(filePath, "utf-8");
368
+ }
369
+ function getTailwindVersion(cwd) {
370
+ try {
371
+ const tailwindPackageJson = require$1.resolve("tailwindcss/package.json", { paths: [cwd] });
372
+ return JSON.parse(node_fs.readFileSync(tailwindPackageJson, "utf-8")).version;
373
+ } catch {
374
+ return;
375
+ }
376
+ }
377
+ function isV4Config(version) {
378
+ return version?.startsWith("4.") ?? false;
379
+ }
380
+ function isCssConfigFile$1(filePath) {
381
+ return filePath.endsWith(".css");
382
+ }
383
+ async function loadTailwindConfig$1(configPath) {
384
+ if (isCssConfigFile$1(configPath)) return {};
385
+ if (!node_path.isAbsolute(configPath)) throw new Error(`Config path must be absolute for security reasons: ${configPath}`);
386
+ try {
387
+ delete require$1.cache[configPath];
388
+ const configModule = require$1(configPath);
389
+ const config = "default" in configModule ? configModule.default : configModule;
390
+ if (typeof config !== "object" || config === null) throw new Error("Config must be an object");
391
+ return config;
392
+ } catch (error) {
393
+ const errorMessage = error instanceof Error ? error.message : String(error);
394
+ throw new Error(`Failed to load config from ${configPath}: ${errorMessage}`);
395
+ }
396
+ }
397
+ async function findTailwindConfigPath$1(cwd, configPath) {
398
+ if (configPath) {
399
+ const resolved = node_path.isAbsolute(configPath) ? configPath : node_path.resolve(cwd, configPath);
400
+ return fileExists$1(resolved) ? resolved : null;
401
+ }
402
+ for (const p of require_constants.V3_CONFIG_PATHS) {
403
+ const fullPath = node_path.join(cwd, p);
404
+ if (fileExists$1(fullPath)) return fullPath;
405
+ }
406
+ const v4Paths = require_constants.V4_CSS_FOLDERS.flatMap((folder) => require_constants.V4_CSS_NAMES.map((name) => node_path.join(folder, name)));
407
+ for (const p of v4Paths) {
408
+ const fullPath = node_path.join(cwd, p);
409
+ if (fileExists$1(fullPath)) try {
410
+ const content = readFileSync$1(fullPath);
411
+ if (content.includes("@import \"tailwindcss\"") || content.includes("@import 'tailwindcss'")) return fullPath;
412
+ } catch {}
413
+ }
414
+ return null;
415
+ }
416
+ function resolveTailwindPath(cwd, configDir) {
417
+ const paths = configDir ? [configDir, cwd] : [cwd];
418
+ try {
419
+ return require$1.resolve("tailwindcss", { paths });
420
+ } catch {
421
+ throw new Error(`Could not resolve tailwindcss module from ${paths.join(" or ")}`);
422
+ }
423
+ }
424
+ async function createState(cwd, configPath, verbose = false) {
425
+ const resolvedConfigPath = await findTailwindConfigPath$1(cwd, configPath);
426
+ if (!resolvedConfigPath) throw new Error("Could not find tailwind config file (JS/TS or CSS)");
427
+ const isCssConfig = isCssConfigFile$1(resolvedConfigPath);
428
+ const tailwindcss = require$1(resolveTailwindPath(cwd, node_path.dirname(resolvedConfigPath)));
429
+ const version = getTailwindVersion(cwd);
430
+ const isV4 = isV4Config(version);
431
+ if (verbose) {
432
+ console.log(` Tailwind version: ${version || "unknown"}`);
433
+ console.log(` Config type: ${isCssConfig ? "CSS (v4)" : "JavaScript"}`);
434
+ console.log(` Config path: ${resolvedConfigPath}`);
435
+ }
436
+ let config = {};
437
+ let resolvedConfig = { separator: ":" };
438
+ if (!isCssConfig) {
439
+ config = await loadTailwindConfig$1(resolvedConfigPath);
440
+ resolvedConfig = {
441
+ ...config,
442
+ separator: config.separator ?? require_constants.DEFAULT_SEPARATOR
443
+ };
444
+ if (tailwindcss.resolveConfig) resolvedConfig = tailwindcss.resolveConfig(config);
445
+ }
446
+ const state = {
447
+ enabled: true,
448
+ configPath: resolvedConfigPath,
449
+ config: resolvedConfig,
450
+ version,
451
+ v4: isV4 || void 0,
452
+ separator: resolvedConfig.separator || require_constants.DEFAULT_SEPARATOR,
453
+ screens: [],
454
+ variants: [],
455
+ classNames: void 0,
456
+ classList: void 0,
457
+ modules: void 0,
458
+ blocklist: [],
459
+ editor: createEditorState(cwd),
460
+ features: ["diagnostics"]
461
+ };
462
+ if (isV4 || isCssConfig) await loadV4DesignSystem(state, cwd, resolvedConfigPath, verbose);
463
+ else await loadV3ClassMetadata(state, cwd, verbose);
464
+ return state;
465
+ }
466
+
467
+ //#endregion
468
+ //#region src/linter.ts
469
+ function fileExists(filePath) {
470
+ try {
471
+ return require("node:fs").existsSync(filePath);
472
+ } catch {
473
+ return false;
474
+ }
475
+ }
476
+ function readFileSync(filePath) {
477
+ if (!filePath || typeof filePath !== "string") throw new TypeError("File path must be a non-empty string");
478
+ return require("node:fs").readFileSync(filePath, "utf-8");
479
+ }
480
+ function writeFileSync(filePath, content) {
481
+ if (!filePath || typeof filePath !== "string") throw new TypeError("File path must be a non-empty string");
482
+ if (typeof content !== "string") throw new TypeError("Content must be a string");
483
+ require("node:fs").writeFileSync(filePath, content, "utf-8");
484
+ }
485
+ function serializeDiagnostics(diagnostics) {
486
+ return diagnostics.map((diagnostic) => ({
487
+ range: {
488
+ start: {
489
+ line: diagnostic.range.start.line,
490
+ character: diagnostic.range.start.character
491
+ },
492
+ end: {
493
+ line: diagnostic.range.end.line,
494
+ character: diagnostic.range.end.character
495
+ }
496
+ },
497
+ severity: diagnostic.severity || 2,
498
+ message: diagnostic.message,
499
+ code: diagnostic.code?.toString(),
500
+ source: diagnostic.source
501
+ }));
502
+ }
503
+ function getLanguageId(filePath) {
504
+ return {
505
+ ".astro": "astro",
506
+ ".css": "css",
507
+ ".erb": "erb",
508
+ ".hbs": "handlebars",
509
+ ".htm": "html",
510
+ ".html": "html",
511
+ ".js": "javascript",
512
+ ".jsx": "javascriptreact",
513
+ ".less": "less",
514
+ ".md": "markdown",
515
+ ".mdx": "mdx",
516
+ ".php": "php",
517
+ ".sass": "sass",
518
+ ".scss": "scss",
519
+ ".svelte": "svelte",
520
+ ".ts": "typescript",
521
+ ".tsx": "typescriptreact",
522
+ ".twig": "twig",
523
+ ".vue": "vue"
524
+ }[node_path.extname(filePath).toLowerCase()] || "html";
525
+ }
526
+ async function validateDocument(state, filePath, content) {
527
+ try {
528
+ if (!state) throw new Error("State is not initialized");
529
+ if (state.v4 && !state.designSystem) throw new Error("Design system not initialized for Tailwind v4. This might indicate a configuration issue.");
530
+ if (!state.v4 && !state.modules?.tailwindcss) throw new Error("Tailwind modules not initialized for Tailwind v3. This might indicate a configuration issue.");
531
+ const languageId = getLanguageId(filePath);
532
+ const uri = `file://${filePath}`;
533
+ return serializeDiagnostics(await (0, _tailwindcss_language_service.doValidate)(state, vscode_languageserver_textdocument.TextDocument.create(uri, languageId, 1, content)));
534
+ } catch (error) {
535
+ const message = error instanceof Error ? error.message : String(error);
536
+ throw new Error(`Failed to validate document ${filePath}: ${message}`);
537
+ }
538
+ }
539
+ async function findTailwindConfigPath(cwd, configPath) {
540
+ const { V3_CONFIG_PATHS, V4_CSS_FOLDERS, V4_CSS_NAMES } = await Promise.resolve().then(() => require("./constants-Bstz7FuV.cjs"));
541
+ if (configPath) {
542
+ const resolved = node_path.isAbsolute(configPath) ? configPath : node_path.resolve(cwd, configPath);
543
+ return fileExists(resolved) ? resolved : null;
544
+ }
545
+ for (const p of V3_CONFIG_PATHS) {
546
+ const fullPath = node_path.join(cwd, p);
547
+ if (fileExists(fullPath)) return fullPath;
548
+ }
549
+ const v4Paths = V4_CSS_FOLDERS.flatMap((folder) => V4_CSS_NAMES.map((name) => node_path.join(folder, name)));
550
+ for (const p of v4Paths) {
551
+ const fullPath = node_path.join(cwd, p);
552
+ if (fileExists(fullPath)) try {
553
+ const content = readFileSync(fullPath);
554
+ if (content.includes("@import \"tailwindcss\"") || content.includes("@import 'tailwindcss'")) return fullPath;
555
+ } catch {}
556
+ }
557
+ return null;
558
+ }
559
+ function isCssConfigFile(filePath) {
560
+ return filePath.endsWith(".css");
561
+ }
562
+ async function loadTailwindConfig(configPath) {
563
+ if (isCssConfigFile(configPath)) return {};
564
+ if (!node_path.isAbsolute(configPath)) throw new Error(`Config path must be absolute for security reasons: ${configPath}`);
565
+ try {
566
+ const { createRequire } = await import("node:module");
567
+ const require = createRequire(require("url").pathToFileURL(__filename).href || __filename);
568
+ delete require.cache[configPath];
569
+ const configModule = require(configPath);
570
+ const config = "default" in configModule ? configModule.default : configModule;
571
+ if (typeof config !== "object" || config === null) throw new Error("Config must be an object");
572
+ return config;
573
+ } catch (error) {
574
+ const errorMessage = error instanceof Error ? error.message : String(error);
575
+ throw new Error(`Failed to load config from ${configPath}: ${errorMessage}`);
576
+ }
577
+ }
578
+ async function discoverFiles(cwd, patterns, configPath, autoDiscover) {
579
+ if (autoDiscover) return discoverFilesFromConfig(cwd, configPath);
580
+ return expandPatterns(cwd, patterns);
581
+ }
582
+ async function expandPatterns(cwd, patterns) {
583
+ const explicitFiles = [];
584
+ const globPatterns = [];
585
+ for (const pattern of patterns) if (pattern.includes("*") || pattern.includes("?") || pattern.includes("[")) globPatterns.push(pattern);
586
+ else if (fileExists(node_path.resolve(cwd, pattern))) explicitFiles.push(pattern);
587
+ if (globPatterns.length === 0) return explicitFiles;
588
+ const globResults = await (0, fast_glob.default)(globPatterns, {
589
+ cwd,
590
+ absolute: false,
591
+ ignore: require_constants.DEFAULT_IGNORE_PATTERNS
592
+ });
593
+ if (explicitFiles.length === 0) return globResults;
594
+ const fileSet = new Set(explicitFiles);
595
+ for (const file of globResults) fileSet.add(file);
596
+ return Array.from(fileSet);
597
+ }
598
+ async function discoverFilesFromConfig(cwd, configPath) {
599
+ const configFilePath = await findTailwindConfigPath(cwd, configPath);
600
+ if (!configFilePath) throw new Error("Could not find Tailwind config");
601
+ if (!isCssConfigFile(configFilePath)) {
602
+ const config = await loadTailwindConfig(configFilePath);
603
+ if (!config || !config.content) throw new Error("Could not find Tailwind config or config has no content property");
604
+ const patterns = extractContentPatterns(config);
605
+ if (patterns.length === 0) throw new Error("No content patterns found in Tailwind config");
606
+ return expandPatterns(cwd, patterns);
607
+ }
608
+ throw new Error("Auto-discovery is not supported for CSS-based configs (v4). Please specify file patterns.");
609
+ }
610
+ function extractContentPatterns(config) {
611
+ if (!config.content) return [];
612
+ if (Array.isArray(config.content)) return config.content.filter((p) => typeof p === "string");
613
+ if (config.content.files) return config.content.files.filter((p) => typeof p === "string");
614
+ return [];
615
+ }
616
+ async function processFiles(state, cwd, files, fix, onProgress) {
617
+ const results = [];
618
+ for (let i = 0; i < files.length; i++) {
619
+ if (onProgress) onProgress(i + 1, files.length, files[i]);
620
+ const result = await processFile(state, cwd, files[i], fix);
621
+ if (result) results.push(result);
622
+ }
623
+ return results;
624
+ }
625
+ async function processFile(state, cwd, filePath, fix) {
626
+ const absolutePath = node_path.isAbsolute(filePath) ? filePath : node_path.resolve(cwd, filePath);
627
+ if (!fileExists(absolutePath)) return null;
628
+ let content = readFileSync(absolutePath);
629
+ let diagnostics = await validateDocument(state, absolutePath, content);
630
+ let fixedCount = 0;
631
+ let wasFixed = false;
632
+ if (fix && diagnostics.length > 0) {
633
+ const fixResult = await applyCodeActions(state, absolutePath, content, diagnostics);
634
+ if (fixResult.changed) {
635
+ writeFileSync(absolutePath, fixResult.content);
636
+ content = fixResult.content;
637
+ wasFixed = true;
638
+ fixedCount = fixResult.fixedCount;
639
+ diagnostics = await validateDocument(state, absolutePath, content);
640
+ }
641
+ }
642
+ return {
643
+ path: node_path.relative(cwd, absolutePath),
644
+ diagnostics,
645
+ fixed: wasFixed,
646
+ fixedCount
647
+ };
648
+ }
649
+ async function initializeState(cwd, configPath, verbose = false) {
650
+ try {
651
+ if (verbose) console.log("→ Initializing Tailwind CSS language service...");
652
+ const state = await createState(cwd, configPath, verbose);
653
+ if (verbose) console.log(" ✓ State initialized successfully\n");
654
+ return state;
655
+ } catch (error) {
656
+ const message = error instanceof Error ? error.message : String(error);
657
+ throw new Error(`Failed to initialize Tailwind state: ${message}`);
658
+ }
659
+ }
660
+ async function lint({ cwd, patterns, configPath, autoDiscover, fix = false, verbose = false, onProgress }) {
661
+ const files = await discoverFiles(cwd, patterns, configPath, autoDiscover);
662
+ if (verbose) console.log(`→ Discovered ${files.length} file${files.length !== 1 ? "s" : ""} to lint`);
663
+ if (files.length === 0) return {
664
+ files: [],
665
+ totalFilesProcessed: 0
666
+ };
667
+ return {
668
+ files: (await processFiles(await initializeState(cwd, configPath, verbose), cwd, files, fix, onProgress)).filter((result) => result.diagnostics.length > 0 || result.fixed),
669
+ totalFilesProcessed: files.length
670
+ };
671
+ }
672
+
673
+ //#endregion
674
+ Object.defineProperty(exports, '__toESM', {
675
+ enumerable: true,
676
+ get: function () {
677
+ return __toESM;
678
+ }
679
+ });
680
+ Object.defineProperty(exports, 'lint', {
681
+ enumerable: true,
682
+ get: function () {
683
+ return lint;
684
+ }
685
+ });
686
+ //# sourceMappingURL=linter-QRh7wAZ7.cjs.map