enhanced-resolve
Advanced tools
Comparing version 0.4.2 to 0.4.4
@@ -270,4 +270,8 @@ /* | ||
if(!part.path) return callback(); | ||
// find the "*" | ||
var idx = part.path.indexOf("*"); | ||
if(idx < 0) return callback(); | ||
// return some basic completes for "./" and "../" | ||
// Complete absolute path starting is not enabled | ||
switch(part.path) { | ||
@@ -314,2 +318,4 @@ case ".*": | ||
} | ||
// check if we want to complete a module name | ||
if(part.module) { | ||
@@ -320,6 +326,22 @@ var idxSlash = part.path.indexOf("/"); | ||
var moduleStr = idxSlash >= 0 ? part.path.slice(0, idxSlash) : part.path; | ||
// delegate it to the module name completion method | ||
return completeModule(context, moduleStr, options, type, sync, function(err, result) { | ||
if(err) return callback(err); | ||
if(!result) return callback(null, null); | ||
result.forEach(function(item) { | ||
// There is a special case if module is complete typed and | ||
// insert position is at the end, we offer to complete the slash | ||
if(item.insert == "" && part.path.slice(-1) == "*") { | ||
result.push({ | ||
insert: "/", | ||
seqment: item.seqment + "/" | ||
}); | ||
} | ||
}); | ||
// completeModule only returns insert and seqment | ||
// we have to add part here | ||
result.forEach(function(item) { | ||
var oldPath = part.path; | ||
@@ -330,2 +352,6 @@ part.path = part.path.replace("*", item.insert); | ||
}); | ||
// if we complete from the beginning like "*test" or "*" | ||
// we also offer to switch to relative paths | ||
// except for empty module names followed by "/", like "*/" | ||
if(part.path.slice(0, 1) == "*" && part.path.slice(1, 2) != "/") { | ||
@@ -346,7 +372,18 @@ result.unshift({ | ||
} | ||
// extract the left "/" or "\\" before "*" | ||
var idxStarting1 = part.path.slice(0, idx).lastIndexOf("/"); | ||
var idxStarting2 = part.path.slice(0, idx).lastIndexOf("\\"); | ||
var idxStarting = Math.max(idxStarting1, idxStarting2); | ||
// If there is no slash left from the "*" | ||
// that is weird and we return nothing to complete | ||
// (I know no case where this can occur) | ||
if(idxStarting < 0) return callback(null, null); | ||
// get the starting, which is the path before the left slash | ||
// we handle this as if the user has finished typing here | ||
var starting = part.path.slice(0, idxStarting); | ||
// get the right "/" or "\\" after "*" | ||
// or default to the full length if no found | ||
var idxSeqmentEnd1 = part.path.slice(idx).indexOf("/"); | ||
@@ -363,7 +400,19 @@ if(idxSeqmentEnd1 < 0) | ||
var idxSeqmentEnd = Math.min(idxSeqmentEnd1, idxSeqmentEnd2); | ||
// get the pathEnd, which is the path after the right slash | ||
// it's not used for resolving, because the user may not finished typing it | ||
// it's just appended to the part | ||
var pathEnd = part.path.slice(idxSeqmentEnd); | ||
// start and end of the sequement to complete | ||
var seqmentStart = part.path.slice(idxStarting+1, idx); | ||
var seqmentEnd = part.path.slice(idx+1, idxSeqmentEnd); | ||
var pathEnd = part.path.slice(idxSeqmentEnd); | ||
// resolve the starting as context (directory) | ||
// if this results in an error it is returned and should be reported | ||
// to the user, as starting is handled as finished | ||
resolve(context, parse.part(starting), options, type === "loader" ? "loader-context" : "context", sync, function(err, resolvedStarting) { | ||
if(err) return callback(err); | ||
// get the directory name and read the content | ||
var dirname = resolvedStarting.path; | ||
@@ -375,12 +424,23 @@ (sync?readdirSync:readdirAsync)(dirname, function(err, files) { | ||
var extensions = type === "loader" ? options.loaderExtensions : options.extensions; | ||
// get possible shortcuts for all files "a.js" -> ["a", "a.js"] | ||
var seqments = cutExtensions(files, extensions); | ||
seqments.forEach(function(file) { | ||
// check if file matches the allready typed starting and ending of the seqment | ||
if(file.indexOf(seqmentStart) !== 0) return; | ||
if(file.length < seqmentEnd.length || file.lastIndexOf(seqmentEnd) !== file.length - seqmentEnd.length) return; | ||
if(file.length < seqmentEnd.length || | ||
file.lastIndexOf(seqmentEnd) !== file.length - seqmentEnd.length) return; | ||
// read stats of file. keep in mind that this is maybe only a shortcut and we have to expand it to get the pathname | ||
count++; | ||
(sync?statSync:statAsync)(path.join(dirname, findFileExtensionFromList(files, extensions, file)), function(err, stat) { | ||
var fullFilename = findFileExtensionFromList(files, extensions, file); | ||
(sync?statSync:statAsync)(path.join(dirname, fullFilename), function(err, stat) { | ||
if(err) return endOne(err); | ||
if(seqmentEnd === "" && pathEnd === "" && stat.isDirectory()) { | ||
// There is a special case if the user typed a directory and the insert position is at the end | ||
// than we can complete to a slash, so the slash don't have to be typed | ||
if(seqmentEnd === "" && pathEnd === "" && stat.isDirectory() && fullFilename == seqmentStart) { | ||
results.push({ | ||
insert: file.slice(seqmentStart.length) + "/", | ||
insert: "/", | ||
seqment: file + "/", | ||
@@ -390,7 +450,14 @@ part: starting + "/" + file + "/" + (part.query ? part.query : "") | ||
} | ||
results.push({ | ||
insert: file.slice(seqmentStart.length, file.length - seqmentEnd.length), | ||
seqment: file, | ||
part: starting + "/" + file + pathEnd + (part.query ? part.query : "") | ||
}); | ||
// The default case is to complete to the shortcutted filename | ||
// directories cannot be shortcutted with a file extension, so we filter these here | ||
// NOTE: it seem the be better to filter these before iterating, but this would cause more calls to stat | ||
// if the user already typed something. We want to minimize the calls to stat. | ||
if(!stat.isDirectory() || fullFilename == file) { | ||
results.push({ | ||
insert: file.slice(seqmentStart.length, file.length - seqmentEnd.length), | ||
seqment: file, | ||
part: starting + "/" + file + pathEnd + (part.query ? part.query : "") | ||
}); | ||
} | ||
return endOne(); | ||
@@ -403,3 +470,6 @@ }); | ||
if(errored) return; | ||
if(err) return callback(err); | ||
if(err) { | ||
errored = true; | ||
return callback(err); | ||
} | ||
if(--count == 0) | ||
@@ -406,0 +476,0 @@ return callback(null, results); |
{ | ||
"name": "enhanced-resolve", | ||
"version": "0.4.2", | ||
"version": "0.4.4", | ||
"author": "Tobias Koppers @sokra", | ||
@@ -5,0 +5,0 @@ "description": "Offers a async require.resolve function. It's highly configurable.", |
@@ -5,6 +5,13 @@ # enhanced-resolve | ||
[![Build Status](https://secure.travis-ci.org/webpack/enhanced-resolve.png?branch=master)](http://travis-ci.org/webpack/enhanced-resolve) | ||
More documentation coming soon... | ||
## Features | ||
* sync and async versions | ||
* loaders and query strings | ||
* normal resolve | ||
* context resolve (resolve a directory) | ||
* loaders resolve | ||
* code completion | ||
## Request Format | ||
@@ -31,26 +38,45 @@ | ||
// Resolve a normal request | ||
resolve(context: String, identifier: String, options: Object, callback: (err: Error, result: String) => void) => void | ||
resolve.sync(context: String, identifier: String, options: Object) => String | ||
resolve(context: String, identifier: String, options?: Object, callback: (err: Error, result: String)) | ||
resolve.sync(context: String, identifier: String, options?: Object) => String | ||
// Resolve a context request, which means the result should be a folder | ||
resolve.context(context: String, identifier: String, options: Object, callback: (err: Error, result: String) => void) => void | ||
resolve.context.sync(context: String, identifier: String, options: Object) => String | ||
resolve.context(context: String, identifier: String, options?: Object, callback: (err: Error, result: String)) | ||
resolve.context.sync(context: String, identifier: String, options?: Object) => String | ||
// Only resolve loaders, a array of resolved loaders is the result | ||
resolve.loaders(context: String, identifier: String, options: Object, callback: (err: Error, result: String[]) => void) => void | ||
resolve.loaders.sync(context: String, identifier: String, options: Object) => String[] | ||
resolve.loaders(context: String, identifier: String, options?: Object, callback: (err: Error, result: String[])) | ||
resolve.loaders.sync(context: String, identifier: String, options?: Object) => String[] | ||
// Autocomplete a incomplete require expression. | ||
// identifier must contain exactly one "*", which indicates the insert position | ||
resolve.complete(context: String, identifier: String, options?: Object, callback: (err: Error, result: Completion[])) | ||
resolve.complete.sync(context: String, identifier: String, options?: Object) => Completion[] | ||
// parse a request | ||
resolve.parse(identifier: String) => {loaders: Part[], resource: Part} | ||
// parse only a part | ||
resolve.parse.part(identifierPart: String) => Part | ||
// stringify a parsed request | ||
resolve.stringify(parsed: {loaders: Part[], resource: Part}) => String | ||
// stringify only a part | ||
resolve.stringify.part(part: Part) => String | ||
// checks if a request part is a module | ||
resolve.parse.isModule(identifierPart: String) => Boolean | ||
// the type used for parse and stringify | ||
type Part { path: String, query: String, module: Boolean } | ||
// checks if a request part is a module | ||
resolve.parse.isModule(identifierPart: String) | ||
type Completion { // examples for "loader!module/dir/fi*?query" | ||
insert: String, // i. e. "le.js" | ||
seqment: String, // i. e. "file.js" | ||
part: String, // i. e. "module/dir/file.js?query" | ||
result: String // i. e. "loader!module/dir/file.js?query" | ||
} | ||
``` | ||
## Options | ||
@@ -132,2 +158,15 @@ | ||
*It is used i. e. in [webpack](https://github.com/webpack/webpack) and [Scripted](https://github.com/scripted-editor/scripted)* | ||
## Tests | ||
``` javascript | ||
npm test | ||
``` | ||
[![Build Status](https://secure.travis-ci.org/webpack/enhanced-resolve.png?branch=master)](http://travis-ci.org/webpack/enhanced-resolve) | ||
## License | ||
Copyright (c) 2012 Tobias Koppers | ||
MIT (http://www.opensource.org/licenses/mit-license.php) |
@@ -54,2 +54,5 @@ /* | ||
"./*ib": [{ insert: "l", seqment: "lib", part: "./lib", result: "./lib" }], | ||
"./li*": [ | ||
{ insert: "b", seqment: "lib", part: "./lib", result: "./lib" } | ||
], | ||
"./lib*": [ | ||
@@ -84,2 +87,7 @@ { insert: "", seqment: "lib", part: "./lib", result: "./lib" }, | ||
], | ||
"m2*": [ | ||
{ insert: "", seqment: "m2", part: "m2", result: "m2" }, | ||
{ insert: "-loader", seqment: "m2-loader", part: "m2-loader", result: "m2-loader" }, | ||
{ insert: "/", seqment: "m2/", part: "m2/", result: "m2/" } | ||
], | ||
"invalidPa*": [ | ||
@@ -98,2 +106,16 @@ { insert: "ckageJson", seqment: "invalidPackageJson", part: "invalidPackageJson", result: "invalidPackageJson" } | ||
{ insert: "mp", seqment: "complexm", part: "complexm/step1", result: "complexm/step1" } | ||
], | ||
"./shortcut*": [ | ||
{ insert: "dir.js", seqment: "shortcutdir.js", part: "./shortcutdir.js", result: "./shortcutdir.js" } | ||
], | ||
"./*cutdir": [], | ||
"./*cutdir.js": [ | ||
{ insert: "short", seqment: "shortcutdir.js", part: "./shortcutdir.js", result: "./shortcutdir.js" } | ||
], | ||
"./shortcutdir*/": [ | ||
{ insert: ".js", seqment: "shortcutdir.js", part: "./shortcutdir.js/", result: "./shortcutdir.js/" } | ||
], | ||
"./shortcutdir.js*": [ | ||
{ insert: "", seqment: "shortcutdir.js", part: "./shortcutdir.js", result: "./shortcutdir.js" }, | ||
{ insert: "/", seqment: "shortcutdir.js/", part: "./shortcutdir.js/", result: "./shortcutdir.js/" } | ||
] | ||
@@ -105,3 +127,3 @@ } | ||
var result = testCases[testCase]; | ||
it("should complete " + testCase, function() { | ||
it("should complete " + testCase + " (sync)", function() { | ||
var results = resolve.complete.sync(fixtures, testCase, options); | ||
@@ -111,3 +133,11 @@ should.exist(results); | ||
}); | ||
it("should complete " + testCase + " (async)", function(done) { | ||
resolve.complete(fixtures, testCase, options, function(err, results) { | ||
if(err) throw err; | ||
should.exist(results); | ||
results.should.be.eql(result); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
66437
38
2029
169