├── .gitignore ├── .npmignore ├── README.md ├── package.json ├── src ├── index.ts ├── templates │ └── clean-architecture │ │ ├── .babelrc │ │ ├── .editorconfig │ │ ├── .eslintignore │ │ ├── .eslintrc │ │ ├── .gitignore │ │ ├── .prettierrc │ │ ├── __mocks__ │ │ ├── emptyFileMock.js │ │ ├── setupTest.js │ │ └── svgMock.js │ │ ├── jest.config.js │ │ ├── package.json │ │ ├── public │ │ └── index.html │ │ ├── src │ │ ├── @types │ │ │ └── declarations.d.ts │ │ ├── domain │ │ │ ├── models │ │ │ │ └── ITodo.model.ts │ │ │ └── usecases │ │ │ │ └── ICreateTodoList.usecase.ts │ │ ├── infrastructure │ │ │ ├── cache │ │ │ │ ├── __tests__ │ │ │ │ │ └── localStorage.spec.ts │ │ │ │ ├── implementation │ │ │ │ │ └── LocalStorage.ts │ │ │ │ ├── inMemory │ │ │ │ │ └── LocalStorage.ts │ │ │ │ ├── index.ts │ │ │ │ └── models │ │ │ │ │ └── ICache.model.ts │ │ │ └── http │ │ │ │ └── httpClient │ │ │ │ ├── __tests__ │ │ │ │ └── axios.spec.ts │ │ │ │ ├── dtos │ │ │ │ └── IHttpClient.dto.ts │ │ │ │ ├── implementation │ │ │ │ └── Axios.ts │ │ │ │ ├── index.ts │ │ │ │ └── models │ │ │ │ └── IHttpClient.model.ts │ │ ├── presentation │ │ │ ├── App.tsx │ │ │ ├── __tests__ │ │ │ │ └── App.spec.tsx │ │ │ ├── assets │ │ │ │ └── styles │ │ │ │ │ └── global.ts │ │ │ ├── bootstrap.tsx │ │ │ ├── index.ts │ │ │ └── pages │ │ │ │ └── Home │ │ │ │ ├── __tests__ │ │ │ │ └── index.spec.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── styles.ts │ │ ├── shared │ │ │ └── Either.ts │ │ └── usecases │ │ │ ├── CreateTodoList.usecase.ts │ │ │ ├── __tests__ │ │ │ └── CreateTodoList.usecase.spec.ts │ │ │ └── index.ts │ │ ├── tsconfig.json │ │ └── webpack.config.js └── utils │ └── template.ts ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | node_modules 3 | dist 4 | yarn-error.log 5 | .DS_Store 6 | .vscode/** 7 | .idea/ 8 | result.xml 9 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | ./src 3 | ./tsconfig.json 4 | .gitignore 5 | yarn.lock -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Clean Architecture CLI 2 | 3 | Create an App React with clean architecture and Typescript. 4 | Jest, styled components and webpack 5 with federation module for microfrontend already configured. 5 | 6 | ## Install 7 | 8 | ```shell 9 | npm install -g react-clean-architecture-cli 10 | ``` 11 | 12 | or 13 | 14 | ```shell 15 | yarn global add react-clean-architecture-cli 16 | ``` 17 | 18 | ## Creating an App 19 | 20 | ```shell 21 | npx react-clean-architecture-cli my-app 22 | ``` 23 | 24 | or 25 | 26 | ```shell 27 | react-clean-architecture my-app 28 | ``` 29 | 30 | or 31 | 32 | ```shell 33 | react-clean-architecture 34 | ``` 35 | 36 | and insert app name 37 | 38 | It will create a directory called `my-app` inside the current folder.
39 | Inside that directory, it will generate the initial project structure and install the transitive dependencies: 40 | 41 | ``` 42 | my-app 43 | ├── node_modules 44 | ├── __mocks__ 45 | │ ├── emptyFileMock.js 46 | │ └── setupTest.js 47 | ├── package.json 48 | ├── .editorconfig 49 | ├── .eslintignore 50 | ├── .eslintrc 51 | ├── .gitignore 52 | ├── .prettierrc 53 | ├── jest.config.js 54 | ├── tsconfig.json 55 | ├── webpack.config.js 56 | ├── public 57 | │ └── index.html 58 | └── src 59 | ├── @types 60 | │── domain 61 | │ ├── models 62 | │ └── usecases 63 | ├── infrastructure 64 | │ ├── http 65 | │ │ ├── __tests__ 66 | │ │ ├── implementation 67 | │ │ ├── inMemory 68 | │ │ ├── models 69 | │ │ └── index.ts 70 | │ └── cache 71 | │ ├── __tests__ 72 | │ ├── dtos 73 | │ ├── implementation 74 | │ ├── models 75 | │ └── index.ts 76 | ├── presentation 77 | │ ├── __tests__ 78 | │ ├── assets 79 | │ ├── components 80 | │ ├── hooks 81 | │ ├── pages 82 | │ ├── App.tsx 83 | │ └── index.tsx 84 | ├── shared 85 | │ └── Either.ts 86 | └── usecases 87 | ``` 88 | 89 | ```sh 90 | cd my-app 91 | ``` 92 | 93 | Inside the newly created project, you can run some built-in commands: 94 | 95 | ### `npm start:dev` or `yarn start:dev` 96 | 97 | Runs the app in development mode.
98 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 99 | 100 | The page will automatically reload if you make changes to the code.
101 | You will see the build errors and lint warnings in the console. 102 | 103 | ### `npm test` or `yarn test` 104 | 105 | Runs the test.
106 | 107 | ### `npm test:cov` or `yarn test:cov` 108 | 109 | Runs the test and generate coverage.
110 | 111 | ### `npm test:watch` or `yarn test:watch` 112 | 113 | Runs the test watcher in an interactive mode.
114 | 115 | ### `npm run build` or `yarn build` 116 | 117 | Builds the app for production to the `dist` folder.
118 | 119 | Your app is ready to be deployed. 120 | 121 | ## License 122 | 123 | This project is licensed under the [MIT License](https://opensource.org/licenses/MIT). 124 | 125 | Development by: [andrecoelho.dev](https://andrecoelho.dev) | Software Engineer 126 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-clean-architecture-cli", 3 | "description": "React.js Clean Architecture application", 4 | "version": "1.0.21", 5 | "main": "dist/index.js", 6 | "keywords": [ 7 | "react", 8 | "javascript", 9 | "typescript", 10 | "cli", 11 | "clean architecture", 12 | "clean", 13 | "architecture", 14 | "webpack", 15 | "styled-components", 16 | "node", 17 | "jest", 18 | "testing-library" 19 | ], 20 | "author": "André Coelho", 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/avrcoelho/react-clean-architecture-cli.git" 24 | }, 25 | "bugs": { 26 | "url": "https://github.com/avrcoelho/react-clean-architecture-cli/issues" 27 | }, 28 | "homepage": "https://github.com/avrcoelho/react-clean-architecture-cli", 29 | "scripts": { 30 | "start": "ts-node src/index.ts", 31 | "build": "tsc && shx cp -r src/templates dist" 32 | }, 33 | "bin": { 34 | "react-clean-architecture": "./dist/index.js" 35 | }, 36 | "license": "MIT", 37 | "devDependencies": { 38 | "@types/ejs": "^3.0.6", 39 | "@types/inquirer": "^7.3.1", 40 | "@types/node": "^15.0.2", 41 | "@types/shelljs": "^0.8.8", 42 | "@types/yargs": "^16.0.1", 43 | "shx": "^0.3.3", 44 | "ts-node": "^7.0.1", 45 | "typescript": "^3.0.3" 46 | }, 47 | "dependencies": { 48 | "ejs": "^3.1.6", 49 | "inquirer": "^8.0.0", 50 | "shelljs": "^0.8.4", 51 | "yargs": "^17.0.1" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import * as inquirer from "inquirer"; 4 | import * as fs from "fs"; 5 | import * as path from "path"; 6 | import * as shell from "shelljs"; 7 | import * as template from "./utils/template"; 8 | import * as chalk from "chalk"; 9 | import * as yargs from "yargs"; 10 | 11 | const QUESTIONS = [ 12 | { 13 | name: "name", 14 | type: "input", 15 | message: "App name:", 16 | when: () => !yargs.argv["name"] && !yargs.argv._[0], 17 | validate: (input: string) => { 18 | if (/^([A-Za-z\-\_\d])+$/.test(input)) return true; 19 | else 20 | return "App name may only include letters, numbers, underscores and hashes."; 21 | }, 22 | }, 23 | ]; 24 | 25 | const CURR_DIR = process.cwd(); 26 | 27 | export interface TemplateConfig { 28 | files?: string[]; 29 | postMessage?: string; 30 | } 31 | 32 | export interface CliOptions { 33 | projectName: string; 34 | templateName: string; 35 | templatePath: string; 36 | tartgetPath: string; 37 | config: TemplateConfig; 38 | } 39 | 40 | console.log( 41 | chalk.blue(` 42 | ------------------------------------- 43 | andrecoelho.dev | Software Enginner 44 | ------------------------------------- 45 | `) 46 | ); 47 | 48 | inquirer.prompt(QUESTIONS).then((answers) => { 49 | answers = Object.assign({}, answers, { 50 | name: yargs.argv["name"] || yargs.argv._[0], 51 | }); 52 | 53 | const projectChoice = "clean-architecture"; 54 | const projectName = answers["name"]; 55 | const templatePath = path.join(__dirname, "templates", projectChoice); 56 | const tartgetPath = path.join(CURR_DIR, projectName); 57 | const templateConfig = getTemplateConfig(templatePath); 58 | 59 | const options: CliOptions = { 60 | projectName, 61 | templateName: projectChoice, 62 | templatePath, 63 | tartgetPath, 64 | config: templateConfig, 65 | }; 66 | 67 | if (!createProject(tartgetPath)) { 68 | return; 69 | } 70 | 71 | createDirectoryContents(templatePath, projectName, templateConfig); 72 | 73 | if (!postProcess(options)) { 74 | return; 75 | } 76 | 77 | showMessage(options); 78 | }); 79 | 80 | function showMessage(options: CliOptions) { 81 | console.log(""); 82 | console.log(chalk.green("Done.")); 83 | console.log(chalk.green(`Go into the project: cd ${options.projectName}`)); 84 | 85 | const message = options.config.postMessage; 86 | 87 | if (message) { 88 | console.log(""); 89 | console.log(chalk.yellow(message)); 90 | console.log(""); 91 | } 92 | } 93 | 94 | function getTemplateConfig(templatePath: string): TemplateConfig { 95 | const configPath = path.join(templatePath, ".template.json"); 96 | 97 | if (!fs.existsSync(configPath)) return {}; 98 | 99 | const templateConfigContent = fs.readFileSync(configPath); 100 | 101 | if (templateConfigContent) { 102 | return JSON.parse(templateConfigContent.toString()); 103 | } 104 | 105 | return {}; 106 | } 107 | 108 | function createProject(projectPath: string) { 109 | if (fs.existsSync(projectPath)) { 110 | console.log( 111 | chalk.red(`Folder ${projectPath} exists. Delete or use another name.`) 112 | ); 113 | return false; 114 | } 115 | 116 | fs.mkdirSync(projectPath); 117 | return true; 118 | } 119 | 120 | function postProcess(options: CliOptions) { 121 | if (isNode(options)) { 122 | return postProcessNode(options); 123 | } 124 | return true; 125 | } 126 | 127 | function isNode(options: CliOptions) { 128 | return fs.existsSync(path.join(options.templatePath, "package.json")); 129 | } 130 | 131 | function postProcessNode(options: CliOptions) { 132 | shell.cd(options.tartgetPath); 133 | 134 | let cmd = ""; 135 | 136 | if (shell.which("yarn")) { 137 | cmd = "yarn"; 138 | } else if (shell.which("npm")) { 139 | cmd = "npm install"; 140 | } 141 | 142 | if (cmd) { 143 | const result = shell.exec(cmd); 144 | 145 | if (result.code !== 0) { 146 | return false; 147 | } 148 | } else { 149 | console.log(chalk.red("No yarn or npm found. Cannot run installation.")); 150 | } 151 | 152 | return true; 153 | } 154 | 155 | const SKIP_FILES = ["node_modules", ".template.json"]; 156 | 157 | function createDirectoryContents( 158 | templatePath: string, 159 | projectName: string, 160 | config: TemplateConfig 161 | ) { 162 | const filesToCreate = fs.readdirSync(templatePath); 163 | 164 | filesToCreate.forEach((file) => { 165 | const origFilePath = path.join(templatePath, file); 166 | 167 | // get stats about the current file 168 | const stats = fs.statSync(origFilePath); 169 | 170 | if (SKIP_FILES.indexOf(file) > -1) return; 171 | 172 | if (stats.isFile()) { 173 | let contents = fs.readFileSync(origFilePath, "utf8"); 174 | const microName = projectName.replace(/[^a-zA-Z0-9]/g, ""); 175 | contents = template.render(contents, { projectName, microName }); 176 | const writePath = path.join(CURR_DIR, projectName, file); 177 | fs.writeFileSync(writePath, contents, "utf8"); 178 | } else if (stats.isDirectory()) { 179 | fs.mkdirSync(path.join(CURR_DIR, projectName, file)); 180 | 181 | // recursive call 182 | createDirectoryContents( 183 | path.join(templatePath, file), 184 | path.join(projectName, file), 185 | config 186 | ); 187 | } 188 | }); 189 | } 190 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", 4 | ["@babel/preset-react", { 5 | "runtime": "automatic" 6 | }], 7 | "@babel/preset-typescript" 8 | ], 9 | "plugins": ["babel-plugin-styled-components"] 10 | } 11 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/.editorconfig: -------------------------------------------------------------------------------- 1 | # https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 2 8 | indent_style = space 9 | insert_final_newline = true 10 | max_line_length = 80 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | max_line_length = 0 15 | trim_trailing_whitespace = false 16 | 17 | [COMMIT_EDITMSG] 18 | max_line_length = 0 -------------------------------------------------------------------------------- /src/templates/clean-architecture/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/** 2 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | 4 | "plugins": [ 5 | "react", 6 | "react-hooks", 7 | "jsx-a11y", 8 | "@typescript-eslint", 9 | "prettier" 10 | ], 11 | 12 | "settings": { 13 | "react": { "version": "detect" } 14 | }, 15 | 16 | "env": { 17 | "jest": true, 18 | "browser": true 19 | }, 20 | 21 | "parserOptions": { 22 | "ecmaFeatures": { 23 | "jsx": true, 24 | "modules": true 25 | } 26 | }, 27 | 28 | "extends": [ 29 | "eslint:recommended", 30 | "plugin:react/recommended", 31 | "plugin:jsx-a11y/recommended", 32 | "plugin:@typescript-eslint/eslint-recommended", 33 | "plugin:@typescript-eslint/recommended", 34 | "prettier/@typescript-eslint", 35 | "plugin:prettier/recommended" 36 | ], 37 | 38 | "rules": { 39 | "react/jsx-uses-react": "off", 40 | "react/react-in-jsx-scope": "off", 41 | 42 | // Spacing 43 | "no-mixed-spaces-and-tabs": "error", 44 | "no-tabs": "error", 45 | 46 | // Semicolons 47 | "semi": ["error", "always"], 48 | "semi-spacing": "warn", 49 | "no-extra-semi": "error", 50 | 51 | // General Syntax 52 | "prefer-arrow-callback": "warn", 53 | "no-extra-boolean-cast": "off", 54 | 55 | // React 56 | "react/prop-types": "error", 57 | "react-hooks/rules-of-hooks": "error", 58 | 59 | // Code smells 60 | "max-lines": ["warn", { "max": 150, "skipBlankLines": true, "skipComments": true}], 61 | "max-statements": ["warn", { "max": 15 }], 62 | "array-callback-return": ["error", { "checkForEach": true }], 63 | "max-nested-callbacks": ["warn", { "max": 5 }], 64 | "no-console": "error", 65 | 66 | // Typescript 67 | "@typescript-eslint/explicit-module-boundary-types": "off" 68 | }, 69 | 70 | "overrides": [ 71 | { 72 | // Disable prop types check on TypeScript files since props rely on Interfaces 73 | "files": ["*.tsx"], 74 | "rules": { 75 | "react/prop-types": "off" 76 | } 77 | }, 78 | { 79 | // Empty functions and long files are acceptable on tests 80 | "files": ["*.spec.js", "*.spec.jsx", "*.spec.ts", "*.spec.tsx"], 81 | "rules": { 82 | "@typescript-eslint/no-empty-function": "off", 83 | "max-lines": "off", 84 | "max-statements": "off" 85 | } 86 | } 87 | ] 88 | } 89 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/.gitignore: -------------------------------------------------------------------------------- 1 | coverage 2 | node_modules 3 | dist 4 | yarn-error.log 5 | .DS_Store 6 | eslint-report.json 7 | .vscode/** 8 | .idea/ 9 | result.xml 10 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "singleQuote": true, 6 | "trailingComma": "all", 7 | "arrowParens": "avoid" 8 | } 9 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/__mocks__/emptyFileMock.js: -------------------------------------------------------------------------------- 1 | /* globals module */ 2 | module.exports = 'empty-file-mock'; 3 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/__mocks__/setupTest.js: -------------------------------------------------------------------------------- 1 | import 'core-js/stable'; 2 | import 'regenerator-runtime/runtime'; 3 | 4 | process.env.API_URL = 'http://localhost:3333'; 5 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/__mocks__/svgMock.js: -------------------------------------------------------------------------------- 1 | export default 'empty-file-mock' 2 | export const ReactComponent = 'empty-file-mock' 3 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/jest.config.js: -------------------------------------------------------------------------------- 1 | /* globals module */ 2 | module.exports = { 3 | clearMocks: true, 4 | collectCoverageFrom: [ 5 | '/src/**/*.{ts,tsx}', 6 | '!/src/**/dtos/*', 7 | '!/src/**/models/*', 8 | '!/src/@types/*', 9 | '!/src/presentation/assets/**/*', 10 | '!/src/presentation/index.tsx', 11 | '!/src/infrastructure/**/index.ts', 12 | '!/src/**/inMemory/*', 13 | '!/src/domain/usecases/*', 14 | '!/src/usecases/index.ts', 15 | '!/src/shared/Either.ts', 16 | ], 17 | coverageDirectory: 'coverage', 18 | coverageThreshold: { 19 | global: { 20 | branches: 0, 21 | functions: 0, 22 | lines: 0, 23 | }, 24 | }, 25 | moduleNameMapper: { 26 | '\\.(css|png|jpe?g)$': '/__mocks__/emptyFileMock.js', 27 | '\\.svg$': '/__mocks__/svgMock.js', 28 | '@/(.*)': '/src/$1', 29 | }, 30 | testMatch: ['/src/**/__tests__/**/*.spec.{ts,tsx}'], 31 | setupFiles: ['/__mocks__/setupTest.js'], 32 | }; 33 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= projectName %>", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "private": true, 7 | "scripts": { 8 | "start:dev": "NODE_OPTIONS=--max-old-space-size=3584 webpack-cli serve --mode development", 9 | "build": "NODE_OPTIONS=--max-old-space-size=3584 webpack --mode production", 10 | "test": "jest --config=jest.config.js", 11 | "test:cov": "jest --config=jest.config.js --coverage", 12 | "test:watch": "jest --config=jest.config.json --watch" 13 | }, 14 | "dependencies": { 15 | "axios": "^0.21.1", 16 | "react": "^17.0.2", 17 | "react-dom": "^17.0.2", 18 | "styled-components": "^5.2.3" 19 | }, 20 | "devDependencies": { 21 | "@babel/cli": "^7.13.16", 22 | "@babel/core": "^7.14.0", 23 | "@babel/plugin-transform-react-jsx": "^7.13.12", 24 | "@babel/polyfill": "^7.12.1", 25 | "@babel/preset-env": "^7.14.1", 26 | "@babel/preset-react": "^7.13.13", 27 | "@babel/preset-typescript": "^7.13.0", 28 | "@babel/runtime": "^7.14.0", 29 | "@svgr/webpack": "^5.5.0", 30 | "@testing-library/jest-dom": "^5.12.0", 31 | "@testing-library/react": "^11.2.6", 32 | "@testing-library/react-hooks": "^5.1.2", 33 | "@types/jest": "^26.0.23", 34 | "@types/react": "^17.0.5", 35 | "@types/react-dom": "^17.0.3", 36 | "@types/styled-components": "^5.1.9", 37 | "@typescript-eslint/eslint-plugin": "^4.22.1", 38 | "@typescript-eslint/parser": "^4.22.1", 39 | "autoprefixer": "^10.2.5", 40 | "babel-loader": "^8.2.2", 41 | "babel-jest": "^26.6.3", 42 | "babel-plugin-styled-components": "^1.12.0", 43 | "babel-polyfill": "^6.26.0", 44 | "clean-webpack-plugin": "^4.0.0-alpha.0", 45 | "core-js": "^3.12.1", 46 | "css-loader": "^5.2.4", 47 | "eslint": "^7.25.0", 48 | "eslint-config-airbnb": "^18.2.1", 49 | "eslint-config-prettier": "^8.3.0", 50 | "eslint-plugin-import": "^2.22.1", 51 | "eslint-plugin-jsx-a11y": "^6.4.1", 52 | "eslint-plugin-prettier": "^3.4.0", 53 | "eslint-plugin-react": "^7.21.5", 54 | "eslint-plugin-react-hooks": "^4", 55 | "html-webpack-plugin": "^5.3.1", 56 | "jest": "^26.6.3", 57 | "mini-css-extract-plugin": "^1.6.0", 58 | "msw": "^0.28.2", 59 | "node-polyfill-webpack-plugin": "^1.1.0", 60 | "postcss": "^8.2.13", 61 | "postcss-loader": "^5.2.0", 62 | "postcss-preset-env": "^6.7.0", 63 | "prettier": "^2.2.1", 64 | "regenerator-runtime": "^0.13.7", 65 | "sass": "^1.32.12", 66 | "sass-loader": "^11.0.1", 67 | "style-loader": "^2.0.0", 68 | "ts-loader": "^9.1.1", 69 | "typescript": "^4.2.4", 70 | "url-loader": "^4.1.1", 71 | "webpack": "^5.36.2", 72 | "webpack-cli": "^4.6.0", 73 | "webpack-dev-server": "^3.11.2" 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | Document 13 | 14 | 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/@types/declarations.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module '*.svg' { 4 | const content: any; 5 | export default content; 6 | export const ReactComponent: React.ComponentType; 7 | } 8 | 9 | declare module '*.png' { 10 | const content: any; 11 | export default content; 12 | } 13 | 14 | declare module '*.jpg' { 15 | const content: any; 16 | export default content; 17 | } 18 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/domain/models/ITodo.model.ts: -------------------------------------------------------------------------------- 1 | export default interface ITodoListModel { 2 | id: string; 3 | title: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/domain/usecases/ICreateTodoList.usecase.ts: -------------------------------------------------------------------------------- 1 | import { Either } from '@/shared/Either'; 2 | import ITodoModel from '../models/ITodo.model'; 3 | 4 | export interface ICreateTodoListUsecaseArgs { 5 | title: string; 6 | } 7 | 8 | export interface ICreateTodoListUsecase { 9 | execute: ( 10 | args: ICreateTodoListUsecaseArgs, 11 | ) => Promise>; 12 | } 13 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/infrastructure/cache/__tests__/localStorage.spec.ts: -------------------------------------------------------------------------------- 1 | import LocalStorage from '../implementation/LocalStorage'; 2 | 3 | let localStorageCache: LocalStorage; 4 | 5 | describe('LocalStorage', () => { 6 | beforeEach(() => { 7 | localStorageCache = new LocalStorage(); 8 | }); 9 | 10 | it('should be able to save data in localstorage', async () => { 11 | const setItemSpy = jest.spyOn(Storage.prototype, 'setItem'); 12 | const data = JSON.stringify({ name: 'John Doe' }); 13 | 14 | localStorageCache.save('test', data); 15 | 16 | expect(setItemSpy).toBeCalledWith('test', data); 17 | }); 18 | 19 | it('should be able to get data item in localstorage', async () => { 20 | const data = JSON.stringify({ name: 'John Doe' }); 21 | localStorageCache.save('test', data); 22 | 23 | const itemData = localStorageCache.get('test'); 24 | 25 | expect(itemData).toEqual({ name: 'John Doe' }); 26 | }); 27 | 28 | it('should be able to returned null when item not exists', async () => { 29 | const itemData = localStorageCache.get('test-2'); 30 | 31 | expect(itemData).toBe(null); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/infrastructure/cache/implementation/LocalStorage.ts: -------------------------------------------------------------------------------- 1 | import ICacheModel from '../models/ICache.model'; 2 | 3 | class LocalStorage implements ICacheModel { 4 | private readonly storage: Storage; 5 | 6 | constructor() { 7 | this.storage = localStorage; 8 | } 9 | 10 | public get(key: string): T | null { 11 | const data = this.storage.getItem(key); 12 | 13 | if (!data) { 14 | return null; 15 | } 16 | 17 | const parsedData = JSON.parse(data) as T; 18 | 19 | return parsedData; 20 | } 21 | 22 | public save(key: string, value: string): void { 23 | this.storage.setItem(key, value); 24 | } 25 | } 26 | 27 | export default LocalStorage; 28 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/infrastructure/cache/inMemory/LocalStorage.ts: -------------------------------------------------------------------------------- 1 | import ICacheModel from '../models/ICache.model'; 2 | 3 | interface ICacheData { 4 | [key: string]: string; 5 | } 6 | 7 | class LocalStorage implements ICacheModel { 8 | private storage: ICacheData = {}; 9 | 10 | public get(key: string): T | null { 11 | const data = this.storage[key]; 12 | 13 | if (!data) { 14 | return null; 15 | } 16 | 17 | const parsedData = JSON.parse(data) as T; 18 | 19 | return parsedData; 20 | } 21 | 22 | public save(key: string, value: string): void { 23 | this.storage[key] = value; 24 | } 25 | } 26 | 27 | export default LocalStorage; 28 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/infrastructure/cache/index.ts: -------------------------------------------------------------------------------- 1 | import LocalStorage from './implementation/LocalStorage'; 2 | 3 | const providers = { 4 | LocalStorage: new LocalStorage(), 5 | }; 6 | 7 | export default providers.LocalStorage; 8 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/infrastructure/cache/models/ICache.model.ts: -------------------------------------------------------------------------------- 1 | export default interface ICache { 2 | save(key: string, value: string): void; 3 | get(key: string): T | null; 4 | } 5 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/infrastructure/http/httpClient/__tests__/axios.spec.ts: -------------------------------------------------------------------------------- 1 | import { rest } from 'msw'; 2 | import { setupServer } from 'msw/node'; 3 | 4 | import Axios from '../implementation/Axios'; 5 | 6 | let axios: Axios; 7 | 8 | const BASE_URL = process.env.API_URL; 9 | 10 | const server = setupServer( 11 | rest.get(`${BASE_URL}/`, (req, res, ctx) => { 12 | return res(ctx.json(['a', 'b', 'c'])); 13 | }), 14 | rest.post(`${BASE_URL}/`, (req, res, ctx) => { 15 | return res(ctx.json({ success: true })); 16 | }), 17 | rest.put(`${BASE_URL}/`, (req, res, ctx) => { 18 | return res(ctx.json({ success: true })); 19 | }), 20 | rest.patch(`${BASE_URL}/`, (req, res, ctx) => { 21 | return res(ctx.json({ success: true })); 22 | }), 23 | rest.delete(`${BASE_URL}/`, (req, res, ctx) => { 24 | return res(ctx.json({ success: true })); 25 | }), 26 | ); 27 | 28 | describe('Axios', () => { 29 | beforeAll(() => server.listen()); 30 | 31 | beforeEach(() => { 32 | axios = new Axios(); 33 | }); 34 | 35 | afterEach(() => server.resetHandlers()); 36 | 37 | afterAll(() => server.close()); 38 | 39 | it('should be able to return data on method GET', async () => { 40 | const { data } = await axios.get({ url: '/' }); 41 | 42 | expect(data).toEqual(['a', 'b', 'c']); 43 | }); 44 | 45 | it('should be able to return data on method POST', async () => { 46 | const { data } = await axios.post({ url: '/' }); 47 | 48 | expect(data).toEqual({ success: true }); 49 | }); 50 | 51 | it('should be able to return data on method PUT', async () => { 52 | const { data } = await axios.put({ url: '/' }); 53 | 54 | expect(data).toEqual({ success: true }); 55 | }); 56 | 57 | it('should be able to return data on method PATCH', async () => { 58 | const { data } = await axios.patch({ url: '/' }); 59 | 60 | expect(data).toEqual({ success: true }); 61 | }); 62 | 63 | it('should be able to DELETE', async () => { 64 | const { data } = await axios.delete({ url: '/' }); 65 | 66 | expect(data).toEqual({ success: true }); 67 | }); 68 | }); 69 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/infrastructure/http/httpClient/dtos/IHttpClient.dto.ts: -------------------------------------------------------------------------------- 1 | export interface IHttpClientGetDTO { 2 | url: string; 3 | params?: any; 4 | headers?: any; 5 | } 6 | 7 | export interface IHttpClientPostDTO { 8 | url: string; 9 | data?: any; 10 | params?: any; 11 | headers?: any; 12 | } 13 | 14 | export interface IHttpClientPutDTO { 15 | url: string; 16 | data?: any; 17 | params?: any; 18 | headers?: any; 19 | } 20 | 21 | export interface IHttpClientPatchDTO { 22 | url: string; 23 | data?: any; 24 | params?: any; 25 | headers?: any; 26 | } 27 | 28 | export interface IHttpClientDeleteDTO { 29 | url: string; 30 | params?: any; 31 | headers?: any; 32 | } 33 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/infrastructure/http/httpClient/implementation/Axios.ts: -------------------------------------------------------------------------------- 1 | import axios, { AxiosInstance, AxiosResponse } from 'axios'; 2 | 3 | import { 4 | IHttpClientDeleteDTO, 5 | IHttpClientGetDTO, 6 | IHttpClientPatchDTO, 7 | IHttpClientPostDTO, 8 | IHttpClientPutDTO, 9 | } from '../dtos/IHttpClient.dto'; 10 | import IHttpClientModel from '../models/IHttpClient.model'; 11 | 12 | class AxiosHttpClient implements IHttpClientModel { 13 | private readonly baseUrl: string | undefined; 14 | 15 | private readonly axiosInstance: AxiosInstance; 16 | 17 | constructor() { 18 | this.axiosInstance = axios.create({}); 19 | this.baseUrl = process.env.API_URL; 20 | } 21 | 22 | public get({ 23 | url, 24 | params = null, 25 | headers = null, 26 | }: IHttpClientGetDTO): Promise> { 27 | return this.axiosInstance({ 28 | method: 'GET', 29 | url: `${this.baseUrl}${url}`, 30 | params, 31 | headers, 32 | }); 33 | } 34 | 35 | public post({ 36 | url, 37 | params = null, 38 | data = null, 39 | headers = null, 40 | }: IHttpClientPostDTO): Promise> { 41 | return this.axiosInstance({ 42 | method: 'POST', 43 | url: `${this.baseUrl}${url}`, 44 | params, 45 | data, 46 | headers, 47 | }); 48 | } 49 | 50 | public put({ 51 | url, 52 | params = null, 53 | data = null, 54 | headers = null, 55 | }: IHttpClientPutDTO): Promise> { 56 | return this.axiosInstance({ 57 | method: 'PUT', 58 | url: `${this.baseUrl}${url}`, 59 | params, 60 | data, 61 | headers, 62 | }); 63 | } 64 | 65 | public patch({ 66 | url, 67 | params = null, 68 | data = null, 69 | headers = null, 70 | }: IHttpClientPatchDTO): Promise> { 71 | return this.axiosInstance({ 72 | method: 'PUT', 73 | url: `${this.baseUrl}${url}`, 74 | params, 75 | data, 76 | headers, 77 | }); 78 | } 79 | 80 | public delete({ 81 | url, 82 | params = null, 83 | headers = null, 84 | }: IHttpClientDeleteDTO): Promise> { 85 | return this.axiosInstance({ 86 | method: 'DELETE', 87 | url: `${this.baseUrl}${url}`, 88 | params, 89 | headers, 90 | }); 91 | } 92 | } 93 | 94 | export default AxiosHttpClient; 95 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/infrastructure/http/httpClient/index.ts: -------------------------------------------------------------------------------- 1 | import Axios from './implementation/Axios'; 2 | 3 | const providers = { 4 | Axios: new Axios(), 5 | }; 6 | 7 | export default providers.Axios; 8 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/infrastructure/http/httpClient/models/IHttpClient.model.ts: -------------------------------------------------------------------------------- 1 | import { AxiosResponse } from 'axios'; 2 | 3 | import { 4 | IHttpClientDeleteDTO, 5 | IHttpClientGetDTO, 6 | IHttpClientPatchDTO, 7 | IHttpClientPostDTO, 8 | IHttpClientPutDTO, 9 | } from '../dtos/IHttpClient.dto'; 10 | 11 | export default interface IHttpClientModel { 12 | get: ( 13 | data: IHttpClientGetDTO, 14 | ) => Promise>; 15 | post: ( 16 | data: IHttpClientPostDTO, 17 | ) => Promise>; 18 | put: ( 19 | data: IHttpClientPutDTO, 20 | ) => Promise>; 21 | patch: ( 22 | data: IHttpClientPatchDTO, 23 | ) => Promise>; 24 | delete: ( 25 | data: IHttpClientDeleteDTO, 26 | ) => Promise>; 27 | } 28 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/presentation/App.tsx: -------------------------------------------------------------------------------- 1 | import { GlobalStyle } from './assets/styles/global'; 2 | import Home from './pages/Home'; 3 | 4 | const App = () => ( 5 | <> 6 | 7 | 8 | 9 | ); 10 | 11 | export default App; 12 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/presentation/__tests__/App.spec.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react'; 2 | 3 | import App from '../App'; 4 | 5 | describe('App', () => { 6 | it('should be able to render App', () => { 7 | expect(() => { 8 | render(); 9 | }).not.toThrow(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/presentation/assets/styles/global.ts: -------------------------------------------------------------------------------- 1 | import { createGlobalStyle } from 'styled-components'; 2 | 3 | export const GlobalStyle = createGlobalStyle` 4 | * { 5 | padding: 0; 6 | margin: 0; 7 | box-sizing: border-box 8 | } 9 | 10 | :root { 11 | --white: #fff; 12 | 13 | font-size: 62.5%; 14 | } 15 | 16 | body { 17 | background: var(--white); 18 | } 19 | 20 | body, 21 | input, 22 | textarea, 23 | select, 24 | button { 25 | font: 400 1.6rem "Inter",Helvetica,Arial,sans-serif; 26 | } 27 | 28 | h1, h2, h3, h4, h5, h6 { 29 | font-family: inherit; 30 | font-weight: 600; 31 | line-height: 1.1; 32 | color: inherit; 33 | } 34 | 35 | button { 36 | cursor: pointer; 37 | border: none; 38 | background-color: transparent; 39 | } 40 | 41 | `; 42 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/presentation/bootstrap.tsx: -------------------------------------------------------------------------------- 1 | import * as ReactDOM from 'react-dom'; 2 | 3 | import App from './App'; 4 | 5 | ReactDOM.render(, document.getElementById('root')); 6 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/presentation/index.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import('./bootstrap'); 3 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/presentation/pages/Home/__tests__/index.spec.tsx: -------------------------------------------------------------------------------- 1 | import { screen, render } from '@testing-library/react'; 2 | 3 | import Home from '..'; 4 | 5 | describe('Home page', () => { 6 | it('should be able to render page', () => { 7 | render(); 8 | 9 | expect(screen.getByText('Hello, Dev :)')).toBeTruthy(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/presentation/pages/Home/index.tsx: -------------------------------------------------------------------------------- 1 | import { Container } from './styles'; 2 | 3 | const Home = () => { 4 | return ( 5 | 6 |

