Comparing version 2.0.2 to 2.0.3
@@ -0,3 +1,4 @@ | ||
"use strict"; | ||
module.exports = require("./streams").BufferStream; | ||
<!-- vim:ts=4:sts=4:sw=4:et:tw=60 --> | ||
## 2.0.2 | ||
- Fixed problems with hanging connections, and problems with early termination | ||
of streams. | ||
- Added missing `node` property to Node writable stream wrapper. | ||
- Removed `Reader.join`. Removed support for `Reader.prototype.join`. | ||
Use `Reader(x).read()` and `Buffer.concat(buffers)`. | ||
- Added `node/process` process stream wrapper. | ||
- HTTP client now warns when there is a missing host header. | ||
- Fix problem with HTTP agent option with Node.js v0.11. | ||
- Refactored file system to use prototype inheritance pattern | ||
instead of Crockford style closure constructors. | ||
- Merged changes from v1 for HTTP request normalization. | ||
- Added support for response.statusText | ||
## 2.0.1 | ||
- Fixed URL dependency. | ||
## 2.0.0 :warning: | ||
@@ -4,0 +23,0 @@ |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
@@ -2,0 +3,0 @@ require("collections/shim"); |
@@ -0,1 +1,3 @@ | ||
"use strict"; | ||
/** | ||
@@ -2,0 +4,0 @@ * @module deprecate |
731
fs-common.js
@@ -0,467 +1,360 @@ | ||
"use strict"; | ||
// Originally from Narwhal, with contributions from Kris Kowal and Tom Robinson | ||
var Q = require("q"); | ||
var Boot = require("./fs-boot"); | ||
var RootFs = require("./fs-root"); | ||
var MockFs = require("./fs-mock"); | ||
var BaseFs = require("./fs-base"); | ||
// TODO patternToRegExp | ||
// TODO glob | ||
// TODO match | ||
module.exports = CommonFs; | ||
function CommonFs() { | ||
} | ||
var concat = function (arrays) { | ||
return Array.prototype.concat.apply([], arrays); | ||
CommonFs.prototype = Object.create(BaseFs.prototype); | ||
/** | ||
* Read a complete file. | ||
* @param {String} path Path to the file. | ||
* @param {String} [options.flags] The mode to open the file with. | ||
* @param {String} [options.charset] The charset to open the file with. | ||
* @param {Object} [options] An object with options. | ||
* second argument. | ||
* @returns {Promise.<String || Buffer>} | ||
*/ | ||
CommonFs.prototype.read = function (path, flags, charset, options) { | ||
if (typeof flags === "object") { | ||
options = flags; | ||
} else if (typeof charset === "object") { | ||
options = charset; | ||
options.flags = flags; | ||
} else { | ||
options = options || {}; | ||
options.flags = flags; | ||
options.charset = charset; | ||
} | ||
options.flags = options.flags || "r"; | ||
return this.open(path, options).then(function (stream) { | ||
return stream.read(); | ||
}, function (cause) { | ||
var error = new Error("Can't read " + JSON.stringify(path) + " because " + cause.message); | ||
error.code = cause.code; | ||
error.cause = cause; | ||
error.path = path; | ||
error.flags = flags; | ||
error.charset = charset; | ||
throw error; | ||
}); | ||
}; | ||
exports.update = function (exports, workingDirectory) { | ||
for (var name in Boot) { | ||
exports[name] = Boot[name]; | ||
/** | ||
* Write content to a file, overwriting the existing content. | ||
* @param {String} path Path to the file. | ||
* @param {String || Buffer} content | ||
* @param {String} [options.flags] The mode to open the file with. | ||
* @param {String} [options.charset] The charset to open the file with. | ||
* @param {Object} [options] An object with options. | ||
* @returns {Promise.<undefined>} a promise that resolves when the writing is | ||
* complete. | ||
*/ | ||
CommonFs.prototype.write = function (path, content, flags, charset, options) { | ||
var self = this; | ||
if (typeof flags === "object") { | ||
options = flags; | ||
} else if (typeof charset === "object") { | ||
options = charset; | ||
options.flags = flags; | ||
} else { | ||
options = options || {}; | ||
options.flags = flags; | ||
options.charset = charset; | ||
} | ||
/** | ||
* Read a complete file. | ||
* @param {String} path Path to the file. | ||
* @param {String} [options.flags] The mode to open the file with. | ||
* @param {String} [options.charset] The charset to open the file with. | ||
* @param {Object} [options] An object with options. | ||
* second argument. | ||
* @returns {Promise * (String || Buffer)} | ||
*/ | ||
exports.read = function (path, flags, charset, options) { | ||
if (typeof flags === "object") { | ||
options = flags; | ||
} else if (typeof charset === "object") { | ||
options = charset; | ||
options.flags = flags; | ||
} else { | ||
options = options || {}; | ||
options.flags = flags; | ||
options.charset = charset; | ||
flags = options.flags || "w"; | ||
if (flags.indexOf("b") !== -1) { | ||
if (!(content instanceof Buffer)) { | ||
content = new Buffer(content); | ||
} | ||
options.flags = options.flags || "r"; | ||
return this.open(path, options).then(function (stream) { | ||
return stream.read(); | ||
}, function (error) { | ||
error.message = "Can't read " + path + " because " + error.message; | ||
error.path = path; | ||
error.flags = flags; | ||
error.charset = charset; | ||
throw error; | ||
} else if (content instanceof Buffer) { | ||
flags += "b"; | ||
} | ||
options.flags = flags; | ||
return self.open(path, options).then(function (stream) { | ||
return stream.write(content).then(function () { | ||
return stream.close(); | ||
}); | ||
}; | ||
}); | ||
}; | ||
/** | ||
* Write content to a file, overwriting the existing content. | ||
* @param {String} path Path to the file. | ||
* @param {String || Buffer} content | ||
* @param {String} [options.flags] The mode to open the file with. | ||
* @param {String} [options.charset] The charset to open the file with. | ||
* @param {Object} [options] An object with options. | ||
* @returns {Promise * Undefined} a promise that resolves | ||
* when the writing is complete. | ||
*/ | ||
exports.write = function (path, content, flags, charset, options) { | ||
var self = this; | ||
if (typeof flags === "object") { | ||
options = flags; | ||
} else if (typeof charset === "object") { | ||
options = charset; | ||
options.flags = flags; | ||
} else { | ||
options = options || {}; | ||
options.flags = flags; | ||
options.charset = charset; | ||
} | ||
flags = options.flags || "w"; | ||
if (flags.indexOf("b") !== -1) { | ||
if (!(content instanceof Buffer)) { | ||
content = new Buffer(content); | ||
} | ||
} else if (content instanceof Buffer) { | ||
flags += "b"; | ||
} | ||
/** | ||
* Append content to the end of a file. | ||
* @param {String} path Path to the file. | ||
* @param {String || Buffer} content | ||
* @param {String} [options.flags] The mode to open the file with. | ||
* @param {String} [options.charset] The charset to open the file with. | ||
* @param {Object} [options] An object with options. | ||
* @returns {Promise * Undefined} a promise that resolves | ||
* when the writing is complete. | ||
*/ | ||
CommonFs.prototype.append = function (path, content, flags, charset, options) { | ||
var self = this; | ||
if (typeof flags === "object") { | ||
options = flags; | ||
} else if (typeof charset === "object") { | ||
options = charset; | ||
options.flags = flags; | ||
return self.open(path, options).then(function (stream) { | ||
return stream.write(content).then(function () { | ||
return stream.close(); | ||
}); | ||
} else { | ||
options = options || {}; | ||
options.flags = flags; | ||
options.charset = charset; | ||
} | ||
flags = options.flags || "a"; | ||
if (content instanceof Buffer) { | ||
flags += "b"; | ||
} | ||
options.flags = flags; | ||
return self.open(path, options).then(function (stream) { | ||
return stream.write(content).then(function () { | ||
return stream.close(); | ||
}); | ||
}; | ||
}); | ||
}; | ||
/** | ||
* Append content to the end of a file. | ||
* @param {String} path Path to the file. | ||
* @param {String || Buffer} content | ||
* @param {String} [options.flags] The mode to open the file with. | ||
* @param {String} [options.charset] The charset to open the file with. | ||
* @param {Object} [options] An object with options. | ||
* @returns {Promise * Undefined} a promise that resolves | ||
* when the writing is complete. | ||
*/ | ||
exports.append = function (path, content, flags, charset, options) { | ||
var self = this; | ||
if (typeof flags === "object") { | ||
options = flags; | ||
} else if (typeof charset === "object") { | ||
options = charset; | ||
options.flags = flags; | ||
CommonFs.prototype.move = function (source, target) { | ||
var self = this; | ||
return this.rename(source, target) | ||
.catch(function (error) { | ||
if (error.crossDevice) { | ||
return self.copyTree(source, target) | ||
.then(function () { | ||
return self.removeTree(source); | ||
}); | ||
} else { | ||
options = options || {}; | ||
options.flags = flags; | ||
options.charset = charset; | ||
throw error; | ||
} | ||
flags = options.flags || "a"; | ||
if (content instanceof Buffer) { | ||
flags += "b"; | ||
} | ||
options.flags = flags; | ||
return self.open(path, options).then(function (stream) { | ||
return stream.write(content).then(function () { | ||
return stream.close(); | ||
}); | ||
}); | ||
}; | ||
CommonFs.prototype.copy = function (source, target) { | ||
var self = this; | ||
return Q([ | ||
self.open(source, {flags: "rb"}), | ||
self.open(target, {flags: "wb"}) | ||
]).spread(function (reader, writer) { | ||
return reader.forEach(function (block) { | ||
return writer.write(block); | ||
}).then(function () { | ||
return Q.all([ | ||
reader.close(), | ||
writer.close() | ||
]); | ||
}); | ||
}; | ||
}); | ||
}; | ||
exports.move = function (source, target) { | ||
var self = this; | ||
return this.rename(source, target) | ||
.catch(function (error) { | ||
if (error.crossDevice) { | ||
return self.copyTree(source, target) | ||
.then(function () { | ||
return self.removeTree(source); | ||
CommonFs.prototype.copyTree = function (source, target) { | ||
var self = this; | ||
return self.stat(source).then(function (stat) { | ||
if (stat.isFile()) { | ||
return self.copy(source, target); | ||
} else if (stat.isDirectory()) { | ||
return self.exists(target).then(function (targetExists) { | ||
var copySubTree = self.list(source).then(function (list) { | ||
return Q.all(list.map(function (child) { | ||
return self.copyTree( | ||
self.join(source, child), | ||
self.join(target, child) | ||
); | ||
})); | ||
}); | ||
} else { | ||
throw error; | ||
} | ||
}); | ||
}; | ||
if (targetExists) { | ||
return copySubTree; | ||
} else { | ||
return self.makeDirectory(target).then(function () { | ||
return copySubTree; | ||
}); | ||
} | ||
}); | ||
} else if (stat.isSymbolicLink()) { | ||
// TODO copy the link and type with readPath (but what about | ||
// Windows junction type?) | ||
return self.symbolicCopy(source, target); | ||
} | ||
}); | ||
}; | ||
exports.copy = function (source, target) { | ||
var self = this; | ||
return Q([ | ||
self.open(source, {flags: "rb"}), | ||
self.open(target, {flags: "wb"}) | ||
]).spread(function (reader, writer) { | ||
return reader.forEach(function (block) { | ||
return writer.write(block); | ||
}).then(function () { | ||
return Q.all([ | ||
reader.close(), | ||
writer.close() | ||
]); | ||
}); | ||
}); | ||
CommonFs.prototype.listTree = function (basePath, guard) { | ||
var self = this; | ||
basePath = String(basePath || ""); | ||
if (!basePath) { | ||
basePath = "."; | ||
} | ||
guard = guard || function () { | ||
return true; | ||
}; | ||
exports.copyTree = function (source, target) { | ||
var self = this; | ||
return self.stat(source).then(function (stat) { | ||
if (stat.isFile()) { | ||
return self.copy(source, target); | ||
} else if (stat.isDirectory()) { | ||
return self.exists(target).then(function (targetExists) { | ||
var copySubTree = self.list(source).then(function (list) { | ||
return Q.all(list.map(function (child) { | ||
return self.copyTree( | ||
self.join(source, child), | ||
self.join(target, child) | ||
); | ||
})); | ||
}); | ||
if (targetExists) { | ||
return copySubTree; | ||
} else { | ||
return self.makeDirectory(target).then(function () { | ||
return copySubTree; | ||
}); | ||
} | ||
return self.stat(basePath).then(function (stat) { | ||
var paths = []; | ||
var mode; // true:include, false:exclude, null:no-recur | ||
var include = guard(basePath, stat); | ||
return Q(include).then(function (include) { | ||
if (include) { | ||
paths.push([basePath]); | ||
} | ||
if (include !== null && stat.isDirectory()) { | ||
return self.list(basePath).then(function (children) { | ||
paths.push.apply(paths, children.map(function (child) { | ||
var path = self.join(basePath, child); | ||
return self.listTree(path, guard); | ||
})); | ||
return paths; | ||
}); | ||
} else if (stat.isSymbolicLink()) { | ||
// TODO copy the link and type with readPath (but what about | ||
// Windows junction type?) | ||
return self.symbolicCopy(source, target); | ||
} else { | ||
return paths; | ||
} | ||
}); | ||
}; | ||
}, function noSuchFile(error) { | ||
throw error; // XXX TODO REMOVE | ||
return []; | ||
}).then(Q.all).then(concat); | ||
}; | ||
exports.listTree = function (basePath, guard) { | ||
var self = this; | ||
basePath = String(basePath || ''); | ||
if (!basePath) | ||
basePath = "."; | ||
guard = guard || function () { | ||
return true; | ||
}; | ||
return self.stat(basePath).then(function (stat) { | ||
var paths = []; | ||
var mode; // true:include, false:exclude, null:no-recur | ||
var include = guard(basePath, stat); | ||
return Q(include).then(function (include) { | ||
if (include) { | ||
paths.push([basePath]); | ||
} | ||
if (include !== null && stat.isDirectory()) { | ||
return self.list(basePath).then(function (children) { | ||
paths.push.apply(paths, children.map(function (child) { | ||
var path = self.join(basePath, child); | ||
return self.listTree(path, guard); | ||
})); | ||
return paths; | ||
}); | ||
CommonFs.prototype.listDirectoryTree = function (path) { | ||
return this.listTree(path, function (path, stat) { | ||
return stat.isDirectory(); | ||
}); | ||
}; | ||
CommonFs.prototype.makeTree = function (path, mode) { | ||
path = String(path); | ||
var self = this; | ||
var parts = self.split(path); | ||
var at = []; | ||
if (self.isAbsolute(path)) { | ||
// On Windows use the root drive (e.g. "C:"), on *nix the first | ||
// part is the falsey "", and so use the root ("/") | ||
at.push(parts.shift() || self.root); | ||
} | ||
return parts.reduce(function (parent, part) { | ||
return parent.then(function () { | ||
at.push(part); | ||
var parts = self.join(at) || "."; | ||
var made = self.makeDirectory(parts, mode); | ||
return Q.when(made, null, function rejected(error) { | ||
// throw away errors for already made directories | ||
if (error.exists) { | ||
return; | ||
} else { | ||
return paths; | ||
throw error; | ||
} | ||
}); | ||
}, function noSuchFile(reason) { | ||
return []; | ||
}).then(Q.all).then(concat); | ||
}; | ||
exports.listDirectoryTree = function (path) { | ||
return this.listTree(path, function (path, stat) { | ||
return stat.isDirectory(); | ||
}); | ||
}; | ||
}, Q()); | ||
}; | ||
exports.makeTree = function (path, mode) { | ||
path = String(path); | ||
var self = this; | ||
var parts = self.split(path); | ||
var at = []; | ||
if (self.isAbsolute(path)) { | ||
// On Windows use the root drive (e.g. "C:"), on *nix the first | ||
// part is the falsey "", and so use the ROOT ("/") | ||
at.push(parts.shift() || self.ROOT); | ||
} | ||
return parts.reduce(function (parent, part) { | ||
return parent.then(function () { | ||
at.push(part); | ||
var parts = self.join(at) || "."; | ||
var made = self.makeDirectory(parts, mode); | ||
return Q.when(made, null, function rejected(error) { | ||
// throw away errors for already made directories | ||
if (error.exists) { | ||
return; | ||
} else { | ||
throw error; | ||
} | ||
CommonFs.prototype.removeTree = function (path) { | ||
var self = this; | ||
return self.statLink(path).then(function (stat) { | ||
if (stat.isSymbolicLink()) { | ||
return self.remove(path); | ||
} else if (stat.isDirectory()) { | ||
return self.list(path) | ||
.then(function (list) { | ||
// asynchronously remove every subtree | ||
return Q.all(list.map(function (name) { | ||
return self.removeTree(self.join(path, name)); | ||
})) | ||
.then(function () { | ||
return self.removeDirectory(path); | ||
}); | ||
}); | ||
}, Q()); | ||
}; | ||
} else { | ||
return self.remove(path); | ||
} | ||
}); | ||
}; | ||
exports.removeTree = function (path) { | ||
var self = this; | ||
return self.statLink(path).then(function (stat) { | ||
if (stat.isSymbolicLink()) { | ||
return self.remove(path); | ||
} else if (stat.isDirectory()) { | ||
return self.list(path) | ||
.then(function (list) { | ||
// asynchronously remove every subtree | ||
return Q.all(list.map(function (name) { | ||
return self.removeTree(self.join(path, name)); | ||
})) | ||
.then(function () { | ||
return self.removeDirectory(path); | ||
}); | ||
}); | ||
} else { | ||
return self.remove(path); | ||
} | ||
}); | ||
}; | ||
CommonFs.prototype.symbolicCopy = function (source, target, type) { | ||
var self = this; | ||
return self.relative(target, source).then(function (relative) { | ||
return self.symbolicLink(target, relative, type || "file"); | ||
}); | ||
}; | ||
exports.symbolicCopy = function (source, target, type) { | ||
var self = this; | ||
return self.relative(target, source).then(function (relative) { | ||
return self.symbolicLink(target, relative, type || "file"); | ||
}); | ||
}; | ||
CommonFs.prototype.exists = function (path) { | ||
return this.stat(path).then(returnTrue, returnFalse); | ||
}; | ||
exports.exists = function (path) { | ||
return this.stat(path).then(returnTrue, returnFalse); | ||
}; | ||
CommonFs.prototype.isFile = function (path) { | ||
return this.stat(path).then(function (stat) { | ||
return stat.isFile(); | ||
}, returnFalse); | ||
}; | ||
exports.isFile = function (path) { | ||
return this.stat(path).then(function (stat) { | ||
return stat.isFile(); | ||
}, returnFalse); | ||
}; | ||
CommonFs.prototype.isDirectory = function (path) { | ||
return this.stat(path).then(function (stat) { | ||
return stat.isDirectory(); | ||
}, returnFalse); | ||
}; | ||
exports.isDirectory = function (path) { | ||
return this.stat(path).then(function (stat) { | ||
return stat.isDirectory(); | ||
}, returnFalse); | ||
}; | ||
CommonFs.prototype.isSymbolicLink = function (path) { | ||
return this.statLink(path).then(function (stat) { | ||
return stat.isSymbolicLink(); | ||
}, returnFalse); | ||
}; | ||
exports.isSymbolicLink = function (path) { | ||
return this.statLink(path).then(function (stat) { | ||
return stat.isSymbolicLink(); | ||
}, returnFalse); | ||
}; | ||
CommonFs.prototype.lastModified = function (path) { | ||
return this.stat(path).invoke("lastModified"); | ||
}; | ||
exports.lastModified = function (path) { | ||
return this.stat(path).invoke('lastModified'); | ||
}; | ||
CommonFs.prototype.lastAccessed = function (path) { | ||
return this.stat(path).invoke("lastAccessed"); | ||
}; | ||
exports.lastAccessed = function (path) { | ||
return this.stat(path).invoke('lastAccessed'); | ||
}; | ||
CommonFs.prototype.reroot = function (path) { | ||
var self = this; | ||
path = path || this.root; | ||
return require("./fs-root")(self, path); | ||
} | ||
exports.absolute = function (path) { | ||
if (this.isAbsolute(path)) | ||
return this.normal(path); | ||
return this.join(workingDirectory(), path); | ||
}; | ||
exports.relative = function (source, target) { | ||
var self = this; | ||
return this.isDirectory(source).then(function (isDirectory) { | ||
if (isDirectory) { | ||
return self.relativeFromDirectory(source, target); | ||
} else { | ||
return self.relativeFromFile(source, target); | ||
} | ||
}); | ||
}; | ||
exports.relativeFromFile = function (source, target) { | ||
source = this.absolute(source); | ||
target = this.absolute(target); | ||
source = source.split(this.SEPARATORS_RE()); | ||
target = target.split(this.SEPARATORS_RE()); | ||
source.pop(); | ||
while ( | ||
source.length && | ||
target.length && | ||
target[0] == source[0] | ||
) { | ||
source.shift(); | ||
target.shift(); | ||
} | ||
while (source.length) { | ||
source.shift(); | ||
target.unshift(".."); | ||
} | ||
return target.join(this.SEPARATOR); | ||
}; | ||
exports.relativeFromDirectory = function (source, target) { | ||
if (!target) { | ||
target = source; | ||
source = workingDirectory(); | ||
} | ||
source = this.absolute(source); | ||
target = this.absolute(target); | ||
source = source.split(this.SEPARATORS_RE()); | ||
target = target.split(this.SEPARATORS_RE()); | ||
if (source.length === 2 && source[1] === "") | ||
source.pop(); | ||
while ( | ||
source.length && | ||
target.length && | ||
target[0] == source[0] | ||
) { | ||
source.shift(); | ||
target.shift(); | ||
} | ||
while (source.length) { | ||
source.shift(); | ||
target.unshift(".."); | ||
} | ||
return target.join(this.SEPARATOR); | ||
}; | ||
exports.contains = function (parent, child) { | ||
parent = this.absolute(parent); | ||
child = this.absolute(child); | ||
parent = parent.split(this.SEPARATORS_RE()); | ||
child = child.split(this.SEPARATORS_RE()); | ||
if (parent.length === 2 && parent[1] === "") | ||
parent.pop(); | ||
if (parent.length > child.length) | ||
return false; | ||
for (index = 0; index < parent.length; index++) { | ||
if (parent[index] !== child[index]) | ||
break; | ||
} | ||
return index === parent.length; | ||
}; | ||
exports.reroot = reroot; | ||
function reroot(path) { | ||
var self = this; | ||
path = path || this.ROOT; | ||
return RootFs(self, path); | ||
} | ||
exports.toObject = function (path) { | ||
var self = this; | ||
return self.listTree(path || "", function (path, stat) { | ||
return stat.isFile(); | ||
}).then(function (list) { | ||
var tree = {}; | ||
return Q.all(list.map(function (path) { | ||
return self.read(path, "rb").then(function (content) { | ||
tree[path] = content; | ||
}); | ||
})).then(function () { | ||
return tree; | ||
CommonFs.prototype.toObject = function (path) { | ||
var self = this; | ||
return self.listTree(path || "", function (path, stat) { | ||
return stat.isFile(); | ||
}).then(function (list) { | ||
var tree = {}; | ||
return Q.all(list.map(function (path) { | ||
return self.read(path, "rb").then(function (content) { | ||
tree[path] = content; | ||
}); | ||
})).then(function () { | ||
return tree; | ||
}); | ||
}; | ||
}); | ||
}; | ||
exports.merge = function (fss) { | ||
var tree = {}; | ||
var done = Q(); | ||
fss.forEach(function (fs) { | ||
done = done.then(function () { | ||
return fs.listTree("", function (path, stat) { | ||
return stat.isFile(); | ||
}) | ||
.then(function (list) { | ||
return Q.all(list.map(function (path) { | ||
return Q.when(fs.read(path, "rb"), function (content) { | ||
tree[path] = content; | ||
}); | ||
})); | ||
}); | ||
CommonFs.prototype.merge = function (fss) { | ||
var tree = {}; | ||
var done = Q(); | ||
fss.forEach(function (fs) { | ||
done = done.then(function () { | ||
return fs.listTree("", function (path, stat) { | ||
return stat.isFile(); | ||
}) | ||
.then(function (list) { | ||
return Q.all(list.map(function (path) { | ||
return fs.read(path, "rb").then(function (content) { | ||
tree[path] = content; | ||
}); | ||
})); | ||
}); | ||
}) | ||
return done.then(function () { | ||
return MockFs(tree); | ||
}); | ||
}; | ||
exports.Stats = Stats; | ||
function Stats(nodeStat) { | ||
this.node = nodeStat; | ||
this.size = nodeStat.size; | ||
} | ||
var stats = [ | ||
"isDirectory", | ||
"isFile", | ||
"isBlockDevice", | ||
"isCharacterDevice", | ||
"isSymbolicLink", | ||
"isFIFO", | ||
"isSocket" | ||
]; | ||
stats.forEach(function (name) { | ||
Stats.prototype[name] = function () { | ||
return this.node[name](); | ||
}; | ||
}) | ||
return done.then(function () { | ||
return require("./fs-mock")(tree); | ||
}); | ||
}; | ||
Stats.prototype.lastModified = function () { | ||
return new Date(this.node.mtime); | ||
}; | ||
CommonFs.prototype.mock = function (path) { | ||
return require("./fs-mock").mock(this, path); | ||
}; | ||
Stats.prototype.lastAccessed = function () { | ||
return new Date(this.node.atime); | ||
}; | ||
function concat(arrays) { | ||
return Array.prototype.concat.apply([], arrays); | ||
} | ||
@@ -468,0 +361,0 @@ |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
@@ -2,0 +3,0 @@ var Q = require("q"); |
@@ -0,5 +1,5 @@ | ||
"use strict"; | ||
var Q = require("q"); | ||
var Boot = require("./fs-boot"); | ||
var Common = require("./fs-common"); | ||
var CommonFs = require("./fs-common"); | ||
var Set = require("collections/set"); | ||
@@ -10,3 +10,2 @@ var join = require("./streams").join; | ||
module.exports = MockFs; | ||
function MockFs(files, workingDirectory) { | ||
@@ -18,20 +17,21 @@ if (!(this instanceof MockFs)) { | ||
function init() { | ||
// construct a file tree | ||
} | ||
Common.update(this, function () { | ||
workingDirectory = workingDirectory || this.root; | ||
this.workingDirectory = function () { | ||
return workingDirectory; | ||
}); | ||
}; | ||
workingDirectory = workingDirectory || this.ROOT; | ||
if (files) { | ||
this._init(files); | ||
this.load(files); | ||
} | ||
} | ||
MockFs.prototype = Object.create(Boot); | ||
MockFs.prototype = Object.create(CommonFs.prototype); | ||
MockFs.prototype.constructor = MockFs; | ||
MockFs.prototype._init = function (files, tree) { | ||
tree = tree || this.ROOT; | ||
MockFs.prototype.root = "/"; | ||
MockFs.prototype.separator = "/"; | ||
MockFs.prototype.separatorsExpression = /\//g; | ||
MockFs.prototype.load = function (files, tree) { | ||
tree = tree || this.root; | ||
Object.keys(files).forEach(function (path) { | ||
@@ -49,3 +49,3 @@ var content = files[path]; | ||
// make content | ||
this._init(content, path); | ||
this.load(content, path); | ||
return; | ||
@@ -100,3 +100,3 @@ } else { | ||
if (!node._entries[base]) { | ||
node._entries[base] = new FileNode(this); | ||
node._entries[base] = new FileNode(self); | ||
} | ||
@@ -129,3 +129,3 @@ var fileNode = node._entries[base]._follow(path); | ||
[ | ||
join(fileNode._chunks) | ||
Buffer.concat(fileNode._chunks) | ||
.slice(options.begin, options.end) | ||
@@ -210,5 +210,5 @@ ], | ||
var self = this; | ||
path = self.absolute(path); | ||
return Q.try(function () { | ||
path = self.absolute(path); | ||
return new self.Stats(self._root._walk(path)._follow(path)); | ||
return self._root._walk(path)._follow(path); | ||
}); | ||
@@ -370,4 +370,5 @@ }; | ||
function Node(fs) { | ||
if (!fs) | ||
if (!fs) { | ||
throw new Error("FS required argument"); | ||
} | ||
this._fs = fs; | ||
@@ -377,2 +378,3 @@ this._accessed = this._modified = new Date(); | ||
this._owner = null; | ||
this.hash = Math.random().toString(36).slice(2); | ||
} | ||
@@ -384,5 +386,5 @@ | ||
parts.shift(); | ||
return this._fs._root._walkParts(parts, make, this._fs.ROOT); | ||
return this._fs._root._walkParts(parts, make, this._fs.root); | ||
} else { | ||
return this._walkParts(parts, make, via || this._fs.ROOT); | ||
return this._walkParts(parts, make, via || this._fs.root); | ||
} | ||
@@ -412,3 +414,3 @@ }; | ||
parts.shift(); | ||
var via = this._fs.ROOT; | ||
var via = this._fs.root; | ||
return via + this._fs._root._canonicalParts(parts, via); | ||
@@ -490,3 +492,3 @@ }; | ||
DirectoryNode.prototype._walkParts = function (parts, make, via) { | ||
via = via || this._fs.ROOT; | ||
via = via || this._fs.root; | ||
if (parts.length === 0) { | ||
@@ -503,3 +505,3 @@ return this; | ||
} else { | ||
var error = new Error("Can't find " + JSON.stringify(this._fs.join(parts)) + " via " + JSON.stringify(via)); | ||
var error = new Error("Can't find " + JSON.stringify(this._fs.join(parts.concat([part]))) + " via " + JSON.stringify(via)); | ||
error.code = "ENOENT"; | ||
@@ -521,3 +523,3 @@ throw error; | ||
} | ||
if (via === this._fs.ROOT) { | ||
if (via === this._fs.root) { | ||
via = ""; | ||
@@ -558,3 +560,3 @@ } | ||
LinkNode.prototype._canonicalParts = function (parts, via) { | ||
return this._fs.relativeFromDirectory(this._fs.ROOT, | ||
return this._fs.relativeFromDirectory(this._fs.root, | ||
this._fs._root._canonical( | ||
@@ -561,0 +563,0 @@ this._fs.absolute(this._fs.join(via, "..", this._link)) |
@@ -0,11 +1,16 @@ | ||
"use strict"; | ||
var Q = require("q"); | ||
var BOOT = require("./fs-boot"); | ||
var COMMON = require("./fs-common"); | ||
var CommonFs = require("./fs-common"); | ||
module.exports = RootFs; | ||
function RootFs(outer, root) { | ||
var inner = Object.create(BOOT); | ||
var inner = Object.create(CommonFs.prototype); | ||
inner.root = outer.root; | ||
inner.separator = outer.separator; | ||
inner.altSeparator = outer.altSeparator; | ||
inner.separatorsExpression = outer.separatorsExpression; | ||
function attenuate(path) { | ||
@@ -19,3 +24,3 @@ | ||
if (outer.isAbsolute(path)) { | ||
actual = outer.relativeFromDirectory(outer.ROOT, path); | ||
actual = outer.relativeFromDirectory(outer.root, path); | ||
} else { | ||
@@ -28,8 +33,9 @@ actual = path; | ||
// behavior | ||
actual = outer.join(outer.ROOT, actual); | ||
actual = outer.join(outer.root, actual); | ||
// then we reconstruct the path relative to the | ||
// inner root | ||
actual = outer.relativeFromDirectory(outer.ROOT, actual); | ||
actual = outer.relativeFromDirectory(outer.root, actual); | ||
// and rejoin it on the outer root | ||
actual = outer.join(root, actual); | ||
var IN = actual; | ||
// and find the corresponding real path | ||
@@ -47,3 +53,3 @@ return outer.canonical(actual) | ||
return { | ||
"inner": outer.join(outer.ROOT, outer.relativeFromDirectory(root, actual)), | ||
"inner": outer.join(outer.root, outer.relativeFromDirectory(root, actual)), | ||
"outer": actual | ||
@@ -60,7 +66,5 @@ }; | ||
function workingDirectory() { | ||
return outer.ROOT; | ||
return outer.root; | ||
} | ||
COMMON.update(inner, workingDirectory); | ||
inner.list = function (path) { | ||
@@ -70,3 +74,3 @@ return attenuate(path).then(function (path) { | ||
}).then(null, function (reason) { | ||
return Q.reject("Can't list " + JSON.stringify(path)); | ||
throw new Error("Can't list " + JSON.stringify(path)); | ||
}); | ||
@@ -79,3 +83,3 @@ }; | ||
}).then(null, function (reason) { | ||
return Q.reject("Can't open " + JSON.stringify(path)); | ||
throw new Error("Can't open " + JSON.stringify(path)); | ||
}); | ||
@@ -88,3 +92,3 @@ }; | ||
}).then(null, function (reason) { | ||
return Q.reject("Can't stat " + JSON.stringify(path)); | ||
throw new Error("Can't stat " + JSON.stringify(path)); | ||
}); | ||
@@ -97,3 +101,3 @@ }; | ||
}).then(null, function (reason) { | ||
return Q.reject("Can't statLink " + JSON.stringify(path)); | ||
throw new Error("Can't statLink " + JSON.stringify(path)); | ||
}); | ||
@@ -106,3 +110,3 @@ }; | ||
}).then(null, function (reason) { | ||
return Q.reject("Can't find canonical of " + JSON.stringify(path)); | ||
throw new Error("Can't find canonical of " + JSON.stringify(path)); | ||
}); | ||
@@ -114,3 +118,3 @@ }; | ||
return outer.makeDirectory(path.outer); | ||
}).catch(function (error) { | ||
}).then(null, function (error) { | ||
throw new Error("Can't make directory " + JSON.stringify(path)); | ||
@@ -123,3 +127,3 @@ }); | ||
return outer.removeDirectory(path.outer); | ||
}).catch(function (error) { | ||
}).then(null, function (error) { | ||
throw new Error("Can't remove directory " + JSON.stringify(path)); | ||
@@ -126,0 +130,0 @@ }); |
361
fs.js
@@ -1,359 +0,4 @@ | ||
/** | ||
* An asynchronous local file system API, based on a subset | ||
* of the `narwhal/fs` API and the `narwhal/promise` API, | ||
* such that the method names are the same but some return | ||
* values are promises instead of fully resolved values. | ||
* @module | ||
*/ | ||
"use strict"; | ||
/*whatsupdoc*/ | ||
var FS = require("fs"); // node | ||
var Q = require("q"); | ||
var Reader = require("./node/reader"); | ||
var Writer = require("./node/writer"); | ||
var Common = require("./fs-common"); | ||
var Mock = require("./fs-mock"); | ||
var Root = require("./fs-root"); | ||
Common.update(exports, process.cwd); | ||
exports.Mock = Mock; | ||
exports.Root = Root; | ||
// facilitates AIMD (additive increase, multiplicative decrease) for backing off | ||
var backOffDelay = 0; | ||
var backOffFactor = 1.0001; | ||
function dampen(wrapped, thisp) { | ||
wrapped = Q(wrapped); | ||
var retry = function () { | ||
var args = arguments; | ||
var ready = Q(); | ||
if (backOffDelay) { | ||
ready = ready.delay(backOffDelay); | ||
} | ||
return ready.then(function () { | ||
return wrapped.apply(thisp, args).then(function (stream) { | ||
backOffDelay = Math.max(0, backOffDelay - 1); | ||
return stream; | ||
}, function (error) { | ||
if (error.code === "EMFILE") { | ||
backOffDelay = (backOffDelay + 1) * backOffFactor; | ||
return retry.apply(null, args); | ||
} else { | ||
throw error; | ||
} | ||
}); | ||
}); | ||
}; | ||
return retry; | ||
} | ||
/** | ||
* @param {String} path | ||
* @param {Object} options (flags, mode, bufferSize, charset, begin, end) | ||
* @returns {Promise * Stream} a stream from the `q-io` module. | ||
*/ | ||
exports.open = dampen(function (path, flags, charset, options) { | ||
var self = this; | ||
if (typeof flags == "object") { | ||
options = flags; | ||
flags = options.flags; | ||
charset = options.charset; | ||
} | ||
options = options || {}; | ||
flags = flags || "r"; | ||
var nodeFlags = flags.replace(/b/g, "") || "r"; | ||
var nodeOptions = { | ||
"flags": nodeFlags | ||
}; | ||
if ("bufferSize" in options) { | ||
nodeOptions.bufferSize = options.bufferSize; | ||
} | ||
if ("mode" in options) { | ||
nodeOptions.mode = options.mode; | ||
} | ||
if ("begin" in options) { | ||
nodeOptions.start = options.begin; | ||
nodeOptions.end = options.end - 1; | ||
} | ||
if (flags.indexOf("b") >= 0) { | ||
if (charset) { | ||
throw new Error("Can't open a binary file with a charset: " + charset); | ||
} | ||
} else { | ||
charset = charset || 'utf-8'; | ||
} | ||
if (flags.indexOf("w") >= 0 || flags.indexOf("a") >= 0) { | ||
var stream = FS.createWriteStream(String(path), nodeOptions); | ||
return Writer(stream, charset); | ||
} else { | ||
var stream = FS.createReadStream(String(path), nodeOptions); | ||
return Reader(stream, charset); | ||
} | ||
}); | ||
exports.remove = function (path) { | ||
path = String(path); | ||
var done = Q.defer(); | ||
FS.unlink(path, function (error) { | ||
if (error) { | ||
error.message = "Can't remove " + JSON.stringify(path) + ": " + error.message; | ||
done.reject(error); | ||
} else { | ||
done.resolve(); | ||
} | ||
}); | ||
return done.promise; | ||
}; | ||
exports.rename = function (source, target) { | ||
source = String(source); | ||
target = String(target); | ||
return Q.ninvoke(FS, "rename", source, target) | ||
.catch(function (error) { | ||
if (error.code === "EXDEV") { | ||
error.message = "source and target are on different devices: " + error.message; | ||
error.crossDevice = true; | ||
} | ||
error.message = ( | ||
"Can't move " + JSON.stringify(source) + " to " + | ||
JSON.stringify(target) + " because " + error.message | ||
); | ||
throw error; | ||
}); | ||
}; | ||
exports.makeDirectory = function (path, mode) { | ||
path = String(path); | ||
var done = Q.defer(); | ||
if (typeof mode === "string") { | ||
mode = parseInt(mode, 8); | ||
} else if (mode === void 0) { | ||
mode = parseInt('755', 8); | ||
} | ||
FS.mkdir(path, mode, function (error) { | ||
if (error) { | ||
if (error.code === "EISDIR") { | ||
error.exists = true; | ||
error.isDirectory = true; | ||
error.message = "directory already exists: " + error.message; | ||
} | ||
if (error.code === "EEXIST") { | ||
error.exists = true; | ||
error.message = "file exists at that path: " + error.message; | ||
} | ||
error.message = "Can't makeDirectory " + JSON.stringify(path) + " with mode " + mode + ": " + error.message; | ||
done.reject(error); | ||
} else { | ||
done.resolve(); | ||
} | ||
}); | ||
return done.promise; | ||
}; | ||
exports.removeDirectory = function (path) { | ||
path = String(path); | ||
var done = Q.defer(); | ||
FS.rmdir(path, function (error) { | ||
if (error) { | ||
error.message = "Can't removeDirectory " + JSON.stringify(path) + ": " + error.message; | ||
done.reject(error); | ||
} else { | ||
done.resolve(); | ||
} | ||
}); | ||
return done.promise; | ||
}; | ||
/** | ||
*/ | ||
exports.list = dampen(function (path) { | ||
path = String(path); | ||
var result = Q.defer(); | ||
FS.readdir(path, function (error, list) { | ||
if (error) { | ||
error.message = "Can't list " + JSON.stringify(path) + ": " + error.message; | ||
return result.reject(error); | ||
} else { | ||
result.resolve(list); | ||
} | ||
}); | ||
return result.promise; | ||
}); | ||
/** | ||
* @param {String} path | ||
* @returns {Promise * Stat} | ||
*/ | ||
exports.stat = function (path) { | ||
var self = this; | ||
path = String(path); | ||
var done = Q.defer(); | ||
try { | ||
FS.stat(path, function (error, stat) { | ||
if (error) { | ||
error.message = "Can't stat " + JSON.stringify(path) + ": " + error; | ||
done.reject(error); | ||
} else { | ||
done.resolve(new self.Stats(stat)); | ||
} | ||
}); | ||
} catch (error) { | ||
done.reject(error); | ||
} | ||
return done.promise; | ||
}; | ||
exports.statLink = function (path) { | ||
path = String(path); | ||
var done = Q.defer(); | ||
try { | ||
FS.lstat(path, function (error, stat) { | ||
if (error) { | ||
error.message = "Can't statLink " + JSON.stringify(path) + ": " + error.message; | ||
done.reject(error); | ||
} else { | ||
done.resolve(stat); | ||
} | ||
}); | ||
} catch (error) { | ||
done.reject(error); | ||
} | ||
return done.promise; | ||
}; | ||
exports.statFd = function (fd) { | ||
fd = Number(fd); | ||
var done = Q.defer(); | ||
try { | ||
FS.fstat(fd, function (error, stat) { | ||
if (error) { | ||
error.message = "Can't statFd file descriptor " + JSON.stringify(fd) + ": " + error.message; | ||
done.reject(error); | ||
} else { | ||
done.resolve(stat); | ||
} | ||
}); | ||
} catch (error) { | ||
done.reject(error); | ||
} | ||
return done.promise; | ||
}; | ||
exports.link = function (source, target) { | ||
source = String(source); | ||
target = String(target); | ||
var done = Q.defer(); | ||
try { | ||
FS.link(source, target, function (error) { | ||
if (error) { | ||
error.message = "Can't link " + JSON.stringify(source) + " to " + JSON.stringify(target) + ": " + error.message; | ||
done.reject(error); | ||
} else { | ||
done.resolve(); | ||
} | ||
}); | ||
} catch (error) { | ||
done.reject(error); | ||
} | ||
return done.promise; | ||
}; | ||
// this lookup table translates the link types that Q-IO accepts (which have | ||
// been normalized to full words to be consistent with the naming convention) | ||
var linkTypes = { | ||
"file": "file", | ||
"directory": "dir", | ||
"junction": "junction" | ||
}; | ||
exports.symbolicLink = function (target, relative, type) { | ||
if (!linkTypes.hasOwnProperty(type)) { | ||
console.warn(new Error("For Windows compatibility, symbolicLink must be called with a type argument \"file\", \"directory\", or \"junction\"")); | ||
} | ||
type = linkTypes[type]; | ||
target = String(target); | ||
relative = String(relative); | ||
var done = Q.defer(); | ||
try { | ||
FS.symlink(relative, target, type || 'file', function (error) { | ||
if (error) { | ||
error.message = "Can't create symbolicLink " + JSON.stringify(target) + " to relative location " + JSON.stringify(relative) + ": " + error.message; | ||
done.reject(error); | ||
} else { | ||
done.resolve(); | ||
} | ||
}); | ||
} catch (error) { | ||
done.reject(error); | ||
} | ||
return done.promise; | ||
}; | ||
exports.chown = function (path, uid, gid) { | ||
path = String(path); | ||
var done = Q.defer(); | ||
try { | ||
FS.chown(path, uid, gid, function (error) { | ||
if (error) { | ||
error.message = "Can't chown (change owner) of " + JSON.stringify(path) + " to user " + JSON.stringify(uid) + " and group " + JSON.stringify(gid) + ": " + error.message; | ||
done.reject(error); | ||
} else { | ||
done.resolve(); | ||
} | ||
}); | ||
} catch (error) { | ||
done.reject(error); | ||
} | ||
return done.promise; | ||
}; | ||
exports.chmod = function (path, mode) { | ||
path = String(path); | ||
mode = String(mode); | ||
var done = Q.defer(); | ||
try { | ||
FS.chmod(path, mode, function (error) { | ||
if (error) { | ||
error.message = "Can't chmod (change permissions mode) of " + JSON.stringify(path) + " to (octal number) " + mode.toString(8) + ": " + error.message; | ||
done.reject(error); | ||
} else { | ||
done.resolve(); | ||
} | ||
}); | ||
} catch (error) { | ||
done.reject(error); | ||
} | ||
return done.promise; | ||
}; | ||
exports.canonical = function (path) { | ||
var result = Q.defer(); | ||
FS.realpath(path, function (error, canonicalPath) { | ||
if (error) { | ||
error.message = "Can't get canonical path of " + JSON.stringify(path) + " by way of C realpath: " + error.message; | ||
result.reject(error); | ||
} else { | ||
result.resolve(canonicalPath); | ||
} | ||
}); | ||
return result.promise; | ||
}; | ||
exports.readLink = function (path) { | ||
var result = Q.defer(); | ||
FS.readlink(path, function (error, path) { | ||
if (error) { | ||
error.message = "Can't get link from " + JSON.stringify(path) + " by way of C readlink: " + error.message; | ||
result.reject(error); | ||
} else { | ||
result.resolve(path); | ||
} | ||
}); | ||
return result.promise; | ||
}; | ||
exports.mock = function (path) { | ||
return Mock.mock(this, path); | ||
}; | ||
var Fs = require("./fs-constructor"); | ||
module.exports = new Fs(); |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
@@ -2,0 +3,0 @@ var Q = require("q"); |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
@@ -2,0 +3,0 @@ /** |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
@@ -2,0 +3,0 @@ module.exports = Chain; |
@@ -0,3 +1,6 @@ | ||
"use strict"; | ||
var Q = require("q"); | ||
var Negotiate = require("./negotiate"); | ||
var Reader = require("../reader"); | ||
var QS = require("qs"); | ||
@@ -61,3 +64,4 @@ var URL = require("url2"); | ||
return function (request) { | ||
return Q(request.body || nobody).invoke("join", "") | ||
return Reader(request.body || nobody) | ||
.read() | ||
.then(function (body) { | ||
@@ -64,0 +68,0 @@ return app(body, request); |
@@ -0,4 +1,6 @@ | ||
"use strict"; | ||
var Q = require("q"); | ||
var Cookie = require("../http-cookie"); | ||
Q.longStackSupport = true; | ||
@@ -9,2 +11,5 @@ exports.CookieJar = function (app) { | ||
if (!request.headers.host) { | ||
throw new Error("Requests must have a host header"); | ||
} | ||
var hosts = allHostsContaining(request.headers.host); | ||
@@ -34,4 +39,5 @@ | ||
.map(function (host) { | ||
if (!hostContains(host, request.headers.host)) | ||
if (!hostContains(host, request.headers.host)) { | ||
return []; | ||
} | ||
var pathCookies = hostCookies[host]; | ||
@@ -79,5 +85,6 @@ return concat( | ||
if (response.headers["set-cookie"]) { | ||
var requestHost = ipRe.test(request.headers.host) ? | ||
request.headers.host : | ||
"." + request.headers.host; | ||
var host = request.headers.host; | ||
var hostParts = splitHost(host); | ||
var hostname = hostParts[0]; | ||
var requestHost = ipRe.test(hostname) ? host : "." + host; | ||
// normalize to array | ||
@@ -111,13 +118,26 @@ if (!Array.isArray(response.headers["set-cookie"])) { | ||
var ipRe = /^\d+\.\d+\.\d+\.\d+$/; | ||
var portRe = /^(.*)(:\d+)$/; | ||
function allHostsContaining(content) { | ||
if (ipRe.test(content)) { | ||
return [content]; | ||
} if (content === "localhost") { | ||
return [content]; | ||
function splitHost(host) { | ||
var match = portRe.exec(host); | ||
if (match) { | ||
return [match[1], match[2]]; | ||
} else { | ||
var parts = content.split("."); | ||
return [host, ""]; | ||
} | ||
} | ||
function allHostsContaining(host) { | ||
var parts = splitHost(host); | ||
var hostname = parts[0]; | ||
var port = parts[1]; | ||
if (ipRe.test(hostname)) { | ||
return [hostname + port]; | ||
} if (hostname === "localhost") { | ||
return [hostname + port]; | ||
} else { | ||
var parts = hostname.split("."); | ||
var hosts = []; | ||
while (parts.length > 1) { | ||
hosts.push("." + parts.join(".")); | ||
hosts.push("." + parts.join(".") + port); | ||
parts.shift(); | ||
@@ -129,14 +149,23 @@ } | ||
function hostContains(container, content) { | ||
if (ipRe.test(container) || ipRe.test(content)) { | ||
return container === content; | ||
} else if (/^\./.test(container)) { | ||
function hostContains(containerHost, contentHost) { | ||
var containerParts = splitHost(containerHost); | ||
var containerHostname = containerParts[0]; | ||
var containerPort = containerParts[1]; | ||
var contentParts = splitHost(contentHost); | ||
var contentHostname = contentParts[0]; | ||
var contentPort = contentParts[1]; | ||
if (containerPort !== contentPort) { | ||
return false; | ||
} | ||
if (ipRe.test(containerHostname) || ipRe.test(contentHostname)) { | ||
return containerHostname === contentHostname; | ||
} else if (/^\./.test(containerHostname)) { | ||
return ( | ||
content.lastIndexOf(container) === | ||
content.length - container.length | ||
contentHostname.lastIndexOf(containerHostname) === | ||
contentHostname.length - containerHostname.length | ||
) || ( | ||
container.slice(1) === content | ||
containerHostname.slice(1) === contentHostname | ||
); | ||
} else { | ||
return container === content; | ||
return containerHostname === contentHostname; | ||
} | ||
@@ -143,0 +172,0 @@ }; |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
@@ -2,0 +3,0 @@ var Q = require("q"); |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
@@ -84,3 +85,3 @@ var Q = require("q"); | ||
return fs.stat(path).then(function (stat) { | ||
var etag = exports.etag(stat); | ||
var etag = stat.hash; | ||
var options = { | ||
@@ -193,14 +194,2 @@ flags: "rb" | ||
/** | ||
* @param {Stat} | ||
* @returns {String} | ||
*/ | ||
exports.etag = function (stat) { | ||
return [ | ||
stat.node.ino, | ||
stat.size, | ||
stat.lastModified().getTime() | ||
].join("-"); | ||
}; | ||
/** | ||
* @param {Request} request | ||
@@ -207,0 +196,0 @@ * @param {String} path |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
@@ -2,0 +3,0 @@ var Q = require("q"); |
@@ -0,1 +1,3 @@ | ||
"use strict"; | ||
var Q = require("q"); | ||
@@ -2,0 +4,0 @@ var Content = require("./content"); |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
@@ -2,0 +3,0 @@ var Q = require("q"); |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
@@ -2,0 +3,0 @@ var HTTP = require("../http"); |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
@@ -2,0 +3,0 @@ var Q = require("q"); |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
@@ -2,0 +3,0 @@ var Q = require("q"); |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
@@ -9,3 +10,3 @@ var Negotiation = require("./negotiate"); | ||
*/ | ||
// Every standard HTTP code mapped to the appropriate message. | ||
// Every standard HTTP code mapped to the appropriate statusText. | ||
// Stolen from Rack which stole from Mongrel | ||
@@ -94,3 +95,3 @@ exports.statusCodes = { | ||
* @param {Number} status an HTTP status code | ||
* @param {String} message (optional) a message to include | ||
* @param {String} statusText (optional) a message to include | ||
* in the response body. | ||
@@ -102,6 +103,7 @@ * @returns a JSGI HTTP response object with the given status | ||
exports.responseForStatus = function(request, status, addendum) { | ||
if (exports.statusCodes[status] === undefined) | ||
throw "Unknown status code"; | ||
if (exports.statusCodes[status] === void 0) { | ||
throw new Error("Unknown status code"); | ||
} | ||
var message = exports.statusCodes[status]; | ||
var statusText = exports.statusCodes[status]; | ||
@@ -123,8 +125,8 @@ // RFC 2616, 10.2.5: | ||
var responseForStatus = Negotiation.negotiate(request, handlers) || exports.textResponseForStatus; | ||
return responseForStatus(request, status, message, addendum); | ||
return responseForStatus(request, status, statusText, addendum); | ||
} | ||
}; | ||
exports.textResponseForStatus = function (request, status, message, addendum) { | ||
var content = message + "\n"; | ||
exports.textResponseForStatus = function (request, status, statusText, addendum) { | ||
var content = statusText + "\n"; | ||
if (addendum) { | ||
@@ -136,3 +138,3 @@ content += addendum + "\n"; | ||
status: status, | ||
statusMessage: message, | ||
statusText: statusText, | ||
headers: { | ||
@@ -145,11 +147,11 @@ "content-length": contentLength | ||
exports.htmlResponseForStatus = function (request, status, message, addendum) { | ||
exports.htmlResponseForStatus = function (request, status, statusText, addendum) { | ||
return { | ||
status: status, | ||
statusMessage: message, | ||
statusText: statusText, | ||
headers: {}, | ||
htmlTitle: message, | ||
htmlTitle: statusText, | ||
htmlFragment: { | ||
forEach: function (write) { | ||
write("<h1>" + HtmlApps.escapeHtml(message) + "</h1>\n"); | ||
write("<h1>" + HtmlApps.escapeHtml(statusText) + "</h1>\n"); | ||
write("<p>Status: " + status + "</p>\n"); | ||
@@ -156,0 +158,0 @@ if (addendum) { |
@@ -0,9 +1,7 @@ | ||
"use strict"; | ||
/** | ||
* Provides utilities for reading and writing HTTP cookies. | ||
* @module | ||
*/ | ||
/*whatsupdoc*/ | ||
var QS = require("qs"); | ||
@@ -10,0 +8,0 @@ |
88
http.js
@@ -0,8 +1,7 @@ | ||
"use strict"; | ||
/** | ||
* A promise-based Q-JSGI server and client API. | ||
* @module | ||
*/ | ||
/*whatsupdoc*/ | ||
var HTTP = require("http"); // node | ||
@@ -43,3 +42,7 @@ var HTTPS = require("https"); // node | ||
_response.writeHead(response.status, response.headers); | ||
if (response.statusText) { | ||
_response.writeHead(response.status, response.statusText, response.headers); | ||
} else { | ||
_response.writeHead(response.status, response.headers); | ||
} | ||
@@ -76,8 +79,5 @@ // TODO remove support for response.charset? | ||
listening = undefined; | ||
//server.getConnections(function (error, connections) { | ||
// if (connections) { | ||
// console.warn(connections + " outstanding connections at time to of close"); | ||
// } | ||
//}); | ||
return stopped.promise; | ||
return Q(); | ||
// XXX does not seem to ever resolve in some cases: | ||
// return stopped.promise; | ||
}; | ||
@@ -164,4 +164,5 @@ | ||
/*** {String} host */ | ||
request.host = request.hostname + ":" + address.port; | ||
request.port = address.port; | ||
var defaultPort = request.port === (ssl ? 443 : 80); | ||
request.host = request.hostname + (defaultPort ? "" : ":" + request.port); | ||
@@ -204,16 +205,34 @@ var socket = _request.socket; | ||
if (typeof request === "string") { | ||
request = { | ||
url: request | ||
}; | ||
request = {url: request}; | ||
} | ||
request.method = request.method || "GET"; | ||
request.headers = request.headers || {}; | ||
if (request.url) { | ||
var url = URL.parse(request.url); | ||
request.host = url.hostname; | ||
request.port = url.port; | ||
request.ssl = url.protocol === "https:"; | ||
request.method = request.method || "GET"; | ||
request.hostname = url.hostname; | ||
request.host = url.host; | ||
request.port = +url.port; | ||
request.path = (url.pathname || "") + (url.search || ""); | ||
request.headers = request.headers || {}; | ||
request.headers.host = url.hostname; // FIXME name consistency | ||
if (url.auth) { | ||
request.auth = url.auth; | ||
if (!request.headers["authorization"]) { | ||
request.headers["authorization"] = ( | ||
"Basic " + new Buffer(url.auth) | ||
.toString("base64") | ||
); | ||
} | ||
} | ||
} | ||
request.host = request.host || request.headers.host; | ||
request.port = request.port || (request.ssl ? 443 : 80); | ||
if (request.host && !request.hostname) { | ||
request.hostname = request.host.split(":")[0]; | ||
} | ||
if (request.hostname && request.port && !request.host) { | ||
var defaultPort = request.ssl ? 443 : 80; | ||
request.host = request.hostname + (defaultPort ? "" : ":" + request.port); | ||
} | ||
request.headers.host = request.headers.host || request.host; | ||
request.path = request.path || "/"; | ||
return request; | ||
@@ -252,17 +271,17 @@ }; | ||
var deferred = Q.defer(); | ||
var ssl = request.ssl; | ||
var http = ssl ? HTTPS : HTTP; | ||
var http = request.ssl ? HTTPS : HTTP; | ||
var headers = request.headers || {}; | ||
var requestOptions = { | ||
"host": request.hostname, // Node.js quirk | ||
"port": request.port || (request.ssl ? 443 : 80), | ||
"path": request.path || "/", | ||
"method": request.method || "GET", | ||
"headers": request.headers | ||
}; | ||
headers.host = headers.host || request.host; | ||
if (request.agent) { | ||
requestOptions.agent = request.agent; | ||
} | ||
var _request = http.request({ | ||
"host": request.host, | ||
"port": request.port || (ssl ? 443 : 80), | ||
"path": request.path || "/", | ||
"method": request.method || "GET", | ||
"headers": headers, | ||
"agent": request.agent | ||
}, function (_response) { | ||
var _request = http.request(requestOptions, function (_response) { | ||
// TODO request.charset or request.acceptCharset? | ||
@@ -275,4 +294,2 @@ var response = exports.ClientResponse(_response, request.charset); | ||
}); | ||
reader.cancel(); | ||
writer.cancel(); | ||
}); | ||
@@ -304,3 +321,4 @@ | ||
}; | ||
return exports.request(request).then(function (response) { | ||
return exports.request(request) | ||
.then(function (response) { | ||
if (!qualifier(response)){ | ||
@@ -311,3 +329,3 @@ var error = new Error("HTTP request failed with code " + response.status); | ||
} | ||
return Q(response.body).invoke("join", ""); | ||
return Reader(response.body || nobody).read(); | ||
}); | ||
@@ -314,0 +332,0 @@ }; |
@@ -109,4 +109,6 @@ | ||
self.node = _stream; | ||
return self; | ||
} | ||
{ | ||
"name": "q-io", | ||
"version": "2.0.2", | ||
"version": "2.0.3", | ||
"publishConfig": { | ||
"tag": "future" | ||
}, | ||
"description": "IO using Q promises", | ||
"homepage": "http://github.com/kriskowal/q-io/", | ||
"author": "Kris Kowal <kris@cixar.com> (http://github.com/kriskowal/)", | ||
"contributors": [ | ||
"Andreas Pizsa (http://github.com/AndreasPizsa/)" | ||
], | ||
"bugs": { | ||
@@ -25,17 +31,17 @@ "mail": "kris@cixar.com", | ||
"dependencies": { | ||
"q": "^2.0.1", | ||
"qs": "^0.6.6", | ||
"url2": "^1.0.1", | ||
"mime": "^1.2.11", | ||
"mimeparse": "^0.1.4", | ||
"collections": "^2.0.1" | ||
"q": ">=2.0.1 <3.0.0", | ||
"qs": ">=0.6.6 <0.7.0", | ||
"url2": ">=2.0.0 <3.0.0", | ||
"mime": ">=1.2.11 <2.0.0", | ||
"mimeparse": ">=0.1.4 <0.2.0", | ||
"collections": ">=2.0.1 <3.0.0" | ||
}, | ||
"devDependencies": { | ||
"jshint": "^0.9.1", | ||
"jasminum": "^2.0.1" | ||
"jshint": ">=0.9.1 <0.10.0", | ||
"jasminum": ">=2.0.2 <3.0.0" | ||
}, | ||
"scripts": { | ||
"test": "jasminum test", | ||
"test": "cd node_modules/q-io; jasminum test", | ||
"lint": "jshint" | ||
} | ||
} |
@@ -0,3 +1,4 @@ | ||
"use strict"; | ||
module.exports = require("./streams").Pipe; | ||
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
@@ -2,0 +3,0 @@ var streams = require("./streams"); |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
@@ -8,19 +9,22 @@ var Q = require("q"); | ||
module.exports = Reader; | ||
function Reader(input, charset) { | ||
function Reader(source, charset) { | ||
if (!(this instanceof Reader)) { | ||
return new Reader(input, charset); | ||
return new Reader(source, charset); | ||
} | ||
this.iteratorPromise = Q(input).iterate() | ||
.catch(function (error) { | ||
if (input.forEach) { | ||
this.iteratorPromise = Q(source).iterate() | ||
.catch(function (cause) { | ||
if (source.forEach) { | ||
var buffer = new BufferStream(); | ||
input.forEach(function (value, index) { | ||
buffer.return(source.forEach(function (value, index) { | ||
buffer.yield(value, index); | ||
}); | ||
})); | ||
return buffer; | ||
} else { | ||
error.message += " and is not forEachable"; | ||
var error = new Error("Can't iterate because source is not forEachable and because " + cause.message); | ||
error.notIterable = true; | ||
error.notForEachable = true; | ||
throw error; | ||
} | ||
throw error; | ||
}); | ||
this.source = source; | ||
this.charset = charset; | ||
@@ -27,0 +31,0 @@ } |
@@ -566,11 +566,3 @@ | ||
Additionally, the `Reader` constructor has the following methods: | ||
- `read(stream, charset)` accepts any foreachable and returns either a | ||
buffer or a string if given a charset. | ||
- `join(buffers)` consolidates an array of buffers into a single | ||
buffer. The buffers array is collapsed in place and the new first | ||
and only buffer is returned. | ||
The `reader` module exports a function that accepts a Node reader and | ||
The `node/reader` module exports a function that accepts a Node reader and | ||
returns a Q reader. | ||
@@ -590,3 +582,3 @@ | ||
The `writer` module exports a function that accepts a Node writer and | ||
The `node/writer` module exports a function that accepts a Node writer and | ||
returns a Q writer. | ||
@@ -593,0 +585,0 @@ |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
@@ -2,0 +3,0 @@ var Q = require("q"); |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
@@ -210,4 +211,8 @@ // TODO Writable, with support for buffer | ||
}) | ||
.then(function () { | ||
return output.return(); | ||
.then(function (value) { | ||
output.return(); | ||
return value; | ||
}, function (error) { | ||
output.throw(error); | ||
return error; | ||
}); | ||
@@ -219,4 +224,3 @@ }; | ||
*/ | ||
Readable.prototype.read = // TODO consider one or the other | ||
Readable.prototype.join = function (delimiter) { | ||
Readable.prototype.read = function () { | ||
var chunks = []; | ||
@@ -229,5 +233,5 @@ var self = this; | ||
if (self.charset) { | ||
return chunks.join(delimiter || ""); | ||
return chunks.join(""); | ||
} else { | ||
return join(chunks, delimiter); | ||
return Buffer.concat(chunks); | ||
} | ||
@@ -237,37 +241,2 @@ }); | ||
exports.join = join; | ||
function join(buffers, delimiter) { | ||
if (delimiter !== void 0) { | ||
delimiter = Buffer(delimiter); | ||
} else if (!delimiter) { | ||
delimiter = void 0; | ||
} | ||
var length = 0; | ||
var at; | ||
var i; | ||
var ii = buffers.length; | ||
var buffer; | ||
var result; | ||
for (i = 0; i < ii; i++) { | ||
buffer = buffers[i]; | ||
length += buffer.length; | ||
if (delimiter && i !== 0) { | ||
length += delimiter.length; | ||
} | ||
} | ||
result = new Buffer(length); | ||
at = 0; | ||
for (i = 0; i < ii; i++) { | ||
buffer = buffers[i]; | ||
buffer.copy(result, at, 0); | ||
at += buffer.length; | ||
if (delimiter && i !== 0) { | ||
buffer.copy(delimiter, at, 0); | ||
at += delimiter.length; | ||
} | ||
} | ||
buffers.splice(0, ii, result); | ||
return result; | ||
} | ||
Readable.prototype.cancel = function () { | ||
@@ -274,0 +243,0 @@ }; |
var FS = require("../../fs-boot"); | ||
var normalize = FS.normal; | ||
var FS = require("../../fs"); | ||
@@ -20,3 +19,3 @@ var specs = [ | ||
"from": "..", | ||
"to": normalize("../..") | ||
"to": FS.normal("../..") | ||
}, | ||
@@ -29,7 +28,7 @@ { | ||
"from": "/foo/bar", | ||
"to": normalize("/foo") | ||
"to": FS.normal("/foo") | ||
}, | ||
{ | ||
"from": "/foo", | ||
"to": normalize("/") | ||
"to": FS.normal("/") | ||
}, | ||
@@ -36,0 +35,0 @@ { |
@@ -5,3 +5,2 @@ "use strict"; | ||
var FS = require("../../fs"); | ||
var _n = FS.normal; | ||
@@ -21,4 +20,4 @@ describe("makeTree", function () { | ||
"a", | ||
_n("a/b"), | ||
_n("a/b/c") | ||
FS.normal("a/b"), | ||
FS.normal("a/b/c") | ||
]); | ||
@@ -55,5 +54,5 @@ }) | ||
"a", | ||
_n("a/b"), | ||
_n("a/b/c"), | ||
_n("a/b/c/d") | ||
FS.normal("a/b"), | ||
FS.normal("a/b/c"), | ||
FS.normal("a/b/c/d") | ||
]); | ||
@@ -78,5 +77,5 @@ }) | ||
"a", | ||
_n("a/b"), | ||
_n("a/b/c"), | ||
_n("a/b/c/d") | ||
FS.normal("a/b"), | ||
FS.normal("a/b/c"), | ||
FS.normal("a/b/c/d") | ||
]); | ||
@@ -83,0 +82,0 @@ }) |
@@ -6,3 +6,2 @@ "use strict"; | ||
var Mock = require("../../../fs-mock"); | ||
var normalize = FS.normal; | ||
@@ -43,10 +42,10 @@ describe("copyTree", function () { | ||
"a", | ||
normalize("a/b"), | ||
normalize("a/b/c"), | ||
normalize("a/b/c/d"), | ||
normalize("a/b/c/e"), | ||
normalize("a/f"), | ||
normalize("a/f/c"), | ||
normalize("a/f/c/d"), | ||
normalize("a/f/c/e") | ||
FS.normal("a/b"), | ||
FS.normal("a/b/c"), | ||
FS.normal("a/b/c/d"), | ||
FS.normal("a/b/c/e"), | ||
FS.normal("a/f"), | ||
FS.normal("a/f/c"), | ||
FS.normal("a/f/c/d"), | ||
FS.normal("a/f/c/e") | ||
]); | ||
@@ -53,0 +52,0 @@ }) |
var MockFs = require("../../../fs-mock"); | ||
var normalize = require('../../../fs').normal; | ||
@@ -44,5 +43,5 @@ describe("link", function () { | ||
"a", | ||
normalize("a/b"), | ||
normalize("a/b/c.txt"), | ||
normalize("a/b/d.txt") | ||
mock.normal("a/b"), | ||
mock.normal("a/b/c.txt"), | ||
mock.normal("a/b/d.txt") | ||
]) | ||
@@ -49,0 +48,0 @@ }) |
@@ -6,3 +6,2 @@ "use strict"; | ||
var Mock = require("../../../fs-mock"); | ||
var normalize = FS.normal; | ||
@@ -27,4 +26,4 @@ describe("makeTree", function () { | ||
"a", | ||
normalize("a/b"), | ||
normalize("a/b/c") | ||
FS.normal("a/b"), | ||
FS.normal("a/b/c") | ||
]); | ||
@@ -66,5 +65,5 @@ }) | ||
"a", | ||
normalize("a/b"), | ||
normalize("a/b/c"), | ||
normalize("a/b/c/d") | ||
FS.normal("a/b"), | ||
FS.normal("a/b/c"), | ||
FS.normal("a/b/c/d") | ||
]); | ||
@@ -71,0 +70,0 @@ }) |
@@ -6,3 +6,2 @@ "use strict"; | ||
var Mock = require("../../../fs-mock"); | ||
var normalize = FS.normal; | ||
@@ -37,4 +36,4 @@ describe("makeTree", function () { | ||
"1", | ||
normalize("1/2"), | ||
normalize("1/2/3"), | ||
FS.normal("1/2"), | ||
FS.normal("1/2/3"), | ||
"a", | ||
@@ -41,0 +40,0 @@ "b", |
@@ -6,3 +6,2 @@ "use strict"; | ||
var Mock = require("../../../fs-mock"); | ||
var normalize = FS.normal; | ||
@@ -32,3 +31,3 @@ describe("removeTree", function () { | ||
"a", | ||
normalize("a/b") | ||
FS.normal("a/b") | ||
]); | ||
@@ -35,0 +34,0 @@ }) |
@@ -14,3 +14,2 @@ "use strict"; | ||
.then(function (stat) { | ||
expect(stat.node).toBeDefined(); | ||
expect(stat.size).toBeDefined(); | ||
@@ -22,6 +21,3 @@ expect(stat.size).toBeGreaterThan(0); | ||
}); | ||
}); | ||
var MockFs = require("../../../fs-mock"); | ||
var normalize = require('../../../fs').normal; | ||
@@ -52,5 +51,5 @@ describe("symbolic link", function () { | ||
"a", | ||
normalize("a/b"), | ||
normalize("a/b/c.txt"), | ||
normalize("a/b/d.txt") | ||
mock.normal("a/b"), | ||
mock.normal("a/b/c.txt"), | ||
mock.normal("a/b/d.txt") | ||
]) | ||
@@ -57,0 +56,0 @@ }) |
@@ -44,1 +44,2 @@ var FS = require("../../fs"); | ||
}); | ||
/*global __dirname*/ | ||
var Q = require("q"); | ||
var Http = require("../../http"); | ||
@@ -13,23 +14,35 @@ var Apps = require("../../http-apps"); | ||
.then(function (mockFS) { | ||
return FS.merge([ mockFS, Mock({ "6789/0123.txt": "0123\n" })]); | ||
return FS.merge([ | ||
mockFS, | ||
Mock({ "6789/0123.txt": "0123\n" }) | ||
]); | ||
}).then(function (mockFS) { | ||
return Q().then(function () { | ||
return mockFS.symbolicCopy( | ||
"6789", | ||
FS.join("9012","linkedDir"), | ||
"directory" | ||
) | ||
}) | ||
.then(function () { | ||
return mockFS.symbolicCopy( | ||
FS.join("6789","0123.txt"), | ||
FS.join("9012","linkedFile.txt"), | ||
"file" | ||
) | ||
}) | ||
.then(function () { | ||
return new Apps.Chain() | ||
.use(Apps.ListDirectories) | ||
.use(function () { | ||
return Apps.FileTree(FS.join("/","9012"), { | ||
fs: mockFS, | ||
followInsecureSymbolicLinks: followInsecureSymbolicLinks | ||
}); | ||
}) | ||
.end() | ||
}).then(function (app) { | ||
return Http.Server(app).listen(0) | ||
}); | ||
}) | ||
.then(function (mockFS) { | ||
return mockFS.symbolicCopy("6789", FS.join("9012","linkedDir"), "directory").thenResolve(mockFS); | ||
}) | ||
.then(function (mockFS) { | ||
return mockFS.symbolicCopy( FS.join("6789","0123.txt"), FS.join("9012","linkedFile.txt"), "file").thenResolve(mockFS); | ||
}) | ||
.then(function (mockFS) { | ||
return new Apps.Chain() | ||
.use(Apps.ListDirectories) | ||
.use(function () { | ||
return Apps.FileTree(FS.join("/","9012"), { | ||
fs: mockFS, | ||
followInsecureSymbolicLinks: followInsecureSymbolicLinks | ||
}); | ||
}) | ||
.end() | ||
}).then(function (app) { | ||
return Http.Server(app).listen(0) | ||
}); | ||
}; | ||
@@ -36,0 +49,0 @@ |
@@ -93,4 +93,21 @@ | ||
it('should set correct HTTP Basic authentication headers when username and password are passed in the URL',function(){ | ||
request = HTTP.normalizeRequest('http://username:password@www.google.com/'); | ||
expect(request.auth).toBe('username:password'); | ||
expect(request.headers.authorization).toBe('Basic dXNlcm5hbWU6cGFzc3dvcmQ='); | ||
}); | ||
it('should successfully access resources that require HTTP Basic authentication when using the username:password@host.com URL syntax', function(){ | ||
// This tries to access a public resource, see http://test.webdav.org/ | ||
// | ||
// The resource is password protected, but there's no content behind it | ||
// so we will actually receive a 404; that's ok though as at least it's | ||
// a well-defined and expected status. | ||
return HTTP.request('http://user1:user1@test.webdav.org/auth-basic/') | ||
.then(function(response){ | ||
expect(response.status).not.toBe(401); | ||
expect(response.status).toBe(404); | ||
}); | ||
}); | ||
}); | ||
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
@@ -2,0 +3,0 @@ var Q = require("q"); |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
@@ -2,0 +3,0 @@ // Two years after @johnjbarton sends me the code for this, I got around to |
Sorry, the diff of this file is not supported yet
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
271330
90
7013
921
+ Addedpunycode@1.0.0(transitive)
+ Addedquerystring@0.1.0(transitive)
+ Addedurl@0.7.9(transitive)
+ Addedurl2@2.0.0(transitive)
- Removedpunycode@1.3.2(transitive)
- Removedurl@0.10.2(transitive)
- Removedurl2@1.0.4(transitive)
Updatedcollections@>=2.0.1 <3.0.0
Updatedmime@>=1.2.11 <2.0.0
Updatedmimeparse@>=0.1.4 <0.2.0
Updatedq@>=2.0.1 <3.0.0
Updatedqs@>=0.6.6 <0.7.0
Updatedurl2@>=2.0.0 <3.0.0