manifestFile = function () { var revisioner; // Drop any existing files off the stream, push the generated manifest file return Through.obj(function (file, enc, callback) { if (!revisioner) { revisioner = file.revisioner; } callback(); }, function (callback) { if (!revisioner) { this.emit('error', new PluginError(PLUGIN_NAME, 'revision() must be called first!')); return callback(); } this.push(revisioner.manifestFile()); callback(); }); }
...
* See [gulp-awspublish](https://www.npmjs.org/package/gulp-awspublish), [gulp-cloudfront](https://www.npmjs.org/package/gulp-cloudfront
)
## Methods
### .revision({ options })
Returns a transform function that can be used to pipe files through so that they may be revisioned, also corrects refererences to
said files.
### .manifestFile()
Returns a transform function that will filter out any existing files going through the pipe and will emit a new manifest file.
Must be called after `.revision()`.
```js
var gulp = require('gulp');
var RevAll = require('gulp-rev-all');
gulp.task('default', function () {
...
revision = function (options) { var revisioner = new Revisioner(options); // Feed the RevAll Revisioner with all the files in the stream, don't emit them until all of them have been processed return Through.obj(function (file, enc, callback) { if (file.isStream()) { this.emit('error', new PluginError(PLUGIN_NAME, 'Streams not supported!')); return callback(); } if (file.isBuffer()) { revisioner.processFile(file); } file.revisioner = revisioner; callback(); }, function (callback) { revisioner.run(); var files = revisioner.files; for (var filename in files) { this.push(files[filename]); } callback(); }); }
...
var gulp = require('gulp');
var RevAll = require('gulp-rev-all');
gulp.task('default', function () {
gulp
.src('dist/**')
.pipe(RevAll.revision())
.pipe(gulp.dest('cdn'));
});
```
```js
...
revisioner = function (options) { var defaults = { 'hashLength': 8, 'dontGlobal': [ /^\/favicon.ico$/g ], 'dontRenameFile': [], 'dontUpdateReference': [], 'dontSearchFile': [], 'fileNameVersion': 'rev-version.json', 'fileNameManifest': 'rev-manifest.json', 'prefix': '', 'referenceToRegexs': referenceToRegexs, 'annotator': annotator, 'replacer': replacer, 'debug': false, 'includeFilesInManifest': ['.css', '.js'] }; this.options = Merge(defaults, options); // File pool, any file passed into the Revisioner is stored in this object this.files = {}; this.filesTemp = []; // Stores the combined hash of all processed files, used to create the version file this.hashCombined = ''; // Stores the before : after path of assets, used to create the manifset file this.manifest = {}; // Enable / Disable logger based on supplied options this.log = (this.options.debug) ? Gutil.log : function () {}; // Make tools available client side callbacks supplied in options this.Tool = Tool; var nonFileNameChar = '[^a-zA-Z0-9\\.\\-\\_\\/]'; var qoutes = '\'|"'; function referenceToRegexs(reference) { var escapedRefPathBase = Tool.path_without_ext(reference.path).replace(/([^0-9a-z])/ig, '\\$1'); var escapedRefPathExt = Path.extname(reference.path).replace(/([^0-9a-z])/ig, '\\$1'); var regExp, regExps = []; var isJSReference = reference.path.match(/\.js$/); // Extensionless javascript file references has to to be qouted if (isJSReference) { regExp = '('+ qoutes +')(' + escapedRefPathBase + ')()('+ qoutes + '|$)'; regExps.push(new RegExp(regExp, 'g')); } // Expect left and right sides of the reference to be a non-filename type character, escape special regex chars regExp = '('+ nonFileNameChar +')(' + escapedRefPathBase + ')(' + escapedRefPathExt + ')('+ nonFileNameChar + '|$)'; regExps.push(new RegExp(regExp, 'g')); return regExps; } function annotator(contents, path) { return [{'contents': contents}]; } function replacer(fragment, replaceRegExp, newReference, referencedFile) { fragment.contents = fragment.contents.replace(replaceRegExp, '$1' + newReference + '$3$4'); } }
n/a
versionFile = function () { var revisioner; // Drop any existing files off the stream, push the generated version file return Through.obj(function (file, enc, callback) { if (!revisioner) { revisioner = file.revisioner; } // Drop any existing files off the stream callback(); }, function (callback) { if (!revisioner) { this.emit('error', new PluginError(PLUGIN_NAME, 'revision() must be called first!')); return callback(); } this.push(revisioner.versionFile()); callback(); }); }
...
```json
{
"css/unicorn.css": "css/unicorn.098f6bcd.css",
"js/unicorn.js": "js/unicorn.273c2cin.js"
}
```
### .versionFile()
Returns a transform function that will filter out any existing files going through the pipe and will emit a new version file. Must
be called after `.revision()`.
```js
var gulp = require('gulp');
var RevAll = require('gulp-rev-all');
gulp.task('default', function () {
...
revisioner = function (options) { var defaults = { 'hashLength': 8, 'dontGlobal': [ /^\/favicon.ico$/g ], 'dontRenameFile': [], 'dontUpdateReference': [], 'dontSearchFile': [], 'fileNameVersion': 'rev-version.json', 'fileNameManifest': 'rev-manifest.json', 'prefix': '', 'referenceToRegexs': referenceToRegexs, 'annotator': annotator, 'replacer': replacer, 'debug': false, 'includeFilesInManifest': ['.css', '.js'] }; this.options = Merge(defaults, options); // File pool, any file passed into the Revisioner is stored in this object this.files = {}; this.filesTemp = []; // Stores the combined hash of all processed files, used to create the version file this.hashCombined = ''; // Stores the before : after path of assets, used to create the manifset file this.manifest = {}; // Enable / Disable logger based on supplied options this.log = (this.options.debug) ? Gutil.log : function () {}; // Make tools available client side callbacks supplied in options this.Tool = Tool; var nonFileNameChar = '[^a-zA-Z0-9\\.\\-\\_\\/]'; var qoutes = '\'|"'; function referenceToRegexs(reference) { var escapedRefPathBase = Tool.path_without_ext(reference.path).replace(/([^0-9a-z])/ig, '\\$1'); var escapedRefPathExt = Path.extname(reference.path).replace(/([^0-9a-z])/ig, '\\$1'); var regExp, regExps = []; var isJSReference = reference.path.match(/\.js$/); // Extensionless javascript file references has to to be qouted if (isJSReference) { regExp = '('+ qoutes +')(' + escapedRefPathBase + ')()('+ qoutes + '|$)'; regExps.push(new RegExp(regExp, 'g')); } // Expect left and right sides of the reference to be a non-filename type character, escape special regex chars regExp = '('+ nonFileNameChar +')(' + escapedRefPathBase + ')(' + escapedRefPathExt + ')('+ nonFileNameChar + '|$)'; regExps.push(new RegExp(regExp, 'g')); return regExps; } function annotator(contents, path) { return [{'contents': contents}]; } function replacer(fragment, replaceRegExp, newReference, referencedFile) { fragment.contents = fragment.contents.replace(replaceRegExp, '$1' + newReference + '$3$4'); } }
n/a
calculateHash = function (file, stack) { stack = stack || []; var hash = file.revHashOriginal; stack.push(file); // Resolve hash for child references if (Object.keys(file.revReferenceFiles).length > 0) { for (var key in file.revReferenceFiles) { // Prevent infinite loops caused by circular references, don't recurse if we've already encountered this file if (stack.indexOf(file.revReferenceFiles[key]) === -1) { hash += this.calculateHash(file.revReferenceFiles[key], stack); } } // This file's hash should change if any of its references will be prefixed. if (this.options.prefix && Object.keys(file.referenceGroupsContainer.absolute).length) { hash += this.options.prefix; } // Consolidate many hashes into one hash = this.Tool.md5(hash); } return hash; }
...
// Resolve hash for child references
if (Object.keys(file.revReferenceFiles).length > 0) {
for (var key in file.revReferenceFiles) {
// Prevent infinite loops caused by circular references, don't recurse if we've already encountered this file
if (stack.indexOf(file.revReferenceFiles[key]) === -1) {
hash += this.calculateHash(file.revReferenceFiles[key], stack);
}
}
// This file's hash should change if any of its references will be prefixed.
if (this.options.prefix &&
Object.keys(file.referenceGroupsContainer.absolute).length) {
...
manifestFile = function () { var file = new Gutil.File({ cwd: this.pathCwd, base: this.pathBase, path: Path.join(this.pathBase, this.options.fileNameManifest), contents: new Buffer(JSON.stringify(this.manifest, null, 2)), }); file.revisioner = this; return file; }
...
* See [gulp-awspublish](https://www.npmjs.org/package/gulp-awspublish), [gulp-cloudfront](https://www.npmjs.org/package/gulp-cloudfront
)
## Methods
### .revision({ options })
Returns a transform function that can be used to pipe files through so that they may be revisioned, also corrects refererences to
said files.
### .manifestFile()
Returns a transform function that will filter out any existing files going through the pipe and will emit a new manifest file.
Must be called after `.revision()`.
```js
var gulp = require('gulp');
var RevAll = require('gulp-rev-all');
gulp.task('default', function () {
...
processFile = function (file) { if (!this.pathCwd) { this.pathCwd = file.cwd; } // Chnage relative paths to absolute if (!file.base.match(/^(\/|[a-z]:)/i)) { file.base = Tool.join_path(file.cwd, file.base); } // Normalize the base common to all the files if (!this.pathBase) { this.pathBase = file.base; } else if (file.base.indexOf(this.pathBase) === -1) { var levelsBase = this.pathBase.split(/[\/|\\]/); var levelsFile = file.base.split(/[\/|\\]/); var common = []; for (var level = 0, length = levelsFile.length; level < length; level++) { if (level < levelsBase.length && level < levelsFile.length && levelsBase[level] === levelsFile[level]) { common.push(levelsFile[level]); continue; } } if (common[common.length - 1] !== '') { common.push(''); } this.pathBase = common.join('/'); } // Set original values before any processing occurs file.revPathOriginal = file.revOrigPath = file.path; file.revFilenameExtOriginal = Path.extname(file.path); file.revFilenameOriginal = Path.basename(file.path, file.revFilenameExtOriginal); file.revHashOriginal = this.Tool.md5(String(file.contents)); file.revContentsOriginal = file.contents; this.filesTemp.push(file); }
...
if (file.isStream()) {
this.emit('error', new PluginError(PLUGIN_NAME, 'Streams not supported!'));
return callback();
}
if (file.isBuffer()) {
revisioner.processFile(file);
}
file.revisioner = revisioner;
callback();
}, function (callback) {
...
resolveReferences = function (fileResolveReferencesIn) { var contents = String(fileResolveReferencesIn.revContentsOriginal); fileResolveReferencesIn.revReferencePaths = {}; fileResolveReferencesIn.revReferenceFiles = {}; var referenceGroupRelative = []; var referenceGroupAbsolute = []; fileResolveReferencesIn.referenceGroupsContainer = { 'relative': referenceGroupRelative, 'absolute': referenceGroupAbsolute }; // Don't try and resolve references in binary files or files that have been blacklisted if (this.Tool.is_binary_file(fileResolveReferencesIn) || !this.shouldSearchFile(fileResolveReferencesIn)) { return; } // For the current file (fileResolveReferencesIn), look for references to any other file in the project for (var path in this.files) { // Organize them by relative vs absolute reference types var fileCurrentReference = this.files[path]; var references; references = this.Tool.get_reference_representations_relative(fileCurrentReference, fileResolveReferencesIn); for (var i = 0, length = references.length; i < length; i++) { referenceGroupRelative.push({ 'file': this.files[path], 'path': references[i] }); } references = this.Tool.get_reference_representations_absolute(fileCurrentReference, fileResolveReferencesIn); for (var i = 0, length = references.length; i < length; i++) { referenceGroupAbsolute.push({ 'file': this.files[path], 'path': references[i] }); } } // Priority relative references higher than absolute for (var referenceType in fileResolveReferencesIn.referenceGroupsContainer) { var referenceGroup = fileResolveReferencesIn.referenceGroupsContainer[referenceType]; for (var referenceIndex = 0, referenceGroupLength = referenceGroup.length; referenceIndex < referenceGroupLength; referenceIndex ++) { var reference = referenceGroup[referenceIndex]; var regExps = this.options.referenceToRegexs(reference); for (var j = 0; j < regExps.length; j++) { if (contents.match(regExps[j])) { // Only register this reference if we don't have one already by the same path if (!fileResolveReferencesIn.revReferencePaths[reference.path]) { fileResolveReferencesIn.revReferenceFiles[reference.file.path] = reference.file; fileResolveReferencesIn.revReferencePaths[reference.path] = { 'regExps': [regExps[j]], 'file': reference.file, 'path': reference.path }; this.log('gulp-rev-all:', 'Found', referenceType, 'reference [', Gutil.colors.magenta(reference.path), '] -> [', Gutil .colors.green(reference.file.path), '] in [', Gutil.colors.blue(fileResolveReferencesIn.revPathOriginal), ']'); } else if (fileResolveReferencesIn.revReferencePaths[reference.path].file.revPathOriginal === reference.file.revPathOriginal ) { // Append the other regexes to account for inconsitent use fileResolveReferencesIn.revReferencePaths[reference.path].regExps.push(regExps[j]); } else { this.log('gulp-rev-all:', 'Possible ambiguous reference detected [', Gutil.colors.red(fileResolveReferencesIn.revReferencePaths [reference.path].path), ' (', fileResolveReferencesIn.revReferencePaths[reference.path].file.revPathOriginal, ')] <-> [', Gutil. colors.red(reference.path), '(', Gutil.colors.red(reference.file.revPathOriginal), ')]'); } } } } } }
...
var path = this.Tool.get_relative_path(this.pathBase, this.filesTemp[i].path);
this.files[path] = this.filesTemp[i];
}
// Resolve references to other files
for (var path in this.files) {
this.resolveReferences(this.files[path]);
}
// Resolve and set revisioned filename based on hash + reference hashes and ignore rules
for (var path in this.files) {
this.revisionFilename(this.files[path]);
}
...
revisionFilename = function (file) { var filename = file.revFilenameOriginal; var ext = file.revFilenameExtOriginal; file.revHash = this.calculateHash(file); // Allow the client to transform the final filename if (this.options.transformFilename) { filename = this.options.transformFilename.call(this, file, file.revHash); } else { filename = filename + '.' + file.revHash.substr(0, this.options.hashLength) + ext; } file.revFilename = filename; // file.revFilenameNoExt = Tool.path_without_ext(file.revFilename); if (this.shouldFileBeRenamed(file)) { file.path = this.Tool.join_path(Path.dirname(file.path), filename); } // Maintain the combined hash used in version file this.hashCombined += file.revHash; // Maintain the manifset file var pathOriginal = this.Tool.get_relative_path(this.pathBase, file.revPathOriginal, true); var pathRevisioned = this.Tool.get_relative_path(file.base, file.path, true); // Add only specific file types to the manifest file if (this.options.includeFilesInManifest.indexOf(ext) !== -1) { this.manifest[pathOriginal] = pathRevisioned; } file.revPath = pathRevisioned; }
...
// Resolve references to other files
for (var path in this.files) {
this.resolveReferences(this.files[path]);
}
// Resolve and set revisioned filename based on hash + reference hashes and ignore rules
for (var path in this.files) {
this.revisionFilename(this.files[path]);
}
// Consolidate the concatinated hash of all the files, into a single hash for the version file
this.hashCombined = this.Tool.md5(this.hashCombined);
// Update references to revisioned filenames
for (var path in this.files) {
...
run = function () { this.hashCombined = ''; // Go through and correct the base path now that we have proccessed all the files coming in for (var i = 0, length = this.filesTemp.length; i < length; i++) { this.filesTemp[i].base = this.pathBase; var path = this.Tool.get_relative_path(this.pathBase, this.filesTemp[i].path); this.files[path] = this.filesTemp[i]; } // Resolve references to other files for (var path in this.files) { this.resolveReferences(this.files[path]); } // Resolve and set revisioned filename based on hash + reference hashes and ignore rules for (var path in this.files) { this.revisionFilename(this.files[path]); } // Consolidate the concatinated hash of all the files, into a single hash for the version file this.hashCombined = this.Tool.md5(this.hashCombined); // Update references to revisioned filenames for (var path in this.files) { this.updateReferences(this.files[path]); } }
...
file.revisioner = revisioner;
callback();
}, function (callback) {
revisioner.run();
var files = revisioner.files;
for (var filename in files) {
this.push(files[filename]);
}
callback();
...
shouldFileBeRenamed = function (file) { var filename = this.Tool.get_relative_path(file.base, file.revPathOriginal); for (var i = this.options.dontGlobal.length; i--;) { var regex = (this.options.dontGlobal[i] instanceof RegExp) ? this.options.dontGlobal[i] : new RegExp(this.options.dontGlobal [i] + '$', 'ig'); if (filename.match(regex)) { return false; } } for (var i = this.options.dontRenameFile.length; i--;) { var regex = (this.options.dontRenameFile[i] instanceof RegExp) ? this.options.dontRenameFile[i] : new RegExp(this.options.dontRenameFile [i] + '$', 'ig'); if (filename.match(regex)) { return false; } } return true; }
...
} else {
filename = filename + '.' + file.revHash.substr(0, this.options.hashLength) + ext;
}
file.revFilename = filename;
// file.revFilenameNoExt = Tool.path_without_ext(file.revFilename);
if (this.shouldFileBeRenamed(file)) {
file.path = this.Tool.join_path(Path.dirname(file.path), filename);
}
// Maintain the combined hash used in version file
this.hashCombined += file.revHash;
// Maintain the manifset file
...
shouldSearchFile = function (file) { var filename = this.Tool.get_relative_path(file.base, file.revPathOriginal); for (var i = this.options.dontGlobal.length; i--;) { var regex = (this.options.dontGlobal[i] instanceof RegExp) ? this.options.dontGlobal[i] : new RegExp(this.options.dontGlobal [i] + '$', 'ig'); if (filename.match(regex)) { return false; } } for (var i = this.options.dontSearchFile.length; i--;) { var regex = (this.options.dontSearchFile[i] instanceof RegExp) ? this.options.dontSearchFile[i] : new RegExp(this.options.dontSearchFile [i] + '$', 'ig'); if (filename.match(regex)) { return false; } } return true; }
...
var referenceGroupAbsolute = [];
fileResolveReferencesIn.referenceGroupsContainer = {
'relative': referenceGroupRelative,
'absolute': referenceGroupAbsolute
};
// Don't try and resolve references in binary files or files that have been blacklisted
if (this.Tool.is_binary_file(fileResolveReferencesIn) || !this.shouldSearchFile(fileResolveReferencesIn
)) {
return;
}
// For the current file (fileResolveReferencesIn), look for references to any other file in the project
for (var path in this.files) {
// Organize them by relative vs absolute reference types
...
shouldUpdateReference = function (file) { var filename = this.Tool.get_relative_path(file.base, file.revPathOriginal); for (var i = this.options.dontGlobal.length; i--;) { var regex = (this.options.dontGlobal[i] instanceof RegExp) ? this.options.dontGlobal[i] : new RegExp(this.options.dontGlobal [i] + '$', 'ig'); if (filename.match(regex)) { return false; } } for (var i = this.options.dontUpdateReference.length; i--;) { var regex = (this.options.dontUpdateReference[i] instanceof RegExp) ? this.options.dontUpdateReference[i] : new RegExp(this. options.dontUpdateReference[i] + '$', 'ig'); if (filename.match(regex)) { return false; } } return true; }
...
// Transform path using client supplied transformPath callback,
pathReferenceReplace = this.options.transformPath.call(this, pathReferenceReplace, reference.path, reference.file, file);
} else if (this.options.prefix && pathReferenceReplace[0] === '/') {
// Append with user supplied prefix
pathReferenceReplace = this.Tool.join_path_url(this.options.prefix, pathReferenceReplace);
}
if (this.shouldUpdateReference(reference.file)) {
// The extention should remain constant so we dont add extentions to references without extentions
var noExtReplace = Tool.path_without_ext(pathReferenceReplace);
for(var i = 0; i < annotatedContent.length; i++){
for(var j = 0; j < reference.regExps.length; j++){
this.options.replacer(annotatedContent[i], reference.regExps[j], noExtReplace, reference.file);
}
...
updateReferences = function (file) { // Don't try and update references in binary files or blacklisted files if (this.Tool.is_binary_file(file) || !this.shouldSearchFile(file)) { return; } var contents = String(file.revContentsOriginal); var annotatedContent = this.options.annotator(contents, file.revPathOriginal); for (var pathReference in file.revReferencePaths) { var reference = file.revReferencePaths[pathReference]; // Replace regular filename with revisioned version var referencePath = reference.path.substr(0, reference.path.length - (reference.file.revFilenameOriginal.length + reference. file.revFilenameExtOriginal.length)); var pathReferenceReplace = referencePath + reference.file.revFilename; if (this.options.transformPath) { // Transform path using client supplied transformPath callback, pathReferenceReplace = this.options.transformPath.call(this, pathReferenceReplace, reference.path, reference.file, file); } else if (this.options.prefix && pathReferenceReplace[0] === '/') { // Append with user supplied prefix pathReferenceReplace = this.Tool.join_path_url(this.options.prefix, pathReferenceReplace); } if (this.shouldUpdateReference(reference.file)) { // The extention should remain constant so we dont add extentions to references without extentions var noExtReplace = Tool.path_without_ext(pathReferenceReplace); for(var i = 0; i < annotatedContent.length; i++){ for(var j = 0; j < reference.regExps.length; j++){ this.options.replacer(annotatedContent[i], reference.regExps[j], noExtReplace, reference.file); } } } } contents = annotatedContent.map(function(annotation) { return annotation.contents; }).join(''); file.contents = new Buffer(contents); }
...
}
// Consolidate the concatinated hash of all the files, into a single hash for the version file
this.hashCombined = this.Tool.md5(this.hashCombined);
// Update references to revisioned filenames
for (var path in this.files) {
this.updateReferences(this.files[path]);
}
};
/**
* Go through each file in the file pool, search for references to any other file in the pool.
*/
...
versionFile = function () { var out = { hash: this.hashCombined, timestamp: new Date() }; var file = new Gutil.File({ cwd: this.pathCwd, base: this.pathBase, path: Path.join(this.pathBase, this.options.fileNameVersion), contents: new Buffer(JSON.stringify(out, null, 2)), revisioner: this }); file.revisioner = this; return file; }
...
```json
{
"css/unicorn.css": "css/unicorn.098f6bcd.css",
"js/unicorn.js": "js/unicorn.273c2cin.js"
}
```
### .versionFile()
Returns a transform function that will filter out any existing files going through the pipe and will emit a new version file. Must
be called after `.revision()`.
```js
var gulp = require('gulp');
var RevAll = require('gulp-rev-all');
gulp.task('default', function () {
...
get_reference_representations_absolute = function (fileCurrentReference, file) { var representations = []; var representation; // Scenario 1: Current file is anywhere // /view/index.html (reference: absolute) representations.push(get_relative_path(fileCurrentReference.base, fileCurrentReference.revPathOriginal, false)); // Without starting slash, only if it contains a directory // view/index.html (reference: absolute, without slash prefix) representation = get_relative_path(fileCurrentReference.base, fileCurrentReference.revPathOriginal, true); if (representation.indexOf('/')) { representations.push(representation); } return representations; }
...
path: '/first/second/third/script.js',
base: base
});
file.revPathOriginal = file.path;
fileReference.revPathOriginal = fileReference.path;
var references = Tool.get_reference_representations_absolute(fileReference, file);
references.length.should.equal(2);
references[0].should.equal('/third/script.js');
references[1].should.equal('third/script.js');
});
...
get_reference_representations_relative = function (fileCurrentReference, file) { var representations = []; // Scenario 2: Current file is the same directory or lower than the reference // (ie. file.path and the reference file.path are the same) // // file.base = /user/project // file.path = /user/project/second/current_file.html // fileCurrentReference.path = /user/project/second/index.html if (dirname_with_sep(fileCurrentReference.path).indexOf(dirname_with_sep(file.path)) === 0) { // index.html representations.push(get_relative_path(Path.dirname(file.path), fileCurrentReference.revPathOriginal, true)); // ./index.html (reference: relative) representations.push('.' + get_relative_path(Path.dirname(file.path), fileCurrentReference.revPathOriginal, false)); } // Scenario 3: Current file is in a different child directory than the reference // (ie. file.path and the reference file.path are different, not in root directory) // // file.base = /user/project // file.path = /user/project/first/index.html // fileCurrentReference.path = /user/project/second/index.html if (dirname_with_sep(file.path) !== dirname_with_sep(fileCurrentReference.path) && dirname_with_sep(fileCurrentReference.path).indexOf(dirname_with_sep(file.path)) === -1) { var pathCurrentReference = dirname_with_sep(get_relative_path(fileCurrentReference.base, fileCurrentReference.revPathOriginal )); var pathFile = dirname_with_sep(get_relative_path(file.base, file.revPathOriginal)); // ../second/index.html var relPath = Path.relative(pathFile, pathCurrentReference); relPath = relPath.replace(/\\/g, '/'); representations.push(relPath + '/' + Path.basename(fileCurrentReference.revPathOriginal)); } return representations; }
...
path: '/first/second/third/script.js',
base: base
});
file.revPathOriginal = file.path;
fileReference.revPathOriginal = fileReference.path;
var references = Tool.get_reference_representations_relative(fileReference, file);
references.length.should.equal(2);
references[0].should.equal('script.js');
references[1].should.equal('./script.js');
});
...
get_relative_path = function (base, path, noStartingSlash) { if (base === path) { return ''; } // Sanitize inputs, convert windows to posix style slashes, ensure trailing slash for base base = base.replace(/^[a-z]:/i, '').replace(/\\/g, '/').replace(/\/$/g, '') + '/'; path = path.replace(/^[a-z]:/i, '').replace(/\\/g, '/'); // Only truncate paths that overap with the base if (base === path.substr(0, base.length)) { path = '/' + path.substr(base.length); } var modifyStartingSlash = noStartingSlash !== undefined; if (modifyStartingSlash) { if (path[0] === '/' && noStartingSlash) { path = path.substr(1); } else if (path[0] !== '/' && !noStartingSlash){ path = '/' + path; } } return path; }
...
});
describe('get_relative_path', function () {
it('should only truncate paths that overap with the base', function () {
Tool.get_relative_path('/base/', 'sub/index.html').should.equal
('sub/index.html');
Tool.get_relative_path('/base/', '/sub/index.html').should.equal('/sub/index.html');
Tool.get_relative_path('/base/', '/base/sub/index.html').should.equal('/sub/index.html');
});
describe('windows', function () {
...
is_binary_file = function (file) { var length = (file.contents.length > 50) ? 50 : file.contents.length; for (var i = 0; i < length; i++) { if (file.contents[i] === 0) { return true; } } return false; }
...
var referenceGroupAbsolute = [];
fileResolveReferencesIn.referenceGroupsContainer = {
'relative': referenceGroupRelative,
'absolute': referenceGroupAbsolute
};
// Don't try and resolve references in binary files or files that have been blacklisted
if (this.Tool.is_binary_file(fileResolveReferencesIn) || !this.shouldSearchFile(fileResolveReferencesIn
)) {
return;
}
// For the current file (fileResolveReferencesIn), look for references to any other file in the project
for (var path in this.files) {
// Organize them by relative vs absolute reference types
...
join_path = function (directory, filename) { return Path.join(directory, filename).replace(/^[a-z]:\\/i, '/').replace(/\\/g, '/'); }
...
describe('joinPath', function () {
describe('windows', function () {
it('should correct slashes', function () {
Tool.join_path('d:\\first\\second', 'images.png').should.equal(
x27;/first/second/images.png');
});
it('should not add starting slash', function () {
Tool.join_path('first\\second', 'images.png').should.equal('first/second/images.png');
...
join_path_url = function (prefix, path) { prefix = prefix.replace(/\/$/, ''); path = path.replace(/^\//, ''); return [ prefix, path ].join('/'); }
...
});
it('should replaced references using transform if it is supplied', function (done) {
setup({
transformPath: function (reved, source, path) {
return this.Tool.join_path_url('//images.example.com/', reved.replace('
;img/', ''));
}
});
streamRevision.on('data', function () {});
streamRevision.on('end', function () {
String(files['/index.html'].contents).should.match(/\/\/images\.example\.com\/image1\.[a-z0-9]{8}\.jpg/);
...
md5 = function (str) { return crypto.createHash('md5').update(str, 'utf8').digest('hex'); }
...
}
// Set original values before any processing occurs
file.revPathOriginal = file.revOrigPath = file.path;
file.revFilenameExtOriginal = Path.extname(file.path);
file.revFilenameOriginal = Path.basename(file.path, file.revFilenameExtOriginal);
file.revHashOriginal = this.Tool.md5(String(file.contents));
file.revContentsOriginal = file.contents;
this.filesTemp.push(file);
};
/**
...
path_without_ext = function (path) { var ext = Path.extname(path); return path.substr(0, path.length - ext.length); }
...
this.Tool = Tool;
var nonFileNameChar = '[^a-zA-Z0-9\\.\\-\\_\\/]';
var qoutes = '\'|"';
function referenceToRegexs(reference) {
var escapedRefPathBase = Tool.path_without_ext(reference.path).replace(/([^0-9a-z])/ig
, '\\$1');
var escapedRefPathExt = Path.extname(reference.path).replace(/([^0-9a-z])/ig, '\\$1');
var regExp, regExps = [];
var isJSReference = reference.path.match(/\.js$/);
// Extensionless javascript file references has to to be qouted
if (isJSReference) {
...