├── .babel-preset.js ├── .babelrc ├── .gitignore ├── README.md ├── package.json ├── src ├── .templates │ ├── js │ │ ├── component.js │ │ ├── story.js │ │ └── test.js │ └── re │ │ ├── component.js │ │ ├── rnscene.js │ │ ├── story.js │ │ └── test.js ├── cli.js ├── gen.js ├── index.js ├── init.js └── reporter │ ├── __tests__ │ └── errors.js │ ├── errors.js │ ├── index.js │ └── prepare-stack-trace.js └── yarn.lock /.babel-preset.js: -------------------------------------------------------------------------------- 1 | const r = m => require.resolve(m) 2 | 3 | function preset(context, options = {}) { 4 | const { browser = false, debug = false } = options 5 | const { NODE_ENV, BABEL_ENV } = process.env 6 | 7 | const PRODUCTION = (BABEL_ENV || NODE_ENV) === "production" 8 | 9 | const browserConfig = { 10 | useBuiltIns: false, 11 | targets: { 12 | browsers: PRODUCTION 13 | ? [`last 4 versions`, `safari >= 7`, "ie >= 9"] 14 | : [`last 2 versions`, `not ie <= 11`, `not android 4.4.3`], 15 | }, 16 | } 17 | 18 | const nodeConfig = { 19 | targets: { 20 | node: PRODUCTION ? 6.0 : "current", 21 | }, 22 | } 23 | 24 | return { 25 | presets: [ 26 | [ 27 | r("@babel/preset-env"), 28 | Object.assign( 29 | { 30 | loose: true, 31 | debug: !!debug, 32 | useBuiltIns: "entry", 33 | shippedProposals: true, 34 | modules: "commonjs", 35 | }, 36 | browser ? browserConfig : nodeConfig 37 | ), 38 | ], 39 | r("@babel/preset-flow"), 40 | ], 41 | } 42 | } 43 | 44 | module.exports = preset -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["./.babel-preset.js"] 4 | ] 5 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /lib 3 | /node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Astroman 🧐 2 | 3 | Astrocoders command line tool. 4 | 5 | Let's you create new sites using the following frameworks: 6 | - [Create React App](https://github.com/Astrocoders/cra-starter). 7 | - [Gatsby v2](https://github.com/Astrocoders/gatsby-starter). 8 | - [ReasonML](https://github.com/Astrocoders/reasonml-starter). 9 | 10 | When you create a project running astroman, you will get projects with our guidelines(https://github.com/Astrocoders/guidelines). 11 | 12 | ## Install 13 | 14 | `npm install --global @astrocoders/astroman` 15 | 16 | ### New 17 | 18 | `astroman new awesome-project [cra|gatsby|reason]` 19 | 20 | ### Gen 21 | 22 | astroman already comes with [gen](https://github.com/Astrocoders/gen), a simple lib that we use for fast generating components and screens. 23 | 24 | We grouped generators by language, currently we have Javascript and ReasonML available. We also have generators for React Native with both languages. 25 | 26 | #### JavaScript 27 | 28 | Create a simple react component. This command also create automatically a test file and a docz story for it. 29 | `astroman gen component js Test` 30 | 31 | Create tests for this component 32 | `astroman gen test js Test` 33 | 34 | Create a docz file for this component 35 | `astroman gen story js Test` 36 | 37 | 38 | #### ReasonML 39 | 40 | Create a simple reasonml component 41 | `astroman gen component re Test` 42 | 43 | Create tests for this component 44 | `astroman gen test re Test` 45 | 46 | Create a story on storybook for this component 47 | `astroman gen story re Test` 48 | 49 | 50 | #### React Native 51 | 52 | WIP! 53 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@astrocoders/astroman", 3 | "description": "Command-line interface for creating new sites based on Gatsby, ReasonML or Create React App", 4 | "version": "1.2.0", 5 | "author": "Astrocoders ", 6 | "bin": { 7 | "astroman": "lib/index.js" 8 | }, 9 | "bugs": { 10 | "url": "https://github.com/Astrocoders/astroman/issues" 11 | }, 12 | "dependencies": { 13 | "@babel/code-frame": "^7.0.0", 14 | "@babel/preset-env": "^7.1.0", 15 | "@babel/preset-flow": "^7.0.0", 16 | "@babel/runtime": "^7.0.0", 17 | "bluebird": "^3.5.0", 18 | "common-tags": "^1.4.0", 19 | "convert-hrtime": "^2.0.0", 20 | "core-js": "^2.5.0", 21 | "envinfo": "^5.8.1", 22 | "execa": "^0.8.0", 23 | "fs-exists-cached": "^1.0.0", 24 | "fs-extra": "^4.0.1", 25 | "hosted-git-info": "^2.6.0", 26 | "lodash": "^4.17.10", 27 | "opentracing": "^0.14.3", 28 | "pretty-error": "^2.1.1", 29 | "resolve-cwd": "^2.0.0", 30 | "source-map": "^0.5.7", 31 | "stack-trace": "^0.0.10", 32 | "update-notifier": "^2.3.0", 33 | "yargs": "^11.1.0", 34 | "yurnalist": "^0.2.1" 35 | }, 36 | "devDependencies": { 37 | "@babel/cli": "^7.0.0", 38 | "@babel/core": "^7.0.0", 39 | "cross-env": "^5.1.4" 40 | }, 41 | "files": [ 42 | "lib" 43 | ], 44 | "homepage": "https://github.com/Astrocoders/astroman#README", 45 | "license": "MIT", 46 | "main": "lib/index.js", 47 | "repository": "https://github.com/Astrocoders/astroman", 48 | "scripts": { 49 | "build": "babel src --out-dir lib --ignore **/__tests__", 50 | "prepare": "cross-env NODE_ENV=production npm run build", 51 | "watch": "babel -w src --out-dir lib --ignore **/__tests__" 52 | }, 53 | "yargs": { 54 | "boolean-negation": false 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/.templates/js/component.js: -------------------------------------------------------------------------------- 1 | const { stripIndent } = require('common-tags') 2 | const chalk = require('chalk') 3 | const fs = require('fs') 4 | 5 | module.exports.args = { name: 'Component name' } 6 | 7 | module.exports.where = (name) => { 8 | if (!fs.existsSync('components')){ 9 | fs.mkdirSync('components') 10 | return `components/${name}.js` 11 | } else { 12 | return `components/${name}.js` 13 | } 14 | } 15 | 16 | module.exports.postBuild = (name) => 17 | console.log('✅ ', chalk.green(`Component ${name} successfully created`)) 18 | 19 | module.exports.gen = (name) => stripIndent` 20 | 21 | import React from 'react' 22 | import PropTypes from 'prop-types' 23 | 24 | const ${name} = ({prop}) => ( 25 |
{prop}
26 | ) 27 | 28 | ${name}.defaultProps = { 29 | prop: '', 30 | } 31 | 32 | ${name}.propTypes = { 33 | prop: PropTypes.string.isRequired, 34 | } 35 | 36 | export default ${name} 37 | ` -------------------------------------------------------------------------------- /src/.templates/js/story.js: -------------------------------------------------------------------------------- 1 | const { stripIndent } = require('common-tags') 2 | const fs = require('fs') 3 | const chalk = require('chalk') 4 | 5 | module.exports.args = { name: 'Component name for the story' } 6 | 7 | module.exports.where = (name) => { 8 | if (!fs.existsSync('docz')){ 9 | fs.mkdirSync('docz') 10 | return `docz/${name}.mdx` 11 | } else { 12 | return `docz/${name}.mdx` 13 | } 14 | } 15 | 16 | module.exports.postBuild = (name) => 17 | console.log( 18 | '✅ ', 19 | chalk.green(`You can see your component on docz/${name}.mdx`), 20 | ) 21 | 22 | module.exports.gen = (name) => stripIndent` 23 | --- 24 | name: ${name} 25 | menu: Components 26 | --- 27 | 28 | import { Playground, PropsTable } from 'docz' 29 | import ${name} from '../components/${name}' 30 | 31 | # ${name} 32 | 33 | 34 | 35 | ## Basic usage 36 | 37 | 38 | <${name}/> 39 | 40 | ` -------------------------------------------------------------------------------- /src/.templates/js/test.js: -------------------------------------------------------------------------------- 1 | const { stripIndent } = require('common-tags') 2 | const chalk = require('chalk') 3 | const fs = require('fs') 4 | 5 | module.exports.args = { name: 'Component name' } 6 | 7 | module.exports.where = (name) => { 8 | if (!fs.existsSync('components')){ 9 | fs.mkdirSync('components') 10 | return `components/${name}.test.js` 11 | } else { 12 | return `components/${name}.test.js` 13 | } 14 | } 15 | 16 | module.exports.postBuild = (name) => 17 | console.log('✅ ', chalk.green(`Test for ${name} successfully created`)) 18 | 19 | module.exports.gen = (name) => stripIndent` 20 | 21 | import React from 'react' 22 | import { render, cleanup } from 'react-testing-library' 23 | 24 | import ${name} from './${name}' 25 | 26 | afterEach(cleanup) 27 | 28 | describe('${name} component', () => { 29 | it('should render ${name} component', () => { 30 | const { queryByTestId } = render(<${name} />) 31 | 32 | expect(queryByTestId('${name}Wrapper')).toBeInTheDocument() 33 | }) 34 | }) 35 | ` -------------------------------------------------------------------------------- /src/.templates/re/component.js: -------------------------------------------------------------------------------- 1 | const { stripIndent } = require('common-tags') 2 | const chalk = require('chalk') 3 | const fs = require('fs') 4 | 5 | module.exports.args = { name: 'Component name' } 6 | 7 | module.exports.where = (name) => { 8 | if (!fs.existsSync('components')){ 9 | fs.mkdirSync('components') 10 | return `components/${name}.re` 11 | } else { 12 | return `components/${name}.re` 13 | } 14 | } 15 | 16 | module.exports.postBuild = (name) => 17 | console.log('✅ ', chalk.green(`Component ${name} successfully created`)) 18 | 19 | module.exports.gen = (name) => stripIndent` 20 | open Rebolt; 21 | module Styles = { 22 | open Style; 23 | let text = style([]); 24 | }; 25 | let component = ReasonReact.statelessComponent("${name}"); 26 | let make = (_children) => { 27 | ...component, 28 | render: _self => { 29 | (ReasonReact.string("Hello")) 30 | } 31 | }; 32 | ` -------------------------------------------------------------------------------- /src/.templates/re/rnscene.js: -------------------------------------------------------------------------------- 1 | const { stripIndent } = require('common-tags') 2 | const fs = require('fs') 3 | const chalk = require('chalk') 4 | 5 | module.exports.where = (name) => { 6 | if (!fs.existsSync('scenes')){ 7 | fs.mkdirSync('scenes') 8 | return `scenes/${name}.re` 9 | } else { 10 | return `scenes/${name}.re` 11 | } 12 | } 13 | 14 | module.exports.args = { name: 'Scene name' } 15 | 16 | module.exports.postBuild = () => 17 | console.log( 18 | '✅ ', 19 | chalk.green( 20 | 'Now update your ./re/NavigationConfig.re with your scene constructor', 21 | ), 22 | ) 23 | 24 | module.exports.gen = (name) => stripIndent`open Rebolt; 25 | open NavigationConfig; 26 | let component = ReasonReact.statelessComponent("${name}"); 27 | let make = (~navigation, _children) => { 28 | ...component, 29 | render: _self => 30 | 31 | ...(() => ) 32 | , 33 | };` -------------------------------------------------------------------------------- /src/.templates/re/story.js: -------------------------------------------------------------------------------- 1 | const { stripIndent } = require('common-tags') 2 | const fs = require('fs') 3 | const chalk = require('chalk') 4 | 5 | module.exports.args = { name: 'Component name for the story' } 6 | 7 | module.exports.where = (name) => { 8 | if (!fs.existsSync('stories')){ 9 | fs.mkdirSync('stories') 10 | return `stories/${name}Stories.re` 11 | } else { 12 | return `stories/${name}Stories.re` 13 | } 14 | } 15 | 16 | module.exports.postBuild = () => 17 | console.log( 18 | '✅ ', 19 | chalk.green('Now require your story in stories/index'), 20 | ) 21 | 22 | module.exports.gen = (name) => stripIndent` 23 | open Rebolt; 24 | Storybook.( 25 | storiesOf("${name}", module_) 26 | |> add("default", () => <${name} />) 27 | ); 28 | ` -------------------------------------------------------------------------------- /src/.templates/re/test.js: -------------------------------------------------------------------------------- 1 | const { stripIndent } = require('common-tags') 2 | const chalk = require('chalk') 3 | const fs = require('fs') 4 | 5 | module.exports.args = { name: 'Component name' } 6 | 7 | module.exports.where = (name) => { 8 | if (!fs.existsSync('components')){ 9 | fs.mkdirSync('components') 10 | return `components/${name}.test.re` 11 | } else { 12 | return `components/${name}.test.re` 13 | } 14 | } 15 | 16 | module.exports.postBuild = (name) => 17 | console.log('✅ ', chalk.green(`Test for ${name} successfully created`)) 18 | 19 | module.exports.gen = (name) => stripIndent` 20 | open Jest; 21 | 22 | test("Tests for ${name}", (_) => 23 | Expect.(expect(3 + 4) |> toBe(7)) 24 | ); 25 | ` -------------------------------------------------------------------------------- /src/cli.js: -------------------------------------------------------------------------------- 1 | const yargs = require(`yargs`) 2 | const report = require(`./reporter`) 3 | 4 | const handlerP = fn => (...args) => { 5 | Promise.resolve(fn(...args)).then( 6 | () => process.exit(0), 7 | err => report.panic(err) 8 | ) 9 | } 10 | 11 | module.exports = (argv) => { 12 | let cli = yargs() 13 | 14 | cli 15 | .usage(`Usage: $0 [options]`) 16 | .alias(`h`, `help`) 17 | .alias(`v`, `version`) 18 | .option(`verbose`, { 19 | default: false, 20 | type: `boolean`, 21 | describe: `Turn on verbose output`, 22 | global: true, 23 | }) 24 | .option(`no-color`, { 25 | default: false, 26 | type: `boolean`, 27 | describe: `Turn off the color in output`, 28 | global: true, 29 | }) 30 | 31 | return cli 32 | .command({ 33 | command: `new [rootPath] [starter]`, 34 | desc: 'astroman new [cra|gatsby|reason]', 35 | handler: handlerP( 36 | ({ rootPath, starter }) => { 37 | const initStarter = require(`./init`) 38 | return initStarter(starter, { rootPath }) 39 | } 40 | ), 41 | }) 42 | .command({ 43 | command: `gen [template] [language] [name]`, 44 | desc: 'astroman gen