ramp-resources
Advanced tools
Comparing version 0.4.1 to 0.5.0
["fixtures/**/*", { | ||
"path": "/", | ||
"content": "<h1>Welcome, stranger!</h1><ul><li><a href='fixtures/1.png'>A png</a></li><li><a href='./fixtures/2.html'>A web page</a></li><li><a href='fixtures/3.txt'>A text file</a></li><li><a href='fixtures/4.tgz'>A tgz file</a></li><li><a href='twitter/'>A proxy</a></ul>" | ||
"content": "<h1>Welcome, stranger!</h1><ul><li><a href='fixtures/1.png'>A png</a></li><li><a href='./fixtures/2.html'>A web page</a></li><li><a href='fixtures/3.txt'>A text file</a></li><li><a href='fixtures/4.tgz'>A tgz file</a></li><li><a href='buster'>A proxy</a></li></ul>" | ||
}, { | ||
"path": "/twitter", | ||
"backend": "http://twitter.com" | ||
"path": "/buster", | ||
"backend": "http://busterjs.org" | ||
}] |
@@ -11,3 +11,2 @@ /** | ||
var rs = require("../../lib/ramp-resources"); | ||
var B = require("buster-core"); | ||
@@ -66,3 +65,3 @@ if (process.argv.length < 3) { | ||
if (!cached || !config) { return; } | ||
var resourceSet = rs.resourceSet.create(__dirname); | ||
var resourceSet = rs.createResourceSet(__dirname); | ||
resourceSet.addResources(config); | ||
@@ -69,0 +68,0 @@ console.log("Built resource set"); |
@@ -6,3 +6,3 @@ /** | ||
var http = require("http"); | ||
var rs = require("../../lib/ramp-resources"); | ||
var rr = require("../../lib/ramp-resources"); | ||
var HOUR = 1000 * 60 * 60; | ||
@@ -12,4 +12,4 @@ var MB = 1024; | ||
// These two objects should live as long as your server lives | ||
var middleware = rs.resourceMiddleware.create("/resources"); | ||
var cache = rs.resourceSetCache.create({ ttl: HOUR, maxSize: 100 * MB }); | ||
var middleware = rr.createMiddleware("/resources"); | ||
var cache = rr.createCache({ ttl: HOUR, maxSize: 100 * MB }); | ||
@@ -23,4 +23,4 @@ /** | ||
function mount(payload) { | ||
rs.resourceSet.deserialize(payload.resourceSet).then(function (rs) { | ||
cache.inflate(rs).then(function (resourceSet) { | ||
rr.deserialize(payload.resourceSet).then(function (rr) { | ||
cache.inflate(rr).then(function (resourceSet) { | ||
console.log("Mounting resource set at", payload.mountPoint); | ||
@@ -27,0 +27,0 @@ middleware.mount(payload.mountPoint, resourceSet); |
@@ -43,2 +43,4 @@ var http = require("http"); | ||
respond: function (req, res) { | ||
delete req.headers.host; | ||
var backendRequest = http.request({ | ||
@@ -45,0 +47,0 @@ host: host, |
@@ -1,2 +0,1 @@ | ||
var partial = require("buster-core").partial; | ||
var resource = require("./resource"); | ||
@@ -3,0 +2,0 @@ var invalid = require("./invalid-error"); |
@@ -18,5 +18,5 @@ var toString = Object.prototype.toString; | ||
return "(function (" + args + ") {" + content + exportStmt + "}.call(this" + | ||
(glbl ? ", " + glbl : "") + "));"; | ||
return "(function (" + args + ") {" + content + exportStmt + | ||
"}.call(this" + (glbl ? ", " + glbl : "") + "));"; | ||
}; | ||
}; |
@@ -0,9 +1,27 @@ | ||
var resource = require("./resource"); | ||
var resourceSet = require("./resource-set"); | ||
var resourceSetCache = require("./resource-set-cache"); | ||
var resourceMiddleware = require("./resource-middleware"); | ||
var processors = { iife: require("./processors/iife") }; | ||
module.exports = { | ||
resource: require("./resource"), | ||
resourceSet: require("./resource-set"), | ||
resourceSetCache: require("./resource-set-cache"), | ||
resourceMiddleware: require("./resource-middleware"), | ||
processors: { | ||
iife: require("./processors/iife") | ||
createResourceSet: function (rootPath) { | ||
return resourceSet.create(rootPath); | ||
}, | ||
createMiddleware: function (mountPoint) { | ||
return resourceMiddleware.create(mountPoint); | ||
}, | ||
createCache: function (options) { | ||
return resourceSetCache.create(options); | ||
}, | ||
createResource: function (path, options) { | ||
return resource.create(path, options); | ||
}, | ||
deserialize: function (serialize) { | ||
return resourceSet.deserialize(serialize); | ||
} | ||
}; |
var bResource = require("./resource"); | ||
var when = require("when"); | ||
var invalid = require("./invalid-error"); | ||
var B = require("buster-core"); | ||
@@ -6,0 +5,0 @@ module.exports = { |
@@ -1,8 +0,11 @@ | ||
var B = require("buster-core"); | ||
var when = require("when"); | ||
var fs = require("fs"); | ||
var glob = require("buster-glob").glob; | ||
var glob = require("multi-glob").glob; | ||
var Path = require("path"); | ||
var fileEtag = require("./file-etag"); | ||
function partial(fn, arg) { | ||
return fn.bind(null, arg); | ||
} | ||
function addUnique(arr1, arr2) { | ||
@@ -29,6 +32,6 @@ arr1 = arr1 || []; | ||
function outsideRootError(rootPath, paths) { | ||
var offendingPaths = paths.filter(B.partial(outsideRoot, rootPath)); | ||
var offendingPaths = paths.filter(partial(outsideRoot, rootPath)); | ||
if (offendingPaths.length === 0) { return; } | ||
var plural = offendingPaths.length > 1 ? "Some paths are " : "A path is "; | ||
var offending = offendingPaths.map(B.partial(Path.relative, rootPath)); | ||
var offending = offendingPaths.map(partial(Path.relative, rootPath)); | ||
@@ -46,6 +49,6 @@ return new Error(plural + "outside the project root. Set rootPath to " + | ||
}, function (err, files) { | ||
var ms = files.map(B.partial(absolutePath, rs.rootPath)); | ||
var ms = files.map(partial(absolutePath, rs.rootPath)); | ||
err = err || outsideRootError(rs.rootPath, ms); | ||
if (err) { return callback.call(rs, err); } | ||
ms = ms.map(B.partial(relativePath, rs.rootPath)); | ||
ms = ms.map(partial(relativePath, rs.rootPath)); | ||
ms = addUnique(ms, rs.matchPaths(paths)); | ||
@@ -52,0 +55,0 @@ callback.call(rs, err, ms); |
@@ -1,7 +0,7 @@ | ||
var buster = require("buster-core"); | ||
var resource = require("./resource"); | ||
var http = require("http"); | ||
var when = require("when"); | ||
var url = require("url"); | ||
var qs = require("querystring"); | ||
var path = require("path"); | ||
var resource = require("./resource"); | ||
@@ -20,3 +20,3 @@ /** | ||
function getResource(mounted, path) { | ||
function getResource(mounted, path, mimeType) { | ||
var resourceSet = (mounted && mounted.resourceSet) || []; | ||
@@ -29,3 +29,4 @@ var resource = resourceSet.filter(function (resource) { | ||
} | ||
return resource; | ||
var toServe = mimeType ? resource.getContentFor(mimeType) : resource; | ||
return toServe || resource; | ||
} | ||
@@ -45,24 +46,30 @@ | ||
// TODO | ||
// The script injection may be replaced with a more generalized | ||
// load path loader. This would be plugged into the middleware, and | ||
// would allow different implementations to do different things - | ||
// script tags is one, loading scripts in svg another, AMD yet | ||
// another. | ||
// | ||
function prepare(mounted, resource, content) { | ||
var paths = mounted.resourceSet.loadPath.paths(); | ||
if (resource.path !== "/" || paths.length === 0) { | ||
return new Buffer(content, resource.encoding); | ||
} | ||
function loadPaths(mounted, paths, mimeType) { | ||
return paths.filter(function (path) { | ||
return !!mounted.resourceSet.get(path).getContentFor(mimeType); | ||
}).map(function (p) { | ||
var type = mounted.resourceSet.get(p).mimeType(); | ||
var qParam = type !== mimeType ? "?rampMimeType=" + mimeType : ""; | ||
return contextPath + mounted.mountPoint + p + qParam; | ||
}); | ||
} | ||
var ctx = mounted.mountPoint; | ||
var resolvePaths = function (p) { return contextPath + ctx + p; }; | ||
var scripts = paths.map(resolvePaths).map(function (p) { | ||
return "<script src=\"" + p + "\"></script>"; | ||
}).join(""); | ||
if (/{{scripts}}/.test(content)) { | ||
function scriptTagsFor(paths) { | ||
return paths.reduce(function (html, path) { | ||
return html + "<script src=\"" + path + "\"></script>"; | ||
}, ""); | ||
} | ||
function linkTagsFor(paths) { | ||
return paths.reduce(function (html, path) { | ||
return html + "<link rel=\"stylesheet\" type=\"text/css\" " + | ||
"href=\"" + path + "\">"; | ||
}, ""); | ||
} | ||
function embedScripts(content, scripts) { | ||
if ((/\{\{scripts\}\}/).test(content)) { | ||
return content.replace("{{scripts}}", scripts); | ||
} | ||
if (/<\/body>/.test(content)) { | ||
if ((/<\/body>/).test(content)) { | ||
return content.replace("</body>", scripts + "</body>"); | ||
@@ -76,2 +83,44 @@ } | ||
function embedStylesheets(content, styles) { | ||
if ((/\{\{styles\}\}/).test(content)) { | ||
return content.replace("{{styles}}", styles); | ||
} | ||
if ((/<\/head>/).test(content)) { | ||
return content.replace("</head>", styles + "</head>"); | ||
} | ||
if (/<body>/.test(content)) { | ||
return content.replace("<body>", styles + "<body>"); | ||
} | ||
if (/<html>/.test(content)) { | ||
return content.replace("<html>", "<html>" + styles); | ||
} | ||
return styles + content; | ||
} | ||
// Embed tags in the root resource that loads paths from the load path. | ||
// | ||
// JavaScript resources, or resources that have application/javascript | ||
// alternatives are loaded using script tags, and placed either where | ||
// "{{scripts}}" directs, or at the end of the document. | ||
// | ||
// Ramp resources uses application/javascript (over text/javascript), as | ||
// suggested by http://www.rfc-editor.org/rfc/rfc4329.txt | ||
// | ||
// CSS resources, or resources that have text/css alternatives are loaded | ||
// using link tags, and placed wither where "{{styles}}" directs, or, if | ||
// possible, in the head of the document. If neither "{{styles}}" or <head> | ||
// is present, add link tags to the beginning of the document. | ||
// | ||
function prepare(mounted, resource, content) { | ||
var paths = mounted.resourceSet.loadPath.paths(); | ||
if (resource.path !== "/" || paths.length === 0) { | ||
return new Buffer(content, resource.encoding); | ||
} | ||
var mime = "application/javascript"; | ||
var scripts = scriptTagsFor(loadPaths(mounted, paths, mime)); | ||
var styles = linkTagsFor(loadPaths(mounted, paths, "text/css")); | ||
return embedStylesheets(embedScripts(content, scripts), styles); | ||
} | ||
function ok(res, headers, content) { | ||
@@ -120,4 +169,8 @@ res.writeHead(200, headers); | ||
function pathName(reqUrl) { | ||
return url.parse(reqUrl).pathname.replace(ctxRegexp, "") || "/"; | ||
function parseUrl(reqUrl) { | ||
var parsed = url.parse(reqUrl); | ||
return { | ||
pathname: parsed.pathname.replace(ctxRegexp, "") || "/", | ||
params: qs.parse(parsed.query) | ||
}; | ||
} | ||
@@ -132,3 +185,5 @@ | ||
function unmount(mountPoint) { | ||
resourceSets[strippedPath(mountPoint)].filter(function (r) { | ||
var resourceSet = resourceSets[strippedPath(mountPoint)]; | ||
if (!resourceSet) { return; } | ||
resourceSet.filter(function (r) { | ||
return r.backend; | ||
@@ -160,3 +215,4 @@ }).forEach(function (proxy) { | ||
if (mountPoint) { return unmount(mountPoint); } | ||
for (mountPoint in resourceSets) { unmount(mountPoint); } | ||
var mp; | ||
for (mp in resourceSets) { unmount(mp); } | ||
}, | ||
@@ -171,5 +227,11 @@ | ||
if (!handle(req.url)) { return; } | ||
var path = pathName(req.url); | ||
var parsedUrl = parseUrl(req.url); | ||
var path = parsedUrl.pathname; | ||
var mimeType = parsedUrl.params.rampMimeType; | ||
var mounted = getMounted(path); | ||
var resource = getResource(mounted, resourcePath(mounted, path)); | ||
var resource = getResource( | ||
mounted, | ||
resourcePath(mounted, path), | ||
mimeType | ||
); | ||
if (resource) { | ||
@@ -184,3 +246,7 @@ if (resource.backend) { | ||
mounted = getMounted(path); | ||
resource = getResource(mounted, resourcePath(mounted, path)); | ||
resource = getResource( | ||
mounted, | ||
resourcePath(mounted, path), | ||
mimeType | ||
); | ||
if (resource) { | ||
@@ -187,0 +253,0 @@ res.writeHead(302, { location: path }); |
@@ -0,5 +1,4 @@ | ||
var _ = require("lodash"); | ||
var when = require("when"); | ||
var resourceSet = require("./resource-set"); | ||
var bind = require("buster-core").bind; | ||
var partial = require("buster-core").partial; | ||
var when = require("when"); | ||
var HOUR = 60 * 60 * 1000; | ||
@@ -116,3 +115,3 @@ | ||
var d = when.defer(); | ||
var replace = bind(resourceSet, "addResource"); | ||
var replace = _.bind(resourceSet, "addResource"); | ||
when.all( | ||
@@ -156,3 +155,3 @@ resourceSet.filter(etagged).map(resolveContent), | ||
if (currentFreeze) { | ||
return setTimeout(bind(this, "purgeAll"), | ||
return setTimeout(_.bind(this, "purgeAll"), | ||
currentFreeze - Date.now()); | ||
@@ -159,0 +158,0 @@ } |
@@ -1,3 +0,4 @@ | ||
var B = require("buster-core"); | ||
var _ = require("lodash"); | ||
var when = require("when"); | ||
var mm = require("minimatch"); | ||
var invalid = require("./invalid-error"); | ||
@@ -8,3 +9,2 @@ var bResource = require("./resource"); | ||
var loadPath = require("./load-path"); | ||
var mm = require("minimatch"); | ||
@@ -72,3 +72,3 @@ function rejected(err) { | ||
resourceSet[index >= 0 ? index : resourceSet.length++] = resource; | ||
processors.forEach(B.bind(resource, "addProcessor")); | ||
processors.forEach(_.bind(resource, "addProcessor")); | ||
return resource; | ||
@@ -132,3 +132,3 @@ } | ||
addResources: function (resources) { | ||
return when.all(resources.map(B.bind(this, "addResource"))); | ||
return when.all(resources.map(_.bind(this, "addResource"))); | ||
}, | ||
@@ -157,3 +157,7 @@ | ||
if (typeof resource === "string") { | ||
return this.addGlobResource(resource); | ||
if (bResource.isQualified(resource)) { | ||
return this.addResource({ path: resource }); | ||
} else { | ||
return this.addGlobResource(resource); | ||
} | ||
} | ||
@@ -298,3 +302,3 @@ var err = exports.validate(resource); | ||
whenAllAdded(function () { | ||
var s = B.partial(serialize, cached); | ||
var s = serialize.bind(null, cached); | ||
when.all(this.map(s)).then(function (resources) { | ||
@@ -324,3 +328,3 @@ d.resolver.resolve({ | ||
var allPaths = this.map(function (r) { return r.path; }); | ||
return B.flatten(paths.map(function (path) { | ||
return _.flatten(paths.map(function (path) { | ||
return this.get(path) ? path : mm.match(allPaths, path, { | ||
@@ -369,6 +373,6 @@ matchBase: true | ||
if (promiseCount < promises.length) { | ||
var callback = B.partial(next, promises.length); | ||
var callback = next.bind(null, promises.length); | ||
whenAllAdded(callback, callback); | ||
} else { | ||
whenAllAdded(B.partial(cb, rs), eb); | ||
whenAllAdded(cb.bind(null, rs), eb); | ||
} | ||
@@ -412,3 +416,4 @@ }; | ||
} | ||
if (!resource.combine && !resource.file) { | ||
if (!resource.combine && !resource.file && | ||
!bResource.isQualified(resource.path)) { | ||
return bResource.validate(resource); | ||
@@ -418,2 +423,13 @@ } | ||
function addResourceWithAlternative(resource) { | ||
var d = when.defer(); | ||
this.addResource(resource).then(function (r) { | ||
(resource.alternatives || []).forEach(function (alt) { | ||
r.addAlternative(alt); | ||
}); | ||
d.resolve(r); | ||
}, d.reject); | ||
return d.promise; | ||
} | ||
/** | ||
@@ -428,3 +444,4 @@ * De-serializes data structures created by serialize(). Returns a | ||
var resources = data.resources || []; | ||
when.all(resources.map(B.bind(rs, "addResource"))).then(function () { | ||
var promises = resources.map(_.bind(addResourceWithAlternative, rs)); | ||
when.all(promises).then(function () { | ||
rs.loadPath.append(data.loadPath || []); | ||
@@ -431,0 +448,0 @@ d.resolver.resolve(rs); |
@@ -1,2 +0,2 @@ | ||
var buster = require("buster-core"); | ||
var _ = require("lodash"); | ||
var mime = require("mime"); | ||
@@ -20,4 +20,9 @@ var httpProxy = require("./http-proxy"); | ||
return url.parse(backend.replace(/^(?:http:\/\/)?/, "http://")); | ||
} | ||
exports.isQualified = function (path) { | ||
return (/^[a-z]+:\/\//i).test(path); | ||
}; | ||
/** | ||
@@ -39,5 +44,8 @@ * Create a new resource. Note that some properties can only be | ||
exports.create = function (path, rs) { | ||
var err = exports.validate(rs); | ||
if (err) { throw err; } | ||
path = exports.normalizePath(path); | ||
if (!exports.isQualified(path)) { | ||
var err = exports.validate(rs); | ||
if (err) { throw err; } | ||
path = exports.normalizePath(path); | ||
} | ||
rs = rs || {}; | ||
var content = rs.content; | ||
@@ -47,2 +55,3 @@ var processors = []; | ||
var resource; | ||
var alternatives = []; | ||
@@ -61,3 +70,4 @@ /** | ||
function mimeType() { | ||
return hasExtension() ? mime.lookup(path) : "text/html"; | ||
return rs.mimeType || | ||
(hasExtension() ? mime.lookup(path) : "text/html"); | ||
} | ||
@@ -69,2 +79,12 @@ | ||
function serializeAlternatives() { | ||
var alts = [], d = when.defer(); | ||
when.all(alternatives.map(function (alt, i) { | ||
var promise = alt.serialize(); | ||
promise.then(function (serializedAlt) { alts[i] = serializedAlt; }); | ||
return promise; | ||
})).then(function () { d.resolve(alts); }, d.reject); | ||
return d.promise; | ||
} | ||
function serialized(content) { | ||
@@ -77,2 +97,3 @@ var data = { | ||
}; | ||
if (rs.mimeType) { data.mimeType = rs.mimeType; } | ||
if (resource.etag) { data.etag = resource.etag; } | ||
@@ -84,3 +105,15 @@ if (resourceHeaders) { data.headers = resourceHeaders; } | ||
} | ||
return data; | ||
try { | ||
if (content && alternatives.length > 0) { | ||
var d = when.defer(); | ||
serializeAlternatives().then(function (alts) { | ||
data.alternatives = alts; | ||
d.resolve(data); | ||
}, d.reject); | ||
return d.promise; | ||
} | ||
} catch (e) { | ||
return when.reject(e); | ||
} | ||
return when(data); | ||
} | ||
@@ -123,2 +156,12 @@ | ||
function alternativeCacheKeys() { | ||
return alternatives.sort(function (a, b) { | ||
var atype = a.mimeType(); | ||
var btype = b.mimeType(); | ||
return atype < btype ? 1 : (btype < atype ? -1 : 0); | ||
}).map(function (alt) { | ||
return alt.etag || alt.mimeType(); | ||
}); | ||
} | ||
function recalculateEtag() { | ||
@@ -128,3 +171,3 @@ var shasum = crypto.createHash("sha1"); | ||
return p.toString() || ""; | ||
}).join("")); | ||
}).join("") + alternativeCacheKeys().join("")); | ||
resource.etag = shasum.digest("hex"); | ||
@@ -156,3 +199,3 @@ } | ||
} | ||
return buster.extend(headers, resourceHeaders); | ||
return _.extend(headers, resourceHeaders); | ||
}, | ||
@@ -176,2 +219,5 @@ | ||
content: function () { | ||
if (exports.isQualified(path)) { | ||
return when(path); | ||
} | ||
if (typeof content === "function") { | ||
@@ -237,3 +283,3 @@ return processedFunctionContent(content); | ||
function resolve(content) { | ||
d.resolver.resolve(serialized(content)); | ||
serialized(content).then(d.resolve, d.reject); | ||
} | ||
@@ -244,3 +290,3 @@ if (!options || options.includeContent) { | ||
} catch (e) { | ||
d.resolver.reject(e); | ||
d.reject(e); | ||
} | ||
@@ -251,2 +297,21 @@ } else { | ||
return d.promise; | ||
}, | ||
getContentFor: function (mime) { | ||
if (mime === mimeType()) { return this; } | ||
return alternatives.filter(function (r) { | ||
return r.getContentFor(mime); | ||
})[0]; | ||
}, | ||
addAlternative: function (options) { | ||
var i, l, added, alternative = exports.create(path, options); | ||
for (i = 0, l = alternatives.length; i < l; ++i) { | ||
if (alternatives[i].mimeType() === options.mimeType) { | ||
alternatives[i] = alternative; | ||
added = true; | ||
} | ||
} | ||
if (!added) { alternatives.push(alternative); } | ||
recalculateEtag(); | ||
} | ||
@@ -260,2 +325,8 @@ }; | ||
if (rs.alternatives) { | ||
rs.alternatives.forEach(function (alt) { | ||
resource.addAlternative(alt); | ||
}); | ||
} | ||
return resource; | ||
@@ -265,2 +336,3 @@ }; | ||
exports.normalizePath = function (path) { | ||
if (exports.isQualified(path)) { return path; } | ||
return path.replace("\\", "/").replace(/\/?$/, "").replace(/^\/?/, "/"); | ||
@@ -267,0 +339,0 @@ }; |
{ | ||
"name": "ramp-resources", | ||
"version": "0.4.1", | ||
"version": "0.5.0", | ||
"description": "Virtual file systems for exposing files and other resources on e.g. web servers", | ||
"homepage": "http://busterjs.org/docs/resources", | ||
"author": { "name": "August Lilleaas and Christian Johansen" }, | ||
"author": { "name": "August Lilleaas" }, | ||
"contributors": [{ | ||
@@ -15,2 +15,6 @@ "name": "August Lilleaas", | ||
"url": "http://cjohansen.no" | ||
}, { | ||
"name": "Stein Magnus Jodal", | ||
"email": "stein.magnus@jodal.no", | ||
"url": "http://jodal.no" | ||
}], | ||
@@ -26,7 +30,7 @@ "main": "./lib/ramp-resources", | ||
"dependencies": { | ||
"buster-core": ">=0.6.2", | ||
"mime": "~1", | ||
"buster-glob": ">=0.3.2", | ||
"multi-glob": "~0.4.0", | ||
"when": "https://github.com/cujojs/when/tarball/1.3.0", | ||
"minimatch": "~0.1.5" | ||
"minimatch": "~0.1.5", | ||
"lodash": "~0.5" | ||
}, | ||
@@ -33,0 +37,0 @@ "devDependencies": { |
var buster = require("buster"); | ||
var resourceSet = require("../lib/resource-set"); | ||
var rr = require("../lib/ramp-resources"); | ||
require("./test-helper.js"); | ||
@@ -7,3 +7,3 @@ | ||
setUp: function () { | ||
this.rs = resourceSet.create(); | ||
this.rs = rr.createResourceSet(); | ||
}, | ||
@@ -10,0 +10,0 @@ |
var buster = require("buster"); | ||
var resource = require("../../lib/resource"); | ||
var rr = require("../../lib/ramp-resources"); | ||
var iife = require("../../lib/processors/iife"); | ||
@@ -9,3 +9,3 @@ require("../test-helper"); | ||
setUp: function () { | ||
this.resource = resource.create("/buster.js", { | ||
this.resource = rr.createResource("/buster.js", { | ||
content: "var buster = {};" | ||
@@ -17,5 +17,5 @@ }); | ||
this.resource.addProcessor(iife()); | ||
var content = "(function () {var buster = {};}.call(this));"; | ||
assert.content(this.resource, | ||
"(function () {var buster = {};}.call(this));", done); | ||
assert.content(this.resource, content, done); | ||
}, | ||
@@ -45,3 +45,3 @@ | ||
"separates exports from contents with semicolon": function (done) { | ||
this.resource = resource.create("/buster.js", { | ||
this.resource = rr.createResource("/buster.js", { | ||
content: "var buster = {}" | ||
@@ -48,0 +48,0 @@ }); |
var buster = require("buster"); | ||
var resourceSet = require("../lib/resource-set"); | ||
var resourceMiddleWare = require("../lib/resource-middleware"); | ||
var when = require("when"); | ||
var Path = require("path"); | ||
var rr = require("../lib/ramp-resources"); | ||
var h = require("./test-helper"); | ||
@@ -10,4 +9,4 @@ | ||
var resourceSets = { | ||
withBuster: resourceSet.create(), | ||
withSinon: resourceSet.create() | ||
withBuster: rr.createResourceSet(), | ||
withSinon: rr.createResourceSet() | ||
}; | ||
@@ -30,4 +29,4 @@ | ||
this.backend = h.createProxyBackend(2222); | ||
this.resources = resourceMiddleWare.create(); | ||
this.rs = resourceSet.create(); | ||
this.resources = rr.createMiddleware(); | ||
this.rs = rr.createResourceSet(); | ||
this.rs.addResource({ path: options.path, backend: options.backend }); | ||
@@ -52,3 +51,3 @@ this.resources.mount(options.mountPoint, this.rs); | ||
setUp: function (done) { | ||
this.resources = resourceMiddleWare.create(); | ||
this.resources = rr.createMiddleware(); | ||
this.server = h.createServer(this.resources, done); | ||
@@ -96,3 +95,3 @@ }, | ||
"fails if mounting nothing": function () { | ||
var middleware = resourceMiddleWare.create(); | ||
var middleware = rr.createMiddleware(); | ||
assert.exception(function () { | ||
@@ -106,3 +105,3 @@ middleware.mount("/", null); | ||
setUp: function (done) { | ||
this.resources = resourceMiddleWare.create(); | ||
this.resources = rr.createMiddleware(); | ||
this.resources.mount("/", this.sets.withBuster); | ||
@@ -166,3 +165,3 @@ this.server = h.createServer(this.resources, done); | ||
h.req({ path: "/" }, done(function (req, res, body) { | ||
refute.match(body, "{{scripts}}") | ||
refute.match(body, "{{scripts}}"); | ||
assert.match(body, "<html>foo<script"); | ||
@@ -205,3 +204,4 @@ assert.match(body, "src=\"/buster.js\""); | ||
assert.equals(res.statusCode, 500); | ||
assert.match(body, Path.join("test", "resource-middleware-test")); | ||
var path = Path.join("test", "resource-middleware-test"); | ||
assert.match(body, path); | ||
assert.match(body, "Damnit"); | ||
@@ -272,5 +272,86 @@ })).end(); | ||
"CSS resources in load path": { | ||
setUp: function (done) { | ||
this.sets.withBuster.addResource({ | ||
path: "/buster.css", | ||
content: "body {}" | ||
}); | ||
this.sets.withBuster.loadPath.append("/buster.css"); | ||
this.resources = rr.createMiddleware(); | ||
this.resources.mount("/", this.sets.withBuster); | ||
this.server = h.createServer(this.resources, done); | ||
}, | ||
tearDown: h.serverTearDown, | ||
"serves root resource with loadPath styles": function (done) { | ||
h.req({ path: "/" }, done(function (req, res, body) { | ||
assert.match(body, "<link"); | ||
assert.match(body, "href=\"/buster.css\""); | ||
assert.match(body, "type=\"text/css\""); | ||
assert.match(body, "rel=\"stylesheet\""); | ||
})).end(); | ||
}, | ||
"serves custom root resource with loadPath styles": function (done) { | ||
this.sets.withBuster.addResource({ | ||
path: "/", | ||
content: "<html></html>" | ||
}); | ||
h.req({ path: "/" }, done(function (req, res, body) { | ||
assert.match(body, "<html><link"); | ||
})).end(); | ||
}, | ||
"adds loadPath styles in head": function (done) { | ||
this.sets.withBuster.addResource({ | ||
path: "/", | ||
content: "<html><head></head><body></body></html>" | ||
}); | ||
h.req({ path: "/" }, done(function (req, res, body) { | ||
assert.match(body, "<head><link"); | ||
})).end(); | ||
}, | ||
"serves blank root resource with loadPath styles": function (done) { | ||
this.sets.withBuster.addResource({ path: "/", content: "<h1>Yo" }); | ||
h.req({ path: "/" }, done(function (req, res, body) { | ||
assert.match(body, "\"/buster.css\"><h1>Yo"); | ||
})).end(); | ||
}, | ||
"serves root resource with custom styles location": function (done) { | ||
this.sets.withBuster.addResource({ | ||
path: "/", | ||
content: "<html>foo{{styles}}bar</html>" | ||
}); | ||
h.req({ path: "/" }, done(function (req, res, body) { | ||
refute.match(body, "{{scripts}}"); | ||
assert.match(body, "<html>foo<link"); | ||
})).end(); | ||
}, | ||
"does not create script tag for CSS in load path": function (done) { | ||
h.req({ path: "/" }, done(function (req, res, body) { | ||
refute.match(body, "href=\"/buster.js\""); | ||
})).end(); | ||
}, | ||
"does not create link tag for JS in load path": function (done) { | ||
h.req({ path: "/" }, done(function (req, res, body) { | ||
refute.match(body, "src=\"/buster.css\""); | ||
})).end(); | ||
} | ||
}, | ||
"resource set mounted at path": { | ||
setUp: function (done) { | ||
this.resources = resourceMiddleWare.create(); | ||
this.resources = rr.createMiddleware(); | ||
this.resources.mount("/buster/2.0", this.sets.withBuster); | ||
@@ -368,3 +449,3 @@ this.server = h.createServer(this.resources, done); | ||
setUp: function (done) { | ||
this.resources = resourceMiddleWare.create("/ctx/1"); | ||
this.resources = rr.createMiddleware("/ctx/1"); | ||
this.resources.mount("/", this.sets.withBuster); | ||
@@ -543,3 +624,3 @@ this.server = h.createServer(this.resources, done); | ||
setUp: function (done) { | ||
this.resources = resourceMiddleWare.create(); | ||
this.resources = rr.createMiddleware(); | ||
this.resources.mount("/buster", this.sets.withBuster); | ||
@@ -579,6 +660,15 @@ this.server = h.createServer(this.resources, done); | ||
assert.equals(res.statusCode, 418); | ||
h.req({ path: "/buster/buster.js" }, done(function (req, res, body) { | ||
h.req({ | ||
path: "/buster/buster.js" | ||
}, done(function (req, res, body) { | ||
assert.equals(res.statusCode, 418); | ||
})).end(); | ||
}).end(); | ||
}, | ||
"ignores unmounted paths": function () { | ||
var self = this; | ||
refute.exception(function () { | ||
self.resources.unmount("/the-cake-is-a-lie"); | ||
}); | ||
} | ||
@@ -610,3 +700,3 @@ }, | ||
setUp: function () { | ||
this.resources = resourceMiddleWare.create(); | ||
this.resources = rr.createMiddleware(); | ||
}, | ||
@@ -635,3 +725,83 @@ | ||
} | ||
}, | ||
"alternatives": { | ||
setUp: function (done) { | ||
this.resources = rr.createMiddleware(); | ||
var resource = this.sets.withBuster.addResource({ | ||
path: "/sinon.coffee", | ||
content: "Coffee", | ||
mimeType: "text/coffeescript" | ||
}).then(function (resource) { | ||
resource.addAlternative({ | ||
mimeType: "application/javascript", | ||
content: "JavaScript" | ||
}); | ||
this.sets.withBuster.loadPath.append("/sinon.coffee"); | ||
this.resources.mount("/", this.sets.withBuster); | ||
this.server = h.createServer(this.resources, done); | ||
}.bind(this)); | ||
}, | ||
tearDown: h.serverTearDown, | ||
"serves original resource": function (done) { | ||
h.req({ | ||
path: "/sinon.coffee" | ||
}, done(function (req, res, body) { | ||
assert.equals(res.statusCode, 200); | ||
assert.equals(body, "Coffee"); | ||
})).end(); | ||
}, | ||
"serves alternative for given mimeType": function (done) { | ||
h.req({ | ||
path: "/sinon.coffee?rampMimeType=application/javascript" | ||
}, done(function (req, res, body) { | ||
assert.equals(res.statusCode, 200); | ||
assert.equals(body, "JavaScript"); | ||
assert.match(res.headers["content-type"], | ||
"application/javascript"); | ||
})).end(); | ||
}, | ||
"serves original for missing mimeType alternative": function (done) { | ||
h.req({ | ||
path: "/sinon.coffee?rampMimeType=text/css" | ||
}, done(function (req, res, body) { | ||
assert.equals(body, "Coffee"); | ||
})).end(); | ||
}, | ||
"loads mime alternative in load path": function (done) { | ||
h.req({ path: "/" }, done(function (req, res, body) { | ||
var context = "src=\"/sinon.coffee?" + | ||
"rampMimeType=application/javascript\""; | ||
assert.match(body, context); | ||
})).end(); | ||
} | ||
}, | ||
"fully qualified resources": { | ||
setUp: function (done) { | ||
this.resources = rr.createMiddleware(); | ||
var p = this.sets.withBuster.addResource("file:///tmp/hey.js"); | ||
p.then(function (r) { | ||
this.sets.withBuster.loadPath.append(r.path); | ||
this.resources.mount("/", this.sets.withBuster); | ||
this.server = h.createServer(this.resources, done); | ||
}.bind(this)); | ||
}, | ||
tearDown: h.serverTearDown, | ||
"includes fully qualified resource with script tag": function (done) { | ||
h.req({ | ||
path: "/" | ||
}, done(function (req, res, body) { | ||
assert.equals(res.statusCode, 200); | ||
assert.match(body, "src=\"file:///tmp/hey.js\""); | ||
})).end(); | ||
} | ||
} | ||
}); |
var buster = require("buster"); | ||
var when = require("when"); | ||
var resourceSet = require("../lib/resource-set"); | ||
var resourceSetCache = require("../lib/resource-set-cache"); | ||
var rr = require("../lib/ramp-resources"); | ||
require("./test-helper"); | ||
@@ -24,5 +23,5 @@ | ||
function maxSizeSetUp(done) { | ||
this.rs = resourceSet.create(); | ||
this.rs2 = resourceSet.create(); | ||
this.cache = resourceSetCache.create({ ttl: 250, maxSize: 150 }); | ||
this.rs = rr.createResourceSet(); | ||
this.rs2 = rr.createResourceSet(); | ||
this.cache = rr.createCache({ ttl: 250, maxSize: 150 }); | ||
@@ -40,6 +39,6 @@ when.all([ | ||
this.clock = this.useFakeTimers(); | ||
this.rs = resourceSet.create(); | ||
this.cache = resourceSetCache.create({ ttl: 250 }); | ||
this.rs = rr.createResourceSet(); | ||
this.cache = rr.createCache({ ttl: 250 }); | ||
var rs = resourceSet.create(); | ||
var rs = rr.createResourceSet(); | ||
when.all([ | ||
@@ -54,2 +53,15 @@ add(rs, "/buster.js", "Yo!", { etag: "abcd1234" }), | ||
"inflate": { | ||
setUp: function (done) { | ||
var rs = rr.createResourceSet(); | ||
add(rs, "/buster.coffee", "Yoo!", { | ||
etag: "dedede", | ||
alternatives: [{ | ||
content: "HAHA", | ||
mimeType: "text/uppercase" | ||
}] | ||
}).then(function () { | ||
this.cache.inflate(rs).then(function () { done(); }); | ||
}.bind(this)); | ||
}, | ||
"resolves with resource set": function (done) { | ||
@@ -69,2 +81,15 @@ this.cache.inflate(this.rs).then(done(function (rs) { | ||
"uses cached alternatives for empty-content resource": function (done) { | ||
addResourcesAndInflate(this.cache, this.rs, [ | ||
["/buster.coffee", "", { | ||
etag: "13ae76a598b2aa2cad2c7fd1f4954fff745835d1" | ||
}] | ||
], function (rs) { | ||
var resource = rs.get("/buster.coffee"); | ||
var alternative = resource.getContentFor("text/uppercase"); | ||
assert.defined(alternative); | ||
assert.content(alternative, "HAHA", done); | ||
}); | ||
}, | ||
"does not use cache when etag does not match": function (done) { | ||
@@ -116,3 +141,3 @@ addResourcesAndInflate(this.cache, this.rs, [ | ||
"does not cache uncacheable resource": function (done) { | ||
var rs2 = resourceSet.create(); | ||
var rs2 = rr.createResourceSet(); | ||
addResourcesAndInflate(this.cache, this.rs, [ | ||
@@ -130,3 +155,3 @@ ["/uncacheable.js", "Stuff", { cacheable: false, etag: "1" }] | ||
"does not cache resources when content() rejects": function (done) { | ||
var rs2 = resourceSet.create(); | ||
var rs2 = rr.createResourceSet(); | ||
var d = when.defer(); | ||
@@ -146,3 +171,3 @@ d.resolver.reject("Oh noes"); | ||
"does not look up from cache when content() rejects": function (done) { | ||
var rs2 = resourceSet.create(); | ||
var rs2 = rr.createResourceSet(); | ||
var d = when.defer(); | ||
@@ -167,3 +192,3 @@ d.resolver.reject("Oh noes"); | ||
"does not look up from cache when content() throws": function (done) { | ||
var rs2 = resourceSet.create(); | ||
var rs2 = rr.createResourceSet(); | ||
addResourcesAndInflate(this.cache, this.rs, [ | ||
@@ -200,4 +225,4 @@ ["/a.js", "Cached", { etag: "1" }] | ||
"keeps resources indefinitely with -1 ttl": function (done) { | ||
var rs = resourceSet.create(); | ||
var cache = resourceSetCache.create({ ttl: -1 }); | ||
var rs = rr.createResourceSet(); | ||
var cache = rr.createCache({ ttl: -1 }); | ||
@@ -204,0 +229,0 @@ add(rs, "/buster.js", "Yo!", { etag: "abcd" }).then(function () { |
var buster = require("buster"); | ||
var resource = require("../lib/resource"); | ||
var resourceSet = require("../lib/resource-set"); | ||
var rr = require("../lib/ramp-resources"); | ||
var Path = require("path"); | ||
@@ -16,3 +15,3 @@ var when = require("when"); | ||
setUp: function () { | ||
this.rs = resourceSet.create(FIXTURE_DIR); | ||
this.rs = rr.createResourceSet(FIXTURE_DIR); | ||
}, | ||
@@ -22,3 +21,3 @@ | ||
"defaults root path to current working directory": function () { | ||
var rs = resourceSet.create(); | ||
var rs = rr.createResourceSet(); | ||
assert.equals(rs.rootPath, process.cwd()); | ||
@@ -28,3 +27,3 @@ }, | ||
"specifies root path": function () { | ||
var rs = resourceSet.create("/tmp"); | ||
var rs = rr.createResourceSet("/tmp"); | ||
assert.equals(rs.rootPath, "/tmp"); | ||
@@ -104,3 +103,3 @@ } | ||
})); | ||
}, | ||
} | ||
}, | ||
@@ -139,3 +138,3 @@ | ||
setUp: function () { | ||
this.resource = resource.create("/buster.js", { | ||
this.resource = rr.createResource("/buster.js", { | ||
content: "var buster = {};" | ||
@@ -158,3 +157,3 @@ }); | ||
setUp: function () { | ||
this.resource = resource.create("/buster.js", { | ||
this.resource = rr.createResource("/buster.js", { | ||
content: "var buster = {};" | ||
@@ -194,3 +193,3 @@ }); | ||
"exposes added resource on numeric index": function (done) { | ||
var rs = resource.create("/sinon.js", { content: "var sinon;" }); | ||
var rs = rr.createResource("/sinon.js", { content: "var sinon;" }); | ||
when.all([this.rs.addResource(this.resource), | ||
@@ -243,4 +242,5 @@ this.rs.addResource(rs)]).then(done(function (resources) { | ||
"uses strict globbing to catch any non-matching pattern": function (done) { | ||
this.rs.addResources(["foo.js", "zyng/*.js"]).then(done(function () { | ||
"uses strict globbing to catch non-matching pattern": function (done) { | ||
var patterns = ["foo.js", "zyng/*.js"]; | ||
this.rs.addResources(patterns).then(done(function () { | ||
assert(false, "Should produce error"); | ||
@@ -365,4 +365,4 @@ }), done(function (err) { | ||
this.resources = [ | ||
resource.create("/a.txt", { content: "a", etag: "1234" }), | ||
resource.create("/b.txt", { content: "b", etag: "2345" }) | ||
rr.createResource("/a.txt", { content: "a", etag: "1234" }), | ||
rr.createResource("/b.txt", { content: "b", etag: "2345" }) | ||
]; | ||
@@ -377,4 +377,4 @@ var deferred = when.defer(); | ||
"processes all resources": function (done) { | ||
var resources = [resource.create("/a.txt", { content: "a" }), | ||
resource.create("/b.txt", { content: "b" })]; | ||
var resources = [rr.createResource("/a.txt", { content: "a" }), | ||
rr.createResource("/b.txt", { content: "b" })]; | ||
var deferred = when.defer(); | ||
@@ -392,21 +392,6 @@ deferred.resolver.resolve(null); | ||
"processes all resources": function (done) { | ||
var resources = [resource.create("/a.txt", { content: "a" }), | ||
resource.create("/b.txt", { content: "b" })]; | ||
var deferred = when.defer(); | ||
deferred.resolver.resolve(null); | ||
this.stub(resources[0], "process").returns(deferred.promise); | ||
this.stub(resources[1], "process").returns(deferred.promise); | ||
this.rs.addResources(resources); | ||
this.rs.process().then(done(function () { | ||
assert.calledOnce(resources[0].process); | ||
assert.calledOnce(resources[1].process); | ||
})); | ||
}, | ||
"skips resources in cache manifest": function (done) { | ||
var resources = [ | ||
resource.create("/a.txt", { content: "a", etag: "1234" }), | ||
resource.create("/b.txt", { content: "b", etag: "2345" }) | ||
rr.createResource("/a.txt", { content: "a", etag: "1234" }), | ||
rr.createResource("/b.txt", { content: "b", etag: "2345" }) | ||
]; | ||
@@ -427,4 +412,4 @@ var deferred = when.defer(); | ||
var resources = [ | ||
resource.create("/a.txt", { content: "a", etag: "1234" }), | ||
resource.create("/b.txt", { content: "b", etag: "2345" }) | ||
rr.createResource("/a.txt", { content: "a", etag: "1234" }), | ||
rr.createResource("/b.txt", { content: "b", etag: "2345" }) | ||
]; | ||
@@ -445,4 +430,4 @@ var deferred = when.defer(); | ||
var resources = [ | ||
resource.create("/a.txt", { content: "a", etag: "1234" }), | ||
resource.create("/b.txt", { content: "b", etag: "2345" }) | ||
rr.createResource("/a.txt", { content: "a", etag: "1234" }), | ||
rr.createResource("/b.txt", { content: "b", etag: "2345" }) | ||
]; | ||
@@ -465,4 +450,4 @@ var deferred = when.defer(); | ||
var resources = [ | ||
resource.create("/a.txt", { content: "a", etag: "1234" }), | ||
resource.create("/b.txt", { content: "b", etag: "2345" }) | ||
rr.createResource("/a.txt", { content: "a", etag: "1234" }), | ||
rr.createResource("/b.txt", { content: "b", etag: "2345" }) | ||
]; | ||
@@ -759,3 +744,3 @@ var deferred = when.defer(); | ||
"resolves as resource set with single resource": function (done) { | ||
resourceSet.deserialize({ resources: [{ | ||
rr.deserialize({ resources: [{ | ||
path: "/buster.js", | ||
@@ -770,3 +755,3 @@ content: "Hey mister" | ||
"resolves resource set with two resources": function (done) { | ||
resourceSet.deserialize({ resources: [{ | ||
rr.deserialize({ resources: [{ | ||
path: "/buster.js", | ||
@@ -785,3 +770,3 @@ content: "Hey mister" | ||
"resolves resource set with load path": function (done) { | ||
resourceSet.deserialize({ loadPath: ["/buster.js"], resources: [{ | ||
rr.deserialize({ loadPath: ["/buster.js"], resources: [{ | ||
path: "/buster.js", | ||
@@ -798,7 +783,7 @@ content: "Hey mister" | ||
"deserializes serialized resource set": function (done) { | ||
var rs = resourceSet.create(FIXTURE_DIR); | ||
var rs = rr.createResourceSet(FIXTURE_DIR); | ||
rs.addResources(["foo.js", "bar.js"]); | ||
var cb = buster.countdown(2, done); | ||
rs.serialize().then(function (serialized) { | ||
resourceSet.deserialize(serialized).then(function (rs2) { | ||
rr.deserialize(serialized).then(function (rs2) { | ||
assert.equals(rs.length, rs2.length); | ||
@@ -815,3 +800,3 @@ assert.equals(rs.loadPath.paths, rs.loadPath.paths); | ||
"rejects if deserialized data is corrupt": function (done) { | ||
resourceSet.deserialize({ loadPath: ["/buster.js"], resources: [{ | ||
rr.deserialize({ loadPath: ["/buster.js"], resources: [{ | ||
path: "/buster.js" | ||
@@ -825,3 +810,3 @@ }] }).then(function () {}, done(function (err) { | ||
"deserializes cacheable flag": function (done) { | ||
resourceSet.deserialize({ resources: [{ | ||
rr.deserialize({ resources: [{ | ||
path: "/buster.js", | ||
@@ -838,2 +823,18 @@ content: "Hey mister", | ||
})); | ||
}, | ||
"resolves resource with alternatives": function (done) { | ||
rr.deserialize({ resources: [{ | ||
path: "/buster.js", | ||
content: "Hey mister", | ||
alternatives: [{ | ||
mimeType: "text/uppercase", | ||
content: "YOYO" | ||
}] | ||
}] }).then(function (rs) { | ||
var resource = rs.get("/buster.js"); | ||
var alternative = resource.getContentFor("text/uppercase"); | ||
assert(alternative); | ||
assert.content(alternative, "YOYO", done); | ||
}); | ||
} | ||
@@ -844,4 +845,4 @@ }, | ||
"creates new resource set": function () { | ||
var rs1 = resourceSet.create(); | ||
var rs2 = resourceSet.create(); | ||
var rs1 = rr.createResourceSet(); | ||
var rs2 = rr.createResourceSet(); | ||
@@ -855,7 +856,7 @@ var rs3 = rs1.concat(rs2); | ||
"adds resources from all sources": function (done) { | ||
var rs1 = resourceSet.create(); | ||
var rs1 = rr.createResourceSet(); | ||
var add1 = rs1.addResource({ path: "/buster.js", content: "Ok" }); | ||
var rs2 = resourceSet.create(); | ||
var rs2 = rr.createResourceSet(); | ||
var add2 = rs2.addResource({ path: "/sinon.js", content: "Nok" }); | ||
var rs3 = resourceSet.create(); | ||
var rs3 = rr.createResourceSet(); | ||
var add3 = rs2.addResource({ path: "/when.js", content: "when()" }); | ||
@@ -874,5 +875,5 @@ | ||
"resources overwrite from right to left": function (done) { | ||
var rs1 = resourceSet.create(); | ||
var rs1 = rr.createResourceSet(); | ||
var add1 = rs1.addResource({ path: "/buster.js", content: "Ok" }); | ||
var rs2 = resourceSet.create(); | ||
var rs2 = rr.createResourceSet(); | ||
var add2 = rs2.addResource({ path: "/buster.js", content: "Nok" }); | ||
@@ -887,5 +888,5 @@ | ||
"appends load in order": function (done) { | ||
var rs1 = resourceSet.create(); | ||
var rs1 = rr.createResourceSet(); | ||
var add1 = rs1.addResource({ path: "/buster.js", content: "Ok" }); | ||
var rs2 = resourceSet.create(); | ||
var rs2 = rr.createResourceSet(); | ||
var add2 = rs2.addResource({ path: "/sinon.js", content: "Nok" }); | ||
@@ -903,3 +904,3 @@ | ||
"concats backend resources": function (done) { | ||
var rs1 = resourceSet.create(); | ||
var rs1 = rr.createResourceSet(); | ||
@@ -916,3 +917,3 @@ rs1.addResource({ | ||
"concats combine resources": function (done) { | ||
var rs1 = resourceSet.create(); | ||
var rs1 = rr.createResourceSet(); | ||
rs1.addResources([ | ||
@@ -931,4 +932,4 @@ { path: "/a", content: "1" }, | ||
"uses rootpath of target resource set": function () { | ||
var rs1 = resourceSet.create("/tmp"); | ||
var rs2 = resourceSet.create("/var"); | ||
var rs1 = rr.createResourceSet("/tmp"); | ||
var rs2 = rr.createResourceSet("/var"); | ||
@@ -941,3 +942,3 @@ var rs3 = rs1.concat(rs2); | ||
"restricts length to unique resources": function (done) { | ||
var rs1 = resourceSet.create(); | ||
var rs1 = rr.createResourceSet(); | ||
var add1 = rs1.addResource({ path: "/buster.js", content: "Ok" }); | ||
@@ -957,3 +958,3 @@ var add2 = rs1.addResource({ path: "/sinon.js", content: "Yep" }); | ||
setUp: function (done) { | ||
this.rs = resourceSet.create(FIXTURE_DIR); | ||
this.rs = rr.createResourceSet(FIXTURE_DIR); | ||
var resource = { path: "/buster.js", content: "Ok" }; | ||
@@ -1017,3 +1018,4 @@ this.rs.addResource(resource).then(function () { | ||
this.rs.appendLoad(paths).then(done, done(function (err) { | ||
assert.match(err.message, "'*.txt' matched no files or resources"); | ||
assert.match(err.message, | ||
"'*.txt' matched no files or resources"); | ||
})); | ||
@@ -1025,3 +1027,4 @@ }, | ||
this.rs.appendLoad(paths).then(done, done(function (err) { | ||
assert.match(err.message, "'/*.txt' matched no files or resources"); | ||
assert.match(err.message, | ||
"'/*.txt' matched no files or resources"); | ||
})); | ||
@@ -1033,3 +1036,3 @@ } | ||
setUp: function (done) { | ||
this.rs = resourceSet.create(FIXTURE_DIR); | ||
this.rs = rr.createResourceSet(FIXTURE_DIR); | ||
var resource = { path: "/buster.js", content: "Ok" }; | ||
@@ -1094,3 +1097,4 @@ this.rs.addResource(resource).then(function () { | ||
this.rs.prependLoad(paths).then(done, done(function (err) { | ||
assert.match(err.message, "'*.txt' matched no files or resources"); | ||
assert.match(err.message, | ||
"'*.txt' matched no files or resources"); | ||
})); | ||
@@ -1102,3 +1106,4 @@ }, | ||
this.rs.prependLoad(paths).then(done, done(function (err) { | ||
assert.match(err.message, "'/*.txt' matched no files or resources"); | ||
assert.match(err.message, | ||
"'/*.txt' matched no files or resources"); | ||
})); | ||
@@ -1110,3 +1115,3 @@ } | ||
setUp: function () { | ||
this.rs = resourceSet.create(FIXTURE_DIR); | ||
this.rs = rr.createResourceSet(FIXTURE_DIR); | ||
}, | ||
@@ -1113,0 +1118,0 @@ |
var buster = require("buster"); | ||
var when = require("when"); | ||
var resource = require("../lib/resource"); | ||
var rr = require("../lib/ramp-resources"); | ||
require("./test-helper.js"); | ||
@@ -37,3 +37,3 @@ | ||
"does not fail with only etag": function () { | ||
var rs = resource.create("/path", { etag: "abc123" }); | ||
var rs = rr.createResource("/path", { etag: "abc123" }); | ||
assert.defined(rs); | ||
@@ -43,3 +43,3 @@ }, | ||
"returns resource": function () { | ||
var rs = resource.create("/path", { | ||
var rs = rr.createResource("/path", { | ||
content: "Something" | ||
@@ -52,3 +52,3 @@ }); | ||
"creates cacheable resources by default": function () { | ||
var rs = resource.create("/path", { | ||
var rs = rr.createResource("/path", { | ||
content: "Something" | ||
@@ -61,3 +61,3 @@ }); | ||
"creates uncacheable resource": function () { | ||
var rs = resource.create("/path", { | ||
var rs = rr.createResource("/path", { | ||
content: "Something", | ||
@@ -73,3 +73,3 @@ cacheable: false | ||
"are never null": function () { | ||
var rs = resource.create("/path", { content: "Hey" }); | ||
var rs = rr.createResource("/path", { content: "Hey" }); | ||
assert.defined(rs.headers()); | ||
@@ -79,3 +79,3 @@ }, | ||
"reflect configured values": function () { | ||
var rs = resource.create("/path", { | ||
var rs = rr.createResource("/path", { | ||
content: "Hey", | ||
@@ -95,3 +95,3 @@ headers: { | ||
"has default Content-Type": function () { | ||
var rs = resource.create("/path", { content: "Hey" }); | ||
var rs = rr.createResource("/path", { content: "Hey" }); | ||
@@ -102,3 +102,3 @@ assert.defined(rs.headers()["Content-Type"]); | ||
"includes etag when set": function () { | ||
var rs = resource.create("/path", { | ||
var rs = rr.createResource("/path", { | ||
etag: "1234abc", | ||
@@ -112,3 +112,3 @@ content: "Hey" | ||
"are empty for backend resource": function () { | ||
var rs = resource.create("/api", { backend: "http://localhost" }); | ||
var rs = rr.createResource("/api", { backend: "http://localhost" }); | ||
@@ -121,3 +121,3 @@ assert.equals(rs.headers(), {}); | ||
"defaults to text/html and utf-8": function () { | ||
var rs = resource.create("/path", { content: "<!DOCTYPE html>" }); | ||
var rs = rr.createResource("/path", { content: "<!DOCTYPE html>" }); | ||
@@ -129,3 +129,3 @@ assert.equals(rs.header("Content-Type"), | ||
"defaults to text/html and set charset": function () { | ||
var rs = resource.create("/path", { | ||
var rs = rr.createResource("/path", { | ||
encoding: "iso-8859-1", | ||
@@ -140,3 +140,3 @@ content: "<!DOCTYPE html>" | ||
"defaults to text/css for CSS files": function () { | ||
var rs = resource.create("/path.css", { | ||
var rs = rr.createResource("/path.css", { | ||
content: "body {}" | ||
@@ -150,3 +150,3 @@ }); | ||
"defaults to application/javascript for JS files": function () { | ||
var rs = resource.create("/path.js", { | ||
var rs = rr.createResource("/path.js", { | ||
content: "function () {}" | ||
@@ -160,3 +160,3 @@ }); | ||
"does not include charset for binary files": function () { | ||
var rs = resource.create("/file.png", { | ||
var rs = rr.createResource("/file.png", { | ||
content: new Buffer([]) | ||
@@ -169,3 +169,3 @@ }); | ||
"defaults encoding to base64 for binary files": function () { | ||
var rs = resource.create("/file.png", { | ||
var rs = rr.createResource("/file.png", { | ||
content: new Buffer([]) | ||
@@ -180,3 +180,3 @@ }); | ||
"serves string as content": function (done) { | ||
var rs = resource.create("/path.js", { | ||
var rs = rr.createResource("/path.js", { | ||
content: "console.log(42);" | ||
@@ -192,3 +192,3 @@ }); | ||
var bytes = [231, 167, 129, 227, 129, 175, 227, 130, 172]; | ||
var rs = resource.create("/path.txt", { | ||
var rs = rr.createResource("/path.txt", { | ||
content: new Buffer(bytes) | ||
@@ -201,3 +201,3 @@ }); | ||
"encodes png with base64": function (done) { | ||
var rs = resource.create("/3x3-cross.png", { | ||
var rs = rr.createResource("/3x3-cross.png", { | ||
content: new Buffer([137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, | ||
@@ -232,3 +232,3 @@ 13, 73, 72, 68, 82, 0, 0, 0, 3, 0, 0, 0, | ||
"true when path matches resource path": function () { | ||
var rs = resource.create("/file.js", { content: "Yo" }); | ||
var rs = rr.createResource("/file.js", { content: "Yo" }); | ||
assert(rs.respondsTo("/file.js")); | ||
@@ -238,3 +238,3 @@ }, | ||
"true when path sans trailing slash == resource path": function () { | ||
var rs = resource.create("/file", { content: "Yo" }); | ||
var rs = rr.createResource("/file", { content: "Yo" }); | ||
assert(rs.respondsTo("/file/")); | ||
@@ -244,3 +244,3 @@ }, | ||
"true when path == resource path sans trailing slash": function () { | ||
var rs = resource.create("/file/", { content: "Yo" }); | ||
var rs = rr.createResource("/file/", { content: "Yo" }); | ||
assert(rs.respondsTo("/file")); | ||
@@ -250,3 +250,3 @@ }, | ||
"false for different paths": function () { | ||
var rs = resource.create("/styles.css", { content: "Yo" }); | ||
var rs = rr.createResource("/styles.css", { content: "Yo" }); | ||
refute(rs.respondsTo("/")); | ||
@@ -256,3 +256,3 @@ }, | ||
"false for partial path match": function () { | ||
var rs = resource.create("/styles", { content: "Yo" }); | ||
var rs = rr.createResource("/styles", { content: "Yo" }); | ||
refute(rs.respondsTo("/styles/page.css")); | ||
@@ -264,3 +264,3 @@ } | ||
"content is proxy instance": function () { | ||
var rs = resource.create("/api", { backend: "localhost" }); | ||
var rs = rr.createResource("/api", { backend: "localhost" }); | ||
@@ -272,3 +272,3 @@ assert.isObject(rs.content()); | ||
"content is always same proxy instance": function () { | ||
var rs = resource.create("/api", { backend: "localhost" }); | ||
var rs = rr.createResource("/api", { backend: "localhost" }); | ||
@@ -279,3 +279,3 @@ assert.same(rs.content(), rs.content()); | ||
"defaults port to 80": function () { | ||
var rs = resource.create("/api", { backend: "localhost" }); | ||
var rs = rr.createResource("/api", { backend: "localhost" }); | ||
@@ -286,3 +286,3 @@ assert.equals(rs.content().port, 80); | ||
"defaults path to nothing": function () { | ||
var rs = resource.create("/api", { backend: "localhost" }); | ||
var rs = rr.createResource("/api", { backend: "localhost" }); | ||
@@ -293,3 +293,3 @@ assert.equals(rs.content().path, ""); | ||
"overrides default port": function () { | ||
var rs = resource.create("/api", { backend: "localhost:79" }); | ||
var rs = rr.createResource("/api", { backend: "localhost:79" }); | ||
@@ -300,3 +300,3 @@ assert.equals(rs.content().port, 79); | ||
"overrides default path": function () { | ||
var rs = resource.create("/api", { backend: "localhost/yep" }); | ||
var rs = rr.createResource("/api", { backend: "localhost/yep" }); | ||
@@ -308,3 +308,3 @@ assert.equals(rs.content().path, "/yep"); | ||
"uses full URL": function () { | ||
var rs = resource.create("/api", { | ||
var rs = rr.createResource("/api", { | ||
backend: "http://something:8080/crowd/" | ||
@@ -322,3 +322,3 @@ }); | ||
setUp: function () { | ||
this.rs = resource.create("/api", { backend: "localhost" }); | ||
this.rs = rr.createResource("/api", { backend: "localhost" }); | ||
}, | ||
@@ -342,3 +342,3 @@ | ||
"resolves with content function return value": function (done) { | ||
var rs = resource.create("/api", { content: function () { | ||
var rs = rr.createResource("/api", { content: function () { | ||
return "42"; | ||
@@ -352,3 +352,3 @@ } }); | ||
var d = when.defer(); | ||
var rs = resource.create("/api", { content: function () { | ||
var rs = rr.createResource("/api", { content: function () { | ||
return d.promise; | ||
@@ -363,3 +363,3 @@ } }); | ||
var d = when.defer(); | ||
var rs = resource.create("/api", { content: function () { | ||
var rs = rr.createResource("/api", { content: function () { | ||
return d.promise; | ||
@@ -376,3 +376,3 @@ } }); | ||
var content = this.spy(); | ||
var rs = resource.create("/api", { content: content }); | ||
var rs = rr.createResource("/api", { content: content }); | ||
@@ -386,5 +386,33 @@ rs.content(); | ||
"with fully qualified url as path": { | ||
"content is path": function (done) { | ||
var rs = rr.createResource("file:///tmp/trash.txt"); | ||
rs.content().then(done(function (content) { | ||
assert.equals(content, "file:///tmp/trash.txt"); | ||
})); | ||
} | ||
}, | ||
"getContentFor": { | ||
"returns self for own MIME type": function () { | ||
var res = rr.createResource("/meh", { content: "Content" }); | ||
assert.same(res.getContentFor("text/html"), res); | ||
}, | ||
"returns null for unrecognized MIME type": function () { | ||
var res = rr.createResource("/meh", { content: "Content" }); | ||
refute(res.getContentFor("text/css")); | ||
}, | ||
"returns alternative with desired MIME type": function () { | ||
var res = rr.createResource("/meh", { content: "Content" }); | ||
res.addAlternative({ mimeType: "text/css", content: "body {}" }); | ||
assert(res.getContentFor("text/css")); | ||
} | ||
}, | ||
"processors": { | ||
"process content": function (done) { | ||
var rs = resource.create("/path", { | ||
var rs = rr.createResource("/path", { | ||
content: "Hey" | ||
@@ -401,3 +429,3 @@ }); | ||
"process content in a chain": function (done) { | ||
var rs = resource.create("/path", { | ||
var rs = rr.createResource("/path", { | ||
content: "Hey" | ||
@@ -417,3 +445,3 @@ }); | ||
"processes deferred content": function (done) { | ||
var rs = resource.create("/path", { | ||
var rs = rr.createResource("/path", { | ||
content: function () { return "42"; } | ||
@@ -433,3 +461,3 @@ }); | ||
"leaves content untouched if returns undefined": function (done) { | ||
var rs = resource.create("/path", { | ||
var rs = rr.createResource("/path", { | ||
content: function () { return "42"; } | ||
@@ -444,3 +472,3 @@ }); | ||
"blanks content by returning blank string": function (done) { | ||
var rs = resource.create("/path", { | ||
var rs = rr.createResource("/path", { | ||
content: function () { return "42"; } | ||
@@ -455,3 +483,3 @@ }); | ||
"rejects if string content processor throws": function (done) { | ||
var rs = resource.create("/path", { content: "Hey" }); | ||
var rs = rr.createResource("/path", { content: "Hey" }); | ||
rs.addProcessor(function () { throw new Error("Process fail"); }); | ||
@@ -467,3 +495,3 @@ | ||
"rejects if function content processor throws": function (done) { | ||
var rs = resource.create("/path", { | ||
var rs = rr.createResource("/path", { | ||
content: this.stub().returns("Hey") | ||
@@ -481,3 +509,3 @@ }); | ||
"creates etag hash": function () { | ||
var rs = resource.create("/path", { | ||
var rs = rr.createResource("/path", { | ||
content: "Hey" | ||
@@ -492,3 +520,3 @@ }); | ||
"updates existing etag": function () { | ||
var rs = resource.create("/path", { | ||
var rs = rr.createResource("/path", { | ||
etag: "123", | ||
@@ -504,3 +532,3 @@ content: "Hey" | ||
"always update existing etag": function () { | ||
var rs = resource.create("/path", { | ||
var rs = rr.createResource("/path", { | ||
etag: "123", | ||
@@ -514,2 +542,13 @@ content: "Hey" | ||
assert.equals(rs.etag, "4b0b20e81e9db06b84fc7589e22507eb3d3db04c"); | ||
}, | ||
"does not process content for alternatives": function (done) { | ||
var rs = rr.createResource("/path", { content: "Hey" }); | ||
rs.addAlternative({ content: "Haha", mimeType: "text/css" }); | ||
rs.addProcessor(function (resource, content) { | ||
return content + "!!"; | ||
}); | ||
assert.content(rs.getContentFor("text/css"), "Haha", done); | ||
} | ||
@@ -521,3 +560,3 @@ }, | ||
this.content = this.stub().returns("Something"); | ||
this.rs = resource.create("/path", { content: this.content }); | ||
this.rs = rr.createResource("/path", { content: this.content }); | ||
}, | ||
@@ -548,7 +587,7 @@ | ||
"yields processed content": function (done) { | ||
var processor = this.stub().returns("\m/"); | ||
var processor = this.stub().returns("\\m/"); | ||
this.rs.addProcessor(processor); | ||
this.rs.process().then(done(function (content) { | ||
assert.equals(content, "\m/"); | ||
assert.equals(content, "\\m/"); | ||
}.bind(this))); | ||
@@ -568,3 +607,3 @@ }, | ||
"wraps content in an iife": function (done) { | ||
var rs = resource.create("/path", { | ||
var rs = rr.createResource("/path", { | ||
content: this.stub().returns("var a = 42;"), | ||
@@ -575,3 +614,4 @@ enclose: true | ||
rs.content().then(done(function (content) { | ||
assert.equals(content, "(function () {var a = 42;}.call(this));"); | ||
var expected = "(function () {var a = 42;}.call(this));"; | ||
assert.equals(content, expected); | ||
}.bind(this))); | ||
@@ -581,3 +621,3 @@ }, | ||
"adds exports to iife": function (done) { | ||
var rs = resource.create("/path", { | ||
var rs = rr.createResource("/path", { | ||
content: this.stub().returns("var a = 42;"), | ||
@@ -589,3 +629,6 @@ enclose: true, | ||
rs.content().then(done(function (content) { | ||
assert.equals(content, "(function (global) {var a = 42;global.a=a;}.call(this, typeof global != \"undefined\" ? global : this));"); | ||
var context = "(function (global) {var a = 42;global.a=a;}" + | ||
".call(this, typeof global != \"undefined\" ? " + | ||
"global : this));"; | ||
assert.equals(content, context); | ||
}.bind(this))); | ||
@@ -599,3 +642,3 @@ } | ||
d.resolver.reject("MEH"); | ||
var res = resource.create("/meh", { | ||
var res = rr.createResource("/meh", { | ||
content: function () { return d.promise; } | ||
@@ -611,3 +654,3 @@ }); | ||
"fails if content throws": function (done) { | ||
var res = resource.create("/meh", { | ||
var res = rr.createResource("/meh", { | ||
content: function () { throw new Error("MEH"); } | ||
@@ -623,3 +666,3 @@ }); | ||
"includes enclose property if true": function (done) { | ||
var res = resource.create("/meh", { | ||
var res = rr.createResource("/meh", { | ||
content: "Hey", | ||
@@ -635,3 +678,3 @@ enclose: true | ||
"includes exports if set": function (done) { | ||
var res = resource.create("/meh", { | ||
var res = rr.createResource("/meh", { | ||
content: "Hey", | ||
@@ -648,3 +691,3 @@ enclose: true, | ||
"fails if content processor throws": function (done) { | ||
var res = resource.create("/meh", { | ||
var res = rr.createResource("/meh", { | ||
content: function () { return "Content"; } | ||
@@ -662,3 +705,3 @@ }); | ||
"includes cacheable flag": function (done) { | ||
var res = resource.create("/meh", { | ||
var res = rr.createResource("/meh", { | ||
content: function () { return "Content"; } | ||
@@ -670,4 +713,92 @@ }); | ||
}), function () {}); | ||
}, | ||
"includes alternatives": function (done) { | ||
var res = rr.createResource("/meh", { content: "Content" }); | ||
res.addAlternative({ | ||
content: "CONTENT", | ||
mimeType: "text/uppercase" | ||
}); | ||
res.serialize().then(done(function (serialized) { | ||
assert.match(serialized.alternatives, [{ | ||
content: "CONTENT", | ||
mimeType: "text/uppercase" | ||
}]); | ||
}), function (e) { console.log(e); }); | ||
}, | ||
"does not include alternatives when skipping content": function (done) { | ||
var res = rr.createResource("/meh", { content: "Content" }); | ||
res.addAlternative({ | ||
content: "CONTENT", | ||
mimeType: "text/uppercase" | ||
}); | ||
res.serialize({ includeContent: false }).then(done(function (s) { | ||
refute(s.content); | ||
refute.defined(s.alternatives); | ||
}), function (e) { console.log(e); }); | ||
}, | ||
"does not include content for fully qualified path": function (done) { | ||
var res = rr.createResource("http://cdn/thing.js"); | ||
res.serialize({ includeContent: false }).then(done(function (s) { | ||
refute(s.content); | ||
assert.equals(s.path, "http://cdn/thing.js"); | ||
}), function (e) { console.log(e); }); | ||
} | ||
}, | ||
"addAlternative": { | ||
"updates etag": function () { | ||
var res = rr.createResource("/meh", { content: "Ok", etag: "1" }); | ||
res.addAlternative({ | ||
content: "CONTENT", | ||
mimeType: "text/uppercase" | ||
}); | ||
assert.equals(res.etag, "d24ea95e25ef1cfbb7c7ee4187eae88695b13729"); | ||
}, | ||
"updates etag for every additional mime type alternative": function () { | ||
var res = rr.createResource("/meh", { content: "Ok", etag: "1" }); | ||
res.addAlternative({ content: "CONTENT", mimeType: "text/upcase" }); | ||
res.addAlternative({ content: "CONTENT", mimeType: "text/locase" }); | ||
assert.equals(res.etag, "dec94ef5d39fff3bc911f4a16409d573238ea497"); | ||
}, | ||
"does not update etag when overriding existing alt": function () { | ||
var res = rr.createResource("/meh", { content: "Ok", etag: "1" }); | ||
res.addAlternative({ content: "CONTENT", mimeType: "text/upcase" }); | ||
res.addAlternative({ content: "CONTENT", mimeType: "text/locase" }); | ||
res.addAlternative({ content: "OTHER", mimeType: "text/upcase" }); | ||
assert.equals(res.etag, "dec94ef5d39fff3bc911f4a16409d573238ea497"); | ||
}, | ||
"alternative ordering does not affect etag": function () { | ||
var res = rr.createResource("/meh", { content: "Ok" }); | ||
res.addAlternative({ content: "A", mimeType: "text/upcase" }); | ||
res.addAlternative({ content: "B", mimeType: "text/locase" }); | ||
var res2 = rr.createResource("/meh", { content: "Ok" }); | ||
res2.addAlternative({ content: "A", mimeType: "text/locase" }); | ||
res2.addAlternative({ content: "B", mimeType: "text/upcase" }); | ||
assert.equals(res.etag, res2.etag); | ||
}, | ||
"uses alternative custom etag for etag generation": function () { | ||
var res = rr.createResource("/meh", { content: "Ok" }); | ||
res.addAlternative({ content: "A", mimeType: "text/a", etag: "A" }); | ||
var res2 = rr.createResource("/meh", { content: "Ok" }); | ||
res2.addAlternative({ content: "A", mimeType: "text/a" }); | ||
refute.equals(res.etag, res2.etag); | ||
} | ||
} | ||
}); |
var B = require("buster"); | ||
var resource = require("../lib/resource"); | ||
var rr = require("../lib/ramp-resources"); | ||
var when = require("when"); | ||
@@ -8,3 +8,3 @@ var http = require("http"); | ||
if (e.name !== "InvalidResourceError") { | ||
this.fail("Expected resource.create to fail with " + | ||
this.fail("Expected rr.createResource to fail with " + | ||
"InvalidResourceError, but failed with " + e.name); | ||
@@ -23,3 +23,3 @@ } | ||
if (typeof path === "string") { | ||
resource.create(path, res); | ||
rr.createResource(path, res); | ||
return false; | ||
@@ -26,0 +26,0 @@ } else { |
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
No License Found
License(Experimental) License information could not be found.
Found 1 instance in 1 package
255604
43
0
4673
18
+ Addedlodash@~0.5
+ Addedmulti-glob@~0.4.0
+ Added@isaacs/cliui@8.0.2(transitive)
+ Addedansi-regex@5.0.16.1.0(transitive)
+ Addedansi-styles@4.3.06.2.1(transitive)
+ Addedasync@3.2.6(transitive)
+ Addedbalanced-match@1.0.2(transitive)
+ Addedbrace-expansion@2.0.1(transitive)
+ Addedcolor-convert@2.0.1(transitive)
+ Addedcolor-name@1.1.4(transitive)
+ Addedcross-spawn@7.0.5(transitive)
+ Addedeastasianwidth@0.2.0(transitive)
+ Addedemoji-regex@8.0.09.2.2(transitive)
+ Addedforeground-child@3.3.0(transitive)
+ Addedglob@11.0.0(transitive)
+ Addedis-fullwidth-code-point@3.0.0(transitive)
+ Addedisexe@2.0.0(transitive)
+ Addedjackspeak@4.0.2(transitive)
+ Addedlodash@0.5.2(transitive)
+ Addedlru-cache@11.0.2(transitive)
+ Addedminimatch@10.0.1(transitive)
+ Addedminipass@7.1.2(transitive)
+ Addedmulti-glob@0.4.0(transitive)
+ Addedpackage-json-from-dist@1.0.1(transitive)
+ Addedpath-key@3.1.1(transitive)
+ Addedpath-scurry@2.0.0(transitive)
+ Addedshebang-command@2.0.0(transitive)
+ Addedshebang-regex@3.0.0(transitive)
+ Addedsignal-exit@4.1.0(transitive)
+ Addedstring-width@4.2.35.1.2(transitive)
+ Addedstrip-ansi@6.0.17.1.0(transitive)
+ Addedwhich@2.0.2(transitive)
+ Addedwrap-ansi@7.0.08.1.0(transitive)
- Removedbuster-core@>=0.6.2
- Removedbuster-glob@>=0.3.2
- Removedbuster-core@0.6.4(transitive)
- Removedbuster-glob@0.3.3(transitive)