mirror of
https://github.com/flynx/features.js.git
synced 2025-10-29 10:20:09 +00:00
new algorithm done, not yet used...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
cad40b850e
commit
4c73da1043
159
features.js
159
features.js
@ -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...
|
||||||
@ -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,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user