<commit_before>'use strict';

/**
 * Module dependencies.
 */
var fs          = require('fs');
var path        = require('path');
var util        = require('util');
var postcss     = require('postcss');
var lodash      = require('lodash');
var async       = require('async');
var Q           = require('q');
var spritesmith = require('spritesmith');
var mkdirp      = require('mkdirp');

/**
 * Constants.
 *
 * @type {String}
 */
var GROUP_DELIMITER   = '.';
var GROUP_MASK        = '*';
var BACKGROUND        = 'background';
var BACKGROUND_IMAGE  = 'background-image';
var BACKGROUND_COLOR  = 'background-color';
var BACKGROUND_REPEAT = 'background-repeat';
var BACKGROUND_SIZE   = 'background-size';

/**
 * Defaults.
 *
 * @type {Object}
 */
var defaults = {
	stylesheetPath  : './',
  imagePath       : '.',
	spritePath      : './sprite.png',
	skipPrefix      : false,
	outputDimensions: false,
	filterBy        : [],
	groupBy         : [],
	retina          : false,
	verbose         : false,

	// spritesmith options
	engine        : 'pixelsmith',
	algorithm     : 'binary-tree',
	padding       : 0,
	engineOpts    : {},
	exportOpts    : {}
};

/**
 * Register the PostCSS plugin.
 */
module.exports = postcss.plugin('postcss-sprites', plugin);

/**
 * PostCSS plugin definition.
 *
 * @param  {Object}  opts
 * @return {Function}
 */
function plugin(opts) {
	// Extend default options.
	var options = lodash.merge({}, defaults, opts || {});

	// Prepare filterBy functions.
	setupFilterBy(options);

	// Prepare groupBy functions.
	setupGroupBy(options);

	// Plugin initializer.
	return function(css) {
		return Q
			.all([getImages(css, options), options])
			.spread(applyFilterBy)
			.spread(applyGroupBy)
			.spread(function(images, opts){
				return setTokens(images, opts, css);
			})
			.spread(runSpriteSmith)
			.spread(saveSprites)
			.spread(mapSpritesProperties)
			.spread(function(images, opts, sprites) {
				return updateReferences(images, opts, sprites, css);
			})
			.then(function() {
				// we don't need no education
				//log('Done.', options.verbose);
			})
			.catch(function(err) {
				if (err) {
					log('Error: ' + err);
				}
			});
	}
}

/**
 * Return all images that can be used
 * to generate a sprite.
 *
 * @param  {Object} css
 * @param  {Object} opts
 * @return {Array}
*/
function getImages(css, opts) {
	var images        = [];
	var styleFilePath = css.source.input.file;

	// Find only background & background-image declarations.
	css.eachRule(function(rule) {
		// The host object
		// for each found image.
		var image = {
			path    : null,
			url     : null,
			retina  : false,
			ratio   : 1,
			groups  : [],
			token   : ''
		};

		// Manipulate only rules with background image
		// in them.
		if (hasImageInRule(rule.toString())) {
			image.url = getImageUrl(rule.toString());

			if (isImageSupported(image.url)) {
				// Perform search for retina
				// images if option is allowed.
				if (opts.retina && isRetinaImage(image.url)) {
					image.retina = true;
					image.ratio  = getRetinaRatio(image.url);
				}

				// Get the path to the image.
        if (/^\//.test(image.url)) {
          image.path = path.resolve(opts.imagePath+image.url);
        } else {
				  image.path = path.resolve(styleFilePath.substring(0, styleFilePath.lastIndexOf(path.sep)), image.url);
        }
				// remove get params from path;
				image.path = image.path.split('?')[0];
				// skip inlined
				if (/^data\:image/i.test(image.url)) return;
				images.push(image);

			} else {
				log('Skip ' + image.url + ' - not supported.', opts.verbose);
			}
		}
	});

	// Remove duplicates and empty values
	images = lodash
		.chain(images)
		.unique(function(image) {
			return image.path;
		})
		.value();

	return images;
}

/**
 * Prepare functions that will be used
 * to filter images.
 *
 * @param  {Object} opts
 * @return
 */
