├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── index.js
├── package.json
├── test.js
└── utils.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 'stable'
4 | - '0.12'
5 | - '0.10'
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 James K Nelson
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [gulp](https://github.com/wearefractal/gulp)-rev-replace [](https://travis-ci.org/jamesknelson/gulp-rev-replace)
2 | ================
3 |
4 | Rewrite occurrences of filenames which have been renamed by gulp-rev
5 |
6 | ### Note: this package is no longer maintained. Development continues in [TheDancingCode/gulp-rev-rewrite](https://github.com/TheDancingCode/gulp-rev-rewrite).
7 |
8 | ## Install
9 |
10 | ```bash
11 | $ npm install --save-dev gulp-rev-replace
12 | ```
13 |
14 |
15 | ## Usage
16 |
17 | Pipe through a stream which has both the files you want to be updated, as well as the files which have been renamed.
18 |
19 | For example, we can use [gulp-useref](https://github.com/jonkemp/gulp-useref) to concatenate assets in an index.html,
20 | and then use [gulp-rev](https://github.com/sindresorhus/gulp-rev) and gulp-rev-replace to cache-bust them.
21 |
22 | ```js
23 | var gulp = require('gulp');
24 | var rev = require('gulp-rev');
25 | var revReplace = require('gulp-rev-replace');
26 | var useref = require('gulp-useref');
27 | var filter = require('gulp-filter');
28 | var uglify = require('gulp-uglify');
29 | var csso = require('gulp-csso');
30 |
31 | gulp.task("index", function() {
32 | var jsFilter = filter("**/*.js", { restore: true });
33 | var cssFilter = filter("**/*.css", { restore: true });
34 | var indexHtmlFilter = filter(['**/*', '!**/index.html'], { restore: true });
35 |
36 | return gulp.src("src/index.html")
37 | .pipe(useref()) // Concatenate with gulp-useref
38 | .pipe(jsFilter)
39 | .pipe(uglify()) // Minify any javascript sources
40 | .pipe(jsFilter.restore)
41 | .pipe(cssFilter)
42 | .pipe(csso()) // Minify any CSS sources
43 | .pipe(cssFilter.restore)
44 | .pipe(indexHtmlFilter)
45 | .pipe(rev()) // Rename the concatenated files (but not index.html)
46 | .pipe(indexHtmlFilter.restore)
47 | .pipe(revReplace()) // Substitute in new filenames
48 | .pipe(gulp.dest('public'));
49 | });
50 | ```
51 |
52 | It is also possible to use gulp-rev-replace without gulp-useref:
53 |
54 | ```js
55 | var rev = require("gulp-rev");
56 | var revReplace = require("gulp-rev-replace");
57 | gulp.task("revision", ["dist:css", "dist:js"], function(){
58 | return gulp.src(["dist/**/*.css", "dist/**/*.js"])
59 | .pipe(rev())
60 | .pipe(gulp.dest(opt.distFolder))
61 | .pipe(rev.manifest())
62 | .pipe(gulp.dest(opt.distFolder))
63 | })
64 |
65 | gulp.task("revreplace", ["revision"], function(){
66 | var manifest = gulp.src("./" + opt.distFolder + "/rev-manifest.json");
67 |
68 | return gulp.src(opt.srcFolder + "/index.html")
69 | .pipe(revReplace({manifest: manifest}))
70 | .pipe(gulp.dest(opt.distFolder));
71 | });
72 | ```
73 |
74 |
75 | ## API
76 |
77 | ### revReplace(options)
78 |
79 | #### options.canonicalUris
80 | Type: `boolean`
81 |
82 | Default: `true`
83 |
84 | Use canonical Uris when replacing filePaths, i.e. when working with filepaths
85 | with non forward slash (`/`) path separators we replace them with forward slash.
86 |
87 | #### options.replaceInExtensions
88 | Type: `Array`
89 |
90 | Default: `['.js', '.css', '.html', '.hbs']`
91 |
92 | Only substitute in new filenames in files of these types.
93 |
94 | #### options.prefix
95 | Type: `string`
96 |
97 | Default: ``
98 |
99 | Add the prefix string to each replacement.
100 |
101 | #### options.manifest
102 | Type: `Stream` (e.g., `gulp.src()`)
103 |
104 | Read JSON manifests written out by `rev`. Allows replacing filenames that were
105 | `rev`ed prior to the current task.
106 |
107 | #### options.modifyUnreved, options.modifyReved
108 | Type: `Function`
109 |
110 | Modify the name of the unreved/reved files before using them. The filename is
111 | passed to the function as the first argument.
112 |
113 | For example, if in your manifest you have:
114 |
115 | ```js
116 | {"js/app.js.map": "js/app-98adc164.js.map"}
117 | ```
118 |
119 | If you wanted to get rid of the `js/` path just for `.map` files (because they
120 | are sourcemaps and the references to them are relative, not absolute) you could
121 | do the following:
122 |
123 | ```js
124 | function replaceJsIfMap(filename) {
125 | if (filename.indexOf('.map') > -1) {
126 | return filename.replace('js/', '');
127 | }
128 | return filename;
129 | }
130 |
131 | return gulp.src(opt.distFolder + '**/*.js')
132 | .pipe(revReplace({
133 | manifest: manifest,
134 | modifyUnreved: replaceJsIfMap,
135 | modifyReved: replaceJsIfMap
136 | }))
137 | .pipe(gulp.dest(opt.distFolder));
138 | ```
139 |
140 | ## Contributors
141 |
142 | - Chad Jablonski
143 | - Denis Parchenko
144 | - Evgeniy Vasilev
145 | - George Song
146 | - Håkon K. Eide
147 | - Juan Lasheras
148 | - Majid Burney
149 | - Simon Ihmig
150 | - Vincent Voyer
151 | - Bradley Abrahams
152 |
153 |
154 | ## License
155 |
156 | [MIT](http://opensource.org/licenses/MIT) © [James K Nelson](http://jamesknelson.com)
157 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = plugin;
4 |
5 | var path = require('path');
6 | var PluginError = require('plugin-error');
7 | var through = require('through2');
8 |
9 | var utils = require('./utils');
10 |
11 | function plugin(options) {
12 | var renames = [];
13 | var cache = [];
14 |
15 | options = options || {};
16 |
17 | if (typeof options.canonicalUris === 'undefined') {
18 | options.canonicalUris = true;
19 | }
20 |
21 | options.prefix = options.prefix || '';
22 |
23 | options.replaceInExtensions = options.replaceInExtensions || ['.js', '.css', '.html', '.hbs'];
24 |
25 | return through.obj(function collectRevs(file, enc, cb) {
26 | if (file.isNull()) {
27 | this.push(file);
28 | return cb();
29 | }
30 |
31 | if (file.isStream()) {
32 | this.emit('error', new PluginError('gulp-rev-replace', 'Streaming not supported'));
33 | return cb();
34 | }
35 |
36 | // Collect renames from reved files.
37 | if (file.revOrigPath) {
38 | renames.push({
39 | unreved: fmtPath(file.revOrigBase, file.revOrigPath),
40 | reved: options.prefix + fmtPath(file.base, file.path)
41 | });
42 | }
43 |
44 | if (options.replaceInExtensions.indexOf(path.extname(file.path)) > -1) {
45 | // file should be searched for replaces
46 | cache.push(file);
47 | } else {
48 | // nothing to do with this file
49 | this.push(file);
50 | }
51 |
52 | cb();
53 | }, function replaceInFiles(cb) {
54 | var stream = this;
55 |
56 | if (options.manifest) {
57 | // Read manifest file for the list of renames.
58 | options.manifest.on('data', function (file) {
59 | var manifest = JSON.parse(file.contents.toString());
60 | Object.keys(manifest).forEach(function (srcFile) {
61 | renames.push({
62 | unreved: canonicalizeUri(srcFile),
63 | reved: options.prefix + canonicalizeUri(manifest[srcFile])
64 | });
65 | });
66 | });
67 | options.manifest.on('end', replaceContents);
68 | }
69 | else {
70 | replaceContents();
71 | }
72 |
73 | function replaceContents() {
74 | renames = renames.sort(utils.byLongestUnreved);
75 |
76 | // Once we have a full list of renames, search/replace in the cached
77 | // files and push them through.
78 | cache.forEach(function replaceInFile(file) {
79 | var contents = file.contents.toString();
80 |
81 | renames.forEach(function replaceOnce(rename) {
82 | var unreved = options.modifyUnreved ? options.modifyUnreved(rename.unreved) : rename.unreved;
83 | var reved = options.modifyReved ? options.modifyReved(rename.reved) : rename.reved;
84 | contents = contents.split(unreved).join(reved);
85 | if (options.prefix) {
86 | contents = contents.split('/' + options.prefix).join(options.prefix + '/');
87 | }
88 | });
89 |
90 | file.contents = new Buffer(contents);
91 | stream.push(file);
92 | });
93 |
94 | cb();
95 | }
96 | });
97 |
98 | function fmtPath(base, filePath) {
99 | var newPath = path.relative(base, filePath);
100 |
101 | return canonicalizeUri(newPath);
102 | }
103 |
104 | function canonicalizeUri(filePath) {
105 | if (path.sep !== '/' && options.canonicalUris) {
106 | filePath = filePath.split(path.sep).join('/');
107 | }
108 |
109 | return filePath;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gulp-rev-replace",
3 | "version": "0.4.4",
4 | "description": "Rewrite occurences of filenames which have been renamed by gulp-rev",
5 | "main": "index.js",
6 | "repository": "jamesknelson/gulp-rev-replace",
7 | "scripts": {
8 | "test": "mocha"
9 | },
10 | "keywords": [
11 | "gulpplugin",
12 | "rev",
13 | "revision",
14 | "version",
15 | "replace",
16 | "asset"
17 | ],
18 | "author": {
19 | "name": "James K Nelson",
20 | "email": "james@numbattech.com",
21 | "url": "http://jamesknelson.com"
22 | },
23 | "engines": {
24 | "node": ">=0.10.0"
25 | },
26 | "license": "MIT",
27 | "dependencies": {
28 | "plugin-error": "^0.1.2",
29 | "through2": "^2.0.0"
30 | },
31 | "devDependencies": {
32 | "event-stream": "^3.2.2",
33 | "gulp-filter": "^3.0.1",
34 | "gulp-rev": "^6.0.1",
35 | "mocha": "^2.3.4",
36 | "vinyl": "^2.1.0"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/test.js:
--------------------------------------------------------------------------------
1 | /* global it describe */
2 |
3 | 'use strict';
4 |
5 | var assert = require('assert');
6 | var filter = require('gulp-filter');
7 | var Vinyl = require('vinyl');
8 | var path = require('path');
9 | var rev = require('gulp-rev');
10 | var es = require('event-stream');
11 |
12 | var revReplace = require('./index');
13 | var utils = require('./utils');
14 |
15 | var svgFileBody = '';
16 | var cssFileBody = '@font-face { font-family: \'test\'; src: url(\'/fonts/font.svg\'); }\nbody { color: red; }';
17 | var jsFileBody = 'console.log("Hello world"); //# sourceMappingURL=app.js.map';
18 | var htmlFileBody = '

';
19 |
20 | it('should by default replace filenames in .css and .html files', function (cb) {
21 | var filesToRevFilter = filter(['**/*.css', '**/*.svg', '**/*.png'], {restore: true});
22 |
23 | var stream = filesToRevFilter
24 | .pipe(rev())
25 | .pipe(filesToRevFilter.restore)
26 | .pipe(revReplace());
27 |
28 | var fileCount = 0;
29 | var unreplacedCSSFilePattern = /style\.css/;
30 | var unreplacedSVGFilePattern = /font\.svg/;
31 | var unreplacedPNGFilePattern = /image\.png/;
32 | stream.on('data', function(file) {
33 | var contents = file.contents.toString();
34 | var extension = path.extname(file.path);
35 |
36 | if (extension === '.html') {
37 | assert(
38 | !unreplacedCSSFilePattern.test(contents),
39 | 'The renamed CSS file\'s name should be replaced'
40 | );
41 | assert(
42 | !unreplacedPNGFilePattern.test(contents),
43 | 'The renamed PNG file\'s name should be globally replaced'
44 | );
45 | } else if (extension === '.css') {
46 | assert(
47 | !unreplacedSVGFilePattern.test(contents),
48 | 'The renamed SVG file\'s name should be replaced'
49 | );
50 | } else if (extension === '.svg') {
51 | assert(
52 | contents === svgFileBody,
53 | 'The SVG file should not be modified'
54 | );
55 | }
56 |
57 | fileCount++;
58 | });
59 | stream.on('end', function() {
60 | assert.equal(fileCount, 4, 'Only four files should pass through the stream');
61 | cb();
62 | });
63 |
64 | filesToRevFilter.write(new Vinyl({
65 | path: path.join('css', 'style.css'),
66 | contents: new Buffer(cssFileBody)
67 | }));
68 | filesToRevFilter.write(new Vinyl({
69 | path: path.join('fonts', 'font.svg'),
70 | contents: new Buffer(svgFileBody)
71 | }));
72 | filesToRevFilter.write(new Vinyl({
73 | path: 'images/image.png',
74 | contents: new Buffer('PNG')
75 | }));
76 | filesToRevFilter.write(new Vinyl({
77 | path: 'index.html',
78 | contents: new Buffer(htmlFileBody)
79 | }));
80 |
81 | filesToRevFilter.end();
82 | });
83 |
84 | it('should not replace filenames in extensions not in replaceInExtensions', function (cb) {
85 | var filesToRevFilter = filter(['**/*.css'], {restore: true});
86 |
87 | var stream = filesToRevFilter
88 | .pipe(rev())
89 | .pipe(filesToRevFilter.restore)
90 | .pipe(revReplace({replaceInExtensions: ['.svg']}));
91 |
92 | var unreplacedCSSFilePattern = /style\.css/;
93 | stream.on('data', function(file) {
94 | var contents = file.contents.toString();
95 | var extension = path.extname(file.path);
96 |
97 | if (extension === '.html') {
98 | assert(
99 | unreplacedCSSFilePattern.test(contents),
100 | 'The renamed CSS file\'s name should not be replaced'
101 | );
102 | }
103 | });
104 | stream.on('end', function() {
105 | cb();
106 | });
107 |
108 | filesToRevFilter.write(new Vinyl({
109 | path: 'css\\style.css',
110 | contents: new Buffer(cssFileBody)
111 | }));
112 | filesToRevFilter.write(new Vinyl({
113 | path: 'index.html',
114 | contents: new Buffer(htmlFileBody)
115 | }));
116 |
117 | filesToRevFilter.end();
118 | });
119 |
120 | it('should not canonicalize URIs when option is off', function (cb) {
121 | var filesToRevFilter = filter(['**/*.css'], {restore: true});
122 |
123 | var stream = filesToRevFilter
124 | .pipe(rev())
125 | .pipe(filesToRevFilter.restore)
126 | .pipe(revReplace({canonicalUris: false}));
127 |
128 | var unreplacedCSSFilePattern = /style\.css/;
129 | stream.on('data', function(file) {
130 | var contents = file.contents.toString();
131 | var extension = path.extname(file.path);
132 |
133 | if (extension === '.html') {
134 | assert(
135 | unreplacedCSSFilePattern.test(contents),
136 | 'The renamed CSS file\'s name should not be replaced'
137 | );
138 | }
139 | });
140 | stream.on('end', function() {
141 | cb();
142 | });
143 |
144 | filesToRevFilter.write(new Vinyl({
145 | path: 'css\\style.css',
146 | contents: new Buffer(cssFileBody)
147 | }));
148 | filesToRevFilter.write(new Vinyl({
149 | path: 'index.html',
150 | contents: new Buffer(htmlFileBody)
151 | }));
152 |
153 | filesToRevFilter.end();
154 | });
155 |
156 |
157 | it('should add prefix to path', function (cb) {
158 | var filesToRevFilter = filter(['**/*.css'], {restore: true});
159 |
160 | var stream = filesToRevFilter
161 | .pipe(rev())
162 | .pipe(filesToRevFilter.restore)
163 | .pipe(revReplace({prefix: 'http://example.com'}));
164 |
165 | var replacedCSSFilePattern = /"http:\/\/example\.com\/css\/style-[^\.]+\.css"/;
166 | stream.on('data', function(file) {
167 | var contents = file.contents.toString();
168 | var extension = path.extname(file.path);
169 | if (extension === '.html') {
170 | assert(
171 | replacedCSSFilePattern.test(contents),
172 | 'The prefix should be added in to the file url'
173 | );
174 | }
175 | });
176 | stream.on('end', function() {
177 | cb();
178 | });
179 |
180 | filesToRevFilter.write(new Vinyl({
181 | path: 'css/style.css',
182 | contents: new Buffer(cssFileBody)
183 | }));
184 | filesToRevFilter.write(new Vinyl({
185 | path: 'index.html',
186 | contents: new Buffer(htmlFileBody)
187 | }));
188 |
189 | filesToRevFilter.end();
190 | });
191 |
192 | it('should stop at first longest replace', function(cb) {
193 | var jsFileBody = 'var loadFile = "nopestyle.css"';
194 | var replacedJsFileBody = 'var loadFile = "nopestyle-19269897ba.css"';
195 |
196 | var filesToRevFilter = filter(['**/*.css'], {restore: true});
197 |
198 | var stream = filesToRevFilter
199 | .pipe(rev())
200 | .pipe(filesToRevFilter.restore)
201 | .pipe(revReplace({canonicalUris: false}));
202 |
203 | stream.on('data', function(file) {
204 | if (file.path === 'script.js') {
205 | assert.equal(
206 | file.contents.toString(),
207 | replacedJsFileBody,
208 | 'It should have replaced using the longest string match (nopestyle)'
209 | );
210 | }
211 | });
212 | stream.on('end', function() {
213 | cb();
214 | });
215 |
216 | filesToRevFilter.write(new Vinyl({
217 | path: 'style.css',
218 | contents: new Buffer(cssFileBody)
219 | }));
220 | filesToRevFilter.write(new Vinyl({
221 | path: 'nopestyle.css',
222 | contents: new Buffer('boooooo')
223 | }));
224 | filesToRevFilter.write(new Vinyl({
225 | path: 'script.js',
226 | contents: new Buffer(jsFileBody)
227 | }));
228 |
229 | filesToRevFilter.end();
230 | });
231 |
232 | describe('manifest option', function () {
233 | it('should replace filenames from manifest files', function (cb) {
234 | var manifest = es.readArray([
235 | new Vinyl({
236 | path: '/project/rev-manifest.json',
237 | contents: new Buffer(JSON.stringify({
238 | '/css/style.css': '/css/style-12345.css'
239 | }))
240 | }),
241 | new Vinyl({
242 | path: '/project/rev-image-manifest.json',
243 | contents: new Buffer(JSON.stringify({
244 | 'images/image.png': 'images/image-12345.png',
245 | '/fonts/font.svg': '/fonts/font-12345.svg'
246 | }))
247 | })
248 | ]);
249 |
250 | var stream = revReplace({manifest: manifest});
251 |
252 | var replacedCSSFilePattern = /style-12345\.css/;
253 | var replacedSVGFilePattern = /font-12345\.svg/;
254 | var replacedPNGFilePattern = /image-12345\.png/;
255 | stream.on('data', function(file) {
256 | var contents = file.contents.toString();
257 | var extension = path.extname(file.path);
258 |
259 | if (extension === '.html') {
260 | assert(
261 | replacedCSSFilePattern.test(contents),
262 | 'The renamed CSS file\'s name should be replaced'
263 | );
264 | assert(
265 | replacedPNGFilePattern.test(contents),
266 | 'The renamed PNG file\'s name should be globally replaced'
267 | );
268 | } else if (extension === '.css') {
269 | assert(
270 | replacedSVGFilePattern.test(contents),
271 | 'The renamed SVG file\'s name should be replaced'
272 | );
273 | } else if (extension === '.svg') {
274 | assert(
275 | contents === svgFileBody,
276 | 'The SVG file should not be modified'
277 | );
278 | }
279 | });
280 | stream.on('end', function() {
281 | cb();
282 | });
283 |
284 | stream.write(new Vinyl({
285 | path: path.join('css', 'style.css'),
286 | contents: new Buffer(cssFileBody)
287 | }));
288 | stream.write(new Vinyl({
289 | path: path.join('fonts', 'font.svg'),
290 | contents: new Buffer(svgFileBody)
291 | }));
292 | stream.write(new Vinyl({
293 | path: 'index.html',
294 | contents: new Buffer(htmlFileBody)
295 | }));
296 |
297 | stream.end();
298 | });
299 |
300 | it('should add prefix to path', function (cb) {
301 | var manifest = es.readArray([
302 | new Vinyl({
303 | path: '/project/rev-manifest.json',
304 | contents: new Buffer(JSON.stringify({
305 | '/css/style.css': '/css/style-12345.css'
306 | }))
307 | })
308 | ]);
309 |
310 | var stream = revReplace({prefix: 'http://example.com', manifest: manifest});
311 |
312 | var replacedCSSFilePattern = /"http:\/\/example\.com\/css\/style-12345\.css"/;
313 | stream.on('data', function(file) {
314 | var contents = file.contents.toString();
315 | var extension = path.extname(file.path);
316 | if (extension === '.html') {
317 | assert(
318 | replacedCSSFilePattern.test(contents),
319 | 'The prefix should be added in to the file url'
320 | );
321 | }
322 | });
323 | stream.on('end', function() {
324 | cb();
325 | });
326 |
327 | stream.write(new Vinyl({
328 | path: 'index.html',
329 | contents: new Buffer(htmlFileBody)
330 | }));
331 |
332 | stream.end();
333 | });
334 | });
335 |
336 | describe('utils.byLongestUnreved', function() {
337 | it('should arrange renames from longest to shortest', function() {
338 | var renames = [{
339 | unreved: 'data/favicon.ico',
340 | reved: 'data/favicon-15d0f308.ico'
341 | }, {
342 | unreved: 'fonts/FontAwesome.otf',
343 | reved: 'fonts/FontAwesome-0b462f5c.otf'
344 | }, {
345 | unreved: 'fonts/fontawesome-webfont.eot',
346 | reved: 'fonts/fontawesome-webfont-f7c2b4b7.eot'
347 | }, {
348 | unreved: 'fonts/fontawesome-webfont.svg',
349 | reved: 'fonts/fontawesome-webfont-29800836.svg'
350 | }, {
351 | unreved: 'fonts/fontawesome-webfont.ttf',
352 | reved: 'fonts/fontawesome-webfont-706450d7.ttf'
353 | }, {
354 | unreved: 'fonts/fontawesome-webfont.woff',
355 | reved: 'fonts/fontawesome-webfont-d9ee23d5.woff'
356 | }, {
357 | unreved: 'fonts/fontawesome-webfont.woff2',
358 | reved: 'fonts/fontawesome-webfont-97493d3f.woff2'
359 | }, {
360 | unreved: 'fonts/glyphicons-halflings-regular.eot',
361 | reved: 'fonts/glyphicons-halflings-regular-f4769f9b.eot'
362 | }, {
363 | unreved: 'fonts/glyphicons-halflings-regular.svg',
364 | reved: 'fonts/glyphicons-halflings-regular-89889688.svg'
365 | }, {
366 | unreved: 'fonts/glyphicons-halflings-regular.ttf',
367 | reved: 'fonts/glyphicons-halflings-regular-e18bbf61.ttf'
368 | }, {
369 | unreved: 'fonts/glyphicons-halflings-regular.woff',
370 | reved: 'fonts/glyphicons-halflings-regular-fa277232.woff'
371 | }, {
372 | unreved: 'fonts/glyphicons-halflings-regular.woff2',
373 | reved: 'fonts/glyphicons-halflings-regular-448c34a5.woff2'
374 | }, {
375 | unreved: 'images/busy-indicator-lg-dark.gif',
376 | reved: 'images/busy-indicator-lg-dark-8f372b90.gif'
377 | }, {
378 | unreved: 'images/busy-indicator-lg-light.gif',
379 | reved: 'images/busy-indicator-lg-light-25050875.gif'
380 | }, {
381 | unreved: 'images/busy-indicator-sm-light.gif',
382 | reved: 'images/busy-indicator-sm-light-b464283c.gif'
383 | }, {
384 | unreved: 'images/footer-logo.png',
385 | reved: 'images/footer-logo-df3d73ed.png'
386 | }, {
387 | unreved: 'images/icon-progress-indicator.png',
388 | reved: 'images/icon-progress-indicator-b342c570.png'
389 | }, {
390 | unreved: 'images/scripps-swirl.png',
391 | reved: 'images/scripps-swirl-65b0319e.png'
392 | }, {
393 | unreved: 'images/sprite.png',
394 | reved: 'images/sprite-9e275087.png'
395 | }, {
396 | unreved: 'images/sprite_2x.png',
397 | reved: 'images/sprite_2x-c7af344b.png'
398 | }, {
399 | unreved: 'scripts/app.js', reved: 'scripts/app-137924b0.js'
400 | }, {
401 | unreved: 'styles/app.css', reved: 'styles/app-4858235a.css'
402 | }, {
403 | unreved: 'env/deploy/features.json',
404 | reved: 'env/deploy/features-2a501331.json'
405 | }];
406 |
407 | var expected = [{
408 | unreved: 'fonts/glyphicons-halflings-regular.woff2',
409 | reved: 'fonts/glyphicons-halflings-regular-448c34a5.woff2'
410 | }, {
411 | unreved: 'fonts/glyphicons-halflings-regular.woff',
412 | reved: 'fonts/glyphicons-halflings-regular-fa277232.woff'
413 | }, {
414 | unreved: 'fonts/glyphicons-halflings-regular.svg',
415 | reved: 'fonts/glyphicons-halflings-regular-89889688.svg'
416 | }, {
417 | unreved: 'fonts/glyphicons-halflings-regular.ttf',
418 | reved: 'fonts/glyphicons-halflings-regular-e18bbf61.ttf'
419 | }, {
420 | unreved: 'fonts/glyphicons-halflings-regular.eot',
421 | reved: 'fonts/glyphicons-halflings-regular-f4769f9b.eot'
422 | }, {
423 | unreved: 'images/busy-indicator-lg-light.gif',
424 | reved: 'images/busy-indicator-lg-light-25050875.gif'
425 | }, {
426 | unreved: 'images/busy-indicator-sm-light.gif',
427 | reved: 'images/busy-indicator-sm-light-b464283c.gif'
428 | }, {
429 | unreved: 'images/icon-progress-indicator.png',
430 | reved: 'images/icon-progress-indicator-b342c570.png'
431 | }, {
432 | unreved: 'images/busy-indicator-lg-dark.gif',
433 | reved: 'images/busy-indicator-lg-dark-8f372b90.gif'
434 | }, {
435 | unreved: 'fonts/fontawesome-webfont.woff2',
436 | reved: 'fonts/fontawesome-webfont-97493d3f.woff2'
437 | }, {
438 | unreved: 'fonts/fontawesome-webfont.woff',
439 | reved: 'fonts/fontawesome-webfont-d9ee23d5.woff'
440 | }, {
441 | unreved: 'fonts/fontawesome-webfont.eot',
442 | reved: 'fonts/fontawesome-webfont-f7c2b4b7.eot'
443 | }, {
444 | unreved: 'fonts/fontawesome-webfont.ttf',
445 | reved: 'fonts/fontawesome-webfont-706450d7.ttf'
446 | }, {
447 | unreved: 'fonts/fontawesome-webfont.svg',
448 | reved: 'fonts/fontawesome-webfont-29800836.svg'
449 | }, {
450 | unreved: 'env/deploy/features.json',
451 | reved: 'env/deploy/features-2a501331.json'
452 | }, {
453 | unreved: 'images/scripps-swirl.png',
454 | reved: 'images/scripps-swirl-65b0319e.png'
455 | }, {
456 | unreved: 'images/footer-logo.png',
457 | reved: 'images/footer-logo-df3d73ed.png'
458 | }, {
459 | unreved: 'fonts/FontAwesome.otf',
460 | reved: 'fonts/FontAwesome-0b462f5c.otf'
461 | }, {
462 | unreved: 'images/sprite_2x.png',
463 | reved: 'images/sprite_2x-c7af344b.png'
464 | }, {
465 | unreved: 'images/sprite.png',
466 | reved: 'images/sprite-9e275087.png'
467 | }, {
468 | unreved: 'data/favicon.ico',
469 | reved: 'data/favicon-15d0f308.ico'
470 | }, {
471 | unreved: 'scripts/app.js', reved: 'scripts/app-137924b0.js'
472 | }, {
473 | unreved: 'styles/app.css', reved: 'styles/app-4858235a.css'
474 | }];
475 |
476 | assert.deepEqual(renames.sort(utils.byLongestUnreved), expected);
477 | });
478 | });
479 |
480 | describe('modifyUnreved and modifyReved options', function() {
481 | it('should modify the names of reved and un-reved files', function(cb) {
482 | var manifest = es.readArray([
483 | new Vinyl({
484 | path: '/project/rev-manifest.json',
485 | contents: new Buffer(JSON.stringify({
486 | 'js/app.js.map': 'js/app-12345.js.map',
487 | 'css/style.css': 'css/style-12345.css'
488 | }))
489 | })
490 | ]);
491 |
492 | function replaceJsIfMap(filename) {
493 | if (filename.indexOf('.map') > -1) {
494 | return filename.replace('js/', '');
495 | }
496 | return filename;
497 | }
498 |
499 | var stream = revReplace({
500 | manifest: manifest,
501 | modifyUnreved: replaceJsIfMap,
502 | modifyReved: replaceJsIfMap
503 | });
504 |
505 | var replacedJSMapFilePattern = /sourceMappingURL\=app-12345\.js\.map/;
506 | var replacedCSSFilePattern = /css\/style-12345\.css/;
507 |
508 | stream.on('data', function(file) {
509 | var contents = file.contents.toString();
510 | var extension = path.extname(file.path);
511 |
512 | if (extension === '.js') {
513 | assert(
514 | replacedJSMapFilePattern.test(contents),
515 | 'The source map has been correctly replaced using modifyReved and modifyUnreved'
516 | );
517 | } else if (extension === '.html') {
518 | assert(
519 | replacedCSSFilePattern.test(contents),
520 | 'The renamed CSS file\'s name should be replaced and not affected by modifyReved or modifyUnreved'
521 | );
522 | }
523 | });
524 |
525 | stream.on('end', function() {
526 | cb();
527 | });
528 |
529 | stream.write(new Vinyl({
530 | path: path.join('js', 'app.js'),
531 | contents: new Buffer(jsFileBody)
532 | }));
533 | stream.write(new Vinyl({
534 | path: 'index.html',
535 | contents: new Buffer(htmlFileBody)
536 | }));
537 |
538 | stream.end();
539 | });
540 | });
541 |
--------------------------------------------------------------------------------
/utils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function byLongestUnreved(a, b) {
4 | return b.unreved.length - a.unreved.length;
5 | }
6 |
7 | module.exports = {
8 | byLongestUnreved: byLongestUnreved
9 | };
10 |
--------------------------------------------------------------------------------