├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── index.js ├── package.json └── test ├── is-it-friday.js └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Compiled binary addons (http://nodejs.org/api/addons.html) 18 | build/Release 19 | 20 | # Dependency directories 21 | node_modules 22 | 23 | # Optional npm cache directory 24 | .npm 25 | 26 | # Optional REPL history 27 | .node_repl_history 28 | 29 | # Webstorm 30 | .idea -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: "6" 3 | script: npm run-script test-travis 4 | # Send coverage data to Coveralls 5 | after_script: "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2011-2017 JS Foundation and contributors, https://js.foundation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # patch-module 2 | 3 | [![npm version](https://badge.fury.io/js/patch-module.svg)](https://badge.fury.io/js/patch-module) 4 | [![Build Status](https://travis-ci.org/kus/patch-module.svg?branch=master)](https://travis-ci.org/kus/patch-module) 5 | [![Coverage Status](https://coveralls.io/repos/github/kus/patch-module/badge.svg?branch=master)](https://coveralls.io/github/kus/patch-module?branch=master) 6 | 7 | Monkey patch npm modules. 8 | 9 | Have you ever looked through a module you are using and wished it was written just a little bit different? 10 | 11 | Knowing the hassle of forking a repo, changing the code, submitting a Pull Request (which may not get accepted) and then losing track of updates in the original module; I built Patch Module.

 Patch Module allows you to change the source code of another module before it is `required`. It mimics node's `require` functionality, making it familiar to use whilst avoiding the use of `eval`. Patch Module will load a module from the file system, apply the patches you wish to make and then compiles the module. 12 | 13 | Patch Module includes a couple of optional safety features too. You can define the version of the module you are patching as well as how many times the regex for the patch should match. If either of those operations don't match your settings, Patch Module will alert you letting you know that the module you are trying to patch has been updated and you should check your patch is still necessary. 14 | 15 | # Install 16 | 17 | ```bash 18 | $ npm install patch-module --save 19 | ``` 20 | 21 | # Usage 22 | 23 | We will use the module [is-it-friday](https://www.npmjs.com/package/is-it-friday) as an example of a module to patch. [is-it-friday](https://www.npmjs.com/package/is-it-friday) is simply one line `module.exports = "Probably not...";` 24 | 25 | Default [is-it-friday](https://www.npmjs.com/package/is-it-friday) behaviour: 26 | 27 | ```javascript 28 | // file: index.js 29 | var isItFriday = require('is-it-friday'); 30 | console.log(isItFriday); // Probably not... 31 | ``` 32 | 33 | Patching as a `require`: 34 | 35 | ```javascript 36 | // file: index.js 37 | var patch = require('patch-module'); 38 | var isItFriday = patch('./node_modules/is-it-friday/index.js', { 39 | version: '0.1.0', 40 | package: './node_modules/is-it-friday/package.json' 41 | }, [ 42 | {find: '"Probably not..."', replace: '(new Date()).getDay() === 5 ? "Yes" : "No"', expect: 1} 43 | ]); 44 | console.log(isItFriday); // "Yes" or "No" depending if it's Friday 45 | ``` 46 | 47 | 
Here we create our patched `isItFriday` module so we can require it elsewhere in our project whilst making it easy to revert to the original module later if needed: 48 | 49 | ```javascript 50 | // file: index.js 51 | var isItFriday = require('./patch/is-it-friday.js'); 52 | console.log(isItFriday); // "Yes" or "No" depending if it's Friday 53 | 54 | // file: patch/is-it-friday.js 55 | var patch = require('patch-module'); 56 | module.exports = patch('./node_modules/is-it-friday/index.js', { 57 | version: '0.1.0', 58 | package: './node_modules/is-it-friday/package.json' 59 | }, [ 60 | {find: '"Probably not..."', replace: '(new Date()).getDay() === 5 ? "Yes" : "No"', expect: 1} 61 | ]); 62 | ``` 63 | 64 | # Advanced Usage 65 | 66 | To show an example of patching multiple files in a module we will use [jugglingdb](https://www.npmjs.com/package/jugglingdb) as an example. Let's patch the way jugglingdb handles connection errors when trying to connect to a Mongo database that is not available, by adding the ability to listen to a new `error` event and handle it instead of it `throwing` an uncatchable error. 67 | 68 | In [jugglingdb](https://www.npmjs.com/package/jugglingdb) if a full path is specified for a `Schema` it will load that instead of looking in `node_modules` so we can point it directly to our modified `jugglingdb-mongodb` module. 69 | 70 | ```javascript 71 | // file: index.js 72 | var jugglingdb = require('./patch/jugglingdb.js'); 73 | var Schema = jugglingdb.Schema; 74 | var db = new Schema(__dirname + '/patch/jugglingdb-mongodb.js', { 75 | url: process.env.MONGO_URL || 'mongodb://localhost:27017/test' 76 | }); 77 | db.on('connected', function () { 78 | console.log('connected!'); 79 | }); 80 | db.on('disconnected', function () { 81 | console.log('disconnected!'); 82 | }); 83 | // This is new functionality 84 | db.on('error', function (err) { 85 | console.log('error!', err.message); 86 | }); 87 | ``` 88 | 89 | We need to modify the Schema class, which is loaded from the modules `index.js`. 90 | 91 | Important: If you are modifying a relative require (`require(./`) you need to replace the new path with the full path. 92 | 93 | ```javascript 94 | // file: patch/jugglingdb.js 95 | var patch = require('patch-module'); 96 | module.exports = patch('./node_modules/jugglingdb/index.js', { 97 | version: '2.0.0-rc8', 98 | package: './node_modules/jugglingdb/package.json' 99 | }, [ 100 | {find: 'var Schema = exports.Schema = require(\'./lib/schema\').Schema;', replace: 'var Schema = exports.Schema = require(\'' + __dirname + '/patch/jugglingdb-schema.js\').Schema;', expect: 1} 101 | ]); 102 | ``` 103 | 104 | Here we are modifying the [jugglingdb-mongodb](https://www.npmjs.com/package/jugglingdb-mongodb) connector module and changing the `throw` to calling the callback and passing the error on, that way we can choose how to handle it. We expect to make two replacements, so we've set `expect` to `2`. 105 | 106 | ```javascript 107 | // file: patch/jugglingdb-mongodb.js 108 | var patch = require('patch-module'); 109 | module.exports = patch('./node_modules/jugglingdb-mongodb/lib/mongodb.js', { 110 | version: '0.2.0', 111 | package: './node_modules/jugglingdb-mongodb/package.json' 112 | }, [ 113 | {find: /if \(err\) throw err;/mg, replace: 'if (err) return callback(err);', expect: 2}, 114 | ]); 115 | ``` 116 | 117 | When [jugglingdb](https://www.npmjs.com/package/jugglingdb) connects to a database, it creates a `client` variable that holds the connection to the database in the connector and passes it back. However it doesn't check if the `client` variable actually has a valid connection that emits the `connected` event. So we are checking if the `client` variable has a valid connection to a database and only emitting the `connected` event then, if not we will emit a new `error` event with the error. 118 | 119 | ```javascript 120 | // file: patch/jugglingdb-schema.js 121 | var patch = require('patch-module'); 122 | module.exports = patch('./node_modules/jugglingdb/lib/schema.js', { 123 | version: '2.0.0-rc8', 124 | package: './node_modules/jugglingdb/package.json' 125 | }, [ 126 | {find: 'adapter.initialize(this, function () {', replace: 'adapter.initialize(this, function (err) {', expect: 1}, 127 | {find: /this\.connecting = false;\s+this\.connected = true;\s+this\.emit\('connected'\);/m, replace: `if (this.client) { 128 | this.connecting = false; 129 | this.connected = true; 130 | this.emit('connected'); 131 | } else { 132 | this.emit('error', err); 133 | }`, expect: 1} 134 | ]); 135 | ``` 136 | 137 | # patch(filePath, options = {}, replacements = []) 138 | 139 | * The first argument `filePath` is the path to the file you want to patch. 140 | * The second argument can be either an [options Object](#options-object), [replacements Array](#replacements-array), [callback Function](#callback-function) or `undefined`. 141 | * The third argument can be a [replacements Array](#replacements-array), [callback Function](#callback-function) or `undefined`. 142 | 143 | ## options Object 144 | * `version` - Version that we expect from the `package` file for the module we are modifying 145 | * `package` - Package file to look in when `version` is defined 146 | * `dontReplaceRelativeRequires` - Don't automatically replace `require(./` with `require(path/to/file/you/are/changing`. The module is set to replace relative requires from a module back to the original path by default as a convenience 147 | * `callback` - `callback` `Function`, see [callback Function](#callback-function) below 148 | * `returnAsString` - Useful for debugging your modifications, will return the source as a string which you can write to a file or `console.log` 149 | 150 | ## replacements Array 151 | 152 | An `Array` of replacement `Objects` with keys: 153 | 154 | * `find` - `String` or `RegExp` to look for 155 | * `replace` - `String` to replace what we find with 156 | * `expect` - _(Optional)_ Explicitly define an `Integer` for how many occurrences of `find` we expect. This helps with module updates and old patches 157 | 158 | ## callback Function 159 | 160 | A `Function` that takes a string `function (str) { /* ...modify str... */ return str; }`, modifies it and `returns` it to be compiled. If you have a `callback` `Function` and `replacements` `Array` the `callback` `Function` modifies the source first than the `replacements` are applied. 161 | 162 | # Tests 163 | 164 | To run the test suite, first install the dependencies, then run `npm test`: 165 | 166 | ```bash 167 | $ npm install 168 | $ npm test 169 | ``` 170 | 171 | ## License 172 | 173 | [MIT](LICENSE) -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | var util = require('util'); 6 | var assert = require('assert').ok; 7 | var Module = require('module'); 8 | var crypto = require('crypto'); 9 | 10 | /** 11 | * Monkey patch a dependency 12 | * 13 | * @static 14 | * @param {String} filePath - Path to file you want to patch. 15 | * @param {Object} [opts={}] - Options 16 | * @param {String} [opts.version] - Version to check for (package required if set) 17 | * @param {String} [opts.package] - Package file to check version from (required if version set) 18 | * @param {Boolean} [opts.dontReplaceRelativeRequires=false] - Try to automatically replace relative requires. Set to true to disable. 19 | * @param {Boolean} [opts.returnAsString=false] - Return modified source as string. 20 | * @param {Boolean} [opts.inputSource=false] - filePath is source instead of file path. 21 | * @param {Boolean} [opts.extension=undefined] - Override extension. 22 | * @param {Function} [opts.callback=undefined] - Function to pass the source through and return modified. 23 | * @param {Object[]} [replacements=[]] - Array of replacement objects with find, replace, expect (optional) keys. 24 | * @param {String|RegExp} replacements[].find - What to find 25 | * @param {String} replacements[].replace - What to replace with 26 | * @param {Number} [replacements[].expect] - How many matches expected to find 27 | * @returns {String} Returns modified module exports 28 | * @example 29 | * // file: index.js 30 | * var isItFriday = require('./is-it-friday.js'); 31 | * console.log(isItFriday); 32 | * 33 | * // file: is-it-friday.js 34 | * var patch = require('patch-module'); 35 | * module.exports = patch('./node_modules/is-it-friday/index.js', { 36 | * version: '0.1.0', 37 | * package: './node_modules/is-it-friday/package.json' 38 | * }, [ 39 | * {find: '"Probably not..."', replace: '(new Date()).getDay() === 5 ? "Yes" : "No"', expect: 1} 40 | * ]); 41 | */ 42 | function patch (filePath, opts, replacements) { 43 | assert(filePath, 'missing path'); 44 | assert(util.isString(filePath), 'path must be a string'); 45 | if (Array.isArray(opts)) { 46 | replacements = opts; 47 | opts = {}; 48 | } 49 | if (typeof opts === 'function') { 50 | opts = { 51 | callback: opts 52 | }; 53 | } 54 | if (typeof replacements === 'function') { 55 | opts.callback = replacements; 56 | replacements = []; 57 | } 58 | if (typeof opts === 'undefined') { 59 | opts = {}; 60 | } 61 | if (typeof replacements === 'undefined') { 62 | replacements = []; 63 | } 64 | var targetPath; 65 | if (!opts.inputSource) { 66 | try { 67 | var stats = fs.statSync(filePath); 68 | } catch (e) { 69 | throw new Error(filePath + ' does not exist!'); 70 | } 71 | targetPath = path.resolve(filePath); 72 | } else { 73 | targetPath = './' + crypto.createHash('md5').update(filePath).digest('hex') + '.js'; 74 | } 75 | if (opts.version && opts.package) { 76 | var packageObj = require(opts.package); 77 | if (opts.version !== packageObj.version) { 78 | throw new Error('Expected version ' + opts.version + ' but found verison ' + packageObj.version + ' for ' + filePath + '!'); 79 | } 80 | } 81 | if (!opts.dontReplaceRelativeRequires) { 82 | replacements.push({ 83 | find: /require\('.\//g, 84 | replace: 'require(\'' + path.resolve(filePath, '..') + '/' 85 | }); 86 | } 87 | var content; 88 | if (!opts.inputSource) { 89 | content = stripBOM(fs.readFileSync(targetPath, 'utf8')); 90 | } else { 91 | content = stripBOM(filePath); 92 | } 93 | if (opts.callback && typeof opts.callback === 'function') { 94 | content = opts.callback(content); 95 | } 96 | if (replacements.length) { 97 | replacements.forEach(function (obj) { 98 | if (obj.find && obj.replace) { 99 | if (obj.expect) { 100 | var count; 101 | if (typeof obj.find === 'string') { 102 | var lastIndex = 0; 103 | count = 0; 104 | while ((lastIndex = content.indexOf(obj.find, lastIndex) + 1) > 0) { 105 | count++; 106 | } 107 | } else if (obj.find instanceof RegExp) { 108 | if (!obj.find.global) { 109 | count = (content.match(addRegexpFlags(obj.find, 'g')) || []).length; 110 | } else { 111 | count = (content.match(obj.find) || []).length; 112 | } 113 | } 114 | if (count === obj.expect) { 115 | content = content.replace(obj.find, obj.replace); 116 | } else { 117 | throw new Error('Expected ' + obj.expect + ' but found ' + count + ' for "' + obj.find + '".'); 118 | } 119 | } else { 120 | content = content.replace(obj.find, obj.replace); 121 | } 122 | } 123 | }); 124 | } 125 | if (opts.returnAsString) { 126 | return content; 127 | } else { 128 | var targetModule = new Module(targetPath, module.parent); 129 | targetModule.filename = targetPath; 130 | targetModule.paths = Module._nodeModulePaths(path.dirname(targetPath)); 131 | var extension = opts.extension || path.extname(targetPath).toLowerCase() || '.js'; 132 | switch (extension) { 133 | case '.json': 134 | try { 135 | targetModule.exports = JSON.parse(content); 136 | } catch (err) { 137 | err.message = filePath + ': ' + err.message; 138 | throw err; 139 | } 140 | break; 141 | default: 142 | targetModule._compile(content, targetPath); 143 | break; 144 | } 145 | targetModule.loaded = true; 146 | return targetModule.exports; 147 | } 148 | } 149 | 150 | function addRegexpFlags (re, add) { 151 | var flags = ''; 152 | flags += (re.global) ? 'g' : ''; 153 | flags += (re.ignoreCase) ? 'i' : ''; 154 | flags += (re.multiline) ? 'm' : ''; 155 | flags += (re.sticky) ? 'y' : ''; 156 | flags += (re.unicode) ? 'u' : ''; 157 | add.toString().split('').forEach(function (i) { 158 | if (flags.indexOf(i) === -1) { 159 | flags += i; 160 | } 161 | }); 162 | return new RegExp(re.source, flags); 163 | } 164 | 165 | // @see https://github.com/joyent/node/blob/master/lib/module.js 166 | function stripBOM (content) { 167 | // Remove byte order marker. This catches EF BB BF (the UTF-8 BOM) 168 | // because the buffer-to-string conversion in `fs.readFileSync()` 169 | // translates it to FEFF, the UTF-16 BOM. 170 | if (content.charCodeAt(0) === 0xFEFF) { 171 | content = content.slice(1); 172 | } 173 | return content; 174 | } 175 | 176 | module.exports = patch; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "patch-module", 3 | "version": "0.1.0", 4 | "description": "Monkey patch npm modules.", 5 | "author": "Blake Kus ", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "./node_modules/mocha/bin/mocha ./test/test.js", 9 | "test-travis": "./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha -- -R spec ./test/test.js" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git://github.com/kus/patch-module.git" 14 | }, 15 | "keywords": [ 16 | "patch", 17 | "module", 18 | "monkey patch", 19 | "require" 20 | ], 21 | "license": "MIT", 22 | "homepage": "https://github.com/kus/patch-module", 23 | "bugs": { 24 | "url": "https://github.com/kus/patch-module/issues" 25 | }, 26 | "devDependencies": { 27 | "coveralls": "^2.12.0", 28 | "is-it-friday": "^0.1.0", 29 | "istanbul": "^0.4.5", 30 | "mocha": "^3.2.0", 31 | "should": "^11.2.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/is-it-friday.js: -------------------------------------------------------------------------------- 1 | var patch = require('../'); 2 | module.exports = patch('./node_modules/is-it-friday/index.js', { 3 | version: '0.1.0', 4 | package: './node_modules/is-it-friday/package.json' 5 | }, [ 6 | {find: '"Probably not..."', replace: '(new Date()).getDay() === 5 ? "Yes" : "No"', expect: 1} 7 | ]); -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var should = require('should'); 2 | var patch = require('../'); 3 | 4 | describe('Functionality', function () { 5 | 6 | describe('Patch 3rd party module: is-it-friday', function () { 7 | 8 | var isItFriday = require('is-it-friday'); 9 | 10 | it('should make an educated guess', function (done) { 11 | isItFriday.should.equal('Probably not...'); 12 | done(); 13 | }); 14 | 15 | var isItFridayPatched = patch('./node_modules/is-it-friday/index.js', { 16 | version: '0.1.0', 17 | package: './node_modules/is-it-friday/package.json' 18 | }, [ 19 | {find: '"Probably not..."', replace: '(new Date()).getDay() === 5 ? "Yes" : "No"', expect: 1} 20 | ]); 21 | 22 | it('should actually know when patched and work like a require', function (done) { 23 | isItFridayPatched.should.equal((new Date()).getDay() === 5 ? 'Yes' : 'No'); 24 | done(); 25 | }); 26 | 27 | var isItFridayPatchFile = require('./is-it-friday'); 28 | 29 | it('should actually know when patched and from a patch file', function (done) { 30 | isItFridayPatched.should.equal((new Date()).getDay() === 5 ? 'Yes' : 'No'); 31 | done(); 32 | }); 33 | 34 | }); 35 | 36 | describe('Patch JSON: package.json', function () { 37 | 38 | var patchedPackage = patch('./package.json', [ 39 | {find: 'Blake Kus ', replace: 'Blake Kus ', expect: 1} 40 | ]); 41 | 42 | it('should be able to patch JSON', function (done) { 43 | patchedPackage.author.should.equal('Blake Kus '); 44 | done(); 45 | }); 46 | 47 | }); 48 | 49 | }); 50 | 51 | describe('File path', function () { 52 | 53 | describe('Error handling', function () { 54 | 55 | it('should throw an error if not present', function (done) { 56 | (function(){ 57 | patch(); 58 | }).should.throw(); 59 | done(); 60 | }); 61 | 62 | it('should throw an error if not string', function (done) { 63 | (function(){ 64 | patch(1); 65 | }).should.throw(); 66 | done(); 67 | }); 68 | 69 | it('should throw an error if file doesn\'t exist', function (done) { 70 | (function(){ 71 | patch('does_not_exist.js'); 72 | }).should.throw(); 73 | done(); 74 | }); 75 | 76 | it('should strip out BOM from file', function (done) { 77 | patch(String.fromCodePoint(0xFEFF) + 'module.exports = "BOM";', { 78 | inputSource: true, 79 | returnAsString: true 80 | }, []).length.should.equal(23); 81 | done(); 82 | }); 83 | 84 | }); 85 | 86 | }); 87 | 88 | describe('Options', function () { 89 | 90 | describe('version', function () { 91 | 92 | it('should throw an error if different', function (done) { 93 | (function(){ 94 | patch('./node_modules/is-it-friday/index.js', { 95 | version: '0.2.0', 96 | package: './node_modules/is-it-friday/package.json' 97 | }, [ 98 | {find: '"Probably not..."', replace: '(new Date()).getDay() === 5 ? "Yes" : "No"', expect: 1} 99 | ]); 100 | }).should.throw(); 101 | done(); 102 | }); 103 | 104 | it('should not throw an error if the same', function (done) { 105 | (function(){ 106 | patch('./node_modules/is-it-friday/index.js', { 107 | version: '0.1.0', 108 | package: './node_modules/is-it-friday/package.json' 109 | }, [ 110 | {find: '"Probably not..."', replace: '(new Date()).getDay() === 5 ? "Yes" : "No"', expect: 1} 111 | ]); 112 | }).should.not.throw(); 113 | done(); 114 | }); 115 | 116 | }); 117 | 118 | describe('package', function () { 119 | 120 | it('should throw an error if file doesn\'t exist', function (done) { 121 | (function(){ 122 | patch('./node_modules/is-it-friday/index.js', { 123 | version: '0.1.0', 124 | package: './node_modules/is-it-friday/packages.json' 125 | }, [ 126 | {find: '"Probably not..."', replace: '(new Date()).getDay() === 5 ? "Yes" : "No"', expect: 1} 127 | ]); 128 | }).should.throw(); 129 | done(); 130 | }); 131 | 132 | }); 133 | 134 | describe('returnAsString', function () { 135 | 136 | it('should return as string if set', function (done) { 137 | (typeof patch('./node_modules/is-it-friday/index.js', { 138 | returnAsString: true 139 | }, [ 140 | {find: '"Probably not..."', replace: '(new Date()).getDay() === 5 ? "Yes" : "No"', expect: 1} 141 | ]) === 'string').should.equal(true); 142 | done(); 143 | }); 144 | 145 | }); 146 | 147 | describe('inputSource', function () { 148 | 149 | it('should return a valid module from input source instead of file', function (done) { 150 | patch(` 151 | module.exports = 'Works!'; 152 | `, { 153 | inputSource: true 154 | }, []).should.equal('Works!'); 155 | done(); 156 | }); 157 | 158 | }); 159 | 160 | describe('dontReplaceRelativeRequires', function () { 161 | 162 | it('should not replace relative paths if this option is set', function (done) { 163 | (patch(` 164 | var isItFriday = require('./is-it-friday.js'); 165 | module.exports = isItFriday; 166 | `, { 167 | inputSource: true, 168 | dontReplaceRelativeRequires: true, 169 | returnAsString: true 170 | }, []).indexOf('require(\'./is-it-friday.js\')') > -1).should.equal(true); 171 | done(); 172 | }); 173 | 174 | }); 175 | 176 | describe('extension', function () { 177 | 178 | it('should overwrite extension', function (done) { 179 | (function(){ 180 | patch('./node_modules/is-it-friday/index.js', { 181 | extension: '.json' 182 | }, [ 183 | {find: '"Probably not..."', replace: '(new Date()).getDay() === 5 ? "Yes" : "No"', expect: 1} 184 | ]); 185 | }).should.throw(); 186 | done(); 187 | }); 188 | 189 | }); 190 | 191 | }); 192 | 193 | describe('Replacements', function () { 194 | 195 | describe('RegExp', function () { 196 | 197 | it('should add global flag when checking for count', function (done) { 198 | patch('./node_modules/is-it-friday/index.js', { 199 | version: '0.1.0', 200 | package: './node_modules/is-it-friday/package.json' 201 | }, [ 202 | {find: /\.{3}/, replace: '!', expect: 1} 203 | ]).should.equal('Probably not!'); 204 | done(); 205 | }); 206 | 207 | it('should leave global flag as is if exists when checking for count', function (done) { 208 | patch('./node_modules/is-it-friday/index.js', { 209 | version: '0.1.0', 210 | package: './node_modules/is-it-friday/package.json' 211 | }, [ 212 | {find: /\.{3}/g, replace: '!', expect: 1} 213 | ]).should.equal('Probably not!'); 214 | done(); 215 | }); 216 | 217 | }); 218 | 219 | describe('Expect', function () { 220 | 221 | it('should throw if found different amount to expect', function (done) { 222 | (function(){ 223 | patch('./node_modules/is-it-friday/index.js', [ 224 | {find: '.', replace: '!', expect: 1} 225 | ]); 226 | }).should.throw(); 227 | done(); 228 | }); 229 | 230 | }); 231 | 232 | }); 233 | 234 | 235 | describe('Callback', function () { 236 | 237 | describe('Options param', function () { 238 | 239 | it('should take function in options param', function (done) { 240 | patch('./node_modules/is-it-friday/index.js', function (str) {return 'module.exports = "Hello World!"';}).should.equal('Hello World!'); 241 | done(); 242 | }); 243 | 244 | }); 245 | 246 | describe('Replacements param', function () { 247 | 248 | it('should take function in replacements param', function (done) { 249 | patch('./node_modules/is-it-friday/index.js', {}, function (str) {return 'module.exports = "Hello World!"';}).should.equal('Hello World!'); 250 | done(); 251 | }); 252 | 253 | }); 254 | 255 | }); --------------------------------------------------------------------------------