<commit_before>/*jslint node: true */
'use strict';

var pkg = require('./package.json');

//Using exclusion patterns slows down Grunt significantly
//instead of creating a set of patterns like '**/*.js' and '!**/node_modules/**'
//this method is used to create a set of inclusive patterns for all subdirectories
//skipping node_modules, bower_components, dist, and any .dirs
//This enables users to create any directory structure they desire.
var createFolderGlobs = function(fileTypePatterns) {
  fileTypePatterns = Array.isArray(fileTypePatterns) ? fileTypePatterns : [fileTypePatterns];
  var ignore = ['node_modules','bower_components','dist','temp'];
  var fs = require('fs');
  return fs.readdirSync(process.cwd())
          .map(function(file){
            if (ignore.indexOf(file) !== -1 ||
                file.indexOf('.') === 0 ||
                !fs.lstatSync(file).isDirectory()) {
              return null;
            } else {
              return fileTypePatterns.map(function(pattern) {
                return file + '/**/' + pattern;
              });
            }
          })
          .filter(function(patterns){
            return patterns;
          })
          .concat(fileTypePatterns);
};

module.exports = function (grunt) {

  // load all grunt tasks
  require('load-grunt-tasks')(grunt);

  // Project configuration.
  grunt.initConfig({
    connect: {
      main: {
        options: {
          port: 9001
        }
      }
    },
    watch: {
      main: {
        options: {
            livereload: true,
            livereloadOnError: false,
            spawn: false
        },
        files: [createFolderGlobs(['*.js','*.less','*.html']),'!_SpecRunner.html','!.grunt'],
        tasks: [] //all the tasks are run dynamically during the watch event handler
      }
    },
    jshint: {
      main: {
        options: {
            jshintrc: '.jshintrc'
        },
        src: createFolderGlobs('*.js')
      }
    },
    clean: {
      before:{
        src:['dist','temp']
      },
      after: {
        src:['temp']
      }
    },
    less: {
      production: {
        options: {
        },
        files: {
          'temp/app.css': 'app.less'
        }
      }
    },
    autoprefixer: {
      options: {
        browsers: ['ie >= 8', 'ff > 4', 'last 8 versions']
      },
      main: {
        src: 'temp/app.css'
      }
    },
    ngtemplates: {
      main: {
        options: {
            module: pkg.name,
            htmlmin:'<%= htmlmin.main.options %>'
        },
        src: [createFolderGlobs('*.html'),'!index.html','!_SpecRunner.html'],
        dest: 'temp/templates.js'
      }
    },
    copy: {
      main: {
        files: [
          {src: ['img/**'], dest: 'dist/'},
          {src: ['temp_data/**'], dest: 'dist/'},
          {
            expand: true,
            cwd: 'bower_components/bootstrap/fonts/',
            src: ['**'],
            dest: 'dist/fonts/'
          },
          {
            expand: true,
            cwd: 'bower_components/bootstrap/fonts/',
            src: ['**'],
            dest: 'dist/fonts/'
          },
          {
            src: ['locales/**'],
            dest: 'dist/'
          },
//           {src: ['bower_components/font-awesome/fonts/**'], dest: 'dist/',filter:'isFile',expand:true}
          //{src: ['bower_components/angular-ui-utils/ui-utils-ieshiv.min.js'], dest: 'dist/'},
          //{src: ['bower_components/select2/*.png','bower_components/select2/*.gif'], dest:'dist/css/',flatten:true,expand:true},
          //{src: ['bower_components/angular-mocks/angular-mocks.js'], dest: 'dist/'}
        ]
      }
    },
    dom_munger:{
      read: {
        options: {
          read:[
            {selector:'script[class="libnocompat"]',attribute:'src',writeto:'libnocompatjs'},
            {selector:'script[class="lib"]',attribute:'src',writeto:'libjs'},
            {selector:'script[class="app"]',attribute:'src',writeto:'appjs'},
            {selector:'link[rel="stylesheet"][data-concat!="false"]',attribute:'href',writeto:'appcss'}
          ]
        },
        src: 'index.html'
      },
      update: {
        options: {
          remove: ['script[data-remove!="false"]','link[data-remove!="false"]'],
          append: [
            {selector:'body',html:'<!--[if lte IE 8]><script src="libcompat.min.js"></script><![endif]--><!--[if gt IE 9]><script src="libnocompat.min.js"></script><![endif]--><!--[if !IE]><!--><script src="libnocompat.min.js"></script><!--<![endif]-->'},
            {selector:'body',html:'<script src="lib.min.js"></script>'},
            {selector:'body',html:'<script src="avConfig.js"></script>'},
            {selector:'body',html:'<script src="app.min.js"></script>'},
            {selector:'head',html:'<link rel="stylesheet" href="app.full.min.css">'}
          ]
        },
        src:'index.html',
        dest: 'dist/index.html'
      }
    },
    cssmin: {
      main: {
        src:['temp/app.css','<%= dom_munger.data.appcss %>'],
        dest:'dist/app.full.min.css'
      },
    },
    concat: {
      main: {
        files: {
          'temp/libcompat.js': [
             'vendor/jquery.compat/jquery-1.11.1.js',
             'vendor/json3/json-v3.3.2.js'
          ],
          'temp/libnocompat.js': ['<%= dom_munger.data.libnocompatjs %>'],
          'temp/lib.js': ['<%= dom_munger.data.libjs %>'],
          'temp/app.js': ['<%= dom_munger.data.appjs %>','<%= ngtemplates.main.dest %>'],
          'dist/avConfig.js': ['avConfig.js']
        }
      }
    },
    ngAnnotate: {
      main: {
        files: {
        'temp/app.js':['temp/app.js'],
        'temp/lib.js': ['temp/lib.js'],
        'temp/libnocompat.js': ['temp/libnocompat.js'],
        'temp/libcompat.js': ['temp/libcompat.js']
        }
      }
    },
    uglify: {
      main: {
        files: {
          'dist/app.min.js': 'temp/app.js',
          'dist/lib.min.js': 'temp/lib.js',
          'dist/libnocompat.min.js': 'temp/libnocompat.js',
          'dist/libcompat.min.js': 'temp/libcompat.js'
        }
      }
    },
    htmlmin: {
      main: {
        options: {
          collapseBooleanAttributes: true,
          collapseWhitespace: true,
          removeAttributeQuotes: false,
          removeComments: false,
          removeEmptyAttributes: true,
          removeScriptTypeAttributes: true,
          removeStyleLinkTypeAttributes: true
        },
        files: {
          'dist/index.html': 'dist/index.html'
        }
      }
    },
    imagemin: {
      main:{
        files: [{
          expand: true, cwd:'dist/',
          src:['**/{*.png,*.jpg}'],
          dest: 'dist/'
        }]
      }
    },
    karma: {
      options: {
        frameworks: ['jasmine'],
        files: [  //this files data is also updated in the watch handler, if updated change there too
          '<%= dom_munger.data.libnocompatjs %>',
          '<%= dom_munger.data.libjs %>',
          'avConfig.js',
          '<%= dom_munger.data.appjs %>',
          '<%= ngtemplates.main.dest %>',
          'bower_components/angular-mocks/angular-mocks.js',
          createFolderGlobs('*-spec.js')
        ],
        logLevel:'ERROR',
        reporters:['mocha'],
        autoWatch: false, //watching is handled by grunt-contrib-watch
        singleRun: true
      },
      all_tests: {
        browsers: ['PhantomJS','Chrome','Firefox']
      },
      during_watch: {
        browsers: ['PhantomJS']
      },
    },
    protractor: {
      options: {
        configFile: "node_modules/protractor/referenceConf.js", // Default config file
        keepAlive: true, // If false, the grunt process stops when the test fails.
        noColor: false, // If true, protractor will not use colors in its output.
        args: {
        // Arguments passed to the command
      }
    },
    //your_target: {   // Grunt requires at least one target to run so you can simply put 'all: {}' here too.
      all: {
      options: {
        configFile: "e2e.conf.js", // Target-specific config file
        args: {} // Target-specific arguments
      }
    },
  },

  });

  grunt.registerTask('build',['jshint','clean:before','less','autoprefixer','dom_munger','ngtemplates','cssmin','concat','ngAnnotate','uglify','copy','htmlmin','imagemin','clean:after']);
  grunt.registerTask('serve', ['dom_munger:read','jshint','connect', 'watch']);
  grunt.registerTask('test',['dom_munger:read','karma:all_tests']);

  grunt.event.on('watch', function(action, filepath) {
    //https://github.com/gruntjs/grunt-contrib-watch/issues/156

    var tasksToRun = [];

    if ((filepath.lastIndexOf('.json') !== -1 && filepath.lastIndexOf('.json') === filepath.length - 5) ||
        (filepath.lastIndexOf('.js') !== -1 && filepath.lastIndexOf('.js') === filepath.length - 3)) {

      //lint the changed js file
      grunt.config('jshint.main.src', filepath);
      tasksToRun.push('jshint');

      //find the appropriate unit t est for the changed file
      var spec = filepath;
      if (filepath.lastIndexOf('-spec.js') === -1 || filepath.lastIndexOf('-spec.js') !== filepath.length - 8) {
        spec = filepath.substring(0,filepath.length - 3) + '-spec.js';
      }

      //if the spec exists then lets run it
      if (grunt.file.exists(spec)) {
        var files = [].concat(grunt.config('dom_munger.data.libnocompatjs'));
        files.concat(grunt.config('dom_munger.data.libjs'));
        files.push('bower_components/angular-mocks/angular-mocks.js');
        files.push('avConfig.js');
        files.concat(grunt.config('dom_munger.data.appjs'));
        files.concat(grunt.config('ngtemplates.main.dest'));
        files.push(spec);
        grunt.config('karma.options.files', files);
        tasksToRun.push('karma:during_watch');
      }
    }

    //if index.html changed, we need to reread the <script> tags so our next run of karma
    //will have the correct environment
    if (filepath === 'index.html') {
      tasksToRun.push('dom_munger:read');
    }

    grunt.config('watch.main.tasks',tasksToRun);

  });

  grunt.loadNpmTasks('grunt-protractor-runner');
};
<commit_msg>Support for IE9<commit_after>/*jslint node: true */
'use strict';

