<commit_before>/**
 * AliasResolvers provide logic used for expanding and resolving feature identifiers using more than one mechanism (if required).
 *
 * A feature identifier is an object key with optionally a 'flags' (array) property and other properties.  The key is the string identifying a feature (or group of features), 'flags' is an array containing any flags that alter the way that the feature should be polyfilled (and therefore also need to apply to any aliased polyfills), while all other properties are preserved only on the parent.
 *
 *  e.g: { "modernizr:es5": { flags: ["always"], polyfillVariant: "default" } }
 */
var AliasResolver = function(resolvers) {

	/** An array of functions that map a feature name and properties identifier (e.g. an alias)
	 * to a promise of a set of alternate string identifiers (e.g. expanded names the alias refers to)
	 *
	 * The key point is that each is invoked in sequence with the result of
	 * the previous resolver function as an argument.
	 */
	this.polyfillNameResolverFunctions = resolvers;
};

/**
 * Resolve an array of polyfill identifiers by iteratively invoking the
 * resolver functions on each element.
 *
 * @param {array} featureSet The feature identifiers to resolve.
 * @returns {array} A list of resolved feature identifiers.
 */
AliasResolver.prototype.resolve = function(featureSet) {
	return this.polyfillNameResolverFunctions.reduce(function(resolvingSetPromise, resolverFunction) {
		return resolvingSetPromise.then(function(set) {
			return applyResolverToIdentifiers(set, resolverFunction);
		});
	}, Promise.resolve(featureSet));
};

module.exports = AliasResolver;



/**
 * Run a name resolver function over each polyfill identifier in an array,
 * remove duplicates after the resolution and keep track of aliases and
 * flags.
 *
 * @param {array}    featureSet           A list of feature identifier objects to expand.
 * @param {Function} nameResolverFunction The function to use in the resolution process. Must take a string name as a single arg and return an array of names to which the specified name maps, or undefined if it has no mapping for that name.
 *
 * @return {array} An expanded list of polyfill identifiers
 */
function applyResolverToIdentifiers(featureSet, nameResolverFunction) {
	var _ = require('lodash');

	return Promise.all(Object.keys(featureSet).map(function(featureName) {
		return Promise.resolve(nameResolverFunction(featureName)).then(function(resultItems) {
			var feature = featureSet[featureName];
			if (!Array.isArray(resultItems)) return true;

			resultItems.forEach(function(newName) {
				if (newName !== featureName) {
					var result = _.extend({}, feature, {
						aliasOf: _.uniq([featureName].concat(feature.aliasOf || [])),
						flags: feature.flags || []
					});

					if (!featureSet[newName]) {
						featureSet[newName] = result;
					} else {
						['flags', 'aliasOf'].forEach(function mergeProperties(prop) {
							featureSet[newName][prop] = (prop in featureSet[newName]) ? _.uniq(featureSet[newName][prop].concat(result[prop])) : result[prop];
						});
					}
				}
			});

			if (resultItems.indexOf(featureName) === -1) delete featureSet[featureName];
		});
	})).then(function() {
		return featureSet;
	});
}
<commit_msg>Define feature as early as possible<commit_after>/**
 * AliasResolvers provide logic used for expanding and resolving feature identifiers using more than one mechanism (if required).
 *
 * A feature identifier is an object key with optionally a 'flags' (array) property and other properties.  The key is the string identifying a feature (or group of features), 'flags' is an array containing any flags that alter the way that the feature should be polyfilled (and therefore also need to apply to any aliased polyfills), while all other properties are preserved only on the parent.
 *
 *  e.g: { "modernizr:es5": { flags: ["always"], polyfillVariant: "default" } }
 */
var AliasResolver = function(resolvers) {

	/** An array of functions that map a feature name and properties identifier (e.g. an alias)
	 * to a promise of a set of alternate string identifiers (e.g. expanded names the alias refers to)
	 *
	 * The key point is that each is invoked in sequence with the result of
	 * the previous resolver function as an argument.
	 */
	this.polyfillNameResolverFunctions = resolvers;
};

/**
 * Resolve an array of polyfill identifiers by iteratively invoking the
 * resolver functions on each element.
 *
 * @param {array} featureSet The feature identifiers to resolve.
 * @returns {array} A list of resolved feature identifiers.
 */
AliasResolver.prototype.resolve = function(featureSet) {
	return this.polyfillNameResolverFunctions.reduce(function(resolvingSetPromise, resolverFunction) {
		return resolvingSetPromise.then(function(set) {
			return applyResolverToIdentifiers(set, resolverFunction);
		});
	}, Promise.resolve(featureSet));
};

module.exports = AliasResolver;



/**
 * Run a name resolver function over each polyfill identifier in an array,
 * remove duplicates after the resolution and keep track of aliases and
 * flags.
 *
 * @param {array}    featureSet           A list of feature identifier objects to expand.
 * @param {Function} nameResolverFunction The function to use in the resolution process. Must take a string name as a single arg and return an array of names to which the specified name maps, or undefined if it has no mapping for that name.
 *
 * @return {array} An expanded list of polyfill identifiers
 */
function applyResolverToIdentifiers(featureSet, nameResolverFunction) {
	var _ = require('lodash');

	return Promise.all(Object.keys(featureSet).map(function(featureName) {
		var feature = featureSet[featureName];
		return Promise.resolve(nameResolverFunction(featureName)).then(function(resultItems) {

			// Alias resolver does not know this feature - do not modify feature set
			if (!Array.isArray(resultItems)) return true;

			resultItems.forEach(function(newName) {
				if (newName !== featureName) {
					var result = _.extend({}, feature, {
						aliasOf: _.uniq([featureName].concat(feature.aliasOf || [])),
						flags: feature.flags || []
					});

					if (!featureSet[newName]) {
						featureSet[newName] = result;
					} else {
						['flags', 'aliasOf'].forEach(function mergeProperties(prop) {
							featureSet[newName][prop] = (prop in featureSet[newName]) ? _.uniq(featureSet[newName][prop].concat(result[prop])) : result[prop];
						});
					}
				}
			});

			// Alias resolver returned a list that did not include the original name, so remove that from the feature set
			if (resultItems.indexOf(featureName) === -1) delete featureSet[featureName];
		});
	})).then(function() {
		return featureSet;
	});
}

{'fraction_non_alphanumeric': 0.09876909387512976, 'fraction_numerical': 0.0005932077710218003, 'mean_word_length': 4.2564302416212, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1821235', 'n_tokens_mistral': 1970, 'n_tokens_neox': 1762, 'n_words': 688}