├── .npmrc ├── .travis.yml ├── LICENSE ├── bench ├── index.js └── input.js ├── example ├── brfs.js ├── brfs │ ├── source.js │ └── x.txt ├── fs.js └── fs │ ├── source.js │ └── x.txt ├── index.js ├── package.json ├── readme.markdown ├── security.md └── test ├── assign.js ├── assign ├── comma.js └── source.js ├── brfs.js ├── brfs ├── attribute.js ├── attribute_brackets.js ├── attribute_vars.js ├── brackets.js ├── empty.js ├── multi_require.js ├── multi_require_with_uninitialized.js ├── source.js ├── x.txt └── x5.js ├── fn.js ├── fn └── source.js ├── fs.js ├── fs ├── html.js ├── readfile.js ├── robot.html └── x.txt ├── fs_twice.js ├── fs_twice ├── 4x.js ├── html.js ├── readfile.js ├── robot.html ├── vars.js └── x.txt ├── inline.js ├── inline ├── fn.js ├── fn_call.js ├── fn_expr.js ├── obj.js ├── obj_call.js └── obj_expr.js ├── keep-used.js ├── keep-used ├── fs.js └── source.js ├── limit-parsing.js ├── log.js ├── log └── source.js ├── many.js ├── many ├── a.txt ├── all_inline.js ├── b.txt ├── c.txt ├── inline.js └── source.js ├── mixed.js ├── mixed ├── source.js ├── unmixed.js └── xyz.txt ├── nested.js ├── nested └── source.js ├── obj.js ├── obj └── source.js ├── prop.js ├── prop └── source.js ├── readfile_resolve.js ├── readfile_resolve ├── main.js └── node_modules │ └── aaa │ └── wow.txt ├── scope.js ├── scope ├── block.js └── source.js ├── shebang.js ├── shebang └── source.js ├── sourcemap.js ├── sourcemap └── main.js ├── unary.js ├── unary ├── supported.js └── unsupported.js ├── varmod.js ├── varmod ├── source.js └── vars.html ├── vars.js └── vars ├── five.js ├── multi-require.js ├── one.js ├── source.js └── vars.html /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "13" 4 | - "12" 5 | - "10" 6 | - "8" 7 | - "6" 8 | - "4" 9 | - "0.12" 10 | - "0.10" 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2014 James Halliday 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /bench/index.js: -------------------------------------------------------------------------------- 1 | var bench = require('nanobench'); 2 | var fs = require('fs'); 3 | var path = require('path'); 4 | var through = require('through2'); 5 | 6 | bench('small file × 5', function (b) { 7 | warmup(run, function () { 8 | b.start(); 9 | 10 | var i = 5; 11 | run(function next () { 12 | if (--i === 0) b.end(); 13 | else run(next); 14 | }); 15 | }); 16 | 17 | function run (cb) { 18 | smallFile() 19 | .pipe(brfs()) 20 | .on('data', function () {}) 21 | .on('end', function () { 22 | cb(); 23 | }); 24 | } 25 | }); 26 | 27 | bench('large file without fs', function (b) { 28 | warmup(run, function () { 29 | b.start(); 30 | 31 | var i = 5; 32 | run(function next () { 33 | if (--i === 0) b.end(); 34 | else run(next); 35 | }); 36 | }); 37 | 38 | function run (cb) { 39 | largeFile() 40 | .pipe(brfs()) 41 | .on('data', function () {}) 42 | .on('end', function () { 43 | b.end(); 44 | }); 45 | } 46 | }); 47 | 48 | bench('large file with fs', function (b) { 49 | warmup(run, function () { 50 | b.start(); 51 | 52 | var i = 5; 53 | run(function next () { 54 | if (--i === 0) b.end(); 55 | else run(next); 56 | }); 57 | }); 58 | 59 | function run (cb) { 60 | largeFile() 61 | .pipe(withFS()) 62 | .pipe(brfs()) 63 | .on('data', function () {}) 64 | .on('end', function () { 65 | b.end(); 66 | }); 67 | } 68 | }); 69 | 70 | function brfs () { 71 | return require('../')({ 72 | fs: { 73 | readFileSync: function (path) { 74 | return path; 75 | } 76 | } 77 | }); 78 | } 79 | 80 | function smallFile () { 81 | var r = through(); 82 | r.end('var a, fs = require("fs"), x; fs.readFileSync("index.js");'); 83 | return r; 84 | } 85 | function largeFile () { 86 | return fs.createReadStream(path.join(__dirname, './input.js')); 87 | } 88 | function withFS () { 89 | return through(function (chunk, enc, next) { 90 | next(null, chunk); 91 | }, function (next) { 92 | this.push('\nvar a, fs = require("fs"), x; fs.readFileSync("index.js");'); 93 | next(); 94 | }); 95 | } 96 | 97 | function warmup (run, cb) { 98 | var i = 5; 99 | run(function next () { 100 | if (--i === 0) cb(); 101 | else run(next); 102 | }); 103 | } 104 | -------------------------------------------------------------------------------- /example/brfs.js: -------------------------------------------------------------------------------- 1 | var staticModule = require('../'); 2 | var quote = require('quote-stream'); 3 | var fs = require('fs'); 4 | 5 | var sm = staticModule({ 6 | fs: { 7 | readFileSync: function (file) { 8 | return fs.createReadStream(file).pipe(quote()); 9 | } 10 | } 11 | }, { vars: { __dirname: __dirname + '/brfs' } }); 12 | process.stdin.pipe(sm).pipe(process.stdout); 13 | -------------------------------------------------------------------------------- /example/brfs/source.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var src = fs.readFileSync(__dirname + '/x.txt'); 3 | console.log(src); 4 | -------------------------------------------------------------------------------- /example/brfs/x.txt: -------------------------------------------------------------------------------- 1 | beep boop 2 | -------------------------------------------------------------------------------- /example/fs.js: -------------------------------------------------------------------------------- 1 | var staticModule = require('../'); 2 | var quote = require('quote-stream'); 3 | var through = require('through2'); 4 | var fs = require('fs'); 5 | 6 | var sm = staticModule({ 7 | fs: { 8 | readFileSync: function (file) { 9 | return fs.createReadStream(file).pipe(quote()); 10 | }, 11 | readFile: function (file, cb) { 12 | var stream = through(write, end); 13 | stream.push('process.nextTick(function(){(' + cb + ')(null,'); 14 | return fs.createReadStream(file).pipe(quote()).pipe(stream); 15 | 16 | function write (buf, enc, next) { this.push(buf); next() } 17 | function end (next) { this.push(')})'); this.push(null); next() } 18 | } 19 | } 20 | }, { vars: { __dirname: __dirname + '/fs' } }); 21 | process.stdin.pipe(sm).pipe(process.stdout); 22 | -------------------------------------------------------------------------------- /example/fs/source.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | fs.readFile(__dirname + '/x.txt', function (err, src) { 3 | console.log(src); 4 | }); 5 | -------------------------------------------------------------------------------- /example/fs/x.txt: -------------------------------------------------------------------------------- 1 | beep boop 2 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | var Readable = require('readable-stream').Readable; 3 | 4 | var concat = require('concat-stream'); 5 | var duplexer = require('duplexer2'); 6 | var acorn = require('acorn-node'); 7 | var walkAst = require('acorn-node/walk').full; 8 | var scan = require('scope-analyzer'); 9 | var unparse = require('escodegen').generate; 10 | var inspect = require('object-inspect'); 11 | var evaluate = require('static-eval'); 12 | var copy = require('shallow-copy'); 13 | var has = require('has'); 14 | var MagicString = require('magic-string'); 15 | var convertSourceMap = require('convert-source-map'); 16 | var mergeSourceMap = require('merge-source-map'); 17 | 18 | module.exports = function parse (modules, opts) { 19 | if (!opts) opts = {}; 20 | var vars = opts.vars || {}; 21 | var varModules = opts.varModules || {}; 22 | var parserOpts = copy(opts.parserOpts || {}); 23 | var updates = []; 24 | var moduleBindings = []; 25 | var sourcemapper; 26 | var inputMap; 27 | 28 | var output = through(); 29 | var body, ast; 30 | return duplexer(concat({ encoding: 'buffer' }, function (buf) { 31 | try { 32 | body = buf.toString('utf8').replace(/^#!/, '//#!'); 33 | var matches = false; 34 | for (var key in modules) { 35 | if (body.indexOf(key) !== -1) { 36 | matches = true; 37 | break; 38 | } 39 | } 40 | 41 | if (!matches) { 42 | // just pass it through 43 | output.end(buf); 44 | return; 45 | } 46 | 47 | if (opts.sourceMap) { 48 | inputMap = convertSourceMap.fromSource(body); 49 | if (inputMap) inputMap = inputMap.toObject(); 50 | body = convertSourceMap.removeComments(body); 51 | sourcemapper = new MagicString(body); 52 | } 53 | 54 | ast = acorn.parse(body, parserOpts); 55 | // scan.crawl does .parent tracking, so we can use acorn's builtin walker. 56 | scan.crawl(ast); 57 | walkAst(ast, walk); 58 | } 59 | catch (err) { return error(err) } 60 | 61 | finish(body); 62 | }), output); 63 | 64 | function finish (src) { 65 | var pos = 0; 66 | src = String(src); 67 | 68 | moduleBindings.forEach(function (binding) { 69 | if (binding.isReferenced()) { 70 | return; 71 | } 72 | var node = binding.initializer; 73 | if (node.type === 'VariableDeclarator') { 74 | var i = node.parent.declarations.indexOf(node); 75 | if (node.parent.declarations.length === 1) { 76 | // remove the entire declaration 77 | updates.push({ 78 | start: node.parent.start, 79 | offset: node.parent.end - node.parent.start, 80 | stream: st() 81 | }); 82 | } else if (i === node.parent.declarations.length - 1) { 83 | updates.push({ 84 | // remove ", a = 1" 85 | start: node.parent.declarations[i - 1].end, 86 | offset: node.end - node.parent.declarations[i - 1].end, 87 | stream: st() 88 | }); 89 | } else { 90 | updates.push({ 91 | // remove "a = 1, " 92 | start: node.start, 93 | offset: node.parent.declarations[i + 1].start - node.start, 94 | stream: st() 95 | }); 96 | } 97 | } else if (node.parent.type === 'SequenceExpression' && node.parent.expressions.length > 1) { 98 | var i = node.parent.expressions.indexOf(node); 99 | if (i === node.parent.expressions.length - 1) { 100 | updates.push({ 101 | // remove ", a = 1" 102 | start: node.parent.expressions[i - 1].end, 103 | offset: node.end - node.parent.expressions[i - 1].end, 104 | stream: st() 105 | }); 106 | } else { 107 | updates.push({ 108 | // remove "a = 1, " 109 | start: node.start, 110 | offset: node.parent.expressions[i + 1].start - node.start, 111 | stream: st() 112 | }); 113 | } 114 | } else { 115 | if (node.parent.type === 'ExpressionStatement') node = node.parent; 116 | updates.push({ 117 | start: node.start, 118 | offset: node.end - node.start, 119 | stream: st() 120 | }); 121 | } 122 | }); 123 | updates.sort(function(a, b) { return a.start - b.start; }); 124 | 125 | (function next () { 126 | if (updates.length === 0) return done(); 127 | var s = updates.shift(); 128 | 129 | output.write(src.slice(pos, s.start)); 130 | pos = s.start + s.offset; 131 | 132 | s.stream.pipe(output, { end: false }); 133 | if (opts.sourceMap) { 134 | s.stream.pipe(concat({ encoding: 'string' }, function (chunk) { 135 | // We have to give magic-string the replacement string, 136 | // so it can calculate the amount of lines and columns. 137 | if (s.offset === 0) { 138 | sourcemapper.appendRight(s.start, chunk); 139 | } else { 140 | sourcemapper.overwrite(s.start, s.start + s.offset, chunk); 141 | } 142 | })).on('finish', next); 143 | } else { 144 | s.stream.on('end', next); 145 | } 146 | })(); 147 | 148 | function done () { 149 | output.write(src.slice(pos)); 150 | if (opts.sourceMap) { 151 | var map = sourcemapper.generateMap({ 152 | source: opts.inputFilename || 'input.js', 153 | includeContent: true 154 | }); 155 | if (inputMap) { 156 | var merged = mergeSourceMap(inputMap, map); 157 | output.write('\n' + convertSourceMap.fromObject(merged).toComment() + '\n'); 158 | } else { 159 | output.write('\n//# sourceMappingURL=' + map.toUrl() + '\n'); 160 | } 161 | } 162 | output.end(); 163 | } 164 | } 165 | 166 | function error (msg) { 167 | var err = typeof msg === 'string' ? new Error(msg) : msg; 168 | output.emit('error', err); 169 | } 170 | 171 | function walk (node) { 172 | if (opts.sourceMap) { 173 | sourcemapper.addSourcemapLocation(node.start); 174 | sourcemapper.addSourcemapLocation(node.end); 175 | } 176 | 177 | var isreq = isRequire(node); 178 | var isreqm = false, isreqv = false, reqid; 179 | if (isreq) { 180 | reqid = node.arguments[0].value; 181 | isreqm = has(modules, reqid); 182 | isreqv = has(varModules, reqid); 183 | } 184 | 185 | if (isreqv && node.parent.type === 'VariableDeclarator' 186 | && node.parent.id.type === 'Identifier') { 187 | var binding = scan.getBinding(node.parent.id); 188 | if (binding) binding.value = varModules[reqid]; 189 | } 190 | else if (isreqv && node.parent.type === 'AssignmentExpression' 191 | && node.parent.left.type === 'Identifier') { 192 | var binding = scan.getBinding(node.parent.left); 193 | if (binding) binding.value = varModules[reqid]; 194 | } 195 | else if (isreqv && node.parent.type === 'MemberExpression' 196 | && isStaticProperty(node.parent.property) 197 | && node.parent.parent.type === 'VariableDeclarator' 198 | && node.parent.parent.id.type === 'Identifier') { 199 | var binding = scan.getBinding(node.parent.parent.id); 200 | var v = varModules[reqid][resolveProperty(node.parent.property)]; 201 | if (binding) binding.value = v; 202 | } 203 | else if (isreqv && node.parent.type === 'MemberExpression' 204 | && node.parent.property.type === 'Identifier') { 205 | //vars[node.parent.parent.id.name] = varModules[reqid]; 206 | } 207 | else if (isreqv && node.parent.type === 'CallExpression') { 208 | // 209 | } 210 | 211 | if (isreqm && node.parent.type === 'VariableDeclarator' 212 | && node.parent.id.type === 'Identifier') { 213 | var binding = scan.getBinding(node.parent.id); 214 | if (binding) { 215 | binding.module = modules[reqid]; 216 | binding.initializer = node.parent; 217 | binding.remove(node.parent.id); 218 | moduleBindings.push(binding); 219 | } 220 | } 221 | else if (isreqm && node.parent.type === 'AssignmentExpression' 222 | && node.parent.left.type === 'Identifier') { 223 | var binding = scan.getBinding(node.parent.left); 224 | if (binding) { 225 | binding.module = modules[reqid]; 226 | binding.initializer = node.parent; 227 | binding.remove(node.parent.left); 228 | moduleBindings.push(binding); 229 | } 230 | } 231 | else if (isreqm && node.parent.type === 'MemberExpression' 232 | && isStaticProperty(node.parent.property) 233 | && node.parent.parent.type === 'VariableDeclarator' 234 | && node.parent.parent.id.type === 'Identifier') { 235 | var binding = scan.getBinding(node.parent.parent.id); 236 | if (binding) { 237 | binding.module = modules[reqid][resolveProperty(node.parent.property)]; 238 | binding.initializer = node.parent.parent; 239 | binding.remove(node.parent.parent.id); 240 | moduleBindings.push(binding); 241 | } 242 | } 243 | else if (isreqm && node.parent.type === 'MemberExpression' 244 | && isStaticProperty(node.parent.property)) { 245 | var name = resolveProperty(node.parent.property); 246 | var cur = copy(node.parent.parent); 247 | cur.callee = copy(node.parent.property); 248 | cur.callee.parent = cur; 249 | traverse(cur.callee, modules[reqid][name]); 250 | } 251 | else if (isreqm && node.parent.type === 'CallExpression') { 252 | var cur = copy(node.parent); 253 | var iname = Math.pow(16,8) * Math.random(); 254 | cur.callee = { 255 | type: 'Identifier', 256 | name: '_' + Math.floor(iname).toString(16), 257 | parent: cur 258 | }; 259 | traverse(cur.callee, modules[reqid]); 260 | } 261 | 262 | if (node.type === 'Identifier') { 263 | var binding = scan.getBinding(node) 264 | if (binding && binding.module) traverse(node, binding.module, binding); 265 | } 266 | } 267 | 268 | function traverse (node, val, binding) { 269 | for (var p = node; p; p = p.parent) { 270 | if (p.start === undefined || p.end === undefined) continue; 271 | } 272 | 273 | if (node.parent.type === 'CallExpression') { 274 | if (typeof val !== 'function') { 275 | return error( 276 | 'tried to statically call ' + inspect(val) 277 | + ' as a function' 278 | ); 279 | } 280 | 281 | var xvars = getVars(node.parent, vars); 282 | xvars[node.name] = val; 283 | 284 | var res = evaluate(node.parent, xvars); 285 | if (res !== undefined) { 286 | if (binding) binding.remove(node) 287 | updates.push({ 288 | start: node.parent.start, 289 | offset: node.parent.end - node.parent.start, 290 | stream: isStream(res) ? wrapStream(res) : st(String(res)) 291 | }); 292 | } 293 | } 294 | else if (node.parent.type === 'MemberExpression') { 295 | if (!isStaticProperty(node.parent.property)) { 296 | return error( 297 | 'dynamic property in member expression: ' 298 | + body.slice(node.parent.start, node.parent.end) 299 | ); 300 | } 301 | 302 | var cur = node.parent.parent; 303 | 304 | if (cur.type === 'MemberExpression') { 305 | cur = cur.parent; 306 | if (cur.type !== 'CallExpression' 307 | && cur.parent.type === 'CallExpression') { 308 | cur = cur.parent; 309 | } 310 | } 311 | if (node.parent.type === 'MemberExpression' 312 | && (cur.type !== 'CallExpression' 313 | && cur.type !== 'MemberExpression')) { 314 | cur = node.parent; 315 | } 316 | 317 | var xvars = getVars(cur, vars); 318 | xvars[node.name] = val; 319 | 320 | var res = evaluate(cur, xvars); 321 | if (res === undefined && cur.type === 'CallExpression') { 322 | // static-eval can't safely evaluate code with callbacks, so do it manually in a safe way 323 | var callee = evaluate(cur.callee, xvars); 324 | var args = cur.arguments.map(function (arg) { 325 | // Return a function stub for callbacks so that `static-module` users 326 | // can do `callback.toString()` and get the original source 327 | if (arg.type === 'FunctionExpression' || arg.type === 'ArrowFunctionExpression') { 328 | var fn = function () { 329 | throw new Error('static-module: cannot call callbacks defined inside source code'); 330 | }; 331 | fn.toString = function () { 332 | return body.slice(arg.start, arg.end); 333 | }; 334 | return fn; 335 | } 336 | return evaluate(arg, xvars); 337 | }); 338 | 339 | if (callee !== undefined) { 340 | try { 341 | res = callee.apply(null, args); 342 | } catch (err) { 343 | // Evaluate to undefined 344 | } 345 | } 346 | } 347 | 348 | if (res !== undefined) { 349 | if (binding) binding.remove(node) 350 | updates.push({ 351 | start: cur.start, 352 | offset: cur.end - cur.start, 353 | stream: isStream(res) ? wrapStream(res) : st(String(res)) 354 | }); 355 | } 356 | } 357 | else if (node.parent.type === 'UnaryExpression') { 358 | var xvars = getVars(node.parent, vars); 359 | xvars[node.name] = val; 360 | 361 | var res = evaluate(node.parent, xvars); 362 | if (res !== undefined) { 363 | if (binding) binding.remove(node) 364 | updates.push({ 365 | start: node.parent.start, 366 | offset: node.parent.end - node.parent.start, 367 | stream: isStream(res) ? wrapStream(res) : st(String(res)) 368 | }); 369 | } else { 370 | output.emit('error', new Error( 371 | 'unsupported unary operator: ' + node.parent.operator 372 | )); 373 | } 374 | } 375 | else { 376 | output.emit('error', new Error( 377 | 'unsupported type for static module: ' + node.parent.type 378 | + '\nat expression:\n\n ' + unparse(node.parent) + '\n' 379 | )); 380 | } 381 | } 382 | } 383 | 384 | function isRequire (node) { 385 | var c = node.callee; 386 | return c 387 | && node.type === 'CallExpression' 388 | && c.type === 'Identifier' 389 | && c.name === 'require' 390 | ; 391 | } 392 | 393 | function isStream (s) { 394 | return s && typeof s === 'object' && typeof s.pipe === 'function'; 395 | } 396 | 397 | function wrapStream (s) { 398 | if (typeof s.read === 'function') return s 399 | else return (new Readable).wrap(s) 400 | } 401 | 402 | function isStaticProperty(node) { 403 | return node.type === 'Identifier' || node.type === 'Literal'; 404 | } 405 | 406 | function resolveProperty(node) { 407 | return node.type === 'Identifier' ? node.name : node.value; 408 | } 409 | 410 | function st (msg) { 411 | var r = new Readable; 412 | r._read = function () {}; 413 | if (msg != null) r.push(msg); 414 | r.push(null); 415 | return r; 416 | } 417 | 418 | function nearestScope(node) { 419 | do { 420 | var scope = scan.scope(node); 421 | if (scope) return scope; 422 | } while ((node = node.parent)); 423 | } 424 | 425 | function getVars(node, vars) { 426 | var xvars = copy(vars || {}); 427 | var scope = nearestScope(node); 428 | if (scope) { 429 | scope.forEachAvailable(function (binding, name) { 430 | if (binding.hasOwnProperty('value')) xvars[name] = binding.value; 431 | }); 432 | } 433 | return xvars; 434 | } 435 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "static-module", 3 | "version": "3.0.4", 4 | "description": "convert module usage to inline expressions", 5 | "main": "index.js", 6 | "dependencies": { 7 | "acorn-node": "^1.3.0", 8 | "concat-stream": "~1.6.0", 9 | "convert-source-map": "^1.5.1", 10 | "duplexer2": "~0.1.4", 11 | "escodegen": "^1.11.1", 12 | "has": "^1.0.1", 13 | "magic-string": "0.25.1", 14 | "merge-source-map": "1.0.4", 15 | "object-inspect": "^1.6.0", 16 | "readable-stream": "~2.3.3", 17 | "scope-analyzer": "^2.0.1", 18 | "shallow-copy": "~0.0.1", 19 | "static-eval": "^2.0.5", 20 | "through2": "~2.0.3" 21 | }, 22 | "devDependencies": { 23 | "from2-string": "^1.1.0", 24 | "nanobench": "^2.1.1", 25 | "quote-stream": "^1.0.2", 26 | "resolve": "^1.5.0", 27 | "source-map": "^0.6.1", 28 | "tape": "^4.8.0", 29 | "uglify-js": "3.3.12" 30 | }, 31 | "scripts": { 32 | "bench": "nanobench bench", 33 | "test": "tape test/*.js" 34 | }, 35 | "repository": { 36 | "type": "git", 37 | "url": "git://github.com/substack/static-module.git" 38 | }, 39 | "homepage": "https://github.com/substack/static-module", 40 | "keywords": [ 41 | "ast", 42 | "static", 43 | "analysis", 44 | "esprima", 45 | "syntax", 46 | "tree" 47 | ], 48 | "author": { 49 | "name": "James Halliday", 50 | "email": "mail@substack.net", 51 | "url": "http://substack.net" 52 | }, 53 | "license": "MIT" 54 | } 55 | -------------------------------------------------------------------------------- /readme.markdown: -------------------------------------------------------------------------------- 1 | # static-module 2 | 3 | convert module usage to inline expressions 4 | 5 | # example 6 | 7 | Here's a simplified version of the [brfs](https://npmjs.org/package/brfs) module 8 | using static-module. 9 | 10 | brfs converts `fs.readFileSync(file)` calls to inline strings with the contents 11 | of `file` included in-place. 12 | 13 | ``` js 14 | var staticModule = require('static-module'); 15 | var quote = require('quote-stream'); 16 | var fs = require('fs'); 17 | 18 | var sm = staticModule({ 19 | fs: { 20 | readFileSync: function (file) { 21 | return fs.createReadStream(file).pipe(quote()); 22 | } 23 | } 24 | }, { vars: { __dirname: __dirname + '/brfs' } }); 25 | process.stdin.pipe(sm).pipe(process.stdout); 26 | ``` 27 | 28 | input: 29 | 30 | ``` 31 | $ cat brfs/source.js 32 | var fs = require('fs'); 33 | var src = fs.readFileSync(__dirname + '/x.txt'); 34 | console.log(src); 35 | ``` 36 | 37 | output: 38 | 39 | ``` 40 | $ node brfs.js < brfs/source.js 41 | 42 | var src = "beep boop\n"; 43 | console.log(src); 44 | ``` 45 | 46 | # methods 47 | 48 | ``` js 49 | var staticModule = require('static-module') 50 | ``` 51 | 52 | ## var sm = staticModule(modules, opts={}) 53 | 54 | Return a transform stream `sm` that transforms javascript source input to 55 | javascript source output with each property in the `modules` object expanded in 56 | inline form. 57 | 58 | Properties in the `modules` object can be ordinary values that will be included 59 | directly or functions that will be executed with the [statically 60 | evaluated](https://npmjs.org/package/static-eval) arguments from the source 61 | under an optional set of `opts.vars` variables. 62 | 63 | Property functions can return streams, in which case their contents will be 64 | piped directly into the source output. 65 | 66 | Otherwise, the return values of functions will be inlined into the source in 67 | place as strings. 68 | 69 | Use `opts.varModules` to map whitelisted module names to definitions that can be 70 | declared in client code with `var` and will appear in static expressions like 71 | `opts.vars`. 72 | 73 | For example, to make this code with `path.join()` work: 74 | 75 | ``` js 76 | var fs = require('fs'); 77 | var path = require('path'); 78 | var src = fs.readFileSync(path.join(__dirname, 'x.txt'), 'utf8'); 79 | console.log(src); 80 | ``` 81 | 82 | you can do: 83 | 84 | ``` js 85 | var staticModule = require('static-module'); 86 | var quote = require('quote-stream'); 87 | var fs = require('fs'); 88 | 89 | var sm = staticModule({ 90 | fs: { 91 | readFileSync: function (file) { 92 | return fs.createReadStream(file).pipe(quote()); 93 | } 94 | }, 95 | varMods: { path: require('path') } 96 | }, { vars: { __dirname: __dirname + '/brfs' } }); 97 | process.stdin.pipe(sm).pipe(process.stdout); 98 | ``` 99 | 100 | Use `opts.parserOpts` to set additional options for the 101 | [acorn](https://github.com/acornjs/acorn) parser. 102 | 103 | Set `opts.sourceMap` to `true` to generate a source map and add it as an inline 104 | comment. You can add `opts.inputFilename` to configure the original file name 105 | that will be listed in the source map. 106 | 107 | # install 108 | 109 | With [npm](https://npmjs.org) do: 110 | 111 | ``` 112 | npm install static-module 113 | ``` 114 | 115 | # license 116 | 117 | MIT 118 | -------------------------------------------------------------------------------- /security.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | Only the latest major version is supported at any given time. 5 | 6 | ## Reporting a Vulnerability 7 | To report a security vulnerability, please use the 8 | [Tidelift security contact](https://tidelift.com/security). 9 | Tidelift will coordinate the fix and disclosure. 10 | 11 | Note that this module is intended for build-time transforms on 12 | trusted code. As such, if a security fix requires changes that 13 | would make the module significantly less powerful, we may prefer 14 | the unsafety. 15 | -------------------------------------------------------------------------------- /test/assign.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var concat = require('concat-stream'); 3 | var staticModule = require('../'); 4 | var fs = require('fs'); 5 | var path = require('path'); 6 | 7 | test('assign', function (t) { 8 | t.plan(3); 9 | 10 | var expected = [ 12, 555 ]; 11 | var sm = staticModule({ 12 | beep: { x: 4, f: function (n) { return n * 111 } } 13 | }); 14 | readStream('source.js').pipe(sm).pipe(concat(function (body) { 15 | t.equal(body.toString('utf8'), 16 | '\nconsole.log(4 * 3);' 17 | + '\nconsole.log(555);\n' 18 | ); 19 | Function(['console'],body)({ log: log }); 20 | function log (msg) { t.equal(msg, expected.shift()) } 21 | })); 22 | }); 23 | 24 | test('assign comma', function (t) { 25 | t.plan(3); 26 | 27 | var expected = [ 12, 555 ]; 28 | var sm = staticModule({ 29 | beep: { x: 4, f: function (n) { return n * 111 } } 30 | }); 31 | readStream('comma.js').pipe(sm).pipe(concat(function (body) { 32 | t.equal(body.toString('utf8'), 33 | 'x = 5;\n' 34 | + 'console.log(4 * 3);\n' 35 | + 'console.log(555);\n' 36 | ); 37 | Function(['console'],body)({ log: log }); 38 | function log (msg) { t.equal(msg, expected.shift()) } 39 | })); 40 | }); 41 | 42 | function readStream (file) { 43 | return fs.createReadStream(path.join(__dirname, 'assign', file)); 44 | } 45 | -------------------------------------------------------------------------------- /test/assign/comma.js: -------------------------------------------------------------------------------- 1 | x = 5, b = require('beep'); 2 | console.log(b.x * 3); 3 | console.log(b.f(5)); 4 | -------------------------------------------------------------------------------- /test/assign/source.js: -------------------------------------------------------------------------------- 1 | b = require('beep'); 2 | console.log(b.x * 3); 3 | console.log(b.f(5)); 4 | -------------------------------------------------------------------------------- /test/brfs.js: -------------------------------------------------------------------------------- 1 | var staticModule = require('../'); 2 | var test = require('tape'); 3 | var concat = require('concat-stream'); 4 | var quote = require('quote-stream'); 5 | var fs = require('fs'); 6 | var path = require('path'); 7 | var vm = require('vm'); 8 | 9 | test('readFileSync', function (t) { 10 | t.plan(2); 11 | var sm = staticModule({ 12 | fs: { 13 | readFileSync: function (file) { 14 | return fs.createReadStream(file).pipe(quote()); 15 | } 16 | } 17 | }, { vars: { __dirname: path.join(__dirname, 'brfs') } }); 18 | readStream('source.js').pipe(sm).pipe(concat(function (body) { 19 | t.equal(body.toString('utf8'), 20 | '\nvar src = "beep boop\\n";' 21 | + '\nconsole.log(src);\n' 22 | ); 23 | vm.runInNewContext(body.toString('utf8'), { 24 | console: { log: log } 25 | }); 26 | function log (msg) { t.equal(msg, 'beep boop\n') } 27 | })); 28 | }); 29 | 30 | test('readFileSync empty', function (t) { 31 | t.plan(1); 32 | var sm = staticModule({ 33 | fs: { 34 | readFileSync: function (file) { 35 | return fs.createReadStream(file).pipe(quote()); 36 | } 37 | } 38 | }, { vars: { __dirname: path.join(__dirname, 'brfs') } }); 39 | readStream('empty.js').pipe(sm).pipe(concat(function (body) { 40 | t.equal(body.toString('utf8'), ''); 41 | })); 42 | }); 43 | 44 | test('readFileSync attribute', function (t) { 45 | t.plan(2); 46 | var sm = staticModule({ 47 | fs: { 48 | readFileSync: function (file) { 49 | return fs.createReadStream(file).pipe(quote()); 50 | } 51 | } 52 | }, { vars: { __dirname: path.join(__dirname, 'brfs') } }); 53 | readStream('attribute.js').pipe(sm).pipe(concat(function (body) { 54 | t.equal(body.toString('utf8'), 55 | '\nvar src = "beep boop\\n";' 56 | + '\nconsole.log(src);\n' 57 | ); 58 | vm.runInNewContext(body.toString('utf8'), { 59 | console: { log: log } 60 | }); 61 | function log (msg) { t.equal(msg, 'beep boop\n') } 62 | })); 63 | }); 64 | 65 | test('readFileSync attribute with multiple vars', function (t) { 66 | t.plan(2); 67 | var sm = staticModule({ 68 | fs: { 69 | readFileSync: function (file) { 70 | return fs.createReadStream(file).pipe(quote()); 71 | } 72 | } 73 | }, { vars: { __dirname: path.join(__dirname, 'brfs') } }); 74 | readStream('attribute_vars.js').pipe(sm).pipe(concat(function (body) { 75 | t.equal(body.toString('utf8'), 76 | 'var x = 5, y = 2;' 77 | + '\nvar src = "beep boop\\n";' 78 | + '\nconsole.log(src);\n' 79 | ); 80 | vm.runInNewContext(body.toString('utf8'), { 81 | console: { log: log } 82 | }); 83 | function log (msg) { t.equal(msg, 'beep boop\n') } 84 | })); 85 | }); 86 | 87 | test('readFileSync attribute with multiple require vars', function (t) { 88 | t.plan(2); 89 | var sm = staticModule({ 90 | fs: { 91 | readFileSync: function (file) { 92 | return fs.createReadStream(file).pipe(quote()); 93 | } 94 | } 95 | }, { vars: { __dirname: path.join(__dirname, 'brfs') } }); 96 | readStream('multi_require.js').pipe(sm).pipe(concat(function (body) { 97 | t.equal(body.toString('utf8'), 98 | 'var x = 5;' 99 | + '\nvar src = "beep boop\\n";' 100 | + '\nconsole.log(src);\n' 101 | ); 102 | vm.runInNewContext(body.toString('utf8'), { 103 | console: { log: log } 104 | }); 105 | function log (msg) { t.equal(msg, 'beep boop\n') } 106 | })); 107 | }); 108 | 109 | test('readFileSync attribute with multiple require vars including an uninitalized var', function (t) { 110 | t.plan(2); 111 | var sm = staticModule({ 112 | fs: { 113 | readFileSync: function (file) { 114 | return fs.createReadStream(file).pipe(quote()); 115 | } 116 | } 117 | }, { vars: { __dirname: path.join(__dirname, 'brfs') } }); 118 | readStream('multi_require_with_uninitialized.js').pipe(sm).pipe(concat(function (body) { 119 | t.equal(body.toString('utf8'), 120 | 'var x;' 121 | + '\nvar src = "beep boop\\n";' 122 | + '\nconsole.log(src);\n' 123 | ); 124 | vm.runInNewContext(body.toString('utf8'), { 125 | console: { log: log } 126 | }); 127 | function log (msg) { t.equal(msg, 'beep boop\n') } 128 | })); 129 | }); 130 | 131 | test('readFileSync attribute with multiple require vars x5', function (t) { 132 | t.plan(2); 133 | var sm = staticModule({ 134 | fs: { 135 | readFileSync: function (file) { 136 | return fs.createReadStream(file).pipe(quote()); 137 | } 138 | } 139 | }, { vars: { __dirname: path.join(__dirname, 'brfs') } }); 140 | readStream('x5.js').pipe(sm).pipe(concat(function (body) { 141 | t.equal(body.toString('utf8'), 142 | 'var a = 1, b = 2, c = 3, d = 4, ' 143 | + 'src = "beep boop\\n",\n' 144 | + ' e = 5\n' 145 | + ';\n' 146 | + 'console.log(src);\n' 147 | ); 148 | vm.runInNewContext(body.toString('utf8'), { 149 | console: { log: log } 150 | }); 151 | function log (msg) { t.equal(msg, 'beep boop\n') } 152 | })); 153 | }); 154 | 155 | test('readFileSync with bracket notation', function (t) { 156 | t.plan(2); 157 | var sm = staticModule({ 158 | fs: { 159 | readFileSync: function (file) { 160 | return fs.createReadStream(file).pipe(quote()); 161 | } 162 | } 163 | }, { vars: { __dirname: path.join(__dirname, 'brfs') } }); 164 | readStream('brackets.js').pipe(sm).pipe(concat(function (body) { 165 | t.equal(body.toString('utf8'), 166 | '\nvar src = "beep boop\\n";' 167 | + '\nconsole.log(src);\n' 168 | ); 169 | vm.runInNewContext(body.toString('utf8'), { 170 | console: { log: log } 171 | }); 172 | function log (msg) { t.equal(msg, 'beep boop\n') } 173 | })); 174 | }); 175 | 176 | test('readFileSync attribute bracket notation', function (t) { 177 | t.plan(2); 178 | var sm = staticModule({ 179 | fs: { 180 | readFileSync: function (file) { 181 | return fs.createReadStream(file).pipe(quote()); 182 | } 183 | } 184 | }, { vars: { __dirname: path.join(__dirname, 'brfs') } }); 185 | readStream('attribute_brackets.js').pipe(sm).pipe(concat(function (body) { 186 | t.equal(body.toString('utf8'), 187 | '\nvar src = "beep boop\\n";' 188 | + '\nconsole.log(src);\n' 189 | ); 190 | vm.runInNewContext(body.toString('utf8'), { 191 | console: { log: log } 192 | }); 193 | function log (msg) { t.equal(msg, 'beep boop\n') } 194 | })); 195 | }); 196 | 197 | function readStream (file) { 198 | return fs.createReadStream(path.join(__dirname, 'brfs', file)); 199 | } 200 | -------------------------------------------------------------------------------- /test/brfs/attribute.js: -------------------------------------------------------------------------------- 1 | var f = require('fs').readFileSync; 2 | var src = f(__dirname + '/x.txt', 'utf8'); 3 | console.log(src); 4 | -------------------------------------------------------------------------------- /test/brfs/attribute_brackets.js: -------------------------------------------------------------------------------- 1 | var f = require('fs')["readFileSync"]; 2 | var src = f(__dirname + '/x.txt', 'utf8'); 3 | console.log(src); 4 | -------------------------------------------------------------------------------- /test/brfs/attribute_vars.js: -------------------------------------------------------------------------------- 1 | var x = 5, f = require('fs').readFileSync, y = 2; 2 | var src = f(__dirname + '/x.txt', 'utf8'); 3 | console.log(src); 4 | -------------------------------------------------------------------------------- /test/brfs/brackets.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var src = fs["readFileSync"](__dirname + '/x.txt', 'utf8'); 3 | console.log(src); 4 | -------------------------------------------------------------------------------- /test/brfs/empty.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/static-module/397b22b2b96b5af90c153059896aa870a814bf5c/test/brfs/empty.js -------------------------------------------------------------------------------- /test/brfs/multi_require.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'), x = 5; 2 | var src = fs.readFileSync(__dirname + '/x.txt', 'utf8'); 3 | console.log(src); 4 | -------------------------------------------------------------------------------- /test/brfs/multi_require_with_uninitialized.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'), x; 2 | var src = fs.readFileSync(__dirname + '/x.txt', 'utf8'); 3 | console.log(src); 4 | -------------------------------------------------------------------------------- /test/brfs/source.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var src = fs.readFileSync(__dirname + '/x.txt', 'utf8'); 3 | console.log(src); 4 | -------------------------------------------------------------------------------- /test/brfs/x.txt: -------------------------------------------------------------------------------- 1 | beep boop 2 | -------------------------------------------------------------------------------- /test/brfs/x5.js: -------------------------------------------------------------------------------- 1 | var a = 1, b = 2, fs = require('fs'), 2 | c = 3, d = 4, src = fs.readFileSync(__dirname + '/x.txt', 'utf8'), 3 | e = 5 4 | ; 5 | console.log(src); 6 | -------------------------------------------------------------------------------- /test/fn.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var concat = require('concat-stream'); 3 | var staticModule = require('../'); 4 | var fs = require('fs'); 5 | var path = require('path'); 6 | 7 | test('function', function (t) { 8 | t.plan(1); 9 | 10 | var sm = staticModule({ beep: function (n) { return n * 111 } }); 11 | readStream('source.js').pipe(sm).pipe(concat(function (body) { 12 | Function(['console'],body)({ log: log }); 13 | function log (msg) { t.equal(msg, 555) } 14 | })); 15 | }); 16 | 17 | function readStream (file) { 18 | return fs.createReadStream(path.join(__dirname, 'fn', file)); 19 | } 20 | -------------------------------------------------------------------------------- /test/fn/source.js: -------------------------------------------------------------------------------- 1 | var b = require('beep'); 2 | console.log(b(5)); 3 | -------------------------------------------------------------------------------- /test/fs.js: -------------------------------------------------------------------------------- 1 | var staticModule = require('../'); 2 | var test = require('tape'); 3 | var concat = require('concat-stream'); 4 | var quote = require('quote-stream'); 5 | var through = require('through2'); 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | 9 | test('fs.readFile', function (t) { 10 | t.plan(2); 11 | var sm = staticModule({ 12 | fs: { readFile: readFile } 13 | }, { vars: { __dirname: __dirname + '/fs' } }); 14 | readStream('readfile.js').pipe(sm).pipe(concat(function (body) { 15 | t.equal(body.toString('utf8').replace(/;/g,'').trim(), 16 | 'process.nextTick(function(){(function (err, src) {\n' 17 | + ' console.log(src)\n' 18 | + '})(null,"beep boop\\n")})' 19 | ); 20 | Function(['console'],body)({ log: log }); 21 | function log (msg) { t.equal(msg, 'beep boop\n') } 22 | })); 23 | }); 24 | 25 | test('fs.readFileSync', function (t) { 26 | t.plan(2); 27 | var sm = staticModule({ 28 | fs: { readFileSync: readFileSync } 29 | }, { vars: { __dirname: __dirname + '/fs' } }); 30 | readStream('html.js').pipe(sm).pipe(concat(function (body) { 31 | t.equal(body.toString('utf8'), 32 | 'var html = "EXTERMINATE\\n";\n' 33 | + 'console.log(html);\n' 34 | ); 35 | Function(['console'],body)({ log: log }); 36 | function log (msg) { t.equal(msg, 'EXTERMINATE\n') } 37 | })); 38 | }); 39 | 40 | function readStream (file) { 41 | return fs.createReadStream(path.join(__dirname, 'fs', file)); 42 | } 43 | 44 | function readFile (file, cb) { 45 | var stream = through(write, end); 46 | stream.push('process.nextTick(function(){(' + cb + ')(null,'); 47 | return fs.createReadStream(file).pipe(quote()).pipe(stream); 48 | 49 | function write (buf, enc, next) { this.push(buf); next() } 50 | function end (next) { this.push(')})'); this.push(null); next() } 51 | } 52 | 53 | function readFileSync (file, opts) { 54 | return fs.createReadStream(file).pipe(quote()); 55 | } 56 | -------------------------------------------------------------------------------- /test/fs/html.js: -------------------------------------------------------------------------------- 1 | var html = require('fs').readFileSync(__dirname + '/robot.html', 'utf8'); 2 | console.log(html); 3 | -------------------------------------------------------------------------------- /test/fs/readfile.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | fs.readFile(__dirname + '/x.txt', function (err, src) { 3 | console.log(src); 4 | }); 5 | -------------------------------------------------------------------------------- /test/fs/robot.html: -------------------------------------------------------------------------------- 1 | EXTERMINATE 2 | -------------------------------------------------------------------------------- /test/fs/x.txt: -------------------------------------------------------------------------------- 1 | beep boop 2 | -------------------------------------------------------------------------------- /test/fs_twice.js: -------------------------------------------------------------------------------- 1 | var staticModule = require('../'); 2 | var test = require('tape'); 3 | var concat = require('concat-stream'); 4 | var quote = require('quote-stream'); 5 | var through = require('through2'); 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | 9 | test('fs.readFileSync twice', function (t) { 10 | var expected = [ 'EXTERMINATE\n', 'beep boop\n' ]; 11 | t.plan(expected.length + 1); 12 | var sm = staticModule({ 13 | fs: { readFileSync: readFileSync } 14 | }, { vars: { __dirname: __dirname + '/fs_twice' } }); 15 | readStream('html.js').pipe(sm).pipe(concat(function (body) { 16 | t.equal(body.toString('utf8'), 17 | 'var a = "EXTERMINATE\\n";\n' 18 | + 'var b = "beep boop\\n";\n' 19 | + 'console.log(a);\n' 20 | + 'console.log(b);\n' 21 | ); 22 | Function(['console'],body)({ log: log }); 23 | function log (msg) { t.equal(msg, expected.shift()) } 24 | })); 25 | }); 26 | 27 | test('fs.readFileSync twice in vars', function (t) { 28 | var expected = [ 'EXTERMINATE\n', 'beep boop\n' ]; 29 | t.plan(expected.length + 1); 30 | var sm = staticModule({ 31 | fs: { readFileSync: readFileSync } 32 | }, { vars: { __dirname: __dirname + '/fs_twice' } }); 33 | readStream('vars.js').pipe(sm).pipe(concat(function (body) { 34 | t.equal(body.toString('utf8').trim(), 35 | 'var a = "EXTERMINATE\\n",\n' 36 | + ' b = "beep boop\\n";\n' 37 | + 'console.log(a);\n' 38 | + 'console.log(b);' 39 | ); 40 | Function(['console'],body)({ log: log }); 41 | function log (msg) { t.equal(msg, expected.shift()) } 42 | })); 43 | }); 44 | 45 | test('fs.readFileSync 4x', function (t) { 46 | var expected = [ 47 | 'EXTERMINATE\n', 'beep boop\n', 'EXTERMINATE\n', 'beep boop\n' 48 | ]; 49 | t.plan(expected.length + 1); 50 | var sm = staticModule({ 51 | fs: { readFileSync: readFileSync } 52 | }, { vars: { __dirname: __dirname + '/fs_twice' } }); 53 | readStream('4x.js').pipe(sm).pipe(concat(function (body) { 54 | t.equal(body.toString('utf8').trim(), 55 | 'var a = "EXTERMINATE\\n";\n' 56 | + 'var b = "beep boop\\n";\n' 57 | + 'var c = "EXTERMINATE\\n";\n' 58 | + 'var d = "beep boop\\n";\n' 59 | + 'console.log(a);\n' 60 | + 'console.log(b);\n' 61 | + 'console.log(c);\n' 62 | + 'console.log(d);' 63 | ); 64 | Function(['console'],body)({ log: log }); 65 | function log (msg) { t.equal(msg, expected.shift()) } 66 | })); 67 | }); 68 | 69 | function readStream (file) { 70 | return fs.createReadStream(path.join(__dirname, 'fs_twice', file)); 71 | } 72 | 73 | function readFile (file, cb) { 74 | var stream = through(write, end); 75 | stream.push('process.nextTick(function(){(' + cb + ')(null,'); 76 | return fs.createReadStream(file).pipe(quote()).pipe(stream); 77 | 78 | function write (buf, enc, next) { this.push(buf); next() } 79 | function end (next) { this.push(')})'); this.push(null); next() } 80 | } 81 | 82 | function readFileSync (file, opts) { 83 | return fs.createReadStream(file).pipe(quote()); 84 | } 85 | -------------------------------------------------------------------------------- /test/fs_twice/4x.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var a = fs.readFileSync(__dirname + '/robot.html', 'utf8'); 3 | var b = fs.readFileSync(__dirname + '/x.txt', 'utf8'); 4 | var c = fs.readFileSync(__dirname + '/robot.html', 'utf8'); 5 | var d = fs.readFileSync(__dirname + '/x.txt', 'utf8'); 6 | console.log(a); 7 | console.log(b); 8 | console.log(c); 9 | console.log(d); 10 | -------------------------------------------------------------------------------- /test/fs_twice/html.js: -------------------------------------------------------------------------------- 1 | var a = require('fs').readFileSync(__dirname + '/robot.html', 'utf8'); 2 | var b = require('fs').readFileSync(__dirname + '/x.txt', 'utf8'); 3 | console.log(a); 4 | console.log(b); 5 | -------------------------------------------------------------------------------- /test/fs_twice/readfile.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | fs.readFile(__dirname + '/x.txt', function (err, src) { 3 | console.log(src); 4 | }); 5 | -------------------------------------------------------------------------------- /test/fs_twice/robot.html: -------------------------------------------------------------------------------- 1 | EXTERMINATE 2 | -------------------------------------------------------------------------------- /test/fs_twice/vars.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var a = fs.readFileSync(__dirname + '/robot.html', 'utf8'), 3 | b = fs.readFileSync(__dirname + '/x.txt', 'utf8'); 4 | console.log(a); 5 | console.log(b); 6 | -------------------------------------------------------------------------------- /test/fs_twice/x.txt: -------------------------------------------------------------------------------- 1 | beep boop 2 | -------------------------------------------------------------------------------- /test/inline.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var concat = require('concat-stream'); 3 | var staticModule = require('../'); 4 | var fs = require('fs'); 5 | var path = require('path'); 6 | 7 | test('inline object', function (t) { 8 | t.plan(1); 9 | var sm = staticModule({ 10 | beep: { f: function (n) { return n * 111 } } 11 | }); 12 | readStream('obj.js').pipe(sm).pipe(concat(function (body) { 13 | Function(['console'],body)({ log: log }); 14 | function log (msg) { t.equal(msg, 555) } 15 | })); 16 | }); 17 | 18 | test('inline object call', function (t) { 19 | t.plan(1); 20 | var sm = staticModule({ 21 | beep: { f: function (n) { return n * 111 } } 22 | }); 23 | readStream('obj_call.js').pipe(sm).pipe(concat(function (body) { 24 | Function(['console'],body)({ log: log }); 25 | function log (msg) { t.equal(msg, 555) } 26 | })); 27 | }); 28 | 29 | test('inline object expression', function (t) { 30 | t.plan(1); 31 | var sm = staticModule({ 32 | beep: { f: function (n) { return n * 111 } } 33 | }); 34 | readStream('obj_expr.js').pipe(sm).pipe(concat(function (body) { 35 | Function(['console'],body)({ log: log }); 36 | function log (msg) { t.equal(msg, 1110) } 37 | })); 38 | }); 39 | 40 | test('inline function', function (t) { 41 | t.plan(1); 42 | var sm = staticModule({ 43 | beep: function (n) { return n * 111 } 44 | }); 45 | readStream('fn.js').pipe(sm).pipe(concat(function (body) { 46 | Function(['console'],body)({ log: log }); 47 | function log (msg) { t.equal(msg, 555) } 48 | })); 49 | }); 50 | 51 | test('inline function call', function (t) { 52 | t.plan(1); 53 | var sm = staticModule({ 54 | beep: function (n) { return n * 111 } 55 | }); 56 | readStream('fn_call.js').pipe(sm).pipe(concat(function (body) { 57 | Function(['console'],body)({ log: log }); 58 | function log (msg) { t.equal(msg, 555) } 59 | })); 60 | }); 61 | 62 | test('inline function expression', function (t) { 63 | t.plan(1); 64 | var sm = staticModule({ 65 | beep: function (n) { return n * 111 } 66 | }); 67 | readStream('fn_expr.js').pipe(sm).pipe(concat(function (body) { 68 | Function(['console'],body)({ log: log }); 69 | function log (msg) { t.equal(msg, 1665) } 70 | })); 71 | }); 72 | 73 | function readStream (file) { 74 | return fs.createReadStream(path.join(__dirname, 'inline', file)); 75 | } 76 | -------------------------------------------------------------------------------- /test/inline/fn.js: -------------------------------------------------------------------------------- 1 | var x = require('beep')(5); 2 | console.log(x); 3 | -------------------------------------------------------------------------------- /test/inline/fn_call.js: -------------------------------------------------------------------------------- 1 | console.log(require('beep')(5)); 2 | -------------------------------------------------------------------------------- /test/inline/fn_expr.js: -------------------------------------------------------------------------------- 1 | console.log(require('beep')(5) * 3); 2 | -------------------------------------------------------------------------------- /test/inline/obj.js: -------------------------------------------------------------------------------- 1 | var x = require('beep').f(5); 2 | console.log(x); 3 | -------------------------------------------------------------------------------- /test/inline/obj_call.js: -------------------------------------------------------------------------------- 1 | console.log(require('beep').f(5)); 2 | -------------------------------------------------------------------------------- /test/inline/obj_expr.js: -------------------------------------------------------------------------------- 1 | console.log(require('beep').f(5) * 2); 2 | -------------------------------------------------------------------------------- /test/keep-used.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var concat = require('concat-stream'); 3 | var staticModule = require('../'); 4 | var fs = require('fs'); 5 | var path = require('path'); 6 | 7 | test('keep requires if their uses cannot be resolved', function (t) { 8 | t.plan(1); 9 | 10 | var sm = staticModule({ 11 | 'insert-css': function (src) { 12 | return JSON.stringify(hash(src)); 13 | } 14 | }); 15 | readStream('source.js').pipe(sm).pipe(concat(function (body) { 16 | t.equal(body.toString('utf8'), 17 | 'var insertCSS = require(\'insert-css\');\n' 18 | + '\n' + 19 | '"_4e552b4ec7";\n' + 20 | '// can\'t replace this\n' + 21 | 'insertCSS(window.__style);\n' 22 | ); 23 | })); 24 | }); 25 | 26 | test('keep requires if they are still used', function (t) { 27 | t.plan(3); 28 | var filename = path.join(__dirname, 'keep-used/fs.js'); 29 | var expected = [ 30 | "contents", 31 | fs.statSync(filename).size 32 | ]; 33 | var sm = staticModule({ 34 | fs: { 35 | readFileSync: function () { 36 | return '"contents"'; 37 | } 38 | } 39 | }, { vars: { __filename: filename } }); 40 | readStream('fs.js').pipe(sm).pipe(concat(function (body) { 41 | t.equal(body.toString('utf8'), 42 | 'fs = require(\'fs\'),\n' 43 | + '\n' 44 | + ' console.log("contents"),\n' 45 | + ' console.log(fs.statSync(__filename).size)\n' 46 | ); 47 | var fn = Function('require', '__filename', 'console', body.toString('utf8')); 48 | fn(require, filename, { 49 | log: function (v) { 50 | t.equal(v, expected.shift()); 51 | } 52 | }); 53 | })); 54 | }); 55 | 56 | function readStream (file) { 57 | return fs.createReadStream(path.join(__dirname, 'keep-used', file)); 58 | } 59 | function hash (str) { 60 | return '_' + require('crypto').createHash('sha256').update(str).digest('hex').slice(0, 10); 61 | } 62 | -------------------------------------------------------------------------------- /test/keep-used/fs.js: -------------------------------------------------------------------------------- 1 | fs = require('fs'), 2 | 3 | console.log(fs.readFileSync(__filename)), 4 | console.log(fs.statSync(__filename).size) 5 | -------------------------------------------------------------------------------- /test/keep-used/source.js: -------------------------------------------------------------------------------- 1 | var insertCSS = require('insert-css'); 2 | 3 | insertCSS('.a { color: red }'); 4 | // can't replace this 5 | insertCSS(window.__style); 6 | -------------------------------------------------------------------------------- /test/limit-parsing.js: -------------------------------------------------------------------------------- 1 | var concat = require('concat-stream'); 2 | var from = require('from2-string'); 3 | var staticModule = require('../'); 4 | var test = require('tape'); 5 | 6 | test('limit parsing to files including a target module', function (t) { 7 | var passInput = 'THIS WILL NOT PARSE'; 8 | var failInput = passInput + '; require("fs")'; 9 | 10 | t.plan(2); 11 | 12 | from(passInput) 13 | .pipe(staticModule({ fs: require('fs') })) 14 | .pipe(concat(function (passOutput) { 15 | t.equal(passInput, String(passOutput), 'does not parse'); 16 | })); 17 | 18 | from(failInput) 19 | .pipe(staticModule({ fs: require('fs') })) 20 | .once('error', function () { 21 | t.pass('parses if module is included'); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/log.js: -------------------------------------------------------------------------------- 1 | var staticModule = require('../'); 2 | var test = require('tape'); 3 | var concat = require('concat-stream'); 4 | var quote = require('quote-stream'); 5 | var fs = require('fs'); 6 | var path = require('path'); 7 | 8 | test('stream into a console.log', function (t) { 9 | t.plan(1); 10 | var sm = staticModule({ 11 | beep: function () { 12 | var q = quote(); 13 | q.end('eek'); 14 | return q; 15 | } 16 | }, { vars: { __dirname: path.join(__dirname, 'brfs') } }); 17 | readStream('source.js').pipe(sm).pipe(concat(function (body) { 18 | t.equal(body.toString('utf8'), 'console.log("eek");\n'); 19 | })); 20 | }); 21 | 22 | test('trickle stream into a console.log', function (t) { 23 | t.plan(1); 24 | var sm = staticModule({ 25 | beep: function () { 26 | var q = quote(); 27 | var chunks = [ 'beep', ' boop', ' robots' ]; 28 | var iv = setInterval(function () { 29 | if (chunks.length === 0) { 30 | clearInterval(iv); 31 | q.end(); 32 | } 33 | else q.write(chunks.shift()); 34 | }, 10); 35 | return q; 36 | } 37 | }, { vars: { __dirname: path.join(__dirname, 'brfs') } }); 38 | readStream('source.js').pipe(sm).pipe(concat(function (body) { 39 | t.equal(body.toString('utf8'), 'console.log("beep boop robots");\n'); 40 | })); 41 | }); 42 | 43 | function readStream (file) { 44 | return fs.createReadStream(path.join(__dirname, 'log', file)); 45 | } 46 | -------------------------------------------------------------------------------- /test/log/source.js: -------------------------------------------------------------------------------- 1 | console.log(require('beep')()); 2 | -------------------------------------------------------------------------------- /test/many.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var concat = require('concat-stream'); 3 | var quote = require('quote-stream'); 4 | var staticModule = require('../'); 5 | var fs = require('fs'); 6 | var path = require('path'); 7 | 8 | test('many instances', function (t) { 9 | t.plan(2); 10 | 11 | var sm = staticModule({ 12 | fs: { readFileSync: function (file) { 13 | return fs.createReadStream(file).pipe(quote()); 14 | } } 15 | }, { vars: { __dirname: path.join(__dirname, 'many') } }); 16 | readStream('source.js').pipe(sm).pipe(concat(function (body) { 17 | Function(['console'],body)({ log: log }); 18 | t.equal( 19 | body.toString('utf8'), 20 | '\nvar a = "A!\\n";\n' 21 | + 'var b = "B!\\n";\n' 22 | + 'var c = "C!\\n";\n' 23 | + 'console.log(a + b + c);\n' 24 | ); 25 | function log (msg) { t.equal(msg, 'A!\nB!\nC!\n') } 26 | })); 27 | }); 28 | 29 | test('expansions inline', function (t) { 30 | t.plan(2); 31 | 32 | var sm = staticModule({ 33 | fs: { readFileSync: function (file) { 34 | return fs.createReadStream(file).pipe(quote()); 35 | } } 36 | }, { vars: { __dirname: path.join(__dirname, 'many') } }); 37 | readStream('inline.js').pipe(sm).pipe(concat(function (body) { 38 | Function(['console'],body)({ log: log }); 39 | t.equal( 40 | body.toString('utf8'), 41 | '\nvar a = "A!\\n",\n' 42 | + ' b = "B!\\n",\n' 43 | + ' c = "C!\\n"\n' 44 | + ';\n' 45 | + 'console.log(a + b + c);\n' 46 | ); 47 | function log (msg) { t.equal(msg, 'A!\nB!\nC!\n') } 48 | })); 49 | }); 50 | 51 | test('all inline', function (t) { 52 | t.plan(2); 53 | 54 | var sm = staticModule({ 55 | fs: { readFileSync: function (file) { 56 | return fs.createReadStream(file).pipe(quote()); 57 | } } 58 | }, { vars: { __dirname: path.join(__dirname, 'many') } }); 59 | readStream('all_inline.js').pipe(sm).pipe(concat(function (body) { 60 | Function(['console'],body)({ log: log }); 61 | t.equal( 62 | body.toString('utf8'), 63 | 'var a = "A!\\n",\n' 64 | + ' b = "B!\\n",\n' 65 | + ' c = "C!\\n"\n' 66 | + ';\n' 67 | + 'console.log(a + b + c);\n' 68 | ); 69 | function log (msg) { t.equal(msg, 'A!\nB!\nC!\n') } 70 | })); 71 | }); 72 | 73 | function readStream (file) { 74 | return fs.createReadStream(path.join(__dirname, 'many', file)); 75 | } 76 | -------------------------------------------------------------------------------- /test/many/a.txt: -------------------------------------------------------------------------------- 1 | A! 2 | -------------------------------------------------------------------------------- /test/many/all_inline.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'), 2 | a = fs.readFileSync(__dirname + '/a.txt', 'utf8'), 3 | b = fs.readFileSync(__dirname + '/b.txt', 'utf8'), 4 | c = fs.readFileSync(__dirname + '/c.txt', 'utf8') 5 | ; 6 | console.log(a + b + c); 7 | -------------------------------------------------------------------------------- /test/many/b.txt: -------------------------------------------------------------------------------- 1 | B! 2 | -------------------------------------------------------------------------------- /test/many/c.txt: -------------------------------------------------------------------------------- 1 | C! 2 | -------------------------------------------------------------------------------- /test/many/inline.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var a = fs.readFileSync(__dirname + '/a.txt', 'utf8'), 3 | b = fs.readFileSync(__dirname + '/b.txt', 'utf8'), 4 | c = fs.readFileSync(__dirname + '/c.txt', 'utf8') 5 | ; 6 | console.log(a + b + c); 7 | -------------------------------------------------------------------------------- /test/many/source.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var a = fs.readFileSync(__dirname + '/a.txt', 'utf8'); 3 | var b = fs.readFileSync(__dirname + '/b.txt', 'utf8'); 4 | var c = fs.readFileSync(__dirname + '/c.txt', 'utf8'); 5 | console.log(a + b + c); 6 | -------------------------------------------------------------------------------- /test/mixed.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var concat = require('concat-stream'); 3 | var quote = require('quote-stream'); 4 | var staticModule = require('../'); 5 | var fs = require('fs'); 6 | var path = require('path'); 7 | 8 | test('mixed nested objects and streams', function (t) { 9 | t.plan(4); 10 | 11 | var expected = [ 12, 'oh hello\n', 555 ]; 12 | var sm = staticModule({ 13 | beep: { 14 | x: { y: { z: 4 } }, 15 | quote: { 16 | read: function (file) { 17 | return fs.createReadStream(file).pipe(quote()); 18 | } 19 | }, 20 | f: { g: { h: function (n) { return n * 111 } } } 21 | } 22 | }, { vars: { __dirname: path.join(__dirname, 'mixed') } }); 23 | readStream('source.js').pipe(sm).pipe(concat(function (body) { 24 | Function(['console'],body)({ log: log }); 25 | t.equal( 26 | body.toString('utf8'), 27 | '\nconsole.log(4 * 3);' 28 | + '\nconsole.log("oh hello\\n");' 29 | + '\nconsole.log(555);\n' 30 | ); 31 | function log (msg) { t.equal(msg, expected.shift()) } 32 | })); 33 | }); 34 | 35 | test('mixed objects and streams', function (t) { 36 | t.plan(4); 37 | 38 | var expected = [ 12, 'oh hello\n', 555 ]; 39 | var sm = staticModule({ 40 | beep: { 41 | x: 4, 42 | quote: function (file) { 43 | return fs.createReadStream(file).pipe(quote()); 44 | }, 45 | f: function (n) { return n * 111 } 46 | } 47 | }, { vars: { __dirname: path.join(__dirname, 'mixed') } }); 48 | readStream('unmixed.js').pipe(sm).pipe(concat(function (body) { 49 | Function(['console'],body)({ log: log }); 50 | t.equal( 51 | body.toString('utf8'), 52 | '\nconsole.log(4 * 3);' 53 | + '\nconsole.log("oh hello\\n");' 54 | + '\nconsole.log(555);\n' 55 | ); 56 | function log (msg) { t.equal(msg, expected.shift()) } 57 | })); 58 | }); 59 | 60 | function readStream (file) { 61 | return fs.createReadStream(path.join(__dirname, 'mixed', file)); 62 | } 63 | -------------------------------------------------------------------------------- /test/mixed/source.js: -------------------------------------------------------------------------------- 1 | var b = require('beep'); 2 | console.log(b.x.y.z * 3); 3 | console.log(b.quote.read(__dirname + '/xyz.txt')); 4 | console.log(b.f.g.h(5)); 5 | -------------------------------------------------------------------------------- /test/mixed/unmixed.js: -------------------------------------------------------------------------------- 1 | var b = require('beep'); 2 | console.log(b.x * 3); 3 | console.log(b.quote(__dirname + '/xyz.txt')); 4 | console.log(b.f(5)); 5 | -------------------------------------------------------------------------------- /test/mixed/xyz.txt: -------------------------------------------------------------------------------- 1 | oh hello 2 | -------------------------------------------------------------------------------- /test/nested.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var concat = require('concat-stream'); 3 | var staticModule = require('../'); 4 | var fs = require('fs'); 5 | var path = require('path'); 6 | 7 | test('nested object', function (t) { 8 | t.plan(3); 9 | 10 | var expected = [ 12, 555 ]; 11 | var sm = staticModule({ 12 | beep: { 13 | x: { y: { z: 4 } }, 14 | f: { g: { h: function (n) { return n * 111 } } } 15 | } 16 | }); 17 | readStream('source.js').pipe(sm).pipe(concat(function (body) { 18 | Function(['console'],body)({ log: log }); 19 | t.equal( 20 | body.toString('utf8'), 21 | '\nconsole.log(4 * 3);\nconsole.log(555);\n' 22 | ); 23 | function log (msg) { t.equal(msg, expected.shift()) } 24 | })); 25 | }); 26 | 27 | function readStream (file) { 28 | return fs.createReadStream(path.join(__dirname, 'nested', file)); 29 | } 30 | -------------------------------------------------------------------------------- /test/nested/source.js: -------------------------------------------------------------------------------- 1 | var b = require('beep'); 2 | console.log(b.x.y.z * 3); 3 | console.log(b.f.g.h(5)); 4 | -------------------------------------------------------------------------------- /test/obj.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var concat = require('concat-stream'); 3 | var staticModule = require('../'); 4 | var fs = require('fs'); 5 | var path = require('path'); 6 | 7 | test('object', function (t) { 8 | t.plan(2); 9 | 10 | var expected = [ 12, 555 ]; 11 | var sm = staticModule({ 12 | beep: { x: 4, f: function (n) { return n * 111 } } 13 | }); 14 | readStream('source.js').pipe(sm).pipe(concat(function (body) { 15 | Function(['console'],body)({ log: log }); 16 | function log (msg) { t.equal(msg, expected.shift()) } 17 | })); 18 | }); 19 | 20 | function readStream (file) { 21 | return fs.createReadStream(path.join(__dirname, 'obj', file)); 22 | } 23 | -------------------------------------------------------------------------------- /test/obj/source.js: -------------------------------------------------------------------------------- 1 | var b = require('beep'); 2 | console.log(b.x * 3); 3 | console.log(b.f(5)); 4 | -------------------------------------------------------------------------------- /test/prop.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var concat = require('concat-stream'); 3 | var staticModule = require('../'); 4 | var fs = require('fs'); 5 | var path = require('path'); 6 | 7 | test('property', function (t) { 8 | t.plan(1); 9 | 10 | var sm = staticModule({ 11 | fff: function (n) { return '[' + (n * 111) + ']' } 12 | }); 13 | readStream('source.js').pipe(sm).pipe(concat(function (body) { 14 | Function(['console'],body)({ log: log }); 15 | function log (msg) { t.deepEqual(msg, '[object Array]') } 16 | })); 17 | }); 18 | 19 | function readStream (file) { 20 | return fs.createReadStream(path.join(__dirname, 'prop', file)); 21 | } 22 | -------------------------------------------------------------------------------- /test/prop/source.js: -------------------------------------------------------------------------------- 1 | var f = require('fff'); 2 | var toString = Object.prototype.toString; 3 | console.log(toString.call(f(5))); 4 | -------------------------------------------------------------------------------- /test/readfile_resolve.js: -------------------------------------------------------------------------------- 1 | var staticModule = require('../'); 2 | var test = require('tape'); 3 | var concat = require('concat-stream'); 4 | var quote = require('quote-stream'); 5 | var through = require('through2'); 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | var resolve = require('resolve'); 9 | 10 | test('readFileSync of require.resolve()', function (t) { 11 | t.plan(1); 12 | var dir = __dirname + '/readfile_resolve'; 13 | function rres (p) { return resolve.sync(p, { basedir: dir }) } 14 | 15 | var vars = { 16 | __dirname: dir, 17 | require: { resolve: rres } 18 | }; 19 | var sm = staticModule({ 20 | fs: { readFileSync: readFileSync } 21 | }, { vars: vars }); 22 | readStream('main.js').pipe(sm).pipe(concat(function (body) { 23 | Function(['console'],body)({ log: log }); 24 | function log (msg) { t.equal(msg, 'amaze\n') } 25 | })); 26 | }); 27 | 28 | function readStream (file) { 29 | return fs.createReadStream(path.join(__dirname, 'readfile_resolve', file)); 30 | } 31 | 32 | function readFileSync (file, opts) { 33 | return fs.createReadStream(file).pipe(quote()); 34 | } 35 | -------------------------------------------------------------------------------- /test/readfile_resolve/main.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var src = fs.readFileSync(require.resolve('aaa/wow.txt'), 'utf8'); 3 | console.log(src); 4 | -------------------------------------------------------------------------------- /test/readfile_resolve/node_modules/aaa/wow.txt: -------------------------------------------------------------------------------- 1 | amaze 2 | -------------------------------------------------------------------------------- /test/scope.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var concat = require('concat-stream'); 3 | var staticModule = require('../'); 4 | var fs = require('fs'); 5 | var path = require('path'); 6 | 7 | test('scope tracking', function (t) { 8 | t.plan(2); 9 | 10 | var sm = staticModule({ 11 | fs: { 12 | readFileSync: function () { return '"read the file!"' } 13 | } 14 | }); 15 | readStream('source.js').pipe(sm).pipe(concat(function (body) { 16 | Function(['T'],body)(t); 17 | })); 18 | }); 19 | 20 | test('block scope', { skip: !supportsBlockScope() }, function (t) { 21 | t.plan(2); 22 | 23 | var sm = staticModule({ 24 | fs: { 25 | readFileSync: function () { return '"read the file!"' } 26 | } 27 | }); 28 | readStream('block.js').pipe(sm).pipe(concat(function (body) { 29 | Function(['T'],body)(t); 30 | })); 31 | }); 32 | 33 | function readStream (file) { 34 | return fs.createReadStream(path.join(__dirname, 'scope', file)); 35 | } 36 | function supportsBlockScope () { 37 | try { 38 | return eval('{ let a = true; a }'); 39 | } catch (err) { 40 | return false; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/scope/block.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | { // hello block scope 3 | let fs = { readFileSync: () => 'abc' } 4 | T.equal(fs.readFileSync(), 'abc') 5 | } 6 | 7 | T.equal( fs.readFileSync(), 'read the file!' ) 8 | -------------------------------------------------------------------------------- /test/scope/source.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | function a ( fs ) { 3 | return fs.readFileSync() // should not be replaced 4 | } 5 | T.equal( 6 | a( { readFileSync : function () { return 'xyz' } } ), 7 | 'xyz' 8 | ) 9 | 10 | T.equal( fs.readFileSync(), 'read the file!' ) 11 | -------------------------------------------------------------------------------- /test/shebang.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var concat = require('concat-stream'); 3 | var staticModule = require('../'); 4 | var fs = require('fs'); 5 | var path = require('path'); 6 | 7 | test('shebang', function (t) { 8 | t.plan(2); 9 | 10 | var expected = [ 12, 555 ]; 11 | var sm = staticModule({ 12 | beep: { x: 4, f: function (n) { return n * 111 } } 13 | }); 14 | readStream('source.js').pipe(sm).pipe(concat(function (body) { 15 | Function(['console'],body)({ log: log }); 16 | function log (msg) { t.equal(msg, expected.shift()) } 17 | })); 18 | }); 19 | 20 | function readStream (file) { 21 | return fs.createReadStream(path.join(__dirname, 'shebang', file)); 22 | } 23 | -------------------------------------------------------------------------------- /test/shebang/source.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var b = require('beep'); 3 | console.log(b.x * 3); 4 | console.log(b.f(5)); 5 | -------------------------------------------------------------------------------- /test/sourcemap.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var fs = require('fs'); 3 | var concat = require('concat-stream'); 4 | var PassThrough = require('stream').PassThrough; 5 | var convertSourceMap = require('convert-source-map'); 6 | var SourceMapConsumer = require('source-map').SourceMapConsumer; 7 | var uglify = require('uglify-js'); 8 | var staticModule = require('../'); 9 | 10 | test('source maps', function (t) { 11 | t.plan(6); 12 | 13 | var transform = staticModule({ 14 | sheetify: function (filename) { 15 | var stream = PassThrough(); 16 | stream.write('`.css{\n'); 17 | stream.write(' color: red;\n'); 18 | stream.end('}`'); 19 | return stream; 20 | } 21 | }, { sourceMap: true, inputFilename: 'main.js' }); 22 | 23 | fs.createReadStream(__dirname + '/sourcemap/main.js').pipe(transform).pipe(concat({ encoding: 'string' }, function (res) { 24 | var consumer = new SourceMapConsumer(convertSourceMap.fromSource(res).toObject()); 25 | 26 | var mapped = consumer.originalPositionFor({ 27 | line: 8, 28 | column: 0 29 | }); 30 | t.equal(mapped.line, 8); 31 | t.equal(mapped.column, 0); 32 | 33 | mapped = consumer.originalPositionFor({ 34 | line: 10, 35 | column: 2 36 | }); 37 | t.equal(mapped.line, 8); 38 | t.equal(mapped.column, 19); 39 | 40 | mapped = consumer.originalPositionFor({ 41 | line: 12, 42 | column: 0 43 | }); 44 | t.equal(mapped.line, 10); 45 | t.equal(mapped.column, 0); 46 | })); 47 | }); 48 | 49 | test('input source map', function (t) { 50 | t.plan(4); 51 | 52 | var content = fs.readFileSync(__dirname + '/sourcemap/main.js', 'utf8'); 53 | var minified = uglify.minify({ 'main.js': content }, { 54 | output: { beautify: true }, 55 | sourceMap: { 56 | url: 'inline', 57 | includeSources: true 58 | } 59 | }); 60 | 61 | var transform = staticModule({ 62 | sheetify: function (filename) { 63 | var stream = PassThrough(); 64 | stream.end('`.css{\n color: orange;\n}`'); 65 | return stream; 66 | } 67 | }, { sourceMap: true, inputFilename: 'main.js' }); 68 | 69 | transform.pipe(concat({ encoding: 'string' }, function (res) { 70 | var consumer = new SourceMapConsumer(convertSourceMap.fromSource(res).toObject()); 71 | 72 | var mapped = consumer.originalPositionFor({ 73 | line: 7, 74 | column: 0 75 | }); 76 | t.equal(mapped.line, 8); 77 | t.equal(mapped.column, 0); 78 | 79 | mapped = consumer.originalPositionFor({ 80 | line: 9, 81 | column: 4 82 | }); 83 | t.equal(mapped.line, 10); 84 | t.equal(mapped.column, 0); 85 | })); 86 | 87 | transform.end(minified.code); 88 | }); 89 | 90 | test('retain input source map when file has no static-module use', function (t) { 91 | t.plan(4); 92 | 93 | var content = fs.readFileSync(__dirname + '/sourcemap/main.js', 'utf8'); 94 | var minified = uglify.minify({ 'main.js': content }, { 95 | output: { beautify: true }, 96 | sourceMap: { 97 | url: 'inline', 98 | includeSources: true 99 | } 100 | }); 101 | 102 | var transform = staticModule({ 103 | not_sheetify: function () { return 'whatever'; } 104 | }, { sourceMap: true, inputFilename: 'main.js' }); 105 | 106 | transform.pipe(concat({ encoding: 'string' }, function (res) { 107 | var consumer = new SourceMapConsumer(convertSourceMap.fromSource(res).toObject()); 108 | 109 | var mapped = consumer.originalPositionFor({ 110 | line: 7, 111 | column: 0 112 | }); 113 | t.equal(mapped.line, 8); 114 | t.equal(mapped.column, 0); 115 | 116 | mapped = consumer.originalPositionFor({ 117 | line: 7, 118 | column: 21 119 | }); 120 | t.equal(mapped.line, 10); 121 | t.equal(mapped.column, 0); 122 | })); 123 | 124 | 125 | transform.end(minified.code); 126 | }); 127 | -------------------------------------------------------------------------------- /test/sourcemap/main.js: -------------------------------------------------------------------------------- 1 | var css = require('sheetify'); 2 | 3 | function doSomeStuff () { 4 | // doing some stuff before inlining a static module call 5 | return yadda(yadda) 6 | } 7 | 8 | css('filename.css'); 9 | 10 | exports.blah = whatever.xyz 11 | -------------------------------------------------------------------------------- /test/unary.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var concat = require('concat-stream'); 3 | var staticModule = require('../'); 4 | var fs = require('fs'); 5 | var path = require('path'); 6 | 7 | test('supported unary operator', function (t) { 8 | t.plan(1); 9 | 10 | var expected = [ false ]; 11 | var sm = staticModule({ 12 | beep: { x: 42 } 13 | }); 14 | readStream('supported.js').pipe(sm).pipe(concat(function (body) { 15 | Function(['console'],body)({ log: log }); 16 | function log (msg) { t.equal(msg, expected.shift()) } 17 | })); 18 | }); 19 | 20 | test('unsupported unary operator', function (t) { 21 | t.plan(1) 22 | 23 | var sm = staticModule({ 24 | beep: { x: 42 } 25 | }); 26 | readStream('unsupported.js').pipe(sm).on('error', function (error) { 27 | t.equal(error.message, 'unsupported unary operator: typeof') 28 | }) 29 | }) 30 | 31 | function readStream (file) { 32 | return fs.createReadStream(path.join(__dirname, 'unary', file)); 33 | } 34 | -------------------------------------------------------------------------------- /test/unary/supported.js: -------------------------------------------------------------------------------- 1 | var beep = require('beep') 2 | console.log(!beep) 3 | -------------------------------------------------------------------------------- /test/unary/unsupported.js: -------------------------------------------------------------------------------- 1 | var beep = require('beep') 2 | console.log(typeof beep) 3 | -------------------------------------------------------------------------------- /test/varmod.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var concat = require('concat-stream'); 3 | var quote = require('quote-stream'); 4 | var staticModule = require('../'); 5 | var fs = require('fs'); 6 | var path = require('path'); 7 | 8 | test('variable modules', function (t) { 9 | t.plan(2); 10 | 11 | var expected = [ 'beep boop!' ]; 12 | var sm = staticModule({ 13 | fs: { 14 | readFileSync: function (file, enc) { 15 | return fs.createReadStream(file).pipe(quote()); 16 | } 17 | } 18 | }, { 19 | vars: { __dirname: path.join(__dirname, 'vars') }, 20 | varModules: { path: require('path') } 21 | }); 22 | 23 | readStream('source.js').pipe(sm).pipe(concat(function (body) { 24 | t.equal( 25 | body.toString('utf8'), 26 | '\nvar path = require(\'path\');' 27 | + '\nvar html = "beep boop";\nvar x = \'!\';' 28 | + '\nconsole.log(html + x);\n' 29 | ); 30 | Function(['console','require'],body)({ log: log },require); 31 | function log (msg) { t.equal(msg, expected.shift()) } 32 | })); 33 | }); 34 | 35 | function readStream (file) { 36 | return fs.createReadStream(path.join(__dirname, 'varmod', file)); 37 | } 38 | -------------------------------------------------------------------------------- /test/varmod/source.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var path = require('path'); 3 | var html = fs.readFileSync(path.join(__dirname, 'vars.html'), 'utf8'); 4 | var x = '!'; 5 | console.log(html + x); 6 | -------------------------------------------------------------------------------- /test/varmod/vars.html: -------------------------------------------------------------------------------- 1 | beep boop -------------------------------------------------------------------------------- /test/vars.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var concat = require('concat-stream'); 3 | var quote = require('quote-stream'); 4 | var staticModule = require('../'); 5 | var fs = require('fs'); 6 | var path = require('path'); 7 | 8 | test('multi-vars', function (t) { 9 | t.plan(2); 10 | 11 | var expected = [ 'beep boop!' ]; 12 | var sm = staticModule({ 13 | fs: { 14 | readFileSync: function (file, enc) { 15 | return fs.createReadStream(file).pipe(quote()); 16 | } 17 | } 18 | }, { vars: { __dirname: path.join(__dirname, 'vars') } }); 19 | 20 | readStream('source.js').pipe(sm).pipe(concat(function (body) { 21 | t.equal( 22 | body.toString('utf8'), 23 | 'var html = "beep boop",\n x = \'!\'\n;\nconsole.log(html + x);\n' 24 | ); 25 | Function(['console'],body)({ log: log }); 26 | function log (msg) { t.equal(msg, expected.shift()) } 27 | })); 28 | }); 29 | 30 | test('2-var', function (t) { 31 | t.plan(2); 32 | 33 | var expected = [ 'beep boop' ]; 34 | var sm = staticModule({ 35 | fs: { 36 | readFileSync: function (file, enc) { 37 | return fs.createReadStream(file).pipe(quote()); 38 | } 39 | } 40 | }, { vars: { __dirname: path.join(__dirname, 'vars') } }); 41 | 42 | readStream('one.js').pipe(sm).pipe(concat(function (body) { 43 | t.equal( 44 | body.toString('utf8'), 45 | 'var html = "beep boop"\n;\nconsole.log(html);\n' 46 | ); 47 | Function(['console'],body)({ log: log }); 48 | function log (msg) { t.equal(msg, expected.shift()) } 49 | })); 50 | }); 51 | 52 | test('5-var', function (t) { 53 | t.plan(1); 54 | 55 | var expected = [ 'beep boop123' ]; 56 | var sm = staticModule({ 57 | fs: { 58 | readFileSync: function (file, enc) { 59 | return fs.createReadStream(file).pipe(quote()); 60 | } 61 | } 62 | }, { vars: { __dirname: path.join(__dirname, 'vars') } }); 63 | 64 | readStream('five.js').pipe(sm).pipe(concat(function (body) { 65 | Function(['console'],body)({ log: log }); 66 | function log (msg) { t.equal(msg, expected.shift()) } 67 | })); 68 | }); 69 | 70 | test('multi consecutive require vars', function (t) { 71 | t.plan(1); 72 | 73 | var expected = [ 'beep boop' ]; 74 | var sm = staticModule({ 75 | fs: { 76 | readFileSync: function (file, enc) { 77 | return fs.createReadStream(file).pipe(quote()); 78 | } 79 | } 80 | }, { 81 | vars: { __dirname: path.join(__dirname, 'vars') }, 82 | sourceMap: true // Make sure source maps work when replacing 0 length ranges. 83 | }); 84 | 85 | readStream('multi-require.js').pipe(sm).pipe(concat(function (body) { 86 | Function(['console','require'],body)({ log: log }, function() { return {} }); 87 | function log (msg) { t.equal(msg, expected.shift()) } 88 | })); 89 | }); 90 | 91 | function readStream (file) { 92 | return fs.createReadStream(path.join(__dirname, 'vars', file)); 93 | } 94 | -------------------------------------------------------------------------------- /test/vars/five.js: -------------------------------------------------------------------------------- 1 | var a = 1, fs = require('fs'), 2 | b = 2, 3 | html = fs.readFileSync(__dirname + '/vars.html', 'utf8'), 4 | c = 3 5 | ; 6 | console.log(html + a + b + c); 7 | -------------------------------------------------------------------------------- /test/vars/multi-require.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'), 2 | tls = require('tls'), 3 | zlib = require('zlib'), 4 | Socket = require('net').Socket, 5 | EventEmitter = require('events').EventEmitter, 6 | inherits = require('util').inherits, 7 | inspect = require('util').inspect; 8 | 9 | var foo = require('foo'); 10 | var bar = require('bar'); 11 | 12 | var html = fs.readFileSync(__dirname + '/vars.html', 'utf8'); 13 | 14 | console.log(html); 15 | -------------------------------------------------------------------------------- /test/vars/one.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'), 2 | html = fs.readFileSync(__dirname + '/vars.html', 'utf8') 3 | ; 4 | console.log(html); 5 | -------------------------------------------------------------------------------- /test/vars/source.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'), 2 | html = fs.readFileSync(__dirname + '/vars.html', 'utf8'), 3 | x = '!' 4 | ; 5 | console.log(html + x); 6 | -------------------------------------------------------------------------------- /test/vars/vars.html: -------------------------------------------------------------------------------- 1 | beep boop --------------------------------------------------------------------------------