update-browserslist-db 1.3.2 → 1.3.3

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.
Files changed (2) hide show
  1. package/index.js +201 -10
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
- let { execSync } = require('child_process')
1
+ let { execFileSync, execSync } = require('child_process')
2
2
  let escalade = require('escalade/sync')
3
- let { existsSync, readFileSync, writeFileSync } = require('fs')
3
+ let { existsSync, readFileSync, unlinkSync, writeFileSync } = require('fs')
4
4
  let { dirname, join } = require('path')
5
5
  let pico = require('picocolors')
6
6
 
@@ -224,7 +224,7 @@ function updatePackageManually(print, lock, latest) {
224
224
  let caniuseVersions = Object.keys(lockfileData.versions).sort()
225
225
  if (caniuseVersions.length === 1 && caniuseVersions[0] === latest.version) {
226
226
  print(
227
- 'Installed version: ' +
227
+ 'Installed version: ' +
228
228
  pico.bold(pico.green(caniuseVersions[0])) +
229
229
  '\n' +
230
230
  pico.bold(pico.green('caniuse-lite is up to date')) +
@@ -238,7 +238,7 @@ function updatePackageManually(print, lock, latest) {
238
238
  }
239
239
  print(
240
240
  'Installed version' +
241
- (caniuseVersions.length === 1 ? ': ' : 's: ') +
241
+ (caniuseVersions.length === 1 ? ': ' : 's: ') +
242
242
  pico.bold(pico.red(caniuseVersions.join(', '))) +
243
243
  '\n' +
244
244
  'Removing old caniuse-lite from lock file\n'
@@ -328,6 +328,199 @@ function updateBun(print, lock, latest) {
328
328
  updateWith(print, 'bun install', 'Removing the temporary override')
329
329
  }
330
330
 
331
+ function commandErrorText(error) {
332
+ return [error.message, error.stdout, error.stderr]
333
+ .filter(Boolean)
334
+ .map(i => i.toString())
335
+ .join('\n')
336
+ }
337
+
338
+ function getPnpmConfig(name) {
339
+ let output = execFileSync('pnpm', [
340
+ 'config',
341
+ 'get',
342
+ name,
343
+ '--json'
344
+ ]).toString()
345
+ return output.trim() === 'undefined' ? undefined : JSON.parse(output)
346
+ }
347
+
348
+ function getPnpmPackageTimes(name) {
349
+ let times
350
+ try {
351
+ times = JSON.parse(
352
+ execFileSync('pnpm', ['info', name, 'time', '--json']).toString()
353
+ )
354
+ } catch (error) /* c8 ignore start */ {
355
+ throw new BrowserslistUpdateError(
356
+ 'Cannot read publication dates of ' +
357
+ name +
358
+ ' from pnpm. Refusing to bypass pnpm minimumReleaseAge.\n' +
359
+ commandErrorText(error)
360
+ )
361
+ } /* c8 ignore end */
362
+ if (!times || typeof times !== 'object' || Array.isArray(times)) {
363
+ /* c8 ignore next 6 */
364
+ throw new BrowserslistUpdateError(
365
+ 'pnpm returned no publication dates for ' +
366
+ name +
367
+ '. Refusing to bypass pnpm minimumReleaseAge.'
368
+ )
369
+ }
370
+ return times
371
+ }
372
+
373
+ function getMatureVersion(name, minimumReleaseAge) {
374
+ let cutoff = Date.now() - minimumReleaseAge * 60 * 1000
375
+ let times = getPnpmPackageTimes(name)
376
+
377
+ let mature, matureTime
378
+ for (let version of Object.keys(times)) {
379
+ let time = Date.parse(times[version])
380
+ if (!/^\d+\.\d+\.\d+$/.test(version) || !(time <= cutoff)) continue
381
+ if (matureTime === undefined || time > matureTime) {
382
+ mature = version
383
+ matureTime = time
384
+ }
385
+ }
386
+
387
+ if (!mature) {
388
+ throw new BrowserslistUpdateError(
389
+ 'Cannot find a ' +
390
+ name +
391
+ ' version old enough for pnpm minimumReleaseAge (' +
392
+ minimumReleaseAge +
393
+ ' minutes). Wait for a release to pass the age gate and try again.'
394
+ )
395
+ }
396
+
397
+ return mature
398
+ }
399
+
400
+ function restoreFile(file, original) {
401
+ if (original === undefined) {
402
+ if (existsSync(file)) unlinkSync(file)
403
+ } else {
404
+ writeFileSync(file, original)
405
+ }
406
+ }
407
+
408
+ function updatePnpmStrict(print, lock, packages) {
409
+ let minimumReleaseAge = getPnpmConfig('minimumReleaseAge')
410
+ if (
411
+ typeof minimumReleaseAge !== 'number' ||
412
+ !Number.isFinite(minimumReleaseAge) ||
413
+ minimumReleaseAge <= 0
414
+ ) {
415
+ throw new BrowserslistUpdateError(
416
+ 'Cannot read a valid pnpm minimumReleaseAge. Refusing to disable pnpm security checks.'
417
+ )
418
+ }
419
+
420
+ let versions = {}
421
+ for (let name of packages) {
422
+ versions[name] = getMatureVersion(name, minimumReleaseAge)
423
+ }
424
+
425
+ let originalOverrides = getPnpmConfig('overrides')
426
+ if (
427
+ originalOverrides === undefined ||
428
+ originalOverrides === null ||
429
+ Array.isArray(originalOverrides) ||
430
+ typeof originalOverrides !== 'object'
431
+ ) {
432
+ originalOverrides = {}
433
+ }
434
+ let temporaryOverrides = { ...originalOverrides, ...versions }
435
+ let packageDir = dirname(lock.file)
436
+ let workspaceFile = join(packageDir, 'pnpm-workspace.yaml')
437
+ let originalWorkspace = existsSync(workspaceFile)
438
+ ? readFileSync(workspaceFile)
439
+ : undefined
440
+ let originalLockfile = readFileSync(lock.file)
441
+ let command = 'pnpm config set overrides'
442
+
443
+ print(
444
+ 'Strict pnpm minimumReleaseAge detected\n' +
445
+ 'Latest policy-compliant: ' +
446
+ pico.bold(pico.green(versions['caniuse-lite'])) +
447
+ '\n' +
448
+ Object.keys(versions)
449
+ .filter(name => name !== 'caniuse-lite')
450
+ .map(name => ' ' + name + ': ' + versions[name] + '\n')
451
+ .join('')
452
+ )
453
+
454
+ try {
455
+ execFileSync(
456
+ 'pnpm',
457
+ [
458
+ 'config',
459
+ 'set',
460
+ 'overrides',
461
+ JSON.stringify(temporaryOverrides),
462
+ '--json',
463
+ '--location',
464
+ 'project'
465
+ ],
466
+ { cwd: packageDir }
467
+ )
468
+
469
+ command = 'pnpm install --lockfile-only'
470
+ print(
471
+ 'Updating caniuse-lite version\n' +
472
+ pico.yellow('$ ' + command) +
473
+ ' (with temporary policy-compliant overrides)\n'
474
+ )
475
+ execFileSync('pnpm', ['install', '--lockfile-only'], { cwd: packageDir })
476
+
477
+ restoreFile(workspaceFile, originalWorkspace)
478
+ // The lockfile no longer matches the restored overrides, and pnpm
479
+ // freezes the lockfile by default in CI
480
+ command = 'pnpm install --no-frozen-lockfile'
481
+ print(
482
+ 'Removing temporary pnpm overrides\n' + pico.yellow('$ ' + command) + '\n'
483
+ )
484
+ execFileSync('pnpm', ['install', '--no-frozen-lockfile'], {
485
+ cwd: packageDir
486
+ })
487
+ } catch (error) /* c8 ignore start */ {
488
+ restoreFile(workspaceFile, originalWorkspace)
489
+ writeFileSync(lock.file, originalLockfile)
490
+ print(pico.red(commandErrorText(error)))
491
+ print(
492
+ pico.red('\n\nProblem with `' + command + '` call. Run it manually.\n')
493
+ )
494
+ process.exit(1)
495
+ } /* c8 ignore end */
496
+ }
497
+
498
+ function updatePnpm(print, lock) {
499
+ let lockContent = readFileSync(lock.file).toString()
500
+ let packages = lockContent.includes('baseline-browser-mapping')
501
+ ? ['caniuse-lite', 'baseline-browser-mapping']
502
+ : ['caniuse-lite']
503
+ let command = 'pnpm up --depth=9999 --no-save ' + packages.join(' ')
504
+
505
+ print('Updating caniuse-lite version\n' + pico.yellow('$ ' + command) + '\n')
506
+ try {
507
+ execFileSync('pnpm', ['up', '--depth=9999', '--no-save', ...packages], {
508
+ stdio: 'pipe'
509
+ })
510
+ } catch (error) /* c8 ignore start */ {
511
+ let text = commandErrorText(error)
512
+ if (text.includes('ERR_PNPM_STRICT_MIN_RELEASE_AGE_REQUIRES_SAVE')) {
513
+ updatePnpmStrict(print, lock, packages)
514
+ } else {
515
+ print(pico.red(text))
516
+ print(
517
+ pico.red('\n\nProblem with `' + command + '` call. Run it manually.\n')
518
+ )
519
+ process.exit(1)
520
+ }
521
+ } /* c8 ignore end */
522
+ }
523
+
331
524
  function updateWith(print, cmd, message = 'Updating caniuse-lite version') {
332
525
  print(message + '\n' + pico.yellow('$ ' + cmd) + '\n')
333
526
  try {
@@ -361,16 +554,14 @@ module.exports = function updateDB(print = defaultPrint) {
361
554
  listError = e
362
555
  }
363
556
 
364
- print('Latest version: ' + pico.bold(pico.green(latest.version)) + '\n')
557
+ print(
558
+ 'Registry latest: ' + pico.bold(pico.green(latest.version)) + '\n'
559
+ )
365
560
 
366
561
  if (lock.mode === 'yarn' && lock.version !== 1) {
367
562
  updateWith(print, YARN_CMD + ' up -R caniuse-lite baseline-browser-mapping')
368
563
  } else if (lock.mode === 'pnpm') {
369
- let lockContent = readFileSync(lock.file).toString()
370
- let packages = lockContent.includes('baseline-browser-mapping')
371
- ? 'caniuse-lite baseline-browser-mapping'
372
- : 'caniuse-lite'
373
- updateWith(print, 'pnpm up --depth=9999 --no-save ' + packages)
564
+ updatePnpm(print, lock)
374
565
  } else if (lock.mode === 'bun') {
375
566
  updateBun(print, lock, latest)
376
567
  } else if (lock.mode === 'deno') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "update-browserslist-db",
3
- "version": "1.3.2",
3
+ "version": "1.3.3",
4
4
  "description": "CLI tool to update caniuse-lite to refresh target browsers from Browserslist config",
5
5
  "keywords": [
6
6
  "browsers",