tailwint 1.1.10 → 1.1.12

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.
Files changed (3) hide show
  1. package/README.md +10 -6
  2. package/dist/lsp.js +4 -4
  3. package/package.json +11 -3
package/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
  <img src="assets/header.svg" alt="tailwint">
3
3
  </p>
4
4
 
5
+ <p align="center">
6
+ <strong>tail</strong>wind + l<strong>int</strong> = <strong>tailwint</strong> ~≈∼〜 a tiny linter for your Tailwind CSS
7
+ </p>
8
+
5
9
  <p align="center">
6
10
  <a href="https://www.npmjs.com/package/tailwint"><img src="https://img.shields.io/npm/v/tailwint?color=0ea5e9&label=npm" alt="npm version"></a>
7
11
  <a href="https://github.com/peterwangsc/tailwint/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/tailwint?color=a78bfa" alt="license"></a>
@@ -10,7 +14,7 @@
10
14
 
11
15
  ---
12
16
 
13
- The same diagnostics VS Code shows — but from the command line. Catches class conflicts, suggests canonical rewrites, and auto-fixes everything. Built on the official `@tailwindcss/language-server`.
17
+ The same diagnostics VS Code shows — but from the command line. Catches class conflicts, suggests canonical rewrites, and auto-fixes everything. Powered by the official `@tailwindcss/language-server` — not a custom parser, not a regex hack.
14
18
 
15
19
  **Works with Tailwind CSS v4.**
16
20
 
