From 06140da02d15e320b2bacc370d9ad731ceab35fe Mon Sep 17 00:00:00 2001 From: Ivan Montiel Date: Tue, 12 Jan 2016 20:37:31 -0700 Subject: [PATCH 1/4] Change make:view to create a pure view, add make:container --- README.md | 18 ++++++ .../templates/container.jsx.handlebars | 27 +++++++++ scaffolding/templates/view.jsx.handlebars | 11 +--- src/commands/MakeContainerCommand.js | 60 +++++++++++++++++++ src/commands/PrintDocumentationCommand.js | 3 +- src/strategies/CommandStrategy.js | 3 + 6 files changed, 111 insertions(+), 11 deletions(-) create mode 100644 scaffolding/templates/container.jsx.handlebars create mode 100644 src/commands/MakeContainerCommand.js diff --git a/README.md b/README.md index 20b0f0d..683a4d3 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ meteor * [create](#create) * [make:collection](#makecollection) * [make:command](#makecommand) +* [make:container](#makecontainer) * [make:migration](#makemigration) * [make:seeder](#makeseeder) * [make:view](#makeview) @@ -113,6 +114,23 @@ lib You can then call your command using `dispatch(CommandName, arg1, arg2)` or `dispatchAsync(CommandName, arg1, arg2, callback);`. +## make:container + +```sh +kitty make:container [Namespace] ViewName +``` + +This command will create a React container for the +given ViewName: + +``` +client +└──containers + └──[Namespace] + └── ViewName + └── ViewNameContainer.jsx +``` + ## make:meteor-method ```sh diff --git a/scaffolding/templates/container.jsx.handlebars b/scaffolding/templates/container.jsx.handlebars new file mode 100644 index 0000000..7c34ca0 --- /dev/null +++ b/scaffolding/templates/container.jsx.handlebars @@ -0,0 +1,27 @@ +/** + * {{#if hasNamespace}}{{namespace}} {{/if}}{{name}} + */ +{{#if hasNamespace}} +{{namespace}} = typeof {{namespace}} === 'undefined' ? {} : {{namespace}}; + +{{namespace}}.{{/if}}{{name}}Container = React.createClass({ + mixins: [ReactMeteorData, ReactBEM], + getMeteorData() { + return {}; + }, + getInitialState() { + return {}; + }, + componentDidMount() { + // + }, + bem_blocks: ['{{nameDashed}}'], + {{#if hasNamespace}} + bem_block_modifiers: ['{{namespaceDashed}}'], + {{/if}} + bem_render() { + return ( + <{{#if hasNamespace}}{{namespace}}{{/if}}{{name}} /> + ); + } +}); diff --git a/scaffolding/templates/view.jsx.handlebars b/scaffolding/templates/view.jsx.handlebars index 876b047..79d529b 100644 --- a/scaffolding/templates/view.jsx.handlebars +++ b/scaffolding/templates/view.jsx.handlebars @@ -5,19 +5,10 @@ {{namespace}} = typeof {{namespace}} === 'undefined' ? {} : {{namespace}}; {{namespace}}.{{/if}}{{name}} = React.createClass({ - mixins: [ReactMeteorData, ReactBEM], - getMeteorData() { - return {}; - }, - getInitialState() { - return {}; - }, + mixins: [React.addons.PureRenderMixin, ReactBEM], getDefaultProps() { return {}; }, - componentDidMount() { - // - }, bem_blocks: ['{{nameDashed}}'], {{#if hasNamespace}} bem_block_modifiers: ['{{namespaceDashed}}'], diff --git a/src/commands/MakeContainerCommand.js b/src/commands/MakeContainerCommand.js new file mode 100644 index 0000000..420969d --- /dev/null +++ b/src/commands/MakeContainerCommand.js @@ -0,0 +1,60 @@ +var Handlebars = require('handlebars'); +var read = require('read-file'); +var write = require('write'); +var path = require('path'); +var fs = require('fs'); +var MakeUtilities = require('../utilities/MakeUtilities'); + +var MakeContainerCommand = function () { + var _arguments = Array.prototype.slice.call(arguments); + var _namespace = (_arguments.length > 1 ? _arguments[0] : ''); + var _namespaceDashed = MakeUtilities.camelToDash(_namespace); + var _hasNamespace = (_arguments.length > 1); + var _name = (_arguments.length > 1 ? _arguments[1] : _arguments[0] ); + var _nameDashed = MakeUtilities.camelToDash(_name); + + var _templatePath = function() { + return path.join(__dirname, '..', '..', 'scaffolding', 'templates', 'container.jsx.handlebars'); + } + + var _createPath = function(workingDirectory) { + // TODO allow the user to create the new view from anywhere in the project (not just the root) + var componentRoot = path.join(workingDirectory, 'client', 'containers'); + + if (_hasNamespace) { + componentRoot = path.join(componentRoot, _namespace); + } + + componentRoot = path.join(componentRoot, _name); + + return componentRoot; + } + + var _templatize = function (templatePath) { + var raw = read.sync(templatePath, { encoding: 'utf8' }); + var template = Handlebars.compile(raw); + return template({ + namespace: _namespace, + namespaceDashed: _namespaceDashed, + hasNamespace: _hasNamespace, + name: _name, + nameDashed: _nameDashed + }); + } + + var handle = function () { + var jsxContent = _templatize(_templatePath()); + + var workingDirectory = process.cwd(); + var base = _createPath(workingDirectory); + + write.sync(path.join(base, _name + 'Container.jsx'), jsxContent); + + }; + + return { + handle: handle + } +}; + +module.exports = MakeContainerCommand; diff --git a/src/commands/PrintDocumentationCommand.js b/src/commands/PrintDocumentationCommand.js index 67fc8f7..93020d2 100644 --- a/src/commands/PrintDocumentationCommand.js +++ b/src/commands/PrintDocumentationCommand.js @@ -8,8 +8,9 @@ var PrintDocumentationCommand = function () { console.log('├── db'); console.log('| └── seed ─ Seed the database using your seeders'); console.log('├── make'); - console.log('| ├── command ─ Create a dispatchable command'); console.log('| ├── collection ─ Create a collection (only supports Mongo)'); + console.log('| ├── command ─ Create a dispatchable command'); + console.log('| ├── container ─ Create a React container for a View'); console.log('| ├── meteor-method ─ Create a Meteor method'); console.log('| ├── model-factory ─ Create a model factory for the given collection'); console.log('| ├── migration ─ Create a migration (uses percolate:migrations)'); diff --git a/src/strategies/CommandStrategy.js b/src/strategies/CommandStrategy.js index e52e19d..24b4c9d 100644 --- a/src/strategies/CommandStrategy.js +++ b/src/strategies/CommandStrategy.js @@ -1,6 +1,7 @@ var MeowCommand = require('../commands/MeowCommand'); var CreateCommand = require('../commands/CreateCommand'); var MakeViewCommand = require('../commands/MakeViewCommand'); +var MakeContainerCommand = require('../commands/MakeContainerCommand'); var MakeCommandCommand = require('../commands/MakeCommandCommand'); var MakeCollectionCommand = require('../commands/MakeCollectionCommand'); var MakeMeteorMethodCommand = require('../commands/MakeMeteorMethodCommand'); @@ -49,6 +50,8 @@ var CommandStrategy = function(commandPattern, args, flags) { case 'make:collection': _commander(MakeCollectionCommand); break; + case 'make:container': + _commander(MakeContainerCommand); case 'make:migration': _commander(AddMigrationPackageCommand); _commander(MakeMigrationCommand); From 14ebfe3d79f24119084a9264dd2b9f619e5dfbc8 Mon Sep 17 00:00:00 2001 From: Ivan Montiel Date: Wed, 13 Jan 2016 22:56:15 -0700 Subject: [PATCH 2/4] Add prop types to view --- scaffolding/templates/view.jsx.handlebars | 1 + 1 file changed, 1 insertion(+) diff --git a/scaffolding/templates/view.jsx.handlebars b/scaffolding/templates/view.jsx.handlebars index 79d529b..2082524 100644 --- a/scaffolding/templates/view.jsx.handlebars +++ b/scaffolding/templates/view.jsx.handlebars @@ -6,6 +6,7 @@ {{namespace}}.{{/if}}{{name}} = React.createClass({ mixins: [React.addons.PureRenderMixin, ReactBEM], + propTypes: {}, getDefaultProps() { return {}; }, From 4aec89f7ee407c24a6a575de283e95dfcfa5acb5 Mon Sep 17 00:00:00 2001 From: Ivan Montiel Date: Fri, 15 Jan 2016 17:55:05 -0700 Subject: [PATCH 3/4] Minor template fixes --- scaffolding/templates/container.jsx.handlebars | 2 +- scaffolding/templates/view.jsx.handlebars | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scaffolding/templates/container.jsx.handlebars b/scaffolding/templates/container.jsx.handlebars index 7c34ca0..6660261 100644 --- a/scaffolding/templates/container.jsx.handlebars +++ b/scaffolding/templates/container.jsx.handlebars @@ -21,7 +21,7 @@ {{/if}} bem_render() { return ( - <{{#if hasNamespace}}{{namespace}}{{/if}}{{name}} /> + <{{#if hasNamespace}}{{namespace}}.{{/if}}{{name}} /> ); } }); diff --git a/scaffolding/templates/view.jsx.handlebars b/scaffolding/templates/view.jsx.handlebars index 2082524..045a33a 100644 --- a/scaffolding/templates/view.jsx.handlebars +++ b/scaffolding/templates/view.jsx.handlebars @@ -17,7 +17,7 @@ bem_render() { return (
-

Hello

+

{{#if hasNamespace}}{{namespace}} {{/if}}{{name}} says Hello

); } From 0b7d8a78294bef2286893d2cdd9311dda41e20a2 Mon Sep 17 00:00:00 2001 From: Ivan Montiel Date: Sat, 16 Jan 2016 10:07:45 -0700 Subject: [PATCH 4/4] Add make:test generator --- scaffolding/project/.meteor/packages | 22 +++--- scaffolding/templates/test-spec.js.handlebars | 5 ++ src/commands/MakeTestCommand.js | 68 +++++++++++++++++++ src/strategies/CommandStrategy.js | 4 ++ 4 files changed, 88 insertions(+), 11 deletions(-) create mode 100644 scaffolding/templates/test-spec.js.handlebars create mode 100644 src/commands/MakeTestCommand.js diff --git a/scaffolding/project/.meteor/packages b/scaffolding/project/.meteor/packages index f897047..0438b7e 100644 --- a/scaffolding/project/.meteor/packages +++ b/scaffolding/project/.meteor/packages @@ -19,20 +19,20 @@ ecmascript # Enable ECMAScript2015+ syntax in app code autopublish # Publish all data to the clients (for prototyping) insecure # Allow all DB writes from clients (for prototyping) -jsx -react -react-runtime -react-meteor-data -kadira:flow-router -kadira:react-layout +react # React, includes jsx and react-runtime +react-meteor-data # Mixin for React components +kadira:flow-router # Non-reactive router +kadira:react-layout # Layouts for React routes -fourseven:scss -poetic:materialize-scss -fortawesome:fontawesome +fourseven:scss # SCSS support +poetic:materialize-scss # Materialize with SCSS files +fortawesome:fontawesome # FontAwesome -tap:i18n +tap:i18n # Internationalization support -aldeed:collection2 +aldeed:collection2 # Schemas for Mongo collections + +sanjo:jasmine # Jasmine Tests capsulecat:react-bem capsulecat:commands diff --git a/scaffolding/templates/test-spec.js.handlebars b/scaffolding/templates/test-spec.js.handlebars new file mode 100644 index 0000000..2d13667 --- /dev/null +++ b/scaffolding/templates/test-spec.js.handlebars @@ -0,0 +1,5 @@ +describe('{{name}}', function () { + it('is true', function () { + expect(true).toBe(false); + }); +}); diff --git a/src/commands/MakeTestCommand.js b/src/commands/MakeTestCommand.js new file mode 100644 index 0000000..68df777 --- /dev/null +++ b/src/commands/MakeTestCommand.js @@ -0,0 +1,68 @@ +var Handlebars = require('handlebars'); +var read = require('read-file'); +var write = require('write'); +var path = require('path'); +var fs = require('fs'); +var MakeUtilities = require('../utilities/MakeUtilities'); + +var MakeTestCommand = function () { + var _arguments = Array.prototype.slice.call(arguments); + var _name = (_arguments.length > 1 ? _arguments[1] : _arguments[0] ); + var _nameDashed = MakeUtilities.camelToDash(_name); + + var _testRunner = 'jasmine'; + var _typeOfTest = 'integration'; + + var _templatePath = function() { + return path.join(__dirname, '..', '..', 'scaffolding', 'templates', 'test-spec.js.handlebars'); + } + + var _createPath = function(workingDirectory) { + // TODO allow the user to create the new view from anywhere in the project (not just the root) + var componentRoot = path.join(workingDirectory, 'test', _testRunner); + + if (_typeOfTest === 'integration') { + componentRoot = path.join(componentRoot, 'client'); + } else if (_typeOfTest === 'unit' ) { + componentRoot = path.join(componentRoot, 'server'); + } + + componentRoot = path.join(componentRoot, _typeOfTest); + + return componentRoot; + } + + var _templatize = function (templatePath) { + var raw = read.sync(templatePath, { encoding: 'utf8' }); + var template = Handlebars.compile(raw); + return template({ + name: _name, + nameDashed: _nameDashed + }); + } + + var handle = function (flags) { + _typeOfTest = (function () { + if (flags.indexOf('--integration') !== -1) { + return 'integration'; + } else if (flags.indexOf('--unit') !== -1) { + return 'unit'; + } else { + return 'integration'; + } + })(); + + var jsContent = _templatize(_templatePath()); + + var workingDirectory = process.cwd(); + var base = _createPath(workingDirectory); + + write.sync(path.join(base, _name + '-spec.js'), jsContent); + }; + + return { + handle: handle + } +}; + +module.exports = MakeTestCommand; diff --git a/src/strategies/CommandStrategy.js b/src/strategies/CommandStrategy.js index 24b4c9d..84c60cf 100644 --- a/src/strategies/CommandStrategy.js +++ b/src/strategies/CommandStrategy.js @@ -15,6 +15,7 @@ var MakeModelFactoryCommand = require('../commands/MakeModelFactoryCommand'); var MakeSeederCommand = require('../commands/MakeSeederCommand'); var AddSeederRunnerCommand = require('../commands/AddSeederRunnerCommand'); var SeedDatabaseCommand = require('../commands/SeedDatabaseCommand'); +var MakeTestCommand = require('../commands/MakeTestCommand'); var CommandStrategy = function(commandPattern, args, flags) { var _commander = function(klass) { @@ -64,6 +65,9 @@ var CommandStrategy = function(commandPattern, args, flags) { _commander(MakeSeederCommand); _commander(AddSeederRunnerCommand); break; + case 'make:test': + _commander(MakeTestCommand); + break; case 'remind-me:react-loop': _reminder(ReactLoopReminder); break;