UNPKG

customizr

Version:

Build out a lean, mean Modernizr machine.

299 lines (236 loc) 7.95 kB
module.exports = function (modernizrPath) { "use strict"; var _ = require("lodash"); // Dependencies var fs = require("fs"), cwd = process.cwd(), path = require("path"); // Deferreds var promise = require("promised-io/promise"); // Cache utils var utils, settings; return { matchedTestsInFile : {}, stringMatches : {}, filterTests : function (tests) { var i, j, obj = {}, filteredTests = []; for (i = 0, j = tests.length; i < j; i++) { obj[tests[i]] = 0; } for (var key in obj) { filteredTests.push(key); } return filteredTests; }, findStringMatches : function (type, file, data, testpath) { var match, regExp, prefix, basename = path.basename(file); // JavaScript/CoffeeScript/TypeScript files if ((/\.(js|coffee|ts)$/).test(basename)) { // Don't bother if we don't find a reference to Modernizr in the file... if (!(/Modernizr/im).test(data)) { return; } // Match usage such as: Modernizr.classname --or-- Modernizr['classname'] regExp = new RegExp("(?:\\.|\\[(?:\"|'))(" + type + ")(?![\\w-])(?:(?:\"|')\\])?", "gm"); } // If it's not script, assume it's CSS (or similar, e.g.: LESS, SCSS) files else { prefix = settings.classPrefix || ''; // When no prefix, match usage such as: .classname --or-- .no-classname // When prefix set, match usage such as: .<prefix>classname --or-- .<prefix>no-classname regExp = new RegExp("(?:\\." + prefix + ")(?:no-)?(" + type + ")(?![\\w-])", "gm"); } match = (regExp).exec(data); this.matchedTestsInFile[file] = this.matchedTestsInFile[file] || []; while (match) { var test = match[1]; if (test) { this.stringMatches[testpath] = this.stringMatches[testpath] || []; if (this.stringMatches[testpath].indexOf(file) === -1) { this.stringMatches[testpath].push(file); } if (this.matchedTestsInFile[file].indexOf(test) === -1) { this.matchedTestsInFile[file].push(test); } } match = (regExp).exec(data); } }, parseData : function (file, data, metadata) { data = data.toString(); var testpath, test, type, value, i, j; for (test in metadata) { for (type in metadata[test]) { if (type === "name" || type === "path") { continue; } value = metadata[test][type]; testpath = metadata[test].path; if (Array.isArray(value)) { for (i = 0, j = value.length; i < j; i++) { this.findStringMatches(value[i], file, data, testpath); } } else { this.findStringMatches(value, file, data, testpath); } } } var matchedTests = this.matchedTestsInFile[file]; if (!settings.quiet && matchedTests && matchedTests.length) { utils.log.writeln(); var testCount = matchedTests.length; var testText = " match" + (testCount > 1 ? "es" : "") + " in "; utils.log.ok(testCount.toString().green + testText + file); utils.log.ok(matchedTests.sort().join(", ").grey); } }, readFile : function (file, metadata, deferred) { var stream = fs.createReadStream(file); stream.on("data", function (data) { this.parseData(file, data, metadata); }.bind(this)); stream.on("end", function () { if ((++this.currentFile) === this.totalFiles) { return deferred.resolve(); } }.bind(this)); }, readFilesAsync : function (files, metadata) { var deferred = new promise.Deferred(), i, j, last; this.currentFile = 0; this.totalFiles = files.length; for (i = 0, j = files.length; i < j; i++) { this.readFile(files[i], metadata, deferred); } return deferred.promise; }, parseCodeFromBuffers : function (buffers, metadata) { var i, j, file; for (i = 0, j = buffers.length; i < j; i++) { file = buffers[i]; this.parseData(file.path, String(file.contents), metadata); } }, init : function (metadata) { // Cache utils utils = this.utils; settings = utils.getSettings(); var _private = utils.getDefaults().private; var deferred = new promise.Deferred(), buildPath = path.join(modernizrPath, "build"), files; var tests = settings.tests.map(function (test) { var data = metadata.filter(function (data) { if (Array.isArray(test)) { return test.indexOf(data) !== -1 || _.isEqual(test, data.property); } return data.property === test; }); return data[0] || {}; }).filter(function (test) { return test.path; }); if (!settings.quiet && tests && tests.length) { utils.log.writeln(); utils.log.ok("Explicitly including these tests:"); utils.log.ok(tests.map(function (test) { return test.property; }).sort().join(", ").grey); } var excludedTests = settings.excludeTests.map(function (test) { var data = metadata.filter(function (data) { if (Array.isArray(data.property)) { return data.property.indexOf(test) !== -1; } else { return data.property === test; } }); return data[0] || {}; }).filter(function (test) { return test.path; }); if (!settings.quiet && excludedTests && excludedTests.length) { utils.log.writeln(); utils.log.ok("Explicitly excluding these tests:"); utils.log.ok(excludedTests.map(function (test) { return test.property; }).sort().join(", ").grey); } tests = tests.map(function (test) { return test.path; }).filter(function (test) { return excludedTests.map(function (test) { return test.path; }).indexOf(test) === -1; }).concat(settings.customTests.map(function (test) { return path.relative(buildPath, fs.realpathSync(test)); })); metadata = metadata.filter(function (data) { return excludedTests.map(function (test) { return test.path; }).indexOf(data.path) === -1; }); if (settings.crawl !== true && settings.useBuffers !== true) { tests = this.crawler.filterTests(tests); if (!settings.quiet) { utils.log.subhead("Skipping file traversal"); } setTimeout(function () { return deferred.resolve(tests); }, 0); return deferred.promise; } if (!settings.quiet) { utils.log.subhead("Looking for Modernizr references"); } // Support including code via string rather than reading a file. if (settings.useBuffers === true) { this.crawler.parseCodeFromBuffers(settings.files.src, metadata); for (var key in this.crawler.stringMatches) { tests.push(key); } tests = this.crawler.filterTests(tests); setTimeout(function () { return deferred.resolve(tests); }); return deferred.promise; } // Exclude developer build if (settings.devFile !== "remote" && settings.devFile !== false) { if (!fs.existsSync(settings.devFile)) { utils.log.warn([ "Can't find your Modernizr development build at " + settings.devFile, "this tool needs this path to avoid false positives", "", "Update your settings via the modernizr.devFile config option", "See %s#devfile-string for more details".replace("%s", _private.url.github), "", "" ].join("\n ").replace(/\s$/, "")); } else { settings.files.src.push("!" + settings.devFile); } } // Exclude generated file if (settings.dest) { settings.files.src.push("!" + settings.dest); } // And exclude all files in this current directory settings.files.src.push("!" + path.join(__dirname.replace(cwd + path.sep, ""), "**", "*")); files = utils.file.expand({ filter: "isFile" }, settings.files.src); this.crawler.readFilesAsync(files, metadata).then(function () { for (var key in this.crawler.stringMatches) { tests.push(key); } tests = this.crawler.filterTests(tests); return deferred.resolve(tests); }.bind(this)); return deferred.promise; } }; };