tailwint 1.1.2 → 1.1.3

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/index.js CHANGED
@@ -11,8 +11,9 @@
11
11
  import { resolve, relative } from "path";
12
12
  import { readFileSync } from "fs";
13
13
  import { glob } from "glob";
14
- import { startServer, send, notify, shutdown, fileUri, langId, diagnosticsReceived, waitForProjectReady, waitForDiagnosticCount, resetState, } from "./lsp.js";
14
+ import { startServer, send, notify, shutdown, fileUri, langId, diagnosticsReceived, settledProjects, brokenProjects, warnings, waitForAllProjects, resetState, } from "./lsp.js";
15
15
  import { fixFile } from "./edits.js";
16
+ import { prescanCssFiles } from "./prescan.js";
16
17
  import { c, setTitle, windTrail, braille, windWave, dots, tick, advanceTick, startSpinner, progressBar, banner, fileBadge, diagLine, rainbowText, celebrationAnimation, } from "./ui.js";
17
18
  // Re-export for tests
18
19
  export { applyEdits } from "./edits.js";
@@ -85,9 +86,15 @@ export async function run(options = {}) {
85
86
  notify("initialized", {});
86
87
  stopBoot();
87
88
  console.error(` ${c.green}\u2714${c.reset} ${c.dim}language server ready${c.reset} ${windTrail(30)}`);
88
- // Open files triggers the server's project discovery
89
+ // Pre-scan CSS files to predict project count
90
+ const prescan = prescanCssFiles(files);
91
+ // Open found files — triggers the server's project discovery
89
92
  const fileContents = new Map();
90
93
  const fileVersions = new Map();
94
+ const found = files.length;
95
+ const foundText = `sent ${found} file${found === 1 ? "" : "s"} to lsp`;
96
+ const foundPad = 54 - 2 - foundText.length - 1;
97
+ console.error(` ${c.green}\u2714${c.reset} ${c.dim}${foundText}${c.reset} ${windTrail(foundPad)}`);
91
98
  for (const filePath of files) {
92
99
  let content;
93
100
  try {
@@ -107,27 +114,29 @@ export async function run(options = {}) {
107
114
  },
108
115
  });
109
116
  }
