From 3ea9db6114c5550397d4f15e888fc1b1e868a1a5 Mon Sep 17 00:00:00 2001 From: Van Nguyen Date: Tue, 12 Mar 2013 14:28:05 -0700 Subject: [PATCH] unoptimized plugin dependency sorting algo --- lib/ext.js | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 1 deletion(-) diff --git a/lib/ext.js b/lib/ext.js index 49a617b75..9b1a2d9aa 100755 --- a/lib/ext.js +++ b/lib/ext.js @@ -69,7 +69,7 @@ internals.Ext.prototype.sort = function (event) { // Sort - var sorted = input; + var sorted = internals.depsort(input); // Apply @@ -137,3 +137,160 @@ internals.Ext.runProtected = function (log, tags, callback, setup) { }, finish); }; + + +internals.getGraph = function (plugins) { + + var groups = {}; + var graph = {}; + var graphAfters = {}; + var result = []; + + for(var i = 0, il = plugins.length; i < il; ++i) { + var plugin = plugins[i]; + var index = plugin.priority; + var group = plugin.group; + + // Determine Groups + if (groups.hasOwnProperty(group)) { + if (groups[group].indexOf(index) == -1) { + groups[group].push(index); + } + } + else { + groups[group] = [index]; + } + + var hasBefore = plugin.hasOwnProperty('before'); + var hasAfter = plugin.hasOwnProperty('after'); + + // Build intermediary graph using 'before' + if (hasBefore) { + var before = plugin.before; + if (!(before instanceof Array)) { + before = [before]; + } + + graph[index] = (graph[index] || []).concat(before); + } + + // Build second intermediary graph with "after" + if (hasAfter) { + var after = plugin.after; + if (!(after instanceof Array)) { + after = [after]; + } + + for(var j = 0, jl = after.length; j < jl; ++j) { + graphAfters[after[j]] = (graphAfters[after[j]] || []).concat(index); + } + } + } + + // Expand intermediary graph + var nodes = Object.keys(graph); + for(var m in nodes) { + var node = nodes[m]; + var expandedGroups = []; + + for(var groupIndex in graph[node]) { + var group = graph[node][groupIndex]; + groups[group].forEach(function(d){ + expandedGroups.push(d); + }) + } + graph[node] = expandedGroups; + } + + // Merge intermediary graph using graphAfters into final graph + var afterNodes = Object.keys(graphAfters); + for(var n in afterNodes) { + var group = afterNodes[n]; + + for(var itemIndex in groups[group]) { + var node = groups[group][itemIndex]; + graph[node] = (graph[node] || []).concat(graphAfters[group]) + } + } + + return graph; +}; + + +internals.getAncestors = function (graph) { + + var ancestors = {}; + var graphNodes = Object.keys(graph); + for(var i in graphNodes) { + var node = graphNodes[i]; + var children = graph[node]; + + for(var j = 0, jl = children.length; j < jl; ++j) { + ancestors[children[j]] = (ancestors[children[j]] || []).concat(node); + } + } + + return ancestors; +}; + +internals.toposort = function (ancestorsGraph, length) { + + var visited = {}; + var sorted = []; + length = length || ancestorsGraph.length; + + var ancNodes = Object.keys(ancestorsGraph); + + for(var i = 0, il = length; i < il; ++i) { + var next = i; + + if (ancestorsGraph[i]) { + next = null; + for(var j = 0, jl = length; j < jl; ++j) { + if (visited[j] == true) { + continue; + } + + if (!ancestorsGraph[j]) { + ancestorsGraph[j] = []; + } + + var shouldSeeCount = ancestorsGraph[j].length; + var seenCount = 0; + for(var l = 0, ll = shouldSeeCount; l < ll; ++l) { + if (sorted.indexOf(ancestorsGraph[j][l]) >= 0) { + ++seenCount; + } + } + + if (seenCount == shouldSeeCount) { + next = j; + break; + } + } + } + + if (next !== null) { + next = next.toString(); // normalize to string + visited[next] = true; + sorted.push(next); + } + } + + if (sorted.length != length) { + throw "Invalid plugin input supplied"; // Occurs if before/after set to item's group (but not limited to this case) + } + + return sorted; +}; + + +internals.depsort = function (plugins) { + + var graph = internals.getGraph(plugins); + var ancestors = internals.getAncestors(graph); + return internals.toposort(ancestors, plugins.length).map(function (value, index) { + + return plugins[value]; + }); +}; \ No newline at end of file