validate-package-exports 0.14.0 → 0.16.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.
Files changed (3) hide show
  1. package/dist/cli.mjs +4 -4
  2. package/package.json +26 -23
  3. package/readme.md +3 -4
package/dist/cli.mjs CHANGED
@@ -1,9 +1,9 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env -S node --experimental-import-meta-resolve
2
2
  /*!
3
3
  * @file validate-package-exports
4
- * @version 0.14.0
4
+ * @version 0.16.0
5
5
  * @license MIT
6
- * @copyright Eric King 2025
6
+ * @copyright Eric King 2026
7
7
  * @see {@link https://github.com/webdeveric/validate-package-exports/#readme}
8
8
  */
9
- import{setMaxListeners as he}from"node:events";import{Readable as Ee}from"node:stream";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}";if(this.code===1){let r=this.entryPoint.itemPath.length?` (${JSON.stringify(this.entryPoint.itemPath)})`:"";return`${e} ${this.name}: ${this.message}${r} ${this.error??""}`.trim()}else return`${e} ${this.name}: ${this.message}`}};import{EventEmitter as me}from"node:events";import{dirname as ye}from"node:path";import{Readable as w}from"node:stream";var J={emergency:0,alert:1,critical:2,error:3,warning:4,notice:5,info:6,debug:7};import{relative as I}from"node:path";import{stat as kt}from"node:fs/promises";async function M(t){try{return(await kt(t)).isFile()}catch{return!1}}async function D(t){try{if(await M(t.resolvedPath)===!1)throw new Error(`${t.resolvedPath} is not a file`);return new a({name:"file-exists",code:0,message:`${I(process.cwd(),t.resolvedPath)} exists`,entryPoint:t})}catch(e){return new a({name:"file-exists",code:1,entryPoint:t,message:`${I(process.cwd(),t.resolvedPath)} does not exist`,error:e instanceof Error?e:new Error(String(e))})}}import{relative as q}from"node:path";import{exec as bt}from"node:child_process";import{promisify as wt}from"node:util";var f=wt(bt);async function T(t,e){try{return await f(`node --check ${t.resolvedPath}`,e),new a({code:0,entryPoint:t,message:`${q(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 ${q(process.cwd(),t.resolvedPath)}`,name:"check-syntax"})}}import{relative as At,dirname as Nt,basename as Ft}from"node:path";function G(t,e){return e==="."?t:`${t}/${e.replace(/^\.\//,"")}`}function V(t,e="commonjs",r){return r==="require"||t.endsWith(".cjs")?"commonjs":r==="import"||t.endsWith(".mjs")?"module":e}import{createRequire as vt}from"node:module";import{basename as Rt,dirname as Ct,join as jt,resolve as St}from"node:path";function _(t){let e=new Map;return(...o)=>{let i=e.get(o[0]);if(i)return i;let n=t(...o);return e.set(o[0],n),n}}var $t=_(vt);function U(t,e){let r=St(e.directory,t);if(e.type==="commonjs")try{let i=$t(e.directory).resolve(r);return jt(Ct(r),Rt(i))}catch{}return r}function p({moduleName:t,modulePath:e,packageContext:r,subpath:o,itemPath:i,condition:n}){let s=U(e,r);return{moduleName:t??(o?G(r.name,o):void 0),packagePath:r.path,type:V(e,r.type,n),fileName:Ft(s),relativePath:At(r.directory,s),directory:Nt(s),resolvedPath:s,subpath:o,condition:n,itemPath:i}}function W(t,e){return typeof t=="string"?{[e]:t}:t}function*z(t,e){if(t.bin)for(let[r,o]of Object.entries(W(t.bin,t.name)))yield p({condition:void 0,itemPath:typeof t.bin=="string"?["bin"]:["bin",r],modulePath:o,packageContext:e,subpath:void 0})}import{opendir as Ot}from"node:fs/promises";import{resolve as Bt}from"node:path";async function*L(t,e){if(typeof t.directories?.bin=="string"){let r=await Ot(t.directories.bin);for await(let o of r)o.isFile()&&(yield p({condition:void 0,itemPath:["directories","bin"],modulePath:Bt(t.directories.bin,o.name),packageContext:e,subpath:void 0}))}}import{anyOf as l}from"@webdeveric/utils/predicate/factory/anyOf";import{everyItem as P}from"@webdeveric/utils/predicate/factory/everyItem";import{fromEnum as Jt}from"@webdeveric/utils/predicate/factory/fromEnum";import{literal as R}from"@webdeveric/utils/predicate/factory/literal";import{matching as C}from"@webdeveric/utils/predicate/factory/matching";import{nullable as Mt}from"@webdeveric/utils/predicate/factory/nullable";import{optional as u}from"@webdeveric/utils/predicate/factory/optional";import{shape as H}from"@webdeveric/utils/predicate/factory/shape";import{tuple as j}from"@webdeveric/utils/predicate/factory/tuple";import{isBoolean as It}from"@webdeveric/utils/predicate/isBoolean";import{isObject as S}from"@webdeveric/utils/predicate/isObject";import{isOptionalString as d}from"@webdeveric/utils/predicate/isOptionalString";import{isString as k}from"@webdeveric/utils/predicate/isString";import{isStringArray as Dt}from"@webdeveric/utils/predicate/isStringArray";import{isStringRecord as qt}from"@webdeveric/utils/predicate/isStringRecord";function $(t){return typeof t=="string"&&t.startsWith("./")}var gr=Jt(J),Tt=l(R("commonjs"),R("module")),Gt=u(Tt),K=C(/\.\d+(\.gz)?$/),Vt=P(K),_t=l(K,Vt),Ut=u(_t),Wt=H({bin:d,man:d}),zt=u(Wt),Lt=l($,qt),Ht=u(Lt),hr=C(/^(?<before>\.\/[^*]*)\*(?<after>[^*]*)$/),A=Mt($),Kt=C(/^(?![\\.0-9])./);function g(t){return S(t)&&P(j([Kt,F]))(Object.entries(t))}function h(t){return S(t)&&P(j([l(R("."),$),F]))(Object.entries(t))}var Q=l(A,g),N=P(Q),F=l(Q,N),Qt=l(F,h),Xt=u(Qt),O=t=>S(t)&&P(j([k,l(k,It)]))(Object.entries(t)),Yt=l(k,O),X=H({name:k,version:d,main:d,module:d,browser:u(Yt),types:d,man:Ut,directories:zt,type:Gt,exports:Xt,bin:Ht,files:u(Dt)});function*Y(t,e){if(t.browser){if(O(t.browser)){let r=Object.entries(t.browser).filter(o=>typeof o[0]=="string"&&typeof o[1]=="string");for(let[o,i]of r)yield p({condition:void 0,itemPath:["browser",o],modulePath:i,packageContext:e,subpath:void 0});return}yield p({condition:void 0,itemPath:["browser"],modulePath:t.browser,packageContext:e,subpath:void 0})}}var b=class{processExportsEntryPath(e,r,o){return e===null?[]:[p({modulePath:e,subpath:".",...r,packageContext:o})]}processExportsEntry(e,r,o){return g(e)?this.processConditionalExports(e,r,o):this.processExportsEntryPath(e,r,o)}processExportsEntryArray(e,r,o){return e.map((i,n)=>this.processExportsEntry(i,{...r,itemPath:[...r.itemPath,n]},o)).flat()}processSubpathExports(e,r,o){return Object.entries(e).map(([i,n])=>this.process(n,{...r,subpath:i,itemPath:[...r.itemPath,i]},o)).flat()}processConditionalExports(e,r,o){let i=(n,s,m)=>{if(g(s))return n;if(m.at(-1)==="default"){let y=m.at(-2);if(typeof y=="string")return y}return n};return Object.entries(e).map(([n,s])=>{let m=[...r.itemPath,n];return this.process(s,{...r,condition:i(n,s,m),itemPath:m},o)}).flat()}process(e,r,o){return A(e)?this.processExportsEntryPath(e,r,o):N(e)?this.processExportsEntryArray(e,r,o):h(e)?this.processSubpathExports(e,r,o):g(e)?this.processConditionalExports(e,r,o):[]}};import{opendir as Zt}from"node:fs/promises";import{resolve as te}from"node:path";import{escapeRegExp as Z}from"@webdeveric/utils/escapeRegExp";function ee(t,e){return["moduleName","relativePath","fileName","resolvedPath"].reduce((o,i)=>{let n=o[i];return n&&(o[i]=n.replace("*",e)),o},structuredClone(t))}async function*tt(t,e,r){let o=await Zt(t);for await(let i of o){let n=te(t,i.name);i.isDirectory()?yield*tt(n,e,r):i.isFile()&&(typeof r.suffix>"u"||i.name.endsWith(r.suffix))&&(yield ee(e,r.findStar(n)))}}async function*et(t){if(!t.resolvedPath.includes("*")){yield t;return}let[e,r]=t.resolvedPath.split("*"),o={prefix:e,suffix:r,prefixPattern:e?new RegExp(`^${Z(e)}`,"i"):void 0,suffixPattern:r?new RegExp(`${Z(r)}$`,"i"):void 0,findStar(i){let n=i;return this.prefixPattern&&(n=n.replace(this.prefixPattern,"")),this.suffixPattern&&(n=n.replace(this.suffixPattern,"")),n}};yield*tt(t.directory,t,o)}async function*rt(t,e){if(t.exports){let r=new b().process(t.exports,{itemPath:["exports"]},e);for(let o of r)yield*et(o)}}function*ot(t,e){t.main&&(yield p({moduleName:e.name,condition:void 0,itemPath:["main"],modulePath:t.main,packageContext:e,subpath:void 0}))}function*nt(t,e){t.module&&(yield p({moduleName:e.name,condition:void 0,itemPath:["module"],modulePath:t.module,packageContext:e,subpath:void 0}))}function*it(t,e){let r="types"in t?"types":"typings"in t?"typings":void 0;if(r){let o=t[r];o&&(yield p({condition:"types",itemPath:[r],modulePath:o,packageContext:e,subpath:void 0}))}}async function*st(t,e){yield*z(t,e),yield*L(t,e),yield*Y(t,e),yield*ot(t,e),yield*nt(t,e),yield*it(t,e),yield*rt(t,e)}import re from"@npmcli/arborist";import oe from"npm-packlist";import{sep as at}from"node:path";function ct(t){return at==="/"?t:t.replaceAll("/",at)}async function pt(t){let r=await new re({path:t}).loadActual();return(await oe(r)).map(i=>ct(i))}import{AssertionError as ne}from"node:assert";function mt(t){if(!X(t))throw new ne({message:"input is not PackageJson",actual:t})}import{readFile as ie}from"node:fs/promises";async function yt(t){let e=await ie(t,"utf-8");return JSON.parse(e)}async function lt(t){let e=await yt(t);return mt(e),e}import se from"node:assert";function ut(){let[t]=process.versions.node.split(".");return se(t),Number.parseInt(t)}var ae=ut();async function ft(t,e){let r=/\.json$/i.test(t)?`node --input-type=module --eval="import '${t}' ${ae<20?"assert":"with"} { type: 'json' };" --no-warnings`:`node --input-type=module --eval="import '${t}';"`;await f(r,e)}async function dt(t,e){try{return typeof t.moduleName=="string"?(await ft(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 Pt(t,e){let r=`node --input-type=commonjs --eval="require('${t}');"`;await f(r,e)}async function gt(t,e){try{return typeof t.moduleName=="string"?(await Pt(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 ce(t){if(t.itemPath.length===1){let e=t.itemPath[0];if(e==="main"||e==="exports")return t.type!=="module"}return typeof t.condition>"u"||t.condition==="require"}function pe(t){return typeof t.condition>"u"||t.condition==="import"}async function ht(t,e){let r=[];try{typeof t.moduleName=="string"&&(ce(t)&&r.push(await gt(t,e)),pe(t)&&r.push(await dt(t,e)))}catch(o){if(o instanceof Error)throw new Error(`Unable to verify "${t.moduleName}"`,{cause:o})}return r}var v=class extends me{options;packageDirectory;#e;#t;constructor(e){super(),this.options=e,this.packageDirectory=ye(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))}checkPackageJson(e,r){let o={moduleName:`${r.name}/package.json`,packagePath:r.path,type:r.type,fileName:"package.json",resolvedPath:r.path,relativePath:"package.json",subpath:void 0,condition:void 0,directory:r.directory,itemPath:[]},i=new a(h(e.exports)&&!Reflect.has(e.exports,".")?{name:"package-json",code:1,message:'package.json exports is missing "." property.',entryPoint:o,error:new Error('"." is missing from exports.')}:{name:"package-json",code:0,message:"package.json exports has required property.",entryPoint:o});return this.processResult(i),i}async checkFilesExist(e){return await w.from(e).map(async r=>{let o=await D(r);return this.processResults(o),o},{signal:this.#t.signal,concurrency:this.options.concurrency}).toArray({signal:this.#t.signal})}async checkSyntax(e){let r=e.filter(o=>/\.[cm]?js$/i.test(o.resolvedPath));return await w.from(r).map(async o=>{let i=await T(o,{signal:this.#t.signal});return this.processResults(i),i},{signal:this.#t.signal,concurrency:this.options.concurrency}).toArray({signal:this.#t.signal})}async verifyIncludes(e){return(await w.from(e).map(async r=>{let o=await ht(r,{cwd:this.packageDirectory,signal:this.#t.signal});return this.processResults(o),o},{signal:this.#t.signal,concurrency:this.options.concurrency}).toArray({signal:this.#t.signal})).flat()}async checkPacklist(e,r){let o=new Set(await pt(r.directory)),i=e.map(n=>{let s=o.has(n.relativePath);return new a({name:"packlist",code:s?0:1,message:s?`${n.relativePath} will be packed.`:`${n.relativePath} will not be packed.`,error:s?void 0:new Error("EntryPoint relativePath not found in packlist files."),entryPoint:n})});return this.processResults(i),i}async run(){let e=await lt(this.options.package),r={name:e.name,type:e.type??"commonjs",path:this.options.package,directory:this.packageDirectory},o=await w.from(st(e,r),{objectMode:!0}).toArray({signal:this.#t.signal}),i=new Set,n=m=>{m.forEach(y=>{y.code===1&&i.add(y.entryPoint)})},s=m=>m.filter(y=>!i.has(y));return n([this.checkPackageJson(e,r)]),n(await this.checkFilesExist(o)),this.options.check&&n(await this.checkSyntax(s(o))),this.options.verify&&n(await this.verifyIncludes(s(o))),n(await this.checkPacklist(s(o),r)),this.#e}};import{parseArgs as ue}from"node:util";import{availableParallelism as le}from"node:os";function Et(t){let e=le(),r=Number.parseInt(`${t}`);return Number.isInteger(r)?Math.max(1,Math.min(r,e)):e}function xt(t){let e={args: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"},"no-bail":{type:"boolean",default:!1},"no-info":{type:"boolean",default:!1}}},{values:r,positionals:o}=ue(e),i=r["no-bail"]??e.options["no-bail"].default,n=r["no-info"]??e.options["no-info"].default;return{packages:o.length?o:["./package.json"],concurrency:Et(r.concurrency),bail:i?!1:r.bail??e.options.bail.default,check:r.check??e.options.check.default,verify:r.verify??e.options.verify.default,json:r.json??e.options.verify.default,info:n?!1:r.info??e.options.info.default}}import{stat as fe}from"node:fs/promises";import{basename as de,join as Pe,resolve as ge}from"node:path";async function B(t){let e=await fe(t);if(e.isDirectory())return await B(Pe(t,"package.json"));if(e.isFile()&&de(t)==="package.json")return ge(t);throw new Error(`Unable to resolve package.json from ${t}`)}try{let{json:t,info:e,packages:r,...o}=xt(),i=await Ee.from(r).map(c=>B(c),{concurrency:o.concurrency}).toArray(),n=[],s=c=>{n.push(c),!t&&(e||c.code===1)&&console.log(c.toString())},m=new AbortController;he(100,m.signal);let y=i.map(c=>{let E=new v({...o,package:c,controller:m});return E.on("result",s),E});try{for(let c of y)await c.run()}catch(c){if(c instanceof Error&&c.name!=="AbortError")throw c}process.exitCode=n.reduce((c,E)=>E.code===1?1:c,0),t&&process.stdout.write(JSON.stringify(n.filter(c=>e||c.code===1),null,2))}catch(t){console.group("validate-package-exports"),console.dir(t,{depth:null}),console.groupEnd(),process.exitCode??=1}
9
+ import{setMaxListeners as Pe}from"node:events";import{Readable as he}from"node:stream";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}";if(this.code===1){let r=this.entryPoint.itemPath.length?` (${JSON.stringify(this.entryPoint.itemPath)})`:"";return`${e} ${this.name}: ${this.message}${r} ${this.error??""}`.trim()}else return`${e} ${this.name}: ${this.message}`}};import{EventEmitter as ce}from"node:events";import{dirname as pe}from"node:path";import{Readable as b}from"node:stream";var J={emergency:0,alert:1,critical:2,error:3,warning:4,notice:5,info:6,debug:7};import{relative as M}from"node:path";import{stat as ht}from"node:fs/promises";async function D(t){try{return(await ht(t)).isFile()}catch{return!1}}async function T(t){try{if(await D(t.resolvedPath)===!1)throw new Error(`${t.resolvedPath} is not a file`);return new a({name:"file-exists",code:0,message:`${M(process.cwd(),t.resolvedPath)} exists`,entryPoint:t})}catch(e){return new a({name:"file-exists",code:1,entryPoint:t,message:`${M(process.cwd(),t.resolvedPath)} does not exist`,error:e instanceof Error?e:new Error(String(e))})}}import{AssertionError as Et}from"node:assert";import{spawn as xt}from"node:child_process";import{once as kt}from"node:events";import{relative as I}from"node:path";async function q(t,e){try{let r=xt("node",["--check",t.resolvedPath],{...e,cwd:t.packageDirectory,stdio:"inherit"}),[o]=await kt(r,"close",{signal:e.signal});if(o!==0)throw new Et({message:"exit code not ok when checking syntax",expected:0,actual:o});return new a({code:0,entryPoint:t,message:`${I(t.packageDirectory,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 ${I(process.cwd(),t.resolvedPath)}`,name:"check-syntax"})}}import{relative as wt,dirname as vt,basename as Rt}from"node:path";function G(t,e){return e==="."?t:`${t}/${e.replace(/^\.\//,"")}`}function U(t,e="commonjs",r){return r==="require"||t.endsWith(".cjs")?"commonjs":r==="import"||t.endsWith(".mjs")?"module":e}import{resolve as bt}from"node:path";function W(t,e){return bt(e.directory,t)}function p({moduleName:t,modulePath:e,packageContext:r,subpath:o,itemPath:n,condition:i}){let s=W(e,r);return{moduleName:t??(o?G(r.name,o):void 0),packageDirectory:r.directory,packagePath:r.path,type:U(e,r.type,i),fileName:Rt(s),relativePath:wt(r.directory,s),directory:vt(s),resolvedPath:s,subpath:o,condition:i,itemPath:n}}function z(t,e){return typeof t=="string"?{[e]:t}:t}function*V(t,e){if(t.bin)for(let[r,o]of Object.entries(z(t.bin,t.name)))yield p({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 jt}from"node:path";async function*_(t,e){if(typeof t.directories?.bin=="string"){let r=await Ct(t.directories.bin);for await(let o of r)o.isFile()&&(yield p({condition:void 0,itemPath:["directories","bin"],modulePath:jt(t.directories.bin,o.name),packageContext:e,subpath:void 0}))}}import{anyOf as u}from"@webdeveric/utils/predicate/factory/anyOf";import{everyItem as g}from"@webdeveric/utils/predicate/factory/everyItem";import{fromEnum as St}from"@webdeveric/utils/predicate/factory/fromEnum";import{literal as R}from"@webdeveric/utils/predicate/factory/literal";import{matching as C}from"@webdeveric/utils/predicate/factory/matching";import{nullable as At}from"@webdeveric/utils/predicate/factory/nullable";import{optional as f}from"@webdeveric/utils/predicate/factory/optional";import{shape as K}from"@webdeveric/utils/predicate/factory/shape";import{tuple as j}from"@webdeveric/utils/predicate/factory/tuple";import{isBoolean as Ft}from"@webdeveric/utils/predicate/isBoolean";import{isObject as S}from"@webdeveric/utils/predicate/isObject";import{isOptionalString as d}from"@webdeveric/utils/predicate/isOptionalString";import{isString as x}from"@webdeveric/utils/predicate/isString";import{isStringArray as Nt}from"@webdeveric/utils/predicate/isStringArray";import{isStringRecord as $t}from"@webdeveric/utils/predicate/isStringRecord";function A(t){return typeof t=="string"&&t.startsWith("./")}var ur=St(J),Bt=u(R("commonjs"),R("module")),Ot=f(Bt),L=C(/\.\d+(\.gz)?$/),Jt=g(L),Dt=u(L,Jt),Mt=f(Dt),Tt=K({bin:d,man:d}),It=f(Tt),qt=u(A,$t),Gt=f(qt),yr=C(/^(?<before>\.\/[^*]*)\*(?<after>[^*]*)$/),F=At(A),Ut=C(/^(?![\\.0-9])./);function P(t){return S(t)&&g(j([Ut,$]))(Object.entries(t))}function h(t){return S(t)&&g(j([u(R("."),A),$]))(Object.entries(t))}var H=u(F,P),N=g(H),$=u(H,N),Wt=u($,h),zt=f(Wt),B=t=>S(t)&&g(j([x,u(x,Ft)]))(Object.entries(t)),Vt=u(x,B),Q=K({name:x,version:d,main:d,module:d,browser:f(Vt),types:d,man:Mt,directories:It,type:Ot,exports:zt,bin:Gt,files:f(Nt)});function*X(t,e){if(t.browser){if(B(t.browser)){let r=Object.entries(t.browser).filter(o=>typeof o[0]=="string"&&typeof o[1]=="string");for(let[o,n]of r)yield p({condition:void 0,itemPath:["browser",o],modulePath:n,packageContext:e,subpath:void 0});return}yield p({condition:void 0,itemPath:["browser"],modulePath:t.browser,packageContext:e,subpath:void 0})}}var k=class{processExportsEntryPath(e,r,o){return e===null?[]:[p({modulePath:e,subpath:".",...r,packageContext:o})]}processExportsEntry(e,r,o){return P(e)?this.processConditionalExports(e,r,o):this.processExportsEntryPath(e,r,o)}processExportsEntryArray(e,r,o){return e.map((n,i)=>this.processExportsEntry(n,{...r,itemPath:[...r.itemPath,i]},o)).flat()}processSubpathExports(e,r,o){return Object.entries(e).map(([n,i])=>this.process(i,{...r,subpath:n,itemPath:[...r.itemPath,n]},o)).flat()}processConditionalExports(e,r,o){let n=(i,s,m)=>{if(P(s))return i;if(m.at(-1)==="default"){let l=m.at(-2);if(typeof l=="string")return l}return i};return Object.entries(e).map(([i,s])=>{let m=[...r.itemPath,i];return this.process(s,{...r,condition:n(i,s,m),itemPath:m},o)}).flat()}process(e,r,o){return F(e)?this.processExportsEntryPath(e,r,o):N(e)?this.processExportsEntryArray(e,r,o):h(e)?this.processSubpathExports(e,r,o):P(e)?this.processConditionalExports(e,r,o):[]}};import{opendir as _t}from"node:fs/promises";import{resolve as Kt}from"node:path";import{escapeRegExp as Y}from"@webdeveric/utils/escapeRegExp";function Lt(t,e){return["moduleName","relativePath","fileName","resolvedPath"].reduce((o,n)=>{let i=o[n];return i&&(o[n]=i.replace("*",e)),o},structuredClone(t))}async function*Z(t,e,r){let o=await _t(t);for await(let n of o){let i=Kt(t,n.name);n.isDirectory()?yield*Z(i,e,r):n.isFile()&&(typeof r.suffix>"u"||n.name.endsWith(r.suffix))&&(yield Lt(e,r.findStar(i)))}}async function*tt(t){if(!t.resolvedPath.includes("*")){yield t;return}let[e,r]=t.resolvedPath.split("*"),o={prefix:e,suffix:r,prefixPattern:e?new RegExp(`^${Y(e)}`,"i"):void 0,suffixPattern:r?new RegExp(`${Y(r)}$`,"i"):void 0,findStar(n){let i=n;return this.prefixPattern&&(i=i.replace(this.prefixPattern,"")),this.suffixPattern&&(i=i.replace(this.suffixPattern,"")),i}};yield*Z(t.directory,t,o)}async function*et(t,e){if(t.exports){let r=new k().process(t.exports,{itemPath:["exports"]},e);for(let o of r)yield*tt(o)}}function*rt(t,e){t.main&&(yield p({moduleName:e.name,condition:void 0,itemPath:["main"],modulePath:t.main,packageContext:e,subpath:void 0}))}function*ot(t,e){t.module&&(yield p({moduleName:e.name,condition:void 0,itemPath:["module"],modulePath:t.module,packageContext:e,subpath:void 0}))}function*nt(t,e){let r="types"in t?"types":"typings"in t?"typings":void 0;if(r){let o=t[r];o&&(yield p({condition:"types",itemPath:[r],modulePath:o,packageContext:e,subpath:void 0}))}}async function*it(t,e){yield*V(t,e),yield*_(t,e),yield*X(t,e),yield*rt(t,e),yield*ot(t,e),yield*nt(t,e),yield*et(t,e)}import Ht from"@npmcli/arborist";import Qt from"npm-packlist";import{sep as st}from"node:path";function at(t){return st==="/"?t:t.replaceAll("/",st)}async function ct(t){let r=await new Ht({path:t}).loadActual();return(await Qt(r)).map(n=>at(n))}import{AssertionError as Xt}from"node:assert";function pt(t){if(!Q(t))throw new Xt({message:"input is not PackageJson",actual:t})}import{readFile as Yt}from"node:fs/promises";async function mt(t){let e=await Yt(t,"utf-8");return JSON.parse(e)}async function lt(t){let e=await mt(t);return pt(e),e}import{AssertionError as Zt}from"node:assert";import{pathToFileURL as te,fileURLToPath as ee}from"node:url";var re=typeof import.meta.resolve=="function"&&process.execArgv.includes("--experimental-import-meta-resolve");function ut(t){try{if(typeof t.moduleName=="string"&&re){let e=ee(import.meta.resolve(t.moduleName,te(t.packagePath)));if(e!==t.resolvedPath)throw new Zt({message:"The resolved import path does not equal entrypoint resolved path",expected:t.resolvedPath,actual:e});return new a({code:0,entryPoint:t,message:`"${t.moduleName}" works with import`,name:"import"})}return new a({code:2,entryPoint:t,message:`Import skipped: ${t.itemPath.join(".")}`,name:"import"})}catch(e){return new a({code:1,entryPoint:t,error:e instanceof Error?e:new Error(String(e)),message:`${t.moduleName??t.itemPath.join(".")} cannot be imported`,name:"import"})}}import{AssertionError as oe}from"node:assert";import{createRequire as ne}from"node:module";function yt(t){let e=new Map;return(...o)=>{let n=e.get(o[0]);if(n)return n;let i=t(...o);return e.set(o[0],i),i}}var ie=yt(ne);function ft(t){try{if(typeof t.moduleName=="string"){let r=ie(t.packagePath).resolve(t.moduleName,{paths:[t.packageDirectory]});if(r!==t.resolvedPath)throw new oe({message:"The resolved require path does not equal entrypoint resolved path",expected:t.resolvedPath,actual:r});return new a({code:0,entryPoint:t,message:`"${t.moduleName}" works with require`,name:"require"})}return new a({code:2,entryPoint:t,message:`Require skipped: ${t.itemPath.join(".")}`,name:"require"})}catch(e){return new a({code:1,entryPoint:t,error:e instanceof Error?e:new Error(String(e)),message:`${t.moduleName??t.itemPath.join(".")} cannot be required`,name:"require"})}}function se(t){if(t.itemPath.length===1){let e=t.itemPath[0];if(e==="main"||e==="exports")return t.type!=="module"}return typeof t.condition>"u"||t.condition==="require"}function ae(t){return typeof t.condition>"u"||t.condition==="import"}function dt(t){let e=[];return typeof t.moduleName=="string"&&(se(t)&&e.push(ft(t)),ae(t)&&e.push(ut(t))),e}var w=class extends ce{options;packageDirectory;#e;#t;constructor(e){super(),this.options=e,this.packageDirectory=pe(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))}checkPackageJson(e,r){let o={moduleName:`${r.name}/package.json`,packageDirectory:r.directory,packagePath:r.path,type:r.type,fileName:"package.json",resolvedPath:r.path,relativePath:"package.json",subpath:void 0,condition:void 0,directory:r.directory,itemPath:[]},n=new a(h(e.exports)&&!Reflect.has(e.exports,".")?{name:"package-json",code:1,message:'package.json exports is missing "." property.',entryPoint:o,error:new Error('"." is missing from exports.')}:{name:"package-json",code:0,message:"package.json exports has required property.",entryPoint:o});return this.processResult(n),n}async checkFilesExist(e){return await b.from(e).map(async r=>{let o=await T(r);return this.processResults(o),o},{signal:this.#t.signal,concurrency:this.options.concurrency}).toArray({signal:this.#t.signal})}async checkSyntax(e){let r=e.filter(o=>/\.[cm]?js$/i.test(o.resolvedPath));return await b.from(r).map(async o=>{let n=await q(o,{signal:this.#t.signal});return this.processResults(n),n},{signal:this.#t.signal,concurrency:this.options.concurrency}).toArray({signal:this.#t.signal})}async verifyIncludes(e){return(await b.from(e).map(r=>{let o=dt(r);return this.processResults(o),o},{signal:this.#t.signal,concurrency:this.options.concurrency}).toArray({signal:this.#t.signal})).flat()}async checkPacklist(e,r){let o=new Set(await ct(r.directory)),n=e.map(i=>{let s=o.has(i.relativePath);return new a({name:"packlist",code:s?0:1,message:s?`${i.relativePath} will be packed.`:`${i.relativePath} will not be packed.`,error:s?void 0:new Error("EntryPoint relativePath not found in packlist files."),entryPoint:i})});return this.processResults(n),n}async run(){let e=await lt(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}),n=new Set,i=m=>{m.forEach(l=>{l.code===1&&n.add(l.entryPoint)})},s=m=>m.filter(l=>!n.has(l));return i([this.checkPackageJson(e,r)]),i(await this.checkFilesExist(o)),this.options.check&&i(await this.checkSyntax(s(o))),i(await this.verifyIncludes(s(o))),i(await this.checkPacklist(s(o),r)),this.#e}};import{parseArgs as le,styleText as ue}from"node:util";import{availableParallelism as me}from"node:os";function gt(t){let e=me(),r=Number.parseInt(`${t}`);return Number.isInteger(r)?Math.max(1,Math.min(r,e)):e}function Pt(t){let e={args: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",short:"v"},json:{type:"boolean",default:!1,short:"j"},info:{type:"boolean",default:process.env.RUNNER_DEBUG==="1",short:"i"},"no-bail":{type:"boolean",default:!1},"no-info":{type:"boolean",default:!1}}},{values:r,positionals:o}=le(e);"verify"in r&&!r.json&&console.warn(ue(["bold","whiteBright","bgBlack"],"The --verify flag is deprecated and will be removed in the next version."));let n=r["no-bail"]??e.options["no-bail"].default,i=r["no-info"]??e.options["no-info"].default;return{packages:o.length?o:["./package.json"],concurrency:gt(r.concurrency),bail:n?!1:r.bail??e.options.bail.default,check:r.check??e.options.check.default,json:r.json??!1,info:i?!1:r.info??e.options.info.default}}function v(t){if(Array.isArray(t))return t.map(r=>typeof r=="object"?v(r):r);let e=Reflect.ownKeys(t).reduce((r,o)=>{let n=Reflect.get(t,o);return r.push([o,typeof n=="object"?v(n):n]),r},[]);return Object.fromEntries(e)}import{stat as ye}from"node:fs/promises";import{basename as fe,join as de,resolve as ge}from"node:path";async function O(t){let e=await ye(t);if(e.isDirectory())return await O(de(t,"package.json"));if(e.isFile()&&fe(t)==="package.json")return ge(t);throw new Error(`Unable to resolve package.json from ${t}`)}try{let{json:t,info:e,packages:r,...o}=Pt(),n=await he.from(r).map(c=>O(c),{concurrency:o.concurrency}).toArray(),i=[],s=c=>{i.push(c),!t&&(e||c.code===1)&&console.log(c.toString())},m=new AbortController;Pe(100,m.signal);let l=n.map(c=>{let y=new w({...o,package:c,controller:m});return y.on("result",s),y});try{for(let c of l)await c.run()}catch(c){if(c instanceof Error&&c.name!=="AbortError")throw c}process.exitCode=i.reduce((c,y)=>y.code===1?1:c,0),t&&process.stdout.write(JSON.stringify(i.filter(c=>e||c.code===1),(c,y)=>y instanceof Error?v(y):y,2))}catch(t){console.group("validate-package-exports"),console.dir(t,{depth:null}),console.groupEnd(),process.exitCode??=1}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "validate-package-exports",
3
- "version": "0.14.0",
3
+ "version": "0.16.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",
@@ -32,14 +32,14 @@
32
32
  "engines": {
33
33
  "node": ">=20.17.0"
34
34
  },
