├── .editorconfig ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── index.js ├── package.json └── test ├── data ├── file1 └── file2 ├── mocha.opts └── test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | end_of_line = lf 8 | charset = utf-8 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | indent_style = space 12 | indent_size = 4 13 | 14 | [{package.json,.travis.yml}] 15 | indent_size = 2 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: false 3 | node_js: 4 | - '0.10' 5 | - stable 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Ivan Nikulin (ifaaan@gmail.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # read-file-relative 2 | [![Build Status](https://api.travis-ci.org/inikulin/read-file-relative.svg)](https://travis-ci.org/inikulin/read-file-relative) 3 | 4 | *Read files with path relative to the current module without annoying boilerplate code* 5 | 6 | ~~Well, I've expected @sindresorhus has a module for this, but he didn't.~~ 7 | 8 | ## What's going on? 9 | 10 | If you have code like this: 11 | ```js 12 | var fs = require('fs'); 13 | var path = require('path'); 14 | 15 | var data = fs.readFileSync(path.join(__dirname, '/my-awesome-file')).toString(); 16 | ``` 17 | 18 | Now you can replace it with: 19 | ```js 20 | var readSync = require('read-file-relative').readSync; 21 | 22 | var data = readSync('/my-awesome-file'); 23 | ``` 24 | 25 | That's it. 26 | 27 | You want a plain buffer instead of string? No problem - just use optional second argument: 28 | ```js 29 | var readSync = require('read-file-relative').readSync; 30 | 31 | var buffer = readSync('/my-awesome-file', true); 32 | ``` 33 | 34 | You like it the async way (didn't you :wink:)? Do it this way: 35 | ```js 36 | var read = require('read-file-relative').read; 37 | 38 | read('/my-awesome-file', function(err, content) { 39 | ... 40 | }); 41 | ``` 42 | 43 | You can pass options or encoding like for regular `fs.readFile`: 44 | ```js 45 | var read = require('read-file-relative').read; 46 | 47 | read('/my-awesome-file', 'utf8', function(err, content) { 48 | ... 49 | }); 50 | ``` 51 | 52 | BTW, you can just convert given path to absolute: 53 | ```js 54 | var toAbsPath = require('read-file-relative').toAbsPath; 55 | 56 | var absPath = toAbsPath('/my-awesome-file'); 57 | ``` 58 | 59 | ## Install 60 | ``` 61 | npm install read-file-relative 62 | ``` 63 | 64 | ## Author 65 | [Ivan Nikulin](https://github.com/inikulin) (ifaaan@gmail.com) 66 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var fs = require('fs'); 3 | var callSite = require('callsite'); 4 | 5 | function toAbsPath (relativePath) { 6 | var site = callSite(); 7 | var idx = 2; 8 | 9 | // NOTE: skip native call sites 10 | // to support calls from Array 11 | // proto methods 12 | while (site[idx].isNative()) 13 | idx++; 14 | 15 | var caller = site[idx]; 16 | var callerPath = caller.getFileName(); 17 | var basePath = path.dirname(callerPath); 18 | 19 | return path.join(basePath, relativePath); 20 | } 21 | 22 | function readSync (relativePath, binary) { 23 | var absPath = toAbsPath(relativePath); 24 | var content = fs.readFileSync(absPath); 25 | 26 | return binary ? content : content.toString(); 27 | } 28 | 29 | function read (relativePath, options, callback) { 30 | var absPath = toAbsPath(relativePath); 31 | 32 | if (typeof options === 'function') { 33 | callback = options; 34 | options = null; 35 | } 36 | 37 | fs.readFile(absPath, options, callback); 38 | } 39 | 40 | module.exports = { 41 | readSync: readSync, 42 | read: read, 43 | 44 | // NOTE: we need this wrapper to achieve 45 | // correct call site in real `toAbsPath()`. 46 | // It could be done via binary flag, but 47 | // this approach is not `Array.map`-safe. 48 | toAbsPath: function (relativePath) { 49 | return toAbsPath(relativePath); 50 | } 51 | }; 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "read-file-relative", 3 | "version": "1.2.0", 4 | "description": "Read files with path relative to the current module without annoying boilerplate code ", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/inikulin/read-file-relative" 12 | }, 13 | "keywords": [ 14 | "read", 15 | "file", 16 | "relative", 17 | "path" 18 | ], 19 | "author": "Ivan Nikulin (ifaaan@gmail.com)", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/inikulin/read-file-relative/issues" 23 | }, 24 | "homepage": "https://github.com/inikulin/read-file-relative", 25 | "files": [ 26 | "index.js" 27 | ], 28 | "devDependencies": { 29 | "mocha": "^2.3.3" 30 | }, 31 | "dependencies": { 32 | "callsite": "^1.0.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test/data/file1: -------------------------------------------------------------------------------- 1 | 42 2 | -------------------------------------------------------------------------------- /test/data/file2: -------------------------------------------------------------------------------- 1 | Hey ya! 2 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --reporter spec 2 | --ui bdd 3 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var path = require('path'); 3 | var read = require('../').read; 4 | var readSync = require('../').readSync; 5 | var toAbsPath = require('../').toAbsPath; 6 | 7 | it('Should read file sync', function () { 8 | assert.strictEqual(readSync('./data/file1').trim(), '42'); 9 | assert.strictEqual(readSync('./data/file2').trim(), 'Hey ya!'); 10 | }); 11 | 12 | it('Should read file sync as a buffer', function () { 13 | var content = readSync('./data/file1', true); 14 | 15 | assert.ok(content instanceof Buffer); 16 | assert.strictEqual(content.toString().trim(), '42'); 17 | }); 18 | 19 | it('Should read file async', function (done) { 20 | read('./data/file1', function (err, content) { 21 | assert.strictEqual(content.toString().trim(), '42'); 22 | done(); 23 | }); 24 | }); 25 | 26 | it('Should read file async with options', function (done) { 27 | read('./data/file1', 'utf8', function (err, content) { 28 | assert.strictEqual(content.trim(), '42'); 29 | done(); 30 | }); 31 | }); 32 | 33 | it('Should provide conversion to absolute path', function () { 34 | assert.strictEqual(toAbsPath('./data/file1'), path.join(__dirname, './data/file1')); 35 | }); 36 | 37 | it('Should provide support for Array native methods', function () { 38 | var files = [ 39 | './data/file1', 40 | './data/file2' 41 | ]; 42 | 43 | var actualPaths = files.map(toAbsPath); 44 | 45 | var expectedPaths = files.map(function (file) { 46 | return path.join(__dirname, file); 47 | }); 48 | 49 | assert.deepEqual(actualPaths, expectedPaths); 50 | 51 | var actualContent = files.map(function (file) { 52 | return readSync(file).trim(); 53 | }); 54 | 55 | var expectedContent = ['42', 'Hey ya!']; 56 | 57 | assert.deepEqual(actualContent, expectedContent); 58 | }); 59 | --------------------------------------------------------------------------------