mirror of
https://github.com/flynx/features.js.git
synced 2025-10-29 10:20:09 +00:00
cleanup...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
325d9c74af
commit
941df6ef14
341
features.js
341
features.js
@ -667,347 +667,6 @@ var FeatureSetProto = {
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
_buildFeatureList: function(lst, filter){
|
||||
lst = (lst == null || lst == '*') ? this.features : lst
|
||||
lst = lst.constructor !== Array ? [lst] : lst
|
||||
|
||||
var that = this
|
||||
|
||||
// XXX disabled handling is wrong at this point... (???)
|
||||
// - if a feature is encountered before it is disabled it
|
||||
// will still get loaded...
|
||||
// - need to also resolve disable loops...
|
||||
// a disable declaration that will disable the declaring feature...
|
||||
var expand = function(target, lst, store, data, _seen){
|
||||
data = data || {}
|
||||
_seen = _seen || []
|
||||
|
||||
// user filter...
|
||||
lst = filter ?
|
||||
lst.filter(function(n){ return filter.call(that, n) })
|
||||
: lst
|
||||
|
||||
// clear disabled...
|
||||
// NOTE: we do as a separate stage to avoid loading a
|
||||
// feature before it is disabled in the same list...
|
||||
lst = data.disabled ?
|
||||
lst
|
||||
.filter(function(n){
|
||||
// feature disabled -> record and skip...
|
||||
if(n[0] == '-'){
|
||||
n = n.slice(1)
|
||||
if(_seen.indexOf(n) >= 0){
|
||||
// NOTE: a disable loop is when a feature tries to disable
|
||||
// a feature up in the same chain...
|
||||
// XXX should this break or accumulate???
|
||||
console.warn(`Disable loop detected at "${n}" in chain: ${_seen}`)
|
||||
var loop = _seen.slice(_seen.indexOf(n)).concat([n])
|
||||
data.disable_loops = (data.disable_loops || []).push(loop)
|
||||
return false
|
||||
}
|
||||
// XXX STUB -- need to resolve actual loops and
|
||||
// make the disable global...
|
||||
if(n in store){
|
||||
console.warn('Disabling a feature after it is loaded:', n, _seen)
|
||||
}
|
||||
data.disabled.push(n)
|
||||
return false
|
||||
}
|
||||
// skip already disabled features...
|
||||
if(data.disabled.indexOf(n) >= 0){
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
: lst
|
||||
|
||||
// traverse the tree...
|
||||
lst
|
||||
// normalize the list -- remove non-features and resolve aliases...
|
||||
.map(function(n){
|
||||
var f = that[n]
|
||||
// resolve exclusive tags...
|
||||
while(f == null && data.exclusive && n in data.exclusive){
|
||||
var n = data.exclusive[n][0]
|
||||
f = that[n]
|
||||
}
|
||||
// feature not defined or is not a feature...
|
||||
if(f == null){
|
||||
data.missing
|
||||
&& data.missing.indexOf(n) < 0
|
||||
&& data.missing.push(n)
|
||||
return false
|
||||
}
|
||||
return n
|
||||
})
|
||||
.filter(function(e){ return e })
|
||||
|
||||
// sort the list...
|
||||
// build the sort table: [ <priority>, <index>, <elem> ]
|
||||
.map(function(e, i){
|
||||
return [ that[e].getPriority ? that[e].getPriority() : i, i, e ] })
|
||||
// sort by priority or index...
|
||||
// NOTE: JS compares lists as strings so we have to compare
|
||||
// the list manually...
|
||||
.sort(function(a, b){ return a[0] - b[0] || a[1] - b[1] })
|
||||
// cleanup -- drop the sort table...
|
||||
.map(function(e){ return e[2] })
|
||||
|
||||
// traverse down...
|
||||
.forEach(function(f){
|
||||
// dependency loop detection...
|
||||
if(_seen.indexOf(f) >= 0){
|
||||
var loop = _seen.slice(_seen.indexOf(f)).concat([f])
|
||||
data.loops
|
||||
&& data.loops.push(loop)
|
||||
return
|
||||
}
|
||||
|
||||
// skip already done features...
|
||||
if(f in store){
|
||||
return
|
||||
}
|
||||
|
||||
//var feature = store[f] = that[f]
|
||||
var feature = that[f]
|
||||
if(feature){
|
||||
var _lst = []
|
||||
|
||||
// merge lists...
|
||||
;(target instanceof Array ? target : [target])
|
||||
.forEach(function(t){
|
||||
_lst = _lst.concat(feature[t] || [])
|
||||
})
|
||||
store[f] = _lst
|
||||
|
||||
// traverse down...
|
||||
expand(target, _lst, store, data, _seen.concat([f]))
|
||||
|
||||
// XXX makes sense to push the dep here -- at the tail of the recursion...
|
||||
data.list
|
||||
&& data.list.push(f)
|
||||
}
|
||||
})
|
||||
|
||||
return store
|
||||
}
|
||||
|
||||
//var list = []
|
||||
var loops = []
|
||||
var disable_loops = []
|
||||
var disabled = []
|
||||
var missing = []
|
||||
|
||||
// build exclusive groups...
|
||||
// XXX use these as aliases...
|
||||
// ...we need to do this on the build stage to include correct
|
||||
// deps and suggesntions...
|
||||
var exclusive = {}
|
||||
var rev_exclusive = {}
|
||||
var _exclusive = {}
|
||||
// NOTE: we do not need loop detection active here...
|
||||
Object.keys(expand('exclusive', lst, _exclusive))
|
||||
.forEach(function(k){
|
||||
(_exclusive[k] || [])
|
||||
.forEach(function(e){
|
||||
exclusive[e] = (exclusive[e] || []).concat([k])
|
||||
//rev_exclusive[k] = (rev_exclusive[k] || []).concat([e])
|
||||
}) })
|
||||
|
||||
// feature tree...
|
||||
var features = expand('depends', lst, {},
|
||||
{
|
||||
//list: list,
|
||||
loops: loops,
|
||||
disable_loops: disable_loops,
|
||||
disabled: disabled,
|
||||
missing: missing,
|
||||
exclusive: exclusive,
|
||||
})
|
||||
|
||||
// suggestion list...
|
||||
// NOTE: this stage does not track suggested feature dependencies...
|
||||
// NOTE: we do not need loop detection active here...
|
||||
var suggested = Object.keys(
|
||||
expand('suggested', Object.keys(features), {}, {disabled: disabled}))
|
||||
.filter(function(f){ return !(f in features) })
|
||||
// get suggestion dependencies...
|
||||
suggested = expand('depends', suggested, {},
|
||||
{
|
||||
//list: list,
|
||||
loops: loops,
|
||||
})
|
||||
// keep only suggested features..
|
||||
// XXX this might get affected by disabled...
|
||||
Object.keys(suggested)
|
||||
.forEach(function(f){
|
||||
f in features
|
||||
&& (delete suggested[f]) })
|
||||
|
||||
// check/resolve for exclusivity conflicts...
|
||||
// XXX this might get affected by disabled...
|
||||
// XXX
|
||||
|
||||
// report dependency loops...
|
||||
// XXX a loop error should be raised only when one of the loop elements
|
||||
// is encountered during the linearisation process...
|
||||
// XXX this might get affected by disabled...
|
||||
// XXX should we report this here???
|
||||
loops.length > 0
|
||||
&& loops
|
||||
.forEach(function(loop){
|
||||
console.warn('feature loop detected:\n\t' + loop.join('\n\t\t-> ')) })
|
||||
//*/
|
||||
|
||||
// combine the lists...
|
||||
// XXX
|
||||
var list = []
|
||||
expand(['depends', 'suggested'], lst, {},
|
||||
{
|
||||
list: list,
|
||||
disabled: disabled,
|
||||
missing: missing,
|
||||
exclusive: exclusive,
|
||||
})
|
||||
|
||||
// XXX
|
||||
return {
|
||||
list: list,
|
||||
features: features,
|
||||
suggested: suggested,
|
||||
exclusive: exclusive,
|
||||
disabled: disabled,
|
||||
missing: missing,
|
||||
loops: loops,
|
||||
disable_loops: disable_loops,
|
||||
}
|
||||
},
|
||||
|
||||
// C3 implementation...
|
||||
//
|
||||
// NOTE: this is different from the pure C3 in that we do not care
|
||||
// about the dependency order and sort the dependency list...
|
||||
// NOTE: this returns the list in reverse order, i.e. from the input
|
||||
// feature and up the dependency list
|
||||
//
|
||||
// Problems:
|
||||
// - too picky about candidates -- errors in cases that can be solved by re-ordering...
|
||||
// - priority is less significant than level order
|
||||
// Ex:
|
||||
// ImageGridFeatures._buildFeatureListC3(['ui', 'location'])
|
||||
// -> ["location", "introspection", "lifecycle", "workspace", "base", "ui"]
|
||||
// ImageGridFeatures._buildFeatureListC3(['location', 'ui'])
|
||||
// -> ["introspection", "lifecycle", "workspace", "base", "ui", "location"]
|
||||
_buildFeatureListC3: function(lst, filter){
|
||||
lst = (lst == null || lst == '*') ? this.features : lst
|
||||
lst = lst.constructor !== Array ? [lst] : lst
|
||||
|
||||
var that = this
|
||||
|
||||
var expand = function(lst, data, _seen){
|
||||
_seen = _seen || []
|
||||
data = data || {}
|
||||
|
||||
/*/ user filter...
|
||||
lst = filter ?
|
||||
lst.filter(function(n){ return filter.call(that, n) })
|
||||
: lst
|
||||
//*/
|
||||
|
||||
// disabled filter...
|
||||
// XXX
|
||||
|
||||
lst = lst
|
||||
// normalize the list -- remove non-features and resolve aliases...
|
||||
.map(function(n){
|
||||
var f = that[n]
|
||||
// resolve exclusive tags...
|
||||
while(f == null && data.exclusive && n in data.exclusive){
|
||||
var n = data.exclusive[n][0]
|
||||
f = that[n]
|
||||
}
|
||||
// feature not defined or is not a feature...
|
||||
if(f == null){
|
||||
data.missing
|
||||
&& data.missing.indexOf(n) < 0
|
||||
&& data.missing.push(n)
|
||||
return false
|
||||
}
|
||||
return n
|
||||
})
|
||||
.filter(function(e){ return e })
|
||||
|
||||
// sort the list...
|
||||
// build the sort table: [ <priority>, <index>, <elem> ]
|
||||
.map(function(e, i){
|
||||
return [ that[e].getPriority ? that[e].getPriority() : i, i, e ] })
|
||||
// sort by priority or index -- min -> max
|
||||
// NOTE: this will maintain the order of similar priority actions...
|
||||
// NOTE: JS compares lists as strings so we have to compare
|
||||
// the list manually...
|
||||
.sort(function(a, b){ return a[0] - b[0] || a[1] - b[1] })
|
||||
// cleanup -- drop the sort table...
|
||||
.map(function(e){ return e[2] })
|
||||
|
||||
// traverse...
|
||||
.map(function(e){
|
||||
// detect loops...
|
||||
if(_seen.indexOf(e) >= 0){
|
||||
var loop = _seen.slice(_seen.indexOf(e)).concat([e])
|
||||
console.warn('LOOP:', loop)
|
||||
//data.loops
|
||||
// && data.loops.push(loop)
|
||||
return
|
||||
}
|
||||
|
||||
var L = that[e].depends || []
|
||||
|
||||
// traverse down...
|
||||
//return [e].concat(expand(L.slice(), data, _seen.concat([e])))
|
||||
return L.length > 0 ?
|
||||
[e].concat(expand(L.slice(), data, _seen.concat([e])))
|
||||
: [e]
|
||||
})
|
||||
// XXX for some reason this breaks C3...
|
||||
//.concat([lst])
|
||||
|
||||
// merge...
|
||||
var res = []
|
||||
var cur = null
|
||||
while(lst.length > 0){
|
||||
cur = lst
|
||||
// get the heads...
|
||||
.map(function(e){ return e && e[0] })
|
||||
// check if the head is in any of the tails...
|
||||
.filter(function(h){
|
||||
return h && lst
|
||||
.filter(function(e){ return e.slice(1).indexOf(h) >= 0 }).length == 0 })
|
||||
.shift()
|
||||
|
||||
// XXX no candidate found...
|
||||
if(cur == null){
|
||||
console.error('no candidate found!!')
|
||||
break
|
||||
}
|
||||
|
||||
// cleanup...
|
||||
lst = lst
|
||||
.map(function(e){ return e && e.filter(function(f){ return f != cur }) })
|
||||
.filter(function(e){ return e && e.length > 0 })
|
||||
|
||||
cur
|
||||
&& res.push(cur)
|
||||
cur = null
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
return expand(lst)
|
||||
},
|
||||
|
||||
|
||||
// Build list of features in an appropriate order to load...
|
||||
//
|
||||
// Algorithm:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user