async.js (3018B)
1 /** 2 * @license Apache-2.0 3 * 4 * Copyright (c) 2018 The Stdlib Authors. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 'use strict'; 20 21 // MODULES // 22 23 var isString = require( '@stdlib/assert/is-string' ).isPrimitive; 24 var isObject = require( '@stdlib/assert/is-plain-object' ); 25 var isFunction = require( '@stdlib/assert/is-function' ); 26 var readFile = require( './../../read-file' ); 27 var removeBOM = require( '@stdlib/string/remove-utf8-bom' ); 28 var parseJSON = require( '@stdlib/utils/parse-json' ); 29 var instanceOf = require( '@stdlib/assert/instance-of' ); 30 31 32 // MAIN // 33 34 /** 35 * Asynchronously reads a file as JSON. 36 * 37 * @param {(string|Buffer|integer)} file - file path or file descriptor 38 * @param {(Options|string)} [options] - options 39 * @param {(string|null)} [options.encoding] - file encoding 40 * @param {string} [options.flag] - file status flag 41 * @param {Function} [options.reviver] - JSON reviver 42 * @param {Callback} clbk - callback 43 * @throws {TypeError} options argument must be either a string or an object 44 * @throws {TypeError} callback argument must be a function 45 * 46 * @example 47 * var resolve = require( 'path' ).resolve; 48 * 49 * readJSON( resolve( __dirname, '..', 'package.json' ), onJSON ); 50 * 51 * function onJSON( error, data ) { 52 * if ( error ) { 53 * throw error; 54 * } 55 * console.dir( data ); 56 * } 57 */ 58 function readJSON( file, options, clbk ) { 59 var opts; 60 var done; 61 if ( arguments.length < 3 ) { 62 opts = {}; 63 done = options; 64 } else { 65 if ( isString( options ) ) { 66 opts = { 67 'encoding': options 68 }; 69 } else { 70 if ( !isObject( options ) ) { 71 throw new TypeError( 'invalid argument. Options argument must be either a string or an object. Value: `' + options + '`.' ); 72 } 73 opts = options; 74 } 75 done = clbk; 76 } 77 if ( !isFunction( done ) ) { 78 throw new TypeError( 'invalid argument. Callback argument must be a function. Value: `' + done + '`.' ); 79 } 80 readFile( file, opts, onRead ); 81 82 /** 83 * Callback invoked upon reading a file. 84 * 85 * @private 86 * @param {(Error|null)} error - error object 87 * @param {(Buffer|string)} file - file contents 88 * @returns {void} 89 */ 90 function onRead( error, file ) { 91 if ( error ) { 92 return done( error ); 93 } 94 file = file.toString(); 95 if ( opts.encoding === 'utf8' ) { 96 file = removeBOM( file ); 97 } 98 if ( opts.reviver ) { 99 file = parseJSON( file, opts.reviver ); 100 } else { 101 file = parseJSON( file ); 102 } 103 if ( instanceOf( file, Error ) ) { 104 return done( file ); 105 } 106 done( null, file ); 107 } 108 } 109 110 111 // EXPORTS // 112 113 module.exports = readJSON;