var pkg = require('./package.json');

//Using exclusion patterns slows down Grunt significantly
//instead of creating a set of patterns like '**/*.js' and '!**/node_modules/**'
//this method is used to create a set of inclusive patterns for all subdirectories
//skipping node_modules, bower_components, dist, and any .dirs
//This enables users to create any directory structure they desire.
var createFolderGlobs = function(fileTypePatterns) {
  fileTypePatterns = Array.isArray(fileTypePatterns) ? fileTypePatterns : [fileTypePatterns];
  var ignore = ['node_modules','bower_components','dist','temp'];
  var fs = require('fs');
  return fs.readdirSync(process.cwd())
          .map(function(file){
            if (ignore.indexOf(file) !== -1 ||
                file.indexOf('.') === 0 ||
                !fs.lstatSync(file).isDirectory()) {
              return null;
            } else {
              return fileTypePatterns.map(function(pattern) {
                return file + '/**/' + pattern;
              });
            }
          })
          .filter(function(patterns){
            return patterns;
          })
          .concat(fileTypePatterns);
};

module.exports = function (grunt) {

  // load all grunt tasks
  require('load-grunt-tasks')(grunt);

  // Project configuration.
  grunt.initConfig({
    connect: {
      main: {
        options: {
          port: 9001
        }
      }
    },
    watch: {
      main: {
        options: {
            livereload: true,
            livereloadOnError: false,
            spawn: false
        },
        files: [createFolderGlobs(['*.js','*.less','*.html']),'!_SpecRunner.html','!.grunt'],
        tasks: [] //all the tasks are run dynamically during the watch event handler
      }
    },
    jshint: {
      main: {
        options: {
            jshintrc: '.jshintrc'
        },
        src: createFolderGlobs('*.js')
      }
    },
    clean: {
      before:{
        src:['dist','temp']
      },
      after: {
        src:['temp']
      }
    },
    less: {
      production: {
        options: {
        },
        files: {
          'temp/app.css': 'app.less'
        }
      }
    },
    autoprefixer: {
      options: {
        browsers: ['ie >= 8', 'ff > 4', 'last 8 versions']
      },
      main: {
        src: 'temp/app.css'
      }
    },
    ngtemplates: {
      main: {
        options: {
            module: pkg.name,
            htmlmin:'<%= htmlmin.main.options %>'
        },
        src: [createFolderGlobs('*.html'),'!index.html','!_SpecRunner.html'],
        dest: 'temp/templates.js'
      }
    },
    copy: {
      main: {
        files: [
          {src: ['img/**'], dest: 'dist/'},
          {src: ['temp_data/**'], dest: 'dist/'},
          {
            expand: true,
            cwd: 'bower_components/bootstrap/fonts/',
            src: ['**'],
            dest: 'dist/fonts/'
          },
          {
            expand: true,
            cwd: 'bower_components/bootstrap/fonts/',
            src: ['**'],
            dest: 'dist/fonts/'
          },
          {
            src: ['locales/**'],
            dest: 'dist/'
          },
//           {src: ['bower_components/font-awesome/fonts/**'], dest: 'dist/',filter:'isFile',expand:true}
          //{src: ['bower_components/angular-ui-utils/ui-utils-ieshiv.min.js'], dest: 'dist/'},
          //{src: ['bower_components/select2/*.png','bower_components/select2/*.gif'], dest:'dist/css/',flatten:true,expand:true},
          //{src: ['bower_components/angular-mocks/angular-mocks.js'], dest: 'dist/'}
        ]
      }
    },
    dom_munger:{
      read: {
        options: {
          read:[
            {selector:'script[class="libnocompat"]',attribute:'src',writeto:'libnocompatjs'},
            {selector:'script[class="lib"]',attribute:'src',writeto:'libjs'},
            {selector:'script[class="app"]',attribute:'src',writeto:'appjs'},
            {selector:'link[rel="stylesheet"][data-concat!="false"]',attribute:'href',writeto:'appcss'}
          ]
        },
        src: 'index.html'
      },
      update: {
        options: {
          remove: ['script[data-remove!="false"]','link[data-remove!="false"]'],
          append: [
            {selector:'body',html:'<!--[if lte IE 8]><script src="libcompat.min.js"></script><![endif]--><!--[if gte IE 9]><script src="libnocompat.min.js"></script><![endif]--><!--[if !IE]><!--><script src="libnocompat.min.js"></script><!--<![endif]-->'},
            {selector:'body',html:'<script src="lib.min.js"></script>'},
            {selector:'body',html:'<script src="avConfig.js"></script>'},
            {selector:'body',html:'<script src="app.min.js"></script>'},
            {selector:'head',html:'<link rel="stylesheet" href="app.full.min.css">'}
          ]
        },
        src:'index.html',
        dest: 'dist/index.html'
      }
    },
    cssmin: {
      main: {
        src:['temp/app.css','<%= dom_munger.data.appcss %>'],
        dest:'dist/app.full.min.css'
      },
    },
    concat: {
      main: {
        files: {
          'temp/libcompat.js': [
             'vendor/jquery.compat/jquery-1.11.1.js',
             'vendor/json3/json-v3.3.2.js'
          ],
          'temp/libnocompat.js': ['<%= dom_munger.data.libnocompatjs %>'],
          'temp/lib.js': ['<%= dom_munger.data.libjs %>'],
          'temp/app.js': ['<%= dom_munger.data.appjs %>','<%= ngtemplates.main.dest %>'],
          'dist/avConfig.js': ['avConfig.js']
        }
      }
    },
    ngAnnotate: {
      main: {
        files: {
        'temp/app.js':['temp/app.js'],
        'temp/lib.js': ['temp/lib.js'],
        'temp/libnocompat.js': ['temp/libnocompat.js'],
        'temp/libcompat.js': ['temp/libcompat.js']
        }
      }
    },
    uglify: {
      main: {
        files: {
          'dist/app.min.js': 'temp/app.js',
          'dist/lib.min.js': 'temp/lib.js',
          'dist/libnocompat.min.js': 'temp/libnocompat.js',
          'dist/libcompat.min.js': 'temp/libcompat.js'
        }
      }
    },
    htmlmin: {
      main: {
        options: {
          collapseBooleanAttributes: true,
          collapseWhitespace: true,
          removeAttributeQuotes: false,
          removeComments: false,
          removeEmptyAttributes: true,
          removeScriptTypeAttributes: true,
          removeStyleLinkTypeAttributes: true
        },
        files: {
          'dist/index.html': 'dist/index.html'
        }
      }
    },
    imagemin: {
      main:{
        files: [{
          expand: true, cwd:'dist/',
          src:['**/{*.png,*.jpg}'],
          dest: 'dist/'
        }]
      }
    },
    karma: {
      options: {
        frameworks: ['jasmine'],
        files: [  //this files data is also updated in the watch handler, if updated change there too
          '<%= dom_munger.data.libnocompatjs %>',
          '<%= dom_munger.data.libjs %>',
          'avConfig.js',
          '<%= dom_munger.data.appjs %>',
          '<%= ngtemplates.main.dest %>',
          'bower_components/angular-mocks/angular-mocks.js',
          createFolderGlobs('*-spec.js')
        ],
        logLevel:'ERROR',
        reporters:['mocha'],
        autoWatch: false, //watching is handled by grunt-contrib-watch
        singleRun: true
      },
      all_tests: {
        browsers: ['PhantomJS','Chrome','Firefox']
      },
      during_watch: {
        browsers: ['PhantomJS']
      },
    },
    protractor: {
      options: {
        configFile: "node_modules/protractor/referenceConf.js", // Default config file
        keepAlive: true, // If false, the grunt process stops when the test fails.
        noColor: false, // If true, protractor will not use colors in its output.
        args: {
        // Arguments passed to the command
      }
    },
    //your_target: {   // Grunt requires at least one target to run so you can simply put 'all: {}' here too.
      all: {
      options: {
        configFile: "e2e.conf.js", // Target-specific config file
        args: {} // Target-specific arguments
      }
    },
  },

  });

  grunt.registerTask('build',['jshint','clean:before','less','autoprefixer','dom_munger','ngtemplates','cssmin','concat','ngAnnotate','uglify','copy','htmlmin','imagemin','clean:after']);
  grunt.registerTask('serve', ['dom_munger:read','jshint','connect', 'watch']);
  grunt.registerTask('test',['dom_munger:read','karma:all_tests']);

  grunt.event.on('watch', function(action, filepath) {
    //https://github.com/gruntjs/grunt-contrib-watch/issues/156

    var tasksToRun = [];

    if ((filepath.lastIndexOf('.json') !== -1 && filepath.lastIndexOf('.json') === filepath.length - 5) ||
        (filepath.lastIndexOf('.js') !== -1 && filepath.lastIndexOf('.js') === filepath.length - 3)) {

      //lint the changed js file
      grunt.config('jshint.main.src', filepath);
      tasksToRun.push('jshint');

      //find the appropriate unit t est for the changed file
      var spec = filepath;
      if (filepath.lastIndexOf('-spec.js') === -1 || filepath.lastIndexOf('-spec.js') !== filepath.length - 8) {
        spec = filepath.substring(0,filepath.length - 3) + '-spec.js';
      }

      //if the spec exists then lets run it
      if (grunt.file.exists(spec)) {
        var files = [].concat(grunt.config('dom_munger.data.libnocompatjs'));
        files.concat(grunt.config('dom_munger.data.libjs'));
        files.push('bower_components/angular-mocks/angular-mocks.js');
        files.push('avConfig.js');
        files.concat(grunt.config('dom_munger.data.appjs'));
        files.concat(grunt.config('ngtemplates.main.dest'));
        files.push(spec);
        grunt.config('karma.options.files', files);
        tasksToRun.push('karma:during_watch');
      }
    }

    //if index.html changed, we need to reread the <script> tags so our next run of karma
    //will have the correct environment
    if (filepath === 'index.html') {
      tasksToRun.push('dom_munger:read');
    }

    grunt.config('watch.main.tasks',tasksToRun);

  });

  grunt.loadNpmTasks('grunt-protractor-runner');
};
<|endoftext|>


