new algorithm done, not yet used...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2017-06-20 20:35:27 +03:00
parent cad40b850e
commit 4c73da1043

View File

@ -1008,18 +1008,18 @@ var FeatureSetProto = {
}, },
// XXX this looks really promising... // Build list of features in an appropriate order to load...
// XXX //
// - build tree (a-la ._buildFeatureList(..)) // Algorithm:
// - order the features in .depends and .suggested by priority // - expand features:
// - order the features by dependency (similar to .buildFeatureList(..)) // - handle dependencies (detect loops)
// each feature in list must be strictly after it's dependencies // - handle suggestions
// - for each feature // - handle explicitly disabled features (detect loops)
// - check if all dependencies are before // - handle exclusive feature groups/aliases (handle conflicts)
// - if not ??? (XXX) // - sort list of features:
// XXX should we report stuff here??? // - by priority
// XXX TODO: // - by dependency (detect loops/errors)
// - wrapper to pass in applicability filter... //
_buildFeatureListReorder: function(lst, filter){ _buildFeatureListReorder: function(lst, filter){
var all = this.features var all = this.features
lst = (lst == null || lst == '*') ? all : lst lst = (lst == null || lst == '*') ? all : lst
@ -1027,6 +1027,10 @@ var FeatureSetProto = {
var that = this var that = this
// Expand feature references (recursive)...
//
// NOTE: closures are not used here as we need to pass different
// stuff into data in different situations...
var expand = function(target, lst, store, data, _seen){ var expand = function(target, lst, store, data, _seen){
data = data || {} data = data || {}
_seen = _seen || [] _seen = _seen || []
@ -1036,7 +1040,6 @@ var FeatureSetProto = {
// feature before it is disabled in the same list... // feature before it is disabled in the same list...
lst = data.disabled ? lst = data.disabled ?
lst lst
// XXX also skip features depending on disabled...
.filter(function(n){ .filter(function(n){
// feature disabled -> record and skip... // feature disabled -> record and skip...
if(n[0] == '-'){ if(n[0] == '-'){
@ -1122,34 +1125,22 @@ var FeatureSetProto = {
return store return store
} }
var loops = [] // Expand feature dependencies and suggestions recursively...
var disable_loops = [] //
var disabled = [] // NOTE: this relies on the following values being in the closure:
var missing = [] // loops - list of loop chains found
// disable_loops - disable loops
// user filter... // when a feature containing a disable
// NOTE: we build this out of the full feature list... // directive gets disabled as a result
var filtered_out = filter ? // disabled - list of disabled features
all.filter(function(n){ return !filter.call(that, n) }) // missing - list of missing features
: [] // exclusive - exclusive feature index
disabled = disabled.concat(filtered_out) // NOTE: the above containers will get updated as a side-effect.
// NOTE: all of the above values are defined near the location
// build exclusive groups... // they are first used/initiated...
// XXX use these as aliases... // NOTE: closures are used here purely for simplicity and conciseness
// ...we need to do this on the build stage to include correct // as threading data would not add any flexibility but make
// deps and suggesntions... // the code more complex...
var exclusive = {}
var rev_exclusive = {}
all
.filter(function(f){ return !!that[f].exclusive })
.forEach(function(k){
(that[k].exclusive || [])
.forEach(function(e){
exclusive[e] = (exclusive[e] || []).concat([k])
rev_exclusive[k] = (rev_exclusive[k] || []).concat([e]) }) })
// XXX revise:
// - should this be this depending on closure so much???
var expandFeatures = function(lst, features){ var expandFeatures = function(lst, features){
features = features || {} features = features || {}
@ -1194,14 +1185,44 @@ var FeatureSetProto = {
features[f] = s[f] features[f] = s[f]
} }
}) })
return features
} }
var features = {} //--------------------- Globals: filtering / exclusive tags ---
expandFeatures(lst, features)
var loops = []
var disable_loops = []
var disabled = []
var missing = []
// user filter...
// NOTE: we build this out of the full feature list...
var filtered_out = filter ?
all.filter(function(n){ return !filter.call(that, n) })
: []
disabled = disabled.concat(filtered_out)
// build exclusive groups...
var exclusive = {}
var rev_exclusive = {}
all
.filter(function(f){ return !!that[f].exclusive })
.forEach(function(k){
(that[k].exclusive || [])
.forEach(function(e){
exclusive[e] = (exclusive[e] || []).concat([k])
rev_exclusive[k] = (rev_exclusive[k] || []).concat([e]) }) })
// check for exclusivity conflicts and aliases... //-------------------------------- Stage 1: expand features ---
var features = expandFeatures(lst)
//-------------------------------- Exclusive groups/aliases ---
// Handle exclusive feature groups and aliases...
//
var conflicts = {} var conflicts = {}
Object.keys(features) Object.keys(features)
.forEach(function(f){ .forEach(function(f){
@ -1214,7 +1235,7 @@ var FeatureSetProto = {
if(candidates.length == 0){ if(candidates.length == 0){
var target = exclusive[f][0] var target = exclusive[f][0]
// expand target... // expand target to features...
expandFeatures([target], features) expandFeatures([target], features)
// link alias to existing feature... // link alias to existing feature...
@ -1246,13 +1267,18 @@ var FeatureSetProto = {
} }
} }
}) })
// resolve any conflicts found... // resolve any exclusivity conflicts found...
var excluded = []
Object.keys(conflicts) Object.keys(conflicts)
.forEach(function(group){ .forEach(function(group){
// XXX is this how we decide which feature to keep??? // XXX is this how we decide which feature to keep???
disabled = disabled.concat(conflicts[group].slice(1))}) excluded = excluded.concat(conflicts[group].slice(1))})
disabled = disabled.concat(excluded)
//--------------------------------------- Disabled features ---
// Handle disabled features and cleanup...
// reverse dependency index... // reverse dependency index...
// ...this is used to clear out orphaned features later and for // ...this is used to clear out orphaned features later and for
// introspection... // introspection...
@ -1262,7 +1288,7 @@ var FeatureSetProto = {
(features[f] || []) (features[f] || [])
.forEach(function(d){ .forEach(function(d){
rev_features[d] = (rev_features[d] || []).concat([f]) }) }) rev_features[d] = (rev_features[d] || []).concat([f]) }) })
// clear dependency trees containing disabled features... // clear dependency trees containing disabled features...
do { do {
var expanded_disabled = false var expanded_disabled = false
@ -1299,8 +1325,10 @@ var FeatureSetProto = {
delete features[f] delete features[f]
}) })
// expand dependency list... (index)
// ...this is used for feature sorting by dependency... //---------------------------------- Stage 2: sort features ---
// Prepare for sort: expand dependency list in features...
// //
// NOTE: this will expand lst in-place... // NOTE: this will expand lst in-place...
// NOTE: we are not checking for loops here -- mainly because // NOTE: we are not checking for loops here -- mainly because
@ -1331,7 +1359,12 @@ var FeatureSetProto = {
var list = Object.keys(features) var list = Object.keys(features)
list.forEach(function(f){ expanddeps(list, f) }) list.forEach(function(f){ expanddeps(list, f) })
// sort by priority... // sort by priority...
//
// NOTE: this will attempt to only move features with explicitly
// defined priorities and keep the rest in the same order
// when possible...
list = list list = list
// format: // format:
// [ <feature>, <index>, <priority> ] // [ <feature>, <index>, <priority> ]
@ -1380,6 +1413,8 @@ var FeatureSetProto = {
} while(moves > 0 && loop_limit > 0) } while(moves > 0 && loop_limit > 0)
//-------------------------------------------------------------
// XXX should we report stuff here??? // XXX should we report stuff here???
// report dependency loops... // report dependency loops...
// //
@ -1391,26 +1426,34 @@ var FeatureSetProto = {
&& loops && loops
.forEach(function(loop){ .forEach(function(loop){
console.warn('feature loop detected:\n\t' + loop.join('\n\t\t-> ')) }) console.warn('feature loop detected:\n\t' + loop.join('\n\t\t-> ')) })
// report loop limit...
loop_limit <= 0
&& console.error('Hit loop limit while sorting dependencies!')
// report conflicts... // report conflicts...
Object.keys(conflicts) Object.keys(conflicts)
.forEach(function(group){ .forEach(function(group){
console.error('Exclusive "'+ group +'" conflict at:', conflicts[group]) }) console.error('Exclusive "'+ group +'" conflict at:', conflicts[group]) })
// report loop limit...
// XXX store this to data...
loop_limit <= 0
&& console.error('Hit loop limit while sorting dependencies!')
return { return {
input: lst,
list: list, list: list,
features: features, disabled: disabled,
rev_features: rev_features, excluded: excluded,
exclusive: exclusive, filtered_out: filtered_out,
conflicts: conflicts,
// XXX should these be in a error block???
missing: missing, missing: missing,
loops: loops, loops: loops,
filtered_out: filtered_out, conflicts: conflicts,
disabled: disabled, sort_loop_error: loop_limit <= 0,
//features: features,
//rev_features: rev_features,
//exclusive: exclusive,
} }
}, },