validate-package-exports 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  /*!
3
3
  * @file validate-package-exports
4
- * @version 0.1.0
4
+ * @version 0.2.0
5
5
  * @license MIT
6
6
  * @copyright Eric King 2024
7
7
  * @see {@link https://github.com/webdeveric/validate-package-exports/#readme}
8
8
  */
9
- import Ye from"node:assert";import{join as Ze,resolve as et}from"node:path";import{parseArgs as tt}from"node:util";import{Console as $e}from"node:console";var x={emergency:0,alert:1,critical:2,error:3,warning:4,notice:5,info:6,debug:7};var y=e=>t=>typeof t=="string"&&e.test(t),a=e=>t=>Array.isArray(t)&&t.every(e);var i=e=>t=>typeof t>"u"||e(t);var u=e=>typeof e=="string",M=e=>typeof e=="number"&&!Number.isNaN(e),T=e=>typeof e=="bigint",F=e=>typeof e=="boolean",Ee=e=>typeof e>"u",D=e=>typeof e=="symbol",q=e=>e===null;var d=i(u),it=i(M),st=i(T),at=i(F),pt=i(D),ct=i(q),N=a(u),mt=a(M),yt=a(T),lt=a(F),ut=a(Ee),ft=a(D),dt=a(q);var he=y(/^[-+]?\d+(\.\d+)?$/),be=e=>typeof e=="number"||typeof e=="bigint"||he(e),gt=a(be),Pt=y(/^[-+]?\d+$/),xt=y(/^\d+$/);var f=e=>e!==null&&typeof e=="object"&&!Array.isArray(e);var U=e=>f(e)&&Object.entries(e).every(N);function G(e){return Object.keys(x).includes(String(e))}function W(e){return Object.values(x).includes(e)}function ke(e){return e==="commonjs"||e==="module"}var V=y(/\.\d+(\.gz)?$/),ve=a(V),we=e=>V(e)||ve(e),Re=i(we);function Ce(e){return f(e)&&d(e.bin)&&d(e.man)}var Ne=i(Ce);function Le(e){return u(e)||U(e)}function z(e){return typeof e=="string"&&e.startsWith("./")}var Se=/^(?<before>\.\/[^*]*)\*(?<after>[^*]*)$/,vt=y(Se);function L(e){return e===null||z(e)}var je=y(/^(?![\\.0-9])./);function E(e){return f(e)?Object.entries(e).every(([r,o])=>je(r)&&O(o)):!1}function S(e){return f(e)?Object.entries(e).every(([r,o])=>(r==="."||z(r))&&O(o)):!1}function h(e){return L(e)||E(e)}var j=a(h);function O(e){return h(e)||j(e)}function Oe(e){return O(e)||S(e)}var A=e=>f(e)&&Object.entries(e).every(t=>typeof t[0]=="string"&&(typeof t[1]=="string"||typeof t[1]=="boolean"));function Ae(e){return u(e)||A(e)}var Be=i(Ae);function _(e){return f(e)&&u(e.name)&&u(e.version)&&d(e.main)&&d(e.module)&&Be(e.browser)&&d(e.types)&&Re(e.man)&&Ne(e.directories)&&i(ke)(e.type)&&i(Oe)(e.exports)&&i(Le)(e.bin)&&i(N)(e.files)}function B(e){return typeof e>"u"?4:W(e)?e:G(e)?x[e]:4}var b=class extends $e{#e;constructor(t={},r){super({stdout:process.stdout,stderr:process.stderr,inspectOptions:{depth:null},...t}),this.#e=B(r)}get logLevel(){return this.#e}set logLevel(t){this.#e=B(t)}willLog(t){return this.#e>=t}emergency(...t){this.#e>=0&&super.log(...t)}alert(...t){this.#e>=1&&super.log(...t)}critical(...t){this.#e>=2&&super.log(...t)}error(...t){this.#e>=3&&super.error(...t)}warning(...t){this.warn(...t)}warn(...t){this.#e>=4&&super.warn(...t)}notice(...t){this.#e>=5&&super.info(...t)}info(...t){this.#e>=6&&super.info(...t)}debug(...t){this.#e>=7&&super.info(...t)}};import{setMaxListeners as He}from"node:events";import{dirname as Qe}from"node:path";import{Readable as w}from"node:stream";import{relative as K}from"node:path";import{stat as Ie}from"node:fs/promises";async function J(e){return(await Ie(e)).isFile()}async function H(e){try{if(await J(e.resolvedPath)===!1)throw new Error(`${e.resolvedPath} is not a file`);return{name:"file-exists",code:0,message:K(process.cwd(),e.resolvedPath),entryPoint:e}}catch(t){return{name:"file-exists",code:1,entryPoint:e,message:K(process.cwd(),e.resolvedPath),error:t instanceof Error?t:new Error(String(t))}}}import{relative as Q}from"node:path";import{exec as Me}from"node:child_process";import{promisify as Te}from"node:util";var g=Te(Me);async function X(e,t){try{return await g(`node --check ${e.resolvedPath}`,t),{code:0,entryPoint:e,message:Q(process.cwd(),e.resolvedPath),name:"check-syntax"}}catch(r){return{code:1,entryPoint:e,error:r instanceof Error?r:new Error(String(r)),message:Q(process.cwd(),e.resolvedPath),name:"check-syntax"}}}import{relative as Fe,dirname as De,basename as qe,resolve as Ue}from"node:path";function Y(e,t){return t==="."?e:`${e}/${t.replace(/^\.\//,"")}`}function Z(e,t="commonjs",r){return r==="require"||e.endsWith(".cjs")?"commonjs":r==="import"||e.endsWith(".mjs")?"module":t}function s({condition:e,itemPath:t,modulePath:r,packageDirectory:o,packageName:n,packageType:c="commonjs",subpath:p}){let m=Ue(o,r);return{moduleName:p?Y(n,p):void 0,type:Z(r,c,e),fileName:qe(m),relativePath:Fe(o,m),directory:De(m),resolvedPath:m,subpath:p,condition:e,itemPath:t}}function ee(e,t){return typeof e=="string"?{[t]:e}:e}function*te(e,t){if(e.bin)for(let[r,o]of Object.entries(ee(e.bin,e.name)))yield s({condition:void 0,itemPath:typeof e.bin=="string"?["bin"]:["bin",r],modulePath:o,packageDirectory:t,packageName:e.name,packageType:e.type,subpath:void 0})}import{opendir as We}from"node:fs/promises";import{resolve as Ge}from"node:path";function k(e){return Ge(e.path.endsWith(e.name)?e.path.replace(new RegExp(`[/\\\\]${e.name}$`,"i"),""):e.path,e.name)}async function*re(e,t){if(typeof e.directories?.bin=="string"){let r=await We(e.directories.bin);for await(let o of r)o.isFile()&&(yield s({condition:void 0,itemPath:["directories","bin"],modulePath:k(o),packageDirectory:t,packageName:e.name,packageType:e.type,subpath:void 0}))}}function*oe(e,t){if(e.browser){if(A(e.browser)){let r=Object.entries(e.browser).filter(o=>typeof o[0]=="string"&&typeof o[1]=="string");for(let[o,n]of r)yield s({condition:void 0,itemPath:["browser",o],modulePath:n,packageDirectory:t,packageName:e.name,packageType:e.type,subpath:void 0});return}yield s({condition:void 0,itemPath:["browser"],modulePath:e.browser,packageDirectory:t,packageName:e.name,packageType:e.type,subpath:void 0})}}var v=class{processExportsEntryPath(t,r){return t===null?[]:[s({modulePath:t,subpath:".",...r})]}processExportsEntry(t,r){return E(t)?this.processConditionalExports(t,r):this.processExportsEntryPath(t,r)}processExportsEntryArray(t,r){return t.map((o,n)=>this.processExportsEntry(o,{...r,itemPath:[...r.itemPath,n]})).flat()}processSubpathExports(t,r){return Object.entries(t).map(([o,n])=>this.process(n,{...r,subpath:o,itemPath:[...r.itemPath,o]})).flat()}processConditionalExports(t,r){let o=(n,c,p)=>{if(E(c))return n;if(p.at(-1)==="default"){let m=p.at(-2);if(typeof m=="string")return m}return n};return Object.entries(t).map(([n,c])=>{let p=[...r.itemPath,n];return this.process(c,{...r,condition:o(n,c,p),itemPath:p})}).flat()}process(t,r){return L(t)?this.processExportsEntryPath(t,r):j(t)?this.processExportsEntryArray(t,r):h(t)?this.processExportsEntry(t,r):S(t)?this.processSubpathExports(t,r):E(t)?this.processConditionalExports(t,r):[]}};import{opendir as Ve}from"node:fs/promises";async function*ne(e){if(!e.resolvedPath.includes("*")){yield e;return}let[t,r]=e.resolvedPath.split("*"),o=t?new RegExp(`^${t}`,"i"):void 0,n=r?new RegExp(`${r}$`,"i"):void 0,c=["moduleName","relativePath","fileName","resolvedPath"],p=P=>{let l=P;return o&&(l=l.replace(o,"")),n&&(l=l.replace(n,"")),l},m=await Ve(e.directory);for await(let P of m)if(P.isFile()&&(typeof r>"u"||P.name.endsWith(r))){let l=p(k(P));yield c.reduce((C,$)=>{let I=C[$];return I&&(C[$]=I.replace("*",l)),C},structuredClone(e))}}async function*ie(e,t){if(e.exports){let r=new v().process(e.exports,{packageType:e.type??"commonjs",packageName:e.name,packageDirectory:t,itemPath:["exports"]});for(let o of r)yield*ne(o)}}function*se(e,t){e.main&&(yield s({condition:void 0,itemPath:["main"],modulePath:e.main,packageDirectory:t,packageName:e.name,packageType:e.type,subpath:"."}))}function*ae(e,t){e.module&&(yield s({condition:void 0,itemPath:["module"],modulePath:e.module,packageDirectory:t,packageName:e.name,packageType:e.type,subpath:"."}))}function*pe(e,t){let r="types"in e?"types":"typings"in e?"typings":void 0;if(r){let o=e[r];o&&(yield s({condition:"types",itemPath:[r],modulePath:o,packageDirectory:t,packageName:e.name,packageType:e.type,subpath:void 0}))}}async function*ce(e,t){yield*te(e,t),yield*re(e,t),yield*oe(e,t),yield*se(e,t),yield*ae(e,t),yield*pe(e,t),yield*ie(e,t)}import{AssertionError as ze}from"node:assert";function me(e){if(!_(e))throw new ze({message:"input is not PackageJson",actual:e})}import{readFile as _e}from"node:fs/promises";async function ye(e){let t=await _e(e,"utf-8");return JSON.parse(t)}async function le(e){let t=await ye(e);return me(t),t}async function ue(e,t){let r=/\.json$/i.test(e)?`node --input-type=module --eval="import '${e}' assert { type: 'json' };"`:`node --input-type=module --eval="import '${e}';"`;await g(r,t)}async function fe(e,t){try{return typeof e.moduleName=="string"?(await ue(e.moduleName,t),{code:0,entryPoint:e,message:e.moduleName,name:"import"}):{code:2,entryPoint:e,message:`Import skipped: ${e.itemPath.join(".")}`,name:"import"}}catch(r){return{code:1,entryPoint:e,error:r instanceof Error?r:new Error(String(r)),message:`${e.moduleName??e.itemPath.join(".")} cannot be imported`,name:"import"}}}async function de(e,t){let r=`node --input-type=commonjs --eval="require('${e}');"`;await g(r,t)}async function ge(e,t){try{return typeof e.moduleName=="string"?(await de(e.moduleName,t),{code:0,entryPoint:e,message:e.moduleName,name:"require"}):{code:2,entryPoint:e,message:`Require skipped: ${e.itemPath.join(".")}`,name:"require"}}catch(r){return{code:1,entryPoint:e,error:r instanceof Error?r:new Error(String(r)),message:`${e.moduleName??e.itemPath.join(".")} cannot be required`,name:"require"}}}function Je(e){return typeof e.condition>"u"||e.condition==="require"}function Ke(e){return typeof e.condition>"u"||e.condition==="import"}async function Pe(e,t){let r=[];try{typeof e.moduleName=="string"&&(Je(e)&&r.push(await ge(e,t)),Ke(e)&&r.push(await fe(e,t)))}catch(o){if(o instanceof Error)throw new Error(`Unable to verify "${e.moduleName}"`,{cause:o})}return r}var R=class{options;packageDirectory;#e;#t;logger;constructor(t,r){this.options=t,this.packageDirectory=Qe(this.options.package),this.logger=r,this.#e=0,this.#t=new AbortController,He(100,this.#t.signal)}processResult(t){t.code===1&&(this.#e=1,this.options.bail&&this.#t.abort());let r=t.code===0?"\u2705":t.code===1?"\u274C":"\u{1F610}";t.code===1?(this.logger.error(`${r} ${t.name}: ${t.message} (${JSON.stringify(t.entryPoint.itemPath)})`),this.logger.error(t.error)):this.logger.info(`${r} ${t.name}: ${t.message}`)}processResults(t){[t].flat().forEach(r=>this.processResult(r))}async run(){let t=await le(this.options.package);this.logger.debug(`\u{1F4C2} package directory: ${this.packageDirectory}`),this.logger.debug({options:this.options,packageJson:t});let r=await w.from(ce(t,this.packageDirectory),{objectMode:!0}).toArray({signal:this.#t.signal});if(await w.from(r).forEach(async o=>{let n=await H(o);this.processResults(n)},{signal:this.#t.signal,concurrency:this.options.concurrency}),this.options.check){let o=r.filter(n=>/\.[cm]?js$/i.test(n.resolvedPath));await w.from(o).forEach(async n=>{let c=await X(n,{signal:this.#t.signal});this.processResults(c)},{signal:this.#t.signal,concurrency:this.options.concurrency})}return this.options.verify&&await w.from(r).forEach(async o=>{let n=await Pe(o,{cwd:this.packageDirectory,signal:this.#t.signal});this.processResults(n)},{signal:this.#t.signal,concurrency:this.options.concurrency}),this.#e}};import{availableParallelism as Xe}from"node:os";function xe(e){let t=Xe(),r=Number.parseInt(`${e}`);return Number.isInteger(r)?Math.max(1,Math.min(r,t)):t}try{let{values:e}=tt({allowPositionals:!1,strict:!0,tokens:!0,options:{package:{type:"string",short:"p",default:Ze(process.cwd(),"package.json")},concurrency:{type:"string",short:"c"},bail:{type:"boolean",short:"b",default:process.env.CI==="true"},check:{type:"boolean",default:!1,short:"s"},verify:{type:"boolean",default:!1,short:"v"},logLevel:{type:"string",short:"l",default:process.env.RUNNER_DEBUG==="1"?"debug":"info"}}});Ye(e.package,"Package not defined"),process.exitCode=await new R({package:et(e.package),concurrency:xe(e.concurrency),bail:!!e.bail,check:!!e.check,verify:!!e.verify},new b({stdout:process.stdout,stderr:process.stderr,inspectOptions:{depth:null}},e.logLevel)).run()}catch(e){console.dir(e,{depth:null}),process.exitCode??=1}
9
+ import{setMaxListeners as re}from"node:events";var a=class{name;code;message;entryPoint;error;constructor(e){this.name=e.name,this.code=e.code,this.message=e.message,this.entryPoint=e.entryPoint,this.error=e.error}toString(){let e=this.code===0?"\u2705":this.code===1?"\u274C":"\u{1F610}";return this.code===1?`${e} ${this.name}: ${this.message} (${JSON.stringify(this.entryPoint.itemPath)}) ${this.error??""}`.trim():`${e} ${this.name}: ${this.message}`}};import{EventEmitter as Kt}from"node:events";import{dirname as Ht}from"node:path";import{Readable as b}from"node:stream";import{relative as B}from"node:path";import{stat as xt}from"node:fs/promises";async function I(t){return(await xt(t)).isFile()}async function M(t){try{if(await I(t.resolvedPath)===!1)throw new Error(`${t.resolvedPath} is not a file`);return new a({name:"file-exists",code:0,message:`${B(process.cwd(),t.resolvedPath)} exists`,entryPoint:t})}catch(e){return new a({name:"file-exists",code:1,entryPoint:t,message:`${B(process.cwd(),t.resolvedPath)} does not exist`,error:e instanceof Error?e:new Error(String(e))})}}import{relative as D}from"node:path";import{exec as ht}from"node:child_process";import{promisify as kt}from"node:util";var g=kt(ht);async function J(t,e){try{return await g(`node --check ${t.resolvedPath}`,e),new a({code:0,entryPoint:t,message:`${D(process.cwd(),t.resolvedPath)} has valid syntax`,name:"check-syntax"})}catch(r){return new a({code:1,entryPoint:t,error:r instanceof Error?r:new Error(String(r)),message:`Could not validate syntax for ${D(process.cwd(),t.resolvedPath)}`,name:"check-syntax"})}}import{relative as bt,dirname as wt,basename as vt,resolve as jt}from"node:path";function L(t,e){return e==="."?t:`${t}/${e.replace(/^\.\//,"")}`}function q(t,e="commonjs",r){return r==="require"||t.endsWith(".cjs")?"commonjs":r==="import"||t.endsWith(".mjs")?"module":e}function c({condition:t,itemPath:e,modulePath:r,packageContext:o,subpath:s}){let i=jt(o.directory,r);return{moduleName:s?L(o.name,s):void 0,packagePath:o.path,type:q(r,o.type,t),fileName:vt(i),relativePath:bt(o.directory,i),directory:wt(i),resolvedPath:i,subpath:s,condition:t,itemPath:e}}function T(t,e){return typeof t=="string"?{[e]:t}:t}function*G(t,e){if(t.bin)for(let[r,o]of Object.entries(T(t.bin,t.name)))yield c({condition:void 0,itemPath:typeof t.bin=="string"?["bin"]:["bin",r],modulePath:o,packageContext:e,subpath:void 0})}import{opendir as Ct}from"node:fs/promises";import{resolve as Rt}from"node:path";function h(t){return Rt(t.path.endsWith(t.name)?t.path.replace(new RegExp(`[/\\\\]${t.name}$`,"i"),""):t.path,t.name)}async function*U(t,e){if(typeof t.directories?.bin=="string"){let r=await Ct(t.directories.bin);for await(let o of r)o.isFile()&&(yield c({condition:void 0,itemPath:["directories","bin"],modulePath:h(o),packageContext:e,subpath:void 0}))}}var u=t=>e=>typeof e=="string"&&t.test(e),y=t=>e=>Array.isArray(e)&&e.every(t);var p=t=>e=>typeof e>"u"||t(e);var d=t=>typeof t=="string",_=t=>typeof t=="number"&&!Number.isNaN(t),z=t=>typeof t=="bigint",V=t=>typeof t=="boolean",St=t=>typeof t>"u",W=t=>typeof t=="symbol",K=t=>t===null;var E=p(d),Be=p(_),Me=p(z),De=p(V),Je=p(W),Le=p(K),R=y(d),qe=y(_),Te=y(z),Ge=y(V),Ue=y(St),_e=y(W),ze=y(K);var At=u(/^[-+]?\d+(\.\d+)?$/),Ot=t=>typeof t=="number"||typeof t=="bigint"||At(t),Ve=y(Ot),We=u(/^[-+]?\d+$/),Ke=u(/^\d+$/);var P=t=>t!==null&&typeof t=="object"&&!Array.isArray(t);var H=t=>P(t)&&Object.entries(t).every(R);function Nt(t){return t==="commonjs"||t==="module"}var Q=u(/\.\d+(\.gz)?$/),$t=y(Q),Ft=t=>Q(t)||$t(t),It=p(Ft);function Bt(t){return P(t)&&E(t.bin)&&E(t.man)}var Mt=p(Bt);function Dt(t){return d(t)||H(t)}function X(t){return typeof t=="string"&&t.startsWith("./")}var Jt=/^(?<before>\.\/[^*]*)\*(?<after>[^*]*)$/,Ye=u(Jt);function C(t){return t===null||X(t)}var Lt=u(/^(?![\\.0-9])./);function x(t){return P(t)?Object.entries(t).every(([r,o])=>Lt(r)&&O(o)):!1}function S(t){return P(t)?Object.entries(t).every(([r,o])=>(r==="."||X(r))&&O(o)):!1}function Y(t){return C(t)||x(t)}var A=y(Y);function O(t){return Y(t)||A(t)}function qt(t){return O(t)||S(t)}var N=t=>P(t)&&Object.entries(t).every(e=>typeof e[0]=="string"&&(typeof e[1]=="string"||typeof e[1]=="boolean"));function Tt(t){return d(t)||N(t)}var Gt=p(Tt);function Z(t){return P(t)&&d(t.name)&&d(t.version)&&E(t.main)&&E(t.module)&&Gt(t.browser)&&E(t.types)&&It(t.man)&&Mt(t.directories)&&p(Nt)(t.type)&&p(qt)(t.exports)&&p(Dt)(t.bin)&&p(R)(t.files)}function*tt(t,e){if(t.browser){if(N(t.browser)){let r=Object.entries(t.browser).filter(o=>typeof o[0]=="string"&&typeof o[1]=="string");for(let[o,s]of r)yield c({condition:void 0,itemPath:["browser",o],modulePath:s,packageContext:e,subpath:void 0});return}yield c({condition:void 0,itemPath:["browser"],modulePath:t.browser,packageContext:e,subpath:void 0})}}var k=class{processExportsEntryPath(e,r,o){return e===null?[]:[c({modulePath:e,subpath:".",...r,packageContext:o})]}processExportsEntry(e,r,o){return x(e)?this.processConditionalExports(e,r,o):this.processExportsEntryPath(e,r,o)}processExportsEntryArray(e,r,o){return e.map((s,i)=>this.processExportsEntry(s,{...r,itemPath:[...r.itemPath,i]},o)).flat()}processSubpathExports(e,r,o){return Object.entries(e).map(([s,i])=>this.process(i,{...r,subpath:s,itemPath:[...r.itemPath,s]},o)).flat()}processConditionalExports(e,r,o){let s=(i,f,l)=>{if(x(f))return i;if(l.at(-1)==="default"){let n=l.at(-2);if(typeof n=="string")return n}return i};return Object.entries(e).map(([i,f])=>{let l=[...r.itemPath,i];return this.process(f,{...r,condition:s(i,f,l),itemPath:l},o)}).flat()}process(e,r,o){return C(e)?this.processExportsEntryPath(e,r,o):A(e)?this.processExportsEntryArray(e,r,o):S(e)?this.processSubpathExports(e,r,o):x(e)?this.processConditionalExports(e,r,o):[]}};import{opendir as Ut}from"node:fs/promises";async function*et(t){if(!t.resolvedPath.includes("*")){yield t;return}let[e,r]=t.resolvedPath.split("*"),o=e?new RegExp(`^${e}`,"i"):void 0,s=r?new RegExp(`${r}$`,"i"):void 0,i=["moduleName","relativePath","fileName","resolvedPath"],f=n=>{let m=n;return o&&(m=m.replace(o,"")),s&&(m=m.replace(s,"")),m},l=await Ut(t.directory);for await(let n of l)if(n.isFile()&&(typeof r>"u"||n.name.endsWith(r))){let m=f(h(n));yield i.reduce((v,$)=>{let F=v[$];return F&&(v[$]=F.replace("*",m)),v},structuredClone(t))}}async function*rt(t,e){if(t.exports){let r=new k().process(t.exports,{itemPath:["exports"]},e);for(let o of r)yield*et(o)}}function*ot(t,e){t.main&&(yield c({condition:void 0,itemPath:["main"],modulePath:t.main,packageContext:e,subpath:void 0}))}function*nt(t,e){t.module&&(yield c({condition:void 0,itemPath:["module"],modulePath:t.module,packageContext:e,subpath:void 0}))}function*st(t,e){let r="types"in t?"types":"typings"in t?"typings":void 0;if(r){let o=t[r];o&&(yield c({condition:"types",itemPath:[r],modulePath:o,packageContext:e,subpath:void 0}))}}async function*it(t,e){yield*G(t,e),yield*U(t,e),yield*tt(t,e),yield*ot(t,e),yield*nt(t,e),yield*st(t,e),yield*rt(t,e)}import{AssertionError as _t}from"node:assert";function at(t){if(!Z(t))throw new _t({message:"input is not PackageJson",actual:t})}import{readFile as zt}from"node:fs/promises";async function ct(t){let e=await zt(t,"utf-8");return JSON.parse(e)}async function pt(t){let e=await ct(t);return at(e),e}async function mt(t,e){let r=/\.json$/i.test(t)?`node --input-type=module --eval="import '${t}' assert { type: 'json' };"`:`node --input-type=module --eval="import '${t}';"`;await g(r,e)}async function yt(t,e){try{return typeof t.moduleName=="string"?(await mt(t.moduleName,e),new a({code:0,entryPoint:t,message:`"${t.moduleName}" works with import`,name:"import"})):new a({code:2,entryPoint:t,message:`Import skipped: ${t.itemPath.join(".")}`,name:"import"})}catch(r){return new a({code:1,entryPoint:t,error:r instanceof Error?r:new Error(String(r)),message:`${t.moduleName??t.itemPath.join(".")} cannot be imported`,name:"import"})}}async function ft(t,e){let r=`node --input-type=commonjs --eval="require('${t}');"`;await g(r,e)}async function lt(t,e){try{return typeof t.moduleName=="string"?(await ft(t.moduleName,e),new a({code:0,entryPoint:t,message:`"${t.moduleName}" works with require`,name:"require"})):new a({code:2,entryPoint:t,message:`Require skipped: ${t.itemPath.join(".")}`,name:"require"})}catch(r){return new a({code:1,entryPoint:t,error:r instanceof Error?r:new Error(String(r)),message:`${t.moduleName??t.itemPath.join(".")} cannot be required`,name:"require"})}}function Vt(t){return typeof t.condition>"u"||t.condition==="require"}function Wt(t){return typeof t.condition>"u"||t.condition==="import"}async function ut(t,e){let r=[];try{typeof t.moduleName=="string"&&(Vt(t)&&r.push(await lt(t,e)),Wt(t)&&r.push(await yt(t,e)))}catch(o){if(o instanceof Error)throw new Error(`Unable to verify "${t.moduleName}"`,{cause:o})}return r}var w=class extends Kt{options;packageDirectory;#e;#t;constructor(e){super(),this.options=e,this.packageDirectory=Ht(this.options.package),this.#e=0,this.#t=e.controller}processResult(e){this.emit("result",e),e.code===1&&(this.#e=1,this.options.bail&&this.#t.abort())}processResults(e){[e].flat().forEach(r=>this.processResult(r))}async checkFilesExist(e){await b.from(e).forEach(async r=>{let o=await M(r);this.processResults(o)},{signal:this.#t.signal,concurrency:this.options.concurrency})}async checkSyntax(e){let r=e.filter(o=>/\.[cm]?js$/i.test(o.resolvedPath));await b.from(r).forEach(async o=>{let s=await J(o,{signal:this.#t.signal});this.processResults(s)},{signal:this.#t.signal,concurrency:this.options.concurrency})}async verifyIncludes(e){await b.from(e).forEach(async r=>{let o=await ut(r,{cwd:this.packageDirectory,signal:this.#t.signal});this.processResults(o)},{signal:this.#t.signal,concurrency:this.options.concurrency})}async run(){let e=await pt(this.options.package),r={name:e.name,type:e.type??"commonjs",path:this.options.package,directory:this.packageDirectory},o=await b.from(it(e,r),{objectMode:!0}).toArray({signal:this.#t.signal});return await this.checkFilesExist(o),this.options.check&&await this.checkSyntax(o),this.options.verify&&await this.verifyIncludes(o),this.#e}};import{stat as Xt}from"node:fs/promises";import{basename as Yt,join as Pt,resolve as Zt}from"node:path";import{Readable as te}from"node:stream";import{parseArgs as ee}from"node:util";import{availableParallelism as Qt}from"node:os";function dt(t){let e=Qt(),r=Number.parseInt(`${t}`);return Number.isInteger(r)?Math.max(1,Math.min(r,e)):e}async function gt(t){let e=await Xt(t);if(e.isDirectory())return await gt(Pt(t,"package.json"));if(e.isFile()&&Yt(t)==="package.json")return Zt(t);throw new Error(`Unable to resolve package.json from ${t}`)}async function Et(){let t={allowPositionals:!0,strict:!0,tokens:!1,options:{concurrency:{type:"string",short:"c"},bail:{type:"boolean",short:"b",default:process.env.CI==="true"},check:{type:"boolean",default:!1,short:"s"},verify:{type:"boolean",default:!1,short:"v"},json:{type:"boolean",default:!1,short:"j"},info:{type:"boolean",default:process.env.RUNNER_DEBUG==="1",short:"i"}}},{values:e,positionals:r}=ee(t);return{packages:await te.from(r.length?r:[Pt(process.cwd(),"package.json")]).map(s=>gt(s)).toArray(),concurrency:dt(e.concurrency),bail:e.bail??t.options.bail.default,check:e.check??t.options.check.default,verify:e.verify??t.options.verify.default,json:e.json??t.options.verify.default,info:e.info??t.options.info.default}}try{let{json:t,info:e,packages:r,...o}=await Et(),s=[],i=n=>{s.push(n),!t&&(e||n.code===1)&&console.log(n.toString())},f=new AbortController;re(100,f.signal);let l=r.map(n=>{let m=new w({...o,package:n,controller:f});return m.on("result",i),m});try{for(let n of l)await n.run()}catch(n){if(n instanceof Error&&n.name!=="AbortError")throw n}process.exitCode=s.reduce((n,m)=>m.code===1?1:n,0),t&&process.stdout.write(JSON.stringify(s.filter(n=>e||n.code===1),null,2))}catch(t){console.group("validate-package-exports"),console.error(t),console.groupEnd(),process.exitCode??=1}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "validate-package-exports",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Validate your package.json exports actually exist, have valid syntax, and can be imported or required without issues.",
5
5
  "keywords": [
6
6
  "validate",
@@ -42,14 +42,14 @@
42
42
  "@webdeveric/prettier-config": "^0.2.0",
43
43
  "@webdeveric/utils": "^0.29.1",
44
44
  "cross-env": "^7.0.3",
45
- "cspell": "^8.6.0",
45
+ "cspell": "^8.6.1",
46
+ "esbuild": "^0.20.2",
46
47
  "esbuild-plugin-clean": "^1.0.1",
47
48
  "esbuild-plugin-environment": "^0.3.0",
48
- "esbuild": "^0.20.2",
49
+ "eslint": "^8.57.0",
49
50
  "eslint-config-prettier": "^9.1.0",
50
51
  "eslint-import-resolver-typescript": "^3.6.1",
51
52
  "eslint-plugin-import": "^2.29.1",
52
- "eslint": "^8.57.0",
53
53
  "husky": "^9.0.11",
54
54
  "lint-staged": "^15.2.2",
55
55
  "prettier": "^3.2.5",
@@ -58,8 +58,8 @@
58
58
  "vitest": "^1.4.0"
59
59
  },
60
60
  "scripts": {
61
- "predemo": "pnpm build:dev",
62
- "demo": "./dist/cli.mjs",
61
+ "prevalidate": "pnpm build:dev",
62
+ "validate": "./dist/cli.mjs",
63
63
  "format": "prettier --write .",
64
64
  "build": "cross-env NODE_ENV=production node --experimental-json-modules --no-warnings ./build.mjs",
65
65
  "build:dev": "cross-env NODE_ENV=development node --experimental-json-modules --no-warnings ./build.mjs",
package/readme.md CHANGED
@@ -20,16 +20,24 @@ yarn add validate-package-exports -D
20
20
 
21
21
  ## Options
22
22
 
23
- | Flag | Description | Default value | Required |
24
- | --- | --- | --- | --- |
25
- | `--package` / `-p` | Path to `package.json` file | `[cwd]/package.json` | :white_check_mark: |
26
- | `--check` / `-s` | Check syntax of JS files | `false` | |
27
- | `--verify` / `-v` | Verify a module can be imported or required | `false` | |
28
- | `--concurrency` / `-c` | Concurrency | `availableParallelism()` | |
29
- | `--bail` / `-b` | Bail | `process.env.CI === 'true'` | |
30
- | `--logLevel` / `-l` | Log level | `info` | |
23
+ | Flag | Description | Default value |
24
+ | --- | --- | --- |
25
+ | `--check` / `-s` | Check syntax of JS files | `false` |
26
+ | `--verify` / `-v` | Verify a module can be imported or required | `false` |
27
+ | `--concurrency` / `-c` | Concurrency | `availableParallelism()` |
28
+ | `--bail` / `-b` | Bail | `process.env.CI === 'true'` |
29
+ | `--info` / `-i` | Show `info` messages.<br>The default behavior is to only show `error`. | `process.env.RUNNER_DEBUG === '1'` |
30
+ | `--json` / `-j` | Use JSON output | `false` |
31
31
 
32
- ## Recommended usage
32
+ ## Usage
33
+
34
+ ```sh
35
+ validate-package-exports [FILE]... [options]
36
+ ```
37
+
38
+ :information_source: If you do not provide a path to a `package.json`, it will try to find one in the current directory.
39
+
40
+ ### Package scripts examples
33
41
 
34
42
  ```json
35
43
  {
@@ -50,6 +58,12 @@ OR
50
58
  }
51
59
  ```
52
60
 
61
+ ### Using `npx`
62
+
63
+ ```shell
64
+ npx --yes validate-package-exports ./path/to/package.json --check --verify
65
+ ```
66
+
53
67
  ## Local development
54
68
 
55
69
  ```