@kitschpatrol/remark-config
Version:
Markdown and MDX linting for @kitschpatrol/shared-config.
8 lines • 11.2 kB
JavaScript
import{cosmiconfig as e}from"cosmiconfig";import{TypeScriptLoader as t}from"cosmiconfig-typescript-loader";import{execa as n}from"execa";import r from"fs-extra";import i from"node:fs";import a from"node:path";import{PassThrough as o,Transform as s}from"node:stream";import{fileURLToPath as c}from"node:url";import{packageUp as l,packageUpSync as u}from"package-up";import d from"picocolors";import f from"yargs";import{hideBin as p}from"yargs/helpers";import m from"@pinojs/json-colorizer";import h from"decircular";import g from"deepmerge";import _ from"json-stringify-pretty-compact";import{findWorkspacesRoot as v}from"find-workspaces";import y from"node:fs/promises";import{stripVTControlCharacters as b}from"node:util";var x=`7.6.2`;function S(e){return e instanceof Error&&`exitCode`in e&&typeof e.exitCode==`number`}function C(e){return m(_(h(e),{indent:2,replacer(e,t){return typeof t==`function`?t.name:t}}),{colors:{BRACKET:`gray`}})}const w=(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]=T(e[i],a,n):e.includes(a)||r.push(a);return r};function T(e,t,n={arrayMerge:w}){return g(e,t,n)}function E(){let e=u();if(e===void 0)throw Error(`No package.json found.`);return a.dirname(e)}function D(){let e=v();return e===null?E():a.resolve(e.location)}function O(e){if(e===`workspace-root`)return D();if(e===`package-dir`)return E();if(typeof e==`string`){if(!r.pathExistsSync(e))throw Error(`Custom cwd directory does not exist: ${e}`);return e}return process.cwd()}async function k(e,t){try{let{default:n}=await import(`prettier`),r=await n.resolveConfig(e),i=await n.format(t,{filepath:e,...r});await y.writeFile(e,i,`utf8`)}catch{console.warn(`Skipped formatting ${e} since Prettier is not installed.`)}}async function A(e){try{await k(e,await y.readFile(e,`utf8`))}catch{}}const j=/\r?\n/;function M(e){return new s({transform(t,n,r){let i=t.toString().split(j).filter(t=>t.trim()!==``&&!e(b(t))).join(`
`);this.push(i+`
`),r()}})}function N(e,t){return new s({transform(n,r,i){let a=n.toString().split(j).filter(e=>e.trim().length>0).map(n=>`${e?t===void 0?e:d[t](e):``} ${n}\n`).join(``);this.push(a),i()}})}async function P(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 F(e,t){return t===1?e:e+`s`}async function I(e,t,n,r,i){let a=1,o;if(r.logPrefix===void 0)o=e;else{let t=N(r.logPrefix,r.logColor);t.pipe(e),o=t}i&&o.write(d.bold(`Running: "${r.name}() with Positional arguments: ${String(t)} and Option flags: ${String(n)}"`));try{a=await r.execute(o,t,n)}catch(e){console.error(String(e)),a=1}return a}async function L(e,t,r,i,a){let s=1,c;if(i.logPrefix===void 0)c=e;else{let t=N(i.logPrefix,i.logColor);t.pipe(e),c=t}let l=i.subcommands??[],u=[...i.receivePositionalArguments?t:[],...i.positionalArguments??[]],d=[...i.receiveOptionFlags?r:[],...i.optionFlags??[]],f=[...l,...d,...u],p=O(i.cwdOverride);a&&c.write(`Running: "${i.name} ${f.join(` `)}"`);let m=i.prettyJsonOutput?new o:c;try{let e=n(i.name,f,{cwd:p,env:{...process.env.NO_COLOR===void 0?{FORCE_COLOR:`true`}:{}},preferLocal:!0,reject:!1,stdin:`inherit`});if(i.outputFilter){let t=M(i.outputFilter),n=M(i.outputFilter);e.stdout.pipe(t).pipe(m,{end:!1}),e.stderr.pipe(n).pipe(m,{end:!1})}else e.stdout.pipe(m,{end:!1}),e.stderr.pipe(m,{end:!1});if(await e,i.prettyJsonOutput){m.end();let e=await P(m),t=C(JSON.parse(e)).split(`
`);for(let e of t)c.write(`${e}\n`)}s=e.exitCode??1}catch(e){console.error(`${i.name} failed with error:`),console.error(e),S(e)&&(s=typeof e.exitCode==`number`?e.exitCode:1)}return s}function R(e){return`execute`in e}const z=/^ksc-/;function B(e){return e.replace(z,``)}function V(e){return e===void 0||e.length===0?[]:e.flatMap(e=>e.split(`,`)).map(e=>B(e.trim()))}function H(e){return e.option(`skip`,{array:!0,describe:`Tool names to skip (with or without "ksc-" prefix).`,type:`string`})}async function U(e,t,n,r,i,a,o){let s=o??[],c=[],l=[];for(let e of r)s.length>0&&s.includes(B(e.name))?l.push(e):c.push(e);if(s.length>0){let t=new Set(l.map(e=>B(e.name))),n=s.filter(e=>!t.has(e));if(n.length>0){let t=r.map(e=>B(e.name)).join(`, `);e.write(`⚠️ ${d.yellow(`Unrecognized --skip ${F(`value`,n.length)}: ${n.join(`, `)}. Available: ${t}`)}\n`)}}let u=[];for(let r of c){let a=await(R(r)?I(e,t,n,r,i):L(e,t,n,r,i));u.push({exitCode:a,name:r.name})}let f=r.length;if(l.length>0){let t=l.map(({name:e})=>e);e.write(`⏭️ ${d.dim(d.bold(`${t.length} / ${f} ${F(`Command`,t.length)} Skipped:`))} ${d.dim(t.join(`, `))}\n`)}if(a){let t=u.filter(({exitCode:e})=>e===0).map(({name:e})=>e),n=u.filter(({exitCode:e})=>e!==0).map(({name:e})=>e);t.length>0&&e.write(`✅ ${d.green(d.bold(`${t.length} / ${f} ${F(`Command`,t.length)} Succeeded:`))} ${d.green(t.join(`, `))}\n`),n.length>0&&e.write(`❌ ${d.red(d.bold(`${n.length} / ${f} ${F(`Command`,n.length)} Failed:`))} ${d.red(n.join(`, `))}\n`)}return+!u.every(({exitCode:e})=>e===0)}async function W(e,t,n,o){let s=await l();if(s===void 0)throw Error("The `init` command must be used in a directory with a package.json file");let u=await l({cwd:c(import.meta.url)});if(u===void 0)return e.write(`Error: The script being called was not in a package, weird.
`),1;let d=a.join(a.dirname(u),`init`),f=a.dirname(s),p=(t===`file`||t===`package`)&&n!==void 0&&o!==void 0;try{if(p){let n=Object.keys(o)[0];if(t===`package`){let t=r.readJsonSync(s);e.write(`Merging: \nPackage config key "${n}" → "${f}" (Because --location is set to "package")\n`);let i=T(t,o);r.writeJSONSync(s,i,{spaces:` `}),await A(s)}else{let t=r.readJsonSync(s);Object.keys(t).includes(n)&&(e.write(`Deleting: \nPackage config key "${n}" in "${f}" (Because --location is set to "file")\n`),delete t[n],r.writeJSONSync(s,t,{spaces:` `}),await A(s))}}if(!await r.pathExists(d))return 0;if((await r.readdir(d)).length===0)return e.write(`Source directory "${d}" is empty.\n`),0;e.write(`Adding initial configuration files from:\n"${d}" → "${f}"\n`),await r.copy(d,f,{async filter(o,s){let c=i.statSync(o).isFile(),l=i.existsSync(s);if(c){if(p&&t===`package`&&o.includes(n))return l?(e.write(`Deleting: \n"${o}" → "${s}" (Because --location is set to "package")\n`),r.removeSync(s)):e.write(`Skipping: \n"${o}" → "${s}" (Because --location is set to "package")\n`),!1;if(l&&(s.includes(`.vscode/`)||s.includes(`package.json`))&&a.extname(s)===`.json`){e.write(`Merging: \n"${o}" → "${s}"\n`);let t=r.readJSONSync(o),n=T(r.readJSONSync(s),t);return r.writeJSONSync(s,n,{spaces:` `}),await A(s),!1}return l?(e.write(`Overwriting: \n"${o}" → "${s}"\n`),await A(s),!0):(e.write(`Copying: \n"${o}" → "${s}"\n`),await A(s),!0)}return!0},overwrite:!0})}catch(e){return console.error(String(e)),1}return 0}async function G(e){let{commands:{fix:t,init:n,lint:r,printConfig:i},description:a,logColor:o,logPrefix:s,name:c,showSummary:l,verbose:u}=e,d=N(s,o);d.pipe(process.stdout);let m=f(p(process.argv)).scriptName(c).usage(`$0 <command>`,a);n!==void 0&&m.command({builder(e){let t=n.locationOptionFlag?e.option(`location`,{choices:[`file`,`package`],default:`file`,describe:`Where to store the configuration.`,type:`string`}):e;return l?H(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=V(e.skip),i=await U(d,[],t===void 0?[]:[`--location`,t],[{async execute(e,t,r){return W(e,r.at(1),n.configFile,n.configPackageJson)},name:`copyAndMergeInitFiles`},...n.commands??[]],void 0,void 0,r);process.exit(i)}}),r!==void 0&&m.command({builder(e){let t=r.positionalArgumentMode===`none`?e:e.positional(`files`,{array:!0,...r.positionalArgumentDefault===void 0?{}:{default:r.positionalArgumentDefault},describe:`Files or glob pattern to lint.`,type:`string`});return l?H(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=V(e.skip),i=await U(d,t,[],r.commands,u,l,n);process.exit(i)}}),t!==void 0&&m.command({builder(e){let n=t.positionalArgumentMode===`none`?e:e.positional(`files`,{array:!0,...t.positionalArgumentDefault===void 0?{}:{default:t.positionalArgumentDefault},describe:`Files or glob pattern to fix.`,type:`string`});return l?H(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=V(e.skip),i=await U(d,n,[],t.commands,void 0,void 0,r);process.exit(i)}}),i!==void 0&&m.command({builder(e){let t=i.positionalArgumentMode===`none`?e:e.positional(`file`,{...i.positionalArgumentDefault===void 0?{}:{default:i.positionalArgumentDefault},describe:`File or glob pattern to print configuration for.`,type:`string`});return l?H(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=V(e.skip),a=await U(d,n,[],i.commands,u,l,r);process.exit(a)}}),m.alias(`h`,`help`),m.version(x),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.
`),0;let o=C(r).split(`
`);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.`};await G({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});export{};