mirror of
				https://github.com/flynx/features.js.git
				synced 2025-10-30 19:00:10 +00:00 
			
		
		
		
	more cleanup...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
		
							parent
							
								
									270bec2a52
								
							
						
					
					
						commit
						6a240ef261
					
				
							
								
								
									
										484
									
								
								features.js
									
									
									
									
									
								
							
							
						
						
									
										484
									
								
								features.js
									
									
									
									
									
								
							| @ -271,486 +271,6 @@ var FeatureSetProto = { | |||||||
| 					&& that[e] instanceof Feature })  | 					&& that[e] instanceof Feature })  | ||||||
| 	}, | 	}, | ||||||
| 
 | 
 | ||||||
| 	// Build list of features...
 |  | ||||||
| 	//
 |  | ||||||
| 	//	Build list of all features for an empty object...
 |  | ||||||
| 	//	.buildFeatureList()
 |  | ||||||
| 	//	.buildFeatureList({})
 |  | ||||||
| 	//	.buildFeatureList({}, '*')
 |  | ||||||
| 	//		-> data
 |  | ||||||
| 	//
 |  | ||||||
| 	//	Build a list of features for a specific root feature and object...
 |  | ||||||
| 	//	.buildFeatureList(object, feature)
 |  | ||||||
| 	//		-> data
 |  | ||||||
| 	//
 |  | ||||||
| 	//	Build a list of features for a specific set of root features and object...
 |  | ||||||
| 	//	.buildFeatureList(object, [feature, ..])
 |  | ||||||
| 	//		-> data
 |  | ||||||
| 	//		NOTE: to disable a feature and all of it's dependants prefix
 |  | ||||||
| 	//			it's tag with '-' in the list.
 |  | ||||||
| 	//			e.g. including 'some-feature' will include the feature
 |  | ||||||
| 	//			and its dependants while '-some-feature' will remove
 |  | ||||||
| 	//			it and it's dependants.
 |  | ||||||
| 	//
 |  | ||||||
| 	//
 |  | ||||||
| 	// This will build from user input a loadable list of features taking 
 |  | ||||||
| 	// into account feature dependencies, priorities and suggestions.
 |  | ||||||
| 	//
 |  | ||||||
| 	// Roughly this is done in this order starting with the given features:
 |  | ||||||
| 	// 	- include all dependencies (recursively)
 |  | ||||||
| 	// 	- include all suggested features (recursively)
 |  | ||||||
| 	// 	- sort features by priority
 |  | ||||||
| 	// 	- sort features by dependency
 |  | ||||||
| 	// 	- check for feature applicability
 |  | ||||||
| 	// 	- remove non-applicable features and all dependants (recursively)
 |  | ||||||
| 	// 	- remove disabled features and all dependants (recursively)
 |  | ||||||
| 	// 	- check and resolve exclusivity conflicts (XXX needs revision)
 |  | ||||||
| 	// 	- check for missing features and dependencies
 |  | ||||||
| 	//
 |  | ||||||
| 	//
 |  | ||||||
| 	// Return format:
 |  | ||||||
| 	// 	{
 |  | ||||||
| 	// 		// list of input features...
 |  | ||||||
| 	// 		input: [ .. ],
 |  | ||||||
| 	//
 |  | ||||||
| 	//		// features in correct load order...
 |  | ||||||
| 	//		features: [ .. ],
 |  | ||||||
| 	//
 |  | ||||||
| 	//		// features disabled explicitly and their dependants...
 |  | ||||||
| 	//		disabled: [ .. ],
 |  | ||||||
| 	//		// unapplicable features and their dependants...
 |  | ||||||
| 	//		unapplicable: [ .. ],
 |  | ||||||
| 	//
 |  | ||||||
| 	//		// features removed due to exclusivity conflict...
 |  | ||||||
| 	//		excluded: [ .. ],
 |  | ||||||
| 	//
 |  | ||||||
| 	//		missing: {
 |  | ||||||
| 	//			// features explicitly given by user but missing...
 |  | ||||||
| 	//			USER: [ .. ],
 |  | ||||||
| 	//			// missing <feature> dependencies...
 |  | ||||||
| 	//			<feature>: [ .. ],
 |  | ||||||
| 	//			...
 |  | ||||||
| 	//		},
 |  | ||||||
| 	//		conflicts: {
 |  | ||||||
| 	//			XXX
 |  | ||||||
| 	//		},
 |  | ||||||
