diff --git a/package.json b/package.json index 7a4b84d63..22376ab4d 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "prepublish": "gulp build" }, "dependencies": { + "babel-eslint": "^6.1.2", "babel-plugin-syntax-class-properties": "^6.5.0", "babel-plugin-syntax-flow": "^6.5.0", "babel-plugin-transform-flow-strip-types": "^6.7.0", @@ -44,6 +45,7 @@ "glob": "^7.0.5", "gulp-babel": "^6.1.2", "gulp-beautify": "^2.0.0", + "gulp-eslint": "^3.0.1", "gulp-filter": "^4.0.0", "gulp-tap": "^0.1.3", "insight": "~0.8.3", diff --git a/src/generators/app/index.js b/src/generators/app/index.js index ae48e4c82..d66e6f9c6 100644 --- a/src/generators/app/index.js +++ b/src/generators/app/index.js @@ -13,6 +13,7 @@ import babelStream from 'gulp-babel'; import beaufityStream from 'gulp-beautify'; import tap from 'gulp-tap'; import filter from 'gulp-filter'; +import eslint from 'gulp-eslint'; import semver from 'semver'; export class Generator extends Base { @@ -485,9 +486,11 @@ export class Generator extends Base { babelPlugins.push('babel-plugin-transform-flow-strip-types'); } - let jsFilter = filter(['client/**/*.js'], {restore: true}); + const genDir = path.join(__dirname, '../../'); + + let clientJsFilter = filter(['client/**/*.js'], {restore: true}); this.registerTransformStream([ - jsFilter, + clientJsFilter, babelStream({ plugins: babelPlugins.map(require.resolve), /* Babel get's confused about these if you're using an `npm link`ed @@ -523,7 +526,11 @@ export class Generator extends Base { "wrap_attributes_indent_size": 4, "end_with_newline": true }), - jsFilter.restore + eslint({ + fix: true, + configFile: path.join(genDir, 'templates/app/client/.eslintrc(babel)') + }), + clientJsFilter.restore ]); /** @@ -563,6 +570,16 @@ export class Generator extends Base { ]); } + let serverJsFilter = filter(['server/**/*.js'], {restore: true}); + this.registerTransformStream([ + serverJsFilter, + eslint({ + fix: true, + configFile: path.join(genDir, 'templates/app/server/.eslintrc') + }), + serverJsFilter.restore + ]); + let self = this; this.sourceRoot(path.join(__dirname, '../../templates/app')); this.processDirectory('.', '.'); diff --git a/templates/app/.eslintrc b/templates/app/.eslintrc index ef5d7de07..93dbcc287 100644 --- a/templates/app/.eslintrc +++ b/templates/app/.eslintrc @@ -175,7 +175,10 @@ "new-parens": 2, //disallow the omission of parentheses when invoking a constructor with no arguments "newline-after-var": 0, //require or disallow an empty newline after variable declarations "newline-before-return": 0, //require newline before return statement - "newline-per-chained-call": 0, //enforce newline after each call when chaining the calls + "newline-per-chained-call": [ + "error", + {"ignoreChainWithDepth": 2} + ], //enforce newline after each call when chaining the calls "no-array-constructor": 2, //disallow use of the Array constructor "no-bitwise": 0, //disallow use of bitwise operators "no-continue": 0, //disallow use of the continue statement diff --git a/templates/app/client/app/account(auth)/login/index.js b/templates/app/client/app/account(auth)/login/index.js index 187b43be5..ded119f9e 100644 --- a/templates/app/client/app/account(auth)/login/index.js +++ b/templates/app/client/app/account(auth)/login/index.js @@ -1,4 +1,5 @@ 'use strict'; +import angular from 'angular'; import LoginController from './login.controller'; export default angular.module('<%= scriptAppName %>.login', []) diff --git a/templates/app/client/app/account(auth)/settings/index.js b/templates/app/client/app/account(auth)/settings/index.js index 823caa530..6b5eddabe 100644 --- a/templates/app/client/app/account(auth)/settings/index.js +++ b/templates/app/client/app/account(auth)/settings/index.js @@ -1,4 +1,5 @@ 'use strict'; +import angular from 'angular'; import SettingsController from './settings.controller'; export default angular.module('<%= scriptAppName %>.settings', []) diff --git a/templates/app/client/app/account(auth)/signup/index.js b/templates/app/client/app/account(auth)/signup/index.js index 43b4842b7..b95da83e1 100644 --- a/templates/app/client/app/account(auth)/signup/index.js +++ b/templates/app/client/app/account(auth)/signup/index.js @@ -1,5 +1,5 @@ 'use strict'; - +import angular from 'angular'; import SignupController from './signup.controller'; export default angular.module('<%= scriptAppName %>.signup', []) diff --git a/templates/app/client/app/account(auth)/signup/signup.controller.js b/templates/app/client/app/account(auth)/signup/signup.controller.js index 196684c24..85e71d28f 100644 --- a/templates/app/client/app/account(auth)/signup/signup.controller.js +++ b/templates/app/client/app/account(auth)/signup/signup.controller.js @@ -1,5 +1,7 @@ 'use strict'; // @flow +import angular from 'angular'; + <%_ if(filters.flow) { -%> type User = { name: string; diff --git a/templates/app/client/app/admin(auth)/index.js b/templates/app/client/app/admin(auth)/index.js index d78165412..72422ea8f 100644 --- a/templates/app/client/app/admin(auth)/index.js +++ b/templates/app/client/app/admin(auth)/index.js @@ -1,4 +1,5 @@ 'use strict'; +import angular from 'angular'; import routes from './admin.routes'; import AdminController from './admin.controller'; diff --git a/templates/app/client/app/app.js b/templates/app/client/app/app.js index 7ccaaf89c..2937399dd 100644 --- a/templates/app/client/app/app.js +++ b/templates/app/client/app/app.js @@ -14,7 +14,7 @@ import uiRouter from 'angular-ui-router';<% } %> import uiBootstrap from 'angular-ui-bootstrap';<% } %> // import ngMessages from 'angular-messages'; <%_ if(filters.auth) { _%> -//import ngValidationMatch from 'angular-validation-match';<% } %> +// import ngValidationMatch from 'angular-validation-match';<% } %> import {routeConfig} from './app.config'; @@ -35,7 +35,6 @@ import socket from '../components/socket/socket.service';<% } %> import './app.<%= styleExt %>'; angular.module('<%= scriptAppName %>', [ - // ngAnimate, ngCookies, ngResource, ngSanitize, @@ -47,9 +46,7 @@ angular.module('<%= scriptAppName %>', [ uiRouter,<% } _%> <%_ if(filters.uibootstrap) { %> uiBootstrap,<% } %> - // ngMessages, <%_ if(filters.auth) { %> - // ngValidationMatch, _Auth, account, admin,<% } _%> diff --git a/templates/app/client/components/auth(auth)/auth.service.js b/templates/app/client/components/auth(auth)/auth.service.js index 87a0adb2f..ac17e15ce 100644 --- a/templates/app/client/components/auth(auth)/auth.service.js +++ b/templates/app/client/components/auth(auth)/auth.service.js @@ -1,6 +1,6 @@ 'use strict'; // @flow -class User { +class _User { _id: string = ''; name: string = ''; email: string = ''; @@ -11,7 +11,7 @@ class User { export function AuthService($location, $http, $cookies, $q, appConfig, Util, User) { 'ngInject'; var safeCb = Util.safeCb; - var currentUser: User = new User(); + var currentUser: _User = new _User(); var userRoles = appConfig.userRoles || []; /** * Check if userRole is >= role @@ -27,7 +27,6 @@ export function AuthService($location, $http, $cookies, $q, appConfig, Util, Use } var Auth = { - /** * Authenticate user and save token * diff --git a/templates/app/client/components/auth(auth)/router.decorator.js b/templates/app/client/components/auth(auth)/router.decorator.js index ea205ec7d..aaff3be32 100644 --- a/templates/app/client/components/auth(auth)/router.decorator.js +++ b/templates/app/client/components/auth(auth)/router.decorator.js @@ -1,5 +1,4 @@ 'use strict'; -import * as _ from 'lodash'; export function routerDecorator($rootScope<% if(filters.ngroute) { %>, $location<% } if(filters.uirouter) { %>, $state<% } %>, Auth) { 'ngInject'; diff --git a/templates/app/client/components/modal(uibootstrap)/modal.service.js b/templates/app/client/components/modal(uibootstrap)/modal.service.js index 91d94894c..1269ac83b 100644 --- a/templates/app/client/components/modal(uibootstrap)/modal.service.js +++ b/templates/app/client/components/modal(uibootstrap)/modal.service.js @@ -1,4 +1,5 @@ 'use strict'; +import angular from 'angular'; export function Modal($rootScope, $uibModal) { /** @@ -37,9 +38,9 @@ export function Modal($rootScope, $uibModal) { * @param {All} - any additional args are passed straight to del callback */ return function() { - var args = Array.prototype.slice.call(arguments), - name = args.shift(), - deleteModal; + var args = Array.prototype.slice.call(arguments); + var name = args.shift(); + var deleteModal; deleteModal = openModal({ modal: { diff --git a/templates/app/client/components/mongoose-error(auth)/mongoose-error.directive.js b/templates/app/client/components/mongoose-error(auth)/mongoose-error.directive.js index 3ee88f8d9..6405202a5 100644 --- a/templates/app/client/components/mongoose-error(auth)/mongoose-error.directive.js +++ b/templates/app/client/components/mongoose-error(auth)/mongoose-error.directive.js @@ -1,4 +1,5 @@ 'use strict'; +import angular from 'angular'; /** * Removes server error when user updates input diff --git a/templates/app/client/components/navbar/navbar.component.js b/templates/app/client/components/navbar/navbar.component.js index 6a6d37282..8cf2ab0b1 100644 --- a/templates/app/client/components/navbar/navbar.component.js +++ b/templates/app/client/components/navbar/navbar.component.js @@ -1,4 +1,6 @@ 'use strict'; +/* eslint no-sync: 0 */ +import angular from 'angular'; export class NavbarComponent { menu = [{ diff --git a/templates/app/client/components/oauth-buttons(oauth)/index.js b/templates/app/client/components/oauth-buttons(oauth)/index.js index 8ce33c85e..bfa3b6ec0 100644 --- a/templates/app/client/components/oauth-buttons(oauth)/index.js +++ b/templates/app/client/components/oauth-buttons(oauth)/index.js @@ -1,4 +1,5 @@ 'use strict'; +import angular from 'angular'; export function OauthButtonsController($window) { this.loginOauth = function(provider) { diff --git a/templates/app/client/components/socket(socketio)/socket.service.js b/templates/app/client/components/socket(socketio)/socket.service.js index bcaa55b18..3e9dec2fd 100644 --- a/templates/app/client/components/socket(socketio)/socket.service.js +++ b/templates/app/client/components/socket(socketio)/socket.service.js @@ -1,5 +1,6 @@ 'use strict'; - +import * as _ from 'lodash'; +import angular from 'angular'; import io from 'socket.io-client'; function Socket(socketFactory) { diff --git a/templates/app/client/components/util/util.module.js b/templates/app/client/components/util/util.module.js index 3e93a69b9..b627e4486 100644 --- a/templates/app/client/components/util/util.module.js +++ b/templates/app/client/components/util/util.module.js @@ -1,4 +1,5 @@ 'use strict'; +import angular from 'angular'; import {UtilService} from './util.service'; export default angular.module('<%= scriptAppName %>.util', []) diff --git a/templates/app/client/components/util/util.service.js b/templates/app/client/components/util/util.service.js index 39b108988..7101c92f8 100644 --- a/templates/app/client/components/util/util.service.js +++ b/templates/app/client/components/util/util.service.js @@ -1,4 +1,5 @@ 'use strict'; +import angular from 'angular'; /** * The Util service is for thin, globally reusable, utility functions diff --git a/templates/app/server/api/user(auth)/user.controller.js b/templates/app/server/api/user(auth)/user.controller.js index c3e0d50ed..d8a1f5fe3 100644 --- a/templates/app/server/api/user(auth)/user.controller.js +++ b/templates/app/server/api/user(auth)/user.controller.js @@ -2,7 +2,6 @@ <% if (filters.mongooseModels) { %> import User from './user.model';<% } %><% if (filters.sequelizeModels) { %> import {User} from '../../sqldb';<% } %> -import passport from 'passport'; import config from '../../config/environment'; import jwt from 'jsonwebtoken'; @@ -44,7 +43,7 @@ export function index(req, res) { /** * Creates a new user */ -export function create(req, res, next) { +export function create(req, res) { <% if (filters.mongooseModels) { %>var newUser = new User(req.body); newUser.provider = 'local'; newUser.role = 'user'; @@ -99,7 +98,7 @@ export function destroy(req, res) { /** * Change a users password */ -export function changePassword(req, res, next) { +export function changePassword(req, res) { var userId = req.user._id; var oldPass = String(req.body.oldPassword); var newPass = String(req.body.newPassword); @@ -155,6 +154,6 @@ export function me(req, res, next) { /** * Authentication callback */ -export function authCallback(req, res, next) { +export function authCallback(req, res) { res.redirect('/'); } diff --git a/templates/app/server/api/user(auth)/user.events.js b/templates/app/server/api/user(auth)/user.events.js index 1cd0480e5..f8ebebe90 100644 --- a/templates/app/server/api/user(auth)/user.events.js +++ b/templates/app/server/api/user(auth)/user.events.js @@ -14,18 +14,18 @@ UserEvents.setMaxListeners(0); // Model events<% if (filters.mongooseModels) { %> var events = { - 'save': 'save', - 'remove': 'remove' + save: 'save', + remove: 'remove' };<% } if (filters.sequelizeModels) { %> var events = { - 'afterCreate': 'save', - 'afterUpdate': 'save', - 'afterDestroy': 'remove' + afterCreate: 'save', + afterUpdate: 'save', + afterDestroy: 'remove' };<% } %> // Register the event emitter to the model events -for (var e in events) { - var event = events[e];<% if (filters.mongooseModels) { %> +for(var e in events) { + let event = events[e];<% if (filters.mongooseModels) { %> User.schema.post(e, emitEvent(event));<% } if (filters.sequelizeModels) { %> User.hook(e, emitEvent(event));<% } %> } diff --git a/templates/app/server/api/user(auth)/user.model(mongooseModels).js b/templates/app/server/api/user(auth)/user.model(mongooseModels).js index c67632162..f23208f12 100644 --- a/templates/app/server/api/user(auth)/user.model(mongooseModels).js +++ b/templates/app/server/api/user(auth)/user.model(mongooseModels).js @@ -244,14 +244,14 @@ UserSchema.methods = { if(!callback) { return crypto.pbkdf2Sync(password, salt, defaultIterations, defaultKeyLength) - .toString('base64'); + .toString('base64'); } return crypto.pbkdf2(password, salt, defaultIterations, defaultKeyLength, (err, key) => { if(err) { - callback(err); + return callback(err); } else { - callback(null, key.toString('base64')); + return callback(null, key.toString('base64')); } }); } diff --git a/templates/app/server/app.js b/templates/app/server/app.js index a63b97cab..7dbbcba9f 100644 --- a/templates/app/server/app.js +++ b/templates/app/server/app.js @@ -15,11 +15,13 @@ import http from 'http'; mongoose.connect(config.mongo.uri, config.mongo.options); mongoose.connection.on('error', function(err) { console.error('MongoDB connection error: ' + err); - process.exit(-1); + process.exit(-1); // eslint-disable-line no-process-exit }); -<% } %><% if (filters.models) { %> +<% } %><% if(filters.models) { %> // Populate databases with sample data -if (config.seedDB) { require('./config/seed'); } +if(config.seedDB) { + require('./config/seed'); +} <% } %> // Setup server var app = express(); @@ -38,7 +40,7 @@ function startServer() { console.log('Express server listening on %d, in %s mode', config.port, app.get('env')); }); } -<% if (filters.sequelize) { %> +<% if(filters.sequelize) { %> sqldb.sequelize.sync() .then(startServer) .catch(function(err) { diff --git a/templates/app/server/auth(auth)/auth.service.js b/templates/app/server/auth(auth)/auth.service.js index 43de0a3c5..13b345c3b 100644 --- a/templates/app/server/auth(auth)/auth.service.js +++ b/templates/app/server/auth(auth)/auth.service.js @@ -1,6 +1,4 @@ 'use strict'; - -import passport from 'passport'; import config from '../config/environment'; import jwt from 'jsonwebtoken'; import expressJwt from 'express-jwt'; @@ -60,11 +58,10 @@ export function hasRole(roleRequired) { return compose() .use(isAuthenticated()) .use(function meetsRequirements(req, res, next) { - if (config.userRoles.indexOf(req.user.role) >= - config.userRoles.indexOf(roleRequired)) { - next(); + if (config.userRoles.indexOf(req.user.role) >= config.userRoles.indexOf(roleRequired)) { + return next(); } else { - res.status(403).send('Forbidden'); + return res.status(403).send('Forbidden'); } }); } diff --git a/templates/app/server/auth(auth)/index.js b/templates/app/server/auth(auth)/index.js index 09564fe28..3f9983fb3 100644 --- a/templates/app/server/auth(auth)/index.js +++ b/templates/app/server/auth(auth)/index.js @@ -1,7 +1,5 @@ 'use strict'; - import express from 'express'; -import passport from 'passport'; import config from '../config/environment';<% if (filters.mongooseModels) { %> import User from '../api/user/user.model';<% } %><% if (filters.sequelizeModels) { %> import {User} from '../sqldb';<% } %> diff --git a/templates/app/server/config/express.js b/templates/app/server/config/express.js index d0cc7b99a..f80dc5a73 100644 --- a/templates/app/server/config/express.js +++ b/templates/app/server/config/express.js @@ -15,9 +15,9 @@ import errorHandler from 'errorhandler'; import path from 'path'; <%_ if(!filters.noModels) { -%> import lusca from 'lusca';<% } %> -import config from './environment';<% if (filters.auth) { %> +import config from './environment';<% if(filters.auth) { %> import passport from 'passport';<% } %><% if(!filters.noModels) { %> -import session from 'express-session';<% } %><% if (filters.mongoose) { %> +import session from 'express-session';<% } %><% if(filters.mongoose) { %> <%_ if(semver.satisfies(nodeVersion, '>= 4')) { _%> import connectMongo from 'connect-mongo';<% } else { _%> import connectMongo from 'connect-mongo/es5';<% } %> @@ -30,11 +30,11 @@ var Store = expressSequelizeSession(session.Store);<% } %> export default function(app) { var env = app.get('env'); - if (env === 'development' || env === 'test') { + if(env === 'development' || env === 'test') { app.use(express.static(path.join(config.root, '.tmp'))); } - if (env === 'production') { + if(env === 'production') { app.use(favicon(path.join(config.root, 'client', 'favicon.ico'))); } @@ -42,15 +42,15 @@ export default function(app) { app.use(express.static(app.get('appPath'))); app.use(morgan('dev')); - app.set('views', config.root + '/server/views');<% if (filters.html) { %> + app.set('views', config.root + '/server/views');<% if(filters.html) { %> app.engine('html', require('ejs').renderFile); - app.set('view engine', 'html');<% } %><% if (filters.pug) { %> + app.set('view engine', 'html');<% } %><% if(filters.pug) { %> app.set('view engine', 'pug');<% } %> app.use(shrinkRay()); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); app.use(methodOverride()); - app.use(cookieParser());<% if (filters.auth) { %> + app.use(cookieParser());<% if(filters.auth) { %> app.use(passport.initialize());<% } %> <% if(!filters.noModels) { %> @@ -60,7 +60,7 @@ export default function(app) { app.use(session({ secret: config.secrets.session, saveUninitialized: true, - resave: false<% if (filters.mongoose) { %>, + resave: false<% if(filters.mongoose) { %>, store: new MongoStore({ mongooseConnection: mongoose.connection, db: '<%= lodash.slugify(lodash.humanize(appname)) %>' @@ -72,7 +72,7 @@ export default function(app) { * Lusca - express server security * https://github.com/krakenjs/lusca */ - if (env !== 'test' && !process.env.SAUCE_USERNAME) { + if(env !== 'test' && !process.env.SAUCE_USERNAME) { app.use(lusca({ csrf: { angular: true @@ -87,7 +87,7 @@ export default function(app) { })); }<% } %> - if ('development' === env) { + if(env === 'development') { const webpackDevMiddleware = require('webpack-dev-middleware'); const stripAnsi = require('strip-ansi'); const webpack = require('webpack'); @@ -124,7 +124,7 @@ export default function(app) { */ compiler.plugin('done', function (stats) { console.log('webpack done hook'); - if (stats.hasErrors() || stats.hasWarnings()) { + if(stats.hasErrors() || stats.hasWarnings()) { return browserSync.sockets.emit('fullscreen:message', { title: "Webpack Error:", body: stripAnsi(stats.toString()), @@ -135,7 +135,7 @@ export default function(app) { }); } - if ('development' === env || 'test' === env) { + if(env === 'development' || env === 'test') { app.use(errorHandler()); // Error handler - has to be last } } diff --git a/templates/app/server/config/seed(models).js b/templates/app/server/config/seed(models).js index 07d9d52b8..627aa5a36 100644 --- a/templates/app/server/config/seed(models).js +++ b/templates/app/server/config/seed(models).js @@ -19,31 +19,31 @@ var User = sqldb.User;<% } %><% } %> <% if (filters.mongooseModels) { %>Thing.create({<% } if (filters.sequelizeModels) { %>Thing.bulkCreate([{<% } %> name: 'Development Tools', - info: 'Integration with popular tools such as Webpack, Gulp, Babel, TypeScript, Karma, ' + - 'Mocha, ESLint, Node Inspector, Livereload, Protractor, Pug, ' + - 'Stylus, Sass, and Less.' + info: 'Integration with popular tools such as Webpack, Gulp, Babel, TypeScript, Karma, ' + + 'Mocha, ESLint, Node Inspector, Livereload, Protractor, Pug, ' + + 'Stylus, Sass, and Less.' }, { name: 'Server and Client integration', - info: 'Built with a powerful and fun stack: MongoDB, Express, ' + - 'AngularJS, and Node.' + info: 'Built with a powerful and fun stack: MongoDB, Express, ' + + 'AngularJS, and Node.' }, { name: 'Smart Build System', - info: 'Build system ignores `spec` files, allowing you to keep ' + - 'tests alongside code. Automatic injection of scripts and ' + - 'styles into your index.html' + info: 'Build system ignores `spec` files, allowing you to keep ' + + 'tests alongside code. Automatic injection of scripts and ' + + 'styles into your index.html' }, { name: 'Modular Structure', - info: 'Best practice client and server structures allow for more ' + - 'code reusability and maximum scalability' + info: 'Best practice client and server structures allow for more ' + + 'code reusability and maximum scalability' }, { name: 'Optimized Build', - info: 'Build process packs up your templates as a single JavaScript ' + - 'payload, minifies your scripts/css/images, and rewrites asset ' + - 'names for caching.' + info: 'Build process packs up your templates as a single JavaScript ' + + 'payload, minifies your scripts/css/images, and rewrites asset ' + + 'names for caching.' }, { name: 'Deployment Ready', - info: 'Easily deploy your app to Heroku or Openshift with the heroku ' + - 'and openshift subgenerators' + info: 'Easily deploy your app to Heroku or Openshift with the heroku ' + + 'and openshift subgenerators' <% if (filters.mongooseModels) { %>});<% } if (filters.sequelizeModels) { %>}]);<% } %> }); diff --git a/templates/app/server/config/socketio(socketio).js b/templates/app/server/config/socketio(socketio).js index db5730912..367677f82 100644 --- a/templates/app/server/config/socketio(socketio).js +++ b/templates/app/server/config/socketio(socketio).js @@ -3,11 +3,10 @@ */ 'use strict'; -import config from './environment'; +// import config from './environment'; // When the user disconnects.. perform this -function onDisconnect(socket) { -} +function onDisconnect(/*socket*/) {} // When the user connects.. perform this function onConnect(socket) { @@ -37,8 +36,7 @@ export default function(socketio) { // })); socketio.on('connection', function(socket) { - socket.address = socket.request.connection.remoteAddress + - ':' + socket.request.connection.remotePort; + socket.address = `${socket.request.connection.remoteAddress}:${socket.request.connection.remotePort}`; socket.connectedAt = new Date();