Skip to content

Commit 9b8c87c

Browse files
committed
Native modules are no longer included in outputFile
Callback now includes `nativeModules` Array, which includes paths to native modules that were detected (but not included) while scanning the project Added `includeNodeModules` option to allow any code in node_modules to be included in the project Resulting `outputFile` has some line comments removed Fixed up some regex to scan for `require(...)` expressions Added support for `module.parent` Updated README documentation Push to 1.4.0
1 parent b78c46b commit 9b8c87c

File tree

4 files changed

+83
-25
lines changed

4 files changed

+83
-25
lines changed

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,12 @@ modConcat("./project/index.js", outputFile, function(err, files) {
4040

4141
Note: These `require` statements should probably be wrapped in a
4242
try, catch block to prevent uncaught exceptions.
43-
- `cb` - Callback of the form `cb(err, files)` where `files` is an Array
44-
of files that have been included in the project.
43+
- `includeNodeModules` - Set to `true` if node_modules should also be
44+
included in the project.
45+
- `cb` - Callback of the form `cb(err, files, nativeModules)` where `files` is
46+
an Array of files that have been included in the project and
47+
`nativeModules` is an Array of native modules that were found (but not
48+
included) when scanning the project.
4549

4650
## Known limitations
4751
- Dynamic `require()` statements don't work

index.js

Lines changed: 71 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ var header = fs.readFileSync(__dirname + "/lib/header.js").toString("utf8")
7878
7979
Note: These `require` statements should probably be wrapped in a
8080
try, catch block to prevent uncaught exceptions.
81+
- `includeNodeModules` - Set to `true` if node_modules should be
82+
included in the `outputFile`
8183
- `cb` - Callback of the form `cb(err, files)` where `files` is an Array
8284
of files that have been included in the project.
8385
*/
@@ -94,8 +96,22 @@ module.exports = function concat(entryModule, outputFile, opts, cb) {
9496
opts.excludeFiles[i] = path.resolve(opts.excludeFiles[i]);
9597
}
9698
}
99+
// Ensure that `includeNodeModules` will work properly
100+
var _nodeModulePaths;
101+
if(opts.includeNodeModules) {
102+
try {
103+
_nodeModulePaths = require("module")._nodeModulePaths;
104+
if(typeof _nodeModulePaths !== "function") {
105+
opts.includeNodeModules = false;
106+
}
107+
} catch(err) {
108+
opts.includeNodeModules = false;
109+
}
110+
}
97111
// A list of all of the files read and included in the output thus far
98112
var files = [];
113+
// A list of all of the native modules not included in the output thus far
114+
var nativeModules = [];
99115
// The file descriptor pointing to the `outputFile`
100116
var fd;
101117

@@ -119,10 +135,10 @@ module.exports = function concat(entryModule, outputFile, opts, cb) {
119135
}).once("done", function(err) {
120136
if(fd) {
121137
fs.close(fd, function(closeErr) {
122-
cb(err || closeErr, files);
138+
cb(err || closeErr, files, nativeModules);
123139
});
124140
} else {
125-
cb(err, files);
141+
cb(err, files, nativeModules);
126142
}
127143
});
128144