<commit_before>/*global module */

(function () {
    'use strict';

    module.exports = function (grunt) {
        grunt.initConfig({
            pkg: grunt.file.readJSON('package.json'),

            clean: {
                all: ['README.md', 'docs', 'lib', 'src/cldr.zip', 'src/tzdata.tar.gz', 'src/*.json', 'src/cldr', 'src/tz', 'coverage'],
                after: ['src/cldr.zip', 'src/tzdata.tar.gz', 'src/cldr', 'src/tz', 'coverage']
            },

            curl: {
                cldr: {
                    src: '<%= pkg.sources.cldr %>',
                    dest: 'src/cldr.zip'
                },

                tzdata: {
                    src: '<%= pkg.sources.tzdata %>',
                    dest: 'src/tzdata.tar.gz'
                }
            },

            unzip: {
                cldr: {
                    src: 'src/cldr.zip',
                    dest: 'src/cldr'
                }
            },

            extactTargz: {
                tzdata: {
                    src: 'src/tzdata.tar.gz',
                    dest: 'src/tz'
                }
            },

            buildLanguage: {
                all: {
                    src: 'src/cldr',
                    dest: 'src'
                }
            },

            buildLeapSeconds: {
                all: {
                    src: 'src/tz',
                    dest: 'src'
                }
            },

            buildReadme: {
                readme: {
                    readme: 'templates/README.tpl',
                    dest: 'README.md'
                }
            },

            jsbeautifier: {
                lib: {
                    src: ['lib/<%= pkg.name %>.js'],
                    options: {
                        js: {
                            jslintHappy: true
                        }
                    }
                }
            },

            uglify: {
                lib: {
                    files: {
                        'lib/<%= pkg.name %>.min.js': 'lib/<%= pkg.name %>.js'
                    }
                },
                options: {
                    mangle: true,
                    compress: {},
                    output: {
                        'ascii_only': true
                    },
                    report: 'min',
                    preserveComments: 'some'
                }
            },

            jshint: {
                build: ['Gruntfile.js', 'index.js', 'src/*.js', 'tasks/**/*.js', 'tests/**/*.js'],
                lib: ['lib/<%= pkg.name %>.js'],
                options: {
                    'bitwise': true,
                    'camelcase': true,
                    'curly': true,
                    'eqeqeq': true,
                    'forin': true,
                    'freeze': true,
                    'funcscope': true,
                    'globalstrict': true,
                    'immed': true,
                    'newcap': true,
                    'noarg': true,
                    'nomen': true,
                    'nonew': true,
                    'notypeof': true,
                    'plusplus': true,
                    'regexp': true,
                    'strict': true,
                    'trailing': true,
                    'undef': true,
                    'white': true,
                    'noempty': true,
                    'quotmark': 'single'
                }
            },

            jsonlint: {
                all: {
                    src: ['src/*.json']
                }
            },

            replace: {
                lib: {
                    options: {
                        patterns: [{
                            match: 'VERSION',
                            replacement: '<%= pkg.version %>'
                        }, {
                            match: 'MODULE',
                            replacement: '<%= pkg.name %>'
                        }, {
                            match: 'DESCRIPTION',
                            replacement: '<%= pkg.description %>'
                        }, {
                            match: 'AUTHORNAME',
                            replacement: '<%= pkg.author.name %>'
                        }, {
                            match: 'AUTHOREMAIL',
                            replacement: '<%= pkg.author.email %>'
                        }, {
                            match: 'HOMEPAGE',
                            replacement: '<%= pkg.homepage %>'
                        }, {
                            match: 'COPYRIGHT',
                            replacement: '<%= pkg.copyright %>'
                        }, {
                            match: 'LICENSE',
                            replacement: '<%= pkg.licenses[0].type %>'
                        }, {
                            match: 'LICLINK',
                            replacement: '<%= pkg.licenses[0].url %>'
                        }, {
                            match: '/\\/\\*@@leapSeconds\\*\\//g',
                            replacement: '<%= grunt.file.read("src/leapSeconds.json") %>',
                            expression: true
                        }, {
                            match: '/\\/\\*@@supplemental\\*\\//g',
                            replacement: '<%= grunt.file.read("src/supplemental.json") %>',
                            expression: true
                        }, {
                            match: '/\\/\\*@@languages\\*\\//g',
                            replacement: '<%= grunt.file.read("src/language.json") %>',
                            expression: true
                        }, {
                            match: '/\\/\\*@@BigNumber\\*\\//g',
                            replacement: (grunt.file.read('node_modules/bignumber.js/bignumber.js').replace(/\$/g, '$$$$')),
                            expression: true
                        }]
                    },
                    files: [{
                        src: ['src/<%= pkg.name %>.js'],
                        dest: 'lib/<%= pkg.name %>.js'
                    }]
                }
            },

            jsdoc: {
                lib: {
                    jsdoc: 'node_modules/.bin/jsdoc',
                    src: ['README.md', 'lib/<%= pkg.name %>.js'],
                    options: {
                        destination: 'docs',
                        private: false
                    }
                }
            },

            shell: {
                beautified: {
                    options: {
                        stdout: true,
                        stderr: true,
                        failOnError: true,
                        execOptions: {
                            maxBuffer: 1048576
                        }
                    },
                    command: 'node_modules/tape-compact/bin/tape tests/*.js'
                },
                coveralls: {
                    options: {
                        stdout: false,
                        stderr: true,
                        failOnError: true,
                        execOptions: {
                            maxBuffer: 1048576
                        }
                    },
                    command: 'node_modules/istanbul/lib/cli.js cover tests/*.js --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage'
                },
                uglified: {
                    options: {
                        stdout: true,
                        stderr: true,
                        failOnError: true,
                        execOptions: {
                            maxBuffer: 1048576
                        }
                    },
                    command: 'ASTRODATE_COVERAGE=1 node_modules/tape-compact/bin/tape tests/*.js'
                }
            },

            watch: {
                test: {
                    files: [
                        'lib/<%= pkg.name %>.js',
                        'tests/*.js'
                    ],
                    tasks: ['shell:beautified', 'shell:coveralls', 'shell:uglified']
                },

                jshint: {
                    files: [
                        '<%= jshint.build %>',
                        '<%= jshint.lib %>'
                    ],
                    tasks: ['jshint']
                },

                jsonlint: {
                    files: [
                        '<%= jsonlint.all.src %>'
                    ],
                    tasks: ['jsonlint']
                }
            }
        });

        // Custom tasks.
        grunt.loadTasks('tasks');

        // These plugins provide necessary tasks.
        grunt.loadNpmTasks('grunt-contrib-jshint');
        grunt.loadNpmTasks('grunt-contrib-concat');
        grunt.loadNpmTasks('grunt-contrib-uglify');
        grunt.loadNpmTasks('grunt-contrib-watch');
        grunt.loadNpmTasks('grunt-jsdoc');
        grunt.loadNpmTasks('grunt-jsbeautifier');
        grunt.loadNpmTasks('grunt-replace');
        grunt.loadNpmTasks('grunt-contrib-clean');
        grunt.loadNpmTasks('grunt-curl');
        grunt.loadNpmTasks('grunt-zip');
        grunt.loadNpmTasks('grunt-shell');
        grunt.loadNpmTasks('grunt-jsonlint');

        // Default task.
        grunt.registerTask('default', [
            'clean:all',
            'jshint:build',
            'curl',
            'unzip',
            'extactTargz',
            'buildLanguage',
            'buildLeapSeconds',
            'jsonlint',
            'replace:lib',
            'jsbeautifier:lib',
            'jshint:lib',
            'shell:beautified',
            'uglify',
            'shell:uglified',
            //'shell:coveralls',
            'buildReadme',
            'jsdoc',
            'clean:after'
        ]);

        grunt.registerTask('test', [
            'shell:beautified',
            //'shell:coveralls',
            'shell:uglified'
        ]);
    };
}());
<commit_msg>Reinstated coveralls<commit_after>/*global module */

