├── .gitignore ├── img └── rx-generate-demo.gif ├── package.json ├── cmd ├── alias.js ├── template │ └── index.js ├── project.js └── generate.js ├── CHANGELOG.md ├── README.md ├── util └── log.js ├── index.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /img/rx-generate-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveblue/reactor/HEAD/img/rx-generate-demo.gif -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rctr", 3 | "version": "1.0.5", 4 | "main": "index.js", 5 | "repository": "https://github.com/steveblue/reactor.git", 6 | "author": "Steve Belovarich ", 7 | "description": "React CLI", 8 | "license": "MIT", 9 | "dependencies": { 10 | "chalk": "^3.0.0", 11 | "commander": "^4.1.0", 12 | "findup": "^0.1.5", 13 | "glob": "^7.1.6", 14 | "ora": "^4.0.3", 15 | "prettier": "^1.19.1", 16 | "rimraf": "^3.0.1", 17 | "rxjs": "^6.5.4", 18 | "shelljs": "^0.8.3", 19 | "single-line-log": "^1.1.2" 20 | }, 21 | "bin": { 22 | "rx": "index.js" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /cmd/alias.js: -------------------------------------------------------------------------------- 1 | const { spawn } = require('child_process'); 2 | const { Observable, of } = require('rxjs'); 3 | const { catchError, concatMap } = require('rxjs/operators'); 4 | 5 | const log = require('./../util/log.js'); 6 | 7 | log.pause(); 8 | 9 | function yarn(options) { 10 | return new Observable((observer) => { 11 | spawn(`yarn`, [`${options.cmd}`], { stdio: 'inherit' }); 12 | observer.next(); 13 | observer.complete(); 14 | }); 15 | } 16 | 17 | 18 | function alias(options) { 19 | of(options).pipe( 20 | concatMap(results => yarn(results)), 21 | catchError(err => { 22 | log.error(err); 23 | process.exit(1); 24 | }) 25 | ).subscribe() 26 | } 27 | 28 | module.exports = alias; -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## 1.0.5 4 | 5 | - NEW alias for common tasks, i.e. `rx start` aliases `yarn start`. 6 | 7 | ## 1.0.4 8 | 9 | - NEW generate command scaffolds code snippets 10 | - NEW changelog 11 | - CHANGE cli command to rx from rctr 12 | - FIXED issues with logs 13 | - FIXED issue with error reporting in project scaffold 14 | - FIXED issue that could cause project overwrite 15 | 16 | ## 1.0.3 17 | 18 | - FIXED async callbacks, cleaned up messy code 19 | - FIXED issues with logs 20 | - REVERT to require 21 | 22 | ## 1.0.2 23 | 24 | - NEW look and feel for logs 25 | - NEW support for windows 26 | 27 | ## 1.0.1 28 | 29 | - FIXED issues with scaffold 30 | - NEW git initialization 31 | 32 | ### 1.0.0 33 | 34 | - NEW CLI tool for generating projects with React and Parcel 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rx 2 | 3 | CLI for React projects built with Parcel. 4 | 5 | ## Install 6 | 7 | ``` 8 | npm i -g rctr 9 | ``` 10 | 11 | ## Commands 12 | 13 | Below are the avilable commands you can run with the `rx` cli. 14 | 15 | ### new 16 | 17 | ``` 18 | rx new my-app 19 | ``` 20 | 21 | `rx new` scaffolds a new app with support for SSR, lazyloading, i18n, SCSS, and more. We chose the kitchen sink approach. 22 | 23 | For an example of what gets scaffolded, see [react-starter](https://github.com/steveblue/react-starter). 24 | 25 | ### generate 26 | 27 | `rx generate` scaffolds code snippets in the directory the command is run. 28 | 29 | ![](img/rx-generate-demo.gif) 30 | 31 | Here is a list of arguments the `rx generate` command will take. 32 | 33 | | type | file | 34 | | ----------------------- | ------------------------------------------ | 35 | | fn-component, fc | pure function component | 36 | | arrow-fn-component, afc | arrow function component | 37 | | component, c | class component | 38 | | view, v | class component with imported styles, test | 39 | | ssr | server-side rendered view | 40 | | test, t | spec file | 41 | | state, s | state with reducer | 42 | | context , ctx | context | 43 | 44 | #### Example 45 | 46 | `rx generate view Map` 47 | 48 | - Map.tsx created 49 | - Map.spec.tsx created 50 | - Map.scss created 51 | 52 | Some generators support optional arguments `--routing` and `--lazy`. 53 | 54 | `rx g ssr About --routing --lazy` 55 | 56 | - About.tsx created 57 | - About.spec.tsx created 58 | - About.scss created 59 | - App.tsx has new routes 60 | 61 | The first argument `--routing` adds a route to the nearest implementation of React Router. 62 | 63 | ``` 64 | } /> 65 | ``` 66 | 67 | The second argument `--lazy` optionally lazyloads the component. 68 | 69 | ``` 70 | const About = importComponent(() => import("./view/about/About")); 71 | ``` 72 | 73 | ## Development 74 | 75 | If you want to contribute fork this repo, make your changes and submit a pull request. 76 | 77 | To get started with development run `yarn install` and `yarn link`. 78 | -------------------------------------------------------------------------------- /cmd/template/index.js: -------------------------------------------------------------------------------- 1 | const template = { 2 | 'fn-component': ` 3 | import React from "react"; 4 | 5 | export default function {{name}}() { 6 | return ( 7 |

