https://github.com/catamphetamine/require-hacker
Provides a hooking mechanism for Node.js require() calls
https://github.com/catamphetamine/require-hacker
Last synced: about 1 month ago
JSON representation
Provides a hooking mechanism for Node.js require() calls
- Host: GitHub
- URL: https://github.com/catamphetamine/require-hacker
- Owner: catamphetamine
- License: mit
- Created: 2015-11-01T15:01:17.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2022-01-13T00:47:33.000Z (over 3 years ago)
- Last Synced: 2025-04-13T14:51:13.227Z (about 2 months ago)
- Language: JavaScript
- Size: 48.8 KB
- Stars: 62
- Watchers: 2
- Forks: 4
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Changelog: HISTORY.md
- License: LICENSE
Awesome Lists containing this project
README
# require-hacker
[](https://www.npmjs.com/package/require-hacker)
[](https://www.npmjs.com/package/require-hacker)
[](https://travis-ci.org/catamphetamine/require-hacker)
[](https://coveralls.io/r/catamphetamine/require-hacker?branch=master)Is a small helper module providing tools for instrumenting Node.js `require()` calls.
## Topics
- [What it does and why is it needed?](#what-it-does-and-why-is-it-needed)
- [Installation](#installation)
- [Usage](#usage)
- [Configuration](#configuration)
- [API](#api)
- [Gotchas](#gotchas)
- [References](#references)
- [Contributing](#contributing)## What it does and why is it needed?
Standard Node.js `require()` calls simply loaded javascript files from disk and evaluated them.
Some time after various hackers hacked the [Module module](https://github.com/nodejs/node/blob/master/lib/module.js) and various solutions emerged such as `coffee-script/register` and `babel-core/register` allowing everyone to `require()` code written in any language out there (coffeescript and ES7 in case of the aforementioned "require hooks").
This module provides a tool to perform such tricks along with a possibility to also intercept `require()` calls not just for specific file extensions but for an arbitrary abstract path. Consider, for example, `require("http://thor.onion/module?user=123")` or `require("春秋左傳·僖公二十二年")`, whatever. Who might need this? You never know.
## Installation
```bash
$ npm install require-hacker --save
```## Usage
Something basic
```javascript
import require_hacker from 'require-hacker'
import fs from 'fs'// mount require() hook
const hook = require_hacker.hook('txt', path =>
{
return `module.exports = "${fs.readFileSync(path).replace(/"/g, '\"')}"`
})// will output text file contents
console.log(require('./test.txt'))// unmount require() hook
hook.unmount()// will throw "SyntaxError: Unexpected token ILLEGAL"
require('./test without hook.txt')
```Something unusual
```javascript
const hook = require_hacker.global_hook('network', path =>
{
if (!path.starts_with('http://thor.onion/module'))
{
return
}// returns javascript module source code, something like:
//
// "module.exports =
// {
// category : 'module.js',
// versions : ['1.0.0', '1.0.1'],
// unsubscribe: function()
// {
// http.post('http://thor.onion/module/unsubscribe', { id: 123 })
// }
// }"
//
const source = synchronous_http.get(path)
return { source, path }
})const dependency = require('http://thor.onion/module/third-party-dependency')
dependency.unsubscribe()
```Or
```javascript
const hook = require_hacker.global_hook('database', path =>
{
if (!path.starts_with('postgresql://'))
{
return
}// returns javascript module source code, something like:
//
// "module.exports =
// {
// words: ['a', 'b', 'c']
// sum: function()
// {
// return words.join('')
// }
// }"
//
const schema = path.substring(0, 'postgresql://'.length)
const source pg.sql(`select * from ${schema}.generate_javascript()`)
return { source, path }
})const summator = require('postgresql://summator')
console.log(summator.sum())
```And don't ask me what for.
## Configuration
To see debug logs in the console one can use this code
```javascript
require_hacker.log.options.debug = true
```## API
#### .hook(file_extension, resolve)
Will intercept all `require()` calls for paths with this `file_extension` and reroute them to the `resolve` function. The `require()`d path must exist in the filesystem, otherwise an exception will be thrown: `Cannot find module`.
Returns an object with `.unmount()` method which unmounts this `require()` hook from the system.
The `resolve` function takes two parameters:
* the `path` which is `require()`d
* the `module` in which the `require()` call was originated (this `module` parameter can be used for `require_hacker.resolve(path, module)` function call)The `resolve` function must return either a valid CommonJS javascript module source code (i.e. "module.exports = ...", etc) or it can simply `return` nothing and in that case it will skip this hook.
#### .global_hook(meaningful_id, resolve, [options])
Can intercept all `require()` calls. The behaviour is controlled by `precede_node_loader` option:
* when it's `true` (default) it will intercept all `require()` calls before they are passed to the original Node.js `require()` loader
* when it's `false` it will intercept only those `require()` calls which failed to be resolved by the original Node.js `require()` loaderReturns an object with `.unmount()` method which unmounts this `require()` hook from the system.
The `resolve` function takes two parameters:
* the `path` which is `require()`d (e.g. a relative one)
* the `module` in which the `require()` call was originated (this `module` parameter can be used for `require_hacker.resolve(path, module)` function call)The `resolve` function must return either `undefined` (in which case it will skip this hook and proceed as normal) or an object `{ source, path }` where
* `source` is a valid CommonJS javascript module source code (i.e. "module.exports = ...", etc)
* `path` is the absolute path of the `path` argument passed to this `require()` function (which could be relative). This returned `path` is only gonna matter if `require()`ing some other relative path from the `source` being returned (because it would get resolved against this absolute `path`).#### .resolver(resolve)
Can intercept all `require(path)` calls and tamper with the `path` modifying it if needed (this process is called "resolving").
Returns an object with `.unmount()` method which unmounts this interceptor.
The `resolve` function takes two parameters:
* the `path` which is `require()`d.
* the `module` in which the `require()` call was originated (this `module` parameter can be used for `require_hacker.resolve(path, module)` function call)The `resolve` function must either return a real filesystem path to a javascript (or json) file or it can simply `return` nothing and in that case it will take no effect.
#### .to_javascript_module_source(anything)
Converts anyting (an undefined, a string, a JSON object, a function, a regular expression - anything) to a valid CommonJS javascript module source code.
#### .resolve(path, module)
Resolves a requireable `path` to a real filesystem path to a javascript (or json) file. Resolution is performed relative to the `module` (javascript file) passed as the second parameter (resolves `npm link`, global `node_modules`, etc). It's just an alias to the native Node.js path resolution function. Will throw `Error: Cannot find module '...'` if the `path` isn't resolved to an existing javascript (or json) file.
## Gotchas
None whatsoever
## References
There are various articles on this sort of `require()` hook trickery on the internets.
[How require() actually works](http://thenodeway.io/posts/how-require-actually-works/)
[Hooking into Node loader for fun and profit](http://glebbahmutov.com/blog/hooking-into-node-loader-for-fun-and-profit/)
## Contributing
After cloning this repo, ensure dependencies are installed by running:
```sh
npm install
```This module is written in ES6 and uses [Babel](http://babeljs.io/) for ES5
transpilation. Widely consumable JavaScript can be produced by running:```sh
npm run build
```Once `npm run build` has run, you may `import` or `require()` directly from
node.After developing, the full test suite can be evaluated by running:
```sh
npm test
```When you're ready to test your new functionality on a real project, you can run
```sh
npm pack
```It will `build`, `test` and then create a `.tgz` archive which you can then install in your project folder
```sh
npm install [module name with version].tar.gz
```## License
[MIT](LICENSE)