(function () {
    'use strict';

    module.exports = function (grunt) {
        grunt.initConfig({
            pkg: grunt.file.readJSON('package.json'),

            clean: {
                all: ['README.md', 'docs', 'lib', 'src/cldr.zip', 'src/tzdata.tar.gz', 'src/*.json', 'src/cldr', 'src/tz', 'coverage'],
                after: ['src/cldr.zip', 'src/tzdata.tar.gz', 'src/cldr', 'src/tz', 'coverage']
            },

            curl: {
                cldr: {
                    src: '<%= pkg.sources.cldr %>',
                    dest: 'src/cldr.zip'
                },

                tzdata: {
                    src: '<%= pkg.sources.tzdata %>',
                    dest: 'src/tzdata.tar.gz'
                }
            },

            unzip: {
                cldr: {
                    src: 'src/cldr.zip',
                    dest: 'src/cldr'
                }
            },

            extactTargz: {
                tzdata: {
                    src: 'src/tzdata.tar.gz',
                    dest: 'src/tz'
                }
            },

            buildLanguage: {
                all: {
                    src: 'src/cldr',
                    dest: 'src'
                }
            },

            buildLeapSeconds: {
                all: {
                    src: 'src/tz',
                    dest: 'src'
                }
            },

            buildReadme: {
                readme: {
                    readme: 'templates/README.tpl',
                    dest: 'README.md'
                }
            },

            jsbeautifier: {
                lib: {
                    src: ['lib/<%= pkg.name %>.js'],
                    options: {
                        js: {
                            jslintHappy: true
                        }
                    }
                }
            },

            uglify: {
                lib: {
                    files: {
                        'lib/<%= pkg.name %>.min.js': 'lib/<%= pkg.name %>.js'
                    }
                },
                options: {
                    mangle: true,
                    compress: {},
                    output: {
                        'ascii_only': true
                    },
                    report: 'min',
                    preserveComments: 'some'
                }
            },

            jshint: {
                build: ['Gruntfile.js', 'index.js', 'src/*.js', 'tasks/**/*.js', 'tests/**/*.js'],
                lib: ['lib/<%= pkg.name %>.js'],
                options: {
                    'bitwise': true,
                    'camelcase': true,
                    'curly': true,
                    'eqeqeq': true,
                    'forin': true,
                    'freeze': true,
                    'funcscope': true,
                    'globalstrict': true,
                    'immed': true,
                    'newcap': true,
                    'noarg': true,
                    'nomen': true,
                    'nonew': true,
                    'notypeof': true,
                    'plusplus': true,
                    'regexp': true,
                    'strict': true,
                    'trailing': true,
                    'undef': true,
                    'white': true,
                    'noempty': true,
                    'quotmark': 'single'
                }
            },

            jsonlint: {
                all: {
                    src: ['src/*.json']
                }
            },

            replace: {
                lib: {
                    options: {
                        patterns: [{
                            match: 'VERSION',
                            replacement: '<%= pkg.version %>'
                        }, {
                            match: 'MODULE',
                            replacement: '<%= pkg.name %>'
                        }, {
                            match: 'DESCRIPTION',
                            replacement: '<%= pkg.description %>'
                        }, {
                            match: 'AUTHORNAME',
                            replacement: '<%= pkg.author.name %>'
                        }, {
                            match: 'AUTHOREMAIL',
                            replacement: '<%= pkg.author.email %>'
                        }, {
                            match: 'HOMEPAGE',
                            replacement: '<%= pkg.homepage %>'
                        }, {
                            match: 'COPYRIGHT',
                            replacement: '<%= pkg.copyright %>'
                        }, {
                            match: 'LICENSE',
                            replacement: '<%= pkg.licenses[0].type %>'
                        }, {
                            match: 'LICLINK',
                            replacement: '<%= pkg.licenses[0].url %>'
                        }, {
                            match: '/\\/\\*@@leapSeconds\\*\\//g',
                            replacement: '<%= grunt.file.read("src/leapSeconds.json") %>',
                            expression: true
                        }, {
                            match: '/\\/\\*@@supplemental\\*\\//g',
                            replacement: '<%= grunt.file.read("src/supplemental.json") %>',
                            expression: true
                        }, {
                            match: '/\\/\\*@@languages\\*\\//g',
                            replacement: '<%= grunt.file.read("src/language.json") %>',
                            expression: true
                        }, {
                            match: '/\\/\\*@@BigNumber\\*\\//g',
                            replacement: (grunt.file.read('node_modules/bignumber.js/bignumber.js').replace(/\$/g, '$$$$')),
                            expression: true
                        }]
                    },
                    files: [{
                        src: ['src/<%= pkg.name %>.js'],
                        dest: 'lib/<%= pkg.name %>.js'
                    }]
                }
            },

            jsdoc: {
                lib: {
                    jsdoc: 'node_modules/.bin/jsdoc',
                    src: ['README.md', 'lib/<%= pkg.name %>.js'],
                    options: {
                        destination: 'docs',
                        private: false
                    }
                }
            },

            shell: {
                beautified: {
                    options: {
                        stdout: true,
                        stderr: true,
                        failOnError: true,
                        execOptions: {
                            maxBuffer: 1048576
                        }
                    },
                    command: 'node_modules/tape-compact/bin/tape tests/*.js'
                },
                coveralls: {
                    options: {
                        stdout: false,
                        stderr: true,
                        failOnError: true,
                        execOptions: {
                            maxBuffer: 1048576
                        }
                    },
                    command: 'node_modules/istanbul/lib/cli.js cover tests/*.js --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage'
                },
                uglified: {
                    options: {
                        stdout: true,
                        stderr: true,
                        failOnError: true,
                        execOptions: {
                            maxBuffer: 1048576
                        }
                    },
                    command: 'ASTRODATE_COVERAGE=1 node_modules/tape-compact/bin/tape tests/*.js'
                }
            },

            watch: {
                test: {
                    files: [
                        'lib/<%= pkg.name %>.js',
                        'tests/*.js'
                    ],
                    tasks: ['shell:beautified', 'shell:coveralls', 'shell:uglified']
                },

                jshint: {
                    files: [
                        '<%= jshint.build %>',
                        '<%= jshint.lib %>'
                    ],
                    tasks: ['jshint']
                },

                jsonlint: {
                    files: [
                        '<%= jsonlint.all.src %>'
                    ],
                    tasks: ['jsonlint']
                }
            }
        });

        // Custom tasks.
        grunt.loadTasks('tasks');

        // These plugins provide necessary tasks.
        grunt.loadNpmTasks('grunt-contrib-jshint');
        grunt.loadNpmTasks('grunt-contrib-concat');
        grunt.loadNpmTasks('grunt-contrib-uglify');
        grunt.loadNpmTasks('grunt-contrib-watch');
        grunt.loadNpmTasks('grunt-jsdoc');
        grunt.loadNpmTasks('grunt-jsbeautifier');
        grunt.loadNpmTasks('grunt-replace');
        grunt.loadNpmTasks('grunt-contrib-clean');
        grunt.loadNpmTasks('grunt-curl');
        grunt.loadNpmTasks('grunt-zip');
        grunt.loadNpmTasks('grunt-shell');
        grunt.loadNpmTasks('grunt-jsonlint');

        // Default task.
        grunt.registerTask('default', [
            'clean:all',
            'jshint:build',
            'curl',
            'unzip',
            'extactTargz',
            'buildLanguage',
            'buildLeapSeconds',
            'jsonlint',
            'replace:lib',
            'jsbeautifier:lib',
            'jshint:lib',
            'shell:beautified',
            'uglify',
            'shell:uglified',
            'shell:coveralls',
            'buildReadme',
            'jsdoc',
            'clean:after'
        ]);

        grunt.registerTask('test', [
            'shell:beautified',
            'shell:coveralls',
            'shell:uglified'
        ]);
    };
}());
<|endoftext|>


<commit_before>/**
 * Author: guoyao
 * Time: 07-31-2013 18:03
 * Blog: http://www.guoyao.me
 */

