npm-pkg-lint 4.5.3 → 4.6.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
@@ -412,3 +412,23 @@ The following `package.json`:
412
412
  ```
413
413
 
414
414
  will yield an error becase `@tsconfig/node14` is for NodeJS v14 but the `engines.node` constraints the version to v12.
415
+
416
+ ## `package-lock.json` lockfile
417
+
418
+ Requires `package-lock.json`, if present, to pass the following checks:
419
+
420
+ - Lockfile version must be 3.
421
+ - All packages must be resolved from `https://registry.npmjs.org/`.
422
+
423
+ **Why?** Lockfile version 3 (introduced with npm v7) includes the full dependency tree in a more compact and efficient format.
424
+ Older lockfile versions (1 and 2) are either missing information or include redundant data that version 3 supersedes.
425
+ Using version 3 ensures compatibility with modern npm tooling and avoids the ambiguity of the legacy formats.
426
+
427
+ **Why?** Packages resolved from private registries, git URLs, or local paths indicate non-standard dependencies that may not be reproducible in all environments.
428
+ All published production dependencies should be resolvable from the public npm registry to ensure consumers can reliably install the same code.
429
+
430
+ To upgrade an existing lockfile to version 3 run:
431
+
432
+ ```sh
433
+ npm install --lockfile-version 3 --package-lock-only
434
+ ```
package/dist/index.js CHANGED
@@ -349,7 +349,7 @@ var require_argparse = __commonJS({
349
349
  var _UNRECOGNIZED_ARGS_ATTR = "_unrecognized_args";
350
350
  var assert = __require("assert");
351
351
  var util = __require("util");
352
- var fs7 = __require("fs");
352
+ var fs8 = __require("fs");
353
353
  var sub = require_sub();
354
354
  var path8 = __require("path");
355
355
  var repr = util.inspect;
@@ -1838,7 +1838,7 @@ var require_argparse = __commonJS({
1838
1838
  start,
1839
1839
  end,
1840
1840
  highWaterMark,
1841
- fs8
1841
+ fs9
1842
1842
  ] = _parse_opts(arguments, {
1843
1843
  flags: "r",
1844
1844
  encoding: void 0,
@@ -1871,7 +1871,7 @@ var require_argparse = __commonJS({
1871
1871
  if (start !== void 0) this._options.start = start;
1872
1872
  if (end !== void 0) this._options.end = end;
1873
1873
  if (highWaterMark !== void 0) this._options.highWaterMark = highWaterMark;
1874
- if (fs8 !== void 0) this._options.fs = fs8;
1874
+ if (fs9 !== void 0) this._options.fs = fs9;
1875
1875
  }
1876
1876
  call(string) {
1877
1877
  if (string === "-") {
@@ -1886,7 +1886,7 @@ var require_argparse = __commonJS({
1886
1886
  }
1887
1887
  let fd;
1888
1888
  try {
1889
- fd = fs7.openSync(string, this._flags, this._options.mode);
1889
+ fd = fs8.openSync(string, this._flags, this._options.mode);
1890
1890
  } catch (e) {
1891
1891
  let args = { filename: string, error: e.message };
1892
1892
  let message = "can't open '%(filename)s': %(error)s";
@@ -1894,9 +1894,9 @@ var require_argparse = __commonJS({
1894
1894
  }
1895
1895
  let options = Object.assign({ fd, flags: this._flags }, this._options);
1896
1896
  if (this._flags.includes("r")) {
1897
- return fs7.createReadStream(void 0, options);
1897
+ return fs8.createReadStream(void 0, options);
1898
1898
  } else if (this._flags.includes("w")) {
1899
- return fs7.createWriteStream(void 0, options);
1899
+ return fs8.createWriteStream(void 0, options);
1900
1900
  } else {
1901
1901
  let msg = sub('argument "%s" with mode %r', string, this._flags);
1902
1902
  throw new TypeError(msg);
@@ -2755,7 +2755,7 @@ var require_argparse = __commonJS({
2755
2755
  new_arg_strings.push(arg_string);
2756
2756
  } else {
2757
2757
  try {
2758
- let args_file = fs7.readFileSync(arg_string.slice(1), "utf8");
2758
+ let args_file = fs8.readFileSync(arg_string.slice(1), "utf8");
2759
2759
  let arg_strings2 = [];
2760
2760
  for (let arg_line of splitlines(args_file)) {
2761
2761
  for (let arg of this.convert_arg_line_to_args(arg_line)) {
@@ -3203,11 +3203,11 @@ var require_argparse = __commonJS({
3203
3203
  // node_modules/tmp/lib/tmp.js
3204
3204
  var require_tmp = __commonJS({
3205
3205
  "node_modules/tmp/lib/tmp.js"(exports, module) {
3206
- var fs7 = __require("fs");
3206
+ var fs8 = __require("fs");
3207
3207
  var os3 = __require("os");
3208
3208
  var path8 = __require("path");
3209
3209
  var crypto2 = __require("crypto");
3210
- var _c = { fs: fs7.constants, os: os3.constants };
3210
+ var _c = { fs: fs8.constants, os: os3.constants };
3211
3211
  var RANDOM_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
3212
3212
  var TEMPLATE_PATTERN = /XXXXXX/;
3213
3213
  var DEFAULT_TRIES = 3;
@@ -3219,13 +3219,13 @@ var require_tmp = __commonJS({
3219
3219
  var FILE_MODE = 384;
3220
3220
  var EXIT = "exit";
3221
3221
  var _removeObjects = [];
3222
- var FN_RMDIR_SYNC = fs7.rmdirSync.bind(fs7);
3222
+ var FN_RMDIR_SYNC = fs8.rmdirSync.bind(fs8);
3223
3223
  var _gracefulCleanup = false;
3224
3224
  function rimraf(dirPath, callback) {
3225
- return fs7.rm(dirPath, { recursive: true }, callback);
3225
+ return fs8.rm(dirPath, { recursive: true }, callback);
3226
3226
  }
3227
3227
  function FN_RIMRAF_SYNC(dirPath) {
3228
- return fs7.rmSync(dirPath, { recursive: true });
3228
+ return fs8.rmSync(dirPath, { recursive: true });
3229
3229
  }
3230
3230
  function tmpName(options, callback) {
3231
3231
  const args = _parseArguments(options, callback), opts = args[0], cb = args[1];
@@ -3235,7 +3235,7 @@ var require_tmp = __commonJS({
3235
3235
  (function _getUniqueName() {
3236
3236
  try {
3237
3237
  const name = _generateTmpName(sanitizedOptions);
3238
- fs7.stat(name, function(err2) {
3238
+ fs8.stat(name, function(err2) {
3239
3239
  if (!err2) {
3240
3240
  if (tries-- > 0) return _getUniqueName();
3241
3241
  return cb(new Error("Could not get a unique tmp filename, max tries reached " + name));
@@ -3255,7 +3255,7 @@ var require_tmp = __commonJS({
3255
3255
  do {
3256
3256
  const name = _generateTmpName(sanitizedOptions);
3257
3257
  try {
3258
- fs7.statSync(name);
3258
+ fs8.statSync(name);
3259
3259
  } catch (e) {
3260
3260
  return name;
3261
3261
  }
@@ -3266,10 +3266,10 @@ var require_tmp = __commonJS({
3266
3266
  const args = _parseArguments(options, callback), opts = args[0], cb = args[1];
3267
3267
  tmpName(opts, function _tmpNameCreated(err, name) {
3268
3268
  if (err) return cb(err);
3269
- fs7.open(name, CREATE_FLAGS, opts.mode || FILE_MODE, function _fileCreated(err2, fd) {
3269
+ fs8.open(name, CREATE_FLAGS, opts.mode || FILE_MODE, function _fileCreated(err2, fd) {
3270
3270
  if (err2) return cb(err2);
3271
3271
  if (opts.discardDescriptor) {
3272
- return fs7.close(fd, function _discardCallback(possibleErr) {
3272
+ return fs8.close(fd, function _discardCallback(possibleErr) {
3273
3273
  return cb(possibleErr, name, void 0, _prepareTmpFileRemoveCallback(name, -1, opts, false));
3274
3274
  });
3275
3275
  } else {
@@ -3283,9 +3283,9 @@ var require_tmp = __commonJS({
3283
3283
  const args = _parseArguments(options), opts = args[0];
3284
3284
  const discardOrDetachDescriptor = opts.discardDescriptor || opts.detachDescriptor;
3285
3285
  const name = tmpNameSync(opts);
3286
- let fd = fs7.openSync(name, CREATE_FLAGS, opts.mode || FILE_MODE);
3286
+ let fd = fs8.openSync(name, CREATE_FLAGS, opts.mode || FILE_MODE);
3287
3287
  if (opts.discardDescriptor) {
3288
- fs7.closeSync(fd);
3288
+ fs8.closeSync(fd);
3289
3289
  fd = void 0;
3290
3290
  }
3291
3291
  return {
@@ -3298,7 +3298,7 @@ var require_tmp = __commonJS({
3298
3298
  const args = _parseArguments(options, callback), opts = args[0], cb = args[1];
3299
3299
  tmpName(opts, function _tmpNameCreated(err, name) {
3300
3300
  if (err) return cb(err);
3301
- fs7.mkdir(name, opts.mode || DIR_MODE, function _dirCreated(err2) {
3301
+ fs8.mkdir(name, opts.mode || DIR_MODE, function _dirCreated(err2) {
3302
3302
  if (err2) return cb(err2);
3303
3303
  cb(null, name, _prepareTmpDirRemoveCallback(name, opts, false));
3304
3304
  });
@@ -3307,7 +3307,7 @@ var require_tmp = __commonJS({
3307
3307
  function dirSync(options) {
3308
3308
  const args = _parseArguments(options), opts = args[0];
3309
3309
  const name = tmpNameSync(opts);
3310
- fs7.mkdirSync(name, opts.mode || DIR_MODE);
3310
+ fs8.mkdirSync(name, opts.mode || DIR_MODE);
3311
3311
  return {
3312
3312
  name,
3313
3313
  removeCallback: _prepareTmpDirRemoveCallback(name, opts, true)
@@ -3321,20 +3321,20 @@ var require_tmp = __commonJS({
3321
3321
  next();
3322
3322
  };
3323
3323
  if (0 <= fdPath[0])
3324
- fs7.close(fdPath[0], function() {
3325
- fs7.unlink(fdPath[1], _handler);
3324
+ fs8.close(fdPath[0], function() {
3325
+ fs8.unlink(fdPath[1], _handler);
3326
3326
  });
3327
- else fs7.unlink(fdPath[1], _handler);
3327
+ else fs8.unlink(fdPath[1], _handler);
3328
3328
  }
3329
3329
  function _removeFileSync(fdPath) {
3330
3330
  let rethrownException = null;
3331
3331
  try {
3332
- if (0 <= fdPath[0]) fs7.closeSync(fdPath[0]);
3332
+ if (0 <= fdPath[0]) fs8.closeSync(fdPath[0]);
3333
3333
  } catch (e) {
3334
3334
  if (!_isEBADF(e) && !_isENOENT(e)) throw e;
3335
3335
  } finally {
3336
3336
  try {
3337
- fs7.unlinkSync(fdPath[1]);
3337
+ fs8.unlinkSync(fdPath[1]);
3338
3338
  } catch (e) {
3339
3339
  if (!_isENOENT(e)) rethrownException = e;
3340
3340
  }
@@ -3350,7 +3350,7 @@ var require_tmp = __commonJS({
3350
3350
  return sync ? removeCallbackSync : removeCallback;
3351
3351
  }
3352
3352
  function _prepareTmpDirRemoveCallback(name, opts, sync) {
3353
- const removeFunction = opts.unsafeCleanup ? rimraf : fs7.rmdir.bind(fs7);
3353
+ const removeFunction = opts.unsafeCleanup ? rimraf : fs8.rmdir.bind(fs8);
3354
3354
  const removeFunctionSync = opts.unsafeCleanup ? FN_RIMRAF_SYNC : FN_RMDIR_SYNC;
3355
3355
  const removeCallbackSync = _prepareRemoveCallback(removeFunctionSync, name, sync);
3356
3356
  const removeCallback = _prepareRemoveCallback(removeFunction, name, sync, removeCallbackSync);
@@ -3413,24 +3413,24 @@ var require_tmp = __commonJS({
3413
3413
  }
3414
3414
  function _resolvePath(name, tmpDir, cb) {
3415
3415
  const pathToResolve = path8.isAbsolute(name) ? name : path8.join(tmpDir, name);
3416
- fs7.stat(pathToResolve, function(err) {
3416
+ fs8.stat(pathToResolve, function(err) {
3417
3417
  if (err) {
3418
- fs7.realpath(path8.dirname(pathToResolve), function(err2, parentDir) {
3418
+ fs8.realpath(path8.dirname(pathToResolve), function(err2, parentDir) {
3419
3419
  if (err2) return cb(err2);
3420
3420
  cb(null, path8.join(parentDir, path8.basename(pathToResolve)));
3421
3421
  });
3422
3422
  } else {
3423
- fs7.realpath(pathToResolve, cb);
3423
+ fs8.realpath(pathToResolve, cb);
3424
3424
  }
3425
3425
  });
3426
3426
  }
3427
3427
  function _resolvePathSync(name, tmpDir) {
3428
3428
  const pathToResolve = path8.isAbsolute(name) ? name : path8.join(tmpDir, name);
3429
3429
  try {
3430
- fs7.statSync(pathToResolve);
3431
- return fs7.realpathSync(pathToResolve);
3430
+ fs8.statSync(pathToResolve);
3431
+ return fs8.realpathSync(pathToResolve);
3432
3432
  } catch (_err) {
3433
- const parentDir = fs7.realpathSync(path8.dirname(pathToResolve));
3433
+ const parentDir = fs8.realpathSync(path8.dirname(pathToResolve));
3434
3434
  return path8.join(parentDir, path8.basename(pathToResolve));
3435
3435
  }
3436
3436
  }
@@ -3535,10 +3535,10 @@ var require_tmp = __commonJS({
3535
3535
  _gracefulCleanup = true;
3536
3536
  }
3537
3537
  function _getTmpDir(options, cb) {
3538
- return fs7.realpath(options && options.tmpdir || os3.tmpdir(), cb);
3538
+ return fs8.realpath(options && options.tmpdir || os3.tmpdir(), cb);
3539
3539
  }
3540
3540
  function _getTmpDirSync(options) {
3541
- return fs7.realpathSync(options && options.tmpdir || os3.tmpdir());
3541
+ return fs8.realpathSync(options && options.tmpdir || os3.tmpdir());
3542
3542
  }
3543
3543
  process.addListener(EXIT, _garbageCollector);
3544
3544
  Object.defineProperty(module.exports, "tmpdir", {
@@ -5489,7 +5489,7 @@ var require_semver2 = __commonJS({
5489
5489
  });
5490
5490
 
5491
5491
  // src/index.ts
5492
- import { createWriteStream, existsSync, promises as fs6, readFileSync } from "node:fs";
5492
+ import { createWriteStream, existsSync, promises as fs7, readFileSync } from "node:fs";
5493
5493
  import path7 from "node:path";
5494
5494
  import { fileURLToPath as fileURLToPath4 } from "node:url";
5495
5495
 
@@ -12152,6 +12152,86 @@ async function verifyPackageJson(pkg, pkgAst, filePath, options = { allowedDepen
12152
12152
  ];
12153
12153
  }
12154
12154
 
12155
+ // src/package-lock.ts
12156
+ import { promises as fs6 } from "node:fs";
12157
+ var REGISTRY_URL = "https://registry.npmjs.org/";
12158
+ function isErrnoException(err) {
12159
+ return err instanceof Error && "code" in err;
12160
+ }
12161
+ function isPackageLockVersion3(lockfile) {
12162
+ return lockfile.lockfileVersion === 3;
12163
+ }
12164
+ function isValidResolved(pkg) {
12165
+ return pkg.resolved === void 0 || pkg.resolved.startsWith(REGISTRY_URL);
12166
+ }
12167
+ async function readLockfile(lockfilePath) {
12168
+ try {
12169
+ return await fs6.readFile(lockfilePath, "utf-8");
12170
+ } catch (err) {
12171
+ if (isErrnoException(err) && err.code === "ENOENT") {
12172
+ return null;
12173
+ }
12174
+ throw err;
12175
+ }
12176
+ }
12177
+ async function verifyPackageLock() {
12178
+ const lockfilePath = await findUp("package-lock.json");
12179
+ if (!lockfilePath) {
12180
+ return [];
12181
+ }
12182
+ const content = await readLockfile(lockfilePath);
12183
+ if (content === null) {
12184
+ return [];
12185
+ }
12186
+ const lockfile = JSON.parse(content);
12187
+ const ast = parse(content);
12188
+ if (!isPackageLockVersion3(lockfile)) {
12189
+ const { line, column } = jsonLocation(ast, "value", "lockfileVersion");
12190
+ return [
12191
+ {
12192
+ messages: [
12193
+ {
12194
+ ruleId: "package-lock-version",
12195
+ severity: 2,
12196
+ message: `package-lock.json has lockfileVersion ${lockfile.lockfileVersion} but expected 3`,
12197
+ line,
12198
+ column
12199
+ }
12200
+ ],
12201
+ filePath: lockfilePath,
12202
+ errorCount: 1,
12203
+ warningCount: 0,
12204
+ fixableErrorCount: 0,
12205
+ fixableWarningCount: 0
12206
+ }
12207
+ ];
12208
+ }
12209
+ const { packages } = lockfile;
12210
+ const results = [];
12211
+ for (const [name, pkg] of Object.entries(packages)) {
12212
+ if (!isValidResolved(pkg)) {
12213
+ const { line, column } = jsonLocation(ast, "value", "packages", name, "resolved");
12214
+ results.push({
12215
+ messages: [
12216
+ {
12217
+ ruleId: "package-lock-registry",
12218
+ severity: 2,
12219
+ message: `package "${name}" is resolved from "${String(pkg.resolved)}" instead of the npm registry`,
12220
+ line,
12221
+ column
12222
+ }
12223
+ ],
12224
+ filePath: lockfilePath,
12225
+ errorCount: 1,
12226
+ warningCount: 0,
12227
+ fixableErrorCount: 0,
12228
+ fixableWarningCount: 0
12229
+ });
12230
+ }
12231
+ }
12232
+ return results;
12233
+ }
12234
+
12155
12235
  // src/shebang.ts
12156
12236
  function getBinaries(pkg) {
12157
12237
  if (!pkg.bin) {
@@ -12193,6 +12273,7 @@ async function verify(pkg, pkgAst, pkgPath, tarball, options) {
12193
12273
  return [
12194
12274
  ...await verifyTarball(pkg, tarball),
12195
12275
  ...await verifyPackageJson(pkg, pkgAst, pkgPath, options),
12276
+ ...await verifyPackageLock(),
12196
12277
  ...await verifyShebang(pkg, tarball)
12197
12278
  ];
12198
12279
  }
@@ -12221,7 +12302,7 @@ async function preloadStdin() {
12221
12302
  }
12222
12303
  async function getPackageJson(args, regenerateReportName) {
12223
12304
  if (args.pkgfile) {
12224
- const content = await fs6.readFile(args.pkgfile, "utf-8");
12305
+ const content = await fs7.readFile(args.pkgfile, "utf-8");
12225
12306
  const pkg = JSON.parse(content);
12226
12307
  const pkgAst = parse(content);
12227
12308
  return {
@@ -12246,7 +12327,7 @@ async function getPackageJson(args, regenerateReportName) {
12246
12327
  }
12247
12328
  const pkgPath = await findUp(PACKAGE_JSON);
12248
12329
  if (pkgPath) {
12249
- const content = await fs6.readFile(pkgPath, "utf-8");
12330
+ const content = await fs7.readFile(pkgPath, "utf-8");
12250
12331
  const pkg = JSON.parse(content);
12251
12332
  const pkgAst = parse(content);
12252
12333
  return {