tailwind-lint 0.9.0 → 0.9.2
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 +17 -21
- package/dist/{state-CeRvUDZb.cjs → linter-CEnSDkMA.cjs} +202 -137
- package/dist/linter.cjs +5 -168
- package/dist/linter.d.cts +354 -2
- package/package.json +7 -7
package/dist/cli.cjs
CHANGED
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const
|
|
3
|
-
const require_linter = require('./linter.cjs');
|
|
2
|
+
const require_linter = require("./linter-CEnSDkMA.cjs");
|
|
4
3
|
let node_path = require("node:path");
|
|
5
|
-
node_path =
|
|
4
|
+
node_path = require_linter.__toESM(node_path);
|
|
6
5
|
let ansis = require("ansis");
|
|
7
|
-
ansis =
|
|
6
|
+
ansis = require_linter.__toESM(ansis);
|
|
8
7
|
let node_fs = require("node:fs");
|
|
9
|
-
node_fs =
|
|
8
|
+
node_fs = require_linter.__toESM(node_fs);
|
|
10
9
|
let commander = require("commander");
|
|
11
|
-
|
|
12
10
|
//#region src/output.ts
|
|
13
11
|
function countBySeverity(diagnostics) {
|
|
14
12
|
let errors = 0;
|
|
15
13
|
let warnings = 0;
|
|
16
14
|
for (const diagnostic of diagnostics) {
|
|
17
|
-
if (diagnostic.severity ===
|
|
18
|
-
if (diagnostic.severity ===
|
|
15
|
+
if (diagnostic.severity === require_linter.SEVERITY.ERROR) errors++;
|
|
16
|
+
if (diagnostic.severity === require_linter.SEVERITY.WARNING) warnings++;
|
|
19
17
|
}
|
|
20
18
|
return {
|
|
21
19
|
errors,
|
|
@@ -23,8 +21,8 @@ function countBySeverity(diagnostics) {
|
|
|
23
21
|
};
|
|
24
22
|
}
|
|
25
23
|
function toJsonSeverity(severity) {
|
|
26
|
-
if (severity ===
|
|
27
|
-
if (severity ===
|
|
24
|
+
if (severity === require_linter.SEVERITY.ERROR) return "error";
|
|
25
|
+
if (severity === require_linter.SEVERITY.WARNING) return "warning";
|
|
28
26
|
return "info";
|
|
29
27
|
}
|
|
30
28
|
function toJsonDiagnostic(diagnostic) {
|
|
@@ -76,7 +74,6 @@ function createJsonOutput({ files, totalFilesProcessed, cwd, configPath, autoDis
|
|
|
76
74
|
files: mappedFiles
|
|
77
75
|
};
|
|
78
76
|
}
|
|
79
|
-
|
|
80
77
|
//#endregion
|
|
81
78
|
//#region src/cli.ts
|
|
82
79
|
const MAX_FILENAME_DISPLAY_LENGTH = 50;
|
|
@@ -91,7 +88,7 @@ function resolveOptions(files, options) {
|
|
|
91
88
|
const absoluteConfigPath = node_path.isAbsolute(options.config) ? options.config : node_path.resolve(process.cwd(), options.config);
|
|
92
89
|
cwd = node_path.dirname(absoluteConfigPath);
|
|
93
90
|
configPath = node_path.basename(absoluteConfigPath);
|
|
94
|
-
patterns = [
|
|
91
|
+
patterns = [require_linter.DEFAULT_FILE_PATTERN];
|
|
95
92
|
}
|
|
96
93
|
const autoDiscover = hasAutoFlag;
|
|
97
94
|
return {
|
|
@@ -130,8 +127,8 @@ async function displayResults(files, fixMode) {
|
|
|
130
127
|
for (const diagnostic of file.diagnostics) {
|
|
131
128
|
const line = diagnostic.range.start.line + 1;
|
|
132
129
|
const char = diagnostic.range.start.character + 1;
|
|
133
|
-
const severity = diagnostic.severity ===
|
|
134
|
-
const severityColor = diagnostic.severity ===
|
|
130
|
+
const severity = diagnostic.severity === require_linter.SEVERITY.ERROR ? "error" : "warning";
|
|
131
|
+
const severityColor = diagnostic.severity === require_linter.SEVERITY.ERROR ? ansis.default.red(severity) : ansis.default.yellow(severity);
|
|
135
132
|
const code = diagnostic.code ? ansis.default.dim(` (${diagnostic.code})`) : "";
|
|
136
133
|
console.log(` ${ansis.default.dim(`${line}:${char}`)} ${severityColor} ${diagnostic.message}${code}`);
|
|
137
134
|
}
|
|
@@ -158,9 +155,9 @@ const program = new commander.Command();
|
|
|
158
155
|
const getVersion = () => {
|
|
159
156
|
const packageJsonPath = node_path.join(__dirname, "../package.json");
|
|
160
157
|
try {
|
|
161
|
-
return JSON.parse(node_fs.readFileSync(packageJsonPath, "utf-8")).version ||
|
|
158
|
+
return JSON.parse(node_fs.readFileSync(packageJsonPath, "utf-8")).version || "0.0.1";
|
|
162
159
|
} catch {
|
|
163
|
-
return
|
|
160
|
+
return require_linter.DEFAULT_VERSION;
|
|
164
161
|
}
|
|
165
162
|
};
|
|
166
163
|
program.configureHelp({ formatHelp: (cmd, helper) => {
|
|
@@ -224,11 +221,11 @@ ${ansis.default.bold.cyan("Notes:")}
|
|
|
224
221
|
if (isJsonOutput) return;
|
|
225
222
|
if (process.stdout.isTTY && !resolved.verbose) {
|
|
226
223
|
const displayFile = truncateFilename(file);
|
|
227
|
-
process.stdout.write(`\r${ansis.default.cyan("→")} Linting files... ${ansis.default.dim(`(${current}/${total})`)} ${ansis.default.dim(displayFile)}${" ".repeat(
|
|
224
|
+
process.stdout.write(`\r${ansis.default.cyan("→")} Linting files... ${ansis.default.dim(`(${current}/${total})`)} ${ansis.default.dim(displayFile)}${" ".repeat(10)}`);
|
|
228
225
|
} else if (resolved.verbose) console.log(ansis.default.dim(` [${current}/${total}] Linting ${file}`));
|
|
229
226
|
}
|
|
230
227
|
});
|
|
231
|
-
if (process.stdout.isTTY && !resolved.verbose && !isJsonOutput) process.stdout.write(`\r${" ".repeat(
|
|
228
|
+
if (process.stdout.isTTY && !resolved.verbose && !isJsonOutput) process.stdout.write(`\r${" ".repeat(80)}\r`);
|
|
232
229
|
if (results.totalFilesProcessed === 0) {
|
|
233
230
|
if (isJsonOutput) console.log(JSON.stringify(createJsonOutput({
|
|
234
231
|
...resolved,
|
|
@@ -256,7 +253,7 @@ ${ansis.default.bold.cyan("Notes:")}
|
|
|
256
253
|
totalFilesProcessed: results.totalFilesProcessed
|
|
257
254
|
})));
|
|
258
255
|
else await displayResults(results.files, resolved.fix);
|
|
259
|
-
const hasErrors = results.files.some((file) => file.diagnostics.some((d) => d.severity ===
|
|
256
|
+
const hasErrors = results.files.some((file) => file.diagnostics.some((d) => d.severity === require_linter.SEVERITY.ERROR));
|
|
260
257
|
process.exit(hasErrors ? 1 : 0);
|
|
261
258
|
} catch (error) {
|
|
262
259
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -273,5 +270,4 @@ ${ansis.default.bold.cyan("Notes:")}
|
|
|
273
270
|
}
|
|
274
271
|
});
|
|
275
272
|
program.parse();
|
|
276
|
-
|
|
277
|
-
//#endregion
|
|
273
|
+
//#endregion
|
|
@@ -6,16 +6,12 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
8
|
var __copyProps = (to, from, except, desc) => {
|
|
9
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
}
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
19
15
|
}
|
|
20
16
|
return to;
|
|
21
17
|
};
|
|
@@ -23,7 +19,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
19
|
value: mod,
|
|
24
20
|
enumerable: true
|
|
25
21
|
}) : target, mod));
|
|
26
|
-
|
|
27
22
|
//#endregion
|
|
28
23
|
let node_path = require("node:path");
|
|
29
24
|
node_path = __toESM(node_path);
|
|
@@ -37,7 +32,6 @@ let node_fs = require("node:fs");
|
|
|
37
32
|
node_fs = __toESM(node_fs);
|
|
38
33
|
let postcss = require("postcss");
|
|
39
34
|
postcss = __toESM(postcss);
|
|
40
|
-
|
|
41
35
|
//#region src/constants.ts
|
|
42
36
|
const DEFAULT_IGNORE_PATTERNS = [
|
|
43
37
|
"**/node_modules/**",
|
|
@@ -110,23 +104,14 @@ const LANGUAGE_MAP = {
|
|
|
110
104
|
".vue": "vue"
|
|
111
105
|
};
|
|
112
106
|
const DEFAULT_VERSION = "0.0.1";
|
|
113
|
-
const DEFAULT_TAB_SIZE = 2;
|
|
114
|
-
const DEFAULT_SEPARATOR = ":";
|
|
115
|
-
const DEFAULT_ROOT_FONT_SIZE = 16;
|
|
116
|
-
const CONCURRENT_FILES = 10;
|
|
117
107
|
const SEVERITY = {
|
|
118
108
|
ERROR: 1,
|
|
119
109
|
WARNING: 2
|
|
120
110
|
};
|
|
121
|
-
const TERMINAL_WIDTH = 80;
|
|
122
|
-
const TERMINAL_PADDING = 10;
|
|
123
|
-
const MAX_FIX_ITERATIONS = 100;
|
|
124
|
-
const QUICKFIX_ACTION_KIND = "quickfix";
|
|
125
111
|
const TAILWIND_V4_IMPORT_REGEX = /@import\s+["']tailwindcss(?:["'\s/]|$)/;
|
|
126
112
|
function getLanguageId(filePath) {
|
|
127
113
|
return LANGUAGE_MAP[filePath.substring(filePath.lastIndexOf(".")).toLowerCase()] || "html";
|
|
128
114
|
}
|
|
129
|
-
|
|
130
115
|
//#endregion
|
|
131
116
|
//#region src/code-actions.ts
|
|
132
117
|
async function getQuickfixes(state, document, uri, diagnostics) {
|
|
@@ -150,7 +135,7 @@ async function getQuickfixes(state, document, uri, diagnostics) {
|
|
|
150
135
|
}
|
|
151
136
|
},
|
|
152
137
|
context: { diagnostics: lspDiagnostics }
|
|
153
|
-
}, document)).filter((action) => action.kind ===
|
|
138
|
+
}, document)).filter((action) => action.kind === "quickfix" || action.kind?.startsWith(`quickfix.`));
|
|
154
139
|
}
|
|
155
140
|
function applyFirstQuickfix(action, uri, document, content) {
|
|
156
141
|
if (!action.edit?.changes?.[uri]) return null;
|
|
@@ -179,7 +164,7 @@ async function applyCodeActions(state, filePath, content, diagnostics) {
|
|
|
179
164
|
let currentDocument = vscode_languageserver_textdocument.TextDocument.create(uri, languageId, 1, content);
|
|
180
165
|
let currentContent = content;
|
|
181
166
|
let totalFixed = 0;
|
|
182
|
-
for (let iteration = 0; iteration <
|
|
167
|
+
for (let iteration = 0; iteration < 100; iteration++) {
|
|
183
168
|
const currentDiagnostics = await (0, _tailwindcss_language_service.doValidate)(state, currentDocument);
|
|
184
169
|
if (currentDiagnostics.length === 0) break;
|
|
185
170
|
const quickfixes = await getQuickfixes(state, currentDocument, uri, currentDiagnostics);
|
|
@@ -189,7 +174,7 @@ async function applyCodeActions(state, filePath, content, diagnostics) {
|
|
|
189
174
|
currentContent = fixResult.content;
|
|
190
175
|
currentDocument = vscode_languageserver_textdocument.TextDocument.create(uri, languageId, currentDocument.version + 1, currentContent);
|
|
191
176
|
totalFixed++;
|
|
192
|
-
if (iteration ===
|
|
177
|
+
if (iteration === 99) console.warn(`Warning: Reached maximum fix iterations (100) for ${filePath}. Some issues may remain unfixed.`);
|
|
193
178
|
}
|
|
194
179
|
return {
|
|
195
180
|
content: currentContent,
|
|
@@ -209,7 +194,6 @@ async function applyCodeActions(state, filePath, content, diagnostics) {
|
|
|
209
194
|
throw error;
|
|
210
195
|
}
|
|
211
196
|
}
|
|
212
|
-
|
|
213
197
|
//#endregion
|
|
214
198
|
//#region src/adapters/editor-state-adapter.ts
|
|
215
199
|
function isDirectory(filePath) {
|
|
@@ -221,7 +205,7 @@ function isDirectory(filePath) {
|
|
|
221
205
|
}
|
|
222
206
|
function createEditorState(cwd) {
|
|
223
207
|
const settings = {
|
|
224
|
-
editor: { tabSize:
|
|
208
|
+
editor: { tabSize: 2 },
|
|
225
209
|
tailwindCSS: {
|
|
226
210
|
validate: true,
|
|
227
211
|
inspectPort: null,
|
|
@@ -244,7 +228,7 @@ function createEditorState(cwd) {
|
|
|
244
228
|
codeLens: false,
|
|
245
229
|
suggestions: true,
|
|
246
230
|
colorDecorators: true,
|
|
247
|
-
rootFontSize:
|
|
231
|
+
rootFontSize: 16,
|
|
248
232
|
showPixelEquivalents: true,
|
|
249
233
|
files: { exclude: [
|
|
250
234
|
"**/.git/**",
|
|
@@ -292,7 +276,6 @@ function createEditorState(cwd) {
|
|
|
292
276
|
}
|
|
293
277
|
};
|
|
294
278
|
}
|
|
295
|
-
|
|
296
279
|
//#endregion
|
|
297
280
|
//#region src/types.ts
|
|
298
281
|
/**
|
|
@@ -305,7 +288,6 @@ var AdapterLoadError = class extends Error {
|
|
|
305
288
|
this.name = "AdapterLoadError";
|
|
306
289
|
}
|
|
307
290
|
};
|
|
308
|
-
|
|
309
291
|
//#endregion
|
|
310
292
|
//#region src/adapters/v3-adapter.ts
|
|
311
293
|
const require$4 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href || __filename);
|
|
@@ -372,7 +354,6 @@ function extractConfigMetadata(state) {
|
|
|
372
354
|
}));
|
|
373
355
|
if (config.corePlugins) state.corePlugins = Array.isArray(config.corePlugins) ? config.corePlugins : Object.keys(config.corePlugins);
|
|
374
356
|
}
|
|
375
|
-
|
|
376
357
|
//#endregion
|
|
377
358
|
//#region src/utils/fs.ts
|
|
378
359
|
function fileExists(filePath) {
|
|
@@ -404,7 +385,6 @@ function readGitignorePatterns(cwd) {
|
|
|
404
385
|
return [];
|
|
405
386
|
}
|
|
406
387
|
}
|
|
407
|
-
|
|
408
388
|
//#endregion
|
|
409
389
|
//#region src/adapters/v4-adapter.ts
|
|
410
390
|
const require$3 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href || __filename);
|
|
@@ -480,7 +460,6 @@ async function loadV4DesignSystem(state, cwd, configPath, verbose = false) {
|
|
|
480
460
|
throw new Error(`Failed to load v4 design system: ${String(error)}`);
|
|
481
461
|
}
|
|
482
462
|
}
|
|
483
|
-
|
|
484
463
|
//#endregion
|
|
485
464
|
//#region src/utils/config.ts
|
|
486
465
|
const require$2 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href || __filename);
|
|
@@ -572,7 +551,6 @@ function isPreferredCssFolder(relativePath) {
|
|
|
572
551
|
function splitDepth(value) {
|
|
573
552
|
return value.split(/[\\/]/).filter(Boolean).length;
|
|
574
553
|
}
|
|
575
|
-
|
|
576
554
|
//#endregion
|
|
577
555
|
//#region src/state.ts
|
|
578
556
|
const require$1 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href || __filename);
|
|
@@ -615,7 +593,7 @@ async function createState(cwd, configPath, verbose = false) {
|
|
|
615
593
|
config = await loadTailwindConfig(resolvedConfigPath);
|
|
616
594
|
resolvedConfig = {
|
|
617
595
|
...config,
|
|
618
|
-
separator: config.separator ??
|
|
596
|
+
separator: config.separator ?? ":"
|
|
619
597
|
};
|
|
620
598
|
if (tailwindcss.resolveConfig) resolvedConfig = tailwindcss.resolveConfig(config);
|
|
621
599
|
}
|
|
@@ -625,7 +603,7 @@ async function createState(cwd, configPath, verbose = false) {
|
|
|
625
603
|
config: resolvedConfig,
|
|
626
604
|
version,
|
|
627
605
|
v4: isV4 || void 0,
|
|
628
|
-
separator: resolvedConfig.separator ||
|
|
606
|
+
separator: resolvedConfig.separator || ":",
|
|
629
607
|
screens: [],
|
|
630
608
|
variants: [],
|
|
631
609
|
classNames: void 0,
|
|
@@ -639,113 +617,200 @@ async function createState(cwd, configPath, verbose = false) {
|
|
|
639
617
|
else await loadV3ClassMetadata(state, cwd, verbose);
|
|
640
618
|
return state;
|
|
641
619
|
}
|
|
642
|
-
|
|
643
620
|
//#endregion
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
});
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
621
|
+
//#region src/linter.ts
|
|
622
|
+
async function validateDocument(state, filePath, content) {
|
|
623
|
+
try {
|
|
624
|
+
if (!state) throw new Error("State is not initialized");
|
|
625
|
+
if (state.v4 && !state.designSystem) throw new Error("Design system not initialized for Tailwind v4. This might indicate a configuration issue.");
|
|
626
|
+
if (!state.v4 && !state.modules?.tailwindcss) throw new Error("Tailwind modules not initialized for Tailwind v3. This might indicate a configuration issue.");
|
|
627
|
+
const languageId = getLanguageId(filePath);
|
|
628
|
+
const uri = `file://${filePath}`;
|
|
629
|
+
return await (0, _tailwindcss_language_service.doValidate)(state, vscode_languageserver_textdocument.TextDocument.create(uri, languageId, 1, content));
|
|
630
|
+
} catch (error) {
|
|
631
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
632
|
+
if (message.includes("Cannot read") || message.includes("undefined")) {
|
|
633
|
+
if (process.env.DEBUG) console.error(`Debug: Language service error for ${filePath}:`, error);
|
|
634
|
+
console.warn(`Warning: Language service crashed while validating ${filePath}. Skipping this file.`);
|
|
635
|
+
return [];
|
|
636
|
+
}
|
|
637
|
+
throw new Error(`Failed to validate document ${filePath}: ${message}`);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
async function discoverFiles(cwd, patterns, configPath, autoDiscover) {
|
|
641
|
+
if (autoDiscover) return discoverFilesFromConfig(cwd, configPath);
|
|
642
|
+
return expandPatterns(cwd, patterns);
|
|
643
|
+
}
|
|
644
|
+
async function expandPatterns(cwd, patterns, extraIgnore = []) {
|
|
645
|
+
const files = await (0, tinyglobby.glob)(patterns, {
|
|
646
|
+
cwd,
|
|
647
|
+
absolute: false,
|
|
648
|
+
ignore: [...DEFAULT_IGNORE_PATTERNS, ...extraIgnore]
|
|
649
|
+
});
|
|
650
|
+
return [...new Set(files)].sort((a, b) => a.localeCompare(b));
|
|
651
|
+
}
|
|
652
|
+
async function discoverFilesFromConfig(cwd, configPath) {
|
|
653
|
+
const configFilePath = await findTailwindConfigPath(cwd, configPath);
|
|
654
|
+
if (!configFilePath) throw new Error("Could not find Tailwind config for auto-discovery.\nUse --config to specify the path, or provide file patterns directly.");
|
|
655
|
+
if (!isCssConfigFile(configFilePath)) {
|
|
656
|
+
const config = await loadTailwindConfig(configFilePath);
|
|
657
|
+
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}']");
|
|
658
|
+
const patterns = extractContentPatterns(config);
|
|
659
|
+
if (patterns.length === 0) throw new Error("No content patterns found in Tailwind config.\nEnsure your config has a content array with file patterns.");
|
|
660
|
+
return expandPatterns(cwd, patterns);
|
|
661
|
+
}
|
|
662
|
+
const configDir = node_path.dirname(configFilePath);
|
|
663
|
+
const cssContent = readFileSync(configFilePath);
|
|
664
|
+
const { include, exclude } = extractSourcePatterns(cssContent);
|
|
665
|
+
const importSource = extractImportSourceDirectives(cssContent);
|
|
666
|
+
const resolveFromConfig = (pattern) => {
|
|
667
|
+
const absolutePattern = node_path.resolve(configDir, pattern);
|
|
668
|
+
return node_path.relative(cwd, absolutePattern);
|
|
669
|
+
};
|
|
670
|
+
const resolvedExclude = exclude.map(resolveFromConfig);
|
|
671
|
+
const gitignorePatterns = readGitignorePatterns(cwd);
|
|
672
|
+
const extraIgnore = [...resolvedExclude, ...gitignorePatterns];
|
|
673
|
+
if (include.length > 0) return expandPatterns(cwd, include.map(resolveFromConfig), extraIgnore);
|
|
674
|
+
if (importSource.roots.length > 0) return expandPatterns(cwd, importSource.roots.map((root) => resolveFromConfig(node_path.join(root, "**/*.{js,jsx,ts,tsx,html,vue,svelte,astro,mdx}"))), extraIgnore);
|
|
675
|
+
if (importSource.disableAutoSource) return [];
|
|
676
|
+
return expandPatterns(cwd, [DEFAULT_FILE_PATTERN], extraIgnore);
|
|
677
|
+
}
|
|
678
|
+
function extractContentPatterns(config) {
|
|
679
|
+
if (!config.content) return [];
|
|
680
|
+
return (Array.isArray(config.content) ? config.content : config.content.files || []).filter((p) => typeof p === "string");
|
|
681
|
+
}
|
|
682
|
+
function extractSourcePatterns(cssContent) {
|
|
683
|
+
const include = [];
|
|
684
|
+
const exclude = [];
|
|
685
|
+
for (const match of cssContent.matchAll(/@source\s+(not\s+)?(?:inline\(|["']([^"']+)["'])/g)) {
|
|
686
|
+
const isNot = !!match[1];
|
|
687
|
+
const filePath = match[2];
|
|
688
|
+
if (!filePath) continue;
|
|
689
|
+
if (isNot) exclude.push(filePath);
|
|
690
|
+
else include.push(filePath);
|
|
691
|
+
}
|
|
692
|
+
return {
|
|
693
|
+
include,
|
|
694
|
+
exclude
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
function extractImportSourceDirectives(cssContent) {
|
|
698
|
+
const roots = [];
|
|
699
|
+
let disableAutoSource = false;
|
|
700
|
+
for (const match of cssContent.matchAll(/@import\s+["']tailwindcss(?:[^;]*?)\ssource\(\s*(none|["'][^"']+["'])\s*\)/g)) {
|
|
701
|
+
const raw = match[1];
|
|
702
|
+
if (!raw) continue;
|
|
703
|
+
if (raw === "none") {
|
|
704
|
+
disableAutoSource = true;
|
|
705
|
+
continue;
|
|
706
|
+
}
|
|
707
|
+
const sourceRoot = raw.slice(1, -1).trim();
|
|
708
|
+
if (sourceRoot.length > 0) roots.push(sourceRoot);
|
|
709
|
+
}
|
|
710
|
+
return {
|
|
711
|
+
roots: [...new Set(roots)],
|
|
712
|
+
disableAutoSource
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
async function processFiles(state, cwd, files, fix, onProgress) {
|
|
716
|
+
const results = [];
|
|
717
|
+
for (let i = 0; i < files.length; i += 10) {
|
|
718
|
+
const batch = files.slice(i, i + 10);
|
|
719
|
+
const batchResults = await Promise.all(batch.map(async (file, batchIndex) => {
|
|
720
|
+
if (onProgress) onProgress(i + batchIndex + 1, files.length, file);
|
|
721
|
+
return processFile(state, cwd, file, fix);
|
|
722
|
+
}));
|
|
723
|
+
results.push(...batchResults.filter((r) => r !== null));
|
|
724
|
+
}
|
|
725
|
+
return results;
|
|
726
|
+
}
|
|
727
|
+
async function processFile(state, cwd, filePath, fix) {
|
|
728
|
+
const absolutePath = node_path.isAbsolute(filePath) ? filePath : node_path.resolve(cwd, filePath);
|
|
729
|
+
if (!fileExists(absolutePath)) return null;
|
|
730
|
+
const content = readFileSync(absolutePath);
|
|
731
|
+
let diagnostics = await validateDocument(state, absolutePath, content);
|
|
732
|
+
let fixedCount = 0;
|
|
733
|
+
if (fix && diagnostics.length > 0) {
|
|
734
|
+
const fixResult = await applyCodeActions(state, absolutePath, content, diagnostics);
|
|
735
|
+
if (fixResult.changed) {
|
|
736
|
+
writeFileSync(absolutePath, fixResult.content);
|
|
737
|
+
fixedCount = fixResult.fixedCount;
|
|
738
|
+
diagnostics = await validateDocument(state, absolutePath, fixResult.content);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
return {
|
|
742
|
+
path: node_path.relative(cwd, absolutePath),
|
|
743
|
+
diagnostics,
|
|
744
|
+
fixed: fixedCount > 0,
|
|
745
|
+
fixedCount
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
async function initializeState(cwd, configPath, verbose = false) {
|
|
749
|
+
try {
|
|
750
|
+
const state = await createState(cwd, configPath, verbose);
|
|
751
|
+
if (verbose) console.log();
|
|
752
|
+
return state;
|
|
753
|
+
} catch (error) {
|
|
754
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
755
|
+
throw new Error(`Failed to initialize Tailwind state: ${message}`);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
async function lint({ cwd, patterns, configPath, autoDiscover, fix = false, verbose = false, onProgress }) {
|
|
759
|
+
const state = await initializeState(cwd, configPath, verbose);
|
|
760
|
+
const files = await discoverFiles(cwd, patterns, configPath, autoDiscover);
|
|
761
|
+
if (verbose) {
|
|
762
|
+
console.log(ansis.default.cyan.bold(`→ Discovered ${files.length} file${files.length !== 1 ? "s" : ""} to lint`));
|
|
763
|
+
console.log();
|
|
764
|
+
}
|
|
765
|
+
if (files.length === 0) return {
|
|
766
|
+
files: [],
|
|
767
|
+
totalFilesProcessed: 0
|
|
768
|
+
};
|
|
769
|
+
return {
|
|
770
|
+
files: (await processFiles(state, cwd, files, fix, onProgress)).filter((result) => result.diagnostics.length > 0 || result.fixed),
|
|
771
|
+
totalFilesProcessed: files.length
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
//#endregion
|
|
775
|
+
Object.defineProperty(exports, "DEFAULT_FILE_PATTERN", {
|
|
776
|
+
enumerable: true,
|
|
777
|
+
get: function() {
|
|
778
|
+
return DEFAULT_FILE_PATTERN;
|
|
779
|
+
}
|
|
709
780
|
});
|
|
710
|
-
Object.defineProperty(exports,
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
781
|
+
Object.defineProperty(exports, "DEFAULT_VERSION", {
|
|
782
|
+
enumerable: true,
|
|
783
|
+
get: function() {
|
|
784
|
+
return DEFAULT_VERSION;
|
|
785
|
+
}
|
|
715
786
|
});
|
|
716
|
-
Object.defineProperty(exports,
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
787
|
+
Object.defineProperty(exports, "SEVERITY", {
|
|
788
|
+
enumerable: true,
|
|
789
|
+
get: function() {
|
|
790
|
+
return SEVERITY;
|
|
791
|
+
}
|
|
721
792
|
});
|
|
722
|
-
Object.defineProperty(exports,
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
793
|
+
Object.defineProperty(exports, "__toESM", {
|
|
794
|
+
enumerable: true,
|
|
795
|
+
get: function() {
|
|
796
|
+
return __toESM;
|
|
797
|
+
}
|
|
727
798
|
});
|
|
728
|
-
Object.defineProperty(exports,
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
799
|
+
Object.defineProperty(exports, "extractImportSourceDirectives", {
|
|
800
|
+
enumerable: true,
|
|
801
|
+
get: function() {
|
|
802
|
+
return extractImportSourceDirectives;
|
|
803
|
+
}
|
|
733
804
|
});
|
|
734
|
-
Object.defineProperty(exports,
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
805
|
+
Object.defineProperty(exports, "extractSourcePatterns", {
|
|
806
|
+
enumerable: true,
|
|
807
|
+
get: function() {
|
|
808
|
+
return extractSourcePatterns;
|
|
809
|
+
}
|
|
739
810
|
});
|
|
740
|
-
Object.defineProperty(exports,
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
811
|
+
Object.defineProperty(exports, "lint", {
|
|
812
|
+
enumerable: true,
|
|
813
|
+
get: function() {
|
|
814
|
+
return lint;
|
|
815
|
+
}
|
|
745
816
|
});
|
|
746
|
-
Object.defineProperty(exports, 'writeFileSync', {
|
|
747
|
-
enumerable: true,
|
|
748
|
-
get: function () {
|
|
749
|
-
return writeFileSync;
|
|
750
|
-
}
|
|
751
|
-
});
|
package/dist/linter.cjs
CHANGED
|
@@ -1,168 +1,5 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value:
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
let ansis = require("ansis");
|
|
7
|
-
ansis = require_state.__toESM(ansis);
|
|
8
|
-
let tinyglobby = require("tinyglobby");
|
|
9
|
-
let vscode_languageserver_textdocument = require("vscode-languageserver-textdocument");
|
|
10
|
-
|
|
11
|
-
//#region src/linter.ts
|
|
12
|
-
async function validateDocument(state, filePath, content) {
|
|
13
|
-
try {
|
|
14
|
-
if (!state) throw new Error("State is not initialized");
|
|
15
|
-
if (state.v4 && !state.designSystem) throw new Error("Design system not initialized for Tailwind v4. This might indicate a configuration issue.");
|
|
16
|
-
if (!state.v4 && !state.modules?.tailwindcss) throw new Error("Tailwind modules not initialized for Tailwind v3. This might indicate a configuration issue.");
|
|
17
|
-
const languageId = require_state.getLanguageId(filePath);
|
|
18
|
-
const uri = `file://${filePath}`;
|
|
19
|
-
return await (0, _tailwindcss_language_service.doValidate)(state, vscode_languageserver_textdocument.TextDocument.create(uri, languageId, 1, content));
|
|
20
|
-
} catch (error) {
|
|
21
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
22
|
-
if (message.includes("Cannot read") || message.includes("undefined")) {
|
|
23
|
-
if (process.env.DEBUG) console.error(`Debug: Language service error for ${filePath}:`, error);
|
|
24
|
-
console.warn(`Warning: Language service crashed while validating ${filePath}. Skipping this file.`);
|
|
25
|
-
return [];
|
|
26
|
-
}
|
|
27
|
-
throw new Error(`Failed to validate document ${filePath}: ${message}`);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
async function discoverFiles(cwd, patterns, configPath, autoDiscover) {
|
|
31
|
-
if (autoDiscover) return discoverFilesFromConfig(cwd, configPath);
|
|
32
|
-
return expandPatterns(cwd, patterns);
|
|
33
|
-
}
|
|
34
|
-
async function expandPatterns(cwd, patterns, extraIgnore = []) {
|
|
35
|
-
const files = await (0, tinyglobby.glob)(patterns, {
|
|
36
|
-
cwd,
|
|
37
|
-
absolute: false,
|
|
38
|
-
ignore: [...require_state.DEFAULT_IGNORE_PATTERNS, ...extraIgnore]
|
|
39
|
-
});
|
|
40
|
-
return [...new Set(files)].sort((a, b) => a.localeCompare(b));
|
|
41
|
-
}
|
|
42
|
-
async function discoverFilesFromConfig(cwd, configPath) {
|
|
43
|
-
const configFilePath = await require_state.findTailwindConfigPath(cwd, configPath);
|
|
44
|
-
if (!configFilePath) throw new Error("Could not find Tailwind config for auto-discovery.\nUse --config to specify the path, or provide file patterns directly.");
|
|
45
|
-
if (!require_state.isCssConfigFile(configFilePath)) {
|
|
46
|
-
const config = await require_state.loadTailwindConfig(configFilePath);
|
|
47
|
-
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}']");
|
|
48
|
-
const patterns = extractContentPatterns(config);
|
|
49
|
-
if (patterns.length === 0) throw new Error("No content patterns found in Tailwind config.\nEnsure your config has a content array with file patterns.");
|
|
50
|
-
return expandPatterns(cwd, patterns);
|
|
51
|
-
}
|
|
52
|
-
const configDir = node_path.dirname(configFilePath);
|
|
53
|
-
const cssContent = require_state.readFileSync(configFilePath);
|
|
54
|
-
const { include, exclude } = extractSourcePatterns(cssContent);
|
|
55
|
-
const importSource = extractImportSourceDirectives(cssContent);
|
|
56
|
-
const resolveFromConfig = (pattern) => {
|
|
57
|
-
const absolutePattern = node_path.resolve(configDir, pattern);
|
|
58
|
-
return node_path.relative(cwd, absolutePattern);
|
|
59
|
-
};
|
|
60
|
-
const resolvedExclude = exclude.map(resolveFromConfig);
|
|
61
|
-
const gitignorePatterns = require_state.readGitignorePatterns(cwd);
|
|
62
|
-
const extraIgnore = [...resolvedExclude, ...gitignorePatterns];
|
|
63
|
-
if (include.length > 0) return expandPatterns(cwd, include.map(resolveFromConfig), extraIgnore);
|
|
64
|
-
if (importSource.roots.length > 0) return expandPatterns(cwd, importSource.roots.map((root) => resolveFromConfig(node_path.join(root, "**/*.{js,jsx,ts,tsx,html,vue,svelte,astro,mdx}"))), extraIgnore);
|
|
65
|
-
if (importSource.disableAutoSource) return [];
|
|
66
|
-
return expandPatterns(cwd, [require_state.DEFAULT_FILE_PATTERN], extraIgnore);
|
|
67
|
-
}
|
|
68
|
-
function extractContentPatterns(config) {
|
|
69
|
-
if (!config.content) return [];
|
|
70
|
-
return (Array.isArray(config.content) ? config.content : config.content.files || []).filter((p) => typeof p === "string");
|
|
71
|
-
}
|
|
72
|
-
function extractSourcePatterns(cssContent) {
|
|
73
|
-
const include = [];
|
|
74
|
-
const exclude = [];
|
|
75
|
-
for (const match of cssContent.matchAll(/@source\s+(not\s+)?(?:inline\(|["']([^"']+)["'])/g)) {
|
|
76
|
-
const isNot = !!match[1];
|
|
77
|
-
const filePath = match[2];
|
|
78
|
-
if (!filePath) continue;
|
|
79
|
-
if (isNot) exclude.push(filePath);
|
|
80
|
-
else include.push(filePath);
|
|
81
|
-
}
|
|
82
|
-
return {
|
|
83
|
-
include,
|
|
84
|
-
exclude
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
function extractImportSourceDirectives(cssContent) {
|
|
88
|
-
const roots = [];
|
|
89
|
-
let disableAutoSource = false;
|
|
90
|
-
for (const match of cssContent.matchAll(/@import\s+["']tailwindcss(?:[^;]*?)\ssource\(\s*(none|["'][^"']+["'])\s*\)/g)) {
|
|
91
|
-
const raw = match[1];
|
|
92
|
-
if (!raw) continue;
|
|
93
|
-
if (raw === "none") {
|
|
94
|
-
disableAutoSource = true;
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
const sourceRoot = raw.slice(1, -1).trim();
|
|
98
|
-
if (sourceRoot.length > 0) roots.push(sourceRoot);
|
|
99
|
-
}
|
|
100
|
-
return {
|
|
101
|
-
roots: [...new Set(roots)],
|
|
102
|
-
disableAutoSource
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
async function processFiles(state, cwd, files, fix, onProgress) {
|
|
106
|
-
const results = [];
|
|
107
|
-
for (let i = 0; i < files.length; i += require_state.CONCURRENT_FILES) {
|
|
108
|
-
const batch = files.slice(i, i + require_state.CONCURRENT_FILES);
|
|
109
|
-
const batchResults = await Promise.all(batch.map(async (file, batchIndex) => {
|
|
110
|
-
if (onProgress) onProgress(i + batchIndex + 1, files.length, file);
|
|
111
|
-
return processFile(state, cwd, file, fix);
|
|
112
|
-
}));
|
|
113
|
-
results.push(...batchResults.filter((r) => r !== null));
|
|
114
|
-
}
|
|
115
|
-
return results;
|
|
116
|
-
}
|
|
117
|
-
async function processFile(state, cwd, filePath, fix) {
|
|
118
|
-
const absolutePath = node_path.isAbsolute(filePath) ? filePath : node_path.resolve(cwd, filePath);
|
|
119
|
-
if (!require_state.fileExists(absolutePath)) return null;
|
|
120
|
-
const content = require_state.readFileSync(absolutePath);
|
|
121
|
-
let diagnostics = await validateDocument(state, absolutePath, content);
|
|
122
|
-
let fixedCount = 0;
|
|
123
|
-
if (fix && diagnostics.length > 0) {
|
|
124
|
-
const fixResult = await require_state.applyCodeActions(state, absolutePath, content, diagnostics);
|
|
125
|
-
if (fixResult.changed) {
|
|
126
|
-
require_state.writeFileSync(absolutePath, fixResult.content);
|
|
127
|
-
fixedCount = fixResult.fixedCount;
|
|
128
|
-
diagnostics = await validateDocument(state, absolutePath, fixResult.content);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return {
|
|
132
|
-
path: node_path.relative(cwd, absolutePath),
|
|
133
|
-
diagnostics,
|
|
134
|
-
fixed: fixedCount > 0,
|
|
135
|
-
fixedCount
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
async function initializeState(cwd, configPath, verbose = false) {
|
|
139
|
-
try {
|
|
140
|
-
const state = await require_state.createState(cwd, configPath, verbose);
|
|
141
|
-
if (verbose) console.log();
|
|
142
|
-
return state;
|
|
143
|
-
} catch (error) {
|
|
144
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
145
|
-
throw new Error(`Failed to initialize Tailwind state: ${message}`);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
async function lint({ cwd, patterns, configPath, autoDiscover, fix = false, verbose = false, onProgress }) {
|
|
149
|
-
const state = await initializeState(cwd, configPath, verbose);
|
|
150
|
-
const files = await discoverFiles(cwd, patterns, configPath, autoDiscover);
|
|
151
|
-
if (verbose) {
|
|
152
|
-
console.log(ansis.default.cyan.bold(`→ Discovered ${files.length} file${files.length !== 1 ? "s" : ""} to lint`));
|
|
153
|
-
console.log();
|
|
154
|
-
}
|
|
155
|
-
if (files.length === 0) return {
|
|
156
|
-
files: [],
|
|
157
|
-
totalFilesProcessed: 0
|
|
158
|
-
};
|
|
159
|
-
return {
|
|
160
|
-
files: (await processFiles(state, cwd, files, fix, onProgress)).filter((result) => result.diagnostics.length > 0 || result.fixed),
|
|
161
|
-
totalFilesProcessed: files.length
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
//#endregion
|
|
166
|
-
exports.extractImportSourceDirectives = extractImportSourceDirectives;
|
|
167
|
-
exports.extractSourcePatterns = extractSourcePatterns;
|
|
168
|
-
exports.lint = lint;
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_linter = require("./linter-CEnSDkMA.cjs");
|
|
3
|
+
exports.extractImportSourceDirectives = require_linter.extractImportSourceDirectives;
|
|
4
|
+
exports.extractSourcePatterns = require_linter.extractSourcePatterns;
|
|
5
|
+
exports.lint = require_linter.lint;
|
package/dist/linter.d.cts
CHANGED
|
@@ -1,5 +1,357 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
//#region node_modules/.pnpm/vscode-languageserver-types@3.17.3/node_modules/vscode-languageserver-types/lib/umd/main.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* A tagging type for string properties that are actually document URIs.
|
|
4
|
+
*/
|
|
5
|
+
declare type DocumentUri = string;
|
|
6
|
+
declare namespace DocumentUri {
|
|
7
|
+
function is(value: any): value is DocumentUri;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* A tagging type for string properties that are actually URIs
|
|
11
|
+
*
|
|
12
|
+
* @since 3.16.0
|
|
13
|
+
*/
|
|
14
|
+
declare type URI = string;
|
|
15
|
+
declare namespace URI {
|
|
16
|
+
function is(value: any): value is URI;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Defines an integer in the range of -2^31 to 2^31 - 1.
|
|
20
|
+
*/
|
|
21
|
+
declare type integer = number;
|
|
22
|
+
declare namespace integer {
|
|
23
|
+
const MIN_VALUE = -2147483648;
|
|
24
|
+
const MAX_VALUE = 2147483647;
|
|
25
|
+
function is(value: any): value is integer;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Defines an unsigned integer in the range of 0 to 2^31 - 1.
|
|
29
|
+
*/
|
|
30
|
+
declare type uinteger = number;
|
|
31
|
+
declare namespace uinteger {
|
|
32
|
+
const MIN_VALUE = 0;
|
|
33
|
+
const MAX_VALUE = 2147483647;
|
|
34
|
+
function is(value: any): value is uinteger;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The LSP any type.
|
|
38
|
+
*
|
|
39
|
+
* In the current implementation we map LSPAny to any. This is due to the fact
|
|
40
|
+
* that the TypeScript compilers can't infer string access signatures for
|
|
41
|
+
* interface correctly (it can though for types). See the following issue for
|
|
42
|
+
* details: https://github.com/microsoft/TypeScript/issues/15300.
|
|
43
|
+
*
|
|
44
|
+
* When the issue is addressed LSPAny can be defined as follows:
|
|
45
|
+
*
|
|
46
|
+
* ```ts
|
|
47
|
+
* export type LSPAny = LSPObject | LSPArray | string | integer | uinteger | decimal | boolean | null | undefined;
|
|
48
|
+
* export type LSPObject = { [key: string]: LSPAny };
|
|
49
|
+
* export type LSPArray = LSPAny[];
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* Please note that strictly speaking a property with the value `undefined`
|
|
53
|
+
* can't be converted into JSON preserving the property name. However for
|
|
54
|
+
* convenience it is allowed and assumed that all these properties are
|
|
55
|
+
* optional as well.
|
|
56
|
+
*
|
|
57
|
+
* @since 3.17.0
|
|
58
|
+
*/
|
|
59
|
+
declare type LSPAny = any;
|
|
60
|
+
/**
|
|
61
|
+
* Position in a text document expressed as zero-based line and character
|
|
62
|
+
* offset. Prior to 3.17 the offsets were always based on a UTF-16 string
|
|
63
|
+
* representation. So a string of the form `a𐐀b` the character offset of the
|
|
64
|
+
* character `a` is 0, the character offset of `𐐀` is 1 and the character
|
|
65
|
+
* offset of b is 3 since `𐐀` is represented using two code units in UTF-16.
|
|
66
|
+
* Since 3.17 clients and servers can agree on a different string encoding
|
|
67
|
+
* representation (e.g. UTF-8). The client announces it's supported encoding
|
|
68
|
+
* via the client capability [`general.positionEncodings`](#clientCapabilities).
|
|
69
|
+
* The value is an array of position encodings the client supports, with
|
|
70
|
+
* decreasing preference (e.g. the encoding at index `0` is the most preferred
|
|
71
|
+
* one). To stay backwards compatible the only mandatory encoding is UTF-16
|
|
72
|
+
* represented via the string `utf-16`. The server can pick one of the
|
|
73
|
+
* encodings offered by the client and signals that encoding back to the
|
|
74
|
+
* client via the initialize result's property
|
|
75
|
+
* [`capabilities.positionEncoding`](#serverCapabilities). If the string value
|
|
76
|
+
* `utf-16` is missing from the client's capability `general.positionEncodings`
|
|
77
|
+
* servers can safely assume that the client supports UTF-16. If the server
|
|
78
|
+
* omits the position encoding in its initialize result the encoding defaults
|
|
79
|
+
* to the string value `utf-16`. Implementation considerations: since the
|
|
80
|
+
* conversion from one encoding into another requires the content of the
|
|
81
|
+
* file / line the conversion is best done where the file is read which is
|
|
82
|
+
* usually on the server side.
|
|
83
|
+
*
|
|
84
|
+
* Positions are line end character agnostic. So you can not specify a position
|
|
85
|
+
* that denotes `\r|\n` or `\n|` where `|` represents the character offset.
|
|
86
|
+
*
|
|
87
|
+
* @since 3.17.0 - support for negotiated position encoding.
|
|
88
|
+
*/
|
|
89
|
+
interface Position {
|
|
90
|
+
/**
|
|
91
|
+
* Line position in a document (zero-based).
|
|
92
|
+
*
|
|
93
|
+
* If a line number is greater than the number of lines in a document, it defaults back to the number of lines in the document.
|
|
94
|
+
* If a line number is negative, it defaults to 0.
|
|
95
|
+
*/
|
|
96
|
+
line: uinteger;
|
|
97
|
+
/**
|
|
98
|
+
* Character offset on a line in a document (zero-based).
|
|
99
|
+
*
|
|
100
|
+
* The meaning of this offset is determined by the negotiated
|
|
101
|
+
* `PositionEncodingKind`.
|
|
102
|
+
*
|
|
103
|
+
* If the character value is greater than the line length it defaults back to the
|
|
104
|
+
* line length.
|
|
105
|
+
*/
|
|
106
|
+
character: uinteger;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* The Position namespace provides helper functions to work with
|
|
110
|
+
* {@link Position} literals.
|
|
111
|
+
*/
|
|
112
|
+
declare namespace Position {
|
|
113
|
+
/**
|
|
114
|
+
* Creates a new Position literal from the given line and character.
|
|
115
|
+
* @param line The position's line.
|
|
116
|
+
* @param character The position's character.
|
|
117
|
+
*/
|
|
118
|
+
function create(line: uinteger, character: uinteger): Position;
|
|
119
|
+
/**
|
|
120
|
+
* Checks whether the given literal conforms to the {@link Position} interface.
|
|
121
|
+
*/
|
|
122
|
+
function is(value: any): value is Position;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* A range in a text document expressed as (zero-based) start and end positions.
|
|
126
|
+
*
|
|
127
|
+
* If you want to specify a range that contains a line including the line ending
|
|
128
|
+
* character(s) then use an end position denoting the start of the next line.
|
|
129
|
+
* For example:
|
|
130
|
+
* ```ts
|
|
131
|
+
* {
|
|
132
|
+
* start: { line: 5, character: 23 }
|
|
133
|
+
* end : { line 6, character : 0 }
|
|
134
|
+
* }
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
interface Range {
|
|
138
|
+
/**
|
|
139
|
+
* The range's start position.
|
|
140
|
+
*/
|
|
141
|
+
start: Position;
|
|
142
|
+
/**
|
|
143
|
+
* The range's end position.
|
|
144
|
+
*/
|
|
145
|
+
end: Position;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* The Range namespace provides helper functions to work with
|
|
149
|
+
* {@link Range} literals.
|
|
150
|
+
*/
|
|
151
|
+
declare namespace Range {
|
|
152
|
+
/**
|
|
153
|
+
* Create a new Range literal.
|
|
154
|
+
* @param start The range's start position.
|
|
155
|
+
* @param end The range's end position.
|
|
156
|
+
*/
|
|
157
|
+
function create(start: Position, end: Position): Range;
|
|
158
|
+
/**
|
|
159
|
+
* Create a new Range literal.
|
|
160
|
+
* @param startLine The start line number.
|
|
161
|
+
* @param startCharacter The start character.
|
|
162
|
+
* @param endLine The end line number.
|
|
163
|
+
* @param endCharacter The end character.
|
|
164
|
+
*/
|
|
165
|
+
function create(startLine: uinteger, startCharacter: uinteger, endLine: uinteger, endCharacter: uinteger): Range;
|
|
166
|
+
/**
|
|
167
|
+
* Checks whether the given literal conforms to the {@link Range} interface.
|
|
168
|
+
*/
|
|
169
|
+
function is(value: any): value is Range;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Represents a location inside a resource, such as a line
|
|
173
|
+
* inside a text file.
|
|
174
|
+
*/
|
|
175
|
+
interface Location {
|
|
176
|
+
uri: DocumentUri;
|
|
177
|
+
range: Range;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* The Location namespace provides helper functions to work with
|
|
181
|
+
* {@link Location} literals.
|
|
182
|
+
*/
|
|
183
|
+
declare namespace Location {
|
|
184
|
+
/**
|
|
185
|
+
* Creates a Location literal.
|
|
186
|
+
* @param uri The location's uri.
|
|
187
|
+
* @param range The location's range.
|
|
188
|
+
*/
|
|
189
|
+
function create(uri: DocumentUri, range: Range): Location;
|
|
190
|
+
/**
|
|
191
|
+
* Checks whether the given literal conforms to the {@link Location} interface.
|
|
192
|
+
*/
|
|
193
|
+
function is(value: any): value is Location;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Represents a related message and source code location for a diagnostic. This should be
|
|
197
|
+
* used to point to code locations that cause or related to a diagnostics, e.g when duplicating
|
|
198
|
+
* a symbol in a scope.
|
|
199
|
+
*/
|
|
200
|
+
interface DiagnosticRelatedInformation {
|
|
201
|
+
/**
|
|
202
|
+
* The location of this related diagnostic information.
|
|
203
|
+
*/
|
|
204
|
+
location: Location;
|
|
205
|
+
/**
|
|
206
|
+
* The message of this related diagnostic information.
|
|
207
|
+
*/
|
|
208
|
+
message: string;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* The DiagnosticRelatedInformation namespace provides helper functions to work with
|
|
212
|
+
* {@link DiagnosticRelatedInformation} literals.
|
|
213
|
+
*/
|
|
214
|
+
declare namespace DiagnosticRelatedInformation {
|
|
215
|
+
/**
|
|
216
|
+
* Creates a new DiagnosticRelatedInformation literal.
|
|
217
|
+
*/
|
|
218
|
+
function create(location: Location, message: string): DiagnosticRelatedInformation;
|
|
219
|
+
/**
|
|
220
|
+
* Checks whether the given literal conforms to the {@link DiagnosticRelatedInformation} interface.
|
|
221
|
+
*/
|
|
222
|
+
function is(value: any): value is DiagnosticRelatedInformation;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* The diagnostic's severity.
|
|
226
|
+
*/
|
|
227
|
+
declare namespace DiagnosticSeverity {
|
|
228
|
+
/**
|
|
229
|
+
* Reports an error.
|
|
230
|
+
*/
|
|
231
|
+
const Error: 1;
|
|
232
|
+
/**
|
|
233
|
+
* Reports a warning.
|
|
234
|
+
*/
|
|
235
|
+
const Warning: 2;
|
|
236
|
+
/**
|
|
237
|
+
* Reports an information.
|
|
238
|
+
*/
|
|
239
|
+
const Information: 3;
|
|
240
|
+
/**
|
|
241
|
+
* Reports a hint.
|
|
242
|
+
*/
|
|
243
|
+
const Hint: 4;
|
|
244
|
+
}
|
|
245
|
+
declare type DiagnosticSeverity = 1 | 2 | 3 | 4;
|
|
246
|
+
/**
|
|
247
|
+
* The diagnostic tags.
|
|
248
|
+
*
|
|
249
|
+
* @since 3.15.0
|
|
250
|
+
*/
|
|
251
|
+
declare namespace DiagnosticTag {
|
|
252
|
+
/**
|
|
253
|
+
* Unused or unnecessary code.
|
|
254
|
+
*
|
|
255
|
+
* Clients are allowed to render diagnostics with this tag faded out instead of having
|
|
256
|
+
* an error squiggle.
|
|
257
|
+
*/
|
|
258
|
+
const Unnecessary: 1;
|
|
259
|
+
/**
|
|
260
|
+
* Deprecated or obsolete code.
|
|
261
|
+
*
|
|
262
|
+
* Clients are allowed to rendered diagnostics with this tag strike through.
|
|
263
|
+
*/
|
|
264
|
+
const Deprecated: 2;
|
|
265
|
+
}
|
|
266
|
+
declare type DiagnosticTag = 1 | 2;
|
|
267
|
+
/**
|
|
268
|
+
* Structure to capture a description for an error code.
|
|
269
|
+
*
|
|
270
|
+
* @since 3.16.0
|
|
271
|
+
*/
|
|
272
|
+
interface CodeDescription {
|
|
273
|
+
/**
|
|
274
|
+
* An URI to open with more information about the diagnostic error.
|
|
275
|
+
*/
|
|
276
|
+
href: URI;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* The CodeDescription namespace provides functions to deal with descriptions for diagnostic codes.
|
|
280
|
+
*
|
|
281
|
+
* @since 3.16.0
|
|
282
|
+
*/
|
|
283
|
+
declare namespace CodeDescription {
|
|
284
|
+
function is(value: any): value is CodeDescription;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Represents a diagnostic, such as a compiler error or warning. Diagnostic objects
|
|
288
|
+
* are only valid in the scope of a resource.
|
|
289
|
+
*/
|
|
290
|
+
interface Diagnostic {
|
|
291
|
+
/**
|
|
292
|
+
* The range at which the message applies
|
|
293
|
+
*/
|
|
294
|
+
range: Range;
|
|
295
|
+
/**
|
|
296
|
+
* The diagnostic's severity. Can be omitted. If omitted it is up to the
|
|
297
|
+
* client to interpret diagnostics as error, warning, info or hint.
|
|
298
|
+
*/
|
|
299
|
+
severity?: DiagnosticSeverity;
|
|
300
|
+
/**
|
|
301
|
+
* The diagnostic's code, which usually appear in the user interface.
|
|
302
|
+
*/
|
|
303
|
+
code?: integer | string;
|
|
304
|
+
/**
|
|
305
|
+
* An optional property to describe the error code.
|
|
306
|
+
* Requires the code field (above) to be present/not null.
|
|
307
|
+
*
|
|
308
|
+
* @since 3.16.0
|
|
309
|
+
*/
|
|
310
|
+
codeDescription?: CodeDescription;
|
|
311
|
+
/**
|
|
312
|
+
* A human-readable string describing the source of this
|
|
313
|
+
* diagnostic, e.g. 'typescript' or 'super lint'. It usually
|
|
314
|
+
* appears in the user interface.
|
|
315
|
+
*/
|
|
316
|
+
source?: string;
|
|
317
|
+
/**
|
|
318
|
+
* The diagnostic's message. It usually appears in the user interface
|
|
319
|
+
*/
|
|
320
|
+
message: string;
|
|
321
|
+
/**
|
|
322
|
+
* Additional metadata about the diagnostic.
|
|
323
|
+
*
|
|
324
|
+
* @since 3.15.0
|
|
325
|
+
*/
|
|
326
|
+
tags?: DiagnosticTag[];
|
|
327
|
+
/**
|
|
328
|
+
* An array of related diagnostic information, e.g. when symbol-names within
|
|
329
|
+
* a scope collide all definitions can be marked via this property.
|
|
330
|
+
*/
|
|
331
|
+
relatedInformation?: DiagnosticRelatedInformation[];
|
|
332
|
+
/**
|
|
333
|
+
* A data entry field that is preserved between a `textDocument/publishDiagnostics`
|
|
334
|
+
* notification and `textDocument/codeAction` request.
|
|
335
|
+
*
|
|
336
|
+
* @since 3.16.0
|
|
337
|
+
*/
|
|
338
|
+
data?: LSPAny;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* The Diagnostic namespace provides helper functions to work with
|
|
342
|
+
* {@link Diagnostic} literals.
|
|
343
|
+
*/
|
|
344
|
+
declare namespace Diagnostic {
|
|
345
|
+
/**
|
|
346
|
+
* Creates a new Diagnostic literal.
|
|
347
|
+
*/
|
|
348
|
+
function create(range: Range, message: string, severity?: DiagnosticSeverity, code?: integer | string, source?: string, relatedInformation?: DiagnosticRelatedInformation[]): Diagnostic;
|
|
349
|
+
/**
|
|
350
|
+
* Checks whether the given literal conforms to the {@link Diagnostic} interface.
|
|
351
|
+
*/
|
|
352
|
+
function is(value: any): value is Diagnostic;
|
|
353
|
+
}
|
|
354
|
+
//#endregion
|
|
3
355
|
//#region src/types.d.ts
|
|
4
356
|
interface LintFileResult {
|
|
5
357
|
path: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tailwind-lint",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
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",
|
|
@@ -66,16 +66,16 @@
|
|
|
66
66
|
"vscode-languageserver-textdocument": "^1.0.12"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
|
-
"@types/node": "^25.
|
|
70
|
-
"oxfmt": "^0.
|
|
71
|
-
"oxlint": "^1.
|
|
72
|
-
"tsdown": "^0.
|
|
69
|
+
"@types/node": "^25.5.0",
|
|
70
|
+
"oxfmt": "^0.40.0",
|
|
71
|
+
"oxlint": "^1.55.0",
|
|
72
|
+
"tsdown": "^0.21.2",
|
|
73
73
|
"typescript": "^5.9.3",
|
|
74
|
-
"vitest": "^4.0
|
|
74
|
+
"vitest": "^4.1.0"
|
|
75
75
|
},
|
|
76
76
|
"engines": {
|
|
77
77
|
"node": ">=22.0.0",
|
|
78
78
|
"pnpm": ">=10.0.0"
|
|
79
79
|
},
|
|
80
|
-
"packageManager": "pnpm@10.
|
|
80
|
+
"packageManager": "pnpm@10.32.1"
|
|
81
81
|
}
|