module.exports = function (grunt) {
    "use strict";

    // Project configuration.
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        banner: '/**\n' +
            '* <%= pkg.name %>.js v<%= pkg.version %> by @guoyao\n' +
            '* Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
            '* <%= pkg.description %>\n' +
            '* <%= pkg.homepage %>\n' +
            '* <%= _.pluck(pkg.licenses, "url").join(", ") %>\n' +
            '*/\n',

        jqueryCheck: 'if (!jQuery) { throw new Error(\"Graceful-web-ui requires jQuery\") }\n\n',

        clean: {
            dist: ['dist']
        },

        concat: {
            options: {
                banner: '<%= banner %><%= jqueryCheck %>',
                stripBanners: false
            },
            grace: {
                src: ['js/helper.js', 'js/nav.js', 'js/tab.js', 'js/collapse.js', 'js/popup.js', 'js/slider.js', 'js/placeholder.js', 'js/panel.js', 'js/ie-patch.js'],
                dest: 'dist/js/<%= pkg.name %>-<%= pkg.version %>.js'
            }
        },

        recess: {
            options: {
                compile: true
            },
            grace: {
                files: {
                    'dist/css/<%= pkg.name %>-<%= pkg.version %>.css': ['less/graceful-web-ui.less'],
                    'demo/css/index.css': ['demo/less/index.less'],
                    'demo/css/lib/prettify.css': ['demo/less/prettify.less']
                }
            },
            min: {
                options: {
                    compress: true
                },
                files: {
                    'dist/css/<%= pkg.name %>-<%= pkg.version %>.min.css': ['less/graceful-web-ui.less']
                }
            }
        },

        uglify: {
            options: {
                banner: '<%= banner %>'
            },
            grace: {
                files: {
                    'dist/js/<%= pkg.name %>-<%= pkg.version %>.min.js': ['<%= concat.grace.dest %>']
                }
            }
        },

        copy: {
            demo: {
                files: [
                    {
                        'demo/css/<%= pkg.name %>.min.css': 'dist/css/<%= pkg.name %>-<%= pkg.version %>.min.css',
                        'demo/js/<%= pkg.name %>.min.js': 'dist/js/<%= pkg.name %>-<%= pkg.version %>.min.js',
                        'demo/js/lib/jquery.min.js': 'bower_components/jquery/jquery.min.js',
                        'demo/js/lib/prettify.js': 'bower_components/google-code-prettify/src/prettify.js'
                    },
                    {expand: true, src: ['assets/**'], dest: 'demo'}
                ]
            },
            test: {
                files: {
                    'js/tests/vendor/lib/jquery.js': 'bower_components/jquery/jquery.js',
                    'js/tests/vendor/lib/qunit.js': 'bower_components/qunit/qunit//qunit.js',
                    'js/tests/vendor/lib/qunit.css': 'bower_components/qunit/qunit/qunit.css'
                }
            },
            dist_assets: {
                files: [
                    {expand: true, src: ['assets/graceful-web-ui/**'], dest: 'dist'}
                ]
            }
        },

        connect: {
            server: {
                options: {
                    port: 3000,
                    base: 'demo',
                    keepalive: true
                }
            }
        },

        watch: {
            src: {
                files: '<%= jshint.src.src %>',
                tasks: ['jshint:src', 'qunit']
            },
            test: {
                files: '<%= jshint.test.src %>',
                tasks: ['jshint:test', 'qunit']
            },
            recess: {
                files: 'less/*.less',
                tasks: ['recess', 'copy:demo']
            }
        },

        bower: {
            install: {
                options: {
                    copy: false,
                    cleanTargetDir: true
                }
            }
        },

        jshint: {
            options: {
                jshintrc: 'js/.jshintrc'
            },
            gruntfile: {
                src: 'Gruntfile.js'
            },
            src: {
                src: ['js/*.js']
            },
            test: {
                src: ['js/tests/unit/*.js']
            }
        },

        qunit: {
            options: {
                inject: 'js/tests/unit/phantom.js',
                coverage: {
                    src: ['js/*.js'],
                    instrumentedFiles: "temp/",
                    lcovReport: "report/"
                }
            },
            files: ['js/tests/*.html']
        },

        shell: {
            coverall: {
                command: 'node_modules/coveralls/bin/coveralls.js <report/lcov.info'
            }
        }
    });

    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-recess');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-connect');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-bower-task');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-qunit');
    grunt.loadNpmTasks('grunt-qunit-istanbul');
    grunt.loadNpmTasks('grunt-shell');

    // Test task.
    grunt.registerTask('test', ['bower:install', 'copy:test', 'jshint', 'qunit']);

    // generate coverage report after tests
    grunt.event.on('qunit.done', function () {
        grunt.task.run('shell:coverall');
    });

    // CSS distribution task.
    grunt.registerTask('dist-css', ['recess']);

    // JS distribution task.
    grunt.registerTask('dist-js', ['concat', 'uglify']);

    // Assets distribution task.
    grunt.registerTask('dist-assets', ['copy:dist_assets']);

    // Full distribution task.
    grunt.registerTask('dist', ['clean', 'dist-css', 'dist-js', 'dist-assets']);

    // Demo distribution task.
    grunt.registerTask('dist-demo', ['dist', 'bower', 'copy:demo']);

    // Start local server for demo
    grunt.registerTask('s', ['dist-demo', 'connect']);

    // Default task(s).
    grunt.registerTask('default', ['dist-demo']);

};<commit_msg>add coveralls coverage<commit_after>/**
 * Author: guoyao
 * Time: 07-31-2013 18:03
 * Blog: http://www.guoyao.me
 */

module.exports = function (grunt) {
    "use strict";

    // Project configuration.
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        banner: '/**\n' +
            '* <%= pkg.name %>.js v<%= pkg.version %> by @guoyao\n' +
            '* Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
            '* <%= pkg.description %>\n' +
            '* <%= pkg.homepage %>\n' +
            '* <%= _.pluck(pkg.licenses, "url").join(", ") %>\n' +
            '*/\n',

        jqueryCheck: 'if (!jQuery) { throw new Error(\"Graceful-web-ui requires jQuery\") }\n\n',

        clean: {
            dist: ['dist']
        },

        concat: {
            options: {
                banner: '<%= banner %><%= jqueryCheck %>',
                stripBanners: false
            },
            grace: {
                src: ['js/helper.js', 'js/nav.js', 'js/tab.js', 'js/collapse.js', 'js/popup.js', 'js/slider.js', 'js/placeholder.js', 'js/panel.js', 'js/ie-patch.js'],
                dest: 'dist/js/<%= pkg.name %>-<%= pkg.version %>.js'
            }
        },

        recess: {
            options: {
                compile: true
            },
            grace: {
                files: {
                    'dist/css/<%= pkg.name %>-<%= pkg.version %>.css': ['less/graceful-web-ui.less'],
                    'demo/css/index.css': ['demo/less/index.less'],
                    'demo/css/lib/prettify.css': ['demo/less/prettify.less']
                }
            },
            min: {
                options: {
                    compress: true
                },
                files: {
                    'dist/css/<%= pkg.name %>-<%= pkg.version %>.min.css': ['less/graceful-web-ui.less']
                }
            }
        },

        uglify: {
            options: {
                banner: '<%= banner %>'
            },
            grace: {
                files: {
                    'dist/js/<%= pkg.name %>-<%= pkg.version %>.min.js': ['<%= concat.grace.dest %>']
                }
            }
        },

        copy: {
            demo: {
                files: [
                    {
                        'demo/css/<%= pkg.name %>.min.css': 'dist/css/<%= pkg.name %>-<%= pkg.version %>.min.css',
                        'demo/js/<%= pkg.name %>.min.js': 'dist/js/<%= pkg.name %>-<%= pkg.version %>.min.js',
                        'demo/js/lib/jquery.min.js': 'bower_components/jquery/jquery.min.js',
                        'demo/js/lib/prettify.js': 'bower_components/google-code-prettify/src/prettify.js'
                    },
                    {expand: true, src: ['assets/**'], dest: 'demo'}
                ]
            },
            test: {
                files: {
                    'js/tests/vendor/lib/jquery.js': 'bower_components/jquery/jquery.js',
                    'js/tests/vendor/lib/qunit.js': 'bower_components/qunit/qunit//qunit.js',
                    'js/tests/vendor/lib/qunit.css': 'bower_components/qunit/qunit/qunit.css'
                }
            },
            dist_assets: {
                files: [
                    {expand: true, src: ['assets/graceful-web-ui/**'], dest: 'dist'}
                ]
            }
        },

        connect: {
            server: {
                options: {
                    port: 3000,
                    base: 'demo',
                    keepalive: true
                }
            }
        },

        watch: {
            src: {
                files: '<%= jshint.src.src %>',
                tasks: ['jshint:src', 'qunit']
            },
            test: {
                files: '<%= jshint.test.src %>',
                tasks: ['jshint:test', 'qunit']
            },
            recess: {
                files: 'less/*.less',
                tasks: ['recess', 'copy:demo']
            }
        },

        bower: {
            install: {
                options: {
                    copy: false,
                    cleanTargetDir: true
                }
            }
        },

        jshint: {
            options: {
                jshintrc: 'js/.jshintrc'
            },
            gruntfile: {
                src: 'Gruntfile.js'
            },
            src: {
                src: ['js/*.js']
            },
            test: {
                src: ['js/tests/unit/*.js']
            }
        },

        qunit: {
            phantom: {
                options: {
                    inject: 'js/tests/unit/phantom.js',
                    coverage: {
                        src: ['js/*.js'],
                        instrumentedFiles: "temp/",
                        lcovReport: "report/"
                    }
                },
                src: ['js/tests/*.html']
            },
            coverage: {
                options: {
                    coverage: {
                        src: ['js/*.js'],
                        instrumentedFiles: "temp/",
                        lcovReport: "report/"
                    }
                },
                src: ['js/tests/*.html']
            }
        },

        shell: {
            coverall: {
                command: 'node_modules/coveralls/bin/coveralls.js <report/lcov.info'
            }
        }
    });

    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-recess');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-connect');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-bower-task');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-qunit');
    grunt.loadNpmTasks('grunt-qunit-istanbul');
    grunt.loadNpmTasks('grunt-shell');

    // Test task.
    grunt.registerTask('test', ['bower:install', 'copy:test', 'jshint', 'qunit', 'shell:coverall']);

    // generate coverage report after tests
//    grunt.event.on('qunit.done', function () {
//        grunt.task.run('shell:coverall');
//    });

    // CSS distribution task.
    grunt.registerTask('dist-css', ['recess']);

    // JS distribution task.
    grunt.registerTask('dist-js', ['concat', 'uglify']);

    // Assets distribution task.
    grunt.registerTask('dist-assets', ['copy:dist_assets']);

    // Full distribution task.
    grunt.registerTask('dist', ['clean', 'dist-css', 'dist-js', 'dist-assets']);

    // Demo distribution task.
    grunt.registerTask('dist-demo', ['dist', 'bower', 'copy:demo']);

    // Start local server for demo
    grunt.registerTask('s', ['dist-demo', 'connect']);

    // Default task(s).
    grunt.registerTask('default', ['dist-demo']);

};<|endoftext|>


<commit_before>/* eslint-env node */
/* eslint no-console: "off" */
/* eslint quotes: ["error", "single"] */