function setupFilterBy(opts) {
	// Convert user function to array
	if (lodash.isFunction(opts.filterBy)) {
		opts.filterBy = [opts.filterBy];
	}

	// Remove non existing images
	opts.filterBy.unshift(function(image) {
		return Q.Promise(function(resolve, reject) {
			image.tag = image.path.split('#')[1] || false;
			image.groups = [image.tag || 'default'];
			image.path = image.path.split('#')[0];
			if (/^\//.test(image.path)) image.path = '.'+image.path;
			fs.exists(image.path, function(exists) {
				if (!exists) {
					log('Skip ' + image.url + ' - not exist.',  opts.verbose);
				}

				resolve(exists);
			});
		});
	});
}

/**
 * Apply filterBy functions.
 *
 * @param  {Array}  images
 * @param  {Object} opts
 * @return {Promise}
 */
function applyFilterBy(images, opts) {
	return Q.Promise(function(resolve, reject) {
		async.reduce(opts.filterBy, images, function(images, filter, next) {
			async.filter(images, function(image, ok) {<commit_msg>remove old image.path rules<commit_after>'use strict';

/**
 * Module dependencies.
 */
var fs          = require('fs');
var path        = require('path');
var util        = require('util');
var postcss     = require('postcss');
var lodash      = require('lodash');
var async       = require('async');
var Q           = require('q');
var spritesmith = require('spritesmith');
var mkdirp      = require('mkdirp');

/**
 * Constants.
 *
 * @type {String}
 */
var GROUP_DELIMITER   = '.';
var GROUP_MASK        = '*';
var BACKGROUND        = 'background';
var BACKGROUND_IMAGE  = 'background-image';
var BACKGROUND_COLOR  = 'background-color';
var BACKGROUND_REPEAT = 'background-repeat';
var BACKGROUND_SIZE   = 'background-size';

/**
 * Defaults.
 *
 * @type {Object}
 */
var defaults = {
	stylesheetPath  : './',
  imagePath       : '.',
	spritePath      : './sprite.png',
	skipPrefix      : false,
	outputDimensions: false,
	filterBy        : [],
	groupBy         : [],
	retina          : false,
	verbose         : false,

	// spritesmith options
	engine        : 'pixelsmith',
	algorithm     : 'binary-tree',
	padding       : 0,
	engineOpts    : {},
	exportOpts    : {}
};

/**
 * Register the PostCSS plugin.
 */
module.exports = postcss.plugin('postcss-sprites', plugin);

/**
 * PostCSS plugin definition.
 *
 * @param  {Object}  opts
 * @return {Function}
 */
function plugin(opts) {
	// Extend default options.
	var options = lodash.merge({}, defaults, opts || {});

	// Prepare filterBy functions.
	setupFilterBy(options);

	// Prepare groupBy functions.
	setupGroupBy(options);

	// Plugin initializer.
	return function(css) {
		return Q
			.all([getImages(css, options), options])
			.spread(applyFilterBy)
			.spread(applyGroupBy)
			.spread(function(images, opts){
				return setTokens(images, opts, css);
			})
			.spread(runSpriteSmith)
			.spread(saveSprites)
			.spread(mapSpritesProperties)
			.spread(function(images, opts, sprites) {
				return updateReferences(images, opts, sprites, css);
			})
			.then(function() {
				// we don't need no education
				//log('Done.', options.verbose);
			})
			.catch(function(err) {
				if (err) {
					log('Error: ' + err);
				}
			});
	}
}

/**
 * Return all images that can be used
 * to generate a sprite.
 *
 * @param  {Object} css
 * @param  {Object} opts
 * @return {Array}
*/
function getImages(css, opts) {
	var images        = [];
	var styleFilePath = css.source.input.file;

	// Find only background & background-image declarations.
	css.eachRule(function(rule) {
		// The host object
		// for each found image.
		var image = {
			path    : null,
			url     : null,
			retina  : false,
			ratio   : 1,
			groups  : [],
			token   : ''
		};

		// Manipulate only rules with background image
		// in them.
		if (hasImageInRule(rule.toString())) {
			image.url = getImageUrl(rule.toString());

			if (isImageSupported(image.url)) {
				// Perform search for retina
				// images if option is allowed.
				if (opts.retina && isRetinaImage(image.url)) {
					image.retina = true;
					image.ratio  = getRetinaRatio(image.url);
				}

				// Get the path to the image.
        if (/^\//.test(image.url)) {
          image.path = path.resolve(opts.imagePath+image.url);
        } else {
				  image.path = path.resolve(styleFilePath.substring(0, styleFilePath.lastIndexOf(path.sep)), image.url);
        }
				// remove get params from path;
				image.path = image.path.split('?')[0];
				// skip inlined
				if (/^data\:image/i.test(image.url)) return;
				images.push(image);

			} else {
				log('Skip ' + image.url + ' - not supported.', opts.verbose);
			}
		}
	});

	// Remove duplicates and empty values
	images = lodash
		.chain(images)
		.unique(function(image) {
			return image.path;
		})
		.value();

	return images;
}

/**
 * Prepare functions that will be used
 * to filter images.
 *
 * @param  {Object} opts
 * @return
 */
function setupFilterBy(opts) {
	// Convert user function to array
	if (lodash.isFunction(opts.filterBy)) {
		opts.filterBy = [opts.filterBy];
	}

	// Remove non existing images
	opts.filterBy.unshift(function(image) {
		return Q.Promise(function(resolve, reject) {
			image.tag = image.path.split('#')[1] || false;
			image.groups = [image.tag || 'default'];
			image.path = image.path.split('#')[0];
			
			fs.exists(image.path, function(exists) {
				if (!exists) {
					log('Skip ' + image.url + ' - not exist.',  opts.verbose);
				}

				resolve(exists);
			});
		});
	});
}

/**
 * Apply filterBy functions.
 *
 * @param  {Array}  images
 * @param  {Object} opts
 * @return {Promise}
 */
function applyFilterBy(images, opts) {
	return Q.Promise(function(resolve, reject) {
		async.reduce(opts.filterBy, images, function(images, filter, next) {
			async.filter(images, function(image, ok) {
{'fraction_non_alphanumeric': 0.15833160406723387, 'fraction_numerical': 0.0012450715916165179, 'mean_word_length': 2.7681782642689603, 'pattern_counts': {'":': 0, '<': 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': '689476', 'n_tokens_mistral': 3575, 'n_tokens_neox': 3128, 'n_words': 729}