├── .editorconfig ├── .gitattributes ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── commitlint.config.js ├── index.js ├── package-lock.json ├── package.json └── src ├── extname └── index.js ├── inject ├── expected │ ├── addPrefix.html │ ├── addSuffix.html │ ├── customName.html │ ├── customTags.html │ ├── customTagsWithExt.html │ ├── customTagsWithPath.html │ ├── customTransform.json │ ├── defaults.haml │ ├── defaults.html │ ├── defaults.jade │ ├── defaults.jsx │ ├── defaults.less │ ├── defaults.pug │ ├── defaults.sass │ ├── defaults.scss │ ├── defaults.slim │ ├── defaults.slm │ ├── defaults2.html │ ├── emptyTags.html │ ├── emptyTags2.html │ ├── emptyTags3.html │ ├── existingData.html │ ├── existingDataAndReplaced.html │ ├── ignorePath.html │ ├── issue107.html │ ├── issue144.jade │ ├── issue144.pug │ ├── issue176.html │ ├── issue177.html │ ├── issue39.html │ ├── issue56.html │ ├── issue71.html │ ├── issue74.html │ ├── noRootSlash.html │ ├── noRootSlashWithIgnorePath.html │ ├── parallell.html │ ├── relative.html │ ├── removeAndEmptyTags.html │ ├── removeTags.html │ ├── selfClosingTag.html │ └── templateWithExistingData2.html ├── fixtures │ ├── issue107.html │ ├── issue144.jade │ ├── issue144.pug │ ├── issue176.html │ ├── issue39.html │ ├── issue56.html │ ├── issue71.html │ ├── issue74.html │ ├── partial.html │ ├── template.haml │ ├── template.html │ ├── template.jade │ ├── template.json │ ├── template.jsx │ ├── template.less │ ├── template.pug │ ├── template.sass │ ├── template.scss │ ├── template.slim │ ├── template.slm │ ├── template2.html │ ├── templateCustomName.html │ ├── templateCustomTags.html │ ├── templateTagsWithExt.html │ ├── templateTagsWithPath.html │ ├── templateWithExistingData.html │ ├── templateWithExistingData2.html │ └── templateWithExistingData3.html ├── index.js └── inject_test.js ├── path ├── index.js └── path_test.js ├── tags ├── index.js └── tags_test.js └── transform ├── index.js └── transform_test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [test/fixtures/*] 16 | insert_final_newline = false 17 | trim_trailing_whitespace = false 18 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Check 2 | on: push 3 | jobs: 4 | check: 5 | name: Check 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Checkout repo 9 | uses: actions/checkout@v3 10 | 11 | - name: Setup Node 12 | uses: actions/setup-node@v3 13 | with: 14 | node-version: 18 15 | 16 | - name: Install dependencies 17 | run: npm ci 18 | 19 | - name: Run test 20 | run: npm test 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea/ 3 | node_modules/ 4 | temp/ 5 | npm-debug.log 6 | yarn-error.log 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | .idea 3 | src/inject/expected/ 4 | src/inject/fixtures/ 5 | src/inject/*_test.js 6 | src/tags/*_test.js 7 | src/transform/*_test.js 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | notifications: 3 | email: false 4 | node_js: 5 | - '12' 6 | - '10' 7 | - '8' 8 | env: 9 | - BUILD_LEADER_ID=4 10 | branches: 11 | except: 12 | - /^v\d+\.\d+\.\d+$/ 13 | before_script: 14 | - npm prune 15 | jobs: 16 | include: 17 | - stage: release 18 | node_js: 8 19 | os: linux 20 | after_success: 21 | - test $TRAVIS_BRANCH = "master" && test $TRAVIS_PULL_REQUEST = "false" 22 | - echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc 23 | - npm run semantic-release 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2014 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gulp-inject 2 | 3 | --- 4 | ## HELP WANTED 5 | 6 | 7 | ### Contributors are welcomed! 8 | 9 | **I don't have enough time to maintain this plugin as I would want to, so I'm looking for people who want to help out and be contributors/repository admins.** 10 | 11 | 12 | #### Interested? 13 | **Contact me! See `package.json` for contact information.** 14 | 15 | --- 16 | 17 | [![NPM version][npm-image]][npm-url] [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) [![Build Status][travis-image]][travis-url] [![XO code style][codestyle-image]][codestyle-url] [![Dependency Status][depstat-image]][depstat-url] 18 | 19 | > A stylesheet, javascript and webcomponent reference injection plugin for [gulp](https://github.com/wearefractal/gulp). No more manual editing of your index.html! 20 | 21 | # Contents 22 | 23 | 24 | 25 | - [Introduction](#introduction) 26 | - [Installation](#installation) 27 | - [Basic usage](#basic-usage) 28 | - [More examples](#more-examples) 29 | - [Injecting files relative to target files](#injecting-files-relative-to-target-files) 30 | - [Injecting files from multiple source streams](#injecting-files-from-multiple-source-streams) 31 | - [Multiple sources when order is important](#multiple-sources-when-order-is-important) 32 | - [Injecting some files into `` and some into ``](#injecting-some-files-into-head-and-some-into-body) 33 | - [Method 1: Use `gulp-inject`'s `starttag` option.](#method-1-use-gulp-injects-starttag-option) 34 | - [Method 2: Use `gulp-inject`'s `name` option.](#method-2-use-gulp-injects-name-option) 35 | - [Injecting all files for development](#injecting-all-files-for-development) 36 | - [Injecting AngularJS scripts for development](#injecting-angularjs-scripts-for-development) 37 | - [Injecting into a json-file](#injecting-into-a-json-file) 38 | - [Injecting with custom `transform` function with default fallback](#injecting-with-custom-transform-function-with-default-fallback) 39 | - [Injecting dist files into bower.json's main section](#injecting-dist-files-into-bowerjsons-main-section) 40 | - [Injecting all javascript files into a karma config file](#injecting-all-javascript-files-into-a-karma-config-file) 41 | - [Injecting files contents](#injecting-files-contents) 42 | - [Injecting files contents based on file path](#injecting-files-contents-based-on-file-path) 43 | - [API](#api) 44 | - [inject(sources, options)](#injectsources-options) 45 | - [Options](#options) 46 | - [options.ignorePath](#optionsignorepath) 47 | - [options.relative](#optionsrelative) 48 | - [options.addPrefix](#optionsaddprefix) 49 | - [options.addSuffix](#optionsaddsuffix) 50 | - [options.addRootSlash](#optionsaddrootslash) 51 | - [options.name](#optionsname) 52 | - [options.removeTags](#optionsremovetags) 53 | - [options.empty](#optionsempty) 54 | - [options.starttag](#optionsstarttag) 55 | - [options.endtag](#optionsendtag) 56 | - [options.transform](#optionstransform) 57 | - [options.selfClosingTag](#optionsselfclosingtag) 58 | - [~~options.templateString~~](#optionstemplatestring) 59 | - [~~options.sort~~](#optionssort) 60 | - [inject.transform](#injecttransform) 61 | - [License](#license) 62 | 63 | 64 | 65 | ## Introduction 66 | 67 | `gulp-inject` takes a stream of source files, transforms each file to a string and injects each transformed string into placeholders in the target stream files. See [Basic usage](#basic-usage) and [More examples](#more-examples) below. 68 | 69 | Default [transforms](#optionstransform) and [placeholders](#optionsstarttag) exists for injecting files into `html`, `jade`, `pug`, `jsx` , `less`, `slm`, `haml` and `sass` / `scss` files. 70 | 71 | ## Installation 72 | 73 | Install `gulp-inject` as a development dependency: 74 | 75 | ```shell 76 | npm install --save-dev gulp-inject 77 | ``` 78 | 79 | ## Basic usage 80 | 81 | **The target file `src/index.html`:** 82 | 83 | Each pair of comments are the injection placeholders (aka. tags, see [`options.starttag`](#optionsstarttag) and [`options.endtag`](#optionsendtag)). 84 | 85 | ```html 86 | 87 | 88 | 89 | My index 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | ``` 100 | 101 | **The `gulpfile.js`:** 102 | 103 | ```javascript 104 | var gulp = require('gulp'); 105 | var inject = require('gulp-inject'); 106 | 107 | gulp.task('index', function () { 108 | var target = gulp.src('./src/index.html'); 109 | // It's not necessary to read the files (will speed up things), we're only after their paths: 110 | var sources = gulp.src(['./src/**/*.js', './src/**/*.css'], {read: false}); 111 | 112 | return target.pipe(inject(sources)) 113 | .pipe(gulp.dest('./src')); 114 | }); 115 | ``` 116 | 117 | **`src/index.html` after running `gulp index`:** 118 | 119 | ```html 120 | 121 | 122 | 123 | My index 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | ``` 138 | 139 | ## More examples 140 | 141 | ### Injecting files relative to target files 142 | 143 | By default the injected file paths are relative to each source file's `cwd` (see [`options.ignorePath`](#optionsignorepath)). If `options.relative` is set to `true` each injected path will be relative to each target file's directory instead. 144 | 145 | **Project structure:** 146 | 147 | ``` 148 | └── src 149 | ├── module 150 | │ ├── module.js 151 | │ └── module.html 152 | └── app 153 | ├── main.js 154 | └── index.html 155 | ``` 156 | 157 | **`src/app/index.html`:** 158 | 159 | ```html 160 | 161 | 162 | 163 | My Index 164 | 165 | 166 |

Home

167 | 168 | 169 | 170 | 171 | ``` 172 | 173 | **`src/module/module.html`:** 174 | 175 | ```html 176 | 177 | 178 | 179 | Module 180 | 181 | 182 |

Module

183 | 184 | 185 | 186 | 187 | ``` 188 | 189 | **`gulpfile.js`:** 190 | 191 | ```javascript 192 | var inject = require('gulp-inject'); 193 | 194 | gulp.src('./src/**/*.html') 195 | .pipe(inject(gulp.src('./src/**/*.js', {read: false}), {relative: true})) 196 | .pipe(gulp.dest('./src')); 197 | ``` 198 | 199 | **Resulting `src/app/index.html`:** 200 | 201 | ```html 202 | 203 | 204 | 205 | My Index 206 | 207 | 208 |

Home

209 | 210 | 211 | 212 | 213 | 214 | 215 | ``` 216 | 217 | **Resulting `src/module/module.html`:** 218 | 219 | ```html 220 | 221 | 222 | 223 | Module 224 | 225 | 226 |

Home

227 | 228 | 229 | 230 | 231 | 232 | 233 | ``` 234 | 235 | ### Injecting files from multiple source streams 236 | 237 | This example demonstrates how to inject files from multiple different streams into the same injection placeholder. 238 | 239 | Install [`event-stream`](https://www.npmjs.org/package/event-stream) with: `npm install --save-dev event-stream` and use its [`merge`](https://github.com/dominictarr/event-stream#merge-stream1streamn) function. 240 | 241 | **Code:** 242 | 243 | ```javascript 244 | var es = require('event-stream'), 245 | inject = require('gulp-inject'), 246 | concat = require('gulp-concat'), 247 | uglify = require('gulp-uglify'); 248 | 249 | // Concatenate vendor scripts 250 | var vendorStream = gulp.src(['./src/vendors/*.js']) 251 | .pipe(concat('vendors.js')) 252 | .pipe(gulp.dest('./dist')); 253 | 254 | // Concatenate AND minify app sources 255 | var appStream = gulp.src(['./src/app/*.js']) 256 | .pipe(concat('app.js')) 257 | .pipe(uglify()) 258 | .pipe(gulp.dest('./dist')); 259 | 260 | gulp.src('./src/index.html') 261 | .pipe(inject(es.merge(vendorStream, appStream))) 262 | .pipe(gulp.dest('./dist')); 263 | ``` 264 | 265 | #### Multiple sources when order is important 266 | 267 | Use [`stream-series`](https://github.com/rschmukler/stream-series). 268 | 269 | **Code:** 270 | 271 | ```javascript 272 | var series = require('stream-series'), 273 | inject = require('gulp-inject'); 274 | 275 | var vendorStream = gulp.src(['./src/vendors/*.js'], {read: false}); 276 | 277 | var appStream = gulp.src(['./src/app/*.js'], {read: false}); 278 | 279 | gulp.src('./src/index.html') 280 | .pipe(inject(series(vendorStream, appStream))) // This will always inject vendor files before app files 281 | .pipe(gulp.dest('./dist')); 282 | ``` 283 | 284 | ### Injecting some files into `` and some into `` 285 | 286 | #### Method 1: Use `gulp-inject`'s `starttag` option. 287 | 288 | **`gulpfile.js`:** 289 | 290 | ```javascript 291 | var inject = require('gulp-inject'); 292 | 293 | gulp.src('./src/index.html') 294 | .pipe(inject(gulp.src('./src/importantFile.js', {read: false}), {starttag: ''})) 295 | .pipe(inject(gulp.src(['./src/*.js', '!./src/importantFile.js'], {read: false}))) 296 | .pipe(gulp.dest('./dist')); 297 | ``` 298 | 299 | **And in your `./src/index.html`:** 300 | 301 | ```html 302 | 303 | 304 | 305 | My index 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | ``` 318 | 319 | #### Method 2: Use `gulp-inject`'s `name` option. 320 | 321 | **`gulpfile.js`:** 322 | 323 | ```javascript 324 | var inject = require('gulp-inject'); 325 | 326 | gulp.src('./src/index.html') 327 | .pipe(inject(gulp.src('./src/importantFile.js', {read: false}), {name: 'head'})) 328 | .pipe(inject(gulp.src(['./src/*.js', '!./src/importantFile.js'], {read: false}))) 329 | .pipe(gulp.dest('./dist')); 330 | ``` 331 | 332 | **And in your `./src/index.html`:** 333 | 334 | ```html 335 | 336 | 337 | 338 | My index 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | ``` 351 | 352 | 353 | ### Injecting all files for development 354 | 355 | If you use [Bower](http://bower.io/) for frontend dependencies I recommend using [`main-bower-files`](https://www.npmjs.org/package/main-bower-files) and injecting them as well. 356 | 357 | **`gulpfile.js`:** 358 | 359 | ```javascript 360 | var bowerFiles = require('main-bower-files'), 361 | inject = require('gulp-inject'), 362 | stylus = require('gulp-stylus'), 363 | es = require('event-stream'); 364 | 365 | var cssFiles = gulp.src('./src/**/*.styl') 366 | .pipe(stylus()) 367 | .pipe(gulp.dest('./build')); 368 | 369 | gulp.src('./src/index.html') 370 | .pipe(inject(gulp.src(bowerFiles(), {read: false}), {name: 'bower'})) 371 | .pipe(inject(es.merge( 372 | cssFiles, 373 | gulp.src('./src/app/**/*.js', {read: false}) 374 | ))) 375 | .pipe(gulp.dest('./build')); 376 | ``` 377 | 378 | **`src/index.html`:** 379 | 380 | ```html 381 | 382 | 383 | 384 | My index 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | ``` 403 | 404 | **Note** remember to mount `./bower_components`, `./build` and `./src/app` as static resources in your server to make this work. 405 | 406 | ### Injecting AngularJS scripts for development 407 | 408 | If you're writing an AngularJS application and follow [Google's Angular APP Structure Recommendations](https://docs.google.com/document/d/1XXMvReO8-Awi1EZXAXS4PzDzdNvV6pGcuaF4Q9821Es/pub), which I think you should, it's important that the script files are injected in the correct order to avoid module instantiation problems like `Uncaught Error: [$injector:modulerr]`. 409 | 410 | To do this you can use [`gulp-angular-filesort`](https://www.npmjs.org/package/gulp-angular-filesort) together with `gulp-inject` like so: 411 | 412 | ```javascript 413 | var angularFilesort = require('gulp-angular-filesort'), 414 | inject = require('gulp-inject'); 415 | 416 | gulp.src('./src/index.html') 417 | .pipe(inject( 418 | gulp.src('./src/app/**/*.js') // gulp-angular-filesort depends on file contents, so don't use {read: false} here 419 | .pipe(angularFilesort()) 420 | )) 421 | .pipe(gulp.dest('./build')); 422 | ``` 423 | 424 | ### Injecting into a json-file 425 | 426 | You can customize `gulp-inject` further by using the `transform` function option, e.g. by injecting files into a json-file. 427 | 428 | **Code:** 429 | 430 | ```javascript 431 | gulp.src('./files.json') 432 | .pipe(inject(gulp.src(['./src/*.js', './src/*.css', './src/*.html'], {read: false}), { 433 | starttag: '"{{ext}}": [', 434 | endtag: ']', 435 | transform: function (filepath, file, i, length) { 436 | return ' "' + filepath + '"' + (i + 1 < length ? ',' : ''); 437 | } 438 | })) 439 | .pipe(gulp.dest('./')); 440 | ``` 441 | 442 | Initial contents of `files.json`: 443 | 444 | ```json 445 | { 446 | "js": [ 447 | ], 448 | "css": [ 449 | ], 450 | "html": [ 451 | ] 452 | } 453 | ``` 454 | 455 | ### Injecting with custom `transform` function with default fallback 456 | 457 | The [default `transform`](#injecttransform) function is available to use e.g. as a default fallback. 458 | 459 | Used here to inject Word documents as `` tags below: 460 | 461 | **`index.html`:** 462 | 463 | ```html 464 | 465 | 466 | 467 | My documents 468 | 469 | 470 |

Documents

471 | 475 | 476 | 477 | 478 | 479 | ``` 480 | 481 | **`gulpfile.js`:** 482 | 483 | ```javascript 484 | var inject = require('gulp-inject'); 485 | 486 | gulp.src('./index.html') 487 | .pipe(inject( 488 | gulp.src(['./*.js', './docs/*.docx'], {read: false}), { 489 | transform: function (filepath) { 490 | if (filepath.slice(-5) === '.docx') { 491 | return '
  • ' + filepath + '
  • '; 492 | } 493 | // Use the default transform as fallback: 494 | return inject.transform.apply(inject.transform, arguments); 495 | } 496 | } 497 | )) 498 | .pipe(gulp.dest('./')); 499 | ``` 500 | 501 | **Resulting `index.html`:** 502 | 503 | ```html 504 | 505 | 506 | 507 | My documents 508 | 509 | 510 |

    Documents

    511 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | ``` 524 | 525 | ### Injecting dist files into bower.json's main section 526 | 527 | **Code:** 528 | 529 | ```javascript 530 | gulp.src('./bower.json') 531 | .pipe(inject(gulp.src(['./dist/app.min.js', './dist/app.min.css'], {read: false}), { 532 | starttag: '"main": [', 533 | endtag: ']', 534 | transform: function (filepath, file, i, length) { 535 | return ' "' + filepath + '"' + (i + 1 < length ? ',' : ''); 536 | } 537 | })) 538 | .pipe(gulp.dest('./')); 539 | ``` 540 | 541 | ### Injecting all javascript files into a karma config file 542 | 543 | **Code:** 544 | 545 | ```javascript 546 | gulp.src('./karma.conf.js') 547 | .pipe(inject(gulp.src(['./src/**/*.js'], {read: false}), { 548 | starttag: 'files: [', 549 | endtag: ']', 550 | transform: function (filepath, file, i, length) { 551 | return ' "' + filepath + '"' + (i + 1 < length ? ',' : ''); 552 | } 553 | })) 554 | .pipe(gulp.dest('./')); 555 | ``` 556 | 557 | ### Injecting files contents 558 | 559 | In order to inject files contents you have to provide custom `transform` function, that will return file contents as string. You also have to omit `{read: false}` option of `gulp.src` in this case. Example below shows how to inject contents of html partials into head of `index.html`: 560 | 561 | ***Code:*** 562 | 563 | ```javascript 564 | gulp.src('./src/index.html') 565 | .pipe(inject(gulp.src(['./src/partials/head/*.html']), { 566 | starttag: '', 567 | transform: function (filePath, file) { 568 | // return file contents as string 569 | return file.contents.toString('utf8') 570 | } 571 | })) 572 | .pipe(gulp.dest('./dest')); 573 | ``` 574 | 575 | And in your `./src/index.html`: 576 | 577 | ```html 578 | 579 | 580 | 581 | My index 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | ``` 590 | 591 | ### Injecting files contents based on file path 592 | 593 | In order to inject files based on file path you have to provide custom `starttag` which includes `{{path}}`. Additionally, in order to inject file contents include `transform` function, that will return file contents as string. You also have to omit `{read: false}` option of `gulp.src` in this case. Path can be either absolute, or relative in which case you should set [`options.relative`] to true. Example below shows how to inject contents of html partials into `index.html`: 594 | 595 | ***Code:*** 596 | 597 | ```javascript 598 | gulp.src('./src/index.html') 599 | .pipe(inject(gulp.src(['./src/partials/head/*.html']), { 600 | starttag: '', 601 | relative: true, 602 | transform: function (filePath, file) { 603 | // return file contents as string 604 | return file.contents.toString('utf8') 605 | } 606 | })) 607 | .pipe(gulp.dest('./dest')); 608 | ``` 609 | 610 | And in your `./src/index.html`: 611 | 612 | ```html 613 | 614 | 615 | 616 | My index 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | ``` 625 | 626 | ## API 627 | 628 | ### inject(sources, options) 629 | 630 | Parameter: `sources` 631 | Type: `Stream` 632 | 633 | Provide a Vinyl File Stream as input to `inject`, see examples above. 634 | 635 | 636 | Parameter: `options` 637 | Type: `Object` 638 | 639 | For available options see [Options](#options) 640 | 641 | ### Options 642 | 643 | #### options.ignorePath 644 | Type: `String` or `Array` 645 | 646 | Default: `NULL` 647 | 648 | 649 | A path or paths that should be removed from each injected file path. 650 | 651 | This could also be solved by setting the `cwd` option for your `gulp.src` streams, each source file's `cwd` is automatically removed from its path before injection (if not [`options.relative`](#optionsrelative) is set to `true`, see below). 652 | 653 | 654 | #### options.relative 655 | Type: `Boolean` 656 | 657 | Default: `false` 658 | 659 | 660 | If set to `true` paths for the injected files will be relative to each target file, this also means that each source file's `cwd` is not necessary to remove from its path. 661 | 662 | 663 | #### options.addPrefix 664 | Type: `String` 665 | 666 | Default: `NULL` 667 | 668 | 669 | A path that should be prefixed to each injected file path. 670 | 671 | #### options.addSuffix 672 | Type: `String` 673 | 674 | Default: `NULL` 675 | 676 | 677 | A path that should be suffixed to each injected file path. 678 | 679 | #### options.addRootSlash 680 | Type: `Boolean` 681 | 682 | Default: [`!options.relative`](#optionsrelative) 683 | 684 | 685 | The root slash is automatically added at the beginning of the path ('/'), or removed if set to `false`. 686 | 687 | #### options.name 688 | Type: `String` 689 | 690 | Default: `"inject"` 691 | 692 | 693 | Used in the default [start](#optionsstarttag) and [end](#optionsendtag) tags below. 694 | 695 | #### options.removeTags 696 | Type: `Boolean` 697 | 698 | Default: `false` 699 | 700 | 701 | When `true` the start and end tags will be removed when injecting files. 702 | 703 | #### options.empty 704 | Type: `Boolean` 705 | 706 | Default: `false` 707 | 708 | 709 | When `true` all tags without corresponding files will be emptied. 710 | 711 | [**Warning** this has the potential issue of emptying more than expected.](https://github.com/klei/gulp-inject/issues/135) 712 | 713 | 714 | #### options.starttag 715 | 716 | **Type:** `String`|`Function(targetExt, sourceExt)` 717 | 718 | **Params (if function):** 719 | - `targetExt` - The file extension of the target file 720 | - `sourceExt` - The file extension of source file 721 | 722 | **Purpose:** 723 | 724 | Used to dynamically set starting placeholder tag depending on file extensions. 725 | In the provided string, or the string returned from the given function, the string `{{ext}}` is replaced with the source file extension name, e.g. "css", "js" or "html". `{{name}}` will be replaced by [`options.name`](#optionsname). `{{path}}` will be replaced by path to source file (when used together with [`options.relative`] it will allow relative path to source file. 726 | 727 | ##### Default: 728 | 729 | A function dependent on target file type and source file type that returns: 730 | 731 | * html as target: `` 732 | * haml as target: `-# {{name}}:{{ext}}` 733 | * jade as target: `//- {{name}}:{{ext}}` 734 | * pug as target: `//- {{name}}:{{ext}}` 735 | * jsx as target: `{/* {{name}}:{{ext}} */}` 736 | * slm as target: `/ {{name}}:{{ext}}` 737 | * less as target: `/* {{name}}:{{ext}} */` 738 | * sass, scss as target: `/* {{name}}:{{ext}} */` 739 | 740 | #### options.endtag 741 | 742 | **Type:** `String`|`Function(targetExt, sourceExt)` 743 | 744 | **Params (if function):** 745 | - `targetExt` - The file extension of the target file 746 | - `sourceExt` - The file extension of source file 747 | 748 | **Purpose:** 749 | 750 | Used to dynamically set ending placeholder tag depending on file extensions. 751 | In the provided string, or the string returned from the given function, the string `{{ext}}` is replaced with the source file extension name, e.g. "css", "js" or "html". `{{name}}` will be replaced by [`options.name`](#optionsname). `{{path}}` will be replaced by path to source file. 752 | 753 | ##### Default: 754 | 755 | A function dependent on target file type and source file type that returns: 756 | 757 | * html as target: `` 758 | * haml as target: `-# endinject` 759 | * jade as target: `//- endinject` 760 | * pug as target: `//- endinject` 761 | * jsx as target: `{/* endinject */}` 762 | * slm as target: `/ endinject` 763 | * less as target: `/* endinject */` 764 | * sass, scss as target: `/* endinject */` 765 | 766 | #### options.transform 767 | 768 | **Type**: `Function(filepath, file, index, length, targetFile)` 769 | 770 | **Params:** 771 | - `filepath` - The "unixified" path to the file with any `ignorePath`'s removed, `addPrefix` and `addSuffix` added 772 | - `file` - The [File object](https://github.com/wearefractal/vinyl) to inject given from `gulp.src` 773 | - `index` - 0-based file index 774 | - `length` - Total number of files to inject for the current file extension 775 | - `targetFile` - The target [file](https://github.com/wearefractal/vinyl) to inject into 776 | 777 | **Purpose:** 778 | 779 | Used to generate the content to inject for each file. 780 | 781 | ##### Default: 782 | 783 | [A function](#injecttransform) dependent on target file type and source file type that returns: 784 | 785 | **Injecting into `html`** 786 | 787 | * css files: `` 788 | * js files: `` 789 | * coffee files: `` 790 | * html files: `` 791 | * png files: `` 792 | * gif files: `` 793 | * jpg files: `` 794 | * jpeg files: `` 795 | 796 | If `options.selfClosingTag` is `true` the default transformer above will make the `` and `` tags self close, i.e: `` and `` respectively. 797 | 798 | **Injecting into `jsx`** 799 | 800 | The same as for injecting into `html` above with [`options.selfClosingTag`](#optionsselfclosingtag) set to `true`. 801 | 802 | **Injecting into `jade`** 803 | 804 | * css files: `link(rel="stylesheet", href=".css")` 805 | * js files: `script(src=".js")` 806 | * coffee files: `script(type="text/coffeescript", src=".coffee")` 807 | * html files: `link(rel="import", href=".html")` 808 | * png files: `img(src=".png")` 809 | * gif files: `img(src=".gif")` 810 | * jpg files: `img(src=".jpg")` 811 | * jpeg files: `img(src=".jpeg")` 812 | 813 | **Injecting into `pug`** 814 | 815 | * css files: `link(rel="stylesheet", href=".css")` 816 | * js files: `script(src=".js")` 817 | * coffee files: `script(type="text/coffeescript", src=".coffee")` 818 | * html files: `link(rel="import", href=".html")` 819 | * png files: `img(src=".png")` 820 | * gif files: `img(src=".gif")` 821 | * jpg files: `img(src=".jpg")` 822 | * jpeg files: `img(src=".jpeg")` 823 | 824 | **Injecting into `slm`** 825 | 826 | * css files: `link rel="stylesheet" href=".css"` 827 | * js files: `script src=".js"` 828 | * coffee files: `script type="text/coffeescript" src=".coffee"` 829 | * html files: `link rel="import" href=".html"` 830 | * png files: `img src=".png"` 831 | * gif files: `img src=".gif"` 832 | * jpg files: `img src=".jpg"` 833 | * jpeg files: `img src=".jpeg"` 834 | 835 | **Injecting into `haml`** 836 | 837 | * css files: `%link{rel:"stylesheet", href:".css"}` 838 | * js files: `%script{src:".js"}` 839 | * coffee files: `%script{type:"text/coffeescript", src:".coffee"}` 840 | * html files: `%link{rel:"import", href:".html"}` 841 | * png files: `%img{src:".png"}` 842 | * gif files: `%img{src:".gif"}` 843 | * jpg files: `%img{src:".jpg"}` 844 | * jpeg files: `%img{src:".jpeg"}` 845 | 846 | **Injecting into `less`** 847 | 848 | * css files: `@import ".css";` 849 | * less files: `@import ".less";` 850 | 851 | **Injecting into `scss`** 852 | 853 | * css files: `@import ".css";` 854 | * scss files: `@import ".scss";` 855 | * sass files: `@import ".sass";` 856 | 857 | **Injecting into `sass`** 858 | 859 | * css files: `@import ".css"` 860 | * sass files: `@import ".sass"` 861 | * scss files: `@import ".scss"` 862 | 863 | #### options.selfClosingTag 864 | Type: `Boolean` 865 | 866 | Default: `false` 867 | 868 | Affects the default `options.transform` function, see above. 869 | 870 | 871 | #### options.quiet 872 | Type: `Boolean` 873 | 874 | Default: `false` 875 | 876 | Lower the verbosity by setting this to true, suppressing the logging of successful injections. 877 | 878 | 879 | #### ~~options.templateString~~ 880 | 881 | ***DEPRECATED!*** 882 | 883 | *Deprecated since `v.1.0`. Use [`gulp-file`](https://www.npmjs.org/package/gulp-file) instead:* 884 | 885 | ```javascript 886 | var gulp = require('gulp'); 887 | var file = require('gulp-file'); 888 | var inject = require('gulp-inject'); 889 | 890 | file('index.html', '') 891 | .pipe(inject(gulp.src(['./src/app/**/*.js']), { 892 | starttag: '', 893 | endtag: '' 894 | })) 895 | .pipe(gulp.dest('./dest')); 896 | ``` 897 | 898 | #### ~~options.sort~~ 899 | 900 | ***DEPRECATED!*** 901 | 902 | *Deprecated since `v.1.0`. Use [`sort-stream`](https://www.npmjs.org/package/sort-stream) instead:* 903 | 904 | ```javascript 905 | var gulp = require('gulp'); 906 | var sort = require('sort-stream'); 907 | var inject = require('gulp-inject'); 908 | 909 | gulp.src('index.html') 910 | .pipe(inject( 911 | gulp.src(['./src/app/**/*.js']) 912 | .pipe(sort(function (a, b) { 913 | // Sort condition here... 914 | })) 915 | )) 916 | .pipe(gulp.dest('./dest')); 917 | ``` 918 | 919 | ### inject.transform 920 | 921 | The default transform function is exposed in the public API. 922 | 923 | For more details see [the code with tests](https://github.com/klei/gulp-inject/tree/master/src/transform). 924 | 925 | ##### inject.transform.html 926 | 927 | The default transform function for files into `html`, or other file types not `jade`, `pug`, `jsx`, `slm`, `less`, `scss`, `sass` or `haml`. 928 | 929 | ##### inject.transform.jade 930 | 931 | The default transform function for files into `jade`. 932 | 933 | ##### inject.transform.pug 934 | 935 | The default transform function for files into `pug`. 936 | 937 | ##### inject.transform.jsx 938 | 939 | The default transform function for files into `jsx`. 940 | 941 | ##### inject.transform.slm 942 | 943 | The default transform function for files into `slm`. 944 | 945 | ##### inject.transform.haml 946 | 947 | The default transform function for files into `haml`. 948 | 949 | ##### inject.transform.less 950 | 951 | The default transform function for files into `less`. 952 | 953 | ##### inject.transform.sass 954 | 955 | The default transform function for files into `sass`. 956 | 957 | ##### inject.transform.scss 958 | 959 | The default transform function for files into `scss`. 960 | 961 | 962 | ## License 963 | 964 | [MIT](http://en.wikipedia.org/wiki/MIT_License) © [Joakim Carlstein](http://joakim.beng.se) 965 | 966 | [npm-url]: https://npmjs.org/package/gulp-inject 967 | [npm-image]: https://badge.fury.io/js/gulp-inject.svg 968 | 969 | [travis-url]: http://travis-ci.org/klei/gulp-inject 970 | [travis-image]: https://secure.travis-ci.org/klei/gulp-inject.svg?branch=master 971 | 972 | [depstat-url]: https://david-dm.org/klei/gulp-inject 973 | [depstat-image]: https://david-dm.org/klei/gulp-inject.svg 974 | 975 | [codestyle-url]: https://github.com/sindresorhus/xo 976 | [codestyle-image]: https://img.shields.io/badge/code%20style-XO-5ed9c7.svg?style=flat 977 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = { 3 | extends: ['@commitlint/config-angular'] 4 | }; 5 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Export `gulp-inject` 3 | */ 4 | module.exports = exports = require('./src/inject'); 5 | 6 | /** 7 | * Export the default transform function(s) 8 | */ 9 | exports.transform = require('./src/transform'); 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gulp-inject", 3 | "version": "0.0.0-development", 4 | "description": "A javascript, stylesheet and webcomponent injection plugin for Gulp, i.e. inject file references into your index.html", 5 | "main": "index.js", 6 | "license": "MIT", 7 | "homepage": "https://github.com/klei/gulp-inject", 8 | "bugs": "https://github.com/klei/gulp-inject/issues", 9 | "author": { 10 | "name": "Joakim Carlstein", 11 | "email": "joakim@klei.se", 12 | "url": "http://joakim.beng.se" 13 | }, 14 | "keywords": [ 15 | "gulpplugin", 16 | "inject", 17 | "stylesheets", 18 | "webcomponents", 19 | "scripts", 20 | "index" 21 | ], 22 | "repository": { 23 | "type": "git", 24 | "url": "https://github.com/klei/gulp-inject.git" 25 | }, 26 | "scripts": { 27 | "lint": "xo", 28 | "pretest": "npm run -s lint", 29 | "test": "mocha -R spec src/**/*_test.js", 30 | "semantic-release": "semantic-release" 31 | }, 32 | "dependencies": { 33 | "ansi-colors": "^4.1.3", 34 | "arrify": "^2.0.1", 35 | "escape-string-regexp": "^2.0.0", 36 | "fancy-log": "^1.3.3", 37 | "group-array": "^1.0.0", 38 | "plugin-error": "^1.0.1", 39 | "stream-to-array": "^2.3.0", 40 | "through2": "^3.0.2" 41 | }, 42 | "devDependencies": { 43 | "@commitlint/cli": "^8.3.6", 44 | "@commitlint/config-angular": "^8.3.6", 45 | "event-stream": "^4.0.1", 46 | "husky": "^3.1.0", 47 | "mocha": "^6.2.3", 48 | "semantic-release": "^15.14.0", 49 | "should": "^13.2.3", 50 | "strip-color": "^0.1.0", 51 | "vinyl": "^2.2.1", 52 | "xo": "^0.25.3" 53 | }, 54 | "engines": { 55 | "node": ">=8" 56 | }, 57 | "xo": { 58 | "space": true, 59 | "envs": [ 60 | "node" 61 | ], 62 | "rules": { 63 | "func-names": 0, 64 | "func-name-matching": 0, 65 | "no-multi-assign": 0, 66 | "no-useless-escape": 0, 67 | "no-var": 0, 68 | "object-shorthand": [ 69 | 2, 70 | "never" 71 | ], 72 | "padding-line-between-statements": 0, 73 | "prefer-arrow-callback": 0, 74 | "prefer-destructuring": 0, 75 | "prefer-rest-params": 0, 76 | "prefer-spread": 0, 77 | "unicorn/explicit-length-check": 0, 78 | "unicorn/filename-case": 0, 79 | "unicorn/import-index": 0, 80 | "valid-jsdoc": 0 81 | } 82 | }, 83 | "husky": { 84 | "hooks": { 85 | "commit-msg": "commitlint -e" 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/extname/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | 4 | module.exports = exports = function extname(file) { 5 | file = file.split('?')[0]; 6 | return path.extname(file).slice(1); 7 | }; 8 | -------------------------------------------------------------------------------- /src/inject/expected/addPrefix.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/inject/expected/addSuffix.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/inject/expected/customName.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/inject/expected/customTags.html: -------------------------------------------------------------------------------- 1 |

    Hello world

    2 | -------------------------------------------------------------------------------- /src/inject/expected/customTagsWithExt.html: -------------------------------------------------------------------------------- 1 |

    Hello world

    2 | -------------------------------------------------------------------------------- /src/inject/expected/customTagsWithPath.html: -------------------------------------------------------------------------------- 1 |
    Partial body

    Hello world

    2 | -------------------------------------------------------------------------------- /src/inject/expected/customTransform.json: -------------------------------------------------------------------------------- 1 | { 2 | "js": [ 3 | "/lib.js", 4 | "/lib2.js" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /src/inject/expected/defaults.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %head 4 | %title gulp-inject 5 | -# inject:html 6 | %link{rel:"import", href:"/fixtures/component.html"} 7 | -# endinject 8 | -# inject:css 9 | %link{rel:"stylesheet", href:"/fixtures/styles.css"} 10 | -# endinject 11 | %body 12 | 13 | -# inject:js 14 | %script{src:"/fixtures/lib.js"} 15 | -# endinject 16 | -------------------------------------------------------------------------------- /src/inject/expected/defaults.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/inject/expected/defaults.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title gulp-inject 5 | //- inject:html 6 | link(rel="import", href="/fixtures/component.html") 7 | //- endinject 8 | //- inject:css 9 | link(rel="stylesheet", href="/fixtures/styles.css") 10 | //- endinject 11 | body 12 | 13 | //- inject:js 14 | script(src="/fixtures/lib.js") 15 | //- endinject 16 | -------------------------------------------------------------------------------- /src/inject/expected/defaults.jsx: -------------------------------------------------------------------------------- 1 | /* eslint import/no-unresolved:0 */ 2 | var React = require('react'); 3 | 4 | var App = React.createClass({ 5 | 6 | render: function () { 7 | return ( 8 | 9 | 10 | gulp-inject 11 | {/* inject:html */} 12 | 13 | {/* endinject */} 14 | {/* inject:css */} 15 | 16 | {/* endinject */} 17 | 18 | 19 | {/* inject:js */} 20 | 21 | {/* endinject */} 22 | 23 | 24 | ); 25 | } 26 | 27 | }); 28 | 29 | module.exports = App; 30 | -------------------------------------------------------------------------------- /src/inject/expected/defaults.less: -------------------------------------------------------------------------------- 1 | /* inject:css */ 2 | @import "/fixtures/lib.css"; 3 | /* endinject */ 4 | /* inject:less */ 5 | @import "/fixtures/component.less"; 6 | @import "/fixtures/styles.less"; 7 | /* endinject */ 8 | -------------------------------------------------------------------------------- /src/inject/expected/defaults.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title gulp-inject 5 | //- inject:html 6 | link(rel="import", href="/fixtures/component.html") 7 | //- endinject 8 | //- inject:css 9 | link(rel="stylesheet", href="/fixtures/styles.css") 10 | //- endinject 11 | body 12 | 13 | //- inject:js 14 | script(src="/fixtures/lib.js") 15 | //- endinject 16 | -------------------------------------------------------------------------------- /src/inject/expected/defaults.sass: -------------------------------------------------------------------------------- 1 | /* inject:css */ 2 | @import "/fixtures/lib.css" 3 | /* endinject */ 4 | /* inject:sass */ 5 | @import "/fixtures/component.sass" 6 | @import "/fixtures/styles.sass" 7 | /* endinject */ 8 | /* inject:scss */ 9 | @import "/fixtures/component.scss" 10 | @import "/fixtures/styles.scss" 11 | /* endinject */ 12 | -------------------------------------------------------------------------------- /src/inject/expected/defaults.scss: -------------------------------------------------------------------------------- 1 | /* inject:css */ 2 | @import "/fixtures/lib.css"; 3 | /* endinject */ 4 | /* inject:sass */ 5 | @import "/fixtures/component.sass"; 6 | @import "/fixtures/styles.sass"; 7 | /* endinject */ 8 | /* inject:scss */ 9 | @import "/fixtures/component.scss"; 10 | @import "/fixtures/styles.scss"; 11 | /* endinject */ 12 | -------------------------------------------------------------------------------- /src/inject/expected/defaults.slim: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title gulp-inject 5 | / inject:html 6 | link rel="import" href="/fixtures/component.html" 7 | / endinject 8 | / inject:css 9 | link rel="stylesheet" href="/fixtures/styles.css" 10 | / endinject 11 | body 12 | 13 | / inject:js 14 | script src="/fixtures/lib.js" 15 | / endinject 16 | -------------------------------------------------------------------------------- /src/inject/expected/defaults.slm: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title gulp-inject 5 | / inject:html 6 | link rel="import" href="/fixtures/component.html" 7 | / endinject 8 | / inject:css 9 | link rel="stylesheet" href="/fixtures/styles.css" 10 | / endinject 11 | body 12 | 13 | / inject:js 14 | script src="/fixtures/lib.js" 15 | / endinject 16 | -------------------------------------------------------------------------------- /src/inject/expected/defaults2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/inject/expected/emptyTags.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/inject/expected/emptyTags2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/inject/expected/emptyTags3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/inject/expected/existingData.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |

    Hello world

    7 | -------------------------------------------------------------------------------- /src/inject/expected/existingDataAndReplaced.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/inject/expected/ignorePath.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/inject/expected/issue107.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/inject/expected/issue144.jade: -------------------------------------------------------------------------------- 1 | //- inject:js 2 | script(src="/fixtures/lib.js") 3 | //- endinject 4 | 5 | //- inject:jsx 6 | script(type="text/jsx", src="/fixtures/component.jsx") 7 | //- endinject 8 | -------------------------------------------------------------------------------- /src/inject/expected/issue144.pug: -------------------------------------------------------------------------------- 1 | //- inject:js 2 | script(src="/fixtures/lib.js") 3 | //- endinject 4 | 5 | //- inject:jsx 6 | script(type="text/jsx", src="/fixtures/component.jsx") 7 | //- endinject 8 | -------------------------------------------------------------------------------- /src/inject/expected/issue176.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/inject/expected/issue177.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/inject/expected/issue39.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/inject/expected/issue56.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/inject/expected/issue71.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/inject/expected/issue74.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/inject/expected/noRootSlash.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/inject/expected/noRootSlashWithIgnorePath.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/inject/expected/parallell.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/inject/expected/relative.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/inject/expected/removeAndEmptyTags.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/inject/expected/removeTags.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/inject/expected/selfClosingTag.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/inject/expected/templateWithExistingData2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/inject/fixtures/issue107.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/inject/fixtures/issue144.jade: -------------------------------------------------------------------------------- 1 | //- inject:js 2 | //- endinject 3 | 4 | //- inject:jsx 5 | //- endinject 6 | -------------------------------------------------------------------------------- /src/inject/fixtures/issue144.pug: -------------------------------------------------------------------------------- 1 | //- inject:js 2 | //- endinject 3 | 4 | //- inject:jsx 5 | //- endinject 6 | -------------------------------------------------------------------------------- /src/inject/fixtures/issue176.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/inject/fixtures/issue39.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/inject/fixtures/issue56.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/inject/fixtures/issue71.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/inject/fixtures/issue74.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/inject/fixtures/partial.html: -------------------------------------------------------------------------------- 1 |
    Partial body
    -------------------------------------------------------------------------------- /src/inject/fixtures/template.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %head 4 | %title gulp-inject 5 | -# inject:html 6 | -# endinject 7 | -# inject:css 8 | -# endinject 9 | %body 10 | 11 | -# inject:js 12 | -# endinject 13 | -------------------------------------------------------------------------------- /src/inject/fixtures/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/inject/fixtures/template.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title gulp-inject 5 | //- inject:html 6 | //- endinject 7 | //- inject:css 8 | //- endinject 9 | body 10 | 11 | //- inject:js 12 | //- endinject 13 | -------------------------------------------------------------------------------- /src/inject/fixtures/template.json: -------------------------------------------------------------------------------- 1 | { 2 | "js": [ 3 | ] 4 | } 5 | -------------------------------------------------------------------------------- /src/inject/fixtures/template.jsx: -------------------------------------------------------------------------------- 1 | /* eslint import/no-unresolved:0 */ 2 | var React = require('react'); 3 | 4 | var App = React.createClass({ 5 | 6 | render: function () { 7 | return ( 8 | 9 | 10 | gulp-inject 11 | {/* inject:html */} 12 | {/* endinject */} 13 | {/* inject:css */} 14 | {/* endinject */} 15 | 16 | 17 | {/* inject:js */} 18 | {/* endinject */} 19 | 20 | 21 | ); 22 | } 23 | 24 | }); 25 | 26 | module.exports = App; 27 | -------------------------------------------------------------------------------- /src/inject/fixtures/template.less: -------------------------------------------------------------------------------- 1 | /* inject:css */ 2 | /* endinject */ 3 | /* inject:less */ 4 | /* endinject */ 5 | -------------------------------------------------------------------------------- /src/inject/fixtures/template.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title gulp-inject 5 | //- inject:html 6 | //- endinject 7 | //- inject:css 8 | //- endinject 9 | body 10 | 11 | //- inject:js 12 | //- endinject 13 | -------------------------------------------------------------------------------- /src/inject/fixtures/template.sass: -------------------------------------------------------------------------------- 1 | /* inject:css */ 2 | /* endinject */ 3 | /* inject:sass */ 4 | /* endinject */ 5 | /* inject:scss */ 6 | /* endinject */ 7 | -------------------------------------------------------------------------------- /src/inject/fixtures/template.scss: -------------------------------------------------------------------------------- 1 | /* inject:css */ 2 | /* endinject */ 3 | /* inject:sass */ 4 | /* endinject */ 5 | /* inject:scss */ 6 | /* endinject */ 7 | -------------------------------------------------------------------------------- /src/inject/fixtures/template.slim: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title gulp-inject 5 | / inject:html 6 | / endinject 7 | / inject:css 8 | / endinject 9 | body 10 | 11 | / inject:js 12 | / endinject 13 | -------------------------------------------------------------------------------- /src/inject/fixtures/template.slm: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title gulp-inject 5 | / inject:html 6 | / endinject 7 | / inject:css 8 | / endinject 9 | body 10 | 11 | / inject:js 12 | / endinject 13 | -------------------------------------------------------------------------------- /src/inject/fixtures/template2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject2 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/inject/fixtures/templateCustomName.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/inject/fixtures/templateCustomTags.html: -------------------------------------------------------------------------------- 1 |

    Hello world

    2 | -------------------------------------------------------------------------------- /src/inject/fixtures/templateTagsWithExt.html: -------------------------------------------------------------------------------- 1 |

    Hello world

    2 | -------------------------------------------------------------------------------- /src/inject/fixtures/templateTagsWithPath.html: -------------------------------------------------------------------------------- 1 |

    Hello world

    2 | -------------------------------------------------------------------------------- /src/inject/fixtures/templateWithExistingData.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

    Hello world

    6 | -------------------------------------------------------------------------------- /src/inject/fixtures/templateWithExistingData2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/inject/fixtures/templateWithExistingData3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gulp-inject 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/inject/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var through2 = require('through2'); 3 | var fancyLog = require('fancy-log'); 4 | var PluginError = require('plugin-error'); 5 | var colors = require('ansi-colors'); 6 | var streamToArray = require('stream-to-array'); 7 | var escapeStringRegexp = require('escape-string-regexp'); 8 | var groupArray = require('group-array'); 9 | var extname = require('../extname'); 10 | var transform = require('../transform'); 11 | var tags = require('../tags'); 12 | var getFilepath = require('../path'); 13 | 14 | var magenta = colors.magenta; 15 | var cyan = colors.cyan; 16 | var noop = function noop() {}; 17 | 18 | /** 19 | * Constants 20 | */ 21 | var PLUGIN_NAME = 'gulp-inject'; 22 | var DEFAULT_NAME_FOR_TAGS = 'inject'; 23 | var LEADING_WHITESPACE_REGEXP = /^\s*/; 24 | 25 | module.exports = exports = function (sources, opt) { 26 | if (!sources) { 27 | throw error('Missing sources stream!'); 28 | } 29 | if (!opt) { 30 | opt = {}; 31 | } 32 | 33 | if (opt.sort) { 34 | throw error('sort option is deprecated! Use `sort-stream` module instead!'); 35 | } 36 | if (opt.templateString) { 37 | throw error('`templateString` option is deprecated! Create a virtual `vinyl` file instead!'); 38 | } 39 | if (opt.transform && typeof opt.transform !== 'function') { 40 | throw error('transform option must be a function'); 41 | } 42 | // Notify people of common mistakes... 43 | if (typeof opt.read !== 'undefined') { 44 | throw error('There is no `read` option. Did you mean to provide it for `gulp.src` perhaps?'); 45 | } 46 | 47 | // Defaults: 48 | opt.quiet = bool(opt, 'quiet', false); 49 | opt.relative = bool(opt, 'relative', false); 50 | opt.addRootSlash = bool(opt, 'addRootSlash', !opt.relative); 51 | opt.transform = defaults(opt, 'transform', transform); 52 | opt.tags = tags(); 53 | opt.name = defaults(opt, 'name', DEFAULT_NAME_FOR_TAGS); 54 | transform.selfClosingTag = bool(opt, 'selfClosingTag', false); 55 | 56 | // Is the first parameter a Vinyl File Stream: 57 | if (typeof sources.on === 'function' && typeof sources.pipe === 'function') { 58 | return handleVinylStream(sources, opt); 59 | } 60 | 61 | throw error('passing target file as a string is deprecated! Pass a vinyl file stream (i.e. use `gulp.src`)!'); 62 | }; 63 | 64 | function defaults(options, prop, defaultValue) { 65 | return options[prop] || defaultValue; 66 | } 67 | 68 | function bool(options, prop, defaultVal) { 69 | return typeof options[prop] === 'undefined' ? defaultVal : Boolean(options[prop]); 70 | } 71 | 72 | /** 73 | * Handle injection when files to 74 | * inject comes from a Vinyl File Stream 75 | * 76 | * @param {Stream} sources 77 | * @param {Object} opt 78 | * @returns {Stream} 79 | */ 80 | function handleVinylStream(sources, opt) { 81 | var collected = streamToArray(sources); 82 | 83 | return through2.obj(function (target, enc, cb) { 84 | if (target.isStream()) { 85 | return cb(error('Streams not supported for target templates!')); 86 | } 87 | collected.then(function (collection) { // eslint-disable-line promise/prefer-await-to-then 88 | target.contents = getNewContent(target, collection, opt); 89 | this.push(target); 90 | cb(); 91 | }.bind(this)) 92 | .catch(function (error_) { 93 | cb(error_); 94 | }); 95 | }); 96 | } 97 | 98 | /** 99 | * Get new content for template 100 | * with all injections made 101 | * 102 | * @param {Object} target 103 | * @param {Array} collection 104 | * @param {Object} opt 105 | * @returns {Buffer} 106 | */ 107 | function getNewContent(target, collection, opt) { 108 | var logger = opt.quiet ? noop : function (filesCount) { 109 | if (filesCount) { 110 | var pluralState = filesCount > 1 ? 's' : ''; 111 | log(cyan(filesCount) + ' file' + pluralState + ' into ' + magenta(target.relative) + '.'); 112 | } else { 113 | log('Nothing to inject into ' + magenta(target.relative) + '.'); 114 | } 115 | }; 116 | var content = String(target.contents); 117 | var targetExt = extname(target.path); 118 | var files = prepareFiles(collection, targetExt, opt, target); 119 | var filesPerTags = groupArray(files, 'tagKey'); 120 | var startAndEndTags = Object.keys(filesPerTags); 121 | var matches = []; 122 | var injectedFilesCount = 0; 123 | 124 | startAndEndTags.forEach(function (tagKey) { 125 | var files = filesPerTags[tagKey]; 126 | var startTag = files[0].startTag; 127 | var endTag = files[0].endTag; 128 | var tagsToInject = getTagsToInject(files, target, opt); 129 | content = inject(content, { 130 | startTag: startTag, 131 | endTag: endTag, 132 | tagsToInject: tagsToInject, 133 | removeTags: opt.removeTags, 134 | empty: opt.empty, 135 | willInject: function (filesToInject) { 136 | injectedFilesCount += filesToInject.length; 137 | }, 138 | onMatch: function (match) { 139 | matches.push(match[0]); 140 | } 141 | }); 142 | }); 143 | 144 | logger(injectedFilesCount); 145 | 146 | if (opt.empty) { 147 | var ext = '{{ANY}}'; 148 | var startTag = getTagRegExp(opt.tags.start(targetExt, ext, opt.starttag), ext, opt); 149 | var endTag = getTagRegExp(opt.tags.end(targetExt, ext, opt.endtag), ext, opt); 150 | 151 | content = inject(content, { 152 | startTag: startTag, 153 | endTag: endTag, 154 | tagsToInject: [], 155 | removeTags: opt.removeTags, 156 | empty: opt.empty, 157 | shouldAbort: function (match) { 158 | return matches.includes(match[0]); 159 | } 160 | }); 161 | } 162 | 163 | return Buffer.from(content); 164 | } 165 | 166 | /** 167 | * Inject tags into content for given 168 | * start and end tags 169 | * 170 | * @param {String} content 171 | * @param {Object} opt 172 | * @returns {String} 173 | */ 174 | function inject(content, opt) { 175 | var startTag = opt.startTag; 176 | var endTag = opt.endTag; 177 | var startMatch; 178 | var endMatch; 179 | 180 | /** 181 | * The content consists of: 182 | * 183 | * 184 | * 185 | * 186 | * 187 | * 188 | */ 189 | 190 | while ((startMatch = startTag.exec(content)) !== null) { 191 | if (typeof opt.onMatch === 'function') { 192 | opt.onMatch(startMatch); 193 | } 194 | if (typeof opt.shouldAbort === 'function' && opt.shouldAbort(startMatch)) { 195 | continue; 196 | } 197 | // Take care of content length change: 198 | endTag.lastIndex = startTag.lastIndex; 199 | endMatch = endTag.exec(content); 200 | if (!endMatch) { 201 | throw error('Missing end tag for start tag: ' + startMatch[0]); 202 | } 203 | var toInject = opt.tagsToInject.slice(); 204 | 205 | if (typeof opt.willInject === 'function') { 206 | opt.willInject(toInject); 207 | } 208 | 209 | // : 210 | var newContents = content.slice(0, startMatch.index); 211 | 212 | if (opt.removeTags) { 213 | if (opt.empty) { 214 | // Take care of content length change: 215 | startTag.lastIndex -= startMatch[0].length; 216 | } 217 | } else { 218 | // + 219 | toInject.unshift(startMatch[0]); 220 | toInject.push(endMatch[0]); 221 | } 222 | var previousInnerContent = content.slice(startTag.lastIndex, endMatch.index); 223 | var indent = getLeadingWhitespace(previousInnerContent); 224 | // : 225 | newContents += toInject.join(indent); 226 | // : 227 | newContents += content.slice(endTag.lastIndex); 228 | // Replace old content with new: 229 | content = newContents; 230 | } 231 | 232 | return content; 233 | } 234 | 235 | function getLeadingWhitespace(str) { 236 | return str.match(LEADING_WHITESPACE_REGEXP)[0]; 237 | } 238 | 239 | function prepareFiles(files, targetExt, opt, target) { 240 | return files.map(function (file) { 241 | var ext = extname(file.path); 242 | var filePath = getFilepath(file, target, opt); 243 | var startTag = getTagRegExp(opt.tags.start(targetExt, ext, opt.starttag), ext, opt, filePath); 244 | var endTag = getTagRegExp(opt.tags.end(targetExt, ext, opt.endtag), ext, opt, filePath); 245 | var tagKey = String(startTag) + String(endTag); 246 | return { 247 | file: file, 248 | ext: ext, 249 | startTag: startTag, 250 | endTag: endTag, 251 | tagKey: tagKey 252 | }; 253 | }); 254 | } 255 | 256 | function getTagRegExp(tag, sourceExt, opt, sourcePath) { 257 | tag = makeWhiteSpaceOptional(escapeStringRegexp(tag)); 258 | tag = replaceVariables(tag, { 259 | name: opt.name, 260 | path: sourcePath, 261 | ext: sourceExt === '{{ANY}}' ? '.+' : sourceExt 262 | }); 263 | return new RegExp(tag, 'ig'); 264 | } 265 | 266 | function replaceVariables(str, variables) { 267 | return Object.keys(variables).reduce(function (str, variable) { 268 | return str.replace(new RegExp(escapeStringRegexp(escapeStringRegexp('{{' + variable + '}}')), 'ig'), variables[variable] + '\\b'); 269 | }, str); 270 | } 271 | 272 | function makeWhiteSpaceOptional(str) { 273 | return str.replace(/\s+/g, '\\s*'); 274 | } 275 | 276 | function getTagsToInject(files, target, opt) { 277 | return files.reduce(function transformFile(lines, file, i, files) { 278 | var filepath = getFilepath(file.file, target, opt); 279 | var transformedContents = opt.transform(filepath, file.file, i, files.length, target); 280 | if (typeof transformedContents !== 'string') { 281 | return lines; 282 | } 283 | return lines.concat(transformedContents); 284 | }, []); 285 | } 286 | 287 | function log(message) { 288 | fancyLog.info(magenta(PLUGIN_NAME), message); 289 | } 290 | 291 | function error(message) { 292 | return new PluginError(PLUGIN_NAME, message); 293 | } 294 | -------------------------------------------------------------------------------- /src/inject/inject_test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 'use strict'; 3 | 4 | var fs = require('fs'); 5 | var path = require('path'); 6 | var es = require('event-stream'); 7 | var should = require('should'); 8 | var fancyLog = require('fancy-log'); 9 | var Vinyl = require('vinyl'); 10 | var stripColor = require('strip-color'); 11 | var inject = require('../../.'); 12 | 13 | describe('gulp-inject', function () { 14 | var log; 15 | 16 | beforeEach(function () { 17 | log = fancyLog.info; 18 | }); 19 | 20 | afterEach(function () { 21 | fancyLog.info = log; 22 | }); 23 | 24 | it('should throw an error when the old api with target as string is used', function () { 25 | should(function () { 26 | inject('fixtures/template.html'); 27 | }).throw(); 28 | }); 29 | 30 | it('should throw an error if sources stream is undefined', function () { 31 | should(function () { 32 | inject(); 33 | }).throw(); 34 | }); 35 | 36 | it('should throw an error if `templateString` option is specified', function () { 37 | should(function () { 38 | src(['template.html'], {read: true}) 39 | .pipe(inject(src(['file.js']), {templateString: ''})); 40 | }).throw(); 41 | }); 42 | 43 | it('should throw an error if `sort` option is specified', function () { 44 | should(function () { 45 | src(['template.html'], {read: true}) 46 | .pipe(inject(src(['file.js']), {sort: function () {}})); 47 | }).throw(); 48 | }); 49 | 50 | it('should inject stylesheets, scripts, images, jsx and html components into desired file', function (done) { 51 | var target = src(['template.html'], {read: true}); 52 | var sources = src([ 53 | 'lib.js', 54 | 'component.html', 55 | 'styles.css', 56 | 'image.png', 57 | 'lib.jsx' 58 | ]); 59 | 60 | var stream = target.pipe(inject(sources)); 61 | 62 | streamShouldContain(stream, ['defaults.html'], done); 63 | }); 64 | 65 | it('should inject sources into multiple targets', function (done) { 66 | var target = src(['template.html', 'template2.html'], {read: true}); 67 | var sources = src([ 68 | 'lib.js', 69 | 'component.html', 70 | 'styles.css', 71 | 'image.png', 72 | 'lib.jsx' 73 | ]); 74 | 75 | var stream = target.pipe(inject(sources)); 76 | 77 | streamShouldContain(stream, ['defaults.html', 'defaults2.html'], done); 78 | }); 79 | 80 | it('should inject stylesheets, scripts and html components with `ignorePath` removed from file path', function (done) { 81 | var target = src(['template.html'], {read: true}); 82 | var sources = src([ 83 | 'lib.js', 84 | 'component.html', 85 | 'lib2.js', 86 | 'styles.css', 87 | 'lib.jsx' 88 | ]); 89 | 90 | var stream = target.pipe(inject(sources, {ignorePath: '/fixtures'})); 91 | 92 | streamShouldContain(stream, ['ignorePath.html'], done); 93 | }); 94 | 95 | it('should inject stylesheets, scripts and html components with relative paths to target file if `relative` is truthy', function (done) { 96 | var target = src(['template.html'], {read: true}); 97 | var sources = src([ 98 | '../../folder/lib.js', 99 | '../../another/component.html', 100 | '../a-folder/lib2.js', 101 | '../../yet-another/styles.css', 102 | '../components/lib.jsx' 103 | ]); 104 | 105 | var stream = target.pipe(inject(sources, {relative: true})); 106 | 107 | streamShouldContain(stream, ['relative.html'], done); 108 | }); 109 | 110 | it('should inject stylesheets, scripts and html components with `addPrefix` added to file path', function (done) { 111 | var target = src(['template.html'], {read: true}); 112 | var sources = src([ 113 | 'lib.js', 114 | 'component.html', 115 | 'lib2.js', 116 | 'styles.css', 117 | 'lib.jsx' 118 | ]); 119 | 120 | var stream = target.pipe(inject(sources, {addPrefix: 'my-test-dir'})); 121 | 122 | streamShouldContain(stream, ['addPrefix.html'], done); 123 | }); 124 | 125 | it('should inject stylesheets, scripts and html components with `addSuffix` added to file path', function (done) { 126 | var target = src(['template.html'], {read: true}); 127 | var sources = src([ 128 | 'lib.js', 129 | 'component.html', 130 | 'lib2.js', 131 | 'styles.css', 132 | 'lib.jsx' 133 | ]); 134 | 135 | var stream = target.pipe(inject(sources, {addSuffix: '?my-test=suffix'})); 136 | 137 | streamShouldContain(stream, ['addSuffix.html'], done); 138 | }); 139 | 140 | it('should inject stylesheets and html components with self closing tags if `selfClosingTag` is truthy', function (done) { 141 | var target = src(['template.html'], {read: true}); 142 | var sources = src([ 143 | 'component.html', 144 | 'styles.css' 145 | ]); 146 | 147 | var stream = target.pipe(inject(sources, {selfClosingTag: true})); 148 | 149 | streamShouldContain(stream, ['selfClosingTag.html'], done); 150 | }); 151 | 152 | it('should inject stylesheets, scripts and html components without root slash if `addRootSlash` is `false`', function (done) { 153 | var target = src(['template.html'], {read: true}); 154 | var sources = src([ 155 | 'lib.js', 156 | 'component.html', 157 | 'styles.css', 158 | 'lib.jsx' 159 | ]); 160 | 161 | var stream = target.pipe(inject(sources, {addRootSlash: false})); 162 | 163 | streamShouldContain(stream, ['noRootSlash.html'], done); 164 | }); 165 | 166 | it('should inject stylesheets, scripts and html components without root slash if `addRootSlash` is `false` and `ignorePath` is set', function (done) { 167 | var target = src(['template.html'], {read: true}); 168 | var sources = src([ 169 | 'a/folder/lib.js', 170 | 'a/folder/component.html', 171 | 'a/folder/styles.css', 172 | 'a/folder/lib.jsx' 173 | ]); 174 | 175 | var stream = target.pipe(inject(sources, {addRootSlash: false, ignorePath: 'fixtures'})); 176 | 177 | streamShouldContain(stream, ['noRootSlashWithIgnorePath.html'], done); 178 | }); 179 | 180 | it('should use starttag and endtag if specified', function (done) { 181 | var target = src(['templateCustomTags.html'], {read: true}); 182 | var sources = src([ 183 | 'lib.js', 184 | 'lib2.js', 185 | 'style.css' 186 | ]); 187 | 188 | var stream = target.pipe(inject(sources, { 189 | ignorePath: 'fixtures', 190 | starttag: '', 191 | endtag: '

    ' 192 | })); 193 | 194 | streamShouldContain(stream, ['customTags.html'], done); 195 | }); 196 | 197 | it('should use starttag and endtag with specified name if specified', function (done) { 198 | var target = src(['templateCustomName.html'], {read: true}); 199 | var sources = src([ 200 | 'lib.js', 201 | 'lib2.js' 202 | ]); 203 | 204 | var stream = target.pipe(inject(sources, {name: 'head'})); 205 | 206 | streamShouldContain(stream, ['customName.html'], done); 207 | }); 208 | 209 | it('should replace {{ext}} in starttag and endtag with current file extension if specified', function (done) { 210 | var target = src(['templateTagsWithExt.html'], {read: true}); 211 | var sources = src([ 212 | 'lib.js', 213 | 'component.html', 214 | 'lib2.js' 215 | ]); 216 | 217 | var stream = target.pipe(inject(sources, { 218 | ignorePath: 'fixtures', 219 | starttag: '', 220 | endtag: '' 221 | })); 222 | 223 | streamShouldContain(stream, ['customTagsWithExt.html'], done); 224 | }); 225 | 226 | it('should replace {{path}} in starttag and endtag with current file path if specified', function (done) { 227 | var target = src(['templateTagsWithPath.html'], {read: true}); 228 | var sources = src([ 229 | 'template.html', 230 | 'partial.html', 231 | 'template2.html' 232 | ], {read: true}); 233 | 234 | var stream = target.pipe(inject(sources, { 235 | starttag: '', 236 | endtag: '', 237 | transform: function (filePath, file) { 238 | return file.contents.toString('utf8'); 239 | } 240 | })); 241 | 242 | streamShouldContain(stream, ['customTagsWithPath.html'], done); 243 | }); 244 | 245 | it('should replace existing data within start and end tag', function (done) { 246 | var target = src(['templateWithExistingData.html'], {read: true}); 247 | var sources = src([ 248 | 'lib.js', 249 | 'component.html', 250 | 'lib2.js', 251 | 'styles.css' 252 | ]); 253 | 254 | var stream = target.pipe(inject(sources, { 255 | ignorePath: 'fixtures' 256 | })); 257 | 258 | streamShouldContain(stream, ['existingData.html'], done); 259 | }); 260 | 261 | it('should use custom transform function for each file if specified', function (done) { 262 | var target = src(['template.json'], {read: true}); 263 | var sources = src([ 264 | 'lib.js', 265 | 'component.html', 266 | 'lib2.js', 267 | 'styles.css' 268 | ]); 269 | 270 | var stream = target.pipe(inject(sources, { 271 | ignorePath: 'fixtures', 272 | starttag: '"{{ext}}": [', 273 | endtag: ']', 274 | transform: function (srcPath, file, i, length) { 275 | return ' "' + srcPath + '"' + (i + 1 < length ? ',' : ''); 276 | } 277 | })); 278 | 279 | streamShouldContain(stream, ['customTransform.json'], done); 280 | }); 281 | 282 | it('should use special default tags when injecting into jsx files', function (done) { 283 | var target = src(['template.jsx'], {read: true}); 284 | var sources = src([ 285 | 'lib.js', 286 | 'component.html', 287 | 'styles.css' 288 | ]); 289 | 290 | var stream = target.pipe(inject(sources)); 291 | 292 | streamShouldContain(stream, ['defaults.jsx'], done); 293 | }); 294 | 295 | it('should use special default tags when injecting into jade files', function (done) { 296 | var target = src(['template.jade'], {read: true}); 297 | var sources = src([ 298 | 'lib.js', 299 | 'component.html', 300 | 'styles.css' 301 | ]); 302 | 303 | var stream = target.pipe(inject(sources)); 304 | 305 | streamShouldContain(stream, ['defaults.jade'], done); 306 | }); 307 | 308 | it('should use special default tags when injecting into pug files', function (done) { 309 | var target = src(['template.pug'], {read: true}); 310 | var sources = src([ 311 | 'lib.js', 312 | 'component.html', 313 | 'styles.css' 314 | ]); 315 | 316 | var stream = target.pipe(inject(sources)); 317 | 318 | streamShouldContain(stream, ['defaults.pug'], done); 319 | }); 320 | 321 | it('should be able to inject jsx into jade files (Issue #144)', function (done) { 322 | var target = src(['issue144.jade'], {read: true}); 323 | var sources = src([ 324 | 'lib.js', 325 | 'component.jsx' 326 | ]); 327 | 328 | var stream = target.pipe(inject(sources)); 329 | 330 | streamShouldContain(stream, ['issue144.jade'], done); 331 | }); 332 | 333 | it('should be able to inject jsx into pug files (Issue #144)', function (done) { 334 | var target = src(['issue144.pug'], {read: true}); 335 | var sources = src([ 336 | 'lib.js', 337 | 'component.jsx' 338 | ]); 339 | 340 | var stream = target.pipe(inject(sources)); 341 | 342 | streamShouldContain(stream, ['issue144.pug'], done); 343 | }); 344 | 345 | it('should use special default tags when injecting into slm files', function (done) { 346 | var target = src(['template.slm'], {read: true}); 347 | var sources = src([ 348 | 'lib.js', 349 | 'component.html', 350 | 'styles.css' 351 | ]); 352 | 353 | var stream = target.pipe(inject(sources)); 354 | 355 | streamShouldContain(stream, ['defaults.slm'], done); 356 | }); 357 | 358 | it('should use special default tags when injecting into slim files', function (done) { 359 | var target = src(['template.slim'], {read: true}); 360 | var sources = src([ 361 | 'lib.js', 362 | 'component.html', 363 | 'styles.css' 364 | ]); 365 | 366 | var stream = target.pipe(inject(sources)); 367 | 368 | streamShouldContain(stream, ['defaults.slim'], done); 369 | }); 370 | 371 | it('should use special default tags when injecting into haml files', function (done) { 372 | var target = src(['template.haml'], {read: true}); 373 | var sources = src([ 374 | 'lib.js', 375 | 'component.html', 376 | 'styles.css' 377 | ]); 378 | 379 | var stream = target.pipe(inject(sources)); 380 | 381 | streamShouldContain(stream, ['defaults.haml'], done); 382 | }); 383 | 384 | it('should use special default tags when injecting into less files', function (done) { 385 | var target = src(['template.less'], {read: true}); 386 | var sources = src([ 387 | 'lib.css', 388 | 'component.less', 389 | 'styles.less' 390 | ]); 391 | 392 | var stream = target.pipe(inject(sources)); 393 | 394 | streamShouldContain(stream, ['defaults.less'], done); 395 | }); 396 | 397 | it('should use special default tags when injecting into sass files', function (done) { 398 | var target = src(['template.sass'], {read: true}); 399 | var sources = src([ 400 | 'lib.css', 401 | 'component.sass', 402 | 'styles.sass', 403 | 'component.scss', 404 | 'styles.scss' 405 | ]); 406 | 407 | var stream = target.pipe(inject(sources)); 408 | 409 | streamShouldContain(stream, ['defaults.sass'], done); 410 | }); 411 | 412 | it('should use special default tags when injecting into scss files', function (done) { 413 | var target = src(['template.scss'], {read: true}); 414 | var sources = src([ 415 | 'lib.css', 416 | 'component.sass', 417 | 'styles.sass', 418 | 'component.scss', 419 | 'styles.scss' 420 | ]); 421 | 422 | var stream = target.pipe(inject(sources)); 423 | 424 | streamShouldContain(stream, ['defaults.scss'], done); 425 | }); 426 | 427 | it('should be able to chain inject calls with different names without overrides (Issue #39)', function (done) { 428 | var target = src(['issue39.html'], {read: true}); 429 | var sources1 = src([ 430 | 'lib1.js', 431 | 'lib3.js' 432 | ]); 433 | var sources2 = src([ 434 | 'lib2.js', 435 | 'lib4.js' 436 | ]); 437 | 438 | var stream = target 439 | .pipe(inject(sources1, {name: 'head'})) 440 | .pipe(inject(sources2)); 441 | 442 | streamShouldContain(stream, ['issue39.html'], done); 443 | }); 444 | 445 | it('should be able to inject hashed files (Issue #71)', function (done) { 446 | var target = src(['issue71.html'], {read: true}); 447 | var sources = src([ 448 | 'lib.js?abcdef0123456789', 449 | 'styles.css?0123456789abcdef' 450 | ]); 451 | 452 | var stream = target.pipe(inject(sources)); 453 | 454 | streamShouldContain(stream, ['issue71.html'], done); 455 | }); 456 | 457 | it('should be able to inject when tags are missing whitespace (Issue #56)', function (done) { 458 | var target = src(['issue56.html'], {read: true}); 459 | var sources = src([ 460 | 'lib.js' 461 | ]); 462 | 463 | var stream = target.pipe(inject(sources)); 464 | 465 | streamShouldContain(stream, ['issue56.html'], done); 466 | }); 467 | 468 | it('should not crash when transform function returns undefined (Issue #74)', function (done) { 469 | var target = src(['issue74.html'], {read: true}); 470 | var sources = src([ 471 | 'lib.js' 472 | ]); 473 | 474 | var stream = target.pipe(inject(sources, {transform: function () {}})); 475 | 476 | streamShouldContain(stream, ['issue74.html'], done); 477 | }); 478 | 479 | it('should be able to remove tags if removeTags option is set', function (done) { 480 | var target = src(['template.html'], {read: true}); 481 | var sources = src([ 482 | 'lib.js', 483 | 'component.html', 484 | 'styles.css', 485 | 'image.png', 486 | 'lib.jsx' 487 | ]); 488 | 489 | var stream = target.pipe(inject(sources, {removeTags: true})); 490 | 491 | streamShouldContain(stream, ['removeTags.html'], done); 492 | }); 493 | 494 | it('should be able to remove tags without removing whitespace (issue #177)', function (done) { 495 | var target = src(['template.html'], {read: true}); 496 | var sources = src([ 497 | 'lib.js', 498 | 'component.html', 499 | 'styles.css', 500 | 'morestyles.css', 501 | 'andevenmore.css', 502 | 'image.png', 503 | 'lib.jsx' 504 | ]); 505 | 506 | var stream = target.pipe(inject(sources, {removeTags: true})); 507 | 508 | streamShouldContain(stream, ['issue177.html'], done); 509 | }); 510 | 511 | it('should not produce log output if quiet option is set', function (done) { 512 | var logOutput = []; 513 | fancyLog.info = function () { 514 | logOutput.push(arguments); 515 | }; 516 | 517 | var target = src(['template.html'], {read: true}); 518 | var sources = src([ 519 | 'lib.js', 520 | 'component.html', 521 | 'styles.css', 522 | 'image.png' 523 | ]); 524 | 525 | var stream = target.pipe(inject(sources, {quiet: true})); 526 | 527 | // Dummy data reader to make the `end` event be triggered 528 | stream.on('data', function () { 529 | }); 530 | 531 | stream.on('end', function () { 532 | logOutput.should.have.length(0); 533 | done(); 534 | }); 535 | }); 536 | 537 | it('should produce log output if quiet option is not set', function (done) { 538 | var logOutput = []; 539 | fancyLog.info = function () { 540 | logOutput.push(arguments); 541 | }; 542 | 543 | var target = src(['template.html'], {read: true}); 544 | var sources = src([ 545 | 'lib.js', 546 | 'component.html', 547 | 'styles.css', 548 | 'image.png' 549 | ]); 550 | 551 | var stream = target.pipe(inject(sources)); 552 | 553 | // Dummy data reader to make the `end` event be triggered 554 | stream.on('data', function () { 555 | }); 556 | 557 | stream.on('end', function () { 558 | logOutput.should.have.length(1); 559 | done(); 560 | }); 561 | }); 562 | 563 | it('should produce log output only for files actually injected (issue #184)', function (done) { 564 | var logOutput = []; 565 | fancyLog.info = function (a, b) { 566 | logOutput.push(a + ' ' + b); 567 | }; 568 | 569 | var target = src(['template2.html'], {read: true}); 570 | var sources = src([ 571 | 'lib.js', 572 | 'component.html', 573 | 'styles.css', 574 | 'image.png' 575 | ]); 576 | 577 | var stream = target.pipe(inject(sources)); 578 | 579 | // Dummy data reader to make the `end` event be triggered 580 | stream.on('data', function () { 581 | }); 582 | 583 | stream.on('end', function () { 584 | logOutput.should.have.length(1); 585 | stripColor(logOutput[0]).should.equal('gulp-inject 1 file into template2.html.'); 586 | done(); 587 | }); 588 | }); 589 | 590 | it('should produce log output for multiple files actually injected (issue #192)', function (done) { 591 | var logOutput = []; 592 | fancyLog.info = function (a, b) { 593 | logOutput.push(a + ' ' + b); 594 | }; 595 | 596 | var target = src(['template2.html'], {read: true}); 597 | var sources = src([ 598 | 'styles.css', 599 | 'app.css' 600 | ]); 601 | 602 | var stream = target.pipe(inject(sources)); 603 | 604 | // Dummy data reader to make the `end` event be triggered 605 | stream.on('data', function () { 606 | }); 607 | 608 | stream.on('end', function () { 609 | logOutput.should.have.length(1); 610 | stripColor(logOutput[0]).should.equal('gulp-inject 2 files into template2.html.'); 611 | done(); 612 | }); 613 | }); 614 | 615 | it('should be able to modify only the filepath (Issue #107)', function (done) { 616 | var version = '1.0.0'; 617 | 618 | var target = src(['issue107.html'], {read: true}); 619 | var sources = src([ 620 | 'lib.js' 621 | ]); 622 | 623 | var stream = target.pipe(inject(sources, { 624 | transform: function (filepath) { 625 | arguments[0] = filepath + '?v=' + version; 626 | return inject.transform.apply(inject.transform, arguments); 627 | } 628 | })); 629 | 630 | streamShouldContain(stream, ['issue107.html'], done); 631 | }); 632 | 633 | it('should be able to inject source maps (Issue #176)', function (done) { 634 | var target = src(['issue176.html'], {read: true}); 635 | var sources = src([ 636 | 'lib.js', 637 | 'lib.js.map' 638 | ]); 639 | 640 | var stream = target.pipe(inject(sources)); 641 | 642 | streamShouldContain(stream, ['issue176.html'], done); 643 | }); 644 | 645 | it('should be able to empty tags when there are no files for that tag and empty option is set', function (done) { 646 | var target = src(['templateWithExistingData2.html'], {read: true}); 647 | var sources = src([ 648 | 'lib.js' 649 | ]); 650 | 651 | var stream = target.pipe(inject(sources, {empty: true})); 652 | 653 | streamShouldContain(stream, ['emptyTags.html'], done); 654 | }); 655 | 656 | it('should be able both leave and replace tag contents when there are no files for some tags and empty option is not set', function (done) { 657 | var target = src(['templateWithExistingData2.html'], {read: true}); 658 | var sources = src([ 659 | 'picture.png' 660 | ]); 661 | 662 | var stream = target.pipe(inject(sources)); 663 | 664 | streamShouldContain(stream, ['existingDataAndReplaced.html'], done); 665 | }); 666 | 667 | it('should be able to empty all tags when there are no files at all and empty option is set', function (done) { 668 | var target = src(['templateWithExistingData2.html'], {read: true}); 669 | var sources = src([]); 670 | 671 | var stream = target.pipe(inject(sources, {empty: true})); 672 | 673 | streamShouldContain(stream, ['emptyTags2.html'], done); 674 | }); 675 | 676 | it('should leave all tags when there are no files at all and empty option is not set', function (done) { 677 | var target = src(['templateWithExistingData2.html'], {read: true}); 678 | var sources = src([]); 679 | 680 | var stream = target.pipe(inject(sources)); 681 | 682 | streamShouldContain(stream, ['templateWithExistingData2.html'], done); 683 | }); 684 | 685 | it('should be able to remove and empty tags when there are no files for that tag and empty and removeTags option is set', function (done) { 686 | var target = src(['templateWithExistingData2.html'], {read: true}); 687 | var sources = src([ 688 | 'lib.js' 689 | ]); 690 | 691 | var stream = target.pipe(inject(sources, {empty: true, removeTags: true})); 692 | 693 | streamShouldContain(stream, ['removeAndEmptyTags.html'], done); 694 | }); 695 | 696 | it('should be able to empty custom tags when there are no files at all and empty option is set', function (done) { 697 | var target = src(['templateWithExistingData3.html'], {read: true}); 698 | var sources = src([]); 699 | 700 | var stream = target.pipe(inject(sources, {empty: true, starttag: '', endtag: ''})); 701 | 702 | streamShouldContain(stream, ['emptyTags3.html'], done); 703 | }); 704 | }); 705 | 706 | function src(files, opt) { 707 | opt = opt || {}; 708 | var stream = es.readArray(files.map(function (file) { 709 | return fixture(file, opt.read); 710 | })); 711 | return stream; 712 | } 713 | 714 | function streamShouldContain(stream, files, done) { 715 | var received = 0; 716 | 717 | stream.on('error', function (error) { 718 | should.exist(error); 719 | done(error); 720 | }); 721 | 722 | var contents = files.map(function (file) { 723 | return String(expectedFile(file).contents); 724 | }); 725 | 726 | stream.on('data', function (newFile) { 727 | should.exist(newFile); 728 | should.exist(newFile.contents); 729 | 730 | if (contents.length === 1) { 731 | String(newFile.contents).should.equal(contents[0]); 732 | } else { 733 | contents.should.containEql(String(newFile.contents)); 734 | } 735 | 736 | if (++received === files.length) { 737 | done(); 738 | } 739 | }); 740 | } 741 | 742 | function expectedFile(file) { 743 | var filepath = path.resolve(__dirname, 'expected', file); 744 | return new Vinyl({ 745 | path: filepath, 746 | cwd: __dirname, 747 | base: path.resolve(__dirname, 'expected', path.dirname(file)), 748 | contents: fs.readFileSync(filepath) 749 | }); 750 | } 751 | 752 | function fixture(file, read) { 753 | var filepath = path.resolve(__dirname, 'fixtures', file); 754 | return new Vinyl({ 755 | path: filepath, 756 | cwd: __dirname, 757 | base: path.resolve(__dirname, 'fixtures', path.dirname(file)), 758 | contents: read ? fs.readFileSync(filepath) : null 759 | }); 760 | } 761 | -------------------------------------------------------------------------------- /src/path/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var arrify = require('arrify'); 4 | 5 | module.exports = exports = function getFilepath(sourceFile, targetFile, opt) { 6 | opt = opt || {}; 7 | var ignorePath = arrify(opt.ignorePath); 8 | var base = opt.relative ? path.dirname(addRootSlash(unixify(targetFile.path))) : addRootSlash(unixify(sourceFile.cwd)); 9 | 10 | var filepath = unixify(path.relative(base, addRootSlash(unixify(sourceFile.path)))); 11 | 12 | if (ignorePath.length) { 13 | filepath = removeBasePath(ignorePath, filepath); 14 | } 15 | 16 | if (opt.addPrefix) { 17 | filepath = addPrefix(filepath, opt.addPrefix); 18 | } 19 | 20 | if (opt.addRootSlash) { 21 | filepath = addRootSlash(filepath); 22 | } else if (!opt.addPrefix) { 23 | filepath = removeRootSlash(filepath); 24 | } 25 | 26 | if (opt.addSuffix) { 27 | filepath = addSuffix(filepath, opt.addSuffix); 28 | } 29 | 30 | return filepath; 31 | }; 32 | 33 | function unixify(filepath) { 34 | return filepath.replace(/\\/g, '/'); 35 | } 36 | function addRootSlash(filepath) { 37 | return filepath.replace(/^\/*([^\/])/, '/$1'); 38 | } 39 | function removeRootSlash(filepath) { 40 | return filepath.replace(/^\/+/, ''); 41 | } 42 | function addPrefix(filepath, prefix) { 43 | return prefix + addRootSlash(filepath); 44 | } 45 | function addSuffix(filepath, suffix) { 46 | return filepath + suffix; 47 | } 48 | 49 | function removeBasePath(basedirs, filepath) { 50 | return basedirs.map(unixify).reduce(function (path, remove) { 51 | if (path[0] === '/' && remove[0] !== '/') { 52 | remove = '/' + remove; 53 | } 54 | if (path[0] !== '/' && remove[0] === '/') { 55 | path = '/' + path; 56 | } 57 | if (remove && path.indexOf(remove) === 0) { 58 | return path.slice(remove.length); 59 | } 60 | return path; 61 | }, filepath); 62 | } 63 | -------------------------------------------------------------------------------- /src/path/path_test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 'use strict'; 3 | var path = require('path'); 4 | var Vinyl = require('vinyl'); 5 | var getFilepath = require('./'); 6 | 7 | describe('getFilepath', function () { 8 | describe('(relative=false)', function () { 9 | it('returns the path relative to the source file\'s cwd', function () { 10 | var source = new Vinyl({ 11 | cwd: __dirname, 12 | path: path.join(__dirname, 'dir', 'file.js'), 13 | base: path.join(__dirname, 'dir') 14 | }); 15 | 16 | var filepath = getFilepath(source); 17 | filepath.should.equal('dir/file.js'); 18 | }); 19 | 20 | it('returns the unixified path relative to the source file\'s cwd', function () { 21 | var source = new Vinyl({ 22 | cwd: 'C:\\a\\folder', 23 | path: 'C:\\a\\folder\\dir\\file.js', 24 | base: 'C:\\a\\folder\\dir' 25 | }); 26 | 27 | var filepath = getFilepath(source); 28 | filepath.should.equal('dir/file.js'); 29 | }); 30 | }); 31 | 32 | describe('(relative=true)', function () { 33 | it('returns the path relative to the target file\'s directory', function () { 34 | var target = new Vinyl({ 35 | cwd: __dirname, 36 | path: path.join(__dirname, 'dir1', 'index.html'), 37 | base: path.join(__dirname, 'dir1') 38 | }); 39 | var source = new Vinyl({ 40 | cwd: __dirname, 41 | path: path.join(__dirname, 'dir2', 'file.js'), 42 | base: path.join(__dirname, 'dir2') 43 | }); 44 | 45 | var filepath = getFilepath(source, target, {relative: true}); 46 | filepath.should.equal('../dir2/file.js'); 47 | }); 48 | 49 | it('returns the unixified path relative to the source file\'s cwd', function () { 50 | var target = new Vinyl({ 51 | cwd: 'C:\\a\\folder', 52 | path: 'C:\\a\\folder\\dir1\\index.html', 53 | base: 'C:\\a\\folder\\dir1' 54 | }); 55 | var source = new Vinyl({ 56 | cwd: 'C:\\a\\folder', 57 | path: 'C:\\a\\folder\\dir2\\file.js', 58 | base: 'C:\\a\\folder\\dir2' 59 | }); 60 | 61 | var filepath = getFilepath(source, target, {relative: true}); 62 | filepath.should.equal('../dir2/file.js'); 63 | }); 64 | }); 65 | 66 | describe('(ignorePath)', function () { 67 | it('removes the provided `ignorePath` from the beginning of the path', function () { 68 | var source = new Vinyl({ 69 | cwd: __dirname, 70 | path: path.join(__dirname, 'dir', 'file.js'), 71 | base: path.join(__dirname, 'dir') 72 | }); 73 | 74 | var filepath = getFilepath(source, null, {ignorePath: 'dir'}); 75 | filepath.should.equal('file.js'); 76 | }); 77 | 78 | it('removes the provided `ignorePath` even if it both begins and ends in a `/` from the beginning of the path', function () { 79 | var source = new Vinyl({ 80 | cwd: __dirname, 81 | path: path.join(__dirname, 'dir', 'file.js'), 82 | base: path.join(__dirname, 'dir') 83 | }); 84 | 85 | var filepath = getFilepath(source, null, {ignorePath: '/dir/'}); 86 | filepath.should.equal('file.js'); 87 | }); 88 | 89 | it('removes the provided `ignorePath`s from the beginning of the path', function () { 90 | var source = new Vinyl({ 91 | cwd: __dirname, 92 | path: path.join(__dirname, 'dir', 'file.js'), 93 | base: path.join(__dirname, 'dir') 94 | }); 95 | 96 | var filepath = getFilepath(source, null, {ignorePath: ['dir', 'dir2']}); 97 | filepath.should.equal('file.js'); 98 | }); 99 | 100 | it('removes the provided `ignorePath` unixified from the beginning of the path', function () { 101 | var source = new Vinyl({ 102 | cwd: __dirname, 103 | path: path.join(__dirname, 'dir', 'deep', 'file.js'), 104 | base: path.join(__dirname, 'dir', 'deep') 105 | }); 106 | 107 | var filepath = getFilepath(source, null, {ignorePath: ['\\dir\\deep']}); 108 | filepath.should.equal('file.js'); 109 | }); 110 | 111 | it('removes the provided `ignorePath` unixified from the beginning of a unixified path', function () { 112 | var source = new Vinyl({ 113 | cwd: 'C:\\a\\folder', 114 | path: 'C:\\a\\folder\\dir\\deep\\file.js', 115 | base: 'C:\\a\\folder\\dir\\deep' 116 | }); 117 | 118 | var filepath = getFilepath(source, null, {ignorePath: ['\\dir\\deep']}); 119 | filepath.should.equal('file.js'); 120 | }); 121 | 122 | it('removes the provided `ignorePath` from the beginning of a unixified path', function () { 123 | var source = new Vinyl({ 124 | cwd: 'C:\\a\\folder', 125 | path: 'C:\\a\\folder\\dir\\deep\\file.js', 126 | base: 'C:\\a\\folder\\dir\\deep' 127 | }); 128 | 129 | var filepath = getFilepath(source, null, {ignorePath: ['dir/deep']}); 130 | filepath.should.equal('file.js'); 131 | }); 132 | }); 133 | 134 | describe('(addRootSlash=true)', function () { 135 | it('prepends the path with a `/`', function () { 136 | var source = new Vinyl({ 137 | cwd: __dirname, 138 | path: path.join(__dirname, 'dir', 'file.js'), 139 | base: path.join(__dirname, 'dir') 140 | }); 141 | 142 | var filepath = getFilepath(source, null, {addRootSlash: true}); 143 | filepath.should.equal('/dir/file.js'); 144 | }); 145 | }); 146 | 147 | describe('(addPrefix)', function () { 148 | it('prepends the prefix and a `/` to the path', function () { 149 | var source = new Vinyl({ 150 | cwd: __dirname, 151 | path: path.join(__dirname, 'dir', 'file.js'), 152 | base: path.join(__dirname, 'dir') 153 | }); 154 | 155 | var filepath = getFilepath(source, null, {addPrefix: 'hello'}); 156 | filepath.should.equal('hello/dir/file.js'); 157 | }); 158 | 159 | it('keeps any leading `/` from the prefix', function () { 160 | var source = new Vinyl({ 161 | cwd: __dirname, 162 | path: path.join(__dirname, 'dir', 'file.js'), 163 | base: path.join(__dirname, 'dir') 164 | }); 165 | 166 | var filepath = getFilepath(source, null, {addPrefix: '/hello'}); 167 | filepath.should.equal('/hello/dir/file.js'); 168 | }); 169 | }); 170 | 171 | describe('(addSuffix)', function () { 172 | it('appends the suffix to the path', function () { 173 | var source = new Vinyl({ 174 | cwd: __dirname, 175 | path: path.join(__dirname, 'dir', 'file.js'), 176 | base: path.join(__dirname, 'dir') 177 | }); 178 | 179 | var filepath = getFilepath(source, null, {addSuffix: '?hello'}); 180 | filepath.should.equal('dir/file.js?hello'); 181 | }); 182 | }); 183 | }); 184 | -------------------------------------------------------------------------------- /src/tags/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Constants 3 | */ 4 | var DEFAULT_TARGET = 'html'; 5 | var DEFAULTS = { 6 | STARTS: { 7 | html: '', 8 | jsx: '{/* {{name}}:{{ext}} */}', 9 | jade: '//- {{name}}:{{ext}}', 10 | pug: '//- {{name}}:{{ext}}', 11 | slm: '/ {{name}}:{{ext}}', 12 | slim: '/ {{name}}:{{ext}}', 13 | haml: '-# {{name}}:{{ext}}', 14 | less: '/* {{name}}:{{ext}} */', 15 | sass: '/* {{name}}:{{ext}} */', 16 | scss: '/* {{name}}:{{ext}} */' 17 | }, 18 | ENDS: { 19 | html: '', 20 | jsx: '{/* endinject */}', 21 | jade: '//- endinject', 22 | pug: '//- endinject', 23 | slm: '/ endinject', 24 | slim: '/ endinject', 25 | haml: '-# endinject', 26 | less: '/* endinject */', 27 | sass: '/* endinject */', 28 | scss: '/* endinject */' 29 | } 30 | }; 31 | 32 | module.exports = function tags() { 33 | return { 34 | start: getTag.bind(null, DEFAULTS.STARTS), 35 | end: getTag.bind(null, DEFAULTS.ENDS) 36 | }; 37 | }; 38 | 39 | function getTag(defaults, targetExt, sourceExt, defaultValue) { 40 | var tag = defaultValue; 41 | if (!tag) { 42 | tag = defaults[targetExt] || defaults[DEFAULT_TARGET]; 43 | } else if (typeof tag === 'function') { 44 | tag = tag(targetExt, sourceExt); 45 | } 46 | return tag; 47 | } 48 | -------------------------------------------------------------------------------- /src/tags/tags_test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | /* eslint max-nested-callbacks:[1, 5] */ 3 | 'use strict'; 4 | var should = require('should'); 5 | 6 | describe('tags', function () { 7 | var tags; 8 | var tagsModule; 9 | 10 | it('should not crash when required', function () { 11 | should(function () { 12 | tagsModule = require('./'); 13 | }).not.throw(); 14 | }); 15 | 16 | beforeEach(function () { 17 | if (!tagsModule) { 18 | return; 19 | } 20 | tags = tagsModule(); 21 | }); 22 | 23 | describe('start()', function () { 24 | describe('with no default', function () { 25 | it('should return html comment tag for html target files', function () { 26 | tags.start('html').should.equal(''); 27 | }); 28 | 29 | it('should return jsx comments for jsx target files', function () { 30 | tags.start('jsx').should.equal('{/* {{name}}:{{ext}} */}'); 31 | }); 32 | 33 | it('should return jade comments for jade target files', function () { 34 | tags.start('jade', 'css').should.equal('//- {{name}}:{{ext}}'); 35 | }); 36 | 37 | it('should return pug comments for pug target files', function () { 38 | tags.start('pug', 'css').should.equal('//- {{name}}:{{ext}}'); 39 | }); 40 | 41 | it('should return slm comments for slm target files', function () { 42 | tags.start('slm').should.equal('/ {{name}}:{{ext}}'); 43 | }); 44 | 45 | it('should return haml comment tag for haml files', function () { 46 | tags.start('haml').should.equal('-# {{name}}:{{ext}}'); 47 | }); 48 | 49 | it('should return less comment tag for less files', function () { 50 | tags.start('less').should.equal('/* {{name}}:{{ext}} */'); 51 | }); 52 | 53 | it('should return sass comment tag for sass files', function () { 54 | tags.start('sass').should.equal('/* {{name}}:{{ext}} */'); 55 | }); 56 | 57 | it('should return sass comment tag for sass files', function () { 58 | tags.start('scss').should.equal('/* {{name}}:{{ext}} */'); 59 | }); 60 | 61 | it('should return html comment tag for other target files', function () { 62 | tags.start('txt').should.equal(''); 63 | }); 64 | }); 65 | 66 | describe('given a string as default', function () { 67 | it('should return the string', function () { 68 | tags.start('json', 'css', '"{{ext}}": [').should.equal('"{{ext}}": ['); 69 | }); 70 | }); 71 | 72 | describe('given a function as default', function () { 73 | it('should receive target file and source file extensions as parameters', function () { 74 | tags.start('html', 'css', function (targetExt, sourceExt) { 75 | targetExt.should.equal('html'); 76 | sourceExt.should.equal('css'); 77 | }); 78 | }); 79 | 80 | it('should return result of function untouched', function () { 81 | tags.start('json', 'css', function () { 82 | return '"{{ext}}": ['; 83 | }).should.equal('"{{ext}}": ['); 84 | }); 85 | }); 86 | }); 87 | 88 | describe('end()', function () { 89 | describe('with no default', function () { 90 | it('should return html comment tag for html target files', function () { 91 | tags.end('html').should.equal(''); 92 | }); 93 | 94 | it('should return jsx comments for jsx target files', function () { 95 | tags.end('jsx').should.equal('{/* endinject */}'); 96 | }); 97 | 98 | it('should return jade comments for jade target files', function () { 99 | tags.end('jade').should.equal('//- endinject'); 100 | }); 101 | 102 | it('should return pug comments for pug target files', function () { 103 | tags.end('pug').should.equal('//- endinject'); 104 | }); 105 | 106 | it('should return slm comments for slm target files', function () { 107 | tags.end('slm').should.equal('/ endinject'); 108 | }); 109 | 110 | it('should return haml comments for haml target files', function () { 111 | tags.end('haml').should.equal('-# endinject'); 112 | }); 113 | 114 | it('should return haml comments for haml target files', function () { 115 | tags.end('less').should.equal('/* endinject */'); 116 | }); 117 | 118 | it('should return sass comments for sass target files', function () { 119 | tags.end('sass').should.equal('/* endinject */'); 120 | }); 121 | 122 | it('should return scss comments for scss target files', function () { 123 | tags.end('scss').should.equal('/* endinject */'); 124 | }); 125 | 126 | it('should return html comment tag for other target files', function () { 127 | tags.end('txt').should.equal(''); 128 | }); 129 | }); 130 | 131 | describe('given a string as default', function () { 132 | it('should return the string', function () { 133 | tags.end('json', 'css', '] // {{ext}}').should.equal('] // {{ext}}'); 134 | }); 135 | }); 136 | 137 | describe('given a function as default', function () { 138 | it('should receive target file and source file extensions as parameters', function () { 139 | tags.end('html', 'css', function (targetExt, sourceExt) { 140 | targetExt.should.equal('html'); 141 | sourceExt.should.equal('css'); 142 | }); 143 | }); 144 | 145 | it('should return result of function untouched', function () { 146 | tags.end('json', 'css', function () { 147 | return '] // {{ext}}'; 148 | }).should.equal('] // {{ext}}'); 149 | }); 150 | }); 151 | }); 152 | }); 153 | -------------------------------------------------------------------------------- /src/transform/index.js: -------------------------------------------------------------------------------- 1 | /* eslint max-params:[1, 5] */ 2 | 'use strict'; 3 | var extname = require('../extname'); 4 | 5 | /** 6 | * Constants 7 | */ 8 | var TARGET_TYPES = ['html', 'jade', 'pug', 'slm', 'slim', 'jsx', 'haml', 'less', 'sass', 'scss', 'twig']; 9 | var IMAGES = ['jpeg', 'jpg', 'png', 'gif']; 10 | var DEFAULT_TARGET = TARGET_TYPES[0]; 11 | 12 | /** 13 | * Transform module 14 | */ 15 | var transform = module.exports = exports = function (filepath, i, length, sourceFile, targetFile) { 16 | var type; 17 | if (targetFile && targetFile.path) { 18 | var ext = extname(targetFile.path); 19 | type = typeFromExt(ext); 20 | } 21 | if (!isTargetType(type)) { 22 | type = DEFAULT_TARGET; 23 | } 24 | var func = transform[type]; 25 | if (func) { 26 | return func.apply(transform, arguments); 27 | } 28 | }; 29 | 30 | /** 31 | * Options 32 | */ 33 | 34 | transform.selfClosingTag = false; 35 | 36 | /** 37 | * Transform functions 38 | */ 39 | TARGET_TYPES.forEach(function (targetType) { 40 | transform[targetType] = function (filepath) { 41 | var ext = extname(filepath); 42 | var type = typeFromExt(ext); 43 | var func = transform[targetType][type]; 44 | if (func) { 45 | return func.apply(transform[targetType], arguments); 46 | } 47 | }; 48 | }); 49 | 50 | transform.html.css = function (filepath) { 51 | return ''; 56 | }; 57 | transform.html.map = transform.html.js; 58 | 59 | transform.html.jsx = function (filepath) { 60 | return ''; 61 | }; 62 | 63 | transform.html.html = function (filepath) { 64 | return ''; 69 | }; 70 | 71 | transform.html.image = function (filepath) { 72 | return ''; 204 | }; 205 | 206 | /** 207 | * Transformations for jsx is like html 208 | * but always with self closing tags, invalid jsx otherwise 209 | */ 210 | Object.keys(transform.html).forEach(function (type) { 211 | transform.jsx[type] = function () { 212 | var originalOption = transform.selfClosingTag; 213 | transform.selfClosingTag = true; 214 | var result = transform.html[type].apply(transform.html, arguments); 215 | transform.selfClosingTag = originalOption; 216 | return result; 217 | }; 218 | }); 219 | 220 | function end() { 221 | return transform.selfClosingTag ? ' />' : '>'; 222 | } 223 | 224 | function typeFromExt(ext) { 225 | ext = ext.toLowerCase(); 226 | if (isImage(ext)) { 227 | return 'image'; 228 | } 229 | return ext; 230 | } 231 | 232 | function isImage(ext) { 233 | return IMAGES.includes(ext); 234 | } 235 | 236 | function isTargetType(type) { 237 | if (!type) { 238 | return false; 239 | } 240 | return TARGET_TYPES.includes(type); 241 | } 242 | -------------------------------------------------------------------------------- /src/transform/transform_test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 'use strict'; 3 | var path = require('path'); 4 | var fs = require('fs'); 5 | var should = require('should'); 6 | var Vinyl = require('vinyl'); 7 | 8 | describe('transform', function () { 9 | var transform; 10 | 11 | it('should not crash when required', function () { 12 | should(function () { 13 | transform = require('./'); 14 | }).not.throw(); 15 | }); 16 | 17 | it('should be a function', function () { 18 | transform.should.be.type('function'); 19 | }); 20 | 21 | describe('targets', function () { 22 | it('should have a transform function for html target files', function () { 23 | transform.html.should.be.type('function'); 24 | }); 25 | 26 | it('should have a transform function for react javascript (jsx) target files', function () { 27 | transform.jsx.should.be.type('function'); 28 | }); 29 | 30 | it('should have a transform function for jade target files', function () { 31 | transform.jade.should.be.type('function'); 32 | }); 33 | 34 | it('should have a transform function for pug target files', function () { 35 | transform.pug.should.be.type('function'); 36 | }); 37 | 38 | it('should have a transform function for slm target files', function () { 39 | transform.slm.should.be.type('function'); 40 | }); 41 | 42 | it('should have a transform function for haml target files', function () { 43 | transform.haml.should.be.type('function'); 44 | }); 45 | 46 | it('should have a transform function for less target files', function () { 47 | transform.less.should.be.type('function'); 48 | }); 49 | 50 | it('should have a transform function for sass target files', function () { 51 | transform.sass.should.be.type('function'); 52 | }); 53 | 54 | it('should have a transform function for scss target files', function () { 55 | transform.scss.should.be.type('function'); 56 | }); 57 | }); 58 | 59 | describe('html as target', function () { 60 | it('should transform css to a link tag', function () { 61 | transform.html.css.should.be.type('function'); 62 | transform.html.css('test-file.css').should.equal(''); 63 | }); 64 | 65 | it('should transform html to a link tag', function () { 66 | transform.html.html.should.be.type('function'); 67 | transform.html.html('test-file.html').should.equal(''); 68 | }); 69 | 70 | it('should transform javascript to a script tag', function () { 71 | transform.html.js.should.be.type('function'); 72 | transform.html.js('test-file.js').should.equal(''); 73 | }); 74 | 75 | it('should transform jsx to a script tag', function () { 76 | transform.html.jsx.should.be.type('function'); 77 | transform.html.jsx('test-file.jsx').should.equal(''); 78 | }); 79 | 80 | it('should transform coffeescript to a script tag', function () { 81 | transform.html.coffee.should.be.type('function'); 82 | transform.html.coffee('test-file.coffee').should.equal(''); 83 | }); 84 | 85 | it('should transform an image to an img tag', function () { 86 | transform.html.image.should.be.type('function'); 87 | transform.html.image('test-file.png').should.equal(''); 88 | }); 89 | 90 | describe('selfClosingTag option is true', function () { 91 | before(function () { 92 | transform.selfClosingTag = true; 93 | }); 94 | after(function () { 95 | transform.selfClosingTag = false; 96 | }); 97 | 98 | it('should make link tags self closing', function () { 99 | transform.html.css('test-file.css').should.equal(''); 100 | transform.html.html('test-file.html').should.equal(''); 101 | }); 102 | 103 | it('should make img tags self closing', function () { 104 | transform.html.image('test-file.png').should.equal(''); 105 | }); 106 | }); 107 | 108 | it('should use the css transformer for css files automatically', function () { 109 | transform.html('test-file.css').should.equal(transform.html.css('test-file.css')); 110 | }); 111 | 112 | it('should use the html transformer for html files automatically', function () { 113 | transform.html('test-file.html').should.equal(transform.html.html('test-file.html')); 114 | }); 115 | 116 | it('should use the js transformer for js files automatically', function () { 117 | transform.html('test-file.js').should.equal(transform.html.js('test-file.js')); 118 | }); 119 | 120 | it('should use the coffee transformer for coffee files automatically', function () { 121 | transform.html('test-file.coffee').should.equal(transform.html.coffee('test-file.coffee')); 122 | }); 123 | 124 | it('should use the image transformer for png, gif, jpg and jpeg files automatically', function () { 125 | transform.html('test-file.png').should.equal(transform.html.image('test-file.png')); 126 | transform.html('test-file.gif').should.equal(transform.html.image('test-file.gif')); 127 | transform.html('test-file.jpg').should.equal(transform.html.image('test-file.jpg')); 128 | transform.html('test-file.jpeg').should.equal(transform.html.image('test-file.jpeg')); 129 | }); 130 | }); 131 | 132 | describe('jsx as target', function () { 133 | it('should transform css to a self closing link tag', function () { 134 | transform.jsx.css.should.be.type('function'); 135 | transform.jsx.css('test-file.css').should.equal(''); 136 | }); 137 | 138 | it('should transform html to a self closing link tag', function () { 139 | transform.jsx.html.should.be.type('function'); 140 | transform.jsx.html('test-file.html').should.equal(''); 141 | }); 142 | 143 | it('should transform javascript to a script tag', function () { 144 | transform.jsx.js.should.be.type('function'); 145 | transform.jsx.js('test-file.js').should.equal(''); 146 | }); 147 | 148 | it('should transform coffeescript to a script tag', function () { 149 | transform.jsx.coffee.should.be.type('function'); 150 | transform.jsx.coffee('test-file.coffee').should.equal(''); 151 | }); 152 | 153 | it('should transform an image to a self closing img tag', function () { 154 | transform.jsx.image.should.be.type('function'); 155 | transform.jsx.image('test-file.png').should.equal(''); 156 | }); 157 | 158 | it('should use the css transformer for css files automatically', function () { 159 | transform.jsx('test-file.css').should.equal(transform.jsx.css('test-file.css')); 160 | }); 161 | 162 | it('should use the html transformer for html files automatically', function () { 163 | transform.jsx('test-file.html').should.equal(transform.jsx.html('test-file.html')); 164 | }); 165 | 166 | it('should use the js transformer for js files automatically', function () { 167 | transform.jsx('test-file.js').should.equal(transform.jsx.js('test-file.js')); 168 | }); 169 | 170 | it('should use the coffee transformer for coffee files automatically', function () { 171 | transform.jsx('test-file.coffee').should.equal(transform.jsx.coffee('test-file.coffee')); 172 | }); 173 | 174 | it('should use the image transformer for png, gif, jpg and jpeg files automatically', function () { 175 | transform.jsx('test-file.png').should.equal(transform.jsx.image('test-file.png')); 176 | transform.jsx('test-file.gif').should.equal(transform.jsx.image('test-file.gif')); 177 | transform.jsx('test-file.jpg').should.equal(transform.jsx.image('test-file.jpg')); 178 | transform.jsx('test-file.jpeg').should.equal(transform.jsx.image('test-file.jpeg')); 179 | }); 180 | }); 181 | 182 | describe('jade as target', function () { 183 | it('should transform css to a jade link tag', function () { 184 | transform.jade.css.should.be.type('function'); 185 | transform.jade.css('test-file.css').should.equal('link(rel="stylesheet", href="test-file.css")'); 186 | }); 187 | 188 | it('should transform jade to a jade include tag', function () { 189 | transform.jade.html.should.be.type('function'); 190 | transform.jade.jade('test-file.jade').should.equal('include test-file.jade'); 191 | }); 192 | 193 | it('should transform html to a self closing link tag', function () { 194 | transform.jade.html.should.be.type('function'); 195 | transform.jade.html('test-file.html').should.equal('link(rel="import", href="test-file.html")'); 196 | }); 197 | 198 | it('should transform javascript to a script tag', function () { 199 | transform.jade.js.should.be.type('function'); 200 | transform.jade.js('test-file.js').should.equal('script(src="test-file.js")'); 201 | }); 202 | 203 | it('should transform coffeescript to a script tag', function () { 204 | transform.jade.coffee.should.be.type('function'); 205 | transform.jade.coffee('test-file.coffee').should.equal('script(type="text/coffeescript", src="test-file.coffee")'); 206 | }); 207 | 208 | it('should transform an image to a self closing img tag', function () { 209 | transform.jade.image.should.be.type('function'); 210 | transform.jade.image('test-file.png').should.equal('img(src="test-file.png")'); 211 | }); 212 | 213 | it('should use the css transformer for css files automatically', function () { 214 | transform.jade('test-file.css').should.equal(transform.jade.css('test-file.css')); 215 | }); 216 | 217 | it('should use the jade transformer for jade files automatically', function () { 218 | transform.jade('test-file.jade').should.equal(transform.jade.jade('test-file.jade')); 219 | }); 220 | 221 | it('should use the html transformer for html files automatically', function () { 222 | transform.jade('test-file.html').should.equal(transform.jade.html('test-file.html')); 223 | }); 224 | 225 | it('should use the js transformer for js files automatically', function () { 226 | transform.jade('test-file.js').should.equal(transform.jade.js('test-file.js')); 227 | }); 228 | 229 | it('should use the coffee transformer for coffee files automatically', function () { 230 | transform.jade('test-file.coffee').should.equal(transform.jade.coffee('test-file.coffee')); 231 | }); 232 | 233 | it('should use the image transformer for png, gif, jpg and jpeg files automatically', function () { 234 | transform.jade('test-file.png').should.equal(transform.jade.image('test-file.png')); 235 | transform.jade('test-file.gif').should.equal(transform.jade.image('test-file.gif')); 236 | transform.jade('test-file.jpg').should.equal(transform.jade.image('test-file.jpg')); 237 | transform.jade('test-file.jpeg').should.equal(transform.jade.image('test-file.jpeg')); 238 | }); 239 | }); 240 | 241 | describe('pug as target', function () { 242 | it('should transform css to a pug link tag', function () { 243 | transform.pug.css.should.be.type('function'); 244 | transform.pug.css('test-file.css').should.equal('link(rel="stylesheet", href="test-file.css")'); 245 | }); 246 | 247 | it('should transform pug to a pug include tag', function () { 248 | transform.pug.html.should.be.type('function'); 249 | transform.pug.pug('test-file.pug').should.equal('include test-file.pug'); 250 | }); 251 | 252 | it('should transform html to a self closing link tag', function () { 253 | transform.pug.html.should.be.type('function'); 254 | transform.pug.html('test-file.html').should.equal('link(rel="import", href="test-file.html")'); 255 | }); 256 | 257 | it('should transform javascript to a script tag', function () { 258 | transform.pug.js.should.be.type('function'); 259 | transform.pug.js('test-file.js').should.equal('script(src="test-file.js")'); 260 | }); 261 | 262 | it('should transform coffeescript to a script tag', function () { 263 | transform.pug.coffee.should.be.type('function'); 264 | transform.pug.coffee('test-file.coffee').should.equal('script(type="text/coffeescript", src="test-file.coffee")'); 265 | }); 266 | 267 | it('should transform an image to a self closing img tag', function () { 268 | transform.pug.image.should.be.type('function'); 269 | transform.pug.image('test-file.png').should.equal('img(src="test-file.png")'); 270 | }); 271 | 272 | it('should use the css transformer for css files automatically', function () { 273 | transform.pug('test-file.css').should.equal(transform.pug.css('test-file.css')); 274 | }); 275 | 276 | it('should use the pug transformer for pug files automatically', function () { 277 | transform.pug('test-file.pug').should.equal(transform.pug.pug('test-file.pug')); 278 | }); 279 | 280 | it('should use the html transformer for html files automatically', function () { 281 | transform.pug('test-file.html').should.equal(transform.pug.html('test-file.html')); 282 | }); 283 | 284 | it('should use the js transformer for js files automatically', function () { 285 | transform.pug('test-file.js').should.equal(transform.pug.js('test-file.js')); 286 | }); 287 | 288 | it('should use the coffee transformer for coffee files automatically', function () { 289 | transform.pug('test-file.coffee').should.equal(transform.pug.coffee('test-file.coffee')); 290 | }); 291 | 292 | it('should use the image transformer for png, gif, jpg and jpeg files automatically', function () { 293 | transform.pug('test-file.png').should.equal(transform.pug.image('test-file.png')); 294 | transform.pug('test-file.gif').should.equal(transform.pug.image('test-file.gif')); 295 | transform.pug('test-file.jpg').should.equal(transform.pug.image('test-file.jpg')); 296 | transform.pug('test-file.jpeg').should.equal(transform.pug.image('test-file.jpeg')); 297 | }); 298 | }); 299 | 300 | describe('slm as target', function () { 301 | it('should transform css to a slm link tag', function () { 302 | transform.slm.css.should.be.type('function'); 303 | transform.slm.css('test-file.css').should.equal('link rel="stylesheet" href="test-file.css"'); 304 | }); 305 | 306 | it('should transform html to a self closing link tag', function () { 307 | transform.slm.html.should.be.type('function'); 308 | transform.slm.html('test-file.html').should.equal('link rel="import" href="test-file.html"'); 309 | }); 310 | 311 | it('should transform javascript to a script tag', function () { 312 | transform.slm.js.should.be.type('function'); 313 | transform.slm.js('test-file.js').should.equal('script src="test-file.js"'); 314 | }); 315 | 316 | it('should transform coffeescript to a script tag', function () { 317 | transform.slm.coffee.should.be.type('function'); 318 | transform.slm.coffee('test-file.coffee').should.equal('script type="text/coffeescript" src="test-file.coffee"'); 319 | }); 320 | 321 | it('should transform an image to a self closing img tag', function () { 322 | transform.slm.image.should.be.type('function'); 323 | transform.slm.image('test-file.png').should.equal('img src="test-file.png"'); 324 | }); 325 | 326 | it('should use the css transformer for css files automatically', function () { 327 | transform.slm('test-file.css').should.equal(transform.slm.css('test-file.css')); 328 | }); 329 | 330 | it('should use the html transformer for html files automatically', function () { 331 | transform.slm('test-file.html').should.equal(transform.slm.html('test-file.html')); 332 | }); 333 | 334 | it('should use the js transformer for js files automatically', function () { 335 | transform.slm('test-file.js').should.equal(transform.slm.js('test-file.js')); 336 | }); 337 | 338 | it('should use the coffee transformer for coffee files automatically', function () { 339 | transform.slm('test-file.coffee').should.equal(transform.slm.coffee('test-file.coffee')); 340 | }); 341 | 342 | it('should use the image transformer for png, gif, jpg and jpeg files automatically', function () { 343 | transform.slm('test-file.png').should.equal(transform.slm.image('test-file.png')); 344 | transform.slm('test-file.gif').should.equal(transform.slm.image('test-file.gif')); 345 | transform.slm('test-file.jpg').should.equal(transform.slm.image('test-file.jpg')); 346 | transform.slm('test-file.jpeg').should.equal(transform.slm.image('test-file.jpeg')); 347 | }); 348 | }); 349 | 350 | describe('haml as target', function () { 351 | it('should transform css to a haml link tag', function () { 352 | transform.haml.css.should.be.type('function'); 353 | transform.haml.css('test-file.css').should.equal('%link{rel:"stylesheet", href:"test-file.css"}'); 354 | }); 355 | 356 | it('should transform html to a self closing link tag', function () { 357 | transform.haml.html.should.be.type('function'); 358 | transform.haml.html('test-file.html').should.equal('%link{rel:"import", href:"test-file.html"}'); 359 | }); 360 | 361 | it('should transform javascript to a script tag', function () { 362 | transform.haml.js.should.be.type('function'); 363 | transform.haml.js('test-file.js').should.equal('%script{src:"test-file.js"}'); 364 | }); 365 | 366 | it('should transform coffeescript to a script tag', function () { 367 | transform.haml.coffee.should.be.type('function'); 368 | transform.haml.coffee('test-file.coffee').should.equal('%script{type:"text/coffeescript", src:"test-file.coffee"}'); 369 | }); 370 | 371 | it('should transform an image to a self closing img tag', function () { 372 | transform.haml.image.should.be.type('function'); 373 | transform.haml.image('test-file.png').should.equal('%img{src:"test-file.png"}'); 374 | }); 375 | 376 | it('should use the css transformer for css files automatically', function () { 377 | transform.haml('test-file.css').should.equal(transform.haml.css('test-file.css')); 378 | }); 379 | 380 | it('should use the html transformer for html files automatically', function () { 381 | transform.haml('test-file.html').should.equal(transform.haml.html('test-file.html')); 382 | }); 383 | 384 | it('should use the js transformer for js files automatically', function () { 385 | transform.haml('test-file.js').should.equal(transform.haml.js('test-file.js')); 386 | }); 387 | 388 | it('should use the coffee transformer for coffee files automatically', function () { 389 | transform.haml('test-file.coffee').should.equal(transform.haml.coffee('test-file.coffee')); 390 | }); 391 | 392 | it('should use the image transformer for png, gif, jpg and jpeg files automatically', function () { 393 | transform.haml('test-file.png').should.equal(transform.haml.image('test-file.png')); 394 | transform.haml('test-file.gif').should.equal(transform.haml.image('test-file.gif')); 395 | transform.haml('test-file.jpg').should.equal(transform.haml.image('test-file.jpg')); 396 | transform.haml('test-file.jpeg').should.equal(transform.haml.image('test-file.jpeg')); 397 | }); 398 | }); 399 | 400 | describe('less as target', function () { 401 | it('should transform less to a import tag', function () { 402 | transform.less.css.should.be.type('function'); 403 | transform.less.css('test-file.css').should.equal('@import "test-file.css";'); 404 | }); 405 | 406 | it('should transform css to a import tag', function () { 407 | transform.less.less.should.be.type('function'); 408 | transform.less.less('test-file.less').should.equal('@import "test-file.less";'); 409 | }); 410 | 411 | it('should use the less transformer for less files automatically', function () { 412 | transform.less('test-file.less').should.equal(transform.less.less('test-file.less')); 413 | }); 414 | 415 | it('should use the css transformer for css files automatically', function () { 416 | transform.less('test-file.css').should.equal(transform.less.css('test-file.css')); 417 | }); 418 | }); 419 | 420 | describe('sass as target', function () { 421 | it('should transform sass to a import tag', function () { 422 | transform.sass.sass.should.be.type('function'); 423 | transform.sass.sass('test-file.sass').should.equal('@import "test-file.sass"'); 424 | }); 425 | 426 | it('should transform scss to a import tag', function () { 427 | transform.sass.scss.should.be.type('function'); 428 | transform.sass.scss('test-file.scss').should.equal('@import "test-file.scss"'); 429 | }); 430 | 431 | it('should transform css to a import tag', function () { 432 | transform.sass.css.should.be.type('function'); 433 | transform.sass.css('test-file.css').should.equal('@import "test-file.css"'); 434 | }); 435 | 436 | it('should use the sass transformer for sass files automatically', function () { 437 | transform.sass('test-file.sass').should.equal(transform.sass.sass('test-file.sass')); 438 | }); 439 | 440 | it('should use the sass transformer for scss files automatically', function () { 441 | transform.sass('test-file.scss').should.equal(transform.sass.scss('test-file.scss')); 442 | }); 443 | 444 | it('should use the sass transformer for css files automatically', function () { 445 | transform.sass('test-file.css').should.equal(transform.sass.css('test-file.css')); 446 | }); 447 | }); 448 | 449 | describe('scss as target', function () { 450 | it('should transform sass to a import tag', function () { 451 | transform.scss.sass.should.be.type('function'); 452 | transform.scss.sass('test-file.sass').should.equal('@import "test-file.sass";'); 453 | }); 454 | 455 | it('should transform scss to a import tag', function () { 456 | transform.scss.scss.should.be.type('function'); 457 | transform.scss.scss('test-file.scss').should.equal('@import "test-file.scss";'); 458 | }); 459 | 460 | it('should transform css to a import tag', function () { 461 | transform.scss.css.should.be.type('function'); 462 | transform.scss.css('test-file.css').should.equal('@import "test-file.css";'); 463 | }); 464 | 465 | it('should use the scss transformer for sass files automatically', function () { 466 | transform.scss('test-file.sass').should.equal(transform.scss.sass('test-file.sass')); 467 | }); 468 | 469 | it('should use the scss transformer for scss files automatically', function () { 470 | transform.scss('test-file.scss').should.equal(transform.scss.scss('test-file.scss')); 471 | }); 472 | 473 | it('should use the scss transformer for css files automatically', function () { 474 | transform.scss('test-file.css').should.equal(transform.scss.css('test-file.css')); 475 | }); 476 | }); 477 | 478 | it('should pick the correct target transformer for html targets', function () { 479 | var targetFile = fixture('index.html'); 480 | var sourceFile = fixture('style.css'); 481 | transform(sourceFile.path, null, null, sourceFile, targetFile) 482 | .should.equal(transform.html.css(sourceFile.path)); 483 | }); 484 | 485 | it('should pick the correct target transformer for jsx targets', function () { 486 | var targetFile = fixture('app.jsx'); 487 | var sourceFile = fixture('app.js'); 488 | transform(sourceFile.path, null, null, sourceFile, targetFile) 489 | .should.equal(transform.jsx.js(sourceFile.path)); 490 | }); 491 | 492 | it('should pick the correct target transformer for jade targets', function () { 493 | var targetFile = fixture('index.jade'); 494 | var sourceFile = fixture('image.gif'); 495 | transform(sourceFile.path, null, null, sourceFile, targetFile) 496 | .should.equal(transform.jade.image(sourceFile.path)); 497 | }); 498 | 499 | it('should pick the correct target transformer for pug targets', function () { 500 | var targetFile = fixture('index.pug'); 501 | var sourceFile = fixture('image.gif'); 502 | transform(sourceFile.path, null, null, sourceFile, targetFile) 503 | .should.equal(transform.pug.image(sourceFile.path)); 504 | }); 505 | 506 | it('should pick the correct target transformer for slm targets', function () { 507 | var targetFile = fixture('index.slm'); 508 | var sourceFile = fixture('image.gif'); 509 | transform(sourceFile.path, null, null, sourceFile, targetFile) 510 | .should.equal(transform.slm.image(sourceFile.path)); 511 | }); 512 | 513 | it('should pick the correct target transformer for haml targets', function () { 514 | var targetFile = fixture('index.haml'); 515 | var sourceFile = fixture('image.gif'); 516 | transform(sourceFile.path, null, null, sourceFile, targetFile) 517 | .should.equal(transform.haml.image(sourceFile.path)); 518 | }); 519 | 520 | it('should pick the correct target transformer for less targets', function () { 521 | var targetFile = fixture('index.less'); 522 | var sourceFile = fixture('test-file.less'); 523 | transform(sourceFile.path, null, null, sourceFile, targetFile) 524 | .should.equal(transform.less.less(sourceFile.path)); 525 | }); 526 | 527 | it('should pick the correct target transformer for sass targets', function () { 528 | var targetFile = fixture('index.sass'); 529 | var sourceFile = fixture('test-file.sass'); 530 | transform(sourceFile.path, null, null, sourceFile, targetFile) 531 | .should.equal(transform.sass.sass(sourceFile.path)); 532 | }); 533 | 534 | it('should pick the correct target transformer for scss targets', function () { 535 | var targetFile = fixture('index.scss'); 536 | var sourceFile = fixture('test-file.scss'); 537 | transform(sourceFile.path, null, null, sourceFile, targetFile) 538 | .should.equal(transform.scss.scss(sourceFile.path)); 539 | }); 540 | 541 | it('should default to the html target transformer for other files', function () { 542 | var targetFile = fixture('plain.txt'); 543 | var sourceFile = fixture('image.gif'); 544 | transform(sourceFile.path, null, null, sourceFile, targetFile) 545 | .should.equal(transform.html.image(sourceFile.path)); 546 | }); 547 | 548 | it('should default to the html target transformer for unknown files', function () { 549 | var sourceFile = fixture('image.gif'); 550 | transform(sourceFile.path, null, null, sourceFile) 551 | .should.equal(transform.html.image(sourceFile.path)); 552 | }); 553 | }); 554 | 555 | function fixture(file, read) { 556 | var filepath = path.resolve(__dirname, 'fixtures', file); 557 | return new Vinyl({ 558 | path: filepath, 559 | cwd: __dirname, 560 | base: path.resolve(__dirname, 'fixtures', path.dirname(file)), 561 | contents: read ? fs.readFileSync(filepath) : null 562 | }); 563 | } 564 | --------------------------------------------------------------------------------