@kitschpatrol/stylelint-config 8.1.0 → 8.3.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/bin/cli.js CHANGED
@@ -1,8 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import{cosmiconfig as e}from"cosmiconfig";import{TypeScriptLoader as t}from"cosmiconfig-typescript-loader";import{execa as n}from"execa";import r from"fs-extra";import i from"node:fs";import a from"node:path";import{PassThrough as o,Transform as s}from"node:stream";import{fileURLToPath as c}from"node:url";import{packageUp as l,packageUpSync as u}from"package-up";import d from"picocolors";import f from"yargs";import{hideBin as p}from"yargs/helpers";import m from"@pinojs/json-colorizer";import h from"decircular";import g from"deepmerge";import _ from"json-stringify-pretty-compact";import{findWorkspacesRoot as v}from"find-workspaces";import y from"node:fs/promises";import{stripVTControlCharacters as b}from"node:util";import x from"stylelint";var S=`8.1.0`;function C(e){return e instanceof Error&&`exitCode`in e&&typeof e.exitCode==`number`}function w(e){return m(_(h(e),{indent:2,replacer(e,t){return typeof t==`function`?t.name:t}}),{colors:{BRACKET:`gray`}})}const T=(e,t,n)=>{let r=[...e];for(let[i,a]of t.entries())r[i]===void 0?r[i]=n.cloneUnlessOtherwiseSpecified(a,n):n.isMergeableObject(a)?r[i]=E(e[i],a,n):e.includes(a)||r.push(a);return r};function E(e,t,n={arrayMerge:T}){return g(e,t,n)}function D(){let e=u();if(e===void 0)throw Error(`No package.json found.`);return a.dirname(e)}function O(){let e=v();return e===null?D():a.resolve(e.location)}function k(e){let t=a.join(O(),e);if(r.existsSync(t))return t}function A(e){if(e===`workspace-root`)return O();if(e===`package-dir`)return D();if(typeof e==`string`){if(!r.pathExistsSync(e))throw Error(`Custom cwd directory does not exist: ${e}`);return e}return process.cwd()}async function j(e,t){try{let{default:n}=await import(`prettier`),r=await n.resolveConfig(e),i=await n.format(t,{filepath:e,...r});await y.writeFile(e,i,`utf8`)}catch{console.warn(`Skipped formatting ${e} since Prettier is not installed.`)}}async function M(e){try{await j(e,await y.readFile(e,`utf8`))}catch{}}const N=/\r?\n/v;function P(e){return new s({transform(t,n,r){r(void 0,t.toString().split(N).filter(t=>t.trim()!==``&&!e(b(t))).join(`
3
- `)+`
4
- `)}})}function F(e,t){let n=e===void 0||e===``?``:t===void 0?e:d[t](e);return new s({transform(e,t,r){r(void 0,e.toString().split(N).filter(e=>e.trim().length>0).map(e=>`${n} ${e}\n`).join(``))}})}async function I(e){let t=[];return new Promise((n,r)=>{e.on(`data`,e=>{t.push(e)}),e.on(`error`,e=>{r(e)}),e.on(`end`,()=>{n(Buffer.concat(t).toString(`utf8`))})})}function L(e,t){return t===1?e:e+`s`}async function R(e,t,n,r,i){let a;if(r.logPrefix===void 0)a=e;else{let t=F(r.logPrefix,r.logColor);t.pipe(e),a=t}i&&a.write(d.bold(`Running: "${r.name}() with Positional arguments: ${String(t)} and Option flags: ${String(n)}"`));try{return await r.execute(a,t,n)}catch(e){return console.error(String(e)),1}}async function z(e,t,r,i,a){let s=1,c;if(i.logPrefix===void 0)c=e;else{let t=F(i.logPrefix,i.logColor);t.pipe(e),c=t}let l=i.subcommands??[],u=[...i.receivePositionalArguments?t:[],...i.positionalArguments??[]],d=[...i.receiveOptionFlags?r:[],...i.optionFlags??[]],f=[...l,...d,...u],p=A(i.cwdOverride);a&&c.write(`Running: "${i.name} ${f.join(` `)}"`);let m=i.prettyJsonOutput?new o:c;try{let e=n(i.name,f,{cwd:p,env:{...process.env.NO_COLOR===void 0&&{FORCE_COLOR:`true`}},preferLocal:!0,reject:!1,stdin:`inherit`});if(i.outputFilter){let t=P(i.outputFilter),n=P(i.outputFilter);e.stdout.pipe(t).pipe(m,{end:!1}),e.stderr.pipe(n).pipe(m,{end:!1})}else e.stdout.pipe(m,{end:!1}),e.stderr.pipe(m,{end:!1});if(await e,i.prettyJsonOutput){m.end();let e=await I(m),t=w(JSON.parse(e)).split(`
5
- `);for(let e of t)c.write(`${e}\n`)}s=e.exitCode??1}catch(e){console.error(`${i.name} failed with error:`),console.error(e),C(e)&&(s=typeof e.exitCode==`number`?e.exitCode:1)}return s}function B(e){return`execute`in e}const V=/^ksc-/v;function H(e){return e.replace(V,``)}function U(e){return e===void 0||e.length===0?[]:e.flatMap(e=>e.split(`,`)).map(e=>H(e.trim()))}function W(e){return e.option(`skip`,{array:!0,describe:`Tool names to skip (with or without "ksc-" prefix).`,type:`string`})}async function G(e,t,n,r,i,a,o){let s=o??[],c=[],l=[];for(let e of r)s.length>0&&s.includes(H(e.name))?l.push(e):c.push(e);if(s.length>0){let t=new Set(l.map(e=>H(e.name))),n=s.filter(e=>!t.has(e));if(n.length>0){let t=r.map(e=>H(e.name)).join(`, `);e.write(`⚠️ ${d.yellow(`Unrecognized --skip ${L(`value`,n.length)}: ${n.join(`, `)}. Available: ${t}`)}\n`)}}let u=[];for(let r of c){let a=await(B(r)?R(e,t,n,r,i):z(e,t,n,r,i));u.push({exitCode:a,name:r.name})}let f=r.length;if(l.length>0){let t=l.map(({name:e})=>e),n=d.bold(`${t.length} / ${f} ${L(`Command`,t.length)} Skipped:`);e.write(`⏭️ ${d.dim(n)} ${d.dim(t.join(`, `))}\n`)}if(a){let t=u.filter(({exitCode:e})=>e===0).map(({name:e})=>e),n=u.filter(({exitCode:e})=>e!==0).map(({name:e})=>e);if(t.length>0){let n=d.bold(`${t.length} / ${f} ${L(`Command`,t.length)} Succeeded:`);e.write(`✅ ${d.green(n)} ${d.green(t.join(`, `))}\n`)}if(n.length>0){let t=d.bold(`${n.length} / ${f} ${L(`Command`,n.length)} Failed:`);e.write(`❌ ${d.red(t)} ${d.red(n.join(`, `))}\n`)}}return+!u.every(({exitCode:e})=>e===0)}async function K(e,t,n,o){let s=await l();if(s===void 0)throw Error("The `init` command must be used in a directory with a package.json file");let u=await l({cwd:c(import.meta.url)});if(u===void 0)return e.write(`Error: The script being called was not in a package, weird.
6
- `),1;let d=a.join(a.dirname(u),`init`),f=a.dirname(s),p=(t===`file`||t===`package`)&&n!==void 0&&o!==void 0;try{if(p){let n=Object.keys(o)[0],i=r.readJsonSync(s);if(t===`package`){e.write(`Merging: \nPackage config key "${n}" "${f}" (Because --location is set to "package")\n`);let t=E(i,o);r.writeJSONSync(s,t,{spaces:` `}),await M(s)}else n!==void 0&&Object.keys(i).includes(n)&&(e.write(`Deleting: \nPackage config key "${n}" in "${f}" (Because --location is set to "file")\n`),delete i[n],r.writeJSONSync(s,i,{spaces:` `}),await M(s))}if(!await r.pathExists(d))return 0;if((await r.readdir(d)).length===0)return e.write(`Source directory "${d}" is empty.\n`),0;e.write(`Adding initial configuration files from:\n"${d}" → "${f}"\n`),await r.copy(d,f,{async filter(o,s){let c=i.statSync(o).isFile(),l=i.existsSync(s);if(c){if(p&&t===`package`&&o.includes(n))return l?(e.write(`Deleting: \n"${o}" → "${s}" (Because --location is set to "package")\n`),r.removeSync(s)):e.write(`Skipping: \n"${o}" → "${s}" (Because --location is set to "package")\n`),!1;if(l&&(s.includes(`.vscode/`)||s.includes(`package.json`))&&a.extname(s)===`.json`){e.write(`Merging: \n"${o}" → "${s}"\n`);let t=r.readJSONSync(o),n=E(r.readJSONSync(s),t);return r.writeJSONSync(s,n,{spaces:` `}),await M(s),!1}return l?(e.write(`Overwriting: \n"${o}" "${s}"\n`),await M(s),!0):(e.write(`Copying: \n"${o}" → "${s}"\n`),await M(s),!0)}return!0},overwrite:!0})}catch(e){return console.error(String(e)),1}return 0}async function q(e){let{commands:{fix:t,init:n,lint:r,printConfig:i},description:a,logColor:o,logPrefix:s,name:c,showSummary:l,verbose:u}=e,d=F(s,o);d.pipe(process.stdout);let m=f(p(process.argv)).scriptName(c).usage(`$0 <command>`,a);n!==void 0&&m.command({builder(e){let t=n.locationOptionFlag?e.option(`location`,{choices:[`file`,`package`],default:`file`,describe:`Where to store the configuration.`,type:`string`}):e;return l?W(t):t},command:`init`,describe:n.description??`Initialize by copying starter config files to your project root${n.locationOptionFlag?` or to your package.json file.`:`.`}`,async handler(e){let t=n.locationOptionFlag?e.location:void 0,r=U(e.skip),i=await G(d,[],t===void 0?[]:[`--location`,t],[{async execute(e,t,r){return K(e,r.at(1),n.configFile,n.configPackageJson)},name:`copyAndMergeInitFiles`},...n.commands??[]],void 0,void 0,r);process.exitCode=i}}),r!==void 0&&m.command({builder(e){let t=r.positionalArgumentMode===`none`?e:e.positional(`files`,{array:!0,...r.positionalArgumentDefault!==void 0&&{default:r.positionalArgumentDefault},describe:`Files or glob pattern to lint.`,type:`string`});return l?W(t):t},command:r.positionalArgumentMode===`none`?`lint`:r.positionalArgumentMode===`optional`?`lint [files..]`:`lint <files..>`,describe:r.description,async handler(e){let t=e.files??[],n=U(e.skip),i=await G(d,t,[],r.commands,u,l,n);process.exitCode=i}}),t!==void 0&&m.command({builder(e){let n=t.positionalArgumentMode===`none`?e:e.positional(`files`,{array:!0,...t.positionalArgumentDefault!==void 0&&{default:t.positionalArgumentDefault},describe:`Files or glob pattern to fix.`,type:`string`});return l?W(n):n},command:t.positionalArgumentMode===`none`?`fix`:t.positionalArgumentMode===`optional`?`fix [files..]`:`fix <files..>`,describe:t.description,async handler(e){let n=e.files??[],r=U(e.skip),i=await G(d,n,[],t.commands,void 0,void 0,r);process.exitCode=i}}),i!==void 0&&m.command({builder(e){let t=i.positionalArgumentMode===`none`?e:e.positional(`file`,{...i.positionalArgumentDefault!==void 0&&{default:i.positionalArgumentDefault},describe:`File or glob pattern to print configuration for.`,type:`string`});return l?W(t):t},command:i.positionalArgumentMode===`none`?`print-config`:i.positionalArgumentMode===`optional`?`print-config [file]`:`print-config <file>`,describe:i.description,async handler(e){let t=e.file??void 0,n=t===void 0?[]:[t],r=U(e.skip),a=await G(d,n,[],i.commands,u,l,r);process.exitCode=a}}),m.alias(`h`,`help`),m.version(S),m.alias(`v`,`version`),m.help(),m.wrap(process.stdout.isTTY?Math.min(120,m.terminalWidth()):0),await m.parseAsync()}async function J(n){let r=e(n,{loaders:{".ts":t()},searchStrategy:`project`});try{let e=await r.search();if(e===null){console.error(`No ${n} configuration found.`);return}return e}catch(e){console.error(`Error while searching for ${n} configuration:`,e);return}}const Y={fileRun:`Matches files below the current working directory by default.`,monorepoRun:`In a monorepo, it will also run in all packages below the current working directory.`,monorepoSearch:`Searches up to the root of a monorepo if necessary.`,multiArgumentCaveat:`Will use file arguments / globs where possible if provided, but some of the invoked tools only operate at the package scope.`,multiOptionCaveat:`Will use option flags where possible if provided, but some of the invoked tools will ignore them.`,optionalFileRun:`Package-scoped by default, file-scoped if a file argument is provided.`,packageRun:`Package-scoped.`,packageSearch:`Package-scoped.`},X=[`--ignore-path`,k(`.gitignore`)??`.gitignore`,`--allow-empty-input`],Z=`**/*.{${[`css`,`scss`,`sass`,`svelte`,`html`,`astro`,`tsx`,`jsx`,`php`,`vue`].join(`,`)}}`;async function Q(e,t){let n=`stylelint`,r=await J(n);if(r===void 0)return 1;let{filepath:i,isEmpty:o}=r;if(o)return e.write(`Configuration is empty.
7
- `),0;e.write(`Found ${n} configuration at "${i}"\n`);let s,[c]=t;c===void 0?s=A(`package-dir`):(s=a.join(process.cwd(),c),e.write(`Showing config for file at "${s}"\n`));let l=w(await x.resolveConfig(s)).split(`
8
- `);for(let t of l)e.write(`${t}\n`);return 0}await q({commands:{fix:{commands:[{name:`stylelint`,optionFlags:[...X,`--fix`],receivePositionalArguments:!0}],description:`Fix your project with Stylelint. ${Y.fileRun}`,positionalArgumentDefault:Z,positionalArgumentMode:`optional`},init:{configFile:`stylelint.config.js`,configPackageJson:{stylelint:{extends:`@kitschpatrol/stylelint-config`}},locationOptionFlag:!0},lint:{commands:[{name:`stylelint`,optionFlags:X,receivePositionalArguments:!0}],description:`Lint your project with Stylelint. ${Y.fileRun}`,positionalArgumentDefault:Z,positionalArgumentMode:`optional`},printConfig:{commands:[{execute:Q,name:Q.name}],description:`Print the effective Stylelint configuration. ${Y.optionalFileRun}.`,positionalArgumentMode:`optional`}},description:`Kitschpatrol's Stylelint shared configuration tools.`,logColor:`greenBright`,logPrefix:`[Stylelint]`,name:`ksc-stylelint`,order:5});export{};
2
+ import{cosmiconfig as e}from"cosmiconfig";import{TypeScriptLoader as t}from"cosmiconfig-typescript-loader";import{execa as n}from"execa";import r from"fs-extra";import i from"node:fs";import{availableParallelism as a}from"node:os";import o from"node:path";import{PassThrough as s,Transform as c}from"node:stream";import{fileURLToPath as l}from"node:url";import{packageUp as u,packageUpSync as d}from"package-up";import f from"yargs";import{hideBin as p}from"yargs/helpers";import m from"picocolors";import{stripVTControlCharacters as h}from"node:util";import g from"@pinojs/json-colorizer";import _ from"decircular";import ee from"deepmerge";import v from"json-stringify-pretty-compact";import{findWorkspacesRoot as y}from"find-workspaces";import b from"node:fs/promises";import te from"stylelint";var ne=`8.3.0`;const x=[`json`,`machine`,`native`],re=x;function S(e){return typeof e==`string`&&x.includes(e)}function C(){let e=process.env.KSC_FORMAT;return S(e)?e:`native`}function ie(){let{argv:e}=process;for(let[t,n]of e.entries()){let r;n===`--format`?r=e[t+1]:n.startsWith(`--format=`)&&(r=n.slice(9)),S(r)&&(process.env.KSC_FORMAT=r)}}function ae(){let{env:e}=process;if(e.NO_COLOR!==void 0&&e.NO_COLOR!==``)return!1;if(e.FORCE_COLOR!==void 0)return e.FORCE_COLOR!==`0`&&e.FORCE_COLOR!==`false`;if(e.TERM===`dumb`)return!1}function w(e,{ciColor:t=!0}={}){let n=ae();return n===void 0?e.isTTY===!0||t&&!!process.env.CI:n}function T(){return C()===`json`?process.stderr:process.stdout}function E(){return C()===`machine`?m.createColors(!1):m.createColors(w(T()))}function D(e){if(!e)return{FORCE_COLOR:`0`,NO_COLOR:`1`};let t=process.env.FORCE_COLOR;return t===void 0||t===``?{FORCE_COLOR:`1`}:{}}function oe(e,t){let n=o.isAbsolute(e)?e:o.resolve(t,e),r=o.relative(process.cwd(),n);return r===``?`.`:r}const se=/\s*\n\s*/gv,ce=/\r?\n/v;function le(e){let t=e.message.replaceAll(se,` `),n=e.rule===void 0?e.tool:`${e.tool}/${e.rule}`;return e.file===void 0?`${e.severity}: ${t} [${n}]`:`${e.file}:${e.line??1}:${e.column??1}: ${e.severity}: ${t} [${n}]`}function ue(e,t){let n=(e.file??`￿`).localeCompare(t.file??`￿`);if(n!==0)return n;let r=(e.line??0)-(t.line??0);return r===0?(e.column??0)-(t.column??0):r}function de(e,t){let n=t.toSorted(ue);return{cwd:process.cwd(),diagnostics:n,success:e.every(e=>e.exitCode===0),summary:{errors:n.filter(e=>e.severity===`error`).length,infos:n.filter(e=>e.severity===`info`).length,warnings:n.filter(e=>e.severity===`warning`).length},tools:e,version:1}}function O(e){return h(e).split(ce).map(e=>e.trimEnd()).filter(e=>e.trim().length>0)}function k(e){return e instanceof Error&&`exitCode`in e&&typeof e.exitCode==`number`}function A(e){return w(process.stdout,{ciColor:!1})?pe(e):fe(e)}function fe(e){return v(_(e),{indent:2,replacer(e,t){return typeof t==`function`?t.name:t}})}function pe(e){return g(fe(e),{colors:{BRACKET:`gray`}})}const me=(e,t,n)=>{let r=[...e];for(let[i,a]of t.entries())r[i]===void 0?r[i]=n.cloneUnlessOtherwiseSpecified(a,n):n.isMergeableObject(a)?r[i]=j(e[i],a,n):e.includes(a)||r.push(a);return r};function j(e,t,n={arrayMerge:me}){return ee(e,t,n)}function M(e){let{tasks:t}=e;return Array.isArray(t)?t:[]}function he(e,t){let n=[...M(e)];for(let e of M(t)){let t=n.findIndex(t=>t.label!==void 0&&t.label===e.label);t===-1?n.push(e):n[t]=e}return{...e,...t,tasks:n}}function N(){let e=d();if(e===void 0)throw Error(`No package.json found.`);return o.dirname(e)}function P(){let e=y();return e===null?N():o.resolve(e.location)}function ge(e){let t=o.join(P(),e);if(r.existsSync(t))return t}function F(e){if(e===`workspace-root`)return P();if(e===`package-dir`)return N();if(typeof e==`string`){if(!r.pathExistsSync(e))throw Error(`Custom cwd directory does not exist: ${e}`);return e}return process.cwd()}async function _e(e,t){try{let{default:n}=await import(`prettier`),r=await n.resolveConfig(e),i=await n.format(t,{filepath:e,...r});await b.writeFile(e,i,`utf8`)}catch{console.warn(`Skipped formatting ${e} since Prettier is not installed.`)}}async function I(e){try{await _e(e,await b.readFile(e,`utf8`))}catch{}}const L=/\r?\n/v;function ve(e){let t=``,n=t=>t.filter(t=>t.trim()!==``&&!e(h(t))).map(e=>`${e}\n`).join(``);return new c({flush(e){e(void 0,n([t]))},transform(e,r,i){let a=(t+e.toString()).split(L);t=a.pop()??``,i(void 0,n(a))}})}function R(e,t){let n=C()===`native`?e:void 0,r=n===void 0||n===``?``:t===void 0?n:E()[t](n),i=``,a=e=>e.filter(e=>e.trim().length>0).map(e=>r===``?`${e}\n`:`${r} ${e}\n`).join(``);return new c({flush(e){e(void 0,a([i]))},transform(e,t,n){let r=(i+e.toString()).split(L);i=r.pop()??``,n(void 0,a(r))}})}async function ye(e){let t=[];return new Promise((n,r)=>{e.on(`data`,e=>{t.push(e)}),e.on(`error`,e=>{r(e)}),e.on(`end`,()=>{n(Buffer.concat(t).toString(`utf8`))})})}function z(e,t){return t===1?e:e+`s`}async function B(e){return typeof e==`function`?e():e}async function be(e,t,n,r,i){let a;if(r.logPrefix===void 0)a=e;else{let t=R(r.logPrefix,r.logColor);t.pipe(e),a=t}i&&a.write(E().bold(`Running: "${r.name}() with Positional arguments: ${String(t)} and Option flags: ${String(n)}"`)+`
3
+ `);try{return await r.execute(a,t,n)}catch(e){return console.error(String(e)),1}}function V(e,t,n,r,i){return[...e.subcommands??[],...e.receiveOptionFlags?n:[],...r??[],...i&&e.cache!==void 0?[...e.cache.flags,`--cache-location`,o.join(P(),`node_modules`,`.cache`,`ksc`,e.cache.name)]:[],...e.receivePositionalArguments?t:[],...e.positionalArguments??[]]}async function xe(e,t,r,i,a,o){let c=1,l;if(i.logPrefix===void 0)l=e;else{let t=R(i.logPrefix,i.logColor);t.pipe(e),l=t}let u=V(i,t,r,i.optionFlags,a),d=F(i.cwdOverride);o&&l.write(`Running: "${i.name} ${u.join(` `)}"\n`);let f=i.prettyJsonOutput?new s:l,p=D(C()===`native`&&i.prettyJsonOutput!==!0&&w(T()));try{let e=n(i.name,u,{cwd:d,env:{...p},preferLocal:!0,reject:!1,stdin:`inherit`});if(i.outputFilter){let t=ve(i.outputFilter),n=ve(i.outputFilter);e.stdout.pipe(t).pipe(f,{end:!1}),e.stderr.pipe(n).pipe(f,{end:!1})}else e.stdout.pipe(f,{end:!1}),e.stderr.pipe(f,{end:!1});let t=await e;if(i.prettyJsonOutput){f.end();let e=await ye(f),t=A(JSON.parse(e)).split(`
4
+ `);for(let e of t)l.write(`${e}\n`)}c=t.exitCode??1}catch(e){console.error(`${i.name} failed with error:`),console.error(e),k(e)&&(c=typeof e.exitCode==`number`?e.exitCode:1)}return c}function H(e){return`execute`in e}function U(e){return`kind`in e}async function W(e,t,r,i,a){let o=V(r,e,t,r.collect?.optionFlags??r.optionFlags,i),s=F(r.cwdOverride);try{let e=n(r.name,o,{cwd:s,env:D(!1),preferLocal:!0,reject:!1,stdin:`inherit`});a!==void 0&&e.stderr.pipe(a,{end:!1});let t=await e;return{cwd:s,exitCode:t.exitCode??1,stderr:t.stderr,stdout:t.stdout}}catch(e){return console.error(`${r.name} failed with error:`),console.error(e),{cwd:s,exitCode:k(e)&&typeof e.exitCode==`number`?e.exitCode:1,stderr:``,stdout:``}}}function Se(e){return typeof e==`object`&&!!e&&`version`in e&&e.version===1&&`diagnostics`in e&&Array.isArray(e.diagnostics)&&`tools`in e&&Array.isArray(e.tools)}async function Ce(e,t,n,r,i){let a=Date.now(),o=()=>Date.now()-a;if(H(r)){if(r.collect!==void 0)try{let{diagnostics:e,exitCode:i,unparsed:a}=await r.collect(t,n);return{diagnostics:e,exitCode:i,tools:[{durationMs:o(),exitCode:i,name:r.name,unparsed:a}]}}catch(e){return{diagnostics:[],exitCode:1,tools:[{durationMs:o(),exitCode:1,name:r.name,unparsed:[String(e)]}]}}let e=``,i=new s;i.on(`data`,t=>{e+=t.toString()});let a;try{a=await r.execute(i,t,n)}catch(t){e+=`\n${String(t)}`,a=1}return{diagnostics:[],exitCode:a,tools:[{durationMs:o(),exitCode:a,name:r.name,unparsed:O(e)}]}}if(U(r))throw Error(`Command groups must be expanded before collection`);if(r.outputFormatAware){let a=await W(t,n,r,i,e);try{let e=JSON.parse(a.stdout);if(!Se(e))throw Error(`Child output is not a lint report`);return{diagnostics:e.diagnostics,exitCode:a.exitCode,tools:e.tools}}catch{return{diagnostics:[],exitCode:a.exitCode,tools:[{durationMs:o(),exitCode:a.exitCode,name:r.name,unparsed:O(a.stdout)}]}}}let c=await W(t,n,r,i);if(r.collect!==void 0)try{let{diagnostics:e,unparsed:t}=r.collect.parse(c);return{diagnostics:e,exitCode:c.exitCode,tools:[{durationMs:o(),exitCode:c.exitCode,name:r.name,unparsed:t}]}}catch(e){return{diagnostics:[],exitCode:c.exitCode,tools:[{durationMs:o(),exitCode:c.exitCode,name:r.name,unparsed:[...O(c.stdout),...O(c.stderr),String(e)]}]}}return{diagnostics:[],exitCode:c.exitCode,tools:[{durationMs:o(),exitCode:c.exitCode,name:r.name,unparsed:[...O(c.stdout),...O(c.stderr)]}]}}const we=/^ksc-/v;function G(e){return e.replace(we,``)}function K(e){return e===void 0||e.length===0?[]:e.flatMap(e=>e.split(`,`)).map(e=>G(e.trim()))}function q(e){return e.option(`skip`,{array:!0,describe:`Tool names to skip (with or without "ksc-" prefix).`,type:`string`})}function J(e){return e.option(`format`,{choices:re,default:`native`,describe:`Output format: "native" streams each tool's own output, "machine" prints one parseable line per issue for editor problem matchers, "json" prints an aggregate report.`})}function Y(e){return e.option(`cache`,{boolean:!0,default:!0,describe:`Use tool-native caches stored below node_modules/.cache/ksc at the workspace root. Disable with --no-cache.`})}function Te(e,t){return t===`native`||t===`machine`&&!H(e)&&!U(e)&&e.outputFormatAware===!0}function Ee(e,t){for(let n of t.diagnostics)e.write(`${le(n)}\n`);for(let n of t.tools)for(let t of n.unparsed)e.write(`${t}\n`)}function De(){return Math.min(4,a())}var Oe=class{concurrency;active=0;queue=[];constructor(e){this.concurrency=e}async run(e){this.active>=this.concurrency&&await new Promise(e=>{this.queue.push(e)}),this.active+=1;try{return await e()}finally{--this.active,this.queue.shift()?.()}}};async function ke(e){let t=e.cache??!1,n=e.concurrency??De();if(!Number.isInteger(n)||n<1)throw Error(`Concurrency must be a positive integer.`);return t&&await r.ensureDir(o.join(P(),`node_modules`,`.cache`,`ksc`)),{cache:t,scheduler:new Oe(n)}}function Ae(e,t){return e.positionalArgumentMode===`none`?[]:t.length>0?t:e.positionalArgumentDefault===void 0?[]:[e.positionalArgumentDefault]}function je(e,t){if(t.logPrefix===void 0)return e;let n=R(t.logPrefix,t.logColor);return n.pipe(e),n}async function X(e,t){if(U(e)){if(t.nativeVerbose){let n=[e.subcommand,...t.positionalArguments].join(` `);t.logStream.write(`Running: "${e.name} ${n}"\n`)}let n=je(t.logStream,e);try{let r=await Me(await B(e.commands),{...t,logStream:n,nativeVerbose:e.verbose,positionalArguments:Ae(e,t.positionalArguments)},e.parallel===!0);return{diagnostics:r.flatMap(({diagnostics:e})=>e),exitCode:+!r.every(({exitCode:e})=>e===0),machineOutcomes:r.flatMap(({machineOutcomes:e})=>e),name:e.name,tools:r.flatMap(({tools:e})=>e)}}catch(r){let i=String(r),a={durationMs:0,exitCode:1,name:e.name,unparsed:[i]};return t.format===`native`&&n.write(`${i}\n`),{diagnostics:[],exitCode:1,machineOutcomes:[{diagnostics:[],exitCode:1,tools:[a]}],name:e.name,tools:[a]}}}return t.scheduler.run(async()=>{if(Te(e,t.format))return{diagnostics:[],exitCode:await(H(e)?be(t.logStream,t.positionalArguments,t.optionFlags,e,t.nativeVerbose):xe(t.logStream,t.positionalArguments,t.optionFlags,e,t.cache,t.nativeVerbose)),machineOutcomes:[],name:e.name,tools:[]};let n=await Ce(t.logStream,t.positionalArguments,t.optionFlags,e,t.cache);return{diagnostics:n.diagnostics,exitCode:n.exitCode,machineOutcomes:[n],name:e.name,tools:n.tools}})}async function Me(e,t,n){if(!n||t.scheduler.concurrency===1){let n=[];for(let r of e)n.push(await X(r,t));return n}await Promise.resolve();let r=new Map;for(let[t,n]of e.entries()){let e=n.stage??0,i=r.get(e)??[];i.push({command:n,index:t}),r.set(e,i)}let i=Array.from({length:e.length}),a=r.keys().toArray().toSorted((e,t)=>e-t);for(let e of a){let n=r.get(e)??[],a=await Promise.all(n.map(async({command:e,index:n})=>({index:n,outcome:await X(e,t)})));for(let{index:e,outcome:t}of a)i[e]=t}return i.filter(e=>e!==void 0)}function Ne(e,t,n){let r=[],i=[];for(let e of t)n.length>0&&n.includes(G(e.name))?i.push(e):r.push(e);if(n.length>0){let r=new Set(i.map(e=>G(e.name))),a=n.filter(e=>!r.has(e));if(a.length>0){let n=t.map(e=>G(e.name)).join(`, `);e.write(`⚠️ ${E().yellow(`Unrecognized --skip ${z(`value`,a.length)}: ${a.join(`, `)}. Available: ${n}`)}\n`)}}return{commandsToRun:r,skippedCommands:i}}async function Z(e,t,n,r,i,a,o,s=`native`){let c=typeof s==`string`?{}:s,l=typeof s==`string`?s:c.format??`native`,{commandsToRun:u,skippedCommands:d}=Ne(e,r,o??[]),f=l===`native`&&i,{cache:p,scheduler:m}=await ke(c),h=await Me(u,{cache:p,format:l,logStream:e,nativeVerbose:f,optionFlags:n,positionalArguments:t,scheduler:m},c.parallel===!0),g=h.map(({exitCode:e,name:t})=>({exitCode:e,name:t})),_=h.flatMap(({tools:e})=>e),ee=h.flatMap(({diagnostics:e})=>e);if(l===`machine`)for(let t of h)for(let n of t.machineOutcomes)Ee(e,n);let v=r.length,y=E();if(l===`native`&&d.length>0){let t=d.map(({name:e})=>e),n=y.bold(`${t.length} / ${v} ${z(`Command`,t.length)} Skipped:`);e.write(`⏭️ ${y.dim(n)} ${y.dim(t.join(`, `))}\n`)}if(l===`native`&&a){let t=g.filter(({exitCode:e})=>e===0).map(({name:e})=>e),n=g.filter(({exitCode:e})=>e!==0).map(({name:e})=>e);if(t.length>0){let n=y.bold(`${t.length} / ${v} ${z(`Command`,t.length)} Succeeded:`);e.write(`✅ ${y.green(n)} ${y.green(t.join(`, `))}\n`)}if(n.length>0){let t=y.bold(`${n.length} / ${v} ${z(`Command`,n.length)} Failed:`);e.write(`❌ ${y.red(t)} ${y.red(n.join(`, `))}\n`)}}return{exitCode:+!g.every(({exitCode:e})=>e===0),report:l===`json`?de(_,ee):void 0}}async function Pe(e,t,n,a){let s=await u();if(s===void 0)throw Error("The `init` command must be used in a directory with a package.json file");let c=await u({cwd:l(import.meta.url)});if(c===void 0)return e.write(`Error: The script being called was not in a package, weird.
5
+ `),1;let d=o.join(o.dirname(c),`init`),f=o.dirname(s),p=(t===`file`||t===`package`)&&n!==void 0&&a!==void 0;try{if(p){let n=Object.keys(a)[0],i=r.readJsonSync(s);if(t===`package`){e.write(`Merging: \nPackage config key "${n}" → "${f}" (Because --location is set to "package")\n`);let t=j(i,a);r.writeJSONSync(s,t,{spaces:` `}),await I(s)}else n!==void 0&&Object.keys(i).includes(n)&&(e.write(`Deleting: \nPackage config key "${n}" in "${f}" (Because --location is set to "file")\n`),delete i[n],r.writeJSONSync(s,i,{spaces:` `}),await I(s))}if(!await r.pathExists(d))return 0;if((await r.readdir(d)).length===0)return e.write(`Source directory "${d}" is empty.\n`),0;e.write(`Adding initial configuration files from:\n"${d}" → "${f}"\n`),await r.copy(d,f,{async filter(a,s){let c=i.statSync(a).isFile(),l=i.existsSync(s);if(c){if(p&&t===`package`&&a.includes(n))return l?(e.write(`Deleting: \n"${a}" "${s}" (Because --location is set to "package")\n`),r.removeSync(s)):e.write(`Skipping: \n"${a}" → "${s}" (Because --location is set to "package")\n`),!1;if(l&&(s.includes(`.vscode/`)||s.includes(`package.json`))&&o.extname(s)===`.json`){e.write(`Merging: \n"${a}" → "${s}"\n`);let t=r.readJSONSync(a),n=r.readJSONSync(s),i=s.endsWith(`.vscode/tasks.json`)?he(n,t):j(n,t);return r.writeJSONSync(s,i,{spaces:` `}),await I(s),!1}return l?(e.write(`Overwriting: \n"${a}" "${s}"\n`),await I(s),!0):(e.write(`Copying: \n"${a}" "${s}"\n`),await I(s),!0)}return!0},overwrite:!0})}catch(e){return console.error(String(e)),1}return 0}async function Fe(e){let{commands:{fix:t,init:n,lint:r,printConfig:i},description:a,logColor:o,logPrefix:s,name:c,showSummary:l,verbose:u}=e;ie();let d=R(s,o);d.pipe(T());let m=f(p(process.argv)).scriptName(c).usage(`$0 <command>`,a);n!==void 0&&m.command({builder(e){let t=n.locationOptionFlag?e.option(`location`,{choices:[`file`,`package`],default:`file`,describe:`Where to store the configuration.`,type:`string`}):e;return l?q(t):t},command:`init`,describe:n.description??`Initialize by copying starter config files to your project root${n.locationOptionFlag?` or to your package.json file.`:`.`}`,async handler(e){let t=n.locationOptionFlag?e.location:void 0,r=K(e.skip),{exitCode:i}=await Z(d,[],t===void 0?[]:[`--location`,t],[{async execute(e,t,r){return Pe(e,r.at(1),n.configFile,n.configPackageJson)},name:`copyAndMergeInitFiles`},...n.commands??[]],void 0,void 0,r);process.exitCode=i}}),r!==void 0&&m.command({builder(e){let t=Y(J(r.positionalArgumentMode===`none`?e:e.positional(`files`,{array:!0,...r.positionalArgumentDefault!==void 0&&{default:r.positionalArgumentDefault},describe:`Files or glob pattern to lint.`,type:`string`})));return l?q(t):t},command:r.positionalArgumentMode===`none`?`lint`:r.positionalArgumentMode===`optional`?`lint [files..]`:`lint <files..>`,describe:r.description,async handler(e){let t=e.files??[],n=K(e.skip),i=C(),{exitCode:a,report:o}=await Z(d,t,[],await B(r.commands),u,l,n,{cache:e.cache,format:i,parallel:r.parallel});o!==void 0&&process.stdout.write(`${A(o)}\n`),process.exitCode=a}}),t!==void 0&&m.command({builder(e){let n=Y(J(t.positionalArgumentMode===`none`?e:e.positional(`files`,{array:!0,...t.positionalArgumentDefault!==void 0&&{default:t.positionalArgumentDefault},describe:`Files or glob pattern to fix.`,type:`string`})));return l?q(n):n},command:t.positionalArgumentMode===`none`?`fix`:t.positionalArgumentMode===`optional`?`fix [files..]`:`fix <files..>`,describe:t.description,async handler(e){let n=e.files??[],r=K(e.skip),i=C(),{exitCode:a,report:o}=await Z(d,n,[],await B(t.commands),void 0,void 0,r,{cache:e.cache,format:i,parallel:t.parallel});o!==void 0&&process.stdout.write(`${A(o)}\n`),process.exitCode=a}}),i!==void 0&&m.command({builder(e){let t=i.positionalArgumentMode===`none`?e:e.positional(`file`,{...i.positionalArgumentDefault!==void 0&&{default:i.positionalArgumentDefault},describe:`File or glob pattern to print configuration for.`,type:`string`});return l?q(t):t},command:i.positionalArgumentMode===`none`?`print-config`:i.positionalArgumentMode===`optional`?`print-config [file]`:`print-config <file>`,describe:i.description,async handler(e){let t=e.file??void 0,n=t===void 0?[]:[t],r=K(e.skip),{exitCode:a}=await Z(d,n,[],await B(i.commands),u,l,r);process.exitCode=a}}),m.alias(`h`,`help`),m.version(ne),m.alias(`v`,`version`),m.help(),m.wrap(process.stdout.isTTY?Math.min(120,m.terminalWidth()):0),await m.parseAsync()}async function Ie(n){let r=e(n,{loaders:{".ts":t()},searchStrategy:`project`});try{let e=await r.search();if(e===null){console.error(`No ${n} configuration found.`);return}return e}catch(e){console.error(`Error while searching for ${n} configuration:`,e);return}}const Q={fileRun:`Matches files below the current working directory by default.`,monorepoRun:`In a monorepo, it will also run in all packages below the current working directory.`,monorepoSearch:`Searches up to the root of a monorepo if necessary.`,multiArgumentCaveat:`Will use file arguments / globs where possible if provided, but some of the invoked tools only operate at the package scope.`,multiOptionCaveat:`Will use option flags where possible if provided, but some of the invoked tools will ignore them.`,optionalFileRun:`Package-scoped by default, file-scoped if a file argument is provided.`,packageRun:`Package-scoped.`,packageSearch:`Package-scoped.`},$=[`--ignore-path`,ge(`.gitignore`)??`.gitignore`,`--allow-empty-input`],Le=`**/*.{${[`css`,`scss`,`sass`,`svelte`,`html`,`astro`,`tsx`,`jsx`,`php`,`vue`].join(`,`)}}`;function Re(e){let t;try{t=JSON.parse(e.stderr)}catch{return{diagnostics:[],unparsed:[...O(e.stdout),...O(e.stderr)]}}let n=[];for(let r of t){let t=oe(r.source,e.cwd);for(let e of r.warnings){let r=e.rule===void 0?void 0:` (${e.rule})`,i=r!==void 0&&e.text.endsWith(r)?e.text.slice(0,-r.length):e.text;n.push({column:e.column,endColumn:e.endColumn,endLine:e.endLine,file:t,line:e.line,message:i,rule:e.rule,severity:e.severity===`warning`?`warning`:`error`,tool:`stylelint`})}let i=r.parseErrors??[];for(let e of i)n.push({column:e.column,file:t,line:e.line,message:e.text,rule:`parse-error`,severity:`error`,tool:`stylelint`})}return{diagnostics:n,unparsed:O(e.stdout)}}async function ze(e,t){let n=`stylelint`,r=await Ie(n);if(r===void 0)return 1;let{filepath:i,isEmpty:a}=r;if(a)return e.write(`Configuration is empty.
6
+ `),0;e.write(`Found ${n} configuration at "${i}"\n`);let s,[c]=t;c===void 0?s=F(`package-dir`):(s=o.join(process.cwd(),c),e.write(`Showing config for file at "${s}"\n`));let l=A(await te.resolveConfig(s)).split(`
7
+ `);for(let t of l)e.write(`${t}\n`);return 0}await Fe({commands:{fix:{commands:[{cache:{flags:[`--cache`,`--cache-strategy`,`content`],name:`stylelint`},collect:{optionFlags:[...$,`--fix`,`--formatter`,`json`],parse:Re},name:`stylelint`,optionFlags:[...$,`--fix`],receivePositionalArguments:!0}],description:`Fix your project with Stylelint. ${Q.fileRun}`,positionalArgumentDefault:Le,positionalArgumentMode:`optional`},init:{configFile:`stylelint.config.js`,configPackageJson:{stylelint:{extends:`@kitschpatrol/stylelint-config`}},locationOptionFlag:!0},lint:{commands:[{cache:{flags:[`--cache`,`--cache-strategy`,`content`],name:`stylelint`},collect:{optionFlags:[...$,`--formatter`,`json`],parse:Re},name:`stylelint`,optionFlags:$,receivePositionalArguments:!0}],description:`Lint your project with Stylelint. ${Q.fileRun}`,positionalArgumentDefault:Le,positionalArgumentMode:`optional`},printConfig:{commands:[{execute:ze,name:`stylelint-config`}],description:`Print the effective Stylelint configuration. ${Q.optionalFileRun}.`,positionalArgumentMode:`optional`}},description:`Kitschpatrol's Stylelint shared configuration tools.`,logColor:`greenBright`,logPrefix:`[Stylelint]`,name:`ksc-stylelint`,order:5});export{};
@@ -0,0 +1,73 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "tasks": [
4
+ {
5
+ "label": "ksc-stylelint lint",
6
+ "detail": "Lint your project with Stylelint.",
7
+ "type": "shell",
8
+ "command": "pnpm exec ksc-stylelint lint --format machine",
9
+ "options": {
10
+ "cwd": "${workspaceFolder}"
11
+ },
12
+ "presentation": {
13
+ "clear": true,
14
+ "echo": true,
15
+ "focus": false,
16
+ "panel": "dedicated",
17
+ "reveal": "silent",
18
+ "revealProblems": "onProblem",
19
+ "showReuseMessage": false
20
+ },
21
+ "problemMatcher": [
22
+ {
23
+ "owner": "ksc",
24
+ "source": "ksc",
25
+ "fileLocation": ["relative", "${workspaceFolder}"],
26
+ "pattern": {
27
+ "regexp": "^(.+?):(\\d+):(\\d+): (error|warning|info): (.+) \\[([^\\]]+)\\]$",
28
+ "file": 1,
29
+ "line": 2,
30
+ "column": 3,
31
+ "severity": 4,
32
+ "message": 5,
33
+ "code": 6
34
+ }
35
+ }
36
+ ]
37
+ },
38
+ {
39
+ "label": "ksc-stylelint fix",
40
+ "detail": "Fix your project with Stylelint.",
41
+ "type": "shell",
42
+ "command": "pnpm exec ksc-stylelint fix --format machine",
43
+ "options": {
44
+ "cwd": "${workspaceFolder}"
45
+ },
46
+ "presentation": {
47
+ "clear": true,
48
+ "echo": true,
49
+ "focus": false,
50
+ "panel": "dedicated",
51
+ "reveal": "silent",
52
+ "revealProblems": "onProblem",
53
+ "showReuseMessage": false
54
+ },
55
+ "problemMatcher": [
56
+ {
57
+ "owner": "ksc",
58
+ "source": "ksc",
59
+ "fileLocation": ["relative", "${workspaceFolder}"],
60
+ "pattern": {
61
+ "regexp": "^(.+?):(\\d+):(\\d+): (error|warning|info): (.+) \\[([^\\]]+)\\]$",
62
+ "file": 1,
63
+ "line": 2,
64
+ "column": 3,
65
+ "severity": 4,
66
+ "message": 5,
67
+ "code": 6
68
+ }
69
+ }
70
+ ]
71
+ }
72
+ ]
73
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitschpatrol/stylelint-config",
3
- "version": "8.1.0",
3
+ "version": "8.3.0",
4
4
  "description": "Stylelint configuration for @kitschpatrol/shared-config.",
