Skip to content

Commit

Permalink
- All main project dependencies have been updated except sendgrid.
Browse files Browse the repository at this point in the history
- eslint added to the main project. eslint config file added and removed from the package.json
- main project es6 implemented ( changed vars for consts, let and es6 literal objects and functions )
- Main project tests and generator template were broken because the new version of Yeoman has a different way to extend the generator and spawnCommand was moved to another path.
- blueBird promises removed.. Now we are going to use js native promises.

Note:
Main project tests have been fixed but output tests are broken. Probably it is happening because the dependecies update ( new way to use them, ect .)
  • Loading branch information
maustand committed Mar 9, 2018
1 parent d42d788 commit 2ab4e39
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 217 deletions.
12 changes: 12 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extends": ["eslint:recommended"],
"env": {
"node": true,
"es6": true,
"mocha": true
},
"rules": {
"no-var": "error",
"semi": ["error", "always"]
}
}
227 changes: 127 additions & 100 deletions generators/api/index.js
Original file line number Diff line number Diff line change
@@ -1,168 +1,187 @@
'use strict';
var path = require('path');
var yeoman = require('yeoman-generator');
var pluralize = require('pluralize');
var _ = require('lodash');
var recast = require('recast');
var reservedWords = require('reserved-words');

module.exports = yeoman.Base.extend({
prompting: function () {
var srcDir = this.config.get('srcDir') || 'src';
var apiDir = this.config.get('apiDir') || 'api';
var authMethods = this.config.get('authMethods') || [];

var methods = [
{name: 'Create (POST)', value: 'POST'},
{name: 'Retrieve list (GET)', value: 'GET LIST'},
{name: 'Retrieve one (GET)', value: 'GET ONE'},
{name: 'Update (PUT)', value: 'PUT'},
{name: 'Delete (DELETE)', value: 'DELETE'}
const path = require('path');
const generator = require('yeoman-generator');
const pluralize = require('pluralize');
const { camelCase, findLastIndex, findIndex, upperFirst, lowerCase } = require('lodash');
const recast = require('recast');
const reservedWords = require('reserved-words');

module.exports = class extends generator {

prompting () {
const srcDir = this.config.get('srcDir') || 'src';
const apiDir = this.config.get('apiDir') || 'api';
const authMethods = this.config.get('authMethods') || [];

const methods = [
{ name: 'Create (POST)', value: 'POST' },
{ name: 'Retrieve list (GET)', value: 'GET LIST' },
{ name: 'Retrieve one (GET)', value: 'GET ONE' },
{ name: 'Update (PUT)', value: 'PUT' },
{ name: 'Delete (DELETE)', value: 'DELETE' }
];

var getSelectedMethods = function (props) {
return methods.filter(function (method) {
const getSelectedMethods = (props) => {
return methods.filter((method) => {
return props.methods.indexOf(method.value) !== -1;
});
};

var prompts = [{
const prompts = [{
type: 'input',
name: 'kebab',
message: 'What\'s the API name?',
default: 'some-entity'
}, {
},
{
type: 'input',
name: 'lowerSuffix',
message: 'Name is a reserved word, add suffix for lowercase identifier',
default: 'Obj',
when: function (props) {
return reservedWords.check(_.lowerCase(props.kebab), 6);
when (props) {
return reservedWords.check(lowerCase(props.kebab), 6);
}
}, {
},
{
type: 'input',
name: 'kebabs',
message: 'What\'s the endpoint name?',
default: function (props) {
default (props) {
return pluralize(props.kebab);
}
}, {
},
{
type: 'input',
name: 'dir',
message: 'Where to put the code?',
default: srcDir + '/' + apiDir
}, {
},
{
type: 'checkbox',
name: 'methods',
message: 'Which methods it will have?',
default: methods.map(function (method) {
default: methods.map((method) => {
return method.value;
}),
choices: methods.map(function (method) {
return _.assign({}, method, {checked: true});
choices: methods.map((method) => {
return Object.assign({}, method, {checked: true});
})
}, {
},
{
type: 'checkbox',
name: 'masterMethods',
message: 'Which methods are protected by the master key?',
choices: getSelectedMethods,
default: [],
when: function () {
when () {
return authMethods.length;
}
}, {
},
{
type: 'checkbox',
name: 'adminMethods',
message: 'Which methods are only accessible by authenticated admin users?',
default: [],
choices: function (props) {
var choices = getSelectedMethods(props);
return choices.map(function (choice) {
choices (props) {
const choices = getSelectedMethods(props);
return choices.map((choice) => {
if (props.masterMethods.indexOf(choice.value) !== -1) {
return _.assign({}, choice, {disabled: 'Accessible only with master key'});
return Object.assign({}, choice, {disabled: 'Accessible only with master key'});
}
return choice;
});
},
when: function () {
when () {
return authMethods.length;
}
}, {
},
{
type: 'checkbox',
name: 'userMethods',
message: 'Which methods are only accessible by authenticated users?',
default: [],
choices: function (props) {
var choices = getSelectedMethods(props);
return choices.map(function (choice) {
choices (props) {

const choices = getSelectedMethods(props);

return choices.map((choice) => {

if (props.masterMethods.indexOf(choice.value) !== -1) {
return _.assign({}, choice, {disabled: 'Accessible only with master key'});
} else if (props.adminMethods.indexOf(choice.value) !== -1) {
return _.assign({}, choice, {disabled: 'Accessible only by admin users'});
return Object.assign({}, choice, {disabled: 'Accessible only with master key'});
}
else if (props.adminMethods.indexOf(choice.value) !== -1) {
return Object.assign({}, choice, {disabled: 'Accessible only by admin users'});
}

return choice;

});
},
when: function () {
when () {
return authMethods.length;
}
}, {
},
{
type: 'confirm',
name: 'generateModel',
message: 'Do you want to generate a model?',
default: true
}, {
},
{
type: 'input',
name: 'modelFields',
message: 'Which fields the model will have? (comma separated, do not include id)',
when: function (props) {
when (props) {
return props.generateModel;
}
}, {
},
{
type: 'confirm',
name: 'storeUser',
default: true,
message: function (props) {
message (props) {
return 'Do you want to store in a field the user who created the ' + props.kebab + '?';
},
when: function (props) {
when (props) {
return props.generateModel && props.userMethods && props.userMethods.indexOf('POST') !== -1;
}
}, {
},
{
type: 'input',
name: 'userField',
message: 'What\'s the name of the field which will store the user?',
default: 'user',
when: function (props) {
when (props) {
return props.storeUser;
}
}, {
},
{
type: 'confirm',
name: 'getList',
message: 'Do you want the retrieve methods (GET) to have the form { rows, count } ?',
default: false,
when: function (props) {
var methods = getSelectedMethods(props);
return methods.find(function (method) {
when (props) {
const methods = getSelectedMethods(props);

return methods.find((method) => {
return method.value === 'GET LIST';
}) && props.generateModel;
}
}];

return this.prompt(prompts).then(function (props) {
return this.prompt(prompts).then((props) => {
this.props = props;
this.props.camel = _.camelCase(this.props.kebab);
this.props.camels = pluralize(this.props.camel);
this.props.pascal = _.upperFirst(this.props.camel);
this.props.pascals = _.upperFirst(this.props.camels);
this.props.lower = _.lowerCase(this.props.camel);
this.props.lowers = _.lowerCase(this.props.camels);
this.props.start = _.upperFirst(this.props.lower);
this.props.starts = _.upperFirst(this.props.lowers);
this.props.camel = camelCase(this.props.kebab);
this.props.camels = pluralize(this.props.camel);
this.props.pascal = upperFirst(this.props.camel);
this.props.pascals = upperFirst(this.props.camels);
this.props.lower = lowerCase(this.props.camel);
this.props.lowers = lowerCase(this.props.camels);
this.props.start = upperFirst(this.props.lower);
this.props.starts = upperFirst(this.props.lowers);

// append suffix so we don't get reserved word clashes
if (this.props.lowerSuffix) {
this.props.camel = _.lowerCase(this.props.camel) + this.props.lowerSuffix;
this.props.camel = lowerCase(this.props.camel) + this.props.lowerSuffix;
}

this.props.authMethods = authMethods;
Expand All @@ -171,26 +190,26 @@ module.exports = yeoman.Base.extend({

this.props.modelFields = this.props.modelFields || '';
this.props.modelFields = this.props.modelFields ?
this.props.modelFields.split(',').map(function (field) {
return field.trim();
}) : [];
this.props.modelFields.split(',').map((field) => {
return field.trim();
}) : [];

this.props.getList = props.getList || false;
this.props.storeUser = this.props.storeUser || false;

if (props.userField && this.props.modelFields.indexOf(props.userField) !== -1) {
this.props.modelFields.splice(this.props.modelFields.indexOf(props.userField), 1);
}
}.bind(this));
},

writing: function () {
var props = this.props;
var routesFile = path.join(props.dir, 'index.js');
var copyTpl = this.fs.copyTpl.bind(this.fs);
var tPath = this.templatePath.bind(this);
var dPath = this.destinationPath.bind(this);
var filepath = function (filename) {
});
}
writing () {

const props = this.props;
const routesFile = path.join(props.dir, 'index.js');
const copyTpl = this.fs.copyTpl.bind(this.fs);
const tPath = this.templatePath.bind(this);
const dPath = this.destinationPath.bind(this);
const filepath = (filename) => {
return path.join(props.dir, props.kebab, filename);
};

Expand All @@ -204,43 +223,51 @@ module.exports = yeoman.Base.extend({
}

if (this.fs.exists(routesFile)) {
var ast = recast.parse(this.fs.read(routesFile));
var body = ast.program.body;
var lastImportIndex = _.findLastIndex(body, function (statement) {

const ast = recast.parse(this.fs.read(routesFile));
const body = ast.program.body;
const lastImportIndex = findLastIndex(body, (statement) => {
return statement.type === 'ImportDeclaration';
});
var actualImportCode = recast.print(body[lastImportIndex]).code;
var importString = ['import ', props.camel, ' from \'./', props.kebab, '\''].join('');
const actualImportCode = recast.print(body[lastImportIndex]).code;
const importString = ['import ', props.camel, ' from \'./', props.kebab, '\''].join('');

body.splice(lastImportIndex, 1, importString);
body.splice(lastImportIndex, 0, actualImportCode);

var middlewareString = [
'router.use(\'/', props.kebabs, '\', ', props.camel, ')'
].join('');
var lastMiddlewareIndex = _.findLastIndex(body, function (statement) {
const middlewareString = ['router.use(\'/', props.kebabs, '\', ', props.camel, ')'].join('');

const lastMiddlewareIndex = findLastIndex(body, function (statement) {
if (!statement.expression || !statement.expression.callee) {
return false;
}
var callee = statement.expression.callee;

const callee = statement.expression.callee;
return callee.object.name === 'router' && callee.property.name === 'use';

});

if (lastMiddlewareIndex === -1) {
var exportRouterIndex = _.findIndex(body, function (statement) {

const exportRouterIndex = findIndex(body, function (statement) {
return statement.type === 'ExportDefaultDeclaration';
});

body.splice(exportRouterIndex, 0, middlewareString);
} else {
var actualMiddlewareCode = recast.print(body[lastMiddlewareIndex]).code;
}
else {

const actualMiddlewareCode = recast.print(body[lastMiddlewareIndex]).code;

body.splice(lastMiddlewareIndex, 1, middlewareString);
body.splice(lastMiddlewareIndex, 0, actualMiddlewareCode);
}

this.fs.write(routesFile, recast.print(ast).code);
}
},
}

install: function () {
install () {

}
});
};
Loading

0 comments on commit 2ab4e39

Please sign in to comment.