npm-pkg-lint 3.0.0 → 3.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/dist/index.js CHANGED
@@ -12514,8 +12514,11 @@ var require_re = __commonJS({
12514
12514
  createToken("XRANGEPLAINLOOSE", `[v=\\s]*(${src[t.XRANGEIDENTIFIERLOOSE]})(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})(?:${src[t.PRERELEASELOOSE]})?${src[t.BUILD]}?)?)?`);
12515
12515
  createToken("XRANGE", `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAIN]}$`);
12516
12516
  createToken("XRANGELOOSE", `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAINLOOSE]}$`);
12517
- createToken("COERCE", `${"(^|[^\\d])(\\d{1,"}${MAX_SAFE_COMPONENT_LENGTH}})(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?(?:$|[^\\d])`);
12517
+ createToken("COERCEPLAIN", `${"(^|[^\\d])(\\d{1,"}${MAX_SAFE_COMPONENT_LENGTH}})(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`);
12518
+ createToken("COERCE", `${src[t.COERCEPLAIN]}(?:$|[^\\d])`);
12519
+ createToken("COERCEFULL", src[t.COERCEPLAIN] + `(?:${src[t.PRERELEASE]})?(?:${src[t.BUILD]})?(?:$|[^\\d])`);
12518
12520
  createToken("COERCERTL", src[t.COERCE], true);
12521
+ createToken("COERCERTLFULL", src[t.COERCEFULL], true);
12519
12522
  createToken("LONETILDE", "(?:~>?)");
12520
12523
  createToken("TILDETRIM", `(\\s*)${src[t.LONETILDE]}\\s+`, true);
12521
12524
  exports.tildeTrimReplace = "$1~";
@@ -13150,21 +13153,27 @@ var require_coerce = __commonJS({
13150
13153
  options = options || {};
13151
13154
  let match2 = null;
13152
13155
  if (!options.rtl) {
13153
- match2 = version2.match(re[t.COERCE]);
13156
+ match2 = version2.match(options.includePrerelease ? re[t.COERCEFULL] : re[t.COERCE]);
13154
13157
  } else {
13158
+ const coerceRtlRegex = options.includePrerelease ? re[t.COERCERTLFULL] : re[t.COERCERTL];
13155
13159
  let next;
13156
- while ((next = re[t.COERCERTL].exec(version2)) && (!match2 || match2.index + match2[0].length !== version2.length)) {
13160
+ while ((next = coerceRtlRegex.exec(version2)) && (!match2 || match2.index + match2[0].length !== version2.length)) {
13157
13161
  if (!match2 || next.index + next[0].length !== match2.index + match2[0].length) {
13158
13162
  match2 = next;
13159
13163
  }
13160
- re[t.COERCERTL].lastIndex = next.index + next[1].length + next[2].length;
13164
+ coerceRtlRegex.lastIndex = next.index + next[1].length + next[2].length;
13161
13165
  }
13162
- re[t.COERCERTL].lastIndex = -1;
13166
+ coerceRtlRegex.lastIndex = -1;
13163
13167
  }
13164
13168
  if (match2 === null) {
13165
13169
  return null;
13166
13170
  }
13167
- return parse(`${match2[2]}.${match2[3] || "0"}.${match2[4] || "0"}`, options);
13171
+ const major = match2[2];
13172
+ const minor = match2[3] || "0";
13173
+ const patch = match2[4] || "0";
13174
+ const prerelease = options.includePrerelease && match2[5] ? `-${match2[5]}` : "";
13175
+ const build = options.includePrerelease && match2[6] ? `+${match2[6]}` : "";
13176
+ return parse(`${major}.${minor}.${patch}${prerelease}${build}`, options);
13168
13177
  };
13169
13178
  module.exports = coerce;
13170
13179
  }
@@ -15010,7 +15019,6 @@ import { fileURLToPath as fileURLToPath3 } from "url";
15010
15019
 
15011
15020
  // node_modules/find-up/index.js
15012
15021
  import path2 from "path";
15013
- import { fileURLToPath as fileURLToPath2 } from "url";
15014
15022
 
15015
15023
  // node_modules/find-up/node_modules/locate-path/index.js
15016
15024
  import process2 from "process";
@@ -15190,14 +15198,19 @@ async function locatePath(paths, {
15190
15198
  }, { concurrency, preserveOrder });
15191
15199
  }
15192
15200
 
15201
+ // node_modules/unicorn-magic/node.js
15202
+ import { fileURLToPath as fileURLToPath2 } from "url";
15203
+ function toPath2(urlOrPath) {
15204
+ return urlOrPath instanceof URL ? fileURLToPath2(urlOrPath) : urlOrPath;
15205
+ }
15206
+
15193
15207
  // node_modules/find-up/index.js
15194
- var toPath2 = (urlOrPath) => urlOrPath instanceof URL ? fileURLToPath2(urlOrPath) : urlOrPath;
15195
15208
  var findUpStop = Symbol("findUpStop");
15196
15209
  async function findUpMultiple(name, options = {}) {
15197
- let directory2 = path2.resolve(toPath2(options.cwd) || "");
15210
+ let directory2 = path2.resolve(toPath2(options.cwd) ?? "");
15198
15211
  const { root } = path2.parse(directory2);
15199
- const stopAt = path2.resolve(directory2, options.stopAt || root);
15200
- const limit = options.limit || Number.POSITIVE_INFINITY;
15212
+ const stopAt = path2.resolve(directory2, toPath2(options.stopAt ?? root));
15213
+ const limit = options.limit ?? Number.POSITIVE_INFINITY;
15201
15214
  const paths = [name].flat();
15202
15215
  const runMatcher = async (locateOptions) => {
15203
15216
  if (typeof name !== "function") {
@@ -15874,8 +15887,8 @@ async function verifyTarball(pkg, tarball) {
15874
15887
  {
15875
15888
  messages,
15876
15889
  filePath: tarball.reportPath ?? tarball.filePath,
15877
- errorCount: messages.length,
15878
- warningCount: 0,
15890
+ errorCount: messages.filter((it) => it.severity === 2).length,
15891
+ warningCount: messages.filter((it) => it.severity === 1).length,
15879
15892
  fixableErrorCount: 0,
15880
15893
  fixableWarningCount: 0
15881
15894
  }
@@ -15884,6 +15897,7 @@ async function verifyTarball(pkg, tarball) {
15884
15897
 
15885
15898
  // src/validators/validation-error.ts
15886
15899
  var ValidationError = class extends Error {
15900
+ validator;
15887
15901
  constructor(validator, message) {
15888
15902
  super(message);
15889
15903
  this.validator = validator;
@@ -17649,20 +17663,58 @@ async function persistentCacheSet(key, data) {
17649
17663
 
17650
17664
  // src/utils/npm-info.ts
17651
17665
  var cache = /* @__PURE__ */ new Map();
17652
- async function npmInfo(pkg) {
17666
+ function isExecaError(error) {
17667
+ return Boolean(error && error instanceof Error && "stdout" in error);
17668
+ }
17669
+ function isNpmInfoError(error) {
17670
+ return Boolean(error && error instanceof Error && "summary" in error);
17671
+ }
17672
+ function tryParse(maybeJson) {
17673
+ try {
17674
+ return JSON.parse(maybeJson);
17675
+ } catch {
17676
+ return null;
17677
+ }
17678
+ }
17679
+ async function npmInfo(pkg, options = { ignoreUnpublished: false }) {
17680
+ const { ignoreUnpublished } = options;
17653
17681
  const cached = cache.get(pkg);
17654
- if (cached) {
17682
+ if (cached === null) {
17683
+ if (ignoreUnpublished) {
17684
+ return null;
17685
+ }
17686
+ } else if (cached) {
17655
17687
  return cached;
17656
17688
  }
17657
17689
  const persistent = await persistentCacheGet(pkg);
17658
17690
  if (persistent) {
17659
17691
  return persistent;
17660
17692
  }
17661
- const result = await execa("npm", ["info", "--json", pkg]);
17662
- const pkgData = JSON.parse(result.stdout);
17663
- cache.set(pkg, pkgData);
17664
- await persistentCacheSet(pkg, pkgData);
17665
- return pkgData;
17693
+ try {
17694
+ const result = await execa("npm", ["info", "--json", pkg]);
17695
+ const pkgData = JSON.parse(result.stdout);
17696
+ cache.set(pkg, pkgData);
17697
+ await persistentCacheSet(pkg, pkgData);
17698
+ return pkgData;
17699
+ } catch (err) {
17700
+ if (!isExecaError(err)) {
17701
+ throw err;
17702
+ }
17703
+ const parsed = tryParse(err.stdout);
17704
+ if (!parsed) {
17705
+ throw err;
17706
+ }
17707
+ const { code, summary, detail } = parsed.error;
17708
+ cache.set(pkg, null);
17709
+ if (ignoreUnpublished && code === "E404") {
17710
+ return null;
17711
+ }
17712
+ const wrappedError = new Error(summary, { cause: err });
17713
+ wrappedError.code = code;
17714
+ wrappedError.summary = summary;
17715
+ wrappedError.detail = detail;
17716
+ throw wrappedError;
17717
+ }
17666
17718
  }
17667
17719
 
17668
17720
  // src/rules/deprecated-dependency.ts
@@ -17681,17 +17733,31 @@ function* getDependencies(pkg) {
17681
17733
  async function deprecatedDependency(pkg) {
17682
17734
  const messages = [];
17683
17735
  for await (const dependency of getDependencies(pkg)) {
17684
- const { deprecated } = await npmInfo(dependency);
17685
- if (!deprecated) {
17686
- continue;
17736
+ try {
17737
+ const { deprecated } = await npmInfo(dependency);
17738
+ if (!deprecated) {
17739
+ continue;
17740
+ }
17741
+ messages.push({
17742
+ ruleId: ruleId2,
17743
+ severity: 2,
17744
+ message: `"${dependency}" is deprecated and must not be used`,
17745
+ line: 1,
17746
+ column: 1
17747
+ });
17748
+ } catch (err) {
17749
+ if (isNpmInfoError(err) && err.code === "E404") {
17750
+ messages.push({
17751
+ ruleId: ruleId2,
17752
+ severity: 1,
17753
+ message: `the dependency "${dependency}" is not published to the NPM registry`,
17754
+ line: 1,
17755
+ column: 1
17756
+ });
17757
+ continue;
17758
+ }
17759
+ throw err;
17687
17760
  }
17688
- messages.push({
17689
- ruleId: ruleId2,
17690
- severity: 2,
17691
- message: `"${dependency}" is deprecated and must not be used`,
17692
- line: 1,
17693
- column: 1
17694
- });
17695
17761
  }
17696
17762
  return messages;
17697
17763
  }
@@ -17885,7 +17951,10 @@ function* outdatedEngines(pkg) {
17885
17951
  var import_semver3 = __toESM(require_semver2(), 1);
17886
17952
  var ruleId5 = "invalid-engine-constraint";
17887
17953
  async function* getDeepDependencies(pkg, dependency) {
17888
- const pkgData = dependency ? await npmInfo(dependency) : pkg;
17954
+ const pkgData = dependency ? await npmInfo(dependency, { ignoreUnpublished: true }) : pkg;
17955
+ if (!pkgData) {
17956
+ return;
17957
+ }
17889
17958
  for (const [key, version2] of Object.entries(pkgData.dependencies ?? {})) {
17890
17959
  if (key === "@types/node") {
17891
17960
  continue;
@@ -17896,8 +17965,26 @@ async function* getDeepDependencies(pkg, dependency) {
17896
17965
  yield* getDeepDependencies(pkg, deep);
17897
17966
  }
17898
17967
  }
17968
+ async function verifyDependency(dependency, minDeclared, declaredConstraint) {
17969
+ var _a;
17970
+ const pkgData = await npmInfo(dependency);
17971
+ const constraint = (_a = pkgData.engines) == null ? void 0 : _a.node;
17972
+ if (!constraint) {
17973
+ return null;
17974
+ }
17975
+ if (!import_semver3.default.satisfies(minDeclared, constraint)) {
17976
+ return {
17977
+ ruleId: ruleId5,
17978
+ severity: 2,
17979
+ message: `the transitive dependency "${dependency}" (node ${constraint}) does not satisfy the declared node engine "${declaredConstraint}"`,
17980
+ line: 1,
17981
+ column: 1
17982
+ };
17983
+ }
17984
+ return null;
17985
+ }
17899
17986
  async function verifyEngineConstraint(pkg) {
17900
- var _a, _b;
17987
+ var _a;
17901
17988
  const declaredConstraint = (_a = pkg.engines) == null ? void 0 : _a.node;
17902
17989
  if (!declaredConstraint) {
17903
17990
  return [];
@@ -17907,20 +17994,29 @@ async function verifyEngineConstraint(pkg) {
17907
17994
  throw new Error(`Failed to parse engine constraint "${declaredConstraint}"`);
17908
17995
  }
17909
17996
  const messages = [];
17997
+ const visited = /* @__PURE__ */ new Set();
17910
17998
  for await (const dependency of getDeepDependencies(pkg)) {
17911
- const pkgData = await npmInfo(dependency);
17912
- const constraint = (_b = pkgData.engines) == null ? void 0 : _b.node;
17913
- if (!constraint) {
17999
+ if (visited.has(dependency)) {
17914
18000
  continue;
17915
18001
  }
17916
- if (!import_semver3.default.satisfies(minDeclared, constraint)) {
17917
- messages.push({
17918
- ruleId: ruleId5,
17919
- severity: 2,
17920
- message: `the transitive dependency "${dependency}" (node ${constraint}) does not satisfy the declared node engine "${declaredConstraint}"`,
17921
- line: 1,
17922
- column: 1
17923
- });
18002
+ visited.add(dependency);
18003
+ try {
18004
+ const message = await verifyDependency(dependency, minDeclared, declaredConstraint);
18005
+ if (message) {
18006
+ messages.push(message);
18007
+ }
18008
+ } catch (err) {
18009
+ if (isNpmInfoError(err) && err.code === "E404") {
18010
+ messages.push({
18011
+ ruleId: ruleId5,
18012
+ severity: 1,
18013
+ message: `the transitive dependency "${dependency}" is not published to the NPM registry`,
18014
+ line: 1,
18015
+ column: 1
18016
+ });
18017
+ continue;
18018
+ }
18019
+ throw err;
17924
18020
  }
17925
18021
  }
17926
18022
  return messages;
@@ -18048,8 +18144,8 @@ async function verifyPackageJson(pkg, filePath, options = {}) {
18048
18144
  {
18049
18145
  messages,
18050
18146
  filePath,
18051
- errorCount: messages.length,
18052
- warningCount: 0,
18147
+ errorCount: messages.filter((it) => it.severity === 2).length,
18148
+ warningCount: messages.filter((it) => it.severity === 1).length,
18053
18149
  fixableErrorCount: 0,
18054
18150
  fixableWarningCount: 0
18055
18151
  }