Comparing version 0.4.4 to 0.4.5
@@ -40,4 +40,4 @@ var path = require("path"); | ||
var args = minimist(argv.slice(2), { | ||
"boolean": ["verbose", "clean", "ignore-errors", "help", "skip-css", "amend", "quickhash", "ignore-plugin-errors"], | ||
"string": ["exclude", "include", "manifest-format", "manifest-path", "plugins", "clean-old", "base-dir", "passthrough", "disabled-plugins"], | ||
"boolean": ["verbose", "clean", "ignore-errors", "help", "skip-css", "amend", "quickhash", "ignore-plugin-errors", "skip-map"], | ||
"string": ["exclude", "include", "manifest-format", "manifest-path", "plugins", "clean-old", "base-dir", "passthrough", "disabled-plugins", "sourcemap-url-prefix"], | ||
"alias": { | ||
@@ -85,2 +85,3 @@ "verbose": "v", | ||
processCss: !args["skip-css"], | ||
processMap: !args["skip-map"], | ||
quickhash: args["quickhash"], | ||
@@ -90,2 +91,3 @@ amend: args["amend"], | ||
baseDir: args["base-dir"], | ||
sourcemapURLPrefix: args["sourcemap-url-prefix"] || "", | ||
disabledPlugins: args["disabled-plugins"] ? args["disabled-plugins"].split(";") : null | ||
@@ -92,0 +94,0 @@ }; |
@@ -32,3 +32,2 @@ "use strict"; | ||
}; | ||
exports.recurseDirSync = recurseDirSync; | ||
@@ -35,0 +34,0 @@ |
@@ -10,2 +10,3 @@ "use strict"; | ||
var cssProcessor = require("./css-processor"); | ||
var mapProcessor = require("./map-processor"); | ||
var hashcodeGenerator = require("./hashcode-generator"); | ||
@@ -16,4 +17,4 @@ | ||
var getManifestPath = function (directory, serializer) { | ||
var getManifestPath = function(directory, serializer) { | ||
// If the manifest path is declared explicitly, | ||
@@ -28,3 +29,3 @@ // use it and ignore the rest of the rules. | ||
var compare = function (a, b) { | ||
var compare = function(a, b) { | ||
if (a < b) { | ||
@@ -41,9 +42,9 @@ return -1; | ||
// and returns a structure with this data | ||
var createManifestEntry = function (fullPath, basePath, targetBasePath, data, hashCode) { | ||
var relativePath = path.relative(basePath, fullPath); | ||
var targetPath = path.resolve(targetBasePath, relativePath); | ||
var createManifestEntry = function(fullPath, baseDir, targetBaseDir, data, hashCode) { | ||
var relativePath = path.relative(baseDir, fullPath); | ||
var targetPath = path.resolve(targetBaseDir, relativePath); | ||
var targetDir = path.dirname(targetPath); | ||
var hashCodeCoalesced = hashCode || hashcodeGenerator.generateForFile(fullPath, _options.quickhash); | ||
var hashedPathPhysical = hashpattern.getHashedFileName(fullPath, targetDir, hashCodeCoalesced); | ||
var hashedPath = path.relative(targetBasePath, hashedPathPhysical); | ||
var hashedPath = path.relative(targetBaseDir, hashedPathPhysical); | ||
@@ -62,12 +63,11 @@ var manifestEntry = { | ||
var createManifestEntryCss = function (fullPath, basePath, targetDir, data) { | ||
var processImagePath = function (virtualPath) { | ||
var createManifestEntryCss = function(fullPath, baseDir, targetDir, data) { | ||
var getHashedPath = function(virtualPath) { | ||
var isRootRelative = virtualPath[0] == "/"; | ||
var imagePhysicalPath = isRootRelative ? | ||
path.join(basePath, virtualPath) : | ||
var physicalPath = isRootRelative ? | ||
path.join(baseDir, virtualPath) : | ||
path.resolve(path.dirname(fullPath), virtualPath); | ||
var imageEntry = processEntry(imagePhysicalPath, basePath, targetDir, data); | ||
if (!imageEntry) { | ||
var entry = processEntry(physicalPath, baseDir, targetDir, data); | ||
if (!entry) { | ||
return virtualPath; | ||
@@ -77,11 +77,10 @@ } | ||
if (!isRootRelative) { | ||
return path.relative(path.dirname(fullPath), imageEntry.hashedPathPhysical); | ||
return path.relative(path.dirname(fullPath), entry.hashedPathPhysical); | ||
} | ||
return imageEntry.hashedPath; | ||
return entry.hashedPath; | ||
}; | ||
var transformedCssText = cssProcessor.processCss(fsutil.readFileSync(fullPath, "utf8"), processImagePath); | ||
var transformedCssText = cssProcessor.processCss(fsutil.readFileSync(fullPath, "utf8"), getHashedPath); | ||
var entry = createManifestEntry(fullPath, basePath, targetDir, data, hashcodeGenerator.generate(transformedCssText)); | ||
var entry = createManifestEntry(fullPath, baseDir, targetDir, data, hashcodeGenerator.generate(transformedCssText)); | ||
@@ -93,11 +92,11 @@ entry.transformedText = transformedCssText; | ||
var createAndAugmentManifestEntry = function (fullPath, basePath, targetDir, data) { | ||
var createAndAugmentManifestEntry = function(fullPath, baseDir, targetDir, data, hashCode) { | ||
// Special case: image paths in CSS files need to be replaced with their hashed versions | ||
var ext = path.extname(fullPath); | ||
var createManifestEntryMethod = (_options.processCss && ext == ".css") ? createManifestEntryCss : createManifestEntry; | ||
var entry = createManifestEntryMethod(fullPath, basePath, targetDir, data); | ||
var entry = createManifestEntryMethod(fullPath, baseDir, targetDir, data, hashCode); | ||
// If plugins are present, give them a change to add data to the manifest entry | ||
if (_options.plugins) { | ||
_options.plugins.forEach(function (plugin) { | ||
_options.plugins.forEach(function(plugin) { | ||
try { | ||
@@ -120,3 +119,3 @@ var pluginData = plugin.processFile(entry); | ||
} | ||
return entry; | ||
@@ -126,7 +125,11 @@ }; | ||
var isDescendent = function (childPath, baseDir) { | ||
// Should be case insensitive on windows | ||
var isDescendent = function(childPath, baseDir) { | ||
// Should be case insensitive on windows | ||
var preprocess = /^win/.test(process.platform) ? | ||
function (p) { return p.toLowerCase(); } : | ||
function (p) { return p; }; | ||
function(p) { | ||
return p.toLowerCase(); | ||
} : | ||
function(p) { | ||
return p; | ||
}; | ||
@@ -136,4 +139,4 @@ return preprocess(childPath).indexOf(preprocess(baseDir)) === 0; | ||
var processEntry = function (fullPath, baseDir, targetDir, data) { | ||
var processEntry = function(fullPath, baseDir, targetDir, data) { | ||
var ext = path.extname(fullPath); | ||
// See if an existing entry exists in the cache | ||
@@ -156,7 +159,5 @@ var existingEntry = data.lookupMap[fullPath]; | ||
// Apply filters to exclude files if specified | ||
if (_options.shouldBeExcluded) { | ||
if (_options.shouldBeExcluded(fullPath)) { | ||
return; | ||
} | ||
// Ignore map files, we check each css and js file for accompaning map file | ||
if (ext === ".map") { | ||
return; | ||
} | ||
@@ -166,3 +167,2 @@ | ||
if (_options.isPassthrough && _options.isPassthrough(fullPath)) { | ||
// Passthrough means to simply copy file to the destination path, without labeling it with a hashcode or | ||
@@ -174,7 +174,26 @@ // including in the manifest. | ||
return null; | ||
} | ||
else { | ||
var entry = createAndAugmentManifestEntry(fullPath, baseDir, targetDir, data); | ||
} else { | ||
// Improve map files to have the hashed filepath in their source (instead of unhashed filepath) - useful for debugging | ||
// Note: assuming map files are in the same dir as js/css file and they end with .map | ||
var mapFullPath = fullPath + ".map"; | ||
var transformedText = null, | ||
hashCode = null; | ||
if (_options.processMap && fsutil.existsSync(mapFullPath)) { | ||
var mapEntry = createAndAugmentManifestEntry(mapFullPath, baseDir, targetDir, data); | ||
fsutil.copySync(mapFullPath, mapEntry.hashedPathPhysical); | ||
if (_options.logger) { | ||
_options.logger(mapFullPath + " > " + mapEntry.hashedPathPhysical); | ||
} | ||
// The sourcemap filename has changed, so update the minified js/css file and replace unhashed filename with hashed one | ||
// This is done to support zero downtime deployment when two different releases are out at once | ||
transformedText = mapProcessor.processMinFile(ext, fsutil.readFileSync(fullPath, "utf8"), mapEntry.hashedPath, _options.sourcemapURLPrefix); | ||
if (transformedText) { | ||
hashCode = hashcodeGenerator.generate(transformedText); | ||
} | ||
} | ||
// use the generated hashcode for the transformed text to create manifest entry | ||
var entry = createAndAugmentManifestEntry(fullPath, baseDir, targetDir, data, hashCode); | ||
if (_options.logger) { | ||
@@ -184,2 +203,3 @@ _options.logger(fullPath + " > " + entry.hashedPathPhysical); | ||
// If the existing entry is already correct, we can skip the rest. | ||
@@ -194,5 +214,5 @@ if (existingEntry && existingEntry.unverified) { | ||
// Copy the original file to the hashed path | ||
if (entry.transformedText) { | ||
fsutil.writeFileSync(entry.hashedPathPhysical, entry.transformedText, "utf8"); | ||
delete entry.transformedText; | ||
if (transformedText) { | ||
fsutil.writeFileSync(entry.hashedPathPhysical, transformedText, "utf8"); | ||
transformedText = null; | ||
} else { | ||
@@ -209,3 +229,2 @@ fsutil.copySync(entry.pathPhysical, entry.hashedPathPhysical); | ||
data.lookupMap[fullPath] = entry; | ||
return entry; | ||
@@ -224,2 +243,4 @@ } | ||
_options.logError(msg); | ||
_options.logError(); | ||
_options.logError(ex); | ||
} | ||
@@ -234,3 +255,3 @@ | ||
// to their target locations. | ||
var createManifest = function (files, baseDir, targetDir, existingManifestData) { | ||
var createManifest = function(files, baseDir, targetDir, existingManifestData) { | ||
@@ -247,3 +268,3 @@ var data = { | ||
if (existingManifestData) { | ||
existingManifestData.forEach(function (entry) { | ||
existingManifestData.forEach(function(entry) { | ||
entry.unverified = true; | ||
@@ -256,3 +277,5 @@ // Populate the lookup map so we can find the entry quickly. | ||
files.forEach(function (fullPath) { | ||
files.filter(function(fullPath) { | ||
return (_options.shouldBeExcluded) ? !_options.shouldBeExcluded(fullPath) : true; | ||
}).map(function(fullPath) { | ||
processEntry(fullPath, baseDir, targetDir, data); | ||
@@ -264,7 +287,7 @@ }); | ||
var unixifyPath = function (filePath) { | ||
var unixifyPath = function(filePath) { | ||
return filePath.replace(/\\/g, "/"); | ||
}; | ||
var processFilter = function (filters, baseDir) { | ||
var processFilter = function(filters, baseDir) { | ||
if (!filters) { | ||
@@ -278,3 +301,3 @@ return null; | ||
return function (filePath) { | ||
return function(filePath) { | ||
@@ -292,3 +315,3 @@ var relativeFilePath = path.relative(baseDir, filePath); | ||
var initOptions = function (options, baseDir, targetDir) { | ||
var initOptions = function(options, baseDir, targetDir) { | ||
// Store global options. | ||
@@ -298,3 +321,4 @@ // This is to prevent having to pass around data for cross-cutting concerns (i.e. logging) | ||
_options = options || {}; | ||
_options.sourcemapURLPrefix = options.sourcemapURLPrefix || ""; | ||
_options.processMap = options.processMap || true; | ||
// If the passthrough option has been specified, add it to the inclusion filter to make sure | ||
@@ -319,5 +343,5 @@ // we have a chance to process the file. This only makes sense if we are writing content | ||
var excludeFilters = processFilter(_options.exclude, baseDir); | ||
_options.shouldBeExcluded = function (filePath) { | ||
_options.shouldBeExcluded = function(filePath) { | ||
if (excludeFilters && excludeFilters(filePath)) { | ||
@@ -339,3 +363,3 @@ return true; | ||
var handleError = function (ex) { | ||
var handleError = function(ex) { | ||
if (!ex.wasLogged) { | ||
@@ -358,3 +382,3 @@ if (_options.logError) { | ||
// location in targetDir. Creates a manifest json file that documents all the transformations. | ||
exports.processFiles = function (files, baseDir, targetDir, options) { | ||
exports.processFiles = function(files, baseDir, targetDir, options) { | ||
@@ -393,3 +417,3 @@ if (!files) { | ||
existingManifestData = serializer.parse(fsutil.readFileSync(manifestPath, "utf8")); | ||
existingManifestData.forEach(function (entry) { | ||
existingManifestData.forEach(function(entry) { | ||
entry.pathPhysical = baseDir + entry.path; | ||
@@ -406,3 +430,3 @@ entry.hashedPathPhysical = targetDir + entry.hashedPath; | ||
// Remove the manifest itself from the list of files to process | ||
files = files.filter(function (f) { | ||
files = files.filter(function(f) { | ||
return f != manifestPath; | ||
@@ -424,3 +448,3 @@ }); | ||
// be deployed to a web server at a different physical path. | ||
var trimmedManifest = manifestData.manifest.map(function (entry) { | ||
var trimmedManifest = manifestData.manifest.map(function(entry) { | ||
@@ -436,3 +460,3 @@ var newEntry = util._extend(entry); | ||
trimmedManifest.sort(function (a, b) { | ||
trimmedManifest.sort(function(a, b) { | ||
return compare(a.path, b.path); | ||
@@ -465,21 +489,21 @@ }); | ||
// location in targetDir. Creates a manifest json file that documents all the transformations. | ||
exports.processDirectory = function (sourceDir, targetDir, options) { | ||
exports.processDirectory = function(sourceDir, targetDir, options) { | ||
var files = []; | ||
fsutil.recurseDirSync(sourceDir, function (file) { | ||
fsutil.recurseDirSync(sourceDir, function(file) { | ||
files.push(file); | ||
}); | ||
if (options.baseDir) { | ||
if (!isDescendent(sourceDir, options.baseDir)) { | ||
throw new Error("The source directory '" + sourceDir + "' is not in the base directory: '" + options.baseDir + "'"); | ||
} | ||
// Adjust sourceDir so full paths relative to the base folder will be written to the manifest. | ||
sourceDir = options.baseDir; | ||
} | ||
if (options.baseDir) { | ||
if (!isDescendent(sourceDir, options.baseDir)) { | ||
throw new Error("The source directory '" + sourceDir + "' is not in the base directory: '" + options.baseDir + "'"); | ||
} | ||
// Adjust sourceDir so full paths relative to the base folder will be written to the manifest. | ||
sourceDir = options.baseDir; | ||
} | ||
return exports.processFiles(files, sourceDir, targetDir, options); | ||
}; | ||
var deleteFileSync = function (filePath) { | ||
var deleteFileSync = function(filePath) { | ||
if (_options.logger) { | ||
@@ -492,3 +516,3 @@ _options.logger("Deleting " + filePath + "..."); | ||
exports.clean = function (directory, options) { | ||
exports.clean = function(directory, options) { | ||
@@ -507,3 +531,3 @@ initOptions(options, directory); | ||
fsutil.recurseDirSync(directory, function (filePath) { | ||
fsutil.recurseDirSync(directory, function(filePath) { | ||
@@ -516,3 +540,3 @@ if (hashpattern.isHashedFile(filePath)) { | ||
exports.cleanOld = function (directory, options) { | ||
exports.cleanOld = function(directory, options) { | ||
@@ -533,3 +557,3 @@ initOptions(options, directory); | ||
var entries = serializer.parse(fsutil.readFileSync(manifestPath, "utf8")); | ||
entries.forEach(function (entry) { | ||
entries.forEach(function(entry) { | ||
fileSet[directory + entry.hashedPath] = true; | ||
@@ -542,3 +566,3 @@ }); | ||
fsutil.recurseDirSync(directory, function (filePath) { | ||
fsutil.recurseDirSync(directory, function(filePath) { | ||
if (hashpattern.isHashedFile(filePath)) { | ||
@@ -548,3 +572,3 @@ if (fileSet[filePath]) { | ||
} | ||
if (options.cleanOldDays > 0) { | ||
@@ -551,0 +575,0 @@ var stat = fsutil.statSync(filePath); |
{ | ||
"name": "hashly", | ||
"version": "0.4.4", | ||
"version": "0.4.5", | ||
"description": "Renames static files with a hashcode for cache busting", | ||
@@ -5,0 +5,0 @@ "directories": { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
45168
18
844