chushihua

This commit is contained in:
li
2026-01-26 23:20:48 +08:00
commit 7b5aab0206
22521 changed files with 3300090 additions and 0 deletions
+118
View File
@@ -0,0 +1,118 @@
# enhanced-resolve
Offers an async require.resolve function. It's highly configurable.
## Features
* plugin system
* provide a custom filesystem
* sync and async node.js filesystems included
## Getting Started
### Install
```sh
# npm
npm install enhanced-resolve
# or Yarn
yarn add enhanced-resolve
```
### Creating a Resolver
The easiest way to create a resolver is to use the `createResolver` function on `ResolveFactory`, along with one of the supplied File System implementations.
```js
const {
NodeJsInputFileSystem,
CachedInputFileSystem,
ResolverFactory
} = require('enhanced-resolve');
// create a resolver
const myResolver = ResolverFactory.createResolver({
// Typical usage will consume the `NodeJsInputFileSystem` + `CachedInputFileSystem`, which wraps the Node.js `fs` wrapper to add resilience + caching.
fileSystem: new CachedInputFileSystem(new NodeJsInputFileSystem(), 4000),
extensions: ['.js', '.json']
/* any other resolver options here. Options/defaults can be seen below */
});
// resolve a file with the new resolver
const context = {};
const lookupStartPath = '/Users/webpack/some/root/dir';
const request = './path/to-look-up.js';
myResolver.resolve({}, lookupStartPath, request, (err/*Error*/, filepath/*string*/) => {
// Do something with the path
});
```
For more examples creating different types resolvers (sync/async, context, etc) see `lib/node.js`.
#### Resolver Options
| Field | Default | Description |
| ------------------------ | --------------------------- | ---------------------------------------------------------------------------------- |
| modules | ["node_modules"] | A list of directories to resolve modules from, can be absolute path or folder name |
| descriptionFiles | ["package.json"] | A list of description files to read from |
| plugins | [] | A list of additional resolve plugins which should be applied |
| mainFields | ["main"] | A list of main fields in description files |
| aliasFields | [] | A list of alias fields in description files |
| mainFiles | ["index"] | A list of main files in directories |
| extensions | [".js", ".json", ".node"] | A list of extensions which should be tried for files |
| enforceExtension | false | Enforce that a extension from extensions must be used |
| moduleExtensions | [] | A list of module extensions which should be tried for modules |
| enforceModuleExtension | false | Enforce that a extension from moduleExtensions must be used |
| alias | [] | A list of module alias configurations or an object which maps key to value |
| resolveToContext | false | Resolve to a context instead of a file |
| unsafeCache | false | Use this cache object to unsafely cache the successful requests |
| cacheWithContext | true | If unsafe cache is enabled, includes `request.context` in the cache key |
| cachePredicate | function() { return true }; | A function which decides whether a request should be cached or not. An object is passed to the function with `path` and `request` properties. |
| fileSystem | | The file system which should be used |
| resolver | undefined | A prepared Resolver to which the plugins are attached |
## Plugins
Similar to `webpack`, the core of `enhanced-resolve` functionality is implemented as individual plugins that are executed using [`Tapable`](https://github.com/webpack/tapable). These plugins can extend the functionality of the library, adding other ways for files/contexts to be resolved.
A plugin should be a `class` (or its ES5 equivalent) with an `apply` method. The `apply` method will receive a `resolver` instance, that can be used to hook in to the event system.
### Plugin Boilerplate
```js
class MyResolverPlugin {
constructor(source, target) {
this.source = source;
this.target = target;
}
apply(resolver) {
resolver.plugin(this.source, (request, callback) => {
// Any logic you need to create a new `request` can go here
resolver.doResolve(this.target, request, null, callback);
});
}
}
```
Plugins are executed in a pipeline, and register which event they should be executed before/after. In the example above, `source` is the name of the event that starts the pipeline, and `target` is what event this plugin should fire, which is what continues the execution of the pipeline. For an example of how these different plugin events create a chain, see `lib/ResolverFactory.js`, in the `//// pipeline ////` section.
## Tests
``` javascript
npm test
```
[![Build Status](https://secure.travis-ci.org/webpack/enhanced-resolve.png?branch=master)](http://travis-ci.org/webpack/enhanced-resolve)
## Passing options from webpack
If you are using `webpack`, and you want to pass custom options to `enhanced-resolve`, the options are passed from the `resolve` key of your webpack configuration e.g.:
```
resolve: {
extensions: ['', '.js', '.jsx'],
modules: ['src', 'node_modules'],
plugins: [new DirectoryNamedWebpackPlugin()]
...
},
```
## License
Copyright (c) 2012-2016 Tobias Koppers
MIT (http://www.opensource.org/licenses/mit-license.php)
+51
View File
@@ -0,0 +1,51 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var DescriptionFileUtils = require("./DescriptionFileUtils");
var createInnerCallback = require("./createInnerCallback");
var getInnerRequest = require("./getInnerRequest");
function AliasFieldPlugin(source, field, target) {
this.source = source;
this.field = field;
this.target = target;
}
module.exports = AliasFieldPlugin;
AliasFieldPlugin.prototype.apply = function(resolver) {
var target = this.target;
var field = this.field;
resolver.plugin(this.source, function(request, callback) {
if(!request.descriptionFileData) return callback();
var innerRequest = getInnerRequest(resolver, request);
if(!innerRequest) return callback();
var fieldData = DescriptionFileUtils.getField(request.descriptionFileData, field);
if(typeof fieldData !== "object") {
if(callback.log) callback.log("Field '" + field + "' doesn't contain a valid alias configuration");
return callback();
}
var data1 = fieldData[innerRequest];
var data2 = fieldData[innerRequest.replace(/^\.\//, "")];
var data = typeof data1 !== "undefined" ? data1 : data2;
if(data === innerRequest) return callback();
if(data === undefined) return callback();
if(data === false) {
var ignoreObj = Object.assign({}, request, {
path: false
});
return callback(null, ignoreObj);
}
var obj = Object.assign({}, request, {
path: request.descriptionFileRoot,
request: data
});
resolver.doResolve(target, obj, "aliased from description file " + request.descriptionFilePath + " with mapping '" + innerRequest + "' to '" + data + "'", createInnerCallback(function(err, result) {
if(arguments.length > 0) return callback(err, result);
// Don't allow other aliasing or raw request
callback(null, null);
}, callback));
});
};
+57
View File
@@ -0,0 +1,57 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var createInnerCallback = require("./createInnerCallback");
function startsWith(string, searchString) {
var stringLength = string.length;
var searchLength = searchString.length;
// early out if the search length is greater than the search string
if(searchLength > stringLength) {
return false;
}
var index = -1;
while(++index < searchLength) {
if(string.charCodeAt(index) !== searchString.charCodeAt(index)) {
return false;
}
}
return true;
}
function AliasPlugin(source, options, target) {
this.source = source;
this.name = options.name;
this.alias = options.alias;
this.onlyModule = options.onlyModule;
this.target = target;
}
module.exports = AliasPlugin;
AliasPlugin.prototype.apply = function(resolver) {
var target = this.target;
var name = this.name;
var alias = this.alias;
var onlyModule = this.onlyModule;
resolver.plugin(this.source, function(request, callback) {
var innerRequest = request.request;
if(!innerRequest) return callback();
if(innerRequest === name || (!onlyModule && startsWith(innerRequest, name + "/"))) {
if(innerRequest !== alias && !startsWith(innerRequest, alias + "/")) {
var newRequestStr = alias + innerRequest.substr(name.length);
var obj = Object.assign({}, request, {
request: newRequestStr
});
return resolver.doResolve(target, obj, "aliased with mapping '" + name + "': '" + alias + "' to '" + newRequestStr + "'", createInnerCallback(function(err, result) {
if(arguments.length > 0) return callback(err, result);
// don't allow other aliasing or raw request
callback(null, null);
}, callback));
}
}
return callback();
});
};
+22
View File
@@ -0,0 +1,22 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
function AppendPlugin(source, appending, target) {
this.source = source;
this.appending = appending;
this.target = target;
}
module.exports = AppendPlugin;
AppendPlugin.prototype.apply = function(resolver) {
var target = this.target;
var appending = this.appending;
resolver.plugin(this.source, function(request, callback) {
var obj = Object.assign({}, request, {
path: request.path + appending,
relativePath: request.relativePath && (request.relativePath + appending)
});
resolver.doResolve(target, obj, appending, callback);
});
};
+271
View File
@@ -0,0 +1,271 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
function Storage(duration) {
this.duration = duration;
this.running = new Map();
this.data = new Map();
this.levels = [];
if(duration > 0) {
this.levels.push(new Set(), new Set(), new Set(), new Set(), new Set(), new Set(), new Set(), new Set(), new Set());
for(var i = 8000; i < duration; i += 500)
this.levels.push(new Set());
}
this.count = 0;
this.interval = null;
this.needTickCheck = false;
this.nextTick = null;
this.passive = true;
this.tick = this.tick.bind(this);
}
Storage.prototype.ensureTick = function() {
if(!this.interval && this.duration > 0 && !this.nextTick)
this.interval = setInterval(this.tick, Math.floor(this.duration / this.levels.length));
};
Storage.prototype.finished = function(name, err, result) {
var callbacks = this.running.get(name);
this.running.delete(name);
if(this.duration > 0) {
this.data.set(name, [err, result]);
var levelData = this.levels[0];
this.count -= levelData.size;
levelData.add(name);
this.count += levelData.size;
this.ensureTick();
}
for(var i = 0; i < callbacks.length; i++) {
callbacks[i](err, result);
}
};
Storage.prototype.finishedSync = function(name, err, result) {
if(this.duration > 0) {
this.data.set(name, [err, result]);
var levelData = this.levels[0];
this.count -= levelData.size;
levelData.add(name);
this.count += levelData.size;
this.ensureTick();
}
};
Storage.prototype.provide = function(name, provider, callback) {
if(typeof name !== "string") {
callback(new TypeError("path must be a string"));
return;
}
var running = this.running.get(name);
if(running) {
running.push(callback);
return;
}
if(this.duration > 0) {
this.checkTicks();
var data = this.data.get(name);
if(data) {
return process.nextTick(function() {
callback.apply(null, data);
});
}
}
this.running.set(name, running = [callback]);
var _this = this;
provider(name, function(err, result) {
_this.finished(name, err, result);
});
};
Storage.prototype.provideSync = function(name, provider) {
if(typeof name !== "string") {
throw new TypeError("path must be a string");
}
if(this.duration > 0) {
this.checkTicks();
var data = this.data.get(name);
if(data) {
if(data[0])
throw data[0];
return data[1];
}
}
try {
var result = provider(name);
} catch(e) {
this.finishedSync(name, e);
throw e;
}
this.finishedSync(name, null, result);
return result;
};
Storage.prototype.tick = function() {
var decay = this.levels.pop();
for(var item of decay) {
this.data.delete(item);
}
this.count -= decay.size;
decay.clear();
this.levels.unshift(decay);
if(this.count === 0) {
clearInterval(this.interval);
this.interval = null;
this.nextTick = null;
return true;
} else if(this.nextTick) {
this.nextTick += Math.floor(this.duration / this.levels.length);
var time = new Date().getTime();
if(this.nextTick > time) {
this.nextTick = null;
this.interval = setInterval(this.tick, Math.floor(this.duration / this.levels.length));
return true;
}
} else if(this.passive) {
clearInterval(this.interval);
this.interval = null;
this.nextTick = new Date().getTime() + Math.floor(this.duration / this.levels.length);
} else {
this.passive = true;
}
};
Storage.prototype.checkTicks = function() {
this.passive = false;
if(this.nextTick) {
while(!this.tick());
}
};
Storage.prototype.purge = function(what) {
if(!what) {
this.count = 0;
clearInterval(this.interval);
this.nextTick = null;
this.data.clear();
this.levels.forEach(function(level) {
level.clear();
});
} else if(typeof what === "string") {
for(var key of this.data.keys()) {
if(key.startsWith(what))
this.data.delete(key);
}
} else {
for(var i = what.length - 1; i >= 0; i--) {
this.purge(what[i]);
}
}
};
function CachedInputFileSystem(fileSystem, duration) {
this.fileSystem = fileSystem;
this._statStorage = new Storage(duration);
this._readdirStorage = new Storage(duration);
this._readFileStorage = new Storage(duration);
this._readJsonStorage = new Storage(duration);
this._readlinkStorage = new Storage(duration);
this._stat = this.fileSystem.stat ? this.fileSystem.stat.bind(this.fileSystem) : null;
if(!this._stat) this.stat = null;
this._statSync = this.fileSystem.statSync ? this.fileSystem.statSync.bind(this.fileSystem) : null;
if(!this._statSync) this.statSync = null;
this._readdir = this.fileSystem.readdir ? this.fileSystem.readdir.bind(this.fileSystem) : null;
if(!this._readdir) this.readdir = null;
this._readdirSync = this.fileSystem.readdirSync ? this.fileSystem.readdirSync.bind(this.fileSystem) : null;
if(!this._readdirSync) this.readdirSync = null;
this._readFile = this.fileSystem.readFile ? this.fileSystem.readFile.bind(this.fileSystem) : null;
if(!this._readFile) this.readFile = null;
this._readFileSync = this.fileSystem.readFileSync ? this.fileSystem.readFileSync.bind(this.fileSystem) : null;
if(!this._readFileSync) this.readFileSync = null;
if(this.fileSystem.readJson) {
this._readJson = this.fileSystem.readJson.bind(this.fileSystem);
} else if(this.readFile) {
this._readJson = function(path, callback) {
this.readFile(path, function(err, buffer) {
if(err) return callback(err);
try {
var data = JSON.parse(buffer.toString("utf-8"));
} catch(e) {
return callback(e);
}
callback(null, data);
});
}.bind(this);
} else {
this.readJson = null;
}
if(this.fileSystem.readJsonSync) {
this._readJsonSync = this.fileSystem.readJsonSync.bind(this.fileSystem);
} else if(this.readFileSync) {
this._readJsonSync = function(path) {
var buffer = this.readFileSync(path);
var data = JSON.parse(buffer.toString("utf-8"));
return data;
}.bind(this);
} else {
this.readJsonSync = null;
}
this._readlink = this.fileSystem.readlink ? this.fileSystem.readlink.bind(this.fileSystem) : null;
if(!this._readlink) this.readlink = null;
this._readlinkSync = this.fileSystem.readlinkSync ? this.fileSystem.readlinkSync.bind(this.fileSystem) : null;
if(!this._readlinkSync) this.readlinkSync = null;
}
module.exports = CachedInputFileSystem;
CachedInputFileSystem.prototype.stat = function(path, callback) {
this._statStorage.provide(path, this._stat, callback);
};
CachedInputFileSystem.prototype.readdir = function(path, callback) {
this._readdirStorage.provide(path, this._readdir, callback);
};
CachedInputFileSystem.prototype.readFile = function(path, callback) {
this._readFileStorage.provide(path, this._readFile, callback);
};
CachedInputFileSystem.prototype.readJson = function(path, callback) {
this._readJsonStorage.provide(path, this._readJson, callback);
};
CachedInputFileSystem.prototype.readlink = function(path, callback) {
this._readlinkStorage.provide(path, this._readlink, callback);
};
CachedInputFileSystem.prototype.statSync = function(path) {
return this._statStorage.provideSync(path, this._statSync);
};
CachedInputFileSystem.prototype.readdirSync = function(path) {
return this._readdirStorage.provideSync(path, this._readdirSync);
};
CachedInputFileSystem.prototype.readFileSync = function(path) {
return this._readFileStorage.provideSync(path, this._readFileSync);
};
CachedInputFileSystem.prototype.readJsonSync = function(path) {
return this._readJsonStorage.provideSync(path, this._readJsonSync);
};
CachedInputFileSystem.prototype.readlinkSync = function(path) {
return this._readlinkStorage.provideSync(path, this._readlinkSync);
};
CachedInputFileSystem.prototype.purge = function(what) {
this._statStorage.purge(what);
this._readdirStorage.purge(what);
this._readFileStorage.purge(what);
this._readlinkStorage.purge(what);
this._readJsonStorage.purge(what);
};
+24
View File
@@ -0,0 +1,24 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var basename = require("./getPaths").basename;
function CloneBasenamePlugin(source, target) {
this.source = source;
this.target = target;
}
module.exports = CloneBasenamePlugin;
CloneBasenamePlugin.prototype.apply = function(resolver) {
var target = this.target;
resolver.plugin(this.source, function(request, callback) {
var filename = basename(request.path);
var filePath = resolver.join(request.path, filename);
var obj = Object.assign({}, request, {
path: filePath,
relativePath: request.relativePath && resolver.join(request.relativePath, filename)
});
resolver.doResolve(target, obj, "using path: " + filePath, callback);
});
};
+37
View File
@@ -0,0 +1,37 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var concord = require("./concord");
var DescriptionFileUtils = require("./DescriptionFileUtils");
var forEachBail = require("./forEachBail");
var createInnerCallback = require("./createInnerCallback");
function ConcordExtensionsPlugin(source, options, target) {
this.source = source;
this.options = options;
this.target = target;
}
module.exports = ConcordExtensionsPlugin;
ConcordExtensionsPlugin.prototype.apply = function(resolver) {
var target = this.target;
resolver.plugin(this.source, function(request, callback) {
var concordField = DescriptionFileUtils.getField(request.descriptionFileData, "concord");
if(!concordField) return callback();
var extensions = concord.getExtensions(request.context, concordField);
if(!extensions) return callback();
var topLevelCallback = callback;
forEachBail(extensions, function(appending, callback) {
var obj = Object.assign({}, request, {
path: request.path + appending,
relativePath: request.relativePath && (request.relativePath + appending)
});
resolver.doResolve(target, obj, "concord extension: " + appending, createInnerCallback(callback, topLevelCallback));
}, function(err, result) {
if(arguments.length > 0) return callback(err, result);
callback(null, null);
});
});
};
+30
View File
@@ -0,0 +1,30 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var path = require("path");
var concord = require("./concord");
var DescriptionFileUtils = require("./DescriptionFileUtils");
function ConcordMainPlugin(source, options, target) {
this.source = source;
this.options = options;
this.target = target;
}
module.exports = ConcordMainPlugin;
ConcordMainPlugin.prototype.apply = function(resolver) {
var target = this.target;
resolver.plugin(this.source, function(request, callback) {
if(request.path !== request.descriptionFileRoot) return callback();
var concordField = DescriptionFileUtils.getField(request.descriptionFileData, "concord");
if(!concordField) return callback();
var mainModule = concord.getMain(request.context, concordField);
if(!mainModule) return callback();
var obj = Object.assign({}, request, {
request: mainModule
});
var filename = path.basename(request.descriptionFilePath);
return resolver.doResolve(target, obj, "use " + mainModule + " from " + filename, callback);
});
};
+44
View File
@@ -0,0 +1,44 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var concord = require("./concord");
var DescriptionFileUtils = require("./DescriptionFileUtils");
var createInnerCallback = require("./createInnerCallback");
var getInnerRequest = require("./getInnerRequest");
function ConcordModulesPlugin(source, options, target) {
this.source = source;
this.options = options;
this.target = target;
}
module.exports = ConcordModulesPlugin;
ConcordModulesPlugin.prototype.apply = function(resolver) {
var target = this.target;
resolver.plugin(this.source, function(request, callback) {
var innerRequest = getInnerRequest(resolver, request);
if(!innerRequest) return callback();
var concordField = DescriptionFileUtils.getField(request.descriptionFileData, "concord");
if(!concordField) return callback();
var data = concord.matchModule(request.context, concordField, innerRequest);
if(data === innerRequest) return callback();
if(data === undefined) return callback();
if(data === false) {
var ignoreObj = Object.assign({}, request, {
path: false
});
return callback(null, ignoreObj);
}
var obj = Object.assign({}, request, {
path: request.descriptionFileRoot,
request: data
});
resolver.doResolve(target, obj, "aliased from description file " + request.descriptionFilePath + " with mapping '" + innerRequest + "' to '" + data + "'", createInnerCallback(function(err, result) {
if(arguments.length > 0) return callback(err, result);
// Don't allow other aliasing or raw request
callback(null, null);
}, callback));
});
};
+51
View File
@@ -0,0 +1,51 @@
"use strict";
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
const createInnerCallback = require("./createInnerCallback");
const DescriptionFileUtils = require("./DescriptionFileUtils");
class DescriptionFilePlugin {
constructor(source, filenames, target) {
this.source = source;
this.filenames = [].concat(filenames);
this.target = target;
}
apply(resolver) {
const filenames = this.filenames;
const target = this.target;
resolver.plugin(this.source, (request, callback) => {
const directory = request.path;
DescriptionFileUtils.loadDescriptionFile(resolver, directory, filenames, ((err, result) => {
if(err) return callback(err);
if(!result) {
if(callback.missing) {
filenames.forEach((filename) => {
callback.missing.push(resolver.join(directory, filename));
});
}
if(callback.log) callback.log("No description file found");
return callback();
}
const relativePath = "." + request.path.substr(result.directory.length).replace(/\\/g, "/");
const obj = Object.assign({}, request, {
descriptionFilePath: result.path,
descriptionFileData: result.content,
descriptionFileRoot: result.directory,
relativePath: relativePath
});
resolver.doResolve(target, obj, "using description file: " + result.path + " (relative path: " + relativePath + ")", createInnerCallback((err, result) => {
if(err) return callback(err);
if(result) return callback(null, result);
// Don't allow other description files or none at all
callback(null, null);
}, callback));
}));
});
}
}
module.exports = DescriptionFilePlugin;
+93
View File
@@ -0,0 +1,93 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var forEachBail = require("./forEachBail");
function loadDescriptionFile(resolver, directory, filenames, callback) {
(function findDescriptionFile() {
forEachBail(filenames, function(filename, callback) {
var descriptionFilePath = resolver.join(directory, filename);
if(resolver.fileSystem.readJson) {
resolver.fileSystem.readJson(descriptionFilePath, function(err, content) {
if(err) {
if(typeof err.code !== "undefined") return callback();
return onJson(err);
}
onJson(null, content);
});
} else {
resolver.fileSystem.readFile(descriptionFilePath, function(err, content) {
if(err) return callback();
try {
var json = JSON.parse(content);
} catch(e) {
onJson(e);
}
onJson(null, json);
});
}
function onJson(err, content) {
if(err) {
if(callback.log)
callback.log(descriptionFilePath + " (directory description file): " + err);
else
err.message = descriptionFilePath + " (directory description file): " + err;
return callback(err);
}
callback(null, {
content: content,
directory: directory,
path: descriptionFilePath
});
}
}, function(err, result) {
if(err) return callback(err);
if(result) {
return callback(null, result);
} else {
directory = cdUp(directory);
if(!directory) {
return callback();
} else {
return findDescriptionFile();
}
}
});
}());
}
function getField(content, field) {
if(!content) return undefined;
if(Array.isArray(field)) {
var current = content;
for(var j = 0; j < field.length; j++) {
if(current === null || typeof current !== "object") {
current = null;
break;
}
current = current[field[j]];
}
if(typeof current === "object") {
return current;
}
} else {
if(typeof content[field] === "object") {
return content[field];
}
}
}
function cdUp(directory) {
if(directory === "/") return null;
var i = directory.lastIndexOf("/"),
j = directory.lastIndexOf("\\");
var p = i < 0 ? j : j < 0 ? i : i < j ? j : i;
if(p < 0) return null;
return directory.substr(0, p || 1);
}
exports.loadDescriptionFile = loadDescriptionFile;
exports.getField = getField;
exports.cdUp = cdUp;
+30
View File
@@ -0,0 +1,30 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
function DirectoryExistsPlugin(source, target) {
this.source = source;
this.target = target;
}
module.exports = DirectoryExistsPlugin;
DirectoryExistsPlugin.prototype.apply = function(resolver) {
var target = this.target;
resolver.plugin(this.source, function(request, callback) {
var fs = this.fileSystem;
var directory = request.path;
fs.stat(directory, function(err, stat) {
if(err || !stat) {
if(callback.missing) callback.missing.push(directory);
if(callback.log) callback.log(directory + " doesn't exist");
return callback();
}
if(!stat.isDirectory()) {
if(callback.missing) callback.missing.push(directory);
if(callback.log) callback.log(directory + " is not a directory");
return callback();
}
this.doResolve(target, request, "existing directory", callback);
}.bind(this));
});
};
+30
View File
@@ -0,0 +1,30 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
function FileExistsPlugin(source, target) {
this.source = source;
this.target = target;
}
module.exports = FileExistsPlugin;
FileExistsPlugin.prototype.apply = function(resolver) {
var target = this.target;
resolver.plugin(this.source, function(request, callback) {
var fs = this.fileSystem;
var file = request.path;
fs.stat(file, function(err, stat) {
if(err || !stat) {
if(callback.missing) callback.missing.push(file);
if(callback.log) callback.log(file + " doesn't exist");
return callback();
}
if(!stat.isFile()) {
if(callback.missing) callback.missing.push(file);
if(callback.log) callback.log(file + " is not a file");
return callback();
}
this.doResolve(target, request, "existing file: " + file, callback, true);
}.bind(this));
});
};
+19
View File
@@ -0,0 +1,19 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
function FileKindPlugin(source, target) {
this.source = source;
this.target = target;
}
module.exports = FileKindPlugin;
FileKindPlugin.prototype.apply = function(resolver) {
var target = this.target;
resolver.plugin(this.source, function(request, callback) {
if(request.directory) return callback();
var obj = Object.assign({}, request);
delete obj.directory;
resolver.doResolve(target, obj, null, callback);
});
};
+21
View File
@@ -0,0 +1,21 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
function JoinRequestPlugin(source, target) {
this.source = source;
this.target = target;
}
module.exports = JoinRequestPlugin;
JoinRequestPlugin.prototype.apply = function(resolver) {
var target = this.target;
resolver.plugin(this.source, function(request, callback) {
var obj = Object.assign({}, request, {
path: resolver.join(request.path, request.request),
relativePath: request.relativePath && resolver.join(request.relativePath, request.request),
request: undefined
});
resolver.doResolve(target, obj, null, callback);
});
};
+25
View File
@@ -0,0 +1,25 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
function LogInfoPlugin(source) {
this.source = source;
}
module.exports = LogInfoPlugin;
LogInfoPlugin.prototype.apply = function(resolver) {
var source = this.source;
resolver.plugin(this.source, function(request, callback) {
if(!callback.log) return callback();
var log = callback.log;
var prefix = "[" + source + "] ";
if(request.path) log(prefix + "Resolving in directory: " + request.path);
if(request.request) log(prefix + "Resolving request: " + request.request);
if(request.module) log(prefix + "Request is an module request.");
if(request.directory) log(prefix + "Request is a directory request.");
if(request.query) log(prefix + "Resolving request query: " + request.query);
if(request.descriptionFilePath) log(prefix + "Has description data from " + request.descriptionFilePath);
if(request.relativePath) log(prefix + "Relative path from description file is: " + request.relativePath);
callback();
});
};
+48
View File
@@ -0,0 +1,48 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var path = require("path");
function MainFieldPlugin(source, options, target) {
this.source = source;
this.options = options;
this.target = target;
}
module.exports = MainFieldPlugin;
MainFieldPlugin.prototype.apply = function(resolver) {
var target = this.target;
var options = this.options;
resolver.plugin(this.source, function mainField(request, callback) {
if(request.path !== request.descriptionFileRoot) return callback();
var content = request.descriptionFileData;
var filename = path.basename(request.descriptionFilePath);
var mainModule;
var field = options.name;
if(Array.isArray(field)) {
var current = content;
for(var j = 0; j < field.length; j++) {
if(current === null || typeof current !== "object") {
current = null;
break;
}
current = current[field[j]];
}
if(typeof current === "string") {
mainModule = current;
}
} else {
if(typeof content[field] === "string") {
mainModule = content[field];
}
}
if(!mainModule) return callback();
if(options.forceRelative && !/^\.\.?\//.test(mainModule))
mainModule = "./" + mainModule;
var obj = Object.assign({}, request, {
request: mainModule
});
return resolver.doResolve(target, obj, "use " + mainModule + " from " + options.name + " in " + filename, callback);
});
};
+35
View File
@@ -0,0 +1,35 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
function ModuleAppendPlugin(source, appending, target) {
this.source = source;
this.appending = appending;
this.target = target;
}
module.exports = ModuleAppendPlugin;
ModuleAppendPlugin.prototype.apply = function(resolver) {
var appending = this.appending;
var target = this.target;
resolver.plugin(this.source, function(request, callback) {
var i = request.request.indexOf("/"),
j = request.request.indexOf("\\");
var p = i < 0 ? j : j < 0 ? i : i < j ? i : j;
var moduleName, remainingRequest;
if(p < 0) {
moduleName = request.request;
remainingRequest = "";
} else {
moduleName = request.request.substr(0, p);
remainingRequest = request.request.substr(p);
}
if(moduleName === "." || moduleName === "..")
return callback();
var moduleFinalName = moduleName + appending;
var obj = Object.assign({}, request, {
request: moduleFinalName + remainingRequest
});
resolver.doResolve(target, obj, "module variation " + moduleFinalName, callback);
});
};
+26
View File
@@ -0,0 +1,26 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var createInnerCallback = require("./createInnerCallback");
function ModuleKindPlugin(source, target) {
this.source = source;
this.target = target;
}
module.exports = ModuleKindPlugin;
ModuleKindPlugin.prototype.apply = function(resolver) {
var target = this.target;
resolver.plugin(this.source, function(request, callback) {
if(!request.module) return callback();
var obj = Object.assign({}, request);
delete obj.module;
resolver.doResolve(target, obj, "resolve as module", createInnerCallback(function(err, result) {
if(arguments.length > 0) return callback(err, result);
// Don't allow other alternatives
callback(null, null);
}, callback));
});
};
@@ -0,0 +1,46 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var createInnerCallback = require("./createInnerCallback");
var forEachBail = require("./forEachBail");
var getPaths = require("./getPaths");
function ModulesInHierachicDirectoriesPlugin(source, directories, target) {
this.source = source;
this.directories = [].concat(directories);
this.target = target;
}
module.exports = ModulesInHierachicDirectoriesPlugin;
ModulesInHierachicDirectoriesPlugin.prototype.apply = function(resolver) {
var directories = this.directories;
var target = this.target;
resolver.plugin(this.source, function(request, callback) {
var fs = this.fileSystem;
var topLevelCallback = callback;
var addrs = getPaths(request.path).paths.map(function(p) {
return directories.map(function(d) {
return this.join(p, d);
}, this);
}, this).reduce(function(array, p) {
array.push.apply(array, p);
return array;
}, []);
forEachBail(addrs, function(addr, callback) {
fs.stat(addr, function(err, stat) {
if(!err && stat && stat.isDirectory()) {
var obj = Object.assign({}, request, {
path: addr,
request: "./" + request.request
});
var message = "looking for modules in " + addr;
return resolver.doResolve(target, obj, message, createInnerCallback(callback, topLevelCallback));
}
if(topLevelCallback.log) topLevelCallback.log(addr + " doesn't exist or is not a directory");
if(topLevelCallback.missing) topLevelCallback.missing.push(addr);
return callback();
});
}, callback);
});
};
+22
View File
@@ -0,0 +1,22 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
function ModulesInRootPlugin(source, path, target) {
this.source = source;
this.path = path;
this.target = target;
}
module.exports = ModulesInRootPlugin;
ModulesInRootPlugin.prototype.apply = function(resolver) {
var target = this.target;
var path = this.path;
resolver.plugin(this.source, function(request, callback) {
var obj = Object.assign({}, request, {
path: path,
request: "./" + request.request
});
resolver.doResolve(target, obj, "looking for modules in " + path, callback, true);
});
};
+16
View File
@@ -0,0 +1,16 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
function NextPlugin(source, target) {
this.source = source;
this.target = target;
}
module.exports = NextPlugin;
NextPlugin.prototype.apply = function(resolver) {
var target = this.target;
resolver.plugin(this.source, function(request, callback) {
resolver.doResolve(target, request, null, callback);
});
};
+29
View File
@@ -0,0 +1,29 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var fs = require("graceful-fs");
function NodeJsInputFileSystem() {}
module.exports = NodeJsInputFileSystem;
NodeJsInputFileSystem.prototype.stat = fs.stat.bind(fs);
NodeJsInputFileSystem.prototype.readdir = function readdir(path, callback) {
fs.readdir(path, function(err, files) {
callback(err, files && files.map(function(file) {
return file.normalize ? file.normalize("NFC") : file;
}));
});
};
NodeJsInputFileSystem.prototype.readFile = fs.readFile.bind(fs);
NodeJsInputFileSystem.prototype.readlink = fs.readlink.bind(fs);
NodeJsInputFileSystem.prototype.statSync = fs.statSync.bind(fs);
NodeJsInputFileSystem.prototype.readdirSync = function readdirSync(path) {
var files = fs.readdirSync(path);
return files && files.map(function(file) {
return file.normalize ? file.normalize("NFC") : file;
});
};
NodeJsInputFileSystem.prototype.readFileSync = fs.readFileSync.bind(fs);
NodeJsInputFileSystem.prototype.readlinkSync = fs.readlinkSync.bind(fs);
+27
View File
@@ -0,0 +1,27 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
function ParsePlugin(source, target) {
this.source = source;
this.target = target;
}
module.exports = ParsePlugin;
ParsePlugin.prototype.apply = function(resolver) {
var target = this.target;
resolver.plugin(this.source, function(request, callback) {
var parsed = resolver.parse(request.request);
var obj = Object.assign({}, request, parsed);
if(request.query && !parsed.query) {
obj.query = request.query;
}
if(parsed && callback.log) {
if(parsed.module)
callback.log("Parsed request is a module");
if(parsed.directory)
callback.log("Parsed request is a directory");
}
resolver.doResolve(target, obj, null, callback);
});
};
+227
View File
@@ -0,0 +1,227 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var Tapable = require("tapable");
var createInnerCallback = require("./createInnerCallback");
function Resolver(fileSystem) {
Tapable.call(this);
this.fileSystem = fileSystem;
}
module.exports = Resolver;
Resolver.prototype = Object.create(Tapable.prototype);
Resolver.prototype.constructor = Resolver;
Resolver.prototype.resolveSync = function resolveSync(context, path, request) {
var err, result, sync = false;
this.resolve(context, path, request, function(e, r) {
err = e;
result = r;
sync = true;
});
if(!sync) throw new Error("Cannot 'resolveSync' because the fileSystem is not sync. Use 'resolve'!");
if(err) throw err;
return result;
};
Resolver.prototype.resolve = function resolve(context, path, request, callback) {
if(arguments.length === 3) {
throw new Error("Signature changed: context parameter added");
}
var resolver = this;
var obj = {
context: context,
path: path,
request: request
};
var localMissing;
var log;
var message = "resolve '" + request + "' in '" + path + "'";
function writeLog(msg) {
log.push(msg);
}
function logAsString() {
return log.join("\n");
}
function onError(err, result) {
if(callback.log) {
for(var i = 0; i < log.length; i++)
callback.log(log[i]);
}
if(err) return callback(err);
var error = new Error("Can't " + message);
error.details = logAsString();
error.missing = localMissing;
resolver.applyPlugins("no-resolve", obj, error);
return callback(error);
}
function onResolve(err, result) {
if(!err && result) {
return callback(null, result.path === false ? false : result.path + (result.query || ""), result);
}
localMissing = [];
log = [];
return resolver.doResolve("resolve", obj, message, createInnerCallback(onError, {
log: writeLog,
missing: localMissing,
stack: callback.stack
}));
}
onResolve.missing = callback.missing;
onResolve.stack = callback.stack;
return this.doResolve("resolve", obj, message, onResolve);
};
Resolver.prototype.doResolve = function doResolve(type, request, message, callback) {
var resolver = this;
var stackLine = type + ": (" + request.path + ") " +
(request.request || "") + (request.query || "") +
(request.directory ? " directory" : "") +
(request.module ? " module" : "");
var newStack = [stackLine];
if(callback.stack) {
newStack = callback.stack.concat(newStack);
if(callback.stack.indexOf(stackLine) >= 0) {
// Prevent recursion
var recursionError = new Error("Recursion in resolving\nStack:\n " + newStack.join("\n "));
recursionError.recursion = true;
if(callback.log) callback.log("abort resolving because of recursion");
return callback(recursionError);
}
}
resolver.applyPlugins("resolve-step", type, request);
var beforePluginName = "before-" + type;
if(resolver.hasPlugins(beforePluginName)) {
resolver.applyPluginsAsyncSeriesBailResult1(beforePluginName, request, createInnerCallback(beforeInnerCallback, {
log: callback.log,
missing: callback.missing,
stack: newStack
}, message && ("before " + message), true));
} else {
runNormal();
}
function beforeInnerCallback(err, result) {
if(arguments.length > 0) {
if(err) return callback(err);
if(result) return callback(null, result);
return callback();
}
runNormal();
}
function runNormal() {
if(resolver.hasPlugins(type)) {
return resolver.applyPluginsAsyncSeriesBailResult1(type, request, createInnerCallback(innerCallback, {
log: callback.log,
missing: callback.missing,
stack: newStack
}, message));
} else {
runAfter();
}
}
function innerCallback(err, result) {
if(arguments.length > 0) {
if(err) return callback(err);
if(result) return callback(null, result);
return callback();
}
runAfter();
}
function runAfter() {
var afterPluginName = "after-" + type;
if(resolver.hasPlugins(afterPluginName)) {
return resolver.applyPluginsAsyncSeriesBailResult1(afterPluginName, request, createInnerCallback(afterInnerCallback, {
log: callback.log,
missing: callback.missing,
stack: newStack
}, message && ("after " + message), true));
} else {
callback();
}
}
function afterInnerCallback(err, result) {
if(arguments.length > 0) {
if(err) return callback(err);
if(result) return callback(null, result);
return callback();
}
return callback();
}
};
Resolver.prototype.parse = function parse(identifier) {
if(identifier === "") return null;
var part = {
request: "",
query: "",
module: false,
directory: false,
file: false
};
var idxQuery = identifier.indexOf("?");
if(idxQuery === 0) {
part.query = identifier;
} else if(idxQuery > 0) {
part.request = identifier.slice(0, idxQuery);
part.query = identifier.slice(idxQuery);
} else {
part.request = identifier;
}
if(part.request) {
part.module = this.isModule(part.request);
part.directory = this.isDirectory(part.request);
if(part.directory) {
part.request = part.request.substr(0, part.request.length - 1);
}
}
return part;
};
var notModuleRegExp = /^\.$|^\.[\\\/]|^\.\.$|^\.\.[\/\\]|^\/|^[A-Z]:[\\\/]/i;
Resolver.prototype.isModule = function isModule(path) {
return !notModuleRegExp.test(path);
};
var directoryRegExp = /[\/\\]$/i;
Resolver.prototype.isDirectory = function isDirectory(path) {
return directoryRegExp.test(path);
};
var memoryFsJoin = require("memory-fs/lib/join");
var memoizedJoin = new Map();
Resolver.prototype.join = function(path, request) {
var cacheEntry;
var pathCache = memoizedJoin.get(path);
if(typeof pathCache === "undefined") {
memoizedJoin.set(path, pathCache = new Map());
} else {
cacheEntry = pathCache.get(request);
if(typeof cacheEntry !== "undefined")
return cacheEntry;
}
cacheEntry = memoryFsJoin(path, request);
pathCache.set(request, cacheEntry);
return cacheEntry;
};
Resolver.prototype.normalize = require("memory-fs/lib/normalize");
+273
View File
@@ -0,0 +1,273 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var Resolver = require("./Resolver");
var SyncAsyncFileSystemDecorator = require("./SyncAsyncFileSystemDecorator");
var ParsePlugin = require("./ParsePlugin");
var DescriptionFilePlugin = require("./DescriptionFilePlugin");
var NextPlugin = require("./NextPlugin");
var TryNextPlugin = require("./TryNextPlugin");
var ModuleKindPlugin = require("./ModuleKindPlugin");
var FileKindPlugin = require("./FileKindPlugin");
var JoinRequestPlugin = require("./JoinRequestPlugin");
var ModulesInHierachicDirectoriesPlugin = require("./ModulesInHierachicDirectoriesPlugin");
var ModulesInRootPlugin = require("./ModulesInRootPlugin");
var AliasPlugin = require("./AliasPlugin");
var AliasFieldPlugin = require("./AliasFieldPlugin");
var ConcordExtensionsPlugin = require("./ConcordExtensionsPlugin");
var ConcordMainPlugin = require("./ConcordMainPlugin");
var ConcordModulesPlugin = require("./ConcordModulesPlugin");
var DirectoryExistsPlugin = require("./DirectoryExistsPlugin");
var FileExistsPlugin = require("./FileExistsPlugin");
var SymlinkPlugin = require("./SymlinkPlugin");
var MainFieldPlugin = require("./MainFieldPlugin");
var UseFilePlugin = require("./UseFilePlugin");
var AppendPlugin = require("./AppendPlugin");
var ResultPlugin = require("./ResultPlugin");
var ModuleAppendPlugin = require("./ModuleAppendPlugin");
var UnsafeCachePlugin = require("./UnsafeCachePlugin");
exports.createResolver = function(options) {
//// OPTIONS ////
// A list of directories to resolve modules from, can be absolute path or folder name
var modules = options.modules || ["node_modules"];
// A list of description files to read from
var descriptionFiles = options.descriptionFiles || ["package.json"];
// A list of additional resolve plugins which should be applied
// The slice is there to create a copy, because otherwise pushing into plugins
// changes the original options.plugins array, causing duplicate plugins
var plugins = (options.plugins && options.plugins.slice()) || [];
// A list of main fields in description files
var mainFields = options.mainFields || ["main"];
// A list of alias fields in description files
var aliasFields = options.aliasFields || [];
// A list of main files in directories
var mainFiles = options.mainFiles || ["index"];
// A list of extensions which should be tried for files
var extensions = options.extensions || [".js", ".json", ".node"];
// Enforce that a extension from extensions must be used
var enforceExtension = options.enforceExtension || false;
// A list of module extensions which should be tried for modules
var moduleExtensions = options.moduleExtensions || [];
// Enforce that a extension from moduleExtensions must be used
var enforceModuleExtension = options.enforceModuleExtension || false;
// A list of module alias configurations or an object which maps key to value
var alias = options.alias || [];
// Resolve symlinks to their symlinked location
var symlinks = typeof options.symlinks !== "undefined" ? options.symlinks : true;
// Resolve to a context instead of a file
var resolveToContext = options.resolveToContext || false;
// Use this cache object to unsafely cache the successful requests
var unsafeCache = options.unsafeCache || false;
// Whether or not the unsafeCache should include request context as part of the cache key.
var cacheWithContext = typeof options.cacheWithContext !== "undefined" ? options.cacheWithContext : true;
// A function which decides whether a request should be cached or not.
// an object is passed with `path` and `request` properties.
var cachePredicate = options.cachePredicate || function() {
return true;
};
// The file system which should be used
var fileSystem = options.fileSystem;
// Use only the sync variants of the file system calls
var useSyncFileSystemCalls = options.useSyncFileSystemCalls;
// A prepared Resolver to which the plugins are attached
var resolver = options.resolver;
//// options processing ////
if(!resolver) {
resolver = new Resolver(useSyncFileSystemCalls ? new SyncAsyncFileSystemDecorator(fileSystem) : fileSystem);
}
extensions = [].concat(extensions);
moduleExtensions = [].concat(moduleExtensions);
modules = mergeFilteredToArray([].concat(modules), function(item) {
return !isAbsolutePath(item);
});
mainFields = mainFields.map(function(item) {
if(typeof item === "string") {
item = {
name: item,
forceRelative: true
};
}
return item;
});
if(typeof alias === "object" && !Array.isArray(alias)) {
alias = Object.keys(alias).map(function(key) {
var onlyModule = false;
var obj = alias[key];
if(/\$$/.test(key)) {
onlyModule = true;
key = key.substr(0, key.length - 1);
}
if(typeof obj === "string") {
obj = {
alias: obj
};
}
obj = Object.assign({
name: key,
onlyModule: onlyModule
}, obj);
return obj;
});
}
if(unsafeCache && typeof unsafeCache !== "object") {
unsafeCache = {};
}
//// pipeline ////
// resolve
if(unsafeCache) {
plugins.push(new UnsafeCachePlugin("resolve", cachePredicate, unsafeCache, cacheWithContext, "new-resolve"));
plugins.push(new ParsePlugin("new-resolve", "parsed-resolve"));
} else {
plugins.push(new ParsePlugin("resolve", "parsed-resolve"));
}
// parsed-resolve
plugins.push(new DescriptionFilePlugin("parsed-resolve", descriptionFiles, "described-resolve"));
plugins.push(new NextPlugin("after-parsed-resolve", "described-resolve"));
// described-resolve
alias.forEach(function(item) {
plugins.push(new AliasPlugin("described-resolve", item, "resolve"));
});
plugins.push(new ConcordModulesPlugin("described-resolve", {}, "resolve"));
aliasFields.forEach(function(item) {
plugins.push(new AliasFieldPlugin("described-resolve", item, "resolve"));
});
plugins.push(new ModuleKindPlugin("after-described-resolve", "raw-module"));
plugins.push(new JoinRequestPlugin("after-described-resolve", "relative"));
// raw-module
moduleExtensions.forEach(function(item) {
plugins.push(new ModuleAppendPlugin("raw-module", item, "module"));
});
if(!enforceModuleExtension)
plugins.push(new TryNextPlugin("raw-module", null, "module"));
// module
modules.forEach(function(item) {
if(Array.isArray(item))
plugins.push(new ModulesInHierachicDirectoriesPlugin("module", item, "resolve"));
else
plugins.push(new ModulesInRootPlugin("module", item, "resolve"));
});
// relative
plugins.push(new DescriptionFilePlugin("relative", descriptionFiles, "described-relative"));
plugins.push(new NextPlugin("after-relative", "described-relative"));
// described-relative
plugins.push(new FileKindPlugin("described-relative", "raw-file"));
plugins.push(new TryNextPlugin("described-relative", "as directory", "directory"));
// directory
plugins.push(new DirectoryExistsPlugin("directory", "existing-directory"));
if(resolveToContext) {
// existing-directory
plugins.push(new NextPlugin("existing-directory", "resolved"));
} else {
// existing-directory
plugins.push(new ConcordMainPlugin("existing-directory", {}, "resolve"));
mainFields.forEach(function(item) {
plugins.push(new MainFieldPlugin("existing-directory", item, "resolve"));
});
mainFiles.forEach(function(item) {
plugins.push(new UseFilePlugin("existing-directory", item, "undescribed-raw-file"));
});
// undescribed-raw-file
plugins.push(new DescriptionFilePlugin("undescribed-raw-file", descriptionFiles, "raw-file"));
plugins.push(new NextPlugin("after-undescribed-raw-file", "raw-file"));
// raw-file
if(!enforceExtension)
plugins.push(new TryNextPlugin("raw-file", "no extension", "file"));
plugins.push(new ConcordExtensionsPlugin("raw-file", {}, "file"));
extensions.forEach(function(item) {
plugins.push(new AppendPlugin("raw-file", item, "file"));
});
// file
alias.forEach(function(item) {
plugins.push(new AliasPlugin("file", item, "resolve"));
});
plugins.push(new ConcordModulesPlugin("file", {}, "resolve"));
aliasFields.forEach(function(item) {
plugins.push(new AliasFieldPlugin("file", item, "resolve"));
});
if(symlinks)
plugins.push(new SymlinkPlugin("file", "relative"));
plugins.push(new FileExistsPlugin("file", "existing-file"));
// existing-file
plugins.push(new NextPlugin("existing-file", "resolved"));
}
// resolved
plugins.push(new ResultPlugin("resolved"));
//// RESOLVER ////
plugins.forEach(function(plugin) {
resolver.apply(plugin);
});
return resolver;
};
function mergeFilteredToArray(array, filter) {
return array.reduce(function(array, item) {
if(filter(item)) {
var lastElement = array[array.length - 1];
if(Array.isArray(lastElement)) {
lastElement.push(item);
} else {
array.push([item]);
}
return array;
} else {
array.push(item);
return array;
}
}, []);
}
function isAbsolutePath(path) {
return /^[A-Z]:|^\//.test(path);
}
+18
View File
@@ -0,0 +1,18 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
function ResultPlugin(source) {
this.source = source;
}
module.exports = ResultPlugin;
ResultPlugin.prototype.apply = function(resolver) {
resolver.plugin(this.source, function(request, callback) {
var obj = Object.assign({}, request);
resolver.applyPluginsAsyncSeries1("result", obj, function(err) {
if(err) return callback(err);
callback(null, obj);
});
});
};
+47
View File
@@ -0,0 +1,47 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var getPaths = require("./getPaths");
var forEachBail = require("./forEachBail");
function SymlinkPlugin(source, target) {
this.source = source;
this.target = target;
}
module.exports = SymlinkPlugin;
SymlinkPlugin.prototype.apply = function(resolver) {
var target = this.target;
resolver.plugin(this.source, function(request, callback) {
var _this = this;
var fs = _this.fileSystem;
var pathsResult = getPaths(request.path);
var pathSeqments = pathsResult.seqments;
var paths = pathsResult.paths;
var containsSymlink = false;
forEachBail.withIndex(paths, function(path, idx, callback) {
fs.readlink(path, function(err, result) {
if(!err && result) {
pathSeqments[idx] = result;
containsSymlink = true;
// Shortcut when absolute symlink found
if(/^(\/|[a-zA-z]:($|\\))/.test(result))
return callback(null, idx);
}
callback();
});
}, function(err, idx) {
if(!containsSymlink) return callback();
var resultSeqments = typeof idx === "number" ? pathSeqments.slice(0, idx + 1) : pathSeqments.slice();
var result = resultSeqments.reverse().reduce(function(a, b) {
return _this.join(a, b);
});
var obj = Object.assign({}, request, {
path: result
});
resolver.doResolve(target, obj, "resolved symlink to " + result, callback);
});
});
};
+58
View File
@@ -0,0 +1,58 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
function SyncAsyncFileSystemDecorator(fs) {
this.fs = fs;
if(fs.statSync) {
this.stat = function(arg, callback) {
try {
var result = fs.statSync(arg);
} catch(e) {
return callback(e);
}
callback(null, result);
};
}
if(fs.readdirSync) {
this.readdir = function(arg, callback) {
try {
var result = fs.readdirSync(arg);
} catch(e) {
return callback(e);
}
callback(null, result);
};
}
if(fs.readFileSync) {
this.readFile = function(arg, callback) {
try {
var result = fs.readFileSync(arg);
} catch(e) {
return callback(e);
}
callback(null, result);
};
}
if(fs.readlinkSync) {
this.readlink = function(arg, callback) {
try {
var result = fs.readlinkSync(arg);
} catch(e) {
return callback(e);
}
callback(null, result);
};
}
if(fs.readJsonSync) {
this.readJson = function(arg, callback) {
try {
var result = fs.readJsonSync(arg);
} catch(e) {
return callback(e);
}
callback(null, result);
};
}
}
module.exports = SyncAsyncFileSystemDecorator;
+18
View File
@@ -0,0 +1,18 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
function TryNextPlugin(source, message, target) {
this.source = source;
this.message = message;
this.target = target;
}
module.exports = TryNextPlugin;
TryNextPlugin.prototype.apply = function(resolver) {
var target = this.target;
var message = this.message;
resolver.plugin(this.source, function(request, callback) {
resolver.doResolve(target, request, message, callback);
});
};
+43
View File
@@ -0,0 +1,43 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var createInnerCallback = require("./createInnerCallback");
function UnsafeCachePlugin(source, filterPredicate, cache, withContext, target) {
this.source = source;
this.filterPredicate = filterPredicate;
this.withContext = withContext;
this.cache = cache || {};
this.target = target;
}
module.exports = UnsafeCachePlugin;
function getCacheId(request, withContext) {
return JSON.stringify({
context: withContext ? request.context : "",
path: request.path,
query: request.query,
request: request.request
});
}
UnsafeCachePlugin.prototype.apply = function(resolver) {
var filterPredicate = this.filterPredicate;
var cache = this.cache;
var target = this.target;
var withContext = this.withContext;
resolver.plugin(this.source, function(request, callback) {
if(!filterPredicate(request)) return callback();
var cacheId = getCacheId(request, withContext);
var cacheEntry = cache[cacheId];
if(cacheEntry) {
return callback(null, cacheEntry);
}
resolver.doResolve(target, request, null, createInnerCallback(function(err, result) {
if(err) return callback(err);
if(result) return callback(null, cache[cacheId] = result);
callback();
}, callback));
});
};
+23
View File
@@ -0,0 +1,23 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
function UseFilePlugin(source, filename, target) {
this.source = source;
this.filename = filename;
this.target = target;
}
module.exports = UseFilePlugin;
UseFilePlugin.prototype.apply = function(resolver) {
var filename = this.filename;
var target = this.target;
resolver.plugin(this.source, function(request, callback) {
var filePath = resolver.join(request.path, filename);
var obj = Object.assign({}, request, {
path: filePath,
relativePath: request.relativePath && resolver.join(request.relativePath, filename)
});
resolver.doResolve(target, obj, "using path: " + filePath, callback);
});
};
+189
View File
@@ -0,0 +1,189 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var globToRegExp = require("./globToRegExp").globToRegExp;
function parseType(type) {
var items = type.split("+");
var t = items.shift();
return {
type: t === "*" ? null : t,
features: items
};
}
function isTypeMatched(baseType, testedType) {
if(typeof baseType === "string") baseType = parseType(baseType);
if(typeof testedType === "string") testedType = parseType(testedType);
if(testedType.type && testedType.type !== baseType.type) return false;
return testedType.features.every(function(requiredFeature) {
return baseType.features.indexOf(requiredFeature) >= 0;
});
}
function isResourceTypeMatched(baseType, testedType) {
baseType = baseType.split("/");
testedType = testedType.split("/");
if(baseType.length !== testedType.length) return false;
for(var i = 0; i < baseType.length; i++) {
if(!isTypeMatched(baseType[i], testedType[i]))
return false;
}
return true;
}
function isResourceTypeSupported(context, type) {
return context.supportedResourceTypes && context.supportedResourceTypes.some(function(supportedType) {
return isResourceTypeMatched(supportedType, type);
});
}
function isEnvironment(context, env) {
return context.environments && context.environments.every(function(environment) {
return isTypeMatched(environment, env);
});
}
var globCache = {};
function getGlobRegExp(glob) {
var regExp = globCache[glob] || (globCache[glob] = globToRegExp(glob));
return regExp;
}
function matchGlob(glob, relativePath) {
var regExp = getGlobRegExp(glob);
return regExp.exec(relativePath);
}
function isGlobMatched(glob, relativePath) {
return !!matchGlob(glob, relativePath);
}
function isConditionMatched(context, condition) {
var items = condition.split("|");
return items.some(function testFn(item) {
item = item.trim();
var inverted = /^!/.test(item);
if(inverted) return !testFn(item.substr(1));
if(/^[a-z]+:/.test(item)) {
// match named condition
var match = /^([a-z]+):\s*/.exec(item);
var value = item.substr(match[0].length);
var name = match[1];
switch(name) {
case "referrer":
return isGlobMatched(value, context.referrer);
default:
return false;
}
} else if(item.indexOf("/") >= 0) {
// match supported type
return isResourceTypeSupported(context, item);
} else {
// match environment
return isEnvironment(context, item);
}
});
}
function isKeyMatched(context, key) {
while(true) { //eslint-disable-line
var match = /^\[([^\]]+)\]\s*/.exec(key);
if(!match) return key;
key = key.substr(match[0].length);
var condition = match[1];
if(!isConditionMatched(context, condition)) {
return false;
}
}
}
function getField(context, configuration, field) {
var value;
Object.keys(configuration).forEach(function(key) {
var pureKey = isKeyMatched(context, key);
if(pureKey === field) {
value = configuration[key];
}
});
return value;
}
function getMain(context, configuration) {
return getField(context, configuration, "main");
}
function getExtensions(context, configuration) {
return getField(context, configuration, "extensions");
}
function matchModule(context, configuration, request) {
var modulesField = getField(context, configuration, "modules");
if(!modulesField) return request;
var newRequest = request;
var keys = Object.keys(modulesField);
var iteration = 0;
for(var i = 0; i < keys.length; i++) {
var key = keys[i];
var pureKey = isKeyMatched(context, key);
var match = matchGlob(pureKey, newRequest);
if(match) {
var value = modulesField[key];
if(typeof value !== "string") {
return value;
} else if(/^\(.+\)$/.test(pureKey)) {
newRequest = newRequest.replace(getGlobRegExp(pureKey), value);
} else {
var index = 1;
newRequest = value.replace(/(\/?\*)?\*/g, replaceMatcher);
}
i = -1;
if(iteration++ > keys.length) {
throw new Error("Request '" + request + "' matches recursively");
}
}
}
return newRequest;
function replaceMatcher(find) {
switch(find) {
case "/**":
var m = match[index++];
return m ? "/" + m : "";
case "**":
case "*":
return match[index++];
}
}
}
function matchType(context, configuration, relativePath) {
var typesField = getField(context, configuration, "types");
if(!typesField) return undefined;
var type;
Object.keys(typesField).forEach(function(key) {
var pureKey = isKeyMatched(context, key);
if(isGlobMatched(pureKey, relativePath)) {
var value = typesField[key];
if(!type && /\/\*$/.test(value))
throw new Error("value ('" + value + "') of key '" + key + "' contains '*', but there is no previous value defined");
type = value.replace(/\/\*$/, "/" + type);
}
});
return type;
}
exports.parseType = parseType;
exports.isTypeMatched = isTypeMatched;
exports.isResourceTypeSupported = isResourceTypeSupported;
exports.isEnvironment = isEnvironment;
exports.isGlobMatched = isGlobMatched;
exports.isConditionMatched = isConditionMatched;
exports.isKeyMatched = isKeyMatched;
exports.getField = getField;
exports.getMain = getMain;
exports.getExtensions = getExtensions;
exports.matchModule = matchModule;
exports.matchType = matchType;
+41
View File
@@ -0,0 +1,41 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
module.exports = function createInnerCallback(callback, options, message, messageOptional) {
var log = options.log;
if(!log) {
if(options.stack !== callback.stack) {
var callbackWrapper = function callbackWrapper() {
return callback.apply(this, arguments);
};
callbackWrapper.stack = options.stack;
callbackWrapper.missing = options.missing;
return callbackWrapper;
}
return callback;
}
function loggingCallbackWrapper() {
var i;
if(message) {
if(!messageOptional || theLog.length > 0) {
log(message);
for(i = 0; i < theLog.length; i++)
log(" " + theLog[i]);
}
} else {
for(i = 0; i < theLog.length; i++)
log(theLog[i]);
}
return callback.apply(this, arguments);
}
var theLog = [];
loggingCallbackWrapper.log = function writeLog(msg) {
theLog.push(msg);
};
loggingCallbackWrapper.stack = options.stack;
loggingCallbackWrapper.missing = options.missing;
return loggingCallbackWrapper;
};
+65
View File
@@ -0,0 +1,65 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
module.exports = function forEachBail(array, iterator, callback) {
if(array.length === 0) return callback();
var currentPos = array.length;
var currentResult;
var done = [];
for(var i = 0; i < array.length; i++) {
var itCb = createIteratorCallback(i);
iterator(array[i], itCb);
if(currentPos === 0) break;
}
function createIteratorCallback(i) {
return function() {
if(i >= currentPos) return; // ignore
var args = Array.prototype.slice.call(arguments);
done.push(i);
if(args.length > 0) {
currentPos = i + 1;
done = done.filter(function(item) {
return item <= i;
});
currentResult = args;
}
if(done.length === currentPos) {
callback.apply(null, currentResult);
currentPos = 0;
}
};
}
};
module.exports.withIndex = function forEachBailWithIndex(array, iterator, callback) {
if(array.length === 0) return callback();
var currentPos = array.length;
var currentResult;
var done = [];
for(var i = 0; i < array.length; i++) {
var itCb = createIteratorCallback(i);
iterator(array[i], i, itCb);
if(currentPos === 0) break;
}
function createIteratorCallback(i) {
return function() {
if(i >= currentPos) return; // ignore
var args = Array.prototype.slice.call(arguments);
done.push(i);
if(args.length > 0) {
currentPos = i + 1;
done = done.filter(function(item) {
return item <= i;
});
currentResult = args;
}
if(done.length === currentPos) {
callback.apply(null, currentResult);
currentPos = 0;
}
};
}
};
+22
View File
@@ -0,0 +1,22 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
module.exports = function getInnerRequest(resolver, request) {
if(typeof request.__innerRequest === "string" &&
request.__innerRequest_request === request.request &&
request.__innerRequest_relativePath === request.relativePath)
return request.__innerRequest;
var innerRequest;
if(request.request) {
innerRequest = request.request;
if(/^\.\.?\//.test(innerRequest) && request.relativePath) {
innerRequest = resolver.join(request.relativePath, innerRequest);
}
} else {
innerRequest = request.relativePath;
}
request.__innerRequest_request = request.request;
request.__innerRequest_relativePath = request.relativePath;
return request.__innerRequest = innerRequest;
};
+33
View File
@@ -0,0 +1,33 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
module.exports = function getPaths(path) {
var parts = path.split(/(.*?[\\\/]+)/);
var paths = [path];
var seqments = [parts[parts.length - 1]];
var part = parts[parts.length - 1];
path = path.substr(0, path.length - part.length - 1);
paths.push(path);
for(var i = parts.length - 2; i > 2; i -= 2) {
part = parts[i];
path = path.substr(0, path.length - part.length) || "/";
paths.push(path);
seqments.push(part.substr(0, part.length - 1));
}
part = parts[1];
seqments.push(part.length > 1 ? part.substr(0, part.length - 1) : part);
return {
paths: paths,
seqments: seqments
};
};
module.exports.basename = function basename(path) {
var i = path.lastIndexOf("/"),
j = path.lastIndexOf("\\");
var p = i < 0 ? j : j < 0 ? i : i < j ? j : i;
if(p < 0) return null;
var s = path.substr(p + 1);
return s;
};
+188
View File
@@ -0,0 +1,188 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
function globToRegExp(glob) {
// * [^\\\/]*
// /**/ /.+/
// ^* \./.+ (concord special)
// ? [^\\\/]
// [!...] [^...]
// [^...] [^...]
// / [\\\/]
// {...,...} (...|...)
// ?(...|...) (...|...)?
// +(...|...) (...|...)+
// *(...|...) (...|...)*
// @(...|...) (...|...)
if(/^\(.+\)$/.test(glob)) {
// allow to pass an RegExp in brackets
return new RegExp(glob.substr(1, glob.length - 2));
}
var tokens = tokenize(glob);
var process = createRoot();
var regExpStr = tokens.map(process).join("");
return new RegExp("^" + regExpStr + "$");
}
var SIMPLE_TOKENS = {
"@(": "one",
"?(": "zero-one",
"+(": "one-many",
"*(": "zero-many",
"|": "segment-sep",
"/**/": "any-path-segments",
"**": "any-path",
"*": "any-path-segment",
"?": "any-char",
"{": "or",
"/": "path-sep",
",": "comma",
")": "closing-segment",
"}": "closing-or"
};
function tokenize(glob) {
return glob.split(/([@?+*]\(|\/\*\*\/|\*\*|[?*]|\[[\!\^]?(?:[^\]\\]|\\.)+\]|\{|,|\/|[|)}])/g).map(function(item) {
if(!item)
return null;
var t = SIMPLE_TOKENS[item];
if(t) {
return {
type: t
};
}
if(item[0] === "[") {
if(item[1] === "^" || item[1] === "!") {
return {
type: "inverted-char-set",
value: item.substr(2, item.length - 3)
};
} else {
return {
type: "char-set",
value: item.substr(1, item.length - 2)
};
}
}
return {
type: "string",
value: item
};
}).filter(Boolean).concat({
type: "end"
});
}
function createRoot() {
var inOr = [];
var process = createSeqment();
var initial = true;
return function(token) {
switch(token.type) {
case "or":
inOr.push(initial);
return "(";
case "comma":
if(inOr.length) {
initial = inOr[inOr.length - 1];
return "|";
} else {
return process({
type: "string",
value: ","
}, initial);
}
case "closing-or":
if(inOr.length === 0)
throw new Error("Unmatched '}'");
inOr.pop();
return ")";
case "end":
if(inOr.length)
throw new Error("Unmatched '{'");
return process(token, initial);
default:
var result = process(token, initial);
initial = false;
return result;
}
};
}
function createSeqment() {
var inSeqment = [];
var process = createSimple();
return function(token, initial) {
switch(token.type) {
case "one":
case "one-many":
case "zero-many":
case "zero-one":
inSeqment.push(token.type);
return "(";
case "segment-sep":
if(inSeqment.length) {
return "|";
} else {
return process({
type: "string",
value: "|"
}, initial);
}
case "closing-segment":
var segment = inSeqment.pop();
switch(segment) {
case "one":
return ")";
case "one-many":
return ")+";
case "zero-many":
return ")*";
case "zero-one":
return ")?";
}
throw new Error("Unexcepted segment " + segment);
case "end":
if(inSeqment.length > 0) {
throw new Error("Unmatched segment, missing ')'");
}
return process(token, initial);
default:
return process(token, initial);
}
};
}
function createSimple() {
return function(token, initial) {
switch(token.type) {
case "path-sep":
return "[\\\\/]+";
case "any-path-segments":
return "[\\\\/]+(?:(.+)[\\\\/]+)?";
case "any-path":
return "(.*)";
case "any-path-segment":
if(initial) {
return "\\.[\\\\/]+(?:.*[\\\\/]+)?([^\\\\/]+)";
} else {
return "([^\\\\/]*)";
}
case "any-char":
return "[^\\\\/]";
case "inverted-char-set":
return "[^" + token.value + "]";
case "char-set":
return "[" + token.value + "]";
case "string":
return token.value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
case "end":
return "";
default:
throw new Error("Unsupported token '" + token.type + "'");
}
};
}
exports.globToRegExp = globToRegExp;
+144
View File
@@ -0,0 +1,144 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var ResolverFactory = require("./ResolverFactory");
var NodeJsInputFileSystem = require("./NodeJsInputFileSystem");
var CachedInputFileSystem = require("./CachedInputFileSystem");
var nodeFileSystem = new CachedInputFileSystem(new NodeJsInputFileSystem(), 4000);
var nodeContext = {
environments: [
"node+es3+es5+process+native"
]
};
var asyncResolver = ResolverFactory.createResolver({
extensions: [".js", ".json", ".node"],
fileSystem: nodeFileSystem
});
module.exports = function resolve(context, path, request, callback) {
if(typeof context === "string") {
callback = request;
request = path;
path = context;
context = nodeContext;
}
asyncResolver.resolve(context, path, request, callback);
};
var syncResolver = ResolverFactory.createResolver({
extensions: [".js", ".json", ".node"],
useSyncFileSystemCalls: true,
fileSystem: nodeFileSystem
});
module.exports.sync = function resolveSync(context, path, request) {
if(typeof context === "string") {
request = path;
path = context;
context = nodeContext;
}
return syncResolver.resolveSync(context, path, request);
};
var asyncContextResolver = ResolverFactory.createResolver({
extensions: [".js", ".json", ".node"],
resolveToContext: true,
fileSystem: nodeFileSystem
});
module.exports.context = function resolveContext(context, path, request, callback) {
if(typeof context === "string") {
callback = request;
request = path;
path = context;
context = nodeContext;
}
asyncContextResolver.resolve(context, path, request, callback);
};
var syncContextResolver = ResolverFactory.createResolver({
extensions: [".js", ".json", ".node"],
resolveToContext: true,
useSyncFileSystemCalls: true,
fileSystem: nodeFileSystem
});
module.exports.context.sync = function resolveContextSync(context, path, request) {
if(typeof context === "string") {
request = path;
path = context;
context = nodeContext;
}
return syncContextResolver.resolveSync(context, path, request);
};
var asyncLoaderResolver = ResolverFactory.createResolver({
extensions: [".js", ".json", ".node"],
moduleExtensions: ["-loader"],
mainFields: ["loader", "main"],
fileSystem: nodeFileSystem
});
module.exports.loader = function resolveLoader(context, path, request, callback) {
if(typeof context === "string") {
callback = request;
request = path;
path = context;
context = nodeContext;
}
asyncLoaderResolver.resolve(context, path, request, callback);
};
var syncLoaderResolver = ResolverFactory.createResolver({
extensions: [".js", ".json", ".node"],
moduleExtensions: ["-loader"],
mainFields: ["loader", "main"],
useSyncFileSystemCalls: true,
fileSystem: nodeFileSystem
});
module.exports.loader.sync = function resolveLoaderSync(context, path, request) {
if(typeof context === "string") {
request = path;
path = context;
context = nodeContext;
}
return syncLoaderResolver.resolveSync(context, path, request);
};
module.exports.create = function create(options) {
options = Object.assign({
fileSystem: nodeFileSystem
}, options);
var resolver = ResolverFactory.createResolver(options);
return function(context, path, request, callback) {
if(typeof context === "string") {
callback = request;
request = path;
path = context;
context = nodeContext;
}
resolver.resolve(context, path, request, callback);
};
};
module.exports.create.sync = function createSync(options) {
options = Object.assign({
useSyncFileSystemCalls: true,
fileSystem: nodeFileSystem
}, options);
var resolver = ResolverFactory.createResolver(options);
return function(context, path, request) {
if(typeof context === "string") {
request = path;
path = context;
context = nodeContext;
}
return resolver.resolveSync(context, path, request);
};
};
// Export Resolver, FileSystems and Plugins
module.exports.ResolverFactory = ResolverFactory;
module.exports.NodeJsInputFileSystem = NodeJsInputFileSystem;
module.exports.CachedInputFileSystem = CachedInputFileSystem;
+15
View File
@@ -0,0 +1,15 @@
The ISC License
Copyright (c) 2011-2022 Isaac Z. Schlueter, Ben Noordhuis, and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+143
View File
@@ -0,0 +1,143 @@
# graceful-fs
graceful-fs functions as a drop-in replacement for the fs module,
making various improvements.
The improvements are meant to normalize behavior across different
platforms and environments, and to make filesystem access more
resilient to errors.
## Improvements over [fs module](https://nodejs.org/api/fs.html)
* Queues up `open` and `readdir` calls, and retries them once
something closes if there is an EMFILE error from too many file
descriptors.
* fixes `lchmod` for Node versions prior to 0.6.2.
* implements `fs.lutimes` if possible. Otherwise it becomes a noop.
* ignores `EINVAL` and `EPERM` errors in `chown`, `fchown` or
`lchown` if the user isn't root.
* makes `lchmod` and `lchown` become noops, if not available.
* retries reading a file if `read` results in EAGAIN error.
On Windows, it retries renaming a file for up to one second if `EACCESS`
or `EPERM` error occurs, likely because antivirus software has locked
the directory.
## USAGE
```javascript
// use just like fs
var fs = require('graceful-fs')
// now go and do stuff with it...
fs.readFile('some-file-or-whatever', (err, data) => {
// Do stuff here.
})
```
## Sync methods
This module cannot intercept or handle `EMFILE` or `ENFILE` errors from sync
methods. If you use sync methods which open file descriptors then you are
responsible for dealing with any errors.
This is a known limitation, not a bug.
## Global Patching
If you want to patch the global fs module (or any other fs-like
module) you can do this:
```javascript
// Make sure to read the caveat below.
var realFs = require('fs')
var gracefulFs = require('graceful-fs')
gracefulFs.gracefulify(realFs)
```
This should only ever be done at the top-level application layer, in
order to delay on EMFILE errors from any fs-using dependencies. You
should **not** do this in a library, because it can cause unexpected
delays in other parts of the program.
## Changes
This module is fairly stable at this point, and used by a lot of
things. That being said, because it implements a subtle behavior
change in a core part of the node API, even modest changes can be
extremely breaking, and the versioning is thus biased towards
bumping the major when in doubt.
The main change between major versions has been switching between
providing a fully-patched `fs` module vs monkey-patching the node core
builtin, and the approach by which a non-monkey-patched `fs` was
created.
The goal is to trade `EMFILE` errors for slower fs operations. So, if
you try to open a zillion files, rather than crashing, `open`
operations will be queued up and wait for something else to `close`.
There are advantages to each approach. Monkey-patching the fs means
that no `EMFILE` errors can possibly occur anywhere in your
application, because everything is using the same core `fs` module,
which is patched. However, it can also obviously cause undesirable
side-effects, especially if the module is loaded multiple times.
Implementing a separate-but-identical patched `fs` module is more
surgical (and doesn't run the risk of patching multiple times), but
also imposes the challenge of keeping in sync with the core module.
The current approach loads the `fs` module, and then creates a
lookalike object that has all the same methods, except a few that are
patched. It is safe to use in all versions of Node from 0.8 through
7.0.
### v4
* Do not monkey-patch the fs module. This module may now be used as a
drop-in dep, and users can opt into monkey-patching the fs builtin
if their app requires it.
### v3
* Monkey-patch fs, because the eval approach no longer works on recent
node.
* fixed possible type-error throw if rename fails on windows
* verify that we *never* get EMFILE errors
* Ignore ENOSYS from chmod/chown
* clarify that graceful-fs must be used as a drop-in
### v2.1.0
* Use eval rather than monkey-patching fs.
* readdir: Always sort the results
* win32: requeue a file if error has an OK status
### v2.0
* A return to monkey patching
* wrap process.cwd
### v1.1
* wrap readFile
* Wrap fs.writeFile.
* readdir protection
* Don't clobber the fs builtin
* Handle fs.read EAGAIN errors by trying again
* Expose the curOpen counter
* No-op lchown/lchmod if not implemented
* fs.rename patch only for win32
* Patch fs.rename to handle AV software on Windows
* Close #4 Chown should not fail on einval or eperm if non-root
* Fix isaacs/fstream#1 Only wrap fs one time
* Fix #3 Start at 1024 max files, then back off on EMFILE
* lutimes that doens't blow up on Linux
* A full on-rewrite using a queue instead of just swallowing the EMFILE error
* Wrap Read/Write streams as well
### 1.0
* Update engines for node 0.6
* Be lstat-graceful on Windows
* first
+23
View File
@@ -0,0 +1,23 @@
'use strict'
module.exports = clone
var getPrototypeOf = Object.getPrototypeOf || function (obj) {
return obj.__proto__
}
function clone (obj) {
if (obj === null || typeof obj !== 'object')
return obj
if (obj instanceof Object)
var copy = { __proto__: getPrototypeOf(obj) }
else
var copy = Object.create(null)
Object.getOwnPropertyNames(obj).forEach(function (key) {
Object.defineProperty(copy, key, Object.getOwnPropertyDescriptor(obj, key))
})
return copy
}
+448
View File
@@ -0,0 +1,448 @@
var fs = require('fs')
var polyfills = require('./polyfills.js')
var legacy = require('./legacy-streams.js')
var clone = require('./clone.js')
var util = require('util')
/* istanbul ignore next - node 0.x polyfill */
var gracefulQueue
var previousSymbol
/* istanbul ignore else - node 0.x polyfill */
if (typeof Symbol === 'function' && typeof Symbol.for === 'function') {
gracefulQueue = Symbol.for('graceful-fs.queue')
// This is used in testing by future versions
previousSymbol = Symbol.for('graceful-fs.previous')
} else {
gracefulQueue = '___graceful-fs.queue'
previousSymbol = '___graceful-fs.previous'
}
function noop () {}
function publishQueue(context, queue) {
Object.defineProperty(context, gracefulQueue, {
get: function() {
return queue
}
})
}
var debug = noop
if (util.debuglog)
debug = util.debuglog('gfs4')
else if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || ''))
debug = function() {
var m = util.format.apply(util, arguments)
m = 'GFS4: ' + m.split(/\n/).join('\nGFS4: ')
console.error(m)
}
// Once time initialization
if (!fs[gracefulQueue]) {
// This queue can be shared by multiple loaded instances
var queue = global[gracefulQueue] || []
publishQueue(fs, queue)
// Patch fs.close/closeSync to shared queue version, because we need
// to retry() whenever a close happens *anywhere* in the program.
// This is essential when multiple graceful-fs instances are
// in play at the same time.
fs.close = (function (fs$close) {
function close (fd, cb) {
return fs$close.call(fs, fd, function (err) {
// This function uses the graceful-fs shared queue
if (!err) {
resetQueue()
}
if (typeof cb === 'function')
cb.apply(this, arguments)
})
}
Object.defineProperty(close, previousSymbol, {
value: fs$close
})
return close
})(fs.close)
fs.closeSync = (function (fs$closeSync) {
function closeSync (fd) {
// This function uses the graceful-fs shared queue
fs$closeSync.apply(fs, arguments)
resetQueue()
}
Object.defineProperty(closeSync, previousSymbol, {
value: fs$closeSync
})
return closeSync
})(fs.closeSync)
if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) {
process.on('exit', function() {
debug(fs[gracefulQueue])
require('assert').equal(fs[gracefulQueue].length, 0)
})
}
}
if (!global[gracefulQueue]) {
publishQueue(global, fs[gracefulQueue]);
}
module.exports = patch(clone(fs))
if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) {
module.exports = patch(fs)
fs.__patched = true;
}
function patch (fs) {
// Everything that references the open() function needs to be in here
polyfills(fs)
fs.gracefulify = patch
fs.createReadStream = createReadStream
fs.createWriteStream = createWriteStream
var fs$readFile = fs.readFile
fs.readFile = readFile
function readFile (path, options, cb) {
if (typeof options === 'function')
cb = options, options = null
return go$readFile(path, options, cb)
function go$readFile (path, options, cb, startTime) {
return fs$readFile(path, options, function (err) {
if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
enqueue([go$readFile, [path, options, cb], err, startTime || Date.now(), Date.now()])
else {
if (typeof cb === 'function')
cb.apply(this, arguments)
}
})
}
}
var fs$writeFile = fs.writeFile
fs.writeFile = writeFile
function writeFile (path, data, options, cb) {
if (typeof options === 'function')
cb = options, options = null
return go$writeFile(path, data, options, cb)
function go$writeFile (path, data, options, cb, startTime) {
return fs$writeFile(path, data, options, function (err) {
if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
enqueue([go$writeFile, [path, data, options, cb], err, startTime || Date.now(), Date.now()])
else {
if (typeof cb === 'function')
cb.apply(this, arguments)
}
})
}
}
var fs$appendFile = fs.appendFile
if (fs$appendFile)
fs.appendFile = appendFile
function appendFile (path, data, options, cb) {
if (typeof options === 'function')
cb = options, options = null
return go$appendFile(path, data, options, cb)
function go$appendFile (path, data, options, cb, startTime) {
return fs$appendFile(path, data, options, function (err) {
if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
enqueue([go$appendFile, [path, data, options, cb], err, startTime || Date.now(), Date.now()])
else {
if (typeof cb === 'function')
cb.apply(this, arguments)
}
})
}
}
var fs$copyFile = fs.copyFile
if (fs$copyFile)
fs.copyFile = copyFile
function copyFile (src, dest, flags, cb) {
if (typeof flags === 'function') {
cb = flags
flags = 0
}
return go$copyFile(src, dest, flags, cb)
function go$copyFile (src, dest, flags, cb, startTime) {
return fs$copyFile(src, dest, flags, function (err) {
if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
enqueue([go$copyFile, [src, dest, flags, cb], err, startTime || Date.now(), Date.now()])
else {
if (typeof cb === 'function')
cb.apply(this, arguments)
}
})
}
}
var fs$readdir = fs.readdir
fs.readdir = readdir
var noReaddirOptionVersions = /^v[0-5]\./
function readdir (path, options, cb) {
if (typeof options === 'function')
cb = options, options = null
var go$readdir = noReaddirOptionVersions.test(process.version)
? function go$readdir (path, options, cb, startTime) {
return fs$readdir(path, fs$readdirCallback(
path, options, cb, startTime
))
}
: function go$readdir (path, options, cb, startTime) {
return fs$readdir(path, options, fs$readdirCallback(
path, options, cb, startTime
))
}
return go$readdir(path, options, cb)
function fs$readdirCallback (path, options, cb, startTime) {
return function (err, files) {
if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
enqueue([
go$readdir,
[path, options, cb],
err,
startTime || Date.now(),
Date.now()
])
else {
if (files && files.sort)
files.sort()
if (typeof cb === 'function')
cb.call(this, err, files)
}
}
}
}
if (process.version.substr(0, 4) === 'v0.8') {
var legStreams = legacy(fs)
ReadStream = legStreams.ReadStream
WriteStream = legStreams.WriteStream
}
var fs$ReadStream = fs.ReadStream
if (fs$ReadStream) {
ReadStream.prototype = Object.create(fs$ReadStream.prototype)
ReadStream.prototype.open = ReadStream$open
}
var fs$WriteStream = fs.WriteStream
if (fs$WriteStream) {
WriteStream.prototype = Object.create(fs$WriteStream.prototype)
WriteStream.prototype.open = WriteStream$open
}
Object.defineProperty(fs, 'ReadStream', {
get: function () {
return ReadStream
},
set: function (val) {
ReadStream = val
},
enumerable: true,
configurable: true
})
Object.defineProperty(fs, 'WriteStream', {
get: function () {
return WriteStream
},
set: function (val) {
WriteStream = val
},
enumerable: true,
configurable: true
})
// legacy names
var FileReadStream = ReadStream
Object.defineProperty(fs, 'FileReadStream', {
get: function () {
return FileReadStream
},
set: function (val) {
FileReadStream = val
},
enumerable: true,
configurable: true
})
var FileWriteStream = WriteStream
Object.defineProperty(fs, 'FileWriteStream', {
get: function () {
return FileWriteStream
},
set: function (val) {
FileWriteStream = val
},
enumerable: true,
configurable: true
})
function ReadStream (path, options) {
if (this instanceof ReadStream)
return fs$ReadStream.apply(this, arguments), this
else
return ReadStream.apply(Object.create(ReadStream.prototype), arguments)
}
function ReadStream$open () {
var that = this
open(that.path, that.flags, that.mode, function (err, fd) {
if (err) {
if (that.autoClose)
that.destroy()
that.emit('error', err)
} else {
that.fd = fd
that.emit('open', fd)
that.read()
}
})
}
function WriteStream (path, options) {
if (this instanceof WriteStream)
return fs$WriteStream.apply(this, arguments), this
else
return WriteStream.apply(Object.create(WriteStream.prototype), arguments)
}
function WriteStream$open () {
var that = this
open(that.path, that.flags, that.mode, function (err, fd) {
if (err) {
that.destroy()
that.emit('error', err)
} else {
that.fd = fd
that.emit('open', fd)
}
})
}
function createReadStream (path, options) {
return new fs.ReadStream(path, options)
}
function createWriteStream (path, options) {
return new fs.WriteStream(path, options)
}
var fs$open = fs.open
fs.open = open
function open (path, flags, mode, cb) {
if (typeof mode === 'function')
cb = mode, mode = null
return go$open(path, flags, mode, cb)
function go$open (path, flags, mode, cb, startTime) {
return fs$open(path, flags, mode, function (err, fd) {
if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
enqueue([go$open, [path, flags, mode, cb], err, startTime || Date.now(), Date.now()])
else {
if (typeof cb === 'function')
cb.apply(this, arguments)
}
})
}
}
return fs
}
function enqueue (elem) {
debug('ENQUEUE', elem[0].name, elem[1])
fs[gracefulQueue].push(elem)
retry()
}
// keep track of the timeout between retry() calls
var retryTimer
// reset the startTime and lastTime to now
// this resets the start of the 60 second overall timeout as well as the
// delay between attempts so that we'll retry these jobs sooner
function resetQueue () {
var now = Date.now()
for (var i = 0; i < fs[gracefulQueue].length; ++i) {
// entries that are only a length of 2 are from an older version, don't
// bother modifying those since they'll be retried anyway.
if (fs[gracefulQueue][i].length > 2) {
fs[gracefulQueue][i][3] = now // startTime
fs[gracefulQueue][i][4] = now // lastTime
}
}
// call retry to make sure we're actively processing the queue
retry()
}
function retry () {
// clear the timer and remove it to help prevent unintended concurrency
clearTimeout(retryTimer)
retryTimer = undefined
if (fs[gracefulQueue].length === 0)
return
var elem = fs[gracefulQueue].shift()
var fn = elem[0]
var args = elem[1]
// these items may be unset if they were added by an older graceful-fs
var err = elem[2]
var startTime = elem[3]
var lastTime = elem[4]
// if we don't have a startTime we have no way of knowing if we've waited
// long enough, so go ahead and retry this item now
if (startTime === undefined) {
debug('RETRY', fn.name, args)
fn.apply(null, args)
} else if (Date.now() - startTime >= 60000) {
// it's been more than 60 seconds total, bail now
debug('TIMEOUT', fn.name, args)
var cb = args.pop()
if (typeof cb === 'function')
cb.call(null, err)
} else {
// the amount of time between the last attempt and right now
var sinceAttempt = Date.now() - lastTime
// the amount of time between when we first tried, and when we last tried
// rounded up to at least 1
var sinceStart = Math.max(lastTime - startTime, 1)
// backoff. wait longer than the total time we've been retrying, but only
// up to a maximum of 100ms
var desiredDelay = Math.min(sinceStart * 1.2, 100)
// it's been long enough since the last retry, do it again
if (sinceAttempt >= desiredDelay) {
debug('RETRY', fn.name, args)
fn.apply(null, args.concat([startTime]))
} else {
// if we can't do this job yet, push it to the end of the queue
// and let the next iteration check again
fs[gracefulQueue].push(elem)
}
}
// schedule our next run if one isn't already scheduled
if (retryTimer === undefined) {
retryTimer = setTimeout(retry, 0)
}
}
@@ -0,0 +1,118 @@
var Stream = require('stream').Stream
module.exports = legacy
function legacy (fs) {
return {
ReadStream: ReadStream,
WriteStream: WriteStream
}
function ReadStream (path, options) {
if (!(this instanceof ReadStream)) return new ReadStream(path, options);
Stream.call(this);
var self = this;
this.path = path;
this.fd = null;
this.readable = true;
this.paused = false;
this.flags = 'r';
this.mode = 438; /*=0666*/
this.bufferSize = 64 * 1024;
options = options || {};
// Mixin options into this
var keys = Object.keys(options);
for (var index = 0, length = keys.length; index < length; index++) {
var key = keys[index];
this[key] = options[key];
}
if (this.encoding) this.setEncoding(this.encoding);
if (this.start !== undefined) {
if ('number' !== typeof this.start) {
throw TypeError('start must be a Number');
}
if (this.end === undefined) {
this.end = Infinity;
} else if ('number' !== typeof this.end) {
throw TypeError('end must be a Number');
}
if (this.start > this.end) {
throw new Error('start must be <= end');
}
this.pos = this.start;
}
if (this.fd !== null) {
process.nextTick(function() {
self._read();
});
return;
}
fs.open(this.path, this.flags, this.mode, function (err, fd) {
if (err) {
self.emit('error', err);
self.readable = false;
return;
}
self.fd = fd;
self.emit('open', fd);
self._read();
})
}
function WriteStream (path, options) {
if (!(this instanceof WriteStream)) return new WriteStream(path, options);
Stream.call(this);
this.path = path;
this.fd = null;
this.writable = true;
this.flags = 'w';
this.encoding = 'binary';
this.mode = 438; /*=0666*/
this.bytesWritten = 0;
options = options || {};
// Mixin options into this
var keys = Object.keys(options);
for (var index = 0, length = keys.length; index < length; index++) {
var key = keys[index];
this[key] = options[key];
}
if (this.start !== undefined) {
if ('number' !== typeof this.start) {
throw TypeError('start must be a Number');
}
if (this.start < 0) {
throw new Error('start must be >= zero');
}
this.pos = this.start;
}
this.busy = false;
this._queue = [];
if (this.fd === null) {
this._open = fs.open;
this._queue.push([this._open, this.path, this.flags, this.mode, undefined]);
this.flush();
}
}
}
+50
View File
@@ -0,0 +1,50 @@
{
"name": "graceful-fs",
"description": "A drop-in replacement for fs, making various improvements.",
"version": "4.2.10",
"repository": {
"type": "git",
"url": "https://github.com/isaacs/node-graceful-fs"
},
"main": "graceful-fs.js",
"directories": {
"test": "test"
},
"scripts": {
"preversion": "npm test",
"postversion": "npm publish",
"postpublish": "git push origin --follow-tags",
"test": "nyc --silent node test.js | tap -c -",
"posttest": "nyc report"
},
"keywords": [
"fs",
"module",
"reading",
"retry",
"retries",
"queue",
"error",
"errors",
"handling",
"EMFILE",
"EAGAIN",
"EINVAL",
"EPERM",
"EACCESS"
],
"license": "ISC",
"devDependencies": {
"import-fresh": "^2.0.0",
"mkdirp": "^0.5.0",
"rimraf": "^2.2.8",
"tap": "^12.7.0"
},
"files": [
"fs.js",
"graceful-fs.js",
"legacy-streams.js",
"polyfills.js",
"clone.js"
]
}
+355
View File
@@ -0,0 +1,355 @@
var constants = require('constants')
var origCwd = process.cwd
var cwd = null
var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform
process.cwd = function() {
if (!cwd)
cwd = origCwd.call(process)
return cwd
}
try {
process.cwd()
} catch (er) {}
// This check is needed until node.js 12 is required
if (typeof process.chdir === 'function') {
var chdir = process.chdir
process.chdir = function (d) {
cwd = null
chdir.call(process, d)
}
if (Object.setPrototypeOf) Object.setPrototypeOf(process.chdir, chdir)
}
module.exports = patch
function patch (fs) {
// (re-)implement some things that are known busted or missing.
// lchmod, broken prior to 0.6.2
// back-port the fix here.
if (constants.hasOwnProperty('O_SYMLINK') &&
process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
patchLchmod(fs)
}
// lutimes implementation, or no-op
if (!fs.lutimes) {
patchLutimes(fs)
}
// https://github.com/isaacs/node-graceful-fs/issues/4
// Chown should not fail on einval or eperm if non-root.
// It should not fail on enosys ever, as this just indicates
// that a fs doesn't support the intended operation.
fs.chown = chownFix(fs.chown)
fs.fchown = chownFix(fs.fchown)
fs.lchown = chownFix(fs.lchown)
fs.chmod = chmodFix(fs.chmod)
fs.fchmod = chmodFix(fs.fchmod)
fs.lchmod = chmodFix(fs.lchmod)
fs.chownSync = chownFixSync(fs.chownSync)
fs.fchownSync = chownFixSync(fs.fchownSync)
fs.lchownSync = chownFixSync(fs.lchownSync)
fs.chmodSync = chmodFixSync(fs.chmodSync)
fs.fchmodSync = chmodFixSync(fs.fchmodSync)
fs.lchmodSync = chmodFixSync(fs.lchmodSync)
fs.stat = statFix(fs.stat)
fs.fstat = statFix(fs.fstat)
fs.lstat = statFix(fs.lstat)
fs.statSync = statFixSync(fs.statSync)
fs.fstatSync = statFixSync(fs.fstatSync)
fs.lstatSync = statFixSync(fs.lstatSync)
// if lchmod/lchown do not exist, then make them no-ops
if (fs.chmod && !fs.lchmod) {
fs.lchmod = function (path, mode, cb) {
if (cb) process.nextTick(cb)
}
fs.lchmodSync = function () {}
}
if (fs.chown && !fs.lchown) {
fs.lchown = function (path, uid, gid, cb) {
if (cb) process.nextTick(cb)
}
fs.lchownSync = function () {}
}
// on Windows, A/V software can lock the directory, causing this
// to fail with an EACCES or EPERM if the directory contains newly
// created files. Try again on failure, for up to 60 seconds.
// Set the timeout this long because some Windows Anti-Virus, such as Parity
// bit9, may lock files for up to a minute, causing npm package install
// failures. Also, take care to yield the scheduler. Windows scheduling gives
// CPU to a busy looping process, which can cause the program causing the lock
// contention to be starved of CPU by node, so the contention doesn't resolve.
if (platform === "win32") {
fs.rename = typeof fs.rename !== 'function' ? fs.rename
: (function (fs$rename) {
function rename (from, to, cb) {
var start = Date.now()
var backoff = 0;
fs$rename(from, to, function CB (er) {
if (er
&& (er.code === "EACCES" || er.code === "EPERM")
&& Date.now() - start < 60000) {
setTimeout(function() {
fs.stat(to, function (stater, st) {
if (stater && stater.code === "ENOENT")
fs$rename(from, to, CB);
else
cb(er)
})
}, backoff)
if (backoff < 100)
backoff += 10;
return;
}
if (cb) cb(er)
})
}
if (Object.setPrototypeOf) Object.setPrototypeOf(rename, fs$rename)
return rename
})(fs.rename)
}
// if read() returns EAGAIN, then just try it again.
fs.read = typeof fs.read !== 'function' ? fs.read
: (function (fs$read) {
function read (fd, buffer, offset, length, position, callback_) {
var callback
if (callback_ && typeof callback_ === 'function') {
var eagCounter = 0
callback = function (er, _, __) {
if (er && er.code === 'EAGAIN' && eagCounter < 10) {
eagCounter ++
return fs$read.call(fs, fd, buffer, offset, length, position, callback)
}
callback_.apply(this, arguments)
}
}
return fs$read.call(fs, fd, buffer, offset, length, position, callback)
}
// This ensures `util.promisify` works as it does for native `fs.read`.
if (Object.setPrototypeOf) Object.setPrototypeOf(read, fs$read)
return read
})(fs.read)
fs.readSync = typeof fs.readSync !== 'function' ? fs.readSync
: (function (fs$readSync) { return function (fd, buffer, offset, length, position) {
var eagCounter = 0
while (true) {
try {
return fs$readSync.call(fs, fd, buffer, offset, length, position)
} catch (er) {
if (er.code === 'EAGAIN' && eagCounter < 10) {
eagCounter ++
continue
}
throw er
}
}
}})(fs.readSync)
function patchLchmod (fs) {
fs.lchmod = function (path, mode, callback) {
fs.open( path
, constants.O_WRONLY | constants.O_SYMLINK
, mode
, function (err, fd) {
if (err) {
if (callback) callback(err)
return
}
// prefer to return the chmod error, if one occurs,
// but still try to close, and report closing errors if they occur.
fs.fchmod(fd, mode, function (err) {
fs.close(fd, function(err2) {
if (callback) callback(err || err2)
})
})
})
}
fs.lchmodSync = function (path, mode) {
var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode)
// prefer to return the chmod error, if one occurs,
// but still try to close, and report closing errors if they occur.
var threw = true
var ret
try {
ret = fs.fchmodSync(fd, mode)
threw = false
} finally {
if (threw) {
try {
fs.closeSync(fd)
} catch (er) {}
} else {
fs.closeSync(fd)
}
}
return ret
}
}
function patchLutimes (fs) {
if (constants.hasOwnProperty("O_SYMLINK") && fs.futimes) {
fs.lutimes = function (path, at, mt, cb) {
fs.open(path, constants.O_SYMLINK, function (er, fd) {
if (er) {
if (cb) cb(er)
return
}
fs.futimes(fd, at, mt, function (er) {
fs.close(fd, function (er2) {
if (cb) cb(er || er2)
})
})
})
}
fs.lutimesSync = function (path, at, mt) {
var fd = fs.openSync(path, constants.O_SYMLINK)
var ret
var threw = true
try {
ret = fs.futimesSync(fd, at, mt)
threw = false
} finally {
if (threw) {
try {
fs.closeSync(fd)
} catch (er) {}
} else {
fs.closeSync(fd)
}
}
return ret
}
} else if (fs.futimes) {
fs.lutimes = function (_a, _b, _c, cb) { if (cb) process.nextTick(cb) }
fs.lutimesSync = function () {}
}
}
function chmodFix (orig) {
if (!orig) return orig
return function (target, mode, cb) {
return orig.call(fs, target, mode, function (er) {
if (chownErOk(er)) er = null
if (cb) cb.apply(this, arguments)
})
}
}
function chmodFixSync (orig) {
if (!orig) return orig
return function (target, mode) {
try {
return orig.call(fs, target, mode)
} catch (er) {
if (!chownErOk(er)) throw er
}
}
}
function chownFix (orig) {
if (!orig) return orig
return function (target, uid, gid, cb) {
return orig.call(fs, target, uid, gid, function (er) {
if (chownErOk(er)) er = null
if (cb) cb.apply(this, arguments)
})
}
}
function chownFixSync (orig) {
if (!orig) return orig
return function (target, uid, gid) {
try {
return orig.call(fs, target, uid, gid)
} catch (er) {
if (!chownErOk(er)) throw er
}
}
}
function statFix (orig) {
if (!orig) return orig
// Older versions of Node erroneously returned signed integers for
// uid + gid.
return function (target, options, cb) {
if (typeof options === 'function') {
cb = options
options = null
}
function callback (er, stats) {
if (stats) {
if (stats.uid < 0) stats.uid += 0x100000000
if (stats.gid < 0) stats.gid += 0x100000000
}
if (cb) cb.apply(this, arguments)
}
return options ? orig.call(fs, target, options, callback)
: orig.call(fs, target, callback)
}
}
function statFixSync (orig) {
if (!orig) return orig
// Older versions of Node erroneously returned signed integers for
// uid + gid.
return function (target, options) {
var stats = options ? orig.call(fs, target, options)
: orig.call(fs, target)
if (stats) {
if (stats.uid < 0) stats.uid += 0x100000000
if (stats.gid < 0) stats.gid += 0x100000000
}
return stats;
}
}
// ENOSYS means that the fs doesn't support the op. Just ignore
// that, because it doesn't matter.
//
// if there's no getuid, or if getuid() is something other
// than 0, and the error is EINVAL or EPERM, then just ignore
// it.
//
// This specific case is a silent failure in cp, install, tar,
// and most other unix tools that manage permissions.
//
// When running as root, or if other types of errors are
// encountered, then it's strict.
function chownErOk (er) {
if (!er)
return true
if (er.code === "ENOSYS")
return true
var nonroot = !process.getuid || process.getuid() !== 0
if (nonroot) {
if (er.code === "EINVAL" || er.code === "EPERM")
return true
}
return false
}
}
+52
View File
@@ -0,0 +1,52 @@
{
"name": "enhanced-resolve",
"version": "3.4.1",
"author": "Tobias Koppers @sokra",
"description": "Offers a async require.resolve function. It's highly configurable.",
"files": [
"lib"
],
"dependencies": {
"graceful-fs": "^4.1.2",
"memory-fs": "^0.4.0",
"object-assign": "^4.0.1",
"tapable": "^0.2.7"
},
"licenses": [
{
"type": "MIT",
"url": "http://www.opensource.org/licenses/mit-license.php"
}
],
"devDependencies": {
"beautify-lint": "^1.0.3",
"codecov.io": "^0.1.6",
"coveralls": "^2.11.6",
"eslint": "^3.14.1",
"eslint-plugin-node": "^3.0.5",
"eslint-plugin-nodeca": "^1.0.3",
"istanbul": "^0.4.1",
"js-beautify": "^1.5.10",
"mocha": "^2.3.4",
"should": "^8.0.2"
},
"engines": {
"node": ">=4.3.0 <5.0.0 || >=5.10"
},
"main": "lib/node.js",
"homepage": "http://github.com/webpack/enhanced-resolve",
"scripts": {
"beautify-lint": "beautify-lint lib/**.js test/*.js",
"beautify": "beautify-rewrite lib/**.js test/*.js",
"lint": "eslint lib test",
"pretest": "npm run lint && npm run beautify-lint",
"test": "mocha --full-trace --check-leaks",
"precover": "npm run lint && npm run beautify-lint",
"cover": "istanbul cover node_modules/mocha/bin/_mocha",
"travis": "npm run cover -- --report lcovonly"
},
"repository": {
"type": "git",
"url": "git://github.com/webpack/enhanced-resolve.git"
}
}