Skip to content
This repository was archived by the owner on Aug 11, 2022. It is now read-only.

Commit 28064e5

Browse files
committed
install: version: Fix package.json handling to always allow BOM at start
Fixes: #3358 PR-URL: #8724
1 parent 2875ba3 commit 28064e5

File tree

9 files changed

+45
-26
lines changed

9 files changed

+45
-26
lines changed

lib/cache/caching-client.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ var mkdirp = require('mkdirp')
1515
var rimraf = require('rimraf')
1616
var chownr = require('chownr')
1717
var writeFile = require('write-file-atomic')
18+
var parseJSON = require('../utils/parse-json')
1819

1920
function CachingRegistryClient (config) {
2021
RegistryClient.call(this, adaptConfig(config))
@@ -78,11 +79,7 @@ function get (uri, params, cb) {
7879
fs.stat(cachePath, function (er, stat) {
7980
if (!er) {
8081
fs.readFile(cachePath, function (er, data) {
81-
try {
82-
data = JSON.parse(data)
83-
} catch (ex) {
84-
data = null
85-
}
82+
data = parseJSON.noExceptions(data)
8683

8784
params.stat = stat
8885
params.data = data

lib/cache/update-index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ var cacheFile = require('npm-cache-filename')
1111
var getCacheStat = require('./get-stat.js')
1212
var mapToRegistry = require('../utils/map-to-registry.js')
1313
var pulseTillDone = require('../utils/pulse-till-done.js')
14+
var parseJSON = require('../utils/parse-json.js')
1415

1516
/* /-/all is special.
1617
* It uses timestamp-based caching and partial updates,
@@ -47,9 +48,8 @@ function updateIndex (staleness, cb) {
4748
chownr(made || cachePath, st.uid, st.gid, function (er) {
4849
if (er) return cb(er)
4950

50-
try {
51-
data = JSON.parse(data)
52-
} catch (ex) {
51+
data = parseJSON.noExceptions(data)
52+
if (!data) {
5353
fs.writeFile(cachePath, '{}', function (er) {
5454
if (er) return cb(new Error('Broken cache.'))
5555

lib/fetch-package-metadata.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ var tempFilename = require('./utils/temp-filename.js')
2323
var getCacheStat = require('./cache/get-stat.js')
2424
var unpack = require('./utils/tar.js').unpack
2525
var pulseTillDone = require('./utils/pulse-till-done.js')
26+
var parseJSON = require('./utils/parse-json.js')
2627

2728
function andLogAndFinish (spec, tracker, done) {
2829
validate('SF', [spec, done])
@@ -184,7 +185,7 @@ module.exports.addShrinkwrap = function addShrinkwrap (pkg, next) {
184185
untar.close()
185186
log.silly('addShrinkwrap', 'Done reading shrinkwrap')
186187
try {
187-
pkg._shrinkwrap = JSON.parse(shrinkwrap)
188+
pkg._shrinkwrap = parseJSON(shrinkwrap)
188189
} catch (ex) {
189190
var er = new Error('Error parsing ' + pkgname + '@' + ver + "'s npm-shrinkwrap.json: " + ex.message)
190191
er.type = 'ESHRINKWRAP'

lib/install.js

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ var getSaveType = require('./install/save.js').getSaveType
128128
var doSerialActions = require('./install/actions.js').doSerial
129129
var doParallelActions = require('./install/actions.js').doParallel
130130
var doOneAction = require('./install/actions.js').doOne
131+
var parseJSON = require('./utils/parse-json.js')
131132

132133
function unlockCB (lockPath, name, cb) {
133134
validate('SSF', arguments)
@@ -396,21 +397,13 @@ Installer.prototype.computeLinked = function (cb) {
396397
})
397398
}
398399

399-
function safeJSONparse (data) {
400-
try {
401-
return JSON.parse(data)
402-
} catch (ex) {
403-
return
404-
}
405-
}
406-
407400
function isLinkable (pkg, cb) {
408401
var globalPackage = path.resolve(npm.globalPrefix, 'lib', 'node_modules', pkg.package.name)
409402
var globalPackageJson = path.resolve(globalPackage, 'package.json')
410403
fs.stat(globalPackage, function (er) {
411404
if (er) return cb(true, true)
412405
fs.readFile(globalPackageJson, function (er, data) {
413-
var json = safeJSONparse(data)
406+
var json = parseJSON.noExceptions(data)
414407
cb(false, json && json.version === pkg.package.version)
415408
})
416409
})
@@ -520,10 +513,10 @@ Installer.prototype.readLocalPackageData = function (cb) {
520513
}
521514
if (!currentTree.package) currentTree.package = {}
522515
if (currentTree.package._shrinkwrap) return cb()
523-
fs.readFile(path.join(self.where, 'npm-shrinkwrap.json'), {encoding: 'utf8'}, function (er, data) {
516+
fs.readFile(path.join(self.where, 'npm-shrinkwrap.json'), function (er, data) {
524517
if (er) return cb()
525518
try {
526-
currentTree.package._shrinkwrap = JSON.parse(data)
519+
currentTree.package._shrinkwrap = parseJSON(data)
527520
} catch (ex) {
528521
return cb(ex)
529522
}

lib/install/read-shrinkwrap.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@ var path = require('path')
33
var fs = require('graceful-fs')
44
var iferr = require('iferr')
55
var inflateShrinkwrap = require('./inflate-shrinkwrap.js')
6+
var parseJSON = require('../utils/parse-json.js')
67

78
var readShrinkwrap = module.exports = function (child, next) {
8-
fs.readFile(path.join(child.path, 'npm-shrinkwrap.json'), {encoding: 'utf-8'}, function (er, data) {
9+
fs.readFile(path.join(child.path, 'npm-shrinkwrap.json'), function (er, data) {
910
if (er) {
1011
child.package._shrinkwrap = null
1112
return next()
1213
}
1314
try {
14-
child.package._shrinkwrap = JSON.parse(data)
15+
child.package._shrinkwrap = parseJSON(data)
1516
} catch (ex) {
1617
child.package._shrinkwrap = null
1718
return next(ex)

lib/install/save.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ var validate = require('aproba')
1010
var without = require('lodash.without')
1111
var npm = require('../npm.js')
1212
var deepSortObject = require('../utils/deep-sort-object.js')
13+
var parseJSON = require('../utils/parse-json.js')
1314

1415
// if the -S|--save option is specified, then write installed packages
1516
// as dependencies to a package.json file.
@@ -62,7 +63,7 @@ function savePackageJson (args, tree, next) {
6263
// tricky npm-specific stuff that's in there.
6364
fs.readFile(saveTarget, iferr(next, function (packagejson) {
6465
try {
65-
packagejson = JSON.parse(packagejson.toString('utf8'))
66+
packagejson = parseJSON(packagejson)
6667
} catch (ex) {
6768
return next(ex)
6869
}

lib/npm.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
var abbrev = require('abbrev')
2727
var which = require('which')
2828
var CachingRegClient = require('./cache/caching-client.js')
29+
var parseJSON = require('./utils/parse-json.js')
2930

3031
npm.config = {
3132
loaded: false,
@@ -43,7 +44,7 @@
4344

4445
try {
4546
// startup, ok to do this synchronously
46-
var j = JSON.parse(fs.readFileSync(
47+
var j = parseJSON(fs.readFileSync(
4748
path.join(__dirname, '../package.json')) + '')
4849
npm.version = j.version
4950
} catch (ex) {

lib/utils/parse-json.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict'
2+
var parseJSON = module.exports = function (content) {
3+
return JSON.parse(stripBOM(content))
4+
}
5+
6+
parseJSON.noExceptions = function (content) {
7+
try {
8+
return parseJSON(content)
9+
} catch (ex) {
10+
return
11+
}
12+
}
13+
14+
// from read-package-json
15+
function stripBOM (content) {
16+
content = content.toString()
17+
// Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
18+
// because the buffer-to-string conversion in `fs.readFileSync()`
19+
// translates it to FEFF, the UTF-16 BOM.
20+
if (content.charCodeAt(0) === 0xFEFF) {
21+
content = content.slice(1)
22+
}
23+
return content
24+
}

lib/version.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ var npm = require('./npm.js')
1212
var git = require('./utils/git.js')
1313
var assert = require('assert')
1414
var lifecycle = require('./utils/lifecycle.js')
15+
var parseJSON = require('./utils/parse-json.js')
1516

1617
version.usage = 'npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease]' +
1718
'\n(run in package dir)\n' +
@@ -32,7 +33,7 @@ function version (args, silent, cb_) {
3233
fs.readFile(packagePath, function (er, data) {
3334
if (data) data = data.toString()
3435
try {
35-
data = JSON.parse(data)
36+
data = parseJSON(data)
3637
} catch (e) {
3738
er = e
3839
data = null
@@ -107,7 +108,7 @@ function updateShrinkwrap (newVersion, cb) {
107108

108109
try {
109110
data = data.toString()
110-
data = JSON.parse(data)
111+
data = parseJSON(data)
111112
} catch (er) {
112113
log.error('version', 'Bad npm-shrinkwrap.json data')
113114
return cb(er)

0 commit comments

Comments
 (0)