UNPKG

4.54 kBJavaScriptView Raw
1/*
2 Copyright (c) 2014 Google Inc. All rights reserved.
3 Copyright (c) 2012-2013 Johannes Ewald.
4
5 Use of this source code is governed by the MIT License, available in this package's LICENSE file
6 or at http://opensource.org/licenses/MIT.
7 */
8'use strict';
9
10var _ = require('underscore');
11var path = require('path');
12var Module = require('module');
13
14var originalWrapper = Module.wrapper.slice(0);
15
16function wrap(wrappers, script) {
17 return wrappers[0] + script + wrappers[1];
18}
19
20function replaceWrapper(wrapperObj) {
21 var joiner = '\n';
22 var before = wrapperObj.before.join(joiner);
23 var after = wrapperObj.after.join(joiner);
24 var wrappers = [
25 originalWrapper[0] + before,
26 after + originalWrapper[1]
27 ];
28
29 Module.wrap = wrap.bind(null, wrappers);
30}
31
32function restoreWrapper() {
33 Module.wrap = wrap.bind(null, originalWrapper);
34}
35
36function createModule(targetPath, parentModule, moduleCache) {
37 moduleCache[targetPath] = moduleCache[targetPath] || new Module(targetPath, parentModule);
38
39 return moduleCache[targetPath];
40}
41
42/**
43 * Wrapper for `require()` to prevent the target module's dependencies from being swizzled.
44 *
45 * @param {!Module} targetModule - The module that is being swizzled.
46 * @param {!function} nodeRequire - The original `require()` method for the target module.
47 * @param {!string} filepath - The value passed to `require()`.
48 * @return {!Module} The requested module dependency.
49 */
50function requireProxy(targetModule, nodeRequire, filepath) {
51 restoreWrapper();
52 targetModule.require = nodeRequire;
53
54 return nodeRequire.call(targetModule, filepath);
55}
56
57/**
58 * Wrapper for `require()` to swizzle the target module's dependencies, using the same settings as
59 * the target module.
60 *
61 * @param {!Module} targetModule - The module that is being swizzled.
62 * @param {!Object} opts - The Requizzle options object.
63 * @param {!string} filepath - The value passed to `require()`.
64 * @return {!Module} The requested module dependency.
65 */
66function infectProxy(targetModule, cache, opts, filepath) {
67 var moduleExports;
68 var Requizzle = require('./requizzle');
69 var requizzle;
70
71 opts = _.clone(opts);
72 opts.parent = targetModule;
73 requizzle = new Requizzle(opts, cache);
74
75 moduleExports = requizzle.requizzle(filepath);
76
77 return moduleExports;
78}
79
80var load = exports.load = function load(targetPath, parentModule, wrapper, cache, options) {
81 var nodeRequire;
82 var targetModule;
83
84 // Handle circular requires, and avoid reloading modules unnecessarily
85 if (cache.module[targetPath]) {
86 return cache.module[targetPath];
87 }
88
89 targetModule = createModule(targetPath, parentModule, cache.module);
90 nodeRequire = targetModule.require;
91
92 if (options.infect) {
93 targetModule.require = function(filepath) {
94 return infectProxy(targetModule, cache, options, filepath);
95 };
96 } else {
97 targetModule.require = function(filepath) {
98 return requireProxy(targetModule, nodeRequire, filepath);
99 };
100 }
101
102 // update the wrapper before we load the target module
103 replaceWrapper(wrapper);
104
105 targetModule.load(targetModule.id);
106
107 // make sure the wrapper is restored even if the target module doesn't load any dependencies
108 restoreWrapper();
109
110 return targetModule;
111};
112
113/**
114 * Check whether the entire module includes a `'use strict'` declaration.
115 *
116 * @param {string} src - The source file to check.
117 * @return {boolean} Set to `true` if the module includes a `use strict` declaration.
118 */
119function detectStrictMode(src) {
120 return (/^\s*(?:["']use strict["'])[ \t]*(?:[\r\n]|;)/g).test(src);
121}
122
123function loadSource(targetPath, sourceCache) {
124 var fs = require('fs');
125
126 if (sourceCache[targetPath] === undefined) {
127 sourceCache[targetPath] = fs.readFileSync(targetPath, 'utf8');
128 }
129
130 return sourceCache[targetPath];
131}
132
133exports.createWrapper = function createWrapper(targetPath, parentModule, cache, options) {
134 var src;
135 var wrapperObject = {
136 before: [],
137 after: []
138 };
139
140 function add(wrapperFunctions, opts) {
141 var params = [targetPath, parentModule, opts];
142
143 ['before', 'after'].forEach(function(item) {
144 var result = wrapperFunctions[item].apply(null, params);
145
146 if (result) {
147 wrapperObject[item].push(result);
148 }
149 });
150 }
151
152 // Preserve the module's `use strict` declaration if present
153 src = loadSource(targetPath, cache.source);
154 if (detectStrictMode(src) === true) {
155 add(require('./wrappers/strict'));
156 }
157
158 if (options.requirePaths) {
159 add(require('./wrappers/requirepaths'), options.requirePaths);
160 }
161
162 if (options.extras) {
163 add(require('./wrappers/extras'), options.extras);
164 }
165
166 return wrapperObject;
167};