├── .gitattributes ├── test ├── expected │ ├── nojs.html │ ├── oldDomainRel.html │ ├── nocss.css │ ├── customattrs.html │ ├── test.json │ ├── removeprefix.html │ ├── dynamicpaths.html │ ├── templates.js │ ├── staticpaths.html │ └── nested │ │ └── staticpaths.html ├── fixtures │ ├── nojs.html │ ├── oldDomainRel.html │ ├── nocss.css │ ├── customattrs.html │ ├── test.json │ ├── dynamicpaths.html │ ├── removeprefix.html │ ├── staticpaths.html │ ├── nested │ │ └── staticpaths.html │ └── templates.js └── main.js ├── .gitignore ├── .travis.yml ├── .editorconfig ├── .jshintrc ├── package.json ├── LICENSE ├── README.md └── index.js /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /test/expected/nojs.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/fixtures/nojs.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | temp/ 4 | coverage 5 | -------------------------------------------------------------------------------- /test/fixtures/oldDomainRel.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/expected/oldDomainRel.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/expected/nocss.css: -------------------------------------------------------------------------------- 1 | .foo { 2 | 3 | background: url(); 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/nocss.css: -------------------------------------------------------------------------------- 1 | .foo { 2 | 3 | background: url(); 4 | } 5 | -------------------------------------------------------------------------------- /test/expected/customattrs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /test/fixtures/customattrs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 'node' 4 | 5 | install: 6 | - npm install 7 | before_install: 8 | - 'export DISPLAY=:99.0' 9 | - 'sh -e /etc/init.d/xvfb start' 10 | addons: 11 | firefox: 'latest-esr' 12 | script: 13 | - npm test 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*.js] 5 | indent_style = tab 6 | indent_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [test/fixtures/*] 15 | insert_final_newline = false 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "camelcase": true, 6 | "curly": true, 7 | "eqeqeq": true, 8 | "immed": true, 9 | "indent": 4, 10 | "latedef": true, 11 | "newcap": true, 12 | "noarg": true, 13 | "quotmark": "double", 14 | "regexp": true, 15 | "undef": true, 16 | "unused": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "white": true 21 | } 22 | -------------------------------------------------------------------------------- /test/fixtures/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "product_id" : 3, 3 | "product_title" : "Super Widget", 4 | "main_product_image" : "/assets/images/super_widget.jpg", 5 | "secondary_images" : [ 6 | {"path":"/assets/images/super_widget1.jpg"}, 7 | {"path": "/assets/images/super_widget2.jpg"}, 8 | {"path":"/assets/images/super_widget3.jpg"}, 9 | {"path": "/assets/images/super_widget4.jpg"}] 10 | } 11 | {"product_id" : 3,"product_title" : "Super Widget","main_product_image" : "/assets/images/super_widget.jpg","secondary_images" : [{"path": "/assets/images/super_widget1.jpg"},{"path": "/assets/images/super_widget2.jpg"},{"path": "/assets/images/super_widget3.jpg"},{"path": "/assets/images/super_widget4.jpg"}]} 12 | -------------------------------------------------------------------------------- /test/expected/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "product_id" : 3, 3 | "product_title" : "Super Widget", 4 | "main_product_image" : "https://www.newDomain.com/assets/images/super_widget.jpg", 5 | "secondary_images" : [ 6 | {"path":"https://www.newDomain.com/assets/images/super_widget1.jpg"}, 7 | {"path": "https://www.newDomain.com/assets/images/super_widget2.jpg"}, 8 | {"path":"https://www.newDomain.com/assets/images/super_widget3.jpg"}, 9 | {"path": "https://www.newDomain.com/assets/images/super_widget4.jpg"}] 10 | } 11 | {"product_id" : 3,"product_title" : "Super Widget","main_product_image" : "https://www.newDomain.com/assets/images/super_widget.jpg","secondary_images" : [{"path": "https://www.newDomain.com/assets/images/super_widget1.jpg"},{"path": "https://www.newDomain.com/assets/images/super_widget2.jpg"},{"path": "https://www.newDomain.com/assets/images/super_widget3.jpg"},{"path": "https://www.newDomain.com/assets/images/super_widget4.jpg"}]} 12 | -------------------------------------------------------------------------------- /test/expected/removeprefix.html: -------------------------------------------------------------------------------- 1 | /* ----- images ---- */ 2 | 3 | 4 | /* ---- css ---- */ 5 | 6 | 7 | 8 | 9 | /* ---- js ---- */ 10 | 11 | 12 | 13 | 14 | 15 | 16 | /* --- lorem --- */ 17 | 18 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 19 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 20 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 21 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 22 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non 23 | proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gulp-assetpaths", 3 | "version": "0.3.3", 4 | "description": "A Gulp plugin to change asset paths from one environment to another.", 5 | "keywords": [ 6 | "gulpplugin", 7 | "cdn", 8 | "images", 9 | "domains", 10 | "assets", 11 | "urls", 12 | "paths" 13 | ], 14 | "author": { 15 | "name": "Chris Wales", 16 | "email": "qwales1@gmail.com", 17 | "url": "https://github.com/qwales1" 18 | }, 19 | "repository": "qwales1/gulp-assetpaths", 20 | "scripts": { 21 | "test": "mocha test/*.js --reporter spec" 22 | }, 23 | "bugs": { 24 | "url": "https://github.com/qwales1/gulp-assetpaths/issues", 25 | "email": "qwales1@gmail.com" 26 | }, 27 | "dependencies": { 28 | "plugin-error": "^1.0.1", 29 | "through2": "^3.0.0" 30 | }, 31 | "devDependencies": { 32 | "event-stream": "3.3.4", 33 | "mocha": "^5.2.0", 34 | "should": "^13.2.3", 35 | "vinyl": "^2.2.0" 36 | }, 37 | "engines": { 38 | "node": ">=0.8.0", 39 | "npm": ">=1.2.10" 40 | }, 41 | "license": "MIT" 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2014 Chris Wales 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /test/fixtures/dynamicpaths.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | 14 | 15 | 16 | /* --- lorem --- */ 17 | 18 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 19 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 20 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 21 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 22 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non 23 | proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 24 | -------------------------------------------------------------------------------- /test/expected/dynamicpaths.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 42 | 43 | 44 | 45 | 46 | /* --- lorem --- */ 47 | 48 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 49 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 50 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 51 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 52 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non 53 | proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 54 | -------------------------------------------------------------------------------- /test/fixtures/nested/staticpaths.html: -------------------------------------------------------------------------------- 1 | /* ----- images ---- */ 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | .test { 28 | background : url(images/test.jpg); 29 | background : url(/images/test.jpg); 30 | background : url(https://www.oldDomain.com/images/test.jpg); 31 | } 32 | 33 | 34 | /* ---- css ---- */ 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | /* ---- js ---- */ 43 | 44 | 45 | 46 | 47 | 48 | 49 | /* --- lorem --- */ 50 | 51 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 52 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 53 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 54 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 55 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non 56 | proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | gulp-assetpaths 2 | =============== 3 | [![Build Status](https://travis-ci.org/qwales1/gulp-assetpaths.svg?branch=master)](https://travis-ci.org/qwales1/gulp-assetpaths) 4 | 5 | Change paths of assets from one environment to another 6 | Works for anything included with href, src, or url attributes 7 | ```javascript 8 | var assetpaths = require('gulp-assetpaths'); 9 | 10 | gulp.task('change-paths', function(){ 11 | return gulp.src(['./*.html']) 12 | .pipe(assetpaths({ 13 | newDomain: 'www.thenewdomain.com', 14 | oldDomain : 'www.theolddomain.com', 15 | docRoot : 'public_html', 16 | filetypes : ['jpg','jpeg','png','ico','gif','js','css'], 17 | customAttributes: ['data-custom'], 18 | templates: true 19 | })) 20 | .pipe(gulp.dest('../dist')); 21 | }); 22 | ``` 23 | 24 | ### options.newDomain - string 25 | 26 | the new domain 27 | 28 | ### options.oldDomain - string 29 | 30 | the old domain to replace if it was a full path. Anything that doesn't match this domain will be ignored so if you use CDNs for third party code those paths will not be changed. 31 | 32 | ### options.docRoot - string 33 | 34 | this will anchor all relative paths to the document root of your project. An example would be in your css file you include 35 | ``url(images/example.png)`` in a selector. All the directories up to the document root will be prepended to the images/example.png path giving you: 36 | ``url(http://www.thenewdomain.com/css/images/example.png)`` 37 | 38 | ### options.customAttributes 39 | 40 | an array of custom attributes you want to replace the paths of 41 | Ex. `` 42 | 43 | ### options.templates - boolean (true by default) 44 | 45 | If this option is false, only paths to filetypes that are explicitly in the filetypes array will be replaced. 46 | 47 | If true, it will attempt to replace paths to static assets in templates. These paths will be changed : 48 | 49 | all image tags 50 | all css background or background-image properties 51 | all script tags 52 | tags that have a href attribute with a download attribute in the same tag 53 | ```` 54 | 55 | 56 | ### options.filetypes 57 | 58 | Array of filetypes to change the path for. 59 | 60 | 61 | ## Use 62 | 63 | I used this to convert websites to start serving their static assets from a CDN. 64 | 65 | NOTE: This plugin assumes that any paths in a database or other other data sources are relative to the root directory if you are using server side or client side templating. Full paths in the database will give you the wrong path. 66 | 67 | ``/assets/images/image.png - OK`` 68 | 69 | ``http://www.oldDomain.com/assets/images/image.png - FAIL`` 70 | 71 | ``assets/images/image.png - FAIL`` 72 | 73 | Again that is only for dynamically generated paths. All of those examples in code will be replaced correctly. 74 | -------------------------------------------------------------------------------- /test/fixtures/templates.js: -------------------------------------------------------------------------------- 1 | //static in template 2 | define(function(){this["JST"] = this["JST"] || {};this["JST"]["app/scripts/templates/AsamPromo.ejs"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
\n\n\t
\n\n\t\t\n\n\t
\n\t
\n\n\n\t\t

Special Offer

\n\t\t

Order the new edition of The ASAM Criteria and get free 45-day access to the beta enhanced web-based version. \n\t\tAfter the 45-day trial, two subscription add-ons will be available for purchase.

\n\t\t
\n\n\t\t\tORDER NOW!\n\t\t
\n\t
\n
\n\n\n';'
\n\n\t
\n\n\t\t\n\n\t
\n\t
\n\n\n\t\t

Special Offer

\n\t\t

Order the new edition of The ASAM Criteria and get free 45-day access to the beta enhanced web-based version. \n\t\tAfter the 45-day trial, two subscription add-ons will be available for purchase.

\n\t\t
\n\n\t\t\tORDER NOW!\n\t\t
\n\t
\n
\n\n\n';}return __p}; 3 | //dynamic in template 4 | this["JST"]["app/scripts/templates/Access.ejs"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
\n\t
\n\t\t
\n\t\t\t
\n\t\t\t\t\n\t\t\t
\n\t\t
\n\t\t
\n\t\t\t
\n\t\t\t\t
' +((__t = ( dProductTitle )) == null ? '' : __t) +'
\n\t\t\t
\n\t\t
\n\t
\n\t
\n\t\t'; if(dProductTrackable === 1){ ;__p += '\n\t\t
\n\t\t\t
Complete
\n\t\t\t
\n\t\t\t\t\t'; if(dComplete == 1){ ;__p += '\n\t\t\t\t\t\n\t\t\t\t\t'; } else { ;__p += '\n\t\t\t\t\t\n\t\t\t\t\t'; } ;__p += '\n\n\n\t\t\t
\n\t\t\t\n\t\t
\n\t\t'; } ;__p += '\n\t\t
\n\t\t\t
Last Access:
\n\t\t\t'; if(dLastAccess){ ;__p += '\n\t\t\t
' +((__t = ( moment(dLastAccess).format('MMM Do, YYYY') )) == null ? '' : __t) +'
\n\t\t\t
' +((__t = ( moment(dLastAccess).format('h:mm A') )) == null ? '' : __t) +'
\n\t\t\t'; } else { ;__p += '\n\n\t\t\t

Never

\n\t\t\t'; } ;__p += '\n\n\n\t\t
\n\n\n\n\t
\n\n\n\n
\n\n';}return __p}; 5 | -------------------------------------------------------------------------------- /test/expected/templates.js: -------------------------------------------------------------------------------- 1 | //static in template 2 | define(function(){this["JST"] = this["JST"] || {};this["JST"]["app/scripts/templates/AsamPromo.ejs"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
\n\n\t
\n\n\t\t\n\n\t
\n\t
\n\n\n\t\t

Special Offer

\n\t\t

Order the new edition of The ASAM Criteria and get free 45-day access to the beta enhanced web-based version. \n\t\tAfter the 45-day trial, two subscription add-ons will be available for purchase.

\n\t\t
\n\n\t\t\tORDER NOW!\n\t\t
\n\t
\n
\n\n\n';'
\n\n\t
\n\n\t\t\n\n\t
\n\t
\n\n\n\t\t

Special Offer

\n\t\t

Order the new edition of The ASAM Criteria and get free 45-day access to the beta enhanced web-based version. \n\t\tAfter the 45-day trial, two subscription add-ons will be available for purchase.

\n\t\t
\n\n\t\t\tORDER NOW!\n\t\t
\n\t
\n
\n\n\n';}return __p}; 3 | //dynamic in template 4 | this["JST"]["app/scripts/templates/Access.ejs"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
\n\t
\n\t\t
\n\t\t\t
\n\t\t\t\t\n\t\t\t
\n\t\t
\n\t\t
\n\t\t\t
\n\t\t\t\t
' +((__t = ( dProductTitle )) == null ? '' : __t) +'
\n\t\t\t
\n\t\t
\n\t
\n\t
\n\t\t'; if(dProductTrackable === 1){ ;__p += '\n\t\t
\n\t\t\t
Complete
\n\t\t\t
\n\t\t\t\t\t'; if(dComplete == 1){ ;__p += '\n\t\t\t\t\t\n\t\t\t\t\t'; } else { ;__p += '\n\t\t\t\t\t\n\t\t\t\t\t'; } ;__p += '\n\n\n\t\t\t
\n\t\t\t\n\t\t
\n\t\t'; } ;__p += '\n\t\t
\n\t\t\t
Last Access:
\n\t\t\t'; if(dLastAccess){ ;__p += '\n\t\t\t
' +((__t = ( moment(dLastAccess).format('MMM Do, YYYY') )) == null ? '' : __t) +'
\n\t\t\t
' +((__t = ( moment(dLastAccess).format('h:mm A') )) == null ? '' : __t) +'
\n\t\t\t'; } else { ;__p += '\n\n\t\t\t

Never

\n\t\t\t'; } ;__p += '\n\n\n\t\t
\n\n\n\n\t
\n\n\n\n
\n\n';}return __p}; 5 | -------------------------------------------------------------------------------- /test/expected/staticpaths.html: -------------------------------------------------------------------------------- 1 | /* ----- images ---- */ 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | .test { 25 | background : url(https://www.newDomain.com/fixtures/images/test.jpg); 26 | background : url(https://www.newDomain.com/images/test.jpg); 27 | background : url(https://www.newDomain.com/images/test.jpg); 28 | } 29 | 30 | 31 | /* ---- css ---- */ 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | /* ---- js ---- */ 40 | 41 | 42 | 43 | 44 | 45 | 46 | /* --- lorem --- */ 47 | 48 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 49 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 50 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 51 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 52 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non 53 | proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 54 | -------------------------------------------------------------------------------- /test/expected/nested/staticpaths.html: -------------------------------------------------------------------------------- 1 | /* ----- images ---- */ 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | .test { 28 | background : url(https://www.newDomain.com/fixtures/nested/images/test.jpg); 29 | background : url(https://www.newDomain.com/images/test.jpg); 30 | background : url(https://www.newDomain.com/images/test.jpg); 31 | } 32 | 33 | 34 | /* ---- css ---- */ 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | /* ---- js ---- */ 43 | 44 | 45 | 46 | 47 | 48 | 49 | /* --- lorem --- */ 50 | 51 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 52 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 53 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 54 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 55 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non 56 | proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 57 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var PluginError = require('plugin-error'); 2 | var through = require('through2'); 3 | 4 | module.exports = function(opts) { 5 | var rootRegEx; 6 | 7 | if (!opts) { 8 | throw new PluginError('gulp-assetpaths', 'No parameters supplied'); 9 | } 10 | if (!opts.filetypes || !opts.filetypes instanceof Array) { 11 | throw new PluginError( 12 | 'gulp-assetpaths', 13 | 'Missing parameter : filetypes' 14 | ); 15 | } 16 | if (typeof opts.newDomain !== 'string' && !opts.newDomain) { 17 | throw new PluginError( 18 | 'gulp-assetpaths', 19 | 'Missing parameter : newDomain' 20 | ); 21 | } 22 | if (!opts.oldDomain) { 23 | throw new PluginError( 24 | 'gulp-assetpaths', 25 | 'Missing parameter : oldDomain' 26 | ); 27 | } 28 | if (typeof opts.docRoot !== 'string' && !opts.docRoot) { 29 | throw new PluginError('gulp-assetpaths', 'Missing parameter : docRoot'); 30 | } 31 | 32 | var filetypes = new RegExp('.' + opts.filetypes.join('|.')); 33 | var rootRegEx = setReplacementDomain(opts.oldDomain); 34 | var attrsAndProps = [ 35 | { 36 | exp: /(<\s*)(.*?)\bhref\s*=\s*((["{0,1}|'{0,1}]).*?\4)(.*?)>/gi, 37 | captureGroup: 3, 38 | templateCheck: /((\bdownload)(?=(.*?)\bhref\s*=))|((\bhref\s*=)(?=(.*?)\bdownload))/ 39 | }, 40 | { 41 | exp: /((\bbackground|\bbackground-image)\s*:\s*?.*){0,1}\burl\s*((\(\s*[^\w]{0,1}(["{0,1}'{0,1}]{0,1})).*?\5\))/gi, 42 | captureGroup: 3, 43 | templateCheck: /((\bbackground|\bbackground-image)\s*:\s*?.*)\burl\s*\(.*?\)/ 44 | }, 45 | { 46 | exp: /((<\s*){0,1}\bscript)(.*?)\bsrc\s*=\s*((["{0,1}|'{0,1}]).*?\5)/gi, 47 | captureGroup: 4, 48 | templateCheck: /(<\s*){0,1}(\bscript)(.*?)\bsrc\s*=\s*/ 49 | }, 50 | { 51 | exp: /((<\s*){0,1}\bimg)(.*?)\bsrc\s*=\s*((["{0,1}|'{0,1}]).*?\5)/gi, 52 | captureGroup: 4, 53 | templateCheck: /(<\s*){0,1}(\bimg)(.*?)\bsrc\s*=\s*/ 54 | }, 55 | { exp: /(:\s*("(.*?)"))/gi, captureGroup: 2, templateCheck: false } 56 | ]; 57 | 58 | //create custom attributes expressions 59 | if (opts.customAttributes) { 60 | var customAttrs = opts.customAttributes.map(function(attr) { 61 | return { 62 | exp: new RegExp( 63 | '\\b' + attr + '\\s*=\\s*((["{0,1}|\'{0,1}]).*\\2)', 64 | 'gi' 65 | ), 66 | captureGroup: 1, 67 | templateCheck: /.*/ 68 | }; 69 | }); 70 | attrsAndProps = attrsAndProps.concat(customAttrs); 71 | } 72 | 73 | function setReplacementDomain(string) { 74 | if (isRelative(opts.oldDomain)) { 75 | return new RegExp( 76 | '(((\\bhttp|\\bhttps):){0,1}\\/\\/' + string + ')' 77 | ); 78 | } else { 79 | return new RegExp(string); 80 | } 81 | } 82 | 83 | function isRelative(string, insertIndex) { 84 | return string.indexOf('/') === -1 || string.indexOf('/') > insertIndex; 85 | } 86 | 87 | function getInsertIndex(string) { 88 | if (string.search(/^.{0,1}\s*("|')/) !== -1) { 89 | //check to see if template not using interpolated strings 90 | var nonInter = /["|']\s*[+|.][^.]/.exec(string); 91 | if (nonInter) { 92 | return string.search(/"|'/) === nonInter.index 93 | ? nonInter.index 94 | : nonInter.index - 1; 95 | } 96 | return string.search(/"|'/) + 1; 97 | } 98 | return 1; 99 | } 100 | 101 | function insertAtIndex(string, fragment, index) { 102 | return [string.slice(0, index), fragment, string.slice(index)].join(''); 103 | } 104 | 105 | function ignoreUrl(match) { 106 | var regEx = /((\bhttp|\bhttps):){0,1}\/\//; 107 | if (regEx.test(match)) { 108 | if (rootRegEx !== null && !rootRegEx.test(match)) { 109 | return true; 110 | } 111 | } 112 | return false; 113 | } 114 | 115 | function replacementCheck(cGroup, match, regEx) { 116 | if (!opts.templates) { 117 | return filetypes.test(cGroup); 118 | } 119 | if (regEx.templateCheck) { 120 | return filetypes.test(cGroup) || regEx.templateCheck.test(match); 121 | } else { 122 | return filetypes.test(cGroup); 123 | } 124 | } 125 | 126 | function processLine(line, regEx, file) { 127 | line = line.replace(regEx.exp, function(match) { 128 | var cGroup = arguments[regEx.captureGroup]; 129 | if (replacementCheck(cGroup, match, regEx)) { 130 | if (!ignoreUrl(cGroup)) { 131 | return match.replace(cGroup, function(match) { 132 | match = match.replace(rootRegEx, '').trim(); 133 | return insertPath(match, file); 134 | }); 135 | } 136 | } 137 | return match; 138 | }); 139 | //pass back line if noop 140 | return line; 141 | } 142 | 143 | function countRelativeDirs(path) { 144 | var relDirs = path.filter(function(dir) { 145 | return dir.indexOf('..') !== -1 ? true : false; 146 | }); 147 | return relDirs.length; 148 | } 149 | 150 | function anchorToRoot(string, file) { 151 | var index = getInsertIndex(string); 152 | if (isRelative(string, index)) { 153 | //if the path isn't being dynamically generated(i.e. server or in template) 154 | if (!/^\s*[\(]{0,1}\s*["|']{0,1}\s*[<|{|.|+][^.]/.test(string)) { 155 | if (opts.docRoot) { 156 | var currentPath = string.split('/'); 157 | var relDirs = countRelativeDirs(currentPath); 158 | string = string.replace(/\.\.\//g, ''); 159 | relDirs = relDirs > 0 ? relDirs : relDirs + 1; 160 | var fullPath = file.path 161 | .split('/') 162 | .reverse() 163 | .slice(relDirs); 164 | if (fullPath.indexOf(opts.docRoot) !== -1) { 165 | while (fullPath[0] !== opts.docRoot) { 166 | string = insertAtIndex( 167 | string, 168 | fullPath[0] + '/', 169 | index 170 | ); 171 | fullPath = fullPath.slice(1); 172 | } 173 | } 174 | } 175 | } 176 | } 177 | return string; 178 | } 179 | 180 | function insertPath(string, file) { 181 | var string = anchorToRoot(string, file); 182 | var index = getInsertIndex(string); 183 | if (isRelative(string, index)) { 184 | string = insertAtIndex(string, '/', index); 185 | } 186 | return insertAtIndex(string, opts.newDomain, index); 187 | } 188 | 189 | function assetpaths(file, enc, callback) { 190 | // Do nothing if no contents 191 | if (file.isNull()) { 192 | this.push(file); 193 | return callback(); 194 | } 195 | 196 | if (file.isStream()) { 197 | return this.emit( 198 | 'error', 199 | new PluginError('gulp-assetpaths', 'Streaming not supported') 200 | ); 201 | } 202 | 203 | if (file.isBuffer()) { 204 | var outfileContents = ''; 205 | var contents = file.contents.toString('utf8'); 206 | var lineEnding = contents.search(/[\r\n]/) !== -1 ? '\r\n' : '\n'; 207 | var lines = contents.split(lineEnding); 208 | lines.forEach(function(line) { 209 | attrsAndProps.forEach(function(regEx) { 210 | line = processLine(line, regEx, file); 211 | }, this); 212 | outfileContents += line; 213 | }, this); 214 | var outfile = file.clone(); 215 | outfile.contents = new Buffer(outfileContents); 216 | } 217 | 218 | this.push(outfile); 219 | return callback(); 220 | } 221 | 222 | return through.obj(assetpaths); 223 | }; 224 | -------------------------------------------------------------------------------- /test/main.js: -------------------------------------------------------------------------------- 1 | /*global describe, it*/ 2 | 3 | var fs = require('fs'), 4 | es = require('event-stream'), 5 | should = require('should'); 6 | require('mocha'); 7 | 8 | delete require.cache[require.resolve('../')]; 9 | 10 | var Vinyl = require('vinyl'), 11 | assetpaths = require('../'); 12 | 13 | describe('gulp-assetpaths', function() { 14 | it('should replace static paths', function(done) { 15 | var srcFile = new Vinyl({ 16 | path: 'test/fixtures/staticpaths.html', 17 | cwd: 'test/', 18 | base: 'test/fixtures', 19 | contents: fs.readFileSync('test/fixtures/staticpaths.html') 20 | }); 21 | 22 | var expectedStatic = new Vinyl({ 23 | path: 'test/expected/staticpaths.html', 24 | cwd: 'test/', 25 | base: 'test/expected', 26 | contents: fs.readFileSync('test/expected/staticpaths.html') 27 | }); 28 | 29 | var stream = assetpaths({ 30 | oldDomain: 'www.oldDomain.com', 31 | newDomain: 'https://www.newDomain.com', 32 | docRoot: 'test', 33 | filetypes: ['jpg', 'png', 'js', 'css'], 34 | templates: true 35 | }); 36 | 37 | stream.on('error', function(err) { 38 | should.exist(err); 39 | done(err); 40 | }); 41 | 42 | stream.on('data', function(newFile) { 43 | should.exist(newFile); 44 | should.exist(newFile.contents); 45 | String(newFile.contents).should.equal( 46 | String(expectedStatic.contents) 47 | ); 48 | done(); 49 | }); 50 | stream.write(srcFile); 51 | stream.end(); 52 | }); 53 | it('should replace nested static paths', function(done) { 54 | var srcFile = new Vinyl({ 55 | path: 'test/fixtures/nested/staticpaths.html', 56 | cwd: 'test/', 57 | base: 'test/fixtures', 58 | contents: fs.readFileSync('test/fixtures/nested/staticpaths.html') 59 | }); 60 | 61 | var expectedStaticNested = new Vinyl({ 62 | path: 'test/expected/nested/staticpaths.html', 63 | cwd: 'test/', 64 | base: 'test/expected', 65 | contents: fs.readFileSync('test/expected/nested/staticpaths.html') 66 | }); 67 | 68 | var stream = assetpaths({ 69 | oldDomain: 'www.oldDomain.com', 70 | newDomain: 'https://www.newDomain.com', 71 | docRoot: 'test', 72 | filetypes: ['jpg', 'png', 'js', 'css'], 73 | templates: true 74 | }); 75 | 76 | stream.on('error', function(err) { 77 | should.exist(err); 78 | done(err); 79 | }); 80 | 81 | stream.on('data', function(newFile) { 82 | should.exist(newFile); 83 | should.exist(newFile.contents); 84 | String(newFile.contents).should.equal( 85 | String(expectedStaticNested.contents) 86 | ); 87 | done(); 88 | }); 89 | stream.write(srcFile); 90 | stream.end(); 91 | }); 92 | 93 | it('should remove a prefix by passing an empty string for newDomain and docRoot', function(done) { 94 | var srcFile = new Vinyl({ 95 | path: 'test/fixtures/removeprefix.html', 96 | cwd: 'test/', 97 | base: 'test/fixtures', 98 | contents: fs.readFileSync('test/fixtures/removeprefix.html') 99 | }); 100 | 101 | var expectedRemovePrefix = new Vinyl({ 102 | path: 'test/expected/removeprefix.html', 103 | cwd: 'test/', 104 | base: 'test/expected', 105 | contents: fs.readFileSync('test/expected/removeprefix.html') 106 | }); 107 | 108 | var stream = assetpaths({ 109 | oldDomain: 'http://www.somedomain.com/prefix', 110 | newDomain: '', 111 | docRoot: '', 112 | filetypes: ['jpg', 'png', 'js', 'css'], 113 | templates: true 114 | }); 115 | 116 | stream.on('error', function(err) { 117 | should.exist(err); 118 | done(err); 119 | }); 120 | stream.on('data', function(newFile) { 121 | should.exist(newFile); 122 | should.exist(newFile.contents); 123 | String(newFile.contents).should.equal( 124 | String(expectedRemovePrefix.contents) 125 | ); 126 | done(); 127 | }); 128 | stream.write(srcFile); 129 | stream.end(); 130 | }); 131 | it('should replace dynamic paths', function(done) { 132 | var srcFile = new Vinyl({ 133 | path: 'test/fixtures/dynamicpaths.html', 134 | cwd: 'test/', 135 | base: 'test/fixtures', 136 | contents: fs.readFileSync('test/fixtures/dynamicpaths.html') 137 | }); 138 | 139 | var expectedDynamic = new Vinyl({ 140 | path: 'test/expected/staticpaths.html', 141 | cwd: 'test/', 142 | base: 'test/expected', 143 | contents: fs.readFileSync('test/expected/dynamicpaths.html') 144 | }); 145 | 146 | var stream = assetpaths({ 147 | oldDomain: 'www.oldDomain.com', 148 | newDomain: 'https://www.newDomain.com', 149 | docRoot: 'test', 150 | filetypes: ['jpg', 'png', 'css'], 151 | templates: true 152 | }); 153 | 154 | stream.on('error', function(err) { 155 | should.exist(err); 156 | done(err); 157 | }); 158 | 159 | stream.on('data', function(newFile) { 160 | should.exist(newFile); 161 | should.exist(newFile.contents); 162 | String(newFile.contents).should.equal( 163 | String(expectedDynamic.contents) 164 | ); 165 | done(); 166 | }); 167 | 168 | stream.write(srcFile); 169 | stream.end(); 170 | }); 171 | it('should replace paths in compiled templates', function(done) { 172 | var srcFile = new Vinyl({ 173 | path: 'test/fixtures/nojs.html', 174 | cwd: 'test/', 175 | base: 'test/fixtures', 176 | contents: fs.readFileSync('test/fixtures/templates.js') 177 | }); 178 | 179 | var expectedTemplates = new Vinyl({ 180 | path: 'test/expected/templates.js', 181 | cwd: 'test/', 182 | base: 'test/expected', 183 | contents: fs.readFileSync('test/expected/templates.js') 184 | }); 185 | 186 | var stream = assetpaths({ 187 | oldDomain: 'www.oldDomain.com', 188 | newDomain: 'https://www.newDomain.com', 189 | docRoot: 'test', 190 | filetypes: ['jpg', 'png', 'css'], 191 | templates: true 192 | }); 193 | 194 | stream.on('error', function(err) { 195 | should.exist(err); 196 | done(err); 197 | }); 198 | 199 | stream.on('data', function(newFile) { 200 | should.exist(newFile); 201 | should.exist(newFile.contents); 202 | String(newFile.contents).should.equal( 203 | String(expectedTemplates.contents) 204 | ); 205 | done(); 206 | }); 207 | 208 | stream.write(srcFile); 209 | stream.end(); 210 | }); 211 | it('should not replace excluded css file type', function(done) { 212 | var srcFile = new Vinyl({ 213 | path: 'test/fixtures/nocss.css', 214 | cwd: 'test/', 215 | base: 'test/fixtures', 216 | contents: fs.readFileSync('test/fixtures/nocss.css') 217 | }); 218 | 219 | var expectedNoCSS = new Vinyl({ 220 | path: 'test/expected/nocss.css', 221 | cwd: 'test/', 222 | base: 'test/expected', 223 | contents: fs.readFileSync('test/expected/nocss.css') 224 | }); 225 | 226 | var stream = assetpaths({ 227 | oldDomain: 'www.oldDomain.com', 228 | newDomain: 'https://www.newDomain.com', 229 | docRoot: 'test', 230 | filetypes: ['jpg', 'png', 'js'], 231 | noTemplates: true 232 | }); 233 | 234 | stream.on('error', function(err) { 235 | should.exist(err); 236 | done(err); 237 | }); 238 | 239 | stream.on('data', function(newFile) { 240 | should.exist(newFile); 241 | should.exist(newFile.contents); 242 | String(newFile.contents).should.equal( 243 | String(expectedNoCSS.contents) 244 | ); 245 | done(); 246 | }); 247 | 248 | stream.write(srcFile); 249 | stream.end(); 250 | }); 251 | 252 | it('should not replace excluded js file type', function(done) { 253 | var srcFile = new Vinyl({ 254 | path: 'test/fixtures/nojs.html', 255 | cwd: 'test/', 256 | base: 'test/fixtures', 257 | contents: fs.readFileSync('test/fixtures/nojs.html') 258 | }); 259 | 260 | var expectedNoJS = new Vinyl({ 261 | path: 'test/expected/nojs.html', 262 | cwd: 'test/', 263 | base: 'test/expected', 264 | contents: fs.readFileSync('test/expected/nojs.html') 265 | }); 266 | 267 | var stream = assetpaths({ 268 | oldDomain: 'www.oldDomain.com', 269 | newDomain: 'https://www.newDomain.com', 270 | docRoot: 'test', 271 | filetypes: ['jpg', 'png', 'css'], 272 | noTemplates: true 273 | }); 274 | 275 | stream.on('error', function(err) { 276 | should.exist(err); 277 | done(err); 278 | }); 279 | 280 | stream.on('data', function(newFile) { 281 | should.exist(newFile); 282 | should.exist(newFile.contents); 283 | String(newFile.contents).should.equal( 284 | String(expectedNoJS.contents) 285 | ); 286 | done(); 287 | }); 288 | 289 | stream.write(srcFile); 290 | stream.end(); 291 | }); 292 | 293 | it('should allow relative path in oldDomain option', function(done) { 294 | var srcFile = new Vinyl({ 295 | path: 'test/fixtures/oldDomainRel.html', 296 | cwd: 'test/', 297 | base: 'test/fixtures', 298 | contents: fs.readFileSync('test/fixtures/oldDomainRel.html') 299 | }); 300 | 301 | var oldDomainRel = new Vinyl({ 302 | path: 'test/expected/oldDomainRel.html', 303 | cwd: 'test/', 304 | base: 'test/expected', 305 | contents: fs.readFileSync('test/expected/oldDomainRel.html') 306 | }); 307 | 308 | var stream = assetpaths({ 309 | oldDomain: '../assets', 310 | newDomain: '//www.newDomain.com', 311 | docRoot: 'test', 312 | filetypes: ['jpg', 'png', 'css'], 313 | templates: true 314 | }); 315 | 316 | stream.on('error', function(err) { 317 | should.exist(err); 318 | done(err); 319 | }); 320 | 321 | stream.on('data', function(newFile) { 322 | should.exist(newFile); 323 | should.exist(newFile.contents); 324 | String(newFile.contents).should.equal( 325 | String(oldDomainRel.contents) 326 | ); 327 | done(); 328 | }); 329 | 330 | stream.write(srcFile); 331 | stream.end(); 332 | }); 333 | it('should change the paths in a json file', function(done) { 334 | var srcFile = new Vinyl({ 335 | path: 'test/fixtures/test.json', 336 | cwd: 'test/', 337 | base: 'test/fixtures', 338 | contents: fs.readFileSync('test/fixtures/test.json') 339 | }); 340 | 341 | var expectedJSON = new Vinyl({ 342 | path: 'test/expected/test.json', 343 | cwd: 'test/', 344 | base: 'test/expected', 345 | contents: fs.readFileSync('test/expected/test.json') 346 | }); 347 | 348 | var stream = assetpaths({ 349 | oldDomain: 'https://www.oldDomain.com', 350 | newDomain: 'https://www.newDomain.com', 351 | docRoot: 'test', 352 | filetypes: ['jpg', 'png', 'css'], 353 | templates: true 354 | }); 355 | 356 | stream.on('error', function(err) { 357 | should.exist(err); 358 | done(err); 359 | }); 360 | 361 | stream.on('data', function(newFile) { 362 | should.exist(newFile); 363 | should.exist(newFile.contents); 364 | String(newFile.contents).should.equal( 365 | String(expectedJSON.contents) 366 | ); 367 | done(); 368 | }); 369 | 370 | stream.write(srcFile); 371 | stream.end(); 372 | }); 373 | 374 | it('should error on stream', function(done) { 375 | var srcFile = new Vinyl({ 376 | path: 'test/fixtures/dynamicpaths.html', 377 | cwd: 'test/', 378 | base: 'test/fixtures', 379 | contents: fs.createReadStream('test/fixtures/dynamicpaths.html') 380 | }); 381 | 382 | var stream = assetpaths({ 383 | oldDomain: 'www.oldDomain.com', 384 | newDomain: 'https://www.newDomain.com', 385 | docRoot: 'test', 386 | filetypes: ['jpg', 'png', 'js', 'css'] 387 | }); 388 | 389 | stream.on('error', function(err) { 390 | should.exist(err); 391 | done(); 392 | }); 393 | 394 | stream.on('data', function(newFile) { 395 | newFile.contents.pipe( 396 | es.wait(function(err, data) { 397 | done(err); 398 | }) 399 | ); 400 | }); 401 | 402 | stream.write(srcFile); 403 | stream.end(); 404 | }); 405 | 406 | it('should replace custom attributes', function(done) { 407 | var srcFile = new Vinyl({ 408 | path: 'test/fixtures/customattrs.html', 409 | cwd: 'test/', 410 | base: 'test/fixtures', 411 | contents: fs.readFileSync('test/fixtures/customattrs.html') 412 | }); 413 | 414 | var expected = new Vinyl({ 415 | path: 'test/expected/customattrs.html', 416 | cwd: 'test/', 417 | base: 'test/expected', 418 | contents: fs.readFileSync('test/expected/customattrs.html') 419 | }); 420 | 421 | var stream = assetpaths({ 422 | oldDomain: 'www.oldDomain.com', 423 | newDomain: 'https://www.newDomain.com', 424 | docRoot: 'test', 425 | filetypes: ['jpg', 'png', 'js', 'css'], 426 | templates: true, 427 | customAttributes: ['data-custom'] 428 | }); 429 | 430 | stream.on('error', function(err) { 431 | should.exist(err); 432 | done(err); 433 | }); 434 | 435 | stream.on('data', function(newFile) { 436 | should.exist(newFile); 437 | should.exist(newFile.contents); 438 | String(newFile.contents).should.equal(String(expected.contents)); 439 | done(); 440 | }); 441 | 442 | stream.write(srcFile); 443 | stream.end(); 444 | }); 445 | }); 446 | --------------------------------------------------------------------------------