const path   = require('path');
const fs     = require('fs');
const semver = require('semver');
const webpack = require('webpack');
const TerserPlugin = require('terser-webpack-plugin');

//require('webpack-load-plugins')();

const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), {encoding: 'utf8'}));
const verDir  = /^(\d+\.)/.exec(pkg.version)[1] + 'x';

function getLicense(pkg) {
  return `@license twgl.js ${pkg.version} Copyright (c) 2015, Gregg Tavares All Rights Reserved.
Available via the MIT license.
see: http://github.com/greggman/twgl.js for details`;
}

const replaceHandlers = {};
function registerReplaceHandler(keyword, handler) {  // eslint-disable-line
  replaceHandlers[keyword] = handler;
}

/**
 * Replace %(id)s in strings with values in objects(s)
 *
 * Given a string like `"Hello %(name)s from %(user.country)s"`
 * and an object like `{name:"Joe",user:{country:"USA"}}` would
 * return `"Hello Joe from USA"`.
 *
 * @param {string} str string to do replacements in
 * @param {Object|Object[]} params one or more objects.
 * @returns {string} string with replaced parts
 */
const replaceParams = (function() {
  const replaceParamsRE = /%\(([^)]+)\)s/g;

  return function(str, params) {
    if (!params.length) {
      params = [params];
    }

    return str.replace(replaceParamsRE, function(match, key) {
      const colonNdx = key.indexOf(':');
      if (colonNdx >= 0) {
        /*
        try {
          const args = hanson.parse("{" + key + "}");
          const handlerName = Object.keys(args)[0];
          const handler = replaceHandlers[handlerName];
          if (handler) {
            return handler(args[handlerName]);
          }
          console.error("unknown substition handler: " + handlerName);
        } catch (e) {
          console.error(e);
          console.error("bad substitution: %(" + key + ")s");
        }
        */
        throw new Error('unsupported');
      } else {
        // handle normal substitutions.
        const keys = key.split('.');
        for (let ii = 0; ii < params.length; ++ii) {
          let obj = params[ii];
          for (let jj = 0; jj < keys.length; ++jj) {
            const key = keys[jj];
            obj = obj[key];
            if (obj === undefined) {
              break;
            }
          }
          if (obj !== undefined) {
            return obj;
          }
        }
      }
      console.error('unknown key: ' + key);
      return '%(' + key + ')s';
    });
  };
}());

module.exports = function(grunt) {

  require('load-grunt-tasks')(grunt);

  const srcFiles = [
    'src/twgl.js',
    'src/attributes.js',
    'src/draw.js',
    'src/framebuffers.js',
    'src/programs.js',
    'src/textures.js',
    'src/typedarrays.js',
    'src/utils.js',
    'src/vertex-arrays.js',
  ];

  const extraFiles = [
    'src/v3.js',
    'src/m4.js',
    'src/primitives.js',
  ];

  const fullFiles = srcFiles.concat(extraFiles);
  const docsFiles = fullFiles.concat('README.md');

  const idRegex = /^(colorRenderable|textureFilterable|bytesPerElement|numColorComponents|textureFormat)$/;

  const noIdeaWhatThisIs = {};
  /*
  const noIdeaWhatThisIs = {
    loaders: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
        query: {
          presets: ['@babel/preset-env'],
          plugins: [
            ['@babel/plugin-transform-modules-commonjs', {loose: true}],
          ],
        },
      },
    ],
  };
  */

  const optimization = {
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          mangle: {
            properties: {
              keep_quoted: true,
              regex: idRegex,
            },
          },
        },
      }),
    ],
  };

  grunt.initConfig({
    jsdoc: {
      docs: {
        src: docsFiles,
        options: {
          destination: 'docs',
          configure: 'build/jsdoc.conf.json',
          template: './node_modules/minami',
          outputSourceFiles: false,
        },
      },
      ts: {
        src: fullFiles,
        options: {
          destination: `dist/${verDir}`,
          configure: 'build/jsdoc.conf.json',
          template: './node_modules/tsd-jsdoc/dist',
          outputSourceFiles: false,
        },
      },
    },
    webpack: {
      full: {
        entry: './src/twgl-full.js',
        mode: 'development',
        devtool: 'source-map',
        plugins: [
          new webpack.BannerPlugin(getLicense(pkg)),
        ],
        module: noIdeaWhatThisIs,
        output: {
          path: path.join(__dirname, `dist/${verDir}`),
          filename: 'twgl-full.js',
          library: 'twgl',
          libraryTarget: 'umd',
          globalObject: 'typeof self !== \'undefined\' ? self : this',
        },
      },
      base: {
        entry: './src/twgl-base.js',
        mode: 'development',
        devtool: 'source-map',
        plugins: [
          new webpack.BannerPlugin(getLicense(pkg)),
        ],
        module: noIdeaWhatThisIs,
        output: {
          path: path.join(__dirname, `dist/${verDir}`),
          filename: 'twgl.js',
          library: 'twgl',
          libraryTarget: 'umd',
          globalObject: 'typeof self !== \'undefined\' ? self : this',
        },
      },
      fullMin: {
        entry: './src/twgl-full.js',
        mode: 'production',
        plugins: [
          new webpack.BannerPlugin(getLicense(pkg)),
        ],
        optimization,
        module: noIdeaWhatThisIs,
        output: {
          path: path.join(__dirname, `dist/${verDir}`),
          filename: 'twgl-full.min.js',
          library: 'twgl',
          libraryTarget: 'umd',
          globalObject: 'typeof self !== \'undefined\' ? self : this',
        },
      },
      baseMin: {
        entry: './src/twgl-base.js',
        mode: 'production',
        plugins: [
          new webpack.BannerPlugin(getLicense(pkg)),
        ],
        optimization,
        module: noIdeaWhatThisIs,
        output: {
          path: path.join(__dirname, `dist/${verDir}`),
          filename: 'twgl.min.js',
          library: 'twgl',
          libraryTarget: 'umd',
          globalObject: 'typeof self !== \'undefined\' ? self : this',
        },
      },
    },
    eslint: {
      lib: {
        src: [
          'src/*',
        ],
        options: {
          //configFile: 'build/conf/eslint.json',
          //rulesdir: ['build/rules'],
        },
      },
      examples: {
        src: [
          'resources/js',
          'examples/*.html',
          'examples/js',
        ],
        options: {
          //configFile: 'build/conf/eslint-docs.json',
          //rulesdir: ['build/rules'],
        },
      },
    },
    copy: {
      twgl: {
        src: `dist/${verDir}/twgl.js`,
        dest: `npm/base/dist/${verDir}/twgl.js`,
      },
      readme: {
        src: 'README.md',
        dest: 'npm/base/README.md',
      },
    },
    browserify: {
      example: {
        files: {
          'examples/js/browserified-example.js': ['examples/js/browserify-example.js'],
        },
      },
    },
    clean: {
      dist: [ `dist/${verDir}` ],
      docs: [ 'docs' ],
    },
    ts: {
      example: {
        src: ['examples/*.ts'],
        options: {
          module: 'umd',
        },
      },
    },
  });

  grunt.registerTask('makeindex', function() {
    const marked  = require('marked');
    const fs      = require('fs');
    marked.setOptions({ rawHtml: true });
    const html = marked(fs.readFileSync('README.md', {encoding: 'utf8'}));
    const template = fs.readFileSync('build/templates/index.template', {encoding: 'utf8'});
    let content = replaceParams(template, {
      content: html,
      license: getLicense(pkg),
      srcFileName: 'README.md',
      title: 'TWGL.js, a tiny WebGL helper library',
      version: pkg.version,
    });
    content = content.replace(/href="http:\/\/twgljs.org\//g, 'href="/');
    fs.writeFileSync('index.html', content);
  });

  function getHeaderVersion(filename) {
    const twglVersionRE = / (\d+\.\d+\.\d+) /;
    return twglVersionRE.exec(fs.readFileSync(filename, {encoding: 'utf8'}))[1];
  }

  function getPackageVersion(filename) {
    return JSON.parse(fs.readFileSync(filename, {encoding: 'utf8'})).version;
  }

  function bump(type) {
    pkg.version = semver.inc(pkg.version, type);
    fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2));
    const filename = 'bower.json';
    const p = JSON.parse(fs.readFileSync(filename, {encoding: 'utf8'}));
    p.version = pkg.version;
    fs.writeFileSync(filename, JSON.stringify(p, null, 2));
    grunt.config.set('webpack.full.plugins.0', new webpack.BannerPlugin(getLicense(pkg)));
    grunt.config.set('webpack.base.plugins.0', new webpack.BannerPlugin(getLicense(pkg)));
    grunt.config.set('webpack.fullMin.plugins.0', new webpack.BannerPlugin(getLicense(pkg)));
    grunt.config.set('webpack.baseMin.plugins.0', new webpack.BannerPlugin(getLicense(pkg)));
  }

  grunt.registerTask('bumppatchimpl', function() {
    bump('patch');
  });
  grunt.registerTask('bumpminorimpl', function() {
    bump('minor');
  });
  grunt.registerTask('bumpmajorimpl', function() {
    bump('major');
  });

  grunt.registerTask('versioncheck', function() {
    let good = true;
    [
      { filename: `dist/${verDir}/twgl.js`,          fn: getHeaderVersion, },
      { filename: `dist/${verDir}/twgl-full.js`,     fn: getHeaderVersion, },
      { filename: `dist/${verDir}/twgl.min.js`,      fn: getHeaderVersion, },
      { filename: `dist/${verDir}/twgl-full.min.js`, fn: getHeaderVersion, },
      { filename: 'package.json',          fn: getPackageVersion, },
    ].forEach(function(file) {
      const version = file.fn(file.filename);
      if (version !== pkg.version) {
        good = false;
        grunt.log.error('version mis-match in:', file.filename, ' Expected:', pkg.version, ' Actual:', version);
      }
    });
    return good;
  });

  grunt.registerTask('npmpackage', function() {
    const p = JSON.parse(fs.readFileSync('package.json', {encoding: 'utf8'}));
    p.name = 'twgl-base.js';
    p.scripts = {};
    p.devDependencies = {};
    p.main = `dist/${verDir}/twgl.js`;
    p.files = [ `dist/${  verDir}/twgl.js` ];
    fs.writeFileSync('npm/base/package.json', JSON.stringify(p, null, 2), {encoding: 'utf8'});
  });

  grunt.registerTask('tsmunge', function() {
    // Fix up syntax and content issues with the auto-generated
    // TypeScript definitions.
    let content = fs.readFileSync(`dist/${verDir}/types.d.ts`, {encoding: 'utf8'});
    // Remove docstrings (Declarations do not by convention include these)
    content = content.replace(/\/\*\*[\s\S]*?\*\/\s*/g, '');
    // Docs use "?" to represent an arbitrary type; TS uses "any"
    content = content.replace(/\]: \?/g, ']: any');
    // Docs use "constructor"; TS expects something more like "Function"
    content = content.replace(/: constructor/g, ': Function');
    // What docs call an "augmentedTypedArray" is technically an "ArrayBufferView"
    // albeit with a patched-in "push" method.
    content = content.replace(/\bAugmentedTypedArray\b/g, 'ArrayBufferView');
    // Remove every instance of "module:twgl" and "module:twgl/whatever"
    // Except for "module:twgl.(m4|v3|primitives)" which become just "m4.", etc.
    content = content.replace(/module:twgl(\/(m4|v3|primitives))\./g, '$2.');
    content = content.replace(/module:twgl(\/\w+)?\./g, '');
    // Replace "function", "type" declarations with "export function", "export type"
    content = content.replace(/^(\s*)(function|type) /mg, '$1export $2 ');
    // Break the file down into a list of modules
    const modules = content.match(/^declare module twgl(\/(\w+))? \{[\s\S]*?^\}/mg);
    // Split into core modules and extra (only in twgl-full) modules
    const coreModules = modules.filter(
      (code) => !code.match(/^declare module twgl\/(m4|v3|primitives)/)
    );
    const extraModules = modules.filter(
      (code) => code.match(/^declare module twgl\/(m4|v3|primitives)/)
    );
    // Build code for the core twgl.js output
    const coreContent = coreModules.map((code) => {
      // Get rid of "declare module twgl/whatever" scope
      code = code.replace(/^declare module twgl(\/\w+)? \{([\s\S]*?)^\}/mg, '$2');
      // De-indent the contents of that scope
      code = code.replace(/^ {4}/mg, '');
      // All done
      return code;
    }).join('\n');
    // Build additional code for the extended twgl-full.js output
    const extraContent = extraModules.map((code) => {
      // Fix "declare module twgl/whatever" statements
      return code.replace(/^declare module twgl(\/(\w+))? \{/m,
        'declare module $2 {'
      );
    }).join('\n');
    // Write twgl-full declarations to destination file
    const fullContent = [coreContent, extraContent].join('\n');
    fs.writeFileSync(`dist/${verDir}/twgl-full.d.ts`, fullContent);
    // Write core declarations to destination file
    fs.writeFileSync(`dist/${verDir}/twgl.d.ts`, coreContent);
    // Remove the auto-generated input file
    fs.unlinkSync(`dist/${verDir}/types.d.ts`);
  });

  grunt.registerTask('docs', [
      'eslint:examples',
      'clean:docs',
      'jsdoc:docs',
      'makeindex',
  ]);
  grunt.registerTask('buildts', [
      'jsdoc:ts',
      'tsmunge',
  ]);
  grunt.registerTask('build', [
      'eslint:lib',
      'clean:dist',
      'webpack',
      'buildts',
      'ts',
      'copy',
      'npmpackage',
  ]);
  grunt.registerTask('bumppatch', [
      'eslint:lib',
      'eslint:examples',
      'bumppatchimpl',
      'build',
      'browserify',
      'docs',
  ]);
  grunt.registerTask('bumpminor', [
      'eslint:lib',
      'eslint:examples',
      'bumpminorimpl',
      'build',
      'browserify',
      'docs',
  ]);
  grunt.registerTask('bumpmajor', [
      'eslint:lib',
      'eslint:examples',
      'bumpmajorimpl',
      'build',
      'browserify',
      'docs',
  ]);
  grunt.registerTask('default', 'build');
};

