Comparing version 0.5.2 to 0.6.0
0.6.0 / 2015-12-05 | ||
================== | ||
* adding `Tree#getFiles()` | ||
* removing `Tree#topologicalOrder()` | ||
* adding `options` argument to `Tree#getFiles()` | ||
* replacing `recursive` with `options` argument in `Tree#dependenciesOf()` and `Tree#dependantsOf()` | ||
* adding `options.objects` to `Tree#getFiles()`, `Tree#getEntries()`, `Tree#dependenciesOf()` and `Tree#dependantsOf()` | ||
0.5.2 / 2015-12-01 | ||
@@ -3,0 +12,0 @@ ================== |
@@ -34,8 +34,8 @@ | ||
dependencies(recursive) { | ||
return this.tree.dependenciesOf(this.path, recursive); | ||
dependencies(options) { | ||
return this.tree.dependenciesOf(this.path, options); | ||
} | ||
dependants(recursive) { | ||
return this.tree.dependantsOf(this.path, recursive); | ||
dependants(options) { | ||
return this.tree.dependantsOf(this.path, options); | ||
} | ||
@@ -42,0 +42,0 @@ |
@@ -5,2 +5,3 @@ | ||
let debug = require('debug')('mako-tree'); | ||
let defaults = require('defaults'); | ||
let Graph = require('graph.js/dist/graph.full.js'); | ||
@@ -34,2 +35,14 @@ let File = require('./file'); | ||
getFiles(options) { | ||
let config = defaults(options, { | ||
topological: false, | ||
objects: false | ||
}); | ||
debug('getting files: %j', config); | ||
return config.topological | ||
? toposort(this.graph) | ||
: Array.from(this.graph.vertices()).map(vertices(config.objects)); | ||
} | ||
removeFile(location) { | ||
@@ -44,17 +57,22 @@ debug('removing node %s', location); | ||
getEntries(from) { | ||
debug('listing entry files'); | ||
getEntries(options) { | ||
let config = defaults(options, { | ||
from: null, | ||
objects: false | ||
}); | ||
debug('getting entry files: %j', config); | ||
let entries = Array.from(this.graph.sinks()) | ||
.filter(vertex => !!vertex[1].entry) | ||
.map(vertex => vertex[0]); | ||
.filter(vertex => !!vertex[1].entry); | ||
if (from) { | ||
debug('filtering out entry files not linked to %s', from); | ||
entries = entries.filter(entry => { | ||
return from === entry || this.graph.hasPath(from, entry); | ||
if (config.from) { | ||
entries = entries.filter(vertex => { | ||
let start = config.from; | ||
let end = vertex[0]; | ||
return start === end || this.graph.hasPath(start, end); | ||
}); | ||
} | ||
debug('%d entries found %j', entries.length, entries); | ||
return entries; | ||
debug('%d entries found', entries.length); | ||
return entries.map(vertices(config.objects)); | ||
} | ||
@@ -84,22 +102,32 @@ | ||
dependenciesOf(node, recursive) { | ||
let deps = recursive | ||
dependenciesOf(node, options) { | ||
let config = defaults(options, { | ||
recursive: false, | ||
objects: false | ||
}); | ||
debug('getting dependencies of %s: %j', node, config); | ||
let deps = config.recursive | ||
? this.graph.verticesWithPathTo(node) | ||
: this.graph.verticesTo(node); | ||
return Array.from(deps).map(vertex => vertex[0]); | ||
debug('%d dependencies found', deps.length); | ||
return Array.from(deps).map(vertices(config.objects)); | ||
} | ||
dependantsOf(node, recursive) { | ||
let deps = recursive | ||
dependantsOf(node, options) { | ||
let config = defaults(options, { | ||
recursive: false, | ||
objects: false | ||
}); | ||
debug('getting dependants of %s: %j', node, config); | ||
let deps = config.recursive | ||
? this.graph.verticesWithPathFrom(node) | ||
: this.graph.verticesFrom(node); | ||
return Array.from(deps).map(vertex => vertex[0]); | ||
debug('%d dependants found', deps.length); | ||
return Array.from(deps).map(vertices(config.objects)); | ||
} | ||
topologicalOrder() { | ||
return toposort(this.graph); | ||
} | ||
size() { | ||
@@ -110,2 +138,3 @@ return this.graph.vertexCount(); | ||
clone() { | ||
debug('cloning tree'); | ||
let tree = new Tree(); | ||
@@ -119,3 +148,3 @@ tree.graph = this.graph.clone(file => file.clone(tree), value => value); | ||
if (!entries) entries = this.getEntries(); | ||
let files = this.topologicalOrder(); | ||
let files = this.getFiles({ topological: true }); | ||
@@ -136,1 +165,16 @@ files | ||
module.exports = Tree; | ||
/** | ||
* Helper for mapping a list of vertices. By default, the vertex key (absolute | ||
* path) is returned, but if `value` is truthy, it will return the `File` | ||
* object instead. | ||
* | ||
* @param {Boolean} value Whether to use the key or value. | ||
* @return {Function} | ||
*/ | ||
function vertices(value) { | ||
return function (vertex) { | ||
return value ? vertex[1] : vertex[0]; | ||
}; | ||
} |
{ | ||
"name": "mako-tree", | ||
"version": "0.5.2", | ||
"version": "0.6.0", | ||
"description": "The build tree structure used internally by mako", | ||
@@ -8,2 +8,3 @@ "repository": "makojs/tree", | ||
"debug": "^2.2.0", | ||
"defaults": "^1.0.3", | ||
"file-extension": "^2.0.1", | ||
@@ -10,0 +11,0 @@ "graph-toposort": "0.0.1", |
@@ -60,2 +60,12 @@ # mako-tree | ||
### Tree#getFiles([options]) | ||
Returns an `Array` of all the files in this graph. | ||
If `options.topological` is set, the returned list will be in | ||
[topological order](https://en.wikipedia.org/wiki/Topological_sorting), which respects all | ||
dependencies so processing is safe where order matters. | ||
If `options.objects` is set, the returned list will be `File` objects. | ||
### Tree#removeFile(location) | ||
@@ -72,3 +82,3 @@ | ||
### Tree#getEntries([from]) | ||
### Tree#getEntries([options]) | ||
@@ -78,5 +88,7 @@ Returns an `Array` of all the entry files in this graph. (in other words, files that are at the | ||
If `from` is provided, the returned list will only include entries that are reachable from that | ||
If `options.from` is set, the returned list will only include entries that are reachable from that | ||
specified file. | ||
If `options.objects` is set, the returned list will be `File` objects. | ||
### Tree#hasDependency(parent, child) | ||
@@ -102,20 +114,20 @@ | ||
### Tree#dependenciesOf(file, [recursive]) | ||
### Tree#dependenciesOf(file, [options]) | ||
Returns an `Array` of files that are dependencies of the given `file`. | ||
By default, it will only return the direct descendants, but adding `recursive` will return a flat | ||
list of all the files **down** the entire dependency chain. | ||
By default, it will only return the direct descendants, but setting `options.recursive` will return | ||
a flat list of all the files **down** the entire dependency chain. | ||
### Tree#dependantsOf(file, [recursive]) | ||
If `options.objects` is set, the returned list will be `File` objects. | ||
### Tree#dependantsOf(file, [options]) | ||
Returns an `Array` of files that depend on the given `file`. | ||
By default, it will only return the direct ancestors, but adding `recursive` will return a flat | ||
list of all the files **up** the entire dependency chain. | ||
By default, it will only return the direct ancestors, but adding `options.recursive` will return a | ||
flat list of all the files **up** the entire dependency chain. | ||
### Tree#topologicalOrder() | ||
If `options.objects` is set, the returned list will be `File` objects. | ||
Returns an `Array` of files that can be processed in an order that respects all the dependencies. | ||
### Tree#clone() | ||
@@ -194,9 +206,9 @@ | ||
### File#dependencies([recursive]) | ||
### File#dependencies([options]) | ||
Short-hand for `tree.dependenciesOf(file.path, recursive)`. | ||
Short-hand for `tree.dependenciesOf(file.path, options)`. | ||
### File#dependants([recursive]) | ||
### File#dependants([options]) | ||
Short-hand for `tree.dependantsOf(file.path, recursive)`. | ||
Short-hand for `tree.dependantsOf(file.path, options)`. | ||
@@ -203,0 +215,0 @@ ### File#dirty() |
@@ -86,3 +86,3 @@ | ||
describe('#dependencies(recursive)', function () { | ||
describe('#dependencies([options])', function () { | ||
// a -> b -> c -> d | ||
@@ -99,8 +99,18 @@ let tree = new Tree(); | ||
it('should return the entire dependency chain', function () { | ||
assert.deepEqual(b.dependencies(true), [ 'c', 'd' ]); | ||
context('with options', function () { | ||
context('.recursive', function () { | ||
it('should return the entire dependency chain', function () { | ||
assert.deepEqual(b.dependencies({ recursive: true }), [ 'c', 'd' ]); | ||
}); | ||
}); | ||
context('.objects', function () { | ||
it('should return the file objects', function () { | ||
b.dependencies({ objects: true }).forEach(file => assert.instanceOf(file, File)); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('#dependants(recursive)', function () { | ||
describe('#dependants([options])', function () { | ||
// a -> b -> c -> d | ||
@@ -117,4 +127,14 @@ let tree = new Tree(); | ||
it('should return the entire dependency chain', function () { | ||
assert.deepEqual(c.dependants(true), [ 'b', 'a' ]); | ||
context('with options', function () { | ||
context('.recursive', function () { | ||
it('should return the entire dependency chain', function () { | ||
assert.deepEqual(c.dependants({ recursive: true }), [ 'b', 'a' ]); | ||
}); | ||
}); | ||
context('.objects', function () { | ||
it('should return the file objects', function () { | ||
c.dependants({ objects: true }).forEach(file => assert.instanceOf(file, File)); | ||
}); | ||
}); | ||
}); | ||
@@ -121,0 +141,0 @@ }); |
127
test/tree.js
@@ -79,2 +79,35 @@ | ||
describe('#getFiles([options])', function () { | ||
// a <- b <- c <- d | ||
// <- e | ||
let tree = new Tree(); | ||
tree.addFile('a'); | ||
tree.addFile('b'); | ||
tree.addFile('c'); | ||
tree.addFile('d'); | ||
tree.addFile('e'); | ||
tree.addDependency('a', 'b'); | ||
tree.addDependency('a', 'e'); | ||
tree.addDependency('b', 'c'); | ||
tree.addDependency('c', 'd'); | ||
it('should return a list of all the files in the tree', function () { | ||
assert.deepEqual(tree.getFiles(), [ 'a', 'b', 'c', 'd', 'e' ]); | ||
}); | ||
context('with options', function () { | ||
context('.topological', function () { | ||
it('should sort the results topologically', function () { | ||
assert.deepEqual(tree.getFiles({ topological: true }), [ 'd', 'e', 'c', 'b', 'a' ]); | ||
}); | ||
}); | ||
context('.objects', function () { | ||
it('should return the file objects', function () { | ||
tree.getFiles({ objects: true }).forEach(file => assert.instanceOf(file, File)); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('#removeFile(location)', function () { | ||
@@ -102,3 +135,3 @@ it('should remove the file from the tree', function () { | ||
describe('#getEntries([from])', function () { | ||
describe('#getEntries([options])', function () { | ||
it('should return an empty list', function () { | ||
@@ -140,18 +173,26 @@ let tree = new Tree(); | ||
context('with from', function () { | ||
it('should only return all the linked entries', function () { | ||
// a <- b | ||
// c <- d <- e | ||
let tree = new Tree(); | ||
tree.addFile('a', true); | ||
tree.addFile('b'); | ||
tree.addFile('c', true); | ||
tree.addFile('d'); | ||
tree.addFile('e'); | ||
tree.addDependency('a', 'b'); | ||
tree.addDependency('c', 'd'); | ||
tree.addDependency('d', 'e'); | ||
context('with options', function () { | ||
// a <- b | ||
// c <- d <- e | ||
let tree = new Tree(); | ||
tree.addFile('a', true); | ||
tree.addFile('b'); | ||
tree.addFile('c', true); | ||
tree.addFile('d'); | ||
tree.addFile('e'); | ||
tree.addDependency('a', 'b'); | ||
tree.addDependency('c', 'd'); | ||
tree.addDependency('d', 'e'); | ||
assert.deepEqual(tree.getEntries('e'), [ 'c' ]); | ||
context('.from', function () { | ||
it('should only return all the linked entries', function () { | ||
assert.deepEqual(tree.getEntries({ from: 'e' }), [ 'c' ]); | ||
}); | ||
}); | ||
context('.objects', function () { | ||
it('should return the file objects', function () { | ||
tree.getEntries({ objects: true }).forEach(file => assert.instanceOf(file, File)); | ||
}); | ||
}); | ||
}); | ||
@@ -272,3 +313,3 @@ }); | ||
describe('#dependenciesOf(node, [recursive])', function () { | ||
describe('#dependenciesOf(node, [options])', function () { | ||
// a <- b <- c <- d | ||
@@ -288,10 +329,18 @@ let tree = new Tree(); | ||
context('with recursive', function () { | ||
it('should all the dependencies of node', function () { | ||
assert.deepEqual(tree.dependenciesOf('a', true), [ 'b', 'c', 'd' ]); | ||
context('with options', function () { | ||
context('.recursive', function () { | ||
it('should all the dependencies of node', function () { | ||
assert.deepEqual(tree.dependenciesOf('a', { recursive: true }), [ 'b', 'c', 'd' ]); | ||
}); | ||
}); | ||
context('.objects', function () { | ||
it('should return the file objects', function () { | ||
tree.dependenciesOf('a', { objects: true }).forEach(file => assert.instanceOf(file, File)); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('#dependantsOf(node, [recursive])', function () { | ||
describe('#dependantsOf(node, [options])', function () { | ||
// a <- b <- c <- d | ||
@@ -311,24 +360,14 @@ let tree = new Tree(); | ||
context('with recursive', function () { | ||
it('should all the dependencies of node', function () { | ||
assert.deepEqual(tree.dependantsOf('d', true), [ 'c', 'b', 'a' ]); | ||
context('with options', function () { | ||
context('.recursive', function () { | ||
it('should all the dependencies of node', function () { | ||
assert.deepEqual(tree.dependantsOf('d', { recursive: true }), [ 'c', 'b', 'a' ]); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('#topologicalOrder()', function () { | ||
// a <- b <- c <- d | ||
// <- e | ||
let tree = new Tree(); | ||
tree.addFile('a'); | ||
tree.addFile('b'); | ||
tree.addFile('c'); | ||
tree.addFile('d'); | ||
tree.addDependency('a', 'b'); | ||
tree.addDependency('a', 'e'); | ||
tree.addDependency('b', 'c'); | ||
tree.addDependency('c', 'd'); | ||
it('should return a topolically sorted list', function () { | ||
assert.deepEqual(tree.topologicalOrder(), [ 'd', 'e', 'c', 'b', 'a' ]); | ||
context('.objects', function () { | ||
it('should return the file objects', function () { | ||
tree.dependantsOf('d', { objects: true }).forEach(file => assert.instanceOf(file, File)); | ||
}); | ||
}); | ||
}); | ||
@@ -353,3 +392,3 @@ }); | ||
assert.strictEqual(tree.size(), clone.size()); | ||
assert.deepEqual(tree.topologicalOrder(), clone.topologicalOrder()); | ||
assert.deepEqual(tree.getFiles({ topolical: true }), clone.getFiles({ topolical: true })); | ||
}); | ||
@@ -406,3 +445,3 @@ }); | ||
assert.deepEqual(tree.topologicalOrder(), [ 'c', 'b', 'a' ]); | ||
assert.deepEqual(tree.getFiles({ topological: true }), [ 'c', 'b', 'a' ]); | ||
}); | ||
@@ -428,3 +467,3 @@ | ||
assert.deepEqual(tree.topologicalOrder(), [ 'd', 'c', 'b', 'a' ]); | ||
assert.deepEqual(tree.getFiles({ topological: true }), [ 'd', 'c', 'b', 'a' ]); | ||
}); | ||
@@ -446,3 +485,3 @@ | ||
assert.deepEqual(tree.topologicalOrder(), [ 'd', 'c' ]); | ||
assert.deepEqual(tree.getFiles({ topological: true }), [ 'd', 'c' ]); | ||
}); | ||
@@ -449,0 +488,0 @@ }); |
38107
758
221
5
+ Addeddefaults@^1.0.3
+ Addedclone@1.0.4(transitive)
+ Addeddefaults@1.0.4(transitive)