npm-pkg-lint 3.3.0 → 3.4.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/README.md CHANGED
@@ -19,7 +19,8 @@ Core principles:
19
19
 
20
20
  ```
21
21
  usage: index.js [-h] [-v] [-t TARBALL] [-p PKGFILE] [--cache CACHE]
22
- [--allow-types-dependencies] [--ignore-missing-fields]
22
+ [--allow-dependency DEPENDENCY] [--allow-types-dependencies]
23
+ [--ignore-missing-fields]
23
24
 
24
25
  Opiniated linter for NPM package tarball and package.json metadata
25
26
 
@@ -31,8 +32,11 @@ optional arguments:
31
32
  -p PKGFILE, --pkgfile PKGFILE
32
33
  specify package.json location
33
34
  --cache CACHE specify cache directory
35
+ --allow-dependency DEPENDENCY
36
+ explicitly allow given dependency (can be given
37
+ multiple times or as a comma-separated list)
34
38
  --allow-types-dependencies
35
- allow dependencies to `@types/*`
39
+ allow production dependencies to `@types/*`
36
40
  --ignore-missing-fields
37
41
  ignore errors for missing fields (but still checks for
38
42
  empty and valid)
@@ -99,29 +103,7 @@ Examples of disallowed packages:
99
103
 
100
104
  By default `@types/*` is disallowed but this can be disabled with `--allow-types-dependencies`.
101
105
 
102
- ## Obsolete dependencies
103
-
104
- Disallows certain packages from being included as `dependencies`, `devDependencies` or `peerDependencies` entirely.
105
- These dependencies have native replacements supported by all supported NodeJS versions.
106
-
107
- **Why?** Obsolete packages have native replacements and thus only clutter the dependency graphs thus increasing the time to install, the size on disk and produces noise with tools analyzing `package-lock.json`.
108
-
109
- Examples of obsolete packages:
110
-
111
- - `mkdirp` - `fs#mkdir` supports the `recursive` flag since NodeJS v10.
112
- - `stable` - `Array#sort` is stable since NodeJS v12.
113
-
114
- ## Deprecated dependencies
115
-
116
- Disallows deprecated packages from being included as `dependencies`, `devDependencies` or `peerDependencies` entirely.
117
- These dependences are explicitly marked as deprecated by the package author.
118
-
119
- **Why?** Deprecated packages should be removed or replaced with alternatives as they are often unmaintained and might contain security vulnerabilities.
120
-
121
- Examples of obsolete packages:
122
-
123
- - `mkdirp` - `fs#mkdir` supports the `recursive` flag since NodeJS v10.
124
- - `stable` - `Array#sort` is stable since NodeJS v12.
106
+ If needed, `--allow-dependency` can be used to ignore one or more dependencies.
125
107
 
126
108
  ### ESLint
127
109
 
@@ -210,6 +192,30 @@ If your `package.json` contains the `"prettier"` keyword the Prettier packages c
210
192
  }
211
193
  ```
212
194
 
195
+ ## Obsolete dependencies
196
+
197
+ Disallows certain packages from being included as `dependencies`, `devDependencies` or `peerDependencies` entirely.
198
+ These dependencies have native replacements supported by all supported NodeJS versions.
199
+
200
+ **Why?** Obsolete packages have native replacements and thus only clutter the dependency graphs thus increasing the time to install, the size on disk and produces noise with tools analyzing `package-lock.json`.
201
+
202
+ Examples of obsolete packages:
203
+
204
+ - `mkdirp` - `fs#mkdir` supports the `recursive` flag since NodeJS v10.
205
+ - `stable` - `Array#sort` is stable since NodeJS v12.
206
+
207
+ ## Deprecated dependencies
208
+
209
+ Disallows deprecated packages from being included as `dependencies`, `devDependencies` or `peerDependencies` entirely.
210
+ These dependences are explicitly marked as deprecated by the package author.
211
+
212
+ **Why?** Deprecated packages should be removed or replaced with alternatives as they are often unmaintained and might contain security vulnerabilities.
213
+
214
+ Examples of obsolete packages:
215
+
216
+ - `mkdirp` - `fs#mkdir` supports the `recursive` flag since NodeJS v10.
217
+ - `stable` - `Array#sort` is stable since NodeJS v12.
218
+
213
219
  ## Shebang
214
220
 
215
221
  Require all binaries to have UNIX-style shebang at the beginning of the file.
package/dist/index.js CHANGED
@@ -12365,7 +12365,7 @@ var require_merge_stream = __commonJS({
12365
12365
  var import_argparse = __toESM(require_argparse(), 1);
12366
12366
  import { existsSync, createWriteStream as createWriteStream2, readFileSync as readFileSync2, promises as fs4 } from "fs";
12367
12367
  import path7 from "path";
12368
- import { fileURLToPath as fileURLToPath3 } from "url";
12368
+ import { fileURLToPath as fileURLToPath4 } from "url";
12369
12369
 
12370
12370
  // node_modules/find-up/index.js
12371
12371
  import path2 from "path";
@@ -13327,14 +13327,14 @@ function validateUrl(key, value) {
13327
13327
  if (value !== value.trim()) {
13328
13328
  throw new Error(`"${key}.url" must not have leading or trailing whitespace`);
13329
13329
  }
13330
- const url2 = new URL(value);
13331
- if (url2.protocol === "git+http:" || url2.protocol === "http:") {
13330
+ const url = new URL(value);
13331
+ if (url.protocol === "git+http:" || url.protocol === "http:") {
13332
13332
  throw new Error(`"${key}.url" must use "git+https://" instead of "http://"`);
13333
13333
  }
13334
- if (url2.protocol !== "git+https:") {
13334
+ if (url.protocol !== "git+https:") {
13335
13335
  throw new Error(`"${key}.url" must use "git+https://" protocol`);
13336
13336
  }
13337
- if (url2.host === "") {
13337
+ if (url.host === "") {
13338
13338
  throw new Error(`"${key}.url" be a valid url`);
13339
13339
  }
13340
13340
  }
@@ -13407,7 +13407,7 @@ function stripFinalNewline(input) {
13407
13407
  // node_modules/execa/node_modules/npm-run-path/index.js
13408
13408
  import process3 from "process";
13409
13409
  import path3 from "path";
13410
- import url from "url";
13410
+ import { fileURLToPath as fileURLToPath3 } from "url";
13411
13411
 
13412
13412
  // node_modules/execa/node_modules/path-key/index.js
13413
13413
  function pathKey(options = {}) {
@@ -13422,31 +13422,43 @@ function pathKey(options = {}) {
13422
13422
  }
13423
13423
 
13424
13424
  // node_modules/execa/node_modules/npm-run-path/index.js
13425
- function npmRunPath(options = {}) {
13426
- const {
13427
- cwd = process3.cwd(),
13428
- path: path_ = process3.env[pathKey()],
13429
- execPath = process3.execPath
13430
- } = options;
13431
- let previous;
13432
- const cwdString = cwd instanceof URL ? url.fileURLToPath(cwd) : cwd;
13433
- let cwdPath = path3.resolve(cwdString);
13425
+ var npmRunPath = ({
13426
+ cwd = process3.cwd(),
13427
+ path: pathOption = process3.env[pathKey()],
13428
+ preferLocal = true,
13429
+ execPath = process3.execPath,
13430
+ addExecPath = true
13431
+ } = {}) => {
13432
+ const cwdString = cwd instanceof URL ? fileURLToPath3(cwd) : cwd;
13433
+ const cwdPath = path3.resolve(cwdString);
13434
13434
  const result = [];
13435
+ if (preferLocal) {
13436
+ applyPreferLocal(result, cwdPath);
13437
+ }
13438
+ if (addExecPath) {
13439
+ applyExecPath(result, execPath, cwdPath);
13440
+ }
13441
+ return [...result, pathOption].join(path3.delimiter);
13442
+ };
13443
+ var applyPreferLocal = (result, cwdPath) => {
13444
+ let previous;
13435
13445
  while (previous !== cwdPath) {
13436
13446
  result.push(path3.join(cwdPath, "node_modules/.bin"));
13437
13447
  previous = cwdPath;
13438
13448
  cwdPath = path3.resolve(cwdPath, "..");
13439
13449
  }
13440
- result.push(path3.resolve(cwdString, execPath, ".."));
13441
- return [...result, path_].join(path3.delimiter);
13442
- }
13443
- function npmRunPathEnv({ env = process3.env, ...options } = {}) {
13450
+ };
13451
+ var applyExecPath = (result, execPath, cwdPath) => {
13452
+ const execPathString = execPath instanceof URL ? fileURLToPath3(execPath) : execPath;
13453
+ result.push(path3.resolve(cwdPath, execPathString, ".."));
13454
+ };
13455
+ var npmRunPathEnv = ({ env = process3.env, ...options } = {}) => {
13444
13456
  env = { ...env };
13445
- const path8 = pathKey({ env });
13446
- options.path = env[path8];
13447
- env[path8] = npmRunPath(options);
13457
+ const pathName = pathKey({ env });
13458
+ options.path = env[pathName];
13459
+ env[pathName] = npmRunPath(options);
13448
13460
  return env;
13449
- }
13461
+ };
13450
13462
 
13451
13463
  // node_modules/execa/node_modules/mimic-fn/index.js
13452
13464
  var copyProperty = (to, from, property, ignoreNonConfigurable) => {
@@ -15076,7 +15088,12 @@ var ruleId2 = "no-deprecated-dependency";
15076
15088
  function* getDependencies(pkg) {
15077
15089
  const { dependencies = {}, devDependencies = {}, peerDependencies = {} } = pkg;
15078
15090
  const allDependencies = { ...dependencies, ...devDependencies, ...peerDependencies };
15079
- for (const [key, version2] of Object.entries(allDependencies)) {
15091
+ for (let [key, version2] of Object.entries(allDependencies)) {
15092
+ if (version2.startsWith("npm:")) {
15093
+ const [newKey, newVersion] = version2.slice("npm:".length).split("@", 2);
15094
+ key = newKey;
15095
+ version2 = newVersion;
15096
+ }
15080
15097
  if (key === "@types/node") {
15081
15098
  continue;
15082
15099
  }
@@ -15297,8 +15314,8 @@ function* outdatedEngines(pkg) {
15297
15314
  if (!import_semver2.default.satisfies(expanded, range)) {
15298
15315
  continue;
15299
15316
  }
15300
- const nodeRelease = ((parsed == null ? void 0 : parsed.major) ?? 0) || `0.${(parsed == null ? void 0 : parsed.minor) ?? ""}`;
15301
- const message = `engines.node is satisfied by Node ${nodeRelease} (EOL since ${descriptor.eol})`;
15317
+ const nodeRelease = ((parsed == null ? void 0 : parsed.major) ?? 0) || `0.${String((parsed == null ? void 0 : parsed.minor) ?? "")}`;
15318
+ const message = `engines.node is satisfied by Node ${String(nodeRelease)} (EOL since ${descriptor.eol})`;
15302
15319
  yield {
15303
15320
  ruleId: ruleId4,
15304
15321
  severity: severity2,
@@ -15318,7 +15335,12 @@ async function* getDeepDependencies(pkg, dependency) {
15318
15335
  if (!pkgData) {
15319
15336
  return;
15320
15337
  }
15321
- for (const [key, version2] of Object.entries(pkgData.dependencies ?? {})) {
15338
+ for (let [key, version2] of Object.entries(pkgData.dependencies ?? {})) {
15339
+ if (version2.startsWith("npm:")) {
15340
+ const [newKey, newVersion] = version2.slice("npm:".length).split("@", 2);
15341
+ key = newKey;
15342
+ version2 = newVersion;
15343
+ }
15322
15344
  if (key === "@types/node") {
15323
15345
  continue;
15324
15346
  }
@@ -15412,10 +15434,12 @@ function* typesNodeMatchingEngine(pkg) {
15412
15434
  return;
15413
15435
  }
15414
15436
  if (typesVersion.major !== nodeVersion.major) {
15437
+ const actualVersion = `v${String(typesVersion.major)}`;
15438
+ const expectedVersion = `v${String(nodeVersion.major)}`;
15415
15439
  yield {
15416
15440
  ruleId: ruleId6,
15417
15441
  severity: severity3,
15418
- message: `@types/node v${typesVersion.major} does not equal engines.node v${nodeVersion.major}`,
15442
+ message: `@types/node ${actualVersion} does not equal engines.node ${expectedVersion}`,
15419
15443
  line: 1,
15420
15444
  column: 1
15421
15445
  };
@@ -15458,19 +15482,31 @@ function verifyFields(pkg, options) {
15458
15482
  }
15459
15483
  return messages;
15460
15484
  }
15485
+ function getActualDependency(key, version2) {
15486
+ if (version2.startsWith("npm:")) {
15487
+ const [name] = version2.slice("npm:".length).split("@", 2);
15488
+ return name;
15489
+ }
15490
+ return key;
15491
+ }
15461
15492
  function verifyDependencies(pkg, options) {
15462
15493
  const messages = [];
15463
15494
  const { dependencies = {}, devDependencies = {}, peerDependencies = {} } = pkg;
15464
15495
  const allDependencies = { ...dependencies, ...devDependencies, ...peerDependencies };
15465
- for (const dependency of Object.keys(dependencies)) {
15496
+ for (const [key, version2] of Object.entries(dependencies)) {
15497
+ const dependency = getActualDependency(key, version2);
15498
+ if (options.allowedDependencies.has(dependency)) {
15499
+ continue;
15500
+ }
15466
15501
  if (options.allowTypesDependencies && dependency.match(/^@types\//)) {
15467
15502
  continue;
15468
15503
  }
15469
15504
  if (isDisallowedDependency(pkg, dependency)) {
15505
+ const name = key === dependency ? dependency : `"${key}" ("npm:${dependency}")`;
15470
15506
  messages.push({
15471
15507
  ruleId: "disallowed-dependency",
15472
15508
  severity: 2,
15473
- message: `${dependency} should be a devDependency`,
15509
+ message: `"${name}" should be a devDependency`,
15474
15510
  line: 1,
15475
15511
  column: 1
15476
15512
  });
@@ -15482,7 +15518,7 @@ function verifyDependencies(pkg, options) {
15482
15518
  messages.push({
15483
15519
  ruleId: "obsolete-dependency",
15484
15520
  severity: 2,
15485
- message: `${dependency} is obsolete and should no longer be used: ${obsolete2.message}`,
15521
+ message: `"${dependency}" is obsolete and should no longer be used: ${obsolete2.message}`,
15486
15522
  line: 1,
15487
15523
  column: 1
15488
15524
  });
@@ -15490,7 +15526,7 @@ function verifyDependencies(pkg, options) {
15490
15526
  }
15491
15527
  return messages;
15492
15528
  }
15493
- async function verifyPackageJson(pkg, filePath, options = {}) {
15529
+ async function verifyPackageJson(pkg, filePath, options = { allowedDependencies: /* @__PURE__ */ new Set() }) {
15494
15530
  const messages = [
15495
15531
  ...await deprecatedDependency(pkg),
15496
15532
  ...await verifyEngineConstraint(pkg),
@@ -15552,7 +15588,7 @@ async function verifyShebang(pkg, tarball) {
15552
15588
  }
15553
15589
 
15554
15590
  // src/verify.ts
15555
- async function verify(pkg, pkgPath, tarball, options = {}) {
15591
+ async function verify(pkg, pkgPath, tarball, options) {
15556
15592
  return [
15557
15593
  ...await verifyTarball(pkg, tarball),
15558
15594
  ...await verifyPackageJson(pkg, pkgPath, options),
@@ -15571,7 +15607,7 @@ function tarballLocation(pkg, pkgPath) {
15571
15607
  }
15572
15608
 
15573
15609
  // src/index.ts
15574
- var pkgFilepath = fileURLToPath3(new URL("../package.json", import.meta.url));
15610
+ var pkgFilepath = fileURLToPath4(new URL("../package.json", import.meta.url));
15575
15611
  var { version } = JSON.parse(readFileSync2(pkgFilepath, "utf-8"));
15576
15612
  var PACKAGE_JSON = "package.json";
15577
15613
  async function preloadStdin() {
@@ -15628,15 +15664,22 @@ async function run() {
15628
15664
  parser.add_argument("-t", "--tarball", { help: "specify tarball location" });
15629
15665
  parser.add_argument("-p", "--pkgfile", { help: "specify package.json location" });
15630
15666
  parser.add_argument("--cache", { help: "specify cache directory" });
15667
+ parser.add_argument("--allow-dependency", {
15668
+ action: "append",
15669
+ default: [],
15670
+ metavar: "DEPENDENCY",
15671
+ help: "explicitly allow given dependency (can be given multiple times or as a comma-separated list)"
15672
+ });
15631
15673
  parser.add_argument("--allow-types-dependencies", {
15632
15674
  action: "store_true",
15633
- help: "allow dependencies to `@types/*`"
15675
+ help: "allow production dependencies to `@types/*`"
15634
15676
  });
15635
15677
  parser.add_argument("--ignore-missing-fields", {
15636
15678
  action: "store_true",
15637
15679
  help: "ignore errors for missing fields (but still checks for empty and valid)"
15638
15680
  });
15639
15681
  const args = parser.parse_args();
15682
+ const allowedDependencies2 = new Set(args.allow_dependency.map((it) => it.split(",")).flat());
15640
15683
  if (args.cache) {
15641
15684
  await setCacheDirecory(args.cache);
15642
15685
  }
@@ -15662,6 +15705,7 @@ async function run() {
15662
15705
  }
15663
15706
  setupBlacklist(pkg.name);
15664
15707
  const options = {
15708
+ allowedDependencies: allowedDependencies2,
15665
15709
  allowTypesDependencies: args.allow_types_dependencies,
15666
15710
  ignoreMissingFields: args.ignore_missing_fields
15667
15711
  };