├── .npmignore ├── test └── unit │ └── .gitkeep ├── index.js ├── lib ├── index.js ├── Tileset.js └── Tilemap.js ├── .travis.yml ├── .editorconfig ├── .gitignore ├── gulpfile.js ├── package.json ├── README.md ├── bin └── image2tmx.js └── .jshintrc /.npmignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/unit/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/index'); 2 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | Tileset: require('./Tileset'), 3 | Tilemap: require('./Tilemap') 4 | }; 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | 5 | branches: 6 | only: 7 | - master 8 | 9 | install: 10 | - npm install 11 | 12 | cache: 13 | directories: 14 | - node_modules 15 | 16 | script: 17 | - npm run-script testci 18 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Unix-style newlines with a newline ending every file 2 | [*] 3 | end_of_line = lf 4 | insert_final_newline = true 5 | trim_trailing_whitespace = true 6 | indent_style = space 7 | indent_size = 4 8 | 9 | [*.md] 10 | trim_trailing_whitespace = false 11 | 12 | [{package.json,.travis.yml}] 13 | indent_size = 2 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # sublime text 2 files 2 | *.sublime-* 3 | *.*~*.TMP 4 | 5 | # temp files 6 | .DS_Store 7 | Thumbs.db 8 | Desktop.ini 9 | npm-debug.log 10 | 11 | # vim swap files 12 | *.sw* 13 | 14 | # emacs temp files 15 | *~ 16 | \#*# 17 | 18 | # project ignores 19 | build/ 20 | node_modules/ 21 | test/result/ 22 | !.gitkeep 23 | *__temp 24 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | mocha = require('gulp-mocha'), 3 | jshint = require('gulp-jshint'); 4 | 5 | /***** 6 | * JSHint task, lints the lib and test *.js files. 7 | *****/ 8 | gulp.task('jshint', function () { 9 | return gulp.src(['./lib/**/*.js', './test/**/*.js']) 10 | .pipe(jshint()) 11 | .pipe(jshint.reporter('default')); 12 | }); 13 | 14 | /***** 15 | * Test task, runs mocha against unit test files. 16 | *****/ 17 | gulp.task('test', function () { 18 | return gulp.src('./test/unit/**/*.test.js', { read: false }) 19 | .pipe(mocha({ 20 | ui: 'bdd', 21 | reporter: 'spec' 22 | })); 23 | }); 24 | 25 | /***** 26 | * Default task, runs jshint and test tasks. 27 | *****/ 28 | gulp.task('default', ['jshint', 'test']); 29 | 30 | /***** 31 | * CI test task, runs jshint and test tasks. 32 | *****/ 33 | gulp.task('testci', ['jshint', 'test']); 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "image2tmx", 3 | "version": "1.1.0", 4 | "description": "Converts images into tmx maps", 5 | "author": "Chad Engler ", 6 | "license": "MIT", 7 | "preferGlobal": true, 8 | "main": "index.js", 9 | "bin": { 10 | "image2tmx": "./bin/image2tmx.js" 11 | }, 12 | "scripts": { 13 | "test": "gulp test", 14 | "testci": "gulp testci" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/englercj/image2tmx.git" 19 | }, 20 | "bugs": { 21 | "url": "https://github.com/englercj/image2tmx/issues" 22 | }, 23 | "homepage": "https://github.com/englercj/image2tmx", 24 | "devDependencies": { 25 | "gulp": "^3.8.7", 26 | "gulp-mocha": "^1.0.0", 27 | "gulp-jshint": "^1.7.1", 28 | "chai": "^1.9.1" 29 | }, 30 | "dependencies": { 31 | "async": "^0.9.0", 32 | "glob": "^4.0.5", 33 | "pngjs": "^0.4.0", 34 | "yargs": "^1.3.1" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # image2tmx 2 | 3 | Converts images into .tmx maps for use with the [Tiled Editor][0]. 4 | 5 | [0]: http://mapeditor.org/ 6 | 7 | ## License 8 | 9 | The MIT License (MIT) 10 | 11 | Copyright (c) 2014 Chad Engler 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a copy 14 | of this software and associated documentation files (the "Software"), to deal 15 | in the Software without restriction, including without limitation the rights 16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | copies of the Software, and to permit persons to whom the Software is 18 | furnished to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in 21 | all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | THE SOFTWARE. 30 | -------------------------------------------------------------------------------- /lib/Tileset.js: -------------------------------------------------------------------------------- 1 | var events = require('events'), 2 | fs = require('fs'), 3 | util = require('util'), 4 | zlib = require('zlib'), 5 | Buffer = require('buffer').Buffer, 6 | PNG = require('pngjs').PNG; 7 | 8 | /** 9 | * @class Tileset 10 | * @constructor 11 | * @param imageData {PNG|Buffer} The image that should be split into a tileset (or a tileset image itself) 12 | * @param tileWidth {Number} The width of a tile in the tileset 13 | * @param tileHeight {Number} The height of a tile in the tileset 14 | * @param [powerOfTwo=true] {Boolean} Should the resulting image have deminsions that are a power of two 15 | */ 16 | function Tileset(tileWidth, tileHeight, powerOfTwo) { 17 | events.EventEmitter.call(this); 18 | 19 | this.tileWidth = tileWidth || 16; 20 | this.tileHeight = tileHeight || 16; 21 | 22 | this.gridWidth = 0; 23 | this.gridHeight = 0; 24 | 25 | this.tmp = new PNG({ 26 | width: this.tileWidth, 27 | height: this.tileHeight 28 | }); 29 | 30 | // this.black = new PNG({ 31 | // width: this.tileWidth, 32 | // height: this.tileHeight 33 | // }); 34 | 35 | // for (var y = 0; y < this.tileHeight; ++y) { 36 | // for (var x = 0; x < this.tileWidth; ++x) { 37 | // var index = (this.tileWidth * y + x) << 2; 38 | // this.black.data[index] = 0; 39 | // this.black.data[index+1] = 0; 40 | // this.black.data[index+2] = 0; 41 | // this.black.data[index+3] = 255; 42 | // } 43 | // } 44 | 45 | this.tileIdMap = {}; 46 | this.tiles = []; 47 | 48 | this.ready = false; 49 | 50 | this.pot = powerOfTwo != null ? powerOfTwo : true; 51 | this.outSquare = 0; 52 | this.outWidth = 0; 53 | this.outHeight = 0; 54 | 55 | this.setMaxListeners(Infinity); 56 | }; 57 | 58 | util.inherits(Tileset, events.EventEmitter); 59 | 60 | module.exports = Tileset; 61 | 62 | /** 63 | * @method writeImage 64 | * @param path {String} The path to write to 65 | * @param [callback] {Function} A callback function when the write completes 66 | * @return {PNG} The PNG instance that is being written 67 | */ 68 | Tileset.prototype.writeImage = function (path, cb) { 69 | var outPng = new PNG({ 70 | width: this.outWidth, 71 | height: this.outHeight, 72 | filterType: 1, 73 | deflateLevel: zlib.Z_BEST_COMPRESSION, 74 | deflateStrategy: zlib.Z_FILTERED 75 | }), 76 | sq = this.outSquare; 77 | 78 | for(var y = 0; y < sq; ++y) { 79 | for(var x = 0; x < sq; ++x) { 80 | var idx = (sq * y) + x; 81 | 82 | if (idx < this.tiles.length) { 83 | this.tiles[idx].bitblt(outPng, 0, 0, this.tileWidth, this.tileHeight, x * this.tileWidth, y * this.tileHeight); 84 | } else { 85 | break; 86 | // this.black.bitblt(outPng, 0, 0, this.tileWidth, this.tileHeight, x * this.tileWidth, y * this.tileHeight); 87 | } 88 | } 89 | } 90 | 91 | return outPng.pack().pipe(fs.createWriteStream(path)); 92 | }; 93 | 94 | Tileset.prototype.append = function (imageData) { 95 | if (imageData instanceof PNG) { 96 | this._appendTileset(null, imageData); 97 | } else { 98 | this.png = new PNG(); 99 | 100 | var self = this; 101 | this.png.parse(imageData, this._appendTileset.bind(this)); 102 | } 103 | 104 | return this; 105 | }; 106 | 107 | Tileset.prototype._appendTileset = function (err, png) { 108 | if (err) return this.emit('error', err); 109 | 110 | this.gridWidth = png.width / this.tileWidth; 111 | this.gridHeight = png.height / this.tileHeight; 112 | 113 | var key = null, 114 | tile = null, 115 | idx = 0; 116 | 117 | for (var y = 0; y < this.gridHeight; ++y) { 118 | for (var x = 0; x < this.gridWidth; ++x) { 119 | png.bitblt(this.tmp, x * this.tileWidth, y * this.tileHeight, this.tileWidth, this.tileHeight, 0, 0); 120 | key = this.tmp.data.toString('base64'); 121 | 122 | if (!this.tileIdMap[key]) { 123 | tile = new PNG({ width: this.tileWidth, height: this.tileHeight }); 124 | this.tmp.bitblt(tile, 0, 0, this.tileWidth, this.tileHeight, 0, 0); 125 | 126 | this.tileIdMap[key] = this.tiles.push(tile); 127 | } 128 | } 129 | } 130 | 131 | var sq = Math.ceil(Math.sqrt(this.tiles.length)); 132 | 133 | if (this.pot) { 134 | sq = Math.pow(2, Math.round(Math.log(sq) / Math.log(2))); 135 | } 136 | 137 | this.outSquare = sq; 138 | this.outWidth = sq * this.tileWidth; 139 | this.outHeight = sq * this.tileHeight; 140 | 141 | this.ready = true; 142 | setImmediate(function () { 143 | this.emit('parsed'); 144 | }.bind(this)); 145 | }; 146 | -------------------------------------------------------------------------------- /lib/Tilemap.js: -------------------------------------------------------------------------------- 1 | var events = require('events'), 2 | fs = require('fs'), 3 | util = require('util'), 4 | zlib = require('zlib'), 5 | Buffer = require('buffer').Buffer, 6 | PNG = require('pngjs').PNG; 7 | 8 | /** 9 | * @class Tilemap 10 | * @constructor 11 | * @param tileset {Tileset} The tileset for this map 12 | * @param imageData {PNG|Buffer} The raw image data for this map 13 | */ 14 | function Tilemap(tileset, imageData) { 15 | events.EventEmitter.call(this); 16 | 17 | this.tileset = tileset; 18 | 19 | this.gridWidth = 0; 20 | this.gridHeight = 0; 21 | 22 | this.tmp = new PNG({ 23 | width: this.tileset.tileWidth, 24 | height: this.tileset.tileHeight 25 | }); 26 | 27 | this.ready = false; 28 | this.tilesetReady = false; 29 | this.imageReady = false; 30 | 31 | this.buffer = null 32 | 33 | if (tileset.ready) { 34 | this.tilesetReady = true; 35 | } 36 | 37 | if (imageData instanceof PNG) { 38 | this.png = imageData; 39 | this.imageReady = true; 40 | } else { 41 | this.png = new PNG(); 42 | this.png.parse(imageData, function () { 43 | this.imageReady = true; 44 | this._createTilemap(); 45 | }.bind(this)); 46 | } 47 | 48 | this._createTilemap(); 49 | }; 50 | 51 | util.inherits(Tilemap, events.EventEmitter); 52 | 53 | module.exports = Tilemap; 54 | 55 | /** 56 | * @method writeXml 57 | * @param path {String} The path to write to 58 | * @param path {String} The path to the tileset file created for this map 59 | * @param [format="gzip"] {String} The format of the output tilemap data. Can be: base64, gzip, or zlib 60 | * @param [callback] {Function} A callback function when the write completes 61 | */ 62 | Tilemap.prototype.writeXml = function (path, tilesetPath, format, cb) { 63 | var self = this; 64 | 65 | switch(format) { 66 | case 'gzip': 67 | // gzip 68 | zlib.gzip(this.buffer, function (err, zbuffer) { 69 | if (err) throw err; 70 | 71 | self._doXmlWrite(path, tilesetPath, zbuffer, 'gzip', cb); 72 | }); 73 | break; 74 | 75 | case 'zlib': 76 | // zlib 77 | zlib.deflate(this.buffer, function (err, zbuffer) { 78 | if (err) throw err; 79 | 80 | self._doXmlWrite(path, tilesetPath, zbuffer, 'zlib', cb); 81 | }); 82 | break; 83 | 84 | case 'base64': 85 | default: 86 | this._doXmlWrite(path, tilesetPath, this.buffer, null, cb); 87 | break; 88 | } 89 | }; 90 | 91 | Tilemap.prototype._doXmlWrite = function(path, tilesetPath, buff, comp, cb) { 92 | var xml = 93 | '\n' + 94 | '\n' + 95 | ' \n' + 96 | ' \n' + 97 | ' \n' + 98 | ' \n' + 99 | ' \n' + 100 | ' ' + buff.toString('base64') + '\n' + 101 | ' \n' + 102 | ' \n' + 103 | '\n'; 104 | 105 | 106 | fs.writeFile(path, xml, function (err) { 107 | if (err) throw err; 108 | 109 | if (cb) cb(); 110 | }); 111 | }; 112 | 113 | Tilemap.prototype._createTilemap = function () { 114 | if (!this.tilesetReady || !this.imageReady) { 115 | return; 116 | } 117 | 118 | this.gridWidth = this.png.width / this.tileset.tileWidth; 119 | this.gridHeight = this.png.height / this.tileset.tileHeight; 120 | 121 | // if tileset was passed a map image, it will create our buffer for us 122 | if (this.tileset.tilemapBuffer) { 123 | this.buffer = this.tileset.tilemapBuffer; 124 | } else { 125 | this.buffer = new Buffer(4 * this.gridWidth * this.gridHeight); 126 | 127 | var key = null, 128 | idx = 0, 129 | tile = 0; 130 | 131 | for (var y = 0; y < this.gridHeight; ++y) { 132 | for (var x = 0; x < this.gridWidth; ++x) { 133 | this.png.bitblt(this.tmp, x * this.tileset.tileWidth, y * this.tileset.tileHeight, this.tileset.tileWidth, this.tileset.tileHeight, 0, 0); 134 | key = this.tmp.data.toString('base64'); 135 | tile = this.tileset.tileIdMap[key]; 136 | 137 | if (tile !== undefined) { 138 | this.buffer.writeUInt32LE(tile, idx); 139 | 140 | idx += 4; 141 | } else { 142 | console.log('WARNING: Tile not found in tileset (' + tile + ')'); 143 | } 144 | } 145 | } 146 | } 147 | 148 | this.ready = true; 149 | setImmediate(function () { 150 | this.emit('parsed'); 151 | }.bind(this)); 152 | }; 153 | -------------------------------------------------------------------------------- /bin/image2tmx.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var glob = require('glob'), 4 | async = require('async'), 5 | yargs = require('yargs') 6 | .usage('Converts an image to a .tmx tilemap\nUsage: image2tmx [options] [tileheight] ') 7 | .example('image2tmx 16 ./image.png') 8 | .example('image2tmx 16 32 ./image.png') 9 | .example('image2tmx 16 "./{cave,dungeon}*.png"') 10 | .options('h', { 11 | alias: 'help', 12 | describe: 'Prints this help/usage information.' 13 | }) 14 | .options('f', { 15 | alias: 'format', 16 | describe: 'Defines the data format for the tilemap output. Can be base64, gzip, or zlib', 17 | default: 'gzip' 18 | }) 19 | .options('o', { 20 | alias: 'output-dir', 21 | describe: 'The output directory to put the tilemap and tileset' 22 | }) 23 | .options('s', { 24 | alias: 'tileset', 25 | describe: 'A tileset image to use instead of creating a new one' 26 | }) 27 | .options('c', { 28 | alias: 'common-tileset', 29 | describe: 'Use a single tileset for all the images we convert' 30 | }) 31 | .demand(2), 32 | argv = yargs.argv, 33 | tw = 0, 34 | th = 0, 35 | imgPath = null; 36 | 37 | function usage() { 38 | console.log(yargs.help()); 39 | process.exit(1); 40 | } 41 | 42 | // valid case of "image2tmx " 43 | if (argv._.length === 2 && typeof argv._[0] === 'number') { 44 | tw = th = argv._[0]; 45 | imgPath = argv._[1]; 46 | } 47 | // valid case of "image2tmx " 48 | else if (argv._.length === 3 && typeof argv._[0] === 'number' && typeof argv._[1] === 'number') { 49 | tw = argv._[0]; 50 | th = argv._[1]; 51 | imgPath = argv._[2]; 52 | } 53 | // unknown params 54 | else { 55 | usage(); 56 | } 57 | 58 | var reuseTileset = null, 59 | randName = require('crypto').randomBytes(4).toString('hex'), 60 | reuseTilesetPath = require('path').join(argv.outputDir || '.', randName + '.png'); 61 | 62 | glob(imgPath, function (err, files) { 63 | if (err) throw err; 64 | 65 | async.forEach( 66 | files, 67 | function (path, _cb) { 68 | convertImage(path, tw, th, _cb); 69 | }, 70 | function (err) { 71 | if (err) throw err; 72 | 73 | if (argv.commonTileset) { 74 | console.log('Writing common ', reuseTileset.outWidth, 'x', reuseTileset.outHeight, 'tileset, with', reuseTileset.tiles.length, 'tiles.'); 75 | reuseTileset.writeImage(reuseTilesetPath); 76 | } 77 | } 78 | ); 79 | }); 80 | 81 | function convertImage(imagePath, tileWidth, tileHeight, cb) { 82 | console.log('Parsing map.'); 83 | console.log('Tile Size:', tileWidth, 'x', tileHeight); 84 | console.log('Map Image:', imagePath); 85 | 86 | // If we get here, we have valid params that have been read. Lets start parsing! 87 | var fs = require('fs'), 88 | path = require('path'), 89 | tmx = require('../lib'), 90 | PNG = require('pngjs').PNG, 91 | outDir = argv.outputDir || path.dirname(imagePath), 92 | fext = path.extname(imagePath), 93 | fbase = path.basename(imagePath, fext), 94 | 95 | tilesetPath = argv.commonTileset ? reuseTilesetPath : path.join(outDir, fbase + '-tileset.png'), 96 | tilemapPath = path.join(outDir, fbase + '.tmx'), 97 | 98 | image = null, 99 | tilesetImage = null, 100 | tileset = null, 101 | tilemap = null; 102 | 103 | if (argv.tileset) { 104 | fs.createReadStream(argv.tileset) 105 | .pipe(new PNG()) 106 | .on('parsed', function () { 107 | tilesetImage = this; 108 | load(); 109 | }); 110 | } else { 111 | load(); 112 | } 113 | 114 | function load() { 115 | fs.createReadStream(imagePath) 116 | .pipe(new PNG()) 117 | .on('parsed', function() { 118 | image = this; 119 | 120 | if (argv.commonTileset && reuseTileset) { 121 | tileset = reuseTileset; 122 | } else { 123 | tileset = reuseTileset = new tmx.Tileset(tileWidth, tileHeight); 124 | } 125 | 126 | tileset.append(tilesetImage || image).once('parsed', function () { 127 | if (!tilesetImage && !argv.commonTileset) { 128 | console.log('Writing', tileset.outWidth, 'x', tileset.outHeight, 'tileset, with', tileset.tiles.length, 'tiles.'); 129 | tileset.writeImage(tilesetPath); 130 | } 131 | 132 | var tilemap = new tmx.Tilemap(tileset, image); 133 | 134 | tilemap.once('parsed', function () { 135 | console.log('Writing', tilemap.gridWidth, 'x', tilemap.gridWidth, 'tilemap.'); 136 | tilemap.writeXml(tilemapPath, path.basename(argv.tileset || tilesetPath), argv.format); 137 | 138 | cb(); 139 | }); 140 | }); 141 | }); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | // -------------------------------------------------------------------- 3 | // JSHint Configuration 4 | // -------------------------------------------------------------------- 5 | // 6 | // @author Chad Engler 7 | 8 | // == Enforcing Options =============================================== 9 | // 10 | // These options tell JSHint to be more strict towards your code. Use 11 | // them if you want to allow only a safe subset of JavaScript, very 12 | // useful when your codebase is shared with a big number of developers 13 | // with different skill levels. 14 | 15 | "bitwise" : false, // Disallow bitwise operators (&, |, ^, etc.). 16 | "camelcase" : true, // Force all variable names to use either camelCase or UPPER_CASE. 17 | "curly" : false, // Require {} for every new block or scope. 18 | "eqeqeq" : true, // Require triple equals i.e. `===`. 19 | "es3" : false, // Enforce conforming to ECMAScript 3. 20 | "forin" : false, // Disallow `for in` loops without `hasOwnPrototype`. 21 | "immed" : true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );` 22 | "indent" : 4, // Require that 4 spaces are used for indentation. 23 | "latedef" : true, // Prohibit variable use before definition. 24 | "newcap" : true, // Require capitalization of all constructor functions e.g. `new F()`. 25 | "noarg" : true, // Prohibit use of `arguments.caller` and `arguments.callee`. 26 | "noempty" : true, // Prohibit use of empty blocks. 27 | "nonew" : true, // Prohibit use of constructors for side-effects. 28 | "plusplus" : false, // Disallow use of `++` & `--`. 29 | "quotmark" : true, // Force consistency when using quote marks. 30 | "undef" : true, // Require all non-global variables be declared before they are used. 31 | "unused" : true, // Warn when varaibles are created by not used. 32 | "strict" : false, // Require `use strict` pragma in every file. 33 | "trailing" : true, // Prohibit trailing whitespaces. 34 | "maxparams" : 6, // Prohibit having more than X number of params in a function. 35 | "maxdepth" : 6, // Prohibit nested blocks from going more than X levels deep. 36 | "maxstatements" : false, // Restrict the number of statements in a function. 37 | "maxcomplexity" : false, // Restrict the cyclomatic complexity of the code. 38 | "maxlen" : 120, // Require that all lines are 100 characters or less. 39 | "predef" : [ // Register predefined globals used throughout the code. 40 | // Predef Mocha BDD interface 41 | "describe", "it", "before", "beforeEach", "after", "afterEach" 42 | ], 43 | 44 | // == Relaxing Options ================================================ 45 | // 46 | // These options allow you to suppress certain types of warnings. Use 47 | // them only if you are absolutely positive that you know what you are 48 | // doing. 49 | 50 | "asi" : false, // Tolerate Automatic Semicolon Insertion (no semicolons). 51 | "boss" : false, // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments. 52 | "debug" : false, // Allow debugger statements e.g. browser breakpoints. 53 | "eqnull" : false, // Tolerate use of `== null`. 54 | "esnext" : false, // Allow ES.next specific features such as `const` and `let`. 55 | "evil" : false, // Tolerate use of `eval`. 56 | "expr" : false, // Tolerate `ExpressionStatement` as Programs. 57 | "funcscope" : false, // Tolerate declarations of variables inside of control structures while accessing them later from the outside. 58 | "globalstrict" : false, // Allow global "use strict" (also enables 'strict'). 59 | "iterator" : false, // Allow usage of __iterator__ property. 60 | "lastsemic" : false, // Tolerate missing semicolons when the it is omitted for the last statement in a one-line block. 61 | "laxbreak" : false, // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons. 62 | "laxcomma" : false, // Suppress warnings about comma-first coding style. 63 | "loopfunc" : false, // Allow functions to be defined within loops. 64 | "moz" : false, // Code that uses Mozilla JS extensions will set this to true 65 | "multistr" : false, // Tolerate multi-line strings. 66 | "proto" : false, // Tolerate __proto__ property. This property is deprecated. 67 | "scripturl" : false, // Tolerate script-targeted URLs. 68 | "smarttabs" : false, // Tolerate mixed tabs and spaces when the latter are used for alignmnent only. 69 | "shadow" : false, // Allows re-define variables later in code e.g. `var x=1; x=2;`. 70 | "sub" : false, // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`. 71 | "supernew" : false, // Tolerate `new function () { ... };` and `new Object;`. 72 | "validthis" : false, // Tolerate strict violations when the code is running in strict mode and you use this in a non-constructor function. 73 | 74 | // == Environments ==================================================== 75 | // 76 | // These options pre-define global variables that are exposed by 77 | // popular JavaScript libraries and runtime environments—such as 78 | // browser or node.js. 79 | 80 | "browser" : false, // Standard browser globals e.g. `window`, `document`. 81 | "couch" : false, // Enable globals exposed by CouchDB. 82 | "devel" : false, // Allow development statements e.g. `console.log();`. 83 | "dojo" : false, // Enable globals exposed by Dojo Toolkit. 84 | "jquery" : false, // Enable globals exposed by jQuery JavaScript library. 85 | "mootools" : false, // Enable globals exposed by MooTools JavaScript framework. 86 | "node" : true, // Enable globals available when code is running inside of the NodeJS runtime environment. 87 | "nonstandard" : false, // Define non-standard but widely adopted globals such as escape and unescape. 88 | "prototypejs" : false, // Enable globals exposed by Prototype JavaScript framework. 89 | "rhino" : false, // Enable globals available when your code is running inside of the Rhino runtime environment. 90 | "worker" : false, // Enable globals available when your code is running as a WebWorker. 91 | "wsh" : false, // Enable globals available when your code is running as a script for the Windows Script Host. 92 | "yui" : false, // Enable globals exposed by YUI library. 93 | 94 | // == JSLint Legacy =================================================== 95 | // 96 | // These options are legacy from JSLint. Aside from bug fixes they will 97 | // not be improved in any way and might be removed at any point. 98 | 99 | "nomen" : false, // Prohibit use of initial or trailing underbars in names. 100 | "onevar" : false, // Allow only one `var` statement per function. 101 | "passfail" : false, // Stop on first error. 102 | "white" : false, // Check against strict whitespace and indentation rules. 103 | 104 | // == Undocumented Options ============================================ 105 | // 106 | // While I've found these options in [example1][2] and [example2][3] 107 | // they are not described in the [JSHint Options documentation][4]. 108 | // 109 | // [4]: http://www.jshint.com/options/ 110 | 111 | "maxerr" : 100 // Maximum errors before stopping. 112 | } 113 | --------------------------------------------------------------------------------