5
5
  "keywords": [
6
6
  "stylelint-config",
@@ -46,7 +46,7 @@
46
46
  "cosmiconfig-typescript-loader": "^6.3.0",
47
47
  "decircular": "^1.0.0",
48
48
  "deepmerge": "^4.3.1",
49
- "execa": "^9.6.1",
49
+ "execa": "^10.0.0",
50
50
  "find-workspaces": "^0.3.1",
51
51
  "fs-extra": "^11.3.6",
52
52
  "json-stringify-pretty-compact": "^4.0.0",
package/readme.md CHANGED
@@ -181,10 +181,12 @@ ksc-stylelint lint [files..]
181
181
  | ------------------- | ------------------------------ | ------- | ---------------------------------------------------------- |
182
182
  | `files` | Files or glob pattern to lint. | `array` | `"**/*.{css,scss,sass,svelte,html,astro,tsx,jsx,php,vue}"` |
183
183
 
184
- | Option | Description | Type |
185
- | ------------------- | ------------------- | --------- |
186
- | `--help`<br>`-h` | Show help | `boolean` |
187
- | `--version`<br>`-v` | Show version number | `boolean` |
184
+ | Option | Description | Type | Default |
185
+ | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ---------- |
186
+ | `--format` | Output format: "native" streams each tool's own output, "machine" prints one parseable line per issue for editor problem matchers, "json" prints an aggregate report. | `"json"` `"machine"` `"native"` | `"native"` |
187
+ | `--cache` | Use tool-native caches stored below node\_modules/.cache/ksc at the workspace root. Disable with --no-cache. | `boolean` | `true` |
188
+ | `--help`<br>`-h` | Show help | `boolean` | |
189
+ | `--version`<br>`-v` | Show version number | `boolean` | |
188
190
 
189
191
  #### Subcommand: `ksc-stylelint fix`
190
192
 
@@ -200,10 +202,12 @@ ksc-stylelint fix [files..]
200
202
  | ------------------- | ----------------------------- | ------- | ---------------------------------------------------------- |
201
203
  | `files` | Files or glob pattern to fix. | `array` | `"**/*.{css,scss,sass,svelte,html,astro,tsx,jsx,php,vue}"` |
202
204
 
203
- | Option | Description | Type |
204
- | ------------------- | ------------------- | --------- |
205
- | `--help`<br>`-h` | Show help | `boolean` |
206
- | `--version`<br>`-v` | Show version number | `boolean` |
205
+ | Option | Description | Type | Default |
206
+ | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ---------- |
207
+ | `--format` | Output format: "native" streams each tool's own output, "machine" prints one parseable line per issue for editor problem matchers, "json" prints an aggregate report. | `"json"` `"machine"` `"native"` | `"native"` |
208
+ | `--cache` | Use tool-native caches stored below node\_modules/.cache/ksc at the workspace root. Disable with --no-cache. | `boolean` | `true` |
209
+ | `--help`<br>`-h` | Show help | `boolean` | |
210
+ | `--version`<br>`-v` | Show version number | `boolean` | |
207
211
 
208
212
  #### Subcommand: `ksc-stylelint print-config`
209
213
 
@@ -226,6 +230,26 @@ ksc-stylelint print-config [file]
226
230
 
227
231
  <!-- /cli-help -->
228
232
 
233
+ ### VS Code tasks
234
+
235
+ `ksc-stylelint init` adds a `.vscode/tasks.json` with two tasks:
236
+
237
+ - **`ksc-stylelint lint`** runs `ksc-stylelint lint --format machine` across the whole project
238
+ - **`ksc-stylelint fix`** runs `ksc-stylelint fix --format machine`, applying auto-fixes and reporting whatever couldn't be fixed
239
+
240
+ If you're using the complete [@kitschpatrol/shared-config](https://github.com/kitschpatrol/shared-config) package, you'd more likely want to run:
241
+
242
+ - **`ksc lint`** runs `ksc lint --format machine`, which runs all `ksc lint` tools across the whole project
243
+ - **`ksc fix`** runs `ksc fix --format machine`, which applies all `ksc fix` auto-fixes and reports anything unfixable
244
+
245
+ Run them via the _Tasks: Run Task_ command (or the _Terminal → Run Task…_ menu item).
246
+
247
+ Each task's problem matcher parses the machine-format output and populates VS Code's [Problems panel](https://code.visualstudio.com/docs/debugtest/debugging#_errors-and-warnings) with every reported issue, pointing to the offending file, line, and column.
248
+
249
+ The tasks share a problem matcher owner with the other `@kitschpatrol/shared-config` tasks, so the panel reflects the most recent run rather than stacking duplicates.
250
+
251
+ If your project already has a `.vscode/tasks.json`, `init` merges by task label: your own tasks are left alone, and same-label tasks are replaced with the latest definitions.
252
+
229
253
  ### API
230
254
 
231
255
  The package also exports `fix`, `fixFile` functions for linting and fixing CSS programmatically, pre-configured with the shared Stylelint configuration.