110
- // Wait for project init + diagnostics event-driven, no polling
111
- setTitle("tailwint ~ initializing...");
112
- const stopAnalyze = startSpinner(() => {
117
+ // Wait for all projects to be resolved (settled or broken)
118
+ setTitle("tailwint ~ scanning...");
119
+ const stopScan = startSpinner(() => {
113
120
  const received = diagnosticsReceived.size;
114
- const label = received > 0 ? "analyzing" : "initializing";
115
- setTitle(`tailwint ~ ${label} ${received}/${files.length}`);
116
- const pct = Math.round((received / files.length) * 100);
121
+ const resolved = settledProjects + brokenProjects;
122
+ const label = received > 0 ? "scanning" : "initializing";
123
+ setTitle(`tailwint ~ ${label} ${resolved}/${prescan.maxProjects}`);
124
+ const pct = found > 0 ? Math.round((received / found) * 100) : 0;
117
125
  const bar = progressBar(pct, 18, true);
118
- const totalStr = String(files.length);
126
+ const totalStr = String(found);
119
127
  const recvStr = String(received).padStart(totalStr.length);
120
- const countText = `${recvStr}/${totalStr}`;
121
- const usedCols = 2 + 1 + 1 + 20 + 1 + label.length + 3 + 1 + countText.length + 1;
122
- const waveCols = Math.max(0, 56 - usedCols);
123
- return ` ${braille()} ${bar} ${c.dim}${label}${dots()}${c.reset} ${c.bold}${recvStr}${c.reset}${c.dim}/${totalStr}${c.reset} ${windTrail(waveCols, tick)}`;
128
+ return ` ${braille()} ${bar} ${c.dim}${label}${dots()}${c.reset} ${c.bold}${recvStr}${c.reset}${c.dim}/${totalStr} scanned${c.reset} ${windTrail(12, tick)}`;
124
129
  }, 80);
125
- await waitForProjectReady();
126
- await waitForDiagnosticCount(files.length);
127
- stopAnalyze();
128
- const analyzedText = `${files.length} files analyzed`;
129
- const analyzePad = 54 - 2 - analyzedText.length - 1;
130
- console.error(` ${c.green}\u2714${c.reset} ${c.dim}${analyzedText}${c.reset} ${windTrail(analyzePad)}`);
130
+ await waitForAllProjects(prescan.predictedRoots, prescan.maxProjects);
131
+ stopScan();
132
+ // Log warnings for broken projects
133
+ for (const w of warnings) {
134
+ console.error(` ${c.yellow}\u26A0${c.reset} ${c.dim}${w}${c.reset}`);
135
+ }
136
+ const scanned = diagnosticsReceived.size;
137
+ const scannedText = `${scanned}/${found} files received`;
138
+ const scannedPad = 54 - 2 - scannedText.length - 1;
139
+ console.error(` ${c.green}\u2714${c.reset} ${c.dim}${scannedText}${c.reset} ${windTrail(scannedPad)}`);
131
140
  console.error("");
132
141
  // Collect issues
133
142
  let totalIssues = 0;
@@ -149,13 +158,13 @@ export async function run(options = {}) {
149
158
  const elapsed = ((Date.now() - t0) / 1000).toFixed(1);
150
159
  setTitle("tailwint \u2714 all clear");
151
160
  await celebrationAnimation();
152
- console.error(` ${c.green}\u2714${c.reset} ${c.bold}${files.length}${c.reset} files scanned ${c.dim}// ${rainbowText("all clear")} ${c.dim}${elapsed}s${c.reset}`);
161
+ console.error(` ${c.green}\u2714${c.reset} ${c.bold}${scanned}${c.reset} files scanned ${c.dim}// ${rainbowText("all clear")} ${c.dim}${elapsed}s${c.reset}`);
153
162
  console.error("");
154
163
  await shutdown();
155
164
  return 0;
156
165
  }
157
166
  // Summary
158
- console.error(` ${c.bold}${c.white}${files.length}${c.reset} files scanned ${c.dim}//${c.reset} ${c.orange}${c.bold}${conflicts}${c.reset}${c.orange} conflicts${c.reset} ${c.dim}\u2502${c.reset} ${c.yellow}${c.bold}${canonical}${c.reset}${c.yellow} canonical${c.reset}`);
167
+ console.error(` ${c.bold}${c.white}${scanned}${c.reset} files scanned ${c.dim}//${c.reset} ${c.orange}${c.bold}${conflicts}${c.reset}${c.orange} conflicts${c.reset} ${c.dim}\u2502${c.reset} ${c.yellow}${c.bold}${canonical}${c.reset}${c.yellow} canonical${c.reset}`);
159
168
  console.error("");
160
169
  // Report
161
170
  let fileNum = 0;
package/dist/lsp.d.ts CHANGED
@@ -3,12 +3,22 @@
3
3
  */
4
4
  export declare const diagnosticsReceived: Map<string, any[]>;
5
5
  export declare let projectReady: boolean;
6
+ /** Tracking for projectInitialized events */
7
+ export declare let projectInitCount: number;
8
+ export declare let settledProjects: number;
9
+ export declare let brokenProjects: number;
10
+ export declare const warnings: string[];
6
11
  /** Reset module state between runs (for programmatic multi-run usage). */
7
12
  export declare function resetState(): void;
8
- /** Returns a promise that resolves when @/tailwindCSS/projectInitialized fires. */
9
- export declare function waitForProjectReady(timeoutMs?: number): Promise<void>;
10
- /** Returns a promise that resolves when diagnosticsReceived.size >= count. */
11
- export declare function waitForDiagnosticCount(count: number, timeoutMs?: number): Promise<void>;
13
+ /**
14
+ * Wait for all expected projects to be resolved (settled or broken).
15
+ *
16
+ * @param predictedRoots - Number of CSS files predicted to be project roots
17
+ * @param maxProjects - Upper bound (predictedRoots + predictedNonRoots)
18
+ * @param initTimeoutMs - How long to wait for each projectInitialized event
19
+ * @param debounceMs - Silence window to consider diagnostics "settled"
20
+ */
21
+ export declare function waitForAllProjects(predictedRoots: number, maxProjects: number, initTimeoutMs?: number, debounceMs?: number): Promise<void>;
12
22
  /** Returns a promise that resolves when diagnostics are published for a specific URI. */
13
23
  export declare function waitForDiagnostic(uri: string, timeoutMs?: number): Promise<any[]>;
14
24
  export declare function startServer(root: string): void;
package/dist/lsp.js CHANGED
@@ -61,12 +61,25 @@ const pending = new Map();
61
61
  export const diagnosticsReceived = new Map();
62
62
  export let projectReady = false;
63
63
  // ---------------------------------------------------------------------------
64
- // Event-driven waiters — resolved by processMessages, no polling
64
+ // Project-aware wait state
65
65
  // ---------------------------------------------------------------------------
66
- let projectReadyResolve = null;
67
- let diagTarget = 0;
68
- let diagTargetResolve = null;
66
+ /** Tracking for projectInitialized events */
67
+ export let projectInitCount = 0;
68
+ export let settledProjects = 0;
69
+ export let brokenProjects = 0;
70
+ let lastInitMs = 0;
71
+ let inBrokenSequence = false;
72
+ let awaitingFirstDiag = false;
73
+ let currentProjectDiagCount = 0;
74
+ export const warnings = [];
75
+ /** Internal waiter state */
76
+ let projectWaitResolve = null;
77
+ let diagDebounceTimer = null;
78
+ let projectInitTimer = null;
79
+ let outerTimer = null;
69
80
  const diagWaiters = new Map();
81
+ /** Config for the current wait */
82
+ let waitConfig = { predictedRoots: 0, maxProjects: 0, initTimeoutMs: 5000, debounceMs: 500 };
70
83
  /** Reset module state between runs (for programmatic multi-run usage). */
71
84
  export function resetState() {
72
85
  msgId = 0;
@@ -76,38 +89,172 @@ export function resetState() {
76
89
  pending.clear();
77
90
  diagnosticsReceived.clear();
78
91
  projectReady = false;
79
- projectReadyResolve = null;
80
- diagTarget = 0;
81
- diagTargetResolve = null;
92
+ projectInitCount = 0;
93
+ settledProjects = 0;
94
+ brokenProjects = 0;
95
+ lastInitMs = 0;
96
+ inBrokenSequence = false;
97
+ awaitingFirstDiag = false;
98
+ currentProjectDiagCount = 0;
99
+ warnings.length = 0;
100
+ projectWaitResolve = null;
101
+ if (diagDebounceTimer) {
102
+ clearTimeout(diagDebounceTimer);
103
+ diagDebounceTimer = null;
104
+ }
105
+ if (projectInitTimer) {
106
+ clearTimeout(projectInitTimer);
107
+ projectInitTimer = null;
108
+ }
109
+ if (outerTimer) {
110
+ clearTimeout(outerTimer);
111
+ outerTimer = null;
112
+ }
82
113
  diagWaiters.clear();
83
114
  vscodeSettings = null;
84
115
  }
85
- /** Returns a promise that resolves when @/tailwindCSS/projectInitialized fires. */
86
- export function waitForProjectReady(timeoutMs = 15_000) {
87
- if (projectReady || serverDead)
88
- return Promise.resolve();
89
- return new Promise((res, rej) => {
90
- projectReadyResolve = res;
91
- const timer = setTimeout(() => {
92
- projectReadyResolve = null;
93
- res(); // resolve anyway — don't block forever
94
- }, timeoutMs);
95
- // Clean up timer if resolved early
96
- const origRes = res;
97
- projectReadyResolve = () => { clearTimeout(timer); origRes(); };
98
- });
116
+ function cleanupWaitTimers() {
117
+ if (diagDebounceTimer) {
118
+ clearTimeout(diagDebounceTimer);
119
+ diagDebounceTimer = null;
120
+ }
121
+ if (projectInitTimer) {
122
+ clearTimeout(projectInitTimer);
123
+ projectInitTimer = null;
124
+ }
125
+ if (outerTimer) {
126
+ clearTimeout(outerTimer);
127
+ outerTimer = null;
128
+ }
129
+ }
130
+ function finishWait() {
131
+ if (!projectWaitResolve)
132
+ return;
133
+ const resolve = projectWaitResolve;
134
+ projectWaitResolve = null;
135
+ cleanupWaitTimers();
136
+ resolve();
137
+ }
138
+ function isAllResolved() {
139
+ const resolved = settledProjects + brokenProjects;
140
+ return resolved >= waitConfig.maxProjects;
141
+ }
142
+ function startProjectInitTimeout() {
143
+ if (projectInitTimer)
144
+ clearTimeout(projectInitTimer);
145
+ projectInitTimer = setTimeout(() => {
146
+ // Timer fired — either no project init came, or we were waiting for
147
+ // more diagnostics after a single early one. If we got any diagnostics
148
+ // for the current project, settle it before finishing.
149
+ if (currentProjectDiagCount > 0 && !awaitingFirstDiag) {
150
+ settleCurrentProject();
151
+ }
152
+ else {
153
+ finishWait();
154
+ }
155
+ }, waitConfig.initTimeoutMs);
156
+ }
157
+ function onProjectInitialized() {
158
+ projectInitCount++;
159
+ const now = Date.now();
160
+ projectReady = true;
161
+ if (lastInitMs > 0 && (now - lastInitMs) < 500) {
162
+ // Rapid re-init — broken project
163
+ if (!inBrokenSequence) {
164
+ // First rapid init after a healthy one — the previous healthy init was actually broken
165
+ inBrokenSequence = true;
166
+ brokenProjects++;
167
+ warnings.push("A CSS file failed to initialize (likely an @apply referencing an unknown utility). " +
168
+ "That project's files will not receive diagnostics. " +
169
+ "See https://github.com/tailwindlabs/tailwindcss-intellisense/issues/1121");
170
+ // The previous init was counted as starting a healthy project's diagnostic wait.
171
+ // Cancel that wait — this project won't produce diagnostics.
172
+ if (diagDebounceTimer) {
173
+ clearTimeout(diagDebounceTimer);
174
+ diagDebounceTimer = null;
175
+ }
176
+ }
177
+ // Additional rapid inits for the same broken project — just update timestamp
178
+ }
179
+ else {
180
+ // Healthy init — new project starting
181
+ inBrokenSequence = false;
182
+ awaitingFirstDiag = true;
183
+ currentProjectDiagCount = 0;
184
+ // Cancel any pending project-init timeout since we just got a new one
185
+ if (projectInitTimer) {
186
+ clearTimeout(projectInitTimer);
187
+ projectInitTimer = null;
188
+ }
189
+ if (diagDebounceTimer) {
190
+ clearTimeout(diagDebounceTimer);
191
+ diagDebounceTimer = null;
192
+ }
193
+ // Don't start the diagnostic debounce yet — wait for the first diagnostic to arrive.
194
+ // Use the init timeout as the safety net (if no diagnostics arrive at all,
195
+ // this project is effectively broken even though it didn't rapid-fire).
196
+ startProjectInitTimeout();
197
+ }
198
+ lastInitMs = now;
199
+ // Check if broken projects pushed us to completion
200
+ if (isAllResolved()) {
201
+ finishWait();
202
+ }
203
+ }
204
+ function settleCurrentProject() {
205
+ settledProjects++;
206
+ if (isAllResolved()) {
207
+ finishWait();
208
+ }
209
+ else {
210
+ startProjectInitTimeout();
211
+ }
212
+ }
213
+ function startDiagDebounce() {
214
+ if (diagDebounceTimer)
215
+ clearTimeout(diagDebounceTimer);
216
+ // Cancel the init timeout — we're now in diagnostic-settling mode
217
+ if (projectInitTimer) {
218
+ clearTimeout(projectInitTimer);
219
+ projectInitTimer = null;
220
+ }
221
+ diagDebounceTimer = setTimeout(settleCurrentProject, waitConfig.debounceMs);
222
+ }
223
+ function onDiagnosticReceived() {
224
+ if (!projectWaitResolve)
225
+ return;
226
+ currentProjectDiagCount++;
227
+ if (awaitingFirstDiag) {
228
+ // First diagnostic after a healthy init — don't start the debounce yet.
229
+ // The first diagnostic is often just the CSS entry point, followed by a
230
+ // ~1s pause before the bulk TSX diagnostics arrive. Starting the debounce
231
+ // here would settle too early on large projects.
232
+ awaitingFirstDiag = false;
233
+ }
234
+ else if (currentProjectDiagCount >= 2) {
235
+ // Second diagnostic and beyond — the bulk is flowing, debounce is safe
236
+ startDiagDebounce();
237
+ }
99
238
  }
100
- /** Returns a promise that resolves when diagnosticsReceived.size >= count. */
101
- export function waitForDiagnosticCount(count, timeoutMs = 30_000) {
102
- if (diagnosticsReceived.size >= count || serverDead)
239
+ /**
240
+ * Wait for all expected projects to be resolved (settled or broken).
241
+ *
242
+ * @param predictedRoots - Number of CSS files predicted to be project roots
243
+ * @param maxProjects - Upper bound (predictedRoots + predictedNonRoots)
244
+ * @param initTimeoutMs - How long to wait for each projectInitialized event
245
+ * @param debounceMs - Silence window to consider diagnostics "settled"
246
+ */
247
+ export function waitForAllProjects(predictedRoots, maxProjects, initTimeoutMs = 5_000, debounceMs = 500) {
248
+ if (serverDead || maxProjects === 0)
103
249
  return Promise.resolve();
250
+ waitConfig = { predictedRoots, maxProjects, initTimeoutMs, debounceMs };
104
251
  return new Promise((res) => {
105
- diagTarget = count;
106
- const timer = setTimeout(() => {
107
- diagTargetResolve = null;
108
- res();
109
- }, timeoutMs);
110
- diagTargetResolve = () => { clearTimeout(timer); res(); };
252
+ projectWaitResolve = res;
253
+ // Start waiting for first project init
254
+ startProjectInitTimeout();
255
+ // Hard outer timeout — never wait longer than this
256
+ const outerMs = initTimeoutMs + (maxProjects * 3000) + 5000;
257
+ outerTimer = setTimeout(finishWait, Math.min(outerMs, 30_000));
111
258
  });
112
259
  }
113
260
  /** Returns a promise that resolves when diagnostics are published for a specific URI. */
@@ -217,21 +364,12 @@ function processMessages() {
217
364
  diagWaiters.delete(uri);
218
365
  resolve(diags);
219
366
  }
220
- // Resolve count-based waiter
221
- if (diagTargetResolve && diagnosticsReceived.size >= diagTarget) {
222
- const resolve = diagTargetResolve;
223
- diagTargetResolve = null;
224
- resolve();
225
- }
367
+ // Notify the project-aware wait system
368
+ onDiagnosticReceived();
226
369
  }
227
370
  // Tailwind project initialized
228
371
  if (msg.method === "@/tailwindCSS/projectInitialized") {
229
- projectReady = true;
230
- if (projectReadyResolve) {
231
- const resolve = projectReadyResolve;
232
- projectReadyResolve = null;
233
- resolve();
234
- }
372
+ onProjectInitialized();
235
373
  }
236
374
  }
237
375
  }
@@ -249,18 +387,8 @@ function drainAll(reason) {
249
387
  p.reject(reason);
250
388
  pending.delete(id);
251
389
  }
252
- // Resolve project-ready waiter (so run() doesn't hang)
253
- if (projectReadyResolve) {
254
- const r = projectReadyResolve;
255
- projectReadyResolve = null;
256
- r();
257
- }
258
- // Resolve count-based waiter
259
- if (diagTargetResolve) {
260
- const r = diagTargetResolve;
261
- diagTargetResolve = null;
262
- r();
263
- }
390
+ // Resolve project wait (so run() doesn't hang)
391
+ finishWait();
264
392
  // Resolve all URI-specific waiters with empty arrays
265
393
  for (const [uri, r] of diagWaiters) {
266
394
  r([]);
@@ -323,7 +451,10 @@ export function notify(method, params) {
323
451
  export async function shutdown() {
324
452
  if (serverDead)
325
453
  return;
326
- await send("shutdown", {}).catch(() => { });
454
+ await Promise.race([
455
+ send("shutdown", {}).catch(() => { }),
456
+ new Promise(r => setTimeout(r, 3000)),
457
+ ]);
327
458
  notify("exit", {});
328
459
  serverDead = true;
329
460
  try {
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Pre-scan CSS files to predict how many projects the language server will create.
3
+ *
4
+ * analyzeStylesheet() is adapted from tailwindlabs/tailwindcss-intellisense
5
+ * (packages/tailwindcss-language-server/src/version-guesser.ts, MIT licensed).
6
+ */
7
+ type TailwindVersion = "3" | "4";
8
+ export interface TailwindStylesheet {
9
+ root: boolean;
10
+ versions: TailwindVersion[];
11
+ explicitImport: boolean;
12
+ }
13
+ export declare function analyzeStylesheet(content: string): TailwindStylesheet;
14
+ export interface PrescanResult {
15
+ /** Total CSS files found */
16
+ totalCssFiles: number;
17
+ /** CSS files predicted to be project roots */
18
+ predictedRoots: number;
19
+ /** CSS files that are Tailwind-related but not roots (could be promoted) */
20
+ predictedNonRoots: number;
21
+ /** CSS files with no Tailwind signals */
22
+ predictedUnrelated: number;
23
+ /** Upper bound on projects the server might create */
24
+ maxProjects: number;
25
+ }
26
+ export declare function prescanCssFiles(files: string[]): PrescanResult;
27
+ export {};
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Pre-scan CSS files to predict how many projects the language server will create.
3
+ *
4
+ * analyzeStylesheet() is adapted from tailwindlabs/tailwindcss-intellisense
5
+ * (packages/tailwindcss-language-server/src/version-guesser.ts, MIT licensed).
6
+ */
7
+ import { readFileSync } from "fs";
8
+ const HAS_V4_IMPORT = /@import\s*['"]tailwindcss(?:\/[^'"]+)?['"]/;
9
+ const HAS_V4_DIRECTIVE = /@(theme|plugin|utility|custom-variant|variant|reference)\s*[^;{]+[;{]/;
10
+ const HAS_V4_FN = /--(alpha|spacing|theme)\(/;
11
+ const HAS_LEGACY_TAILWIND = /@tailwind\s*(base|preflight|components|variants|screens)+;/;
12
+ const HAS_TAILWIND_UTILITIES = /@tailwind\s*utilities\s*[^;]*;/;
13
+ const HAS_TAILWIND = /@tailwind\s*[^;]+;/;
14
+ const HAS_COMMON_DIRECTIVE = /@(config|apply)\s*[^;{]+[;{]/;
15
+ const HAS_NON_URL_IMPORT = /@import\s*['"](?!([a-z]+:|\/\/))/;
16
+ export function analyzeStylesheet(content) {
17
+ if (HAS_V4_IMPORT.test(content)) {
18
+ return { root: true, versions: ["4"], explicitImport: true };
19
+ }
20
+ if (HAS_V4_DIRECTIVE.test(content)) {
21
+ if (HAS_TAILWIND_UTILITIES.test(content)) {
22
+ return { root: true, versions: ["4"], explicitImport: false };
23
+ }
24
+ return { root: false, versions: ["4"], explicitImport: false };
25
+ }
26
+ if (HAS_V4_FN.test(content)) {
27
+ return { root: false, versions: ["4"], explicitImport: false };
28
+ }
29
+ if (HAS_LEGACY_TAILWIND.test(content)) {
30
+ return { root: false, versions: ["3"], explicitImport: false };
31
+ }
32
+ if (HAS_TAILWIND.test(content)) {
33
+ return { root: true, versions: ["4", "3"], explicitImport: false };
34
+ }
35
+ if (HAS_COMMON_DIRECTIVE.test(content)) {
36
+ return { root: false, versions: ["4", "3"], explicitImport: false };
37
+ }
38
+ if (HAS_NON_URL_IMPORT.test(content)) {
39
+ return { root: true, versions: ["4", "3"], explicitImport: false };
40
+ }
41
+ return { root: false, versions: [], explicitImport: false };
42
+ }
43
+ export function prescanCssFiles(files) {
44
+ let predictedRoots = 0;
45
+ let predictedNonRoots = 0;
46
+ let predictedUnrelated = 0;
47
+ for (const filePath of files) {
48
+ if (!filePath.endsWith(".css"))
49
+ continue;
50
+ let content;
51
+ try {
52
+ content = readFileSync(filePath, "utf-8");
53
+ }
54
+ catch {
55
+ continue;
56
+ }
57
+ const result = analyzeStylesheet(content);
58
+ if (result.versions.length === 0) {
59
+ predictedUnrelated++;
60
+ }
61
+ else if (result.root) {
62
+ predictedRoots++;
63
+ }
64
+ else {
65
+ predictedNonRoots++;
66
+ }
67
+ }
68
+ const totalCssFiles = predictedRoots + predictedNonRoots + predictedUnrelated;
69
+ return {
70
+ totalCssFiles,
71
+ predictedRoots,
72
+ predictedNonRoots,
73
+ predictedUnrelated,
74
+ maxProjects: predictedRoots + predictedNonRoots,
75
+ };
76
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tailwint",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "Tailwind CSS linter for CI — drives the official language server to catch class issues and auto-fix them",
5
5
  "license": "MIT",
6
6
  "author": "Peter Wang",