diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c7a63eaf..bf3937671 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ + +# [4.2.0](https://github.com/angular-fullstack/generator-angular-fullstack/compare/4.1.4...v4.2.0) (2017-04-19) + +## Notable Changes + +* `node-inspector` has been taken out in favor of Node's integrated `--inspect` flag. +* @benmarten has taken care of a lot of the lint issues we've seen pulluting the console +* @benmarten also enabled the use of (Yarn)[https://yarnpkg.com] if you have it installed. Thanks Ben! +* Various other fixes. See the [comparison](https://github.com/angular-fullstack/generator-angular-fullstack/compare/4.1.4...4.2.0) for the full list. + +### Bug Fixes + +* **angular-validation-match:** Integration with Babel & Typescript ([#2517](https://github.com/angular-fullstack/generator-angular-fullstack/issues/2517)) ([9db9918](https://github.com/angular-fullstack/generator-angular-fullstack/commit/9db9918)) + + + ## [4.1.4](https://github.com/angular-fullstack/generator-angular-fullstack/compare/4.1.2...v4.1.4) (2017-03-01) diff --git a/angular-fullstack-deps b/angular-fullstack-deps index 1fee2d68f..a654f8f36 160000 --- a/angular-fullstack-deps +++ b/angular-fullstack-deps @@ -1 +1 @@ -Subproject commit 1fee2d68ff55a8ad8a3ba0efd908b5c5e5d6571d +Subproject commit a654f8f36cf6efb8947f12c867f7a63bbf93d3ad diff --git a/gulpfile.js b/gulpfile.js index 768e6d419..f9afc6d36 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -148,7 +148,16 @@ gulp.task('installFixtures', function() { }, 1 * 1000); shell.cd('test/fixtures'); - execAsync('npm install --quiet', {cwd: '../fixtures'}).then(() => { + let installCommand; + if(process.platform === 'win32') { + installCommand = 'yarn --version >nul 2>&1 && ( yarn install ) || ( npm install --quiet )'; + } else { + installCommand = 'type yarn &> /dev/null | yarn install || npm install --quiet'; + } + + execAsync(installCommand, { + cwd: '../fixtures' + }).then(() => { process.stdout.write('\n'); if(!process.env.SAUCE_USERNAME) { gutil.log('running npm run-script update-webdriver'); diff --git a/package.json b/package.json index 9cfe6592d..7fe2b2c04 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "generator-angular-fullstack", - "version": "4.1.4", + "version": "4.2.0", "description": "Yeoman generator for creating MEAN stack applications, using MongoDB, Express, AngularJS, and Node", "keywords": [ "yeoman-generator", diff --git a/readme.md b/readme.md index 2a26f85da..6d24535ab 100644 --- a/readme.md +++ b/readme.md @@ -1,5 +1,5 @@ # AngularJS Full-Stack generator -![generator-angular-fullstack](https://angular-fullstack.github.io/assets/angular-fullstack-logo.svg) +[![generator-angular-fullstack](https://angular-fullstack.github.io/assets/angular-fullstack-logo.svg)](https://angular-fullstack.github.io/) ![Build Status](https://img.shields.io/circleci/project/angular-fullstack/generator-angular-fullstack/master.svg) [![npm version](https://img.shields.io/npm/v/generator-angular-fullstack.svg)](https://www.npmjs.com/package/generator-angular-fullstack) @@ -79,27 +79,27 @@ yo angular-fullstack Available generators: * App - - [angular-fullstack](/docs/generators/app.md) (aka [angular-fullstack:app](/docs/generators/app.md)) + - [angular-fullstack](https://angular-fullstack.github.io/generators/app/) (aka [angular-fullstack:app](https://angular-fullstack.github.io/generators/app/)) * Server Side - - [angular-fullstack:endpoint](/docs/generators/endpoint.md) + - [angular-fullstack:endpoint](https://angular-fullstack.github.io/generators/endpoint) * Client Side (via [generator-ng-component](https://github.com/DaftMonk/generator-ng-component)) - - [angular-fullstack:route](/docs/generators/route.md) - - [angular-fullstack:component](/docs/generators/component.md) - - [angular-fullstack:controller](/docs/generators/controller.md) - - [angular-fullstack:filter](/docs/generators/filter.md) - - [angular-fullstack:directive](/docs/generators/directive.md) - - [angular-fullstack:service](/docs/generators/service.md) - - [angular-fullstack:provider](/docs/generators/service.md) - - [angular-fullstack:factory](/docs/generators/service.md) - - [angular-fullstack:decorator](/docs/generators/decorator.md) + - [angular-fullstack:route](https://angular-fullstack.github.io/generators/route) + - [angular-fullstack:component](https://angular-fullstack.github.io/generators/component) + - [angular-fullstack:controller](https://angular-fullstack.github.io/generators/controller) + - [angular-fullstack:filter](https://angular-fullstack.github.io/generators/filter) + - [angular-fullstack:directive](https://angular-fullstack.github.io/generators/directive) + - [angular-fullstack:service](https://angular-fullstack.github.io/generators/service) + - [angular-fullstack:provider](https://angular-fullstack.github.io/generators/service) + - [angular-fullstack:factory](https://angular-fullstack.github.io/generators/service) + - [angular-fullstack:decorator](https://angular-fullstack.github.io/generators/decorator) * Deployment - - [angular-fullstack:openshift](/docs/generators/openshift.md) - - [angular-fullstack:heroku](/docs/generators/heroku.md) + - [angular-fullstack:openshift](https://angular-fullstack.github.io/generators/openshift) + - [angular-fullstack:heroku](https://angular-fullstack.github.io/generators/heroku) ## Documentation -Check out our [documentation home page](http://angular-fullstack.github.io/generator-angular-fullstack). +Check out our [documentation home page](http://angular-fullstack.github.io/). ## Contribute @@ -166,4 +166,4 @@ Is your company using Angular-FullStack? Ask your boss to support the project. Y -![generator-angular-fullstack](https://angular-fullstack.github.io/assets/angular-fullstack-boxes.svg) +[![generator-angular-fullstack](https://angular-fullstack.github.io/assets/angular-fullstack-boxes.svg)](https://angular-fullstack.github.io/) diff --git a/src/generators/app/index.js b/src/generators/app/index.js index d66e6f9c6..9c169d0ce 100644 --- a/src/generators/app/index.js +++ b/src/generators/app/index.js @@ -96,6 +96,7 @@ export class Generator extends Base { }, info: function () { this.log(this.yoWelcome); + this.log('Angular Fullstack v' + this.rootGeneratorVersion() +'\n'); this.log('Out of the box I create an AngularJS app with an Express server.\n'); }, checkForConfig: function() { @@ -546,7 +547,8 @@ export class Generator extends Base { ['ngRoute', 'angular-route'], ['uiBootstrap', 'angular-ui-bootstrap'], ['ngMessages', 'angular-messages'], - ['io', 'socket.io-client'] + ['io', 'socket.io-client'], + ['ngValidationMatch', 'angular-validation-match'] ]; function replacer(contents) { modulesToFix.forEach(([moduleName, importName]) => { @@ -604,7 +606,15 @@ export class Generator extends Base { install() { if(!this.options['skip-install']) { - this.spawnCommand('npm', ['install']); + let yarnCheckCommand; + if (process.platform === 'win32') { + yarnCheckCommand = 'yarn --version >nul 2>&1'; + } else { + yarnCheckCommand = 'type yarn &> /dev/null'; + } + exec(yarnCheckCommand, (error, stdout, stderr) => { + return this.spawnCommand((!error) ? 'yarn' : 'npm', ['install']); + }); } } diff --git a/templates/app/.eslintrc b/templates/app/.eslintrc index 93dbcc287..28a8da424 100644 --- a/templates/app/.eslintrc +++ b/templates/app/.eslintrc @@ -82,7 +82,7 @@ "no-octal-escape": 0, //disallow use of octal escape sequences in string literals, such as var foo = "Copyright \251"; "no-octal": 0, //disallow use of octal literals "no-param-reassign": 0, //disallow reassignment of function parameters - "no-process-env": 1, //disallow use of process.env + "no-process-env": 0, //disallow use of process.env "no-proto": 2, //disallow usage of __proto__ property "no-redeclare": 2, //disallow declaring the same variable more than once "no-return-assign": 2, //disallow use of assignment in return statement diff --git a/templates/app/_package.json b/templates/app/_package.json index 7cb086235..6d6ff0091 100644 --- a/templates/app/_package.json +++ b/templates/app/_package.json @@ -22,7 +22,7 @@ <%# END CLIENT %> "core-js": "^2.2.1", "express": "^4.13.3", - "morgan": "~1.7.0", + "morgan": "^1.8.0", "body-parser": "^1.13.3", "method-override": "^2.3.5", "cookie-parser": "^1.3.5", @@ -92,7 +92,6 @@ "gulp-istanbul-enforcer": "^1.0.3", "gulp-load-plugins": "^1.0.0-rc.1", "gulp-mocha": "^2.1.3", - "gulp-node-inspector": "^0.1.0", "gulp-plumber": "^1.0.1", "gulp-protractor": "^3.0.0", "gulp-rev": "^7.0.0", diff --git a/templates/app/client/app/app.js b/templates/app/client/app/app.js index 2937399dd..cda6907e9 100644 --- a/templates/app/client/app/app.js +++ b/templates/app/client/app/app.js @@ -4,6 +4,7 @@ import angular from 'angular'; import ngCookies from 'angular-cookies'; import ngResource from 'angular-resource'; import ngSanitize from 'angular-sanitize'; + <%_ if(filters.socketio) { _%> import 'angular-socket-io';<% } %> <%_ if(filters.ngroute) { _%> @@ -12,9 +13,9 @@ const ngRoute = require('angular-route');<% } %> import uiRouter from 'angular-ui-router';<% } %> <%_ if(filters.uibootstrap) { _%> import uiBootstrap from 'angular-ui-bootstrap';<% } %> -// import ngMessages from 'angular-messages'; <%_ if(filters.auth) { _%> -// import ngValidationMatch from 'angular-validation-match';<% } %> +import 'angular-validation-match'; +<% } %> import {routeConfig} from './app.config'; @@ -49,7 +50,9 @@ angular.module('<%= scriptAppName %>', [ <%_ if(filters.auth) { %> _Auth, account, - admin,<% } _%> + admin, + 'validation.match', + <% } _%> navbar, footer, main, diff --git a/templates/app/client/components/auth(auth)/auth.service.js b/templates/app/client/components/auth(auth)/auth.service.js index e38a12632..b4fc54758 100644 --- a/templates/app/client/components/auth(auth)/auth.service.js +++ b/templates/app/client/components/auth(auth)/auth.service.js @@ -1,4 +1,7 @@ 'use strict'; + +import _ from 'lodash'; + // @flow class _User { _id: string = ''; @@ -185,9 +188,8 @@ export function AuthService($location, $http, $cookies, $q, appConfig, Util, Use * @param {Function|*} callback - optional, function(is) * @return {Bool|Promise} */ - isAdmin() { - return Auth.hasRole - .apply(Auth, [].concat.apply(['admin'], arguments)); + isAdmin(...args) { + return Auth.hasRole(...Reflect.apply([].concat, ['admin'], args)); }, /** @@ -196,6 +198,7 @@ export function AuthService($location, $http, $cookies, $q, appConfig, Util, Use * @return {Bool} */ isAdminSync() { + // eslint-disable-next-line no-sync return Auth.hasRoleSync('admin'); }, diff --git a/templates/app/client/components/modal(uibootstrap)/modal.service.js b/templates/app/client/components/modal(uibootstrap)/modal.service.js index 31de851db..5dff0da27 100644 --- a/templates/app/client/components/modal(uibootstrap)/modal.service.js +++ b/templates/app/client/components/modal(uibootstrap)/modal.service.js @@ -37,9 +37,9 @@ export function Modal($rootScope, $uibModal) { * @param {String} name - name or info to show on modal * @param {All} - any additional args are passed straight to del callback */ - return function() { - var args = Array.prototype.slice.call(arguments); - var name = args.shift(); + return function(...args) { + var slicedArgs = Reflect.apply(Array.prototype.slice, args); + var name = slicedArgs.shift(); var deleteModal; deleteModal = openModal({ @@ -64,7 +64,7 @@ export function Modal($rootScope, $uibModal) { }, 'modal-danger'); deleteModal.result.then(function(event) { - del.apply(event, args); + Reflect.apply(del, event, slicedArgs); }); }; } diff --git a/templates/app/gulpfile.babel.js b/templates/app/gulpfile.babel.js index 4e6db6421..357ef8d35 100644 --- a/templates/app/gulpfile.babel.js +++ b/templates/app/gulpfile.babel.js @@ -331,17 +331,11 @@ gulp.task('start:server:prod', () => { .on('log', onServerLog); }); -gulp.task('start:inspector', () => { - gulp.src([]) - .pipe(plugins.nodeInspector({ - debugPort: <%= debugPort %> - })); -}); - gulp.task('start:server:debug', () => { process.env.NODE_ENV = process.env.NODE_ENV || 'development'; config = require(`./${serverPath}/config/environment`); - nodemon(`-w ${serverPath} --debug=<%= debugPort %> --debug-brk ${serverPath}`) + // nodemon(`-w ${serverPath} --debug=<%= debugPort %> --debug-brk ${serverPath}`) + nodemon(`-w ${serverPath} --inspect --debug-brk ${serverPath}`) .on('log', onServerLog); }); @@ -385,7 +379,6 @@ gulp.task('serve:debug', cb => { 'typings'<% } %> ], 'webpack:dev', - 'start:inspector', ['start:server:debug', 'start:client'], 'watch', cb 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 b19e3ff36..c62104f0b 100644 --- a/templates/app/server/api/user(auth)/user.model(mongooseModels).js +++ b/templates/app/server/api/user(auth)/user.model(mongooseModels).js @@ -99,10 +99,10 @@ UserSchema // Validate email is not taken UserSchema .path('email') - .validate(function(value, respond) { + .validate(function(value) { <%_ if(filters.oauth) { -%> if(authTypes.indexOf(this.provider) !== -1) { - return respond(true); + return true; } <%_ } -%> @@ -110,11 +110,11 @@ UserSchema .then(user => { if(user) { if(this.id === user.id) { - return respond(true); + return true; } - return respond(false); + return false; } - return respond(true); + return true; }) .catch(function(err) { throw err; @@ -197,14 +197,16 @@ UserSchema.methods = { * @return {String} * @api public */ - makeSalt(byteSize, callback) { - var defaultByteSize = 16; + makeSalt(...args) { + let byteSize; + let callback; + let defaultByteSize = 16; - if(typeof arguments[0] === 'function') { - callback = arguments[0]; + if(typeof args[0] === 'function') { + callback = args[0]; byteSize = defaultByteSize; - } else if(typeof arguments[1] === 'function') { - callback = arguments[1]; + } else if(typeof args[1] === 'function') { + callback = args[1]; } else { throw new Error('Missing Callback'); } @@ -244,17 +246,20 @@ UserSchema.methods = { var salt = new Buffer(this.salt, 'base64'); if(!callback) { - return crypto.pbkdf2Sync(password, salt, defaultIterations, defaultKeyLength) + // eslint-disable-next-line no-sync + return crypto.pbkdf2Sync(password, salt, defaultIterations, + defaultKeyLength, 'sha1') .toString('base64'); } - return crypto.pbkdf2(password, salt, defaultIterations, defaultKeyLength, (err, key) => { - if(err) { - return callback(err); - } else { - return callback(null, key.toString('base64')); - } - }); + return crypto.pbkdf2(password, salt, defaultIterations, defaultKeyLength, + 'sha1', (err, key) => { + if(err) { + return callback(err); + } else { + return callback(null, key.toString('base64')); + } + }); } }; diff --git a/templates/app/server/api/user(auth)/user.model(sequelizeModels).js b/templates/app/server/api/user(auth)/user.model(sequelizeModels).js index 58e8f5ae2..991bc9403 100644 --- a/templates/app/server/api/user(auth)/user.model(sequelizeModels).js +++ b/templates/app/server/api/user(auth)/user.model(sequelizeModels).js @@ -135,8 +135,10 @@ export default function(sequelize, DataTypes) { * @return {String} * @api public */ - makeSalt(byteSize, callback) { - var defaultByteSize = 16; + makeSalt(...args) { + let byteSize; + let callback; + let defaultByteSize = 16; if(typeof arguments[0] === 'function') { callback = arguments[0]; @@ -177,6 +179,7 @@ export default function(sequelize, DataTypes) { var salt = new Buffer(this.salt, 'base64'); if(!callback) { + // eslint-disable-next-line no-sync return crypto.pbkdf2Sync(password, salt, defaultIterations, defaultKeyLength) .toString('base64'); } diff --git a/templates/app/server/config/seed(models).js b/templates/app/server/config/seed(models).js index cd4f07d33..053b26c66 100644 --- a/templates/app/server/config/seed(models).js +++ b/templates/app/server/config/seed(models).js @@ -17,8 +17,8 @@ export default function seedDatabaseIfNeeded() { <% if (filters.mongooseModels) { %>Thing.find({}).remove()<% } if (filters.sequelizeModels) { %>return Thing.destroy({ where: {} })<% } %> .then(() => { - <% if (filters.mongooseModels) { %>Thing.create({<% } - if (filters.sequelizeModels) { %>return Thing.bulkCreate([{<% } %> + <% if (filters.mongooseModels) { %>let thing = Thing.create({<% } + if (filters.sequelizeModels) { %>let thing = Thing.bulkCreate([{<% } %> name: 'Development Tools', info: 'Integration with popular tools such as Webpack, Gulp, Babel, TypeScript, Karma, ' + 'Mocha, ESLint, Node Inspector, Livereload, Protractor, Pug, ' @@ -47,6 +47,7 @@ export default function seedDatabaseIfNeeded() { + 'and openshift subgenerators' <% if (filters.mongooseModels) { %>});<% } if (filters.sequelizeModels) { %>}]);<% } %> + return thing; }) .then(() => console.log('finished populating things')) .catch(err => console.log('error populating things', err)); diff --git a/templates/endpoint/basename.controller.js b/templates/endpoint/basename.controller.js index a9b5fa74c..098f7d532 100644 --- a/templates/endpoint/basename.controller.js +++ b/templates/endpoint/basename.controller.js @@ -27,6 +27,7 @@ function respondWithResult(res, statusCode) { function patchUpdates(patches) { return function(entity) { try { + // eslint-disable-next-line prefer-reflect jsonpatch.apply(entity, patches, /*validate*/ true); } catch(err) { return Promise.reject(err); @@ -98,7 +99,7 @@ export function create(req, res) { // Upserts the given <%= classedName %> in the DB at the specified ID export function upsert(req, res) { if(req.body._id) { - delete req.body._id; + Reflect.deleteProperty(req.body, '_id'); } <%_ if(filters.mongooseModels) { -%> return <%= classedName %>.findOneAndUpdate({_id: req.params.id}, req.body, {new: true, upsert: true, setDefaultsOnInsert: true, runValidators: true}).exec()<% } %> @@ -115,7 +116,7 @@ export function upsert(req, res) { // Updates an existing <%= classedName %> in the DB export function patch(req, res) { if(req.body._id) { - delete req.body._id; + Reflect.deleteProperty(req.body, '_id'); } <% if(filters.mongooseModels) { %>return <%= classedName %>.findById(req.params.id).exec()<% } if(filters.sequelizeModels) { %>return <%= classedName %>.find({