Skip to content

Commit

Permalink
Refactor implementation to ES6 class
Browse files Browse the repository at this point in the history
  • Loading branch information
lukemelia committed Oct 30, 2020
1 parent c292119 commit 0e0d247
Showing 1 changed file with 130 additions and 137 deletions.
267 changes: 130 additions & 137 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,178 +17,171 @@ function relative(a, b) {
return relativePath.charAt(0) !== '.' ? './' + relativePath : relativePath;
}

function AssetRewrite(inputNode, options) {
if (!(this instanceof AssetRewrite)) {
return new AssetRewrite(inputNode, options);
}

options = options || {};

Filter.call(this, inputNode, {
extensions: options.replaceExtensions || ['html', 'css'],
// We should drop support for `description` in the next major release
annotation: options.description || options.annotation
});

this.assetMap = options.assetMap || {};
this.prepend = options.prepend || '';
this.ignore = options.ignore || []; // files to ignore

this.assetMapKeys = null;
}

AssetRewrite.prototype = Object.create(Filter.prototype);
AssetRewrite.prototype.constructor = AssetRewrite;

AssetRewrite.prototype.processAndCacheFile = function (srcDir, destDir, relativePath) {
this._cache = new Cache();

return Filter.prototype.processAndCacheFile.apply(this, arguments);
}
class AssetRewrite extends Filter {

constructor(inputNode, options = {}) {
super(inputNode, {
extensions: options.replaceExtensions || ['html', 'css'],
annotation: options.annotation
});

/**
* Checks that file is not being ignored and destination doesn't already have a file
* @param relativePath
* @returns {boolean}
*/
this.assetMap = options.assetMap || {};
this.prepend = options.prepend || '';
this.ignore = options.ignore || []; // files to ignore

AssetRewrite.prototype.canProcessFile = function(relativePath) {
if (!this.assetMapKeys) {
this.generateAssetMapKeys();
this.assetMapKeys = null;
}

if (!this.inverseAssetMap) {
var inverseAssetMap = {};
var assetMap = this.assetMap;

Object.keys(assetMap).forEach(function(key) {
var value = assetMap[key];
inverseAssetMap[value] = key;
}, this);

this.inverseAssetMap = inverseAssetMap;
processAndCacheFile(srcDir, destDir, relativePath) {
this._cache = new Cache();
return super.processAndCacheFile(...arguments);
}

/*
* relativePath can be fingerprinted or not.
* Check that neither of these variations are being ignored
/**
* Checks that file is not being ignored and destination doesn't already have a file
* @param relativePath
* @returns {boolean}
*/

if (this.ignore.indexOf(relativePath) !== -1 || this.ignore.indexOf(this.inverseAssetMap[relativePath]) !== -1) {
return false;
}
canProcessFile(relativePath) {
if (!this.assetMapKeys) {
this.generateAssetMapKeys();
}

return Filter.prototype.canProcessFile.apply(this, arguments);
}
if (!this.inverseAssetMap) {
var inverseAssetMap = {};
var assetMap = this.assetMap;

AssetRewrite.prototype.rewriteAssetPath = function (string, assetPath, replacementPath) {

// Early exit: does the file contain the asset path?
if (string.indexOf(assetPath) === -1) return string;

var newString = string;

/*
* Replace all of the assets with their new fingerprint name
*
* Uses a regular expression to find assets in html tags, css backgrounds, handlebars pre-compiled templates, etc.
*
* ["\'(=] - Match one of "'(= exactly one time
* \\s* - Any amount of white space
* ( - Starts the first capture group
* [^"\'()=]* - Do not match any of ^"'()= 0 or more times
* [^"\n\'()\\>=]* - Do not match any of ^"\n'()\>= 0 or more times - Explicitly add \ here because of handlebars compilation
* ) - End first capture group
* (\\?[^"\')> ]*)? - Allow for query parameters to be present after the URL of an asset
* \\s* - Any amount of white space
* \\\\* - Allow any amount of \ - For handlebars compilation (includes \\\)
* \\s* - Any amount of white space
* ["\')>\s] - Match one of "'(\n> exactly one time
*/
Object.keys(assetMap).forEach(function(key) {
var value = assetMap[key];
inverseAssetMap[value] = key;
}, this);

var re = new RegExp('["\'(=]\\s*([^"\'()=]*' + escapeRegExp(assetPath) + '[^"\n\'()\\>=]*)(\\?[^"\')> ]*)?\\s*\\\\*\\s*["\')>\s]', 'g');
var match = null;

/*
* This is to ignore matches that should not be changed
* Any URL encoded match that would be ignored above will be ignored by this: "'()=\
*/
var ignoreLibraryCode = new RegExp('%(22|27|5C|28|29|3D)[^"\'()=]*' + escapeRegExp(assetPath));

while (match = re.exec(newString)) {
var replaceString = '';
if (ignoreLibraryCode.exec(match[1])) {
continue;
this.inverseAssetMap = inverseAssetMap;
}

replaceString = match[1].replace(assetPath, replacementPath);
/*
* relativePath can be fingerprinted or not.
* Check that neither of these variations are being ignored
*/

if (this.prepend && replaceString.indexOf(this.prepend) !== 0) {
var removeLeadingRelativeOrSlashRegex = new RegExp('^(\\.*/)*(.*)$');
replaceString = this.prepend + removeLeadingRelativeOrSlashRegex.exec(replaceString)[2];
if (this.ignore.indexOf(relativePath) !== -1 || this.ignore.indexOf(this.inverseAssetMap[relativePath]) !== -1) {
return false;
}

newString = newString.replace(new RegExp(escapeRegExp(match[1]), 'g'), replaceString);
return super.canProcessFile(...arguments);
}

var self = this;
return newString.replace(new RegExp('sourceMappingURL=' + escapeRegExp(assetPath)), function(wholeMatch) {
var replaceString = replacementPath;
if (self.prepend && (!/^sourceMappingURL=(http|https|\/\/)/.test(wholeMatch))) {
replaceString = self.prepend + replacementPath;
rewriteAssetPath(string, assetPath, replacementPath) {

// Early exit: does the file contain the asset path?
if (string.indexOf(assetPath) === -1) return string;

var newString = string;

/*
* Replace all of the assets with their new fingerprint name
*
* Uses a regular expression to find assets in html tags, css backgrounds, handlebars pre-compiled templates, etc.
*
* ["\'(=] - Match one of "'(= exactly one time
* \\s* - Any amount of white space
* ( - Starts the first capture group
* [^"\'()=]* - Do not match any of ^"'()= 0 or more times
* [^"\n\'()\\>=]* - Do not match any of ^"\n'()\>= 0 or more times - Explicitly add \ here because of handlebars compilation
* ) - End first capture group
* (\\?[^"\')> ]*)? - Allow for query parameters to be present after the URL of an asset
* \\s* - Any amount of white space
* \\\\* - Allow any amount of \ - For handlebars compilation (includes \\\)
* \\s* - Any amount of white space
* ["\')>\s] - Match one of "'(\n> exactly one time
*/

var re = new RegExp('["\'(=]\\s*([^"\'()=]*' + escapeRegExp(assetPath) + '[^"\n\'()\\>=]*)(\\?[^"\')> ]*)?\\s*\\\\*\\s*["\')>\s]', 'g');
var match = null;

/*
* This is to ignore matches that should not be changed
* Any URL encoded match that would be ignored above will be ignored by this: "'()=\
*/
var ignoreLibraryCode = new RegExp('%(22|27|5C|28|29|3D)[^"\'()=]*' + escapeRegExp(assetPath));

while (match = re.exec(newString)) {
var replaceString = '';
if (ignoreLibraryCode.exec(match[1])) {
continue;
}

replaceString = match[1].replace(assetPath, replacementPath);

if (this.prepend && replaceString.indexOf(this.prepend) !== 0) {
var removeLeadingRelativeOrSlashRegex = new RegExp('^(\\.*/)*(.*)$');
replaceString = this.prepend + removeLeadingRelativeOrSlashRegex.exec(replaceString)[2];
}

newString = newString.replace(new RegExp(escapeRegExp(match[1]), 'g'), replaceString);
}
return wholeMatch.replace(assetPath, replaceString);
});
};

AssetRewrite.prototype.processString = function (string, relativePath) {
var newString = string;
var self = this;
return newString.replace(new RegExp('sourceMappingURL=' + escapeRegExp(assetPath)), function(wholeMatch) {
var replaceString = replacementPath;
if (self.prepend && (!/^sourceMappingURL=(http|https|\/\/)/.test(wholeMatch))) {
replaceString = self.prepend + replacementPath;
}
return wholeMatch.replace(assetPath, replaceString);
});
};

processString(string, relativePath) {
var newString = string;

for (var i = 0, keyLength = this.assetMapKeys.length; i < keyLength; i++) {
var key = this.assetMapKeys[i];
for (var i = 0, keyLength = this.assetMapKeys.length; i < keyLength; i++) {
var key = this.assetMapKeys[i];

if (this.assetMap.hasOwnProperty(key)) {
/*
* Rewrite absolute URLs
*/
if (this.assetMap.hasOwnProperty(key)) {
/*
* Rewrite absolute URLs
*/

newString = this.rewriteAssetPath(newString, key, this.assetMap[key]);
newString = this.rewriteAssetPath(newString, key, this.assetMap[key]);

/*
* Rewrite relative URLs. If there is a prepend, use the full absolute path.
*/
/*
* Rewrite relative URLs. If there is a prepend, use the full absolute path.
*/

var pathDiff = relative(relativePath, key).replace(/^\.\//, "");
var replacementDiff = relative(relativePath, this.assetMap[key]).replace(/^\.\//, "");
var pathDiff = relative(relativePath, key).replace(/^\.\//, "");
var replacementDiff = relative(relativePath, this.assetMap[key]).replace(/^\.\//, "");

if (this.prepend && this.prepend !== '') {
replacementDiff = this.assetMap[key];
}
if (this.prepend && this.prepend !== '') {
replacementDiff = this.assetMap[key];
}

newString = this.rewriteAssetPath(newString, pathDiff, replacementDiff);
newString = this.rewriteAssetPath(newString, pathDiff, replacementDiff);
}
}
}

return newString;
};
return newString;
}

AssetRewrite.prototype.generateAssetMapKeys = function () {
var keys = Object.keys(this.assetMap);
generateAssetMapKeys () {
var keys = Object.keys(this.assetMap);

keys.sort(function (a, b) {
if (a.length < b.length) {
return 1;
}
keys.sort(function (a, b) {
if (a.length < b.length) {
return 1;
}

if (a.length > b.length) {
return -1;
}
if (a.length > b.length) {
return -1;
}

return 0;
});
return 0;
});

this.assetMapKeys = keys;
};
this.assetMapKeys = keys;
}
}

/*
* /([.*+?^=!:${}()|\[\]\/\\])/g - Replace .*+?^=!:${}()|[]/\ in filenames with an escaped version for an exact name match
Expand Down

0 comments on commit 0e0d247

Please sign in to comment.