validate-package-exports 0.1.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/LICENSE +21 -0
- package/dist/cli.mjs +9 -0
- package/package.json +73 -0
- package/readme.md +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Eric King
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/*!
|
|
3
|
+
* @file validate-package-exports
|
|
4
|
+
* @version 0.1.0
|
|
5
|
+
* @license MIT
|
|
6
|
+
* @copyright Eric King 2024
|
|
7
|
+
* @see {@link https://github.com/webdeveric/validate-package-exports/#readme}
|
|
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}
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "validate-package-exports",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Validate your package.json exports actually exist, have valid syntax, and can be imported or required without issues.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"validate",
|
|
7
|
+
"package",
|
|
8
|
+
"package.json",
|
|
9
|
+
"exports"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"author": {
|
|
13
|
+
"email": "eric@webdeveric.com",
|
|
14
|
+
"name": "Eric King",
|
|
15
|
+
"url": "http://webdeveric.com/"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/webdeveric/validate-package-exports.git"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/webdeveric/validate-package-exports/issues"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/webdeveric/validate-package-exports/#readme",
|
|
25
|
+
"type": "module",
|
|
26
|
+
"bin": {
|
|
27
|
+
"validate-package-exports": "./dist/cli.mjs"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"./dist"
|
|
31
|
+
],
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=18.11.0"
|
|
34
|
+
},
|
|
35
|
+
"packageManager": "pnpm@8.15.5+sha256.4b4efa12490e5055d59b9b9fc9438b7d581a6b7af3b5675eb5c5f447cee1a589",
|
|
36
|
+
"sideEffects": false,
|
|
37
|
+
"prettier": "@webdeveric/prettier-config",
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^20.11.30",
|
|
40
|
+
"@vitest/coverage-v8": "^1.4.0",
|
|
41
|
+
"@webdeveric/eslint-config-ts": "^0.7.1",
|
|
42
|
+
"@webdeveric/prettier-config": "^0.2.0",
|
|
43
|
+
"@webdeveric/utils": "^0.29.1",
|
|
44
|
+
"cross-env": "^7.0.3",
|
|
45
|
+
"cspell": "^8.6.0",
|
|
46
|
+
"esbuild-plugin-clean": "^1.0.1",
|
|
47
|
+
"esbuild-plugin-environment": "^0.3.0",
|
|
48
|
+
"esbuild": "^0.20.2",
|
|
49
|
+
"eslint-config-prettier": "^9.1.0",
|
|
50
|
+
"eslint-import-resolver-typescript": "^3.6.1",
|
|
51
|
+
"eslint-plugin-import": "^2.29.1",
|
|
52
|
+
"eslint": "^8.57.0",
|
|
53
|
+
"husky": "^9.0.11",
|
|
54
|
+
"lint-staged": "^15.2.2",
|
|
55
|
+
"prettier": "^3.2.5",
|
|
56
|
+
"typescript": "^5.4.3",
|
|
57
|
+
"vite-tsconfig-paths": "^4.3.2",
|
|
58
|
+
"vitest": "^1.4.0"
|
|
59
|
+
},
|
|
60
|
+
"scripts": {
|
|
61
|
+
"predemo": "pnpm build:dev",
|
|
62
|
+
"demo": "./dist/cli.mjs",
|
|
63
|
+
"format": "prettier --write .",
|
|
64
|
+
"build": "cross-env NODE_ENV=production node --experimental-json-modules --no-warnings ./build.mjs",
|
|
65
|
+
"build:dev": "cross-env NODE_ENV=development node --experimental-json-modules --no-warnings ./build.mjs",
|
|
66
|
+
"postbuild": "node dist/cli.mjs --check --verify",
|
|
67
|
+
"typecheck": "tsc --noEmit && tsc -p ./tsconfig.project-files.json",
|
|
68
|
+
"spellcheck": "cspell --no-progress \"./src/**/*.{ts,js,json}\" \"./*.{md,js,mjs,mts}\" \"./LICENSE\" \"./package.json\"",
|
|
69
|
+
"lint": "eslint ./src ./*.{mjs,mts} --ext .ts",
|
|
70
|
+
"test": "vitest -c vitest.config.mts",
|
|
71
|
+
"coverage": "vitest run -c vitest.config.mts --coverage"
|
|
72
|
+
}
|
|
73
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# validate-package-exports
|
|
2
|
+
|
|
3
|
+
[](https://github.com/webdeveric/validate-package-exports/actions/workflows/node.js.yml)
|
|
4
|
+
|
|
5
|
+
Validate your `package.json` exports actually exist, have valid syntax, and can be imported or required without issues.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```shell
|
|
10
|
+
pnpm add validate-package-exports -D
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```shell
|
|
14
|
+
npm i validate-package-exports -D
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```shell
|
|
18
|
+
yarn add validate-package-exports -D
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Options
|
|
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` | |
|
|
31
|
+
|
|
32
|
+
## Recommended usage
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "YOUR-BUILD-SCRIPT",
|
|
38
|
+
"postbuild": "validate-package-exports --check --verify"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
OR
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"scripts": {
|
|
48
|
+
"prepublishOnly": "validate-package-exports --check --verify"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Local development
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
fnm use
|
|
57
|
+
corepack enable
|
|
58
|
+
pnpm install
|
|
59
|
+
pnpm build
|
|
60
|
+
```
|