ultracite 6.1.0 → 6.2.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.
- package/README.md +2 -2
- package/dist/index.d.ts +3 -1
- package/dist/index.js +148 -26
- package/package.json +12 -12
package/README.md
CHANGED
|
@@ -67,13 +67,13 @@ npx ultracite check
|
|
|
67
67
|
Tests are written in [Vitest](https://vitest.dev). You can run them with:
|
|
68
68
|
|
|
69
69
|
```bash
|
|
70
|
-
|
|
70
|
+
bun test
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
Check the coverage of the CLI with:
|
|
74
74
|
|
|
75
75
|
```bash
|
|
76
|
-
|
|
76
|
+
bun test:coverage
|
|
77
77
|
```
|
|
78
78
|
|
|
79
79
|
---
|
package/dist/index.d.ts
CHANGED
|
@@ -21,7 +21,9 @@ declare const router: _trpc_server.TRPCBuiltRouter<{
|
|
|
21
21
|
meta: TrpcCliMeta;
|
|
22
22
|
}>;
|
|
23
23
|
check: _trpc_server.TRPCQueryProcedure<{
|
|
24
|
-
input: string[] | undefined
|
|
24
|
+
input: [string[] | undefined, {
|
|
25
|
+
"diagnostic-level"?: "info" | "warn" | "error" | undefined;
|
|
26
|
+
}] | undefined;
|
|
25
27
|
output: void;
|
|
26
28
|
meta: TrpcCliMeta;
|
|
27
29
|
}>;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
2
|
+
var Y=Object.defineProperty;var Ve=Object.getOwnPropertyDescriptor;var Ye=Object.getOwnPropertyNames;var Ke=Object.prototype.hasOwnProperty;var K=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,n)=>(typeof require<"u"?require:t)[n]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')}),me=e=>t=>{var n=e[t];if(n)return n();throw new Error("Module not found in bundle: "+t)};var E=(e,t)=>()=>(e&&(t=e(e=0)),t);var X=(e,t)=>{for(var n in t)Y(e,n,{get:t[n],enumerable:!0})},Xe=(e,t,n,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of Ye(t))!Ke.call(e,s)&&s!==n&&Y(e,s,{get:()=>t[s],enumerable:!(i=Ve(t,s))||i.enumerable});return e};var Q=e=>Xe(Y({},"__esModule",{value:!0}),e);import{access as Ze,readFile as ge,writeFile as et}from"fs/promises";import{parse as tt}from"jsonc-parser";var l,h,he,k,nt,st,U,u=E(()=>{"use strict";l=async e=>{try{return await Ze(e),!0}catch{return!1}},h=async()=>{if(await l("pnpm-workspace.yaml"))return!0;try{let e=tt(await ge("package.json","utf-8"));return e?!!e.workspaces||!!e.workspace:!1}catch{return!1}},he=`
|
|
3
3
|
888 888 888 88888888888 8888888b. d8888 .d8888b. 8888888 88888888888 8888888888
|
|
4
4
|
888 888 888 888 888 Y88b d88888 d88P Y88b 888 888 888
|
|
5
5
|
888 888 888 888 888 888 d88P888 888 888 888 888 888
|
|
@@ -8,7 +8,7 @@ var K=Object.defineProperty;var ot=Object.getOwnPropertyDescriptor;var it=Object
|
|
|
8
8
|
888 888 888 888 888 T88b d88P 888 888 888 888 888 888
|
|
9
9
|
Y88b. .d88P 888 888 888 T88b d8888888888 Y88b d88P 888 888 888
|
|
10
10
|
"Y88888P" 88888888 888 888 T88b d88P 888 "Y8888P" 8888888 888 8888888888
|
|
11
|
-
`,
|
|
11
|
+
`,k=async({dependencies:e,devDependencies:t,scripts:n})=>{let i=await ge("package.json","utf8"),s=JSON.parse(i),o={...s};(s.devDependencies||t)&&(o.devDependencies={...s.devDependencies,...t}),(s.dependencies||e)&&(o.dependencies={...s.dependencies,...e}),(s.scripts||n)&&(o.scripts={...s.scripts,...n}),await et("package.json",JSON.stringify(o,null,2))},nt=/[ $(){}[\]&|;<>!"'`*?#~]/,st=/'/g,U=e=>e.map(t=>nt.test(t)?`'${t.replace(st,"'\\''")}' `:t)});var Me={};X(Me,{husky:()=>x});import{execSync as Lt}from"child_process";import{mkdir as zt,readFile as Bt,writeFile as Oe}from"fs/promises";import{addDevDependency as Wt,dlxCommand as re}from"nypm";var Te,G,x,ae=E(()=>{"use strict";u();Te=e=>`#!/bin/sh
|
|
12
12
|
# Exit on any error
|
|
13
13
|
set -e
|
|
14
14
|
|
|
@@ -76,10 +76,10 @@ if [ "$STAGED_HASH" != "$NEW_STAGED_HASH" ]; then
|
|
|
76
76
|
fi
|
|
77
77
|
|
|
78
78
|
exit $FORMAT_EXIT_CODE
|
|
79
|
-
`,G="./.husky/pre-commit",
|
|
80
|
-
${
|
|
79
|
+
`,G="./.husky/pre-commit",x={exists:()=>l(G),install:async e=>{await Wt("husky",{packageManager:e,workspace:await h()}),await k({scripts:{prepare:"husky"}})},init:e=>{let t=re(e,"husky",{args:["init"]});try{Lt(t,{stdio:"inherit"})}catch{}},create:async e=>{await zt(".husky",{recursive:!0});let t=re(e,"ultracite",{args:["fix"],short:e==="npm"}),n=Te(t);await Oe(G,n)},update:async e=>{let t=await Bt(G,"utf-8"),n=re(e,"ultracite",{args:["fix"],short:e==="npm"}),i=Te(n);await Oe(G,`${t}
|
|
80
|
+
${i}`)}}});var Je={};X(Je,{lefthook:()=>R});import{execSync as Ht}from"child_process";import{readFile as Gt,writeFile as O}from"fs/promises";import{addDevDependency as qt,dlxCommand as _e}from"nypm";var Vt,Yt,Ue,v,Ie,R,ce=E(()=>{"use strict";u();Vt=/(pre-commit:\s*\n\s*jobs:\s*\n)/,Yt=/(pre-commit:\s*\n)/,Ue=e=>_e(e,"ultracite",{args:["fix"],short:e==="npm"}),v="./lefthook.yml",Ie=e=>`pre-commit:
|
|
81
81
|
jobs:
|
|
82
|
-
- run: ${
|
|
82
|
+
- run: ${Ue(e)}
|
|
83
83
|
glob:
|
|
84
84
|
- "*.js"
|
|
85
85
|
- "*.jsx"
|
|
@@ -89,7 +89,7 @@ ${o}`)}}});var Ye={};Q(Ye,{lefthook:()=>S});import{execSync as ns}from"child_pro
|
|
|
89
89
|
- "*.jsonc"
|
|
90
90
|
- "*.css"
|
|
91
91
|
stage_fixed: true
|
|
92
|
-
`,
|
|
92
|
+
`,R={exists:()=>l(v),install:async e=>{await qt("lefthook",{packageManager:e,workspace:await h()});let t=_e(e,"lefthook",{args:["install"],short:e==="npm"});Ht(t)},create:async e=>{let t=Ie(e);await O(v,t)},update:async e=>{let t=await Gt(v,"utf-8"),n=Ue(e),i=Ie(e);if(t.includes(n))return;if(t.startsWith("# EXAMPLE USAGE:")){await O(v,i);return}if(t.includes("pre-commit:"))if(t.includes("jobs:")){let o=` - run: ${n}
|
|
93
93
|
glob:
|
|
94
94
|
- "*.js"
|
|
95
95
|
- "*.jsx"
|
|
@@ -98,9 +98,9 @@ ${o}`)}}});var Ye={};Q(Ye,{lefthook:()=>S});import{execSync as ns}from"child_pro
|
|
|
98
98
|
- "*.json"
|
|
99
99
|
- "*.jsonc"
|
|
100
100
|
- "*.css"
|
|
101
|
-
stage_fixed: true`,
|
|
102
|
-
`);await
|
|
103
|
-
- run: ${
|
|
101
|
+
stage_fixed: true`,r=t.replace(Vt,`$1${o}
|
|
102
|
+
`);await O(v,r)}else{let o=` jobs:
|
|
103
|
+
- run: ${n}
|
|
104
104
|
glob:
|
|
105
105
|
- "*.js"
|
|
106
106
|
- "*.jsx"
|
|
@@ -109,28 +109,150 @@ ${o}`)}}});var Ye={};Q(Ye,{lefthook:()=>S});import{execSync as ns}from"child_pro
|
|
|
109
109
|
- "*.json"
|
|
110
110
|
- "*.jsonc"
|
|
111
111
|
- "*.css"
|
|
112
|
-
stage_fixed: true`,
|
|
113
|
-
`);await
|
|
114
|
-
${
|
|
115
|
-
`).filter(
|
|
116
|
-
`;for(let
|
|
117
|
-
`}else t+=`${
|
|
118
|
-
`;return t},
|
|
119
|
-
`;await
|
|
120
|
-
`;await
|
|
121
|
-
`),e.push(
|
|
122
|
-
\u{1F4CA} Summary:`),console.log(` ${t} passed, ${
|
|
123
|
-
\u{1F4A1} To fix issues, run: npx ultracite init`),process.exit(1)),
|
|
112
|
+
stage_fixed: true`,r=t.replace(Yt,`$1${o}
|
|
113
|
+
`);await O(v,r)}else await O(v,`${t}
|
|
114
|
+
${i}`)}}});var Kt,le=E(()=>{Kt=me({"./husky.ts":()=>(ae(),Q(Me)),"./lefthook.ts":()=>(ce(),Q(Je)),"./lint-staged.ts":()=>(de(),Q(Le))})});var Le={};X(Le,{lintStaged:()=>A});import{readFile as q,writeFile as C}from"fs/promises";import{pathToFileURL as Xt}from"url";import T from"deepmerge";import{parse as pe}from"jsonc-parser";import{addDevDependency as Qt,dlxCommand as Zt}from"nypm";var y,ze,en,tn,nn,sn,on,rn,an,cn,ln,fe,dn,A,de=E(()=>{"use strict";u();le();y=e=>({"*.{js,jsx,ts,tsx,json,jsonc,css,scss,md,mdx}":[Zt(e,"ultracite",{args:["fix"],short:e==="npm"})]}),ze=["./package.json","./.lintstagedrc.json","./.lintstagedrc.js","./.lintstagedrc.cjs","./.lintstagedrc.mjs","./lint-staged.config.js","./lint-staged.config.cjs","./lint-staged.config.mjs","./.lintstagedrc.yaml","./.lintstagedrc.yml","./.lintstagedrc"],en=(e,t,n,i)=>{let s=e.trim();if(s.includes(":")&&!s.startsWith("-")){n&&i.length>0&&(t[n]=i);let[o,...r]=s.split(":"),c=r.join(":").trim(),f=o.trim().replace(/['"]/g,"");return c&&c!==""?(c.startsWith("[")&&c.endsWith("]")?t[f]=c.slice(1,-1).split(",").map(g=>g.trim().replace(/['"]/g,"")):t[f]=c.replace(/['"]/g,""),{newCurrentKey:null,newCurrentArray:[]}):{newCurrentKey:f,newCurrentArray:[]}}if(s.startsWith("-")&&n){let o=[...i,s.slice(1).trim().replace(/['"]/g,"")];return{newCurrentKey:n,newCurrentArray:o}}return{newCurrentKey:n,newCurrentArray:i}},tn=e=>{let t=e.split(`
|
|
115
|
+
`).filter(o=>o.trim()&&!o.trim().startsWith("#")),n={},i=null,s=[];for(let o of t){let r=en(o,n,i,s);i=r.newCurrentKey,s=r.newCurrentArray}return i&&s.length>0&&(n[i]=s),n},nn=e=>{let t="";for(let[n,i]of Object.entries(e))if(Array.isArray(i)){t+=`${n}:
|
|
116
|
+
`;for(let s of i)t+=` - '${s}'
|
|
117
|
+
`}else t+=`${n}: '${i}'
|
|
118
|
+
`;return t},sn=async()=>{try{let e=pe(await q("./package.json","utf-8"));return e?e.type==="module":!1}catch{return!1}},on=async e=>{let t=pe(await q("./package.json","utf-8"));t&&(t["lint-staged"]?t["lint-staged"]=T(t["lint-staged"],y(e)):t["lint-staged"]=y(e),await C("./package.json",JSON.stringify(t,null,2)))},rn=async(e,t)=>{let n=await q(e,"utf-8"),i=pe(n);if(!i)return;let s=T(i,y(t));await C(e,JSON.stringify(s,null,2))},an=async(e,t)=>{let n=await q(e,"utf-8"),i=tn(n);if(!i)return;let s=T(i,y(t));await C(e,nn(s))},cn=async(e,t)=>{let s=(await import(Xt(e).href)).default||{},o=T(s,y(t)),r=`export default ${JSON.stringify(o,null,2)};
|
|
119
|
+
`;await C(e,r)},ln=async(e,t)=>{delete K.cache[K.resolve(`./${e}`)];let n=Kt(`./${e}`),i=T(n,y(t)),s=`module.exports = ${JSON.stringify(i,null,2)};
|
|
120
|
+
`;await C(e,s)},fe=async e=>{await C(".lintstagedrc.json",JSON.stringify(y(e),null,2))},dn=async(e,t)=>{if(e==="./package.json"){await on(t);return}if(e.endsWith(".json")||e==="./.lintstagedrc"){await rn(e,t);return}if(e.endsWith(".yaml")||e.endsWith(".yml")){await an(e,t);return}let n=await sn();if(e.endsWith(".mjs")||e.endsWith(".js")&&n){try{await cn(e,t)}catch{await fe(t)}return}if(e.endsWith(".cjs")||e.endsWith(".js")&&!n)try{await ln(e,t)}catch{await fe(t)}},A={exists:async()=>{for(let e of ze)if(await l(e))return!0;return!1},install:async e=>{await Qt("lint-staged",{packageManager:e,workspace:await h()})},create:async e=>{await C(".lintstagedrc.json",JSON.stringify(y(e),null,2))},update:async e=>{let t=null;for(let n of ze)if(await l(n)){t=n;break}if(!t){await fe(e);return}await dn(t,e)}}});import{initTRPC as Nn}from"@trpc/server";import{createCli as Dn}from"trpc-cli";import a from"zod";var w={name:"ultracite",description:"The AI-ready formatter that helps you write and generate code faster.",version:"6.2.0",type:"module",bin:{ultracite:"dist/index.js"},files:["config","dist","README.md"],scripts:{build:"tsup",test:"bun test","test:coverage":"bun test --coverage"},exports:{"./*":"./config/*/biome.jsonc"},author:"Hayden Bleasel <hello@haydenbleasel.com>",bugs:{url:"https://github.com/haydenbleasel/ultracite/issues"},homepage:"https://www.ultracite.ai/",keywords:["ultracite","biome","linter","formatter","fixer"],license:"MIT",publishConfig:{access:"public",registry:"https://registry.npmjs.org/"},repository:{type:"git",url:"git+https://github.com/haydenbleasel/ultracite.git"},devDependencies:{"@biomejs/biome":"2.3.2","@types/node":"^24.10.0",tsup:"^8.5.0",turbo:"^2.6.0"},dependencies:{"@clack/prompts":"^0.11.0","@trpc/server":"^11.7.1",deepmerge:"^4.3.1",glob:"^11.0.3","jsonc-parser":"^3.3.1",nypm:"^0.6.2","trpc-cli":"^0.12.0",zod:"^4.1.12"},packageManager:"bun@1.3.1"};u();import{spawnSync as it}from"child_process";import ye from"process";var Z=e=>{let t=e?.[0]||[],n=e?.[1]["diagnostic-level"],i=["npx","@biomejs/biome","check","--no-errors-on-unmatched"];n&&i.push(`--diagnostic-level=${n}`),t.length>0?i.push(...U(t)):i.push("./");let s=i.join(" "),o=it(s,{stdio:"inherit",shell:!0});o.error&&(console.error("Failed to run Ultracite:",o.error.message),ye.exit(1)),o.status!==0&&ye.exit(o.status??1)};import{spawnSync as kt}from"child_process";import{existsSync as F}from"fs";import{readFile as je}from"fs/promises";import{join as $}from"path";import{parse as bt}from"jsonc-parser";u();import{readFile as we,unlink as ot,writeFile as rt}from"fs/promises";import{parse as ke}from"jsonc-parser";import{removeDependency as at}from"nypm";var J=[".eslintrc",".eslintrc.js",".eslintrc.json",".eslintrc.yml",".eslintrc.yaml",".eslintrc.config.js","eslint.config.js","eslint.config.mjs","eslint.config.cjs",".eslintignore"],be=async()=>{try{let e=await we("package.json","utf-8"),t=ke(e);if(!t||typeof t!="object")return[];let n=t.dependencies||{},i=t.devDependencies||{},s={...n,...i};return Object.keys(s).filter(o=>o.includes("eslint"))}catch{return[]}},ct=async(e,t)=>{if(t.length!==0)try{for(let n of t)await at(n,{packageManager:e})}catch(n){console.warn(n)}},lt=async()=>{let e=[];for(let t of J)if(await l(t))try{await ot(t),e.push(t)}catch(n){console.warn(n)}return e},dt=async()=>{let e="./.vscode/settings.json";if(!await l(e))return!1;try{let t=await we(e,"utf-8"),n=ke(t);if(!n||typeof n!="object")return!1;let i=!1,s={...n},o=["eslint.enable","eslint.format.enable","eslint.validate","eslint.workingDirectories","eslint.codeAction.showDocumentation","eslint.run","eslint.autoFixOnSave","eslint.quiet","eslint.packageManager","eslint.options","eslint.trace.server"];for(let r of o)r in s&&(delete s[r],i=!0);if("editor.codeActionsOnSave"in s){let r=s["editor.codeActionsOnSave"];if(r&&typeof r=="object"){let c=["source.fixAll.eslint","source.organizeImports.eslint"];for(let f of c)f in r&&(delete r[f],i=!0);Object.keys(r).length===0&&(s["editor.codeActionsOnSave"]=void 0)}}return i?(await rt(e,JSON.stringify(s,null,2)),!0):!1}catch(t){return console.warn(t),!1}},ft=async()=>{if((await be()).length>0)return!0;for(let t of J)if(await l(t))return!0;return!1},ee={hasEsLint:ft,remove:async e=>{let t=await be();await ct(e,t);let n=await lt(),i=await dt();return{packagesRemoved:t,filesRemoved:n,vsCodeCleaned:i}}};u();import{readFile as xe,unlink as pt,writeFile as ut}from"fs/promises";import{parse as ve}from"jsonc-parser";import{removeDependency as mt}from"nypm";var L=[".prettierrc",".prettierrc.js",".prettierrc.json",".prettierrc.yml",".prettierrc.yaml",".prettierrc.config.js","prettier.config.js","prettier.config.mjs",".prettierignore"],Ce=async()=>{try{let e=await xe("package.json","utf-8"),t=ve(e);if(!t||typeof t!="object")return[];let n=t.dependencies||{},i=t.devDependencies||{},s={...n,...i};return Object.keys(s).filter(o=>o.includes("prettier"))}catch{return[]}},gt=async(e,t)=>{if(t.length!==0)try{for(let n of t)await mt(n,{packageManager:e})}catch(n){console.warn(n)}},ht=async()=>{let e=[];for(let t of L)if(await l(t))try{await pt(t),e.push(t)}catch(n){console.warn(n)}return e},yt=async()=>{let e="./.vscode/settings.json";if(!await l(e))return!1;try{let t=await xe(e,"utf-8"),n=ve(t);if(!n||typeof n!="object")return!1;let i=!1,s={...n},o=["editor.defaultFormatter","prettier.enable","prettier.requireConfig","prettier.configPath","prettier.printWidth","prettier.tabWidth","prettier.useTabs","prettier.semi","prettier.singleQuote","prettier.quoteProps","prettier.trailingComma","prettier.bracketSpacing","prettier.arrowParens","prettier.endOfLine"];for(let c of o)c in s&&(c==="editor.defaultFormatter"&&s[c]==="esbenp.prettier-vscode"||c!=="editor.defaultFormatter")&&(delete s[c],i=!0);let r=Object.keys(s).filter(c=>c.startsWith("[")&&c.includes("javascript"));for(let c of r){let f=s[c];f&&typeof f=="object"&&"editor.defaultFormatter"in f&&f["editor.defaultFormatter"]==="esbenp.prettier-vscode"&&(delete f["editor.defaultFormatter"],i=!0,Object.keys(f).length===0&&delete s[c])}return i?(await ut(e,JSON.stringify(s,null,2)),!0):!1}catch(t){return console.warn(t),!1}},wt=async()=>{if((await Ce()).length>0)return!0;for(let t of L)if(await l(t))return!0;return!1},te={hasPrettier:wt,remove:async e=>{let t=await Ce();await gt(e,t);let n=await ht(),i=await yt();return{packagesRemoved:t,filesRemoved:n,vsCodeCleaned:i}}};var xt=()=>{let e=kt("npx @biomejs/biome --version",{shell:!0,encoding:"utf-8"});return e.status===0&&e.stdout?{name:"Biome installation",status:"pass",message:`Biome is installed (${e.stdout.trim()})`}:{name:"Biome installation",status:"fail",message:"Biome is not installed or not accessible"}},vt=async()=>{let e=$(process.cwd(),"biome.json"),t=$(process.cwd(),"biome.jsonc"),n=null;if(F(e)?n=e:F(t)&&(n=t),!n)return{name:"Biome configuration",status:"fail",message:"No biome.json or biome.jsonc file found"};try{let i=await je(n,"utf-8"),s=bt(i);return Array.isArray(s?.extends)&&s.extends.includes("ultracite/core")?{name:"Biome configuration",status:"pass",message:"biome.json(c) extends ultracite/core"}:{name:"Biome configuration",status:"warn",message:"biome.json(c) exists but doesn't extend ultracite/core"}}catch{return{name:"Biome configuration",status:"fail",message:"Could not parse biome.json(c) file"}}},Ct=async()=>{let e=$(process.cwd(),"package.json");if(!F(e))return{name:"Ultracite dependency",status:"warn",message:"No package.json found"};try{let t=JSON.parse(await je(e,"utf-8")),n=t.dependencies?.ultracite||t.devDependencies?.ultracite||t.peerDependencies?.ultracite;return n?{name:"Ultracite dependency",status:"pass",message:`Ultracite is in package.json (${n})`}:{name:"Ultracite dependency",status:"warn",message:"Ultracite not found in package.json dependencies"}}catch{return{name:"Ultracite dependency",status:"warn",message:"Could not parse package.json"}}},jt=()=>{let e=L.some(n=>F($(process.cwd(),n))),t=J.some(n=>F($(process.cwd(),n)));if(e||t){let n=[];return e&&n.push("Prettier"),t&&n.push("ESLint"),{name:"Conflicting tools",status:"warn",message:`Found potentially conflicting tools: ${n.join(", ")}`}}return{name:"Conflicting tools",status:"pass",message:"No conflicting formatting/linting tools found"}},Pe=async()=>{let e=[];console.log(`\u{1FA7A} Running Ultracite doctor...
|
|
121
|
+
`),e.push(xt()),e.push(await vt()),e.push(await Ct()),e.push(jt());let t=e.filter(s=>s.status==="pass").length,n=e.filter(s=>s.status==="fail").length,i=e.filter(s=>s.status==="warn").length;for(let s of e){let o;s.status==="pass"?o="\u2705":s.status==="fail"?o="\u274C":o="\u26A0\uFE0F",console.log(`${o} ${s.name}: ${s.message}`)}console.log(`
|
|
122
|
+
\u{1F4CA} Summary:`),console.log(` ${t} passed, ${i} warnings, ${n} failed`),n>0&&(console.log(`
|
|
123
|
+
\u{1F4A1} To fix issues, run: npx ultracite init`),process.exit(1)),i>0?console.log(`
|
|
124
124
|
\u{1F4A1} Some optional improvements available. Run 'npx ultracite init' to configure.`):console.log(`
|
|
125
|
-
\u2728 Everything looks good!`)};
|
|
125
|
+
\u2728 Everything looks good!`)};u();import{spawnSync as Pt}from"child_process";import Se from"process";var ne=(e,t={})=>{let n=["npx","@biomejs/biome","check","--write","--no-errors-on-unmatched"];t.unsafe&&n.push("--unsafe"),e.length>0?n.push(...U(e)):n.push("./");let i=n.join(" "),s=Pt(i,{stdio:"inherit",shell:!0});s.error&&(console.error("Failed to run Ultracite:",s.error.message),Se.exit(1)),s.status!==0&&Se.exit(s.status??1)};import{packageManagers as St}from"nypm";var b={packageManagers:St.map(e=>e.name),editorConfigs:["vscode","zed"],agents:["vscode-copilot","cursor","windsurf","zed","claude","codex","kiro","cline","amp","aider","firebase-studio","open-hands","gemini-cli","junie","augmentcode","kilo-code","goose","roo-code","warp"],integrations:["husky","lefthook","lint-staged"],frameworks:["react","next","solid","vue","svelte","qwik","remix","angular","astro"],migrations:["eslint","prettier"]};import j from"process";import{cancel as M,intro as wn,isCancel as I,log as V,multiselect as _,spinner as m}from"@clack/prompts";import{addDevDependency as kn,detectPackageManager as bn}from"nypm";import{mkdir as Rt,readFile as Ae,writeFile as S}from"fs/promises";import{dirname as At}from"path";var Re={"vscode-copilot":{path:"./.github/copilot-instructions.md",header:`---
|
|
126
126
|
applyTo: "**/*.{ts,tsx,js,jsx}"
|
|
127
127
|
---`,appendMode:!0},cursor:{path:"./.cursor/rules/ultracite.mdc",header:`---
|
|
128
128
|
description: Ultracite Rules - AI-Ready Formatter and Linter
|
|
129
129
|
globs: "**/*.{ts,tsx,js,jsx,json,jsonc,html,vue,svelte,astro,css,yaml,yml,graphql,gql,md,mdx,grit}"
|
|
130
130
|
alwaysApply: false
|
|
131
|
-
---`},windsurf:{path:"./.windsurf/rules/ultracite.md"},zed:{path:"./.rules",appendMode:!0},claude:{path:"./.claude/CLAUDE.md",appendMode:!0},codex:{path:"./AGENTS.md",appendMode:!0},kiro:{path:"./.kiro/steering/ultracite.md"},cline:{path:"./.clinerules",appendMode:!0},amp:{path:"./AGENT.md",appendMode:!0},aider:{path:"./ultracite.md"},"firebase-studio":{path:"./.idx/airules.md",appendMode:!0},"open-hands":{path:"./.openhands/microagents/repo.md",appendMode:!0},"gemini-cli":{path:"./GEMINI.md",appendMode:!0},junie:{path:"./.junie/guidelines.md",appendMode:!0},augmentcode:{path:"./.augment/rules/ultracite.md"},"kilo-code":{path:"./.kilocode/rules/ultracite.md"},goose:{path:"./.goosehints",appendMode:!0},"roo-code":{path:"./.roo/rules/ultracite.md",appendMode:!0},warp:{path:"./WARP.md",appendMode:!0}};m();var Re=["Avoid `accessKey` attr and distracting els",'No `aria-hidden="true"` on focusable els',"No ARIA roles, states, props on unsupported els","Use `scope` prop only on `<th>` els","No non-interactive ARIA roles on interactive els","Label els need text and associated input","No event handlers on non-interactive els","No interactive ARIA roles on non-interactive els","No `tabIndex` on non-interactive els","No positive integers on `tabIndex` prop","No `image`, `picture`, or `photo` in img alt props","No explicit role matching implicit role","Valid role attrs on static, visible els w/ click handlers","Use `title` el for `svg` els","Provide meaningful alt text for all els requiring it","Anchors need accessible content","Assign `tabIndex` to non-interactive els w/ `aria-activedescendant`","Include all required ARIA attrs for els w/ ARIA roles","Use valid ARIA props for the el's role","Use `type` attr on `button` els","Make els w/ interactive roles and handlers focusable","Heading els need accessible content","Add `lang` attr to `html` el","Use `title` attr on `iframe` els","Pair `onClick` w/ `onKeyUp`, `onKeyDown`, or `onKeyPress`","Pair `onMouseOver`/`onMouseOut` w/ `onFocus`/`onBlur`","Add caption tracks to audio and video els","Use semantic els vs role attrs","All anchors must be valid and navigable","Use valid, non-abstract ARIA props, roles, states, and values","Use valid values for `autocomplete` attr","Use correct ISO language codes in `lang` attr","Include generic font family in font families","No consecutive spaces in regex literals","Avoid `arguments`, comma op, and primitive type aliases","No empty type params in type aliases and interfaces","Keep fns under Cognitive Complexity limit","Limit nesting depth of `describe()` in tests","No unnecessary boolean casts or callbacks on `flatMap`","Use `for...of` vs `Array.forEach`","No classes w/ only static members","No `this` and `super` in static contexts","No unnecessary catch clauses, ctors, `continue`, escape sequences in regex literals, fragments, labels, or nested blocks","No empty exports","No renaming imports, exports, or destructured assignments to same name","No unnecessary string/template literal concatenation or useless cases in switch stmts, `this` aliasing, or `String.raw` without escape sequences","Use simpler alternatives to ternary ops if possible","No `any` or `unknown` as type constraints or initializing vars to `undefined`","Avoid `void` op","Use arrow fns vs function exprs","Use `Date.now()` for milliseconds since Unix Epoch","Use `.flatMap()` vs `map().flat()`","Use `indexOf`/`lastIndexOf` vs `findIndex`/`findLastIndex` for simple lookups","Use literal property access vs computed property access","Use binary, octal, or hex literals vs `parseInt()`","Use concise optional chains vs chained logical exprs","Use regex literals vs `RegExp` ctor","Use base 10 or underscore separators for number literal object member names","Remove redundant terms from logical exprs","Use `while` loops vs `for` loops if initializer and update aren't needed","No reassigning `const` vars or constant exprs in conditions","No `Math.min`/`Math.max` to clamp values where result is constant","No return values from ctors or setters","No empty character classes in regex literals or destructuring patterns","No `__dirname` and `__filename` in global scope","No calling global object props as fns or declaring fns and `var` accessible outside their block","Instantiate builtins correctly","Use `super()` correctly in classes","Use standard direction values for linear gradient fns","Use valid named grid areas in CSS Grid Layouts","Use `@import` at-rules in valid positions","No vars and params before their decl","Include `var` fn for CSS vars","No `\\8` and `\\9` escape sequences in strings","No literal numbers that lose precision, configured els, or assigning where both sides are same","Compare string case modifications w/ compliant values","No lexical decls in switch clauses or undeclared vars","No unknown CSS value fns, media feature names, props, pseudo-class/pseudo-element selectors, type selectors, or units","No unmatchable An+B selectors or unreachable code","Call `super()` exactly once before accessing `this` in ctors","No control flow stmts in `finally` blocks","No optional chaining where `undefined` is not allowed","No unused fn params, imports, labels, private class members, or vars","No return values from fns w/ return type `void`","Specify all dependencies correctly in React hooks and names for GraphQL operations","Call React hooks from top level of component fns","Use `isNaN()` when checking for NaN",'Use `{ type: "json" }` for JSON module imports',"Use radix arg w/ `parseInt()`","Start JSDoc comment lines w/ single asterisk","Move `for` loop counters in right direction","Compare `typeof` exprs to valid values","Include `yield` in generator fns","No importing deprecated exports, duplicate dependencies, or Promises where they're likely a mistake","No non-null assertions after optional chaining or shadowing vars from outer scope","No expr stmts that aren't fn calls or assignments or useless `undefined`","Add `href` attr to `<a>` els and `width`/`height` attrs to `<img>` els","Use consistent arrow fn bodies and either `interface` or `type` consistently","Specify deletion date w/ `@deprecated` directive","Make switch-case stmts exhaustive and limit number of fn params","Sort CSS utility classes","No spread syntax on accumulators, barrel files, `delete` op, dynamic namespace import access, namespace imports, or duplicate polyfills from Polyfill.io","Use `preconnect` attr w/ Google Fonts","Declare regex literals at top level",'Add `rel="noopener"` when using `target="_blank"`',"No dangerous JSX props","No both `children` and `dangerouslySetInnerHTML` props","No global `eval()`","No callbacks in async tests and hooks, TS enums, exporting imported vars, type annotations for vars initialized w/ literals, magic numbers without named constants, or TS namespaces","No negating `if` conditions when there's an `else` clause, nested ternary exprs, non-null assertions (`!`), reassigning fn params, parameter props in class ctors, specified global var names, importing specified modules, or specified user-defined types","No constants where value is upper-case version of name, template literals without interpolation or special chars, `else` blocks when `if` block breaks early, yoda exprs, or `Array` ctors","Use `String.slice()` vs `String.substr()` and `String.substring()`","Use `as const` vs literal type annotations and `at()` vs integer index access","Follow curly brace conventions","Use `else if` vs nested `if` in `else` clauses and single `if` vs nested `if` clauses","Use `T[]` vs `Array<T>`","Use `new` for all builtins except `String`, `Number`, and `Boolean`","Use consistent accessibility modifiers on class props and methods","Declare object literals consistently","Use `const` for vars only assigned once","Put default and optional fn params last","Include `default` clause in switch stmts","Specify reason arg w/ `@deprecated` directive","Explicitly initialize each enum member value","Use `**` op vs `Math.pow`","Use `export type` and `import type` for types","Use kebab-case, ASCII filenames","Use `for...of` vs `for` loops w/ array index access","Use `<>...</>` vs `<Fragment>...</Fragment>`","Capitalize all enum values","Place getters and setters for same prop adjacent","Use literal values for all enum members","Use `node:assert/strict` vs `node:assert`","Use `node:` protocol for Node.js builtin modules","Use `Number` props vs global ones","Use numeric separators in numeric literals","Use object spread vs `Object.assign()` for new objects","Mark members `readonly` if never modified outside ctor","No extra closing tags for comps without children","Use assignment op shorthand","Use fn types vs object types w/ call signatures","Add description param to `Symbol()`","Use template literals vs string concatenation","Use `new` when throwing an error","No throwing non-`Error` values","Use `String.trimStart()`/`String.trimEnd()` vs `String.trimLeft()`/`String.trimRight()`","No overload signatures that can be unified","No lower specificity selectors after higher specificity selectors","No `@value` rule in CSS modules","No `alert`, `confirm`, and `prompt`","Use standard constants vs approximated literals","No assigning in exprs","No async fns as Promise executors","No `!` pattern in first position of `files.includes`","No bitwise ops","No reassigning exceptions in catch clauses","No reassigning class members","No inserting comments as text nodes","No comparing against `-0`","No labeled stmts that aren't loops","No `void` type outside generic or return types","No `console`","No TS const enums","No exprs where op doesn't affect value","No control chars in regex literals","No `debugger`","No assigning directly to `document.cookie`","Use `===` and `!==`","No duplicate `@import` rules, case labels, class members, custom props, conditions in if-else-if chains, GraphQL fields, font family names, object keys, fn param names, decl block props, keyframe selectors, or describe hooks","No empty CSS blocks, block stmts, static blocks, or interfaces","No letting vars evolve into `any` type through reassignments","No `any` type","No `export` or `module.exports` in test files","No misusing non-null assertion op (`!`)","No fallthrough in switch clauses","No focused or disabled tests","No reassigning fn decls","No assigning to native objects and read-only global vars","Use `Number.isFinite` and `Number.isNaN` vs global `isFinite` and `isNaN`","No implicit `any` type on var decls","No assigning to imported bindings","No `!important` within keyframe decls","No irregular whitespace chars","No labels that share name w/ var","No chars made w/ multiple code points in char classes","Use `new` and `constructor` properly","Place assertion fns inside `it()` fn calls","No shorthand assign when var appears on both sides","No octal escape sequences in strings","No `Object.prototype` builtins directly","No `quickfix.biome` in editor settings","No redeclaring vars, fns, classes, and types in same scope","No redundant `use strict`","No comparing where both sides are same","No shadowing restricted names","No shorthand props that override related longhand props","No sparse arrays","No template literal placeholder syntax in regular strings","No `then` prop","No `@ts-ignore` directive","No `let` or `var` vars that are read but never assigned","No unknown at-rules","No merging interface and class decls unsafely","No unsafe negation (`!`)","No unnecessary escapes in strings or useless backreferences in regex literals","No `var`","No `with` stmts","No separating overload signatures","Use `await` in async fns","Use correct syntax for ignoring folders in config","Put default clauses in switch stmts last","Pass message value when creating built-in errors","Return value from get methods","Use recommended display strategy w/ Google Fonts","Include `if` stmt in for-in loops","Use `Array.isArray()` vs `instanceof Array`","Return consistent values in iterable callbacks","Use `namespace` keyword vs `module` keyword","Use digits arg w/ `Number#toFixed()`","Use static `Response` methods vs `new Response()`","Use `use strict` directive in script files"],Ae=["No passing children as props. Nest children between opening and closing tags","No defining comps inside other comps","No reassigning props in React comps","No using return value from `ReactDOM.render()`","No adding children to void els like `<img>` and `<br>`","Specify all dependencies correctly in React hooks","Call React hooks from top level of comp fns only","Add `key` prop to els in iterables","No legacy `React.forwardRef`. Use ref as prop instead (React 19+)","Use fn comps vs class comps","No array indices as keys","No duplicate props in JSX","No semicolons that change JSX el semantics"],Ue=["No async client comps. Use server comps for async operations","Use Next.js `<Image>` comp vs `<img>` el","Use Next.js `next/head` or App Router metadata API vs `<head>` el","No importing `next/document` in page files","No importing `next/head` in `_document.tsx`. Use `<Head>` from `next/document` instead"],Fe=["No `useVisibleTask$`. Use `useTask$` or `useResource$` instead","Use `class` object syntax vs string concatenation for dynamic classes","Explicitly capture vars from outer scopes in Qwik's `$` fns","Use Qwik-specific methods and APIs correctly","No React-specific props like `className` and `htmlFor`. Use `class` and `for` instead"],Ee=["No destructuring props in Solid comps. Access props directly","Use `<For>` comp for iterating over arrays","No React-specific props like `className` and `htmlFor`. Use `class` and `for` instead"],$e=["No React-specific props like `className` and `htmlFor`. Use `class` and `for` instead"],Ie=["No object decls for `data` option. Use fn that returns object","No duplicate keys in Vue comp options","No Vue reserved keys like `$data`, `$props`, and `$el` in comp options","No Vue reserved props like `key`, `ref`, and `is` as custom comp props","Use multi-word comp names to avoid conflicts w/ HTML els","No React-specific props like `className` and `htmlFor`. Use `class` and `for` instead"],Oe=[],Me=[],De=["Use `let` or `var` when variables are reassigned in Astro comp frontmatter","Avoid explicit import types in Astro files for better compat","Unused vars and imports are allowed in Astro files due to frontmatter constraints","No React-specific props like `className` and `htmlFor`. Use `class` and `for` instead"];var Jt=e=>{let t=[...Re];return e&&(e.includes("react")&&t.push(...Ae),e.includes("next")&&t.push(...Ue),e.includes("qwik")&&t.push(...Fe),e.includes("solid")&&t.push(...Ee),e.includes("svelte")&&t.push(...$e),e.includes("vue")&&t.push(...Ie),e.includes("angular")&&t.push(...Oe),e.includes("remix")&&t.push(...Me),e.includes("astro")&&t.push(...De)),t.join(`
|
|
132
|
-
`)},Te=(e,t)=>{let s=Pe[e],o=Jt(t),n=s.header?`${s.header}
|
|
131
|
+
---`},windsurf:{path:"./.windsurf/rules/ultracite.md"},zed:{path:"./.rules",appendMode:!0},claude:{path:"./.claude/CLAUDE.md",appendMode:!0},codex:{path:"./AGENTS.md",appendMode:!0},kiro:{path:"./.kiro/steering/ultracite.md"},cline:{path:"./.clinerules",appendMode:!0},amp:{path:"./AGENT.md",appendMode:!0},aider:{path:"./ultracite.md"},"firebase-studio":{path:"./.idx/airules.md",appendMode:!0},"open-hands":{path:"./.openhands/microagents/repo.md",appendMode:!0},"gemini-cli":{path:"./GEMINI.md",appendMode:!0},junie:{path:"./.junie/guidelines.md",appendMode:!0},augmentcode:{path:"./.augment/rules/ultracite.md"},"kilo-code":{path:"./.kilocode/rules/ultracite.md"},goose:{path:"./.goosehints",appendMode:!0},"roo-code":{path:"./.roo/rules/ultracite.md",appendMode:!0},warp:{path:"./WARP.md",appendMode:!0}};u();var N=`# Ultracite Code Standards
|
|
133
132
|
|
|
134
|
-
|
|
133
|
+
This project uses **Ultracite**, a zero-config Biome preset that enforces strict code quality standards through automated formatting and linting.
|
|
135
134
|
|
|
136
|
-
${o}`)}else await J(s.path,n)}}};m();import{readFile as Lt,writeFile as _e}from"fs/promises";import zt from"deepmerge";import{parse as qt}from"jsonc-parser";var Je={$schema:"./node_modules/@biomejs/biome/configuration_schema.json",extends:["ultracite/core"]},oe=async()=>await c("./biome.json")?"./biome.json":"./biome.jsonc",L={exists:async()=>{let e=await oe();return c(e)},create:async e=>{let t=await oe(),s=["ultracite/core"];if(e?.frameworks&&e.frameworks.length>0)for(let n of e.frameworks)s.push(`ultracite/${n}`);let o={...Je,extends:s};return _e(t,JSON.stringify(o,null,2))},update:async e=>{let t=await oe(),s=await Lt(t,"utf-8"),n=qt(s)||{},a=[...n.extends&&Array.isArray(n.extends)?n.extends:[]];if(a.includes("ultracite/core")||a.push("ultracite/core"),e?.frameworks&&e.frameworks.length>0)for(let g of e.frameworks){let d=`ultracite/${g}`;a.includes(d)||a.push(d)}n.extends=a;let r={$schema:Je.$schema},p=zt(n,r);await _e(t,JSON.stringify(p,null,2))}};m();import{spawnSync as Bt}from"child_process";import{mkdir as Gt,readFile as Wt,writeFile as Le}from"fs/promises";import Ht from"deepmerge";import{parse as Vt}from"jsonc-parser";var ie={"editor.defaultFormatter":"esbenp.prettier-vscode","[javascript]":{"editor.defaultFormatter":"biomejs.biome"},"[typescript]":{"editor.defaultFormatter":"biomejs.biome"},"[javascriptreact]":{"editor.defaultFormatter":"biomejs.biome"},"[typescriptreact]":{"editor.defaultFormatter":"biomejs.biome"},"[json]":{"editor.defaultFormatter":"biomejs.biome"},"[jsonc]":{"editor.defaultFormatter":"biomejs.biome"},"[css]":{"editor.defaultFormatter":"biomejs.biome"},"[graphql]":{"editor.defaultFormatter":"biomejs.biome"},"typescript.tsdk":"node_modules/typescript/lib","editor.formatOnSave":!0,"editor.formatOnPaste":!0,"emmet.showExpandedAbbreviation":"never","editor.codeActionsOnSave":{"source.fixAll.biome":"explicit","source.organizeImports.biome":"explicit"}};var z="./.vscode/settings.json",F={exists:()=>c(z),create:async()=>{await Gt(".vscode",{recursive:!0}),await Le(z,JSON.stringify(ie,null,2))},update:async()=>{let e=await Wt(z,"utf-8"),s=Vt(e)||{},o=Ht(s,ie);await Le(z,JSON.stringify(o,null,2))},extension:()=>Bt("code --install-extension biomejs.biome",{stdio:"inherit",shell:!0})};m();import{mkdir as Yt,readFile as Kt,writeFile as ze}from"fs/promises";import Xt from"deepmerge";import{parse as Qt}from"jsonc-parser";var ae={formatter:"language_server",format_on_save:"on",languages:{JavaScript:{formatter:{language_server:{name:"biome"}},code_actions_on_format:{"source.fixAll.biome":!0,"source.organizeImports.biome":!0}},TypeScript:{formatter:{language_server:{name:"biome"}},code_actions_on_format:{"source.fixAll.biome":!0,"source.organizeImports.biome":!0}},JSX:{formatter:{language_server:{name:"biome"}},code_actions_on_format:{"source.fixAll.biome":!0,"source.organizeImports.biome":!0}},TSX:{formatter:{language_server:{name:"biome"}},code_actions_on_format:{"source.fixAll.biome":!0,"source.organizeImports.biome":!0}}},lsp:{"typescript-language-server":{settings:{typescript:{preferences:{includePackageJsonAutoImports:"on"}}}}}};var q="./.zed/settings.json",B={exists:()=>c(q),create:async()=>{await Yt(".zed",{recursive:!0}),await ze(q,JSON.stringify(ae,null,2))},update:async()=>{let e=await Kt(q,"utf-8"),s=Qt(e)||{},o=Xt(s,ae);await ze(q,JSON.stringify(o,null,2))}};ce();le();pe();m();import{readFile as xs,writeFile as Qe}from"fs/promises";import Ns from"deepmerge";import{parse as Cs}from"jsonc-parser";var Ze={compilerOptions:{strictNullChecks:!0}},H="./tsconfig.json",V={exists:()=>c(H),create:()=>Qe(H,JSON.stringify(Ze,null,2)),update:async()=>{let e=await xs(H,"utf-8"),s=Cs(e)||{},o=Ns(s,Ze);await Qe(H,JSON.stringify(o,null,2))}};m();var et=w.devDependencies["@biomejs/biome"],tt=w.version,Rs=async(e,t=!0)=>{let s=f();s.start("Installing dependencies...");let o=[`ultracite@${tt}`,`@biomejs/biome@${et}`];if(t)for(let n of o)await Ss(n,{packageManager:e,workspace:await h()});else await v({devDependencies:{"@biomejs/biome":et,ultracite:tt}});s.stop("Dependencies installed.")},As=async()=>{let e=f();if(e.start("Checking for tsconfig.json..."),await V.exists()){e.message("tsconfig.json found, updating..."),await V.update(),e.stop("tsconfig.json updated.");return}e.message("tsconfig.json not found, creating..."),await V.create(),e.stop("tsconfig.json created.")},Us=async()=>{let e=f();if(e.start("Checking for .vscode/settings.json..."),await F.exists()){e.message("settings.json found, updating..."),await F.update(),e.stop("settings.json updated.");return}e.message("settings.json not found, creating..."),await F.create(),e.message("settings.json created."),e.message("Installing Biome extension...");try{F.extension(),e.stop("settings.json created.")}catch(t){e.stop(`Failed to install Biome extension (${t}), but continuing...`)}},Fs=async()=>{let e=f();if(e.start("Checking for .zed/settings.json..."),await B.exists()){e.message("settings.json found, updating..."),await B.update(),e.stop("settings.json updated.");return}e.message("settings.json not found, creating..."),await B.create(),e.message("settings.json created. Install the Biome extension: https://biomejs.dev/reference/zed/")},Es=async e=>{let t=f();if(t.start("Checking for Biome configuration..."),await L.exists()){t.message("Biome configuration found, updating..."),await L.update({frameworks:e}),t.stop("Biome configuration updated.");return}t.message("Biome configuration not found, creating..."),await L.create({frameworks:e}),t.stop("Biome configuration created.")},$s=async(e,t=!0)=>{let s=f();if(s.start("Initializing pre-commit hooks..."),s.message("Installing Husky..."),t?await k.install(e):await v({devDependencies:{husky:"latest"},scripts:{prepare:"husky"}}),s.message("Initializing Husky..."),k.init(e),await k.exists()){s.message("Pre-commit hook found, updating..."),await k.update(e),s.stop("Pre-commit hook updated.");return}s.message("Pre-commit hook not found, creating..."),await k.create(e),s.stop("Pre-commit hook created.")},Is=async(e,t=!0)=>{let s=f();if(s.start("Initializing lefthook..."),s.message("Installing lefthook..."),t?await S.install(e):await v({devDependencies:{lefthook:"latest"}}),await S.exists()){s.message("lefthook.yml found, updating..."),await S.update(e),s.stop("lefthook.yml updated.");return}s.message("lefthook.yml not found, creating..."),await S.create(e),s.stop("lefthook.yml created.")},Os=async(e,t=!0)=>{let s=f();if(s.start("Initializing lint-staged..."),s.message("Installing lint-staged..."),t?await P.install(e):await v({devDependencies:{"lint-staged":"latest"}}),await P.exists()){s.message("lint-staged found, updating..."),await P.update(e),s.stop("lint-staged updated.");return}s.message("lint-staged not found, creating..."),await P.create(e),s.stop("lint-staged created.")},Ms=async(e,t,s)=>{let o=f();o.start(`Checking for ${t}...`);let n=Te(e,s);if(await n.exists()){o.message(`${t} found, updating...`),await n.update(),o.stop(`${t} updated.`);return}o.message(`${t} not found, creating...`),await n.create(),o.stop(`${t} created.`)},Ds=async e=>{let t=f();t.start("Removing Prettier dependencies and configuration...");try{let s=await se.remove(e);s.packagesRemoved.length>0&&t.message(`Removed Prettier packages: ${s.packagesRemoved.join(", ")}`),s.filesRemoved.length>0&&t.message(`Removed config files: ${s.filesRemoved.join(", ")}`),s.vsCodeCleaned&&t.message("Cleaned VS Code settings"),t.stop("Prettier removed successfully.")}catch{t.stop("Failed to remove Prettier completely, but continuing...")}},Ts=async e=>{let t=f();t.start("Removing ESLint dependencies and configuration...");try{let s=await te.remove(e);s.packagesRemoved.length>0&&t.message(`Removed ESLint packages: ${s.packagesRemoved.join(", ")}`),s.filesRemoved.length>0&&t.message(`Removed config files: ${s.filesRemoved.join(", ")}`),s.vsCodeCleaned&&t.message("Cleaned VS Code settings"),t.stop("ESLint removed successfully.")}catch{t.stop("Failed to remove ESLint completely, but continuing...")}},st=async e=>{js(he);try{let t=e??{},{pm:s}=t;if(!s){let d=await Ps(C.cwd());if(!d)throw new Error("No package manager specified or detected");if(d.warnings)for(let u of d.warnings)Y.warn(u);Y.info(`Detected lockfile, using ${d.name}`),s=d.name}let o=t.migrate?.includes("prettier"),n=t.migrate?.includes("eslint");if(o===void 0||n===void 0){let d=[];if(o===void 0&&await se.hasPrettier()&&d.push({label:"Remove Prettier (dependencies, config files, VS Code settings)",value:"prettier"}),n===void 0&&await te.hasEsLint()&&d.push({label:"Remove ESLint (dependencies, config files, VS Code settings)",value:"eslint"}),d.length>0){let u=await M({message:"Remove existing formatters/linters (recommended for clean migration)?",options:d,required:!1});O(u)&&(I("Operation cancelled."),C.exit(0)),o===void 0&&(o=u.includes("prettier")),n===void 0&&(n=u.includes("eslint"))}}let i=t.frameworks;if(i===void 0)if(t.pm||t.editors||t.agents||t.integrations!==void 0||t.migrate!==void 0)i=[];else{let u=await M({message:"Which frameworks are you using (optional)?",options:[{label:"React",value:"react"},{label:"Next.js",value:"next"},{label:"Solid",value:"solid"},{label:"Vue",value:"vue"},{label:"Svelte",value:"svelte"},{label:"Qwik",value:"qwik"},{label:"Angular",value:"angular"},{label:"Remix / TanStack Router / React Router",value:"remix"},{label:"Astro",value:"astro"}],required:!1});O(u)&&(I("Operation cancelled."),C.exit(0)),i=u}let a=t.editors;if(!a){let d=await M({message:"Which editors do you want to configure (recommended)?",options:[{label:"VSCode / Cursor / Windsurf",value:"vscode"},{label:"Zed",value:"zed"}],required:!1});O(d)&&(I("Operation cancelled."),C.exit(0)),a=d}let r=t.agents,p={"vscode-copilot":"GitHub Copilot (VSCode)",cursor:"Cursor",windsurf:"Windsurf",zed:"Zed",claude:"Claude Code",codex:"OpenAI Codex / Jules / OpenCode",kiro:"Kiro IDE",cline:"Cline",amp:"AMP",aider:"Aider","firebase-studio":"Firebase Studio","open-hands":"Open Hands","gemini-cli":"Gemini CLI",junie:"Junie",augmentcode:"Augment Code","kilo-code":"Kilo Code",goose:"Codename Goose","roo-code":"Roo Code",warp:"Warp"};if(!r){let d=await M({message:"Which agents do you want to enable (optional)?",options:Object.entries(p).map(([u,nt])=>({value:u,label:nt})),required:!1});O(d)&&(I("Operation cancelled."),C.exit(0)),r=d}let g=t.integrations;if(g===void 0)if(t.pm||t.editors||t.agents||t.migrate!==void 0)g=[];else{let u=await M({message:"Would you like any of the following (optional)?",options:[{label:"Husky pre-commit hook",value:"husky"},{label:"Lefthook pre-commit hook",value:"lefthook"},{label:"Lint-staged",value:"lint-staged"}],required:!1});O(u)&&(I("Operation cancelled."),C.exit(0)),g=u}o&&await Ds(s),n&&await Ts(s),await Rs(s,!t.skipInstall),await As(),await Es(i),a?.includes("vscode")&&await Us(),a?.includes("zed")&&await Fs();for(let d of r??[])await Ms(d,p[d],i);g?.includes("husky")&&await $s(s,!t.skipInstall),g?.includes("lefthook")&&await Is(s,!t.skipInstall),g?.includes("lint-staged")&&await Os(s,!t.skipInstall),Y.success("Successfully initialized Ultracite configuration!")}catch(t){let s=t instanceof Error?t.message:"Unknown error";Y.error(`Failed to initialize Ultracite configuration: ${s}`),C.exit(1)}};var j=_s.meta().create(),Ls=j.router({init:j.procedure.meta({description:"Initialize Ultracite in the current directory"}).input(l.object({pm:l.enum(b.packageManagers).optional().describe("Package manager to use"),editors:l.array(l.enum(b.editorConfigs)).optional().describe("Editors to configure"),agents:l.array(l.enum(b.agents)).optional().describe("Agents to enable"),frameworks:l.array(l.enum(b.frameworks)).optional().describe("Frameworks being used"),integrations:l.array(l.enum(b.integrations)).optional().describe("Additional integrations to enable"),migrate:l.array(l.enum(b.migrations)).optional().describe("Migration tools to remove (e.g., eslint, prettier). Removes dependencies, config files, and editor settings."),skipInstall:l.boolean().default(!1).describe("Skip installing dependencies")})).mutation(async({input:e})=>{await st(e)}),check:j.procedure.meta({description:"Run Biome linter without fixing files"}).input(l.array(l.string()).optional().default([]).describe("specific files to lint")).query(({input:e})=>{ee(e)}),fix:j.procedure.meta({description:"Run Biome linter and fixes files"}).input(l.tuple([l.array(l.string()).optional().default([]).describe("specific files to format"),l.object({unsafe:l.boolean().optional().describe("apply unsafe fixes")})])).mutation(({input:e})=>{let[t,s]=e;ne(t,{unsafe:s.unsafe})}),doctor:j.procedure.meta({description:"Verify your Ultracite setup and check for issues"}).query(async()=>{await je()}),lint:j.procedure.meta({description:"\u26A0\uFE0F DEPRECATED: Use 'check' instead - Run Biome linter without fixing files"}).input(l.array(l.string()).optional().default([]).describe("specific files to lint")).query(({input:e})=>{console.warn("\u26A0\uFE0F Warning: 'lint' command is deprecated. Please use 'check' instead."),ee(e)}),format:j.procedure.meta({description:"\u26A0\uFE0F DEPRECATED: Use 'fix' instead - Run Biome linter and fixes files"}).input(l.tuple([l.array(l.string()).optional().default([]).describe("specific files to format"),l.object({unsafe:l.boolean().optional().describe("apply unsafe fixes")})])).mutation(({input:e})=>{let[t,s]=e;console.warn("\u26A0\uFE0F Warning: 'format' command is deprecated. Please use 'fix' instead."),ne(t,{unsafe:s.unsafe})})}),zs=Js({router:Ls,name:w.name,version:w.version,description:w.description});process.env.VITEST||zs.run();export{Ls as router};
|
|
135
|
+
## Quick Reference
|
|
136
|
+
|
|
137
|
+
- **Format code**: \`npx ultracite fix\`
|
|
138
|
+
- **Check for issues**: \`npx ultracite check\`
|
|
139
|
+
- **Diagnose setup**: \`npx ultracite doctor\`
|
|
140
|
+
|
|
141
|
+
Biome (the underlying engine) provides extremely fast Rust-based linting and formatting. Most issues are automatically fixable.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Core Principles
|
|
146
|
+
|
|
147
|
+
Write code that is **accessible, performant, type-safe, and maintainable**. Focus on clarity and explicit intent over brevity.
|
|
148
|
+
|
|
149
|
+
### Type Safety & Explicitness
|
|
150
|
+
|
|
151
|
+
- Use explicit types for function parameters and return values when they enhance clarity
|
|
152
|
+
- Prefer \`unknown\` over \`any\` when the type is genuinely unknown
|
|
153
|
+
- Use const assertions (\`as const\`) for immutable values and literal types
|
|
154
|
+
- Leverage TypeScript's type narrowing instead of type assertions
|
|
155
|
+
- Use meaningful variable names instead of magic numbers - extract constants with descriptive names
|
|
156
|
+
|
|
157
|
+
### Modern JavaScript/TypeScript
|
|
158
|
+
|
|
159
|
+
- Use arrow functions for callbacks and short functions
|
|
160
|
+
- Prefer \`for...of\` loops over \`.forEach()\` and indexed \`for\` loops
|
|
161
|
+
- Use optional chaining (\`?.\`) and nullish coalescing (\`??\`) for safer property access
|
|
162
|
+
- Prefer template literals over string concatenation
|
|
163
|
+
- Use destructuring for object and array assignments
|
|
164
|
+
- Use \`const\` by default, \`let\` only when reassignment is needed, never \`var\`
|
|
165
|
+
|
|
166
|
+
### Async & Promises
|
|
167
|
+
|
|
168
|
+
- Always \`await\` promises in async functions - don't forget to use the return value
|
|
169
|
+
- Use \`async/await\` syntax instead of promise chains for better readability
|
|
170
|
+
- Handle errors appropriately in async code with try-catch blocks
|
|
171
|
+
- Don't use async functions as Promise executors
|
|
172
|
+
|
|
173
|
+
### React & JSX
|
|
174
|
+
|
|
175
|
+
- Use function components over class components
|
|
176
|
+
- Call hooks at the top level only, never conditionally
|
|
177
|
+
- Specify all dependencies in hook dependency arrays correctly
|
|
178
|
+
- Use the \`key\` prop for elements in iterables (prefer unique IDs over array indices)
|
|
179
|
+
- Nest children between opening and closing tags instead of passing as props
|
|
180
|
+
- Don't define components inside other components
|
|
181
|
+
- Use semantic HTML and ARIA attributes for accessibility:
|
|
182
|
+
- Provide meaningful alt text for images
|
|
183
|
+
- Use proper heading hierarchy
|
|
184
|
+
- Add labels for form inputs
|
|
185
|
+
- Include keyboard event handlers alongside mouse events
|
|
186
|
+
- Use semantic elements (\`<button>\`, \`<nav>\`, etc.) instead of divs with roles
|
|
187
|
+
|
|
188
|
+
### Error Handling & Debugging
|
|
189
|
+
|
|
190
|
+
- Remove \`console.log\`, \`debugger\`, and \`alert\` statements from production code
|
|
191
|
+
- Throw \`Error\` objects with descriptive messages, not strings or other values
|
|
192
|
+
- Use \`try-catch\` blocks meaningfully - don't catch errors just to rethrow them
|
|
193
|
+
- Prefer early returns over nested conditionals for error cases
|
|
194
|
+
|
|
195
|
+
### Code Organization
|
|
196
|
+
|
|
197
|
+
- Keep functions focused and under reasonable cognitive complexity limits
|
|
198
|
+
- Extract complex conditions into well-named boolean variables
|
|
199
|
+
- Use early returns to reduce nesting
|
|
200
|
+
- Prefer simple conditionals over nested ternary operators
|
|
201
|
+
- Group related code together and separate concerns
|
|
202
|
+
|
|
203
|
+
### Security
|
|
204
|
+
|
|
205
|
+
- Add \`rel="noopener"\` when using \`target="_blank"\` on links
|
|
206
|
+
- Avoid \`dangerouslySetInnerHTML\` unless absolutely necessary
|
|
207
|
+
- Don't use \`eval()\` or assign directly to \`document.cookie\`
|
|
208
|
+
- Validate and sanitize user input
|
|
209
|
+
|
|
210
|
+
### Performance
|
|
211
|
+
|
|
212
|
+
- Avoid spread syntax in accumulators within loops
|
|
213
|
+
- Use top-level regex literals instead of creating them in loops
|
|
214
|
+
- Prefer specific imports over namespace imports
|
|
215
|
+
- Avoid barrel files (index files that re-export everything)
|
|
216
|
+
- Use proper image components (e.g., Next.js \`<Image>\`) over \`<img>\` tags
|
|
217
|
+
|
|
218
|
+
### Framework-Specific Guidance
|
|
219
|
+
|
|
220
|
+
**Next.js:**
|
|
221
|
+
- Use Next.js \`<Image>\` component for images
|
|
222
|
+
- Use \`next/head\` or App Router metadata API for head elements
|
|
223
|
+
- Use Server Components for async data fetching instead of async Client Components
|
|
224
|
+
|
|
225
|
+
**React 19+:**
|
|
226
|
+
- Use ref as a prop instead of \`React.forwardRef\`
|
|
227
|
+
|
|
228
|
+
**Solid/Svelte/Vue/Qwik:**
|
|
229
|
+
- Use \`class\` and \`for\` attributes (not \`className\` or \`htmlFor\`)
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Testing
|
|
234
|
+
|
|
235
|
+
- Write assertions inside \`it()\` or \`test()\` blocks
|
|
236
|
+
- Avoid done callbacks in async tests - use async/await instead
|
|
237
|
+
- Don't use \`.only\` or \`.skip\` in committed code
|
|
238
|
+
- Keep test suites reasonably flat - avoid excessive \`describe\` nesting
|
|
239
|
+
|
|
240
|
+
## When Biome Can't Help
|
|
241
|
+
|
|
242
|
+
Biome's linter will catch most issues automatically. Focus your attention on:
|
|
243
|
+
|
|
244
|
+
1. **Business logic correctness** - Biome can't validate your algorithms
|
|
245
|
+
2. **Meaningful naming** - Use descriptive names for functions, variables, and types
|
|
246
|
+
3. **Architecture decisions** - Component structure, data flow, and API design
|
|
247
|
+
4. **Edge cases** - Handle boundary conditions and error states
|
|
248
|
+
5. **User experience** - Accessibility, performance, and usability considerations
|
|
249
|
+
6. **Documentation** - Add comments for complex logic, but prefer self-documenting code
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
Most formatting and common issues are automatically fixed by Biome. Run \`npx ultracite fix\` before committing to ensure compliance.
|
|
254
|
+
`;var Ee=e=>{let t=Re[e],n=t.header?`${t.header}
|
|
255
|
+
|
|
256
|
+
${N}`:N,i=async()=>{let s=At(t.path);if(s!=="."){let o=s.startsWith("./")?s.slice(2):s;await Rt(o,{recursive:!0})}};return{exists:()=>l(t.path),create:async()=>{await i(),await S(t.path,n),e==="cursor"&&await S("./.cursor/hooks.json",JSON.stringify({version:1,hooks:{afterFileEdit:[{command:"npx ultracite fix"}]}},null,2))},update:async()=>{if(await i(),t.appendMode){if(!await l(t.path)){await S(t.path,n);return}let s=await Ae(t.path,"utf-8");if(s.includes(N.trim()))return;await S(t.path,`${s}
|
|
257
|
+
|
|
258
|
+
${N}`)}else await S(t.path,n);if(e==="cursor"){let s=await Ae("./.cursor/hooks.json","utf-8"),o=JSON.parse(s);o.hooks.afterFileEdit.some(c=>c.command.includes("ultracite"))||(o.hooks.afterFileEdit.push({command:"npx ultracite fix"}),await S("./.cursor/hooks.json",JSON.stringify(o,null,2)))}}}};u();import{readFile as Et,writeFile as Fe}from"fs/promises";import Ft from"deepmerge";import{parse as $t}from"jsonc-parser";var $e={$schema:"./node_modules/@biomejs/biome/configuration_schema.json",extends:["ultracite/core"]},se=async()=>await l("./biome.json")?"./biome.json":"./biome.jsonc",z={exists:async()=>{let e=await se();return l(e)},create:async e=>{let t=await se(),n=["ultracite/core"];if(e?.frameworks&&e.frameworks.length>0)for(let s of e.frameworks)n.push(`ultracite/${s}`);let i={...$e,extends:n};return Fe(t,JSON.stringify(i,null,2))},update:async e=>{let t=await se(),n=await Et(t,"utf-8"),s=$t(n)||{},r=[...s.extends&&Array.isArray(s.extends)?s.extends:[]];if(r.includes("ultracite/core")||r.push("ultracite/core"),e?.frameworks&&e.frameworks.length>0)for(let g of e.frameworks){let d=`ultracite/${g}`;r.includes(d)||r.push(d)}s.extends=r;let c={$schema:$e.$schema},f=Ft(s,c);await Fe(t,JSON.stringify(f,null,2))}};u();import{spawnSync as Nt}from"child_process";import{mkdir as Dt,readFile as Ot,writeFile as Ne}from"fs/promises";import Tt from"deepmerge";import{parse as Mt}from"jsonc-parser";var ie={"editor.defaultFormatter":"esbenp.prettier-vscode","[javascript]":{"editor.defaultFormatter":"biomejs.biome"},"[typescript]":{"editor.defaultFormatter":"biomejs.biome"},"[javascriptreact]":{"editor.defaultFormatter":"biomejs.biome"},"[typescriptreact]":{"editor.defaultFormatter":"biomejs.biome"},"[json]":{"editor.defaultFormatter":"biomejs.biome"},"[jsonc]":{"editor.defaultFormatter":"biomejs.biome"},"[css]":{"editor.defaultFormatter":"biomejs.biome"},"[graphql]":{"editor.defaultFormatter":"biomejs.biome"},"typescript.tsdk":"node_modules/typescript/lib","editor.formatOnSave":!0,"editor.formatOnPaste":!0,"emmet.showExpandedAbbreviation":"never","editor.codeActionsOnSave":{"source.fixAll.biome":"explicit","source.organizeImports.biome":"explicit"}};var B="./.vscode/settings.json",D={exists:()=>l(B),create:async()=>{await Dt(".vscode",{recursive:!0}),await Ne(B,JSON.stringify(ie,null,2))},update:async()=>{let e=await Ot(B,"utf-8"),n=Mt(e)||{},i=Tt(n,ie);await Ne(B,JSON.stringify(i,null,2))},extension:()=>Nt("code --install-extension biomejs.biome",{stdio:"inherit",shell:!0})};u();import{mkdir as It,readFile as _t,writeFile as De}from"fs/promises";import Ut from"deepmerge";import{parse as Jt}from"jsonc-parser";var oe={formatter:"language_server",format_on_save:"on",languages:{JavaScript:{formatter:{language_server:{name:"biome"}},code_actions_on_format:{"source.fixAll.biome":!0,"source.organizeImports.biome":!0}},TypeScript:{formatter:{language_server:{name:"biome"}},code_actions_on_format:{"source.fixAll.biome":!0,"source.organizeImports.biome":!0}},JSX:{formatter:{language_server:{name:"biome"}},code_actions_on_format:{"source.fixAll.biome":!0,"source.organizeImports.biome":!0}},TSX:{formatter:{language_server:{name:"biome"}},code_actions_on_format:{"source.fixAll.biome":!0,"source.organizeImports.biome":!0}}},lsp:{"typescript-language-server":{settings:{typescript:{preferences:{includePackageJsonAutoImports:"on"}}}}}};var W="./.zed/settings.json",H={exists:()=>l(W),create:async()=>{await It(".zed",{recursive:!0}),await De(W,JSON.stringify(oe,null,2))},update:async()=>{let e=await _t(W,"utf-8"),n=Jt(e)||{},i=Ut(n,oe);await De(W,JSON.stringify(i,null,2))}};ae();ce();de();import{readFile as fn,writeFile as pn}from"fs/promises";import un from"deepmerge";import{glob as mn}from"glob";import{parse as gn}from"jsonc-parser";var hn={compilerOptions:{strictNullChecks:!0}},Be=async()=>{try{return await mn("**/tsconfig*.json",{ignore:["**/node_modules/**","**/dist/**","**/build/**","**/.next/**"],absolute:!1})}catch{return[]}},yn=async e=>{try{let t=await fn(e,"utf-8"),i=gn(t)||{},s=un(i,hn);await pn(e,JSON.stringify(s,null,2))}catch(t){console.warn(`Failed to update ${e}:`,t)}},ue={exists:async()=>(await Be()).length>0,update:async()=>{let e=await Be();if(e.length===0){console.warn("No tsconfig.json files found in the project");return}await Promise.all(e.map(t=>yn(t)))}};u();var We=w.devDependencies["@biomejs/biome"],He=w.version,xn=async(e,t=!0)=>{let n=m();n.start("Installing dependencies...");let i=[`ultracite@${He}`,`@biomejs/biome@${We}`];if(t)for(let s of i)await kn(s,{packageManager:e,workspace:await h()});else await k({devDependencies:{"@biomejs/biome":We,ultracite:He}});n.stop("Dependencies installed.")},vn=async()=>{let e=m();if(e.start("Checking for tsconfig.json files..."),await ue.exists()){e.message("Found tsconfig.json files, updating with strictNullChecks..."),await ue.update(),e.stop("tsconfig.json files updated.");return}e.stop("No tsconfig.json files found, skipping.")},Cn=async()=>{let e=m();if(e.start("Checking for .vscode/settings.json..."),await D.exists()){e.message("settings.json found, updating..."),await D.update(),e.stop("settings.json updated.");return}e.message("settings.json not found, creating..."),await D.create(),e.message("settings.json created."),e.message("Installing Biome extension...");try{D.extension(),e.stop("settings.json created.")}catch(t){e.stop(`Failed to install Biome extension (${t}), but continuing...`)}},jn=async()=>{let e=m();if(e.start("Checking for .zed/settings.json..."),await H.exists()){e.message("settings.json found, updating..."),await H.update(),e.stop("settings.json updated.");return}e.message("settings.json not found, creating..."),await H.create(),e.message("settings.json created. Install the Biome extension: https://biomejs.dev/reference/zed/")},Pn=async e=>{let t=m();if(t.start("Checking for Biome configuration..."),await z.exists()){t.message("Biome configuration found, updating..."),await z.update({frameworks:e}),t.stop("Biome configuration updated.");return}t.message("Biome configuration not found, creating..."),await z.create({frameworks:e}),t.stop("Biome configuration created.")},Sn=async(e,t=!0)=>{let n=m();if(n.start("Initializing pre-commit hooks..."),n.message("Installing Husky..."),t?await x.install(e):await k({devDependencies:{husky:"latest"},scripts:{prepare:"husky"}}),n.message("Initializing Husky..."),x.init(e),await x.exists()){n.message("Pre-commit hook found, updating..."),await x.update(e),n.stop("Pre-commit hook updated.");return}n.message("Pre-commit hook not found, creating..."),await x.create(e),n.stop("Pre-commit hook created.")},Rn=async(e,t=!0)=>{let n=m();if(n.start("Initializing lefthook..."),n.message("Installing lefthook..."),t?await R.install(e):await k({devDependencies:{lefthook:"latest"}}),await R.exists()){n.message("lefthook.yml found, updating..."),await R.update(e),n.stop("lefthook.yml updated.");return}n.message("lefthook.yml not found, creating..."),await R.create(e),n.stop("lefthook.yml created.")},An=async(e,t=!0)=>{let n=m();if(n.start("Initializing lint-staged..."),n.message("Installing lint-staged..."),t?await A.install(e):await k({devDependencies:{"lint-staged":"latest"}}),await A.exists()){n.message("lint-staged found, updating..."),await A.update(e),n.stop("lint-staged updated.");return}n.message("lint-staged not found, creating..."),await A.create(e),n.stop("lint-staged created.")},En=async(e,t)=>{let n=m();n.start(`Checking for ${t}...`);let i=Ee(e);if(await i.exists()){n.message(`${t} found, updating...`),await i.update(),n.stop(`${t} updated.`);return}n.message(`${t} not found, creating...`),await i.create(),n.stop(`${t} created.`)},Fn=async e=>{let t=m();t.start("Removing Prettier dependencies and configuration...");try{let n=await te.remove(e);n.packagesRemoved.length>0&&t.message(`Removed Prettier packages: ${n.packagesRemoved.join(", ")}`),n.filesRemoved.length>0&&t.message(`Removed config files: ${n.filesRemoved.join(", ")}`),n.vsCodeCleaned&&t.message("Cleaned VS Code settings"),t.stop("Prettier removed successfully.")}catch{t.stop("Failed to remove Prettier completely, but continuing...")}},$n=async e=>{let t=m();t.start("Removing ESLint dependencies and configuration...");try{let n=await ee.remove(e);n.packagesRemoved.length>0&&t.message(`Removed ESLint packages: ${n.packagesRemoved.join(", ")}`),n.filesRemoved.length>0&&t.message(`Removed config files: ${n.filesRemoved.join(", ")}`),n.vsCodeCleaned&&t.message("Cleaned VS Code settings"),t.stop("ESLint removed successfully.")}catch{t.stop("Failed to remove ESLint completely, but continuing...")}},Ge=async e=>{wn(he);try{let t=e??{},{pm:n}=t;if(!n){let d=await bn(j.cwd());if(!d)throw new Error("No package manager specified or detected");if(d.warnings)for(let p of d.warnings)V.warn(p);V.info(`Detected lockfile, using ${d.name}`),n=d.name}let i=t.migrate?.includes("prettier"),s=t.migrate?.includes("eslint");if(i===void 0||s===void 0){let d=[];if(i===void 0&&await te.hasPrettier()&&d.push({label:"Remove Prettier (dependencies, config files, VS Code settings)",value:"prettier"}),s===void 0&&await ee.hasEsLint()&&d.push({label:"Remove ESLint (dependencies, config files, VS Code settings)",value:"eslint"}),d.length>0){let p=await _({message:"Remove existing formatters/linters (recommended for clean migration)?",options:d,required:!1});I(p)&&(M("Operation cancelled."),j.exit(0)),i===void 0&&(i=p.includes("prettier")),s===void 0&&(s=p.includes("eslint"))}}let o=t.frameworks;if(o===void 0)if(t.pm||t.editors||t.agents||t.integrations!==void 0||t.migrate!==void 0)o=[];else{let p=await _({message:"Which frameworks are you using (optional)?",options:[{label:"React",value:"react"},{label:"Next.js",value:"next"},{label:"Solid",value:"solid"},{label:"Vue",value:"vue"},{label:"Svelte",value:"svelte"},{label:"Qwik",value:"qwik"},{label:"Angular",value:"angular"},{label:"Remix / TanStack Router / React Router",value:"remix"},{label:"Astro",value:"astro"}],required:!1});I(p)&&(M("Operation cancelled."),j.exit(0)),o=p}let r=t.editors;if(!r){let d=await _({message:"Which editors do you want to configure (recommended)?",options:[{label:"VSCode / Cursor / Windsurf",value:"vscode"},{label:"Zed",value:"zed"}],required:!1});I(d)&&(M("Operation cancelled."),j.exit(0)),r=d}let c=t.agents,f={"vscode-copilot":"GitHub Copilot (VSCode)",cursor:"Cursor",windsurf:"Windsurf",zed:"Zed",claude:"Claude Code",codex:"OpenAI Codex / Jules / OpenCode",kiro:"Kiro IDE",cline:"Cline",amp:"AMP",aider:"Aider","firebase-studio":"Firebase Studio","open-hands":"Open Hands","gemini-cli":"Gemini CLI",junie:"Junie",augmentcode:"Augment Code","kilo-code":"Kilo Code",goose:"Codename Goose","roo-code":"Roo Code",warp:"Warp"};if(!c){let d=await _({message:"Which agents do you want to enable (optional)?",options:Object.entries(f).map(([p,qe])=>({value:p,label:qe})),required:!1});I(d)&&(M("Operation cancelled."),j.exit(0)),c=d}let g=t.integrations;if(g===void 0)if(t.pm||t.editors||t.agents||t.migrate!==void 0)g=[];else{let p=await _({message:"Would you like any of the following (optional)?",options:[{label:"Husky pre-commit hook",value:"husky"},{label:"Lefthook pre-commit hook",value:"lefthook"},{label:"Lint-staged",value:"lint-staged"}],required:!1});I(p)&&(M("Operation cancelled."),j.exit(0)),g=p}i&&await Fn(n),s&&await $n(n),await xn(n,!t.skipInstall),await vn(),await Pn(o),r?.includes("vscode")&&await Cn(),r?.includes("zed")&&await jn();for(let d of c??[])await En(d,f[d]);g?.includes("husky")&&await Sn(n,!t.skipInstall),g?.includes("lefthook")&&await Rn(n,!t.skipInstall),g?.includes("lint-staged")&&await An(n,!t.skipInstall),V.success("Successfully initialized Ultracite configuration!")}catch(t){let n=t instanceof Error?t.message:"Unknown error";V.error(`Failed to initialize Ultracite configuration: ${n}`),j.exit(1)}};var P=Nn.meta().create(),On=P.router({init:P.procedure.meta({description:"Initialize Ultracite in the current directory"}).input(a.object({pm:a.enum(b.packageManagers).optional().describe("Package manager to use"),editors:a.array(a.enum(b.editorConfigs)).optional().describe("Editors to configure"),agents:a.array(a.enum(b.agents)).optional().describe("Agents to enable"),frameworks:a.array(a.enum(b.frameworks)).optional().describe("Frameworks being used"),integrations:a.array(a.enum(b.integrations)).optional().describe("Additional integrations to enable"),migrate:a.array(a.enum(b.migrations)).optional().describe("Migration tools to remove (e.g., eslint, prettier). Removes dependencies, config files, and editor settings."),skipInstall:a.boolean().default(!1).describe("Skip installing dependencies")})).mutation(async({input:e})=>{await Ge(e)}),check:P.procedure.meta({description:"Run Biome linter without fixing files"}).input(a.tuple([a.array(a.string()).optional().default([]).describe("specific files to lint"),a.object({"diagnostic-level":a.enum(["info","warn","error"]).optional().describe("level of diagnostics to show. In order, from the lowest to the most important: info, warn, error.")})]).optional()).query(({input:e})=>{Z(e)}),fix:P.procedure.meta({description:"Run Biome linter and fixes files"}).input(a.tuple([a.array(a.string()).optional().default([]).describe("specific files to format"),a.object({unsafe:a.boolean().optional().describe("apply unsafe fixes")})])).mutation(({input:e})=>{let[t,n]=e;ne(t,{unsafe:n.unsafe})}),doctor:P.procedure.meta({description:"Verify your Ultracite setup and check for issues"}).query(async()=>{await Pe()}),lint:P.procedure.meta({description:"\u26A0\uFE0F DEPRECATED: Use 'check' instead - Run Biome linter without fixing files"}).input(a.array(a.string()).optional().default([]).describe("specific files to lint")).query(({input:e})=>{console.warn("\u26A0\uFE0F Warning: 'lint' command is deprecated. Please use 'check' instead."),Z([e,{}])}),format:P.procedure.meta({description:"\u26A0\uFE0F DEPRECATED: Use 'fix' instead - Run Biome linter and fixes files"}).input(a.tuple([a.array(a.string()).optional().default([]).describe("specific files to format"),a.object({unsafe:a.boolean().optional().describe("apply unsafe fixes")})])).mutation(({input:e})=>{let[t,n]=e;console.warn("\u26A0\uFE0F Warning: 'format' command is deprecated. Please use 'fix' instead."),ne(t,{unsafe:n.unsafe})})}),Tn=Dn({router:On,name:w.name,version:w.version,description:w.description});process.env.VITEST||Tn.run();export{On as router};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultracite",
|
|
3
3
|
"description": "The AI-ready formatter that helps you write and generate code faster.",
|
|
4
|
-
"version": "6.
|
|
4
|
+
"version": "6.2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"ultracite": "dist/index.js"
|
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
"dist",
|
|
12
12
|
"README.md"
|
|
13
13
|
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsup",
|
|
16
|
+
"test": "bun test",
|
|
17
|
+
"test:coverage": "bun test --coverage"
|
|
18
|
+
},
|
|
14
19
|
"exports": {
|
|
15
20
|
"./*": "./config/*/biome.jsonc"
|
|
16
21
|
},
|
|
@@ -37,24 +42,19 @@
|
|
|
37
42
|
},
|
|
38
43
|
"devDependencies": {
|
|
39
44
|
"@biomejs/biome": "2.3.2",
|
|
40
|
-
"@types/node": "^24.
|
|
41
|
-
"@vitest/coverage-v8": "4.0.3",
|
|
45
|
+
"@types/node": "^24.10.0",
|
|
42
46
|
"tsup": "^8.5.0",
|
|
43
|
-
"turbo": "^2.
|
|
44
|
-
"vitest": "^4.0.3"
|
|
47
|
+
"turbo": "^2.6.0"
|
|
45
48
|
},
|
|
46
49
|
"dependencies": {
|
|
47
50
|
"@clack/prompts": "^0.11.0",
|
|
48
|
-
"@trpc/server": "^11.
|
|
51
|
+
"@trpc/server": "^11.7.1",
|
|
49
52
|
"deepmerge": "^4.3.1",
|
|
53
|
+
"glob": "^11.0.3",
|
|
50
54
|
"jsonc-parser": "^3.3.1",
|
|
51
55
|
"nypm": "^0.6.2",
|
|
52
56
|
"trpc-cli": "^0.12.0",
|
|
53
57
|
"zod": "^4.1.12"
|
|
54
58
|
},
|
|
55
|
-
"
|
|
56
|
-
|
|
57
|
-
"test": "vitest run",
|
|
58
|
-
"test:coverage": "vitest run --coverage"
|
|
59
|
-
}
|
|
60
|
-
}
|
|
59
|
+
"packageManager": "bun@1.3.1"
|
|
60
|
+
}
|