@kitschpatrol/shared-config 8.13.1 → 8.14.1
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 +13 -12
- package/dist/index.d.ts +0 -2
- package/package.json +21 -21
- package/readme.md +18 -3
- package/skills/mdat/SKILL.md +140 -0
- package/skills/mdat-plugin-authoring/SKILL.md +177 -0
package/bin/cli.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
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,{constants as a}from"node:fs";import{availableParallelism as o}from"node:os";import s from"node:path";import{PassThrough as c,Transform as l}from"node:stream";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
|
|
3
|
-
`);try{return await r.execute(a,t,n)}catch(e){return console.error(String(e)),1}}function
|
|
4
|
-
`);for(let e of t)l.write(`${e}\n`)}s=t.exitCode??1}catch(e){console.error(`${i.name} failed with error:`),console.error(e),
|
|
5
|
-
`),1;let l=s.dirname(o),d=(t===`file`||t===`package`)&&n!==void 0&&a!==void 0;try{if(d){let n=Object.keys(a)[0],i=r.readJsonSync(o);if(t===`package`){e.write(`Merging: \nPackage config key "${n}" → "${l}" (Because --location is set to "package")\n`);let t=
|
|
6
|
-
`),0;let o=
|
|
7
|
-
`);for(let e of o)t.write(`${e}\n`);return 0},name:`Cosmiconfig ${e}`}}async function
|
|
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,{constants as a}from"node:fs";import{availableParallelism as o}from"node:os";import s from"node:path";import{PassThrough as c,Transform as l}from"node:stream";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{findWorkspaces as y,findWorkspacesRoot as te}from"find-workspaces";import b,{access as ne}from"node:fs/promises";import{getDefaultConfigLoader as x,resolveConfigFileImports as re}from"cspell-lib";import{fileURLToPath as S}from"node:url";import{createReaderWriter as ie}from"cspell-config-lib";import{loadFile as ae,writeFile as oe}from"magicast";import{getDefaultExportOptions as se}from"magicast/helpers";import{lint as ce}from"cspell";import"deepmerge-ts";import{loadConfig as le}from"mdat";import{globby as ue}from"globby";import C,{gt as de,minVersion as fe}from"semver";import{readWantedLockfile as pe}from"@pnpm/lockfile.fs";import me from"stylelint";var he=`8.14.1`;const ge=[`json`,`machine`,`native`],_e=ge;function ve(e){return typeof e==`string`&&ge.includes(e)}function w(){let e=process.env.KSC_FORMAT;return ve(e)?e:`native`}function ye(){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)),ve(r)&&(process.env.KSC_FORMAT=r)}}function be(){let{env:e}=process;return e.NO_COLOR!==void 0&&e.NO_COLOR!==``?!1:e.FORCE_COLOR===void 0?e.TERM!==`dumb`&&void 0:e.FORCE_COLOR!==`0`&&e.FORCE_COLOR!==`false`}function T(e,{ciColor:t=!0}={}){return be()??(e.isTTY===!0||t&&!!process.env.CI)}function E(){return w()===`json`?process.stderr:process.stdout}function D(){return m.createColors(w()!==`machine`&&T(E()))}function xe(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 O(e,t){let n=s.isAbsolute(e)?e:s.resolve(t,e),r=s.relative(process.cwd(),n);return r===``?`.`:r}const Se=/\s*\n\s*/gv,Ce=/\r?\n/v;function we(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 Te(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 Ee(e,t){let n=t.toSorted(Te);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 k(e){return h(e).split(Ce).map(e=>e.trimEnd()).filter(e=>e.trim().length>0)}function De(e){return e instanceof Error&&`exitCode`in e&&typeof e.exitCode==`number`}function A(e){return T(process.stdout,{ciColor:!1})?ke(e):Oe(e)}function Oe(e){return v(_(e),{indent:2,replacer(e,t){return typeof t==`function`?t.name:t}})}function ke(e){return g(Oe(e),{colors:{BRACKET:`gray`}})}const Ae=(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]=je(e[i],a,n):e.includes(a)||r.push(a);return r};function je(e,t,n={arrayMerge:Ae}){return ee(e,t,n)}function Me(e){let{tasks:t}=e;return Array.isArray(t)?t:[]}function Ne(e,t){let n=[...Me(e)];for(let e of Me(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 Pe(e,t){return e.startsWith(t+s.sep)}function j(){let e=M(),t=/* @__PURE__ */ new Set([e]),n=y();if(n!==null)for(let r of n){let n=s.resolve(r.location);Pe(n,e)&&t.add(n)}return[...t]}function M(){let e=d();if(e===void 0)throw Error(`No package.json found.`);return s.dirname(e)}function Fe(){return te()!==null}function N(){let e=te();return e===null?M():s.resolve(e.location)}function P(e){let t=s.join(N(),e);return r.existsSync(t)?t:void 0}function F(e){if(e===`workspace-root`)return N();if(e===`package-dir`)return M();if(typeof e==`string`){if(!r.pathExistsSync(e))throw Error(`Custom cwd directory does not exist: ${e}`);return e}return process.cwd()}async function Ie(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 Ie(e,await b.readFile(e,`utf8`))}catch{}}const Le=/\r?\n/v;function Re(e){let t=``,n=t=>t.filter(t=>{let n=h(t);return n.trim()!==``&&!e(n)}).map(e=>`${e}\n`).join(``);return new l({flush(e){e(void 0,n([t]))},transform(e,r,i){let a=(t+e.toString()).split(Le);t=a.pop()??``,i(void 0,n(a))}})}function L(e,t){let n=w()===`native`?e:void 0,r=n===void 0||n===``?``:t===void 0?n:D()[t](n),i=``,a=e=>e.filter(e=>e.trim().length>0).map(e=>r===``?`${e}\n`:`${r} ${e}\n`).join(``);return new l({flush(e){e(void 0,a([i]))},transform(e,t,n){let r=(i+e.toString()).split(Le);i=r.pop()??``,n(void 0,a(r))}})}async function ze(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 Be(e){return e.replaceAll(/[A-Z\u{C0}-\u{D6}\u{D8}-\u{DE}]/gv,e=>`-`+e.toLowerCase())}function R(e,t){return t===1?e:e+`s`}async function z(e){return typeof e==`function`?e():e}async function Ve(e,t,n,r,i){let a;if(r.logPrefix===void 0)a=e;else{let t=L(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)}"`)+`
|
|
3
|
+
`);try{return await r.execute(a,t,n)}catch(e){return console.error(String(e)),1}}function He(e,t,n,r,i){return[...e.subcommands??[],...e.receiveOptionFlags?n:[],...r??[],...i&&e.cache!==void 0?[...e.cache.flags,`--cache-location`,s.join(N(),`node_modules`,`.cache`,`ksc`,e.cache.name)]:[],...e.receivePositionalArguments?t:[],...e.positionalArguments??[]]}async function Ue(e,t,r,i,a,o){let s=1,l;if(i.logPrefix===void 0)l=e;else{let t=L(i.logPrefix,i.logColor);t.pipe(e),l=t}let u=He(i,t,r,i.optionFlags,a),d=F(i.cwdOverride);o&&l.write(`Running: "${i.name} ${u.join(` `)}"\n`);let f=i.prettyJsonOutput?new c:void 0,p=f??l,m=xe(w()===`native`&&i.prettyJsonOutput!==!0&&T(E()));try{let e=n(i.name,u,{cwd:d,env:m,preferLocal:!0,reject:!1,stdin:`inherit`});if(i.outputFilter){let t=Re(i.outputFilter),n=Re(i.outputFilter);e.stdout.pipe(t).pipe(p,{end:!1}),e.stderr.pipe(n).pipe(p,{end:!1})}else e.stdout.pipe(p,{end:!1}),e.stderr.pipe(p,{end:!1});let t=await e;if(f!==void 0){f.end();let e=await ze(f),t=A(JSON.parse(e)).split(`
|
|
4
|
+
`);for(let e of t)l.write(`${e}\n`)}s=t.exitCode??1}catch(e){console.error(`${i.name} failed with error:`),console.error(e),De(e)&&(s=typeof e.exitCode==`number`?e.exitCode:1)}return s}function B(e){return`execute`in e}function V(e){return`kind`in e}async function We(e,t,r,i,a){let o=He(r,e,t,r.collect?.optionFlags??r.optionFlags,i),s=F(r.cwdOverride);try{let e=n(r.name,o,{cwd:s,env:xe(!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:De(e)&&typeof e.exitCode==`number`?e.exitCode:1,stderr:``,stdout:``}}}function Ge(e){return typeof e==`object`&&!!e&&`version`in e&&e.version===1&&`diagnostics`in e&&Array.isArray(e.diagnostics)&&`success`in e&&typeof e.success==`boolean`&&`tools`in e&&Array.isArray(e.tools)}function Ke(e,t){return e===0&&t.some(({severity:e})=>e===`error`)?1:e}async function qe(e,t,n,r,i){let a=Date.now(),o=()=>Date.now()-a;if(B(r)){if(r.collect!==void 0)try{let e=await r.collect(t,n),i=Ke(e.exitCode,e.diagnostics);return{diagnostics:e.diagnostics,exitCode:i,tools:[{durationMs:o(),exitCode:i,name:r.name,unparsed:e.unparsed}]}}catch(e){return{diagnostics:[],exitCode:1,tools:[{durationMs:o(),exitCode:1,name:r.name,unparsed:[String(e)]}]}}let e=``,i=new c;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:k(e)}]}}if(V(r))throw Error(`Command groups must be expanded before collection`);if(r.outputFormatAware){let a=await We(t,n,r,i,e);try{let e=JSON.parse(a.stdout);if(!Ge(e))throw Error(`Child output is not a lint report`);return{diagnostics:e.diagnostics,exitCode:a.exitCode===0&&e.success&&e.diagnostics.every(({severity:e})=>e!==`error`)?0:1,tools:e.tools}}catch{return{diagnostics:[],exitCode:a.exitCode,tools:[{durationMs:o(),exitCode:a.exitCode,name:r.name,unparsed:k(a.stdout)}]}}}let s=await We(t,n,r,i);if(r.collect!==void 0)try{let{diagnostics:e,unparsed:t}=r.collect.parse(s),n=Ke(s.exitCode,e);return{diagnostics:e,exitCode:n,tools:[{durationMs:o(),exitCode:n,name:r.name,unparsed:t}]}}catch(e){return{diagnostics:[],exitCode:s.exitCode,tools:[{durationMs:o(),exitCode:s.exitCode,name:r.name,unparsed:[...k(s.stdout),...k(s.stderr),String(e)]}]}}return{diagnostics:[],exitCode:s.exitCode,tools:[{durationMs:o(),exitCode:s.exitCode,name:r.name,unparsed:[...k(s.stdout),...k(s.stderr)]}]}}const Je=/^ksc-/v;function H(e){return e.replace(Je,``)}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`})}function Ye(e){return e.option(`format`,{choices:_e,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 Xe(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 Ze(e,t){return t===`native`||t===`machine`&&!B(e)&&!V(e)&&e.outputFormatAware===!0}function Qe(e,t){for(let n of t.diagnostics)e.write(`${we(n)}\n`);for(let n of t.tools)for(let t of n.unparsed)e.write(`${t}\n`)}function $e(){return Math.min(4,o())}var et=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 tt(e){let t=e.cache??!1,n=e.concurrency??$e();if(!Number.isInteger(n)||n<1)throw Error(`Concurrency must be a positive integer.`);return t&&await r.ensureDir(s.join(N(),`node_modules`,`.cache`,`ksc`)),{cache:t,scheduler:new et(n)}}const nt=/[*?\[\]\{\}]/v,rt=/[!\(\)*+?@\[\\\]\{\|\}]/gv,it=/\/+$/v;function at(e,t){if(t===void 0)return e;let n=t.length===1?t[0]:`{${t.join(`,`)}}`;return e.flatMap(e=>i.statSync(e,{throwIfNoEntry:!1})?.isDirectory()===!0?`${e.split(s.sep).join(`/`).replace(it,``).replaceAll(rt,String.raw`\$&`)}/**/*.${n}`:nt.test(e)||t.includes(s.extname(e).slice(1).toLowerCase())?e:[])}function ot(e,t){return e.length===0||at(e,t).length>0}function st(e,t){return e.positionalArgumentMode===`none`?[]:t.length>0?at(t,e.positionalArgumentExtensions):e.positionalArgumentDefault===void 0?[]:[e.positionalArgumentDefault]}function ct(e,t){if(t.logPrefix===void 0)return e;let n=L(t.logPrefix,t.logColor);return n.pipe(e),n}function lt(e){return V(e)?`${e.name} ${e.subcommand}`:B(e)||e.subcommands===void 0?e.name:[e.name,...e.subcommands].join(` `)}async function ut(e,t){if(V(e)){let n=ct(t.logStream,e);try{let r=await z(e.commands);if(t.nativeVerbose){let n=[e.subcommand,...t.positionalArguments].join(` `),i=e.showResolvedCommands?` (${r.map(e=>lt(e)).join(`, `)})`:``;t.logStream.write(`Running: "${e.name} ${n}"${i}\n`)}let i=await dt(r,{...t,logStream:n,nativeVerbose:e.verbose,positionalArguments:st(e,t.positionalArguments)},e.parallel===!0);return{diagnostics:i.flatMap(({diagnostics:e})=>e),exitCode:+!i.every(({exitCode:e})=>e===0),machineOutcomes:i.flatMap(({machineOutcomes:e})=>e),name:e.name,tools:i.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(Ze(e,t.format))return{diagnostics:[],exitCode:await(B(e)?Ve(t.logStream,t.positionalArguments,t.optionFlags,e,t.nativeVerbose):Ue(t.logStream,t.positionalArguments,t.optionFlags,e,t.cache,t.nativeVerbose)),machineOutcomes:[],name:e.name,tools:[]};let n=await qe(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 dt(e,t,n){if(!n||t.scheduler.concurrency===1){let n=[];for(let r of e)n.push(await ut(r,t));return n}await Promise.resolve();let r=/* @__PURE__ */ 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 ut(e,t)})));for(let{index:e,outcome:t}of a)i[e]=t}return i.filter(e=>e!==void 0)}function ft(e,t,n,r,i){let a=[],o=[],s=ot(r,i);for(let e of t){let t=!V(e)||ot(r,e.positionalArgumentExtensions);!s||!t||n.includes(H(e.name))?o.push(e):a.push(e)}if(n.length>0){let r=new Set(o.map(e=>H(e.name))),i=n.filter(e=>!r.has(e));if(i.length>0){let n=t.map(e=>H(e.name)).join(`, `);e.write(`⚠️ ${D().yellow(`Unrecognized --skip ${R(`value`,i.length)}: ${i.join(`, `)}. Available: ${n}`)}\n`)}}return{commandsToRun:a,skippedCommands:o}}async function G(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}=ft(e,r,o??[],t,c.positionalArgumentExtensions),f=l===`native`&&i,{cache:p,scheduler:m}=await tt(c),h=await dt(u,{cache:p,format:l,logStream:e,nativeVerbose:f,optionFlags:n,positionalArguments:at(t,c.positionalArgumentExtensions),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)Qe(e,n);let v=r.length,y=D();if(l===`native`&&d.length>0){let t=d.map(({name:e})=>e),n=y.bold(`${t.length} / ${v} ${R(`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} ${R(`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} ${R(`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`?Ee(_,ee):void 0}}async function pt(e){let t=await u({cwd:e});return t===void 0?void 0:s.join(s.dirname(t),`init`)}async function mt(e,t,n,a){let o=await u();if(o===void 0)throw Error("The `init` command must be used in a directory with a package.json file");let c=await pt(import.meta.dirname);if(c===void 0)return e.write(`Error: Could not locate the package containing this CLI.
|
|
5
|
+
`),1;let l=s.dirname(o),d=(t===`file`||t===`package`)&&n!==void 0&&a!==void 0;try{if(d){let n=Object.keys(a)[0],i=r.readJsonSync(o);if(t===`package`){e.write(`Merging: \nPackage config key "${n}" → "${l}" (Because --location is set to "package")\n`);let t=je(i,a);r.writeJSONSync(o,t,{spaces:` `}),await I(o)}else n!==void 0&&Object.keys(i).includes(n)&&(e.write(`Deleting: \nPackage config key "${n}" in "${l}" (Because --location is set to "file")\n`),delete i[n],r.writeJSONSync(o,i,{spaces:` `}),await I(o))}if(!await r.pathExists(c))return 0;if((await r.readdir(c)).length===0)return e.write(`Source directory "${c}" is empty.\n`),0;e.write(`Adding initial configuration files from:\n"${c}" → "${l}"\n`),await r.copy(c,l,{async filter(a,o){let c=i.statSync(a).isFile(),l=i.existsSync(o);if(c){if(d&&t===`package`&&a.includes(n))return l?(e.write(`Deleting: \n"${a}" → "${o}" (Because --location is set to "package")\n`),r.removeSync(o)):e.write(`Skipping: \n"${a}" → "${o}" (Because --location is set to "package")\n`),!1;if(l&&(o.includes(`.vscode/`)||o.includes(`package.json`))&&s.extname(o)===`.json`){e.write(`Merging: \n"${a}" → "${o}"\n`);let t=r.readJSONSync(a),n=r.readJSONSync(o),i=o.endsWith(`.vscode/tasks.json`)?Ne(n,t):je(n,t);return r.writeJSONSync(o,i,{spaces:` `}),await I(o),!1}return l?(e.write(`Overwriting: \n"${a}" → "${o}"\n`),await I(o),!0):(e.write(`Copying: \n"${a}" → "${o}"\n`),await I(o),!0)}return!0},overwrite:!0})}catch(e){return console.error(String(e)),1}return 0}async function ht(e){let{commands:{fix:t,init:n,lint:r,printConfig:i},description:a,logColor:o,logPrefix:s,name:c,showSummary:l,verbose:u}=e;ye();let d=L(s,o);d.pipe(E());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),{exitCode:i}=await G(d,[],t===void 0?[]:[`--location`,t],[{async execute(e,t,r){return mt(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=Xe(Ye(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=w(),{exitCode:a,report:o}=await G(d,t,[],await z(r.commands),u,l,n,{cache:e.cache,format:i,parallel:r.parallel,positionalArgumentExtensions:r.positionalArgumentExtensions});o!==void 0&&process.stdout.write(`${A(o)}\n`),process.exitCode=a}}),t!==void 0&&m.command({builder(e){let n=Xe(Ye(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=w(),{exitCode:a,report:o}=await G(d,n,[],await z(t.commands),void 0,void 0,r,{cache:e.cache,format:i,parallel:t.parallel,positionalArgumentExtensions:t.positionalArgumentExtensions});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?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),{exitCode:a}=await G(d,n,[],await z(i.commands),u,l,r);process.exitCode=a}}),m.alias(`h`,`help`),m.version(he),m.alias(`v`,`version`),m.help(),m.wrap(process.stdout.isTTY?Math.min(120,m.terminalWidth()):0),await m.parseAsync()}function K(e){return{async execute(t){let n=await q(e);if(n===void 0)return 1;let{config:r,filepath:i,isEmpty:a}=n;if(t.write(`Found ${e} configuration at "${i}"\n`),a)return t.write(`Configuration is empty.
|
|
6
|
+
`),0;let o=A(r).split(`
|
|
7
|
+
`);for(let e of o)t.write(`${e}\n`);return 0},name:`Cosmiconfig ${e}`}}async function q(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 J={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.`},gt=/['\u{2019}\u{2018}]s$/v;async function _t(e=[`.`]){let t=await x().searchForConfigFile(void 0);if(t===void 0)throw Error(`No CSpell configuration found.`);let{settings:n,url:r}=t;if(n.words===void 0||n.words.length===0)return{errors:0,filesChecked:0,unusedWords:[]};let i=[...n.words];delete n.words;let a=await ce(e,{config:{settings:n,url:r},progress:!1,unique:!0,wordsOnly:!0},{issue({text:e,uri:t}){i=i.filter(n=>n.toLowerCase()!==e.toLowerCase().replace(gt,``)||t===r.href)}});return{errors:a.errors,filesChecked:a.files,unusedWords:i}}const vt=/* @__PURE__ */ new Set([`.cjs`,`.cts`,`.js`,`.mjs`,`.mts`,`.ts`]);async function yt(e=[`**/*`]){let t=await x().searchForConfigFile(void 0);if(t===void 0)throw Error(`No CSpell configuration found.`);let n=S(t.url),r=[...t.settings.words??[]];if(r.length===0)return;let{errors:i,filesChecked:a,unusedWords:o}=await _t(e);if(a===0||i>0)throw Error(`Refusing to modify "${n}": CSpell checked ${a} files with ${i} errors, so word usage can't be determined. Check your file globs and configuration.`);let s=new Set(o),c=r.filter(e=>!s.has(e)),l=bt([...new Set(c)]);return xt(l,r)?{configFilePath:n,removedWords:[],reordered:!1}:(await St(t.url,l),{configFilePath:n,removedWords:[...s],reordered:!xt(l,c)})}function bt(e){return e.toSorted((e,t)=>{let n=e.toLowerCase().localeCompare(t.toLowerCase());return n===0?e.localeCompare(t):n})}function xt(e,t){return e.length===t.length&&e.every((e,n)=>e===t[n])}async function St(e,t){let n=S(e),r=s.extname(n).toLowerCase();if(vt.has(r)){let e=await ae(n),r=se(e);r.words=t,await oe(e,n),await I(n);return}let i=ie(),a=await i.readConfig(e);if(a.readonly)throw Error(`CSpell configuration file "${n}" can't be modified automatically. Please update the words list manually.`);a.setValue(`words`,t),await i.writeConfig(a)}const Ct=`**/*`;function wt(e){return e.length===0||e.length===1&&e[0]===Ct}async function Tt(){let e=await x().searchForConfigFile(void 0);return e===void 0?void 0:S(e.url)}async function Et(){let e=await x().searchForConfigFile(void 0);if(e===void 0)throw Error(`No CSpell configuration found.`);let t=await re(e);return t.ignorePaths===void 0?``:Array.from(t.ignorePaths,e=>typeof e==`string`?e:e.glob).join(`,`)}const Dt=/^(?<file>.+?):(?<line>\d+):(?<column>\d+) - (?<message>.+)$/v,Ot=/ fix: \((?<suggestion>[^\)]+)\)$/v;function kt(e){let t=[],n=[];for(let r of k(`${e.stdout}\n${e.stderr}`)){let i=Dt.exec(r);if(i?.groups===void 0){n.push(r);continue}let{column:a,file:o=``,line:s,message:c=``}=i.groups,l=Ot.exec(c),u=l?.groups?.suggestion;t.push({column:Number(a),file:O(o,e.cwd),line:Number(s),message:l===null?c:c.slice(0,-l[0].length),...u!==void 0&&{suggestion:u},severity:`warning`,tool:`cspell`})}return{diagnostics:t,unparsed:n}}async function At(e,t){if(!wt(t))return 0;let{errors:n,filesChecked:r,unusedWords:i}=await _t(t);if(n>0||r===0&&i.length>0){let t=L(`[Unused Words]`,`cyanBright`);return t.pipe(e),t.write(`Could not check for unused words: CSpell checked ${r} files with ${n} errors.\n`),1}if(i.length>0){let t=L(`[Unused Words]`,`cyanBright`);t.pipe(e);for(let e of i)t.write(`${e}\n`);return 1}return 0}async function jt(e){if(!wt(e))return{diagnostics:[],exitCode:0,unparsed:[]};let{errors:t,filesChecked:n,unusedWords:r}=await _t(e);if(t>0||n===0&&r.length>0)return{diagnostics:[{message:`Could not check for unused words: CSpell checked ${n} files with ${t} errors`,severity:`error`,tool:`unused-words`}],exitCode:1,unparsed:[]};let i=await Tt(),a=i===void 0?{}:{file:O(i,process.cwd())};return{diagnostics:r.map(e=>({...a,message:`Unused word in CSpell config "words" array: ${e}`,severity:`warning`,tool:`unused-words`})),exitCode:+(r.length>0),unparsed:[]}}async function Mt(e,t){let n=L(`[Words]`,`cyanBright`);if(n.pipe(e),!wt(t))return n.write(`Skipping unused word removal because file arguments were provided. Run without file arguments to remove unused words.
|
|
8
8
|
`),0;let r=await yt(t);if(r===void 0)return 0;for(let e of r.removedWords)n.write(`Removed unused word: ${e}\n`);return r.reordered&&n.write(`Sorted the "words" array alphabetically.
|
|
9
|
-
`),0}async function Nt(){let e=import.meta.resolve(`@kitschpatrol/cspell-config`),t=await u({cwd:s.dirname(
|
|
10
|
-
`);for(let t of n)e.write(`${t}\n`);return 0}const Lt={commands:{fix:{async commands(){return[{collect:{parse:Ft},logColor:`cyanBright`,logPrefix:`[Case Police]`,name:`case-police`,optionFlags:[`--fix`,`--dict`,await Nt(),`--ignore`,await Et()],outputFilter:e=>!e.includes(`→`),receivePositionalArguments:!0},{execute:Mt,name:`words`},{cache:{flags:[`--cache`,`--cache-strategy`,`content`],name:`cspell`},collect:{parse:kt},name:`cspell`,optionFlags:[`--quiet`],receivePositionalArguments:!0}]},description:`Fix letter casing issues, remove unused words from the local CSpell configuration's "words" array, and report remaining (unfixable) spelling errors. ${
|
|
11
|
-
`);for(let t of r)e.write(`${t}\n`);return 0}async function Xt(e){let t=A(),n=await Jt(),r=[];for(let i of t)r.push({cwdOverride:i,name:`mdat`,optionFlags:n===void 0||n===``?[`--format`]:[`--config`,n,`--format`],subcommands:[e]});return r}const Zt={commands:{fix:{commands:await Xt(`expand`),description:`Expand all Mdat content placeholders in your readme.md file(s). ${K.packageRun} ${K.monorepoRun}`,parallel:!0,positionalArgumentMode:`none`},init:{configFile:`mdat.config.ts`,configPackageJson:{mdat:{$import:`node_modules/@kitschpatrol/mdat-config/dist/index.js`}},locationOptionFlag:!0},lint:{commands:await Xt(`check`),description:`Validate that all Mdat content placeholders in your readme.md file(s) have been expanded and are up to date. ${K.packageRun} ${K.monorepoRun}`,parallel:!0,positionalArgumentMode:`none`},printConfig:{commands:[{execute:Yt,name:`mdat-config`}],description:`Print the effective Mdat configuration. ${K.packageSearch}. ${K.monorepoSearch}.`,positionalArgumentMode:`none`}},description:`Kitschpatrol's Mdat shared configuration tools.`,logColor:`green`,logPrefix:`[Mdat Config]`,name:`ksc-mdat`,order:2},Qt=/^\[warn\] (?<file>\S+)$/v,$t=/^\[error\] (?<message>.+)$/v;function en(e){let t=[],n=[];for(let r of D(`${e.stdout}\n${e.stderr}`)){let i=Qt.exec(r);if(i?.groups?.file!==void 0){t.push({file:E(i.groups.file,e.cwd),message:`File is not formatted with Prettier`,severity:`warning`,tool:`prettier`});continue}if(r.startsWith(`[warn] Code style issues found`))continue;let a=$t.exec(r);if(a?.groups?.message!==void 0){t.push({message:a.groups.message,severity:`error`,tool:`prettier`});continue}n.push(r)}return{diagnostics:t,unparsed:n}}const tn=[`--log-level=warn`,`--ignore-unknown`,`--plugin=prettier-plugin-astro`,`--plugin=@prettier/plugin-php`,`--plugin=@prettier/plugin-ruby`,`--plugin=@prettier/plugin-xml`,`--plugin=prettier-plugin-jsdoc`,`--plugin=prettier-plugin-packagejson`,`--plugin=prettier-plugin-sh`,`--plugin=prettier-plugin-svelte`,`--plugin=prettier-plugin-toml`,`--plugin=prettier-plugin-tailwindcss`,`--ignore-path=${Le(`.gitignore`)??`.gitignore`}`,`--ignore-path=${Le(`.prettierignore`)??`.prettierignore`}`],nn={commands:{fix:{commands:[{cache:{flags:[`--cache`,`--cache-strategy`,`content`],name:`prettier`},collect:{parse:en},name:`prettier`,optionFlags:[...tn,`--write`],receivePositionalArguments:!0}],description:`Format files according to your Prettier configuration. ${K.fileRun}`,positionalArgumentDefault:`.`,positionalArgumentMode:`optional`},init:{configFile:`prettier.config.ts`,configPackageJson:{prettier:`@kitschpatrol/prettier-config`},locationOptionFlag:!0},lint:{commands:[{cache:{flags:[`--cache`,`--cache-strategy`,`content`],name:`prettier`},collect:{parse:en},name:`prettier`,optionFlags:[...tn,`--check`],receivePositionalArguments:!0}],description:`Check that files are formatted according to your Prettier configuration. ${K.fileRun}`,positionalArgumentDefault:`.`,positionalArgumentMode:`optional`},printConfig:{commands:[W(`prettier`)],description:`Print the effective Prettier configuration. ${K.packageSearch}. ${K.monorepoSearch}.`,positionalArgumentMode:`none`}},description:`Kitschpatrol's Prettier shared configuration tools.`,logColor:`blue`,logPrefix:`[Prettier]`,name:`ksc-prettier`,order:9},rn={commands:{init:{configFile:`.remarkrc.js`,configPackageJson:{remarkConfig:{plugins:[`@kitschpatrol/remark-config`]}},locationOptionFlag:!0},printConfig:{commands:[W(`remark`)],description:`Print the effective Remark configuration. ${K.packageSearch} ${K.monorepoSearch}`,positionalArgumentMode:`none`}},description:`Kitschpatrol's Remark and Remark Lint shared configuration tools. (Actual linting and fixing is managed through @kitschpatrol/eslint-config.)`,logColor:`blue`,logPrefix:`[remarklint]`,name:`ksc-remark`,order:8},an=[/Version 2\.0,?\s*January 2004/gv,/Version 1,?\s*February 1989/gv,/Version 2,?\s*June 1991/gv,/Version 3,?\s*29 June 2007/gv,/Version 2\.1,?\s*February 1999/gv,/Version 3,?\s*19 November 2007/gv,/Version 1\.0\s*-\s*August 17th,?\s*2003/gv,/Version 1\.1,?\s*March 2000/gv,/Version 1\.2,?\s*November 2002/gv,/Version 1\.3,?\s*3 November 2008/gv,/Version 1\.0\s*-\s*22 November 2005/gv,/Version 1\.1\s*-\s*26 February 2007/gv,/Version 2,?\s*December 2004/gv,/20 December 1996/gv,/December 20,?\s*1996/gv,/11 March 1996/gv,/28 March 2007/gv,/November 1,?\s*2008/gv,/August 1,?\s*2009/gv,/1 April 19\d{2}/gv,/Copyright \(c\) 2000-2006,?\s*The Perl Foundation/giv,/Copyright \(C\) (?:\d{4},?\s*)+Free Software Foundation/gv],on=[`node_modules/**`,`test/**`];function sn(e){let t=e;for(let e of an)e.lastIndex=0,t=t.replace(e,e=>e.replaceAll(/\d/gv,`X`));return t}const cn=/(\d{4})\s*-\s*(\d{4})/v,ln=/(\d{4})/v;function un(e,t){let n=sn(e),r=cn,i=r.exec(n);if(i){let[,n,a]=i;if(Number(a)!==t){let a=`${n}-${t}`;return e.slice(0,i.index)+e.slice(i.index).replace(r,()=>a)}return e}let a=ln,o=a.exec(n);if(o){let[,n]=o;if(Number(n)!==t){let r=`${n}-${t}`;return e.slice(0,o.index)+e.slice(o.index).replace(a,()=>r)}return e}return e}async function dn(e){let t=(/* @__PURE__ */ new Date()).getFullYear(),n=[`**/license.txt`,`**/license`,...on.map(e=>`!${e}`)],r=await de(n,{caseSensitiveMatch:!1,cwd:j(),followSymbolicLinks:!1,gitignore:!0}),i=[];for(let n of r)try{let r=await y.readFile(n,`utf8`),a=un(r,t);a!==r&&(i.push(n),e&&await y.writeFile(n,a,`utf8`))}catch(e){console.error(`Failed to process ${n}:`,e)}return i}async function fn(e,t=!1){let n=await dn(t);if(n.length>0){e.write(`${t?`Fixed`:`Found`} ${n.length} license ${F(`file`,n.length)} with outdated copyright year:\n`);for(let t of n)e.write(` - ${t}\n`);return+!t}return 0}async function pn(e){return fn(e,!1)}async function mn(){let e=await dn(!1);return{diagnostics:e.map(e=>({file:E(e,j()),message:`License file has an outdated copyright year`,severity:`error`,tool:`copyright-year`})),exitCode:+(e.length>0),unparsed:[]}}async function hn(e){return fn(e,!0)}const gn=`pnpm-lock.yaml`;function _n(e){let t=M(),n=s.resolve(e);for(;;){if(r.existsSync(s.join(n,gn)))return n;if(n===t)break;let e=s.dirname(n);if(e===n)break;n=e}}function vn(e,t,n){let r=`${e}@${t}`;return Object.hasOwn(n,r)?r:Object.hasOwn(n,t)?t:void 0}function yn(e,t){return e===void 0||e===``?t===void 0||t===``?void 0:t:t===void 0||t===``||fe(e,t)?e:t}async function bn(e){let t=_n(e);if(t===void 0||t===``)throw Error(`${gn} not found at or above "${e}".`);let n=s.join(t,gn),r=await me(t,{ignoreIncompatible:!1});if(!r?.importers)throw Error(`Lockfile at "${n}" is unreadable or missing importers.`);let i=r.packages??{},a,o,c={},l={};function u(e,t){let n,r=/* @__PURE__ */ new Set;function a(e,t){if(t.startsWith(`link:`))return;let o=vn(e,t,i);if(o===void 0||o===``||r.has(o))return;r.add(o);let s=i[o];if(s===void 0)return;let c=s.engines?.node;if(c!==void 0&&c!==``){let e=pe(c)?.version;e!==void 0&&e!==``&&(n===void 0||n===``||fe(e,n))&&(n=e)}if(s.dependencies)for(let[e,t]of Object.entries(s.dependencies))a(e,t)}return a(e,t),n}function d(e,t){for(let[n,r]of Object.entries(e)){let e=u(n,typeof r==`string`?r:r.version);if(e===void 0||e===``)continue;let i=t?l:c;i[e]??=/* @__PURE__ */ new Set,i[e].add(n);let s=t?o:a;(s===void 0||s===``||fe(e,s))&&(t?o=e:a=e)}}let f=s.relative(t,e),p=f===``?`.`:f,m=r.importers[p];m!==void 0&&(m.dependencies&&d(m.dependencies,!1),m.devDependencies&&d(m.devDependencies,!0));let h=yn(a,o),g=h===void 0?void 0:`>=${h}`;return{dependencies:a!==void 0&&a!==``?{topLevelCauses:[...c[a]??[]],version:`>=${a}`}:void 0,devDependencies:o!==void 0&&o!==``?{topLevelCauses:[...l[o]??[]],version:`>=${o}`}:void 0,lockfile:n,version:g}}function xn(e){let t=e.devEngines;if(t?.runtime)return(Array.isArray(t.runtime)?t.runtime:[t.runtime]).find(e=>e.name===`node`)?.version}function Sn(e,t){let n=e.devEngines??{};if(n.runtime){if(Array.isArray(n.runtime)){let e=n.runtime.find(e=>e.name===`node`);e===void 0?n.runtime.push({name:`node`,version:t}):e.version=t}else n.runtime.name===`node`?n.runtime.version=t:n.runtime=[n.runtime,{name:`node`,version:t}]}else n.runtime={name:`node`,version:t};e.devEngines=n}function Cn(e){let t=e.devEngines;if(t?.runtime){if(Array.isArray(t.runtime)){t.runtime=t.runtime.filter(e=>e.name!==`node`);let[e]=t.runtime;e===void 0?delete t.runtime:t.runtime.length===1&&(t.runtime=e)}else t.runtime.name===`node`&&delete t.runtime;Object.keys(t).length===0&&delete e.devEngines}}function J(e){return e.length===0?``:` (from ${e.join(`, `)})`}async function wn(e,t){let n=s.join(t,`package.json`);if(!r.existsSync(n))return{issues:[],packageJsonPath:n};let i=r.readJsonSync(n),a=i.engines?.node,o=xn(i),c=await bn(t),l=c.dependencies?.version,u=c.dependencies?.topLevelCauses??[],d=c.version,f=c.devDependencies?.topLevelCauses??[],p=[];if(l!==void 0){if(a===void 0){if(p.push(`Missing engines.node — suggest setting to "${l}"${J(u)}`),e){let e=i.engines??{};e.node=l,i.engines=e}}else{let t=S.minVersion(a),n=S.minVersion(l);t&&n&&S.lt(t,n)&&(p.push(`engines.node is "${a}" but production dependencies require at least "${l}"${J(u)}`),e&&(i.engines.node=l))}}let m=(()=>{if(l!==void 0&&l!==``&&a!==void 0&&a!==``){let e=S.minVersion(l),t=S.minVersion(a);if(e&&t)return S.gt(e,t)?l:a}return l??a})(),h=m!==void 0&&m!==``?S.minVersion(m):void 0,g=d!==void 0&&d!==``?S.minVersion(d):void 0,ee=g&&h&&S.gt(g,h);if(d!==void 0&&ee){if(o===void 0)p.push(`devDependencies require a higher Node.js minimum (${d}) than engines.node (${m??`none`}) — suggest adding devEngines.runtime for node with version "${d}"${J(f)}`),e&&Sn(i,d);else{let t=S.minVersion(o);t&&S.lt(t,g)&&(p.push(`devEngines.runtime.version for node is "${o}" but all dependencies require at least "${d}"${J(f)}`),e&&Sn(i,d))}}else if(o!==void 0){let t=S.minVersion(o);t&&h&&S.lte(t,h)&&(p.push(`devEngines.runtime.version for node is redundant (engines.node already covers the requirement) — suggest removing`),e&&Cn(i))}return e&&p.length>0&&(r.writeJsonSync(n,i,{spaces:` `}),await N(n)),{issues:p,packageJsonPath:n}}async function Tn(e,t){let n=A(),r=0;for(let i of n){let{issues:n,packageJsonPath:a}=await wn(t,i);if(n.length!==0){e.write(`${t?`Fixed`:`Found`} ${n.length} Node.js version ${F(`issue`,n.length)} in ${a}:\n`);for(let t of n)e.write(` - ${t}\n`);t||(r=1)}}return r}async function En(){let e=A(),t=[];for(let n of e){let{issues:e,packageJsonPath:r}=await wn(!1,n);for(let n of e)t.push({file:E(r,process.cwd()),message:n,severity:`error`,tool:`node-version`})}return{diagnostics:t,exitCode:+(t.length>0),unparsed:[]}}async function Dn(e){let t=O(await bn(j())).split(`
|
|
12
|
-
`);for(let n of t)e.write(`${n}\n`);return 0}async function
|
|
13
|
-
`)
|
|
14
|
-
`);for(let t of l)e.write(`${t}\n`);return 0}const Fn={commands:{fix:{commands:[{cache:{flags:[`--cache`,`--cache-strategy`,`content`],name:`stylelint`},collect:{optionFlags:[...Y,`--fix`,`--formatter`,`json`],parse:Nn},name:`stylelint`,optionFlags:[...Y,`--fix`],receivePositionalArguments:!0}],description:`Fix your project with Stylelint. ${K.fileRun}`,positionalArgumentDefault:Mn,positionalArgumentExtensions:jn,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:[...Y,`--formatter`,`json`],parse:Nn},name:`stylelint`,optionFlags:Y,receivePositionalArguments:!0}],description:`Lint your project with Stylelint. ${K.fileRun}`,positionalArgumentDefault:Mn,positionalArgumentExtensions:jn,positionalArgumentMode:`optional`},printConfig:{commands:[{execute:Pn,name:`stylelint-config`}],description:`Print the effective Stylelint configuration. ${K.optionalFileRun}.`,positionalArgumentMode:`optional`}},description:`Kitschpatrol's Stylelint shared configuration tools.`,logColor:`greenBright`,logPrefix:`[Stylelint]`,name:`ksc-stylelint`,order:5},In=/^\s/v,Ln=/\berror\b|\bfailed\b|\bfailure\b/iv;function X(e,t,n,r){return e.exitCode!==0&&t.every(({severity:e})=>e!==`error`)&&t.push({message:r.find(e=>Ln.test(e))??`${n} exited with code ${e.exitCode} without a parseable error.`,severity:`error`,tool:n}),{diagnostics:t,unparsed:r}}function Rn(e){return In.test(e)}function Z(e){return typeof e==`object`&&!!e}function Q(e){try{let t=JSON.parse(e);return typeof t==`string`?t:void 0}catch{return}}const zn=/^(?<file>.+?):(?<line>\d+):(?<column>\d+) - (?<severity>error|warning|hint) (?<rule>[^:]+): (?<message>.*)$/v,Bn=/^(?:\d{2}:\d{2}:\d{2} )?(?:✘ )?\[(?<severity>ERROR|WARN)\](?: \[(?<label>[^\]]+)\])? (?<message>.*)$/v,Vn=/^\d{2}:\d{2}:\d{2}\s+\[(?!ERROR\]|WARN\])[^\]]+\]\s+/v,Hn=/^(?:Result \(\d+ files?\):|- \d+ (?:errors?|warnings?|hints?))$/v,Un=/^(?:\d+\s.*|\s*[~^]+)$/v;function Wn(e){try{let t=JSON.parse(e);return!Z(t)||typeof t.message!=`string`||t.level!==`debug`&&t.level!==`error`&&t.level!==`info`&&t.level!==`warn`?void 0:{...typeof t.label==`string`&&t.label.length>0&&{label:t.label},level:t.level,message:t.message}}catch{return}}function Gn(e){return e.level!==`error`&&e.level!==`warn`?void 0:{...e.label!==void 0&&{rule:e.label},message:e.message,severity:e.level===`error`?`error`:`warning`,tool:`astro`}}function Kn(e,t){let n=zn.exec(e);if(n?.groups===void 0)return;let{column:r,file:i=``,line:a,message:o=``,rule:s,severity:c}=n.groups;return{column:Number(r),file:E(i,t),line:Number(a),message:o,rule:s?.trim()??`unknown`,severity:c===`error`?`error`:c===`hint`?`info`:`warning`,tool:`astro`}}function qn(e){let t=Bn.exec(e);if(t?.groups===void 0)return;let{label:n,message:r=``,severity:i}=t.groups;return{...n!==void 0&&{rule:n},message:r,severity:i===`ERROR`?`error`:`warning`,tool:`astro`}}function Jn(e){let t=e.trimEnd();return Vn.test(t)||Hn.test(t)||t.startsWith(`Getting diagnostics for Astro files in `)}function Yn(e){let t=[],n=[];for(let r of D(`${e.stdout}\n${e.stderr}`)){let i=Wn(r);if(i!==void 0){let e=Gn(i);e!==void 0&&t.push(e);continue}let a=Kn(r,e.cwd)??qn(r);if(a!==void 0){t.push(a);continue}if(Jn(r)||Un.test(r))continue;let o=t.at(-1);if(o!==void 0&&Rn(r)){o.message+=`\n${r.trim()}`;continue}n.push(r)}return X(e,t,`astro`,n)}const Xn=/^(?:Loading svelte-check in workspace: |Getting Svelte diagnostics\.\.\.|svelte-check found 0 errors and 0 warnings$)/v,Zn=/^\d+ (?:START "|COMPLETED \d+ FILES 0 ERRORS 0 WARNINGS 0 FILES_WITH_PROBLEMS$)/v,Qn=/^\d+ (?:START "|COMPLETED \d+ FILES \d+ ERRORS \d+ WARNINGS \d+ FILES_WITH_PROBLEMS$)/v,$n=/^\d+ (?<severity>ERROR|WARNING) (?<file>"(?:\\.|[^"\\])*") (?<line>\d+):(?<column>\d+) (?<message>"(?:\\.|[^"\\])*")$/v,er=/^\d+ FAILURE (?<message>.+)$/v,tr=/^\d+\s/v;function nr(e,t){let n=typeof e==`string`&&e.length>0?e:void 0,r=typeof t==`string`||typeof t==`number`?String(t):void 0;return n!==void 0&&r!==void 0?`${n}(${r})`:n??r}function rr(e,t){let n=e.indexOf(`{`);if(!(n<=0||!tr.test(e)))try{let r=JSON.parse(e.slice(n));if(!Z(r)||r.type!==`ERROR`&&r.type!==`WARNING`||typeof r.filename!=`string`||typeof r.message!=`string`||!Z(r.start)||typeof r.start.line!=`number`||typeof r.start.character!=`number`)return;let i=Z(r.end)?r.end:void 0,a=nr(r.source,r.code);return{column:r.start.character+1,...i!==void 0&&typeof i.character==`number`&&{endColumn:i.character+1},...i!==void 0&&typeof i.line==`number`&&{endLine:i.line+1},file:E(r.filename,t),line:r.start.line+1,message:r.message,...a!==void 0&&{rule:a},severity:r.type===`ERROR`?`error`:`warning`,tool:`svelte-check`}}catch{return}}function ir(e,t){let n=$n.exec(e);if(n?.groups===void 0)return;let{column:r,file:i=``,line:a,message:o=``,severity:s}=n.groups,c=Q(i),l=Q(o);return c===void 0||l===void 0?void 0:{column:Number(r),file:E(c,t),line:Number(a),message:l,severity:s===`ERROR`?`error`:`warning`,tool:`svelte-check`}}function ar(e){let t=er.exec(e);if(t?.groups===void 0)return;let n=t.groups.message??``;return{message:Q(n)??n,severity:`error`,tool:`svelte-check`}}function or(e){return Xn.test(e)||Zn.test(e)}function sr(e){let t=[],n=[];for(let r of D(`${e.stdout}\n${e.stderr}`)){let i=rr(r,e.cwd)??ir(r,e.cwd)??ar(r);if(i!==void 0){t.push(i);continue}!Qn.test(r)&&!or(r)&&n.push(r)}return X(e,t,`svelte-check`,n)}const cr=/^(?<file>.+?)\((?<line>\d+),(?<column>\d+)\): (?<severity>error|warning) (?<code>TS\d+): (?<message>.*)$/v,lr=/^(?<severity>error|warning) (?<code>TS\d+): (?<message>.*)$/v;function ur(e){let t=[],n=[];for(let r of D(`${e.stdout}\n${e.stderr}`)){let i=cr.exec(r);if(i?.groups!==void 0){let{code:n,column:r,file:a=``,line:o,message:s=``,severity:c}=i.groups;t.push({column:Number(r),file:E(a,e.cwd),line:Number(o),message:s,rule:n,severity:c===`warning`?`warning`:`error`,tool:`tsc`});continue}let a=lr.exec(r);if(a?.groups!==void 0){let{code:e,message:n=``,severity:r}=a.groups;t.push({message:n,rule:e,severity:r===`warning`?`warning`:`error`,tool:`tsc`});continue}let o=t.at(-1);if(o!==void 0&&Rn(r)){o.message+=`\n${r.trim()}`;continue}n.push(r)}return X(e,t,`tsc`,n)}async function dr(e){let t=await r.readJson(s.join(e,`package.json`));return/* @__PURE__ */ new Set([...Object.keys(t.dependencies??{}),...Object.keys(t.devDependencies??{})])}function fr(e,t=`package-dir`){let n=e.has(`@astrojs/check`),r=e.has(`svelte-check`);if(n||r){let e=n?[{collect:{optionFlags:[`--json`],parse:Yn},cwdOverride:t,name:`astro`,outputFilter:Jn,subcommands:[`check`]}]:[];if(r){let r=n?[]:[`--tsconfig`,`./tsconfig.json`];e.push({collect:{optionFlags:[...r,`--output`,`machine-verbose`],parse:sr},cwdOverride:t,name:`svelte-check`,optionFlags:r,outputFilter:or})}return e}return[{collect:{parse:ur},cwdOverride:t,name:`tsc`,optionFlags:[`--noEmit`]}]}function pr(e){let t=e.some(({hasTypeScriptConfig:e})=>e);return e.flatMap(({dependencies:e,directory:n,hasTypeScriptConfig:r},i)=>{let a=e.has(`@astrojs/check`)||e.has(`svelte-check`);return r||a||!t&&i===0?fr(e,n):[]})}async function mr(){let e=A();return pr(await Promise.all(e.map(async e=>{let[t,n]=await Promise.all([dr(e),r.pathExists(s.join(e,`tsconfig.json`))]);return{dependencies:t,directory:e,hasTypeScriptConfig:n}})))}const hr=[Bt,Lt,qt,Zt,nn,rn,An,Fn,{commands:{init:{locationOptionFlag:!1},lint:{commands:mr,description:`Run type checking on your project. ${K.packageRun} ${K.monorepoRun}`,positionalArgumentMode:`none`,showResolvedCommands:!0},printConfig:{commands:[{name:`tsc`,optionFlags:[`--showConfig`],prettyJsonOutput:!0}],description:`Print the TypeScript configuration for the project. ${K.packageSearch} ${K.monorepoSearch}`,positionalArgumentMode:`none`}},description:`Kitschpatrol's TypeScript shared configuration tools.`,logColor:`blueBright`,logPrefix:`[TypeScript Config]`,name:`ksc-typescript`,order:3}],gr={"ksc-cspell":4,"ksc-eslint":2,"ksc-knip":6,"ksc-mdat":1,"ksc-prettier":5,"ksc-repo":0,"ksc-stylelint":3,"ksc-typescript":6};function $(e){let t=hr.toSorted((e,t)=>e.order-t.order),n=[];for(let r of t)r.commands[e]!==void 0&&n.push({definition:r,effectiveKey:e});if(e===`fix`)for(let e of t)e.commands.fix===void 0&&e.commands.lint!==void 0&&n.push({definition:e,effectiveKey:`lint`});let r=[];for(let{definition:t,effectiveKey:i}of n){let n=i===`lint`?t.commands.lint:i===`fix`?t.commands.fix:void 0;if(n!==void 0&&(e===`lint`||e===`fix`)){let a={commands:n.commands,kind:`group`,logColor:t.logColor,logPrefix:t.logPrefix,name:t.name,parallel:n.parallel,positionalArgumentDefault:n.positionalArgumentDefault,positionalArgumentExtensions:n.positionalArgumentExtensions,positionalArgumentMode:n.positionalArgumentMode,showResolvedCommands:n.showResolvedCommands,stage:e===`fix`?gr[t.name]??7:0,subcommand:Ue(i),verbose:t.verbose};r.push(a);continue}let a={name:t.name,...i===`init`?{receiveOptionFlags:t.commands.init?.locationOptionFlag??!1}:{receivePositionalArguments:t.commands[i]?.positionalArgumentMode!==`none`},subcommands:[Ue(i)]};r.push(a)}return r}await ht({commands:{fix:{commands:$(`fix`),description:`Fix your project with multiple tools in one go. Tools without auto-fixes run their checks afterward, so remaining issues match a subsequent lint. ${K.multiArgumentCaveat}`,parallel:!0,positionalArgumentMode:`optional`},init:{commands:$(`init`),description:`Initialize configuration files for the entire suite of @kitschpatrol/shared-config tools. ${K.multiOptionCaveat}`,locationOptionFlag:!0},lint:{commands:$(`lint`),description:`Lint your project with multiple tools in one go. ${K.multiArgumentCaveat}`,parallel:!0,positionalArgumentMode:`optional`},printConfig:{commands:$(`printConfig`),description:`Print aggregated tool configuration data. ${K.multiArgumentCaveat}`,positionalArgumentMode:`optional`}},description:`Run aggregated @kitschpatrol/shared-config commands.`,logColor:`yellow`,logPrefix:`🔬`,name:`ksc`,order:0,showSummary:!0,verbose:!0});export{};
|
|
9
|
+
`),0}async function Nt(){let e=import.meta.resolve(`@kitschpatrol/cspell-config`),t=await u({cwd:s.dirname(S(e))});if(t===void 0)throw Error(`Could not find Case Police dictionary parent package.`);let n=s.join(s.dirname(t),`dictionaries`,`case-police.json`);try{await ne(n,a.F_OK)}catch{throw Error(`Case Police dictionary file "${n}" does not exist.`)}return n}const Pt=/^(?<from>\S+) → (?<to>\S+)\s+(?<file>\S+):(?<line>\d+):(?<column>\d+)$/v;function Ft(e){let t=[],n=[];for(let r of k(`${e.stdout}\n${e.stderr}`)){if(!r.includes(`→`))continue;let i=Pt.exec(r);if(i?.groups===void 0){n.push(r);continue}let{column:a,file:o=``,from:s,line:c,to:l}=i.groups;t.push({column:Number(a),file:O(o,e.cwd),line:Number(c),message:`Case error: "${s}" should be "${l}"`,severity:`warning`,...l!==void 0&&{suggestion:l},tool:`case-police`})}return{diagnostics:t,unparsed:n}}async function It(e){let t=await x().searchForConfigFile(void 0);if(t===void 0)throw Error(`No CSpell configuration found.`);e.write(`Found cspell readme configuration at "${S(t.url)}"\n`);let n=A(await re(t)).split(`
|
|
10
|
+
`);for(let t of n)e.write(`${t}\n`);return 0}const Lt={commands:{fix:{async commands(){return[{collect:{parse:Ft},logColor:`cyanBright`,logPrefix:`[Case Police]`,name:`case-police`,optionFlags:[`--fix`,`--dict`,await Nt(),`--ignore`,await Et()],outputFilter:e=>!e.includes(`→`),receivePositionalArguments:!0},{execute:Mt,name:`words`},{cache:{flags:[`--cache`,`--cache-strategy`,`content`],name:`cspell`},collect:{parse:kt},name:`cspell`,optionFlags:[`--quiet`],receivePositionalArguments:!0}]},description:`Fix letter casing issues, remove unused words from the local CSpell configuration's "words" array, and report remaining (unfixable) spelling errors. ${J.fileRun} Unused words are only removed when no file arguments are given, since detecting them requires checking every file.`,positionalArgumentDefault:Ct,positionalArgumentMode:`optional`},init:{configFile:`cspell.config.ts`,configPackageJson:{cspell:{import:`@kitschpatrol/cspell-config`}},locationOptionFlag:!0},lint:{async commands(){return[{cache:{flags:[`--cache`,`--cache-strategy`,`content`],name:`cspell`},collect:{parse:kt},name:`cspell`,optionFlags:[`--quiet`],receivePositionalArguments:!0},{collect:jt,execute:At,name:`unused-words`},{collect:{parse:Ft},logColor:`cyanBright`,logPrefix:`[Case Police]`,name:`case-police`,optionFlags:[`--dict`,await Nt(),`--ignore`,await Et()],outputFilter:e=>!e.includes(`→`),receivePositionalArguments:!0}]},description:`Check for spelling mistakes. ${J.fileRun} Unused words in the configuration's "words" array are only reported when no file arguments are given, since detecting them requires checking every file.`,positionalArgumentDefault:Ct,positionalArgumentMode:`optional`},printConfig:{commands:[{execute:It,name:`cspell-config`}],description:`Print the resolved CSpell configuration. ${J.packageSearch} ${J.monorepoSearch}`,positionalArgumentMode:`none`}},description:`Kitschpatrol's CSpell shared configuration tools.`,logColor:`cyan`,logPrefix:`[CSpell]`,name:`ksc-cspell`,order:6};async function Rt(e,t){let n,[r]=t;if(r===void 0)n=K(`eslint`);else{let t=s.join(process.cwd(),r);e.write(`Showing configuration for file: ${t}\n`),n={name:`eslint`,optionFlags:[`--print-config`],receivePositionalArguments:!0}}let{exitCode:i}=await G(e,t,[],[n]);return i}function zt(e){let t;try{t=JSON.parse(e.stdout)}catch{return{diagnostics:[],unparsed:[...k(e.stdout),...k(e.stderr)]}}let n=[];for(let r of t)for(let t of r.messages)n.push({column:t.column,endColumn:t.endColumn,endLine:t.endLine,file:O(r.filePath,e.cwd),line:t.line,message:t.message,rule:t.ruleId??void 0,severity:t.fatal===!0||t.severity===2?`error`:`warning`,tool:`eslint`});return{diagnostics:n,unparsed:k(e.stderr)}}const Y=[`--max-warnings`,`0`,`--no-warn-ignored`],Bt={commands:{fix:{commands:[{collect:{optionFlags:[`--fix`,...Y,`--format`,`json`],parse:zt},name:`eslint`,optionFlags:[`--fix`,...Y],receivePositionalArguments:!0}],description:`Fix your project with ESLint. ${J.fileRun}`,positionalArgumentDefault:`.`,positionalArgumentMode:`optional`},init:{locationOptionFlag:!1},lint:{commands:[{collect:{optionFlags:[...Y,`--format`,`json`],parse:zt},name:`eslint`,optionFlags:Y,receivePositionalArguments:!0}],description:`Lint your project with ESLint. ${J.fileRun}`,positionalArgumentDefault:`.`,positionalArgumentMode:`optional`},printConfig:{commands:[{execute:Rt,name:`eslint-config`}],description:`Print the effective ESLint configuration. ${J.optionalFileRun} Use \`@eslint/config-inspector\` for a more detailed view.`,positionalArgumentMode:`optional`}},description:`Kitschpatrol's ESLint shared configuration tools.`,logColor:`magenta`,logPrefix:`[ESLint]`,name:`ksc-eslint`,order:4},Vt={cspell:!0,entry:[`{index,cli,main}.{js,mjs,cjs,jsx,ts,tsx,mts,cts}!`,`src/{index,cli,main}.{js,mjs,cjs,jsx,ts,tsx,mts,cts}!`,`src/{bin,lib,cli}/{index,cli,main}.{js,mjs,cjs,jsx,ts,tsx,mts,cts}!`,`scripts/**/*.{js,mjs,cjs,ts,mts,cts}`,`skills/*/scripts/**/*.{js,mjs,cjs,ts,mts,cts}`,`.remarkrc.{js,mjs,cjs,ts,mts,cts}`,`eslint.config.{js,mjs,cjs,ts,mts,cts}`,`mdat.config.{js,mjs,cjs,ts,mts,cts}`,`prettier.config.{js,mjs,cjs,ts,mts,cts}`,`stylelint.config.{js,mjs,cjs,ts,mts,cts}`],ignoreBinaries:[`gh`,`ksc-cspell`,`ksc-eslint`,`ksc-knip`,`ksc-mdat`,`ksc-prettier`,`ksc-remark`,`ksc-repo`,`ksc-stylelint`,`ksc-typescript`,`op`],ignoreDependencies:[`@astrojs/check`,`@kitschpatrol/cspell-config`,`@kitschpatrol/eslint-config`,`@kitschpatrol/knip-config`,`@kitschpatrol/mdat-config`,`@kitschpatrol/prettier-config`,`@kitschpatrol/remark-config`,`@kitschpatrol/repo-config`,`@kitschpatrol/stylelint-config`,`@kitschpatrol/typescript-config`,`@prettier/plugin-php`,`@prettier/plugin-ruby`,`@prettier/plugin-xml`,`node-addon-api`,`node-gyp`,`prettier-plugin-packagejson`,`prettier-plugin-sh`,`prettier-plugin-tailwindcss`,`prettier-plugin-toml`,`remark-attribute-list`,`remark-directive`,`sharp`,`svelte-check`]},Ht={binaries:`Unlisted binary`,catalog:`Unused catalog entry`,classMembers:`Unused class member`,dependencies:`Unused dependency`,devDependencies:`Unused devDependency`,duplicates:`Duplicate export`,enumMembers:`Unused enum member`,exports:`Unused export`,files:`Unused file`,namespaceMembers:`Unused namespace member`,nsExports:`Unused namespace export`,nsTypes:`Unused namespace type`,optionalPeerDependencies:`Unused optional peer dependency`,types:`Unused exported type`,unlisted:`Unlisted dependency`,unresolved:`Unresolved import`};function Ut(e){return Array.isArray(e)?e.flatMap(e=>Array.isArray(e)?e:[e]):[]}function Wt(e){let t;try{t=JSON.parse(e.stdout)}catch{return{diagnostics:[],unparsed:[...k(e.stdout),...k(e.stderr)]}}let n=[],r=t.issues??[];for(let t of r){let r=O(t.file,e.cwd);for(let[e,i]of Object.entries(t)){let t=Ht[e];if(t!==void 0)for(let a of Ut(i)){let i=typeof a==`string`?a:a.name,o=typeof a==`string`?{}:{column:a.col,line:a.line};n.push({...o,file:r,message:e===`files`?t:`${t}: ${i}`,rule:e,severity:`warning`,tool:`knip`})}}}return{diagnostics:n,unparsed:k(e.stderr)}}function Gt(){if(Fe()){let e=M(),t=N();if(e!==t){let n=s.relative(t,e);if(n!==``)return[`--workspace`,n.split(s.sep).join(`/`)]}}return[]}function Kt(){return{knip:Vt}}const qt={commands:{init:{configFile:`knip.config.ts`,configPackageJson:Kt(),locationOptionFlag:!0},lint:{commands:[{collect:{optionFlags:[`--no-progress`,`--no-config-hints`,...Gt(),`--reporter`,`json`],parse:Wt},cwdOverride:`workspace-root`,name:`knip`,optionFlags:[`--no-progress`,`--no-config-hints`,...Gt()]}],description:`Check for unused code and dependencies. ${J.packageRun} ${J.monorepoRun}`,positionalArgumentMode:`none`},printConfig:{commands:[K(`knip`)],description:`Print the effective Knip configuration. ${J.packageSearch} ${J.monorepoSearch}`,positionalArgumentMode:`none`}},description:`Kitschpatrol's Knip shared configuration tools.`,logColor:`cyan`,logPrefix:`[Knip]`,name:`ksc-knip`,order:7};async function Jt(){return(await q(`mdat`))?.filepath}async function Yt(e){let t=`mdat`,n=await q(t);n!==void 0&&e.write(`Found ${t} readme configuration at "${n.filepath}"\n`);let r=A(await le()).split(`
|
|
11
|
+
`);for(let t of r)e.write(`${t}\n`);return 0}async function Xt(e){let t=j(),n=await Jt();return t.map(t=>({cwdOverride:t,name:`mdat`,optionFlags:n===void 0||n===``?[`--format`]:[`--config`,n,`--format`],subcommands:[e]}))}const Zt={commands:{fix:{commands:await Xt(`expand`),description:`Expand all Mdat content placeholders in your readme.md file(s). ${J.packageRun} ${J.monorepoRun}`,parallel:!0,positionalArgumentMode:`none`},init:{configFile:`mdat.config.ts`,configPackageJson:{mdat:{$import:`node_modules/@kitschpatrol/mdat-config/dist/index.js`}},locationOptionFlag:!0},lint:{commands:await Xt(`check`),description:`Validate that all Mdat content placeholders in your readme.md file(s) have been expanded and are up to date. ${J.packageRun} ${J.monorepoRun}`,parallel:!0,positionalArgumentMode:`none`},printConfig:{commands:[{execute:Yt,name:`mdat-config`}],description:`Print the effective Mdat configuration. ${J.packageSearch}. ${J.monorepoSearch}.`,positionalArgumentMode:`none`}},description:`Kitschpatrol's Mdat shared configuration tools.`,logColor:`green`,logPrefix:`[Mdat Config]`,name:`ksc-mdat`,order:2},Qt=/^\[warn\] (?<file>\S+)$/v,$t=/^\[error\] (?<message>.+)$/v;function en(e){let t=[],n=[];for(let r of k(`${e.stdout}\n${e.stderr}`)){let i=Qt.exec(r);if(i?.groups?.file!==void 0){t.push({file:O(i.groups.file,e.cwd),message:`File is not formatted with Prettier`,severity:`warning`,tool:`prettier`});continue}if(r.startsWith(`[warn] Code style issues found`))continue;let a=$t.exec(r);a?.groups?.message===void 0?n.push(r):t.push({message:a.groups.message,severity:`error`,tool:`prettier`})}return{diagnostics:t,unparsed:n}}const tn=[`--log-level=warn`,`--ignore-unknown`,`--plugin=prettier-plugin-astro`,`--plugin=@prettier/plugin-php`,`--plugin=@prettier/plugin-ruby`,`--plugin=@prettier/plugin-xml`,`--plugin=prettier-plugin-jsdoc`,`--plugin=prettier-plugin-packagejson`,`--plugin=prettier-plugin-sh`,`--plugin=prettier-plugin-svelte`,`--plugin=prettier-plugin-toml`,`--plugin=prettier-plugin-tailwindcss`,`--ignore-path=${P(`.gitignore`)??`.gitignore`}`,`--ignore-path=${P(`.prettierignore`)??`.prettierignore`}`],nn={commands:{fix:{commands:[{cache:{flags:[`--cache`,`--cache-strategy`,`content`],name:`prettier`},collect:{parse:en},name:`prettier`,optionFlags:[...tn,`--write`],receivePositionalArguments:!0}],description:`Format files according to your Prettier configuration. ${J.fileRun}`,positionalArgumentDefault:`.`,positionalArgumentMode:`optional`},init:{configFile:`prettier.config.ts`,configPackageJson:{prettier:`@kitschpatrol/prettier-config`},locationOptionFlag:!0},lint:{commands:[{cache:{flags:[`--cache`,`--cache-strategy`,`content`],name:`prettier`},collect:{parse:en},name:`prettier`,optionFlags:[...tn,`--check`],receivePositionalArguments:!0}],description:`Check that files are formatted according to your Prettier configuration. ${J.fileRun}`,positionalArgumentDefault:`.`,positionalArgumentMode:`optional`},printConfig:{commands:[K(`prettier`)],description:`Print the effective Prettier configuration. ${J.packageSearch}. ${J.monorepoSearch}.`,positionalArgumentMode:`none`}},description:`Kitschpatrol's Prettier shared configuration tools.`,logColor:`blue`,logPrefix:`[Prettier]`,name:`ksc-prettier`,order:9},rn={commands:{init:{configFile:`.remarkrc.js`,configPackageJson:{remarkConfig:{plugins:[`@kitschpatrol/remark-config`]}},locationOptionFlag:!0},printConfig:{commands:[K(`remark`)],description:`Print the effective Remark configuration. ${J.packageSearch} ${J.monorepoSearch}`,positionalArgumentMode:`none`}},description:`Kitschpatrol's Remark and Remark Lint shared configuration tools. (Actual linting and fixing is managed through @kitschpatrol/eslint-config.)`,logColor:`blue`,logPrefix:`[remarklint]`,name:`ksc-remark`,order:8},an=[/Version 2\.0,?\s*January 2004/gv,/Version 1,?\s*February 1989/gv,/Version 2,?\s*June 1991/gv,/Version 3,?\s*29 June 2007/gv,/Version 2\.1,?\s*February 1999/gv,/Version 3,?\s*19 November 2007/gv,/Version 1\.0\s*-\s*August 17th,?\s*2003/gv,/Version 1\.1,?\s*March 2000/gv,/Version 1\.2,?\s*November 2002/gv,/Version 1\.3,?\s*3 November 2008/gv,/Version 1\.0\s*-\s*22 November 2005/gv,/Version 1\.1\s*-\s*26 February 2007/gv,/Version 2,?\s*December 2004/gv,/20 December 1996/gv,/December 20,?\s*1996/gv,/11 March 1996/gv,/28 March 2007/gv,/November 1,?\s*2008/gv,/August 1,?\s*2009/gv,/1 April 19\d{2}/gv,/Copyright \(c\) 2000-2006,?\s*The Perl Foundation/giv,/Copyright \(C\) (?:\d{4},?\s*)+Free Software Foundation/gv],on=[`node_modules/**`,`test/**`];function sn(e){let t=e;for(let e of an)e.lastIndex=0,t=t.replace(e,e=>e.replaceAll(/\d/gv,`X`));return t}const cn=/(\d{4})\s*-\s*(\d{4})/v,ln=/(\d{4})/v,un=/\bcopyright\b|©/iv;function dn(e){let t={start:0,end:e.length},n=0;for(let r of e.split(`
|
|
12
|
+
`))un.test(r)&&ln.test(r)&&(t={start:n,end:n+r.length}),n+=r.length+1;return t}function fn(e,t){let{start:n,end:r}=dn(sn(e)),i=pn(e.slice(n,r),t);return e.slice(0,n)+i+e.slice(r)}function pn(e,t){let n=sn(e),r=cn,i=r.exec(n);if(i){let[,n,a]=i;if(Number(a)!==t){let a=`${n}-${t}`;return e.slice(0,i.index)+e.slice(i.index).replace(r,()=>a)}return e}let a=ln,o=a.exec(n);if(o){let[,n]=o;if(Number(n)!==t){let r=`${n}-${t}`;return e.slice(0,o.index)+e.slice(o.index).replace(a,()=>r)}return e}return e}async function mn(e){let t=(/* @__PURE__ */ new Date()).getFullYear(),n=[`**/license.txt`,`**/license`,...on.map(e=>`!${e}`)],r=await ue(n,{caseSensitiveMatch:!1,cwd:M(),followSymbolicLinks:!1,gitignore:!0}),i=[];for(let n of r)try{let r=await b.readFile(n,`utf8`),a=fn(r,t);a!==r&&(i.push(n),e&&await b.writeFile(n,a,`utf8`))}catch(e){console.error(`Failed to process ${n}:`,e)}return i}async function hn(e,t=!1){let n=await mn(t);if(n.length>0){e.write(`${t?`Fixed`:`Found`} ${n.length} license ${R(`file`,n.length)} with outdated copyright year:\n`);for(let t of n)e.write(` - ${t}\n`);return+!t}return 0}async function gn(e){return hn(e,!1)}async function _n(){let e=await mn(!1);return{diagnostics:e.map(e=>({file:O(e,M()),message:`License file has an outdated copyright year`,severity:`error`,tool:`copyright-year`})),exitCode:+(e.length>0),unparsed:[]}}async function vn(e){return hn(e,!0)}const yn=`pnpm-lock.yaml`;function bn(e){let t=N(),n=s.resolve(e);for(;;){if(r.existsSync(s.join(n,yn)))return n;if(n===t)break;let e=s.dirname(n);if(e===n)break;n=e}}function xn(e,t,n){let r=`${e}@${t}`;return Object.hasOwn(n,r)?r:Object.hasOwn(n,t)?t:void 0}function Sn(e,t){return e===void 0||e===``?t===void 0||t===``?void 0:t:t===void 0||t===``||de(e,t)?e:t}async function Cn(e){let t=bn(e);if(t===void 0||t===``)throw Error(`${yn} not found at or above "${e}".`);let n=s.join(t,yn),r=await pe(t,{ignoreIncompatible:!1});if(!r?.importers)throw Error(`Lockfile at "${n}" is unreadable or missing importers.`);let i=r.packages??{},a,o,c={},l={};function u(e,t){let n,r=/* @__PURE__ */ new Set;function a(e,t){if(t.startsWith(`link:`))return;let o=xn(e,t,i);if(o===void 0||o===``||r.has(o))return;r.add(o);let s=i[o];if(s===void 0)return;let c=s.engines?.node;if(c!==void 0&&c!==``){let e=fe(c)?.version;e!==void 0&&e!==``&&(n===void 0||n===``||de(e,n))&&(n=e)}if(s.dependencies)for(let[e,t]of Object.entries(s.dependencies))a(e,t)}return a(e,t),n}function d(e,t){for(let[n,r]of Object.entries(e)){let e=u(n,typeof r==`string`?r:r.version);if(e===void 0||e===``)continue;let i=t?l:c;i[e]??=/* @__PURE__ */ new Set,i[e].add(n);let s=t?o:a;(s===void 0||s===``||de(e,s))&&(t?o=e:a=e)}}let f=s.relative(t,e),p=f===``?`.`:f,m=r.importers[p];m!==void 0&&(m.dependencies&&d(m.dependencies,!1),m.devDependencies&&d(m.devDependencies,!0));let h=Sn(a,o),g=h===void 0?void 0:`>=${h}`;return{dependencies:a===void 0||a===``?void 0:{topLevelCauses:[...c[a]??[]],version:`>=${a}`},devDependencies:o===void 0||o===``?void 0:{topLevelCauses:[...l[o]??[]],version:`>=${o}`},lockfile:n,version:g}}function wn(e){let t=e.devEngines;if(t?.runtime)return(Array.isArray(t.runtime)?t.runtime:[t.runtime]).find(e=>e.name===`node`)?.version}function Tn(e,t){let n=e.devEngines??{};if(n.runtime){if(Array.isArray(n.runtime)){let e=n.runtime.find(e=>e.name===`node`);e===void 0?n.runtime.push({name:`node`,version:t}):e.version=t}else n.runtime.name===`node`?n.runtime.version=t:n.runtime=[n.runtime,{name:`node`,version:t}]}else n.runtime={name:`node`,version:t};e.devEngines=n}function En(e){let t=e.devEngines;if(t?.runtime){if(Array.isArray(t.runtime)){t.runtime=t.runtime.filter(e=>e.name!==`node`);let[e]=t.runtime;e===void 0?delete t.runtime:t.runtime.length===1&&(t.runtime=e)}else t.runtime.name===`node`&&delete t.runtime;Object.keys(t).length===0&&delete e.devEngines}}function X(e){return e.length===0?``:` (from ${e.join(`, `)})`}async function Dn(e,t){let n=s.join(t,`package.json`);if(!r.existsSync(n))return{issues:[],packageJsonPath:n};let i=r.readJsonSync(n),a=i.engines?.node,o=wn(i),c=await Cn(t),l=c.dependencies?.version,u=c.dependencies?.topLevelCauses??[],d=c.version,f=c.devDependencies?.topLevelCauses??[],p=[];if(l!==void 0){if(a===void 0){if(p.push(`Missing engines.node — suggest setting to "${l}"${X(u)}`),e){let e=i.engines??{};e.node=l,i.engines=e}}else{let t=C.minVersion(a),n=C.minVersion(l);t&&n&&C.lt(t,n)&&(p.push(`engines.node is "${a}" but production dependencies require at least "${l}"${X(u)}`),e&&(i.engines.node=l))}}let m=(()=>{if(l!==void 0&&l!==``&&a!==void 0&&a!==``){let e=C.minVersion(l),t=C.minVersion(a);if(e&&t)return C.gt(e,t)?l:a}return l??a})(),h=m===void 0||m===``?void 0:C.minVersion(m),g=d===void 0||d===``?void 0:C.minVersion(d),_=g&&h&&C.gt(g,h);if(d!==void 0&&_){if(o===void 0)p.push(`devDependencies require a higher Node.js minimum (${d}) than engines.node (${m??`none`}) — suggest adding devEngines.runtime for node with version "${d}"${X(f)}`),e&&Tn(i,d);else{let t=C.minVersion(o);t&&C.lt(t,g)&&(p.push(`devEngines.runtime.version for node is "${o}" but all dependencies require at least "${d}"${X(f)}`),e&&Tn(i,d))}}else if(o!==void 0){let t=C.minVersion(o);t&&h&&C.lte(t,h)&&(p.push(`devEngines.runtime.version for node is redundant (engines.node already covers the requirement) — suggest removing`),e&&En(i))}return e&&p.length>0&&(r.writeJsonSync(n,i,{spaces:` `}),await I(n)),{issues:p,packageJsonPath:n}}async function On(e,t){let n=j(),r=0;for(let i of n){let{issues:n,packageJsonPath:a}=await Dn(t,i);if(n.length!==0){e.write(`${t?`Fixed`:`Found`} ${n.length} Node.js version ${R(`issue`,n.length)} in ${a}:\n`);for(let t of n)e.write(` - ${t}\n`);t||(r=1)}}return r}async function kn(){let e=j(),t=[];for(let n of e){let{issues:e,packageJsonPath:r}=await Dn(!1,n);for(let n of e)t.push({file:O(r,process.cwd()),message:n,severity:`error`,tool:`node-version`})}return{diagnostics:t,exitCode:+(t.length>0),unparsed:[]}}async function An(e){let t=A(await Cn(M())).split(`
|
|
13
|
+
`);for(let n of t)e.write(`${n}\n`);return 0}async function jn(e){return On(e,!1)}async function Mn(e){return On(e,!0)}const Nn={commands:{fix:{commands:[{execute:vn,name:`copyright-year`},{execute:Mn,name:`node-version`}],description:`Fix common issues like outdated copyright years in license files. ${J.packageRun} ${J.monorepoRun}`,positionalArgumentMode:`none`},init:{locationOptionFlag:!1},lint:{commands:[{collect:_n,execute:gn,name:`copyright-year`},{collect:kn,execute:jn,name:`node-version`}],description:`Check the repo for common issues. ${J.packageRun} ${J.monorepoRun}`,positionalArgumentMode:`none`},printConfig:{commands:[{execute:An,name:`node-version`}],description:`Print minimum Node.js version constraints from the pnpm lockfile.`,positionalArgumentMode:`none`}},description:`Kitschpatrol's repository-related shared configuration tools.`,logColor:`gray`,logPrefix:`[Repo Config]`,name:`ksc-repo`,order:1},Z=[`--ignore-path`,P(`.gitignore`)??`.gitignore`,`--allow-empty-input`],Pn=[`css`,`scss`,`sass`,`svelte`,`html`,`astro`,`tsx`,`jsx`,`php`,`vue`],Fn=`**/*.{${Pn.join(`,`)}}`;function In(e){let t;try{t=JSON.parse(e.stderr)}catch{return{diagnostics:[],unparsed:[...k(e.stdout),...k(e.stderr)]}}let n=[];for(let r of t){let t=O(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:k(e.stdout)}}async function Ln(e,t){let n=`stylelint`,r=await q(n);if(r===void 0)return 1;let{filepath:i,isEmpty:a}=r;if(a)return e.write(`Configuration is empty.
|
|
14
|
+
`),0;e.write(`Found ${n} configuration at "${i}"\n`);let o,[c]=t;c===void 0?o=F(`package-dir`):(o=s.join(process.cwd(),c),e.write(`Showing config for file at "${o}"\n`));let l=A(await me.resolveConfig(o)).split(`
|
|
15
|
+
`);for(let t of l)e.write(`${t}\n`);return 0}const Rn={commands:{fix:{commands:[{cache:{flags:[`--cache`,`--cache-strategy`,`content`],name:`stylelint`},collect:{optionFlags:[...Z,`--fix`,`--formatter`,`json`],parse:In},name:`stylelint`,optionFlags:[...Z,`--fix`],receivePositionalArguments:!0}],description:`Fix your project with Stylelint. ${J.fileRun}`,positionalArgumentDefault:Fn,positionalArgumentExtensions:Pn,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:[...Z,`--formatter`,`json`],parse:In},name:`stylelint`,optionFlags:Z,receivePositionalArguments:!0}],description:`Lint your project with Stylelint. ${J.fileRun}`,positionalArgumentDefault:Fn,positionalArgumentExtensions:Pn,positionalArgumentMode:`optional`},printConfig:{commands:[{execute:Ln,name:`stylelint-config`}],description:`Print the effective Stylelint configuration. ${J.optionalFileRun}.`,positionalArgumentMode:`optional`}},description:`Kitschpatrol's Stylelint shared configuration tools.`,logColor:`greenBright`,logPrefix:`[Stylelint]`,name:`ksc-stylelint`,order:5},zn=/^\s/v,Bn=/\berror\b|\bfailed\b|\bfailure\b/iv;function Vn(e,t,n,r){return e.exitCode!==0&&t.every(({severity:e})=>e!==`error`)&&t.push({message:r.find(e=>Bn.test(e))??`${n} exited with code ${e.exitCode} without a parseable error.`,severity:`error`,tool:n}),{diagnostics:t,unparsed:r}}function Hn(e){return zn.test(e)}function Q(e){return typeof e==`object`&&!!e}function Un(e){try{let t=JSON.parse(e);return typeof t==`string`?t:void 0}catch{return}}const Wn=/^(?<file>.+?):(?<line>\d+):(?<column>\d+) - (?<severity>error|warning|hint) (?<rule>[^:]+): (?<message>.*)$/v,Gn=/^(?:\d{2}:\d{2}:\d{2} )?(?:✘ )?\[(?<severity>ERROR|WARN)\](?: \[(?<label>[^\]]+)\])? (?<message>.*)$/v,Kn=/^\d{2}:\d{2}:\d{2}\s+\[(?!ERROR\]|WARN\])[^\]]+\]\s+/v,qn=/^(?:Result \(\d+ files?\):|- \d+ (?:errors?|warnings?|hints?))$/v,Jn=/^(?:\d+\s.*|\s*[~^]+)$/v,Yn=/* @__PURE__ */ new Set([`debug`,`error`,`info`,`warn`]);function Xn(e){return Yn.has(e)}function Zn(e){try{let t=JSON.parse(e);return Q(t)&&typeof t.message==`string`&&Xn(t.level)?{...typeof t.label==`string`&&t.label.length>0&&{label:t.label},level:t.level,message:t.message}:void 0}catch{return}}function Qn(e){return e.level===`error`||e.level===`warn`?{...e.label!==void 0&&{rule:e.label},message:e.message,severity:e.level===`error`?`error`:`warning`,tool:`astro`}:void 0}function $n(e,t){let n=Wn.exec(e);if(n?.groups===void 0)return;let{column:r,file:i=``,line:a,message:o=``,rule:s,severity:c}=n.groups;return{column:Number(r),file:O(i,t),line:Number(a),message:o,rule:s?.trim()??`unknown`,severity:c===`error`?`error`:c===`hint`?`info`:`warning`,tool:`astro`}}function er(e){let t=Gn.exec(e);if(t?.groups===void 0)return;let{label:n,message:r=``,severity:i}=t.groups;return{...n!==void 0&&{rule:n},message:r,severity:i===`ERROR`?`error`:`warning`,tool:`astro`}}function tr(e){let t=e.trimEnd();return Kn.test(t)||qn.test(t)||t.startsWith(`Getting diagnostics for Astro files in `)}function nr(e){let t=[],n=[];for(let r of k(`${e.stdout}\n${e.stderr}`)){let i=Zn(r);if(i!==void 0){let e=Qn(i);e!==void 0&&t.push(e);continue}let a=$n(r,e.cwd)??er(r);if(a!==void 0){t.push(a);continue}if(tr(r)||Jn.test(r))continue;let o=t.at(-1);o!==void 0&&Hn(r)?o.message+=`\n${r.trim()}`:n.push(r)}return Vn(e,t,`astro`,n)}const rr=/^(?:Loading svelte-check in workspace: |Getting Svelte diagnostics\.\.\.|svelte-check found 0 errors and 0 warnings$)/v,ir=/^\d+ (?:START "|COMPLETED \d+ FILES 0 ERRORS 0 WARNINGS 0 FILES_WITH_PROBLEMS$)/v,ar=/^\d+ (?:START "|COMPLETED \d+ FILES \d+ ERRORS \d+ WARNINGS \d+ FILES_WITH_PROBLEMS$)/v,or=/^\d+ (?<severity>ERROR|WARNING) (?<file>"(?:\\.|[^"\\])*") (?<line>\d+):(?<column>\d+) (?<message>"(?:\\.|[^"\\])*")$/v,sr=/^\d+ FAILURE (?<message>.+)$/v,cr=/^\d+\s/v;function lr(e,t){let n=typeof e==`string`&&e.length>0?e:void 0,r=typeof t==`string`||typeof t==`number`?String(t):void 0;return n===void 0||r===void 0?n??r:`${n}(${r})`}function ur(e,t){let n=e.indexOf(`{`);if(!(n<=0||!cr.test(e)))try{let r=JSON.parse(e.slice(n));if(!Q(r)||r.type!==`ERROR`&&r.type!==`WARNING`||typeof r.filename!=`string`||typeof r.message!=`string`||!Q(r.start)||typeof r.start.line!=`number`||typeof r.start.character!=`number`)return;let i=Q(r.end)?r.end:void 0,a=lr(r.source,r.code);return{column:r.start.character+1,...i!==void 0&&typeof i.character==`number`&&{endColumn:i.character+1},...i!==void 0&&typeof i.line==`number`&&{endLine:i.line+1},file:O(r.filename,t),line:r.start.line+1,message:r.message,...a!==void 0&&{rule:a},severity:r.type===`ERROR`?`error`:`warning`,tool:`svelte-check`}}catch{return}}function dr(e,t){let n=or.exec(e);if(n?.groups===void 0)return;let{column:r,file:i=``,line:a,message:o=``,severity:s}=n.groups,c=Un(i),l=Un(o);return c===void 0||l===void 0?void 0:{column:Number(r),file:O(c,t),line:Number(a),message:l,severity:s===`ERROR`?`error`:`warning`,tool:`svelte-check`}}function fr(e){let t=sr.exec(e);if(t?.groups===void 0)return;let n=t.groups.message??``;return{message:Un(n)??n,severity:`error`,tool:`svelte-check`}}function pr(e){return rr.test(e)||ir.test(e)}function mr(e){let t=[],n=[];for(let r of k(`${e.stdout}\n${e.stderr}`)){let i=ur(r,e.cwd)??dr(r,e.cwd)??fr(r);i===void 0?!ar.test(r)&&!pr(r)&&n.push(r):t.push(i)}return Vn(e,t,`svelte-check`,n)}const hr=/^(?<file>.+?)\((?<line>\d+),(?<column>\d+)\): (?<severity>error|warning) (?<code>TS\d+): (?<message>.*)$/v,gr=/^(?<severity>error|warning) (?<code>TS\d+): (?<message>.*)$/v;function _r(e){let t=[],n=[];for(let r of k(`${e.stdout}\n${e.stderr}`)){let i=hr.exec(r);if(i?.groups!==void 0){let{code:n,column:r,file:a=``,line:o,message:s=``,severity:c}=i.groups;t.push({column:Number(r),file:O(a,e.cwd),line:Number(o),message:s,rule:n,severity:c===`warning`?`warning`:`error`,tool:`tsc`});continue}let a=gr.exec(r);if(a?.groups!==void 0){let{code:e,message:n=``,severity:r}=a.groups;t.push({message:n,rule:e,severity:r===`warning`?`warning`:`error`,tool:`tsc`});continue}let o=t.at(-1);o!==void 0&&Hn(r)?o.message+=`\n${r.trim()}`:n.push(r)}return Vn(e,t,`tsc`,n)}async function vr(e){let t=await r.readJson(s.join(e,`package.json`));return/* @__PURE__ */ new Set([...Object.keys(t.dependencies??{}),...Object.keys(t.devDependencies??{})])}function yr(e,t=`package-dir`){let n=e.has(`@astrojs/check`),r=e.has(`svelte-check`);if(n||r){let e=n?[{collect:{optionFlags:[`--json`],parse:nr},cwdOverride:t,name:`astro`,outputFilter:tr,subcommands:[`check`]}]:[];if(r){let r=n?[]:[`--tsconfig`,`./tsconfig.json`];e.push({collect:{optionFlags:[...r,`--output`,`machine-verbose`],parse:mr},cwdOverride:t,name:`svelte-check`,optionFlags:r,outputFilter:pr})}return e}return[{collect:{parse:_r},cwdOverride:t,name:`tsc`,optionFlags:[`--noEmit`]}]}function br(e){let t=e.some(({hasTypeScriptConfig:e})=>e);return e.flatMap(({dependencies:e,directory:n,hasTypeScriptConfig:r},i)=>{let a=e.has(`@astrojs/check`)||e.has(`svelte-check`);return r||a||!t&&i===0?yr(e,n):[]})}async function xr(){let e=j();return br(await Promise.all(e.map(async e=>{let[t,n]=await Promise.all([vr(e),r.pathExists(s.join(e,`tsconfig.json`))]);return{dependencies:t,directory:e,hasTypeScriptConfig:n}})))}const Sr=[Bt,Lt,qt,Zt,nn,rn,Nn,Rn,{commands:{init:{locationOptionFlag:!1},lint:{commands:xr,description:`Run type checking on your project. ${J.packageRun} ${J.monorepoRun}`,positionalArgumentMode:`none`,showResolvedCommands:!0},printConfig:{commands:[{name:`tsc`,optionFlags:[`--showConfig`],prettyJsonOutput:!0}],description:`Print the TypeScript configuration for the project. ${J.packageSearch} ${J.monorepoSearch}`,positionalArgumentMode:`none`}},description:`Kitschpatrol's TypeScript shared configuration tools.`,logColor:`blueBright`,logPrefix:`[TypeScript Config]`,name:`ksc-typescript`,order:3}],Cr={"ksc-cspell":4,"ksc-eslint":2,"ksc-knip":6,"ksc-mdat":1,"ksc-prettier":5,"ksc-repo":0,"ksc-stylelint":3,"ksc-typescript":6};function $(e){let t=Sr.toSorted((e,t)=>e.order-t.order),n=[];for(let r of t)r.commands[e]!==void 0&&n.push({definition:r,effectiveKey:e});if(e===`fix`)for(let e of t)e.commands.fix===void 0&&e.commands.lint!==void 0&&n.push({definition:e,effectiveKey:`lint`});let r=[];for(let{definition:t,effectiveKey:i}of n){let n=i===`lint`?t.commands.lint:i===`fix`?t.commands.fix:void 0;if(n!==void 0&&(e===`lint`||e===`fix`)){let a={commands:n.commands,kind:`group`,logColor:t.logColor,logPrefix:t.logPrefix,name:t.name,parallel:n.parallel,positionalArgumentDefault:n.positionalArgumentDefault,positionalArgumentExtensions:n.positionalArgumentExtensions,positionalArgumentMode:n.positionalArgumentMode,showResolvedCommands:n.showResolvedCommands,stage:e===`fix`?Cr[t.name]??7:0,subcommand:Be(i),verbose:t.verbose};r.push(a);continue}let a={name:t.name,...i===`init`?{receiveOptionFlags:t.commands.init?.locationOptionFlag??!1}:{receivePositionalArguments:t.commands[i]?.positionalArgumentMode!==`none`},subcommands:[Be(i)]};r.push(a)}return r}await ht({commands:{fix:{commands:$(`fix`),description:`Fix your project with multiple tools in one go. Tools without auto-fixes run their checks afterward, so remaining issues match a subsequent lint. ${J.multiArgumentCaveat}`,parallel:!0,positionalArgumentMode:`optional`},init:{commands:$(`init`),description:`Initialize configuration files for the entire suite of @kitschpatrol/shared-config tools. ${J.multiOptionCaveat}`,locationOptionFlag:!0},lint:{commands:$(`lint`),description:`Lint your project with multiple tools in one go. ${J.multiArgumentCaveat}`,parallel:!0,positionalArgumentMode:`optional`},printConfig:{commands:$(`printConfig`),description:`Print aggregated tool configuration data. ${J.multiArgumentCaveat}`,positionalArgumentMode:`optional`}},description:`Run aggregated @kitschpatrol/shared-config commands.`,logColor:`yellow`,logPrefix:`🔬`,name:`ksc`,order:0,showSummary:!0,verbose:!0});export{};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { FileType, FileType as FileType$1 } from "@kitschpatrol/prettier-config";
|
|
2
|
-
//#region src/api.d.ts
|
|
3
2
|
/**
|
|
4
3
|
* Fix a source string by running all shared-config tools in sequence: Mdat →
|
|
5
4
|
* ESLint → Stylelint → Prettier. Mdat only runs for Markdown file type hints.
|
|
@@ -27,5 +26,4 @@ export declare function fixFile(filePath: string): Promise<void>;
|
|
|
27
26
|
* `fixFile` will re-import all tools.
|
|
28
27
|
*/
|
|
29
28
|
export declare function clearCache(): void;
|
|
30
|
-
//#endregion
|
|
31
29
|
export type { FileType };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kitschpatrol/shared-config",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.14.1",
|
|
4
4
|
"description": "A collection of shared configurations, linters, and formatting tools for TypeScript projects. All managed as a single dependency. All invoked via a single CLI command.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"shared-config",
|
|
@@ -49,41 +49,41 @@
|
|
|
49
49
|
"ksc": "bin/cli.js"
|
|
50
50
|
},
|
|
51
51
|
"files": [
|
|
52
|
-
"bin
|
|
53
|
-
"dist
|
|
54
|
-
"init
|
|
55
|
-
"skills
|
|
52
|
+
"bin",
|
|
53
|
+
"dist",
|
|
54
|
+
"init",
|
|
55
|
+
"skills"
|
|
56
56
|
],
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@kitschpatrol/cspell-config": "8.
|
|
59
|
-
"@kitschpatrol/eslint-config": "8.
|
|
60
|
-
"@kitschpatrol/knip-config": "8.
|
|
61
|
-
"@kitschpatrol/mdat-config": "8.
|
|
62
|
-
"@kitschpatrol/prettier-config": "8.
|
|
63
|
-
"@kitschpatrol/remark-config": "8.
|
|
64
|
-
"@kitschpatrol/repo-config": "8.
|
|
65
|
-
"@kitschpatrol/stylelint-config": "8.
|
|
66
|
-
"@kitschpatrol/typescript-config": "8.
|
|
58
|
+
"@kitschpatrol/cspell-config": "8.14.1",
|
|
59
|
+
"@kitschpatrol/eslint-config": "8.14.1",
|
|
60
|
+
"@kitschpatrol/knip-config": "8.14.1",
|
|
61
|
+
"@kitschpatrol/mdat-config": "8.14.1",
|
|
62
|
+
"@kitschpatrol/prettier-config": "8.14.1",
|
|
63
|
+
"@kitschpatrol/remark-config": "8.14.1",
|
|
64
|
+
"@kitschpatrol/repo-config": "8.14.1",
|
|
65
|
+
"@kitschpatrol/stylelint-config": "8.14.1",
|
|
66
|
+
"@kitschpatrol/typescript-config": "8.14.1",
|
|
67
67
|
"@pinojs/json-colorizer": "^4.0.0",
|
|
68
|
-
"@pnpm/lockfile.fs": "^1100.2.
|
|
68
|
+
"@pnpm/lockfile.fs": "^1100.2.16",
|
|
69
69
|
"cosmiconfig": "^10.0.1",
|
|
70
70
|
"cosmiconfig-typescript-loader": "^6.3.0",
|
|
71
|
-
"cspell": "^10.
|
|
72
|
-
"cspell-config-lib": "^10.
|
|
73
|
-
"cspell-lib": "^10.
|
|
71
|
+
"cspell": "^10.4.0",
|
|
72
|
+
"cspell-config-lib": "^10.4.0",
|
|
73
|
+
"cspell-lib": "^10.4.0",
|
|
74
74
|
"decircular": "^1.0.0",
|
|
75
75
|
"deepmerge": "^4.3.1",
|
|
76
76
|
"deepmerge-ts": "^8.0.2",
|
|
77
|
-
"execa": "^10.1
|
|
77
|
+
"execa": "^10.2.1",
|
|
78
78
|
"find-workspaces": "^0.3.1",
|
|
79
79
|
"fs-extra": "^11.4.1",
|
|
80
80
|
"globby": "^16.2.4",
|
|
81
81
|
"json-stringify-pretty-compact": "^4.0.0",
|
|
82
82
|
"magicast": "^0.5.5",
|
|
83
|
-
"mdat": "^3.6.
|
|
83
|
+
"mdat": "^3.6.6",
|
|
84
84
|
"package-up": "^5.0.0",
|
|
85
85
|
"picocolors": "^1.1.1",
|
|
86
|
-
"prettier": "^3.9.
|
|
86
|
+
"prettier": "^3.9.10",
|
|
87
87
|
"semver": "^7.8.5",
|
|
88
88
|
"stylelint": "^17.16.0",
|
|
89
89
|
"yargs": "^18.2.0"
|
package/readme.md
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
[](https://www.npmjs.com/package/@kitschpatrol/shared-config)
|
|
8
8
|
[](https://opensource.org/license/mit)
|
|
9
9
|
[](https://github.com/kitschpatrol/shared-config/actions/workflows/ci.yml)
|
|
10
|
+
[](https://www.npmjs.com/package/@kitschpatrol/shared-config)
|
|
10
11
|
|
|
11
12
|
<!-- description -->
|
|
12
13
|
|
|
@@ -202,7 +203,7 @@ pnpm --package=@kitschpatrol/repo-config dlx ksc-repo init && pnpm i && pnpm add
|
|
|
202
203
|
gh secret set PERSONAL_ACCESS_TOKEN --app actions --body $(op read 'op://Personal/GitHub Mika/PERSONAL_ACCESS_TOKEN')
|
|
203
204
|
```
|
|
204
205
|
|
|
205
|
-
The
|
|
206
|
+
The monthly dependency update workflow also needs a `CLAUDE_CODE_OAUTH_TOKEN` secret, a Claude subscription token generated with `claude setup-token`:
|
|
206
207
|
|
|
207
208
|
```sh
|
|
208
209
|
gh secret set CLAUDE_CODE_OAUTH_TOKEN --app actions --body $(op read 'op://Personal/Claude Code OAuth Token/credential')
|
|
@@ -386,9 +387,15 @@ The tasks share a problem matcher owner, so the panel reflects the most recent r
|
|
|
386
387
|
|
|
387
388
|
## Agent skills
|
|
388
389
|
|
|
389
|
-
This project bundles
|
|
390
|
+
This project bundles 4 [Agent Skills](https://agentskills.io) in its published package to help coding agents work with @kitschpatrol/shared-config.
|
|
390
391
|
|
|
391
|
-
To
|
|
392
|
+
To link the skills into your project with [pnpm](https://pnpm.io/agent-skills) 12.11 or later, approve the package once and pnpm links its skills on every install:
|
|
393
|
+
|
|
394
|
+
```sh
|
|
395
|
+
pnpm approve @kitschpatrol/shared-config
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
With other package managers, sync the skills from your project root with Vercel's [skills CLI](https://github.com/vercel-labs/skills):
|
|
392
399
|
|
|
393
400
|
```sh
|
|
394
401
|
npx skills experimental_sync
|
|
@@ -410,6 +417,14 @@ Code conventions and lint workflow for projects that use @kitschpatrol/shared-co
|
|
|
410
417
|
|
|
411
418
|
Run full dependency and repository maintenance in kitschpatrol shared config pnpm repositories and monorepos.
|
|
412
419
|
|
|
420
|
+
### Skill: [`mdat`](skills/mdat/SKILL.md)
|
|
421
|
+
|
|
422
|
+
Use and configure mdat, the Markdown Autophagic Template CLI and library that expands HTML comment placeholders such as `<!-- title -->` in Markdown files.
|
|
423
|
+
|
|
424
|
+
### Skill: [`mdat-plugin-authoring`](skills/mdat-plugin-authoring/SKILL.md)
|
|
425
|
+
|
|
426
|
+
Write custom mdat expansion rules and publishable mdat rule plugins (mdat-plugin-\* packages).
|
|
427
|
+
|
|
413
428
|
<!-- /skills -->
|
|
414
429
|
|
|
415
430
|
## Implementation notes
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mdat
|
|
3
|
+
description: Use and configure mdat, the Markdown Autophagic Template CLI and library that expands HTML comment placeholders such as `<!-- title -->` in Markdown files. Use when a readme or other Markdown file contains mdat comment placeholders, when editing mdat.config.ts or an "mdat" key in package.json, when generating or updating readme boilerplate from project metadata, when `mdat check` fails, or when calling the mdat TypeScript API.
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Using mdat
|
|
8
|
+
|
|
9
|
+
mdat expands HTML comments in Markdown files into generated content. A comment like `<!-- title -->` is a placeholder. Running `mdat` fills it in from a rule and adds a closing tag:
|
|
10
|
+
|
|
11
|
+
```md
|
|
12
|
+
<!-- title -->
|
|
13
|
+
|
|
14
|
+
# my-project
|
|
15
|
+
|
|
16
|
+
<!-- /title -->
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The comments stay in the file, so the content can be regenerated whenever the underlying data changes.
|
|
20
|
+
|
|
21
|
+
## Ground rules
|
|
22
|
+
|
|
23
|
+
- **Never hand-edit content between an opening tag and its closing tag.** It is overwritten on the next run. Change the comment's arguments, the rule, or the project metadata the rule reads from (e.g. `package.json`), then re-run `mdat`.
|
|
24
|
+
- **Text outside the tags is ordinary Markdown.** Edit it freely.
|
|
25
|
+
- **Re-run `mdat` after any change that affects generated content**, such as editing headings (the table of contents), `package.json` fields, or embedded files. Then confirm with `mdat check`.
|
|
26
|
+
- `mdat` rewrites files in place. Do not run it on files with uncommitted work you cannot recover.
|
|
27
|
+
- To add a placeholder, write only the opening comment. `mdat` adds the closing tag.
|
|
28
|
+
- Comments whose first word is not a known rule keyword are left alone, as are code-style comments like `<!-- // note -->`.
|
|
29
|
+
|
|
30
|
+
## CLI
|
|
31
|
+
|
|
32
|
+
If mdat is a project dependency, run it through the package manager (`pnpm mdat`, `npx mdat`). Run `mdat <command> --help` for the full option list.
|
|
33
|
+
|
|
34
|
+
| Command | Effect |
|
|
35
|
+
| ----------------------- | -------------------------------------------------------------------------------------- |
|
|
36
|
+
| `mdat` or `mdat expand` | Expand placeholders. With no files, expands the closest `readme.md`. |
|
|
37
|
+
| `mdat check` | Dry-run. Exits with code 1 if any file has stale or unexpanded content. Good for CI. |
|
|
38
|
+
| `mdat collapse` | Remove generated content, leaving only the opening comments. |
|
|
39
|
+
| `mdat strip` | Remove the mdat comments but keep the generated content. |
|
|
40
|
+
| `mdat create` | Create a new readme from a bundled template. Interactive unless `--interactive false`. |
|
|
41
|
+
|
|
42
|
+
Common options:
|
|
43
|
+
|
|
44
|
+
- `mdat docs/*.md` processes specific files.
|
|
45
|
+
- `--config a.ts b.json` (`-c`) loads additional rule files. Available on `expand` and `check`.
|
|
46
|
+
- `--format` (`-f`) formats output with Prettier, which must be installed. If the project formats Markdown with Prettier, pass `--format` to both `mdat` and `mdat check` so they agree.
|
|
47
|
+
- `--print` writes to stdout instead of the file.
|
|
48
|
+
- `--output` (`-o`) and `--name` (`-n`) write to a different directory or file name.
|
|
49
|
+
|
|
50
|
+
## Comment arguments
|
|
51
|
+
|
|
52
|
+
Arguments use function-call syntax with a single [JSON5](https://json5.org) value. Parentheses are required:
|
|
53
|
+
|
|
54
|
+
```md
|
|
55
|
+
<!-- install({ headingLevel: 2, dev: true }) -->
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Only JSON5 values are accepted. No JavaScript is evaluated. Bundled rules validate their arguments and report an error on unknown shapes.
|
|
59
|
+
|
|
60
|
+
## Bundled rules
|
|
61
|
+
|
|
62
|
+
These work without any configuration. They read normalized project metadata, so most also work in Python, Rust, Go, and Ruby projects, not only Node.
|
|
63
|
+
|
|
64
|
+
Rules that generate a section emit their own heading. Their `heading` option is `true` by default, takes a string to replace the heading text, and takes `false` to leave the heading out, e.g. under a hand-written heading or when a rule appears several times in one section. `headingLevel` sets the heading's level, with sub-headings nested one level deeper whether or not the heading is shown.
|
|
65
|
+
|
|
66
|
+
| Keyword | Output | Options |
|
|
67
|
+
| ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
68
|
+
| `title` | Project name as a heading. | |
|
|
69
|
+
| `banner` | A banner image found in the project directory. | |
|
|
70
|
+
| `badges` | npm version, license, CI, Git LFS, VS Code Marketplace, and Homebrew badges when detected, plus opt-in GitHub release, npm downloads, Obsidian downloads, and bundle size badges. | `npm`, `license`, `ci`, `gitLfs`, `vscode`, `homebrew`, `githubRelease`, `npmDownloads`, `obsidianDownloads`, `bundleSize`: `false` hides, `true` requires. Also `npm: string[]`, `homebrew: "owner/tap/formula"`, `custom: { [name]: { image, link } }` |
|
|
71
|
+
| `description` (alias `short-description`) | Project description. | |
|
|
72
|
+
| `table-of-contents` (alias `toc`) | Table of contents from the document headings. | `depth` (default `3`), `heading`, `headingLevel` (default `2`) |
|
|
73
|
+
| `install` (alias `installation`) | Install instructions for consumers of the package. Private packages are rejected. | `heading`, `headingLevel` (default `3`), `dev`, `homebrew` |
|
|
74
|
+
| `dependencies` | Runtime platform requirements and required peer dependencies. | `heading`, `headingLevel` (default `3`) |
|
|
75
|
+
| `development-dependencies` (alias `dev-dependencies`) | Tools needed to work on the project, from `devEngines` and `packageManager`. | `heading`, `headingLevel` (default `3`) |
|
|
76
|
+
| `contributing` | Invitation to open issues and pull requests. | `heading`, `headingLevel` (default `2`) |
|
|
77
|
+
| `license` | License section. | `heading`, `headingLevel` (default `2`) |
|
|
78
|
+
| `code` | A code block embedded from a file. | `file` (required), `language`, `trim` (default `true`) |
|
|
79
|
+
| `size` | A file's size. | `file` (required), `compression`: `none`, `gzip`, `brotli` |
|
|
80
|
+
| `size-table` | A table of file sizes with Gzip and Brotli columns. | `files` (required), `precision` (default `0`) |
|
|
81
|
+
| `skills` | Agent Skills found in `skills/<name>/SKILL.md` and how to install them. | `heading`, `headingLevel` (default `2`) |
|
|
82
|
+
| `header` | Compound: `title`, `banner`, `badges`, `short-description`. | Array, one entry per sub-rule in order. |
|
|
83
|
+
| `footer` | Compound: `contributing`, `license`. | Array, one entry per sub-rule in order. |
|
|
84
|
+
|
|
85
|
+
File paths in `code`, `size`, and `size-table` resolve from the current working directory.
|
|
86
|
+
|
|
87
|
+
## Configuration
|
|
88
|
+
|
|
89
|
+
Custom rules live in a config file found by [cosmiconfig](https://github.com/cosmiconfig/cosmiconfig). `mdat.config.ts` in the project root is the usual choice. The file default-exports a record whose keys become comment keywords:
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import { defineConfig } from 'mdat'
|
|
93
|
+
|
|
94
|
+
export default defineConfig({
|
|
95
|
+
// Object form: adds processing order
|
|
96
|
+
date: {
|
|
97
|
+
content: () => new Date().toISOString(),
|
|
98
|
+
order: 1,
|
|
99
|
+
},
|
|
100
|
+
// String: static replacement
|
|
101
|
+
greeting: 'Hello, world!',
|
|
102
|
+
// Function: sync or async, receives the comment's arguments, e.g. <!-- repeat(3) -->
|
|
103
|
+
repeat: (options) => 'ha'.repeat(Number(options)),
|
|
104
|
+
})
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
- A rule must return non-empty Markdown. Empty content and thrown errors are reported as errors.
|
|
108
|
+
- Custom rules merge with the bundled rules. A custom rule with the same keyword as a bundled rule replaces it.
|
|
109
|
+
- With multiple config files, the last rule for a keyword wins, and `--config` files take precedence over discovered config.
|
|
110
|
+
- JSON files work as rule sets. Nested keys are flattened into dot-notated keywords, so `{ "a": { "b": "x" } }` provides `<!-- a.b -->`.
|
|
111
|
+
- `package.json` can hold rules under an `"mdat"` key, or name a shared config package: `"mdat": "@scope/mdat-config"`.
|
|
112
|
+
- Rules from a plugin package are spread into the config: `defineConfig({ ...examplePlugin })`.
|
|
113
|
+
|
|
114
|
+
For rules that take validated arguments, read the document tree, or are shared across projects, use the `mdat-plugin-authoring` skill if it is available.
|
|
115
|
+
|
|
116
|
+
## Library API
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
import { check, expand, expandString } from 'mdat'
|
|
120
|
+
import { write } from 'to-vfile'
|
|
121
|
+
|
|
122
|
+
// Returns VFiles. Writing is the caller's responsibility.
|
|
123
|
+
const [file] = await expand('readme.md')
|
|
124
|
+
await write(file)
|
|
125
|
+
|
|
126
|
+
const result = await expandString('<!-- title -->')
|
|
127
|
+
console.log(result.toString())
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
- `expand`, `collapse`, `strip`, and `check` take file paths. With no files they find the closest readme.
|
|
131
|
+
- `expandString`, `collapseString`, `stripString`, and `checkString` take Markdown strings.
|
|
132
|
+
- `create` and `createInteractive` create a readme from a bundled template.
|
|
133
|
+
- `loadConfig` discovers and merges config. `defineConfig` and `mergeConfig` build config objects.
|
|
134
|
+
|
|
135
|
+
## Troubleshooting
|
|
136
|
+
|
|
137
|
+
- **A comment is not expanding.** The keyword does not match a loaded rule. Check spelling, confirm the config file is discovered or passed with `--config`, and run with `--verbose`.
|
|
138
|
+
- **`mdat check` fails.** Run `mdat` (with `--format` if the check used it) and commit the result. If it still fails, the rule output is non-deterministic, e.g. a timestamp.
|
|
139
|
+
- **Arguments are ignored or rejected.** Use parentheses: `<!-- keyword({ key: "value" }) -->`. The 1.x form without parentheses is no longer supported.
|
|
140
|
+
- **Old commands.** `mdat readme` is now `mdat`, `mdat readme init` is `mdat create`, and `mdat readme check` is `mdat check`. The `--rules`, `--assets`, `--package`, `--meta`, and `--prefix` options were removed in favor of `--config`.
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mdat-plugin-authoring
|
|
3
|
+
description: Write custom mdat expansion rules and publishable mdat rule plugins (mdat-plugin-* packages). Use when creating or debugging rule functions for mdat comment placeholders, validating comment arguments, reading project metadata or the Markdown tree inside a rule, building compound rules, or packaging and testing rules for reuse across projects.
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Authoring mdat rules and plugins
|
|
8
|
+
|
|
9
|
+
An mdat rule maps a comment keyword to generated Markdown. A rule plugin is an npm package whose default export is a record of rules. Start with a rule in the project's `mdat.config.ts`. Move it to a plugin package only when more than one project needs it.
|
|
10
|
+
|
|
11
|
+
## Rule shapes
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import type { Config } from 'mdat'
|
|
15
|
+
|
|
16
|
+
export default {
|
|
17
|
+
// String: static replacement for <!-- greeting -->
|
|
18
|
+
greeting: 'Hello, world!',
|
|
19
|
+
// Array: compound rule, each entry is itself a rule
|
|
20
|
+
intro: ['# My Project', () => 'Generated description.'],
|
|
21
|
+
// Object: adds processing order
|
|
22
|
+
summary: {
|
|
23
|
+
content: (_options, context) => `Source: ${context.filePath ?? 'unknown'}`,
|
|
24
|
+
order: 1,
|
|
25
|
+
},
|
|
26
|
+
// Function: sync or async
|
|
27
|
+
time: () => new Date().toDateString(),
|
|
28
|
+
} satisfies Config
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The full signature of a content function:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
type Content = (options: JsonValue, context: RuleContext) => Promise<string> | string
|
|
35
|
+
|
|
36
|
+
type RuleContext = {
|
|
37
|
+
/** File path of the source document, if known. */
|
|
38
|
+
filePath: string | undefined
|
|
39
|
+
/** Parsed YAML frontmatter from the document, if present. */
|
|
40
|
+
frontmatter: Record<string, unknown> | undefined
|
|
41
|
+
/** The full mdast tree of the document. Do not mutate. */
|
|
42
|
+
tree: Root
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Requirements for a rule
|
|
47
|
+
|
|
48
|
+
- **Return a non-empty Markdown string.** Empty output is reported as an error. If there is nothing to output, throw an error that says why.
|
|
49
|
+
- **Be deterministic.** `mdat check` compares a fresh expansion against the file on disk, so timestamps, random values, and unstable ordering make the check fail on every run.
|
|
50
|
+
- **Fail with a clear message.** Thrown errors are reported against the comment that triggered them. Include what was missing and how to fix it.
|
|
51
|
+
- **Resolve relative paths deliberately.** The bundled rules resolve file arguments from `process.cwd()`. Use `context.filePath` to resolve relative to the document instead.
|
|
52
|
+
- **Do not include the comment tags in the output.** mdat adds the opening and closing tags.
|
|
53
|
+
|
|
54
|
+
## Keywords
|
|
55
|
+
|
|
56
|
+
A keyword consists of letters, numbers, `_`, `$`, `-`, and `.`, and cannot start with `/`, `*`, `#`, `-`, or `.`. Prefer kebab-case, e.g. `cli-help`. Pick a specific keyword. A rule with the same keyword as a bundled rule (`title`, `badges`, `install`, `license`, and so on) replaces it.
|
|
57
|
+
|
|
58
|
+
## Arguments
|
|
59
|
+
|
|
60
|
+
A comment passes a single JSON5 value: `<!-- keyword({ file: "./a.ts", trim: false }) -->`. A comment without parentheses passes `{}`. Arguments are untrusted input, so validate them. The bundled rules use [Zod](https://zod.dev):
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import type { Config } from 'mdat'
|
|
64
|
+
import fs from 'node:fs/promises'
|
|
65
|
+
import path from 'node:path'
|
|
66
|
+
import { z } from 'zod'
|
|
67
|
+
|
|
68
|
+
const optionsSchema = z.object({
|
|
69
|
+
file: z.string(),
|
|
70
|
+
language: z.string().optional(),
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
export default {
|
|
74
|
+
embed: {
|
|
75
|
+
async content(options) {
|
|
76
|
+
const { file, language } = optionsSchema.parse(options)
|
|
77
|
+
const code = await fs.readFile(path.join(process.cwd(), file), 'utf8')
|
|
78
|
+
return `\`\`\`${language ?? path.extname(file).slice(1)}\n${code.trim()}\n\`\`\``
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
} satisfies Config
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Prefer an object argument over a bare primitive so options can be added later without breaking existing comments.
|
|
85
|
+
|
|
86
|
+
## Project metadata
|
|
87
|
+
|
|
88
|
+
mdat exports helpers so rules do not need to parse `package.json` themselves. Both are memoized and work across ecosystems (Node, Python, Rust, Go, Ruby) via [metascope](https://github.com/kitschpatrol/metascope):
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
import { getContextMetadata, getReadmeMetadata } from 'mdat'
|
|
92
|
+
|
|
93
|
+
// Normalized fields the bundled readme rules use, e.g. name, description,
|
|
94
|
+
// repositoryUrl, issuesUrl, license, author, bin, engines, peerDependencies.
|
|
95
|
+
// Any field may be undefined.
|
|
96
|
+
const { name, repositoryUrl } = await getReadmeMetadata()
|
|
97
|
+
|
|
98
|
+
// The full metascope metadata context for anything not covered above.
|
|
99
|
+
const metadata = await getContextMetadata()
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
See the exported `ReadmeMetadata` type for the complete field list. Call `resetMetadataCaches()` between tests that change project files on disk.
|
|
103
|
+
|
|
104
|
+
## Headings
|
|
105
|
+
|
|
106
|
+
Follow the convention of the bundled rules so that readmes stay consistent:
|
|
107
|
+
|
|
108
|
+
- A rule that generates a section emits its own heading. A rule that generates inline content, like a badge or a code block, has no heading.
|
|
109
|
+
- Accept a `heading` option. `true` is the default and emits the rule's standard heading, a string replaces the heading text, and `false` leaves the heading out.
|
|
110
|
+
- Accept a `headingLevel` option (`1`-`6`) for the heading's level. Nest any sub-headings one level deeper, whether or not the heading is shown. Default to the level that suits the section's usual place in a readme.
|
|
111
|
+
|
|
112
|
+
## Order and compound rules
|
|
113
|
+
|
|
114
|
+
- `order` defaults to `0`. Rules with a higher order run later. Use it when a rule reads content other rules generate. The bundled `table-of-contents` rule uses `order: 1` so that it sees headings produced by other rules.
|
|
115
|
+
- A compound rule is an array of rules whose output is joined under one keyword. Its comment takes an array of arguments, one entry per sub-rule in order: `<!-- footer([{ headingLevel: 3 }, { headingLevel: 3 }]) -->`.
|
|
116
|
+
- To reuse a rule from another single-rule record inside a compound rule, use `getSoleRule` from `remark-mdat`.
|
|
117
|
+
|
|
118
|
+
## Packaging a plugin
|
|
119
|
+
|
|
120
|
+
- Name the package with the `mdat-plugin-` prefix and add the `mdat-plugin` keyword.
|
|
121
|
+
- Publish ESM with a default export of the rule record, typed with `satisfies Config`.
|
|
122
|
+
- Declare `mdat` as a peer dependency, and as a dev dependency for tests.
|
|
123
|
+
- One package may export several related rules.
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"name": "mdat-plugin-example",
|
|
128
|
+
"type": "module",
|
|
129
|
+
"exports": {
|
|
130
|
+
".": {
|
|
131
|
+
"types": "./dist/index.d.ts",
|
|
132
|
+
"import": "./dist/index.js"
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
"keywords": ["mdat", "mdat-plugin"],
|
|
136
|
+
"peerDependencies": {
|
|
137
|
+
"mdat": "^3.0.0"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Consumers spread the plugin into their config:
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import { defineConfig } from 'mdat'
|
|
146
|
+
import example from 'mdat-plugin-example'
|
|
147
|
+
|
|
148
|
+
export default defineConfig({ ...example })
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
[mdat-plugin-example](https://github.com/kitschpatrol/mdat-plugin-example) is a minimal template repository. [mdat-plugin-cli-help](https://github.com/kitschpatrol/mdat-plugin-cli-help) and [mdat-plugin-tldraw](https://github.com/kitschpatrol/mdat-plugin-tldraw) are fuller examples with arguments and file output.
|
|
152
|
+
|
|
153
|
+
## Testing
|
|
154
|
+
|
|
155
|
+
Test rules through the public API with `expandString`, passing the rule record as config:
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
import { expandString } from 'mdat'
|
|
159
|
+
import { expect, it } from 'vitest'
|
|
160
|
+
import plugin from '../src/index'
|
|
161
|
+
|
|
162
|
+
it('expands the example rule', async () => {
|
|
163
|
+
const result = await expandString('<!-- example -->', plugin)
|
|
164
|
+
expect(result.toString()).toContain('Hello from')
|
|
165
|
+
expect(result.messages.filter((message) => message.fatal)).toHaveLength(0)
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
it('is stable across runs', async () => {
|
|
169
|
+
const first = await expandString('<!-- example -->', plugin)
|
|
170
|
+
const second = await expandString(first.toString(), plugin)
|
|
171
|
+
expect(second.toString()).toEqual(first.toString())
|
|
172
|
+
})
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Also cover invalid arguments. Rule errors are not thrown. They are reported as messages on the returned VFile with `fatal: true`, alongside informational messages for each successful expansion, so assert on the fatal messages in `result.messages`.
|
|
176
|
+
|
|
177
|
+
To try a rule file against a real document without touching it, run `mdat --config ./my-rules.ts --print some-file.md`.
|