From b1180f7649636b159c1d17834ec1f2d51574c279 Mon Sep 17 00:00:00 2001 From: Mykyta Lyzhov Date: Tue, 11 Sep 2018 19:43:49 +0300 Subject: [PATCH] Fix and update the cli (#847) Fixes: #847 --- package.json | 3 +- packages/server/package.json | 1 - tools/cli.js | 29 ++-- tools/cli/CommandInvoker.js | 54 +++++++ tools/cli/commands/addModule.js | 61 ++++++++ tools/cli/commands/deleteModule.js | 57 +++++++ tools/cli/config.js | 11 ++ tools/cli/helpers/util.js | 63 ++++++++ tools/cli/module.js | 145 ------------------ .../module/client/__tests__/Module.spec.ts | 17 ++ .../{ModuleView.jsx => ModuleView.native.tsx} | 9 +- .../module/client/components/ModuleView.tsx | 29 ++++ .../client/components/ModuleView.web.jsx | 28 ---- .../module/client/containers/Module.jsx | 15 -- .../module/client/containers/Module.spec.js | 17 -- .../module/client/containers/Module.tsx | 16 ++ .../module/client/graphql/ModuleQuery.graphql | 5 + tools/templates/module/client/index.jsx | 21 --- .../templates/module/client/index.native.tsx | 33 ++++ tools/templates/module/client/index.tsx | 25 +++ tools/templates/module/client/index.web.jsx | 19 --- .../client/locales/en/translations.json | 6 + .../templates/module/client/locales/index.js | 5 + .../client/locales/ru/translations.json | 6 + .../templates/module/client/reducers/index.js | 8 - .../Module.spec.ts} | 16 +- .../module/server/{index.js => index.ts} | 0 tools/templates/module/server/resolvers.js | 6 - tools/templates/module/server/resolvers.ts | 5 + tools/templates/module/server/schema.graphql | 17 +- .../module/server/{sql.js => sql.ts} | 1 - tslint.json | 2 +- 32 files changed, 443 insertions(+), 287 deletions(-) create mode 100644 tools/cli/CommandInvoker.js create mode 100644 tools/cli/commands/addModule.js create mode 100644 tools/cli/commands/deleteModule.js create mode 100644 tools/cli/config.js create mode 100644 tools/cli/helpers/util.js delete mode 100644 tools/cli/module.js create mode 100644 tools/templates/module/client/__tests__/Module.spec.ts rename tools/templates/module/client/components/{ModuleView.jsx => ModuleView.native.tsx} (69%) create mode 100644 tools/templates/module/client/components/ModuleView.tsx delete mode 100644 tools/templates/module/client/components/ModuleView.web.jsx delete mode 100644 tools/templates/module/client/containers/Module.jsx delete mode 100644 tools/templates/module/client/containers/Module.spec.js create mode 100644 tools/templates/module/client/containers/Module.tsx delete mode 100644 tools/templates/module/client/index.jsx create mode 100644 tools/templates/module/client/index.native.tsx create mode 100644 tools/templates/module/client/index.tsx delete mode 100644 tools/templates/module/client/index.web.jsx create mode 100644 tools/templates/module/client/locales/en/translations.json create mode 100644 tools/templates/module/client/locales/index.js create mode 100644 tools/templates/module/client/locales/ru/translations.json delete mode 100644 tools/templates/module/client/reducers/index.js rename tools/templates/module/server/{Module.spec.js => __tests__/Module.spec.ts} (50%) rename tools/templates/module/server/{index.js => index.ts} (100%) delete mode 100644 tools/templates/module/server/resolvers.js create mode 100644 tools/templates/module/server/resolvers.ts rename tools/templates/module/server/{sql.js => sql.ts} (68%) diff --git a/package.json b/package.json index 0b243f2fde..a35c445803 100644 --- a/package.json +++ b/package.json @@ -135,7 +135,8 @@ "webpack-merge": "^4.1.4", "webpack-node-externals": "^1.7.2", "webpack-sources": "^1.1.0", - "webpack-virtual-modules": "^0.1.10" + "webpack-virtual-modules": "^0.1.10", + "shelljs": "^0.8.1" }, "optionalDependencies": { "dotenv": "^6.0.0", diff --git a/packages/server/package.json b/packages/server/package.json index 9caf0d0635..dd51ab3a07 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -110,7 +110,6 @@ "react-stripe-elements": "^1.2.1", "redux": "^4.0.0", "serialize-javascript": "^1.4.0", - "shelljs": "^0.8.1", "shortid": "^2.2.8", "source-map-support": "^0.5.0", "sourcemapped-stacktrace": "^1.1.8", diff --git a/tools/cli.js b/tools/cli.js index 1a535a90d3..6f599f1b1b 100644 --- a/tools/cli.js +++ b/tools/cli.js @@ -1,25 +1,30 @@ +require('babel-register')({ presets: ['env'], plugins: ['transform-class-properties'] }); +require('babel-polyfill'); const prog = require('caporal'); -const moduleCmd = require('./cli/module'); + +const addModuleCommand = require('./cli/commands/addModule'); +const deleteModuleCommand = require('./cli/commands/deleteModule'); +const CommandInvoker = require('./cli/CommandInvoker'); + +const commandInvoker = new CommandInvoker(addModuleCommand, deleteModuleCommand); prog .version('1.0.0') - .command('addmodule', 'Create a new Module') - .argument('', 'Module name') + .description('Full info: https://github.com/sysgears/apollo-universal-starter-kit/wiki/Apollo-Starter-Kit-CLI') + // Add module + .command('addmodule', 'Create a new Module.') + .argument('', 'Module name') .argument( '[location]', 'Where should new module be created. [both, server, client]', ['both', 'server', 'client'], 'both' ) - .action((args, options, logger) => moduleCmd('addmodule', args, options, logger)) + .action((args, options, logger) => commandInvoker.runAddModule(args, options, logger)) + // Delete module .command('deletemodule', 'Delete a Module') - .argument('', 'Module name') - .argument( - '[location]', - 'Where should new module be created. [both, server, client]', - ['both', 'server', 'client'], - 'both' - ) - .action((args, options, logger) => moduleCmd('deletemodule', args, options, logger)); + .argument('', 'Module name') + .argument('[location]', 'Where should we delete module. [both, server, client]', ['both', 'server', 'client'], 'both') + .action((args, options, logger) => commandInvoker.runDeleteModule(args, options, logger)); prog.parse(process.argv); diff --git a/tools/cli/CommandInvoker.js b/tools/cli/CommandInvoker.js new file mode 100644 index 0000000000..7443d61249 --- /dev/null +++ b/tools/cli/CommandInvoker.js @@ -0,0 +1,54 @@ +const { MODULE_TEMPLATES } = require('./config'); + +/** + * Class CommandInvoker. Takes all CLI operations and calls certain CLI operation depends of variables. + */ +class CommandInvoker { + /** + * Sets CLI operations (functions). + * @constructor + * + * @param addModule - The function for creating a new module. + * @param deleteModule - The function for deleting existing module. + */ + constructor(addModule, deleteModule) { + this.addModule = addModule; + this.deleteModule = deleteModule; + } + + /** + * Calls CLI operation with correct location. + * + * @param func - The func to call. + * @param location - The location for a new module [client|server|both]. + * @param args - The function for deleting existing module. + */ + static runCommand(func, location, ...args) { + // client + if (location === 'client' || location === 'both') { + func(...args, 'client'); + } + // server + if (location === 'server' || location === 'both') { + func(...args, 'server'); + } + } + + /** + * Runs operation (function) for creating a new module. + */ + runAddModule(args, options, logger) { + const { moduleName, location = 'both' } = args; + CommandInvoker.runCommand(this.addModule, location, logger, MODULE_TEMPLATES, moduleName); + } + + /** + * Runs operation (function) for deleting existing module. + */ + runDeleteModule(args, options, logger) { + const { moduleName, location = 'both' } = args; + CommandInvoker.runCommand(this.deleteModule, location, logger, moduleName); + } +} + +module.exports = CommandInvoker; diff --git a/tools/cli/commands/addModule.js b/tools/cli/commands/addModule.js new file mode 100644 index 0000000000..de703b1ffc --- /dev/null +++ b/tools/cli/commands/addModule.js @@ -0,0 +1,61 @@ +const shell = require('shelljs'); +const fs = require('fs'); +const chalk = require('chalk'); +const { copyFiles, renameFiles, computeModulesPath } = require('../helpers/util'); + +/** + * Adds module in client or server and adds a new module to the Feature connector. + * + * @param logger - The Logger. + * @param templatesPath - The path to the templates for a new module. + * @param moduleName - The name of a new module. + * @param location - The location for a new module [client|server|both]. + * @param finished - The flag about the end of the generating process. + */ +function addModule(logger, templatesPath, moduleName, location, finished = true) { + logger.info(`Copying ${location} files…`); + + // create new module directory + const destinationPath = computeModulesPath(location, moduleName); + const newModule = shell.mkdir(destinationPath); + + // continue only if directory does not jet exist + if (newModule.code !== 0) { + logger.error(chalk.red(`The ${moduleName} directory is already exists.`)); + process.exit(); + } + //copy and rename templates in destination directory + copyFiles(destinationPath, templatesPath, location); + renameFiles(destinationPath, moduleName); + + logger.info(chalk.green(`✔ The ${location} files have been copied!`)); + + // get index file path + const modulesPath = computeModulesPath(location); + const indexFullFileName = fs.readdirSync(modulesPath).find(name => name.search(/index/) >= 0); + const indexPath = modulesPath + indexFullFileName; + let indexContent; + + try { + // prepend import module + indexContent = `import ${moduleName} from './${moduleName}';\n` + fs.readFileSync(indexPath); + } catch (e) { + logger.error(chalk.red(`Failed to read ${indexPath} file`)); + process.exit(); + } + + // extract Feature modules + const featureRegExp = /Feature\(([^()]+)\)/g; + const [, featureModules] = featureRegExp.exec(indexContent) || ['', '']; + + // add module to Feature connector + shell + .ShellString(indexContent.replace(RegExp(featureRegExp, 'g'), `Feature(${moduleName}, ${featureModules})`)) + .to(indexPath); + + if (finished) { + logger.info(chalk.green(`✔ Module for ${location} successfully created!`)); + } +} + +module.exports = addModule; diff --git a/tools/cli/commands/deleteModule.js b/tools/cli/commands/deleteModule.js new file mode 100644 index 0000000000..fd7999e808 --- /dev/null +++ b/tools/cli/commands/deleteModule.js @@ -0,0 +1,57 @@ +const shell = require('shelljs'); +const fs = require('fs'); +const chalk = require('chalk'); +const { computeModulesPath } = require('../helpers/util'); + +/** + * Removes the module from client, server or both locations and removes the module from the Feature connector. + * + * @param logger - The Logger. + * @param moduleName - The name of a new module. + * @param location - The location for a new module [client|server|both]. + */ +function deleteModule(logger, moduleName, location) { + logger.info(`Deleting ${location} files…`); + const modulePath = computeModulesPath(location, moduleName); + + if (fs.existsSync(modulePath)) { + // remove module directory + shell.rm('-rf', modulePath); + + const modulesPath = computeModulesPath(location); + + // get index file path + const indexFullFileName = fs.readdirSync(modulesPath).find(name => name.search(/index/) >= 0); + const indexPath = modulesPath + indexFullFileName; + let indexContent; + + try { + indexContent = fs.readFileSync(indexPath); + } catch (e) { + logger.error(chalk.red(`Failed to read ${indexPath} file`)); + process.exit(); + } + + // extract Feature modules + const featureRegExp = /Feature\(([^()]+)\)/g; + const [, featureModules] = featureRegExp.exec(indexContent) || ['', '']; + const featureModulesWithoutDeleted = featureModules + .split(',') + .filter(featureModule => featureModule.trim() !== moduleName); + + const contentWithoutDeletedModule = indexContent + .toString() + // replace features modules on features without deleted module + .replace(featureRegExp, `Feature(${featureModulesWithoutDeleted.toString().trim()})`) + // remove import module + .replace(RegExp(`import ${moduleName} from './${moduleName}';\n`, 'g'), ''); + + fs.writeFileSync(indexPath, contentWithoutDeletedModule); + + logger.info(chalk.green(`✔ Module for ${location} successfully deleted!`)); + } else { + logger.info(chalk.red(`✘ Module ${location} location for ${modulePath} not found!`)); + } +} + +module.exports = deleteModule; diff --git a/tools/cli/config.js b/tools/cli/config.js new file mode 100644 index 0000000000..cc8408efec --- /dev/null +++ b/tools/cli/config.js @@ -0,0 +1,11 @@ +const path = require('path'); + +const BASE_PATH = path.resolve(`${__dirname}/../..`); +const TEMPLATES_DIR = `${BASE_PATH}/tools/templates`; +const MODULE_TEMPLATES = `${TEMPLATES_DIR}/module`; + +module.exports = { + BASE_PATH, + TEMPLATES_DIR, + MODULE_TEMPLATES +}; diff --git a/tools/cli/helpers/util.js b/tools/cli/helpers/util.js new file mode 100644 index 0000000000..1d18723554 --- /dev/null +++ b/tools/cli/helpers/util.js @@ -0,0 +1,63 @@ +const shell = require('shelljs'); +const { pascalize, decamelize } = require('humps'); +const { startCase } = require('lodash'); +const { BASE_PATH } = require('../config'); + +/** + * Copies the templates to the destination directory. + * + * @param destinationPath - The destination path for a new module. + * @param templatesPath - The path to the templates for a new module. + * @param location - The location for a new module [client|server|both]. + */ +function copyFiles(destinationPath, templatesPath, location) { + shell.cp('-R', `${templatesPath}/${location}/*`, destinationPath); +} + +/** + * Renames the templates in the destination directory. + * + * @param destinationPath - The destination path of a new module. + * @param moduleName - The name of a new module. + */ +function renameFiles(destinationPath, moduleName) { + const Module = pascalize(moduleName); + + // change to destination directory + shell.cd(destinationPath); + + // rename files + shell.ls('-Rl', '.').forEach(entry => { + if (entry.isFile()) { + shell.mv(entry.name, entry.name.replace('Module', Module)); + } + }); + + // replace module names + shell.ls('-Rl', '.').forEach(entry => { + if (entry.isFile()) { + shell.sed('-i', /\$module\$/g, moduleName, entry.name); + shell.sed('-i', /\$_module\$/g, decamelize(moduleName), entry.name); + shell.sed('-i', /\$Module\$/g, Module, entry.name); + shell.sed('-i', /\$MoDuLe\$/g, startCase(moduleName), entry.name); + shell.sed('-i', /\$MODULE\$/g, moduleName.toUpperCase(), entry.name); + } + }); +} + +/** + * Gets the computed path of the module or modules dir path. + * + * @param location - The location for a new module [client|server|both]. + * @param moduleName - The name of a new module. + * @returns {string} - Return the computed path + */ +function computeModulesPath(location, moduleName = '') { + return `${BASE_PATH}/packages/${location}/src/modules/${moduleName}`; +} + +module.exports = { + renameFiles, + copyFiles, + computeModulesPath +}; diff --git a/tools/cli/module.js b/tools/cli/module.js deleted file mode 100644 index 5f7a37d082..0000000000 --- a/tools/cli/module.js +++ /dev/null @@ -1,145 +0,0 @@ -const shell = require('shelljs'); -const fs = require('fs'); - -String.prototype.toCamelCase = function() { - return this.replace(/^([A-Z])|\s(\w)/g, function(match, p1, p2) { - if (p2) return p2.toUpperCase(); - return p1.toLowerCase(); - }); -}; - -String.prototype.capitalize = function() { - return this.charAt(0).toUpperCase() + this.slice(1); -}; - -function copyFiles(logger, templatePath, module, location) { - logger.info(`Copying ${location} files…`); - - // create new module directory - const mkdir = shell.mkdir(`${__dirname}/../../packages/${location}/src/modules/${module}`); - - // continue only if directory does not jet exist - if (mkdir.code === 0) { - const destinationPath = `${__dirname}/../../packages/${location}/src/modules/${module}`; - shell.cp('-R', `${templatePath}/${location}/*`, destinationPath); - - logger.info(`✔ The ${location} files have been copied!`); - - // change to destination directory - shell.cd(destinationPath); - - // rename files - shell.ls('-Rl', '.').forEach(entry => { - if (entry.isFile()) { - const moduleFile = entry.name.replace('Module', module.capitalize()); - shell.mv(entry.name, moduleFile); - } - }); - - // replace module names - shell.ls('-Rl', '.').forEach(entry => { - if (entry.isFile()) { - shell.sed('-i', /\$module\$/g, module, entry.name); - shell.sed('-i', /\$Module\$/g, module.toCamelCase().capitalize(), entry.name); - } - }); - - // get index file path - const modulesPath = `${__dirname}/../../packages/${location}/src/modules/`; - const indexFullFileName = fs.readdirSync(modulesPath).find(name => name.search(/index/) >= 0); - const indexPath = modulesPath + indexFullFileName; - let indexContent; - - try { - // prepend import module - indexContent = `import ${module} from './${module}';\n` + fs.readFileSync(indexPath); - } catch (e) { - logger.error(`Failed to read ${indexPath} file`); - process.exit(); - } - - // extract Feature modules - const featureRegExp = /Feature\(([^()]+)\)/g; - const [, featureModules] = featureRegExp.exec(indexContent) || ['', '']; - - // add module to Feature connector - shell - .ShellString(indexContent.replace(RegExp(featureRegExp, 'g'), `Feature(${module}, ${featureModules})`)) - .to(indexPath); - - logger.info(`✔ Module for ${location} successfully created!`); - } -} - -function deleteFiles(logger, templatePath, module, location) { - logger.info(`Deleting ${location} files…`); - - const modulePath = `${__dirname}/../../packages/${location}/src/modules/${module}`; - - if (fs.existsSync(modulePath)) { - // delete module directory - shell.rm('-rf', modulePath); - - // path to modules index file - const modulesPath = `${__dirname}/../../packages/${location}/src/modules/`; - - // get index file path - const indexFullFileName = fs.readdirSync(modulesPath).find(name => name.search(/index/) >= 0); - const indexPath = modulesPath + indexFullFileName; - let indexContent; - - try { - indexContent = fs.readFileSync(indexPath); - } catch (e) { - logger.error(`Failed to read ${indexPath} file`); - process.exit(); - } - - // extract Feature modules - const featureRegExp = /Feature\(([^()]+)\)/g; - const [, featureModules] = featureRegExp.exec(indexContent) || ['', '']; - const featureModulesWithoutDeleted = featureModules - .split(',') - .filter(featureModule => featureModule.trim() !== module); - - const contentWithoutDeletedModule = indexContent - .toString() - // replace features modules on features without deleted module - .replace(featureRegExp, `Feature(${featureModulesWithoutDeleted.toString().trim()})`) - // remove import module - .replace(RegExp(`import ${module} from './${module}';\n`, 'g'), ''); - - fs.writeFileSync(indexPath, contentWithoutDeletedModule); - - logger.info(`✔ Module for ${location} successfully deleted!`); - } else { - logger.info(`✔ Module ${location} location for ${modulePath} wasn't found!`); - } -} - -module.exports = (action, args, options, logger) => { - const templatePath = `${__dirname}/../templates/module`; - - if (!fs.existsSync(templatePath)) { - logger.error(`The requested location for ${args.location} wasn't found.`); - process.exit(1); - } - - // client - if (args.location === 'client' || args.location === 'both') { - if (action === 'addmodule') { - copyFiles(logger, templatePath, args.module, 'client'); - } else if (action === 'deletemodule') { - deleteFiles(logger, templatePath, args.module, 'client'); - } - } - - // server - if (args.location === 'server' || args.location === 'both') { - if (action === 'addmodule') { - copyFiles(logger, templatePath, args.module, 'server'); - } else if (action === 'deletemodule') { - deleteFiles(logger, templatePath, args.module, 'server'); - } - } -}; diff --git a/tools/templates/module/client/__tests__/Module.spec.ts b/tools/templates/module/client/__tests__/Module.spec.ts new file mode 100644 index 0000000000..fa5b8cb0ef --- /dev/null +++ b/tools/templates/module/client/__tests__/Module.spec.ts @@ -0,0 +1,17 @@ +import { expect } from 'chai'; +import { step } from 'mocha-steps'; + +import Renderer from '../../../testHelpers/Renderer'; +import { updateContent } from '../../../testHelpers/testUtils'; + +describe('$Module$ UI works', () => { + const renderer = new Renderer({}); + let app; + + step('$Module$ page renders on mount', () => { + app = renderer.mount(); + renderer.history.push('/$Module$'); + // tslint:disable:no-unused-expression + expect(updateContent(app.container)).to.not.be.empty; + }); +}); diff --git a/tools/templates/module/client/components/ModuleView.jsx b/tools/templates/module/client/components/ModuleView.native.tsx similarity index 69% rename from tools/templates/module/client/components/ModuleView.jsx rename to tools/templates/module/client/components/ModuleView.native.tsx index 04c16384fe..9198bf1cab 100644 --- a/tools/templates/module/client/components/ModuleView.jsx +++ b/tools/templates/module/client/components/ModuleView.native.tsx @@ -1,11 +1,16 @@ import React from 'react'; import { StyleSheet, Text, View } from 'react-native'; +import { TranslateFunction } from '../../../i18n'; -const $Module$View = () => { +interface $Module$ViewProps { + t: TranslateFunction; +} + +const $Module$View = ({ t }: $Module$ViewProps) => { return ( - Hello $Module$! + {t('welcomeText')} ); diff --git a/tools/templates/module/client/components/ModuleView.tsx b/tools/templates/module/client/components/ModuleView.tsx new file mode 100644 index 0000000000..2ea17b7028 --- /dev/null +++ b/tools/templates/module/client/components/ModuleView.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import Helmet from 'react-helmet'; +import { PageLayout } from '../../common/components/web'; +import { TranslateFunction } from '../../../i18n'; +import settings from '../../../../../../settings'; + +interface $Module$ViewProps { + t: TranslateFunction; +} + +const renderMetaData = (t: TranslateFunction) => ( + +); + +const $Module$View = ({ t }: $Module$ViewProps) => { + return ( + + {renderMetaData(t)} +
+

{t('welcomeText')}

+
+
+ ); +}; + +export default $Module$View; diff --git a/tools/templates/module/client/components/ModuleView.web.jsx b/tools/templates/module/client/components/ModuleView.web.jsx deleted file mode 100644 index 49bca7ba8b..0000000000 --- a/tools/templates/module/client/components/ModuleView.web.jsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; -import Helmet from 'react-helmet'; -import { PageLayout } from '../../common/components/web'; - -const renderMetaData = () => ( - -); - -const $Module$View = () => { - return ( - - {renderMetaData()} -
-

Hello $Module$!

-
-
- ); -}; - -export default $Module$View; diff --git a/tools/templates/module/client/containers/Module.jsx b/tools/templates/module/client/containers/Module.jsx deleted file mode 100644 index 59510a61c5..0000000000 --- a/tools/templates/module/client/containers/Module.jsx +++ /dev/null @@ -1,15 +0,0 @@ -/*eslint-disable no-unused-vars*/ -import React from 'react'; -import { graphql, compose } from 'react-apollo'; - -import $Module$View from '../components/$Module$View'; - -class $Module$ extends React.Component { - render() { - return <$Module$View {...this.props} />; - } -} - -const $Module$WithApollo = compose()($Module$); - -export default $Module$WithApollo; diff --git a/tools/templates/module/client/containers/Module.spec.js b/tools/templates/module/client/containers/Module.spec.js deleted file mode 100644 index 29ebdb682e..0000000000 --- a/tools/templates/module/client/containers/Module.spec.js +++ /dev/null @@ -1,17 +0,0 @@ -import { expect } from 'chai'; -import { step } from 'mocha-steps'; -import Renderer from '../../../../client/testHelpers/Renderer'; -import Routes from '../../../../client/app/Routes'; - -describe('$Module$ UI works', () => { - const renderer = new Renderer({}); - let app; - let content; - - step('$Module$ page renders on mount', () => { - app = renderer.mount(Routes); - renderer.history.push('/$module$'); - content = app.find('#content'); - expect(content).to.not.be.empty; - }); -}); diff --git a/tools/templates/module/client/containers/Module.tsx b/tools/templates/module/client/containers/Module.tsx new file mode 100644 index 0000000000..0542467790 --- /dev/null +++ b/tools/templates/module/client/containers/Module.tsx @@ -0,0 +1,16 @@ +import React from 'react'; + +import $Module$View from '../components/$Module$View'; +import translate, { TranslateFunction } from '../../../i18n'; + +interface $Module$Props { + t: TranslateFunction; +} + +class $Module$ extends React.Component<$Module$Props> { + public render() { + return <$Module$View {...this.props} />; + } +} + +export default translate('$module$')($Module$); diff --git a/tools/templates/module/client/graphql/ModuleQuery.graphql b/tools/templates/module/client/graphql/ModuleQuery.graphql index f16c43a24b..f9c5113153 100644 --- a/tools/templates/module/client/graphql/ModuleQuery.graphql +++ b/tools/templates/module/client/graphql/ModuleQuery.graphql @@ -1 +1,6 @@ # GraphQL queries +query queryNameQuery { + queryName { + typename + } +} diff --git a/tools/templates/module/client/index.jsx b/tools/templates/module/client/index.jsx deleted file mode 100644 index e61b873a24..0000000000 --- a/tools/templates/module/client/index.jsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Ionicons } from '@expo/vector-icons'; -import { createTabBarIconWrapper } from '../common/components/native'; -import $Module$ from './containers/$Module$'; -import reducers from './reducers'; - -import Feature from '../connector'; - -export default new Feature({ - tabItem: { - $Module$: { - screen: $Module$, - navigationOptions: { - tabBarIcon: createTabBarIconWrapper(Ionicons, { - name: 'ios-browsers-outline', - size: 30 - }) - } - } - }, - reducer: { $module$: reducers } -}); diff --git a/tools/templates/module/client/index.native.tsx b/tools/templates/module/client/index.native.tsx new file mode 100644 index 0000000000..dcfe256bd5 --- /dev/null +++ b/tools/templates/module/client/index.native.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { createStackNavigator } from 'react-navigation'; + +import resources from './locales'; +import { HeaderTitle, IconButton } from '../common/components/native'; +import $Module$ from './containers/$Module$'; +import Feature from '../connector.native'; +import translate from '../../i18n'; + +const HeaderTitleWithI18n = translate('$module$')(HeaderTitle); + +export default new Feature({ + drawerItem: { + $Module$: { + screen: createStackNavigator({ + $Module$: { + screen: $Module$, + navigationOptions: ({ navigation }: any) => ({ + headerTitle: , + headerLeft: ( + navigation.openDrawer()} /> + ), + headerStyle: { backgroundColor: '#fff' } + }) + } + }), + navigationOptions: { + drawerLabel: + } + } + }, + localization: { ns: '$module$', resources } +}); diff --git a/tools/templates/module/client/index.tsx b/tools/templates/module/client/index.tsx new file mode 100644 index 0000000000..70cf5abedc --- /dev/null +++ b/tools/templates/module/client/index.tsx @@ -0,0 +1,25 @@ +import React from 'react'; + +import Feature from '../connector'; +import translate, { TranslateFunction } from '../../i18n'; + +import { Route, NavLink } from 'react-router-dom'; +import { MenuItem } from '../../modules/common/components/web'; +import $Module$ from './containers/$Module$'; +import resources from './locales'; + +const NavLinkWithI18n = translate()(({ t }: { t: TranslateFunction }) => ( + + {t('$module$:navLink')} + +)); + +export default new Feature({ + route: , + navItem: ( + + + + ), + localization: { ns: '$module$', resources } +}); diff --git a/tools/templates/module/client/index.web.jsx b/tools/templates/module/client/index.web.jsx deleted file mode 100644 index ba6a70cd43..0000000000 --- a/tools/templates/module/client/index.web.jsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; -import { Route, NavLink } from 'react-router-dom'; -import { MenuItem } from '../../modules/common/components/web'; -import $Module$ from './containers/$Module$'; -import reducers from './reducers'; - -import Feature from '../connector'; - -export default new Feature({ - route: , - navItem: ( - - - $Module$ - - - ), - reducer: { $module$: reducers } -}); diff --git a/tools/templates/module/client/locales/en/translations.json b/tools/templates/module/client/locales/en/translations.json new file mode 100644 index 0000000000..8131aae904 --- /dev/null +++ b/tools/templates/module/client/locales/en/translations.json @@ -0,0 +1,6 @@ +{ + "navLink": "$Module$ nav link", + "title": "$Module$ module", + "meta": "$Module$ example", + "welcomeText": "Hello, This is the $Module$ module" +} \ No newline at end of file diff --git a/tools/templates/module/client/locales/index.js b/tools/templates/module/client/locales/index.js new file mode 100644 index 0000000000..9abc2aac88 --- /dev/null +++ b/tools/templates/module/client/locales/index.js @@ -0,0 +1,5 @@ +/* +* The index.js can be empty, it's just needed to point the loader to the root directory of the locales. +* https://github.com/alienfast/i18next-loader#option-2-use-with-import-syntax +*/ +export default {}; \ No newline at end of file diff --git a/tools/templates/module/client/locales/ru/translations.json b/tools/templates/module/client/locales/ru/translations.json new file mode 100644 index 0000000000..1bace811f7 --- /dev/null +++ b/tools/templates/module/client/locales/ru/translations.json @@ -0,0 +1,6 @@ +{ + "navLink": "$Module$ ссылка", + "title": "$Module$ модуль", + "meta": "$Module$ пример", + "welcomeText": "Привет, это $Module$ модуль" +} \ No newline at end of file diff --git a/tools/templates/module/client/reducers/index.js b/tools/templates/module/client/reducers/index.js deleted file mode 100644 index 6c6ee75a42..0000000000 --- a/tools/templates/module/client/reducers/index.js +++ /dev/null @@ -1,8 +0,0 @@ -const defaultState = {}; - -export default function(state = defaultState, action) { - switch (action.type) { - default: - return state; - } -} diff --git a/tools/templates/module/server/Module.spec.js b/tools/templates/module/server/__tests__/Module.spec.ts similarity index 50% rename from tools/templates/module/server/Module.spec.js rename to tools/templates/module/server/__tests__/Module.spec.ts index 25c9d6f2ab..c119cb1a39 100644 --- a/tools/templates/module/server/Module.spec.js +++ b/tools/templates/module/server/__tests__/Module.spec.ts @@ -1,10 +1,10 @@ -/*eslint-disable no-unused-vars*/ import chai from 'chai'; import { step } from 'mocha-steps'; -import { getServer, getApollo } from '../../testHelpers/integrationSetup'; +import { getServer, getApollo } from '../../../testHelpers/integrationSetup'; describe('$Module$ API works', () => { - let server, apollo; + let server: any; + let apollo: any; before(() => { server = getServer(); @@ -14,10 +14,12 @@ describe('$Module$ API works', () => { step('Has GraphQL Playground endpoint', () => { return chai .request(server) - .get('/gplayground') - .end((err, res) => { - res.status.should.be(200); - res.body.should.be('{}'); + .keepOpen() + .get('/graphql') + .set('Accept', 'text/html') + .then(res => { + res.should.have.status(200); + res.body.should.be.eql({}); }); }); }); diff --git a/tools/templates/module/server/index.js b/tools/templates/module/server/index.ts similarity index 100% rename from tools/templates/module/server/index.js rename to tools/templates/module/server/index.ts diff --git a/tools/templates/module/server/resolvers.js b/tools/templates/module/server/resolvers.js deleted file mode 100644 index 13582f9182..0000000000 --- a/tools/templates/module/server/resolvers.js +++ /dev/null @@ -1,6 +0,0 @@ -/*eslint-disable no-unused-vars*/ -export default pubsub => ({ - Query: {}, - Mutation: {}, - Subscription: {} -}); diff --git a/tools/templates/module/server/resolvers.ts b/tools/templates/module/server/resolvers.ts new file mode 100644 index 0000000000..3f32ddc897 --- /dev/null +++ b/tools/templates/module/server/resolvers.ts @@ -0,0 +1,5 @@ +export default (pubsub: any) => ({ + Query: {}, + Mutation: {}, + Subscription: {} +}); diff --git a/tools/templates/module/server/schema.graphql b/tools/templates/module/server/schema.graphql index b224b3517b..8dfc4da35d 100644 --- a/tools/templates/module/server/schema.graphql +++ b/tools/templates/module/server/schema.graphql @@ -1,5 +1,16 @@ -extend type Query {} +# Entity +type TypeName { + typeName: String! +} -extend type Mutation {} +extend type Query { + queryName: TypeName +} -extend type Subscription {} +extend type Mutation { + mutationName(varName: Int!): TypeName +} + +extend type Subscription { + subscriptionName: TypeName +} diff --git a/tools/templates/module/server/sql.js b/tools/templates/module/server/sql.ts similarity index 68% rename from tools/templates/module/server/sql.js rename to tools/templates/module/server/sql.ts index 71381b28a0..ec7d45b5d9 100644 --- a/tools/templates/module/server/sql.js +++ b/tools/templates/module/server/sql.ts @@ -1,4 +1,3 @@ -/*eslint-disable no-unused-vars*/ import knex from '../../sql/connector'; export default class $Module$ {} diff --git a/tslint.json b/tslint.json index 135ceea563..7fe4c9c2b2 100644 --- a/tslint.json +++ b/tslint.json @@ -12,7 +12,7 @@ ] }, "linterOptions": { - "exclude": ["**/*.js", "**/*.jsx", "**/*.d.ts"] + "exclude": ["**/*.js", "**/*.jsx", "**/*.d.ts", "tools/**/*.*"] }, "rules": { "prettier": [true, {