var walk = require('walk'); var fs = require('fs'); var classesOrIds = []; var viewsAndTemplates = [] var walkers = []; var maybeUnusedClassesOrIds = []; var compleWalkersCount = 0; var classesToFileMap = {} // Calback Function every time a walker ends var onWalkerEnd = function(walkerId) { compleWalkersCount++ // All walkers are complete // We can only perform this logic once we have all the data if (compleWalkersCount === walkers.length) { // Loop through all the classes or IDs for (i = 0; i < classesOrIds.length; i++) { // The class or ID we are looking for classOrId = classesOrIds[i] // Loop through all the views and Templates for (ii = 0; ii < viewsAndTemplates.length; ii++) { // We found this class or ID in a view or template if (viewsAndTemplates[ii].indexOf(classOrId.substring(1)) > -1) { break; } // We didnt find this class or id inside any view or template if (ii === viewsAndTemplates.length -1) { maybeUnusedClassesOrIds.push(classOrId) } } } console.log("Found " + classesOrIds.length + " CSS classes or ids"); console.log(maybeUnusedClassesOrIds.length + " of those might not be in use anymore:"); console.log(" "); // Log each class or ID that we couldnt find maybeUnusedClassesOrIds.forEach(function(classOrId) { logString = classOrId // Right Pad the string so we a nice column of locations for (i = 0; i < 40 - classOrId.length; i++) { logString += " " } console.log(logString + classesToFileMap[classOrId]); }) } }; // Gets all the CSS Classes or Ids walkers.push(walk.walk('./app/assets/css', { followLinks: false }).on('file', function(root, stat, next) { // Opens each file // Note this will open other files as well fs.readFile(root + '/' + stat.name, 'utf8', function(error, data) { // Assume the CSS is unminified // If so we assume that each selector starts on a new line data.split('\n').forEach(function(line) { // Find Class selectors // Assume that lines starting with a . are a class selectors // Note this won't catch instances of element.class if (line[0] === '.') { name = line.split('.')[1].split(' ')[0].split(':')[0].split('\t')[0].split(',')[0].split('[')[0]; if (classesOrIds.indexOf("." + name) === -1) { classesOrIds.push("." + name); classesToFileMap["." + name] = root + '/' + stat.name; } } // Find ID selectors // Assume that lines starting with a # are ID selectors // Note this won't catch instances of element#id if (line[0] === '#') { name = line.split('#')[1].split(' ')[0].split(':')[0].split('\t')[0].split(',')[0].split('[')[0].split('.')[0]; if (classesOrIds.indexOf("#" + name) === -1) { classesOrIds.push("#" + name); classesToFileMap["#" + name] = root + '/' + stat.name; } } }) next(); }); }).on('end', onWalkerEnd)); // Gets all the mustache templates walkers.push(walk.walk('./app/templates', { followLinks: false }).on('file', function(root, stat, next) { // Read & save the content of the mustache template // We'll check this for classes or ids later fs.readFile(root + '/' + stat.name, 'utf8', function(error, data) { viewsAndTemplates.push(data); next(); }); }).on('end', onWalkerEnd)); // Gets all the views/components walkers.push(walk.walk('./app/coffeescript/views', { followLinks: false }).on('file', function(root, stat, next) { // Read & save the content of the view // We'll check this for classes or ids later fs.readFile(root + '/' + stat.name, 'utf8', function(error, data) { viewsAndTemplates.push(data) next(); }); }).on('end', onWalkerEnd));