@saashub/qoq-cli
Version:
CLI that handles formatting, linting and testing Your JS/TS code
3 lines (2 loc) • 28.9 kB
JavaScript
;var e,t,s,i,r=require("fs/promises"),n=require("cac"),o=require("@saashub/qoq-utils"),a=require("fs"),c=require("url"),l=require("picocolors"),g=require("prompts"),p=require("micromatch"),u=require("child_process"),h=require("path"),f=require("react-fast-compare"),m=require("@antfu/install-pkg");function d(){if(t)return e;t=1;const s=Symbol.for("indent"),i=Symbol.for("newline"),r=/^\uFEFF/,n=/^\s*[{[]((?:\r?\n)+)([\s\t]*)/,o=/^(?:\{\}|\[\])((?:\r?\n)+)?$/,a=/^Unexpected token '?(.)'?(,)? /i,c=e=>String(e).replace(r,""),l=(e,t,s=0)=>({message:`${e} while parsing ${t}`,position:s});class g extends SyntaxError{constructor(e,t,s,i){const r=((e,t,s=20)=>{let i=e.message;if(!t)return l(i,"empty string");const r=i.match(a),n=i.match(/ position\s+(\d+)/i);let o;if(r&&(i=i.replace(a,`Unexpected token ${JSON.stringify(r[1])} (${(e=>{const t=e.charCodeAt(0).toString(16).toUpperCase();return`0x${t.length%2?"0":""}${t}`})(r[1])})$2 `)),n?o=+n[1]:i.match(/^Unexpected end of JSON.*/i)&&(o=t.length-1),null==o)return l(i,`'${t.slice(0,2*s)}'`);const c=o<=s?0:o-s,g=o+s>=t.length?t.length:o+s,p=`${c?"...":""}${t.slice(c,g)}${g===t.length?"":"..."}`;return l(i,`${t===p?"":"near "}${JSON.stringify(p)}`,o)})(e,t,s);super(r.message),Object.assign(this,r),this.code="EJSONPARSE",this.systemError=e,Error.captureStackTrace(this,i||this.constructor)}get name(){return this.constructor.name}set name(e){}get[Symbol.toStringTag](){return this.constructor.name}}const p=(e,t)=>{const r=JSON.parse(e,t);if(r&&"object"==typeof r){const t=e.match(o)||e.match(n)||[null,"",""];r[i]=t[1]??"\n",r[s]=t[2]??" "}return r},u=(e,t,s)=>{const i=c(e);try{return p(i,t)}catch(t){if("string"!=typeof e&&!Buffer.isBuffer(e)){const s=Array.isArray(e)&&0===e.length?"an empty array":String(e);throw Object.assign(new TypeError(`Cannot parse ${s}`),{code:"EJSONPARSE",systemError:t})}throw new g(t,i,s,u)}};return e=u,u.JSONParseError=g,u.noExceptions=(e,t)=>{try{return p(c(e),t)}catch{}},e}var E=function(){if(i)return s;i=1;const{readFile:e}=r,t=d();async function n(t){try{return await e(t,"utf8")}catch(e){throw e.message=`Could not read package.json: ${e}`,e}}function o(e){try{return t(e)}catch(e){throw e.message=`Invalid package.json: ${e}`,e}}return s={read:n,parse:o,readPackage:async function(e){return o(await n(e))}}}();const S=o.resolveCwdPath("/package.json"),y=o.resolveCwdPath("/qoq.config.js"),T=o.resolveCwdPath("/.gitignore"),C="./src";class _{modulesConfig;config;packages=[];nextHandler;constructor(e,t){this.modulesConfig=e,this.config=t}async getPrompts(){return this.nextHandler?this.nextHandler.getPrompts():Promise.resolve()}getConfigFromModules(){return this.nextHandler?this.nextHandler.getConfigFromModules():this.config}getModulesFromConfig(){return this.nextHandler?this.nextHandler.getModulesFromConfig():this.modulesConfig}setNext(e){return this.nextHandler=e,e}getPackages(){return this.nextHandler?[...this.packages,...this.nextHandler.getPackages()]:this.packages}}var w=(e=>(e[e.OK=0]="OK",e[e.ERROR=1]="ERROR",e[e.EXCEPTION=2]="EXCEPTION",e))(w||{}),I=(e=>(e.CJS="CJS",e.ESM="ESM",e))(I||{});class P extends _{static CONFIG_FILE_PATH=o.resolveCwdRelativePath("/qoq.config.js");async getPrompts(){const{srcPath:e,configType:t}=await g.prompt([{type:"text",name:"srcPath",message:"What's your project source path (from project root dir)?",initial:C},{type:"select",name:"configType",message:"In what format should we create config file?",choices:[{title:I.CJS,value:I.CJS},{title:I.ESM,value:I.ESM}]}]);return this.modulesConfig.srcPath=e,this.modulesConfig.configType=t,super.getPrompts()}getConfigFromModules(){const{srcPath:e}=this.modulesConfig;return e!==C&&(this.config.srcPath=e),super.getConfigFromModules()}getModulesFromConfig(){this.modulesConfig.srcPath=this.config.srcPath??C;try{const e=a.readFileSync(P.CONFIG_FILE_PATH,"utf-8");this.modulesConfig.configType=e.includes("module.exports-")||e.includes("module.exports ")?I.CJS:I.ESM}catch{this.modulesConfig.configType=I.ESM}return super.getModulesFromConfig()}getPackages(){return this.packages=["@saashub/qoq-cli"],super.getPackages()}}var N=(e=>(e.ESLINT_V9_JS="@saashub/qoq-eslint-v9-js",e.ESLINT_V9_JS_JEST="@saashub/qoq-eslint-v9-js-jest",e.ESLINT_V9_JS_JEST_RTL="@saashub/qoq-eslint-v9-js-jest-rtl",e.ESLINT_V9_JS_REACT="@saashub/qoq-eslint-v9-js-react",e.ESLINT_V9_JS_VITEST="@saashub/qoq-eslint-v9-js-vitest",e.ESLINT_V9_JS_VITEST_RTL="@saashub/qoq-eslint-v9-js-vitest-rtl",e.ESLINT_V9_TS="@saashub/qoq-eslint-v9-ts",e.ESLINT_V9_TS_JEST="@saashub/qoq-eslint-v9-ts-jest",e.ESLINT_V9_TS_JEST_RTL="@saashub/qoq-eslint-v9-ts-jest-rtl",e.ESLINT_V9_TS_REACT="@saashub/qoq-eslint-v9-ts-react",e.ESLINT_V9_TS_VITEST="@saashub/qoq-eslint-v9-ts-vitest",e.ESLINT_V9_TS_VITEST_RTL="@saashub/qoq-eslint-v9-ts-vitest-rtl",e))(N||{});const k=e=>e[0].toUpperCase()+e.slice(1),F=e=>e.startsWith("./")?e.replace("./",""):e,j=(e,t,s,i)=>e===I.CJS?((e,t,s)=>{const i=Object.keys(e).map(t=>`const ${t} = require('${e[t]}')`);return[...i,...t].length>0?`${[...i,...t].join(";")}; module.exports = ${s};`:`module.exports = ${s};`})(t,s,i):((e,t,s)=>{const i=Object.keys(e).map(t=>`import ${t} from '${e[t]}'`);return[...i,...t].length>0?`${[...i,...t].join(";")}; export default ${s};`:`export default ${s};`})(t,s,i);class L extends _{static CONFIG_FILE_PATH=o.resolveCwdRelativePath("/eslint.config.js");async getPrompts(){let e,t,s,i;this.configFileExists()&&process.stdout.write(l.red("\n 'eslint.config.js' already exists in the project root, config will be overwritten by this setup!\n\n"));try{e=!!o.getPackageInfo("typescript")}catch{e=!1}try{t=!!o.getPackageInfo("react")}catch{t=!1}try{s=!!o.getPackageInfo("jest")}catch{s=!1}try{i=!!o.getPackageInfo("vitest")}catch{i=!1}const{eslintPackages:r}=await g.prompt([{type:"toggle",name:"eslint",message:l.reset(`Do You use ${l.green("TypeScript")} in Your project?`),initial:e,active:l.green("yes"),inactive:l.red("no")},{type:e=>e?"multiselect":null,name:"eslintPackages",message:"What options should we use?",choices:[{title:"Basic TypeScript only",value:N.ESLINT_V9_TS,selected:e&&!t},{title:"TypeScript + React",value:N.ESLINT_V9_TS_REACT,selected:e&&t},{title:"TypeScript + Jest",value:N.ESLINT_V9_TS_JEST,selected:e&&s},{title:"TypeScript + Vitest",value:N.ESLINT_V9_TS_VITEST,selected:e&&i}],min:1},{type:e=>e?null:"multiselect",name:"eslintPackages",message:"What options should we use?",choices:[{title:"Basic JavaScript only",value:N.ESLINT_V9_JS,selected:!e&&!t},{title:"JavaScript + React",value:N.ESLINT_V9_JS_REACT,selected:!e&&t},{title:"JavaScript + Jest",value:N.ESLINT_V9_JS_JEST,selected:!e&&s},{title:"JavaScript + Vitest",value:N.ESLINT_V9_JS_VITEST,selected:!e&&i}],min:1}]),{srcPath:n}=this.modulesConfig;if(r.length>0){const e=F(n);this.modulesConfig.modules.eslint=[];for(const t of r){let s,i;switch(process.stderr.write(l.green(`\nProvide configuration for ${t} checks:\n`)),!0){case t===N.ESLINT_V9_JS:s=`${e}/**/*.js`,i="**/*.spec.js";break;case t===N.ESLINT_V9_JS_REACT:s=`${e}/**/*.{js,jsx}`,i="**/*.spec.js";break;case t===N.ESLINT_V9_TS:s=`${e}/**/*.{js,ts}`,i="**/*.spec.{js,ts}";break;case t===N.ESLINT_V9_TS_REACT:s=`${e}/**/*.{js,jsx,ts,tsx}`,i="**/*.spec.{js,ts}";break;case[N.ESLINT_V9_JS_JEST,N.ESLINT_V9_JS_VITEST].includes(t):s=`${e}/**/*.spec.js`,i="";break;case[N.ESLINT_V9_TS_JEST,N.ESLINT_V9_TS_VITEST].includes(t):s=`${e}/**/*.spec.{js,ts}`,i="";break;default:s="",i=""}const{files:r,ignores:n}=await g.prompt([{type:"list",name:"files",message:'Provide files paths (from project root dir), space " " separated',separator:" ",initial:s??!1},{type:"list",name:"ignores",message:'Provide files paths (from project root dir), space " " separated',separator:" ",initial:i??!1}]);this.modulesConfig.modules.eslint.push({template:t,files:r.filter(e=>!!e),ignores:n.filter(e=>!!e)})}}return this.configFileExists()&&a.rmSync(L.CONFIG_FILE_PATH),a.writeFileSync(L.CONFIG_FILE_PATH,j(this.modulesConfig.configType,{config:`@saashub/qoq-cli/bin/eslint.config.${this.modulesConfig.configType===I.ESM?"m":"c"}js`},[],"config")),super.getPrompts()}getConfigFromModules(){const{modules:{eslint:e}}=this.modulesConfig;return this.config.eslint=e,super.getConfigFromModules()}getModulesFromConfig(){return this.modulesConfig.modules.eslint=this.config.eslint,super.getModulesFromConfig()}getPackages(){const e=(this.modulesConfig.modules.eslint??[]).filter(e=>e.template&&e.template!==N.ESLINT_V9_JS).map(e=>String(e.template));return this.packages=e.length>0?e:[N.ESLINT_V9_JS],super.getPackages()}configFileExists(){return a.existsSync(L.CONFIG_FILE_PATH)}}function v(e){return null!=e&&"function"!=typeof e&&function(e){return Number.isSafeInteger(e)&&e>=0}(e.length)}function x(e,t=1){return function(e,t=1){const s=[],i=Math.floor(t);if(!v(e))return s;const r=(e,t)=>{for(let n=0;n<e.length;n++){const o=e[n];t<i&&(Array.isArray(o)||Boolean(o?.[Symbol.isConcatSpreadable])||null!==o&&"object"==typeof o&&"[object Arguments]"===Object.prototype.toString.call(o))?Array.isArray(o)?r(o,t+1):r(Array.from(o),t+1):s.push(o)}};return r(Array.from(e),0),s}(e,t)}const O=async(e,t=[])=>new Promise((s,i)=>{const r=u.spawn(e,t,{shell:!0});r.stdout.on("data",e=>{process.stdout.write(e.toString("utf-8"))}),r.stderr.on("data",e=>{process.stderr.write(e.toString("utf-8"))}),r.on("error",e=>{i(e)}),r.on("close",e=>{s(e??w.OK)})});class b extends Error{}class R{modulesConfig;silent;hideTimer;constructor(e,t=!1,s=!1){this.modulesConfig=e,this.silent=t,this.hideTimer=s}async run(e,t){const s=`${this.getName()} execution time:`;console.time(l.italic(l.gray(s))),this.silent||process.stdout.write(l.green(`\nRunning ${this.getName()}:\n`));const i=[...this.getCommandArgs()];try{return await this.prepare(i,e,t),e.warmup?w.OK:await O(this.getCommandName(),i)}catch(e){return e instanceof b||(process.stderr.write("Unknown error!\n"),process.exit(w.EXCEPTION)),w.OK}finally{this.silent||this.hideTimer||console.timeEnd(l.italic(l.gray(s)))}}async prepare(e,t,s=[]){if(!t.disableCache){const s=this.constructor.CACHE_PATH;if(!s)throw new Error("No cache path for executor defined!");e.push("--cache","--cache-location",s),t.warmup&&a.existsSync(s)&&a.rmSync(s,{recursive:!0,force:!0})}return Promise.resolve(w.OK)}}var A="@saashub/qoq-cli";const $=e=>h.resolve(`${(()=>{try{const{rootPath:e}=o.getPackageInfo(A)??{};return e}catch{return process.cwd()}})()}${e}`),q=e=>o.getRelativePath($(e));class D extends R{static CACHE_PATH=q("/bin/.eslintcache");getName(){return k(this.getCommandName())}getCommandName(){return"eslint"}getCommandArgs(){return["--max-warnings","0"]}async prepare(e,t,s=[]){try{const{configType:i,modules:r}=this.modulesConfig,n=$(`/bin/eslint.config.${i===I.ESM?"m":"c"}js`),o={"{ objectMergeRight }":"@saashub/qoq-utils","{ includeIgnoreFile }":"@eslint/compat"},l=(r?.eslint??[]).reduce((e,t,s)=>{const{template:r,...n}=t;return Object.values(N).includes(r)?(i===I.ESM?o[`{ baseConfig as baseConfig${s} }`]=String(r):o[`{ baseConfig: baseConfig${s} }`]=String(r),e.push(`const config${s} = [objectMergeRight(baseConfig${s}, ${JSON.stringify(n)})]`)):e.push(`const config${s} = [${JSON.stringify(n)}]`),e},[]),g=`${a.existsSync(T)?`[includeIgnoreFile('${T.replaceAll("\\","\\\\")}')]`:"[]"}${(r?.eslint??[]).map((e,t)=>`.concat(config${t})`).join("")}`;if(a.writeFileSync(n,j(i,o,l,g)),e.push("-c",L.CONFIG_FILE_PATH),s.length>0){let t=[...s];try{const e=await import(c.pathToFileURL(n).toString()),i=e=>e.startsWith("**")||e.startsWith("./")?e:`**/${e}`,r=e=>{let t;return t=e?Array.isArray(e)?x(e,1/0):[e]:[],t.map(i)},o=e.default.reduce((e,t)=>e.concat([{files:r(t.files),ignores:r(t.ignores)}]),[]),a=e=>o.some(({files:t,ignores:s})=>p.isMatch(e,t)&&!p.isMatch(e,s));t=s.filter(e=>a(e))}catch{throw new Error}if(0===t.length)throw new b;e.push("--stdin-filename",...t)}return t.fix&&e.push("--fix"),super.prepare(e,t,s)}catch(e){if(e instanceof b)throw e;return process.stderr.write(l.red(`Can't load ${this.getName()} package config!\n`)),process.exit(w.EXCEPTION)}}}const H=e=>(e.eslint??[]).some(e=>e.template===N.ESLINT_V9_TS||e.template===N.ESLINT_V9_TS_JEST||e.template===N.ESLINT_V9_TS_REACT||e.template===N.ESLINT_V9_TS_VITEST),J=e=>(e.eslint??[]).some(e=>e.template===N.ESLINT_V9_JS_REACT||e.template===N.ESLINT_V9_TS_REACT),M=e=>{switch(!0){case H(e)&&J(e):return["js","jsx","ts","tsx"];case H(e):return["ts"];case J(e):return["js","jsx"];default:return["js"]}};class V extends _{static DEFAULT_THRESHOLD=2;static DEFAULT_IGNORE=[];async getPrompts(){const{jscpdThreshold:e,jscpdFormat:t,jscpdIgnore:s}=await g.prompt([{type:"number",name:"jscpdThreshold",message:"What threshold should we use for copy/paste detector?",initial:V.DEFAULT_THRESHOLD},{type:"list",name:"jscpdFormat",message:'Provide files format (initially autodetected from previous config), space " " separated',separator:" ",initial:this.getDefaultFormat().join(" ")},{type:"list",name:"jscpdIgnore",message:'Provide files format (initially autodetected from previous config), space " " separated',separator:" ",initial:this.getDefaultIgnore().join(" ")}]);return this.modulesConfig.modules.jscpd={threshold:e??V.DEFAULT_THRESHOLD,format:t.filter(e=>!!e),ignore:s.filter(e=>!!e)},super.getPrompts()}getConfigFromModules(){const{modules:{jscpd:e}}=this.modulesConfig;return this.config.jscpd={format:e?.format},e?.threshold&&e.threshold!==V.DEFAULT_THRESHOLD&&(this.config.jscpd.threshold=e.threshold),e?.ignore&&!f(e.ignore,V.DEFAULT_IGNORE)&&(this.config.jscpd.ignore=e.ignore),super.getConfigFromModules()}getModulesFromConfig(){return this.modulesConfig.modules.jscpd={format:this.config.jscpd?.format??this.getDefaultFormat(),threshold:this.config.jscpd?.threshold??V.DEFAULT_THRESHOLD,ignore:this.config.jscpd?.ignore??this.getDefaultIgnore()},super.getModulesFromConfig()}getPackages(){return this.packages=["@saashub/qoq-jscpd"],super.getPackages()}getDefaultFormat=()=>M(this.modulesConfig.modules).map(e=>{switch(e){case"js":return"javascript";case"ts":return"typescript";default:return e}});getDefaultIgnore=()=>this.getDefaultFormat().map(e=>`**/*.spec.${e.replace("javascript","js").replace("typescript","ts")}`)}class G extends R{getName(){return this.getCommandName().toUpperCase()}getCommandName(){return"jscpd"}getCommandArgs(){const{srcPath:e,modules:t,workspaces:s}=this.modulesConfig,{format:i,threshold:r}=t.jscpd;return s?[...s.reduce((e,t)=>{if(t.includes("*")){const s=`/${t.replaceAll("*","")}`;return e.concat(a.readdirSync(o.resolveCwdPath(s),{withFileTypes:!0}).filter(e=>e.isDirectory()).map(({parentPath:e,name:t})=>o.getRelativePath(`${e}/${t}`)))}return e.push(t),e},[]),"-g","-a","-f",i.join(),"-t",String(r??V.DEFAULT_THRESHOLD)]:[e,"-a","-f",i.join(),"-t",String(r??V.DEFAULT_THRESHOLD)]}async prepare(e,t){try{const{ignore:s}=this.modulesConfig.modules.jscpd;return s&&s.length>0&&e.push("-i",s.join()),super.prepare(e,{...t,disableCache:!0})}catch{return process.stderr.write(l.red(`Can't load ${this.getName()} package config!\n`)),process.exit(w.EXCEPTION)}}}class U extends _{static DEFAULT_IGNORE=[];static DEFAULT_IGNORE_DEPENDENCIES=["@saashub/*"];static DEFAULT_IGNORE_BINARIES=[];async getPrompts(){const{knipEntry:e,knipProject:t,knipIgnore:s,knipIgnoreDependencies:i,knipIgnoreBinaries:r}=await g.prompt([{type:"list",name:"knipEntry",message:'Provide entry (initially autodetected from previous config), space " " separated',separator:" ",initial:this.getDefaultEntry().join(" ")},{type:"list",name:"knipProject",message:'Provide project (initially autodetected from previous config), space " " separated',separator:" ",initial:this.getDefaultProject().join(" ")},{type:"list",name:"knipIgnore",message:'Provide ignore (initially autodetected from previous config), space " " separated',separator:" "},{type:"list",name:"knipIgnoreDependencies",message:'Provide ignoreDependencies (initially autodetected from previous config), space " " separated',separator:" "},{type:"list",name:"knipIgnoreBinaries",message:'Provide ignoreBinaries (initially autodetected from previous config), space " " separated',separator:" "}]);return this.modulesConfig.modules.knip={entry:e.filter(e=>!!e).map(F),project:t.filter(e=>!!e).map(F),ignore:s.filter(e=>!!e).map(F),ignoreDependencies:i.filter(e=>!!e),ignoreBinaries:r.filter(e=>!!e)},super.getPrompts()}getConfigFromModules(){const{modules:{knip:e}}=this.modulesConfig;return this.config.knip={},e?.entry&&!f(e.entry,this.getDefaultEntry())&&(this.config.knip.entry=e.entry),e?.project&&!f(e.project,this.getDefaultProject())&&(this.config.knip.project=e.project),e?.ignore&&e.ignore.length>0&&!f(e.ignore,U.DEFAULT_IGNORE)&&(this.config.knip.ignore=e.ignore),e?.ignoreDependencies&&e.ignoreDependencies.length>0&&!f(e.ignoreDependencies,U.DEFAULT_IGNORE_DEPENDENCIES)&&(this.config.knip.ignoreDependencies=e.ignoreDependencies),e?.ignoreBinaries&&e.ignoreBinaries.length>0&&!f(e.ignoreBinaries,U.DEFAULT_IGNORE_BINARIES)&&(this.config.knip.ignoreBinaries=e.ignoreBinaries),0===Object.keys(this.config.knip).length&&delete this.config.knip,super.getConfigFromModules()}getModulesFromConfig(){return this.modulesConfig.modules.knip={entry:this.config.knip?.entry??this.getDefaultEntry(),project:this.config.knip?.project??this.getDefaultProject(),ignore:this.config.knip?.ignore?[...U.DEFAULT_IGNORE,...this.config.knip.ignore]:U.DEFAULT_IGNORE,ignoreDependencies:this.config.knip?.ignoreDependencies?[...U.DEFAULT_IGNORE_DEPENDENCIES,...this.config.knip.ignoreDependencies]:U.DEFAULT_IGNORE_DEPENDENCIES,ignoreBinaries:this.config.knip?.ignoreBinaries?[...U.DEFAULT_IGNORE_BINARIES,...this.config.knip.ignoreBinaries]:U.DEFAULT_IGNORE_BINARIES},super.getModulesFromConfig()}getPackages(){return this.packages=["@saashub/qoq-knip"],super.getPackages()}getDefaultEntry=()=>{const{srcPath:e,modules:t}=this.modulesConfig;return[`${F(e)}/{index,cli,main,root}.{${M(t).join()}}`]};getDefaultProject=()=>{const{srcPath:e,modules:t}=this.modulesConfig;return[`${F(e)}/**/*.{${M(t).join()}}`]}}class B extends R{static CACHE_PATH=q("/bin/.knipcache");getName(){return k(this.getCommandName())}getCommandName(){return"knip"}getCommandArgs(){return["--exclude","enumMembers"]}async prepare(e,t){const{configHints:s}=t;s||e.push("--no-config-hints");try{const{srcPath:s,configType:i,workspaces:r,modules:{knip:n}}=this.modulesConfig,{entry:c,project:l,ignore:g,ignoreDependencies:p,ignoreBinaries:u}=n,h=$(`/bin/knip.config.${i===I.ESM?"m":"c"}js`),f=((e=".src",t=[`${e}/index.js`],s=[`${e}/**/*.js`],i=["package.json"],r=[],n=[])=>({entry:t,project:s,ignore:i,ignoreDependencies:r,ignoreBinaries:n}))(s,c,l,g,p,u);if(r){const{entry:e,project:t,...s}=f,i={...s,workspaces:r.reduce((e,t)=>(e[t]={entry:c,project:l},e),{})};a.writeFileSync(h,j(this.modulesConfig.configType,{},[],JSON.stringify(i)))}else a.writeFileSync(h,j(this.modulesConfig.configType,{},[],JSON.stringify(f)));return e.push("-c",o.getRelativePath(h)),super.prepare(e,t)}catch{return process.stderr.write(l.red(`Can't load ${this.getName()} package config!\n`)),process.exit(w.EXCEPTION)}}}var Q=(e=>(e.PRETTIER="@saashub/qoq-prettier",e.PRETTIER_WITH_JSON_SORT="@saashub/qoq-prettier-with-json-sort",e))(Q||{});class W extends _{static CONFIG_FILE_PATH=o.resolveCwdRelativePath("/.prettierrc");async getPrompts(){this.configFileExists()&&process.stdout.write(l.red("\n '.prettierrc' already exists in the project root, config will be overwritten by this setup!\n\n"));const{prettierPackage:e,prettierSources:t}=await g.prompt([{type:"select",name:"prettierPackage",message:l.reset(`What options should we use for ${l.green("Prettier")}?`),choices:[{title:"Basic Prettier",value:Q.PRETTIER},{title:"Prettier with JSON sort",value:Q.PRETTIER_WITH_JSON_SORT}]},{type:"toggle",name:"otherSources",message:"Should we format other paths than sources?",initial:!1,active:l.green("yes"),inactive:l.red("no")},{type:e=>e?"list":null,name:"prettierSources",message:'Provide paths (from project root dir), space " " separated',separator:" "}]);this.configFileExists()&&a.rmSync(W.CONFIG_FILE_PATH),a.writeFileSync(W.CONFIG_FILE_PATH,`"${e}"`);const{srcPath:s}=this.modulesConfig;return this.modulesConfig.modules.prettier={sources:t?t.filter(e=>!!e):[s]},super.getPrompts()}getConfigFromModules(){const{srcPath:e,modules:{prettier:t}}=this.modulesConfig;return t?.sources&&!f(t.sources,[e])&&(this.config.prettier={...t}),super.getConfigFromModules()}getModulesFromConfig(){const{srcPath:e,modules:t}=this.modulesConfig;return t.prettier={sources:this.config.prettier?.sources??[e]},super.getModulesFromConfig()}getPackages(){if(this.configFileExists())try{const e=a.readFileSync(W.CONFIG_FILE_PATH,"utf-8");this.packages=[e.includes(Q.PRETTIER_WITH_JSON_SORT)?Q.PRETTIER_WITH_JSON_SORT:Q.PRETTIER]}catch{this.packages=[Q.PRETTIER]}else this.packages=[Q.PRETTIER];return super.getPackages()}configFileExists(){return a.existsSync(W.CONFIG_FILE_PATH)}}class K extends R{static CACHE_PATH=q("/bin/.prettiercache");getName(){return k(this.getCommandName())}getCommandName(){return"prettier"}getCommandArgs(){return["--config",W.CONFIG_FILE_PATH,"--ignore-unknown"]}async prepare(e,t,s=[]){const{disableCache:i,fix:n}=t;i||e.push("--cache-strategy","metadata");try{const{srcPath:i,modules:c}=this.modulesConfig,l=o.resolveCwdPath("/.prettierignore");let g=c?.prettier?.sources??[i];if(s.length>0){try{const e=[];if(a.existsSync(T)){const t=await r.open(T);for await(const s of t.readLines())s.startsWith("#")||""===s||e.push(s)}if(a.existsSync(l)){const t=await r.open(l);for await(const s of t.readLines())s.startsWith("#")||""===s||e.push(s)}g=s.filter(t=>!p.isMatch(t,e))}catch{throw new Error}if(0===g.length)throw new b}return e.push("--check",...g),n&&e.push("--write"),super.prepare(e,t,s)}catch(e){if(e instanceof b)throw e;return process.stderr.write(l.red(`Can't load ${this.getName()} package config!\n`)),process.exit(w.EXCEPTION)}}}var X=(e=>(e.STYLELINT_CSS="@saashub/qoq-stylelint-css",e.STYLELINT_SCSS="@saashub/qoq-stylelint-scss",e))(X||{});class Y extends _{static CONFIG_FILE_PATH=o.resolveCwdRelativePath("/stylelint.config.js");async getPrompts(){const{stylelint:e}=await g.prompt([{type:"toggle",name:"stylelint",message:"Should we include style linting?",initial:!1,active:l.green("yes"),inactive:l.red("no")}]);if(!e)return super.getPrompts();this.configFileExists()&&process.stdout.write(l.red("\n 'stylelint.config.js' already exists in the project root, config will be overwritten by this setup!\n\n"));const{stylelintPackage:t,stylelintStrict:s}=await g.prompt([{type:"select",name:"stylelintPackage",message:l.reset(`What options should we use for ${l.green("Stylelint")}?`),choices:[{title:"CSS",value:X.STYLELINT_CSS},{title:"SCSS",value:X.STYLELINT_SCSS}]},{type:"toggle",name:"stylelintStrict",message:"Should style linting be strict (fail on warnings)?",initial:!1,active:l.green("yes"),inactive:l.red("no")}]);return this.configFileExists()&&a.rmSync(Y.CONFIG_FILE_PATH),a.writeFileSync(Y.CONFIG_FILE_PATH,j(this.modulesConfig.configType,{config:`@saashub/qoq-cli/bin/stylelint.config.${this.modulesConfig.configType===I.ESM?"m":"c"}js`},[],"config")),this.modulesConfig.modules.stylelint={strict:s,template:t},super.getPrompts()}getConfigFromModules(){const{modules:{stylelint:e}}=this.modulesConfig;if(e){const{strict:t}=e;if(e.template)this.config.stylelint={strict:!!t,template:e.template};else{if(!e.pattern)throw new Error("Bad config!");this.config.stylelint={strict:!!t,pattern:e.pattern}}}return super.getConfigFromModules()}getModulesFromConfig(){const{modules:e}=this.modulesConfig,{stylelint:t}=this.config;if(t){const{strict:s,...i}=t;if(t.template)e.stylelint={strict:!!s,template:t.template,...i};else{if(!t.pattern)throw new Error("Bad config!");e.stylelint={strict:!!s,pattern:t.pattern,...i}}}return super.getModulesFromConfig()}getPackages(){const{stylelint:e}=this.modulesConfig.modules;return e&&e.template&&Object.values(X).includes(e.template)&&(this.packages=[e.template]),super.getPackages()}configFileExists(){return a.existsSync(Y.CONFIG_FILE_PATH)}}class z extends R{static CACHE_PATH=q("/bin/.stylelintcache");getName(){return k(this.getCommandName())}getCommandName(){return"stylelint"}getCommandArgs(){return[]}async prepare(e,t,s=[]){const{srcPath:i,configType:n,modules:{stylelint:o}}=this.modulesConfig;if(!o)throw new b;const{strict:c}=o;let g;if(o.pattern){const{pattern:t,...s}=o;g=s,e.push(`"${t}"`)}else{if(!o.template)throw new Error("Bad config!");{const{template:t,...s}=o;g=s,t===X.STYLELINT_SCSS?e.push(`${i}/**/*.{css,scss,sass}`):e.push(`${i}/**/*.css`)}}const{disableCache:u,fix:h}=t;u||e.push("--cache-strategy","metadata");try{c&&e.push("--max-warnings","0");const i=$(`/bin/stylelint.config.${n===I.ESM?"m":"c"}js`),l={"{ objectMergeRight }":"@saashub/qoq-utils"},u=[];o.template?(l["{ baseConfig }"]=String(o.template),u.push(`const config = objectMergeRight(baseConfig, ${JSON.stringify(g)})`)):u.push(`const config = ${JSON.stringify(g)}`);const f="config";if(a.writeFileSync(i,j(n,l,u,f)),e.push("-c",Y.CONFIG_FILE_PATH),s.length>0){let t=[...s];try{const e=[];if(a.existsSync(T)){const t=await r.open(T);for await(const s of t.readLines())s.startsWith("#")||""===s||e.push(s)}t=s.filter(t=>!p.isMatch(t,e))}catch{throw new Error}if(0===t.length)throw new b;e.push("--stdin-filename",...t)}return h&&e.push("--fix"),super.prepare(e,t,s)}catch(e){if(e instanceof b)throw e;return process.stderr.write(l.red(`Can't load ${this.getName()} package config!\n`)),process.exit(w.EXCEPTION)}}}const Z=(e,t)=>{const s=new P(e,t),i=new W(e,t),r=new L(e,t),n=new V(e,t),o=new U(e,t),a=new Y(e,t);return s.setNext(i).setNext(r).setNext(n).setNext(o).setNext(a),s},ee=(e,t)=>Z({modules:{},workspaces:t},e).getModulesFromConfig(),te=async(e,t=!1)=>{const s={modules:{},workspaces:e},i={};await Z(s,i).getPrompts(),a.existsSync(P.CONFIG_FILE_PATH)&&a.rmSync(P.CONFIG_FILE_PATH);const r=Z(s,i).getConfigFromModules();a.writeFileSync(P.CONFIG_FILE_PATH,j(s.configType,{},[],JSON.stringify(r)));const n=Z(s,i).getPackages();return await(async e=>{for(const t of e)process.stderr.write(`Installing ${l.green(t)}...\n`),await m.installPackage(t,{dev:!0}),process.stderr.write("\n")})(n),t||await O("qoq",["--warmup"]),s},se=async(e,t=!1)=>{if(!t&&!a.existsSync(y)){const{config:t}=await g.prompt({type:"toggle",name:"config",message:"No QoQ config found, do You want to run setup now?",initial:!0,active:l.green("yes"),inactive:l.red("no")});return t?te(e,!0):(process.stderr.write("Running with defaults\n"),ee({},e))}try{const t=await import(c.pathToFileURL(y).toString());return ee(t.default,e)}catch{return process.stderr.write("Running with defaults\n"),ee({},e)}},ie=async(e,t,s)=>{const{silent:i,warmup:r,skipPrettier:n,skipJscpd:o,skipKnip:a,skipEslint:c}=t,g=!!i||!!r,p="Total execution time:";console.time(l.italic(l.gray(p)));const u=new K(e,g),h=new G(e,g,!0),f=new B(e,g),m=new D(e,g),d=new z(e,g),E={[u.getName()]:w.OK,[h.getName()]:w.OK,[f.getName()]:w.OK,[m.getName()]:w.OK,[d.getName()]:w.OK};n||(E[u.getName()]=await u.run(t,s)),o||(E[h.getName()]=await h.run(t,s)),a||(E[f.getName()]=await f.run(t,s)),c||(E[m.getName()]=await m.run(t,s)),e.modules.stylelint&&(E[d.getName()]=await d.run(t,s)),Object.keys(E).filter(e=>E[e]!==w.OK).forEach(e=>{process.exitCode=w.ERROR,process.stderr.write(l.red(`\nQoQ found some ${e} errors!\n\n`))}),g||(process.stdout.write("\n-------------------------\n\n"),console.timeEnd(l.italic(l.gray(p))))},re=n("qoq");re.command("").option("--init","Initialize QoQ cli config").option("--check","Perform QoQ quality checks").option("--fix","Apply fixes to QoQ check findings where possible").option("--disable-cache","Disable cache to all tools").option("--skip-prettier","Skip Prettier checks").option("--skip-jscpd","Skip JSCPD checks").option("--skip-knip","Skip Knip checks").option("--skip-eslint","Skip Eslint checks").option("--warmup","Create configs for tools without QoQ execution").option("--silent","Mute all QoQ messages").option("--config-hints","Enable config hints").action(async e=>{const{workspaces:t}=await E.readPackage(S),{init:s,fix:i,disableCache:r}=e;if(s)return await te(t);const n=await se(t);return await ie(n,{...e,fix:!!i,disableCache:!!r})}),re.command("staged [...files]","Perform QoQ quality checks but only on filelist, usefull for eg `lint-staged` config").option("--disable-cache","Disable cache to all tools").option("--skip-prettier","Skip Prettier checks").option("--skip-jscpd","Skip JSCPD checks").option("--skip-knip","Skip Knip checks").option("--skip-eslint","Skip Eslint checks").option("--config-hints","Enable config hints").action(async(e=[],t)=>{const{workspaces:s}=await E.readPackage(S),i=await se(s,!0);return await ie(i,{...t,fix:!1,disableCache:!!t.disableCache},e)}),re.help(),re.parse();