@@ -156,11 +160,11 @@ const exitCode = await run({
156
160
 
157
161
  tailwint exits with meaningful codes for CI pipelines:
158
162
 
159
- | Exit code | Meaning |
160
- | --------- | ------------------------------------------------- |
161
- | `0` | No issues found, or all issues fixed with `--fix` |
162
- | `1` | Issues found (without `--fix`) |
163
- | `2` | Fatal error (language server not found, crash) |
163
+ | Exit code | Meaning |
164
+ | --------- | ---------------------------------------------------------------- |
165
+ | `0` | No issues found, or all issues fixed with `--fix` |
166
+ | `1` | Issues found, or unfixable issues remain after `--fix` |
167
+ | `2` | Fatal error (language server not found, crash) |
164
168
 
165
169
  ### GitHub Actions
166
170
 
package/dist/lsp.js CHANGED
@@ -1,7 +1,7 @@
1
- import{spawn as q}from"child_process";import{resolve as I}from"path";import{existsSync as $,readFileSync as V}from"fs";const N=process.env.DEBUG==="1";let O="",m=null;function H(){if(m!==null)return m;const e=I(O,".vscode/settings.json");if(!$(e))return m={},m;try{const t=V(e,"utf-8").replace(/\/\/[^\n]*/g,"").replace(/,\s*([\]}])/g,"$1");m=JSON.parse(t)}catch{m={}}return m}function K(e){const t=H(),n=e+".",o={};for(const[l,y]of Object.entries(t)){if(!l.startsWith(n))continue;const c=l.slice(n.length).split(".");let p=o;for(let r=0;r<c.length-1;r++)(!(c[r]in p)||typeof p[c[r]]!="object")&&(p[c[r]]={}),p=p[c[r]];p[c[c.length-1]]=y}return o}let a,d=!1,L=0;const f=[];let T=0;const h=new Map,P=new Map;let A=!1,F=0,D=0,M=0,R=0,B=!1,x=!1,j=0;const J=[];let w=null,i=null,s=null,v=null;const g=new Map;let k={predictedRoots:0,maxProjects:0,initTimeoutMs:5e3,debounceMs:500};function ce(){L=0,d=!1,f.length=0,T=0,h.clear(),P.clear(),A=!1,F=0,D=0,M=0,R=0,B=!1,x=!1,j=0,J.length=0,w=null,i&&(clearTimeout(i),i=null),s&&(clearTimeout(s),s=null),v&&(clearTimeout(v),v=null),g.clear(),m=null}function Q(){i&&(clearTimeout(i),i=null),s&&(clearTimeout(s),s=null),v&&(clearTimeout(v),v=null)}function S(){if(!w)return;const e=w;w=null,Q(),e()}function _(){return D+M>=k.maxProjects}function W(){s&&clearTimeout(s),s=setTimeout(()=>{j>0&&!x?z():S()},k.initTimeoutMs)}function X(){F++;const e=Date.now();A=!0,R>0&&e-R<500?B||(B=!0,M++,J.push("A CSS file failed to initialize (likely an @apply referencing an unknown utility). That project's files will not receive diagnostics. See https://github.com/tailwindlabs/tailwindcss-intellisense/issues/1121"),i&&(clearTimeout(i),i=null)):(B=!1,x=!0,j=0,s&&(clearTimeout(s),s=null),i&&(clearTimeout(i),i=null),W()),R=e,_()&&S()}function z(){D++,_()?S():W()}function Y(){i&&clearTimeout(i),s&&(clearTimeout(s),s=null),i=setTimeout(z,k.debounceMs)}function Z(){w&&(j++,x?x=!1:j>=2&&Y())}function ae(e,t,n=5e3,o=500){return d||t===0?Promise.resolve():(k={predictedRoots:e,maxProjects:t,initTimeoutMs:n,debounceMs:o},new Promise(l=>{w=l,W();const y=n+t*3e3+5e3;v=setTimeout(S,Math.min(y,3e4))}))}function ue(e,t=1e4){return d?Promise.resolve([]):(P.delete(e),new Promise(n=>{const o=setTimeout(()=>{g.has(e)&&(g.delete(e),n([]))},t);g.set(e,l=>{clearTimeout(o),n(l)})}))}function C(e){const t=JSON.stringify(e);return`Content-Length: ${Buffer.byteLength(t)}\r
1
+ import{spawn as H}from"child_process";import{resolve as $}from"path";import{existsSync as N,readFileSync as K}from"fs";const O=process.env.DEBUG==="1";let L="",m=null;function Q(){if(m!==null)return m;const e=$(L,".vscode/settings.json");if(!N(e))return m={},m;try{const t=K(e,"utf-8").replace(/\/\/[^\n]*/g,"").replace(/,\s*([\]}])/g,"$1");m=JSON.parse(t)}catch{m={}}return m}function X(e){const t=Q(),n=e+".",s={};for(const[l,y]of Object.entries(t)){if(!l.startsWith(n))continue;const c=l.slice(n.length).split(".");let p=s;for(let r=0;r<c.length-1;r++)(!(c[r]in p)||typeof p[c[r]]!="object")&&(p[c[r]]={}),p=p[c[r]];p[c[c.length-1]]=y}return s}let a,d=!1,A=0;const f=[];let x=0;const h=new Map,P=new Map;let F=!1,J=0,M=0,W=0,R=0,k=!1,j=0;const _=[];let v=null,i=null,o=null,w=null;const g=new Map;let B={predictedRoots:0,maxProjects:0,initTimeoutMs:5e3,debounceMs:500};function ae(){A=0,d=!1,f.length=0,x=0,h.clear(),P.clear(),F=!1,J=0,M=0,W=0,R=0,k=!1,j=0,_.length=0,v=null,b=!1,D=0,i&&(clearTimeout(i),i=null),o&&(clearTimeout(o),o=null),w&&(clearTimeout(w),w=null),g.clear(),m=null}function Y(){i&&(clearTimeout(i),i=null),o&&(clearTimeout(o),o=null),w&&(clearTimeout(w),w=null)}function S(){if(!v)return;const e=v;v=null,Y(),e()}function z(){return M+W>=B.maxProjects}function C(){o&&clearTimeout(o),o=setTimeout(()=>{j>0&&!b?(b=!0,G()):j>0?U():S()},B.initTimeoutMs)}function Z(){J++;const e=Date.now();F=!0,R>0&&e-R<500?k||(k=!0,W++,_.push("A CSS file failed to initialize (likely an @apply referencing an unknown utility). That project's files will not receive diagnostics. See https://github.com/tailwindlabs/tailwindcss-intellisense/issues/1121"),i&&(clearTimeout(i),i=null)):(k=!1,j=0,o&&(clearTimeout(o),o=null),i&&(clearTimeout(i),i=null),C()),R=e,z()&&S()}function U(){M++,z()?S():C()}function G(){i&&clearTimeout(i),o&&(clearTimeout(o),o=null),i=setTimeout(U,B.debounceMs)}let b=!1,D=0;function ee(){if(!v)return;j++;const e=Date.now(),t=D>0?e-D:0;D=e,b||t>=100&&(b=!0),b&&G()}function ue(e,t,n=5e3,s=500){return d||t===0?Promise.resolve():(B={predictedRoots:e,maxProjects:t,initTimeoutMs:n,debounceMs:s},new Promise(l=>{v=l,C();const y=n+t*3e3+5e3;w=setTimeout(S,Math.min(y,3e4))}))}function fe(e,t=1e4){return d?Promise.resolve([]):(P.delete(e),new Promise(n=>{const s=setTimeout(()=>{g.has(e)&&(g.delete(e),n([]))},t);g.set(e,l=>{clearTimeout(s),n(l)})}))}function I(e){const t=JSON.stringify(e);return`Content-Length: ${Buffer.byteLength(t)}\r
2
2
  \r
3
- ${t}`}function ee(){if(f.length===0)return Buffer.alloc(0);if(f.length===1)return f[0];const e=Buffer.concat(f,T);return f.length=0,f.push(e),e}function E(e){f.length=0,e.length>0?(f.push(e),T=e.length):T=0}function te(){for(;;){const e=ee();if(e.length===0)break;const t=e.toString("ascii",0,Math.min(e.length,256)),n=t.indexOf(`\r
3
+ ${t}`}function te(){if(f.length===0)return Buffer.alloc(0);if(f.length===1)return f[0];const e=Buffer.concat(f,x);return f.length=0,f.push(e),e}function E(e){f.length=0,e.length>0?(f.push(e),x=e.length):x=0}function ne(){for(;;){const e=te();if(e.length===0)break;const t=e.toString("ascii",0,Math.min(e.length,256)),n=t.indexOf(`\r
4
4
  \r
5
- `);if(n===-1){E(e);break}const l=t.slice(0,n).match(/Content-Length:\s*(\d+)/i);if(!l){E(e.subarray(n+4));continue}const y=parseInt(l[1],10),c=n+4;if(e.length<c+y){E(e);break}const p=e.subarray(c,c+y).toString("utf-8");E(e.subarray(c+y));let r;try{r=JSON.parse(p)}catch{continue}if(N&&console.error(`<- ${r.method||`response#${r.id}`}`),r.id!=null&&!r.method&&h.has(r.id)){const u=h.get(r.id);h.delete(r.id),r.error?u.reject(r.error):u.resolve(r.result);continue}if(r.id!=null&&r.method){let u=null;r.method==="workspace/configuration"&&(u=(r.params?.items||[]).map(b=>b.section?K(b.section):{})),a.stdin.write(C({jsonrpc:"2.0",id:r.id,result:u}));continue}if(r.method==="textDocument/publishDiagnostics"&&r.params){const u=r.params.uri,b=r.params.diagnostics||[];if(P.set(u,b),g.has(u)){const G=g.get(u);g.delete(u),G(b)}Z()}r.method==="@/tailwindCSS/projectInitialized"&&X()}}function ne(e){const t=I(e,"node_modules/.bin/tailwindcss-language-server");return $(t)?t:"tailwindcss-language-server"}function U(e){d=!0;for(const t of h.values())t.reject(e);h.clear(),S();for(const t of g.values())t([]);g.clear()}function fe(e){O=e;const t=ne(e);a=q(t,["--stdio"],{stdio:["pipe","pipe","pipe"]}),a.on("error",n=>{n.code==="ENOENT"&&(console.error(`
5
+ `);if(n===-1){E(e);break}const l=t.slice(0,n).match(/Content-Length:\s*(\d+)/i);if(!l){E(e.subarray(n+4));continue}const y=parseInt(l[1],10),c=n+4;if(e.length<c+y){E(e);break}const p=e.subarray(c,c+y).toString("utf-8");E(e.subarray(c+y));let r;try{r=JSON.parse(p)}catch{continue}if(O&&console.error(`<- ${r.method||`response#${r.id}`}`),r.id!=null&&!r.method&&h.has(r.id)){const u=h.get(r.id);h.delete(r.id),r.error?u.reject(r.error):u.resolve(r.result);continue}if(r.id!=null&&r.method){let u=null;r.method==="workspace/configuration"&&(u=(r.params?.items||[]).map(T=>T.section?X(T.section):{})),a.stdin.write(I({jsonrpc:"2.0",id:r.id,result:u}));continue}if(r.method==="textDocument/publishDiagnostics"&&r.params){const u=r.params.uri,T=r.params.diagnostics||[];if(P.set(u,T),g.has(u)){const V=g.get(u);g.delete(u),V(T)}ee()}r.method==="@/tailwindCSS/projectInitialized"&&Z()}}function re(e){const t=$(e,"node_modules/.bin/tailwindcss-language-server");return N(t)?t:"tailwindcss-language-server"}function q(e){d=!0;for(const t of h.values())t.reject(e);h.clear(),S();for(const t of g.values())t([]);g.clear()}function de(e){L=e;const t=re(e);a=H(t,["--stdio"],{stdio:["pipe","pipe","pipe"]}),a.on("error",n=>{n.code==="ENOENT"&&(console.error(`
6
6
  \x1B[38;5;203m\x1B[1mERROR\x1B[0m @tailwindcss/language-server not found.`),console.error(` Install it: \x1B[1mnpm install -D @tailwindcss/language-server\x1B[0m
7
- `)),U(new Error(n.code==="ENOENT"?"@tailwindcss/language-server not found":`language server error: ${n.message}`))}),a.on("close",(n,o)=>{d||U(new Error(o?`language server killed by ${o}`:`language server exited with code ${n}`))}),a.stdout.on("data",n=>{f.push(n),T+=n.length,te()}),a.stderr.on("data",n=>{N&&process.stderr.write(n)})}function re(e,t){if(d)return Promise.reject(new Error("language server is not running"));const n=++L;return new Promise((o,l)=>{h.set(n,{resolve:o,reject:l});try{a.stdin.write(C({jsonrpc:"2.0",id:n,method:e,params:t}))}catch{h.delete(n),l(new Error("language server is not running"))}})}function ie(e,t){if(!d)try{a.stdin.write(C({jsonrpc:"2.0",method:e,params:t}))}catch{}}async function de(){if(!d){await Promise.race([re("shutdown",{}).catch(()=>{}),new Promise(e=>setTimeout(e,500))]),ie("exit",{}),d=!0;try{a.stdin.end()}catch{}try{a.stdout.destroy()}catch{}try{a.stderr.destroy()}catch{}a.kill()}}function ge(e){return`file://${e}`}function pe(e){return e.endsWith(".css")?"css":e.endsWith(".html")||e.endsWith(".vue")||e.endsWith(".svelte")||e.endsWith(".astro")?"html":e.endsWith(".mdx")?"mdx":e.endsWith(".jsx")?"javascriptreact":"typescriptreact"}export{M as brokenProjects,P as diagnosticsReceived,ge as fileUri,pe as langId,ie as notify,F as projectInitCount,A as projectReady,ce as resetState,re as send,D as settledProjects,de as shutdown,fe as startServer,ae as waitForAllProjects,ue as waitForDiagnostic,J as warnings};
7
+ `)),q(new Error(n.code==="ENOENT"?"@tailwindcss/language-server not found":`language server error: ${n.message}`))}),a.on("close",(n,s)=>{d||q(new Error(s?`language server killed by ${s}`:`language server exited with code ${n}`))}),a.stdout.on("data",n=>{f.push(n),x+=n.length,ne()}),a.stderr.on("data",n=>{O&&process.stderr.write(n)})}function ie(e,t){if(d)return Promise.reject(new Error("language server is not running"));const n=++A;return new Promise((s,l)=>{h.set(n,{resolve:s,reject:l});try{a.stdin.write(I({jsonrpc:"2.0",id:n,method:e,params:t}))}catch{h.delete(n),l(new Error("language server is not running"))}})}function oe(e,t){if(!d)try{a.stdin.write(I({jsonrpc:"2.0",method:e,params:t}))}catch{}}async function ge(){if(!d){await Promise.race([ie("shutdown",{}).catch(()=>{}),new Promise(e=>setTimeout(e,500))]),oe("exit",{}),d=!0;try{a.stdin.end()}catch{}try{a.stdout.destroy()}catch{}try{a.stderr.destroy()}catch{}a.kill()}}function pe(e){return`file://${e}`}function me(e){return e.endsWith(".css")?"css":e.endsWith(".html")||e.endsWith(".vue")||e.endsWith(".svelte")||e.endsWith(".astro")?"html":e.endsWith(".mdx")?"mdx":e.endsWith(".jsx")?"javascriptreact":"typescriptreact"}export{W as brokenProjects,P as diagnosticsReceived,pe as fileUri,me as langId,oe as notify,J as projectInitCount,F as projectReady,ae as resetState,ie as send,M as settledProjects,ge as shutdown,de as startServer,ue as waitForAllProjects,fe as waitForDiagnostic,_ as warnings};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tailwint",
3
- "version": "1.1.10",
4
- "description": "Tailwind CSS linter for CI — drives the official language server to catch class issues and auto-fix them",
3
+ "version": "1.1.12",
4
+ "description": "Tiny Tailwind CSS linter and auto-fixer for CI — powered by the official language server, not regex",
5
5
  "license": "MIT",
6
6
  "author": "Peter Wang",
7
7
  "homepage": "https://github.com/peterwangsc/tailwint",
@@ -13,16 +13,24 @@
13
13
  "keywords": [
14
14
  "tailwindcss",
15
15
  "tailwind",
16
+ "tailwind-lint",
16
17
  "lint",
17
18
  "linter",
19
+ "cli",
18
20
  "ci",
21
+ "ci-cd",
19
22
  "autofix",
20
23
  "language-server",
21
24
  "lsp",
22
25
  "tailwind-v4",
23
26
  "css",
24
27
  "diagnostics",
25
- "code-quality"
28
+ "code-quality",
29
+ "class-conflicts",
30
+ "canonical",
31
+ "github-actions",
32
+ "pre-commit",
33
+ "static-analysis"
26
34
  ],
27
35
  "engines": {
28
36
  "node": ">=18"