Skip to content
This repository has been archived by the owner on Aug 17, 2019. It is now read-only.

Commit

Permalink
fix(json): strip BOM when reading JSON files (#8)
Browse files Browse the repository at this point in the history
fs.readFile* don't strip the BOM header, even when specifying 'utf8' as
the encoding, and JSON.parse() doesn't handle it either. There are
technically a bunch of BOM indicators, but this is the one seen most
commonly and actually appears in a number of package.json files in the
wild.

See nodejs/node#6924, nodejs/node#3040 for background.
  • Loading branch information
rmg authored and zkat committed Sep 6, 2017
1 parent d912d16 commit 2529149
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 3 deletions.
7 changes: 6 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,18 @@ class Installer {
}
}
module.exports = Installer
module.exports._readJson = readJson

function readJson (jsonPath, name, ignoreMissing) {
return readFileAsync(path.join(jsonPath, name), 'utf8')
.then(str => JSON.parse(str))
.then(str => JSON.parse(stripBOM(str)))
.catch({code: 'ENOENT'}, err => {
if (!ignoreMissing) {
throw err
}
})
}

function stripBOM (str) {
return str.replace(/^\uFEFF/, '')
}
6 changes: 6 additions & 0 deletions test/lib/package-json-with-bom.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "strong-spawn-npm",
"version": "1.0.0",
"description": "Reliably spawn npm™ on any platform",
"homepage": "https://github.com/strongloop/strong-spawn-npm"
}
22 changes: 20 additions & 2 deletions test/specs/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
'use strict'

const fixtureHelper = require('../lib/fixtureHelper.js')
const fs = require('fs')
const path = require('path')
const test = require('tap').test
const requireInject = require('require-inject')
const fixtureHelper = require('../lib/fixtureHelper.js')
const test = require('tap').test

let extract = () => {}
const pkgName = 'hark-a-package'
Expand Down Expand Up @@ -298,3 +299,20 @@ test('skips lifecycle scripts with ignoreScripts is set', t => {
t.end()
})
})

test('handles JSON docs that contain a BOM', t => {
t.plan(2)
const Installer = requireInject('../../index.js', {/* just don't want to cache */})
const bomJSON = 'package-json-with-bom.json'
const bomJSONDir = path.resolve(__dirname, '../lib')
const actualJSON = {
name: 'strong-spawn-npm',
version: '1.0.0',
description: 'Reliably spawn npm™ on any platform',
homepage: 'https://github.com/strongloop/strong-spawn-npm'
}
// ensure that the file does indeed fail to be parsed by JSON.parse
t.throws(() => JSON.parse(fs.readFileSync(path.join(bomJSONDir, bomJSON), 'utf8')),
{message: 'Unexpected token \uFEFF'})
return Installer._readJson(bomJSONDir, bomJSON).then(obj => t.match(obj, actualJSON))
})

0 comments on commit 2529149

Please sign in to comment.