npm-package-json-lint
Version:
Configurable linter for package.json files.
28 lines (26 loc) • 18 kB
JavaScript
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),s=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},c=(n,r,a)=>(a=n==null?{}:e(i(n)),s(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let l=require(`chalk`);l=c(l);let u=require(`meow`);u=c(u);let d=require(`cosmiconfig`),f=require(`ajv`);f=c(f);let p=require(`ajv-errors`);p=c(p);let m=require(`node:path`);m=c(m);let h=require(`node:fs`);h=c(h);let g=require(`strip-json-comments`);g=c(g);let _=require(`minimatch`),v=require(`globby`);v=c(v);let y=require(`ignore`);y=c(y);const b=e=>e.startsWith(`\\\\?\\`)?e:e.replaceAll(`\\`,`/`),ee=e=>{if(typeof e!=`object`||!e)return!1;let t=Object.getPrototypeOf(e);return(t===null||t===Object.prototype||Object.getPrototypeOf(t)===null)&&!(Symbol.toStringTag in e)&&!(Symbol.iterator in e)},x=new f.default({allErrors:!0,jsonPointers:!0});(0,p.default)(x);const S=e=>e.map(e=>`\t- ${e.message}\n`).join(``),C={type:`string`,enum:[`off`,`warning`,`error`],errorMessage:{type:`severity must be a string.`,enum:`severity must be either "off", "warning", or "error".`}},te=e=>({type:`array`,items:[C,{type:`array`,minItems:e,uniqueItems:!0,errorMessage:{type:`the second item in an array rule config must be an array.`,minItems:`the second item in an array rule config must have at least 1 item.`,uniqueItems:`the second item in an array rule config must have unique items.`}}],minItems:2,maxItems:2,additionalItems:!1,errorMessage:{type:`rule config must be an array, e.g. ["error", ["value1", "value2"]].`,minItems:`array rules must have two items, severity and options array. e.g. ["error", ["value1", "value2"]].`,maxItems:`array rules must have two items, severity and options array. e.g. ["error", ["value1", "value2"]].`,additionalItems:`array rules are only allowed two items, severity and the list is values. e.g. ["error", ["value1", "value2"]].`}}),w={type:`array`,items:[C,{type:`object`,errorMessage:{type:`the second item in an object rule config must be an object.`}}],minItems:2,maxItems:2,additionalItems:!1,errorMessage:{type:`rule config must be an array, e.g. ["error", {}].`,minItems:`object rules must have two items, severity and options object. e.g. ["error", {}].`,maxItems:`object rules must have two items, severity and options object. e.g. ["error", {}].`,additionalItems:`object rules are only allowed two items, severity and options object. e.g. ["error", {}].`}},ne={type:`array`,items:[{type:`string`,errorMessage:{type:`each exception must be a string.`}}],uniqueItems:!0,minItems:1,errorMessage:{type:`expections must be an array.`,minItems:`expections must have at least 1 item.`,uniqueItems:`expections must have unique items.`}},T=e=>{let t=x.compile(C);if(!t(e))throw Error(`${S(t.errors)}`);return!0},re=(e,t)=>{let n=x.compile(te(t));if(!n(e))throw Error(`${S(n.errors)}`);return!0},E=e=>{let t=x.compile(w);if(!t(e))throw Error(`${S(t.errors)}`);return!0},ie=e=>{let t=x.compile(ne);if(!t(e))throw Error(`${S(t.errors)}`);return!0},ae=e=>{if(typeof e==`string`&&e===`off`)return!0;if(typeof e==`string`&&e!==`off`)throw Error(` - is an object type rule. It must be set to "off" if an object is not supplied.`);return E(e)},oe=e=>typeof e==`string`?T(e):E(e)&&e[1].hasOwnProperty(`exceptions`)?ie(e[1].exceptions):!0,se=(e,t)=>{if(typeof e==`string`&&e===`off`)return!0;if(typeof e==`string`&&e!==`off`)throw Error(` - is an array type rule. It must be set to "off" if an array is not supplied.`);return re(e,t)},ce=e=>T(e),D=(e,t,n,r)=>{if(e)try{switch(e.ruleType){case`array`:se(n,e.minItems);break;case`object`:ae(n);break;case`optionalObject`:oe(n);break;default:ce(n)}}catch(e){let n=`Configuration for rule "${t}" is invalid:\n${e.message}`;throw Error(typeof r==`string`?`${r}:\n\t${n}`:n)}},O=(e,t,n)=>{e&&Object.keys(e).forEach(r=>{D(n.get(r),r,e[r],t)})},k=e=>require(e),le=e=>h.default.readFileSync(e,`utf8`).replace(/^\uFEFF/,``),A=(e,t)=>{throw Error(`Failed to read config file: ${e}. \nError: ${t.message}`)},ue=Symbol(`JSON source`),j=e=>{let t={},n=``;try{n=le(e),t=JSON.parse((0,g.default)(n))}catch(t){A(e,t)}return Object.defineProperty(t,ue,{value:n,enumerable:!1,writable:!1,configurable:!1}),t},de=e=>{let t={};try{t=k(e)}catch(t){A(e,t)}return t},M=require(`debug`)(`npm-package-json-lint:applyExtendsIfSpecified`),N=(e,t,n)=>{let r=e.extends;return Array.isArray(e.extends)||(r=[e.extends]),r.reduceRight((e,r)=>{try{let t=fe(r,n),i={...t,...e},a={...t.rules,...e.rules},o=Array.isArray(t.plugins)?t.plugins:[],s=Array.isArray(e.plugins)?e.plugins:[],c=[...o,...s],l=[...new Set(c)],u=Array.isArray(t.overrides)?t.overrides:[],d=Array.isArray(e.overrides)?e.overrides:[],f=[...u,...d];return i.rules=a,c.length>0&&(i.plugins=l),f.length>0&&(i.overrides=f),i}catch(e){throw e.message+=`\nReferenced from: ${t}`,e}},e)},fe=(e,t)=>{let n,r=e;if(e.startsWith(`./`))r=m.default.join(process.cwd(),e),n=pe(r);else{let e=require.resolve(r,{paths:[m.default.dirname(t)]});n=require(e)}return Object.keys(n).length>0&&n.extends&&(n=N(n,r,t)),n},pe=e=>{let t;switch(m.default.extname(e)){case`.js`:t=de(e);break;case`.json`:t=j(e);break;default:throw Error(`Unsupport config file extension. File path: ${e}`)}return t},P=(e,t)=>{let n={...e};return M(`Loading extends, if applicable`),n?.hasOwnProperty(`extends`)&&n.extends&&(M(`extends property present, applying.`),n=N(n,t,t)),M(`Loading extends complete`),n},F=require(`debug`)(`npm-package-json-lint:applyOverrides`),I=(e,t,n,r)=>{let i={...n};if(F(`overrides`),F(r),r){let n=m.default.relative(e,t).replace(/\\/g,`/`);r.forEach(e=>{let t=e.patterns.filter(e=>e.length).map(e=>e.endsWith(`/package.json`)?e:`${e}/package.json`),r=t.some(e=>(0,_.minimatch)(n,e.replace(/^\.\//,``),{dot:!0}));F(`relativeFilePath: %s, patterns: %o, matches: %s`,n,t,r),r&&(i={...i,...e.rules})})}return F(`finalRules`),F(i),i},L=require(`debug`)(`npm-package-json-lint:cosmicConfigTransformer`),R=(e,t,n)=>(L(`cwd: ${e}`),L(`configBaseDirectory`),L(t),r=>{if(L(`cosmiconfigResult`),L(r),!r)return null;let{config:i,filepath:a}=r;L(`cosmiconfigResult.config`),L(i),L(`cosmiconfigResult.filepath`),L(a),t||m.default.dirname(a||``);let o=P({...i},n);return I(e,n,o.rules,o.overrides)}),z=require(`debug`)(`npm-package-json-lint:Config`);var B=class{constructor(e,t,n,r,i){t&&(this.config=P(t,`PassedConfig`)),this.cwd=e,this.configFile=n,this.configBaseDirectory=r,this.rules=i}getConfigForFile(e){z(`Getting config for ${e}`);let t=e;z(`filePathToSearch: ${t}`);let n;if(this.config===void 0)z(`User passed config is undefined.`),this.configFile?(z(`Config file specified, loading it.`),n=(0,d.cosmiconfigSync)(`npmpackagejsonlint`,{transform:R(this.cwd,this.configBaseDirectory,e)}).load(this.configFile)):(z(`Config file wasn't specified, searching for config.`),n=(0,d.cosmiconfigSync)(`npmpackagejsonlint`,{transform:R(this.cwd,this.configBaseDirectory,t)}).search(t));else{z(`User passed config is set, using it.`);let t=this.config;z(`Applying overrides to config for ${e}`),n=I(this.cwd,e,t.rules,t.overrides),z(`Overrides applied for ${e}`)}if(!n)throw Error(`No npm-package-json-lint configuration found.\n${t}`);if(Object.keys(n).length===0)throw Error(`No rules specified in configuration.\n${t}`);return z(`Overrides applied for ${e}`),z(`Final Config`),z(n),O(n,`cli`,this.rules),n}},me=class{constructor(){this.rules={}}load(){let e=m.default.join(__dirname,`rules`);try{return(0,h.readdirSync)(e).forEach(t=>{let n=t.slice(0,-3),r=m.default.join(e,t);this.registerRule(n,r)}),this.rules}catch(e){throw Error(`Error while loading rules from rules directory - ${e.message}`,e)}}get(e){if(this.rules[e]===void 0){let t=`Rule, ${e}, is invalid. Please ensure it matches a valid option.`;throw Error(l.default.bold.red(t))}return require(this.rules[e])}getRules(){return this.rules}registerRule(e,t){this.rules[e]=t}};const he=e=>e.reduce((e,t)=>{let n=t.severity===`error`;return{errorCount:n?e.errorCount+1:e.errorCount,warningCount:n?e.warningCount:e.warningCount+1}},{errorCount:0,warningCount:0}),V=e=>e.reduce((e,t)=>({ignoreCount:t.ignored?e.ignoreCount+1:e.ignoreCount,errorCount:e.errorCount+t.errorCount,warningCount:e.warningCount+t.warningCount}),{ignoreCount:0,errorCount:0,warningCount:0}),H=require(`debug`)(`npm-package-json-lint:linter`),U=e=>{let{cwd:t,fileName:n,ignored:r,issues:i,errorCount:a,warningCount:o}=e;return{filePath:`./${m.default.relative(t,n)}`,issues:i,ignored:r,errorCount:a,warningCount:o}},ge=(e,t,n)=>{let r=[];for(let i in t){let a=n.get(i),o=`off`,s;if(a.ruleType===`array`||a.ruleType===`object`?(o=typeof t[i]==`string`&&t[i]===`off`?t[i]:t[i][0],s=typeof t[i]==`string`?{}:t[i][1]):a.ruleType===`optionalObject`?typeof t[i]==`string`?(o=t[i],s={}):(o=t[i][0],s=t[i][1]):o=t[i],o!==`off`){let t=a.lint(e,o,s);t!==null&&r.push(t)}}return r},W=(e,t,n,r,i)=>{let a=ge(t,n,i),o=he(a);return U({cwd:e,fileName:r,ignored:!1,issues:a,errorCount:o.errorCount,warningCount:o.warningCount})},_e=(e,t,n,r)=>W(e,j(m.default.resolve(t)),n,t,r),ve=e=>{let{cwd:t,packageJsonObject:n,filename:r,ignorer:i,configHelper:a,rules:o}=e;H(`executing on package.json object`);let s=[],c=r||``,l=m.default.isAbsolute(c)?c:m.default.resolve(t,c),u=m.default.relative(t,l);if(i.ignores(u)){H(`Ignored: ${u}`);let e=U({cwd:t,fileName:l,ignored:!0,issues:[],errorCount:0,warningCount:0});s.push(e)}else{H(`Getting config for ${l}`);let e=a.getConfigForFile(l);H(`Config fetched for ${l}`);let r=W(t,n,e,l,o);s.push(r)}H(`Aggregating overall counts`);let d=V(s);return H(`stats`),H(d),{results:s,ignoreCount:d.ignoreCount,errorCount:d.errorCount,warningCount:d.warningCount}},ye=e=>{let{cwd:t,fileList:n,ignorer:r,configHelper:i,rules:a}=e;H(`executing on package.json files`);let o=n.map(e=>{let n=m.default.relative(t,e);if(r.ignores(n))return H(`Ignored: ${n}`),U({cwd:t,fileName:e,ignored:!0,issues:[],errorCount:0,warningCount:0});H(`Getting config for ${e}`);let o=i.getConfigForFile(e);return H(`Config fetched for ${e}`),_e(t,e,o,a)});H(`Aggregating overall counts`);let s=V(o);return H(`stats`),H(s),{results:o,ignoreCount:s.ignoreCount,errorCount:s.errorCount,warningCount:s.warningCount}},G=require(`debug`)(`npm-package-json-lint:getFileList`),be=(e,t)=>{G(`patterns`),G(e);let n=e.filter(e=>e.length);G(`filteredPatterns`),G(n);let r=n.map(e=>e.endsWith(`/package.json`)?e:`${e}/**/package.json`);r.push(`!**/node_modules/**`),G(`globPatterns`),G(r);let i=[],a=new Set,o=v.default.sync(r,{cwd:t,gitignore:!0});return G(`globFiles`),G(o),o.forEach(e=>{let n=m.default.resolve(t,e);a.has(n)||(a.add(n),i.push(n))}),G("Final file list from `getFileList`"),G(i),i},K=require(`debug`)(`npm-package-json-lint:getIgnorer`),xe=(e,t)=>{let n=t||`.npmpackagejsonlintignore`;K(`ignoreFilePath: ${n}`);let r=m.default.isAbsolute(n)?n:m.default.resolve(e,n);K(`absoluteIgnoreFilePath: ${r}`);let i=``;try{i=h.default.readFileSync(r,`utf8`)}catch(e){if(e.code!==`ENOENT`)throw e}return K(`Ignore text added`),(0,y.default)().add(i)};var Se=o(((e,t)=>{t.exports={name:`npm-package-json-lint`,version:`0.0.0`,description:`Configurable linter for package.json files.`,keywords:[`lint`,`linter`,`package.json`,`audit`,`auditor`,`npm-package-json-lint`],homepage:`https://github.com/tclindner/npm-package-json-lint`,bugs:{url:`https://github.com/tclindner/npm-package-json-lint/issues`},author:`Thomas Lindner`,repository:{type:`git`,url:`https://github.com/tclindner/npm-package-json-lint.git`},bin:{npmPkgJsonLint:`dist/cli.js`},files:[`CONTRIBUTING.md`,`dist`],main:`dist/api.js`,types:`dist/src/api.d.ts`,scripts:{build:`tsdown`,eslint:`eslint .`,npmpackagejsonlint:`node dist/cli.js ./package.json`,lint:`npm run eslint && npm run npmpackagejsonlint`,test:`npm run build && jest`,"test:ci":`jest --runInBand`},dependencies:{ajv:`6.14.0`,minimatch:`10.2.4`,"ajv-errors":`1.0.1`,chalk:`4.1.2`,cosmiconfig:`8.3.6`,debug:`4.4.3`,globby:`11.1.0`,ignore:`5.3.2`,"jsonc-parser":`3.3.1`,meow:`9.0.0`,semver:`7.7.4`,"strip-json-comments":`3.1.1`,"type-fest":`5.6.0`,"validate-npm-package-name":`6.0.0`},devDependencies:{"@eslint/js":`10.0.1`,"@types/jest":`30.0.0`,"@types/node":`25.6.0`,eslint:`10.2.1`,"eslint-config-prettier":`10.1.8`,"eslint-config-tc":`28.0.3`,"eslint-config-typescript-tc":`12.1.0`,"eslint-plugin-import-x":`4.16.2`,"eslint-plugin-jest":`29.15.2`,"eslint-plugin-prettier":`5.5.5`,"eslint-plugin-unicorn":`64.0.0`,globals:`17.5.0`,jest:`30.3.0`,"npm-package-json-lint-config-default":`9.0.1`,"npm-package-json-lint-config-tc":`10.0.2`,prettier:`3.8.3`,"ts-jest":`29.4.9`,tsdown:`0.21.10`,typescript:`5.4.5`,"typescript-eslint":`8.59.0`},engines:{node:`>=22.0.0`,npm:`>=10.0.0`},license:`MIT`}}));const q=require(`debug`)(`npm-package-json-lint:NpmPackageJsonLint`),Ce=Se(),we=e=>e.severity===`error`,J=e=>ee(e),Te=(e,t)=>!t&&!J(e)||t&&(e||J(e)),Ee=e=>{let t=[];return e.forEach(e=>{let n=e.issues.filter(we);if(n.length>0){let r={issues:n,errorCount:n.length,warningCount:0};t.push(Object.assign(e,r))}}),t};var De=class{constructor(e){let{cwd:t,packageJsonObject:n,packageJsonFilePath:r,config:i,configFile:a,configBaseDirectory:o,patterns:s,quiet:c,ignorePath:l,fix:u}=e;this.cwd=b(t||process.cwd()),this.packageJsonObject=n,this.packageJsonFilePath=r&&b(r),this.patterns=s,this.quiet=c||!1,this.ignorePath=l||``,this.fix=u||!1,this.version=Ce.version,this.rules=new me,this.rules.load(),this.configHelper=new B(this.cwd,i,a,o,this.rules)}lint(){if(q(`Starting lint`),Te(this.packageJsonObject,this.patterns))throw Error("You must pass npm-package-json-lint a `patterns` glob or a `packageJsonObject` string, though not both.");let e=xe(this.cwd,this.ignorePath),t;if(this.patterns){if(q(`Linting using patterns`),!Array.isArray(this.patterns))throw TypeError(`Patterns must be an array.`);let n=be(this.patterns,this.cwd);t=ye({cwd:this.cwd,fileList:n,ignorer:e,configHelper:this.configHelper,rules:this.rules})}else q(`Linting using passed object.`),t=ve({cwd:this.cwd,packageJsonObject:this.packageJsonObject,ignorer:e,filename:this.packageJsonFilePath,configHelper:this.configHelper,rules:this.rules});return this.quiet?{results:Ee(t.results),ignoreCount:t.ignoreCount,errorCount:t.errorCount,warningCount:t.warningCount}:(q(`lint complete`),t)}};const Y=(e,t)=>t>1||t===0?`${e}s`:e,Oe=e=>{e.forEach(e=>{console.log(e.toString())})},ke=(e,t)=>{let{filePath:n,issues:r,ignored:i,errorCount:a,warningCount:o}=e;if(i)console.log(``),console.log(`${l.default.yellow.underline(n)} - ignored`);else if(a>0||!t&&o>0){console.log(``),console.log(l.default.underline(n)),Oe(r);let e=`${a} ${Y(`error`,a)}`,i=`${o} ${Y(`warning`,o)}`;console.log(l.default.red.bold(e)),t||console.log(l.default.yellow.bold(i))}},Ae=(e,t)=>{let{errorCount:n,warningCount:r,ignoreCount:i}=e;if(n>0||r>0){let e=`${n} ${Y(`error`,n)}`,a=`${r} ${Y(`warning`,r)}`,o=`${i} ${Y(`file`,i)} ignored`;console.log(``),console.log(l.default.underline(`Totals`)),console.log(l.default.red.bold(e)),t||(console.log(l.default.yellow.bold(a)),console.log(l.default.yellow.bold(o)))}},je=(e,t)=>{e.results.forEach(e=>{ke(e,t)}),e.results.length>1&&Ae(e,t)},X=require(`debug`)(`npm-package-json-lint:cli`),Z={zeroClean:0,oneMissingTarget:1,twoLintErrorsDetected:2,runTimeException:3,exceedMaxWarnings:4},{input:Me,flags:Q}=(0,u.default)(`
Usage
$ npmPkgJsonLint <patterns>
Options
--quiet, -q Report errors only
--noConfigFiles, -ncf Disables use of .npmpackagejsonlintrc.json files, npmpackagejsonlint.config.js files, and npmpackagejsonlint object in package.json file.
--configFile, -c File path of .npmpackagejsonlintrc.json
--ignorePath, -i Path to a file containing patterns that describe files to ignore. The path can be absolute or relative to process.cwd(). By default, npm-package-json-lint looks for .npmpackagejsonlintignore in process.cwd().
--maxWarnings, -mw Maximum number of warnings that can be detected before an error is thrown.
--allowEmptyTargets Do not throw an error when a list of targets is empty.
Examples
$ npmPkgJsonLint --version
$ npmPkgJsonLint .
$ npmPkgJsonLint ./packages
$ npmPkgJsonLint ./package1 ./package2
$ npmPkgJsonLint -c ./config/.npmpackagejsonlintrc.json .
$ npmPkgJsonLint --configFile ./config/npmpackagejsonlint.config.json .
$ npmPkgJsonLint -q .
$ npmPkgJsonLint --quiet ./packages
$ npmPkgJsonLint . --ignorePath .gitignore
$ npmPkgJsonLint . -i .gitignore
$ npmPkgJsonLint . --maxWarnings 10
$ npmPkgJsonLint . -mw 10
`,{flags:{quiet:{type:`boolean`,alias:`q`,default:!1},noConfigFiles:{type:`boolean`,alias:`ncf`,default:!1},configFile:{type:`string`,alias:`c`,default:``},ignorePath:{type:`string`,alias:`i`,default:``},maxWarnings:{type:`number`,alias:`mw`,default:1e7},allowEmptyTargets:{type:`boolean`,default:!1}}}),$=Me;if(X(`patterns: ${$}`),$.length===0){X(`No lint targets provided`),console.log(l.default.red.bold(`No lint targets provided`));let e=Q.allowEmptyTargets?Z.zeroClean:Z.oneMissingTarget;process.exit(e)}try{let e=Z.zeroClean;X(`Creating NpmPackageJsonLint instance`);let t=new De({cwd:process.cwd(),configFile:Q.configFile,patterns:$,ignorePath:Q.ignorePath,quiet:Q.quiet}).lint();X(`NpmPackageJsonLint.lint complete`),X(`Reporter.write starting`),je(t,Q.quiet),X(`Reporter.write complete`),t.warningCount>Q.maxWarnings&&(X(`Max warnings exceeded`),e=Z.exceedMaxWarnings),t.errorCount>0&&(X(`Lint errors detected`),e=Z.twoLintErrorsDetected),process.exit(e)}catch(e){console.log(l.default.red.bold(e.message)),process.exit(Z.runTimeException)}
//# sourceMappingURL=cli.js.map