<commit_msg>fix building for old browsers<commit_after>/* eslint-env node */
/* eslint no-console: "off" */
/* eslint quotes: ["error", "single"] */

const path   = require('path');
const fs     = require('fs');
const semver = require('semver');
const webpack = require('webpack');
const TerserPlugin = require('terser-webpack-plugin');

//require('webpack-load-plugins')();

const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), {encoding: 'utf8'}));
const verDir  = /^(\d+\.)/.exec(pkg.version)[1] + 'x';

function getLicense(pkg) {
  return `@license twgl.js ${pkg.version} Copyright (c) 2015, Gregg Tavares All Rights Reserved.
Available via the MIT license.
see: http://github.com/greggman/twgl.js for details`;
}

const replaceHandlers = {};
function registerReplaceHandler(keyword, handler) {  // eslint-disable-line
  replaceHandlers[keyword] = handler;
}

/**
 * Replace %(id)s in strings with values in objects(s)
 *
 * Given a string like `"Hello %(name)s from %(user.country)s"`
 * and an object like `{name:"Joe",user:{country:"USA"}}` would
 * return `"Hello Joe from USA"`.
 *
 * @param {string} str string to do replacements in
 * @param {Object|Object[]} params one or more objects.
 * @returns {string} string with replaced parts
 */
const replaceParams = (function() {
  const replaceParamsRE = /%\(([^)]+)\)s/g;

  return function(str, params) {
    if (!params.length) {
      params = [params];
    }

    return str.replace(replaceParamsRE, function(match, key) {
      const colonNdx = key.indexOf(':');
      if (colonNdx >= 0) {
        /*
        try {
          const args = hanson.parse("{" + key + "}");
          const handlerName = Object.keys(args)[0];
          const handler = replaceHandlers[handlerName];
          if (handler) {
            return handler(args[handlerName]);
          }
          console.error("unknown substition handler: " + handlerName);
        } catch (e) {
          console.error(e);
          console.error("bad substitution: %(" + key + ")s");
        }
        */
        throw new Error('unsupported');
      } else {
        // handle normal substitutions.
        const keys = key.split('.');
        for (let ii = 0; ii < params.length; ++ii) {
          let obj = params[ii];
          for (let jj = 0; jj < keys.length; ++jj) {
            const key = keys[jj];
            obj = obj[key];
            if (obj === undefined) {
              break;
            }
          }
          if (obj !== undefined) {
            return obj;
          }
        }
      }
      console.error('unknown key: ' + key);
      return '%(' + key + ')s';
    });
  };
}());