35
- "packageManager": "pnpm@10.17.1+sha512.17c560fca4867ae9473a3899ad84a88334914f379be46d455cbf92e5cf4b39d34985d452d2583baf19967fa76cb5c17bc9e245529d0b98745721aa7200ecaf7a",
35
+ "packageManager": "pnpm@10.28.2+sha512.41872f037ad22f7348e3b1debbaf7e867cfd448f2726d9cf74c08f19507c31d2c8e7a11525b983febc2df640b5438dee6023ebb1f84ed43cc2d654d2bc326264",
36
36
  "scripts": {
37
37
  "prevalidate": "pnpm build:dev",
38
38
  "validate": "./dist/cli.mjs",
39
39
  "format": "prettier --write .",
40
40
  "build": "cross-env NODE_ENV=production node --experimental-json-modules --no-warnings ./build.mjs",
41
41
  "build:dev": "cross-env NODE_ENV=development node --experimental-json-modules --no-warnings ./build.mjs",
42
- "postbuild": "node dist/cli.mjs --check --verify",
42
+ "postbuild": "node dist/cli.mjs --check",
43
43
  "typecheck": "tsc --noEmit && tsc -p ./tsconfig.project-files.json",
44
44
  "spellcheck": "cspell --no-progress \"./src/**/*.{ts,js,json}\" \"./*.{md,js,mjs,mts}\" \"./LICENSE\" \"./package.json\"",
45
45
  "lint": "eslint ./src \"./*.{mjs,mts}\" --ext .ts",
@@ -52,25 +52,25 @@
52
52
  "sideEffects": false,
53
53
  "prettier": "@webdeveric/prettier-config",
54
54
  "dependencies": {
55
- "@npmcli/arborist": "^9.1.5",
56
- "@webdeveric/utils": "^0.72.0",
57
- "npm-packlist": "^10.0.2"
55
+ "@npmcli/arborist": "^9.1.10",
56
+ "@webdeveric/utils": "^0.74.1",
57
+ "npm-packlist": "^10.0.3"
58
58
  },
59
59
  "devDependencies": {
60
- "@commitlint/config-conventional": "^20.0.0",
61
- "@commitlint/types": "^20.0.0",
62
- "@types/node": "^20.19.17",
60
+ "@commitlint/config-conventional": "^20.4.1",
61
+ "@commitlint/types": "^20.4.0",
62
+ "@types/node": "^20.19.30",
63
63
  "@types/npm-packlist": "^7.0.3",
64
- "@types/npmcli__arborist": "^6.3.1",
65
- "@vitest/coverage-v8": "^3.2.4",
64
+ "@types/npmcli__arborist": "^6.3.2",
65
+ "@vitest/coverage-v8": "^4.0.18",
66
66
  "@webdeveric/eslint-config-ts": "^0.11.0",
67
67
  "@webdeveric/prettier-config": "^0.3.0",
68
- "commitlint": "^20.0.0",
69
- "commitlint-plugin-cspell": "^0.3.0",
68
+ "commitlint": "^20.4.1",
69
+ "commitlint-plugin-cspell": "^0.4.0",
70
70
  "conventional-changelog-conventionalcommits": "^9.1.0",
71
- "cross-env": "^10.0.0",
72
- "cspell": "^9.2.1",
73
- "esbuild": "^0.25.10",
71
+ "cross-env": "^10.1.0",
72
+ "cspell": "^9.6.3",
73
+ "esbuild": "^0.27.2",
74
74
  "esbuild-plugin-clean": "^1.0.1",
75
75
  "esbuild-plugin-environment": "^0.4.0",
76
76
  "eslint": "^8.57.1",
@@ -78,17 +78,20 @@
78
78
  "eslint-import-resolver-typescript": "^4.4.4",
79
79
  "eslint-plugin-import": "^2.32.0",
80
80
  "husky": "^9.1.7",
81
- "lint-staged": "^16.2.1",
82
- "prettier": "^3.6.2",
83
- "semantic-release": "^24.2.9",
84
- "typescript": "^5.9.2",
85
- "vite-tsconfig-paths": "^5.1.4",
86
- "vitest": "^3.2.4"
81
+ "lint-staged": "^16.2.7",
82
+ "prettier": "^3.8.1",
83
+ "semantic-release": "^25.0.3",
84
+ "typescript": "^5.9.3",
85
+ "vite-tsconfig-paths": "^6.0.5",
86
+ "vitest": "^4.0.18"
87
87
  },
88
88
  "pnpm": {
89
89
  "onlyBuiltDependencies": [
90
90
  "esbuild",
91
91
  "unrs-resolver"
92
- ]
92
+ ],
93
+ "overrides": {
94
+ "undici@<6.23.0": ">=6.23.0"
95
+ }
93
96
  }
