1 | # require-hacker
|
2 |
|
3 | [![NPM Version][npm-image]][npm-url]
|
4 | [![NPM Downloads][downloads-image]][downloads-url]
|
5 | [![Build Status][travis-image]][travis-url]
|
6 | [![Test Coverage][coveralls-image]][coveralls-url]
|
7 |
|
8 |
|
9 | [![Gratipay][gratipay-image]][gratipay-url]
|
10 | -->
|
11 |
|
12 | Is a small helper module providing tools for instrumenting Node.js `require()` calls.
|
13 |
|
14 | ## Topics
|
15 |
|
16 | - [What it does and why is it needed?](#what-it-does-and-why-is-it-needed)
|
17 | - [Installation](#installation)
|
18 | - [Usage](#usage)
|
19 | - [Configuration](#configuration)
|
20 | - [API](#api)
|
21 | - [Gotchas](#gotchas)
|
22 | - [References](#references)
|
23 | - [Contributing](#contributing)
|
24 |
|
25 | ## What it does and why is it needed?
|
26 |
|
27 | Standard Node.js `require()` calls simply loaded javascript files from disk and evaluated them.
|
28 |
|
29 | 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").
|
30 |
|
31 | 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.
|
32 |
|
33 | ## Installation
|
34 |
|
35 | ```bash
|
36 | $ npm install require-hacker --save
|
37 | ```
|
38 |
|
39 | ## Usage
|
40 |
|
41 | Something basic
|
42 |
|
43 | ```javascript
|
44 | import Require_hacker from 'require-hacker'
|
45 | import fs from 'fs'
|
46 |
|
47 | const require_hacker = new Require_hacker({ debug: false })
|
48 |
|
49 | // mount require() hook
|
50 | const hook = require_hacker.hook('txt', path =>
|
51 | {
|
52 | return `module.exports = "${fs.readFileSync(path).replace(/"/g, '\"')}"`
|
53 | })
|
54 |
|
55 | // will output text file contents
|
56 | console.log(require('./test.txt'))
|
57 |
|
58 | // unmount require() hook
|
59 | hook.unmount()
|
60 |
|
61 | // will throw "SyntaxError: Unexpected token ILLEGAL"
|
62 | require('./test without hook.txt')
|
63 | ```
|
64 |
|
65 | Something unusual
|
66 |
|
67 | ```javascript
|
68 | const hook = require_hacker.global_hook('network', path =>
|
69 | {
|
70 | if (!path.starts_with('http://xhamster.com'))
|
71 | {
|
72 | return
|
73 | }
|
74 |
|
75 | // returns javascript module source code, something like:
|
76 | //
|
77 | // "module.exports =
|
78 | // {
|
79 | // category : 'redhead',
|
80 | // videos : [12345, 12346, 12347],
|
81 | // unsubscribe: function()
|
82 | // {
|
83 | // http.post('http://xhamster.com/unsubscribe', { user: 123 })
|
84 | // }
|
85 | // }"
|
86 | //
|
87 | return synchronous_http.get(path)
|
88 | })
|
89 |
|
90 | const readheads = require('http://xhamster.com/category/redhead')
|
91 | readheads.unsubscribe()
|
92 | ```
|
93 |
|
94 | Or
|
95 |
|
96 | ```javascript
|
97 | const hook = require_hacker.global_hook('database', path =>
|
98 | {
|
99 | if (!path.starts_with('postgresql://'))
|
100 | {
|
101 | return
|
102 | }
|
103 |
|
104 | // returns javascript module source code, something like:
|
105 | //
|
106 | // "module.exports =
|
107 | // {
|
108 | // words: ['a', 'b', 'c']
|
109 | // sum: function()
|
110 | // {
|
111 | // return words.join('')
|
112 | // }
|
113 | // }"
|
114 | //
|
115 | const schema = path.substring(0, 'postgresql://'.length)
|
116 | return pg.sql(`select * from ${schema}.generate_javascript()`)
|
117 | })
|
118 |
|
119 | const summator = require('postgresql://summator')
|
120 | console.log(summator.sum())
|
121 | ```
|
122 |
|
123 | And don't ask me what for.
|
124 |
|
125 | ## Configuration
|
126 |
|
127 | Available configuration parameters:
|
128 |
|
129 | ```javascript
|
130 | {
|
131 | // debug mode.
|
132 | // when set to true, lets you see debugging messages in the console.
|
133 | debug: true // is false by default
|
134 | }
|
135 | ```
|
136 |
|
137 | ## API
|
138 |
|
139 | #### Constructor
|
140 |
|
141 | Takes an object with options (see [Configuration](#configuration) section above)
|
142 |
|
143 | #### .hook(file_extension, resolve)
|
144 |
|
145 | Will intercept all `require()` calls for paths with this `file_extension` and reroute them to the `resolve` function.
|
146 |
|
147 | Returns an object with `.unmount()` method which unmounts this `require()` hook from the system.
|
148 |
|
149 | The `resolve` function takes one parameter: the `path` which is `require()`d.
|
150 |
|
151 | The `resolve` function must return either a valid CommonJS javascript module source code or it can simply `return` nothing and in that case it will skip this hook.
|
152 |
|
153 | #### .global_hook(meaningful_id, resolve, [options])
|
154 |
|
155 | Can intercept all `require()` calls. The behaviour is controlled by `precede_node_loader` option:
|
156 |
|
157 | * when it's `false` (default) it will intercept only those `require()` calls which failed to be resolved by the original Node.js `require()` loader
|
158 | * when it's `true` it will intercept all `require()` calls before they are passed to the original Node.js `require()` loader
|
159 |
|
160 | Returns an object with `.unmount()` method which unmounts this `require()` hook from the system.
|
161 |
|
162 | The `resolve` function takes one parameter: the `path` which is `require()`d.
|
163 |
|
164 | The `resolve` function must return either a valid CommonJS javascript module source code or it can simply `return` nothing and in that case it will skip this resolver.
|
165 |
|
166 | #### (static) .to_javascript_module_source(anything)
|
167 |
|
168 | Converts anyting (an undefined, a string, a JSON object, a function, a regular expression - anything) to a valid CommonJS javascript module source code.
|
169 |
|
170 | ## Gotchas
|
171 |
|
172 | None whatsoever
|
173 |
|
174 | ## References
|
175 |
|
176 | There are various articles on this sort of `require()` hook trickery on the internets.
|
177 |
|
178 | [How require() actually works](http://thenodeway.io/posts/how-require-actually-works/)
|
179 |
|
180 | [Hooking into Node loader for fun and profit](http://glebbahmutov.com/blog/hooking-into-node-loader-for-fun-and-profit/)
|
181 |
|
182 | ## Contributing
|
183 |
|
184 | After cloning this repo, ensure dependencies are installed by running:
|
185 |
|
186 | ```sh
|
187 | npm install
|
188 | ```
|
189 |
|
190 | This module is written in ES6 and uses [Babel](http://babeljs.io/) for ES5
|
191 | transpilation. Widely consumable JavaScript can be produced by running:
|
192 |
|
193 | ```sh
|
194 | npm run build
|
195 | ```
|
196 |
|
197 | Once `npm run build` has run, you may `import` or `require()` directly from
|
198 | node.
|
199 |
|
200 | After developing, the full test suite can be evaluated by running:
|
201 |
|
202 | ```sh
|
203 | npm test
|
204 | ```
|
205 |
|
206 | While actively developing, one can use (personally I don't use it)
|
207 |
|
208 | ```sh
|
209 | npm run watch
|
210 | ```
|
211 |
|
212 | in a terminal. This will watch the file system and run tests automatically
|
213 | whenever you save a js file.
|
214 |
|
215 | When you're ready to test your new functionality on a real project, you can run
|
216 |
|
217 | ```sh
|
218 | npm run tryout
|
219 | ```
|
220 |
|
221 | It will `build`, `test` and then create a `.tar.gz` archive which you can then install in your project folder
|
222 |
|
223 | ```sh
|
224 | npm install [module name with version].tar.gz
|
225 | ```
|
226 |
|
227 | ## License
|
228 |
|
229 | [MIT](LICENSE)
|
230 | [npm-image]: https://img.shields.io/npm/v/require-hacker.svg
|
231 | [npm-url]: https://npmjs.org/package/require-hacker
|
232 | [travis-image]: https://img.shields.io/travis/halt-hammerzeit/require-hacker/master.svg
|
233 | [travis-url]: https://travis-ci.org/halt-hammerzeit/require-hacker
|
234 | [downloads-image]: https://img.shields.io/npm/dm/require-hacker.svg
|
235 | [downloads-url]: https://npmjs.org/package/require-hacker
|
236 | [coveralls-image]: https://img.shields.io/coveralls/halt-hammerzeit/require-hacker/master.svg
|
237 | [coveralls-url]: https://coveralls.io/r/halt-hammerzeit/require-hacker?branch=master
|
238 |
|
239 |
|
240 | [gratipay-image]: https://img.shields.io/gratipay/dougwilson.svg
|
241 | [gratipay-url]: https://gratipay.com/dougwilson/
|
242 | --> |
\ | No newline at end of file |