diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 000000000..db482617c --- /dev/null +++ b/.eslintrc @@ -0,0 +1,44 @@ +{ + "env": { + "node": true + }, + "parserOptions": { + "ecmaVersion": 8 + }, + "globals": { + "window": false, + "document": false + }, + "rules": { + "comma-style": [ + 2, + "last" + ], + "eqeqeq": ["error", "always", {"null": "ignore"}], + "indent": [ + 2, + 2, + { + "SwitchCase": 1 + } + ], + "new-cap": 2, + "quotes": [ + 2, + "single" + ], + "no-undef": 2, + "no-shadow": 0, + "no-unused-expressions": 2, + "no-cond-assign": [ + 2, + "except-parens" + ] + }, + "overrides": [ + { + "files": ["test/**/*.mocha.js", "test/browser/*.js"], + "env": {"mocha": true, "node": true} + } + ] +} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d2323aa4a..2e659eb29 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,4 +30,4 @@ jobs: - name: Install run: npm install - name: Test - run: npm run test + run: npm run checks diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index cf514a151..000000000 --- a/.jshintrc +++ /dev/null @@ -1,18 +0,0 @@ -{ - "node": true, - "laxcomma": true, - "eqnull": true, - "eqeqeq": true, - "indent": 2, - "newcap": true, - "quotmark": "single", - "undef": true, - "trailing": true, - "shadow": true, - "expr": true, - "boss": true, - "globals": { - "window": false, - "document": false - } -} diff --git a/lib/AppForServer.js b/lib/AppForServer.js index 2910bd4ac..0f3d44d20 100644 --- a/lib/AppForServer.js +++ b/lib/AppForServer.js @@ -26,8 +26,8 @@ if (module.require) { var STYLE_EXTENSIONS = ['.css']; var VIEW_EXTENSIONS = ['.html']; var COMPILERS = { - '.css': cssCompiler -, '.html': htmlCompiler + '.css': cssCompiler, + '.html': htmlCompiler }; function cssCompiler(file, filename, options) { return {css: file, files: [filename]}; @@ -121,7 +121,9 @@ AppForServer.prototype.bundle = function(backend, options, cb) { cb = options; options = null; } - options || (options = {}); + if (options == null) { + options = {}; + } if (options.minify == null) options.minify = util.isProduction; // Turn all of the app's currently registered views into a javascript // function that can recreate them in the client @@ -136,7 +138,7 @@ AppForServer.prototype.bundle = function(backend, options, cb) { if (filename !== viewsFilename) return through(); return through( function write() {} - , function end() { + , function end() { this.queue(viewsSource); this.queue(null); } @@ -204,7 +206,9 @@ AppForServer.prototype.writeScripts = function(backend, dir, options, cb) { fs.unlinkSync(oldFilename); } } - cb && cb(); + if (cb) { + cb(); + } }); }; @@ -229,10 +233,10 @@ AppForServer.prototype.serialize = function() { this.scriptMapUrl.slice(this.scriptMapBaseUrl.length) : this.scriptMapUrl; var serialized = JSON.stringify({ - scriptBaseUrl: this.scriptBaseUrl - , scriptMapBaseUrl: this.scriptMapBaseUrl - , scriptUrl: scriptUrl - , scriptMapUrl: scriptMapUrl + scriptBaseUrl: this.scriptBaseUrl, + scriptMapBaseUrl: this.scriptMapBaseUrl, + scriptUrl: scriptUrl, + scriptMapUrl: scriptMapUrl }); fs.writeFileSync(this.serializedBase + '.json', serialized, 'utf8'); }; diff --git a/lib/Dom.js b/lib/Dom.js index 0462e2e23..ed582d6ca 100644 --- a/lib/Dom.js +++ b/lib/Dom.js @@ -35,7 +35,7 @@ Dom.prototype.addListener = function(type, target, listener, useCapture) { } var domListener = (type === 'destroy') ? new DestroyListener(target, listener) : - new DomListener(type, target, listener, useCapture); + new DomListener(type, target, listener, useCapture); if (-1 === this._listenerIndex(domListener)) { var listeners = this._listeners || this._initListeners(); listeners.push(domListener); diff --git a/lib/Page.js b/lib/Page.js index e20536a8d..0d36ea406 100644 --- a/lib/Page.js +++ b/lib/Page.js @@ -126,7 +126,9 @@ Page.prototype.destroy = function() { silentModel.destroy('_page'); silentModel.destroy('$components'); // Unfetch and unsubscribe from all queries and documents - silentModel.unloadAll && silentModel.unloadAll(); + if (silentModel.unloadAll) { + silentModel.unloadAll(); + } }; Page.prototype._addModelListeners = function(eventModel) { diff --git a/lib/PageForServer.js b/lib/PageForServer.js index c05f5987a..24b545850 100644 --- a/lib/PageForServer.js +++ b/lib/PageForServer.js @@ -96,9 +96,9 @@ function stringifyBundle(bundle) { // TODO: Cleanup; copied from tracks function pageParams(req) { var params = { - url: req.url - , body: req.body - , query: req.query + url: req.url, + body: req.body, + query: req.query, }; for (var key in req.params) { params[key] = req.params[key]; diff --git a/lib/eventmodel.js b/lib/eventmodel.js index 62f82b1e3..3864e88b2 100644 --- a/lib/eventmodel.js +++ b/lib/eventmodel.js @@ -257,7 +257,9 @@ EventModel.prototype._removeItemContext = function(context) { EventModel.prototype._addBinding = function(binding) { var bindings = this.bindings || (this.bindings = new BindingsMap()); - binding.eventModels || (binding.eventModels = new EventModelsMap()); + if (bindings.eventModel == null) { + binding.eventModels = new EventModelsMap(); + } bindings[binding.id] = binding; binding.eventModels[this.id] = this; }; diff --git a/lib/files.js b/lib/files.js index 0da39fd97..8cc132c97 100644 --- a/lib/files.js +++ b/lib/files.js @@ -54,7 +54,9 @@ function loadViewsSync(app, sourceFilename, namespace) { } function loadStylesSync(app, sourceFilename, options) { - options || (options = {compress: util.isProduction}); + if (options == null) { + options = { compress: util.isProduction }; + } var resolved = resolve.sync(sourceFilename, { extensions: app.styleExtensions, packageFilter: deleteMain} diff --git a/lib/textDiff.js b/lib/textDiff.js index 335b1b38a..99a8c50ff 100644 --- a/lib/textDiff.js +++ b/lib/textDiff.js @@ -6,7 +6,9 @@ function onStringInsert(el, previous, index, text) { function transformCursor(cursor) { return (index < cursor) ? cursor + text.length : cursor; } - previous || (previous = ''); + if (!previous) { + previous = ''; + } var newText = previous.slice(0, index) + text + previous.slice(index); replaceText(el, newText, transformCursor); } @@ -15,7 +17,9 @@ function onStringRemove(el, previous, index, howMany) { function transformCursor(cursor) { return (index < cursor) ? cursor - Math.min(howMany, cursor - index) : cursor; } - previous || (previous = ''); + if (!previous) { + previous = ''; + } var newText = previous.slice(0, index) + previous.slice(index + howMany); replaceText(el, newText, transformCursor); } diff --git a/package.json b/package.json index 4c6179a01..2cf39ceb0 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,9 @@ }, "main": "index.js", "scripts": { - "test": "./node_modules/.bin/mocha test/all/*.mocha.js test/dom/*.mocha.js test/server/*.mocha.js; ./node_modules/.bin/jshint lib/*.js test/*.js test-utils/*.js", + "checks": "npm run lint && npm test", + "lint": "npx eslint *.js lib/**/*.js test/**/*.js test-utils/**/*.js", + "test": "npx mocha test/all/*.mocha.js test/dom/*.mocha.js test/server/*.mocha.js", "test-browser": "node test/server.js" }, "dependencies": { @@ -27,9 +29,9 @@ "async": "^1.5.2", "browserify": "^16.2.2", "chai": "^4.2.0", + "eslint": "^8.24.0", "express": "^4.13.3", "jsdom": "^15.2.0", - "jshint": "^2.9.5", "mocha": "^6.2.0" }, "optionalDependencies": {}, diff --git a/test-utils/assertions.js b/test-utils/assertions.js index d5d20ec3f..6437e0cdf 100644 --- a/test-utils/assertions.js +++ b/test-utils/assertions.js @@ -18,7 +18,7 @@ module.exports = function(dom, Assertion) { // NodeFilter.SHOW_COMMENT === 128 var treeWalker = domDocument.createTreeWalker(clone, 128, null, false); var toRemove = []; - for (var item; item = treeWalker.nextNode();) { + for (var item = treeWalker.nextNode(); item != null; item = treeWalker.nextNode()) { toRemove.push(item); } for (var i = toRemove.length; i--;) { diff --git a/test/dom/bindings.mocha.js b/test/dom/bindings.mocha.js index 0b7d8a29d..fe74f0393 100644 --- a/test/dom/bindings.mocha.js +++ b/test/dom/bindings.mocha.js @@ -417,7 +417,7 @@ describe('bindings', function() { var page = app.createPage(); page.model.on('insert', '_data.items', function(index, values) { - if (values[0] == 'B') { + if (values[0] === 'B') { page.model.insert('_data.items', 0, 'C'); } });