Hello, Dev :)

7 |
8 | ); 9 | }; 10 | 11 | export default Home; 12 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/presentation/pages/Home/styles.ts: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const Container = styled.div``; 4 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/shared/Either.ts: -------------------------------------------------------------------------------- 1 | export type Either = Left | Right; 2 | 3 | export class Left { 4 | readonly value: L; 5 | 6 | constructor(value: L) { 7 | this.value = value; 8 | } 9 | 10 | isLeft(): this is Left { 11 | return true; 12 | } 13 | 14 | isRight(): this is Right { 15 | return false; 16 | } 17 | } 18 | 19 | export class Right { 20 | readonly value: A; 21 | 22 | constructor(value: A) { 23 | this.value = value; 24 | } 25 | 26 | isLeft(): this is Left { 27 | return false; 28 | } 29 | 30 | isRight(): this is Right { 31 | return true; 32 | } 33 | } 34 | 35 | export const left = (l: L): Either => { 36 | return new Left(l); 37 | }; 38 | 39 | export const right = (a: A): Either => { 40 | return new Right(a); 41 | }; 42 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/usecases/CreateTodoList.usecase.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ICreateTodoListUsecase, 3 | ICreateTodoListUsecaseArgs, 4 | } from '@/domain/usecases/ICreateTodoList.usecase'; 5 | import ICacheModel from '@/infrastructure/cache/models/ICache.model'; 6 | import IHttpClientModel from '@/infrastructure/http/httpClient/models/IHttpClient.model'; 7 | import ITodoModel from '@/domain/models/ITodo.model'; 8 | import { Either, right } from '@/shared/Either'; 9 | 10 | class CreateTodoListUsecase implements ICreateTodoListUsecase { 11 | constructor( 12 | private readonly cache: ICacheModel, 13 | private readonly httpClient: IHttpClientModel, 14 | ) {} 15 | 16 | async execute( 17 | args: ICreateTodoListUsecaseArgs, 18 | ): Promise> { 19 | const { data } = await this.httpClient.post({ 20 | url: '/todo-list', 21 | data: args, 22 | }); 23 | 24 | const parsedData = JSON.stringify(data); 25 | this.cache.save('todolist', parsedData); 26 | 27 | return right(data); 28 | } 29 | } 30 | 31 | export default CreateTodoListUsecase; 32 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/usecases/__tests__/CreateTodoList.usecase.spec.ts: -------------------------------------------------------------------------------- 1 | import { rest } from 'msw'; 2 | import { setupServer } from 'msw/node'; 3 | 4 | import Localstorage from '@/infrastructure/cache/inMemory/LocalStorage'; 5 | import AxiosHttpClient from '@/infrastructure/http/httpClient/implementation/Axios'; 6 | import CreateTodoListUsecase from '../CreateTodoList.usecase'; 7 | 8 | let createTodoListUsecase: CreateTodoListUsecase; 9 | let localstorage: Localstorage; 10 | let httpClient: AxiosHttpClient; 11 | const { API_URL } = process.env; 12 | 13 | const data = { 14 | id: '123', 15 | title: 'Create project', 16 | }; 17 | const server = setupServer( 18 | rest.post(`${API_URL}/todo-list`, (req, res, ctx) => { 19 | return res(ctx.json(data)); 20 | }), 21 | ); 22 | 23 | describe('CreateTodoList usecase', () => { 24 | beforeAll(() => server.listen()); 25 | 26 | afterEach(() => server.resetHandlers()); 27 | 28 | afterAll(() => server.close()); 29 | 30 | beforeEach(() => { 31 | localstorage = new Localstorage(); 32 | httpClient = new AxiosHttpClient(); 33 | createTodoListUsecase = new CreateTodoListUsecase(localstorage, httpClient); 34 | }); 35 | 36 | it('should be able to create', async () => { 37 | const response = await createTodoListUsecase.execute({ 38 | title: data.title, 39 | }); 40 | 41 | expect(response.value).toEqual(data); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/src/usecases/index.ts: -------------------------------------------------------------------------------- 1 | import httpClient from '@/infrastructure/http/httpClient'; 2 | import cache from '@/infrastructure/cache'; 3 | import CreateTodoListUsecase from './CreateTodoList.usecase'; 4 | 5 | const createTodoListUsecase = new CreateTodoListUsecase(cache, httpClient); 6 | 7 | export { createTodoListUsecase }; 8 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["ES6", "ES2017", "DOM"], 4 | "target": "ES5", 5 | "jsx": "react-jsx", 6 | "allowJs": true, 7 | "outDir": "", 8 | "noImplicitAny": true, 9 | "strictNullChecks": true, 10 | "isolatedModules": true, 11 | "esModuleInterop": true, 12 | "typeRoots": ["src/types", "node_modules/@types"], 13 | "resolveJsonModule": true, 14 | "baseUrl": "./", 15 | "paths": { 16 | "@/*": ["./src/*"], 17 | } 18 | }, 19 | "include": ["src/**/*"], 20 | "exclude": ["node_modules", "public", "dist"] 21 | } 22 | -------------------------------------------------------------------------------- /src/templates/clean-architecture/webpack.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | const path = require('path'); 3 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 4 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 5 | const NodePolyfillPlugin = require('node-polyfill-webpack-plugin'); 6 | const { ModuleFederationPlugin } = require('webpack').container; 7 | 8 | module.exports = (env, argv) => { 9 | const isProduction = argv['mode'] === 'production'; 10 | 11 | return { 12 | entry: ['babel-polyfill', './src/presentation/index'], 13 | output: { 14 | publicPath: 'auto', 15 | path: path.join(__dirname, 'dist'), 16 | filename: '[name].[contenthash].js', 17 | }, 18 | resolve: { 19 | extensions: ['.ts', '.tsx', '.js', '.svg'], 20 | alias: { 21 | '@': path.resolve(__dirname, 'src'), 22 | }, 23 | }, 24 | module: { 25 | rules: [ 26 | { 27 | test: /\.tsx?$/, 28 | loader: 'babel-loader', 29 | exclude: /node_modules/, 30 | }, 31 | { 32 | test: /\.css$/i, 33 | use: ['style-loader', 'css-loader'], 34 | }, 35 | { 36 | test: /\.(png|jpe?g)$/, 37 | use: [ 38 | { 39 | loader: 'url-loader', 40 | options: { 41 | limit: 8000, 42 | name: 'images/[hash]-[name].[ext]', 43 | }, 44 | }, 45 | ], 46 | }, 47 | { 48 | test: /\.svg$/, 49 | use: ['@svgr/webpack', 'url-loader'], 50 | }, 51 | { 52 | test: /\.(eot|ttf|woff|woff2)$/, 53 | loader: 'file-loader', 54 | options: { 55 | name: 'public/fonts/[name].[ext]', 56 | }, 57 | }, 58 | ], 59 | }, 60 | plugins: [ 61 | new NodePolyfillPlugin(), 62 | new HtmlWebpackPlugin({ 63 | template: './public/index.html', 64 | }), 65 | new ModuleFederationPlugin({ 66 | name: '<%= microName %>', 67 | filename: 'remoteEntry.js', 68 | exposes: { 69 | '.': './src/presentation/App', 70 | }, 71 | remotes: {}, 72 | shared: [{ react: { singleton: true } }], 73 | }), 74 | new CleanWebpackPlugin(), 75 | ], 76 | 77 | devtool: isProduction ? false : 'eval-cheap-module-source-map', 78 | 79 | devServer: { 80 | overlay: true, 81 | contentBase: path.join(__dirname, 'public'), 82 | disableHostCheck: true, 83 | historyApiFallback: { 84 | disableDotRule: true, 85 | }, 86 | port: 3000, 87 | }, 88 | }; 89 | }; 90 | -------------------------------------------------------------------------------- /src/utils/template.ts: -------------------------------------------------------------------------------- 1 | import * as ejs from "ejs"; 2 | 3 | export interface TemplateData { 4 | projectName: string; 5 | microName: string; 6 | } 7 | export function render(content: string, data: TemplateData) { 8 | return ejs.render(content, data); 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "dist", 4 | "target": "es5", 5 | "lib": ["es6", "dom"], 6 | "sourceMap": true, 7 | "allowJs": true, 8 | "moduleResolution": "node", 9 | "rootDir": "src", 10 | "forceConsistentCasingInFileNames": true, 11 | "noImplicitReturns": true, 12 | "noImplicitThis": true, 13 | "noImplicitAny": true, 14 | "strictNullChecks": true, 15 | "suppressImplicitAnyIndexErrors": true, 16 | "noUnusedLocals": true 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | "dist", 21 | "src/templates" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/ejs@^3.0.6": 6 | version "3.0.6" 7 | resolved "https://registry.yarnpkg.com/@types/ejs/-/ejs-3.0.6.tgz#aca442289df623bfa8e47c23961f0357847b83fe" 8 | integrity sha512-fj1hi+ZSW0xPLrJJD+YNwIh9GZbyaIepG26E/gXvp8nCa2pYokxUYO1sK9qjGxp2g8ryZYuon7wmjpwE2cyASQ== 9 | 10 | "@types/glob@*": 11 | version "7.1.3" 12 | resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183" 13 | integrity sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w== 14 | dependencies: 15 | "@types/minimatch" "*" 16 | "@types/node" "*" 17 | 18 | "@types/inquirer@^7.3.1": 19 | version "7.3.1" 20 | resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-7.3.1.tgz#1f231224e7df11ccfaf4cf9acbcc3b935fea292d" 21 | integrity sha512-osD38QVIfcdgsPCT0V3lD7eH0OFurX71Jft18bZrsVQWVRt6TuxRzlr0GJLrxoHZR2V5ph7/qP8se/dcnI7o0g== 22 | dependencies: 23 | "@types/through" "*" 24 | rxjs "^6.4.0" 25 | 26 | "@types/minimatch@*": 27 | version "3.0.4" 28 | resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.4.tgz#f0ec25dbf2f0e4b18647313ac031134ca5b24b21" 29 | integrity sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA== 30 | 31 | "@types/node@*", "@types/node@^15.0.2": 32 | version "15.0.2" 33 | resolved "https://registry.yarnpkg.com/@types/node/-/node-15.0.2.tgz#51e9c0920d1b45936ea04341aa3e2e58d339fb67" 34 | integrity sha512-p68+a+KoxpoB47015IeYZYRrdqMUcpbK8re/zpFB8Ld46LHC1lPEbp3EXgkEhAYEcPvjJF6ZO+869SQ0aH1dcA== 35 | 36 | "@types/shelljs@^0.8.8": 37 | version "0.8.8" 38 | resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.8.8.tgz#e439c69929b88a2c8123c1a55e09eb708315addf" 39 | integrity sha512-lD3LWdg6j8r0VRBFahJVaxoW0SIcswxKaFUrmKl33RJVeeoNYQAz4uqCJ5Z6v4oIBOsC5GozX+I5SorIKiTcQA== 40 | dependencies: 41 | "@types/glob" "*" 42 | "@types/node" "*" 43 | 44 | "@types/through@*": 45 | version "0.0.30" 46 | resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.30.tgz#e0e42ce77e897bd6aead6f6ea62aeb135b8a3895" 47 | integrity sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg== 48 | dependencies: 49 | "@types/node" "*" 50 | 51 | "@types/yargs-parser@*": 52 | version "20.2.0" 53 | resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.0.tgz#dd3e6699ba3237f0348cd085e4698780204842f9" 54 | integrity sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA== 55 | 56 | "@types/yargs@^16.0.1": 57 | version "16.0.1" 58 | resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.1.tgz#5fc5d41f69762e00fbecbc8d4bf9dea47d8726f4" 59 | integrity sha512-x4HABGLyzr5hKUzBC9dvjciOTm11WVH1NWonNjGgxapnTHu5SWUqyqn0zQ6Re0yQU0lsQ6ztLCoMAKDGZflyxA== 60 | dependencies: 61 | "@types/yargs-parser" "*" 62 | 63 | ansi-escapes@^4.2.1: 64 | version "4.3.2" 65 | resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" 66 | integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== 67 | dependencies: 68 | type-fest "^0.21.3" 69 | 70 | ansi-regex@^5.0.0: 71 | version "5.0.0" 72 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" 73 | integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== 74 | 75 | ansi-styles@^3.2.1: 76 | version "3.2.1" 77 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 78 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 79 | dependencies: 80 | color-convert "^1.9.0" 81 | 82 | ansi-styles@^4.0.0, ansi-styles@^4.1.0: 83 | version "4.3.0" 84 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 85 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 86 | dependencies: 87 | color-convert "^2.0.1" 88 | 89 | arrify@^1.0.0: 90 | version "1.0.1" 91 | resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" 92 | 93 | async@0.9.x: 94 | version "0.9.2" 95 | resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" 96 | integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= 97 | 98 | balanced-match@^1.0.0: 99 | version "1.0.2" 100 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 101 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 102 | 103 | brace-expansion@^1.1.7: 104 | version "1.1.11" 105 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 106 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 107 | dependencies: 108 | balanced-match "^1.0.0" 109 | concat-map "0.0.1" 110 | 111 | buffer-from@^1.0.0, buffer-from@^1.1.0: 112 | version "1.1.1" 113 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" 114 | 115 | chalk@^2.4.2: 116 | version "2.4.2" 117 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 118 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 119 | dependencies: 120 | ansi-styles "^3.2.1" 121 | escape-string-regexp "^1.0.5" 122 | supports-color "^5.3.0" 123 | 124 | chalk@^4.1.0: 125 | version "4.1.1" 126 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad" 127 | integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg== 128 | dependencies: 129 | ansi-styles "^4.1.0" 130 | supports-color "^7.1.0" 131 | 132 | chardet@^0.7.0: 133 | version "0.7.0" 134 | resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" 135 | integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== 136 | 137 | cli-cursor@^3.1.0: 138 | version "3.1.0" 139 | resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" 140 | integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== 141 | dependencies: 142 | restore-cursor "^3.1.0" 143 | 144 | cli-width@^3.0.0: 145 | version "3.0.0" 146 | resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" 147 | integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== 148 | 149 | cliui@^7.0.2: 150 | version "7.0.4" 151 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" 152 | integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== 153 | dependencies: 154 | string-width "^4.2.0" 155 | strip-ansi "^6.0.0" 156 | wrap-ansi "^7.0.0" 157 | 158 | color-convert@^1.9.0: 159 | version "1.9.3" 160 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 161 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 162 | dependencies: 163 | color-name "1.1.3" 164 | 165 | color-convert@^2.0.1: 166 | version "2.0.1" 167 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 168 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 169 | dependencies: 170 | color-name "~1.1.4" 171 | 172 | color-name@1.1.3: 173 | version "1.1.3" 174 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 175 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 176 | 177 | color-name@~1.1.4: 178 | version "1.1.4" 179 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 180 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 181 | 182 | concat-map@0.0.1: 183 | version "0.0.1" 184 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 185 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 186 | 187 | diff@^3.1.0: 188 | version "3.5.0" 189 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" 190 | 191 | ejs@^3.1.6: 192 | version "3.1.6" 193 | resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.6.tgz#5bfd0a0689743bb5268b3550cceeebbc1702822a" 194 | integrity sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw== 195 | dependencies: 196 | jake "^10.6.1" 197 | 198 | emoji-regex@^8.0.0: 199 | version "8.0.0" 200 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" 201 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== 202 | 203 | escalade@^3.1.1: 204 | version "3.1.1" 205 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" 206 | integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== 207 | 208 | escape-string-regexp@^1.0.5: 209 | version "1.0.5" 210 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 211 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 212 | 213 | external-editor@^3.0.3: 214 | version "3.1.0" 215 | resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" 216 | integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== 217 | dependencies: 218 | chardet "^0.7.0" 219 | iconv-lite "^0.4.24" 220 | tmp "^0.0.33" 221 | 222 | figures@^3.0.0: 223 | version "3.2.0" 224 | resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" 225 | integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== 226 | dependencies: 227 | escape-string-regexp "^1.0.5" 228 | 229 | filelist@^1.0.1: 230 | version "1.0.2" 231 | resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.2.tgz#80202f21462d4d1c2e214119b1807c1bc0380e5b" 232 | integrity sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ== 233 | dependencies: 234 | minimatch "^3.0.4" 235 | 236 | fs.realpath@^1.0.0: 237 | version "1.0.0" 238 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 239 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 240 | 241 | function-bind@^1.1.1: 242 | version "1.1.1" 243 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 244 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 245 | 246 | get-caller-file@^2.0.5: 247 | version "2.0.5" 248 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 249 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 250 | 251 | glob@^7.0.0: 252 | version "7.1.7" 253 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" 254 | integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== 255 | dependencies: 256 | fs.realpath "^1.0.0" 257 | inflight "^1.0.4" 258 | inherits "2" 259 | minimatch "^3.0.4" 260 | once "^1.3.0" 261 | path-is-absolute "^1.0.0" 262 | 263 | has-flag@^3.0.0: 264 | version "3.0.0" 265 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 266 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 267 | 268 | has-flag@^4.0.0: 269 | version "4.0.0" 270 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 271 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 272 | 273 | has@^1.0.3: 274 | version "1.0.3" 275 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 276 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 277 | dependencies: 278 | function-bind "^1.1.1" 279 | 280 | iconv-lite@^0.4.24: 281 | version "0.4.24" 282 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 283 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 284 | dependencies: 285 | safer-buffer ">= 2.1.2 < 3" 286 | 287 | inflight@^1.0.4: 288 | version "1.0.6" 289 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 290 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 291 | dependencies: 292 | once "^1.3.0" 293 | wrappy "1" 294 | 295 | inherits@2: 296 | version "2.0.4" 297 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 298 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 299 | 300 | inquirer@^8.0.0: 301 | version "8.0.0" 302 | resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.0.0.tgz#957a46db1abcf0fdd2ab82deb7470e90afc7d0ac" 303 | integrity sha512-ON8pEJPPCdyjxj+cxsYRe6XfCJepTxANdNnTebsTuQgXpRyZRRT9t4dJwjRubgmvn20CLSEnozRUayXyM9VTXA== 304 | dependencies: 305 | ansi-escapes "^4.2.1" 306 | chalk "^4.1.0" 307 | cli-cursor "^3.1.0" 308 | cli-width "^3.0.0" 309 | external-editor "^3.0.3" 310 | figures "^3.0.0" 311 | lodash "^4.17.21" 312 | mute-stream "0.0.8" 313 | run-async "^2.4.0" 314 | rxjs "^6.6.6" 315 | string-width "^4.1.0" 316 | strip-ansi "^6.0.0" 317 | through "^2.3.6" 318 | 319 | interpret@^1.0.0: 320 | version "1.4.0" 321 | resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" 322 | integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== 323 | 324 | is-core-module@^2.2.0: 325 | version "2.3.0" 326 | resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.3.0.tgz#d341652e3408bca69c4671b79a0954a3d349f887" 327 | integrity sha512-xSphU2KG9867tsYdLD4RWQ1VqdFl4HTO9Thf3I/3dLEfr0dbPTWKsuCKrgqMljg4nPE+Gq0VCnzT3gr0CyBmsw== 328 | dependencies: 329 | has "^1.0.3" 330 | 331 | is-fullwidth-code-point@^3.0.0: 332 | version "3.0.0" 333 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 334 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== 335 | 336 | jake@^10.6.1: 337 | version "10.8.2" 338 | resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.2.tgz#ebc9de8558160a66d82d0eadc6a2e58fbc500a7b" 339 | integrity sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A== 340 | dependencies: 341 | async "0.9.x" 342 | chalk "^2.4.2" 343 | filelist "^1.0.1" 344 | minimatch "^3.0.4" 345 | 346 | lodash@^4.17.21: 347 | version "4.17.21" 348 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 349 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 350 | 351 | make-error@^1.1.1: 352 | version "1.3.5" 353 | resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" 354 | 355 | mimic-fn@^2.1.0: 356 | version "2.1.0" 357 | resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" 358 | integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== 359 | 360 | minimatch@^3.0.4: 361 | version "3.0.4" 362 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 363 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 364 | dependencies: 365 | brace-expansion "^1.1.7" 366 | 367 | minimist@0.0.8: 368 | version "0.0.8" 369 | resolved "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 370 | 371 | minimist@^1.2.0: 372 | version "1.2.0" 373 | resolved "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 374 | 375 | minimist@^1.2.3: 376 | version "1.2.5" 377 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" 378 | integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== 379 | 380 | mkdirp@^0.5.1: 381 | version "0.5.1" 382 | resolved "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 383 | dependencies: 384 | minimist "0.0.8" 385 | 386 | mute-stream@0.0.8: 387 | version "0.0.8" 388 | resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" 389 | integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== 390 | 391 | once@^1.3.0: 392 | version "1.4.0" 393 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 394 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 395 | dependencies: 396 | wrappy "1" 397 | 398 | onetime@^5.1.0: 399 | version "5.1.2" 400 | resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" 401 | integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== 402 | dependencies: 403 | mimic-fn "^2.1.0" 404 | 405 | os-tmpdir@~1.0.2: 406 | version "1.0.2" 407 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" 408 | integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= 409 | 410 | path-is-absolute@^1.0.0: 411 | version "1.0.1" 412 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 413 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 414 | 415 | path-parse@^1.0.6: 416 | version "1.0.6" 417 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" 418 | integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== 419 | 420 | rechoir@^0.6.2: 421 | version "0.6.2" 422 | resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" 423 | integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= 424 | dependencies: 425 | resolve "^1.1.6" 426 | 427 | require-directory@^2.1.1: 428 | version "2.1.1" 429 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 430 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= 431 | 432 | resolve@^1.1.6: 433 | version "1.20.0" 434 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" 435 | integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== 436 | dependencies: 437 | is-core-module "^2.2.0" 438 | path-parse "^1.0.6" 439 | 440 | restore-cursor@^3.1.0: 441 | version "3.1.0" 442 | resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" 443 | integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== 444 | dependencies: 445 | onetime "^5.1.0" 446 | signal-exit "^3.0.2" 447 | 448 | run-async@^2.4.0: 449 | version "2.4.1" 450 | resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" 451 | integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== 452 | 453 | rxjs@^6.4.0, rxjs@^6.6.6: 454 | version "6.6.7" 455 | resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" 456 | integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== 457 | dependencies: 458 | tslib "^1.9.0" 459 | 460 | "safer-buffer@>= 2.1.2 < 3": 461 | version "2.1.2" 462 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 463 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 464 | 465 | shelljs@^0.8.4: 466 | version "0.8.4" 467 | resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2" 468 | integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ== 469 | dependencies: 470 | glob "^7.0.0" 471 | interpret "^1.0.0" 472 | rechoir "^0.6.2" 473 | 474 | shx@^0.3.3: 475 | version "0.3.3" 476 | resolved "https://registry.yarnpkg.com/shx/-/shx-0.3.3.tgz#681a88c7c10db15abe18525349ed474f0f1e7b9f" 477 | integrity sha512-nZJ3HFWVoTSyyB+evEKjJ1STiixGztlqwKLTUNV5KqMWtGey9fTd4KU1gdZ1X9BV6215pswQ/Jew9NsuS/fNDA== 478 | dependencies: 479 | minimist "^1.2.3" 480 | shelljs "^0.8.4" 481 | 482 | signal-exit@^3.0.2: 483 | version "3.0.3" 484 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" 485 | integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== 486 | 487 | source-map-support@^0.5.6: 488 | version "0.5.9" 489 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f" 490 | dependencies: 491 | buffer-from "^1.0.0" 492 | source-map "^0.6.0" 493 | 494 | source-map@^0.6.0: 495 | version "0.6.1" 496 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 497 | 498 | string-width@^4.1.0, string-width@^4.2.0: 499 | version "4.2.2" 500 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" 501 | integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== 502 | dependencies: 503 | emoji-regex "^8.0.0" 504 | is-fullwidth-code-point "^3.0.0" 505 | strip-ansi "^6.0.0" 506 | 507 | strip-ansi@^6.0.0: 508 | version "6.0.0" 509 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" 510 | integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== 511 | dependencies: 512 | ansi-regex "^5.0.0" 513 | 514 | supports-color@^5.3.0: 515 | version "5.5.0" 516 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 517 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 518 | dependencies: 519 | has-flag "^3.0.0" 520 | 521 | supports-color@^7.1.0: 522 | version "7.2.0" 523 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" 524 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== 525 | dependencies: 526 | has-flag "^4.0.0" 527 | 528 | through@^2.3.6: 529 | version "2.3.8" 530 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" 531 | integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= 532 | 533 | tmp@^0.0.33: 534 | version "0.0.33" 535 | resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" 536 | integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== 537 | dependencies: 538 | os-tmpdir "~1.0.2" 539 | 540 | ts-node@^7.0.1: 541 | version "7.0.1" 542 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-7.0.1.tgz#9562dc2d1e6d248d24bc55f773e3f614337d9baf" 543 | dependencies: 544 | arrify "^1.0.0" 545 | buffer-from "^1.1.0" 546 | diff "^3.1.0" 547 | make-error "^1.1.1" 548 | minimist "^1.2.0" 549 | mkdirp "^0.5.1" 550 | source-map-support "^0.5.6" 551 | yn "^2.0.0" 552 | 553 | tslib@^1.9.0: 554 | version "1.14.1" 555 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" 556 | integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== 557 | 558 | type-fest@^0.21.3: 559 | version "0.21.3" 560 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" 561 | integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== 562 | 563 | typescript@^3.0.3: 564 | version "3.9.9" 565 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.9.tgz#e69905c54bc0681d0518bd4d587cc6f2d0b1a674" 566 | integrity sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w== 567 | 568 | wrap-ansi@^7.0.0: 569 | version "7.0.0" 570 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" 571 | integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== 572 | dependencies: 573 | ansi-styles "^4.0.0" 574 | string-width "^4.1.0" 575 | strip-ansi "^6.0.0" 576 | 577 | wrappy@1: 578 | version "1.0.2" 579 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 580 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 581 | 582 | y18n@^5.0.5: 583 | version "5.0.8" 584 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" 585 | integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== 586 | 587 | yargs-parser@^20.2.2: 588 | version "20.2.7" 589 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a" 590 | integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw== 591 | 592 | yargs@^17.0.1: 593 | version "17.0.1" 594 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.0.1.tgz#6a1ced4ed5ee0b388010ba9fd67af83b9362e0bb" 595 | integrity sha512-xBBulfCc8Y6gLFcrPvtqKz9hz8SO0l1Ni8GgDekvBX2ro0HRQImDGnikfc33cgzcYUSncapnNcZDjVFIH3f6KQ== 596 | dependencies: 597 | cliui "^7.0.2" 598 | escalade "^3.1.1" 599 | get-caller-file "^2.0.5" 600 | require-directory "^2.1.1" 601 | string-width "^4.2.0" 602 | y18n "^5.0.5" 603 | yargs-parser "^20.2.2" 604 | 605 | yn@^2.0.0: 606 | version "2.0.0" 607 | resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a" 608 | --------------------------------------------------------------------------------