@@ -147,48 +163,83 @@ module.exports = function concat(entryModule, outputFile, opts, cb) {
147163
// Read file
148164
fs.readFile(filePath, {"encoding": "utf8"}, this);
149165
}, function processFile(code) {
166+
// Remove some line comments from code
167+
code = code.replace(/(?:\r\n?|\n)\s*\/\/.*/g, "");
150168
// Scan file for `require(...)`, `__dirname`, and `__filename`
151169
/* Quick notes about the somewhat intense `requireRegex`:
152170
- require('...') and require("...") is matched
153171
- The single or double quote matched is group 1
154172
- Whitespace can go anywhere
155173
- The module path matched is group 2
156-
- Backslashes in the module path are escaped (i.e. for Windows paths)
174+
- Backslashes are allowed as escape characters only if followed
175+
by another backlash (to support Windows paths)
157176
*/
158-
var requireRegex = /require\s*\(\s*(["'])((?:(?=(\\?))\3.)*)\1\s*\)/g,
177+
var requireRegex = /require\s*\(\s*(["'])((?:(?:(?!\1)[^\\]|(?:\\\\)))*)\1\s*\)/g,
159178
dirnameRegex = /__dirname/g,
160179
filenameRegex = /__filename/g;
161180
code = code.replace(requireRegex, function(match, quote, modulePath) {
181+
// First thing is to replace "\\" with "\"
182+
modulePath = modulePath.replace("\\\\", "\\");
162183
// Check to see if this require path begins with "./" or "../" or "/"
163184
if(modulePath.match(/^\.?\.?\//) !== null) {
164185
try {
165186
modulePath = require.resolve(path.resolve(
166187
path.join(path.dirname(filePath), modulePath)
167188
) );
168-
// Lookup this module's ID
169-
var index = files.indexOf(modulePath);
170-
if(index < 0) {
171-
// Not found; add this module to the project
172-
if(!opts.excludeFiles ||
173-
opts.excludeFiles.indexOf(modulePath) < 0)
174-
{
175-
index = files.push(modulePath) - 1;
176-
}
177-
else {
178-
// Ignore; do not replace
179-
return match;
180-
}
181-
}
182-
// Replace the `require` statement with `__require`
183-
return "__require(" + index + ")";
189+
// Include module in project at end of this function
184190
} catch(e) {
185191
// Ignore; do not replace
186192
return match;
187193
}
194+
} else if(opts.includeNodeModules) {
195+
var oldPaths = module.paths;
196+
/* Temporarily overwrite `module.paths` to make
197+
`require.resolve` work properly */
198+
module.paths = _nodeModulePaths(path.dirname(filePath) );
199+
try {
200+
var modulePath = require.resolve(modulePath);
201+
} catch(err) {
202+
// Module not found; do not replace
203+
return match;
204+
} finally {
205+
// Restore old `module.paths`
206+
module.paths = oldPaths;
207+
}
208+
// Detect core module
209+
if(modulePath.match(/^[a-z_]+$/) ) {
210+
// Core module; do not replace
211+
return match;
212+
}
213+
// Include module in project at end of this function
188214
} else {
189215
// Ignore; do not replace
190216
return match;
191217
}
218+
/* If we reached this point, we need to include `modulePath`
219+
in our project */
220+
// If this is a native module, abort
221+
if(path.extname(modulePath).toLowerCase() === ".node") {
222+
// This is a native module; do not replace
223+
nativeModules.push(modulePath);
224+
return match;
225+
}
226+
// Lookup this module's ID
227+
var index = files.indexOf(modulePath);
228+
if(index < 0) {
229+
// Not found; add this module to the project
230+
if(!opts.excludeFiles ||
231+
opts.excludeFiles.indexOf(modulePath) < 0)
232+
{
233+
index = files.push(modulePath) - 1;
234+
}
235+
else {
236+
// Ignore; do not replace
237+
return match;
238+
}
239+
}
240+
// Replace the `require` statement with `__require`
241+
var parentIndex = files.indexOf(filePath);
242+
return "__require(" + index + "," + parentIndex + ")";
192243
})
193244
// Replace `__dirname` with `__getDirname(...)`
194245
.replace(dirnameRegex, "__getDirname(" +

lib/header.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ var __modules = {},
1212
__moduleIsCached = {};
1313
/* If the module with the specified `uid` is cached, return it;
1414
otherwise, execute and cache it first. */
15-
function __require(uid) {
15+
function __require(uid, parentUid) {
1616
if(!__moduleIsCached[uid]) {
1717
// Populate the cache initially with an empty `exports` Object
1818
__modulesCache[uid] = {"exports": {}, "loaded": false};
1919
__moduleIsCached[uid] = true;
2020
if(uid === 0) {
21-
require.main = __modulesCache[uid];
21+
require.main = __modulesCache[0];
22+
} else {
23+
__modulesCache[uid].parent = __modulesCache[parentUid];
2224
}
2325
/* Note: if this module requires itself, or if its depenedencies
2426
require it, they will only see an empty Object for now */

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "node-module-concat",
3-
"version": "1.3.0",
3+
"version": "1.4.0",
44
"description": "Node.js module concatenation library",
55
"main": "index.js",
66
"dependencies": {
@@ -19,6 +19,7 @@
1919
"module",
2020
"concatenate",
2121
"obfuscation",
22+
"obfuscate",
2223
"require"
2324
],
2425
"author": "Blake Miner <miner.blake@gmail.com>",

0 commit comments

Comments
 (0)