{{name}} works!

8 | ); 9 | } 10 | 11 | `, 12 | 'arrow-fn-component': ` 13 | import React from "react"; 14 | 15 | export default const {{name}} = () =>

{{name}} works!

; 16 | 17 | `, 18 | 'component': ` 19 | import React from "react"; 20 | 21 | export default class {{name}} extends React.Component { 22 | public render(): JSX.Element { 23 | return ( 24 |

{{name}} works!

25 | ); 26 | } 27 | } 28 | 29 | `, 30 | 'view': ` 31 | import React from "react"; 32 | 33 | import "./{{styleName}}.scss"; 34 | 35 | export default class {{name}} extends React.Component { 36 | public render(): JSX.Element { 37 | return ( 38 |
39 |

{{name}} works!

40 |
41 | ); 42 | } 43 | } 44 | 45 | `, 46 | 'ssr': ` 47 | import React from "react"; 48 | import Helmet from "react-helmet"; 49 | 50 | import "./{{styleName}}.scss"; 51 | 52 | export default class {{name}} extends React.Component { 53 | public render(): JSX.Element { 54 | return ( 55 |
56 | 57 | {{name}} 58 | 59 |

{{name}} works!

60 |
61 | ); 62 | } 63 | } 64 | 65 | `, 66 | 'enzyme-test': ` 67 | import React from "react"; 68 | import { shallow } from "enzyme"; 69 | 70 | import {{name}} from "./{{name}}"; 71 | 72 | describe("{{name}} tests", () => { 73 | it("renders", () => { 74 | const wrapper = shallow(<{{name}} />); 75 | expect(wrapper).toBeDefined(); 76 | }); 77 | }); 78 | 79 | `, 80 | 'state': ` 81 | const {{name}}State = { 82 | 83 | }; 84 | 85 | function reducer(state, action) { 86 | switch (action.type) { 87 | default: 88 | return state; 89 | } 90 | } 91 | 92 | export { {{name}}State, reducer } 93 | 94 | `, 95 | 'hook': ` 96 | import React, { useState, useEffect } from "react"; 97 | 98 | function {{name}}(props) { 99 | const [] = useState(null); 100 | 101 | useEffect(() => { 102 | return; 103 | }); 104 | 105 | return; 106 | } 107 | 108 | `, 109 | 'context': ` 110 | import React from "react"; 111 | 112 | const {{name}}Context = React.createContext({}); 113 | 114 | export { {{name}}Context }; 115 | 116 | `, 117 | 'import': ` 118 | import {{name}} from ".{{path}}/{{name}}.tsx"; 119 | `, 120 | 'route': ` 121 | 122 | `, 123 | 'lazy-route': ` 124 | <{{name}} />} /> 125 | `, 126 | 'imported-component': ` 127 | const {{name}} = importComponent(() => import(".{{path}}/{{name}}")); 128 | ` 129 | } 130 | 131 | module.exports = template; -------------------------------------------------------------------------------- /util/log.js: -------------------------------------------------------------------------------- 1 | const logger = require('single-line-log').stdout; 2 | const ora = require('ora'); 3 | const chalk = require('chalk'); 4 | 5 | class Log { 6 | 7 | constructor() { 8 | this.spinner = ora({ 9 | text: '', 10 | spinner: 'dots10', 11 | color: 'white', 12 | hideCursor: true 13 | }).start(); 14 | this.logger = logger; 15 | } 16 | 17 | break() { 18 | process.stdout.write('\n'); 19 | } 20 | 21 | clear() { 22 | this.logger.clear(); 23 | } 24 | 25 | stop(str) { 26 | this.spinner.stop(); 27 | } 28 | 29 | hasArg(arg) { 30 | return process.argv.indexOf(arg) > -1 || process.argv.indexOf('--'+arg) > -1; 31 | } 32 | 33 | pause() { 34 | this.spinner.stop(); 35 | } 36 | 37 | destroy() { 38 | this.spinner.stop(); 39 | process.stdout.write('\x1B[2J\x1B[0f\u001b[0;0H'); 40 | } 41 | 42 | line() { 43 | process.stdout.write('\n'); 44 | const col = process.stdout.columns; 45 | let line = ' '; 46 | for (let i = 0; i < col - 2; i++) { 47 | line += '\u2500'; 48 | } 49 | line += '\n'; 50 | process.stdout.write(chalk.white(line)); 51 | } 52 | 53 | errorLine() { 54 | process.stdout.write('\n'); 55 | const col = process.stdout.columns; 56 | let line = ' '; 57 | for (let i = 0; i < col - 4; i++) { 58 | line += '\u2500'; 59 | } 60 | line += '💥'; 61 | line += '\n'; 62 | process.stdout.write(chalk.red(line)); 63 | } 64 | 65 | bare(msg) { 66 | this.logger(msg); 67 | process.stderr.write('\x1B[?25l'); 68 | } 69 | 70 | message(msg) { 71 | //this.spinner.stop(); 72 | msg = msg ? '' + chalk.white(msg) : ''; 73 | this.logger(msg); 74 | process.stderr.write('\x1B[?25l'); 75 | } 76 | 77 | print(msg) { 78 | //this.spinner.stop(); 79 | msg = msg ? '' + chalk.white(msg) : ''; 80 | this.logger(msg); 81 | process.stderr.write('\x1B[?25l'); 82 | this.break(); 83 | } 84 | 85 | start(msg) { 86 | msg = msg ? '' + chalk.white(msg) : ''; 87 | this.spinner.text = msg; 88 | this.spinner.start(); 89 | } 90 | 91 | process(msg) { 92 | msg = msg ? '' + chalk.white(msg) : ''; 93 | this.spinner.text = msg; 94 | this.spinner.start(); 95 | } 96 | 97 | complete(msg) { 98 | this.spinner.stop(); 99 | process.stdout.write(msg); 100 | process.stdout.write('\n'); 101 | } 102 | 103 | success(msg, services) { 104 | services.forEach((service) => { this.cancelError(service); }); 105 | if (!this.hasError()) { 106 | this.destroy(); 107 | } 108 | msg = '\n'+ (msg ? '' + chalk.white(msg) : ''); 109 | this.logger(msg); 110 | process.stderr.write('\x1B[?25l'); 111 | } 112 | 113 | fail(msg) { 114 | msg = msg ? '' + chalk.red(msg) : ''; 115 | this.logger(msg); 116 | process.stderr.write('\x1B[?25l'); 117 | } 118 | 119 | alert(msg) { 120 | msg = msg ? '' + chalk.white(msg) : ''; 121 | process.stdout.write(msg); 122 | process.stdout.write('\n'); 123 | } 124 | 125 | warn(msg) { 126 | msg = msg ? '' + chalk.yellow(msg) : ''; 127 | process.stdout.write(msg); 128 | process.stdout.write('\n'); 129 | } 130 | 131 | error(err) { 132 | //err = err ? '' + chalk.red(err) : ''; 133 | process.stdout.write(chalk.red(err)); 134 | process.stdout.write('\n'); 135 | } 136 | 137 | } 138 | 139 | const log = new Log(); 140 | 141 | module.exports = log; -------------------------------------------------------------------------------- /cmd/project.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk'); 2 | const rimraf = require('rimraf'); 3 | const { exec } = require('child_process'); 4 | const { resolve } = require('path'); 5 | const { readFile, existsSync, writeFile } = require( 'fs'); 6 | const { Observable, of } = require('rxjs'); 7 | const { catchError, map, concatMap } = require('rxjs/operators'); 8 | 9 | const log = require('./../util/log.js'); 10 | 11 | function clone(options) { 12 | return new Observable((observer) => { 13 | log.process(`clone`); 14 | exec(`git clone https://github.com/steveblue/react-starter.git ${options.name}`, {}, (error, stdout, stderr) => { 15 | if (stderr.includes('Error')) { 16 | observer.error(error); 17 | } else { 18 | observer.next(options); 19 | } 20 | }); 21 | }); 22 | } 23 | 24 | function processPackage(options) { 25 | return new Observable((observer) => { 26 | log.process(`bootstrap`); 27 | readFile(resolve(`./${options.name}/package.json`), 'utf8', (err, pkg) => { 28 | if (err) { 29 | observer.error(err); 30 | } else { 31 | pkg = JSON.parse(pkg); 32 | pkg.name = options.name; 33 | pkg.version = '1.0.0'; 34 | pkg = JSON.stringify(pkg, null, 4); 35 | writeFile(resolve(`./${options.name}/package.json`), pkg, err => { 36 | if (err) { 37 | observer.error(err); 38 | } else { 39 | observer.next(options); 40 | } 41 | }); 42 | } 43 | }); 44 | }); 45 | } 46 | 47 | function initRepo(options) { 48 | return new Observable((observer) => { 49 | log.process(`git init`); 50 | rimraf(resolve(`./${options.name}/.git`), {}, (err) => { 51 | if (err) { 52 | observer.error(err); 53 | } else { 54 | exec(`git init`, { cwd: resolve(`./${options.name}`) }, (err, stdout, stderr) => { 55 | log.process(`yarn install`); 56 | if (err) { 57 | observer.error(err); 58 | } else { 59 | observer.next(options); 60 | } 61 | }); 62 | } 63 | }); 64 | }); 65 | } 66 | 67 | function install(options) { 68 | return new Observable((observer) => { 69 | log.process(`yarn install`); 70 | exec(`yarn install`, { cwd: resolve(`./${options.name}`) }, (err) => { 71 | if (err) { 72 | observer.error(err); 73 | } else { 74 | observer.next(options); 75 | observer.complete(); 76 | } 77 | }); 78 | }); 79 | } 80 | 81 | function check(options) { 82 | return new Observable((observer) => { 83 | if (existsSync(resolve(`./${options.name}`))) { 84 | observer.error(`${options.name} already exists`); 85 | } else { 86 | observer.next(options); 87 | } 88 | }); 89 | } 90 | 91 | 92 | function project(options) { 93 | log.start(`rctr ${options.name}`); 94 | of(options).pipe( 95 | concatMap(results => check(results)), 96 | concatMap(results => clone(results)), 97 | concatMap(results => processPackage(results)), 98 | concatMap(results => initRepo(results)), 99 | concatMap(results => install(results)), 100 | map(options => { 101 | log.complete(chalk.green(`${options.name} created`)); 102 | }), 103 | catchError(err => { 104 | log.error(err); 105 | process.exit(1); 106 | }) 107 | ).subscribe() 108 | } 109 | 110 | module.exports = project; -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const program = require('commander'); 3 | const { readFileSync } = require('fs'); 4 | const project = require('./cmd/project.js'); 5 | const generate = require('./cmd/generate.js'); 6 | const alias = require('./cmd/alias.js'); 7 | const pkg = readFileSync(__dirname + '/package.json'); 8 | 9 | program.version(pkg.version); 10 | 11 | program.command('dev', {executableFile: './cmd/alias.js'}) 12 | .alias('start') 13 | .description('start dev server') 14 | .action((type, name) => { 15 | return alias({ cmd: 'dev'}); 16 | }); 17 | 18 | program.command('dev:ssr', {executableFile: './cmd/alias.js'}) 19 | .description('start dev server server-side rendered') 20 | .action((type, name) => { 21 | return alias({ cmd: 'dev:ssr'}); 22 | }); 23 | 24 | program.command('ssr', {executableFile: './cmd/alias.js'}) 25 | .description('build project server-side rendered') 26 | .action((type, name) => { 27 | return alias({ cmd: 'ssr'}); 28 | }); 29 | 30 | program.command('prod', {executableFile: './cmd/alias.js'}) 31 | .description('build project for production') 32 | .action((type, name) => { 33 | return alias({ cmd: 'prod'}); 34 | }); 35 | 36 | program.command('serve', {executableFile: './cmd/alias.js'}) 37 | .description('start server') 38 | .action((type, name) => { 39 | return alias({ cmd: 'serve'}); 40 | }); 41 | 42 | program.command('test', {executableFile: './cmd/alias.js'}) 43 | .description('execute unit tests') 44 | .action((type, name) => { 45 | return alias({ cmd: 'test'}); 46 | }); 47 | 48 | program.command('lint', {executableFile: './cmd/alias.js'}) 49 | .description('run linter') 50 | .action((type, name) => { 51 | return alias({ cmd: 'lint'}); 52 | }); 53 | 54 | program.command('storybook', {executableFile: './cmd/alias.js'}) 55 | .description('start storybook server') 56 | .action((type, name) => { 57 | return alias({ cmd: 'storybook'}); 58 | }); 59 | 60 | program.command('pretty', {executableFile: './cmd/alias.js'}) 61 | .description('style source code with prettier') 62 | .action((type, name) => { 63 | return alias({ cmd: 'pretty'}); 64 | }); 65 | 66 | program.command('new ', {executableFile: './cmd/project.js'}) 67 | .alias('n') 68 | .description('scaffold new project') 69 | .action((name) => { 70 | return project({ 71 | name: name, 72 | args: {} 73 | }); 74 | }); 75 | 76 | program.command('generate ', {executableFile: './cmd/generate.js'}) 77 | .alias('g') 78 | .description('generate code snippet') 79 | .action((type, name) => { 80 | return generate({ 81 | type: type, 82 | name: name, 83 | args: { 84 | routing: program.routing, 85 | lazy: program.lazy 86 | } 87 | }); 88 | }); 89 | 90 | program.option('-r, --routing', 'add route for component (generate)') 91 | .option('-l, --lazy', 'lazyload component (generate)') 92 | .parse(process.argv); 93 | 94 | const exitHandler = (options, err) => { 95 | if (err === 0 || err === 1) { 96 | return; 97 | } 98 | if (err !== 'SIGINT') { 99 | process.stdout.write('\n'); 100 | console.log(err); 101 | } 102 | process.exit(1); 103 | }; 104 | 105 | // do something when app is closing 106 | process.on('exit', exitHandler.bind(null, { cleanup: true })); 107 | 108 | // catches ctrl+c event 109 | process.on('SIGINT', exitHandler.bind(null, { exit: true })); 110 | 111 | // catches "kill pid" (for example: nodemon restart) 112 | process.on('SIGUSR1', exitHandler.bind(null, { exit: true })); 113 | process.on('SIGUSR2', exitHandler.bind(null, { exit: true })); 114 | 115 | //catches uncaught exceptions 116 | process.on('uncaughtException', exitHandler.bind(null, { exit: true })); 117 | process.on('unhandledRejection', exitHandler.bind(null, { exit: true })); -------------------------------------------------------------------------------- /cmd/generate.js: -------------------------------------------------------------------------------- 1 | const findup = require('findup'); 2 | const glob = require("glob"); 3 | const mkdir = require('shelljs').mkdir; 4 | const grep = require('shelljs').grep; 5 | const prettier = require("prettier"); 6 | const { join, dirname, basename, resolve } = require('path'); 7 | const { writeFile, existsSync, readFile } = require('fs'); 8 | const { Observable, of } = require('rxjs'); 9 | const { catchError, map, concatMap } = require('rxjs/operators'); 10 | 11 | const log = require('./../util/log.js'); 12 | const template = require('./template/index.js'); 13 | 14 | const cwd = join(dirname(process.cwd()), basename(process.cwd())); 15 | let projectDir = null; 16 | 17 | function getType(type) { 18 | switch (type) { 19 | case 'fc': 20 | return 'fn-component'; 21 | case 'afc': 22 | return 'arrow-fn-component'; 23 | case 'c': 24 | return 'component'; 25 | case 'v': 26 | return 'view'; 27 | case 'ssr': 28 | return 'ssr'; 29 | case 't': 30 | return 'enzyme-test'; 31 | case 's': 32 | return 'state'; 33 | case 'h': 34 | return 'hook'; 35 | case 'ctx': 36 | return 'context'; 37 | default: 38 | return -1; 39 | } 40 | } 41 | 42 | function toKebabCase(str) { 43 | return str.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g) 44 | .map(x => x.toLowerCase()) 45 | .join('-'); 46 | } 47 | 48 | 49 | function init(options) { 50 | return new Observable((observer) => { 51 | try { 52 | projectDir = findup.sync(cwd, 'package.json'); 53 | } catch(e) { 54 | observer.error(`The generate command requires a project, a package.json could not be found.`); 55 | } 56 | observer.next(options); 57 | }); 58 | } 59 | 60 | function getTemplate(options) { 61 | return new Observable((observer) => { 62 | log.process(`analyze template`); 63 | if (getType(options.type) !== -1) { 64 | options.type = getType(options.type); 65 | } 66 | const temp = template[options.type]; 67 | observer.next([options, temp]); 68 | }); 69 | } 70 | 71 | 72 | function processTemplate([options, temp]) { 73 | return new Observable((observer) => { 74 | log.process(`process template`); 75 | const exports = []; 76 | const name = new RegExp('{{name}}', 'g'); 77 | const styleName = new RegExp('{{styleName}}', 'g'); 78 | let fileExt = 'tsx'; 79 | let fileName = options.name; 80 | 81 | if (options.type === 'state') { 82 | fileName = `${toKebabCase(fileName)}.state`; 83 | } 84 | if (options.type === 'hook') { 85 | fileName = `${toKebabCase(fileName)}.hook`; 86 | } 87 | if (options.type === 'context') { 88 | fileName = `${toKebabCase(fileName)}.context`; 89 | } 90 | temp = temp.replace(name, options.name); 91 | temp = temp.replace(styleName, options.name); 92 | exports.push({ 93 | file: `${fileName}.${fileExt}`, 94 | content: temp 95 | }); 96 | 97 | if (options.type === 'view' || 98 | options.type === 'ssr') { 99 | let test = template['enzyme-test']; 100 | test = test.replace(name, options.name); 101 | exports.push({ 102 | file: `${options.name}.spec.${fileExt}`, 103 | content: test 104 | }); 105 | exports.push({ 106 | file: `${options.name}.scss`, 107 | content: '' 108 | }); 109 | } 110 | observer.next([options, exports]); 111 | }); 112 | } 113 | 114 | function saveTemplate([options, exports]) { 115 | return new Observable((observer) => { 116 | log.process(`save template`); 117 | const exportDirName = toKebabCase(options.name); 118 | let exportDir = cwd; 119 | if (basename(process.cwd()) !== exportDirName) { 120 | exportDir = resolve(`${cwd}/${exportDirName}`) 121 | } 122 | 123 | if (existsSync(exportDir) && 124 | existsSync(resolve(`${exportDir}/${options.name}.tsx`)) && 125 | (options.type === 'view' || 126 | options.type === 'component' || 127 | options.type === 'fn-component' || 128 | options.type === 'arrow-fn-component' || 129 | options.type === 'ssr')) { 130 | observer.error(`${exportDirName} already exists`); 131 | } 132 | if (!existsSync(exportDir)) { 133 | mkdir(exportDir); 134 | } 135 | 136 | options.exportDir = exportDir; 137 | 138 | exports.forEach((ext, i) => { 139 | options.results.push(`${ext.file} created`); 140 | writeFile(resolve(`${exportDir}/${ext.file}`), ext.content, 'utf-8', () => { 141 | if (i === exports.length - 1) { 142 | observer.next(options); 143 | } 144 | }); 145 | }); 146 | 147 | }); 148 | } 149 | 150 | 151 | function transformRoutes(content, options) { 152 | const imp = template['import']; 153 | const route = template['route']; 154 | const lazyRoute = template['lazy-route']; 155 | const importedComponent = template['imported-component']; 156 | const routeRegex = new RegExp(//, 'gm'); 157 | const importRegex = new RegExp(/import.*?from.*?;/, 'gm'); 158 | const routeMatches = content.match(routeRegex); 159 | const routeMatch = routeMatches[routeMatches.length - 1]; 160 | const importMatches = content.match(importRegex); 161 | const importMatch = importMatches[importMatches.length - 1]; 162 | if (options.args.lazy) { 163 | let newLazy = importedComponent.replace(/{{name}}/g, options.name); 164 | newLazy = newLazy.replace(/{{path}}/g, options.exportDir.replace(options.routerDir, '')); 165 | let newLazyRoute = lazyRoute.replace(/{{routeName}}/g, toKebabCase(options.name)); 166 | newLazyRoute = newLazyRoute.replace(/{{name}}/g, options.name); 167 | content = content.replace(importMatch, importMatch + newLazy); 168 | content = content.replace(routeMatch, routeMatch + newLazyRoute); 169 | } else { 170 | let newImport = imp.replace(/{{name}}/g, options.name); 171 | newImport = newImport.replace(/{{path}}/g, options.exportDir.replace(options.routerDir, '')); 172 | let newRoute = route.replace(/{{routeName}}/g, toKebabCase(options.name)); 173 | newRoute = newRoute.replace(/{{name}}/g, options.name); 174 | content = content.replace(importMatch, importMatch + importMatch); 175 | content = content.replace(routeMatch, routeMatch + newRoute); 176 | } 177 | content = content.replace(/^\s*$(?:\r\n?|\n)/gm, ''); 178 | content = prettier.format(content, { parser: 'typescript' }); 179 | return content; 180 | } 181 | 182 | function findRouter(options) { 183 | 184 | return new Observable((observer) => { 185 | 186 | function findMatch(dir) { 187 | const fileExt = 'tsx'; 188 | let match = null; 189 | glob(`*.${fileExt}`, { cwd: resolve(dir) , ignore: ['node_modules/**', '.cache/**'] }, function (err, files) { 190 | if (err) { 191 | observer.error(err); 192 | } 193 | files.forEach(file => { 194 | const f = grep('--', 'react-router-dom', join(dir, file)); 195 | if (f.stdout !== '\n') { 196 | match = file; 197 | readFile(join(dir, file), 'utf8', (err, contents) => { 198 | if (err) { 199 | observer.error(err); 200 | } else { 201 | options.routerDir = dir; 202 | writeFile(join(dir, file), transformRoutes(contents, options), (err) => { 203 | options.results.push(`${file} has new routes`); 204 | if (err) { 205 | observer.error(err); 206 | } 207 | observer.next(options); 208 | }); 209 | } 210 | }); 211 | } 212 | }); 213 | if (resolve(dir, '..') === projectDir) { 214 | observer.error('no routing found in project'); 215 | } 216 | if (!match) { 217 | findMatch(resolve(dir, '..')); 218 | } 219 | }); 220 | } 221 | 222 | findMatch(resolve(options.exportDir, '..')); 223 | 224 | }); 225 | } 226 | 227 | function mergeRouter(options) { 228 | if (options.args.routing) { 229 | return findRouter(options); 230 | } else { 231 | return new Observable((observer) => { 232 | observer.next(options); 233 | }); 234 | } 235 | } 236 | 237 | function generate(options) { 238 | options.results = [`\n`]; 239 | log.start(`rctr generate ${options.type} ${options.name}`); 240 | of(options).pipe( 241 | concatMap(results => init(results)), 242 | concatMap(results => getTemplate(results)), 243 | concatMap(results => processTemplate(results)), 244 | concatMap(results => saveTemplate(results)), 245 | concatMap(results => mergeRouter(results)), 246 | map(options => { 247 | options.results.forEach(result => log.print(`${result}`)); 248 | process.exit(0); 249 | }), 250 | catchError(error => { 251 | log.error(error); 252 | process.exit(1); 253 | }) 254 | ).subscribe() 255 | } 256 | 257 | module.exports = generate; -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/color-name@^1.1.1": 6 | version "1.1.1" 7 | resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" 8 | integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== 9 | 10 | ansi-regex@^2.0.0: 11 | version "2.1.1" 12 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 13 | integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= 14 | 15 | ansi-regex@^5.0.0: 16 | version "5.0.0" 17 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" 18 | integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== 19 | 20 | ansi-styles@^3.2.1: 21 | version "3.2.1" 22 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 23 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 24 | dependencies: 25 | color-convert "^1.9.0" 26 | 27 | ansi-styles@^4.1.0: 28 | version "4.2.1" 29 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" 30 | integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== 31 | dependencies: 32 | "@types/color-name" "^1.1.1" 33 | color-convert "^2.0.1" 34 | 35 | balanced-match@^1.0.0: 36 | version "1.0.0" 37 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 38 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 39 | 40 | brace-expansion@^1.1.7: 41 | version "1.1.11" 42 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 43 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 44 | dependencies: 45 | balanced-match "^1.0.0" 46 | concat-map "0.0.1" 47 | 48 | chalk@^2.4.2: 49 | version "2.4.2" 50 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 51 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 52 | dependencies: 53 | ansi-styles "^3.2.1" 54 | escape-string-regexp "^1.0.5" 55 | supports-color "^5.3.0" 56 | 57 | chalk@^3.0.0: 58 | version "3.0.0" 59 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" 60 | integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== 61 | dependencies: 62 | ansi-styles "^4.1.0" 63 | supports-color "^7.1.0" 64 | 65 | cli-cursor@^3.1.0: 66 | version "3.1.0" 67 | resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" 68 | integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== 69 | dependencies: 70 | restore-cursor "^3.1.0" 71 | 72 | cli-spinners@^2.2.0: 73 | version "2.2.0" 74 | resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.2.0.tgz#e8b988d9206c692302d8ee834e7a85c0144d8f77" 75 | integrity sha512-tgU3fKwzYjiLEQgPMD9Jt+JjHVL9kW93FiIMX/l7rivvOD4/LL0Mf7gda3+4U2KJBloybwgj5KEoQgGRioMiKQ== 76 | 77 | clone@^1.0.2: 78 | version "1.0.4" 79 | resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" 80 | integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= 81 | 82 | code-point-at@^1.0.0: 83 | version "1.1.0" 84 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" 85 | integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= 86 | 87 | color-convert@^1.9.0: 88 | version "1.9.3" 89 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 90 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 91 | dependencies: 92 | color-name "1.1.3" 93 | 94 | color-convert@^2.0.1: 95 | version "2.0.1" 96 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 97 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 98 | dependencies: 99 | color-name "~1.1.4" 100 | 101 | color-name@1.1.3: 102 | version "1.1.3" 103 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 104 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 105 | 106 | color-name@~1.1.4: 107 | version "1.1.4" 108 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 109 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 110 | 111 | colors@~0.6.0-1: 112 | version "0.6.2" 113 | resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" 114 | integrity sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w= 115 | 116 | commander@^4.1.0: 117 | version "4.1.0" 118 | resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.0.tgz#545983a0603fe425bc672d66c9e3c89c42121a83" 119 | integrity sha512-NIQrwvv9V39FHgGFm36+U9SMQzbiHvU79k+iADraJTpmrFFfx7Ds0IvDoAdZsDrknlkRk14OYoWXb57uTh7/sw== 120 | 121 | commander@~2.1.0: 122 | version "2.1.0" 123 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" 124 | integrity sha1-0SG7roYNmZKj1Re6lvVliOR8Z4E= 125 | 126 | concat-map@0.0.1: 127 | version "0.0.1" 128 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 129 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 130 | 131 | defaults@^1.0.3: 132 | version "1.0.3" 133 | resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" 134 | integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= 135 | dependencies: 136 | clone "^1.0.2" 137 | 138 | escape-string-regexp@^1.0.5: 139 | version "1.0.5" 140 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 141 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 142 | 143 | findup@^0.1.5: 144 | version "0.1.5" 145 | resolved "https://registry.yarnpkg.com/findup/-/findup-0.1.5.tgz#8ad929a3393bac627957a7e5de4623b06b0e2ceb" 146 | integrity sha1-itkpozk7rGJ5V6fl3kYjsGsOLOs= 147 | dependencies: 148 | colors "~0.6.0-1" 149 | commander "~2.1.0" 150 | 151 | fs.realpath@^1.0.0: 152 | version "1.0.0" 153 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 154 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 155 | 156 | glob@^7.0.0, glob@^7.1.3, glob@^7.1.6: 157 | version "7.1.6" 158 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" 159 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== 160 | dependencies: 161 | fs.realpath "^1.0.0" 162 | inflight "^1.0.4" 163 | inherits "2" 164 | minimatch "^3.0.4" 165 | once "^1.3.0" 166 | path-is-absolute "^1.0.0" 167 | 168 | has-flag@^3.0.0: 169 | version "3.0.0" 170 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 171 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 172 | 173 | has-flag@^4.0.0: 174 | version "4.0.0" 175 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 176 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 177 | 178 | inflight@^1.0.4: 179 | version "1.0.6" 180 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 181 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 182 | dependencies: 183 | once "^1.3.0" 184 | wrappy "1" 185 | 186 | inherits@2: 187 | version "2.0.4" 188 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 189 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 190 | 191 | interpret@^1.0.0: 192 | version "1.2.0" 193 | resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" 194 | integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== 195 | 196 | is-fullwidth-code-point@^1.0.0: 197 | version "1.0.0" 198 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 199 | integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= 200 | dependencies: 201 | number-is-nan "^1.0.0" 202 | 203 | is-interactive@^1.0.0: 204 | version "1.0.0" 205 | resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" 206 | integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== 207 | 208 | log-symbols@^3.0.0: 209 | version "3.0.0" 210 | resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" 211 | integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ== 212 | dependencies: 213 | chalk "^2.4.2" 214 | 215 | mimic-fn@^2.1.0: 216 | version "2.1.0" 217 | resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" 218 | integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== 219 | 220 | minimatch@^3.0.4: 221 | version "3.0.4" 222 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 223 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 224 | dependencies: 225 | brace-expansion "^1.1.7" 226 | 227 | mute-stream@0.0.8: 228 | version "0.0.8" 229 | resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" 230 | integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== 231 | 232 | number-is-nan@^1.0.0: 233 | version "1.0.1" 234 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 235 | integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= 236 | 237 | once@^1.3.0: 238 | version "1.4.0" 239 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 240 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 241 | dependencies: 242 | wrappy "1" 243 | 244 | onetime@^5.1.0: 245 | version "5.1.0" 246 | resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" 247 | integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q== 248 | dependencies: 249 | mimic-fn "^2.1.0" 250 | 251 | ora@^4.0.3: 252 | version "4.0.3" 253 | resolved "https://registry.yarnpkg.com/ora/-/ora-4.0.3.tgz#752a1b7b4be4825546a7a3d59256fa523b6b6d05" 254 | integrity sha512-fnDebVFyz309A73cqCipVL1fBZewq4vwgSHfxh43vVy31mbyoQ8sCH3Oeaog/owYOs/lLlGVPCISQonTneg6Pg== 255 | dependencies: 256 | chalk "^3.0.0" 257 | cli-cursor "^3.1.0" 258 | cli-spinners "^2.2.0" 259 | is-interactive "^1.0.0" 260 | log-symbols "^3.0.0" 261 | mute-stream "0.0.8" 262 | strip-ansi "^6.0.0" 263 | wcwidth "^1.0.1" 264 | 265 | path-is-absolute@^1.0.0: 266 | version "1.0.1" 267 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 268 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 269 | 270 | path-parse@^1.0.6: 271 | version "1.0.6" 272 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" 273 | integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== 274 | 275 | prettier@^1.19.1: 276 | version "1.19.1" 277 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" 278 | integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== 279 | 280 | rechoir@^0.6.2: 281 | version "0.6.2" 282 | resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" 283 | integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= 284 | dependencies: 285 | resolve "^1.1.6" 286 | 287 | resolve@^1.1.6: 288 | version "1.15.0" 289 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.0.tgz#1b7ca96073ebb52e741ffd799f6b39ea462c67f5" 290 | integrity sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw== 291 | dependencies: 292 | path-parse "^1.0.6" 293 | 294 | restore-cursor@^3.1.0: 295 | version "3.1.0" 296 | resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" 297 | integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== 298 | dependencies: 299 | onetime "^5.1.0" 300 | signal-exit "^3.0.2" 301 | 302 | rimraf@^3.0.1: 303 | version "3.0.1" 304 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.1.tgz#48d3d4cb46c80d388ab26cd61b1b466ae9ae225a" 305 | integrity sha512-IQ4ikL8SjBiEDZfk+DFVwqRK8md24RWMEJkdSlgNLkyyAImcjf8SWvU1qFMDOb4igBClbTQ/ugPqXcRwdFTxZw== 306 | dependencies: 307 | glob "^7.1.3" 308 | 309 | rxjs@^6.5.4: 310 | version "6.5.4" 311 | resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c" 312 | integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q== 313 | dependencies: 314 | tslib "^1.9.0" 315 | 316 | shelljs@^0.8.3: 317 | version "0.8.3" 318 | resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097" 319 | integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A== 320 | dependencies: 321 | glob "^7.0.0" 322 | interpret "^1.0.0" 323 | rechoir "^0.6.2" 324 | 325 | signal-exit@^3.0.2: 326 | version "3.0.2" 327 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" 328 | integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= 329 | 330 | single-line-log@^1.1.2: 331 | version "1.1.2" 332 | resolved "https://registry.yarnpkg.com/single-line-log/-/single-line-log-1.1.2.tgz#c2f83f273a3e1a16edb0995661da0ed5ef033364" 333 | integrity sha1-wvg/Jzo+GhbtsJlWYdoO1e8DM2Q= 334 | dependencies: 335 | string-width "^1.0.1" 336 | 337 | string-width@^1.0.1: 338 | version "1.0.2" 339 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 340 | integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= 341 | dependencies: 342 | code-point-at "^1.0.0" 343 | is-fullwidth-code-point "^1.0.0" 344 | strip-ansi "^3.0.0" 345 | 346 | strip-ansi@^3.0.0: 347 | version "3.0.1" 348 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 349 | integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= 350 | dependencies: 351 | ansi-regex "^2.0.0" 352 | 353 | strip-ansi@^6.0.0: 354 | version "6.0.0" 355 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" 356 | integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== 357 | dependencies: 358 | ansi-regex "^5.0.0" 359 | 360 | supports-color@^5.3.0: 361 | version "5.5.0" 362 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 363 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 364 | dependencies: 365 | has-flag "^3.0.0" 366 | 367 | supports-color@^7.1.0: 368 | version "7.1.0" 369 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" 370 | integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== 371 | dependencies: 372 | has-flag "^4.0.0" 373 | 374 | tslib@^1.9.0: 375 | version "1.10.0" 376 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" 377 | integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== 378 | 379 | wcwidth@^1.0.1: 380 | version "1.0.1" 381 | resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" 382 | integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= 383 | dependencies: 384 | defaults "^1.0.3" 385 | 386 | wrappy@1: 387 | version "1.0.2" 388 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 389 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 390 | --------------------------------------------------------------------------------