module.exports = function(grunt) {

  require('load-grunt-tasks')(grunt);

  const srcFiles = [
    'src/twgl.js',
    'src/attributes.js',
    'src/draw.js',
    'src/framebuffers.js',
    'src/programs.js',
    'src/textures.js',
    'src/typedarrays.js',
    'src/utils.js',
    'src/vertex-arrays.js',
  ];

  const extraFiles = [
    'src/v3.js',
    'src/m4.js',
    'src/primitives.js',
  ];

  const fullFiles = srcFiles.concat(extraFiles);
  const docsFiles = fullFiles.concat('README.md');

  const idRegex = /^(colorRenderable|textureFilterable|bytesPerElement|numColorComponents|textureFormat)$/;

  const babelOptionsForWebpack = {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: "babel-loader",
        query: {
          presets: ['@babel/preset-env'],
          plugins: [
            ['@babel/plugin-transform-modules-commonjs', {loose: true}],
          ],
        }
      },
    ],
  };

  const optimization = {
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          mangle: {
            properties: {
              keep_quoted: true,
              regex: idRegex,
            },
          },
        },
      }),
    ],
  };

  grunt.initConfig({
    jsdoc: {
      docs: {
        src: docsFiles,
        options: {
          destination: 'docs',
          configure: 'build/jsdoc.conf.json',
          template: './node_modules/minami',
          outputSourceFiles: false,
        },
      },
      ts: {
        src: fullFiles,
        options: {
          destination: `dist/${verDir}`,
          configure: 'build/jsdoc.conf.json',
          template: './node_modules/tsd-jsdoc/dist',
          outputSourceFiles: false,
        },
      },
    },
    webpack: {
      full: {
        entry: './src/twgl-full.js',
        mode: 'development',
        devtool: 'source-map',
        plugins: [
          new webpack.BannerPlugin(getLicense(pkg)),
        ],
        module: babelOptionsForWebpack,
        output: {
          path: path.join(__dirname, `dist/${verDir}`),
          filename: 'twgl-full.js',
          library: 'twgl',
          libraryTarget: 'umd',
          globalObject: 'typeof self !== \'undefined\' ? self : this',
        },
      },
      base: {
        entry: './src/twgl-base.js',
        mode: 'development',
        devtool: 'source-map',
        plugins: [
          new webpack.BannerPlugin(getLicense(pkg)),
        ],
        module: babelOptionsForWebpack,
        output: {
          path: path.join(__dirname, `dist/${verDir}`),
          filename: 'twgl.js',
          library: 'twgl',
          libraryTarget: 'umd',
          globalObject: 'typeof self !== \'undefined\' ? self : this',
        },
      },
      fullMin: {
        entry: './src/twgl-full.js',
        mode: 'production',
        plugins: [
          new webpack.BannerPlugin(getLicense(pkg)),
        ],
        optimization,
        module: babelOptionsForWebpack,
        output: {
          path: path.join(__dirname, `dist/${verDir}`),
          filename: 'twgl-full.min.js',
          library: 'twgl',
          libraryTarget: 'umd',
          globalObject: 'typeof self !== \'undefined\' ? self : this',
        },
      },
      baseMin: {
        entry: './src/twgl-base.js',
        mode: 'production',
        plugins: [
          new webpack.BannerPlugin(getLicense(pkg)),
        ],
        optimization,
        module: babelOptionsForWebpack,
        output: {
          path: path.join(__dirname, `dist/${verDir}`),
          filename: 'twgl.min.js',
          library: 'twgl',
          libraryTarget: 'umd',
          globalObject: 'typeof self !== \'undefined\' ? self : this',
        },
      },
    },
    eslint: {
      lib: {
        src: [
          'src/*',
        ],
        options: {
          //configFile: 'build/conf/eslint.json',
          //rulesdir: ['build/rules'],
        },
      },
      examples: {
        src: [
          'resources/js',
          'examples/*.html',
          'examples/js',
        ],
        options: {
          //configFile: 'build/conf/eslint-docs.json',
          //rulesdir: ['build/rules'],
        },
      },
    },
    copy: {
      twgl: {
        src: `dist/${verDir}/twgl.js`,
        dest: `npm/base/dist/${verDir}/twgl.js`,
      },
      readme: {
        src: 'README.md',
        dest: 'npm/base/README.md',
      },
    },
    browserify: {
      example: {
        files: {
          'examples/js/browserified-example.js': ['examples/js/browserify-example.js'],
        },
      },
    },
    clean: {
      dist: [ `dist/${verDir}` ],
      docs: [ 'docs' ],
    },
    ts: {
      example: {
        src: ['examples/*.ts'],
        options: {
          module: 'umd',
        },
      },
    },
  });

  grunt.registerTask('makeindex', function() {
    const marked  = require('marked');
    const fs      = require('fs');
    marked.setOptions({ rawHtml: true });
    const html = marked(fs.readFileSync('README.md', {encoding: 'utf8'}));
    const template = fs.readFileSync('build/templates/index.template', {encoding: 'utf8'});
    let content = replaceParams(template, {
      content: html,
      license: getLicense(pkg),
      srcFileName: 'README.md',
      title: 'TWGL.js, a tiny WebGL helper library',
      version: pkg.version,
    });
    content = content.replace(/href="http:\/\/twgljs.org\//g, 'href="/');
    fs.writeFileSync('index.html', content);
  });

  function getHeaderVersion(filename) {
    const twglVersionRE = / (\d+\.\d+\.\d+) /;
    return twglVersionRE.exec(fs.readFileSync(filename, {encoding: 'utf8'}))[1];
  }

  function getPackageVersion(filename) {
    return JSON.parse(fs.readFileSync(filename, {encoding: 'utf8'})).version;
  }

  function bump(type) {
    pkg.version = semver.inc(pkg.version, type);
    fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2));
    const filename = 'bower.json';
    const p = JSON.parse(fs.readFileSync(filename, {encoding: 'utf8'}));
    p.version = pkg.version;
    fs.writeFileSync(filename, JSON.stringify(p, null, 2));
    grunt.config.set('webpack.full.plugins.0', new webpack.BannerPlugin(getLicense(pkg)));
    grunt.config.set('webpack.base.plugins.0', new webpack.BannerPlugin(getLicense(pkg)));
    grunt.config.set('webpack.fullMin.plugins.0', new webpack.BannerPlugin(getLicense(pkg)));
    grunt.config.set('webpack.baseMin.plugins.0', new webpack.BannerPlugin(getLicense(pkg)));
  }

  grunt.registerTask('bumppatchimpl', function() {
    bump('patch');
  });
  grunt.registerTask('bumpminorimpl', function() {
    bump('minor');
  });
  grunt.registerTask('bumpmajorimpl', function() {
    bump('major');
  });

  grunt.registerTask('versioncheck', function() {
    let good = true;
    [
      { filename: `dist/${verDir}/twgl.js`,          fn: getHeaderVersion, },
      { filename: `dist/${verDir}/twgl-full.js`,     fn: getHeaderVersion, },
      { filename: `dist/${verDir}/twgl.min.js`,      fn: getHeaderVersion, },
      { filename: `dist/${verDir}/twgl-full.min.js`, fn: getHeaderVersion, },
      { filename: 'package.json',          fn: getPackageVersion, },
    ].forEach(function(file) {
      const version = file.fn(file.filename);
      if (version !== pkg.version) {
        good = false;
        grunt.log.error('version mis-match in:', file.filename, ' Expected:', pkg.version, ' Actual:', version);
      }
    });
    return good;
  });

  grunt.registerTask('npmpackage', function() {
    const p = JSON.parse(fs.readFileSync('package.json', {encoding: 'utf8'}));
    p.name = 'twgl-base.js';
    p.scripts = {};
    p.devDependencies = {};
    p.main = `dist/${verDir}/twgl.js`;
    p.files = [ `dist/${  verDir}/twgl.js` ];
    fs.writeFileSync('npm/base/package.json', JSON.stringify(p, null, 2), {encoding: 'utf8'});
  });

  grunt.registerTask('tsmunge', function() {
    // Fix up syntax and content issues with the auto-generated
    // TypeScript definitions.
    let content = fs.readFileSync(`dist/${verDir}/types.d.ts`, {encoding: 'utf8'});
    // Remove docstrings (Declarations do not by convention include these)
    content = content.replace(/\/\*\*[\s\S]*?\*\/\s*/g, '');
    // Docs use "?" to represent an arbitrary type; TS uses "any"
    content = content.replace(/\]: \?/g, ']: any');
    // Docs use "constructor"; TS expects something more like "Function"
    content = content.replace(/: constructor/g, ': Function');
    // What docs call an "augmentedTypedArray" is technically an "ArrayBufferView"
    // albeit with a patched-in "push" method.
    content = content.replace(/\bAugmentedTypedArray\b/g, 'ArrayBufferView');
    // Remove every instance of "module:twgl" and "module:twgl/whatever"
    // Except for "module:twgl.(m4|v3|primitives)" which become just "m4.", etc.
    content = content.replace(/module:twgl(\/(m4|v3|primitives))\./g, '$2.');
    content = content.replace(/module:twgl(\/\w+)?\./g, '');
    // Replace "function", "type" declarations with "export function", "export type"
    content = content.replace(/^(\s*)(function|type) /mg, '$1export $2 ');
    // Break the file down into a list of modules
    const modules = content.match(/^declare module twgl(\/(\w+))? \{[\s\S]*?^\}/mg);
    // Split into core modules and extra (only in twgl-full) modules
    const coreModules = modules.filter(
      (code) => !code.match(/^declare module twgl\/(m4|v3|primitives)/)
    );
    const extraModules = modules.filter(
      (code) => code.match(/^declare module twgl\/(m4|v3|primitives)/)
    );
    // Build code for the core twgl.js output
    const coreContent = coreModules.map((code) => {
      // Get rid of "declare module twgl/whatever" scope
      code = code.replace(/^declare module twgl(\/\w+)? \{([\s\S]*?)^\}/mg, '$2');
      // De-indent the contents of that scope
      code = code.replace(/^ {4}/mg, '');
      // All done
      return code;
    }).join('\n');
    // Build additional code for the extended twgl-full.js output
    const extraContent = extraModules.map((code) => {
      // Fix "declare module twgl/whatever" statements
      return code.replace(/^declare module twgl(\/(\w+))? \{/m,
        'declare module $2 {'
      );
    }).join('\n');
    // Write twgl-full declarations to destination file
    const fullContent = [coreContent, extraContent].join('\n');
    fs.writeFileSync(`dist/${verDir}/twgl-full.d.ts`, fullContent);
    // Write core declarations to destination file
    fs.writeFileSync(`dist/${verDir}/twgl.d.ts`, coreContent);
    // Remove the auto-generated input file
    fs.unlinkSync(`dist/${verDir}/types.d.ts`);
  });

  grunt.registerTask('docs', [
      'eslint:examples',
      'clean:docs',
      'jsdoc:docs',
      'makeindex',
  ]);
  grunt.registerTask('buildts', [
      'jsdoc:ts',
      'tsmunge',
  ]);
  grunt.registerTask('build', [
      'eslint:lib',
      'clean:dist',
      'webpack',
      'buildts',
      'ts',
      'copy',
      'npmpackage',
  ]);
  grunt.registerTask('bumppatch', [
      'eslint:lib',
      'eslint:examples',
      'bumppatchimpl',
      'build',
      'browserify',
      'docs',
  ]);
  grunt.registerTask('bumpminor', [
      'eslint:lib',
      'eslint:examples',
      'bumpminorimpl',
      'build',
      'browserify',
      'docs',
  ]);
  grunt.registerTask('bumpmajor', [
      'eslint:lib',
      'eslint:examples',
      'bumpmajorimpl',
      'build',
      'browserify',
      'docs',
  ]);
  grunt.registerTask('default', 'build');
};

<|endoftext|>