Merge pull request #78 from CrshOverride/master

Add support for Flux
This commit is contained in:
Simon Bailey
2015-04-02 20:56:42 +01:00
16 changed files with 292 additions and 18 deletions
+26
View File
@@ -0,0 +1,26 @@
'use strict';
var util = require('util');
var ScriptBase = require('../script-base.js');
var ActionGenerator = module.exports = function ActionGenerator(args, options, config) {
args[0] += 'ActionCreators';
ScriptBase.apply(this, arguments);
}
util.inherits(ActionGenerator, ScriptBase);
ActionGenerator.prototype.createActionFile = function createActionFile() {
this.option('es6');
this.es6 = this.options.es6;
console.log(this.name);
this.generateSourceAndTest(
'Action',
'spec/Action',
void(0),
'actions',
false
);
}
+16
View File
@@ -13,6 +13,7 @@ var ReactWebpackGenerator = module.exports = function ReactWebpackGenerator(args
this.appname = this._.camelize(this._.slugify(this._.humanize(this.appname)));
this.scriptAppName = this._.capitalize(this.appname) + generalUtils.appName(this);
this.config.set('app-name', this.appname);
args = ['main'];
@@ -65,6 +66,20 @@ ReactWebpackGenerator.prototype.askForReactRouter = function () {
}.bind(this));
};
ReactWebpackGenerator.prototype.askForFlux = function() {
var done = this.async();
this.prompt({
type : 'confirm',
name : 'flux',
message : 'Would you like to include flux?',
default : false
}, function(props) {
this.env.options.flux = props.flux;
this.config.set('flux', props.flux);
done();
}.bind(this));
};
ReactWebpackGenerator.prototype.askForStylesLanguage = function () {
var done = this.async();
this.prompt({
@@ -98,6 +113,7 @@ ReactWebpackGenerator.prototype.createIndexHtml = function createIndexHtml() {
ReactWebpackGenerator.prototype.packageFiles = function () {
this.es6 = this.options.es6;
this.reactRouter = this.env.options.reactRouter;
this.flux = this.env.options.flux;
this.stylesLanguage = this.env.options.stylesLanguage;
this.template('../../templates/common/_package.json', 'package.json');
this.template('../../templates/common/_webpack.config.js', 'webpack.config.js');
+3 -5
View File
@@ -3,23 +3,21 @@ var util = require('util');
var ScriptBase = require('../script-base.js');
var ComponentGenerator = module.exports = function ComponentGenerator(args, options, config) {
ScriptBase.apply(this, arguments);
};
util.inherits(ComponentGenerator, ScriptBase);
ComponentGenerator.prototype.createComponentFile = function createComponentFile() {
this.option('es6');
this.option('es6');
this.es6 = this.options.es6;
console.log('es6:', this.es6)
this.generateSourceAndTest(
'Component',
'spec/Component',
'styles/Component',
'components'
'components',
true
);
};
+6
View File
@@ -20,3 +20,9 @@ MainGenerator.prototype.createMainFile = function createMainFile() {
this.appTemplate('main', 'components/main');
}
};
MainGenerator.prototype.createDispatcher = function createDispatcher() {
if(this.env.options.flux) {
this.appTemplate('Dispatcher', 'dispatcher/' + this.scriptAppName + 'Dispatcher');
}
};
+6 -6
View File
@@ -8,8 +8,8 @@ var Generator = module.exports = function Generator() {
yeoman.generators.NamedBase.apply(this, arguments);
// Add capitalize mixin
this._.mixin({ 'capitalize': generalUtils.capitalize });
this._.mixin({ 'capitalizeFile': generalUtils.capitalizeFile });
this._.mixin({ 'capitalize': generalUtils.capitalize });
this._.mixin({ 'capitalizeFile': generalUtils.capitalizeFile });
this._.mixin({ 'capitalizeClass': generalUtils.capitalizeClass });
this._.mixin({ 'lowercase': generalUtils.lowercase });
@@ -18,8 +18,8 @@ var Generator = module.exports = function Generator() {
this.appname = this._.slugify(this._.humanize(this.appname));
this.scriptAppName = this._.camelize(this._.capitalize(this.appname)) + generalUtils.appName(this);
this.classedFileName = this._.capitalizeFile(this.name);
this.classedName = this._.capitalizeClass(this.name);
this.stylesLanguage = this.config.get('styles-language');
this.classedName = this._.capitalizeClass(this.name);
this.stylesLanguage = this.config.get('styles-language');
if (typeof this.options.appPath === 'undefined') {
this.options.appPath = this.options.appPath || 'src/scripts';
@@ -88,8 +88,8 @@ Generator.prototype.htmlTemplate = function (src, dest) {
]);
};
Generator.prototype.generateSourceAndTest = function (appTemplate, testTemplate, stylesTemplate, targetDirectory) {
Generator.prototype.generateSourceAndTest = function (appTemplate, testTemplate, stylesTemplate, targetDirectory, includeStyles) {
this.appTemplate(appTemplate, path.join(targetDirectory, this._.capitalizeFile(this.name)));
this.testTemplate(testTemplate, path.join(targetDirectory, this._.capitalizeFile(this.name)));
this.stylesTemplate(stylesTemplate, path.join(this._.capitalizeFile(this.name)));
if(includeStyles) this.stylesTemplate(stylesTemplate, path.join(this._.capitalizeFile(this.name)));
};
+25
View File
@@ -0,0 +1,25 @@
'use strict';
var util = require('util');
var ScriptBase = require('../script-base.js');
var ActionGenerator = module.exports = function ActionGenerator(args, options, config) {
args[0] += 'Store';
ScriptBase.apply(this, arguments);
}
util.inherits(ActionGenerator, ScriptBase);
ActionGenerator.prototype.createActionFile = function createActionFile() {
this.option('es6');
this.es6 = this.options.es6;
this.dispatcherName = this._.capitalizeFile(this.config.get('app-name')) + 'AppDispatcher';
this.generateSourceAndTest(
'Store',
'spec/Store',
void(0),
'stores',
false
);
}
+4 -1
View File
@@ -10,7 +10,10 @@
"mainInput": "<% if (reactRouter) { %>main<% } else { %><%= scriptAppName %><% } %>",
"mainOutput": "main",
"dependencies": {<% if (reactRouter) { %>
"react-router": "^0.11.6",<% } %>
"react-router": "^0.11.6",<% } if (flux) { %>
"flux": "^2.0.1",
"events": "^1.0.2",
"object-assign": "^2.0.0", <% } %>
"react": "~0.12.2",
"normalize.css": "~3.0.3"
},
+3 -1
View File
@@ -31,7 +31,9 @@ module.exports = {
extensions: ['', '.js'],
alias: {
'styles': '../../../src/styles',
'components': '../../../src/scripts/components/'
'components': '../../../src/scripts/components/'<% if(flux) { %>,
'stores': '../../../src/scripts/stores/',
'actions': '../../../src/scripts/actions/'<% } %>
}
},
module: {
+3 -1
View File
@@ -36,7 +36,9 @@ module.exports = {
extensions: ['', '.js'],
alias: {
'styles': '../../../src/styles',
'components': '../../../src/scripts/components/'
'components': '../../../src/scripts/components/'<% if(flux) { %>,
'stores': '../../../src/scripts/stores/',
'actions': '../../../src/scripts/actions/'<% } %>
}
},
+9 -3
View File
@@ -8,10 +8,14 @@ module.exports = function (config) {
frameworks: ['jasmine'],
files: [
'test/helpers/**/*.js',
'test/spec/components/**/*.js'
'test/spec/components/**/*.js'<% if(flux) { %>,
'test/spec/stores/**/*.js',
'test/spec/actions/**/*.js'<% } %>
],
preprocessors: {
'test/spec/components/**/*.js': ['webpack']
'test/spec/components/**/*.js': ['webpack']<% if(flux) { %>,
'test/spec/stores/**/*.js': ['webpack'],
'test/spec/actions/**/*.js': ['webpack']<% } %>
},
webpack: {
cache: true,
@@ -48,7 +52,9 @@ module.exports = function (config) {
resolve: {
alias: {
'styles': path.join(process.cwd(), './src/styles/'),
'components': path.join(process.cwd(), './src/scripts/components/')
'components': path.join(process.cwd(), './src/scripts/components/')<% if(flux) { %>,
'stores': '../../../src/scripts/stores/',
'actions': '../../../src/scripts/actions/'<% } %>
}
}
},
+8
View File
@@ -0,0 +1,8 @@
'use strict';
var <%= classedName %> = {
}
<% if (es6) { %> export default <%= classedName %>; <% }
else { %>module.exports = <%= classedName %>; <% } %>
+3
View File
@@ -0,0 +1,3 @@
var Dispatcher = require('flux').Dispatcher;
module.exports = new Dispatcher();
+20
View File
@@ -0,0 +1,20 @@
'use strict';
var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
var <%= dispatcherName %> = require('../dispatcher/<%= dispatcherName %>');
var <%= classedName %> = assign({}, EventEmitter.prototype, {
});
<%= classedName %>.dispatchToken = <%= dispatcherName %>.register(function(action) {
switch(action.type) {
default:
}
});
<% if (es6) { %> export default <%= classedName %>; <% }
else { %>module.exports = <%= classedName %>; <% } %>
+13
View File
@@ -0,0 +1,13 @@
'use strict';
describe('<%= classedName %>', function() {
var action;
beforeEach(function() {
action = require('actions/<%= classedFileName %>.js');
});
it('should be defined', function() {
expect(action).toBeDefined();
});
});
+13
View File
@@ -0,0 +1,13 @@
'use strict';
describe('<%= classedName %>', function() {
var store;
beforeEach(function() {
store = require('stores/<%= classedFileName %>.js');
});
it('should be defined', function() {
expect(store).toBeDefined();
});
});
+134 -1
View File
@@ -124,6 +124,22 @@ describe('react-webpack generator', function() {
});
});
it('should not have any flux assets configured', function(done) {
react.run({}, function() {
assert.noFileContent([
['package.json', /flux/],
['package.json', /events/],
['package.json', /object-assign/],
['karma.conf.js', /resolve[\S\s]+alias[\S\s]+stores/m],
['webpack.config.js', /resolve[\S\s]+alias[\S\s]+stores/m],
['webpack.dist.config.js', /resolve[\S\s]+alias[\S\s]+stores/m]
]);
assert.noFile('src/scripts/dispatcher/TempTestAppDispatcher.js');
done();
});
});
});
describe('Generator', function () {
@@ -170,7 +186,55 @@ describe('react-webpack generator', function() {
});
describe('Subgenerators', function() {
describe('When using Flux', function() {
beforeEach(function(done) {
helpers.mockPrompt(react, {
flux: true
});
react.run({}, function() {
done();
})
});
it('should add flux, events, and object-assign packages', function(done) {
assert.fileContent([
['package.json', /flux/],
['package.json', /events/],
['package.json', /object-assign/]
]);
done();
});
it('should add stores and actions alias to karma config', function(done) {
assert.fileContent([
['karma.conf.js', /resolve[\S\s]+alias[\S\s]+stores/m]
]);
done();
});
it('should add stores and actions alias to webpack configs', function(done) {
assert.fileContent([
['webpack.config.js', /resolve[\S\s]+alias[\S\s]+stores/m],
['webpack.dist.config.js', /resolve[\S\s]+alias[\S\s]+stores/m]
]);
done();
});
it('should have a Dispatcher generated', function(done) {
setTimeout(function(){
assert.file('src/scripts/dispatcher/TempTestAppDispatcher.js');
done();
});
})
});
describe('When generating a Component', function() {
var generatorTest = function(name, generatorType, specType, targetDirectory, scriptNameFn, specNameFn, suffix, done) {
var deps = [path.join('../..', generatorType)];
@@ -209,4 +273,73 @@ describe('react-webpack generator', function() {
});
describe('When generating an Action', function() {
beforeEach(function(done){
helpers.mockPrompt(react, {
flux: true
});
react.run({}, function() {
var generator =
helpers.createGenerator(
'react-webpack:action',
[path.join('../../action')],
['Test'],
{ appPath: 'src/scripts' }
);
react.run([], function() {
generator.run([], function() {
done();
})
});
});
});
it('should generate a new action with tests', function(done) {
assert.fileContent([
['src/scripts/actions/TestActionCreators.js', /var TestActionCreators/g],
['test/spec/actions/TestActionCreators.js', /require\('actions\/TestActionCreators.js'\)/g],
['test/spec/actions/TestActionCreators.js', /describe\('TestActionCreators'/g]
]);
done();
});
});
describe('When generating a Store', function() {
beforeEach(function(done) {
helpers.mockPrompt(react, {
flux: true
});
react.run({}, function() {
var generator =
helpers.createGenerator(
'react-webpack:store',
[path.join('../../store')],
['Test'],
{ appPath: 'src/scripts' }
);
react.run([], function() {
generator.run([], function() {
done();
});
});
});
});
it('should generate a new store with tests', function(done) {
assert.fileContent([
['src/scripts/stores/TestStore.js', /var TestStore/g],
['test/spec/stores/TestStore.js', /require\('stores\/TestStore.js'\)/g],
['test/spec/stores/TestStore.js', /describe\('TestStore'/g]
]);
done();
});
});
});