| 	// 	}
 |  | ||||||
| 	//
 |  | ||||||
| 	//
 |  | ||||||
| 	// NOTE: obj (action set) here is used only for applicability testing...
 |  | ||||||
| 	// NOTE: some feature applicability checks (.isApplicable(..)) may 
 |  | ||||||
| 	// 		require a real action set, thus for correct operation one 
 |  | ||||||
| 	// 		should be provided.
 |  | ||||||
| 	// NOTE: all feature sorting is done maintaining relative feature order
 |  | ||||||
| 	// 		when possible...
 |  | ||||||
| 	// NOTE: meta-features are not included in the list as they do not 
 |  | ||||||
| 	// 		need to be setup.
 |  | ||||||
| 	// 		...this is because they are not Feature objects.
 |  | ||||||
| 	//
 |  | ||||||
| 	// XXX should meta-features be MetaFeature objects???
 |  | ||||||
| 	// XXX not sure about handling excluded features (see inside)...
 |  | ||||||
| 	// XXX add dependency loops to .conflicts...
 |  | ||||||
| 	// XXX might be a good idea to check dependency loops on feature 
 |  | ||||||
| 	// 		construction, too... (???)
 |  | ||||||
| 	/* |  | ||||||
| 	buildFeatureList: function(obj, lst){ |  | ||||||
| 		var that = this |  | ||||||
| 		obj = obj || {} |  | ||||||
| 
 |  | ||||||
| 		lst = (lst == null || lst == '*') ? this.features : lst |  | ||||||
| 		lst = lst.constructor !== Array ? [lst] : lst |  | ||||||
| 
 |  | ||||||
| 		var input = lst.slice() |  | ||||||
| 		var disabled = []  |  | ||||||
| 		var excluded = [] |  | ||||||
| 		var unapplicable = [] |  | ||||||
| 		var missing = {} |  | ||||||
| 		var conflicts = {} |  | ||||||
| 
 |  | ||||||
| 		var exclusive = {} |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 		// reverse dependency cache... 
 |  | ||||||
| 		var dependants = {} |  | ||||||
| 
 |  | ||||||
| 		// build dependency list...
 |  | ||||||
| 		var _buildDepList = function(n, seen){ |  | ||||||
| 			seen = seen || [] |  | ||||||
| 			return seen.indexOf(n) >= 0 ? [] |  | ||||||
| 				: seen.push(n) && dependants[n] ? [] |  | ||||||
| 					.concat.apply( |  | ||||||
| 						dependants[n],  |  | ||||||
| 						dependants[n] |  | ||||||
| 							.map(function(n){ return _buildDepList(n, seen) })) |  | ||||||
| 				: [] |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 		// missing stage 1: check if all user included features exist...
 |  | ||||||
| 		// NOTE: we'll ignore missing disabled features too...
 |  | ||||||
| 		lst.forEach(function(n){ |  | ||||||
| 			if(!that[n] && n[0] != '-'){ |  | ||||||
| 				var m = missing['USER'] = missing['USER'] || [] |  | ||||||
| 				m.push(n) |  | ||||||
| 			} |  | ||||||
| 		}) |  | ||||||
| 
 |  | ||||||
| 		// include all dependencies...
 |  | ||||||
| 		//
 |  | ||||||
| 		// NOTE: this should never fall into an infinite loop as we do 
 |  | ||||||
| 		// 		not include feature already seen...
 |  | ||||||
| 		// 		...unless there is an infinite number of features, but 
 |  | ||||||
| 		// 		I'll try to avoid that big a feature creep.
 |  | ||||||
| 		// XXX should we check for dependency loops here???
 |  | ||||||
| 		// 		...this would have been simple if this was a recursion
 |  | ||||||
| 		// 		(just check if cur is in path), but here it is not 
 |  | ||||||
| 		// 		trivial...
 |  | ||||||
| 		for(var i=0; i < lst.length; i++){ |  | ||||||
| 			var k = lst[i] |  | ||||||
| 
 |  | ||||||
| 			// skip disabled or missing features....
 |  | ||||||
| 			if(k[0] == '-' || !that[k]){ |  | ||||||
| 				continue |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			var deps = that[k].depends || [] |  | ||||||
| 			var refs = that[k].suggested || [] |  | ||||||
| 			var excl = that[k].exclusive || [] |  | ||||||
| 
 |  | ||||||
| 			deps.forEach(function(n){ |  | ||||||
| 				// expand lst with dependencies....
 |  | ||||||
| 				lst.indexOf(n) < 0 && lst.push(n) |  | ||||||
| 
 |  | ||||||
| 				// build reverse dependency index...
 |  | ||||||
| 				var d = dependants[n] = dependants[n] || [] |  | ||||||
| 				d.indexOf(k) < 0 && d.push(k) |  | ||||||
| 			}) |  | ||||||
| 
 |  | ||||||
| 			// expand lst with suggenstions....
 |  | ||||||
| 			refs.forEach(function(n){ |  | ||||||
| 				lst.indexOf(n) < 0 && lst.push(n) |  | ||||||
| 			}) |  | ||||||
| 
 |  | ||||||
| 			// build exclusive table...
 |  | ||||||
| 			excl.forEach(function(n){ |  | ||||||
| 				var l = exclusive[n] = exclusive[n] || [] |  | ||||||
| 				l.indexOf(k) < 0 && l.push(k) |  | ||||||
| 			}) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		// sort features by priority or position...
 |  | ||||||
| 		lst = lst |  | ||||||
| 			// remove undefined and non-features...
 |  | ||||||
| 			.filter(function(n){  |  | ||||||
| 				// feature disabled -> record and skip...
 |  | ||||||
| 				if(n[0] == '-'){ |  | ||||||
| 					disabled.push(n.slice(1)) |  | ||||||
| 					return false |  | ||||||
| 				} |  | ||||||
| 				var f = that[n] |  | ||||||
| 				// feature not defined or is not a feature...
 |  | ||||||
| 				if(f == null || !(f instanceof Feature)){ |  | ||||||
| 					return false |  | ||||||
| 				} |  | ||||||
| 				// check applicability...
 |  | ||||||
| 				if(f.isApplicable && !f.isApplicable.call(that, obj)){ |  | ||||||
| 					unapplicable.push(n) |  | ||||||
| 					return false |  | ||||||
| 				} |  | ||||||
| 				return true |  | ||||||
| 			}) |  | ||||||
| 			// remove disabled...
 |  | ||||||
| 			.filter(function(e){ return disabled.indexOf(e) < 0 }) |  | ||||||
| 			// build the sort table: [ <priority>, <index>, <elem> ]
 |  | ||||||
| 			.map(function(e, i){ return [ that[e].getPriority(), i, e ] }) |  | ||||||
| 			// sort by priority then 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] }) |  | ||||||
| 
 |  | ||||||
| 		// remove dependants on not applicable and on disabled...
 |  | ||||||
| 		var _unapplicable = unapplicable.slice() |  | ||||||
| 		var _disabled = disabled.slice() |  | ||||||
| 		// build the full lists of features to remove...
 |  | ||||||
| 		_unapplicable |  | ||||||
| 			.forEach(function(n){ _unapplicable = _unapplicable.concat(_buildDepList(n)) }) |  | ||||||
| 		_disabled |  | ||||||
| 			.forEach(function(n){ _disabled = _disabled.concat(_buildDepList(n)) }) |  | ||||||
| 		// clear...
 |  | ||||||
| 		// NOTE: in case of intersection disabled has priority...
 |  | ||||||
| 		lst = lst |  | ||||||
| 			.filter(function(n){ |  | ||||||
| 				return _disabled.indexOf(n) >= 0 ? |  | ||||||
| 						disabled.push(n) && false |  | ||||||
| 					: _unapplicable.indexOf(n) >= 0 ? |  | ||||||
| 						unapplicable.push(n) && false |  | ||||||
| 					: true }) |  | ||||||
| 
 |  | ||||||
| 		// missing stage 2: dependencies...
 |  | ||||||
| 		lst.forEach(function(k){ |  | ||||||
| 			(that[k].depends || []).forEach(function(d){ |  | ||||||
| 				// NOTE: we do not need to check disabled or unapplicable
 |  | ||||||
| 				// 		here as if the feature depended on dropped feature
 |  | ||||||
| 				// 		it would have been already dropped too...
 |  | ||||||
| 				// NOTE: we skip exclusive tags as they will get replaced 
 |  | ||||||
| 				// 		with actual feature tags later...
 |  | ||||||
| 				// 		if a tag is exclusive then at least one feature 
 |  | ||||||
| 				// 		with it is present...
 |  | ||||||
| 				if(!that[d] && !exclusive[d] && d[0] != '-'){ |  | ||||||
| 					var m = missing[k] = missing[k] || [] |  | ||||||
| 					m.push(d) |  | ||||||
| 				} |  | ||||||
| 			}) |  | ||||||
| 		}) |  | ||||||
| 
 |  | ||||||
| 		// check exclusive -> excluded...
 |  | ||||||
| 		//
 |  | ||||||
| 		// NOTE: this is the right spot for this, just after priority 
 |  | ||||||
| 		// 		sorting and clearing but before dependency sorting.
 |  | ||||||
| 		//
 |  | ||||||
| 		// XXX do we need to clear dependencies pulled by excluded features???
 |  | ||||||
| 		// 		ways to go:
 |  | ||||||
| 		// 			- drop excluded and continue (current state)
 |  | ||||||
| 		// 			- disable excluded, add to original input and rebuild
 |  | ||||||
| 		// 			- err and let the user decide
 |  | ||||||
| 		var _exclusive = [] |  | ||||||
| 		lst = lst.filter(function(n){ |  | ||||||
| 			var e = that[n] |  | ||||||
| 
 |  | ||||||
| 			// keep non-exclusive stuff...
 |  | ||||||
| 			if(!e || e.exclusive == null){ |  | ||||||
| 				return true |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			// count the number of exclusive features already present...
 |  | ||||||
| 			var res = e.exclusive |  | ||||||
| 				.filter(function(n){ |  | ||||||
| 					if(_exclusive.indexOf(n) < 0){ |  | ||||||
| 						_exclusive.push(n) |  | ||||||
| 						return false |  | ||||||
| 					} |  | ||||||
| 					return true |  | ||||||
| 				}) |  | ||||||
| 				.length == 0 |  | ||||||
| 
 |  | ||||||
| 			!res  |  | ||||||
| 				&& excluded.push(n) |  | ||||||
| 				// warn the user...
 |  | ||||||
| 				// XXX not sure if this is the right place for this...
 |  | ||||||
| 				&& console.warn( |  | ||||||
| 					'Excluding unaplicable:', n, '(reccomended to exclude manually)') |  | ||||||
| 
 |  | ||||||
| 			return res |  | ||||||
| 		}) |  | ||||||
| 
 |  | ||||||
| 		// sort by dependency...
 |  | ||||||
| 		var l = lst.length |  | ||||||
| 		// get maximum possible length...
 |  | ||||||
| 		// ...the worst case length appears to be (for full reversal):
 |  | ||||||
| 		// 		S(2*(n-1) + 1)
 |  | ||||||
| 		// 			S = n => n > 0 ? 2*(n-1)+1 + S(n-1) : 0
 |  | ||||||
| 		// 			S = n => n > 0 ? 2*n-1 + S(n-1) : 0
 |  | ||||||
| 		//
 |  | ||||||
| 		// 		2 * S(n) - n
 |  | ||||||
| 		// 			S = n => n > 0 ? n + S(n-1) : 0
 |  | ||||||
| 		// 			f = n => 2 * S(n) - n
 |  | ||||||
| 		//
 |  | ||||||
| 		//		N^2 + C
 |  | ||||||
| 		//			S = n => n * n
 |  | ||||||
| 		//
 |  | ||||||
| 		// NOTE: this is the brute force way to check if we have a 
 |  | ||||||
| 		// 		dependency loop, need something faster...
 |  | ||||||
| 		//
 |  | ||||||
| 		// XXX is O(n^2) good enough worst case here?
 |  | ||||||
| 		// 		...at this point I think it is acceptable as we'll not 
 |  | ||||||
| 		// 		expect dependency graphs too saturated, and the average 
 |  | ||||||
| 		// 		complexity is far better...
 |  | ||||||
| 		var max = l * l |  | ||||||
| 
 |  | ||||||
| 		var moved = [] |  | ||||||
| 		var chain = [] |  | ||||||
| 		var chains = [] |  | ||||||
| 
 |  | ||||||
| 		for(var i=0; i < lst.length; i++){ |  | ||||||
| 			var k = lst[i] |  | ||||||
| 			var depends = (that[k].depends || []).slice() |  | ||||||
| 
 |  | ||||||
| 			// replace dependencies that are exclusive tags...
 |  | ||||||
| 			Object.keys(exclusive).forEach(function(e){ |  | ||||||
| 				var i = depends.indexOf(e) |  | ||||||
| 				i >= 0  |  | ||||||
| 					&& exclusive[e].forEach(function(f){ |  | ||||||
| 						if(lst.indexOf(f) >= 0){ |  | ||||||
| 							//console.log('EXCL->DEP', e, f)
 |  | ||||||
| 							depends[i] = f |  | ||||||
| 						} |  | ||||||
| 					}) |  | ||||||
| 			}) |  | ||||||
| 
 |  | ||||||
| 			// list of dependencies to move...
 |  | ||||||
| 			var move = [] |  | ||||||
| 
 |  | ||||||
| 			lst |  | ||||||
| 				.slice(0, i) |  | ||||||
| 				.forEach(function(n, j){ |  | ||||||
| 					// if n is a dependency of k, prepare to move...
 |  | ||||||
| 					if(depends.indexOf(n) >= 0){ |  | ||||||
| 						delete lst[j]  |  | ||||||
| 						move.push(n) |  | ||||||
| 					} |  | ||||||
| 				}) |  | ||||||
| 
 |  | ||||||
| 			// move the dependencies after k...
 |  | ||||||
| 			// NOTE: this will keep the order within the dependencies...
 |  | ||||||
| 			if(move.length > 0){ |  | ||||||
| 				lst.splice.apply(lst, [i+1, 0].concat(move)) |  | ||||||
| 
 |  | ||||||
| 				// unseen feature -> new chain...
 |  | ||||||
| 				if(moved.indexOf(k) < 0){ |  | ||||||
| 					chain = [] |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				moved.push(k) |  | ||||||
| 
 |  | ||||||
| 				// chain completed -> check and store...
 |  | ||||||
| 				if(chain.indexOf(k) >= 0){ |  | ||||||
| 					var c = JSON.stringify(chain) |  | ||||||
| 					// repeating chain -> loop or order conflict detected...
 |  | ||||||
| 					if(chains.indexOf(c) >= 0){ |  | ||||||
| 						// format the graph... 
 |  | ||||||
| 						// XXX this catches strange things and not only loops...
 |  | ||||||
| 						// 		...at this point I can't repeat this error, see
 |  | ||||||
| 						// 		ImageGrid.Viewer in nwjs load console output...
 |  | ||||||
| 						var graph = [] |  | ||||||
| 						chain.forEach(function(k){  |  | ||||||
| 							graph = graph |  | ||||||
| 								.concat((that[k].depends || []) |  | ||||||
| 									.filter(function(e){  |  | ||||||
| 										return chain.indexOf(e) >= 0 }) |  | ||||||
| 									.map(function(e){  |  | ||||||
| 										return `${k}  \t-> ${e}` })) }) |  | ||||||
| 						console.error('Feature cyclic dependency or order conflict:\n\t'  |  | ||||||
| 							+ graph.join('\n\t')) |  | ||||||
| 
 |  | ||||||
| 						// XXX should we give up completely (break) here 
 |  | ||||||
| 						// 		or move on and find new loops???
 |  | ||||||
| 						break |  | ||||||
| 					} |  | ||||||
| 					chains.push(c) |  | ||||||
| 
 |  | ||||||
| 				// add item to chain...
 |  | ||||||
| 				} else { |  | ||||||
| 					chain.push(k) |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			// check for cyclic dependencies...
 |  | ||||||
| 			// XXX loop signs:
 |  | ||||||
| 			// 		- the tail length stops changing -- we stop progressing to list end
 |  | ||||||
| 			// 		- the loop is packed
 |  | ||||||
| 			// 			- each element includes a set of dependencies
 |  | ||||||
| 			// 			- this set is of the same length when at a specific element
 |  | ||||||
| 			// 		- we only shift the same set of N elements over N iterations
 |  | ||||||
| 			// 		- ...
 |  | ||||||
| 			if(lst.length >= max){ |  | ||||||
| 				// XXX get the actual cycle...
 |  | ||||||
| 				console.error('Feature cyclic dependency:', chain) |  | ||||||
| 				break |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		// cleanup after sort...
 |  | ||||||
| 		lst = lst |  | ||||||
| 			// remove undefined and non-features...
 |  | ||||||
| 			.filter(function(e){  |  | ||||||
| 				return that[e] != null && that[e] instanceof Feature }) |  | ||||||
| 			.reverse() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 		return { |  | ||||||
| 			input: input, |  | ||||||
| 
 |  | ||||||
| 			features: lst, |  | ||||||
| 
 |  | ||||||
| 			disabled: disabled, |  | ||||||
| 			unapplicable: unapplicable, |  | ||||||
| 			excluded: excluded, |  | ||||||
| 
 |  | ||||||
| 			missing: missing, |  | ||||||
| 			conflicts: conflicts, |  | ||||||
| 		} |  | ||||||
| 	}, |  | ||||||
| 	setup: function(obj, lst){ |  | ||||||
| 		// if no explicit object is given, just the list...
 |  | ||||||
| 		if(lst == null){ |  | ||||||
| 			lst = obj |  | ||||||
| 			obj = null |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		obj = obj || (this.__actions__ || actions.Actions)() |  | ||||||
| 
 |  | ||||||
| 		lst = lst.constructor !== Array ? [lst] : lst |  | ||||||
| 		var features = this.buildFeatureList(obj, lst) |  | ||||||
| 		lst = features.features |  | ||||||
| 
 |  | ||||||
| 		// check for conflicts...
 |  | ||||||
| 		if(Object.keys(features.conflicts).length != 0 |  | ||||||
| 				|| Object.keys(features.missing).length != 0){ |  | ||||||
| 			var m = features.missing |  | ||||||
| 			var c = features.conflicts |  | ||||||
| 
 |  | ||||||
| 			// build a report...
 |  | ||||||
| 			var report = [] |  | ||||||
| 
 |  | ||||||
| 			// missing deps...
 |  | ||||||
| 			Object.keys(m).forEach(function(k){ |  | ||||||
| 				report.push(k + ': requires following missing features:\n' |  | ||||||
| 					+'          ' + m[k].join(', ')) |  | ||||||
| 			}) |  | ||||||
| 			report.push('\n') |  | ||||||
| 
 |  | ||||||
| 			// conflicts...
 |  | ||||||
| 			Object.keys(c).forEach(function(k){ |  | ||||||
| 				report.push(k + ': must setup after:\n          ' + c[k].join(', ')) |  | ||||||
| 			}) |  | ||||||
| 
 |  | ||||||
| 			// break...
 |  | ||||||
| 			throw 'Feature dependency error:\n    ' + report.join('\n    ')  |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		// report excluded features...
 |  | ||||||
| 		if(this.__verbose__ && features.excluded.length > 0){ |  | ||||||
| 			console.warn('Excluded features due to exclusivity conflict:',  |  | ||||||
| 					features.excluded.join(', ')) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		// report unapplicable features...
 |  | ||||||
| 		if(this.__verbose__ && features.unapplicable.length > 0){ |  | ||||||
| 			console.log('Features not applicable in current context:',  |  | ||||||
| 					features.unapplicable.join(', ')) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		// do the setup...
 |  | ||||||
| 		var that = this |  | ||||||
| 		var setup = FeatureProto.setup |  | ||||||
| 		lst.forEach(function(n){ |  | ||||||
| 			// setup...
 |  | ||||||
| 			if(that[n] != null){ |  | ||||||
| 				this.__verbose__ && console.log('Setting up feature:', n) |  | ||||||
| 				setup.call(that[n], obj) |  | ||||||
| 			} |  | ||||||
| 		}) |  | ||||||
| 
 |  | ||||||
| 		// XXX should we extend this if it already was in the object???
 |  | ||||||
| 		obj.features = features |  | ||||||
| 
 |  | ||||||
| 		return obj |  | ||||||
| 	}, |  | ||||||
| 	//*/
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	// Build list of features in load order...
 | 	// Build list of features in load order...
 | ||||||
| 	//
 | 	//
 | ||||||
| 	// 	.buildFeatureList()
 | 	// 	.buildFeatureList()
 | ||||||
| @ -1111,7 +631,9 @@ var FeatureSetProto = { | |||||||
| 		var excluded = [] | 		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 BUG: for some reason this does not behave 
 | ||||||
|  | 				// 		deterministically and in some cases the order 
 | ||||||
|  | 				// 		of the list is not stable...
 | ||||||
| 				excluded = excluded.concat(conflicts[group].slice(1))}) | 				excluded = excluded.concat(conflicts[group].slice(1))}) | ||||||
| 		disabled = disabled.concat(excluded) | 		disabled = disabled.concat(excluded) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "ig-features", |   "name": "ig-features", | ||||||
|   "version": "3.1.2", |   "version": "3.1.3", | ||||||
|   "description": "", |   "description": "", | ||||||
|   "main": "features.js", |   "main": "features.js", | ||||||
|   "scripts": { |   "scripts": { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user