94
97
  }
package/readme.md CHANGED
@@ -23,7 +23,6 @@ yarn add validate-package-exports -D
23
23
  | Flag | Description | Default value |
24
24
  | --- | --- | --- |
25
25
  | `--check` / `-s` | Check syntax of JS files | `false` |
26
- | `--verify` / `-v` | Verify a module can be imported or required | `false` |
27
26
  | `--concurrency` / `-c` | Concurrency | `availableParallelism()` |
28
27
  | `--bail` / `-b` | Stop after the first error | `process.env.CI === 'true'` |
29
28
  | `--no-bail` | Turn off `--bail` | `false` |
@@ -45,7 +44,7 @@ validate-package-exports [FILE]... [options]
45
44
  {
46
45
  "scripts": {
47
46
  "build": "YOUR-BUILD-SCRIPT",
48
- "postbuild": "validate-package-exports --check --verify"
47
+ "postbuild": "validate-package-exports --check"
49
48
  }
50
49
  }
51
50
  ```
@@ -55,7 +54,7 @@ OR
55
54
  ```json
56
55
  {
57
56
  "scripts": {
58
- "prepublishOnly": "validate-package-exports --check --verify"
57
+ "prepublishOnly": "validate-package-exports --check"
59
58
  }
60
59
  }
61
60
  ```
@@ -63,7 +62,7 @@ OR
63
62
  ### Using `npx`
64
63
 
65
64
  ```shell
66
- npx --yes validate-package-exports ./path/to/package.json --check --verify
65
+ npx --yes validate-package-exports ./path/to/package.json --check
67
66
  ```
68
67
 
69
68
  ## Local development