concat.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. /*
  2. * grunt-contrib-concat
  3. * http://gruntjs.com/
  4. *
  5. * Copyright (c) 2015 "Cowboy" Ben Alman, contributors
  6. * Licensed under the MIT license.
  7. */
  8. 'use strict';
  9. module.exports = function(grunt) {
  10. // Internal lib.
  11. var comment = require('./lib/comment').init(grunt);
  12. var chalk = require('chalk');
  13. var sourcemap = require('./lib/sourcemap').init(grunt);
  14. grunt.registerMultiTask('concat', 'Concatenate files.', function() {
  15. // Merge task-specific and/or target-specific options with these defaults.
  16. var options = this.options({
  17. separator: grunt.util.linefeed,
  18. banner: '',
  19. footer: '',
  20. stripBanners: false,
  21. process: false,
  22. sourceMap: false,
  23. sourceMapName: undefined,
  24. sourceMapStyle: 'embed'
  25. });
  26. // Normalize boolean options that accept options objects.
  27. if (options.stripBanners === true) { options.stripBanners = {}; }
  28. if (options.process === true) { options.process = {}; }
  29. // Process banner and footer.
  30. var banner = grunt.template.process(options.banner);
  31. var footer = grunt.template.process(options.footer);
  32. // Set a local variable for whether to build source maps or not.
  33. var sourceMap = options.sourceMap;
  34. // If content is not embedded and it will be modified, either exit or do
  35. // not make the source map.
  36. if (
  37. sourceMap && options.sourceMapStyle === 'link' &&
  38. (options.stripBanners || options.process)
  39. ) {
  40. // Warn and exit if --force isn't set.
  41. grunt.warn(
  42. 'stripBanners or process option is enabled. ' +
  43. 'Set sourceMapStyle option to \'embed\' or \'inline\'.'
  44. );
  45. // --force is set, continue on without the source map.
  46. grunt.log.warn('Skipping creation of source maps.');
  47. // Set sourceMap to false to keep maps from being constructed.
  48. sourceMap = false;
  49. }
  50. // Iterate over all src-dest file pairs.
  51. this.files.forEach(function(f) {
  52. // Initialize source map objects.
  53. var sourceMapHelper;
  54. if (sourceMap) {
  55. sourceMapHelper = sourcemap.helper(f, options);
  56. sourceMapHelper.add(banner);
  57. }
  58. // Concat banner + specified files + footer.
  59. var src = banner + f.src.filter(function(filepath) {
  60. // Warn on and remove invalid source files (if nonull was set).
  61. if (!grunt.file.exists(filepath)) {
  62. grunt.log.warn('Source file "' + filepath + '" not found.');
  63. return false;
  64. } else {
  65. return true;
  66. }
  67. }).map(function(filepath, i) {
  68. if (grunt.file.isDir(filepath)) {
  69. return;
  70. }
  71. // Read file source.
  72. var src = grunt.file.read(filepath);
  73. // Process files as templates if requested.
  74. if (typeof options.process === 'function') {
  75. src = options.process(src, filepath);
  76. } else if (options.process) {
  77. src = grunt.template.process(src, options.process);
  78. }
  79. // Strip banners if requested.
  80. if (options.stripBanners) {
  81. src = comment.stripBanner(src, options.stripBanners);
  82. }
  83. // Add the lines of this file to our map.
  84. if (sourceMapHelper) {
  85. src = sourceMapHelper.addlines(src, filepath);
  86. if (i < f.src.length - 1) {
  87. sourceMapHelper.add(options.separator);
  88. }
  89. }
  90. return src;
  91. }).join(options.separator) + footer;
  92. if (sourceMapHelper) {
  93. sourceMapHelper.add(footer);
  94. sourceMapHelper.write();
  95. // Add sourceMappingURL to the end.
  96. src += sourceMapHelper.url();
  97. }
  98. // Write the destination file.
  99. grunt.file.write(f.dest, src);
  100. // Print a success message.
  101. grunt.log.writeln('File ' + chalk.cyan(f.dest) + ' created.');
  102. });
  103. });
  104. };