Gruntfile.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*global module:false*/
  2. module.exports = function(grunt) {
  3. var _ = grunt.util._;
  4. // Project configuration
  5. grunt.initConfig({
  6. // Metadata
  7. pkg: grunt.file.readJSON('package.json'),
  8. fragments: './build/fragments/',
  9. banner: '/*!\n' +
  10. ' * Knockout JavaScript library v<%= pkg.version %>\n' +
  11. ' * (c) Steven Sanderson - <%= pkg.homepage %>\n' +
  12. ' * License: <%= pkg.licenses[0].type %> (<%= pkg.licenses[0].url %>)\n' +
  13. ' */\n\n',
  14. checktrailingspaces: {
  15. main: {
  16. src: [
  17. "**/*.{js,html,css,bat,ps1,sh}",
  18. "!build/output/**",
  19. "!node_modules/**"
  20. ],
  21. filter: 'isFile'
  22. }
  23. },
  24. build: {
  25. debug: './build/output/knockout-latest.debug.js',
  26. min: './build/output/knockout-latest.js'
  27. },
  28. dist: {
  29. debug: './dist/knockout.debug.js',
  30. min: './dist/knockout.js'
  31. },
  32. test: {
  33. phantomjs: 'spec/runner.phantom.js',
  34. node: 'spec/runner.node.js'
  35. }
  36. });
  37. grunt.registerTask('clean', 'Clean up output files.', function (target) {
  38. var output = grunt.config('build');
  39. var files = [ output.debug, output.min ];
  40. var options = { force: (target == 'force') };
  41. _.forEach(files, function (file) {
  42. if (grunt.file.exists(file))
  43. grunt.file.delete(file, options);
  44. });
  45. return !this.errorCount;
  46. });
  47. var trailingSpaceRegex = /[ ]$/;
  48. grunt.registerMultiTask('checktrailingspaces', 'checktrailingspaces', function() {
  49. var matches = [];
  50. this.files[0].src.forEach(function(filepath) {
  51. var content = grunt.file.read(filepath),
  52. lines = content.split(/\r*\n/);
  53. lines.forEach(function(line, index) {
  54. if (trailingSpaceRegex.test(line)) {
  55. matches.push([filepath, (index+1), line].join(':'));
  56. }
  57. });
  58. });
  59. if (matches.length) {
  60. grunt.log.error("The following files have trailing spaces that need to be cleaned up:");
  61. grunt.log.writeln(matches.join('\n'));
  62. return false;
  63. }
  64. });
  65. function getReferencedSources(sourceReferencesFilename) {
  66. // Returns the array of filenames referenced by a file like source-references.js
  67. var result;
  68. global.knockoutDebugCallback = function(sources) { result = sources; };
  69. eval(grunt.file.read(sourceReferencesFilename));
  70. return result;
  71. }
  72. function getCombinedSources() {
  73. var fragments = grunt.config('fragments'),
  74. sourceFilenames = [
  75. fragments + 'extern-pre.js',
  76. fragments + 'amd-pre.js',
  77. getReferencedSources(fragments + 'source-references.js'),
  78. fragments + 'amd-post.js',
  79. fragments + 'extern-post.js'
  80. ],
  81. flattenedSourceFilenames = Array.prototype.concat.apply([], sourceFilenames),
  82. combinedSources = flattenedSourceFilenames.map(function(filename) {
  83. return grunt.file.read('./' + filename);
  84. }).join('');
  85. return combinedSources.replace('##VERSION##', grunt.config('pkg.version'));
  86. }
  87. function buildDebug(output) {
  88. var source = [];
  89. source.push(grunt.config('banner'));
  90. source.push('(function(){\n');
  91. source.push('var DEBUG=true;\n');
  92. source.push(getCombinedSources());
  93. source.push('})();\n');
  94. grunt.file.write(output, source.join('').replace(/\r\n/g, '\n'));
  95. }
  96. function buildMin(output, done) {
  97. var cc = require('closure-compiler');
  98. var options = {
  99. compilation_level: 'ADVANCED_OPTIMIZATIONS',
  100. output_wrapper: '(function() {%output%})();'
  101. };
  102. grunt.log.write('Compiling...');
  103. cc.compile('/**@const*/var DEBUG=false;' + getCombinedSources(), options, function (err, stdout, stderr) {
  104. if (err) {
  105. grunt.log.error(err);
  106. done(false);
  107. } else {
  108. grunt.log.ok();
  109. grunt.file.write(output, (grunt.config('banner') + stdout).replace(/\r\n/g, '\n'));
  110. done(true);
  111. }
  112. });
  113. }
  114. grunt.registerMultiTask('build', 'Build', function() {
  115. if (!this.errorCount) {
  116. var output = this.data;
  117. if (this.target === 'debug') {
  118. buildDebug(output);
  119. } else if (this.target === 'min') {
  120. buildMin(output, this.async());
  121. }
  122. }
  123. return !this.errorCount;
  124. });
  125. grunt.registerMultiTask('test', 'Run tests', function () {
  126. var done = this.async();
  127. grunt.util.spawn({ cmd: this.target, args: [this.data] },
  128. function (error, result, code) {
  129. if (code === 127 /*not found*/) {
  130. grunt.verbose.error(result.stderr);
  131. // ignore this error
  132. done(true);
  133. } else {
  134. grunt.log.writeln(result.stdout);
  135. if (error)
  136. grunt.log.error(result.stderr);
  137. done(!error);
  138. }
  139. }
  140. );
  141. });
  142. grunt.registerTask('dist', function() {
  143. // Update the version in bower.json
  144. var bowerConfig = grunt.file.readJSON('bower.json'),
  145. version = grunt.config('pkg.version');
  146. bowerConfig.version = version;
  147. grunt.file.write('bower.json', JSON.stringify(bowerConfig, true, 2));
  148. var buildConfig = grunt.config('build'),
  149. distConfig = grunt.config('dist');
  150. grunt.file.copy(buildConfig.debug, distConfig.debug);
  151. grunt.file.copy(buildConfig.min, distConfig.min);
  152. console.log('To publish, run:');
  153. console.log(' git add bower.json');
  154. console.log(' git add -f ' + distConfig.debug);
  155. console.log(' git add -f ' + distConfig.min);
  156. console.log(' git checkout head');
  157. console.log(' git commit -m \'Version ' + version + ' for distribution\'');
  158. console.log(' git tag -a v' + version + ' -m \'Add tag v' + version + '\'');
  159. console.log(' git checkout master');
  160. console.log(' git push origin --tags');
  161. });
  162. // Default task.
  163. grunt.registerTask('default', ['clean', 'checktrailingspaces', 'build', 'test']);
  164. };