module.exports = function(grunt) { 'use strict'; var bower = grunt.file.readJSON('bower.json'); var components = []; for (var i in bower.concat.app) { components.push('components/' + bower.concat.app[i] + '/**/*.js'); } var libtextsecurecomponents = []; for (i in bower.concat.libtextsecure) { libtextsecurecomponents.push('components/' + bower.concat.libtextsecure[i] + '/**/*.js'); } grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), concat: { components: { src: components, dest: 'js/components.js', }, libtextsecurecomponents: { src: libtextsecurecomponents, dest: 'libtextsecure/components.js', }, test: { src: [ 'components/mocha/mocha.js', 'components/chai/chai.js', 'test/_test.js' ], dest: 'test/test.js', }, //TODO: Move errors back down? libtextsecure: { options: { banner: ";(function() {\n", footer: "})();\n", }, src: [ 'libtextsecure/errors.js', 'libtextsecure/libsignal-protocol.js', 'libtextsecure/protocol_wrapper.js', 'libtextsecure/crypto.js', 'libtextsecure/storage.js', 'libtextsecure/storage/user.js', 'libtextsecure/storage/devices.js', 'libtextsecure/storage/groups.js', 'libtextsecure/protobufs.js', 'libtextsecure/websocket-resources.js', 'libtextsecure/helpers.js', 'libtextsecure/stringview.js', 'libtextsecure/event_target.js', 'libtextsecure/api.js', 'libtextsecure/account_manager.js', 'libtextsecure/message_receiver.js', 'libtextsecure/outgoing_message.js', 'libtextsecure/sendmessage.js', 'libtextsecure/sync_request.js', 'libtextsecure/contacts_parser.js', ], dest: 'js/libtextsecure.js', }, libtextsecuretest: { src: [ 'components/jquery/dist/jquery.js', 'components/mock-socket/dist/mock-socket.js', 'components/mocha/mocha.js', 'components/chai/chai.js', 'libtextsecure/test/_test.js' ], dest: 'libtextsecure/test/test.js', } }, sass: { stylesheets: { files: { 'stylesheets/manifest.css': 'stylesheets/manifest.scss', 'stylesheets/options.css': 'stylesheets/options.scss' } } }, jshint: { files: [ 'Gruntfile.js', 'js/**/*.js', '!js/libtextsecure.js', '!js/libsignal-protocol-worker.js', '!js/components.js', '!js/signal_protocol_store.js', '_locales/**/*' ], options: { jshintrc: '.jshintrc' }, }, dist: { src: [ 'manifest.json', 'background.html', 'index.html', 'conversation.html', 'options.html', '_locales/**', 'protos/*', 'js/**', 'stylesheets/*.css', '!js/register.js' ], res: [ 'images/**', 'fonts/*', ] }, copy: { res: { files: [{ expand: true, dest: 'dist/', src: ['<%= dist.res %>'] }], }, src: { files: [{ expand: true, dest: 'dist/', src: ['<%= dist.src %>'] }], options: { process: function(content, srcpath) { if (srcpath.match('background.js')) { return content.replace( /textsecure-service-staging.whispersystems.org/g, 'textsecure-service-ca.whispersystems.org:4433').replace( /whispersystems-textsecure-attachments-staging.s3.amazonaws.com/g, 'whispersystems-textsecure-attachments.s3.amazonaws.com'); } else if (srcpath.match('expire.js')) { var gitinfo = grunt.config.get('gitinfo'); var commited = gitinfo.local.branch.current.lastCommitTime; var time = Date.parse(commited) + 1000 * 60 * 60 * 24 * 90; return content.replace( /var BUILD_EXPIRATION = 0/, "var BUILD_EXPIRATION = " + time ); } else { return content; } } } } }, jscs: { all: { src: [ 'Gruntfile', 'js/**/*.js', '!js/libtextsecure.js', '!js/libsignal-protocol-worker.js', '!js/components.js', 'test/**/*.js', '!test/blanket_mocha.js', '!test/test.js', ] } }, watch: { sass: { files: ['./stylesheets/*.scss'], tasks: ['sass'] }, libtextsecure: { files: ['./libtextsecure/*.js', './libtextsecure/storage/*.js'], tasks: ['concat:libtextsecure'] }, dist: { files: ['<%= dist.src %>', '<%= dist.res %>'], tasks: ['copy_dist'] }, scripts: { files: ['<%= jshint.files %>', './js/**/*.js'], tasks: ['jshint'] }, style: { files: ['<%= jscs.all.src %>', './js/**/*.js'], tasks: ['jscs'] }, }, connect: { server: { options: { base: '.', port: 9999 } } }, 'saucelabs-mocha': { all: { options: { urls: [ 'http://127.0.0.1:9999/test/index.html', 'http://127.0.0.1:9999/libtextsecure/test/index.html', ], build: process.env.TRAVIS_JOB_ID, browsers: [ { browserName: 'chrome', version: '41' }, { platform: 'linux', browserName: 'firefox', version: '34' } ], testname: 'TextSecure-Browser Tests', 'max-duration': 300, statusCheckAttempts: 200 } } }, exec: { 'tx-pull': { cmd: 'tx pull' } }, gitinfo: {} // to be populated by grunt gitinfo }); Object.keys(grunt.config.get('pkg').devDependencies).forEach(function(key) { if (/^grunt(?!(-cli)?$)/.test(key)) { // ignore grunt and grunt-cli grunt.loadNpmTasks(key); } }); // Transifex does not understand placeholders, so this task patches all non-en // locales with missing placeholders grunt.registerTask('locale-patch', function(){ var en = grunt.file.readJSON('_locales/en/messages.json'); grunt.file.recurse('_locales', function(abspath, rootdir, subdir, filename){ if (subdir === 'en' || filename !== 'messages.json'){ return; } var messages = grunt.file.readJSON(abspath); for (var key in messages){ if (en[key] !== undefined && messages[key] !== undefined){ if (en[key].placeholders !== undefined && messages[key].placeholders === undefined){ messages[key].placeholders = en[key].placeholders; } } } grunt.file.write(abspath, JSON.stringify(messages, null, 4) + '\n'); }); }); grunt.registerTask('tx', ['exec:tx-pull', 'locale-patch']); grunt.registerTask('dev', ['default', 'connect', 'watch']); grunt.registerTask('test', ['jshint', 'jscs', 'connect', 'saucelabs-mocha']); grunt.registerTask('copy_dist', ['gitinfo', 'copy']); grunt.registerTask('default', ['concat', 'sass', 'copy_dist']); };