+84
-41
@@ -57,3 +57,3 @@ var fs = require('fs'); | ||
| var symbols = []; | ||
| for (var match = rx.exec(source); match !== null; match = rx.exec()) { | ||
| for (var match = rx.exec(source); match !== null; match = rx.exec(source)) { | ||
| symbols.push(match[1]); | ||
@@ -68,3 +68,3 @@ } | ||
| ++count; | ||
| match = rx.exec(); | ||
| match = rx.exec(source); | ||
| } | ||
@@ -104,5 +104,39 @@ if (count !== symbols.length) { | ||
| */ | ||
| function autoload(root, loaders, ondone) { | ||
| function autoload(root, loaders, cachePath, ondone) { | ||
| if (!ondone) { | ||
| ondone = cachePath; | ||
| cachePath = undefined; | ||
| } | ||
| var cache = Object.create(null); | ||
| function injectSymbols(path, loader, symbols) { | ||
| for (var ii = 0; ii < symbols.length; ++ii) { | ||
| // It's possible the symbol has already been defined, in which case we should avoid | ||
| // clobbering it with the autoloader. | ||
| if (!loader.scope.hasOwnProperty(symbols[ii])) { | ||
| ~function(loader, symbol) { | ||
| Object.defineProperty(loader.scope, symbol, { | ||
| get: function() { | ||
| delete loader.scope[symbol]; | ||
| loader.require(path); | ||
| if (loader.scope.hasOwnProperty(symbol)) { | ||
| return loader.scope[symbol]; | ||
| } else { | ||
| throw new Error('Failed to autoload ' + symbol); | ||
| } | ||
| }, | ||
| set: function(val) { | ||
| delete loader.scope[symbol]; | ||
| loader.scope[symbol] = val; | ||
| }, | ||
| configurable: true, | ||
| enumerable: true, | ||
| }); | ||
| }(loader, symbols[ii]); | ||
| } | ||
| } | ||
| } | ||
| function autoloader(path, ondone) { | ||
| var fullPath = joinPath(root, path); | ||
| var fullPath = path ? joinPath(root, path) : root; | ||
@@ -126,44 +160,39 @@ fs.stat(fullPath, function(err, stat) { | ||
| // Read the file from disk to pass to parsers | ||
| fs.readFile(fullPath, 'utf-8', function(err, source) { | ||
| if (err) { | ||
| throw new Error(err); | ||
| } | ||
| // Exists in cache? | ||
| if (fullPath in cache && cache[fullPath].mtime === +stat.mtime) { | ||
| for (var ii = 0; ii < loaders.length; ++ii) { | ||
| if (loaders[ii].pattern.test(path)) { | ||
| // Parse and register autoloading loaders | ||
| var symbols = loaders[ii].parse(source); | ||
| for (var jj = 0; jj < symbols.length; ++jj) { | ||
| // It's possible the symbol has already been defined, in which case we should avoid | ||
| // clobbering it with the autoloader. | ||
| if (!loaders[ii].scope.hasOwnProperty(symbols[jj])) { | ||
| ~function(loader, symbol) { | ||
| Object.defineProperty(loader.scope, symbol, { | ||
| get: function() { | ||
| delete loader.scope[symbol]; | ||
| loader.require(path); | ||
| if (loader.scope.hasOwnProperty(symbol)) { | ||
| return loader.scope[symbol]; | ||
| } else { | ||
| throw new Error('Failed to autoload ' + symbol); | ||
| } | ||
| }, | ||
| set: function(val) { | ||
| delete loader.scope[symbol]; | ||
| loader.scope[symbol] = val; | ||
| }, | ||
| configurable: true, | ||
| enumerable: true, | ||
| }); | ||
| }(loaders[ii], symbols[jj]); | ||
| } | ||
| } | ||
| var symbols = cache[fullPath].symbols[ii]; | ||
| injectSymbols(path, loaders[ii], symbols); | ||
| } | ||
| } | ||
| ondone(); | ||
| }); | ||
| } else { | ||
| } else if (stat.isDirectory()) { | ||
| // Read the file from disk to pass to parsers | ||
| fs.readFile(fullPath, 'utf-8', function(err, source) { | ||
| if (err) { | ||
| throw new Error(err); | ||
| } | ||
| cache[fullPath] = { | ||
| mtime: +stat.mtime, | ||
| symbols: [], | ||
| }; | ||
| for (var ii = 0; ii < loaders.length; ++ii) { | ||
| if (loaders[ii].pattern.test(path)) { | ||
| // Parse and register autoloading loaders | ||
| var symbols = loaders[ii].parse(source, path); | ||
| cache[fullPath].symbols.push(symbols); | ||
| injectSymbols(path, loaders[ii], symbols); | ||
| } else { | ||
| cache[fullPath].symbols.push(null); | ||
| } | ||
| } | ||
| ondone(); | ||
| }); | ||
| } | ||
| } else if (stat.isDirectory() && path !== 'node_modules') { | ||
| // Descend directory | ||
@@ -185,3 +214,3 @@ fs.readdir(fullPath, function(err, files) { | ||
| ~function(a) { | ||
| autoloader(joinPath(path, files[ii]), function() { | ||
| autoloader(path ? joinPath(path, files[ii]) : files[ii], function() { | ||
| if (!--remaining) { | ||
@@ -202,3 +231,17 @@ return ondone(); | ||
| } | ||
| autoloader(false, ondone); | ||
| if (cachePath) { | ||
| fs.readFile(cachePath, 'utf-8', function(err, val) { | ||
| if (!err) { | ||
| try { | ||
| cache = JSON.parse(val); | ||
| cache.__proto__ = null; | ||
| } catch (err) {} | ||
| } | ||
| autoloader(false, function(err, val) { | ||
| fs.writeFile(cachePath, JSON.stringify(cache), 'utf-8', ondone); | ||
| }); | ||
| }); | ||
| } else { | ||
| autoloader(false, ondone); | ||
| } | ||
| } |
+1
-1
| { | ||
| "name": "autoload", | ||
| "version": "0.1.1", | ||
| "version": "0.1.2", | ||
| "description": "Autoloading symbols via source code grokking", | ||
@@ -5,0 +5,0 @@ "keywords": ["autoload", "require"], |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Non-existent author
Supply chain riskThe package was published by an npm account that no longer exists.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
10339
11.53%225
22.28%0
-100%1
Infinity%