├── .editorconfig ├── .eslintrc-base ├── .eslintrc-node ├── .eslintrc-node-test ├── .gitattributes ├── .gitignore ├── .travis.yml ├── .yo-rc.json ├── README.md ├── app ├── index.js └── templates │ ├── _CONTRIBUTING.md │ └── _README.md ├── package.json └── test └── app.spec.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.eslintrc-base: -------------------------------------------------------------------------------- 1 | --- 2 | plugins: 3 | - "filenames" 4 | 5 | rules: 6 | "filenames/filenames": [2, "^[a-z0-9\\-\\.]+$"] # dash-cased filenames. 7 | -------------------------------------------------------------------------------- /.eslintrc-node: -------------------------------------------------------------------------------- 1 | --- 2 | extends: 3 | - "defaults/configurations/walmart/es5-node" 4 | - ".eslintrc-base" 5 | -------------------------------------------------------------------------------- /.eslintrc-node-test: -------------------------------------------------------------------------------- 1 | --- 2 | extends: 3 | - ".eslintrc-node" 4 | 5 | env: 6 | mocha: true 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .DS_Store 3 | npm-debug.log 4 | TEMP_CI 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - iojs 5 | - 0.10 6 | - 0.12 7 | 8 | # Use container-based Travis infrastructure. 9 | sudo: false 10 | 11 | branches: 12 | only: 13 | - master 14 | 15 | script: 16 | - npm run check 17 | -------------------------------------------------------------------------------- /.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-generator": {} 3 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Travis Status][trav_img]][trav_site] 2 | 3 | React Component Generator 4 | ========================= 5 | 6 | This generator creates a starter React component from Formidable Labs' freshest 7 | [react component boilerplate](https://github.com/FormidableLabs/formidable-react-component-boilerplate) or [victory component boilerplate](https://github.com/FormidableLabs/victory-component-boilerplate). Just Follow the interactive prompts! 8 | 9 | ## Installation & Usage 10 | 11 | Globally install this generator from NPM: 12 | 13 | ``` 14 | $ npm install -g generator-formidable-react-component 15 | ``` 16 | 17 | To run the generator: 18 | 19 | ``` 20 | $ yo formidable-react-component 21 | ``` 22 | 23 | and you have a new React component project! 24 | 25 | [trav_img]: https://api.travis-ci.org/FormidableLabs/generator-formidable-react-component.svg 26 | [trav_site]: https://travis-ci.org/FormidableLabs/generator-formidable-react-component 27 | -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var path = require("path"); 4 | var _ = require("lodash"); 5 | var chalk = require("chalk"); 6 | var yeoman = require("yeoman-generator"); 7 | var beautify = require("js-beautify"); 8 | var fs = require("fs"); 9 | var rimraf = require("rimraf"); 10 | var replace = require("replace"); 11 | 12 | module.exports = yeoman.generators.Base.extend({ 13 | 14 | promptUser: function () { 15 | var done = this.async(); 16 | var msg = "Welcome to the Formidable React Component generator"; 17 | this.log("\n" + chalk.bold.underline(msg)); 18 | 19 | var prompts = [{ 20 | type: "input", 21 | name: "inputName", 22 | message: "Please name your component" 23 | }, { 24 | type: "input", 25 | name: "author", 26 | message: "Please enter an author name" 27 | }, { 28 | type: "input", 29 | name: "ghUser", 30 | message: "What github username / organization should this package be published under?" 31 | }, { 32 | type: "list", 33 | name: "victory", 34 | message: "Are you writing a Victory component?", 35 | choices: [ 36 | { 37 | name: "yes", 38 | value: true 39 | }, 40 | { 41 | name: "no", 42 | value: false 43 | } 44 | ] 45 | }]; 46 | 47 | this.prompt(prompts, function (props) { 48 | _.extend(this, props); 49 | this.componentName = _.capitalize(_.camelCase(this.inputName)); 50 | this.projectName = _.kebabCase(_.deburr(this.inputName)); 51 | this.git = "https://github.com/" + this.ghUser + "/" + this.projectName; 52 | this.destinationRoot(this.projectName); 53 | this.boilerplateRepo = this.victory ? 54 | "victory-component-boilerplate" : "formidable-react-component-boilerplate"; 55 | done(); 56 | }.bind(this)); 57 | }, 58 | 59 | getBoilerplate: function () { 60 | var done = this.async(); 61 | var msg = "Fetching Boilerplate"; 62 | this.log("\n" + chalk.cyan(msg)); 63 | 64 | this.remote( 65 | "formidablelabs", 66 | this.boilerplateRepo, 67 | "master", 68 | function (err, remote) { 69 | if (err) { 70 | this.log("\n" + chalk.red("git remote install error: " + err)); 71 | return done(); 72 | } 73 | 74 | remote.directory(".", "."); 75 | done(); 76 | }, 77 | true // removes the cached data so boilerplate is always up to date. 78 | ); 79 | }, 80 | 81 | install: { 82 | 83 | replaceNames: function () { 84 | var msg = "replacing boilerplate names"; 85 | this.log("\n" + chalk.cyan(msg)); 86 | var camelCasedName = this.victory ? 87 | "VictoryComponentBoilerplate" : "FormidableReactComponentBoilerplate"; 88 | var kebabCasedName = this.victory ? 89 | "victory-component-boilerplate" : "formidable-react-component-boilerplate"; 90 | 91 | replace({ 92 | regex: kebabCasedName, 93 | replacement: this.projectName, 94 | paths: [this.destinationRoot()], 95 | recursive: true, 96 | silent: true 97 | }); 98 | 99 | replace({ 100 | regex: camelCasedName, 101 | replacement: this.componentName, 102 | paths: [this.destinationRoot()], 103 | recursive: true, 104 | silent: true 105 | }); 106 | 107 | if (this.victory === true) { 108 | replace({ 109 | regex: "/FormidableLabs/victory-component-boilerplate", 110 | replacement: "/" + this.ghUser + "/" + this.projectName, 111 | paths: [path.join(this.destinationRoot(), "README.md")], 112 | recursive: false, 113 | silent: true 114 | }); 115 | } 116 | }, 117 | 118 | renameFiles: function () { 119 | var done = this.async(); 120 | var msg = "renaming files"; 121 | this.log("\n" + chalk.cyan(msg)); 122 | var originalFile = this.victory ? 123 | "victory-component-boilerplate" : "formidable-react-component-boilerplate"; 124 | fs.rename( 125 | this.destinationRoot() + "/src/components/" + originalFile + ".jsx", 126 | this.destinationRoot() + "/src/components/" + this.projectName + ".jsx", 127 | function (err) { 128 | if (err) { 129 | this.log("\n" + chalk.red("could not rename " + 130 | this.destinationRoot() + 131 | "/src/components/" + originalFile + ".jsx") 132 | ); 133 | } 134 | done(); 135 | }.bind(this) 136 | ); 137 | }, 138 | 139 | renameTestFiles: function () { 140 | var done = this.async(); 141 | var msg = "renaming test files"; 142 | this.log("\n" + chalk.cyan(msg)); 143 | var originalFile = this.victory ? 144 | "victory-component-boilerplate" : "formidable-react-component-boilerplate"; 145 | fs.rename( 146 | this.destinationRoot() + 147 | "/test/client/spec/components/" + originalFile + ".spec.jsx", 148 | this.destinationRoot() + 149 | "/test/client/spec/components/" + this.projectName + ".spec.jsx", 150 | function (err) { 151 | if (err) { 152 | this.log("\n" + chalk.red(this.destinationRoot() + 153 | "/test/client/spec/components/" + originalFile + ".spec.jsx") 154 | ); 155 | } 156 | done(); 157 | }.bind(this) 158 | ); 159 | }, 160 | 161 | updateJSON: function () { 162 | var done = this.async(); 163 | var msg = "Updating package.json"; 164 | this.log("\n" + chalk.cyan(msg)); 165 | var jsonFile = JSON.parse(this.read(this.destinationRoot() + "/package.json")); 166 | jsonFile.version = "0.0.1"; 167 | jsonFile.name = this.projectName; 168 | jsonFile.description = this.victory ? "Victory Component" : "React Component"; 169 | jsonFile.repository.url = this.git + ".git"; 170 | jsonFile.author = this.author; 171 | jsonFile.bugs.url = this.git + "/issues"; 172 | jsonFile.homepage = this.git; 173 | 174 | var updatedJSON = beautify(JSON.stringify(jsonFile), { 175 | /*eslint-disable camelcase*/ 176 | indent_size: 2 177 | /*eslint-enable camelcase*/ 178 | }); 179 | var pkgPath = path.join(this.destinationRoot(), "package.json"); 180 | 181 | rimraf(pkgPath, function () { 182 | this.write(pkgPath, updatedJSON); 183 | done(); 184 | }.bind(this)); 185 | }, 186 | 187 | replaceReadme: function () { 188 | if (this.victory === true) { 189 | return; 190 | } 191 | var done = this.async(); 192 | var msg = "Updating README.md"; 193 | this.log("\n" + chalk.cyan(msg)); 194 | var pkgPath = path.join(this.destinationRoot(), "README.md"); 195 | 196 | rimraf(pkgPath, function () { 197 | this.template("_README.md", "README.md"); 198 | done(); 199 | }.bind(this)); 200 | }, 201 | 202 | replaceContributing: function () { 203 | if (this.victory === true) { 204 | return; 205 | } 206 | var done = this.async(); 207 | var msg = "Updating CONTRIBUTING.md"; 208 | this.log("\n" + chalk.cyan(msg)); 209 | var pkgPath = path.join(this.destinationRoot(), "CONTRIBUTING.md"); 210 | 211 | rimraf(pkgPath, function () { 212 | this.template("_CONTRIBUTING.md", "CONTRIBUTING.md"); 213 | done(); 214 | }.bind(this)); 215 | }, 216 | 217 | install: function () { 218 | this.log("\n" + chalk.cyan("Installing Project Dependencies")); 219 | this.npmInstall(); 220 | } 221 | }, 222 | 223 | end: { 224 | goodbye: function () { 225 | this.log("\n" + chalk.green.underline("SUCCESS")); 226 | } 227 | } 228 | }); 229 | -------------------------------------------------------------------------------- /app/templates/_CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing 2 | ============ 3 | 4 | Thanks for helping out! 5 | 6 | ## Development 7 | 8 | Run `builder run open-dev` to run a webpack dev server with component examples. 9 | 10 | ## Checks, Tests 11 | 12 | Run `builder run check` before committing. 13 | 14 | ## Dist 15 | 16 | Please do not commit changes to files in `dist`. 17 | These files are only committed when we tag releases. 18 | -------------------------------------------------------------------------------- /app/templates/_README.md: -------------------------------------------------------------------------------- 1 | [![Travis Status][trav_img]][trav_site] 2 | 3 | <%= componentName %> 4 | =========================== 5 | 6 | ## Description 7 | This is starter react component generated using [generator-formidable-react-component](https://github.com/FormidableLabs/generator-formidable-react-component) 8 | 9 | ## Development 10 | 11 | Please see [DEVELOPMENT](DEVELOPMENT.md) 12 | 13 | ## Contributing 14 | 15 | Please see [CONTRIBUTING](CONTRIBUTING.md) 16 | 17 | [trav_img]: https://api.travis-ci.org/<%= ghUser %>/<%= projectName %>.svg 18 | [trav_site]: https://travis-ci.org/<%= ghUser %>/<%= projectName %> 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-formidable-react-component", 3 | "version": "1.2.0", 4 | "description": "React component Yeoman generator", 5 | "license": "MIT", 6 | "main": "app/index.js", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/FormidableLabs/generator-formidable-react-component.git" 10 | }, 11 | "bugs": { 12 | "url": "https://github.com/FormidableLabs/generator-formidable-react-component/issues" 13 | }, 14 | "author": { 15 | "name": "Lauren Eastridge", 16 | "email": "lauren.eastridge@formidablelabs.com", 17 | "url": "https://github.com/formidablelabs" 18 | }, 19 | "engines": { 20 | "node": ">=0.10.0" 21 | }, 22 | "scripts": { 23 | "preversion": "npm run check", 24 | "lint-node": "eslint -c .eslintrc-node app", 25 | "lint-node-test": "eslint --ext .js -c .eslintrc-node-test test", 26 | "lint": "npm run lint-node && npm run lint-node-test", 27 | "test": "mocha", 28 | "check": "npm run lint && npm run test" 29 | }, 30 | "files": [ 31 | "app" 32 | ], 33 | "keywords": [ 34 | "yeoman-generator", 35 | "react" 36 | ], 37 | "dependencies": { 38 | "chalk": "^1.0.0", 39 | "js-beautify": "^1.5.10", 40 | "lodash": "^3.9.2", 41 | "replace": "^0.3.0", 42 | "rimraf": "^2.4.2", 43 | "yeoman-generator": "^0.20.1" 44 | }, 45 | "devDependencies": { 46 | "eslint": "^0.24.1", 47 | "eslint-config-defaults": "^3.1.0", 48 | "eslint-plugin-filenames": "^0.1.2", 49 | "mocha": "^2.2.5" 50 | }, 51 | "peerDependencies": { 52 | "yo": ">=1.0.0" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /test/app.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var path = require("path"); 4 | var assert = require("yeoman-generator").assert; 5 | var helpers = require("yeoman-generator").test; 6 | var os = require("os"); 7 | 8 | describe("generate react project", function () { 9 | 10 | before(function (done) { 11 | 12 | // HACK: Manually increase timeout until we figure out slow tests in 13 | // https://github.com/FormidableLabs/generator-formidable-react-component/issues/10 14 | this.timeout(10000); 15 | 16 | helpers 17 | .run(path.join(__dirname, "../app")) 18 | .inDir(path.join(os.tmpdir(), "./temp-test")) 19 | .withOptions({ 20 | "skip-install": true 21 | }) 22 | .withPrompts({ 23 | inputName: "camelCasedComponent", 24 | author: "Joe Test", 25 | ghUser: "joe-test", 26 | victory: false 27 | }) 28 | .on("end", done); 29 | }); 30 | 31 | it("creates files", function () { 32 | assert.file([ 33 | ".gitignore", 34 | "package.json", 35 | "README.md", 36 | "src/components/camel-cased-component.jsx", 37 | "src/index.js", 38 | "test/client/spec/components/camel-cased-component.spec.jsx", 39 | "test/client/main.js" 40 | 41 | // **Note**: We skip the `npm install` which means `dist` isn't rebuilt and `lib` isn't built. 42 | // "dist/camel-cased-component.js", 43 | // "dist/camel-cased-component.js.map", 44 | // "dist/camel-cased-component.min.js", 45 | // "dist/camel-cased-component.min.js.map", 46 | // "lib/components/camel-cased-component.js", 47 | ]); 48 | }); 49 | 50 | it("rewrites package.json", function () { 51 | var pkg = "package.json"; 52 | [ 53 | /"name": "camel-cased-component"/, 54 | /"version": "0.0.1"/, 55 | /"description": "React Component"/, 56 | /"url": "https:\/\/github.com\/joe-test\/camel-cased-component.git"/ 57 | ].forEach(function (regex) { 58 | assert.fileContent(pkg, regex); 59 | }); 60 | }); 61 | 62 | it("rewrites src/components/camel-cased-component.jsx", function () { 63 | var pkg = "src/components/camel-cased-component.jsx"; 64 | [ 65 | /export default class CamelCasedComponent extends React.Component/ 66 | ].forEach(function (regex) { 67 | assert.fileContent(pkg, regex); 68 | }); 69 | }); 70 | 71 | it("rewrites test/client/spec/components/camel-cased-component.spec.jsx", function () { 72 | var pkg = "test/client/spec/components/camel-cased-component.spec.jsx"; 73 | [ 74 | /import Component from "src\/components\/camel-cased-component";/, 75 | /describe\("components\/camel-cased-component"/ 76 | ].forEach(function (regex) { 77 | assert.fileContent(pkg, regex); 78 | }); 79 | }); 80 | 81 | it("writes from the README template", function () { 82 | var pkg = "README.md"; 83 | [ 84 | /This is starter react component/ 85 | ].forEach(function (regex) { 86 | assert.fileContent(pkg, regex); 87 | }); 88 | }); 89 | }); 90 | 91 | describe("generate victory project", function () { 92 | 93 | before(function (done) { 94 | 95 | // HACK: Manually increase timeout until we figure out slow tests in 96 | // https://github.com/FormidableLabs/generator-formidable-react-component/issues/10 97 | this.timeout(10000); 98 | 99 | helpers 100 | .run(path.join(__dirname, "../app")) 101 | .inDir(path.join(os.tmpdir(), "./temp-test")) 102 | .withOptions({ 103 | "skip-install": true 104 | }) 105 | .withPrompts({ 106 | inputName: "camelCasedComponent", 107 | author: "Joe Test", 108 | ghUser: "joe-test", 109 | victory: true 110 | }) 111 | .on("end", done); 112 | }); 113 | 114 | it("rewrites package.json", function () { 115 | var pkg = "package.json"; 116 | [ 117 | /"name": "camel-cased-component"/, 118 | /"version": "0.0.1"/, 119 | /"description": "Victory Component"/, 120 | /"url": "https:\/\/github.com\/joe-test\/camel-cased-component.git"/ 121 | ].forEach(function (regex) { 122 | assert.fileContent(pkg, regex); 123 | }); 124 | }); 125 | 126 | it("rewrites src/components/camel-cased-component.jsx", function () { 127 | var pkg = "src/components/camel-cased-component.jsx"; 128 | [ 129 | /class CamelCasedComponent extends React.Component/ 130 | ].forEach(function (regex) { 131 | assert.fileContent(pkg, regex); 132 | }); 133 | }); 134 | 135 | it("DOES NOT write from the README template", function () { 136 | var pkg = "README.md"; 137 | [ 138 | /This is starter react component/ 139 | ].forEach(function (regex) { 140 | assert.noFileContent(pkg, regex); 141 | }); 142 | }); 143 | 144 | }); 145 | --------------------------------------------------------------------------------